Change name scheme and add tests
Some checks are pending
continuous-integration/drone/push Build is pending
Some checks are pending
continuous-integration/drone/push Build is pending
This commit is contained in:
parent
bb5f00d8dc
commit
bd2f58d5f6
@ -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()
|
||||
|
@ -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
28
fw/test/core.s
Normal 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
|
49
rtl/ALU.sv
49
rtl/ALU.sv
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
48
rtl/alu.sv
Normal 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
65
rtl/alu_decoder.sv
Normal 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
|
@ -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,
|
@ -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
22
rtl/data_memory.sv
Normal 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
18
rtl/data_memory_if.sv
Normal 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
|
||||
|
@ -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
18
rtl/instr_memory.sv
Normal 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
|
@ -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
93
rtl/main_decoder.sv
Normal 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
|
@ -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,
|
@ -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
31
rtl/rv32i_defs.sv
Normal 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
|
121
rtl/single_cycle_datapath.sv
Normal file
121
rtl/single_cycle_datapath.sv
Normal 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
|
@ -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
|
||||
)
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
70
test/test_alu.sv
Normal 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
29
test/test_cache_memory.sv
Normal 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
65
test/test_data_memory.sv
Normal 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
|
@ -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
69
test/test_instr_memory.sv
Normal 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
|
34
test/test_priority_encoder.sv
Normal file
34
test/test_priority_encoder.sv
Normal 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
|
95
test/test_register_file.sv
Normal file
95
test/test_register_file.sv
Normal 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
|
30
test/test_single_cycle_core.sv
Normal file
30
test/test_single_cycle_core.sv
Normal 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
|
Loading…
Reference in New Issue
Block a user