summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rtl/tb_lisp_coproc.sv348
1 files changed, 254 insertions, 94 deletions
diff --git a/rtl/tb_lisp_coproc.sv b/rtl/tb_lisp_coproc.sv
index aa721fc..08e3627 100644
--- a/rtl/tb_lisp_coproc.sv
+++ b/rtl/tb_lisp_coproc.sv
@@ -2,52 +2,82 @@
2 2
3module tb_lisp_coproc; 3module tb_lisp_coproc;
4 4
5 // Signals 5 // ========================================================================
6 // 1. CONFIGURATION & CONSTANTS
7 // ========================================================================
8
9 // Opcodes
10 localparam [7:0] OP_CONS = 8'h01;
11 localparam [7:0] OP_CAR = 8'h02;
12 localparam [7:0] OP_CDR = 8'h03;
13 localparam [7:0] OP_ATOM = 8'h04;
14 localparam [7:0] OP_EQ = 8'h05;
15 localparam [7:0] OP_ADD = 8'h06;
16
17 // Tags
18 localparam [1:0] TAG_NIL = 2'b00;
19 localparam [1:0] TAG_ATOM = 2'b01;
20 localparam [1:0] TAG_NUM = 2'b10;
21 localparam [1:0] TAG_CONS = 2'b11;
22
23 // Standard Values for Testing
24 localparam [7:0] VAL_NIL = {TAG_NIL, 6'h00};
25 localparam [7:0] VAL_TRUE = {TAG_ATOM, 6'h01}; // 'T'
26 localparam [7:0] VAL_A = {TAG_ATOM, 6'h0A};
27 localparam [7:0] VAL_B = {TAG_ATOM, 6'h0B};
28 localparam [7:0] VAL_C = {TAG_ATOM, 6'h0C};
29
30 // Testbench Signals
6 reg clk, rst, cs, rw; 31 reg clk, rst, cs, rw;
7 reg [2:0] addr; 32 reg [2:0] addr;
8 reg [7:0] data_in; 33 reg [7:0] data_in;
9 wire [7:0] data_out; 34 wire [7:0] data_out;
10 35
11 // Verification Vars 36 // Verification Variables
12 reg [7:0] read_data; 37 reg [7:0] read_val;
38 reg [7:0] status_val;
39 reg [7:0] ptr_node3, ptr_node2, ptr_node1;
40 integer errors = 0;
13 integer i; 41 integer i;
14 42
15 // DUT Instance 43 // Instantiate DUT
16 lisp_coproc dut ( 44 lisp_coproc dut (
17 .clk(clk), .rst(rst), .cs(cs), .rw(rw), 45 .clk(clk), .rst(rst), .cs(cs), .rw(rw),
18 .addr(addr), .data_in(data_in), .data_out(data_out) 46 .addr(addr), .data_in(data_in), .data_out(data_out)
19 ); 47 );
20 48
21 // 100MHz Clock 49 // Clock Generation (100MHz)
22 initial begin 50 initial begin
23 clk = 0; 51 clk = 0;
24 forever #5 clk = ~clk; 52 forever #5 clk = ~clk;
25 end 53 end
26 54
27 // --- CPU Bus Tasks --- 55 // ========================================================================
28 56 // 2. HELPER TASKS
57 // ========================================================================
58
29 task cpu_write(input [2:0] w_addr, input [7:0] w_data); 59 task cpu_write(input [2:0] w_addr, input [7:0] w_data);
30 begin 60 begin
31 @(posedge clk); 61 @(posedge clk);
32 cs = 1; rw = 0; addr = w_addr; data_in = w_data; 62 cs = 1; rw = 0; addr = w_addr; data_in = w_data;
33 @(posedge clk); 63 @(posedge clk);
34 cs = 0; data_in = 8'h00; // Clear bus 64 cs = 0; data_in = 8'h00;
35 end 65 end
36 endtask 66 endtask
37 67
38 task cpu_read(input [2:0] r_addr, output [7:0] r_data); 68 // Read with auto-polling for BUSY flag
39 reg [7:0] stat; 69 task cpu_exec_and_read(input [2:0] r_addr, output [7:0] r_data);
40 begin 70 begin
41 // 1. Poll Status for BUSY=0 71 // Poll Status Bit 0 (BUSY)
42 do begin 72 do begin
43 @(posedge clk); 73 @(posedge clk);
44 cs = 1; rw = 1; addr = 3'h4; // Status Reg 74 cs = 1; rw = 1; addr = 3'h4; // Status
45 @(posedge clk); 75 @(posedge clk);
46 stat = data_out; 76 status_val = data_out;
47 cs = 0; 77 cs = 0;
48 end while (stat[0] == 1'b1); 78 end while (status_val[0] === 1'b1);
49 79
50 // 2. Perform Actual Read 80 // Perform Read
51 @(posedge clk); 81 @(posedge clk);
52 cs = 1; rw = 1; addr = r_addr; 82 cs = 1; rw = 1; addr = r_addr;
53 @(posedge clk); 83 @(posedge clk);
@@ -55,92 +85,222 @@ module tb_lisp_coproc;
55 cs = 0; 85 cs = 0;
56 end 86 end
57 endtask 87 endtask
88
89 task check(input [7:0] expected, input [7:0] actual, input string name);
90 if (expected !== actual) begin
91 $display("FAIL: %s | Exp: 0x%h, Got: 0x%h", name, expected, actual);
92 errors = errors + 1;
93 end else begin
94 $display("PASS: %s", name);
95 end
96 endtask
58 97
59 // --- Main Test Sequence --- 98 task check_status(input bit exp_heap, input bit exp_type, input bit exp_carry, input bit exp_zero, input string name);
99 // Status Reg: [7:5]Rsrv, [4]Zero, [3]Carry, [2]Type, [1]Heap, [0]Busy
100 reg [7:0] expected_mask;
101 expected_mask = {3'b000, exp_zero, exp_carry, exp_type, exp_heap, 1'b0};
102
103 cpu_exec_and_read(3'h4, status_val);
104 // Mask out the busy bit for comparison as it should be 0 now
105 if ((status_val & 8'hFE) !== expected_mask) begin
106 $display("FAIL: %s (Status) | Exp: %b, Got: %b", name, expected_mask, status_val);
107 errors = errors + 1;
108 end else begin
109 $display("PASS: %s (Status)", name);
110 end
111 endtask
112
113 // ========================================================================
114 // 3. MAIN TEST SCENARIOS
115 // ========================================================================
116
60 initial begin 117 initial begin
61 $dumpfile("lisp_coproc.vcd"); 118 $dumpfile("lisp_coproc_robust.vcd");
62 $dumpvars(0, tb_lisp_coproc); 119 $dumpvars(0, tb_lisp_coproc);
63 120
64 // Init 121 // --- Initialize ---
65 rst = 1; cs = 0; rw = 0; addr = 0; data_in = 0; 122 rst = 1; cs = 0; rw = 0; addr = 0; data_in = 0;
66 #20 rst = 0; #20; 123 #20 rst = 0; #20;
124 $display("\n=== STARTING ROBUST VERIFICATION ===\n");
125
126 // --------------------------------------------------------
127 // SCENARIO 1: ALU Boundary & Overflow
128 // --------------------------------------------------------
129 $display("--- Scenario 1: ALU Mathematics ---");
67 130
68 $display("--- Starting Lisp Coprocessor Verification ---"); 131 // 1.1 Simple Add: 10 + 15 = 25
69 132 cpu_write(3'h1, {TAG_NUM, 6'd10});
70 // 1. Reset Test 133 cpu_write(3'h2, {TAG_NUM, 6'd15});
71 cpu_read(3'h4, read_data); 134 cpu_write(3'h0, OP_ADD);
72 assert_equals(8'h00, read_data, "Reset Status"); 135 cpu_exec_and_read(3'h3, read_val);
73 136 check({TAG_NUM, 6'd25}, read_val, "Add 10+15");
74 // 2. ADD Test (5 + 6 = 11) 137 check_status(0,0,0,0, "Add Normal Status");
75 $display("\n[Test] ADD Operation"); 138
76 cpu_write(3'h1, 8'h85); // Number(5) 139 // 1.2 Zero Check: 0 + 0 = 0 (Should set Zero flag)
77 cpu_write(3'h2, 8'h86); // Number(6) 140 cpu_write(3'h1, {TAG_NUM, 6'd0});
78 cpu_write(3'h0, 8'h06); // OPCODE: ADD 141 cpu_write(3'h2, {TAG_NUM, 6'd0});
79 cpu_read(3'h3, read_data); 142 cpu_write(3'h0, OP_ADD);
80 assert_equals(8'h8B, read_data, "ADD Result (11)"); 143 cpu_exec_and_read(3'h3, read_val);
81 cpu_read(3'h4, read_data); 144 check({TAG_NUM, 6'd0}, read_val, "Add 0+0");
82 assert_equals(8'h00, read_data, "ADD Status (Clean)"); 145 check_status(0,0,0,1, "Add Zero Status"); // Expect Zero=1
83 146
84 // 3. CONS Test 147 // 1.3 Overflow Check: 63 + 1 = 0 (Should set Carry flag)
85 $display("\n[Test] CONS Operation"); 148 // Max 6-bit unsigned is 63. 63+1 wraps to 0.
86 cpu_write(3'h1, 8'h41); // Atom('T') 149 cpu_write(3'h1, {TAG_NUM, 6'd63});
87 cpu_write(3'h2, 8'h42); // Atom('B') 150 cpu_write(3'h2, {TAG_NUM, 6'd1});
88 cpu_write(3'h0, 8'h01); // OPCODE: CONS 151 cpu_write(3'h0, OP_ADD);
89 cpu_read(3'h3, read_data); 152 cpu_exec_and_read(3'h3, read_val);
90 // Expect CONS Tag (11) | Address (0000) -> 0xC0 153 check({TAG_NUM, 6'd0}, read_val, "Add 63+1 (Wrap)");
91 assert_equals(8'hC0, read_data, "CONS Pointer"); 154 check_status(0,0,1,1, "Add Overflow Status"); // Expect Carry=1, Zero=1
92 155
93 // Verify Heap Persistence via CAR/CDR 156 // --------------------------------------------------------
94 cpu_write(3'h1, 8'hC0); // Pointer to just allocated cell 157 // SCENARIO 2: Equality (EQ) Logic
95 cpu_write(3'h0, 8'h02); // OPCODE: CAR 158 // --------------------------------------------------------
96 cpu_read(3'h3, read_data); 159 $display("\n--- Scenario 2: EQ Logic ---");
97 assert_equals(8'h41, read_data, "CAR Check"); 160
98 161 // 2.1 Atom Equality (True)
99 cpu_write(3'h1, 8'hC0); 162 cpu_write(3'h1, VAL_A);
100 cpu_write(3'h0, 8'h03); // OPCODE: CDR 163 cpu_write(3'h2, VAL_A);
101 cpu_read(3'h3, read_data); 164 cpu_write(3'h0, OP_EQ);
102 assert_equals(8'h42, read_data, "CDR Check"); 165 cpu_exec_and_read(3'h3, read_val);
103 166 check(VAL_TRUE, read_val, "EQ(A, A)");
104 // 4. Error Test (Type Error) 167 check_status(0,0,0,1, "EQ True Status"); // Zero flag used for equality? Spec says "ZERO (From ADD or EQ op)"
105 $display("\n[Test] Error Handling (Type)"); 168
106 cpu_write(3'h1, 8'h85); // Number 169 // 2.2 Atom Inequality (False)
107 cpu_write(3'h0, 8'h02); // OPCODE: CAR (Invalid on Number) 170 cpu_write(3'h1, VAL_A);
108 cpu_read(3'h4, read_data); 171 cpu_write(3'h2, VAL_B);
109 // Bit 2 (ERR_TYPE) should be set -> 0x04 172 cpu_write(3'h0, OP_EQ);
110 assert_equals(8'h04, read_data, "Error Type Flag"); 173 cpu_exec_and_read(3'h3, read_val);
111 174 check(VAL_NIL, read_val, "EQ(A, B)");
112 // 5. Heap Full Test 175 check_status(0,0,0,0, "EQ False Status");
113 $display("\n[Test] Heap Full Error"); 176
114 // We used 2 cells (1 CONS). 14 cells remain. 177 // 2.3 Mixed Type Equality (Number 10 vs Atom 10) -> Should be NIL (Bits differ in Tag)
115 // Loop 7 times to fill exactly to 16. 178 cpu_write(3'h1, {TAG_NUM, 6'd10});
116 for(i=0; i<7; i=i+1) begin 179 cpu_write(3'h2, {TAG_ATOM, 6'd10});
117 cpu_write(3'h1, 8'h41); 180 cpu_write(3'h0, OP_EQ);
118 cpu_write(3'h2, 8'h42); 181 cpu_exec_and_read(3'h3, read_val);
119 cpu_write(3'h0, 8'h01); // CONS 182 check(VAL_NIL, read_val, "EQ(Num, Atom)");
120 cpu_read(3'h3, read_data); // Sync 183
121 end 184 // --------------------------------------------------------
185 // SCENARIO 3: Linked List Construction (Chain Verification)
186 // --------------------------------------------------------
187 $display("\n--- Scenario 3: Linked List (A B C) ---");
188 // Goal: Construct (A . (B . (C . NIL)))
189 // Steps:
190 // 1. Node3 = CONS(C, NIL)
191 // 2. Node2 = CONS(B, Node3)
192 // 3. Node1 = CONS(A, Node2)
193
194 // Step 1: Node 3
195 cpu_write(3'h1, VAL_C);
196 cpu_write(3'h2, VAL_NIL);
197 cpu_write(3'h0, OP_CONS);
198 cpu_exec_and_read(3'h3, ptr_node3);
199 check({TAG_CONS, 2'b00, 4'h0}, ptr_node3, "Alloc Node 3 (Ptr=0)");
200
201 // Step 2: Node 2
202 cpu_write(3'h1, VAL_B);
203 cpu_write(3'h2, ptr_node3);
204 cpu_write(3'h0, OP_CONS);
205 cpu_exec_and_read(3'h3, ptr_node2);
206 check({TAG_CONS, 2'b00, 4'h2}, ptr_node2, "Alloc Node 2 (Ptr=2)");
207
208 // Step 3: Node 1
209 cpu_write(3'h1, VAL_A);
210 cpu_write(3'h2, ptr_node2);
211 cpu_write(3'h0, OP_CONS);
212 cpu_exec_and_read(3'h3, ptr_node1);
213 check({TAG_CONS, 2'b00, 4'h4}, ptr_node1, "Alloc Node 1 (Ptr=4)");
214
215 // Step 4: Traverse! CAR(CDR(ptr_node1)) should be B
216
217 // CDR(Node1) -> Should get Node2 Ptr
218 cpu_write(3'h1, ptr_node1);
219 cpu_write(3'h0, OP_CDR);
220 cpu_exec_and_read(3'h3, read_val);
221 check(ptr_node2, read_val, "Traverse: CDR(Node1)");
222
223 // CAR(Result) -> Should get B
224 cpu_write(3'h1, read_val);
225 cpu_write(3'h0, OP_CAR);
226 cpu_exec_and_read(3'h3, read_val);
227 check(VAL_B, read_val, "Traverse: CAR(Node2)");
228
229 // --------------------------------------------------------
230 // SCENARIO 4: Error Type Matrix
231 // --------------------------------------------------------
232 $display("\n--- Scenario 4: Type Safety ---");
233
234 // 4.1 CAR on ATOM (Fail)
235 cpu_write(3'h1, VAL_A);
236 cpu_write(3'h0, OP_CAR);
237 check_status(0,1,0,0, "Err: CAR on Atom"); // Expect ErrType=1
238
239 // 4.2 CDR on NUMBER (Fail)
240 cpu_write(3'h1, {TAG_NUM, 6'd5});
241 cpu_write(3'h0, OP_CDR);
242 check_status(0,1,0,0, "Err: CDR on Number");
243
244 // 4.3 ADD on CONS (Fail)
245 cpu_write(3'h1, {TAG_NUM, 6'd5});
246 cpu_write(3'h2, ptr_node1);
247 cpu_write(3'h0, OP_ADD);
248 check_status(0,1,0,0, "Err: ADD on CONS");
249
250 // --------------------------------------------------------
251 // SCENARIO 5: Heap Full Boundary
252 // --------------------------------------------------------
253 $display("\n--- Scenario 5: Heap Full Boundary ---");
122 254
123 // Try 8th CONS -> Should fail 255 // Current Alloc Pointer is at 6 (We did 3 CONS ops: 0, 2, 4).
124 cpu_write(3'h1, 8'hAA); 256 // Capacity is 16. Addresses 6, 8, 10, 12, 14 are free.
125 cpu_write(3'h2, 8'hBB); 257 // That is 5 more CONS operations allowed.
126 cpu_write(3'h0, 8'h01); // CONS
127 258
128 cpu_read(3'h4, read_data); 259 // Fill 1 (Ptr 6)
129 // Bit 1 (ERR_HEAP) should be set -> 0x02 260 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS);
130 assert_equals(8'h02, read_data, "Heap Full Flag"); 261 cpu_exec_and_read(3'h3, read_val); // Wait
131 262
132 $display("\n--- All Tests Passed Successfully ---"); 263 // Fill 2 (Ptr 8)
133 $finish; 264 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS);
134 end 265 cpu_exec_and_read(3'h3, read_val);
135 266
136 // Helper task for reporting 267 // Fill 3 (Ptr 10)
137 task assert_equals(input [7:0] expected, input [7:0] actual, input string name); 268 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS);
138 if (expected !== actual) begin 269 cpu_exec_and_read(3'h3, read_val);
139 $display("ERROR: %s failed. Expected 0x%h, Got 0x%h", name, expected, actual); 270
140 $finish; 271 // Fill 4 (Ptr 12)
272 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS);
273 cpu_exec_and_read(3'h3, read_val);
274
275 // Fill 5 (Ptr 14) - THE LAST VALID ONE
276 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS);
277 cpu_exec_and_read(3'h3, read_val);
278 check({TAG_CONS, 2'b00, 4'hE}, read_val, "Last Valid Alloc (Ptr=14)");
279 check_status(0,0,0,0, "Status at Capacity");
280
281 // ATTEMPT OVERFLOW
282 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS);
283
284 // Check Status
285 cpu_exec_and_read(3'h4, status_val);
286 // Expect ErrHeap=1
287 if (status_val[1] !== 1'b1) begin
288 $display("FAIL: Heap Full Detection | Got Status: %b", status_val);
289 errors = errors + 1;
141 end else begin 290 end else begin
142 $display("PASS: %s", name); 291 $display("PASS: Heap Full Detection");
143 end 292 end
144 endtask 293
294 // --------------------------------------------------------
295 // RESULT SUMMARY
296 // --------------------------------------------------------
297 $display("\n==================================");
298 if (errors == 0)
299 $display(" SUCCESS: All Tests Passed");
300 else
301 $display(" FAILURE: %0d Errors Found", errors);
302 $display("==================================");
303 $finish;
304 end
145 305
146endmodule 306endmodule