summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--rtl/lisp_coproc.sv268
-rw-r--r--rtl/tb_lisp_coproc.sv171
3 files changed, 442 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..472c55f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
1rtl/lisp_coproc_sim
2*~
3#* \ No newline at end of file
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
diff --git a/rtl/tb_lisp_coproc.sv b/rtl/tb_lisp_coproc.sv
new file mode 100644
index 0000000..6c39aa4
--- /dev/null
+++ b/rtl/tb_lisp_coproc.sv
@@ -0,0 +1,171 @@
1`timescale 1ns/1ps
2
3module tb_lisp_coproc;
4
5 // Testbench signals
6 reg clk;
7 reg rst;
8 reg cs;
9 reg rw; // 0=Write, 1=Read
10 reg [2:0] addr;
11 reg [7:0] data_in;
12 wire [7:0] data_out;
13
14 // Test variables
15 reg [7:0] read_data;
16 integer i;
17
18 // Instantiate the DUT
19 lisp_coproc dut (
20 .clk(clk),
21 .rst(rst),
22 .cs(cs),
23 .rw(rw),
24 .addr(addr),
25 .data_in(data_in),
26 .data_out(data_out)
27 );
28
29 // Clock generation
30 initial begin
31 clk = 0;
32 forever #5 clk = ~clk;
33 end
34
35 // CPU Write Task
36 task cpu_write;
37 input [2:0] addr_in;
38 input [7:0] data_in_in;
39 begin
40 @(posedge clk);
41 cs = 1'b1;
42 rw = 1'b0; // Write
43 addr = addr_in;
44 data_in = data_in_in;
45 @(posedge clk);
46 cs = 1'b0;
47 end
48 endtask
49
50 // CPU Read Task
51 task cpu_read;
52 input [2:0] addr_in;
53 output [7:0] data_out_out;
54 reg [7:0] status;
55 begin
56 // Poll until not busy
57 do begin
58 @(posedge clk);
59 cs = 1'b1;
60 rw = 1'b1; // Read
61 addr = 3'h4; // Status register
62 @(posedge clk);
63 status = data_out;
64 cs = 1'b0;
65 end while (status[0]); // Check BUSY bit
66
67 // Read the requested address
68 @(posedge clk);
69 cs = 1'b1;
70 rw = 1'b1; // Read
71 addr = addr_in;
72 @(posedge clk);
73 data_out_out = data_out;
74 cs = 1'b0;
75 end
76 endtask
77
78 // Test Sequence
79 initial begin
80 // Initialize signals
81 rst = 1'b1;
82 cs = 1'b0;
83 rw = 1'b0;
84 addr = 3'h0;
85 data_in = 8'h00;
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
146 // Test 5: Heap Full Test
147 $display("\nTest 5: Heap Full Test");
148 // Fill the heap with CONS operations
149 // Since bump_alloc is now 2, we have used 2 cells.
150 // 16 cells total. 14 left. 7 more CONS possible.
151 for (i = 0; i < 7; i = i + 1) begin
152 cpu_write(3'h1, 8'h41);
153 cpu_write(3'h2, 8'h42);
154 cpu_write(3'h0, 8'h01);
155 cpu_read(3'h3, read_data);
156 end
157
158 // One more CONS should cause heap full error
159 cpu_write(3'h1, 8'h41);
160 cpu_write(3'h2, 8'h42);
161 cpu_write(3'h0, 8'h01);
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
167 $display("\nAll tests completed.");
168 $finish;
169 end
170
171endmodule