summaryrefslogtreecommitdiff
path: root/rtl/lisp_coproc.sv
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/lisp_coproc.sv')
-rw-r--r--rtl/lisp_coproc.sv323
1 files changed, 135 insertions, 188 deletions
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