`ifdef VERILATOR
    `include "sdvd_defs.sv"
`endif

module rom_sd_tb;
    bit clk,reset;
    wire ready;
    int errors;
    logic [10:0] i;

    audio_buffer_interface buffer();

    rom_sd #("consecutive.mem") dut (clk,reset,ready,buffer.driver);


    initial forever #10 clk = ~clk;

    initial begin
        reset = 1;
        buffer.address_half = 0;
        @(posedge clk);
        reset = 0;
        // Audio data should not be flowing yet
        #1 assert (buffer.dina == 0) 
        else begin
            errors++;
            $error("Data not zero after reset, found 0x%x",buffer.dina);
        end
        repeat (3) @(posedge clk);
        for (i = 0; i < 1024;) begin
            @(posedge clk);
            #1

            assert (buffer.addra === i)
            else begin 
                errors++;
                $error("Incorrect address, expected %x found %x",i,buffer.addra);
            end

            assert (buffer.dina === ((i + 1) % 256))
            else begin 
                errors++;
                $error("Incorrect data, expected 0x%x but found 0x%x",i[7:0],buffer.dina);
            end

            assert (i == 0 || buffer.ena === 1)
            else begin 
                $error("Enable not high");
                errors++;
            end

            assert (buffer.address_half == 0)
            else begin 
                errors++;
                $error("Incorrect address half, expected 0 but found %d",buffer.address_half);
            end

            i = i + 1;
        end
        // Wait a cycle for the buffer to catch up
        @(posedge clk);
        // Make sure that we start waiting and that we signal that the buffer
        // is ready
        #1 assert(buffer.ena === 0)
        else begin
            errors++;
            $error("Buffer did not wait after first full cycle");
        end
        assert(ready === 1)
        else begin
            errors++;
            $error("Buffer did not signal ready");
        end

        assert(dut.buffer_half === 1)
        else begin
            errors++;
            $error("Buffer half did not correctly change to 1");
        end

        // Set the address half high so we can test waiting/catching up to the
        // buffer
        buffer.address_half = 1;
        repeat (100) @(posedge clk);
        #1 assert(buffer.ena === 0)
        else begin
            errors++;
            $error("Buffer did not wait after first full cycle");
        end

        buffer.address_half = 0;
        repeat (3) @(posedge clk);
        // Check that sending into the upper half of the buffer works as
        // expected
        while (i != 0) begin
            @(posedge clk);
            #1

            assert (buffer.addra === i)
            else begin 
                errors++;
                $error("Incorrect address, expected %x found %x",i,buffer.addra);
            end

            assert (buffer.dina === ((i + 1) % 256))
            else begin 
                errors++;
                $error("Incorrect data, expected 0x%x but found 0x%x",i[7:0],buffer.dina);
            end

            assert (i == 0 || buffer.ena === 1)
            else begin 
                $error("Enable not high");
                errors++;
            end

            assert (buffer.address_half == 0)
            else begin 
                errors++;
                $error("Incorrect address half, expected 0 but found %d",buffer.address_half);
            end

            i = i + 1;
        end

        // Wait a cycle for the buffer to catch up
        @(posedge clk);
        // Make sure that we start waiting
        #1 assert(buffer.ena === 0)
        else begin
            errors++;
            $error("Buffer did not wait after second full cycle");
        end
        assert(ready === 1)
        else begin
            errors++;
            $error("Buffer did not signal ready");
        end

        assert(dut.buffer_half === 0)
        else begin
            errors++;
            $error("Buffer half did not correctly change to 0");
        end


        $display("Found %0d errors while testing rom_sd",errors);

        $finish;



    end

endmodule
