rv_exec.v 8.05 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 
 uRV - a tiny and dumb RISC-V core
 Copyright (c) 2015 twl <twlostow@printf.cc>.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 3.0 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library.
 
*/

`include "rv_defs.v"

`timescale 1ns/1ps

module rv_exec
  (
   input 	     clk_i,
   input 	     rst_i,

   input 	     x_stall_i,
   input 	     x_kill_i,
32
   output 	     x_stall_req_o,
33
		     w_stall_req_i,
34
   
35 36 37 38 39
   
   input [31:0]      d_pc_i,
   input [4:0] 	     d_rd_i,
   input [2:0] 	     d_fun_i,

Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
40
   
41 42
   input [31:0]      rf_rs1_value_i,
   input [31:0]      rf_rs2_value_i,
43 44

   input 	     d_valid_i,
45 46

   input 	     d_load_hazard_i,
47 48 49
   
   input [4:0] 	     d_opcode_i,
   input 	     d_shifter_sign_i,
50 51 52 53 54 55

   input [31:0]      d_imm_i,
   input 	     d_is_signed_compare_i,
   input 	     d_is_signed_alu_op_i,
   input 	     d_is_add_i,
   input 	     d_is_shift_i,
56 57 58 59

   output reg [31:0] f_branch_target_o,
   output reg 	     f_branch_take_o,

60
   output 	     w_load_hazard_o,
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
61
   
62 63 64
   // Writeback stage I/F
   output reg [2:0 ] w_fun_o,
   output reg 	     w_load_o,
65
   output reg 	     w_store_o,
66 67 68 69 70 71 72 73 74 75
   
   output reg [4:0]  w_rd_o,
   output reg [31:0] w_rd_value_o,
   output reg 	     w_rd_write_o,
   output reg [31:0] w_dm_addr_o,
   
   // Data memory I/F (address/store)
   output [31:0]     dm_addr_o,
   output [31:0]     dm_data_s_o,
   output [3:0]      dm_data_select_o,
76 77 78
   output 	     dm_store_o,
   output 	     dm_load_o,
   input 	     dm_ready_i
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
   );

   wire [31:0] 	 rs1, rs2;

   assign rs1 = rf_rs1_value_i;
   assign rs2 = rf_rs2_value_i;
   
   reg [31:0] 	 alu_op1, alu_op2, alu_result;
   reg [31:0] 	 rd_value;
   
   
   reg 		 branch_take;
   reg 		 branch_condition_met;
   
   reg [31:0] 	 branch_target;

   reg [31:0] 	 dm_addr, dm_data_s, dm_select_s;

   reg 	     rd_write;
   
