tb_lisp_coproc.sv (11454B)
1 `timescale 1ns/1ps 2 3 module tb_lisp_coproc; 4 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 31 reg clk, rst, cs, rw; 32 reg [2:0] addr; 33 reg [7:0] data_in; 34 wire [7:0] data_out; 35 36 // Verification Variables 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; 41 integer i; 42 43 // Instantiate DUT 44 lisp_coproc dut ( 45 .clk(clk), .rst(rst), .cs(cs), .rw(rw), 46 .addr(addr), .data_in(data_in), .data_out(data_out) 47 ); 48 49 // Clock Generation (10MHz) 50 initial begin 51 clk = 0; 52 forever #50 clk = ~clk; 53 end 54 55 // ======================================================================== 56 // 2. HELPER TASKS 57 // ======================================================================== 58 59 task cpu_write(input [2:0] w_addr, input [7:0] w_data); 60 begin 61 @(posedge clk); 62 cs = 1; rw = 0; addr = w_addr; data_in = w_data; 63 @(posedge clk); 64 cs = 0; data_in = 8'h00; 65 end 66 endtask 67 68 // Read with auto-polling for BUSY flag 69 task cpu_exec_and_read(input [2:0] r_addr, output [7:0] r_data); 70 integer timeout; 71 begin 72 timeout = 0; 73 // Poll Status Bit 0 (BUSY) 74 do begin 75 @(posedge clk); 76 cs = 1; rw = 1; addr = 3'h4; // Status 77 @(posedge clk); 78 status_val = data_out; 79 cs = 0; 80 81 // Panic button: Break if stuck for 100 cycles 82 timeout = timeout + 1; 83 if (timeout > 100) begin 84 $display("ERROR: Timed out polling BUSY bit! Status: %b", status_val); 85 break; 86 end 87 end while (status_val[0] === 1'b1); 88 89 // Perform Read 90 @(posedge clk); 91 cs = 1; 92 rw = 1; addr = r_addr; 93 @(posedge clk); 94 r_data = data_out; 95 cs = 0; 96 end 97 endtask 98 99 task check(input [7:0] expected, input [7:0] actual, input string name); 100 if (expected !== actual) begin 101 $display("FAIL: %s | Exp: 0x%h, Got: 0x%h", name, expected, actual); 102 errors = errors + 1; 103 end else begin 104 $display("PASS: %s", name); 105 end 106 endtask 107 108 task check_status(input bit exp_heap, input bit exp_type, input bit exp_carry, input bit exp_zero, input string name); 109 // Status Reg: [7:5]Rsrv, [4]Zero, [3]Carry, [2]Type, [1]Heap, [0]Busy 110 reg [7:0] expected_mask; 111 expected_mask = {3'b000, exp_zero, exp_carry, exp_type, exp_heap, 1'b0}; 112 113 cpu_exec_and_read(3'h4, status_val); 114 // Mask out the busy bit for comparison as it should be 0 now 115 if ((status_val & 8'hFE) !== expected_mask) begin 116 $display("FAIL: %s (Status) | Exp: %b, Got: %b", name, expected_mask, status_val); 117 errors = errors + 1; 118 end else begin 119 $display("PASS: %s (Status)", name); 120 end 121 endtask 122 123 // ======================================================================== 124 // 3. MAIN TEST SCENARIOS 125 // ======================================================================== 126 127 initial begin 128 $dumpfile("lisp_coproc.vcd"); 129 $dumpvars(0, tb_lisp_coproc); 130 131 // --- Initialize --- 132 clk = 0; 133 cs = 0; rw = 0; addr = 0; data_in = 0; 134 135 // --- AGGRESSIVE RESET SEQUENCE --- 136 rst = 1; // Assert Reset 137 #500; // Hold for 50 cycles (allows X propagation to clear) 138 rst = 0; // Release Reset 139 #100; // Wait for logic to settle into IDLE 140 141 $display("\n=== STARTING VERIFICATION ===\n"); 142 143 // -------------------------------------------------------- 144 // SCENARIO 1: ALU Boundary & Overflow 145 // -------------------------------------------------------- 146 $display("--- Scenario 1: ALU Mathematics ---"); 147 148 // 1.1 Simple Add: 10 + 15 = 25 149 cpu_write(3'h1, {TAG_NUM, 6'd10}); 150 cpu_write(3'h2, {TAG_NUM, 6'd15}); 151 cpu_write(3'h0, OP_ADD); 152 cpu_exec_and_read(3'h3, read_val); 153 check({TAG_NUM, 6'd25}, read_val, "Add 10+15"); 154 check_status(0,0,0,0, "Add Normal Status"); 155 156 // 1.2 Zero Check: 0 + 0 = 0 (Should set Zero flag) 157 cpu_write(3'h1, {TAG_NUM, 6'd0}); 158 cpu_write(3'h2, {TAG_NUM, 6'd0}); 159 cpu_write(3'h0, OP_ADD); 160 cpu_exec_and_read(3'h3, read_val); 161 check({TAG_NUM, 6'd0}, read_val, "Add 0+0"); 162 check_status(0,0,0,1, "Add Zero Status"); // Expect Zero=1 163 164 // 1.3 Overflow Check: 63 + 1 = 0 (Should set Carry flag) 165 // Max 6-bit unsigned is 63. 63+1 wraps to 0. 166 cpu_write(3'h1, {TAG_NUM, 6'd63}); 167 cpu_write(3'h2, {TAG_NUM, 6'd1}); 168 cpu_write(3'h0, OP_ADD); 169 cpu_exec_and_read(3'h3, read_val); 170 check({TAG_NUM, 6'd0}, read_val, "Add 63+1 (Wrap)"); 171 check_status(0,0,1,1, "Add Overflow Status"); // Expect Carry=1, Zero=1 172 173 // -------------------------------------------------------- 174 // SCENARIO 2: Equality (EQ) Logic 175 // -------------------------------------------------------- 176 $display("\n--- Scenario 2: EQ Logic ---"); 177 178 // 2.1 Atom Equality (True) 179 cpu_write(3'h1, VAL_A); 180 cpu_write(3'h2, VAL_A); 181 cpu_write(3'h0, OP_EQ); 182 cpu_exec_and_read(3'h3, read_val); 183 check(VAL_TRUE, read_val, "EQ(A, A)"); 184 check_status(0,0,0,1, "EQ True Status"); // Zero flag used for equality? Spec says "ZERO (From ADD or EQ op)" 185 186 // 2.2 Atom Inequality (False) 187 cpu_write(3'h1, VAL_A); 188 cpu_write(3'h2, VAL_B); 189 cpu_write(3'h0, OP_EQ); 190 cpu_exec_and_read(3'h3, read_val); 191 check(VAL_NIL, read_val, "EQ(A, B)"); 192 check_status(0,0,0,0, "EQ False Status"); 193 194 // 2.3 Mixed Type Equality (Number 10 vs Atom 10) -> Should be NIL (Bits differ in Tag) 195 cpu_write(3'h1, {TAG_NUM, 6'd10}); 196 cpu_write(3'h2, {TAG_ATOM, 6'd10}); 197 cpu_write(3'h0, OP_EQ); 198 cpu_exec_and_read(3'h3, read_val); 199 check(VAL_NIL, read_val, "EQ(Num, Atom)"); 200 201 // -------------------------------------------------------- 202 // SCENARIO 3: Linked List Construction (Chain Verification) 203 // -------------------------------------------------------- 204 $display("\n--- Scenario 3: Linked List (A B C) ---"); 205 // Goal: Construct (A . (B . (C . NIL))) 206 // Steps: 207 // 1. Node3 = CONS(C, NIL) 208 // 2. Node2 = CONS(B, Node3) 209 // 3. Node1 = CONS(A, Node2) 210 211 // Step 1: Node 3 212 cpu_write(3'h1, VAL_C); 213 cpu_write(3'h2, VAL_NIL); 214 cpu_write(3'h0, OP_CONS); 215 cpu_exec_and_read(3'h3, ptr_node3); 216 check({TAG_CONS, 2'b00, 4'h0}, ptr_node3, "Alloc Node 3 (Ptr=0)"); 217 218 // Step 2: Node 2 219 cpu_write(3'h1, VAL_B); 220 cpu_write(3'h2, ptr_node3); 221 cpu_write(3'h0, OP_CONS); 222 cpu_exec_and_read(3'h3, ptr_node2); 223 check({TAG_CONS, 2'b00, 4'h2}, ptr_node2, "Alloc Node 2 (Ptr=2)"); 224 225 // Step 3: Node 1 226 cpu_write(3'h1, VAL_A); 227 cpu_write(3'h2, ptr_node2); 228 cpu_write(3'h0, OP_CONS); 229 cpu_exec_and_read(3'h3, ptr_node1); 230 check({TAG_CONS, 2'b00, 4'h4}, ptr_node1, "Alloc Node 1 (Ptr=4)"); 231 232 // Step 4: Traverse! CAR(CDR(ptr_node1)) should be B 233 234 // CDR(Node1) -> Should get Node2 Ptr 235 cpu_write(3'h1, ptr_node1); 236 cpu_write(3'h0, OP_CDR); 237 cpu_exec_and_read(3'h3, read_val); 238 check(ptr_node2, read_val, "Traverse: CDR(Node1)"); 239 240 // CAR(Result) -> Should get B 241 cpu_write(3'h1, read_val); 242 cpu_write(3'h0, OP_CAR); 243 cpu_exec_and_read(3'h3, read_val); 244 check(VAL_B, read_val, "Traverse: CAR(Node2)"); 245 246 // -------------------------------------------------------- 247 // SCENARIO 4: Error Type Matrix 248 // -------------------------------------------------------- 249 $display("\n--- Scenario 4: Type Safety ---"); 250 251 // 4.1 CAR on ATOM (Fail) 252 cpu_write(3'h1, VAL_A); 253 cpu_write(3'h0, OP_CAR); 254 check_status(0,1,0,0, "Err: CAR on Atom"); // Expect ErrType=1 255 256 // 4.2 CDR on NUMBER (Fail) 257 cpu_write(3'h1, {TAG_NUM, 6'd5}); 258 cpu_write(3'h0, OP_CDR); 259 check_status(0,1,0,0, "Err: CDR on Number"); 260 261 // 4.3 ADD on CONS (Fail) 262 cpu_write(3'h1, {TAG_NUM, 6'd5}); 263 cpu_write(3'h2, ptr_node1); 264 cpu_write(3'h0, OP_ADD); 265 check_status(0,1,0,0, "Err: ADD on CONS"); 266 267 // -------------------------------------------------------- 268 // SCENARIO 5: Heap Full Boundary 269 // -------------------------------------------------------- 270 $display("\n--- Scenario 5: Heap Full Boundary ---"); 271 272 // Current Alloc Pointer is at 6 (We did 3 CONS ops: 0, 2, 4). 273 // Capacity is 16. Addresses 6, 8, 10, 12, 14 are free. 274 // That is 5 more CONS operations allowed. 275 276 // Fill 1 (Ptr 6) 277 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS); 278 cpu_exec_and_read(3'h3, read_val); // Wait 279 280 // Fill 2 (Ptr 8) 281 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS); 282 cpu_exec_and_read(3'h3, read_val); 283 284 // Fill 3 (Ptr 10) 285 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS); 286 cpu_exec_and_read(3'h3, read_val); 287 288 // Fill 4 (Ptr 12) 289 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS); 290 cpu_exec_and_read(3'h3, read_val); 291 292 // Fill 5 (Ptr 14) - THE LAST VALID ONE 293 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS); 294 cpu_exec_and_read(3'h3, read_val); 295 check({TAG_CONS, 2'b00, 4'hE}, read_val, "Last Valid Alloc (Ptr=14)"); 296 check_status(0,0,0,0, "Status at Capacity"); 297 298 // ATTEMPT OVERFLOW 299 cpu_write(3'h1, VAL_NIL); cpu_write(3'h2, VAL_NIL); cpu_write(3'h0, OP_CONS); 300 301 // Check Status 302 cpu_exec_and_read(3'h4, status_val); 303 // Expect ErrHeap=1 304 if (status_val[1] !== 1'b1) begin 305 $display("FAIL: Heap Full Detection | Got Status: %b", status_val); 306 errors = errors + 1; 307 end else begin 308 $display("PASS: Heap Full Detection"); 309 end 310 311 // -------------------------------------------------------- 312 // RESULT SUMMARY 313 // -------------------------------------------------------- 314 $display("\n=================================="); 315 if (errors == 0) 316 $display(" SUCCESS: All Tests Passed"); 317 else 318 $display(" FAILURE: %0d Errors Found", errors); 319 $display("=================================="); 320 $finish; 321 end 322 323 endmodule