Merge branch 'main' of https://github.com/supleed2/AM04_CPU into main

This commit is contained in:
jc4419 2020-12-09 16:27:20 +04:00
commit 3a2fde81b2
6 changed files with 62 additions and 72 deletions

8
inputs/ori.txt Normal file
View file

@ -0,0 +1,8 @@
34040003
00000008
00000000
00000000
00000000
00000000
00000000
00000000

View file

@ -1,5 +1,4 @@
module mips_cpu_control( module mips_cpu_control(
input logic[31:0] Instr, input logic[31:0] Instr,
input logic ALUCond, input logic ALUCond,
@ -12,17 +11,8 @@ module mips_cpu_control(
output logic CtrlMemWrite, output logic CtrlMemWrite,
output logic CtrlALUSrc, output logic CtrlALUSrc,
output logic CtrlRegWrite 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]{ typedef enum logic[5:0]{
SPECIAL = 6'd0, SPECIAL = 6'd0,
REGIMM = 6'd1, REGIMM = 6'd1,
@ -89,8 +79,9 @@ typedef enum logic[4:0]{
rt_enum rt; rt_enum rt;
assign rt = Instr[20:16]; assign rt = Instr[20:16];
always_comb begin
always @(*) begin
//CtrlRegDst logic //CtrlRegDst logic
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 // 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 CtrlRegDst = 2'd0; //Write address comes from rt
@ -107,7 +98,8 @@ always_comb begin
CtrlPC = 2'd2; // Jumps within 256MB Region using 26-bit immediate in J type instruction CtrlPC = 2'd2; // Jumps within 256MB Region using 26-bit immediate in J type instruction
end else if((op==JR) || (op==JALR))begin end else if((op==JR) || (op==JALR))begin
CtrlPC = 2'd3; // Jumps using Register. 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. //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) || (op==LBU) || (op==LH) || (op==LHU) || (op==LW) || (op==LWL) || (op==LWR))begin if((op==LB) || (op==LBU) || (op==LH) || (op==LHU) || (op==LW) || (op==LWL) || (op==LWR))begin
@ -197,7 +189,7 @@ always_comb begin
end else begin CtrlALUSrc = 1'bx;end end else begin CtrlALUSrc = 1'bx;end
//CtrlRegWrite logic //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 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
((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==XORI) || ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==DIV) || (funct==DIVU) || (funct==MULT) || (funct==MULTU) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR)))) ((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==XORI) || ((op==SPECIAL)&&((funct==ADDU) || (funct==AND) || (funct==DIV) || (funct==DIVU) || (funct==MULT) || (funct==MULTU) || (funct==OR) || (funct==SLL) || (funct==SLLV) || (funct==SLT) || (funct==SLTU) || (funct==SRA) || (funct==SRAV) || (funct==SRL) || (funct==SRLV) || (funct==SUBU) || (funct==XOR))))

View file

@ -31,36 +31,34 @@ module mips_cpu_memory(
); );
parameter RAM_INIT_FILE = ""; 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 initial begin
integer i; integer i;
//Initialise to zero by default //Initialise to zero by default
for (i=0; i<4294967296; i++) begin for (i=0; i<8; i++) begin
memory[i]=0; memory[i]=0;
end end
//Load contents from file if specified //Load contents from file if specified
if (RAM_INIT_FILE != "") begin if (RAM_INIT_FILE != "") begin
$display("RAM : INIT : Loading RAM contents from %s", RAM_INIT_FILE); $display("RAM: Loading RAM contents from %s", RAM_INIT_FILE);
$readmemh(RAM_INIT_FILE, memory, 32'hBFC00000, 32'd0); $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
end end
//Combinatorial read path for data and instruction. //Combinatorial read path for data and instruction.
always_comb begin assign data_readdata = data_read ? {memory[data_address],memory[data_address+1],memory[data_address+2],memory[data_address+3]} : 16'hxxxx;
if (clk == 1'd1) begin assign instr_readdata = memory[instr_address/4];
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
//Synchronous write path //Synchronous write path
always_ff @(posedge clk) begin 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]); //$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 (!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 if (instr_address != data_address) begin //cannot modify the instruction being read
@ -70,3 +68,4 @@ module mips_cpu_memory(
end end
endmodule endmodule

View file

@ -15,12 +15,11 @@ reg[31:0] memory [31:0]; //32 register slots, 32-bits wide
initial begin initial begin
integer i; //Initialise to zero by default integer i; //Initialise to zero by default
for (i = 1; i < 32; i++) begin for (i = 0; i < 32; i++) begin
memory[i] = 0; memory[i] = 0;
end end
end end
assign memory[0] = 32'h00000000;
assign regv0 = memory[2]; //assigning debug $v0 line to $2 of memory assign regv0 = memory[2]; //assigning debug $v0 line to $2 of memory
always_comb begin always_comb begin
@ -29,7 +28,9 @@ always_comb begin
end end
always_ff @(negedge clk) begin 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) case (opcode)
6'b100000: begin //lb, load byte 6'b100000: begin //lb, load byte
case (readdata1[1:0]) case (readdata1[1:0])

