From 6becea322f55d71bc7e1ef39a223622bdf97dc45 Mon Sep 17 00:00:00 2001 From: Aadi Desai <21363892+supleed2@users.noreply.github.com> Date: Tue, 8 Dec 2020 13:23:08 +0000 Subject: [PATCH 1/2] Update mips_cpu_regfile.v Regfile should now compile, write is skipped if $0 is the destination register --- rtl/mips_cpu_regfile.v | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rtl/mips_cpu_regfile.v b/rtl/mips_cpu_regfile.v index 9247da9..bce55e1 100644 --- a/rtl/mips_cpu_regfile.v +++ b/rtl/mips_cpu_regfile.v @@ -15,12 +15,11 @@ reg[31:0] memory [31:0]; //32 register slots, 32-bits wide initial begin integer i; //Initialise to zero by default - for (i = 1; i < 32; i++) begin + for (i = 0; i < 32; i++) begin memory[i] = 0; end end -assign memory[0] = 32'h00000000; assign regv0 = memory[2]; //assigning debug $v0 line to $2 of memory always_comb begin @@ -29,7 +28,9 @@ always_comb begin end always_ff @(negedge clk) begin - if (regwrite) begin + if (writereg == 5'b00000) begin + // skip writing if rd is $0 + end else if (regwrite) begin case (opcode) 6'b100000: begin //lb, load byte case (readdata1[1:0]) From c5aed43ab45ac7c3c0883e7d3efd8d48b4a9afee Mon Sep 17 00:00:00 2001 From: jl7719 Date: Wed, 9 Dec 2020 16:47:58 +0900 Subject: [PATCH 2/2] Update to test each instruction with a small memory --- inputs/ori.txt | 8 +++ rtl/mips_cpu_control.v | 98 ++++++++++++++++----------------- rtl/mips_cpu_memory.v | 27 +++++---- test/test_mips_cpu_harvard.sh | 41 +++++--------- testbench/mips_cpu_harvard_tb.v | 27 ++++----- 5 files changed, 96 insertions(+), 105 deletions(-) create mode 100644 inputs/ori.txt diff --git a/inputs/ori.txt b/inputs/ori.txt new file mode 100644 index 0000000..996347b --- /dev/null +++ b/inputs/ori.txt @@ -0,0 +1,8 @@ +34040003 +00000008 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 \ No newline at end of file diff --git a/rtl/mips_cpu_control.v b/rtl/mips_cpu_control.v index 3b4ab8f..26d4372 100644 --- a/rtl/mips_cpu_control.v +++ b/rtl/mips_cpu_control.v @@ -1,5 +1,4 @@ module mips_cpu_control( - input logic[31:0] Instr, input logic ALUCond, @@ -12,17 +11,8 @@ module mips_cpu_control( output logic CtrlMemWrite, output logic CtrlALUSrc, output logic CtrlRegWrite - ); -/* logic[5:0] op; -logic[5:0] funct; -logic[4:0] rt; */ - -/* assign op = Instr[31:26]; -assign funct = Instr[5:0]; -assign rt = Instr[20:16]; */ - typedef enum logic[5:0]{ SPECIAL = 6'd0, REGIMM = 6'd1, @@ -52,7 +42,7 @@ typedef enum logic[5:0]{ SW = 6'd43 } op_enum; op_enum op; -assign op = Instr[31:26]; +assign op = Instr[31:26]; typedef enum logic[5:0]{ SLL = 6'd0, @@ -87,119 +77,123 @@ typedef enum logic[4:0]{ BGEZAL = 5'd17 } rt_enum; rt_enum rt; -assign rt = Instr[20:16]; +assign rt = Instr[20:16]; -always_comb begin - + + +always @(*) begin //CtrlRegDst logic - if(op == (ADDIU | ANDI | LB | LBU | LH | LHU | LUI | LW | LWL | LWR | ORI | SLTI | SLTIU | XORI))begin + if((op == ADDIU | op == ANDI | op == LB | op == LBU | op == LH | op == LHU | op == LUI | op == LW | op == LWL | op == LWR | op == ORI | op == SLTI | op == SLTIU | op == XORI))begin CtrlRegDst = 2'd0; //Write address comes from rt - end else if (op == (SPECIAL & (funct == (ADDU | AND | JALR | OR | SLL | SLLV | SLT | SLTU | SRA | SRAV | SRL | SRLV | SUBU | XOR))))begin + end else if ((op == SPECIAL) & ((funct == ADDU | funct == AND | funct == JALR | funct == OR | funct == SLL | funct == SLLV | funct == SLT | funct == SLTU | funct == SRA | funct == SRAV | funct == SRL | funct == SRLV | funct == SUBU | funct == XOR)))begin CtrlRegDst = 2'd1; //Write address comes from rd end else if (op == JAL)begin CtrlRegDst = 2'd2; //const reg 31, for writing to the link register end else begin CtrlRegDst = 1'bx; end//Not all instructions are encompassed so, added incase for debug purposes //CtrlPC logic - if(ALUCond & (op == (BEQ | BGTZ | BLEZ | BNE | (REGIMM & (rt == (BGEZ | BGEZAL | BLTZ | BLTZAL))))))begin + if(ALUCond & ( (op == BEQ | op == BGTZ | op ==BLEZ | op ==BNE | (op == REGIMM & ((rt == BGEZ | rt == BGEZAL | rt == BLTZ | rt == BLTZAL))))))begin CtrlPC = 2'd1; // Branches - Jumps relative to PC - end else if(op == (J | JAL))begin + $display("Ctrl PC Branch"); + end else if( (op == J | op == JAL))begin CtrlPC = 2'd2; // Jumps within 256MB Region using 26-bit immediate in J type instruction - end else if(op == (JR | JALR))begin + $display("Ctrl PC Jump Immediate"); + end else if((funct == JR | funct == JALR))begin CtrlPC = 2'd3; // Jumps using Register. - end else begin CtrlPC = 2'd0;end // No jumps or branches, just increment to next word + $display("Ctrl PC Jump Register"); + end else begin CtrlPC = 2'd0; $display("Ctrl PC No Jump/Branch");end // No jumps or branches, just increment to next word //CtrlMemRead and CtrlMemtoReg logic -- Interesting quirk that they have the same logic. Makes sense bc you'd only want to select the read data out when the memory itself is read enabled. - if(op == (LB | LBU | LH | LHU | LW | LWL | LWR))begin + if((op == LB | op == LBU | op == LH | op == LHU | op == LW | op == LWL | op == LWR))begin CtrlMemRead = 1;//Memory is read enabled CtrlMemtoReg = 2'd1;//write data port of memory is fed from data memory - end else if (op == (ADDIU | ANDI | ORI | SLTI | SLTIU | XORI | (SPECIAL & (funct == (ADDU | AND | DIV | DIVU | MTHI | MTLO | MULT | MULTU | OR | SLL | SLLV | SLT | SLTU | SRA | SRAV | SRL | SRLV | SUBU | XOR)))))begin + end else if ((op == ADDIU | op == ANDI | op == ORI | op == SLTI | op == SLTIU | op == XORI | (op == SPECIAL & (funct == (ADDU | AND | DIV | DIVU | MTHI | MTLO | MULT | MULTU | OR | SLL | SLLV | SLT | SLTU | SRA | SRAV | SRL | SRLV | SUBU | XOR)))))begin CtrlMemRead = 0;//Memory is read disabled CtrlMemtoReg = 2'd0;//write data port of memory is fed from ALURes - end else if (op == (JAL | (SPECIAL &(funct == JALR))))begin + end else if ((op == JAL) | ((op == SPECIAL) & (funct == JALR)))begin CtrlMemtoReg = 2'd2;//write data port of memory is fed from PC + 8 end else begin CtrlMemRead = 1'bx;end//Not all instructions are encompassed so, added incase for debug purposes //CtrlALUOp Logic - if(op == (ADDIU | (SPECIAL & (funct == ADDU))))begin + if((op == ADDIU | (op == SPECIAL & (funct == ADDU))))begin CtrlALUOp = 5'd0; //ADD from ALUOps - end else if (op == (ANDI | (SPECIAL & (funct == AND))))begin + end else if ((op == ANDI | (op == SPECIAL & (funct == AND))))begin CtrlALUOp = 5'd4;//AND from ALUOps end else if (op == BEQ) begin CtrlALUOp = 5'd13;//EQ from ALUOps - end else if (op == (REGIMM & (rt == (BGEZ | BGEZAL))))begin + end else if ((op == REGIMM & ((rt == BGEZ | rt == BGEZAL))))begin CtrlALUOp = 5'd17;//GEQ from ALUOps end else if (op == BGTZ)begin CtrlALUOp = 5'd16;//GRT from ALUOps end else if (op == BLEZ)begin CtrlALUOp = 5'd15;//LEQ from ALUOps - end else if (op == (REGIMM & (rt == (BLTZ | BLTZAL))))begin + end else if ((op == REGIMM & ((rt == BLTZ | rt == BLTZAL))))begin CtrlALUOp = 5'd14;//LES from ALUOps - end else if (OP == BNE)begin + end else if (op == BNE)begin CtrlALUOp = 5'd18;//NEQ from ALUOps - end else if (op == (SPECIAL & (funct == DIV)))begin + end else if ((op == SPECIAL & (funct == DIV)))begin CtrlALUOp = 5'd3;//DIV from ALUOps - end else if (op == (SPECIAL & (funct == DIVU)))begin + end else if ((op == SPECIAL & (funct == DIVU)))begin CtrlALUOp = 5'd23;//DIVU from ALUOps - end else if (op == (LB | LBU | LH | LHU | LW | LWL | LWR | SB | SBH | SW))begin + end else if ((op == LB | op == LBU | op == LH | op == LHU | op == LW | op == LWL | op == LWR | op == SB | op == SH | op == SW))begin CtrlALUOp = 5'd0;//ADD from ALUOps end else if (op == LUI)begin CtrlALUOp = 5'd7;//SLL from ALUOps - end else if (op == (SPECIAL & (funct == MTHI | MTLO)))begin + end else if ((op == SPECIAL & (funct == MTHI | MTLO)))begin CtrlALUOp = 5'd19;//PAS from ALUOps - end else if (op == (SPECIAL & (funct == MULT)))begin + end else if ((op == SPECIAL & (funct == MULT)))begin CtrlALUOp = 5'd2;//MUL from ALUOps - end else if (op == (SPECIAL & (funct == MULTU)))begin + end else if ((op == SPECIAL & (funct == MULTU)))begin CtrlALUOp = 5'd22;//MULU from ALUOps - end else if (op == (ORI | (SPECIAL & (funct == OR))))begin + end else if ((op == ORI | (op == SPECIAL & (funct == OR))))begin CtrlALUOp = 5'd5;//OR from ALUOps - end else if (op == (SPECIAL & (funct == SLL)))begin + end else if (op == SPECIAL & (funct == SLL))begin CtrlALUOp = 5'd7;//SLL from ALUOps - end else if (op == (SPECIAL & (funct == SLLV)))begin + end else if (op == SPECIAL & (funct == SLLV))begin CtrlALUOp = 5'd8;//SLLV from ALUOps - end else if (op == (SPECIAL & (funct == SRA)))begin + end else if (op == SPECIAL & (funct == SRA))begin CtrlALUOp = 5'd11;//SRA from ALUOps - end else if (op == (SPECIAL & (funct == SRAV)))begin + end else if (op == SPECIAL & (funct == SRAV))begin CtrlALUOp = 5'd12;//SRAV from ALUOps - end else if (op == (SPECIAL & (funct == SRL)))begin + end else if (op == SPECIAL & (funct == SRL))begin CtrlALUOp = 5'd9;//SRL from ALUOps - end else if (op == (SPECIAL & (funct == SRLV)))begin + end else if (op == SPECIAL & (funct == SRLV))begin CtrlALUOp = 5'd10;//SRLV from ALUOps - end else if (op == (SLTI | (SPECIAL & (funct == SLT))))begin + end else if (op == SLTI | (op == SPECIAL & (funct == SLT)))begin CtrlALUOp = 5'd20;//SLT from ALUOps - end else if (op == (SLTIU | (SPECIAL & (funct == SLTU))))begin + end else if (op == SLTIU | (op == SPECIAL & (funct == SLTU)))begin CtrlALUOp = 5'd21;//SLTU from ALUOps - end else if (op == (SPECIAL & (funct == SUBU)))begin + end else if (op == SPECIAL & (funct == SUBU))begin CtrlALUOp = 5'd1;//SUB from ALUOps - end else if (op == (XORI | (SPECIAL & (funct == XOR))))begin + end else if (op == XORI | (op == SPECIAL & (funct == XOR)))begin CtrlALUOp = 5'd6;//XOR from ALUOps end else begin CtrlALUOp = 5'bxxxxx; end //Ctrlshamt logic - if(op == (SPECIAL & (funct == (SRA | SRL | SLL))))begin + if(op == SPECIAL & (funct == (SRA | SRL | SLL)))begin Ctrlshamt = Instr[10:6];// Shift amount piped in from the instruction end else if(op == LUI)begin Ctrlshamt = 5'd16;//Used specifically to implement LUI as the instruction itslef does not include shamt end else begin Ctrlshamt = 5'bxxxxx;end //CtrlMemWrite logic - if(op == (SB | SH | SW))begin + if(op == SB | op == SH | op == SW)begin CtrlMemWrite = 1;//Memory is write enabled end else begin CtrlMemWrite = 0;end//default is 0 to ensure no accidental overwriting. //CtrlALUSrc logic - if(op == (ADDIU | ANDI | LUI | ORI | SLTI | SLTIU | XORI | LB | LBU | LH | LHU | LW | LWL | LWR | SB | SH | SW))begin + if((op == ADDIU | op == ANDI | op == LUI | op == ORI | op == SLTI | op == SLTIU | op == XORI | op == LB | op == LBU | op == LH | op == LHU | op == LW | op == LWL | op == LWR | op == SB | op == SH | op == SW))begin CtrlALUSrc = 1;//ALU Bus B is fed from the 16-bit immediate sign extended to 32-bit value taken from Instr[15-0] - end else if (op == (BEQ | BGTZ | BLEZ | BNE | (REGIMM & (rt == (BGEZ | BGEZAL | BLTZ | BLTZAL))) | (SPECIAL & (funct == (ADDU | AND | DIV | DIVU | MULT | MULTU | OR | SLLV | SLT | SLTU | SRAV | SRLV | SUBU | XOR)))))begin + end else if ((op == BEQ | op == BGTZ | op == BLEZ | op == BNE | (op == REGIMM & ((rt == BGEZ | rt == BGEZAL | rt == BLTZ | rt == BLTZAL))) | (op == SPECIAL & ((funct == ADDU | funct == AND | funct == DIV | funct == DIVU | funct == MULT | funct == MULTU | funct == OR | funct == SLLV | funct == SLT | funct == SLTU | funct == SRAV | funct == SRLV | funct == SUBU | funct == XOR)))))begin CtrlALUSrc = 0;///ALU Bus B is fed from rt. end else begin CtrlALUSrc = 1'bx;end //CtrlRegWrite logic - if(op == (ADDIU | ANDI | LB | LBU | LH | LHU | LUI | LW | LWL | LWR | ORI | SLTI | SLTIU | XORI | (SPECIAL & (funct == (ADDU | AND | DIV | DIVU | MULT | MULTU | JALR | OR | SLL | SLLV | SLT | SLTU | SRA | SRAV | SRL | SRLV | SUBU | XOR)))))begin + if((op == ADDIU | op == ANDI | op == LB | op == LBU | op == LH | op == LHU | op == LUI | op == LW | op == LWL | op == LWR | op == ORI | op == SLTI | op == SLTIU | op == XORI | (op == SPECIAL & ((funct == ADDU | funct == AND | funct == DIV | funct == DIVU | funct == MULT | funct == MULTU | funct == JALR | funct == OR | funct == SLL | funct == SLLV | funct == SLT | funct == SLTU | funct == SRA | funct == SRAV | funct == SRL | funct == SRLV | funct == SUBU | funct == XOR)))))begin CtrlRegWrite = 1;//The Registers are Write Enabled - end else begin CtrlRegWrite = 0;end // The Registers are Write Disabled - + end else begin CtrlRegWrite = 0; end // The Registers are Write Disabled + end endmodule diff --git a/rtl/mips_cpu_memory.v b/rtl/mips_cpu_memory.v index c8bb8fc..45aa576 100644 --- a/rtl/mips_cpu_memory.v +++ b/rtl/mips_cpu_memory.v @@ -31,36 +31,34 @@ module mips_cpu_memory( ); parameter RAM_INIT_FILE = ""; - reg [31:0] memory [4294967295:0]; // 2^32 memory locations of 32 bits size + reg [31:0] memory [0:7]; // 2^30 set as 8 for now for small testcases initial begin integer i; //Initialise to zero by default - for (i=0; i<4294967296; i++) begin + for (i=0; i<8; i++) begin memory[i]=0; end //Load contents from file if specified if (RAM_INIT_FILE != "") begin - $display("RAM : INIT : Loading RAM contents from %s", RAM_INIT_FILE); - $readmemh(RAM_INIT_FILE, memory, 32'hBFC00000, 32'd0); + $display("RAM: Loading RAM contents from %s", RAM_INIT_FILE); + $readmemh(RAM_INIT_FILE, memory, 32'h4); //32'hBFC00000 equivalent for small memory as byte 16 + end + + //Display what's in memory for debugging + for (integer j = 0; j<$size(memory); j++) begin + $display("Byte %d, %h", j*4, memory[j]); end end //Combinatorial read path for data and instruction. - always_comb begin - if (clk == 1'd1) begin - data_readdata = data_read ? memory[data_address] : 16'hxxxx; - instr_readdata = memory[instr_address]; - end - else begin - data_readdata = data_readdata; - instr_readdata = instr_address; - end - end + assign data_readdata = data_read ? {memory[data_address],memory[data_address+1],memory[data_address+2],memory[data_address+3]} : 16'hxxxx; + assign instr_readdata = memory[instr_address/4]; //Synchronous write path always_ff @(posedge clk) begin + $display("Instruction Read: %h", instr_readdata); //$display("RAM : INFO : data_read=%h, data_address = %h, mem=%h", data_read, data_address, memory[data_address]); if (!data_read & data_write) begin //cannot read and write to memory in the same cycle if (instr_address != data_address) begin //cannot modify the instruction being read @@ -70,3 +68,4 @@ module mips_cpu_memory( end endmodule + diff --git a/test/test_mips_cpu_harvard.sh b/test/test_mips_cpu_harvard.sh index 20e8f96..63cae06 100644 --- a/test/test_mips_cpu_harvard.sh +++ b/test/test_mips_cpu_harvard.sh @@ -23,41 +23,30 @@ echo ${INSTR}; if [[ ${INSTR} == "No instruction specified: running all testcases" ]]; then # All Testcase Files - TESTCASES=$(ls ./inputs | grep ".hex.txt"); + TESTCASES=$(ls ./inputs | grep ".txt"); echo ${TESTCASES} for TESTCASE in ${TESTCASES} do - # Run Each Testcase File - echo ${TESTCASE} -#iverilog -g 2012 \ -# -s mips_cpu_harvard_tb \ -# -P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/"${TESTCASE}\" \ -# -o program/mips_cpu_harvard_tb_${INSTR} testbench/mips_cpu_harvard_tb.v \ -# ${SRC} + # Run Each Testcase File + echo ${TESTCASE} +/mnt/c/Windows/System32/cmd.exe /C \ +iverilog -Wall -g2012 \ + -s mips_cpu_harvard_tb \ + -P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/${TESTCASE}.txt\" \ + -o exec/mips_cpu_harvard_tb_${TESTCASE} testbench/mips_cpu_harvard_tb.v \ + ${SRC} +/mnt/c/Windows/System32/cmd.exe /C vvp ./exec/mips_cpu_harvard_tb_${TESTCASE}; done else - echo ${INSTR}; # Run Testcase File Of Specified Instruction -# Windows Iverilog with WSL -#/mnt/c/Windows/System32/cmd.exe /C iverilog -g2012 \ -# -s mips_cpu_harvard_tb \ -# -P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/${INSTR}.txt\" \ -# -o program/mips_cpu_harvard_tb_${INSTR} testbench/mips_cpu_harvard_tb.v \ -# ${SRC} - -# Linux Iverilog -iverilog -g2012 \ + echo ${INSTR}; +/mnt/c/Windows/System32/cmd.exe /C \ +iverilog -Wall -g2012 \ -s mips_cpu_harvard_tb \ -P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/${INSTR}.txt\" \ - -o program/mips_cpu_harvard_tb_${INSTR} testbench/mips_cpu_harvard_tb.v \ + -o exec/mips_cpu_harvard_tb_${INSTR} testbench/mips_cpu_harvard_tb.v \ ${SRC} +/mnt/c/Windows/System32/cmd.exe /C vvp ./exec/mips_cpu_harvard_tb_${INSTR}; fi -#/mnt/c/Windows/System32/cmd.exe /C \ # need this to run verilog on windows -#iverilog -g 2012 \ -# -s mips_cpu_harvard_tb \ -# -P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/addiu.hex.txt\" \ -# -o program/mips_cpu_harvard_tb testbench/mips_cpu_harvard_tb.v test/mips_cpu_harvard.v \ -# test/mips_cpu_control.v test/mips_cpu_alu.v test/mips_cpu_memory.v test/mips_cpu_regfile.v test/mips_cpu_pc.v - diff --git a/testbench/mips_cpu_harvard_tb.v b/testbench/mips_cpu_harvard_tb.v index 1bae99d..fcb4499 100644 --- a/testbench/mips_cpu_harvard_tb.v +++ b/testbench/mips_cpu_harvard_tb.v @@ -1,14 +1,10 @@ module mips_cpu_harvard_tb; - timeunit 1ns / 10ps; - parameter RAM_INIT_FILE = "inputs/"; - parameter TIMEOUT_CYCLES = 10000; + parameter RAM_INIT_FILE = "inputs/addu.txt"; + parameter TIMEOUT_CYCLES = 100; - logic clk, clk_enable, reset, active; - logic[31:0] register_v0; - logic[31:0] instr_address, instr_readdata; - logic data_read, data_write; - logic[31:0] data_readdata, data_writedata, data_address; + logic clk, clk_enable, reset, active, data_read, data_write; + logic[31:0] register_v0, instr_address, instr_readdata, data_readdata, data_writedata, data_address; mips_cpu_memory #(RAM_INIT_FILE) ramInst( .clk(clk), @@ -50,24 +46,29 @@ module mips_cpu_harvard_tb; end initial begin + $display("Initial Reset 0"); reset <= 0; - + + + $display("Initial Reset 1"); @(posedge clk); reset <= 1; + $display("Initial Reset 0: Start Program"); @(posedge clk); reset <= 0; @(posedge clk); - assert(active==1) // Is this assert still valid? - else $display("TB : CPU did not set active=1 after reset."); + assert(active==1); + else $display("TB: CPU did not set active=1 after reset."); while (active) begin @(posedge clk); + $display("Register v0: %d", register_v0); end - $display("TB : finished; running=0"); - $display("%d",register_v0); + $display("TB: finished; active=0"); + $display("Output: %d", register_v0); $finish; end