EECS151 / riscv-cpu / hardware / sim / c_testbench.v
c_testbench.v
Raw
`timescale 1ns/10ps
/* CHANGE THIS TO POINT TO YOUR CSR REGISTER (like isa_testbench.v) */
`define CSR_PATH CPU.wd

module c_testbench();
    parameter CPU_CLOCK_PERIOD = 20;
    parameter CPU_CLOCK_FREQ = 50_000_000;
    parameter BAUD_RATE = 10_000_000; // Fast baud rate for simulation

    reg clk, rst;
    wire FPGA_SERIAL_RX, FPGA_SERIAL_TX;

    reg   [7:0] data_in;
    reg         data_in_valid;
    wire        data_in_ready;
    wire  [7:0] data_out;
    wire        data_out_valid;
    reg         data_out_ready;

    initial clk = 0;
    always #(CPU_CLOCK_PERIOD/2) clk <= ~clk;

    // Instantiate your Riscv CPU here and connect the FPGA_SERIAL_TX wires
    // to the off-chip UART we use for testing. The CPU has a UART (on-chip UART) inside it.
    Riscv151 # (
        .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ),
        .RESET_PC(32'h1000_0000),
        .BAUD_RATE(BAUD_RATE)
    ) CPU (
        .clk(clk),
        .rst(rst),
        .FPGA_SERIAL_RX(FPGA_SERIAL_RX),
        .FPGA_SERIAL_TX(FPGA_SERIAL_TX)
    );

    // Instantiate the off-chip UART
    uart # (
        .CLOCK_FREQ(CPU_CLOCK_FREQ),
        .BAUD_RATE(BAUD_RATE)
    ) off_chip_uart (
        .clk(clk),
        .reset(rst),
        .data_in(data_in),
        .data_in_valid(data_in_valid),
        .data_in_ready(data_in_ready),
        .data_out(data_out),
        .data_out_valid(data_out_valid),
        .data_out_ready(data_out_ready),
        .serial_in(FPGA_SERIAL_TX),
        .serial_out(FPGA_SERIAL_RX)
    );

    reg done = 0;
    integer cycle = 0;
    integer idx = 0;
    reg [7:0] str [0:3];
    assign str[0] = "x";
    assign str[1] = "y";
    assign str[2] = "z";
    assign str[3] = 8'h0d;
    integer csr_val = 0;
    initial begin
        $readmemh("../../software/c_test/c_test.hex", CPU.dmem.mem, 0, 16384-1);
        $readmemh("../../software/c_test/c_test.hex", CPU.imem.mem, 0, 16384-1);

        `ifndef IVERILOG
            $vcdpluson;
        `endif
        `ifdef IVERILOG
            $dumpfile("c_testbench.fst");
            $dumpvars(0,c_testbench);
        `endif

        // Reset all parts
        rst = 1'b0;
        data_in_valid = 1'b0;
        data_out_ready = 1'b0;

        repeat (20) @(posedge clk); #1;

        rst = 1'b1;
        repeat (30) @(posedge clk); #1;
        rst = 1'b0;

        fork
            begin
                // Receive the characters '151> ' from the UART
                repeat (5) begin
                    while (!data_out_valid) @(posedge clk); #1;
                    $display("Got %c", data_out);

                    data_out_ready = 1'b1;
                    @(posedge clk); #1;
                    data_out_ready = 1'b0;
                end

                // Send the characters 'x' 'y' 'z' '0d' to the CPU's UART
                repeat (4) begin
                    while (!data_in_ready) @(posedge clk); #1;

                    data_in = str[idx];
                    data_in_valid = 1'b1;
                    @(posedge clk); #1;
                    data_in_valid = 1'b0;
                    idx = idx + 1;

                    repeat (300) @(posedge clk); // Give the CPU time to process each character
                end

                while (`CSR_PATH === 32'd0) begin
                    @(posedge clk);
                end
                csr_val = `CSR_PATH;
                done = 1;
            end
            begin
                for (cycle = 0; cycle < 10000; cycle = cycle + 1) begin
                    if (done) begin
                        $display("Got CSR value: %d", csr_val);
                        $finish();
                    end
                    @(posedge clk);
                end
                if (!done) begin
                    $display("Failed: timing out");
                    $finish();
                end
            end
        join

        `ifndef IVERILOG
            $vcdplusoff;
        `endif
        $finish();
    end
endmodule