Change name scheme and add tests
Some checks are pending
continuous-integration/drone/push Build is pending

This commit is contained in:
Mario Romero 2023-02-26 20:26:11 -03:00
parent bb5f00d8dc
commit bd2f58d5f6
51 changed files with 934 additions and 756 deletions

View File

@ -33,37 +33,23 @@ endfunction()
function(rvscc_add_test)
cmake_parse_arguments(TEST
""
"NAME"
"TOP"
"NAME;TOP"
"SOURCES"
${ARGN}
)
message("Adding test ${TEST_NAME}")
set(TEST_TARGET_NAME test-${TEST_NAME})
add_executable(${TEST_TARGET_NAME} sim_individual_test.cpp)
if ("${CMAKE_BUILD_TYPE}" EQUAL "Release")
verilate(${TEST_TARGET_NAME}
SOURCES ${TEST_SOURCES}
TOP_MODULE ${TEST_TOP}
SYSTEMC
VERILATOR_ARGS --timing
)
else() # Debug
verilate(${TEST_TARGET_NAME}
SOURCES ${TEST_SOURCES}
TOP_MODULE ${TEST_TOP}
TRACE
SYSTEMC
VERILATOR_ARGS --timing
)
endif()
set_property(TARGET ${TEST_TARGET_NAME} PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
verilator_link_systemc(${TEST_TARGET_NAME})
list(GET TEST_SOURCES 0 TEST_TOP_MODULE)
get_filename_component(TEST_TOP_MODULE_NAME ${TEST_TOP_MODULE} NAME_WE)
add_executable(${TEST_TARGET_NAME} sim_main.cpp)
message(${TEST_TOP})
verilate(${TEST_TARGET_NAME}
SOURCES ${TEST_SOURCES}
PREFIX verilator_${TEST_TOP}
TOP_MODULE ${TEST_TOP}
TRACE
VERILATOR_ARGS --timing --assert
)
target_compile_definitions(${TEST_TARGET_NAME} PRIVATE
TEST_HEADER="V${TEST_TOP_MODULE_NAME}.h"
TEST_CLASS=V${TEST_TOP_MODULE_NAME}
TEST_HEADER="verilator_${TEST_TOP}.h"
TEST_CLASS=verilator_${TEST_TOP}
)
add_test(NAME ${TEST_TARGET_NAME} COMMAND ${TEST_TARGET_NAME})
endfunction()

View File

@ -5,16 +5,18 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/utils.cmake)
option(DISSASEMBLY "Enable dissasembly" OFF)
list(APPEND TEST_SUBDIRS
itype
rtype
imm
list(APPEND TEST_FILES
itype.s
rtype.s
imm.s
core.s
)
foreach(TEST_SUBDIR IN LISTS TEST_SUBDIRS)
set(TEST_TARGET "test-${TEST_SUBDIR}")
foreach(TEST_FILE IN LISTS TEST_FILES)
get_filename_component(TEST_FILENAME ${TEST_FILE} NAME_WE)
set(TEST_TARGET "test-${TEST_FILENAME}")
add_executable(${TEST_TARGET} ${TEST_SUBDIR}/main.s)
add_executable(${TEST_TARGET} ${TEST_FILENAME}.s)
target_compile_options(${TEST_TARGET} PRIVATE
-march=rv32id

28
fw/test/core.s Normal file
View File

@ -0,0 +1,28 @@
.section .text
.global main
main:
addi x2, x0, 5 # x2 = 5
addi x3, x0, 12 # x3 = 12
addi x7, x3, -9 # x7 = (12 - 9) = 3
or x4, x7, x2 # x4 = (3 OR 5) = 7
and x5, x3, x4 # x5 = (12 AND 7) = 4
add x5, x5, x4 # x5 = 4 + 7 = 11
beq x5, x7, end # shouldn't be taken
slt x4, x3, x4 # x4 = (12 < 7) = 0
beq x4, x0, around # should be taken
addi x5, x0, 0 # shouldn't execute
around:
slt x4, x7, x2 # x4 = (3 < 5) = 1
add x7, x4, x5 # x7 = (1 + 11) = 12
sub x7, x7, x2 # x7 = (12 - 5) = 7
sw x7, 84(x3) # [96] = 7
lw x2, 96(x0) # x2 = [96] = 7
add x9, x2, x5 # x9 = (7 + 11) = 18
jal x3, end # jump to end, x3 = 0x44
addi x2, x0, 1 # shouldn't execute
end:
add x2, x2, x9 # x2 = (7 + 18) = 25
sw x2, 0x20(x3) # [100] = 25
done:
beq x2, x2, done # infinite loop

View File

@ -1,49 +0,0 @@
import rv32i_defs::*;
// N = Bit width
module ALU #(
parameter integer N = 32
) (
input logic [N-1:0] a,
input logic [N-1:0] b,
input alu_opcode operation,
output logic [N-1:0] result,
output logic [ 3:0] status
);
logic n, z, c, v;
always_comb begin
case (operation)
SUM: begin // Addition
{c, result} = a + b;
v = (result[N-1] & !a[N-1] & !b[N-1]) | (!result[N-1] & a[N-1] & b[N-1]);
end
SUB: begin // Substraction
{c, result} = a - b;
v = (result[N-1] & !a[N-1] & !b[N-1]) | (!result[N-1] & a[N-1] & b[N-1]);
end
OR: begin // Or
result = a | b;
c = 'b0;
v = 'b0;
end
AND: begin // And
result = a & b;
c = 'b0;
v = 'b0;
end
SLT: begin // Set less than
result = {31'd0, a < b};
c = 'b0;
v = 'b0;
end
default: begin
result = 'dx;
c = 1'bx;
v = 1'bx;
end
endcase
n = result[N-1];
z = (result == '0);
status = {n, z, c, v};
end
endmodule

View File

@ -1,65 +0,0 @@
`timescale 1ns / 1ps
module ALUDecoder (
input logic opcode_5,
input logic [2:0] funct_3,
input logic funct_7_5,
input logic [1:0] alu_op,
output logic [2:0] alu_ctrl,
output logic branch_neg
);
always_comb begin
casex ({
alu_op, funct_3, opcode_5, funct_7_5
})
'b00xxxxx: begin
alu_ctrl = 'b000; // lw sw
branch_neg = 'dx;
end
'b01000xx: begin
alu_ctrl = 'b001; // beq
branch_neg = 1;
end
'b01100xx: begin
alu_ctrl = 'b101; // blt
branch_neg = 0;
end
'b01101xx: begin
alu_ctrl = 'b101; // bge
branch_neg = 1;
end
'b1000000: begin
alu_ctrl = 'b000; // add
branch_neg = 'dx;
end
'b1000001: begin
alu_ctrl = 'b000; // add
branch_neg = 'dx;
end
'b1000010: begin
alu_ctrl = 'b000; // add
branch_neg = 'dx;
end
'b1000011: begin
alu_ctrl = 'b001; // sub
branch_neg = 'dx;
end
'b10010xx: begin
alu_ctrl = 'b101; // slt
branch_neg = 'dx;
end
'b10110xx: begin
alu_ctrl = 'b000; // or
branch_neg = 'dx;
end
'b10111xx: begin
alu_ctrl = 'b000; // and
branch_neg = 'dx;
end
default: begin
alu_ctrl = 'dx;
branch_neg = 'dx;
end
endcase
end
endmodule

View File

@ -1,28 +0,0 @@
`timescale 1ns / 1ps
module DataMemory #(
parameter int N = 32,
parameter int SIZE = 32,
parameter int BYTE_WIDTH = 8)(
input logic clk, rst,
input logic[N-1:0] addr,
input logic write_enable,
input logic[N-1:0] write_data,
output logic[N-1:0] read_data
);
logic[SIZE*BYTE_WIDTH-1:0][BYTE_WIDTH-1:0] mem;
assign read_data = {mem[addr + 'd0],
mem[addr + 'd1],
mem[addr + 'd2],
mem[addr + 'd3]};
always_ff @(posedge clk) begin
if (rst)
mem <= '{default: '0};
else if (write_enable)
{mem[addr + 'd0],
mem[addr + 'd1],
mem[addr + 'd2],
mem[addr + 'd3]} <= write_data;
end
endmodule

View File

@ -1,19 +0,0 @@
`timescale 1ns / 1ps
// N = Bit width
module InstructionMemory #(
parameter int N = 32,
parameter int N_INSTR = 32,
parameter int BYTE_WIDTH = 8
) (
input logic [N-1:0] addr,
output logic [N-1:0] instr
);
logic [BYTE_WIDTH-1:0] mem[N_INSTR*BYTE_WIDTH-1:0];
always_comb begin
instr = {mem[addr+'d0], mem[addr+'d1], mem[addr+'d2], mem[addr+'d3]};
end
initial $readmemh("sandbox.mem", mem);
endmodule

View File

@ -1,93 +0,0 @@
`timescale 1ns / 1ps
import rv32i_defs::*;
module MainDecoder(
input logic[6:0] opcode,
output logic branch,
output logic jump,
output logic[1:0] result_src,
output logic mem_write,
output logic alu_src,
output logic[1:0] imm_src,
output logic reg_write,
output logic[1:0] alu_op
);
opcode_fmt opcode_enum;
assign opcode_enum = opcode_fmt'(opcode);
always_comb begin
case(opcode)
LOAD: begin // lw
reg_write = 1;
imm_src = 'b00;
alu_src = 1;
mem_write = 0;
result_src = 'b01;
branch = 0;
alu_op = 'b00;
jump = 0;
end
STORE: begin // sw
reg_write = 0;
imm_src = 'b01;
alu_src = 1;
mem_write = 1;
result_src = 'bx0; // xx?
branch = 0;
alu_op = 'b00;
jump = 0;
end
REG_OPERATION: begin // r-type
reg_write = 1;
imm_src = 'bxx;
alu_src = 0;
mem_write = 0;
result_src = 'b00;
branch = 0;
alu_op = 'b10;
jump = 0;
end
BRANCH: begin // b-type
reg_write = 0;
imm_src = 'b10;
alu_src = 0;
mem_write = 0;
result_src = 'bxx;
branch = 1;
alu_op = 'b01;
jump = 0;
end
IMM_OPERATION: begin // i-type
reg_write = 1;
imm_src = 'b00;
alu_src = 1;
mem_write = 0;
result_src = 'b00;
branch = 0;
alu_op = 'b10;
jump = 0;
end
JAL: begin // jal
reg_write = 1;
imm_src = 'b11;
alu_src = 'bx;
mem_write = 0;
result_src = 'b10;
branch = 0;
alu_op = 'bxx;
jump = 1;
end
default: begin
reg_write = 'b0;
imm_src = 'bxx;
alu_src = 'bx;
mem_write = 'b0;
result_src = 'b00;
branch = 'b0;
alu_op = 'bx;
jump = 'b0;
end
endcase
end
endmodule

View File

@ -1,22 +0,0 @@
package rv32i_defs;
typedef enum logic[2:0]{
SUM = 'b000,
SUB = 'b001,
OR = 'b011,
AND = 'b010,
SLT = 'b101
} alu_opcode;
typedef enum logic[6:0]{
STALL = 'b0000000,
REG_OPERATION = 'b0110011,
IMM_OPERATION = 'b0010011,
LOAD = 'b0000011,
STORE = 'b0100011,
BRANCH = 'b1100011,
JAL = 'b1101111,
JALR = 'b1100111,
LUI = 'b0110111,
AUIPC = 'b0010111} opcode_fmt;
endpackage

View File

@ -1,115 +0,0 @@
`timescale 1ns / 1ps
module SingleCycleCPU(
input logic clk, reset
);
logic[31:0] pc, pc_next;
logic[31:0] imm_ext;
logic[31:0] pc_target;
assign pc_target = imm_ext + pc;
always_comb begin
case(pc_src)
'd0: pc_next = pc + 'd4;
'd1: pc_next = pc_target;
endcase
end
always_ff @(posedge clk) begin
if(reset)
pc <= 'b0;
else
pc <= pc_next;
end
logic[31:0] instr;
InstructionMemory #(.N(32)) instruction_memory(pc, instr);
logic reg_write;
logic[31:0] read_data_1, read_data_2;
logic[31:0] result;
RegisterFile #(.N_REG_ADDR(5), .N_DATA(32)) register_file(
clk,
reset,
instr[19:15],
instr[24:20],
instr[11:7],
reg_write,
result,
read_data_1,
read_data_2
);
logic[1:0] result_src;
logic[1:0] imm_src;
logic[2:0] alu_ctrl;
logic alu_status_zero;
ControlUnit control_unit(
instr[6:0],
instr[14:12],
instr[31:25],
result_src,
mem_write,
alu_ctrl,
alu_src,
imm_src,
reg_write,
jump,
branch,
branch_alu_neg
);
JumpControl jump_control(
jump,
branch,
branch_alu_neg,
alu_status_zero,
pc_src);
Extend imm_extend(
imm_src[1:0],
instr[31:7],
imm_ext[31:0]
);
//logic[31:0] src_a = read_data_1;
logic[31:0] src_b;
always_comb begin
case(alu_src)
'd0: src_b = read_data_2;
'd1: src_b = imm_ext;
endcase
end
logic[31:0] alu_result;
logic[3:0] alu_status;
assign alu_status_zero = alu_status[2];
ALU alu(
read_data_1,
src_b,
alu_ctrl,
alu_result,
alu_status
);
logic[31:0] write_data;
assign write_data = read_data_2;
logic[31:0] data_mem_read_data;
DataMemory data_memory(
clk,
reset,
alu_result,
mem_write,
write_data,
data_mem_read_data
);
always_comb begin
case(result_src)
'b00: result = alu_result;
'b01: result = data_mem_read_data;
'b10: result = pc + 'd4;
'b11: result = 'dx;
endcase
end
endmodule

48
rtl/alu.sv Normal file
View File

@ -0,0 +1,48 @@
import rv32i_defs::*;
module alu (
input logic [OperandSize-1:0] a,
input logic [OperandSize-1:0] b,
input alu_opcode_t operation,
output logic [OperandSize-1:0] result,
output logic [3:0] status
);
logic n, z, c, v;
always_comb begin
case (operation)
SUM: begin
{c, result} = a + b;
v = (result[OperandSize-1] & !a[OperandSize-1] & !b[OperandSize-1]) |
(!result[OperandSize-1] & a[OperandSize-1] & b[OperandSize-1]);
end
SUB: begin
{c, result} = a - b;
v = (result[OperandSize-1] & !a[OperandSize-1] & !b[OperandSize-1]) |
(!result[OperandSize-1] & a[OperandSize-1] & !b[OperandSize-1]);
end
OR: begin
result = a | b;
c = 'b0;
v = 'b0;
end
AND: begin
result = a & b;
c = 'b0;
v = 'b0;
end
SLT: begin
result = {31'd0, a < b};
c = 'b0;
v = 'b0;
end
default: begin
result = 'dx;
c = 1'bx;
v = 1'bx;
end
endcase
n = result[OperandSize-1];
z = (result == '0);
status = {n, z, c, v};
end
endmodule

65
rtl/alu_decoder.sv Normal file
View File

@ -0,0 +1,65 @@
`timescale 1ns / 1ps
module alu_decoder(
input logic opcode_5,
input logic [2:0] funct_3,
input logic funct_7_5,
input logic [1:0] alu_op,
output logic [2:0] alu_ctrl,
output logic branch_neg
);
always_comb begin
casez ({
alu_op, funct_3, opcode_5, funct_7_5
})
'b00?????: begin
alu_ctrl = 3'b000; // lw sw
branch_neg = 1'dx;
end
'b01000??: begin
alu_ctrl = 3'b001; // beq
branch_neg = 1'd1;
end
'b01100??: begin
alu_ctrl = 3'b101; // blt
branch_neg = 1'd0;
end
'b01101??: begin
alu_ctrl = 3'b101; // bge
branch_neg = 1'd1;
end
'b1000000: begin
alu_ctrl = 3'b000; // add
branch_neg = 1'dx;
end
'b1000001: begin
alu_ctrl = 3'b000; // add
branch_neg = 1'dx;
end
'b1000010: begin
alu_ctrl = 3'b000; // add
branch_neg = 1'dx;
end
'b1000011: begin
alu_ctrl = 3'b001; // sub
branch_neg = 1'dx;
end
'b10010??: begin
alu_ctrl = 3'b101; // slt
branch_neg = 1'dx;
end
'b10110??: begin
alu_ctrl = 3'b000; // or
branch_neg = 1'dx;
end
'b10111??: begin
alu_ctrl = 3'b000; // and
branch_neg = 1'dx;
end
default: begin
alu_ctrl = 3'bxxx;
branch_neg = 1'dx;
end
endcase
end
endmodule

View File

@ -1,6 +1,6 @@
`timescale 1ns / 1ps
module CacheMemory #(
module cache_memory #(
parameter int ADDR_SIZE = 32,
parameter int NUM_SETS = 16,
parameter int NUM_WAYS = 4,

View File

@ -2,7 +2,7 @@
import rv32i_defs::*;
module ControlUnit (
module control_unit (
input logic [6:0] opcode,
input logic [2:0] funct_3,
input logic [6:0] funct_7,
@ -14,10 +14,10 @@ module ControlUnit (
output logic reg_write,
output logic jump,
output logic branch,
branch_alu_neg
output logic branch_alu_neg
);
logic [1:0] alu_op;
MainDecoder main_decoder (
main_decoder main_decoder (
.opcode(opcode),
.branch(branch),
.jump(jump),
@ -29,7 +29,7 @@ module ControlUnit (
.alu_op(alu_op)
);
ALUDecoder alu_decoder (
alu_decoder alu_decoder (
.opcode_5(opcode[5]),
.funct_3(funct_3),
.funct_7_5(funct_7[5]),

22
rtl/data_memory.sv Normal file
View File

@ -0,0 +1,22 @@
import rv32i_defs::*;
module data_memory #(
parameter int BLOCK_SIZE = 8,
parameter int NUM_BLOCKS = 32
) (
data_memory_if.ram mem_if
);
logic [NUM_BLOCKS-1:0][BLOCK_SIZE-1:0] mem;
assign mem_if.read_data = {
mem[mem_if.addr+'d3], mem[mem_if.addr+'d2], mem[mem_if.addr+'d1], mem[mem_if.addr+'d0]
};
always_ff @(posedge mem_if.clk) begin
if (mem_if.rst) mem <= '{default: '0};
else if (mem_if.write_enable)
{mem[mem_if.addr+'d3],
mem[mem_if.addr+'d2],
mem[mem_if.addr+'d1],
mem[mem_if.addr+'d0]} <= mem_if.write_data;
end
endmodule

18
rtl/data_memory_if.sv Normal file
View File

@ -0,0 +1,18 @@
interface data_memory_if #(
parameter int ADDR_SIZE = 32,
parameter int DATA_SIZE = 32
) (
input logic clk,
input logic rst
);
logic [ADDR_SIZE-1:0] addr;
logic write_enable;
logic [DATA_SIZE-1:0] write_data;
logic [DATA_SIZE-1:0] read_data;
logic valid;
logic ready;
modport datapath(input read_data, output addr, write_enable, write_data);
modport ram(input clk, rst, addr, write_enable, write_data, output read_data);
endinterface

View File

@ -1,6 +1,6 @@
`timescale 1ns / 1ps
module ImmExtend (
module imm_extend (
input logic [ 1:0] imm_src,
input logic [31:7] instr,
output logic [31:0] imm_ext

18
rtl/instr_memory.sv Normal file
View File

@ -0,0 +1,18 @@
import rv32i_defs::*;
module instr_memory #(
parameter int N_INSTR = 32,
parameter string FILE_PATH = ""
) (
input logic [$clog2(N_INSTR * 4)-1:0] addr,
output logic [InstructionSize-1:0] instr
);
// Number of bits referenced with one address
localparam int BlockSize = 8;
localparam int NumBlocks = N_INSTR * 4;
logic [BlockSize-1:0] mem[NumBlocks];
assign instr = {mem[addr+'d0], mem[addr+'d1], mem[addr+'d2], mem[addr+'d3]};
initial $readmemh(FILE_PATH, mem);
endmodule

View File

@ -1,10 +1,10 @@
`timescale 1ns / 1ps
module JumpControl (
module jump_control (
input logic jump,
branch,
branch_alu_neg,
zero,
input logic branch,
input logic branch_alu_neg,
input logic zero,
output logic pc_src
);
logic alu_result, branch_result;
@ -14,7 +14,7 @@ module JumpControl (
case (branch_alu_neg)
'd0: branch_result = alu_result;
'd1: branch_result = !alu_result;
default: branch_result = 'dx;
default: branch_result = 1'dx;
endcase
end

93
rtl/main_decoder.sv Normal file
View File

@ -0,0 +1,93 @@
`timescale 1ns / 1ps
import rv32i_defs::*;
module main_decoder (
input logic [6:0] opcode,
output logic branch,
output logic jump,
output logic [1:0] result_src,
output logic mem_write,
output logic alu_src,
output logic [1:0] imm_src,
output logic reg_write,
output logic [1:0] alu_op
);
opcode_fmt_t opcode_enum;
assign opcode_enum = opcode_fmt_t'(opcode);
always_comb begin
case (opcode)
LOAD: begin // lw
reg_write = 1;
imm_src = 'b00;
alu_src = 1;
mem_write = 0;
result_src = 'b01;
branch = 0;
alu_op = 'b00;
jump = 0;
end
STORE: begin // sw
reg_write = 0;
imm_src = 'b01;
alu_src = 1;
mem_write = 1;
result_src = 2'bx0; // xx?
branch = 0;
alu_op = 'b00;
jump = 0;
end
REG_OPERATION: begin // r-type
reg_write = 1;
imm_src = 2'bxx;
alu_src = 0;
mem_write = 0;
result_src = 'b00;
branch = 0;
alu_op = 'b10;
jump = 0;
end
BRANCH: begin // b-type
reg_write = 0;
imm_src = 'b10;
alu_src = 0;
mem_write = 0;
result_src = 2'bxx;
branch = 1;
alu_op = 'b01;
jump = 0;
end
IMM_OPERATION: begin // i-type
reg_write = 1;
imm_src = 'b00;
alu_src = 1;
mem_write = 0;
result_src = 'b00;
branch = 0;
alu_op = 'b10;
jump = 0;
end
JAL: begin // jal
reg_write = 1;
imm_src = 'b11;
alu_src = 1'bx;
mem_write = 0;
result_src = 'b10;
branch = 0;
alu_op = 2'bxx;
jump = 1;
end
default: begin
reg_write = 'b0;
imm_src = 2'bxx;
alu_src = 1'bx;
mem_write = 'b0;
result_src = 'b00;
branch = 'b0;
alu_op = 2'bxx;
jump = 'b0;
end
endcase
end
endmodule

View File

@ -1,7 +1,7 @@
`timescale 1ns / 1ps
// 2**N to N Priority encoder
module PriorityEncoder #(
module priority_encoder #(
parameter int N = 4
) (
input logic [2**N - 1:0] data_in,

View File

@ -1,23 +1,18 @@
`timescale 1ns / 1ps
import rv32i_defs::*;
// N = Bit width
module RegisterFile #(
parameter int N_REG_ADDR = 5,
parameter int N_REG = 32,
parameter int N_DATA = 32
) (
module register_file (
input logic clk,
rst,
input logic [N_REG_ADDR-1:0] addr_1,
addr_2,
addr_3,
input logic rst,
input logic [RegisterSize-1:0] addr_1,
input logic [RegisterSize-1:0] addr_2,
input logic [RegisterSize-1:0] addr_3,
input logic write_enable_3,
input logic [N_DATA-1:0] write_data_3,
output logic [N_DATA-1:0] read_data_1,
read_data_2
input logic [OperandSize-1:0] write_data_3,
output logic [OperandSize-1:0] read_data_1,
output logic [OperandSize-1:0] read_data_2
);
logic [N_DATA-1:0] mem [N_REG-1:1];
logic [N_DATA-1:0] zero;
logic [OperandSize-1:0] mem [NumRegisters-1:1];
logic [OperandSize-1:0] zero;
always_comb begin
zero = 'd0;

31
rtl/rv32i_defs.sv Normal file
View File

@ -0,0 +1,31 @@
`timescale 1ns / 1ps
package rv32i_defs;
// Sizes in bits
localparam int OperandSize = 32;
localparam int InstructionSize = 32;
localparam int NumRegisters = 32;
localparam int RegisterSize = $clog2(NumRegisters);
typedef enum logic [2:0] {
SUM = 'b000,
SUB = 'b001,
OR = 'b011,
AND = 'b010,
SLT = 'b101
} alu_opcode_t;
typedef enum logic [6:0] {
STALL = 'b0000000,
REG_OPERATION = 'b0110011,
IMM_OPERATION = 'b0010011,
LOAD = 'b0000011,
STORE = 'b0100011,
BRANCH = 'b1100011,
JAL = 'b1101111,
JALR = 'b1100111,
LUI = 'b0110111,
AUIPC = 'b0010111
} opcode_fmt_t;
endpackage

View File

@ -0,0 +1,121 @@
`timescale 1ns / 1ps
import rv32i_defs::*;
module single_cycle_datapath (
input logic clk,
input logic rst,
data_memory_if.datapath mem_if
);
logic [InstructionSize-1:0] pc, pc_next;
logic [OperandSize-1:0] imm_ext;
logic [InstructionSize-1:0] pc_target;
assign pc_target = imm_ext + pc;
logic pc_src;
always_comb begin
case (pc_src)
'd0: pc_next = pc + 'd4;
'd1: pc_next = pc_target;
default: pc_next = 'dx;
endcase
end
always_ff @(posedge clk) begin
if (rst) pc <= 'b0;
else pc <= pc_next;
end
logic [InstructionSize-1:0] instr;
instr_memory #(
.N_INSTR(32)
) instr_memory (
.addr (7'(pc)),
.instr(instr)
);
logic reg_write;
logic [OperandSize-1:0] read_data_1, read_data_2;
logic [OperandSize-1:0] result;
register_file register_file (
.clk(clk),
.rst(rst),
.addr_1(instr[19:15]),
.addr_2(instr[24:20]),
.addr_3(instr[11:7]),
.write_enable_3(reg_write),
.write_data_3(result),
.read_data_1(read_data_1),
.read_data_2(read_data_2)
);
logic [1:0] result_src;
logic [1:0] imm_src;
logic [2:0] alu_ctrl;
logic alu_src;
logic alu_status_zero;
logic jump;
logic branch;
logic branch_alu_neg;
control_unit control_unit (
.opcode(instr[6:0]),
.funct_3(instr[14:12]),
.funct_7(instr[31:25]),
.result_src(result_src),
.mem_write(mem_if.write_enable),
.alu_ctrl(alu_ctrl),
.alu_src(alu_src),
.imm_src(imm_src),
.reg_write(reg_write),
.jump(jump),
.branch(branch),
.branch_alu_neg(branch_alu_neg)
);
jump_control jump_control (
.jump(jump),
.branch(branch),
.branch_alu_neg(branch_alu_neg),
.zero(alu_status_zero),
.pc_src(pc_src)
);
imm_extend imm_extend (
.imm_src(imm_src[1:0]),
.instr (instr[31:7]),
.imm_ext(imm_ext[31:0])
);
logic [OperandSize-1:0] src_b;
always_comb begin
case (alu_src)
'd0: src_b = read_data_2;
'd1: src_b = imm_ext;
default: src_b = 'dx;
endcase
end
logic [OperandSize-1:0] alu_result;
logic [3:0] alu_status;
assign alu_status_zero = alu_status[2];
alu alu (
.a(read_data_1),
.b(src_b),
.operation(alu_ctrl),
.result(alu_result),
.status(alu_status)
);
assign mem_if.write_data = read_data_2;
assign mem_if.addr = alu_result;
always_comb begin
case (result_src)
'b00: result = alu_result;
'b01: result = mem_if.read_data;
'b10: result = pc + 'd4;
'b11: result = 'dx;
default: result = 'dx;
endcase
end
endmodule

View File

@ -1,6 +1,4 @@
cmake_minimum_required(VERSION 3.10)
project(rvscc-tests CXX)
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/utils.cmake)
find_package(verilator HINTS $ENV{VERILATOR_ROOT})
if (NOT verilator_FOUND)
@ -12,55 +10,67 @@ find_package(Threads REQUIRED)
find_package(SystemCLanguage QUIET)
function(rvscc_add_test)
cmake_parse_arguments(TEST
""
"NAME"
"SOURCES"
${ARGN}
)
set(TEST_TARGET_NAME test-${TEST_NAME})
add_executable(${TEST_TARGET_NAME} sim_main.cpp)
verilate(${TEST_TARGET_NAME}
SOURCES ${TEST_SOURCES}
TRACE
VERILATOR_ARGS --timing --assert
)
list(GET TEST_SOURCES 0 TEST_TOP_MODULE)
get_filename_component(TEST_TOP_MODULE_NAME ${TEST_TOP_MODULE} NAME_WE)
target_compile_definitions(${TEST_TARGET_NAME} PRIVATE
TEST_HEADER="V${TEST_TOP_MODULE_NAME}.h"
TEST_CLASS=V${TEST_TOP_MODULE_NAME}
)
add_test(NAME ${TEST_TARGET_NAME} COMMAND ${TEST_TARGET_NAME})
endfunction()
rvscc_add_test(
NAME alu
TOP Test_ALU
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/RV32IDefs.sv
${CMAKE_CURRENT_SOURCE_DIR}/Test_ALU.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/ALU.sv
TOP test_alu
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/rv32i_defs.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/alu.sv
${CMAKE_CURRENT_SOURCE_DIR}/test_alu.sv
)
rvscc_add_test(NAME priority-encoder
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test_PriorityEncoder.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/PriorityEncoder.sv
rvscc_add_test(
NAME priority-encoder
TOP test_priority_encoder
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/priority_encoder.sv
${CMAKE_CURRENT_SOURCE_DIR}/test_priority_encoder.sv
)
rvscc_add_test(NAME data-memory
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test_DataMemory.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/DataMemory.sv
rvscc_add_test(
NAME data-memory
TOP test_data_memory
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/rv32i_defs.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/data_memory_if.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/data_memory.sv
${CMAKE_CURRENT_SOURCE_DIR}/test_data_memory.sv
)
rvscc_add_test(NAME imm-extend
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test_ImmExtend.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/ImmExtend.sv
rvscc_add_test(
NAME imm-extend
TOP test_imm_extend
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/imm_extend.sv
${CMAKE_CURRENT_SOURCE_DIR}/test_imm_extend.sv
)
rvscc_add_test(
NAME register-file
TOP Test_RegisterFile
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test_RegisterFile.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/RegisterFile.sv
TOP test_register_file
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/rv32i_defs.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/register_file.sv
${CMAKE_CURRENT_SOURCE_DIR}/test_register_file.sv
)
rvscc_add_test(
NAME instruction_memory
TOP test_instr_memory
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/rv32i_defs.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/instr_memory.sv
${CMAKE_CURRENT_SOURCE_DIR}/test_instr_memory.sv
)
rvscc_add_test(
NAME single-cycle-core
TOP test_single_cycle_core
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../rtl/rv32i_defs.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/single_cycle_datapath.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/data_memory_if.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/data_memory.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/instr_memory.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/jump_control.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/control_unit.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/alu_decoder.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/main_decoder.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/register_file.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/imm_extend.sv
${CMAKE_CURRENT_SOURCE_DIR}/../rtl/alu.sv
${CMAKE_CURRENT_SOURCE_DIR}/test_single_cycle_core.sv
)

View File

@ -1,43 +0,0 @@
import rv32i_defs::alu_opcode;
module Test_ALU ();
logic [31:0] a, b;
alu_opcode operation;
logic [31:0] result;
logic [ 3:0] status;
ALU alu (
.a(a),
.b(b),
.operation(operation),
.result(result),
.status(status)
);
localparam RandomSumIterations = 32;
task operation_test(input logic[31:0] a_value, input logic[31:0] b_value, input alu_opcode operation, input logic[31:0] expected_result, input logic[3:0] expected_status);
a = a_value;
b = b_value;
operation = operation;
#1;
assert(result == expected_result) else $error("Incorrent result in operation: %0s %0d, %0d = %0d (expected %0d)", operation.name(), a, b, result, expected_result);
assert(status == expected_status) else $error("Incorrent flags in operation: %0s %0d, %0d = %0d (n: %0b, z: %0b, c: %0b, v: %0b) (expected %4b)", operation.name(), a, b, result, status[3], status[2], status[1], status[0], expected_status);
endtask
initial begin
$dumpfile("dump.vcd");
$dumpvars;
operation_test('d0, 'd0, SUM, 'd0, 'b0100);
operation_test('hFFFF_FFFF, 'd0, SUM, 'hFFFF_FFFF, 'b1000);
for(int i = 0; i < RandomSumIterations; i++) begin
a = $random;
b = $random;
operation = SUM;
#1;
assert(result == a + b) else $error("Failed in operation: %d + %d", a, b);
end
$finish;
end
endmodule

View File

@ -1,12 +0,0 @@
`timescale 1ns / 1ps
module Test_CPU();
logic clk, reset;
CPU cpu(clk, reset);
always #10 clk = ~clk;
initial begin
clk = 0;
reset = 1;
#100
reset = 0;
end
endmodule

View File

@ -1,26 +0,0 @@
`timescale 1ns / 1ps
module Test_CacheMemory();
logic[31:0] addr, write_data, read_data;
logic clk, rst, write_enable;
CacheMemory cache_memory(clk, rst, addr, write_enable, write_data, read_data);
always #5 clk = ~clk;
initial begin
clk = 0;
rst = 1;
write_enable = 0;
#25
rst = 0;
addr = 'd7;
write_enable = 1;
write_data = 'd10;
#25
write_enable = 0;
end
endmodule

View File

@ -1,57 +0,0 @@
`timescale 1ns / 1ps
module Test_DataMemory ();
logic clk, rst;
logic [31:0] addr;
logic write_enable;
logic [31:0] write_data;
logic [31:0] read_data;
localparam int MemorySize = 16;
DataMemory #(
.SIZE(MemorySize)
) DUT (
.clk(clk),
.rst(rst),
.addr(addr),
.write_enable(write_enable),
.write_data(write_data),
.read_data(read_data)
);
always #1 clk = ~clk;
localparam int MemoryWriteRange = 16;
logic [MemoryWriteRange:0][31:0] write_values;
int start_addr;
initial begin
// Reset
clk = 0;
rst = 1;
write_enable = 0;
#4;
rst = 0;
#1;
// Write to a range of values in memory
write_enable = 1;
start_addr = $urandom_range(15);
for (int i = 0; i < MemoryWriteRange; i++) begin
addr = start_addr + i*4;
write_values[i] = $urandom();
write_data = write_values[i];
#2;
end
// Read and compare the same range of values
write_enable = 0;
#4;
for (int i = 0; i < MemoryWriteRange; i++) begin
addr = start_addr + i*4;
#1;
assert (read_data == write_values[i])
else $error("Read failed at address %h", addr);
#1;
end
$finish;
end
endmodule

View File

@ -1,21 +0,0 @@
`timescale 1ns / 1ps
module Test_InstrMemory();
logic[31:0] addr;
logic[31:0] instr;
InstructionMemory instruction_memory(
.addr(addr),
.instr(instr)
);
initial begin
addr='d1;
#20
addr='d11;
#20
addr='d12;
#20
addr='d13;
end
endmodule

View File

@ -1,24 +0,0 @@
`timescale 1ns / 1ps
module Test_PriorityEncoder();
logic[7:0] data_in;
logic[2:0] data_out;
logic valid;
PriorityEncoder#(.N(3)) encoder(
.data_in(data_in),
.data_out(data_out),
.valid(valid)
);
initial begin
data_in = 'b00000001;
for (int i = 0; i < 8; i++) begin
#1 assert (data_out == i[2:0] && valid == 1) else $error("Failed one-hot to index check at iteration %0d, %d", i, data_out);
data_in = data_in << 'd1;
end
data_in = 'b00101111;
#1 assert (data_out == 'd5) else $error("Incorrect result with input %b", data_in);
data_in = 'b10101010;
#1 assert (data_out == 'd7) else $error("Incorrect result with input %b", data_in);
$finish;
end
endmodule

View File

@ -1,77 +0,0 @@
`timescale 1ns / 1ps
module Test_RegisterFile();
logic clk, rst;
logic[4:0] addr_1, addr_2, addr_3;
logic write_enable_3;
logic[31:0] write_data_3;
logic[31:0] read_data_1, read_data_2;
RegisterFile register_file(
clk,
rst,
addr_1,
addr_2,
addr_3,
write_enable_3,
write_data_3,
read_data_1,
read_data_2
);
always #1 clk = ~clk;
localparam N_REG_ADDR = 5;
localparam N_DATA = 32;
logic [N_REG_ADDR-1:0][N_DATA-1:0] write_values;
initial begin
$dumpfile("regfile.vcd");
$dumpvars;
// Reset
clk = 0;
rst = 1;
write_enable_3 = 0;
#4;
rst = 0;
#1;
// Write to all registers
write_enable_3 = 1;
for (int i = 0; i < 2**N_REG_ADDR; i++) begin
addr_1 = 5'($urandom_range(0, 2**5));
addr_2 = 5'($urandom);
addr_3 = i[4:0];
write_values[i] = $random();
write_data_3 = write_values[i];
#2;
end
// Read and compare the values stored in each register using addr_1
write_enable_3 = 0;
#4;
for (int i = 0; i < 2**N_REG_ADDR; i++) begin
addr_1 = i[4:0];
addr_2 = 5'($random());
addr_3 = 5'($random());
#2;
if (i == 0) begin
assert (read_data_1 == 'd0)
else $error("Read failed at register x0 using addr_1, value should stay at 0");
end else begin
assert (read_data_1 == write_values[i])
else $error("Read failed at register x%h using addr_1 %d, %d", addr_1, read_data_1, write_values[i]);
end
end
// Read and compare the values stored in each register using addr_2
write_enable_3 = 0;
#4;
for (int i = 0; i < 2**N_REG_ADDR; i++) begin
addr_1 = 5'($random());
addr_2 = i[4:0];
addr_3 = 5'($random());
#2;
assert (read_data_2 == write_values[i])
else $error("Read failed at address %h using addr_2 %d", addr_2, read_data_2);
end
$finish;
end
endmodule

70
test/test_alu.sv Normal file
View File

@ -0,0 +1,70 @@
import rv32i_defs::*;
module test_alu ();
logic [31:0] a, b;
alu_opcode_t operation;
logic [31:0] result;
logic [3:0] status;
alu DUT (
.a(a),
.b(b),
.operation(operation),
.result(result),
.status(status)
);
localparam int RandomSumIterations = 32;
task static operation_test(input logic [31:0] a_value, input logic [31:0] b_value,
input alu_opcode_t operation, input logic [31:0] expected_result,
input logic [3:0] expected_status);
a = a_value;
b = b_value;
operation = operation;
#1;
assert (result == expected_result)
else
$error(
"Incorrent result in operation: %0s %0d, %0d = %0d (expected %0d)",
operation.name(),
a,
b,
result,
expected_result
);
assert (status == expected_status)
else
$error(
"Incorrent flags in operation: %0s %0d, %0d = %0d",
operation.name(),
a,
b,
result,
"(n: %0b, z: %0b, c: %0b, v: %0b) (expected %4b)",
status[3],
status[2],
status[1],
status[0],
expected_status
);
endtask
initial begin
$dumpfile("dump.vcd");
$dumpvars;
operation_test('d0, 'd0, SUM, 'd0, 'b0100);
operation_test('hFFFF_FFFF, 'd0, SUM, 'hFFFF_FFFF, 'b1000);
for (int i = 0; i < RandomSumIterations; i++) begin
a = $urandom;
b = $urandom;
operation = SUM;
#1;
assert (result == a + b)
else $error("Failed in operation: %d + %d", a, b);
end
$finish;
end
endmodule

29
test/test_cache_memory.sv Normal file
View File

@ -0,0 +1,29 @@
`timescale 1ns / 1ps
module test_cache_memory ();
logic [31:0] addr, write_data, read_data;
logic clk, rst, write_enable;
CacheMemory cache_memory (
.clk(clk),
.rst(rst),
write_enable,
write_data,
read_data
);
always #5 clk = ~clk;
initial begin
clk = 0;
rst = 1;
write_enable = 0;
#25 rst = 0;
addr = 'd7;
write_enable = 1;
write_data = 'd10;
#25 write_enable = 0;
end
endmodule

65
test/test_data_memory.sv Normal file
View File

@ -0,0 +1,65 @@
`timescale 1ns / 1ps
import rv32i_defs::*;
module test_data_memory ();
localparam int NumInstr = 64;
// Each block is a byte
localparam int MemoryBlockSize = 8;
// Each instruction address have 4 bytes
localparam int NumMemoryBlocks = NumInstr * 4;
localparam int AddrSize = $clog2(NumMemoryBlocks);
logic clk, rst;
data_memory_if #(
.ADDR_SIZE(AddrSize),
.DATA_SIZE(OperandSize)
) mem_if (
.clk(clk),
.rst(rst)
);
data_memory #(
.BLOCK_SIZE(MemoryBlockSize),
.NUM_BLOCKS(NumMemoryBlocks)
) dut (
.mem_if(mem_if)
);
always #1 clk = ~clk;
localparam int MemoryWriteRange = 16;
logic [MemoryWriteRange-1:0][OperandSize-1:0] write_values;
int start_addr;
initial begin
// Reset
clk = 0;
rst = 1;
mem_if.write_enable = 0;
#4;
rst = 0;
#1;
// Write to a range of values in memory
mem_if.write_enable = 1;
start_addr = $urandom;
for (int i = 0; i < MemoryWriteRange; i++) begin
mem_if.addr = AddrSize'(start_addr + i * 4);
write_values[i] = $urandom;
mem_if.write_data = write_values[i];
#2;
end
// Read and compare the same range of values
mem_if.write_enable = 0;
#4;
for (int i = 0; i < MemoryWriteRange; i++) begin
$display(start_addr, i, AddrSize);
mem_if.addr = AddrSize'(start_addr + i * 4);
#1;
assert (mem_if.read_data == write_values[i])
else $error("Read failed at address %h", mem_if.addr);
#1;
end
$finish;
end
endmodule

View File

@ -1,11 +1,11 @@
`timescale 1ns / 1ps
module Test_ImmExtend ();
module test_imm_extend();
logic [ 1:0] imm_src;
logic [31:0] instr;
logic [31:0] imm_ext;
ImmExtend DUT (
imm_extend DUT (
.imm_src(imm_src),
.instr (instr[31:7]),
.imm_ext(imm_ext)

69
test/test_instr_memory.sv Normal file
View File

@ -0,0 +1,69 @@
`timescale 1ns / 1ps
import rv32i_defs::*;
module test_instr_memory ();
localparam string Path = "../fw/test/test-core.mem";
localparam int NumInstr = 32;
localparam int NumBlocks = NumInstr * 4;
localparam int AddrSize = $clog2(NumBlocks);
logic [AddrSize-1:0] addr;
logic [InstructionSize-1:0] instr;
instr_memory #(
.N_INSTR (NumInstr),
.FILE_PATH(Path)
) instruction_memory (
.addr (addr),
.instr(instr)
);
const
int
assert_instr_mem[21] = {
'h00500113,
'h00C00193,
'hFF718393,
'h0023E233,
'h0041F2B3,
'h004282B3,
'h02728863,
'h0041A233,
'h00020463,
'h00000293,
'h0023A233,
'h005203B3,
'h402383B3,
'h0471AA23,
'h06002103,
'h005104B3,
'h008001EF,
'h00100113,
'h00910133,
'h0221A023,
'h00210063
};
initial begin
addr = 'd0;
#1
assert (!$isunknown(instr))
else $error("Instruction memory not loaded");
#1;
foreach (assert_instr_mem[i]) begin
$display(i);
addr = AddrSize'(i * 4);
#1
assert (instr == assert_instr_mem[i])
else
$error(
"Instruction %h at address %h does not match the expected intruction %h",
instr,
addr,
assert_instr_mem[i]
);
end
$finish;
end
endmodule

View File

@ -0,0 +1,34 @@
`timescale 1ns / 1ps
module test_priority_encoder();
logic [7:0] data_in;
logic [2:0] data_out;
logic valid;
priority_encoder #(
.N(3)
) encoder (
.data_in(data_in),
.data_out(data_out),
.valid(valid)
);
initial begin
data_in = 'b00000001;
for (int i = 0; i < 8; i++) begin
#1
assert (data_out == i[2:0] && valid == 1)
else $error("Failed one-hot to index check at iteration %0d, %d", i, data_out);
data_in = data_in << 'd1;
end
data_in = 'b00101111;
#1
assert (data_out == 'd5)
else $error("Incorrect result with input %b", data_in);
data_in = 'b10101010;
#1
assert (data_out == 'd7)
else $error("Incorrect result with input %b", data_in);
$finish;
end
endmodule

View File

@ -0,0 +1,95 @@
`timescale 1ns / 1ps
import rv32i_defs::*;
module test_register_file ();
logic clk, rst;
logic [RegisterSize-1:0] addr_1, addr_2, addr_3;
logic write_enable_3;
logic [OperandSize-1:0] write_data_3;
logic [OperandSize-1:0] read_data_1, read_data_2;
register_file DUT (
.clk(clk),
.rst(rst),
.addr_1(addr_1),
.addr_2(addr_2),
.addr_3(addr_3),
.write_enable_3(write_enable_3),
.write_data_3(write_data_3),
.read_data_1(read_data_1),
.read_data_2(read_data_2)
);
always #1 clk = ~clk;
logic [NumRegisters-1:0][OperandSize-1:0] write_values;
initial begin
$dumpfile("regfile.vcd");
$dumpvars;
// Reset
clk = 0;
rst = 1;
write_enable_3 = 0;
#4;
rst = 0;
#1;
// Write to all registers
write_enable_3 = 1;
for (int i = 0; i < NumRegisters; i++) begin
addr_1 = 5'($urandom);
addr_2 = 5'($urandom);
addr_3 = i[4:0];
write_values[i] = $urandom;
write_data_3 = write_values[i];
$display("%h", write_values[i]);
#2;
end
// Read and compare the values stored in each register using addr_1
write_enable_3 = 0;
#4;
for (int i = 0; i < NumRegisters; i++) begin
addr_1 = i[4:0];
addr_2 = 5'($urandom);
addr_3 = 5'($urandom);
#2;
if (i == 0) begin
assert (read_data_1 == 'd0)
else $error("Read failed at register x0 using addr_1, value should stay at 0");
end else begin
assert (read_data_1 == write_values[i])
else
$error(
"Read failed at register x%h using addr_1 %d, %d",
addr_1,
read_data_1,
write_values[i]
);
end
end
// Read and compare the values stored in each register using addr_2
write_enable_3 = 0;
#4;
for (int i = 0; i < NumRegisters; i++) begin
addr_1 = 5'($urandom);
addr_2 = i[4:0];
addr_3 = 5'($urandom);
#2;
if (i == 0) begin
assert (read_data_2 == 'd0)
else $error("Read failed at register x0 using addr_2, value should stay at 0");
end else begin
assert (read_data_2 == write_values[i])
else
$error(
"Read failed at register x%h using addr_2 %d, %d",
addr_2,
read_data_2,
write_values[i]
);
end
end
$finish;
end
endmodule

View File

@ -0,0 +1,30 @@
`timescale 1ns / 1ps
module test_single_cycle_core ();
logic clk, rst;
always #1 clk = ~clk;
single_cycle_datapath dut (
.clk(clk),
.rst(rst),
.mem_if(mem_if.datapath)
);
data_memory_if mem_if (
.clk(clk),
.rst(rst)
);
data_memory mem (.mem_if(mem_if.ram));
initial begin
$dumpfile("single_cycle.vcd");
$dumpvars(1, dut);
clk = 0;
rst = 1;
#4;
rst = 0;
#100;
$finish;
end
endmodule