99 100
   wire [32:0] cmp_op1 = { d_is_signed_compare_i ? rs1[31] : 1'b0, rs1 };
   wire [32:0] cmp_op2 = { d_is_signed_compare_i ? rs2[31] : 1'b0, rs2 };
101

Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
102
   wire [32:0] cmp_rs = cmp_op1 - cmp_op2;
103
   
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
104 105 106 107
   wire        cmp_equal = (cmp_op1 == cmp_op2);
   wire        cmp_lt = cmp_rs[32];

   // branch condition decoding   
108 109 110 111 112 113 114 115 116 117 118
   always@*
     case (d_fun_i)
       `BRA_EQ: branch_condition_met <= cmp_equal;
       `BRA_NEQ: branch_condition_met <= ~cmp_equal;
       `BRA_GE: branch_condition_met <= ~cmp_lt | cmp_equal;
       `BRA_LT: branch_condition_met <= cmp_lt;
       `BRA_GEU: branch_condition_met <= ~cmp_lt | cmp_equal;
       `BRA_LTU: branch_condition_met <= cmp_lt;
       default: branch_condition_met <= 0;
     endcase // case (d_fun_i)
   
119 120
   always@*
     case (d_opcode_i)
121 122 123
       `OPC_JAL: branch_target <= d_pc_i + d_imm_i;
       `OPC_JALR: branch_target <= rs1 + d_imm_i;
       `OPC_BRANCH: branch_target <= d_pc_i + d_imm_i;
124 125 126 127 128 129 130
       
       default: branch_target<= 32'hx;
     endcase // case (d_opcode_i)

   // decode ALU operands
   always@*
     begin
131
	case (d_opcode_i)
132 133
	  `OPC_LUI: alu_op1 <= d_imm_i;
	  `OPC_AUIPC: alu_op1 <= d_imm_i;
134 135 136 137 138 139 140 141 142 143 144
	  `OPC_JAL: alu_op1 <= 4;
	  `OPC_JALR: alu_op1 <= 4;
	  default: alu_op1 <= rs1;
	endcase // case (d_opcode_i)
	

	case (d_opcode_i)
	  `OPC_LUI: alu_op2 <= 0;
	  `OPC_AUIPC: alu_op2 <= d_pc_i;
	  `OPC_JAL: alu_op2 <= d_pc_i;
	  `OPC_JALR: alu_op2 <= d_pc_i;
145
	  `OPC_OP_IMM: alu_op2 <= d_imm_i;
146 147 148
	  default: alu_op2 <= rs2;
	endcase // case (d_opcode_i)
	
149 150
     end

151
  
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
152 153 154 155
   
   wire[31:0] shifter_result;


156 157
   wire [32:0] alu_addsub_op1 = {d_is_signed_alu_op_i ? alu_op1[31] : 1'b0, alu_op1 };
   wire [32:0] alu_addsub_op2 = {d_is_signed_alu_op_i ? alu_op2[31] : 1'b0, alu_op2 };
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
158 159 160 161


   
   reg [32:0]  alu_addsub_result;
162

Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
163
   always@*
164
     if(d_is_add_i)
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
165 166 167 168 169
       alu_addsub_result <= alu_addsub_op1 + alu_addsub_op2;
     else
       alu_addsub_result <= alu_addsub_op1 - alu_addsub_op2;
   
   
170 171 172 173
   // the ALU itself
   always@*
     begin
	case (d_fun_i)
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
174
	  `FUNC_ADD:
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
175
	    alu_result <= alu_addsub_result[31:0];
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
176
	      
177 178 179
	  `FUNC_XOR: alu_result <= alu_op1 ^ alu_op2;
	  `FUNC_OR: alu_result <= alu_op1 | alu_op2;
	  `FUNC_AND: alu_result <= alu_op1 & alu_op2;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
180 181
	  `FUNC_SLT: alu_result <= alu_addsub_result[32]?1:0;
	  `FUNC_SLTU: alu_result <= alu_addsub_result[32]?1:0;
182 183
	  `FUNC_SL, `FUNC_SR: alu_result <= shifter_result;
	  
184 185 186 187

	  default: alu_result <= 32'hx;
	endcase // case (d_fun_i)
     end // always@ *
188 189

   reg 	shifter_req_d0;
190 191
   wire shifter_req = !w_stall_req_i && (d_valid_i) && d_is_shift_i;
   
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
      
   rv_shifter shifter 
     (
      .clk_i(clk_i),
      .rst_i(rst_i),

      .d_i(alu_op1),
      .q_o(shifter_result),
      .shift_i(alu_op2[4:0]),
      .func_i(d_fun_i),
      .arith_i(d_shifter_sign_i)
      );



   always@(posedge clk_i)
     shifter_req_d0 <= shifter_req;
   
   wire shifter_stall_req = shifter_req && !shifter_req_d0;
211 212
   
   // rdest write value
213
   always@*
214 215
    begin
       case (d_opcode_i)
216
	 `OPC_OP_IMM, `OPC_OP, `OPC_JAL, `OPC_JALR, `OPC_LUI, `OPC_AUIPC:
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	   begin  
	      rd_value <= alu_result;
	      rd_write <= 1;
	   end
	 
	 default: 
	   begin
	    rd_value <= 32'hx;
	    rd_write <= 0;
	   end
       endcase
    end

   // generate load/store address
   always@*
     begin
	case (d_opcode_i) 
234 235
	  `OPC_LOAD: dm_addr <= rs1 + d_imm_i;
	  `OPC_STORE: dm_addr <= rs1 + d_imm_i;
236 237 238 239 240 241 242 243
	  default: dm_addr <= 32'hx;
	  
	endcase // case (d_opcode_i)
     end

   // generate store value/select
   always@*
     begin
244
	case (d_fun_i)
245 246 247 248 249 250 251 252 253 254 255 256 257
	  `LDST_B: 
	    begin
	       dm_data_s <= { rs2[7:0], rs2[7:0], rs2[7:0], rs2[7:0] };
	       dm_select_s[0] <= (dm_addr [1:0] == 2'b00);
	       dm_select_s[1] <= (dm_addr [1:0] == 2'b01);
	       dm_select_s[2] <= (dm_addr [1:0] == 2'b10);
	       dm_select_s[3] <= (dm_addr [1:0] == 2'b11);
	    end
	  
	  `LDST_H:
	    begin
	       dm_data_s <= { rs2[15:0], rs2[15:0] };
	       dm_select_s[0] <= (dm_addr [1] == 1'b0);
258 259 260
	       dm_select_s[1] <= (dm_addr [1] == 1'b0);
	       dm_select_s[2] <= (dm_addr [1] == 1'b1);
	       dm_select_s[3] <= (dm_addr [1] == 1'b1);
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
	    end

	  `LDST_L:
	    begin
	       dm_data_s <= rs2;
	       dm_select_s <= 4'b1111;
	    end
	  
	  default:
	    begin
	       dm_data_s <= 32'hx;
	       dm_select_s <= 4'hx;
	    end
	endcase // case (d_fun_i)
     end
   
   

   //branch decision
   always@*
281 282 283 284 285 286 287 288
     case (d_opcode_i)
       `OPC_JAL, `OPC_JALR: 
	 branch_take <= 1;
       `OPC_BRANCH:
	 branch_take <= branch_condition_met;
       default: 
	 branch_take <= 0;
     endcase // case (d_opcode_i)
289 290
     
   
291
   // generate load/store requests
292 293 294 295 296

   assign dm_addr_o = dm_addr;
   assign dm_data_s_o = dm_data_s;
   assign dm_data_select_o = dm_select_s;

297 298 299
   wire is_load = (d_opcode_i == `OPC_LOAD ? 1: 0) && d_valid_i && !x_kill_i;
   wire is_store = (d_opcode_i == `OPC_STORE ? 1: 0) && d_valid_i && !x_kill_i;

300 301
   assign dm_load_o = is_load && !x_stall_i;
   assign dm_store_o = is_store && !x_stall_i;
302 303 304 305 306 307 308 309 310
   
   always@(posedge clk_i) 
      if (rst_i) begin
	 f_branch_target_o <= 0;
	 f_branch_take_o <= 0;
	 w_rd_write_o <= 0;
	 w_rd_o <= 0;
	 w_fun_o <= 0;
	 w_load_o <= 0;
311
	 w_store_o <= 0;
312 313
	 w_dm_addr_o <= 0;
	 
314
	 
315
      end else if (!x_stall_i) begin
316
	 f_branch_target_o <= branch_target;
317
	 f_branch_take_o <= branch_take && !x_kill_i && d_valid_i;
318 319

	 w_rd_o <= d_rd_i;
320 321
	 
//	 if(!shifter_stall_req)
322
	 w_rd_value_o <= rd_value;
323
	 w_rd_write_o <= rd_write && !x_kill_i && d_valid_i;
324 325

	 w_fun_o <= d_fun_i;
326 327
   w_load_o <= is_load;
   
328 329
	 w_store_o <= is_store;
	 
330 331
	 w_dm_addr_o <= dm_addr;
	 
332 333 334 335 336 337
      end else begin // if (!x_stall_i)
	 f_branch_take_o <= 0;
	 w_rd_write_o <= 0;
	 w_load_o <= 0;
	 w_store_o <= 0;
  
338 339
end // else: !if(rst_i)
   
340

Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
341
   
342
   assign x_stall_req_o = shifter_stall_req || ((is_store || is_load) && !dm_ready_i);
343 344
   assign w_load_hazard_o = d_load_hazard_i;
   
345

Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
346 347
   
   
348 349 350 351 352 353 354 355

endmodule