mirror of
https://github.com/supleed2/ELEC50010-IAC-CW.git
synced 2024-12-22 21:35:48 +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
|
||||
*.out.txt
|
||||
mips_cpu_harvard.vcd
|
||||
mips_cpu_bus.vcd
|
||||
.DS_Store
|
||||
inputs/.DS_Store
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
3C041234
|
||||
34045678
|
||||
3C05BFC0
|
||||
3405001C
|
||||
3405101C
|
||||
A0A40000
|
||||
80A20000
|
||||
00000008
|
||||
00000008
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
3C041234
|
||||
34045678
|
||||
3C05BFC0
|
||||
3405001C
|
||||
3405101C
|
||||
A4A40000
|
||||
84A40000
|
||||
00000008
|
||||
84A20000
|
||||
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
|
File diff suppressed because it is too large
Load diff
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
|
||||
end else if ((op==SPECIAL)&&(funct == MFLO))begin
|
||||
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
|
||||
|
||||
//CtrlALUOp Logic
|
||||
|
|
|
@ -9,6 +9,7 @@ reg[31:0] npc_curr;
|
|||
|
||||
initial begin
|
||||
npc_curr = (32'hBFC00000 + 32'd4);
|
||||
npc_out = 32'hBFC00000;
|
||||
end // initial
|
||||
|
||||
always_comb begin
|
||||
|
|
|
@ -1,4 +1,60 @@
|
|||
#!/bin/bash
|
||||
|
||||
# should not create any files in the rtl dir
|
||||
# but auxiliary files / dirs can be utilised
|
||||
SRC_DIR=${1?Error: no source directory given in argument};
|
||||
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.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\
|
||||
${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)
|
||||
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
|
||||
|
|
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,61 +1,80 @@
|
|||
module mips_cpu_bus_tb;
|
||||
timeunit 1ns / 10ps;
|
||||
|
||||
parameter RAM_INIT_FILE = "test/01-binary/countdown.hex.txt";
|
||||
parameter TIMEOUT_CYCLES = 10000;
|
||||
parameter INSTR_INIT_FILE = "";
|
||||
parameter DATA_INIT_FILE = "";
|
||||
parameter TIMEOUT_CYCLES = 100; // Timeout cycles are higher to account for memory stall delays
|
||||
|
||||
logic clk;
|
||||
logic rst;
|
||||
logic clk, reset, active, write, read, waitrequest;
|
||||
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;
|
||||
logic write;
|
||||
logic read;
|
||||
logic[15:0] writedata;
|
||||
logic[15:0] readdata;
|
||||
mips_cpu_bus cpuInst(
|
||||
.clk(clk), // clk input to cpu wrapper
|
||||
.reset(reset), // reset input
|
||||
.active(active), // active output flag
|
||||
.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);
|
||||
|
||||
CPU_MU0_delay1 cpuInst(clk, rst, running, address, write, read, writedata, readdata);
|
||||
// Setup and clock
|
||||
initial begin
|
||||
$dumpfile("mips_cpu_bus.vcd");
|
||||
$dumpvars(0,mips_cpu_bus_tb);
|
||||
clk=0;
|
||||
|
||||
// Generate clock
|
||||
initial begin
|
||||
clk=0;
|
||||
|
||||
repeat (TIMEOUT_CYCLES) begin
|
||||
#10;
|
||||
clk = !clk;
|
||||
#10;
|
||||
clk = !clk;
|
||||
end
|
||||
|
||||
$fatal(2, "Simulation did not finish within %d cycles.", TIMEOUT_CYCLES);
|
||||
repeat (TIMEOUT_CYCLES) begin
|
||||
#10;
|
||||
clk = !clk;
|
||||
#10;
|
||||
clk = !clk;
|
||||
end
|
||||
|
||||
initial begin
|
||||
rst <= 0;
|
||||
$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);
|
||||
rst <= 1;
|
||||
|
||||
@(posedge clk);
|
||||
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;
|
||||
|
||||
//$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
|
||||
|
||||
|
||||
@(posedge clk);
|
||||
$display("TB: CPU Halt; active=0");
|
||||
$display("Output:");
|
||||
$display("%d",register_v0);
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in a new issue