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.sv268
1 files changed, 268 insertions, 0 deletions
diff --git a/rtl/lisp_coproc.sv b/rtl/lisp_coproc.sv
new file mode 100644
index 0000000..bd3057a
--- /dev/null
+++ b/rtl/lisp_coproc.sv
@@ -0,0 +1,268 @@
1module lisp_coproc (
2 input wire clk,
3 input wire rst,
4 input wire cs,
5 input wire rw, // 0=Write, 1=Read
6 input wire [2:0] addr,
7 input wire [7:0] data_in,
8 output reg [7:0] data_out
9);
10
11 // FSM States (One-Hot Encoding)
12 parameter [4:0] RESET = 5'b00001;
13 parameter [4:0] IDLE = 5'b00010;
14 parameter [4:0] DECODE = 5'b00100;
15 parameter [4:0] EXECUTE = 5'b01000;
16 parameter [4:0] WRITEBACK= 5'b10000;
17
18 // Internal Registers
19 reg [4:0] state, next_state;
20 reg [7:0] opcode_reg, arg1_reg, arg2_reg, result_reg, status_reg;
21 reg [7:0] heap [0:15]; // 16 entries x 8 bits
22
23 // FIX: Bump allocator must be 5 bits to hold the value '16' (Full)
24 // without wrapping around to 0.
25 reg [4:0] bump_alloc;
26
27 // Status Register Bits
28 wire busy = (state != IDLE);
29 reg err_heap_full, err_type, carry, zero;
30
31 // ALU Signals
32 reg [5:0] alu_a, alu_b;
33
34 // Temporary registers for operations
35 reg [7:0] temp_result;
36 reg [3:0] temp_ptr;
37
38 // FSM State Transition
39 always @(posedge clk or posedge rst) begin
40 if (rst) begin
41 state <= RESET;
42 end else begin
43 state <= next_state;
44 end
45 end
46
47 // FSM Combinational Logic
48 always @(*) begin
49 next_state = state;
50
51 case (state)
52 RESET: begin
53 next_state = IDLE;
54 end
55
56 IDLE: begin
57 if (cs && !rw && addr == 3'h0) begin // Writing to OPCODE triggers operation
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
78 end
79
80 // Register File and Memory Interface
81 always @(posedge clk or posedge rst) begin
82 if (rst) begin
83 opcode_reg <= 8'h00;
84 arg1_reg <= 8'h00;
85 arg2_reg <= 8'h00;
86 result_reg <= 8'h00;
87 status_reg <= 8'h00;
88 bump_alloc <= 5'h00; // Reset 5-bit register
89 err_heap_full <= 1'b0;
90 err_type <= 1'b0;
91 carry <= 1'b0;
92 zero <= 1'b0;
93 end else begin
94 // Memory-mapped register writes
95 if (cs && !rw) begin
96 case (addr)
97 3'h0: opcode_reg <= data_in;
98 3'h1: arg1_reg <= data_in;
99 3'h2: arg2_reg <= data_in;
100 3'h3: result_reg <= data_in; // Direct write to result
101 3'h4: status_reg <= data_in; // Direct write to status
102 endcase
103 end
104
105 // FSM State-specific operations
106 case (state)
107 RESET: begin
108 // Clear heap on reset
109 integer i;
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
120
121 IDLE: begin
122 // Only clear flags when a NEW operation starts.
123 if (cs && !rw && addr == 3'h0) begin
124 err_heap_full <= 1'b0;
125 err_type <= 1'b0;
126 carry <= 1'b0;
127 zero <= 1'b0;
128 end
129 end
130
131 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)
137 // CONS operation
138 8'h01: begin
139 // 5-bit arithmetic: 16 + 2 = 18. 18 > 16 is TRUE.
140 if (bump_alloc + 2 > 16) begin
141 err_heap_full <= 1'b1;
142 end else begin
143 // Store ARG1 and ARG2 in heap
144 heap[bump_alloc[3:0]] <= arg1_reg;
145 heap[bump_alloc[3:0] + 1] <= arg2_reg;
146 // Return CONS tag with pointer as value
147 temp_ptr <= bump_alloc[3:0];
148 bump_alloc <= bump_alloc + 2;
149 end
150 end
151
152 // CAR operation
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
160
161 // CDR operation
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
169
170 // ATOM operation
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
178
179 // EQ operation
180 8'h05: begin
181 if (arg1_reg == arg2_reg) begin
182 temp_result <= 8'h41; // 'T' (01_000001)
183 zero <= 1'b1;
184 end else begin
185 temp_result <= 8'h00; // NIL
186 end
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
202 end
203 endcase
204 end
205
206 WRITEBACK: begin
207 // Write the result based on the operation
208 case (opcode_reg)
209 8'h01: begin // CONS
210 if (!err_heap_full) begin
211 // Tag [7:6] must be set correctly.
212 result_reg <= {2'b11, 2'b00, temp_ptr};
213 end
214 end
215
216 8'h02: begin // CAR
217 if (!err_type) begin
218 result_reg <= temp_result;
219 end
220 end
221
222 8'h03: begin // CDR
223 if (!err_type) begin
224 result_reg <= temp_result;
225 end
226 end
227
228 8'h04: begin // ATOM
229 result_reg <= temp_result;
230 end
231
232 8'h05: begin // EQ
233 result_reg <= temp_result;
234 end
235
236 8'h06: begin // ADD
237 if (!err_type) begin
238 result_reg <= temp_result;
239 end
240 end
241 endcase
242 end
243 endcase
244 end
245 end
246
247 // Update status register
248 always @(*) begin
249 status_reg = {3'b000, zero, carry, err_type, err_heap_full, busy};
250 end
251
252 // Output Logic
253 always @(*) begin
254 if (cs && rw) begin
255 case (addr)
256 3'h0: data_out = opcode_reg;
257 3'h1: data_out = arg1_reg;
258 3'h2: data_out = arg2_reg;
259 3'h3: data_out = result_reg;
260 3'h4: data_out = status_reg;
261 default: data_out = 8'h00;
262 endcase
263 end else begin
264 data_out = 8'hZZ; // High impedance when not reading
265 end
266 end
267
268endmodule