`ifdef VERILATOR
    `include "sdvd_defs.sv"
`endif
import sdvd_defs::SPEED;

module audio_buffer_tb;
    logic clk, reset;

    // Control signals
    logic play, stop;
    SPEED speed;

    // Whether the current address being read from is in the upper or lower
    // half of the 2KiB buffer
    logic address_half;

    // Whether the audio buffer is currently playing
    logic playing;

    // A 16-bit audio sample to output
    logic [15:0] sample;

    // Inputs for the memory buffer
    logic [10:0] addra;
    logic [7:0] dina;
    logic clka, ena;

    logic [9:0] counter;

    logic [15:0] test_memory [1023:0];
    audio_buffer dut(.*);

    // The writer's clock should be much faster than the 48khz buffer clock
    initial clka = 0;
    always #5 clka = ~clka;


    // An order of magnitude difference is fine
    initial clk = 0;
    always #50 clk = ~clk;

    // Reader
    initial begin
        `ifdef DEBUG
        $monitor("PLAYING: %b ADDR: 0x%x DATA: 0x%x WILLDELAY: %b",
                 playing, dut.address, dut.doutb,dut.delay);
        `endif
        fork
        //Reader
        begin
            play = 0;
            stop = 0;
            clk = 0;
            reset = 0;
            speed = 1;
            @(posedge clk)
            reset = 1;
            @(posedge clk)
            reset = 0;
            play = 1;
            @(posedge clk)
            assert (playing == 1) else $error("Audio buffer not playing");
            // Wait an extra clock cycle because of the blockmem delay
            @(posedge clk)
            // The most basic test we can do here is an incrementing counter,
            // where the stored sample is the same as the address
            $display("Running linear test");
            for (counter = 0; counter != 1023; counter++) begin
                #1
                assert ({6'b0, counter} === sample) else
                    $error("Invalid sample, expected 0x%x but found 0x%x",counter,sample);
                @(posedge clk);
            end
            @(posedge clk);
            $display("Running randomized test");
            for (counter = 0; counter != 1023; counter++) begin
                #1
                assert (test_memory[counter] === sample) else
                    $error("Invalid sample, expected 0x%x but found 0x%x",test_memory[counter],sample);
                @(posedge clk);
            end

        end
        // Writer
        begin
            ena = 1;
            for (int i = 0; i<= 1024; i++) begin
                addra = i*2;
                dina = i[7:0];
                @(posedge clka)
                addra = i*2+1;
                dina = i[15:8];
                @(posedge clka);
            end
            wait (address_half==1);
            // random test, write to lower half of memory
            for (int i = 0; i< 512; i++) begin
                addra = i*2;
                dina = $urandom;
                test_memory[i][7:0] = dina;
                @(posedge clka)
                addra = i*2+1;
                dina = $urandom;
                test_memory[i][15:8] = dina;
                @(posedge clka);
            end
            wait (address_half==0);
            // random test, write to upper half of memory
            for (int i = 512; i< 1024; i++) begin
                addra = i*2;
                dina = $urandom;
                test_memory[i][7:0] = dina;
                @(posedge clka)
                addra = i*2+1;
                dina = $urandom;
                test_memory[i][15:8] = dina;
                @(posedge clka);
            end
        end
        join
        $finish;
    end

endmodule