View file

@ -23,41 +23,30 @@ echo ${INSTR};
if [[ ${INSTR} == "No instruction specified: running all testcases" ]]; if [[ ${INSTR} == "No instruction specified: running all testcases" ]];
then then
# All Testcase Files # All Testcase Files
TESTCASES=$(ls ./inputs | grep ".hex.txt"); TESTCASES=$(ls ./inputs | grep ".txt");
echo ${TESTCASES} echo ${TESTCASES}
for TESTCASE in ${TESTCASES} for TESTCASE in ${TESTCASES}
do do
# Run Each Testcase File # Run Each Testcase File
echo ${TESTCASE} echo ${TESTCASE}
#iverilog -g 2012 \ /mnt/c/Windows/System32/cmd.exe /C \
# -s mips_cpu_harvard_tb \ iverilog -Wall -g2012 \
# -P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/"${TESTCASE}\" \ -s mips_cpu_harvard_tb \
# -o program/mips_cpu_harvard_tb_${INSTR} testbench/mips_cpu_harvard_tb.v \ -P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/${TESTCASE}.txt\" \
# ${SRC} -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 done
else else
echo ${INSTR};
# Run Testcase File Of Specified Instruction # Run Testcase File Of Specified Instruction
# Windows Iverilog with WSL echo ${INSTR};
#/mnt/c/Windows/System32/cmd.exe /C iverilog -g2012 \ /mnt/c/Windows/System32/cmd.exe /C \
# -s mips_cpu_harvard_tb \ iverilog -Wall -g2012 \
# -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 \
-s mips_cpu_harvard_tb \ -s mips_cpu_harvard_tb \
-P mips_cpu_harvard_tb.RAM_INIT_FILE=\"inputs/${INSTR}.txt\" \ -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} ${SRC}
/mnt/c/Windows/System32/cmd.exe /C vvp ./exec/mips_cpu_harvard_tb_${INSTR};
fi 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

View file

@ -1,14 +1,10 @@
module mips_cpu_harvard_tb; module mips_cpu_harvard_tb;
timeunit 1ns / 10ps;
parameter RAM_INIT_FILE = "inputs/"; parameter RAM_INIT_FILE = "inputs/addu.txt";
parameter TIMEOUT_CYCLES = 10000; parameter TIMEOUT_CYCLES = 100;
logic clk, clk_enable, reset, active; logic clk, clk_enable, reset, active, data_read, data_write;
logic[31:0] register_v0; logic[31:0] register_v0, instr_address, instr_readdata, data_readdata, data_writedata, data_address;
logic[31:0] instr_address, instr_readdata;
logic data_read, data_write;
logic[31:0] data_readdata, data_writedata, data_address;
mips_cpu_memory #(RAM_INIT_FILE) ramInst( mips_cpu_memory #(RAM_INIT_FILE) ramInst(
.clk(clk), .clk(clk),
@ -50,24 +46,29 @@ module mips_cpu_harvard_tb;
end end
initial begin initial begin
$display("Initial Reset 0");
reset <= 0; reset <= 0;
$display("Initial Reset 1");
@(posedge clk); @(posedge clk);
reset <= 1; reset <= 1;
$display("Initial Reset 0: Start Program");
@(posedge clk); @(posedge clk);
reset <= 0; reset <= 0;
@(posedge clk); @(posedge clk);
assert(active==1) // Is this assert still valid? assert(active==1);
else $display("TB : CPU did not set active=1 after reset."); else $display("TB: CPU did not set active=1 after reset.");
while (active) begin while (active) begin
@(posedge clk); @(posedge clk);
$display("Register v0: %d", register_v0);
end end
$display("TB : finished; running=0"); $display("TB: finished; active=0");
$display("%d",register_v0); $display("Output: %d", register_v0);
$finish; $finish;
end end