summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvin <git@vineetk.net>2025-11-20 11:16:32 -0500
committervin <git@vineetk.net>2025-11-20 11:16:32 -0500
commit8e17e8bc9d84fbaa5c06bf549faf754f087c8ce6 (patch)
treefd85b1f9e4a5ec34ccab0e7279c0885a30b43c7a
parent4dd69d2913152d80af58d7d68fd195c031180606 (diff)
fix rtl, now tests all pass
need to go through the sv files again and also run a linter
-rw-r--r--.gitignore3
-rw-r--r--rtl/lisp_coproc.sv323
-rw-r--r--rtl/tb_lisp_coproc.sv231
3 files changed, 240 insertions, 317 deletions
diff --git a/.gitignore b/.gitignore
index 472c55f..82b46f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
1rtl/lisp_coproc_sim 1rtl/lisp_coproc_sim
2*.vcd
2*~ 3*~
3#* \ No newline at end of file 4#*
diff --git a/rtl/lisp_coproc.sv b/rtl/lisp_coproc.sv
index bd3057a..b855b7b 100644
--- a/rtl/lisp_coproc.sv
+++ b/rtl/lisp_coproc.sv
@@ -8,248 +8,195 @@ module lisp_coproc (
8 output reg [7:0] data_out 8 output reg [7:0] data_out
9); 9);
10 10
11 // FSM States (One-Hot Encoding) 11 // ========================================================================
12 parameter [4:0] RESET = 5'b00001; 12 // 1. DATAPATH Signals & Storage
13 parameter [4:0] IDLE = 5'b00010; 13 // ========================================================================
14 parameter [4:0] DECODE = 5'b00100; 14
15 parameter [4:0] EXECUTE = 5'b01000; 15 // Registers
16 parameter [4:0] WRITEBACK= 5'b10000; 16 reg [7:0] opcode_reg, arg1_reg, arg2_reg, result_reg;
17 17 reg [7:0] heap [0:15];
18 // Internal Registers 18
19 reg [4:0] state, next_state; 19 // Bump Allocator: Uniform 4-bit register (0-15)
20 reg [7:0] opcode_reg, arg1_reg, arg2_reg, result_reg, status_reg; 20 reg [3:0] bump_alloc;
21 reg [7:0] heap [0:15]; // 16 entries x 8 bits
22 21
23 // FIX: Bump allocator must be 5 bits to hold the value '16' (Full) 22 // Heap Status: Sticky bit to track if we have wrapped around (Full)
24 // without wrapping around to 0. 23 reg heap_filled;
25 reg [4:0] bump_alloc;
26 24
27 // Status Register Bits 25 // Internal Flags (Transient for current OP)
28 wire busy = (state != IDLE); 26 reg flag_err_heap, flag_err_type, flag_carry, flag_zero;
29 reg err_heap_full, err_type, carry, zero;
30 27
31 // ALU Signals 28 // ALU Signals
32 reg [5:0] alu_a, alu_b; 29 wire [5:0] alu_val_a = arg1_reg[5:0];
30 wire [5:0] alu_val_b = arg2_reg[5:0];
31 wire [6:0] alu_sum = alu_val_a + alu_val_b;
32 wire alu_eq = (arg1_reg == arg2_reg);
33
34 // Type Checkers
35 wire is_cons_a = (arg1_reg[7:6] == 2'b11);
36 wire is_cons_b = (arg2_reg[7:6] == 2'b11);
37 wire is_num_a = (arg1_reg[7:6] == 2'b10);
38 wire is_num_b = (arg2_reg[7:6] == 2'b10);
39
40 // Allocation Logic (Datapath Adder)
41 // We use a 5-bit wire to capture the carry out.
42 // If bump_alloc is 14 (1110) + 2 = 16 (10000).
43 // alloc_sum[4] (Carry) is 1. alloc_sum[3:0] is 0000.
44 wire [4:0] alloc_sum = {1'b0, bump_alloc} + 5'd2;
45 wire alloc_carry = alloc_sum[4];
46
47 // ========================================================================
48 // 2. FSM CONTROLLER
49 // ========================================================================
33 50
34 // Temporary registers for operations 51 parameter [4:0] RESET = 5'b00001;
35 reg [7:0] temp_result; 52 parameter [4:0] IDLE = 5'b00010;
36 reg [3:0] temp_ptr; 53 parameter [4:0] DECODE = 5'b00100;
54 parameter [4:0] EXECUTE = 5'b01000;
55 parameter [4:0] WRITEBACK = 5'b10000;
56
57 reg [4:0] state, next_state;
37 58
38 // FSM State Transition
39 always @(posedge clk or posedge rst) begin 59 always @(posedge clk or posedge rst) begin
40 if (rst) begin 60 if (rst) state <= RESET;
41 state <= RESET; 61 else state <= next_state;
42 end else begin
43 state <= next_state;
44 end
45 end 62 end
46 63
47 // FSM Combinational Logic
48 always @(*) begin 64 always @(*) begin
49 next_state = state; 65 next_state = state;
50
51 case (state) 66 case (state)
52 RESET: begin 67 RESET: next_state = IDLE;
53 next_state = IDLE; 68 IDLE: if (cs && !rw && addr == 3'h0) next_state = DECODE;
54 end 69 DECODE: next_state = EXECUTE;
55 70 EXECUTE: next_state = WRITEBACK;
56 IDLE: begin 71 WRITEBACK: next_state = IDLE;
57 if (cs && !rw && addr == 3'h0) begin // Writing to OPCODE triggers operation 72 default: next_state = IDLE;
58 next_state = DECODE;
59 end
60 end
61
62 DECODE: begin
63 next_state = EXECUTE;
64 end
65
66 EXECUTE: begin
67 next_state = WRITEBACK;
68 end
69
70 WRITEBACK: begin
71 next_state = IDLE;
72 end
73
74 default: begin
75 next_state = IDLE;
76 end
77 endcase 73 endcase
78 end 74 end
79 75
80 // Register File and Memory Interface 76 // ========================================================================
77 // 3. SEQUENTIAL LOGIC
78 // ========================================================================
79
80 integer i;
81 always @(posedge clk or posedge rst) begin 81 always @(posedge clk or posedge rst) begin
82 if (rst) begin 82 if (rst) begin
83 opcode_reg <= 8'h00; 83 opcode_reg <= 8'h00;
84 arg1_reg <= 8'h00; 84 arg1_reg <= 8'h00;
85 arg2_reg <= 8'h00; 85 arg2_reg <= 8'h00;
86 result_reg <= 8'h00; 86 result_reg <= 8'h00;
87 status_reg <= 8'h00; 87 bump_alloc <= 4'h0;
88 bump_alloc <= 5'h00; // Reset 5-bit register 88 heap_filled <= 1'b0;
89 err_heap_full <= 1'b0; 89
90 err_type <= 1'b0; 90 flag_err_heap <= 1'b0;
91 carry <= 1'b0; 91 flag_err_type <= 1'b0;
92 zero <= 1'b0; 92 flag_carry <= 1'b0;
93 flag_zero <= 1'b0;
94
95 for (i=0; i<16; i=i+1) heap[i] <= 8'h00;
96
93 end else begin 97 end else begin
94 // Memory-mapped register writes 98
99 // --- MMIO Writes ---
95 if (cs && !rw) begin 100 if (cs && !rw) begin
96 case (addr) 101 case (addr)
97 3'h0: opcode_reg <= data_in; 102 3'h0: opcode_reg <= data_in;
98 3'h1: arg1_reg <= data_in; 103 3'h1: arg1_reg <= data_in;
99 3'h2: arg2_reg <= data_in; 104 3'h2: arg2_reg <= data_in;
100 3'h3: result_reg <= data_in; // Direct write to result 105 3'h3: result_reg <= data_in;
101 3'h4: status_reg <= data_in; // Direct write to status
102 endcase 106 endcase
103 end 107 end
104 108
105 // FSM State-specific operations 109 // --- State Actions ---
106 case (state) 110 case (state)
107 RESET: begin 111 RESET: begin
108 // Clear heap on reset 112 bump_alloc <= 4'h0;
109 integer i; 113 heap_filled <= 1'b0;
110 for (i = 0; i < 16; i = i + 1) begin
111 heap[i] <= 8'h00;
112 end
113 bump_alloc <= 5'h00;
114 opcode_reg <= 8'h00;
115 arg1_reg <= 8'h00;
116 arg2_reg <= 8'h00;
117 result_reg <= 8'h00;
118 status_reg <= 8'h00;
119 end 114 end
120 115
121 IDLE: begin 116 IDLE: begin
122 // Only clear flags when a NEW operation starts.
123 if (cs && !rw && addr == 3'h0) begin 117 if (cs && !rw && addr == 3'h0) begin
124 err_heap_full <= 1'b0; 118 flag_err_heap <= 1'b0;
125 err_type <= 1'b0; 119 flag_err_type <= 1'b0;
126 carry <= 1'b0; 120 flag_carry <= 1'b0;
127 zero <= 1'b0; 121 flag_zero <= 1'b0;
128 end 122 end
129 end 123 end
130 124
131 EXECUTE: begin 125 EXECUTE: begin
132 // Assign ALU inputs for ADD operation using BLOCKING assignment
133 alu_a = arg1_reg[5:0];
134 alu_b = arg2_reg[5:0];
135
136 case (opcode_reg) 126 case (opcode_reg)
137 // CONS operation 127 8'h01: begin // CONS
138 8'h01: begin 128 if (heap_filled) begin
139 // 5-bit arithmetic: 16 + 2 = 18. 18 > 16 is TRUE. 129 // If sticky flag is set, we are full. Error.
140 if (bump_alloc + 2 > 16) begin 130 flag_err_heap <= 1'b1;
141 err_heap_full <= 1'b1;
142 end else begin 131 end else begin
143 // Store ARG1 and ARG2 in heap 132 // Perform allocation
144 heap[bump_alloc[3:0]] <= arg1_reg; 133 heap[bump_alloc] <= arg1_reg;
145 heap[bump_alloc[3:0] + 1] <= arg2_reg; 134 heap[bump_alloc + 1] <= arg2_reg;
146 // Return CONS tag with pointer as value 135
147 temp_ptr <= bump_alloc[3:0]; 136 // Update pointer (wraps automatically due to 4-bit)
148 bump_alloc <= bump_alloc + 2; 137 bump_alloc <= alloc_sum[3:0];
138
139 // If we generated a carry (14->16), mark heap as filled
140 if (alloc_carry) heap_filled <= 1'b1;
149 end 141 end
150 end 142 end
151 143 8'h02: begin // CAR
152 // CAR operation 144 if (!is_cons_a) flag_err_type <= 1'b1;
153 8'h02: begin
154 if (arg1_reg[7:6] != 2'b11) begin // Not a CONS
155 err_type <= 1'b1;
156 end else begin
157 temp_result <= heap[arg1_reg[3:0]];
158 end
159 end 145 end
160 146 8'h03: begin // CDR
161 // CDR operation 147 if (!is_cons_a) flag_err_type <= 1'b1;
162 8'h03: begin
163 if (arg1_reg[7:6] != 2'b11) begin // Not a CONS
164 err_type <= 1'b1;
165 end else begin
166 temp_result <= heap[arg1_reg[3:0] + 1];
167 end
168 end 148 end
169 149 8'h05: begin // EQ
170 // ATOM operation 150 if (alu_eq) flag_zero <= 1'b1;
171 8'h04: begin
172 if (arg1_reg[7:6] == 2'b11) begin // Is a CONS
173 temp_result <= 8'h00; // NIL
174 end else begin
175 temp_result <= 8'h41; // 'T' (01_000001)
176 end
177 end 151 end
178 152 8'h06: begin // ADD
179 // EQ operation 153 if (!is_num_a || !is_num_b) begin
180 8'h05: begin 154 flag_err_type <= 1'b1;
181 if (arg1_reg == arg2_reg) begin
182 temp_result <= 8'h41; // 'T' (01_000001)
183 zero <= 1'b1;
184 end else begin 155 end else begin
185 temp_result <= 8'h00; // NIL 156 if (alu_sum[6]) flag_carry <= 1'b1;
186 end 157 if (alu_sum[5:0] == 6'd0) flag_zero <= 1'b1;
187 end
188
189 // ADD operation
190 8'h06: begin
191 if (arg1_reg[7:6] != 2'b10 || arg2_reg[7:6] != 2'b10) begin // Not both NUMBERs
192 err_type <= 1'b1;
193 end else begin
194 if ((alu_a + alu_b) > 6'd63) begin
195 carry <= 1'b1;
196 end
197 if ((alu_a + alu_b) == 6'd0) begin
198 zero <= 1'b1;
199 end
200 temp_result <= {2'b10, alu_a + alu_b}; // NUMBER tag with sum
201 end 158 end
202 end 159 end
203 endcase 160 endcase
204 end 161 end
205 162
206 WRITEBACK: begin 163 WRITEBACK: begin
207 // Write the result based on the operation
208 case (opcode_reg) 164 case (opcode_reg)
209 8'h01: begin // CONS 165 8'h01: begin // CONS
210 if (!err_heap_full) begin 166 if (!flag_err_heap)
211 // Tag [7:6] must be set correctly. 167 // Math trick: If bump_alloc wrapped to 0,
212 result_reg <= {2'b11, 2'b00, temp_ptr}; 168 // 0 - 2 = 14 (1110 in 2's comp), which is the correct pointer.
213 end 169 result_reg <= {2'b11, 2'b00, bump_alloc - 4'd2};
214 end 170 end
215 171 8'h02: begin // CAR
216 8'h02: begin // CAR 172 if (!flag_err_type) result_reg <= heap[arg1_reg[3:0]];
217 if (!err_type) begin
218 result_reg <= temp_result;
219 end
220 end 173 end
221 174 8'h03: begin // CDR
222 8'h03: begin // CDR 175 if (!flag_err_type) result_reg <= heap[arg1_reg[3:0] + 1];
223 if (!err_type) begin
224 result_reg <= temp_result;
225 end
226 end 176 end
227 177 8'h04: begin // ATOM
228 8'h04: begin // ATOM 178 result_reg <= is_cons_a ? 8'h00 : 8'h41;
229 result_reg <= temp_result;
230 end 179 end
231 180 8'h05: begin // EQ
232 8'h05: begin // EQ 181 result_reg <= alu_eq ? 8'h41 : 8'h00;
233 result_reg <= temp_result;
234 end 182 end
235 183 8'h06: begin // ADD
236 8'h06: begin // ADD 184 if (!flag_err_type) result_reg <= {2'b10, alu_sum[5:0]};
237 if (!err_type) begin
238 result_reg <= temp_result;
239 end
240 end 185 end
241 endcase 186 endcase
242 end 187 end
243 endcase 188 endcase
244 end 189 end
245 end 190 end
191
192 // ========================================================================
193 // 4. OUTPUT LOGIC
194 // ========================================================================
246 195
247 // Update status register 196 wire busy_bit = (state != IDLE);
248 always @(*) begin 197 // Note: bit 1 is the transient error flag, not the internal sticky state
249 status_reg = {3'b000, zero, carry, err_type, err_heap_full, busy}; 198 wire [7:0] current_status = {3'b000, flag_zero, flag_carry, flag_err_type, flag_err_heap, busy_bit};
250 end 199
251
252 // Output Logic
253 always @(*) begin 200 always @(*) begin
254 if (cs && rw) begin 201 if (cs && rw) begin
255 case (addr) 202 case (addr)
@@ -257,11 +204,11 @@ module lisp_coproc (
257 3'h1: data_out = arg1_reg; 204 3'h1: data_out = arg1_reg;
258 3'h2: data_out = arg2_reg; 205 3'h2: data_out = arg2_reg;
259 3'h3: data_out = result_reg; 206 3'h3: data_out = result_reg;
260 3'h4: data_out = status_reg; 207 3'h4: data_out = current_status;
261 default: data_out = 8'h00; 208 default: data_out = 8'h00;
262 endcase 209 endcase
263 end else begin 210 end else begin
264 data_out = 8'hZZ; // High impedance when not reading 211 data_out = 8'hZZ;
265 end 212 end
266 end 213 end
267 214
diff --git a/rtl/tb_lisp_coproc.sv b/rtl/tb_lisp_coproc.sv
index 6c39aa4..aa721fc 100644
--- a/rtl/tb_lisp_coproc.sv
+++ b/rtl/tb_lisp_coproc.sv
@@ -2,170 +2,145 @@
2 2
3module tb_lisp_coproc; 3module tb_lisp_coproc;
4 4
5 // Testbench signals 5 // Signals
6 reg clk; 6 reg clk, rst, cs, rw;
7 reg rst;
8 reg cs;
9 reg rw; // 0=Write, 1=Read
10 reg [2:0] addr; 7 reg [2:0] addr;
11 reg [7:0] data_in; 8 reg [7:0] data_in;
12 wire [7:0] data_out; 9 wire [7:0] data_out;
13 10
14 // Test variables 11 // Verification Vars
15 reg [7:0] read_data; 12 reg [7:0] read_data;
16 integer i; 13 integer i;
17 14
18 // Instantiate the DUT 15 // DUT Instance
19 lisp_coproc dut ( 16 lisp_coproc dut (
20 .clk(clk), 17 .clk(clk), .rst(rst), .cs(cs), .rw(rw),
21 .rst(rst), 18 .addr(addr), .data_in(data_in), .data_out(data_out)
22 .cs(cs),
23 .rw(rw),
24 .addr(addr),
25 .data_in(data_in),
26 .data_out(data_out)
27 ); 19 );
28 20
29 // Clock generation 21 // 100MHz Clock
30 initial begin 22 initial begin
31 clk = 0; 23 clk = 0;
32 forever #5 clk = ~clk; 24 forever #5 clk = ~clk;
33 end 25 end
34 26
35 // CPU Write Task 27 // --- CPU Bus Tasks ---
36 task cpu_write; 28
37 input [2:0] addr_in; 29 task cpu_write(input [2:0] w_addr, input [7:0] w_data);
38 input [7:0] data_in_in;
39 begin 30 begin
40 @(posedge clk); 31 @(posedge clk);
41 cs = 1'b1; 32 cs = 1; rw = 0; addr = w_addr; data_in = w_data;
42 rw = 1'b0; // Write
43 addr = addr_in;
44 data_in = data_in_in;
45 @(posedge clk); 33 @(posedge clk);
46 cs = 1'b0; 34 cs = 0; data_in = 8'h00; // Clear bus
47 end 35 end
48 endtask 36 endtask
49 37
50 // CPU Read Task 38 task cpu_read(input [2:0] r_addr, output [7:0] r_data);
51 task cpu_read; 39 reg [7:0] stat;
52 input [2:0] addr_in;
53 output [7:0] data_out_out;
54 reg [7:0] status;
55 begin 40 begin
56 // Poll until not busy 41 // 1. Poll Status for BUSY=0
57 do begin 42 do begin
58 @(posedge clk); 43 @(posedge clk);
59 cs = 1'b1; 44 cs = 1; rw = 1; addr = 3'h4; // Status Reg
60 rw = 1'b1; // Read
61 addr = 3'h4; // Status register
62 @(posedge clk); 45 @(posedge clk);
63 status = data_out; 46 stat = data_out;
64 cs = 1'b0; 47 cs = 0;
65 end while (status[0]); // Check BUSY bit 48 end while (stat[0] == 1'b1);
66 49
67 // Read the requested address 50 // 2. Perform Actual Read
68 @(posedge clk); 51 @(posedge clk);
69 cs = 1'b1; 52 cs = 1; rw = 1; addr = r_addr;
70 rw = 1'b1; // Read
71 addr = addr_in;
72 @(posedge clk); 53 @(posedge clk);
73 data_out_out = data_out; 54 r_data = data_out;
74 cs = 1'b0; 55 cs = 0;
75 end 56 end
76 endtask 57 endtask
77 58
78 // Test Sequence 59 // --- Main Test Sequence ---
79 initial begin 60 initial begin
80 // Initialize signals 61 $dumpfile("lisp_coproc.vcd");
81 rst = 1'b1; 62 $dumpvars(0, tb_lisp_coproc);
82 cs = 1'b0; 63
83 rw = 1'b0; 64 // Init
84 addr = 3'h0; 65 rst = 1; cs = 0; rw = 0; addr = 0; data_in = 0;
85 data_in = 8'h00; 66 #20 rst = 0; #20;
86
87 // Apply reset
88 #20;
89 rst = 1'b0;
90 #20;
91
92 // Test 1: Reset Test
93 $display("Test 1: Reset Test");
94 cpu_read(3'h4, read_data); // Read STATUS
95 $display("STATUS after reset: 0x%02h (expected: 0x00)", read_data);
96 if (read_data != 8'h00) $display("ERROR: Reset test failed");
97
98 // Test 2: ADD Test
99 $display("\nTest 2: ADD Test");
100 cpu_write(3'h1, 8'h85); // ARG1 = NUMBER(5)
101 cpu_write(3'h2, 8'h86); // ARG2 = NUMBER(6)
102 cpu_write(3'h0, 8'h06); // OPCODE = ADD
103
104 cpu_read(3'h3, read_data); // Read RESULT
105 $display("ADD Result: 0x%02h (expected: 0x8B, NUMBER(11))", read_data);
106 if (read_data != 8'h8B) $display("ERROR: ADD test failed");
107
108 cpu_read(3'h4, read_data); // Read STATUS
109 $display("STATUS after ADD: 0x%02h (expected: 0x00, ZERO=0)", read_data);
110 if (read_data != 8'h00) $display("ERROR: ADD status test failed");
111
112 // Test 3: CONS Test
113 $display("\nTest 3: CONS Test");
114 cpu_write(3'h1, 8'h41); // ARG1 = ATOM('T')
115 cpu_write(3'h2, 8'h42); // ARG2 = ATOM('B')
116 cpu_write(3'h0, 8'h01); // OPCODE = CONS
117
118 cpu_read(3'h3, read_data); // Read RESULT
119 $display("CONS Result: 0x%02h (expected: 0xC0, CONS(0))", read_data);
120 if (read_data != 8'hC0) $display("ERROR: CONS test failed");
121
122 // Test CAR and CDR
123 cpu_write(3'h1, read_data); // Use the CONS result as ARG1
124 cpu_write(3'h0, 8'h02); // OPCODE = CAR
125
126 cpu_read(3'h3, read_data); // Read RESULT
127 $display("CAR Result: 0x%02h (expected: 0x41, ATOM('T'))", read_data);
128 if (read_data != 8'h41) $display("ERROR: CAR test failed");
129
130 cpu_write(3'h1, 8'hC0); // ARG1 = CONS(0)
131 cpu_write(3'h0, 8'h03); // OPCODE = CDR
132
133 cpu_read(3'h3, read_data); // Read RESULT
134 $display("CDR Result: 0x%02h (expected: 0x42, ATOM('B'))", read_data);
135 if (read_data != 8'h42) $display("ERROR: CDR test failed");
136
137 // Test 4: Error Test (CAR on a Number)
138 $display("\nTest 4: Error Test (CAR on a Number)");
139 cpu_write(3'h1, 8'h85); // ARG1 = NUMBER(5)
140 cpu_write(3'h0, 8'h02); // OPCODE = CAR
141
142 cpu_read(3'h4, read_data); // Read STATUS
143 $display("STATUS after CAR on Number: 0x%02h (expected: 0x04, ERR_TYPE=1)", read_data);
144 if (read_data != 8'h04) $display("ERROR: Error test failed");
145 67
146 // Test 5: Heap Full Test 68 $display("--- Starting Lisp Coprocessor Verification ---");
147 $display("\nTest 5: Heap Full Test"); 69
148 // Fill the heap with CONS operations 70 // 1. Reset Test
149 // Since bump_alloc is now 2, we have used 2 cells. 71 cpu_read(3'h4, read_data);
150 // 16 cells total. 14 left. 7 more CONS possible. 72 assert_equals(8'h00, read_data, "Reset Status");
151 for (i = 0; i < 7; i = i + 1) begin 73
152 cpu_write(3'h1, 8'h41); 74 // 2. ADD Test (5 + 6 = 11)
153 cpu_write(3'h2, 8'h42); 75 $display("\n[Test] ADD Operation");
154 cpu_write(3'h0, 8'h01); 76 cpu_write(3'h1, 8'h85); // Number(5)
155 cpu_read(3'h3, read_data); 77 cpu_write(3'h2, 8'h86); // Number(6)
78 cpu_write(3'h0, 8'h06); // OPCODE: ADD
79 cpu_read(3'h3, read_data);
80 assert_equals(8'h8B, read_data, "ADD Result (11)");
81 cpu_read(3'h4, read_data);
82 assert_equals(8'h00, read_data, "ADD Status (Clean)");
83
84 // 3. CONS Test
85 $display("\n[Test] CONS Operation");
86 cpu_write(3'h1, 8'h41); // Atom('T')
87 cpu_write(3'h2, 8'h42); // Atom('B')
88 cpu_write(3'h0, 8'h01); // OPCODE: CONS
89 cpu_read(3'h3, read_data);
90 // Expect CONS Tag (11) | Address (0000) -> 0xC0
91 assert_equals(8'hC0, read_data, "CONS Pointer");
92
93 // Verify Heap Persistence via CAR/CDR
94 cpu_write(3'h1, 8'hC0); // Pointer to just allocated cell
95 cpu_write(3'h0, 8'h02); // OPCODE: CAR
96 cpu_read(3'h3, read_data);
97 assert_equals(8'h41, read_data, "CAR Check");
98
99 cpu_write(3'h1, 8'hC0);
100 cpu_write(3'h0, 8'h03); // OPCODE: CDR
101 cpu_read(3'h3, read_data);
102 assert_equals(8'h42, read_data, "CDR Check");
103
104 // 4. Error Test (Type Error)
105 $display("\n[Test] Error Handling (Type)");
106 cpu_write(3'h1, 8'h85); // Number
107 cpu_write(3'h0, 8'h02); // OPCODE: CAR (Invalid on Number)
108 cpu_read(3'h4, read_data);
109 // Bit 2 (ERR_TYPE) should be set -> 0x04
110 assert_equals(8'h04, read_data, "Error Type Flag");
111
112 // 5. Heap Full Test
113 $display("\n[Test] Heap Full Error");
114 // We used 2 cells (1 CONS). 14 cells remain.
115 // Loop 7 times to fill exactly to 16.
116 for(i=0; i<7; i=i+1) begin
117 cpu_write(3'h1, 8'h41);
118 cpu_write(3'h2, 8'h42);
119 cpu_write(3'h0, 8'h01); // CONS
120 cpu_read(3'h3, read_data); // Sync
156 end 121 end
157 122
158 // One more CONS should cause heap full error 123 // Try 8th CONS -> Should fail
159 cpu_write(3'h1, 8'h41); 124 cpu_write(3'h1, 8'hAA);
160 cpu_write(3'h2, 8'h42); 125 cpu_write(3'h2, 8'hBB);
161 cpu_write(3'h0, 8'h01); 126 cpu_write(3'h0, 8'h01); // CONS
162
163 cpu_read(3'h4, read_data); // Read STATUS
164 $display("STATUS after Heap Full: 0x%02h (expected: 0x02, ERR_HEAP_FULL=1)", read_data);
165 if (read_data != 8'h02) $display("ERROR: Heap Full test failed");
166 127
167 $display("\nAll tests completed."); 128 cpu_read(3'h4, read_data);
129 // Bit 1 (ERR_HEAP) should be set -> 0x02
130 assert_equals(8'h02, read_data, "Heap Full Flag");
131
132 $display("\n--- All Tests Passed Successfully ---");
168 $finish; 133 $finish;
169 end 134 end
135
136 // Helper task for reporting
137 task assert_equals(input [7:0] expected, input [7:0] actual, input string name);
138 if (expected !== actual) begin
139 $display("ERROR: %s failed. Expected 0x%h, Got 0x%h", name, expected, actual);
140 $finish;
141 end else begin
142 $display("PASS: %s", name);
143 end
144 endtask
170 145
171endmodule 146endmodule