mirror of
https://github.com/supleed2/ELEC50010-IAC-CW.git
synced 2024-11-10 01:35:49 +00:00
Merge pull request #2 from supleed2/bus_wrapper
Merge Bus Version and updated testcases to Main
This commit is contained in:
commit
099540f6ec
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,5 +3,6 @@ exec/*
|
||||||
*.log.txt
|
*.log.txt
|
||||||
*.out.txt
|
*.out.txt
|
||||||
mips_cpu_harvard.vcd
|
mips_cpu_harvard.vcd
|
||||||
|
mips_cpu_bus.vcd
|
||||||
.DS_Store
|
.DS_Store
|
||||||
inputs/.DS_Store
|
inputs/.DS_Store
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
3C041234
|
3C041234
|
||||||
34045678
|
34045678
|
||||||
3C05BFC0
|
3405101C
|
||||||
3405001C
|
|
||||||
A0A40000
|
A0A40000
|
||||||
80A20000
|
80A20000
|
||||||
00000008
|
00000008
|
|
@ -1,7 +1,6 @@
|
||||||
3C041234
|
3C041234
|
||||||
34045678
|
34045678
|
||||||
3C05BFC0
|
3405101C
|
||||||
3405001C
|
|
||||||
A4A40000
|
A4A40000
|
||||||
84A40000
|
84A20000
|
||||||
00000008
|
00000008
|
1
inputs/sh/sh-2.ref.txt
Normal file
1
inputs/sh/sh-2.ref.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
22136
|
6
inputs/sh/sh-2.txt
Normal file
6
inputs/sh/sh-2.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
3C041234
|
||||||
|
34045678
|
||||||
|
3405101C
|
||||||
|
A4A40000
|
||||||
|
8CA20000
|
||||||
|
00000008
|
|
@ -662,16 +662,14 @@ register_v0 = 65535
|
||||||
|
|
||||||
lui $4, 0x1234
|
lui $4, 0x1234
|
||||||
ori $4, $0, 0x5678
|
ori $4, $0, 0x5678
|
||||||
lui $5, 0xBFC0
|
ori $5, $0, 0x101C
|
||||||
ori $5, $0, 0x001C
|
|
||||||
sb $4, 0($5)
|
sb $4, 0($5)
|
||||||
lb $2, 0($5)
|
lb $2, 0($5)
|
||||||
jr $0
|
jr $0
|
||||||
|
|
||||||
3C041234
|
3C041234
|
||||||
34045678
|
34045678
|
||||||
3C05BFC0
|
3405101C
|
||||||
3405001C
|
|
||||||
A0A40000
|
A0A40000
|
||||||
80A20000
|
80A20000
|
||||||
00000008
|
00000008
|
||||||
|
@ -682,18 +680,32 @@ register_v0 = 0x00000078
|
||||||
|
|
||||||
lui $4, 0x1234
|
lui $4, 0x1234
|
||||||
ori $4, $0, 0x5678
|
ori $4, $0, 0x5678
|
||||||
lui $5, 0xBFC0
|
ori $5, $0, 0x101C
|
||||||
ori $5, $0, 0x001C
|
|
||||||
sh $4, 0($5)
|
sh $4, 0($5)
|
||||||
lh $2, 0($5)
|
lh $2, 0($5)
|
||||||
jr $0
|
jr $0
|
||||||
|
|
||||||
3C041234
|
3C041234
|
||||||
34045678
|
34045678
|
||||||
3C05BFC0
|
3405101C
|
||||||
3405001C
|
|
||||||
A4A40000
|
A4A40000
|
||||||
84A40000
|
84A20000
|
||||||
|
00000008
|
||||||
|
|
||||||
|
-Load Entire Word Version
|
||||||
|
|
||||||
|
lui $4, 0x1234
|
||||||
|
ori $4, $0, 0x5678
|
||||||
|
ori $5, $0, 0x101C
|
||||||
|
sh $4, 0($5)
|
||||||
|
lw $2, 0($5)
|
||||||
|
jr $0
|
||||||
|
|
||||||
|
3C041234
|
||||||
|
34045678
|
||||||
|
3405101C
|
||||||
|
A4A40000
|
||||||
|
8CA20000
|
||||||
00000008
|
00000008
|
||||||
|
|
||||||
register_v0 = 0x00005678
|
register_v0 = 0x00005678
|
||||||
|
|
231
rtl/mips_cpu_bus.v
Normal file
231
rtl/mips_cpu_bus.v
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
module mips_cpu_bus(
|
||||||
|
/* Standard signals */
|
||||||
|
input logic clk,
|
||||||
|
input logic reset,
|
||||||
|
output logic active,
|
||||||
|
output logic[31:0] register_v0,
|
||||||
|
|
||||||
|
/* Avalon memory mapped bus controller (master) */
|
||||||
|
output logic[31:0] address,
|
||||||
|
output logic write,
|
||||||
|
output logic read,
|
||||||
|
input logic waitrequest,
|
||||||
|
output logic[31:0] writedata,
|
||||||
|
output logic[3:0] byteenable,
|
||||||
|
input logic[31:0] readdata
|
||||||
|
);
|
||||||
|
|
||||||
|
logic[1:0] state; // current state of cpu within cycle
|
||||||
|
logic[1:0] n_state; // state to be set at next clk edge
|
||||||
|
logic[31:0] instr_reg; // instruction register / single-word cache for current instruction
|
||||||
|
logic clk_internal; // modulated clock to be passed to harvard cpu
|
||||||
|
logic[31:0] harvard_instr_address; // instr addr from pc
|
||||||
|
logic harvard_read; // harvard cpu read flag
|
||||||
|
logic harvard_write; // harvard cpu write flag
|
||||||
|
logic[31:0] harvard_data_address; // data addr from ALU
|
||||||
|
logic[31:0] harvard_readdata; // <= data read from Avalon MM Device
|
||||||
|
logic[31:0] harvard_writedata; // data to be written to Avalon MM Device
|
||||||
|
logic[3:0] write_byteenable; // byteenable calculator for partial write
|
||||||
|
logic clk_state; // make sure posedge and negedge of clk do not occur repeatedly
|
||||||
|
logic partial_write; // flag to control datapath when doing a partial write
|
||||||
|
logic[31:0] partial_writedata; // modified data for partial writes (StoreHalfword or StoreByte)
|
||||||
|
logic[31:0] write_data_address; // modified data address for partial writes
|
||||||
|
logic clk_enable; // unused floating wire
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
clk_internal = 1'b0;
|
||||||
|
n_state = 2'b00;
|
||||||
|
state = 2'b00;
|
||||||
|
instr_reg = 32'h00000000;
|
||||||
|
address = 32'h00000000;
|
||||||
|
write = 1'b0;
|
||||||
|
read = 1'b0;
|
||||||
|
writedata = 32'h00000000;
|
||||||
|
byteenable = 4'b0000;
|
||||||
|
clk_state = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(negedge reset) begin // kickstart clock after reset
|
||||||
|
clk_internal <= 1'b1;
|
||||||
|
state <= 2'b00;
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin // CLK Rising Edge
|
||||||
|
if (!waitrequest && !clk_state) begin
|
||||||
|
case (n_state)
|
||||||
|
2'b00: begin // fetch
|
||||||
|
clk_internal <= 1'b1;
|
||||||
|
state <= 2'b00;
|
||||||
|
end
|
||||||
|
2'b01: begin // execute
|
||||||
|
state <= 2'b01;
|
||||||
|
instr_reg <= readdata;
|
||||||
|
end
|
||||||
|
2'b10: begin // read
|
||||||
|
state <= 2'b10;
|
||||||
|
end
|
||||||
|
2'b11: begin // write
|
||||||
|
state <= 2'b11;
|
||||||
|
end
|
||||||
|
endcase // state
|
||||||
|
end
|
||||||
|
clk_state <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(negedge clk) begin // CLK Falling Edge
|
||||||
|
if (!waitrequest && clk_state) begin
|
||||||
|
case (state)
|
||||||
|
2'b00: begin // nothing happens on fetch negedge
|
||||||
|
end
|
||||||
|
2'b01: begin // execute negedge
|
||||||
|
if (!harvard_read && !harvard_write) begin // instruction complete, trigger writeback
|
||||||
|
clk_internal <= 1'b0;
|
||||||
|
end // otherwise do nothing
|
||||||
|
end
|
||||||
|
2'b10: begin
|
||||||
|
clk_internal <= 1'b0;
|
||||||
|
end
|
||||||
|
2'b11: begin
|
||||||
|
clk_internal <= 1'b0;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
clk_state <= 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
case (instr_reg[31:26])
|
||||||
|
6'b101000: begin // Store Byte
|
||||||
|
partial_write = 1'b1;
|
||||||
|
case (harvard_data_address[1:0])
|
||||||
|
2'b00: begin
|
||||||
|
partial_writedata = {{24{1'b0}}, harvard_writedata[7:0]};
|
||||||
|
write_byteenable = 4'b0001;
|
||||||
|
write_data_address = {harvard_data_address[31:2], 2'b00};
|
||||||
|
end
|
||||||
|
2'b01: begin
|
||||||
|
partial_writedata = {{16{1'b0}}, harvard_writedata[7:0], {8{1'b0}}};
|
||||||
|
write_byteenable = 4'b0010;
|
||||||
|
write_data_address = {harvard_data_address[31:2], 2'b00};
|
||||||
|
end
|
||||||
|
2'b10: begin
|
||||||
|
partial_writedata = {{8{1'b0}}, harvard_writedata[7:0], {16{1'b0}}};
|
||||||
|
write_byteenable = 4'b0100;
|
||||||
|
write_data_address = {harvard_data_address[31:2], 2'b00};
|
||||||
|
end
|
||||||
|
2'b11: begin
|
||||||
|
partial_writedata = {harvard_writedata[7:0], {24{1'b0}}};
|
||||||
|
write_byteenable = 4'b1000;
|
||||||
|
write_data_address = {harvard_data_address[31:2], 2'b00};
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
6'b101001: begin // Store Halfword
|
||||||
|
partial_write = 1'b1;
|
||||||
|
case (harvard_data_address[1:0])
|
||||||
|
2'b00: begin
|
||||||
|
partial_writedata = {{16{1'b0}}, harvard_writedata[15:0]};
|
||||||
|
write_byteenable = 4'b0011;
|
||||||
|
write_data_address = {harvard_data_address[31:2], 2'b00};
|
||||||
|
end
|
||||||
|
2'b01: begin // halfword address must be matrually aligned, last bit must be 0
|
||||||
|
partial_writedata = 32'hxxxxxxxx;
|
||||||
|
write_byteenable = 4'bxxxx;
|
||||||
|
write_data_address = 32'hxxxxxxxx;
|
||||||
|
end
|
||||||
|
2'b10: begin
|
||||||
|
partial_writedata = {harvard_writedata[15:0], {16{1'b0}}};
|
||||||
|
write_byteenable = 4'b1100;
|
||||||
|
write_data_address = {harvard_data_address[31:2], 2'b00};
|
||||||
|
end
|
||||||
|
2'b11: begin // halfword address must be matrually aligned, last bit must be 0
|
||||||
|
partial_writedata = 32'hxxxxxxxx;
|
||||||
|
write_byteenable = 4'bxxxx;
|
||||||
|
write_data_address = 32'hxxxxxxxx;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
default: begin // Store Word OR All other instructions (These flags are ignored outside the write state)
|
||||||
|
partial_write = 1'b0;
|
||||||
|
partial_writedata = 32'h00000000;
|
||||||
|
write_byteenable = 4'b1111;
|
||||||
|
write_data_address = harvard_data_address;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
if (reset) begin
|
||||||
|
clk_internal = 1'b0;
|
||||||
|
n_state = 2'b00;
|
||||||
|
state = 2'b00;
|
||||||
|
instr_reg = 32'h00000000;
|
||||||
|
address = 32'h00000000;
|
||||||
|
write = 1'b0;
|
||||||
|
read = 1'b0;
|
||||||
|
writedata = 32'h00000000;
|
||||||
|
byteenable = 4'b0000;
|
||||||
|
end else begin
|
||||||
|
case (state)
|
||||||
|
2'b00: begin // connecting wires when in fetch state
|
||||||
|
address = harvard_instr_address;
|
||||||
|
read = 1'b1;
|
||||||
|
write = 1'b0;
|
||||||
|
byteenable = 4'b1111;
|
||||||
|
harvard_readdata = 32'h00000000;
|
||||||
|
writedata = 32'h00000000;
|
||||||
|
n_state = 2'b01;
|
||||||
|
end
|
||||||
|
2'b01: begin // connecting wires when in execute state
|
||||||
|
address = 32'h00000000;
|
||||||
|
read = 1'b0;
|
||||||
|
write = 1'b0;
|
||||||
|
byteenable = 4'b0000;
|
||||||
|
harvard_readdata = 32'h00000000;
|
||||||
|
writedata = 32'h00000000;
|
||||||
|
if (harvard_read) begin
|
||||||
|
n_state = 2'b10; // next state is read
|
||||||
|
end else if (harvard_write) begin
|
||||||
|
n_state = 2'b11; // next state is write
|
||||||
|
end else begin
|
||||||
|
n_state = 2'b00; // next state is fetch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
2'b10: begin // connecting wires when in read state
|
||||||
|
address = harvard_data_address;
|
||||||
|
read = clk_internal ? 1'b1 : 1'b0;
|
||||||
|
write = 1'b0;
|
||||||
|
byteenable = 4'b1111;
|
||||||
|
harvard_readdata = readdata;
|
||||||
|
writedata = 32'h00000000;
|
||||||
|
n_state = 2'b00;
|
||||||
|
end
|
||||||
|
2'b11: begin // connecting wires when in write state
|
||||||
|
address = write_data_address;
|
||||||
|
read = 1'b0;
|
||||||
|
write = 1'b1;
|
||||||
|
byteenable = write_byteenable;
|
||||||
|
harvard_readdata = 32'h00000000;
|
||||||
|
writedata = partial_write ? partial_writedata : harvard_writedata;
|
||||||
|
n_state = 2'b00;
|
||||||
|
end
|
||||||
|
endcase // state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mips_cpu_harvard mips_cpu_harvard( // Harvard CPU within wrapper
|
||||||
|
.clk(clk_internal), // modulated clock input to allow waiting for valid data from memory, input
|
||||||
|
.reset(reset), // CPU reset, input
|
||||||
|
.active(active), // Is CPU active, output
|
||||||
|
.register_v0(register_v0), // $2 / $v0 debug bus, output
|
||||||
|
.clk_enable(clk_enable), // unused clock enable, input
|
||||||
|
.instr_address(harvard_instr_address), // instr addr from pc, output
|
||||||
|
.instr_readdata(instr_reg), // cached instruction passed into harvard cpu, input
|
||||||
|
.data_address(harvard_data_address), // harvard data memory address, output
|
||||||
|
.data_write(harvard_write), // harvard write flag, output
|
||||||
|
.data_read(harvard_read), // harvard read flag, output
|
||||||
|
.data_writedata(harvard_writedata), // data output from regfile readport2, output
|
||||||
|
.data_readdata(harvard_readdata) // data in from read instruction, input
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -117,6 +117,8 @@ always @(*) begin
|
||||||
CtrlMemtoReg = 3'd3;//write data port of regfile is fed from ALUHi
|
CtrlMemtoReg = 3'd3;//write data port of regfile is fed from ALUHi
|
||||||
end else if ((op==SPECIAL)&&(funct == MFLO))begin
|
end else if ((op==SPECIAL)&&(funct == MFLO))begin
|
||||||
CtrlMemtoReg = 3'd4;//write data port of regfile is fed from ALULo
|
CtrlMemtoReg = 3'd4;//write data port of regfile is fed from ALULo
|
||||||
|
end else if (((op==SPECIAL)&&(funct == JR)) || (op == BEQ) || (op==SW) ||((op==REGIMM)&&(rt==BGEZ)) || (op==BGTZ) || ((op==REGIMM)&&(rt==BLTZ)) || (op==BLEZ) || (op==BNE) || (op==J) || ((op==SPECIAL)&&(funct==MTHI)) || ((op==SPECIAL)&&(funct==MTLO)) || ((op==SPECIAL)&&(funct==MULT)) || ((op==SPECIAL)&&(funct==MULTU)) || ((op==SPECIAL)&&(funct==DIV)) || ((op==SPECIAL)&&(funct==DIVU)) || (op==SB) || (op==SH))begin
|
||||||
|
CtrlMemRead = 0;//Read disabled during jump
|
||||||
end else begin CtrlMemRead = 1'bx;end//Not all instructions are encompassed so, added incase for debug purposes
|
end else begin CtrlMemRead = 1'bx;end//Not all instructions are encompassed so, added incase for debug purposes
|
||||||
|
|
||||||
//CtrlALUOp Logic
|
//CtrlALUOp Logic
|
||||||
|
|
|
@ -9,6 +9,7 @@ reg[31:0] npc_curr;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
npc_curr = (32'hBFC00000 + 32'd4);
|
npc_curr = (32'hBFC00000 + 32'd4);
|
||||||
|
npc_out = 32'hBFC00000;
|
||||||
end // initial
|
end // initial
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
|
|
|
@ -1,4 +1,60 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# should not create any files in the rtl dir
|
SRC_DIR=${1?Error: no source directory given in argument};
|
||||||
# but auxiliary files / dirs can be utilised
|
SRC=$(find ./${SRC_DIR}/*);
|
||||||
|
SRC_TEMP="";
|
||||||
|
for src in ${SRC}
|
||||||
|
do
|
||||||
|
SRC_TEMP+=${src}" ";
|
||||||
|
done
|
||||||
|
SRC=${SRC_TEMP};
|
||||||
|
|
||||||
|
|
||||||
|
INSTR=${2:-"No instruction specified: running all testcases"};
|
||||||
|
|
||||||
|
if [[ ${INSTR} == "No instruction specified: running all testcases" ]];
|
||||||
|
then
|
||||||
|
for DIR in inputs/*/
|
||||||
|
do
|
||||||
|
DIR=$(basename ${DIR});
|
||||||
|
LOOP=$(find inputs/${DIR}/* ! -name '*ref*' ! -name '*log*' ! -name '*data*' ! -name '*out*');
|
||||||
|
for TESTCASE in ${LOOP}
|
||||||
|
do
|
||||||
|
TESTCASE=$([[ ${TESTCASE} =~ /([^./]+)\. ]] && echo "${BASH_REMATCH[1]}");
|
||||||
|
iverilog -Wall -g2012 \
|
||||||
|
-s mips_cpu_bus_tb \
|
||||||
|
-P mips_cpu_bus_tb.INSTR_INIT_FILE=\"inputs/${DIR}/${TESTCASE}.txt\" \
|
||||||
|
-P mips_cpu_bus_tb.DATA_INIT_FILE=\"inputs/${DIR}/${TESTCASE}.data.txt\" \
|
||||||
|
-o exec/mips_cpu_bus_tb_${TESTCASE} testbench/mips_cpu_bus_tb.v testbench/mips_cpu_bus_memory.v \
|
||||||
|
${SRC} 2> /dev/null
|
||||||
|
./exec/mips_cpu_bus_tb_${TESTCASE} &> ./inputs/${DIR}/${TESTCASE}.log.txt; # log file for debugging (contains $display)
|
||||||
|
echo "$(tail -1 ./inputs/${DIR}/${TESTCASE}.log.txt)" > ./inputs/${DIR}/${TESTCASE}.out.txt; # register v0 output to compare with reference
|
||||||
|
if diff -w ./inputs/${DIR}/${TESTCASE}.out.txt ./inputs/${DIR}/${TESTCASE}.ref.txt &> /dev/null # compare
|
||||||
|
then
|
||||||
|
echo ${TESTCASE} ${DIR} "Pass";
|
||||||
|
else
|
||||||
|
printf '%s %s %s%d %s%d%s\n' "${TESTCASE}" "${DIR}" "Fail Output=" "$(tail -1 ./inputs/${DIR}/${TESTCASE}.out.txt)" "Ref=" "$(tail -1 ./inputs/${DIR}/${TESTCASE}.ref.txt)" 2> /dev/null;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
else
|
||||||
|
LOOP=$(find inputs/${INSTR}/* ! -name '*ref*' ! -name '*log*' ! -name '*data*' ! -name '*out*');
|
||||||
|
for TESTCASE in ${LOOP}
|
||||||
|
do
|
||||||
|
TESTCASE=$([[ ${TESTCASE} =~ /([^./]+)\. ]] && echo "${BASH_REMATCH[1]}");
|
||||||
|
iverilog -Wall -g2012 \
|
||||||
|
-s mips_cpu_bus_tb \
|
||||||
|
-P mips_cpu_bus_tb.INSTR_INIT_FILE=\"inputs/${INSTR}/${TESTCASE}.txt\" \
|
||||||
|
-P mips_cpu_bus_tb.DATA_INIT_FILE=\"inputs/${INSTR}/${TESTCASE}.data.txt\" \
|
||||||
|
-o exec/mips_cpu_bus_tb_${TESTCASE} testbench/mips_cpu_bus_tb.v testbench/mips_cpu_bus_memory.v \
|
||||||
|
${SRC} 2> /dev/null
|
||||||
|
./exec/mips_cpu_bus_tb_${TESTCASE} &> ./inputs/${INSTR}/${TESTCASE}.log.txt; # log file for debugging (contains $display)
|
||||||
|
echo "$(tail -1 ./inputs/${INSTR}/${TESTCASE}.log.txt)" > ./inputs/${INSTR}/${TESTCASE}.out.txt; # register v0 output to compare with reference
|
||||||
|
if diff -w ./inputs/${INSTR}/${TESTCASE}.out.txt ./inputs/${INSTR}/${TESTCASE}.ref.txt &> /dev/null # compare
|
||||||
|
then
|
||||||
|
echo ${TESTCASE} ${INSTR} "Pass";
|
||||||
|
else
|
||||||
|
printf '%s %s %s%d %s%d%s\n' "${TESTCASE}" "${INSTR}" "Fail Output=" "$(tail -1 ./inputs/${INSTR}/${TESTCASE}.out.txt)" "Ref=" "$(tail -1 ./inputs/${INSTR}/${TESTCASE}.ref.txt)" 2> /dev/null;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
|
@ -47,7 +47,7 @@ else
|
||||||
-P mips_cpu_harvard_tb.INSTR_INIT_FILE=\"inputs/${INSTR}/${TESTCASE}.txt\" \
|
-P mips_cpu_harvard_tb.INSTR_INIT_FILE=\"inputs/${INSTR}/${TESTCASE}.txt\" \
|
||||||
-P mips_cpu_harvard_tb.DATA_INIT_FILE=\"inputs/${INSTR}/${TESTCASE}.data.txt\" \
|
-P mips_cpu_harvard_tb.DATA_INIT_FILE=\"inputs/${INSTR}/${TESTCASE}.data.txt\" \
|
||||||
-o exec/mips_cpu_harvard_tb_${TESTCASE} testbench/mips_cpu_harvard_tb.v testbench/mips_cpu_memory.v\
|
-o exec/mips_cpu_harvard_tb_${TESTCASE} testbench/mips_cpu_harvard_tb.v testbench/mips_cpu_memory.v\
|
||||||
${SRC} #2> /dev/null
|
${SRC} 2> /dev/null
|
||||||
./exec/mips_cpu_harvard_tb_${TESTCASE} &> ./inputs/${INSTR}/${TESTCASE}.log.txt; # log file for debugging (contains $display)
|
./exec/mips_cpu_harvard_tb_${TESTCASE} &> ./inputs/${INSTR}/${TESTCASE}.log.txt; # log file for debugging (contains $display)
|
||||||
echo "$(tail -1 ./inputs/${INSTR}/${TESTCASE}.log.txt)" > ./inputs/${INSTR}/${TESTCASE}.out.txt; # register v0 output to compare with reference
|
echo "$(tail -1 ./inputs/${INSTR}/${TESTCASE}.log.txt)" > ./inputs/${INSTR}/${TESTCASE}.out.txt; # register v0 output to compare with reference
|
||||||
if diff -w ./inputs/${INSTR}/${TESTCASE}.out.txt ./inputs/${INSTR}/${TESTCASE}.ref.txt &> /dev/null # compare
|
if diff -w ./inputs/${INSTR}/${TESTCASE}.out.txt ./inputs/${INSTR}/${TESTCASE}.ref.txt &> /dev/null # compare
|
||||||
|
|
100
testbench/mips_cpu_bus_memory.v
Normal file
100
testbench/mips_cpu_bus_memory.v
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
module mips_cpu_bus_memory( //Avalon memory mapped bus controller (slave)
|
||||||
|
input logic clk,
|
||||||
|
input logic reset,
|
||||||
|
input logic[31:0] address,
|
||||||
|
input logic write,
|
||||||
|
input logic read,
|
||||||
|
output logic waitrequest,
|
||||||
|
input logic[31:0] writedata,
|
||||||
|
input logic[3:0] byteenable,
|
||||||
|
output logic[31:0] readdata
|
||||||
|
);
|
||||||
|
|
||||||
|
parameter INSTR_INIT_FILE = "";
|
||||||
|
parameter DATA_INIT_FILE = "";
|
||||||
|
|
||||||
|
logic [31:0] data_memory [0:63]; // location 0x00001000 onwards
|
||||||
|
logic [31:0] instr_memory [0:63]; // location 0xBFC00000 onwards
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
for (integer i=0; i<$size(data_memory); i++) begin //Initialise data to zero by default
|
||||||
|
data_memory[i] = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
for (integer i=0; i<$size(instr_memory); i++) begin //Initialise instr to zero by default
|
||||||
|
instr_memory[i] = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (INSTR_INIT_FILE != "") begin //Load instr contents from file if specified
|
||||||
|
$display("RAM: Loading RAM contents from %s", INSTR_INIT_FILE);
|
||||||
|
$readmemh(INSTR_INIT_FILE, instr_memory);
|
||||||
|
end
|
||||||
|
|
||||||
|
for (integer i = 0; i<$size(instr_memory); i++) begin //Read out instr contents to log
|
||||||
|
$display("byte +%h: %h", 32'hBFC00000+i*4, instr_memory[i]);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (DATA_INIT_FILE != "") begin //Load data contents from file if specified
|
||||||
|
$display("MEM: Loading MEM contents from %s", DATA_INIT_FILE);
|
||||||
|
$readmemh(DATA_INIT_FILE, data_memory);
|
||||||
|
end else begin
|
||||||
|
$display("MEM FILE NOT GIVEN");
|
||||||
|
end
|
||||||
|
|
||||||
|
for (integer i = 0; i<$size(data_memory); i++) begin //Read out data contents to log
|
||||||
|
$display("byte +%h: %h", 32'h00001000+i*4, data_memory[i]);
|
||||||
|
end
|
||||||
|
|
||||||
|
waitrequest = 1'b0; // set waitrequest low to begin
|
||||||
|
readdata = 32'h00000000; // set readdata low to begin
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
if (reset) begin
|
||||||
|
waitrequest = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge read or posedge write) begin
|
||||||
|
waitrequest <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (waitrequest) begin
|
||||||
|
if (read) begin
|
||||||
|
if (address >= 32'hBFC00000) begin // instruction read
|
||||||
|
readdata <= instr_memory[{address-32'hBFC00000}>>2];
|
||||||
|
end else if (address >= 32'h00001000) begin // data read
|
||||||
|
readdata <= data_memory[{address-32'h00001000}>>2];
|
||||||
|
end
|
||||||
|
waitrequest <= 1'b0; // end with setting waitrequest low
|
||||||
|
end else if (write) begin
|
||||||
|
if (address >= 32'hBFC00000) begin // writing to instr mem area is invalid
|
||||||
|
$display("Error, write attempted in instr area at address: %h", address);
|
||||||
|
end else if (address >= 32'h00001000) begin // write to data mem
|
||||||
|
if (byteenable[3]) begin // if first byte enabled, write
|
||||||
|
data_memory[{address-32'h00001000}>>2][31:24] <= writedata[31:24];
|
||||||
|
end
|
||||||
|
if (byteenable[2]) begin // if second byte enabled, write
|
||||||
|
data_memory[{address-32'h00001000}>>2][23:16] <= writedata[23:16];
|
||||||
|
end
|
||||||
|
if (byteenable[1]) begin // if third byte enabled, write
|
||||||
|
data_memory[{address-32'h00001000}>>2][15:8] <= writedata[15:8];
|
||||||
|
end
|
||||||
|
if (byteenable[0]) begin // if fourth byte enabled, write
|
||||||
|
data_memory[{address-32'h00001000}>>2][7:0] <= writedata[7:0];
|
||||||
|
end
|
||||||
|
waitrequest <= 1'b0; // end with setting waitrequest low
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
waitrequest <= 1'bx;
|
||||||
|
readdata <= 32'hxxxxxxxx;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
waitrequest <= 1'b0;
|
||||||
|
readdata <= 32'h00000000;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,26 +1,43 @@
|
||||||
module mips_cpu_bus_tb;
|
module mips_cpu_bus_tb;
|
||||||
timeunit 1ns / 10ps;
|
|
||||||
|
|
||||||
parameter RAM_INIT_FILE = "test/01-binary/countdown.hex.txt";
|
parameter INSTR_INIT_FILE = "";
|
||||||
parameter TIMEOUT_CYCLES = 10000;
|
parameter DATA_INIT_FILE = "";
|
||||||
|
parameter TIMEOUT_CYCLES = 100; // Timeout cycles are higher to account for memory stall delays
|
||||||
|
|
||||||
logic clk;
|
logic clk, reset, active, write, read, waitrequest;
|
||||||
logic rst;
|
logic[31:0] address, register_v0, writedata, readdata;
|
||||||
|
logic[3:0] byteenable;
|
||||||
|
|
||||||
logic running;
|
mips_cpu_bus_memory #(INSTR_INIT_FILE, DATA_INIT_FILE) memInst( //Avalon memory mapped bus controller (slave)
|
||||||
|
.clk(clk), // clk input to mem
|
||||||
|
.reset(reset), // reset input to stall mem during cpu reset
|
||||||
|
.address(address), // addr input to mem
|
||||||
|
.write(write), // write flag input
|
||||||
|
.read(read), // read flag input
|
||||||
|
.waitrequest(waitrequest), // mem stall output
|
||||||
|
.writedata(writedata), // data to be written
|
||||||
|
.byteenable(byteenable), // byteenable bus for writes
|
||||||
|
.readdata(readdata) // read output port
|
||||||
|
);
|
||||||
|
|
||||||
logic[11:0] address;
|
mips_cpu_bus cpuInst(
|
||||||
logic write;
|
.clk(clk), // clk input to cpu wrapper
|
||||||
logic read;
|
.reset(reset), // reset input
|
||||||
logic[15:0] writedata;
|
.active(active), // active output flag
|
||||||
logic[15:0] readdata;
|
.register_v0(register_v0), // debug $2 or $v0 output bus
|
||||||
|
.address(address), // mem addr output
|
||||||
|
.write(write), // mem write output flag
|
||||||
|
.read(read), // mem read output flag
|
||||||
|
.waitrequest(waitrequest), // mem stall input flag
|
||||||
|
.writedata(writedata), // data to write to mem output
|
||||||
|
.byteenable(byteenable), // bytes to write output
|
||||||
|
.readdata(readdata) // data from mem input
|
||||||
|
);
|
||||||
|
|
||||||
RAM_16x4096_delay1 #(RAM_INIT_FILE) ramInst(clk, address, write, read, writedata, readdata);
|
// Setup and clock
|
||||||
|
initial begin
|
||||||
CPU_MU0_delay1 cpuInst(clk, rst, running, address, write, read, writedata, readdata);
|
$dumpfile("mips_cpu_bus.vcd");
|
||||||
|
$dumpvars(0,mips_cpu_bus_tb);
|
||||||
// Generate clock
|
|
||||||
initial begin
|
|
||||||
clk=0;
|
clk=0;
|
||||||
|
|
||||||
repeat (TIMEOUT_CYCLES) begin
|
repeat (TIMEOUT_CYCLES) begin
|
||||||
|
@ -31,31 +48,33 @@ module mips_cpu_bus_tb;
|
||||||
end
|
end
|
||||||
|
|
||||||
$fatal(2, "Simulation did not finish within %d cycles.", TIMEOUT_CYCLES);
|
$fatal(2, "Simulation did not finish within %d cycles.", TIMEOUT_CYCLES);
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
reset <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
reset <= 0;
|
||||||
|
|
||||||
|
@(posedge clk);
|
||||||
|
assert(active==1)
|
||||||
|
else $display("TB : CPU did not set active=1 after reset.");
|
||||||
|
|
||||||
|
while (active) begin
|
||||||
|
//$display("Clk: %d", clk);
|
||||||
|
@(posedge clk);
|
||||||
|
//$display("Register v0: %d", register_v0);
|
||||||
|
//$display("Reg File Write data: %d", cpuInst.in_writedata);
|
||||||
|
$display("Reg File Out Read data: %h", cpuInst.mips_cpu_harvard.out_readdata1);
|
||||||
|
$display("Reg File opcode: %b", cpuInst.mips_cpu_harvard.regfile.opcode);
|
||||||
|
//$display("ALU output: %h", cpuInst.out_ALURes);
|
||||||
|
//$display("ALU input B: %h", cpuInst.alu.B);
|
||||||
end
|
end
|
||||||
|
|
||||||
initial begin
|
|
||||||
rst <= 0;
|
|
||||||
|
|
||||||
@(posedge clk);
|
@(posedge clk);
|
||||||
rst <= 1;
|
$display("TB: CPU Halt; active=0");
|
||||||
|
$display("Output:");
|
||||||
@(posedge clk);
|
$display("%d",register_v0);
|
||||||
rst <= 0;
|
|
||||||
|
|
||||||
@(posedge clk);
|
|
||||||
assert(running==1)
|
|
||||||
else $display("TB : CPU did not set running=1 after reset.");
|
|
||||||
|
|
||||||
while (running) begin
|
|
||||||
@(posedge clk);
|
|
||||||
end
|
|
||||||
|
|
||||||
$display("TB : finished; running=0");
|
|
||||||
|
|
||||||
$finish;
|
$finish;
|
||||||
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
Loading…
Reference in a new issue