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