cpu16.sv (11442B)
1 // Copyright 2018, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0. 3 4 `default_nettype none 5 6 `timescale 1ns / 1ps 7 8 module cpu16( 9 input clk, 10 output [15:0]ins_rd_addr, 11 input [15:0]ins_rd_data, 12 output ins_rd_req, 13 input ins_rd_rdy, 14 15 output [15:0]dat_rw_addr, 16 output [15:0]dat_wr_data, 17 input [15:0]dat_rd_data, 18 output dat_rd_req, 19 output dat_wr_req, 20 input dat_rd_rdy, 21 input dat_wr_rdy, 22 23 input reset 24 ); 25 26 // Control Signal Constants 27 28 localparam SEL_ALU_OP_ADD = 2'b00; 29 localparam SEL_ALU_OP_MHI = 2'b01; 30 localparam SEL_ALU_OP_FUNC = 2'b10; 31 localparam SEL_ALU_OP_SHFT = 2'b11; 32 33 localparam SEL_XDATA_ADATA = 1'b0; 34 localparam SEL_XDATA_PC = 1'b1; 35 36 localparam SEL_YDATA_BDATA = 1'b0; 37 localparam SEL_YDATA_IMM = 1'b1; 38 39 localparam SEL_REG_B_IR_B = 1'b0; 40 localparam SEL_REG_B_IR_C = 1'b1; 41 42 localparam SEL_REG_W_IR_C = 1'b0; 43 localparam SEL_REG_W_R7 = 1'b1; 44 45 localparam SEL_BR_ALU = 1'b0; 46 localparam SEL_BR_BDATA = 1'b1; 47 48 49 wire ex_do_branch; 50 reg [15:0]ex_branch_tgt; 51 52 wire de_pause; 53 54 // Instruction Fetch (if) 55 reg [15:0]if_pc = 16'd0; 56 57 assign ins_rd_addr = if_pc_next; 58 assign ins_rd_req = 1'b1; 59 60 wire [15:0]if_pc_plus_1 = if_pc + 16'h0001; 61 62 wire [15:0]if_de_ir = ins_rd_data; 63 wire if_de_ir_valid = ins_rd_rdy & (~ex_do_branch); 64 65 reg [15:0]if_pc_next; 66 always_comb begin 67 if (reset) begin 68 if_pc_next = 16'd0; 69 end else if (ex_do_branch) begin 70 if_pc_next = ex_branch_tgt; 71 end else if (if_de_ir_valid & (~de_pause)) begin 72 if_pc_next = if_pc_plus_1; 73 end else begin 74 if_pc_next = if_pc; 75 end 76 end 77 78 always_ff @(posedge clk) begin 79 if_pc <= if_pc_next; 80 end 81 82 // Instruction Decode (de) 83 84 reg [15:0]de_ir = 16'd0; 85 reg [15:0]de_pc_plus_1 = 16'd0; 86 reg de_ir_valid = 1'b0; 87 88 // Immediate Forms 89 // si7 siiiiiixxxxxxxxx -> ssssssssssiiiiii 90 // si9 siiiiiixjjxxxxxx -> ssssssssjjiiiiii 91 // si10 siiiiiijjjxxxxxx -> sssssssjjjiiiiii 92 // si12 siiiiiijjjkkxxxx -> ssssskkjjjiiiiii 93 94 wire de_ir_imm_s = de_ir[15]; 95 wire [5:0]de_ir_imm_i = de_ir[14:9]; 96 wire [2:0]de_ir_imm_j = de_ir[8:6]; 97 wire [1:0]de_ir_imm_k = de_ir[5:4]; 98 wire [3:0]de_ir_sel_f = de_ir[15:12]; 99 wire [2:0]de_ir_sel_b = de_ir[11:9]; 100 wire [2:0]de_ir_sel_a = de_ir[8:6]; 101 wire [2:0]de_ir_sel_c = de_ir[5:3]; 102 wire [2:0]de_ir_opcode = de_ir[2:0]; 103 wire [5:0]de_ir_imm_u = { de_ir[14:12], de_ir[8:6] }; 104 105 reg [15:0]de_ir_imm; 106 always_comb begin 107 casez (de_ir_opcode) 108 3'b??1: de_ir_imm = { {10{de_ir_imm_s}}, de_ir_imm_i }; // si7 109 3'b?00: de_ir_imm = { {8{de_ir_imm_s}}, de_ir_imm_j[1:0], de_ir_imm_i }; // si9 110 3'b010: de_ir_imm = { {7{de_ir_imm_s}}, de_ir_imm_j, de_ir_imm_i }; // si10 111 3'b110: de_ir_imm = { {5{de_ir_imm_s}}, de_ir_imm_k, de_ir_imm_j, de_ir_imm_i }; // si12 112 endcase 113 end 114 115 reg [1:0]de_sel_alu_op; // choose alu op SEL_ALU_OP_* 116 reg de_sel_xdata; // choose alu x input SEL_XDATA_* 117 reg de_sel_ydata; // choose alu y input SEL_YDATA_* 118 reg de_sel_reg_b; // choose reg b addr SEL_REG_B_* 119 reg de_sel_reg_w; // choose reg w addr SEL_REG_W_* 120 reg de_sel_br; // choose branch tgt SEL_BR_* 121 reg de_do_zero_xdata; // force alu x input to 16'h0 122 reg de_do_cond_zero; // branch condition (0=NZ, 1=Z) 123 124 reg de_do_wr_reg; // write alu result to register 125 reg de_do_wr_link; // write PC+1 to R7 126 reg de_do_rd_mem; // read memory during ex 127 reg de_do_wr_mem; // write memory during ex 128 reg de_do_uncon_branch; // execute unconditional branch 129 reg de_do_cond_branch; // execute conditional branch 130 131 reg de_using_reg_a; 132 reg de_using_reg_b; 133 134 reg [3:0]de_alu_op; 135 reg [2:0]de_regs_bsel; 136 reg [2:0]de_regs_wsel; 137 reg [2:0]de_regs_asel; 138 always_comb begin 139 case (de_sel_alu_op) 140 SEL_ALU_OP_ADD: de_alu_op = 4'b0100; 141 SEL_ALU_OP_MHI: de_alu_op = 4'b1111; 142 SEL_ALU_OP_FUNC: de_alu_op = de_ir_sel_f; 143 SEL_ALU_OP_SHFT: de_alu_op = {2'b10,de_ir_sel_f[1:0]}; 144 endcase 145 case (de_sel_reg_b) 146 SEL_REG_B_IR_B: de_regs_bsel = de_ir_sel_b; 147 SEL_REG_B_IR_C: de_regs_bsel = de_ir_sel_c; 148 endcase 149 case (de_sel_reg_w) 150 SEL_REG_W_IR_C: de_regs_wsel = de_ir_sel_c; 151 SEL_REG_W_R7: de_regs_wsel = 3'd7; 152 endcase 153 de_regs_asel = de_ir_sel_a; 154 end 155 156 always_ff @(posedge clk) begin 157 if (~de_pause) begin 158 if (if_de_ir_valid) begin 159 de_ir <= if_de_ir; 160 de_pc_plus_1 <= if_pc_plus_1; 161 end 162 de_ir_valid <= if_de_ir_valid; 163 end 164 end 165 166 wire de_hzd_reg_a; 167 wire de_hzd_reg_b; 168 169 always_comb begin 170 de_sel_alu_op = SEL_ALU_OP_ADD; 171 de_sel_xdata = SEL_XDATA_ADATA; 172 de_sel_ydata = SEL_YDATA_BDATA; 173 de_sel_reg_b = SEL_REG_B_IR_B; 174 de_sel_reg_w = SEL_REG_W_IR_C; 175 de_sel_br = SEL_BR_ALU; 176 de_do_zero_xdata = 1'b0; 177 de_do_cond_zero = 1'b0; 178 de_do_wr_reg = 1'b0; 179 de_do_wr_link = 1'b0; 180 de_do_rd_mem = 1'b0; 181 de_do_wr_mem = 1'b0; 182 de_do_uncon_branch = 1'b0; 183 de_do_cond_branch = 1'b0; 184 de_using_reg_a = 1'b0; 185 de_using_reg_b = 1'b0; 186 case (de_ir_opcode) 187 3'b000: begin // ALU Rc, Ra, Rb 188 de_sel_alu_op = SEL_ALU_OP_FUNC; 189 de_sel_reg_b = SEL_REG_B_IR_B; 190 de_sel_xdata = SEL_XDATA_ADATA; 191 de_sel_ydata = SEL_YDATA_BDATA; 192 de_sel_reg_w = SEL_REG_W_IR_C; 193 de_do_wr_reg = 1'b1; 194 de_using_reg_a = 1'b1; 195 de_using_reg_b = 1'b1; 196 end 197 3'b001: begin // ADD Rc, Ra, si7 198 de_sel_alu_op = SEL_ALU_OP_ADD; 199 de_sel_xdata = SEL_XDATA_ADATA; 200 de_sel_ydata = SEL_YDATA_IMM; 201 de_sel_reg_w = SEL_REG_W_IR_C; 202 de_do_wr_reg = 1'b1; 203 de_using_reg_a = 1'b1; 204 de_using_reg_b = 1'b1; 205 end 206 3'b010: begin // MOV Rc, si10 207 de_sel_alu_op = SEL_ALU_OP_ADD; 208 de_sel_ydata = SEL_YDATA_IMM; 209 de_sel_reg_w = SEL_REG_W_IR_C; 210 de_sel_reg_b = SEL_REG_B_IR_C; 211 de_do_zero_xdata = 1'b1; 212 de_do_wr_reg = 1'b1; 213 end 214 3'b011: begin // LW Rc, [Ra, si7] 215 de_sel_alu_op = SEL_ALU_OP_ADD; 216 de_sel_xdata = SEL_XDATA_ADATA; 217 de_sel_ydata = SEL_YDATA_IMM; 218 de_sel_reg_w = SEL_REG_W_IR_C; 219 de_do_rd_mem = 1'b1; 220 de_using_reg_a = 1'b1; 221 end 222 3'b100: begin // BZ/BNZ Rc, si9 223 de_sel_alu_op = SEL_ALU_OP_ADD; 224 de_sel_xdata = SEL_XDATA_PC; 225 de_sel_ydata = SEL_YDATA_IMM; 226 de_sel_reg_b = SEL_REG_B_IR_C; 227 de_sel_br = SEL_BR_ALU; 228 de_do_cond_branch = 1'b1; 229 de_do_cond_zero = de_ir[8]; 230 de_using_reg_b = 1'b1; 231 end 232 3'b101: begin // SW Rc, [Ra, si7] 233 de_sel_alu_op = SEL_ALU_OP_ADD; 234 de_sel_xdata = SEL_XDATA_ADATA; 235 de_sel_ydata = SEL_YDATA_IMM; 236 de_sel_reg_b = SEL_REG_B_IR_C; 237 de_do_wr_mem = 1'b1; 238 de_using_reg_a = 1'b1; 239 de_using_reg_b = 1'b1; 240 end 241 3'b110: begin // B/BL si12 242 de_sel_alu_op = SEL_ALU_OP_ADD; 243 de_sel_xdata = SEL_XDATA_PC; 244 de_sel_ydata = SEL_YDATA_IMM; 245 de_sel_br = SEL_BR_ALU; 246 de_do_wr_link = de_ir[3]; 247 de_do_uncon_branch = 1'b1; 248 end 249 3'b111: begin 250 if (de_ir[15]) begin // MHI Rc, Ra, si7 251 de_sel_alu_op = SEL_ALU_OP_MHI; 252 de_sel_xdata = SEL_XDATA_ADATA; 253 de_sel_ydata = SEL_YDATA_IMM; 254 de_sel_reg_w = SEL_REG_W_IR_C; 255 de_do_wr_reg = 1'b1; 256 de_using_reg_a = 1'b1; 257 end else case (de_ir[11:9]) 258 3'b000: begin // B/BL Ra 259 de_sel_br = SEL_BR_BDATA; 260 de_do_wr_link = de_ir[3]; 261 de_do_uncon_branch = 1'b1; 262 de_using_reg_a = 1'b1; 263 end 264 3'b001: begin // NOP 265 end 266 3'b010: begin // RSV0 (NOP) 267 //TODO: FAULT 268 end 269 3'b011: begin // RSV1 (NOP) 270 //TODO: FAULT 271 end 272 3'b100: begin // LC Rc, u6 273 //TODO: CTRL REGS 274 end 275 3'b101: begin // SC Rc, u6 276 //TODO: CTRL REGS 277 end 278 3'b110: begin // SHIFT Rc, Ra, 1 279 // imm7 bit0 chooses shift-by-1 280 de_sel_alu_op = SEL_ALU_OP_SHFT; 281 de_sel_xdata = SEL_XDATA_ADATA; 282 de_sel_ydata = SEL_YDATA_IMM; 283 de_sel_reg_w = SEL_REG_W_IR_C; 284 de_do_wr_reg = 1'b1; 285 de_using_reg_a = 1'b1; 286 end 287 3'b111: begin // SHIFT Rc, Ra, 4 288 // imm7 bit0 chooses shift-by-4 289 de_sel_alu_op = SEL_ALU_OP_SHFT; 290 de_sel_xdata = SEL_XDATA_ADATA; 291 de_sel_ydata = SEL_YDATA_IMM; 292 de_sel_reg_w = SEL_REG_W_IR_C; 293 de_do_wr_reg = 1'b1; 294 de_using_reg_a = 1'b1; 295 end 296 endcase 297 end 298 endcase 299 end 300 301 wire [15:0]regs_ex_adata; 302 wire [15:0]regs_ex_bdata; 303 304 reg wb_regs_do_wr_reg = 1'b0; 305 reg wb_regs_do_wr_dat = 1'b0; 306 reg [2:0]wb_regs_wsel = 3'b0; 307 reg [15:0]wb_regs_wdata = 16'd0; 308 309 wire [15:0]regs_wdata = wb_regs_do_wr_dat ? dat_rd_data : wb_regs_wdata; 310 311 cpu16_regs regs( 312 .clk(clk), 313 .asel(de_regs_asel), 314 .adata(regs_ex_adata), 315 .bsel(de_regs_bsel), 316 .bdata(regs_ex_bdata), 317 .wreg(wb_regs_do_wr_reg | wb_regs_do_wr_dat), 318 .wsel(wb_regs_wsel), 319 .wdata(regs_wdata) 320 ); 321 322 // Execute (ex) 323 324 reg [15:0]ex_adata; 325 reg [15:0]ex_bdata; 326 reg [15:0]alu_ex_rdata; 327 328 reg [15:0]ex_pc_plus_1 = 16'd0; 329 reg [15:0]ex_imm = 16'd0; 330 331 reg [3:0]ex_alu_op = 4'd0; 332 reg [2:0]ex_regs_wsel = 3'd0; 333 reg ex_sel_xdata = 1'b0; 334 reg ex_sel_ydata = 1'b0; 335 336 reg ex_sel_br = 1'b0; 337 reg ex_do_zero_xdata = 1'b0; 338 reg ex_do_cond_zero = 1'b0; 339 340 reg ex_do_wr_reg = 1'b0; 341 reg ex_do_wr_link = 1'b0; 342 reg ex_do_rd_mem = 1'b0; 343 reg ex_do_wr_mem = 1'b0; 344 reg ex_do_uncon_branch = 1'b0; 345 reg ex_do_cond_branch = 1'b0; 346 347 reg ex_valid = 1'b0; 348 349 always_ff @(posedge clk) begin 350 ex_pc_plus_1 <= de_pc_plus_1; 351 ex_imm <= de_ir_imm; 352 ex_alu_op <= de_alu_op; 353 ex_regs_wsel <= de_regs_wsel; 354 ex_sel_xdata <= de_sel_xdata; 355 ex_sel_ydata <= de_sel_ydata; 356 ex_sel_br <= de_sel_br; 357 ex_do_cond_zero <= de_do_cond_zero; 358 ex_valid <= de_ir_valid; 359 if ((~de_ir_valid) | de_pause | ex_do_branch) begin 360 ex_do_zero_xdata <= 1'b0; 361 ex_do_wr_reg <= 1'b0; 362 ex_do_wr_link <= 1'b0; 363 ex_do_rd_mem <= 1'b0; 364 ex_do_wr_mem <= 1'b0; 365 ex_do_uncon_branch <= 1'b0; 366 ex_do_cond_branch <= 1'b0; 367 end else begin 368 ex_do_zero_xdata <= de_do_zero_xdata; 369 ex_do_wr_reg <= de_do_wr_reg; 370 ex_do_wr_link <= de_do_wr_link; 371 ex_do_rd_mem <= de_do_rd_mem; 372 ex_do_wr_mem <= de_do_wr_mem; 373 ex_do_uncon_branch <= de_do_uncon_branch; 374 ex_do_cond_branch <= de_do_cond_branch; 375 end 376 end 377 378 wire ex_is_cond_zero = (regs_ex_bdata == 16'd0); 379 380 assign ex_do_branch = ex_do_uncon_branch | (ex_do_cond_branch & (ex_do_cond_zero == ex_is_cond_zero)); 381 382 reg [15:0]alu_x; 383 reg [15:0]alu_y; 384 385 always_comb begin 386 if (ex_do_zero_xdata) begin 387 alu_x = 16'd0; 388 end else begin 389 case (ex_sel_xdata) 390 SEL_XDATA_ADATA: alu_x = regs_ex_adata; 391 SEL_XDATA_PC: alu_x = ex_pc_plus_1; 392 endcase 393 end 394 case (ex_sel_ydata) 395 SEL_YDATA_BDATA: alu_y = regs_ex_bdata; 396 SEL_YDATA_IMM: alu_y = ex_imm; 397 endcase 398 case (ex_sel_br) 399 SEL_BR_ALU: ex_branch_tgt = alu_ex_rdata; 400 SEL_BR_BDATA: ex_branch_tgt = regs_ex_bdata; 401 endcase 402 end 403 404 cpu16_alu alu( 405 .op(ex_alu_op), 406 .x(alu_x), 407 .y(alu_y), 408 .r(alu_ex_rdata) 409 ); 410 411 wire [15:0]ex_regs_wdata = ex_do_wr_link ? ex_pc_plus_1 : alu_ex_rdata; 412 413 assign dat_rw_addr = alu_ex_rdata; 414 assign dat_wr_data = regs_ex_bdata; 415 assign dat_rd_req = ex_do_rd_mem; 416 assign dat_wr_req = ex_do_wr_mem; 417 418 // Write Back (wb) 419 420 always_ff @(posedge clk) begin 421 wb_regs_wsel <= ex_do_wr_link ? 3'd7 : ex_regs_wsel; 422 wb_regs_wdata <= ex_regs_wdata; 423 if (!ex_valid) begin 424 wb_regs_do_wr_reg <= 1'b0; 425 wb_regs_do_wr_dat <= 1'b0; 426 end else begin 427 wb_regs_do_wr_reg <= ex_do_wr_reg | (ex_do_wr_link & ex_do_branch) | ex_do_rd_mem; 428 wb_regs_do_wr_dat <= ex_do_rd_mem; 429 end 430 431 end 432 433 assign de_hzd_reg_a = de_using_reg_a & ( 434 (ex_do_wr_reg & (de_regs_asel == ex_regs_wsel)) | 435 (wb_regs_do_wr_reg & (de_regs_asel == wb_regs_wsel))); 436 assign de_hzd_reg_b = de_using_reg_b & ( 437 (ex_do_wr_reg & (de_regs_bsel == ex_regs_wsel)) | 438 (wb_regs_do_wr_reg & (de_regs_bsel == wb_regs_wsel))); 439 assign de_pause = de_hzd_reg_a | de_hzd_reg_b; 440 441 // ---- SIMULATION DEBUG ASSIST ---- 442 443 `ifdef verilator 444 reg [15:0]dbg_addr = 16'd0; 445 wire [31:0]ir_dbg_dis; 446 reg [31:0]ex_dbg_dis = 32'd0; 447 448 assign ir_dbg_dis = { de_ir, dbg_addr }; 449 450 always_ff @(posedge clk) begin 451 dbg_addr <= if_pc; 452 ex_dbg_dis <= ir_dbg_dis; 453 end 454 `endif 455 456 endmodule 457