gateware

A collection of little open source FPGA hobby projects
git clone http://frotz.net/git/gateware.git
Log | Files | Refs | README

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