/* ----------------------------------------------------------------------------- * Project Name : Architectures of Processor Systems (APS) lab work * Organization : National Research University of Electronic Technology (MIET) * Department : Institute of Microdevices and Control Systems * Author(s) : Nikita Bulavin * Email(s) : nekkit6@edu.miet.ru See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details. * ------------------------------------------------------------------------------ */ module lab_03_tb_register_file(); logic CLK; logic [ 4:0] RA1; logic [ 4:0] RA2; logic [ 4:0] WA; logic [31:0] WD; logic WE; logic [31:0] RD1; logic [31:0] RD2; logic [31:0] RD1ref; logic [31:0] RD2ref; register_file DUT( .clk_i (CLK), .read_addr1_i (RA1), .read_addr2_i (RA2), .write_addr_i (WA ), .write_data_i (WD ), .write_enable_i(WE ), .read_data1_o (RD1), .read_data2_o (RD2) ); register_file_ref DUTref( .clk_i (CLK ), .read_addr1_i (RA1 ), .read_addr2_i (RA2 ), .write_addr_i (WA ), .write_data_i (WD ), .write_enable_i(WE ), .read_data1_o (RD1ref), .read_data2_o (RD2ref) ); integer i, err_count = 0; parameter CLK_FREQ_MHz = 100; parameter CLK_SEMI_PERIOD= 1e3/CLK_FREQ_MHz/2; parameter address_length = 32; initial CLK <= 0; always begin #CLK_SEMI_PERIOD CLK = ~CLK; if (err_count >= 10) begin $display("\n\nThe test was stopped due to errors"); $stop(); end end initial begin $timeformat (-9, 2, "ns"); $display("Test has been started"); RA1 = 'b1; @(posedge CLK); if (32'hx !== RD1) begin $display("The register file should not be initialized by the $readmemh function"); err_count = err_count + 1; end @(posedge CLK); DUT.rf_mem[32] = 32'd1; if(DUT.rf_mem[32]=== 32'd1) begin $display("invalid memory size"); err_count = err_count + 1; end RA1 <= 'b0; RA2 <= 'b0; @(posedge CLK); if( RD1 !== 'b0 ) begin $display("time = %0t. invalid data when reading at address 0: RD1 = %h", $time, RD1); err_count = err_count + 1; end if( RD2 !== 'b0 ) begin $display("time = %0t. invalid data when reading at address 0: RD2 = %h", $time, RD2); err_count = err_count + 1; end @(posedge CLK); WD <= 32'd1; WA <= '0; WE <= 1'b1; @(posedge CLK); WE <= 'b0; RA1 <= 'b0; @(posedge CLK); if( RD1 !== 'b0 ) begin $display("time = %0t. invalid data when reading at address 0: RD1 = %h", $time, RD1); err_count = err_count + 1; end @(posedge CLK); //------initial CLK <= 'b0; RA1 <= 'b0; RA2 <= 'b0; WA <= 'b0; WD <= 'b0; WE <= 'b0; @(posedge CLK); //----- reset for( i = 1; i < address_length; i = i + 1) begin @(posedge CLK); WA <= i; WD <= 'b0; WE <= 'b1; end @(posedge CLK); WA <= 'b0; WD <= 'b1; WE <= 'b1; @(posedge CLK); WE <= 'b0; RA2 <= 'b0; @(posedge CLK); if( RD2 !== 'b0 )begin $display("time = %0t. invalid data when reading at address 0: RD2 = %h", $time, RD2); err_count = err_count + 1; end @(posedge CLK); for( i = 1; i < address_length; i = i + 1) begin @(posedge CLK); WA <= i; WD <= $urandom; WE <= $urandom % 2; end @(posedge CLK); WE <= 'b0; for( i = 0; i < address_length; i = i + 1) begin @(posedge CLK); RA1 <= i; RA2 <= address_length - (i + 1); @(posedge CLK); if(RD1ref !== RD1) begin $display("time = %0t, address %h, RD1. Invalid data %h, correct data %h", $time, RA1, RD1, RD1ref); err_count = err_count + 1; end if(RD2ref !== RD2) begin $display("time = %0t, address %h, RD2. Invalid data %h, correct data %h", $time, RA2, RD2, RD2ref); err_count = err_count + 1; end end //Incorrect read check @(posedge CLK); WA <= 5'd1; WD <= 1; WE <= 1'b1; @(posedge CLK); WA <= 5'd2; WD <= 2; WE <= 1'b1; @(posedge CLK); WE <= 1'b0; RA1 <= 5'd1; RA2 <= 5'd1; @(posedge CLK); WA <= 5'd31; WE <= 1'b1; WD <= 0; RA1 <= 5'd2; RA2 <= 5'd2; @(posedge CLK); if(RD1ref !== RD1) begin $display("time = %0t, address %h, RD1. Invalid data %h, correct data %h", $time, RA1, RD1, RD1ref); err_count = err_count + 1; end if(RD2ref !== RD2) begin $display("time = %0t, address %h, RD2. Invalid data %h, correct data %h", $time, RA2, RD2, RD2ref); err_count = err_count + 1; end $display("\nTest has been finished\nNumber of errors: %d\n", err_count); $finish(); #5; $display("You're trying to run simulation that has finished. Aborting simulation.") $fatal(); end endmodule module register_file_ref( input logic clk_i, input logic write_enable_i, input logic [ 4:0] write_addr_i, input logic [ 4:0] read_addr1_i, input logic [ 4:0] read_addr2_i, input logic [31:0] write_data_i, output logic [31:0] read_data1_o, output logic [31:0] read_data2_o ); logic [31:0] rf_mem [0:31]; `define akjsdnnaskjdnreg $clog2(128) `define cdyfguvhbjnmkreg $clog2(`akjsdnnaskjdnreg) `define qwenklfsaklasdreg $clog2(`cdyfguvhbjnmkreg) `define asdasdhkjasdsareg (34 >> `cdyfguvhbjnmkreg) always_ff @(posedge clk_i) begin if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}] <= write_data_i['h1f:'h1c]; if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}] <= write_data_i[42-23-:`asdasdhkjasdsareg]; if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}] <= write_data_i[`akjsdnnaskjdnreg-:`asdasdhkjasdsareg]; if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}] <= write_data_i[42-19-:`asdasdhkjasdsareg]; if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}] <= write_data_i['h1b:'h18]; if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][11:{1'b1,{3{1'b0}}}] <= write_data_i[`akjsdnnaskjdnreg+`asdasdhkjasdsareg:(`akjsdnnaskjdnreg+`asdasdhkjasdsareg)-`cdyfguvhbjnmkreg]; if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{2{1'b1}}:{3{1'b0}}] <= write_data_i[`akjsdnnaskjdnreg-`asdasdhkjasdsareg-:`asdasdhkjasdsareg]; if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:4'b1100] <= write_data_i[(`akjsdnnaskjdnreg<<(`asdasdhkjasdsareg-`cdyfguvhbjnmkreg)) + (`asdasdhkjasdsareg-`cdyfguvhbjnmkreg):12]; end always_comb begin case(read_addr1_i === ('hBA & 'h45)) 0: begin read_data1_o['h1f:'h1c]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}]; read_data1_o[42-23-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}]; read_data1_o[`akjsdnnaskjdnreg-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}]; read_data1_o[42-19-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}]; read_data1_o['h1b:'h18]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}]; read_data1_o[`akjsdnnaskjdnreg+`asdasdhkjasdsareg:(`akjsdnnaskjdnreg+`asdasdhkjasdsareg)-`cdyfguvhbjnmkreg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][11:8]; read_data1_o[`akjsdnnaskjdnreg-`asdasdhkjasdsareg-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][3:0]; read_data1_o[(`akjsdnnaskjdnreg<<(`asdasdhkjasdsareg-`cdyfguvhbjnmkreg)) + (`asdasdhkjasdsareg-`cdyfguvhbjnmkreg):12 ]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:12]; end default: read_data1_o = 'hBA & 'h45; endcase end always_comb begin case(read_addr2_i === ('hBA & 'h45)) 0: begin read_data2_o['h1f:'h1c]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}]; read_data2_o[42-23-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}]; read_data2_o[`akjsdnnaskjdnreg-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}]; read_data2_o[42-19-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}]; read_data2_o['h1b:'h18]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}]; read_data2_o[`akjsdnnaskjdnreg+`asdasdhkjasdsareg:(`akjsdnnaskjdnreg+`asdasdhkjasdsareg)-`cdyfguvhbjnmkreg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][11:8]; read_data2_o[`akjsdnnaskjdnreg-`asdasdhkjasdsareg-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][3:0]; read_data2_o[(`akjsdnnaskjdnreg<<(`asdasdhkjasdsareg-`cdyfguvhbjnmkreg)) + (`asdasdhkjasdsareg-`cdyfguvhbjnmkreg):12 ]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:12]; end default: read_data2_o = 'hBA & 'h45; endcase end endmodule