1// Copyright 2015, Brian Swetland <swetland@frotz.net> 2// Licensed under the Apache License, Version 2.0. 3 4`timescale 1ns / 1ps 5 6module cpu16( 7 input clk, 8 output [15:0]ins_rd_addr, 9 input [15:0]ins_rd_data, 10 output ins_rd_req, 11 input ins_rd_rdy, 12 13 output [15:0]dat_rw_addr, 14 output [15:0]dat_wr_data, 15 input [15:0]dat_rd_data, 16 output dat_rd_req, 17 output dat_wr_req, 18 input dat_rd_rdy, 19 input dat_wr_rdy, 20 21 input reset 22 ); 23 24localparam INS_NOP = 16'h0001; 25 26// ---- FETCH ---- 27reg [15:0]pc_next; 28reg [15:0]ir_next; 29reg ir_valid_next; 30 31reg [15:0]pc = 16'd0; 32reg [15:0]ir = 16'd0; 33reg ir_valid = 1'b0; 34 35assign ins_rd_addr = pc_next; 36assign ins_rd_req = 1'b1; 37 38always_comb begin 39 if (reset) begin 40 pc_next = 16'h0000; 41 end else if (ex_do_branch_imm) begin 42 pc_next = ex_branch_tgt; 43 end else if (ins_rd_rdy) begin 44 pc_next = pc + 16'h0001; 45 end else begin 46 pc_next = pc; 47 end 48 ir_next = ins_rd_rdy ? ins_rd_data : INS_NOP; 49 ir_valid_next = ins_rd_rdy; 50end 51 52always_ff @(posedge clk) begin 53 pc <= pc_next; 54 ir <= ir_next; 55 ir_valid <= ir_valid_next; 56end 57 58// ---- DECODE ---- 59reg [11:0]de_ext = 12'b0; 60reg de_ext_rdy = 1'b0; 61 62// s6 alu-reg-imm load/store 63// s7 pc-rel-cond-branch 64// s9 mov-imm 65// s11 pc-rel-branch 66// s12 ext 67 68// fields decoded from instruction 69wire [15:0]ir_imm_s6_raw = { {11 {ir[15]}}, ir[14:10] }; 70wire [15:0]ir_imm_s7 = { {10 {ir[15]}}, ir[6], ir[14:10] }; 71wire [15:0]ir_imm_s9_raw = { {8 {ir[15]}}, ir[9:7], ir[14:10] }; 72wire [15:0]ir_imm_s11 = { {6 {ir[15]}}, ir[8:4], ir[14:10] }; 73wire [15:0]ir_imm_s12 = { {5 {ir[15]}}, ir[9:4], ir[14:10] }; 74wire [2:0]ir_csel = ir[6:4]; 75wire [2:0]ir_asel = ir[9:7]; 76wire [2:0]ir_bsel = ir[12:10]; 77wire [2:0]ir_alu_op = ir[3] ? ir[2:0] : ir[15:13]; 78wire [3:0]ir_opcode = ir[3:0]; 79 80reg [11:0]ir_ext_imm = 12'b0; 81reg ir_ext_rdy = 1'b0; 82 83wire [15:0]ir_imm_s6 = { (ir_ext_rdy ? ir_ext_imm : ir_imm_s6_raw[15:4]), ir_imm_s6_raw[3:0] }; 84wire [15:0]ir_imm_s9 = { (ir_ext_rdy ? ir_ext_imm : ir_imm_s9_raw[15:4]), ir_imm_s9_raw[3:0] }; 85 86// control signals 87reg do_wreg_alu; // write from alu 88reg do_wreg_mem; // write from memory 89reg do_adata_zero; // pass 0 to alu.xdata (instead of adata) 90reg do_bdata_imm; // pass imm to alu.ydata (instead of bdata) 91reg do_wr_link; // write PC + 1 to LR 92reg do_branch_imm; // branch to imm 93reg do_branch_reg; // branch to reg + imm 94reg do_branch_cond; // branch if condition met 95reg do_branch_zero; // condition zero(1) or notzero(0) 96reg do_use_imm9_or_imm6; 97reg do_mem_read; 98reg do_mem_write; 99reg do_set_ext; 100 101always_comb begin 102 do_wreg_alu = 1'b0; 103 do_wreg_mem = 1'b0; 104 do_adata_zero = 1'b0; 105 do_bdata_imm = 1'b0; 106 do_wr_link = 1'b0; 107 do_branch_imm = 1'b0; 108 do_branch_reg = 1'b0; 109 do_branch_cond = 1'b0; 110 do_branch_zero = 1'b0; 111 do_use_imm9_or_imm6 = 1'b0; 112 do_mem_read = 1'b0; 113 do_mem_write = 1'b0; 114 do_set_ext = 1'b0; 115 116 casez (ir_opcode) 117 4'b0000: begin // alu Rc, Ra, Rb 118 do_wreg_alu = 1'b1; 119 end 120 4'b0001: begin // expansion (nop) 121 end 122 4'b0010: begin // ext si12 123 do_set_ext = 1'b1; 124 end 125 4'b0011: begin // mov Rc, si9 126 do_wreg_alu = 1'b1; 127 do_adata_zero = 1'b1; 128 do_bdata_imm = 1'b1; 129 do_use_imm9_or_imm6 = 1'b1; 130 end 131 4'b0100: begin // lw Rc, [Ra, si6] 132 do_mem_read = 1'b1; 133 do_use_imm9_or_imm6 = 1'b0; 134 end 135 4'b0101: begin // sw Rc, [Ra, si6] 136 do_mem_write = 1'b1; 137 do_use_imm9_or_imm6 = 1'b0; 138 end 139 4'b0110: begin // b imm12 / bl imm12 140 do_branch_imm = 1'b1; 141 do_wr_link = ir[9]; 142 end 143 4'b0111: begin // BZ/BNZ/B/BL 144 if (ir[5]) begin // b Ra / bl Ra 145 do_branch_reg = 1'b1; 146 do_wr_link = ir[4]; 147 end else begin // bz imm7 / bnz imm7 148 do_branch_cond = 1'b1; 149 do_branch_zero = ~ir[4]; 150 end 151 end 152 4'b1???: begin // alu Rc, Ra, si6 153 do_wreg_alu = 1'b1; 154 do_bdata_imm = 1'b1; 155 do_use_imm9_or_imm6 = 1'b0; 156 end 157 endcase 158end 159 160always_ff @(posedge clk) begin 161 if (ir_valid) 162 ir_ext_rdy <= do_set_ext; 163 if (ir_valid & do_set_ext) 164 ir_ext_imm <= ir_imm_s12[11:0]; 165end 166 167wire [15:0]ex_adata; 168wire [15:0]ex_bdata; 169wire [15:0]ex_alu_rdata; 170 171regs16 regs( 172 .clk(clk), 173 .asel(ir_asel), 174 .bsel(do_mem_write ? ir_csel : ir_bsel), 175 .wsel(ex_wsel), 176 .wreg(ex_do_wreg_alu), 177 .adata(ex_adata), 178 .bdata(ex_bdata), 179 .wdata(ex_alu_rdata) 180 ); 181 182// ---- EXECUTE ---- 183 184reg [15:0]ex_branch_tgt = 16'b0; 185reg [2:0]ex_alu_op = 3'b0; 186reg [2:0]ex_wsel = 3'b0; 187reg ex_do_wreg_alu = 1'b0; 188reg ex_do_wreg_mem = 1'b0; 189reg ex_do_adata_zero = 1'b0; 190reg ex_do_bdata_imm = 1'b0; 191reg ex_do_wr_link = 1'b0; 192reg ex_do_branch_imm = 1'b0; 193reg ex_do_branch_reg = 1'b0; 194reg ex_do_branch_cond = 1'b0; 195reg ex_do_branch_zero = 1'b0; 196reg ex_do_mem_read = 1'b0; 197reg ex_do_mem_write = 1'b0; 198 199reg [15:0]ex_imm = 16'b0; 200 201always_ff @(posedge clk) begin 202 // for mem-read or mem-write we use the ALU for Ra + imm7 203 ex_alu_op <= (do_adata_zero | do_mem_read | do_mem_write) ? 3'b0 : ir_alu_op; 204 ex_wsel <= do_wr_link ? 3'd7 : ir_csel; 205 ex_branch_tgt <= pc + (do_branch_imm ? ir_imm_s11 : ir_imm_s7); 206 ex_do_wreg_alu <= do_wreg_alu; 207 ex_do_wreg_mem <= do_wreg_mem; 208 ex_do_adata_zero <= do_adata_zero; 209 ex_do_bdata_imm <= do_bdata_imm; 210 ex_do_wr_link <= do_wr_link; 211 ex_do_branch_imm <= do_branch_imm; 212 ex_do_branch_reg <= do_branch_reg; 213 ex_do_branch_cond <= do_branch_cond; 214 ex_do_branch_zero <= do_branch_zero; 215 ex_do_mem_read = do_mem_read; 216 ex_do_mem_write = do_mem_write; 217 ex_imm <= (do_mem_read | do_mem_write) ? ir_imm_s7 : (do_use_imm9_or_imm6 ? ir_imm_s9 : ir_imm_s6); 218end 219 220 221alu16 alu( 222 .op(ex_alu_op), 223 .xdata(ex_do_adata_zero ? 16'b0 : ex_adata), 224 .ydata((ex_do_mem_read | ex_do_mem_write | ex_do_bdata_imm) ? ex_imm : ex_bdata), 225 .rdata(ex_alu_rdata) 226 ); 227 228assign dat_rw_addr = ex_alu_rdata; 229assign dat_wr_data = ex_bdata; 230assign dat_rd_req = ex_do_mem_read; 231assign dat_wr_req = ex_do_mem_write; 232 233// ---- SIMULATION DEBUG ASSIST ---- 234 235`ifdef verilator 236reg [15:0]dbg_addr = 16'd0; 237wire [47:0]ir_dbg_dis; 238reg [47:0]ex_dbg_dis = 48'd0; 239 240assign ir_dbg_dis = { ir, 3'b0, ir_ext_rdy, ir_ext_imm, dbg_addr }; 241 242always_ff @(posedge clk) begin 243 dbg_addr <= pc; 244 ex_dbg_dis <= ir_dbg_dis; 245end 246`endif 247 248endmodule 249 250module regs16( 251 input clk, 252 input [2:0]asel, 253 input [2:0]bsel, 254 input [2:0]wsel, 255 input wreg, 256 input [15:0]wdata, 257 output [15:0]adata, 258 output [15:0]bdata 259 ); 260 261reg [15:0]rmem[0:7]; 262reg [15:0]areg; 263reg [15:0]breg; 264 265always_ff @(posedge clk) begin 266 if (wreg) 267 rmem[wsel] <= wdata; 268 areg <= rmem[asel]; 269 breg <= rmem[bsel]; 270end 271 272assign adata = areg; 273assign bdata = breg; 274 275endmodule 276 277 278module alu16( 279 input [2:0]op, 280 input [15:0]xdata, 281 input [15:0]ydata, 282 output [15:0]rdata 283 ); 284 285reg [15:0]r; 286 287always_comb begin 288 case (op) 289 3'b000: r = xdata + ydata; 290 3'b001: r = xdata - ydata; 291 3'b010: r = xdata & ydata; 292 3'b011: r = xdata | ydata; 293 3'b100: r = xdata ^ ydata; 294 3'b101: r = { {15 {1'b0}}, xdata < ydata }; 295 3'b110: r = { {15 {1'b0}}, xdata >= ydata }; 296 3'b111: r = xdata * ydata; 297 endcase 298end 299 300assign rdata = r; 301 302endmodule 303 304