lisp_coproc.sv (8087B)
1 module 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 // ======================================================================== 12 // 1. DATAPATH Signals & Storage 13 // ======================================================================== 14 15 // Registers 16 reg [7:0] opcode_reg, arg1_reg, arg2_reg, result_reg; 17 reg [7:0] heap [0:15]; 18 19 // Bump Allocator: Uniform 4-bit register (0-15) 20 reg [3:0] bump_alloc; 21 22 // Heap Status: Sticky bit to track if we have wrapped around (Full) 23 reg heap_filled; 24 25 // Internal Flags (Transient for current OP) 26 reg flag_err_heap, flag_err_type, flag_carry, flag_zero; 27 28 // ALU Signals 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_num_a = (arg1_reg[7:6] == 2'b10); 37 wire is_num_b = (arg2_reg[7:6] == 2'b10); 38 39 // Allocation Logic (Datapath Adder) 40 // We use a 5-bit wire to capture the carry out. 41 // If bump_alloc is 14 (1110) + 2 = 16 (10000). 42 // alloc_sum[4] (Carry) is 1. alloc_sum[3:0] is 0000. 43 wire [4:0] alloc_sum = {1'b0, bump_alloc} + 5'd2; 44 wire alloc_carry = alloc_sum[4]; 45 46 // ======================================================================== 47 // 2. FSM CONTROLLER (Safe Binary Encoding) 48 // ======================================================================== 49 50 // Explicit 3-bit encoding avoids optimization ambiguity 51 localparam [2:0] RESET = 3'd0; 52 localparam [2:0] IDLE = 3'd1; 53 localparam [2:0] DECODE = 3'd2; 54 localparam [2:0] EXECUTE = 3'd3; 55 localparam [2:0] WRITEBACK = 3'd4; 56 57 reg [2:0] state, next_state; 58 reg busy_bit; 59 60 // Sequential Logic 61 always @(posedge clk or posedge rst) begin 62 if (rst) state <= RESET; 63 else state <= next_state; 64 end 65 66 // Combinational Next-State Logic 67 always @(*) begin 68 // 1. Default assignments to prevent latches 69 next_state = IDLE; // Default to IDLE (Safe recovery) 70 busy_bit = 1'b1; // Default to BUSY 71 72 case (state) 73 RESET: begin 74 next_state = IDLE; 75 busy_bit = 1'b1; 76 end 77 78 IDLE: begin 79 busy_bit = 1'b0; // Not Busy 80 // Transition Logic 81 if (cs && !rw && addr == 3'h0) 82 next_state = DECODE; 83 else 84 next_state = IDLE; 85 end 86 87 DECODE: begin 88 next_state = EXECUTE; 89 busy_bit = 1'b1; 90 end 91 92 EXECUTE: begin 93 next_state = WRITEBACK; 94 busy_bit = 1'b1; 95 end 96 97 WRITEBACK: begin 98 next_state = IDLE; 99 busy_bit = 1'b1; 100 end 101 102 default: begin 103 next_state = IDLE; 104 busy_bit = 1'b1; 105 end 106 endcase 107 end 108 109 // ======================================================================== 110 // 3. SEQUENTIAL LOGIC 111 // ======================================================================== 112 113 integer i; 114 always @(posedge clk or posedge rst) begin 115 if (rst) begin 116 opcode_reg <= 8'h00; 117 arg1_reg <= 8'h00; 118 arg2_reg <= 8'h00; 119 result_reg <= 8'h00; 120 bump_alloc <= 4'h0; 121 heap_filled <= 1'b0; 122 123 flag_err_heap <= 1'b0; 124 flag_err_type <= 1'b0; 125 flag_carry <= 1'b0; 126 flag_zero <= 1'b0; 127 128 for (i=0; i<16; i=i+1) heap[i] <= 8'h00; 129 130 end else begin 131 132 // --- MMIO Writes --- 133 if (cs && !rw) begin 134 case (addr) 135 3'h0: opcode_reg <= data_in; 136 3'h1: arg1_reg <= data_in; 137 3'h2: arg2_reg <= data_in; 138 3'h3: result_reg <= data_in; 139 default: ; 140 endcase 141 end 142 143 // --- State Actions --- 144 case (state) 145 RESET: begin 146 bump_alloc <= 4'h0; 147 heap_filled <= 1'b0; 148 end 149 150 IDLE: begin 151 if (cs && !rw && addr == 3'h0) begin 152 flag_err_heap <= 1'b0; 153 flag_err_type <= 1'b0; 154 flag_carry <= 1'b0; 155 flag_zero <= 1'b0; 156 end 157 end 158 159 EXECUTE: begin 160 case (opcode_reg) 161 8'h01: begin // CONS 162 if (heap_filled) begin 163 // If sticky flag is set, we are full. Error. 164 flag_err_heap <= 1'b1; 165 end else begin 166 // Perform allocation 167 heap[bump_alloc] <= arg1_reg; 168 heap[(bump_alloc + 1) % 16] <= arg2_reg; 169 170 // Update pointer (wraps automatically due to 4-bit) 171 bump_alloc <= alloc_sum[3:0]; 172 173 // If we generated a carry (14->16), mark heap as filled 174 if (alloc_carry) heap_filled <= 1'b1; 175 end 176 end 177 8'h02: begin // CAR 178 if (!is_cons_a) flag_err_type <= 1'b1; 179 end 180 8'h03: begin // CDR 181 if (!is_cons_a) flag_err_type <= 1'b1; 182 end 183 8'h05: begin // EQ 184 if (alu_eq) flag_zero <= 1'b1; 185 end 186 8'h06: begin // ADD 187 if (!is_num_a || !is_num_b) begin 188 flag_err_type <= 1'b1; 189 end else begin 190 if (alu_sum[6]) flag_carry <= 1'b1; 191 if (alu_sum[5:0] == 6'd0) flag_zero <= 1'b1; 192 end 193 end 194 default: ; 195 endcase 196 end 197 198 WRITEBACK: begin 199 case (opcode_reg) 200 8'h01: begin // CONS 201 if (!flag_err_heap) 202 // Math trick: If bump_alloc wrapped to 0, 203 // 0 - 2 = 14 (1110 in 2's comp), which is the correct pointer. 204 result_reg <= {2'b11, 2'b00, bump_alloc - 4'd2}; 205 end 206 8'h02: begin // CAR 207 if (!flag_err_type) result_reg <= heap[arg1_reg[3:0]]; 208 end 209 8'h03: begin // CDR 210 if (!flag_err_type) result_reg <= heap[arg1_reg[3:0] + 1]; 211 end 212 8'h04: begin // ATOM 213 result_reg <= is_cons_a ? 8'h00 : 8'h41; 214 end 215 8'h05: begin // EQ 216 result_reg <= alu_eq ? 8'h41 : 8'h00; 217 end 218 8'h06: begin // ADD 219 if (!flag_err_type) result_reg <= {2'b10, alu_sum[5:0]}; 220 end 221 default: ; 222 endcase 223 end 224 default: ; 225 endcase 226 end 227 end 228 229 // ======================================================================== 230 // 4. OUTPUT LOGIC 231 // ======================================================================== 232 233 // Status Register: [7:5]Rsrv, [4]Zero, [3]Carry, [2]Type, [1]Heap, [0]Busy 234 wire [7:0] current_status = {3'b000, flag_zero, flag_carry, flag_err_type, flag_err_heap, busy_bit}; 235 236 always @(*) begin 237 if (cs && rw) begin 238 case (addr) 239 3'h0: data_out = opcode_reg; 240 3'h1: data_out = arg1_reg; 241 3'h2: data_out = arg2_reg; 242 3'h3: data_out = result_reg; 243 3'h4: data_out = current_status; 244 default: data_out = 8'h00; 245 endcase 246 end else begin 247 data_out = 8'h00; // Drive 0 instead of Z to satisfy internal logic checks 248 end 249 end 250 251 endmodule