`timescale 1ns / 1ps `default_nettype none `define EOF 32'hFFFF_FFFF `define NULL 0 // SPECIFY TRACE FILE HERE `define TESTBENCH_TRACE "code/harness4.trace" `ifdef ICARUS `include "include/bram.v" `include "include/clock_util.v" `include "lc4_pipe.v" `endif // VERSION 1.3 module test_pl_datapath_v; // Inputs reg CLK; reg RST; wire GWE; wire [15:0] IMEM_OUT; wire [15:0] DMEM_OUT; // Outputs wire [15:0] IMEM_ADDR; wire [15:0] DMEM_ADDR; wire [15:0] DMEM_IN; wire DMEM_WE; wire [15:0] _TEST_W_PC; wire [15:0] _TEST_W_INSN; wire [15:0] _TEST_W_REGFILE_DATA_IN; wire _TEST_W_REGFILE_WE; wire [2:0] _TEST_W_NZP_IN; wire _TEST_W_NZP_WE; wire [15:0] _TEST_W_DMEM_ADDR; wire [15:0] _TEST_W_DMEM_IN; wire _TEST_W_DMEM_WE; wire _TEST_W_STALL; wire [15:0] _TEST_PMC_CYCLE, _TEST_PMC_INSN, _TEST_PMC_LOAD_STALL, _TEST_PMC_BRANCH_STALL; reg [15:0] verify_PC, verify_Insn, verify_WeNZP, verify_DataIn, verify_DmemAddr; reg BPRED_ON, BYPASS_ON; wire [15:0] vout_dummy; // Data and video memory block bram memory (.idclk( CLK ), .iaddr( IMEM_ADDR ), .iout( IMEM_OUT ), .daddr ( DMEM_ADDR ), .dout ( DMEM_OUT ), .din ( DMEM_IN ), .dwe ( DMEM_WE ), .vclk ( 1'b0 ), .vaddr ( 16'h0000 ), .vout ( vout_dummy )); // Instantiate your processor here! lc4_pipe proc (.CLK(CLK), .RST(RST), .GWE( GWE ), .IMEM_ADDR(IMEM_ADDR), .IMEM_OUT(IMEM_OUT), .DMEM_ADDR(DMEM_ADDR), .DMEM_IN(DMEM_IN), .DMEM_OUT(DMEM_OUT), .DMEM_WE(DMEM_WE), .BYPASS_ON(BYPASS_ON), .BPRED_ON(BPRED_ON), // These test signals are from the writeback stage of pipeline ._TEST_W_PC(_TEST_W_PC), ._TEST_W_INSN(_TEST_W_INSN), ._TEST_W_REGFILE_DATA_IN(_TEST_W_REGFILE_DATA_IN), ._TEST_W_REGFILE_WE(_TEST_W_REGFILE_WE), ._TEST_W_NZP_IN(_TEST_W_NZP_IN), ._TEST_W_NZP_WE(_TEST_W_NZP_WE), ._TEST_W_DMEM_WE(_TEST_W_DMEM_WE), ._TEST_W_DMEM_IN(_TEST_W_DMEM_IN), ._TEST_W_DMEM_ADDR(_TEST_W_DMEM_ADDR), // Set this signal high for a stall/flush ._TEST_W_STALL(_TEST_W_STALL), ._TEST_PMC_CYCLE(_TEST_PMC_CYCLE), ._TEST_PMC_INSN(_TEST_PMC_INSN), ._TEST_PMC_LOAD_STALL(_TEST_PMC_LOAD_STALL), ._TEST_PMC_BRANCH_STALL(_TEST_PMC_BRANCH_STALL) ); /* Because the memory needs a rising edge in order to read, we have to slow the processor down to run only on every other cycle. We need 2 rising edges to process a load - 1 for the memory, and 1 for the regfile. */ count #(2) gwe_generator(.clk( CLK ), .out( GWE )); always #5 CLK <= ~CLK; integer file, char, retval, lineno, cntErrors; always @(posedge CLK) if (GWE) begin // Display all W-stage data. Comment this line out to suppress unwanted output $display ("PC: %h, INSN: %h", _TEST_W_PC, _TEST_W_INSN); $stop; lineno = lineno + 1; if (lineno == 1000) $finish; end initial begin // Initialize Inputs CLK = 0; RST = 0; BPRED_ON = 0; BYPASS_ON = 1; verify_PC = 0; verify_Insn = 0; verify_WeNZP = 0; verify_DataIn = 0; lineno = 1; cntErrors = 0; // Wait for global reset to finish #20; RST = 1; #40; RST = 0; // open the test inputs file = $fopen(`TESTBENCH_TRACE, "r"); if (file == `NULL) begin $stop; end char = $fgetc(file); while (char != `EOF) begin #1; RST = 0; retval = $ungetc(char, file); // push back the non-EOF char retval = $fscanf(file, "%h %h %h %h %h", verify_PC, verify_Insn, verify_WeNZP, verify_DataIn, verify_DmemAddr); char = $fgetc(file); // eats newline #28; // allow for "setup time" // Ignore all stall cycles; do not compare them against trace cycles. while ( _TEST_W_STALL == 1'b1) begin #40; // big clock end `ifdef VERBOSE // Display all W-stage data. Comment this line out to suppress unwanted output $display ("Line: %d, PC: %h, Instruction: %h, regWrite?: %d, regData: %h", lineno, _TEST_W_PC, _TEST_W_IMEM_OUT, _TEST_W_REGFILE_WE, _TEST_W_REGFILE_DATA_IN); `endif if ( verify_PC != _TEST_W_PC ) begin $display( "Error at line %d: PC should be %h (but was %h)", lineno, verify_PC, _TEST_W_PC ); cntErrors = cntErrors + 1; end if ( verify_Insn != _TEST_W_INSN ) begin $display( "Error at line %d: Current insn should be %h (but was %h)", lineno, verify_Insn, _TEST_W_INSN ); cntErrors = cntErrors + 1; end if ( verify_WeNZP[12] != _TEST_W_REGFILE_WE ) begin $display( "Error at line %d: Regfile WE should be %h (but was %h)", lineno, verify_WeNZP[12], _TEST_W_REGFILE_WE ); cntErrors = cntErrors + 1; end if ( verify_WeNZP[8] != _TEST_W_DMEM_WE ) begin $display( "Error at line %d: Dmem WE should be %h (but was %h)", lineno, verify_WeNZP[8], _TEST_W_DMEM_WE ); cntErrors = cntErrors + 1; end if ( verify_Insn[15:12] != 4'h4 && verify_Insn[15:12] != 4'h15 ) begin if ( verify_WeNZP[4] != _TEST_W_NZP_WE ) begin $display( "Error at line %d: NZP WE should be %h (but was %h)", lineno, verify_WeNZP[4], _TEST_W_NZP_WE ); cntErrors = cntErrors + 1; end if ( verify_WeNZP[4] == 1'b1 && _TEST_W_NZP_IN != verify_WeNZP[2:0] ) begin $display( "Error at line %d: NZP in should be %h (but was %h)", lineno, verify_WeNZP[2:0], _TEST_W_NZP_IN); cntErrors = cntErrors + 1; end end if ( verify_WeNZP[8] == 1'b1 && _TEST_W_DMEM_IN != verify_DataIn ) begin $display( "Error at line %d: Dmem IN should be %h (but was %h)", lineno, verify_DataIn, _TEST_W_DMEM_IN ); cntErrors = cntErrors + 1; end if ( verify_WeNZP[12] == 1'b1 && _TEST_W_REGFILE_DATA_IN != verify_DataIn ) begin $display( "Error at line %d: Regfile IN should be %h (but was %h)", lineno, verify_DataIn, _TEST_W_REGFILE_DATA_IN ); cntErrors = cntErrors + 1; end if ( verify_DmemAddr != 16'h0 && verify_DmemAddr != _TEST_W_DMEM_ADDR ) begin $display( "Error at line %d: Dmem address should be %h (but was %h)", lineno, verify_DmemAddr, _TEST_W_DMEM_ADDR ); cntErrors = cntErrors + 1; end #1; // wait out the rest of the cycle #10; lineno = lineno + 1; end // end while $display ( "Summary: %d discrepancies detected.", cntErrors ); $display ("CYCLE: %d INSN: %d LSTALL: %d BSTALL: %d ALL: %d", _TEST_PMC_CYCLE, _TEST_PMC_INSN, _TEST_PMC_LOAD_STALL, _TEST_PMC_BRANCH_STALL, _TEST_PMC_INSN + _TEST_PMC_LOAD_STALL + _TEST_PMC_BRANCH_STALL); $fclose(file); $stop; end // end initial endmodule