Skip to content

Commit 3da9820

Browse files
authored
docs(dn): Noah MS 10-5-25 (#406)
* Update alu_tb.v * add alu.v * add: reg_file_tb.v * docs(dn): Noah MS 10-5-25
1 parent c2f3364 commit 3da9820

File tree

3 files changed

+316
-0
lines changed

3 files changed

+316
-0
lines changed

src/design_notebooks/2025fall/nm4207.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,15 @@ a page on the website dedicated to the RiSC-16 project, so that everyone can acc
2323
Did presentation and made alu.v and alu_tb.v
2424
### Comments:
2525
none
26+
27+
## Week 4:
28+
### This week I:
29+
- Completed the testbench and module for the register file
30+
- Completed Github presentation with Darren
31+
- Kept tabs on some groups falling behind to catch them up to speed
32+
### Comments:
33+
- I was quite busy this week, and had trouble completing the testbench for the register file. I'm a little concerned that it isn't 100% accurate, or that it isn't in line with the exact specifications in the RiSC-16 Info Sheets
34+
- I decided not too assign any new work this week, and instead have people catch up, and show me their designs functioning with my testbench. I want to discuss their thought process while designing their modules, and also describe how I go about making the testbench.
35+
- There was no slideshow this week because there was no new module to make.
36+
- I don't yet know what to choose for the next module, but I will figure that out in the next few days.
37+
- For the next module, I am considering writing the module and then having the groups write a testbench for it to make sure that it functions properly.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
module alu (
2+
input MUX_alu1, MUX_alu2, // Controlled by Control module. 0-src_reg, 1-alternate input
3+
input [1:0] FUNC_alu, // Controlled by Control module. 00-ADD, 01-NAND, 10-PASS1, 11-EQL
4+
input [15:0] src1_reg, src2_reg, // The two inputs from the register file
5+
input [9:0] imm, // 10 bits from immediate. Only 7 used for the sign-extend-7 value
6+
output reg EQ, // EQ! bit output for BEQ instruction
7+
output reg [15:0] alu_out // Function output
8+
);
9+
10+
11+
wire [15:0] se_imm, ls_imm;
12+
wire [15:0] SRC1, SRC2;
13+
14+
assign se_imm = {{9{imm[6]}}, imm[6:0]}; // Sign extends the least significant 7 bits from immediate value to 16 digits
15+
assign ls_imm = imm << 6; // Left shifts the full 10 digits of immediate value and fills the rest with 0's
16+
17+
assign SRC1 = MUX_alu1 ? ls_imm : src1_reg; // Chooses the input to SRC1
18+
assign SRC2 = MUX_alu2 ? se_imm : src2_reg; // Chooses the input for SRC2
19+
20+
always @(*)
21+
begin
22+
alu_out = 16'h0000;
23+
EQ = (SRC1 == SRC2);
24+
case (FUNC_alu)
25+
2'b00: // Add SRC1 and SRC2 (ADD/ADDI/LW/SW)
26+
begin
27+
alu_out = SRC1 + SRC2;
28+
end
29+
2'b01: // bitwise NAND operation (NAND)
30+
begin
31+
alu_out = ~(SRC1 & SRC2);
32+
end
33+
2'b10: // PASS1 operation (LUI/JALR)
34+
begin
35+
alu_out = SRC1;
36+
end
37+
2'b11: // EQ! operation (BEQ)
38+
begin
39+
alu_out = 16'b0;
40+
end
41+
default: // Default case
42+
begin
43+
alu_out = 16'b0;
44+
EQ = 1'b0;
45+
end
46+
endcase
47+
end
48+
endmodule
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
`timescale 1ns / 1ps
2+
3+
module register_file_tb;
4+
5+
// Inputs
6+
reg clk;
7+
reg [1:0] MUX_tgt; // 00:mem_out 01:alu_out 10:pc+1
8+
reg MUX_rf; // 0:rC(ADD/NAND) 1:rA(SW/BEQ)
9+
reg WE_rf; // 0:SW/BEQ 1:ADD/ADDI/NAND/LUI/LW/JALR
10+
reg [15:0] mem_out, alu_out, pc, instruction;
11+
12+
// Outputs
13+
wire [15:0] reg_out1, reg_out2;
14+
15+
// Instantiate the Unit Under Test (UUT)
16+
register_file uut (
17+
.clk(clk),
18+
.MUX_tgt(MUX_tgt),
19+
.MUX_rf(MUX_rf),
20+
.WE_rf(WE_rf),
21+
.mem_out(mem_out),
22+
.alu_out(alu_out),
23+
.pc(pc),
24+
.instruction(instruction),
25+
.reg_out1(reg_out1),
26+
.reg_out2(reg_out2)
27+
);
28+
29+
// --- Clock Generator ---
30+
initial begin
31+
clk = 0;
32+
end
33+
always begin
34+
#5 clk = ~clk;
35+
end
36+
37+
// --- Verification Task ---
38+
task check_and_print_regs;
39+
input [15:0] exp_r0, exp_r1, exp_r2, exp_r3, exp_r4, exp_r5, exp_r6, exp_r7;
40+
reg [15:0] expected_regs [0:7];
41+
integer i;
42+
integer errors;
43+
44+
begin
45+
expected_regs[0] = exp_r0; expected_regs[1] = exp_r1; expected_regs[2] = exp_r2;
46+
expected_regs[3] = exp_r3; expected_regs[4] = exp_r4; expected_regs[5] = exp_r5;
47+
expected_regs[6] = exp_r6; expected_regs[7] = exp_r7;
48+
49+
errors = 0;
50+
$display(" -> Verifying all register values...");
51+
for (i = 0; i < 8; i = i + 1) begin
52+
if (uut.register_file[i] !== expected_regs[i]) begin
53+
$display(" R%0d: Expected=%h, Actual=%h <-- MISMATCH", i, expected_regs[i], uut.register_file[i]);
54+
errors = errors + 1;
55+
end else begin
56+
$display(" R%0d: Expected=%h, Actual=%h", i, expected_regs[i], uut.register_file[i]);
57+
end
58+
end
59+
60+
if (errors == 0) $display(">> PASSED: All register values are correct.");
61+
else $display(">> FAILED: %0d register value(s) are incorrect.", errors);
62+
end
63+
endtask
64+
65+
// --- Test Sequence ---
66+
initial begin
67+
$display("Starting Official RiSC-16 Register File Testbench...");
68+
69+
// 1. Initialize all inputs.
70+
WE_rf <= 0; MUX_tgt <= 2'bxx; MUX_rf <= 1'bx; instruction <= 16'h0000;
71+
alu_out <= 16'h0000; mem_out <= 16'h0000; pc <= 16'h0000;
72+
@(posedge clk); @(posedge clk);
73+
74+
// TEST 2: Check initial state (all zeros).
75+
$display("\n[TEST] Verifying initial register state...");
76+
@(posedge clk); @(posedge clk);
77+
check_and_print_regs(16'h0, 16'h0, 16'h0, 16'h0, 16'h0, 16'h0, 16'h0, 16'h0);
78+
79+
// TEST 3: LUI (op:011) write 0xE380 to R1.
80+
$display("\n[TEST] LUI writing 0xE380 to R1...");
81+
WE_rf <= 1; MUX_tgt <= 2'b01; MUX_rf <= 0; alu_out <= 16'hE380; // Assume ALU left shifts imm-10 by 6. MUX_rf val doesn't matter
82+
// instr: op=011, rA=R1, imm=10b1110001110 = 10'h38E: This value shifts to 1110001110_000000 = 16'hE380 = 58240
83+
instruction <= 16'b011_001_1110001110;
84+
@(posedge clk); @(posedge clk);
85+
check_and_print_regs(16'h0, 16'hE380, 16'h0, 16'h0, 16'h0, 16'h0, 16'h0, 16'h0);
86+
87+
88+
89+
// TEST 4: ADDI (op:001) add 7'b1110001 to R1.
90+
$display("\n[TEST] ADDI adding 7'b1110001 to R1 and store in R3");
91+
WE_rf <= 1; MUX_tgt <= 2'b01; MUX_rf <= 1; // Assume ALU computes rB(R1) + imm. MUX_rf val doesn't matter
92+
// instr: op=001, rA=R3, rB=R1, imm = 7'd113/7'h71
93+
instruction <= 16'b001_011_001_1110001;
94+
alu_out <= 16'hE3F1; // 16'hE380 + 7'h71 = 58240 + 113 = 58353 = 16'hE3F1
95+
@(posedge clk); @(posedge clk);
96+
97+
// Check SRC1 is correct val
98+
$display("\n[TEST OUTPUT] reg_out1 should be contents of rB/R1: 16'hE380");
99+
if(reg_out1 == 16'hE380) begin
100+
$display("\n[TEST PASSED]");
101+
end else begin
102+
$display("\n[TEST FAILED] reg_out1 contains %h", reg_out1);
103+
end
104+
// Check regs
105+
check_and_print_regs(16'h0, 16'hE380, 16'h0, 16'hE3F1, 16'h0, 16'h0, 16'h0, 16'h0);
106+
107+
108+
109+
// TEST 5: ADD (op:000) attempt to ADD to R0. SHOULD HAVE NO EFFECT
110+
$display("\n[TEST] ADD adding R1 and R3 to R0 (should have no effect)");
111+
WE_rf <= 1; MUX_tgt <= 2'b01; alu_out <= 16'hC771;
112+
MUX_rf <= 0; //MUX_rf chooses the output of rC for the second input
113+
// instr: op=000, rA=R0, rB=R1, rC=R3
114+
instruction <= 16'b000_000_001_0000_011;
115+
@(posedge clk);
116+
@(posedge clk);
117+
// Check SRC1 is correct val
118+
$display("\n[TEST OUTPUT 1] reg_out1 should be contents of rB/R1: 16'hE380");
119+
if(reg_out1 == 16'hE380) begin
120+
$display("[TEST PASSED]");
121+
end else begin
122+
$display("[TEST FAILED] reg_out1 contains %h", reg_out1);
123+
end
124+
// Check SRC2 is correct val
125+
$display("\n[TEST OUTPUT 2] reg_out2 should be contents of rC/R3: 16'hE3F1");
126+
if(reg_out2 == 16'hE3F1) begin
127+
$display("[TEST PASSED]");
128+
end else begin
129+
$display("[TEST FAILED] reg_out2 contains %h", reg_out2);
130+
end
131+
check_and_print_regs(16'h0, 16'hE380, 16'h0000, 16'hE3F1, 16'h0, 16'h0, 16'h0, 16'h0);
132+
133+
134+
135+
// TEST 6: NAND (op:010) R1 and R3, store in R5
136+
$display("\n[TEST] NAND R1 and R3, store in R5");
137+
WE_rf <= 1; MUX_tgt <= 2'b01;
138+
MUX_rf <= 0; //MUX_rf chooses the output of rC for the second input
139+
// instr: op=010, rA=R5, rB=R1, rC=R3
140+
instruction <= 16'b010_101_001_0000_011;
141+
alu_out <= ~(16'hE380 & 16'hE3F1); // Result is ~(16'hE380) = 16'h1C7F
142+
@(posedge clk); @(posedge clk);
143+
// Check SRC1 is correct val
144+
$display("\n[TEST OUTPUT 1] reg_out1 should be contents of rB/R1: 16'hE380");
145+
if(reg_out1 == 16'hE380) begin
146+
$display("[TEST PASSED]");
147+
end else begin
148+
$display("[TEST FAILED] reg_out1 contains %h", reg_out1);
149+
end
150+
// Check SRC2 is correct val
151+
$display("\n[TEST OUTPUT 2] reg_out2 should be contents of rC/R3: 16'hE3F1");
152+
if(reg_out2 == 16'hE3F1) begin
153+
$display("[TEST PASSED]");
154+
end else begin
155+
$display("[TEST FAILED] reg_out2 contains %h", reg_out2);
156+
end
157+
check_and_print_regs(16'h0, 16'hE380, 16'h0, 16'hE3F1, 16'h0, 16'h1C7F, 16'h0, 16'h0);
158+
159+
160+
161+
// TEST 7: LW (op:100) write 0xBEEF from memory to R6 (dest:rA).
162+
$display("\n[TEST] LW writing 0xBEEF to R6...");
163+
WE_rf <= 1; MUX_tgt <= 2'b00; mem_out <= 16'hBEEF; //16'hBEEF is hypothetical val at mem loc [rB] + imm
164+
// instr: op=100, rA=R6, rB=R5
165+
instruction <= 16'b100_110_101_0001110; // Loads instruction from memory location [rB] + imm
166+
@(posedge clk); @(posedge clk);
167+
// Check SRC1 is correct val
168+
$display("\n[TEST OUTPUT 1] reg_out1 should be contents of rB/R5: 16'h1C7F");
169+
if(reg_out1 == 16'h1C7F) begin
170+
$display("[TEST PASSED]");
171+
end else begin
172+
$display("[TEST FAILED] reg_out1 contains %h", reg_out1);
173+
end
174+
check_and_print_regs(16'h0, 16'hE380, 16'h0, 16'hE3F1, 16'h0, 16'h1C7F, 16'hBEEF, 16'h0);
175+
176+
177+
178+
179+
// TEST 8: SW (op:101) Write Inhibit test. Should NOT change any registers.
180+
// reg_out1 should be the value in rB, reg_out2 should be the value in rA to be sent to memory
181+
$display("\n[TEST] SW Write Inhibit. Should not change registers...");
182+
MUX_rf <= 1; WE_rf <= 0; // For SW
183+
MUX_tgt <= 2'b00; //doesn't matter
184+
// instr: op=101, rA=R5 (source), rB=R3, Random imm val
185+
instruction <= 16'b101_101_011_0000111; // Storing [R5] in mem loc [R3] + imm
186+
@(posedge clk); @(posedge clk);
187+
// Check SRC1 is correct val
188+
$display("\n[TEST OUTPUT 1] reg_out1 should be contents of rB/R3: 16'hE3F1");
189+
if(reg_out1 == 16'hE3F1) begin
190+
$display("[TEST PASSED]");
191+
end else begin
192+
$display("[TEST FAILED] reg_out1 contains %h", reg_out1);
193+
end
194+
// Check SRC2 is correct val
195+
$display("\n[TEST OUTPUT 2] reg_out2 should be contents of rA/R5: 16'h1C7F");
196+
if(reg_out2 == 16'h1C7F) begin
197+
$display("[TEST PASSED]");
198+
end else begin
199+
$display("[TEST FAILED] reg_out2 contains %h", reg_out2);
200+
end
201+
check_and_print_regs(16'h0, 16'hE380, 16'h0, 16'hE3F1, 16'h0, 16'h1C7F, 16'hBEEF, 16'h0);
202+
203+
204+
205+
// TEST 9: JALR (op:111) write PC+1 to R7 (dest:rA).
206+
// reg_out1 should be [rB]
207+
// pc+1 stored in rA
208+
$display("\n[TEST] JALR writing PC+1 (0xF00E) to R7...");
209+
WE_rf <= 1; MUX_tgt <= 2'b10; pc <= 16'hF00D;
210+
// instr: op=111, rA=R7, rB= R1
211+
instruction <= 16'b111_111_001_0000000;
212+
@(posedge clk); @(posedge clk);
213+
// Check SRC1 is correct val
214+
$display("\n[TEST OUTPUT 1] reg_out1 should be contents of rB/R1: 16'hE380");
215+
if(reg_out1 == 16'hE380) begin
216+
$display("[TEST PASSED]");
217+
end else begin
218+
$display("[TEST FAILED] reg_out1 contains %h", reg_out1);
219+
end
220+
check_and_print_regs(16'h0, 16'hE380, 16'h0, 16'hE3F1, 16'h0, 16'h1C7F, 16'hBEEF, 16'hF00E);
221+
222+
223+
224+
// TEST 10: BEQ (op:110) Write Inhibit test. Should NOT change any registers.
225+
// reg_out1 should be [rA], reg_out2 should be [rB]
226+
$display("\n[TEST] BEQ Write Inhibit. Should not change registers...");
227+
MUX_tgt <= 2'b01; // Doesn't matter
228+
MUX_rf <= 1; //For BEQ
229+
WE_rf <= 0; // For BEQ
230+
// instr: op=110, rA=R1 (source), rB=R3 (source)
231+
instruction <= 16'b110_001_011_0000000;
232+
@(posedge clk); @(posedge clk);
233+
// Check SRC1 is correct val
234+
$display("\n[TEST OUTPUT 1] reg_out1 should be contents of rB/R3: 16'hE3F1");
235+
if(reg_out1 == 16'hE3F1) begin
236+
$display("[TEST PASSED]");
237+
end else begin
238+
$display("[TEST FAILED] reg_out1 contains %h", reg_out1);
239+
end
240+
// Check SRC2 is correct val
241+
$display("\n[TEST OUTPUT 2] reg_out2 should be contents of rA/R1: 16'hE380");
242+
if(reg_out2 == 16'hE380) begin
243+
$display("[TEST PASSED]");
244+
end else begin
245+
$display("[TEST FAILED] reg_out2 contains %h", reg_out2);
246+
end
247+
check_and_print_regs(16'h0, 16'hE380, 16'h0, 16'hE3F1, 16'h0, 16'h1C7F, 16'hBEEF, 16'hF00E);
248+
249+
250+
251+
#20;
252+
$display("\nAll tests completed.");
253+
$finish;
254+
end
255+
endmodule
256+

0 commit comments

Comments
 (0)