diff --git a/rtl/alu.v b/rtl/alu.v index 5ecee99..e472c87 100644 --- a/rtl/alu.v +++ b/rtl/alu.v @@ -1,6 +1,28 @@ -module alu (S, A, B); - output [31:0] S; - input [31:0] A, B; +module alu (input [31:0] in_a, in_b, + input [3:0] func, + output reg [31:0] out); + + `include "alu_func.vh" - xor N[31:0] (S, A, B); -endmodule \ No newline at end of file + reg signed [31:0] s_in_a; + reg signed [31:0] s_in_b; + + always@ (*) begin + s_in_a = in_a; + s_in_b = in_b; + case (func) + ADD : out <= in_a + in_b; + SUB : out <= in_a - in_b; + SLL : out <= in_a << in_b; + SLT : out <= (s_in_a < s_in_b) ? 1 : 0; + SLTU : out <= (in_a < in_b) ? 1 : 0; + XOR : out <= in_a ^ in_b; + SRL : out <= in_a >> in_b; + SRA : out <= s_in_a >>> in_b; + OR : out <= in_a | in_b; + AND : out <= in_a & in_b; + default : out <= 32'b0; + endcase + end + +endmodule diff --git a/rtl/alu_func.vh b/rtl/alu_func.vh new file mode 100644 index 0000000..8b4142c --- /dev/null +++ b/rtl/alu_func.vh @@ -0,0 +1,10 @@ +parameter [3:0] ADD = 4'b0000; +parameter [3:0] SUB = 4'b0001; +parameter [3:0] SLL = 4'b0010; +parameter [3:0] SLT = 4'b0011; +parameter [3:0] SLTU = 4'b0100; +parameter [3:0] XOR = 4'b0101; +parameter [3:0] SRL = 4'b0110; +parameter [3:0] SRA = 4'b0111; +parameter [3:0] OR = 4'b1000; +parameter [3:0] AND = 4'b1001; \ No newline at end of file diff --git a/rtl/decoder.v b/rtl/decoder.v new file mode 100644 index 0000000..0f9eeee --- /dev/null +++ b/rtl/decoder.v @@ -0,0 +1,229 @@ +module decoder (input [31:0] instruction, + output reg [31:0] imm, + output reg reg_we, + output reg [1:0] reg_sel_data_in, + output reg [4:0] reg_sel_out_a, reg_sel_out_b, reg_sel_in, + output reg alu_src, + output reg [3:0] alu_func, + output reg mem_we, + output reg [1:0] pc_is_branch, + output reg pc_is_jmp, alu_not); + +`include "op_code.vh" +`include "alu_func.vh" + +function [3:0] get_alu_func(input [2:0] func, input arithmetic); + begin + case (func) + 3'b000 : get_alu_func = arithmetic ? SUB : ADD; + 3'b001 : get_alu_func = SLL; + 3'b010 : get_alu_func = SLT; + 3'b011 : get_alu_func = SLTU; + 3'b100 : get_alu_func = XOR; + 3'b101 : get_alu_func = arithmetic ? SRA : SRL; + 3'b110 : get_alu_func = OR; + 3'b111 : get_alu_func = AND; + default : get_alu_func= 4'b0000; + endcase + end +endfunction + +function [3:0] get_alu_func_imm(input [2:0] func, input arithmetic); + begin + case (func) + 3'b000 : get_alu_func_imm = ADD; + 3'b001 : get_alu_func_imm = SLL; + 3'b010 : get_alu_func_imm = SLT; + 3'b011 : get_alu_func_imm = SLTU; + 3'b100 : get_alu_func_imm = XOR; + 3'b101 : get_alu_func_imm = arithmetic ? SRA : SRL; + 3'b110 : get_alu_func_imm = OR; + 3'b111 : get_alu_func_imm = AND; + default : get_alu_func_imm = 4'b0000; + endcase + end +endfunction + +function [3:0] branch_func(input [2:0] func); + begin + case (func) + 3'b000 : branch_func = 4'b0001; + 3'b001 : branch_func = 4'b0001; + 3'b010 : branch_func = 4'b0011; + 3'b011 : branch_func = 4'b0011; + 3'b100 : branch_func = 4'b0011; + 3'b101 : branch_func = 4'b0011; + default : branch_func = 4'b0000; + endcase + end +endfunction + +function branch_not(input [2:0] func); + begin + case (func) + 3'b000 : branch_not = 1; + 3'b001 : branch_not = 0; + 3'b010 : branch_not = 0; + 3'b011 : branch_not = 1; + 3'b100 : branch_not = 0; + 3'b101 : branch_not = 1; + default : branch_not = 0; + endcase + end +endfunction + + // TODO - Manage ALU OP CODE and IMM Extension + + + always @(*) begin + case (instruction[6:2]) + OP : begin // OP - Add, ... + imm = 0; + reg_we = 1; + reg_sel_data_in = 2'b00; + reg_sel_out_a = instruction[19:15]; + reg_sel_out_b = instruction[24:20]; + reg_sel_in = instruction[11:7]; + alu_src = 0; + alu_func = get_alu_func(instruction[14:12], instruction[30]); + mem_we = 0; + pc_is_branch = 2'b00; + pc_is_jmp = 0; + alu_not = 0; + end + OP_IMM : begin // OP-IMM - Addi, ... + imm[11:0] = instruction[31:20]; + imm[31:12] = (instruction[14:12] == 3'b011 || instruction[31] == 0) ? 12'b00000000000000000000 : 12'b11111111111111111111; + reg_we = 1; + reg_sel_data_in = 2'b00; + reg_sel_out_a = instruction[19:15]; + reg_sel_out_b = 5'b00000; + reg_sel_in = instruction[11:7]; + alu_src = 1; + alu_func = get_alu_func_imm(instruction[14:12], instruction[30]); + mem_we = 0; + pc_is_branch = 2'b00; + pc_is_jmp = 0; + alu_not = 0; + end + LOAD : begin // LOAD - Lw, ... + imm[11:0] = instruction[31:20]; + imm[31:12] = (instruction[14:12] == 3'b100 || instruction[14:12] == 3'b101 || instruction[31] == 0) ? 12'b00000000000000000000 : 12'b11111111111111111111; + reg_we = 1; + reg_sel_data_in = 2'b01; + reg_sel_out_a = instruction[19:15]; + reg_sel_out_b = 5'b00000; + reg_sel_in = instruction[11:7]; + alu_src = 1; + alu_func = 3'b000; + mem_we = 0; + pc_is_branch = 2'b00; + pc_is_jmp = 0; + alu_not = 0; + end + STORE : begin // STORE - Sw, ... + imm[11:0] = {instruction[31:25], instruction[11:7]}; + imm[31:12] = (instruction[31] == 0) ? 12'b00000000000000000000 : 12'b11111111111111111111; + reg_we = 0; + reg_sel_data_in = 2'b00; + reg_sel_out_a = instruction[19:15]; + reg_sel_out_b = instruction[24:20]; + reg_sel_in = 5'b00000; + alu_src = 1; + alu_func = 3'b000; + mem_we = 1; + pc_is_branch = 2'b00; + pc_is_jmp = 0; + alu_not = 0; + end + BRANCH : begin // BRANCH - Beq, ... + imm[11:0] = {instruction[31:25], instruction[11:7]}; + imm[31:12] = (instruction[14:12] == 3'b110 || instruction[14:12] == 3'b111 || instruction[31] == 0) ? 12'b00000000000000000000 : 12'b11111111111111111111; + reg_we = 0; + reg_sel_data_in = 2'b00; + reg_sel_out_a = instruction[19:15]; + reg_sel_out_b = instruction[24:20]; + reg_sel_in = 5'b00000; + alu_src = 0; + alu_func = branch_func(instruction[14:12]); + mem_we = 0; + pc_is_branch = 2'b00; + pc_is_jmp = 1; + alu_not = branch_not(instruction[14:12]); + end + JAL : begin // JUMP - Jal + imm[19:0] = instruction[31:12]; + imm[31:20] = (instruction[31] == 0) ? 12'b000000000000 : 12'b111111111111; + reg_we = 1; + reg_sel_data_in = 2'b10; + reg_sel_out_a = 5'b00000; + reg_sel_out_b = 5'b00000; + reg_sel_in = instruction[11:7]; + alu_src = 0; + alu_func = 3'b000; + mem_we = 0; + pc_is_branch = 2'b01; + pc_is_jmp = 0; + alu_not = 0; + end + JALR : begin // JUMP REG - Jalr + imm[11:0] = instruction[31:20]; + imm[31:12] = (instruction[31] == 0) ? 12'b00000000000000000000 : 12'b11111111111111111111; + reg_we = 1; + reg_sel_data_in = 2'b10; + reg_sel_out_a = instruction[19:15]; + reg_sel_out_b = 5'b00000; + reg_sel_in = instruction[11:7]; + alu_src = 0; + alu_func = 3'b000; + mem_we = 0; + pc_is_branch = 2'b10; + pc_is_jmp = 0; + alu_not = 0; + end + LUI : begin // LUI - lui + imm = {instruction[31:12] << 12, 12'b000000000000}; + reg_we = 1; + reg_sel_data_in = 2'b00; + reg_sel_out_a = 5'b00000; + reg_sel_out_b = 5'b00000; + reg_sel_in = instruction[11:7]; + alu_src = 1; + alu_func = 3'b000; + mem_we = 0; + pc_is_branch = 2'b00; + pc_is_jmp = 0; + alu_not = 0; + end + AUIPC : begin // AUIPC - auipc + imm = {instruction[31:12] << 12, 12'b000000000000}; + reg_we = 1; + reg_sel_data_in = 2'b11; + reg_sel_out_a = 5'b00000; + reg_sel_out_b = 5'b00000; + reg_sel_in = instruction[11:7]; + alu_src = 1; + alu_func = 3'b000; + mem_we = 0; + pc_is_branch = 2'b00; + pc_is_jmp = 0; + alu_not = 0; + end + default : begin // NOP + imm = 32'b0; + reg_we = 0; + reg_sel_data_in = 2'b00; + reg_sel_out_a = 5'b00000; + reg_sel_out_b = 5'b00000; + reg_sel_in = 5'b00000; + alu_src = 0; + alu_func = 3'b000; + mem_we = 0; + pc_is_branch = 2'b00; + pc_is_jmp = 0; + alu_not = 0; + end + endcase + end + +endmodule diff --git a/rtl/instruction.v b/rtl/instruction.v new file mode 100644 index 0000000..bb76915 --- /dev/null +++ b/rtl/instruction.v @@ -0,0 +1,8 @@ +module instruction (input [31:0] address, + output [31:0] instruction); + + reg [31:0] memory [63:0]; + + assign instruction = memory[address]; + +endmodule diff --git a/rtl/memory.v b/rtl/memory.v new file mode 100644 index 0000000..d2bd7a2 --- /dev/null +++ b/rtl/memory.v @@ -0,0 +1,18 @@ +module memory (input clock, reset, + input we, + input [31:0] address, + input [31:0] data_in, + output [31:0] data_out); + + reg [63:0] memory [31:0]; + + always @(posedge clock, posedge reset) begin + if (reset == 1) + memory[0] <= 32'b0; + else if (we == 1) + memory[address] <= data_in; + end + + assign data_out = memory[address]; + +endmodule diff --git a/rtl/mux2_1.v b/rtl/mux2_1.v new file mode 100644 index 0000000..ed650c8 --- /dev/null +++ b/rtl/mux2_1.v @@ -0,0 +1,8 @@ +module mux2_1 #(parameter BUS_SIZE = 32) + (input [BUS_SIZE - 1:0] in_1, in_2, + input sel, + output [BUS_SIZE - 1:0] out); + + assign out = sel ? in_2 : in_1; + +endmodule \ No newline at end of file diff --git a/rtl/mux4_1.v b/rtl/mux4_1.v new file mode 100644 index 0000000..8e31303 --- /dev/null +++ b/rtl/mux4_1.v @@ -0,0 +1,9 @@ +module mux4_1 #(parameter BUS_SIZE = 32) + (input [BUS_SIZE - 1:0] in_1, in_2, in_3, in_4, + input [1:0] sel, + output [BUS_SIZE - 1:0] out); + + assign out = sel[1] ? (sel[0] ? in_4 : in_3) + : (sel[0] ? in_2 : in_1); + +endmodule diff --git a/rtl/op_code.vh b/rtl/op_code.vh new file mode 100644 index 0000000..437441a --- /dev/null +++ b/rtl/op_code.vh @@ -0,0 +1,9 @@ +parameter [4:0] OP = 5'b01100; +parameter [4:0] OP_IMM = 5'b00100; +parameter [4:0] LOAD = 5'b00000; +parameter [4:0] STORE = 5'b01000; +parameter [4:0] BRANCH = 5'b11000; +parameter [4:0] JAL = 5'b11011; +parameter [4:0] JALR = 5'b11001; +parameter [4:0] LUI = 5'b01101; +parameter [4:0] AUIPC = 5'b00101; diff --git a/rtl/program_counter.v b/rtl/program_counter.v new file mode 100644 index 0000000..f647764 --- /dev/null +++ b/rtl/program_counter.v @@ -0,0 +1,12 @@ +module program_counter (input clock, reset, + input [31:0] pc_new_addr, + output reg [31:0] pc_addr); + + always @ (posedge clock, posedge reset) begin + if (reset == 1'b1) + pc_addr <= 32'b0; + else + pc_addr <= pc_new_addr; + end + +endmodule diff --git a/rtl/registers_bank.v b/rtl/registers_bank.v new file mode 100644 index 0000000..31c5225 --- /dev/null +++ b/rtl/registers_bank.v @@ -0,0 +1,20 @@ +module registers_bank (input clock, reset, we, + input [4:0] sel_in, sel_out_a, sel_out_b, + input [31:0] data_in, + output [31:0] data_out_a, data_out_b); + + reg [31:0] registers[31:0]; + + assign registers[0] = 32'b0; + + always @(posedge clock, posedge reset) begin + if (reset == 1) + registers[0] <= 32'b0; + else if (we == 1 && sel_in != 5'b00000) + registers[sel_in] <= data_in; + end + + assign data_out_a = registers[sel_out_a]; + assign data_out_b = registers[sel_out_b]; + +endmodule diff --git a/rtl/risc-v_cpu.v b/rtl/risc-v_cpu.v deleted file mode 100644 index e69de29..0000000 diff --git a/rtl/risc_v_cpu.v b/rtl/risc_v_cpu.v new file mode 100644 index 0000000..7b1bdfe --- /dev/null +++ b/rtl/risc_v_cpu.v @@ -0,0 +1,112 @@ +module risc_v_cpu (input clock, reset, + output [31:0] out); + + wire [31:0] instruction; + + wire [31:0] imm; + + wire reg_we; + wire [1:0] reg_sel_data_in; + wire [4:0] reg_sel_out_a, reg_sel_out_b, reg_sel_in; + wire [31:0] reg_data_out_a, reg_data_out_b, reg_data_in; + + wire alu_src, alu_not; + wire [3:0] alu_func; + wire [31:0] alu_in_b, alu_out; + + wire mem_we; + wire [31:0] mem_out; + + wire pc_is_jmp; + wire [1:0] pc_is_branch, pc_sel_in; + wire [31:0] pc_addr, pc_new_addr; + + decoder decoder ( + .instruction(instruction), + .imm(imm), + .reg_we(reg_we), + .reg_sel_data_in(reg_sel_data_in), + .reg_sel_out_a(reg_sel_out_a), + .reg_sel_out_b(reg_sel_out_b), + .reg_sel_in(reg_sel_in), + .alu_src(alu_src), + .alu_func(alu_func), + .mem_we(mem_we), + .pc_is_branch(pc_is_branch), + .pc_is_jmp(pc_is_jmp), + .alu_not(alu_not) + ); + + registers_bank registers_bank ( + .clock(clock), + .reset(reset), + .we(reg_we), + .sel_in(reg_sel_in), + .sel_out_a(reg_sel_out_a), + .sel_out_b(reg_sel_out_b), + .data_in(reg_data_in), + .data_out_a(reg_data_out_a), + .data_out_b(reg_data_out_b) + ); + + mux2_1 mux2_alu_in_b ( + .in_1(reg_data_out_b), + .in_2(imm), + .sel(alu_src), + .out(alu_in_b) + ); + + alu alu ( + .in_a(reg_data_out_a), + .in_b(alu_in_b), + .func(alu_func), + .out(alu_out) + ); + + mux2_1 #(2) mux2_pc_sel_branch ( + .in_1(pc_is_branch), + .in_2({alu_out[1], (alu_not ? ~alu_out[0] : alu_out[0])}), + .sel(pc_is_jmp), + .out(pc_sel_in) + ); + + mux4_1 mux4_pc_sel_in ( + .in_1(pc_addr + 4), + .in_2(pc_addr + imm), + .in_3(alu_out), + .in_4(0), + .sel(pc_sel_in), + .out(pc_new_addr) + ); + + program_counter program_counter ( + .clock(clock), + .reset(reset), + .pc_new_addr(pc_new_addr), + .pc_addr(pc_addr) + ); + + instruction uut_instruction ( + .address(pc_addr), + .instruction(instruction) + ); + + memory memory ( + .clock(clock), + .reset(reset), + .we(mem_we), + .address(alu_out), + .data_in(reg_data_out_b), + .data_out(mem_out) + ); + + mux4_1 mux4_reg_sel_data_in ( + .in_1(alu_out), + .in_2(mem_out), + .in_3(pc_addr + 4), + .in_4(pc_addr + alu_out), + .sel(reg_sel_data_in), + .out(reg_data_in) + ); + +endmodule diff --git a/scripts/gen_simu_do.sh b/scripts/gen_simu_do.sh index 09aecb4..60f3f94 100755 --- a/scripts/gen_simu_do.sh +++ b/scripts/gen_simu_do.sh @@ -33,5 +33,3 @@ add wave -radix unsigned *' >> ./sim/simu.do echo 'run -all' >> ./sim/simu.do exit 0 - -# CRC - Hamming Code diff --git a/tb/tb_alu.v b/tb/tb_alu.v index c07f90a..f0f0b63 100644 --- a/tb/tb_alu.v +++ b/tb/tb_alu.v @@ -1,3 +1,203 @@ -module tb_alu (S); - output [31:0] S; -endmodule \ No newline at end of file +`timescale 1ns / 1ps +`include "tb_tools.vh" + +module tb_alu (); + `include "../rtl/alu_func.vh" + + reg [31:0] in_a; + reg [31:0] in_b; + reg [3:0] func; + wire [31:0] out; + + alu alu ( + .in_a(in_a), + .in_b(in_b), + .func(func), + .out(out) + ); + + initial begin + // ALU - add + func = ADD; + in_a = 32'b0; + in_b = 32'b0; + `assert("alu : 0 + 0", out, 0) + in_a = 32'b1; + `assert("alu : 1 + 0", out, 1) + in_b = 32'b1; + `assert("alu : 1 + 1", out, 2) + in_a = 32'b0; + `assert("alu : 0 + 1", out, 1) + in_a = 32'b1111; + in_b = 32'b1111; + `assert("alu : 15 + 15", out, 30) + in_a = 32'b11111111111111111111111111111111; + in_b = 32'b00000000000000000000000000000000; + `assert("alu : 0 + -1", out, 32'b11111111111111111111111111111111) + in_a = 32'b11111111111111111111111111111111; + in_b = 32'b00000000000000000000000000000001; + `assert("alu : 1 + -1", out, 0) + in_a = 32'b10000000000000000000000000000000; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : MIN_INT + -1", out, 32'b01111111111111111111111111111111) + + // ALU - sub + func = SUB; + in_a = 32'b0; + in_b = 32'b0; + `assert("alu : 0 - 0", out, 0) + in_a = 32'b1; + `assert("alu : 1 - 0", out, 1) + in_b = 32'b1; + `assert("alu : 1 - 1", out, 0) + in_a = 32'b0; + `assert("alu : 0 - 1", out, 32'b11111111111111111111111111111111) + in_a = 32'b11111; + in_b = 32'b1111; + `assert("alu : 31 - 15", out, 16) + in_a = 32'b11111111111111111111111111111111; + in_b = 32'b00000000000000000000000000000000; + `assert("alu : -1 - 0", out, 32'b11111111111111111111111111111111) + in_a = 32'b11111111111111111111111111111111; + in_b = 32'b00000000000000000000000000000001; + `assert("alu : -1 - 1", out, 32'b11111111111111111111111111111110) + in_a = 32'b10000000000000000000000000000000; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : MIN_INT - -1", out, 32'b10000000000000000000000000000001) + + // ALU - left shift + func = SLL; + in_a = 32'b1; + in_b = 32'b1; + `assert("alu : 1 << 1", out, 2) + in_b = 32'b10; + `assert("alu : 1 << 2", out, 4) + in_a = 32'b11; + `assert("alu : 3 << 2", out, 12) + in_b = 32'b11110; + `assert("alu : 3 << 30", out, 32'b11000000000000000000000000000000) + in_b = 32'b11111; + `assert("alu : 3 << 31", out, 32'b10000000000000000000000000000000) + in_b = 32'b100000; + `assert("alu : 3 << 31", out, 32'b00000000000000000000000000000000) + + // ALU - less than + func = SLT; + in_a = 32'b0; + in_b = 32'b0; + `assert("alu : 0 < 0", out, 0) + in_b = 32'b10; + `assert("alu : 0 << 2", out, 1) + in_a = 32'b11; + `assert("alu : 3 < 2", out, 0) + in_b = 32'b11111111111111111111111111111111; + in_a = 32'b11111111111111111111111111111111; + `assert("alu : -1 < -1", out, 0) + in_b = 32'b0; + `assert("alu : -1 < 0", out, 1) + in_a = 32'b10000000000000000000000000000000; + in_b = 32'b10000000000000000000000000000001; + `assert("alu : MIN_INT << MIN_INT + 1", out, 1) + + // ALU - xor + func = XOR; + in_a = 32'b0; + in_b = 32'b0; + `assert("alu : 0 ^ 0", out, 32'b00000000000000000000000000000000) + in_a = 32'b1; + `assert("alu : 1 ^ 0", out, 32'b00000000000000000000000000000001) + in_a = 32'b0; + in_b = 32'b1; + `assert("alu : 0 ^ 1", out, 32'b00000000000000000000000000000001) + in_a = 32'b11111111111111111111111111111111; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : MAX_INT ^ MAX_INT", out, 32'b00000000000000000000000000000000) + in_a = 32'b00000000000000000000000000000000; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : 0 ^ MAX_INT", out, 32'b11111111111111111111111111111111) + in_a = 32'b00000011001000010001000011000000; + in_b = 32'b10101111001011101110111111111011; + `assert("alu : 00000011001000010001000011000000 ^ 10101111001011101110111111111011", out, 32'b10101100000011111111111100111011) + + // ALU - right shift + func = SRL; + in_a = 32'b1; + in_b = 32'b1; + `assert("alu : 1 >> 1", out, 0) + in_a = 32'b10; + `assert("alu : 2 >> 1", out, 1) + in_a = 32'b11; + `assert("alu : 3 >> 2", out, 1) + in_a = 32'b11110; + in_b = 32'b1; + `assert("alu : 30 >> 1", out, 32'b1111) + in_a = 32'b10000000000000000000000000000000; + in_b = 32'b11111; + `assert("alu : 1000...000 >> 31", out, 32'b00000000000000000000000000000001) + in_a = 32'b10000000111100000000000111111111; + in_b = 32'b11111; + `assert("alu : 1000..111 >> 31", out, 32'b00000000000000000000000000000001) + + // ALU - arithmetic right shift + func = SRA; + in_a = 32'b1; + in_b = 32'b1; + `assert("alu : 1 >>> 1", out, 0) + in_a = 32'b10; + `assert("alu : 2 >>> 1", out, 1) + in_a = 32'b11; + `assert("alu : 3 >>> 2", out, 1) + in_a = 32'b11110; + in_b = 32'b1; + `assert("alu : 30 >>> 1", out, 32'b1111) + in_a = 32'b10000000000000000000000000000000; + in_b = 32'b11111; + `assert("alu : 1000...000 >>> 31", out, 32'b11111111111111111111111111111111) + in_a = 32'b10000000111100000000000111111111; + in_b = 32'b11111; + `assert("alu : 1000..111 >>> 31", out, 32'b11111111111111111111111111111111) + + // ALU - or + func = OR; + in_a = 32'b0; + in_b = 32'b0; + `assert("alu : 0 | 0", out, 32'b00000000000000000000000000000000) + in_a = 32'b1; + `assert("alu : 1 | 0", out, 32'b00000000000000000000000000000001) + in_a = 32'b0; + in_b = 32'b1; + `assert("alu : 0 | 1", out, 32'b00000000000000000000000000000001) + in_a = 32'b11111111111111111111111111111111; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : MAX_INT | MAX_INT", out, 32'b11111111111111111111111111111111) + in_a = 32'b00000000000000000000000000000000; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : 0 | MAX_INT", out, 32'b11111111111111111111111111111111) + in_a = 32'b00000011001000010001000011000000; + in_b = 32'b10101111001011101110111111111011; + `assert("alu : 00000011001000010001000011000000 | 10101111001011101110111111111011", out, 32'b10101111001011111111111111111011) + + // ALU - and + func = AND; + in_a = 32'b0; + in_b = 32'b0; + `assert("alu : 0 & 0", out, 32'b00000000000000000000000000000000) + in_a = 32'b1; + `assert("alu : 1 & 0", out, 32'b00000000000000000000000000000000) + in_a = 32'b0; + in_b = 32'b1; + `assert("alu : 0 & 1", out, 32'b00000000000000000000000000000000) + in_a = 32'b11111111111111111111111111111111; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : MAX_INT & MAX_INT", out, 32'b11111111111111111111111111111111) + in_a = 32'b00000000000000000000000000000000; + in_b = 32'b11111111111111111111111111111111; + `assert("alu : 0 & MAX_INT", out, 32'b00000000000000000000000000000000) + in_a = 32'b00000011001000010001000011000000; + in_b = 32'b10101111001011101110111111111011; + `assert("alu : 00000011001000010001000011000000 & 10101111001011101110111111111011", out, 32'b00000011001000000000000011000000) + + `end_message + end + +endmodule : tb_alu diff --git a/tb/tb_mux2_1.v b/tb/tb_mux2_1.v new file mode 100644 index 0000000..4e736d7 --- /dev/null +++ b/tb/tb_mux2_1.v @@ -0,0 +1,39 @@ +`timescale 1ns / 1ps +`include "tb_tools.vh" + +module tb_mux2_1 (); + + reg sel; + reg [31:0] in_1; + reg [31:0] in_2; + wire [31:0] out; + + mux2_1 mux ( + .in_1(in_1), + .in_2(in_2), + .sel(sel), + .out(out) + ); + + initial begin + in_1 = 1'b0; + in_2 = 1'b0; + sel = 1'b0; + `assert("mux in_1: 0, in_2: 0, sel: 0", out, 0) + in_1 = 1'b1; + `assert("mux in_1: 1, in_2: 0, sel: 0", out, 1) + sel = 1'b1; + `assert("mux in_1: 1, in_2: 0, sel: 1", out, 0) + in_2 = 1'b1; + `assert("mux in_1: 1, in_2: 1, sel: 1", out, 1) + in_1 = 1'b0; + `assert("mux in_1: 0, in_2: 1, sel: 1", out, 1) + in_2 = 1'b0; + `assert("mux in_1: 0, in_2: 0, sel: 1", out, 0) + sel = 1'b0; + `assert("mux in_1: 0, in_2: 0, sel: 0", out, 0) + + `end_message + end + +endmodule : tb_mux2_1 diff --git a/tb/tb_mux4_1.v b/tb/tb_mux4_1.v new file mode 100644 index 0000000..078dd32 --- /dev/null +++ b/tb/tb_mux4_1.v @@ -0,0 +1,53 @@ +`timescale 1ns / 1ps +`include "tb_tools.vh" + +module tb_mux4_1 (); + + reg [1:0] sel; + reg [31:0] in_1; + reg [31:0] in_2; + reg [31:0] in_3; + reg [31:0] in_4; + wire [31:0] out; + + mux4_1 mux ( + .in_1(in_1), + .in_2(in_2), + .in_3(in_3), + .in_4(in_4), + .sel(sel), + .out(out) + ); + + initial begin + in_1 = 1'b0; + in_2 = 1'b0; + in_3 = 1'b0; + in_4 = 1'b0; + sel = 2'b00; + `assert("mux in_1: 0, in_2: 0, in_3: 0, in_4: 0, sel: 0", out, 0) + in_1 = 1'b1; + `assert("mux in_1: 1, in_2: 0, in_3: 0, in_4: 0, sel: 0", out, 1) + sel = 2'b01; + `assert("mux in_1: 1, in_2: 0, in_3: 0, in_4: 0, sel: 1", out, 0) + in_2 = 1'b1; + `assert("mux in_1: 1, in_2: 1, in_3: 0, in_4: 0, sel: 1", out, 1) + sel = 2'b10; + `assert("mux in_1: 1, in_2: 0, in_3: 0, in_4: 0, sel: 2", out, 0) + in_3 = 1'b1; + `assert("mux in_1: 1, in_2: 1, in_3: 1, in_4: 0, sel: 2", out, 1) + sel = 2'b11; + `assert("mux in_1: 1, in_2: 0, in_3: 1, in_4: 0, sel: 3", out, 0) + in_4 = 1'b1; + `assert("mux in_1: 1, in_2: 1, in_3: 1, in_4: 1, sel: 3", out, 1) + in_1 = 1'b0; + `assert("mux in_1: 0, in_2: 1, in_3: 1, in_4: 1, sel: 1", out, 1) + in_2 = 1'b0; + `assert("mux in_1: 0, in_2: 0, in_3: 1, in_4: 1, sel: 1", out, 1) + sel = 2'b00; + `assert("mux in_1: 0, in_2: 0, in_3: 1, in_4: 1, sel: 0", out, 0) + + `end_message + end + +endmodule : tb_mux4_1 diff --git a/tb/tb_registers_bank.v b/tb/tb_registers_bank.v new file mode 100644 index 0000000..599b27b --- /dev/null +++ b/tb/tb_registers_bank.v @@ -0,0 +1,75 @@ +`timescale 1ns / 1ps +`include "tb_tools.vh" + +module tb_registers_bank (); + reg clk; + reg reset; + integer i; + reg we; + reg [4:0] sel_in; + reg [4:0] sel_out_a; + reg [4:0] sel_out_b; + reg [31:0] data_in; + wire [31:0] data_out_a; + wire [31:0] data_out_b; + + registers_bank registers_bank ( + .clock(clk), + .reset(reset), + .we(we), + .sel_in(sel_in), + .sel_out_a(sel_out_a), + .sel_out_b(sel_out_b), + .data_in(data_in), + .data_out_a(data_out_a), + .data_out_b(data_out_b) + ); + + initial begin + reset = 1'b1; + #10 + reset = 1'b0; + end + + initial begin + clk = 1'b0; + for (i = 0; i < 100; i = i + 1) begin + #1 clk = ~clk; + end + end + + initial begin + + we = 1'b0; + sel_in = 5'b00000; + sel_out_a = 5'b00000; + sel_out_b = 5'b00000; + data_in = 32'b0; + `assert("registers_bank we: 0, sel_in: 0, sel_out_a: 0, sel_out_b: 0, data_in: 0", data_out_a, 0) + we = 1'b1; + data_in = 32'b1; + `assert("registers_bank we: 1, sel_in: 0, sel_out_a: 0, sel_out_b: 0, data_in: 1", data_out_a, 0) + sel_in = 5'b00001; + `assert("registers_bank we: 1, sel_in: 1, sel_out_a: 0, sel_out_b: 0, data_in: 1", data_out_a, 0) + sel_out_a = 5'b00001; + `assert("registers_bank we: 1, sel_in: 1, sel_out_a: 1, sel_out_b: 0, data_in: 1", data_out_a, 1) + `assert("registers_bank we: 1, sel_in: 1, sel_out_a: 1, sel_out_b: 0, data_in: 1", data_out_b, 0) + sel_out_b = 5'b00001; + `assert("registers_bank we: 1, sel_in: 1, sel_out_a: 1, sel_out_b: 1, data_in: 1", data_out_b, 1) + we = 1'b0; + data_in = 32'b11; + `assert("registers_bank we: 0, sel_in: 1, sel_out_a: 1, sel_out_b: 1, data_in: 3", data_out_a, 1) + `assert("registers_bank we: 0, sel_in: 1, sel_out_a: 1, sel_out_b: 1, data_in: 3", data_out_b, 1) + data_in = 32'b111; + sel_in = 5'b11111; + sel_out_a = 5'b11111; + we = 1'b1; + `assert("registers_bank we: 1, sel_in: 31, sel_out_a: 31, sel_out_b: 1, data_in: 7", data_out_a, 7) + `assert("registers_bank we: 1, sel_in: 31, sel_out_a: 31, sel_out_b: 1, data_in: 7", data_out_b, 1) + + `end_message + end + + + +endmodule : tb_registers_bank diff --git a/tb/tb_risc-v_cpu.v b/tb/tb_risc-v_cpu.v deleted file mode 100644 index e69de29..0000000 diff --git a/tb/tb_risc_v_cpu.v b/tb/tb_risc_v_cpu.v new file mode 100644 index 0000000..0c0da1a --- /dev/null +++ b/tb/tb_risc_v_cpu.v @@ -0,0 +1,166 @@ +`timescale 1ns / 1ps +`include "tb_tools.vh" + +module tb_risc_v_cpu (); + reg clk; + reg reset; + integer i; + wire [31:0] out; + + risc_v_cpu risc_v_cpu ( + .clock(clk), + .reset(reset), + .out(out) + ); + + initial begin + /* Reset */ + reset = 1'b1; + #10 + reset = 1'b0; + + clk = 1'b0; + + /* Fibonacci */ + + /* ADDi $1, R[0], R[6] - R[6] = 1 */ + /* "000000000001_00000_000_00110_0010000" */ + risc_v_cpu.uut_instruction.memory[0] = 32'b00000000000100000000001100010000; + + /* ADDi $0, R[0], R[7] - R[7] = 0 */ + /* "000000000000_00000_000_00111_0010000" */ + risc_v_cpu.uut_instruction.memory[4] = 32'b00000000000000000000001110010000; + + /* ADDi $0, R[6], R[8] - R[8] = R[6] */ + /* "000000000000_00110_000_01000_0010000" */ + risc_v_cpu.uut_instruction.memory[8] = 32'b00000000000000110000010000010000; + + /* ADD R[7], R[6], R[6] - R[6] = R[7] + R[6] */ + /* "0000000_00111_00110_000_00110_0110000" */ + risc_v_cpu.uut_instruction.memory[12] = 32'b00000000011100110000001100110000; + + /* ADDi $0, R[8], R[7] - R[7] = R[8] */ + /* "000000000000_01000_000_00111_0010000" */ + risc_v_cpu.uut_instruction.memory[16] = 32'b00000000000001000000001110010000; + + /* JUMP - 12 */ + /* 11111111111111111101_00111_1101100 */ + risc_v_cpu.uut_instruction.memory[20] = 32'b11111111111111110100001011101100; + + `next_cycle + `assert_no_wait("FIBO INIT: ADDi $1, R[0], R[6] - R[6] = 1", risc_v_cpu.registers_bank.registers[6], 1) + `next_cycle + `assert_no_wait("FIBO INIT: ADDi $0, R[0], R[7] - R[7] = 0", risc_v_cpu.registers_bank.registers[7], 0) + `next_cycle + `assert_no_wait("FIBO CYCLE 1: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 1) + `next_cycle + `assert_no_wait("FIBO CYCLE 1: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 1) + `next_cycle + `assert_no_wait("FIBO CYCLE 1: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 1) + `next_cycle + `assert_no_wait("FIBO VALUE 1: 1", risc_v_cpu.registers_bank.registers[7], 1) + `assert_no_wait("FIBO CYCLE 1: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 2: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 1) + `next_cycle + `assert_no_wait("FIBO CYCLE 2: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 2) + `next_cycle + `assert_no_wait("FIBO CYCLE 2: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 1) + `next_cycle + `assert_no_wait("FIBO VALUE 2: 1", risc_v_cpu.registers_bank.registers[7], 1) + `assert_no_wait("FIBO CYCLE 2: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 3: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 2) + `next_cycle + `assert_no_wait("FIBO CYCLE 3: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 3) + `next_cycle + `assert_no_wait("FIBO CYCLE 3: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 2) + `next_cycle + `assert_no_wait("FIBO VALUE 3: 2", risc_v_cpu.registers_bank.registers[7], 2) + `assert_no_wait("FIBO CYCLE 3: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 4: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 3) + `next_cycle + `assert_no_wait("FIBO CYCLE 4: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 5) + `next_cycle + `assert_no_wait("FIBO CYCLE 4: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 3) + `next_cycle + `assert_no_wait("FIBO VALUE 4: 3", risc_v_cpu.registers_bank.registers[7], 3) + `assert_no_wait("FIBO CYCLE 4: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 5: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 5) + `next_cycle + `assert_no_wait("FIBO CYCLE 5: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 5: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 5) + `next_cycle + `assert_no_wait("FIBO VALUE 5: 5", risc_v_cpu.registers_bank.registers[7], 5) + `assert_no_wait("FIBO CYCLE 5: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 6: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 6: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 13) + `next_cycle + `assert_no_wait("FIBO CYCLE 6: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 8) + `next_cycle + `assert_no_wait("FIBO VALUE 6: 8", risc_v_cpu.registers_bank.registers[7], 8) + `assert_no_wait("FIBO CYCLE 6: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 7: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 13) + `next_cycle + `assert_no_wait("FIBO CYCLE 7: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 21) + `next_cycle + `assert_no_wait("FIBO CYCLE 7: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 13) + `next_cycle + `assert_no_wait("FIBO VALUE 7: 13", risc_v_cpu.registers_bank.registers[7], 13) + `assert_no_wait("FIBO CYCLE 7: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 8: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 21) + `next_cycle + `assert_no_wait("FIBO CYCLE 8: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 34) + `next_cycle + `assert_no_wait("FIBO CYCLE 8: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 21) + `next_cycle + `assert_no_wait("FIBO VALUE 8: 21", risc_v_cpu.registers_bank.registers[7], 21) + `assert_no_wait("FIBO CYCLE 8: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 9: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 34) + `next_cycle + `assert_no_wait("FIBO CYCLE 9: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 55) + `next_cycle + `assert_no_wait("FIBO CYCLE 9: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 34) + `next_cycle + `assert_no_wait("FIBO VALUE 9: 34", risc_v_cpu.registers_bank.registers[7], 34) + `assert_no_wait("FIBO CYCLE 9: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 10: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 55) + `next_cycle + `assert_no_wait("FIBO CYCLE 10: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 89) + `next_cycle + `assert_no_wait("FIBO CYCLE 10: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 55) + `next_cycle + `assert_no_wait("FIBO VALUE 10: 55", risc_v_cpu.registers_bank.registers[7], 55) + `assert_no_wait("FIBO CYCLE 10: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 11: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 89) + `next_cycle + `assert_no_wait("FIBO CYCLE 11: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 144) + `next_cycle + `assert_no_wait("FIBO CYCLE 11: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 89) + `next_cycle + `assert_no_wait("FIBO VALUE 11: 89", risc_v_cpu.registers_bank.registers[7], 89) + `assert_no_wait("FIBO CYCLE 11: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + `next_cycle + `assert_no_wait("FIBO CYCLE 12: ADDi $0, R[6], R[8] - R[8] = R[6]", risc_v_cpu.registers_bank.registers[8], 144) + `next_cycle + `assert_no_wait("FIBO CYCLE 12: ADD R[7], R[6], R[6] - R[6] = R[7] + R[6]", risc_v_cpu.registers_bank.registers[6], 233) + `next_cycle + `assert_no_wait("FIBO CYCLE 12: ADDi $0, R[8], R[7] - R[7] = R[8]", risc_v_cpu.registers_bank.registers[7], 144) + `next_cycle + `assert_no_wait("FIBO VALUE 12: 144", risc_v_cpu.registers_bank.registers[7], 144) + `assert_no_wait("FIBO CYCLE 12: JUMP - 12", risc_v_cpu.program_counter.pc_addr, 8) + + `end_message + end + +endmodule : tb_risc_v_cpu diff --git a/tb/tb_tools.vh b/tb/tb_tools.vh new file mode 100644 index 0000000..5c39e75 --- /dev/null +++ b/tb/tb_tools.vh @@ -0,0 +1,16 @@ +`define assert(message, expected, got) \ + #4 \ + if(expected !== got) begin \ + $display("\033[0;31m[FAILED]\033[0m : %s - got: %d, expected: %d", message, expected, got); \ + end + +`define assert_no_wait(message, expected, got) \ + if(expected !== got) begin \ + $display("\033[0;31m[FAILED]\033[0m : %s - got: %d, expected: %d", message, expected, got); \ + end + +`define end_message $display("\033[0;32mIf no \033[0m[FAILED]\033[0;32m messages, all tests passed!\033[0m"); + +`define next_cycle \ + #1 clk = ~clk; \ + #1 clk = ~clk; \ No newline at end of file