cda4210_lisp_coproc

A primitive Lisp accelerator in a full-custom physical design (Electric VLSI MOSIS 350nm) and RTL digital design (Librelane Sky130nm PDK)
Log | Files | Refs

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