Commit 7dc634dc authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

working on exceptions

parent b57333c6
......@@ -13,4 +13,7 @@ files = [ "rv_cpu.v",
"rv_regfile.v",
"rv_writeback.v",
"rv_shifter.v",
"rv_multiply.v"];
"rv_multiply.v",
"rv_csr.v",
"rv_timer.v",
"rv_exceptions.v"];
......@@ -27,6 +27,8 @@ module rv_cpu
input clk_i,
input rst_i,
input irq_i,
// instruction mem I/F
output [31:0] im_addr_o,
input [31:0] im_data_i,
......@@ -51,7 +53,7 @@ module rv_cpu
wire x_kill;
wire f_kill;
wire [31:0] f2d_pc, f2d_pc_plus_4, f2d_ir;
wire [31:0] f2d_pc, f2d_ir;
wire f2d_ir_valid;
wire [31:0] x2f_pc_bra;
wire x2f_bra;
......@@ -77,13 +79,17 @@ module rv_cpu
wire d2x_is_signed_alu_op;
wire d2x_is_add_o;
wire d2x_is_shift_o;
wire [1:0] d2x_rd_source;
wire [2:0] d2x_rd_source;
wire d2x_rd_write;
wire [11:0] d2x_csr_sel;
wire [4:0] d2x_csr_imm;
wire d2x_is_csr, d2x_is_eret, d2x_csr_load_en;
wire d2x_load_hazard;
wire d_stall, d_kill;
wire [39:0] csr_time, csr_cycles;
rv_fetch fetch
(
......@@ -142,7 +148,14 @@ module rv_cpu
.x_is_add_o(d2x_is_add),
.x_is_shift_o(d2x_is_shift),
.x_rd_source_o(d2x_rd_source),
.x_rd_write_o(d2x_rd_write)
.x_rd_write_o(d2x_rd_write),
.x_csr_sel_o ( d2x_csr_sel),
.x_csr_imm_o ( d2x_csr_imm),
.x_is_csr_o ( d2x_is_csr ),
.x_is_eret_o ( d2x_is_eret )
);
wire [4:0] x2w_rd;
......@@ -196,6 +209,8 @@ module rv_cpu
wire w_stall_req;
rv_exec execute
(
......@@ -204,11 +219,19 @@ module rv_cpu
.x_stall_i(x_stall),
.x_kill_i(x_kill),
.irq_i ( irq_i ),
.x_stall_req_o(x_stall_req),
.w_stall_req_i(w_stall_req),
.d_valid_i(d2x_valid),
.d_is_csr_i ( d2x_is_csr ),
.d_is_eret_i ( d2x_is_eret ),
.d_csr_imm_i ( d2x_csr_imm ),
.d_csr_sel_i (d2x_csr_sel),
.d_load_hazard_i(d2x_load_hazard),
.d_pc_i(d2x_pc),
.d_rd_i(d2x_rd),
......@@ -248,7 +271,12 @@ module rv_cpu
.dm_data_select_o(dm_data_select_o),
.dm_store_o(dm_store_o),
.dm_load_o(dm_load_o),
.dm_ready_i(dm_ready_i)
.dm_ready_i(dm_ready_i),
.csr_time_i (csr_time),
.csr_cycles_i (csr_cycles),
.timer_tick_i (sys_tick)
);
......@@ -281,6 +309,17 @@ module rv_cpu
.rf_rd_write_o(rf_rd_write)
);
rv_timer ctimer (
.clk_i(clk_i),
.rst_i(rst_i),
.csr_time_o(csr_time),
.csr_cycles_o(csr_cycles),
.sys_tick_o(sys_tick)
);
reg x2f_bra_d0, x2f_bra_d1;
always@(posedge clk_i)
......
/*
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_csr
(
input clk_i,
input rst_i,
input x_stall_i,
input d_csr_write_rd_i,
input x_kill_i,
input d_is_csr_i,
input [2:0] d_fun_i,
input [4:0] d_csr_imm_i,
input [11:0] d_csr_sel_i,
input [31:0] d_rs1_i,
input [31:0] d_pc_i, // for exception strage
output reg [31:0] x_rd_o,
output reg x_rd_write_o,
input x_exception_i,
input x_exception_irq_i,
input [2:0] x_exception_id_i
input [39:0] csr_time_i,
input [39:0] csr_cycles_i,
// interrupt management
output [31:0] x_csr_write_value_o,
input [31:0] csr_mstatus_i,
input [31:0] csr_mip_i,
input [31:0] csr_mie_i,
input [31:0] csr_mepc_i,
input [31:0] csr_mcause_i
output [31:0] x_exception_pc_o
);
reg [31:0] csr_mepc;
reg [31:0] csr_mscratch;
reg [31:0] csr_mcause;
reg [31:0] csr_mstatus;
reg [31:0] csr_mscratch = 0;
wire csr_mie;
reg [31:0] csr_in1;
reg [31:0] csr_in2;
reg [31:0] csr_out;
always@*
case(d_csr_sel_i)
`CSR_ID_CYCLESL: csr_in1 <= csr_cycles_i[31:0];
`CSR_ID_CYCLESH: csr_in1 <= { 24'h0, csr_cycles_i[39:32] };
`CSR_ID_TIMEL: csr_in1 <= csr_time_i[31:0];
`CSR_ID_TIMEH: csr_in1 <= { 24'h0, csr_time_i[39:32] };
`CSR_ID_MSCRATCH: csr_in1 <= csr_mscratch;
`CSR_ID_MEPC: csr_in1 <= csr_mepc_i;
`CSR_ID_MSTATUS: csr_in1 <= csr_mstatus_i;
`CSR_ID_MCAUSE: csr_in1 <= csr_mcause_i;
`CSR_ID_MIP: csr_in1 <= csr_mip_i;
`CSR_ID_MIE: csr_in1 <= csr_mie_i;
default: csr_in1 <= 32'hx;
endcase // case (d_csr_sel_i)
always@*
x_rd_o <= csr_in1;
genvar i;
assign x_exception_pc_o = csr_mepc;
always@*
case (d_fun_i)
`CSR_OP_CSRRWI,
`CSR_OP_CSRRSI,
`CSR_OP_CSRRCI:
csr_in2 <= {27'b0, d_csr_imm_i };
default:
csr_in2 <= d_rs1_i;
endcase // case (d_fun_i)
generate
for (i=0;i<32;i=i+1)
begin
always@*
case(d_fun_i)
`CSR_OP_CSRRWI,
`CSR_OP_CSRRW:
csr_out[i] <= csr_in2[i];
`CSR_OP_CSRRCI,
`CSR_OP_CSRRC:
csr_out[i] <= csr_in2[i] ? 1'b0 : csr_in1[i];
`CSR_OP_CSRRSI,
`CSR_OP_CSRRS:
csr_out[i] <= csr_in2[i] ? 1'b1 : csr_in1[i];
default:
csr_out[i] <= 32'hx;
endcase // case (d_csr_op_i)
end // for (i=0;i<32;i=i+1)
endgenerate
always@(posedge clk_i)
if(rst_i)
csr_mscratch <= 0;
else if(!x_stall_i && !x_kill_i && d_is_csr_i)
case (d_csr_sel_i)
`CSR_ID_MSCRATCH:
csr_mscratch <= csr_out;
endcase // case (d_csr_sel_i)
assign x_csr_write_value_o = csr_out;
endmodule
......@@ -27,6 +27,7 @@
`define OPC_BRANCH 5'b11000
`define OPC_LOAD 5'b00000
`define OPC_STORE 5'b01000
`define OPC_SYSTEM 5'b11100
`define BRA_EQ 3'b000
`define BRA_NEQ 3'b001
......@@ -55,7 +56,38 @@
`define FUNC_MULHSU 3'b010
`define FUNC_MULHU 3'b011
`define RD_SOURCE_ALU 2'b00
`define RD_SOURCE_SHIFTER 2'b10
`define RD_SOURCE_MULTIPLY 2'b01
`define RD_SOURCE_DIVIDE 2'b11
`define RD_SOURCE_ALU 3'b000
`define RD_SOURCE_SHIFTER 3'b010
`define RD_SOURCE_MULTIPLY 3'b001
`define RD_SOURCE_DIVIDE 3'b011
`define RD_SOURCE_CSR 3'b011
`define CSR_ID_CYCLESH 12'hc80
`define CSR_ID_CYCLESL 12'hc00
`define CSR_ID_TIMEH 12'hc81
`define CSR_ID_TIMEL 12'hc01
`define CSR_ID_MSCRATCH 12'h340
`define CSR_ID_MEPC 12'h341
`define CSR_ID_MSTATUS 12'h300
`define CSR_ID_MCAUSE 12'h342
`define CSR_ID_MIP 12'h344
`define CSR_ID_MIE 12'h304
`define CSR_OP_CSRRW 3'b001
`define CSR_OP_CSRRS 3'b010
`define CSR_OP_CSRRC 3'b011
`define CSR_OP_CSRRWI 3'b101
`define CSR_OP_CSRRSI 3'b110
`define CSR_OP_CSRRCI 3'b111
`define URV_RESET_VECTOR 32'h00000000
`define URV_TRAP_VECTOR 32'h00000040
`define EXCEPT_ILLEGAL_INSN 2
`define EXCEPT_BREAKPOINT 3
`define EXCEPT_UNALIGNED_LOAD 4
`define EXCEPT_UNALIGNED_STORE 6
`define EXCEPT_TIMER 9
`define EXCEPT_IRQ 10
......@@ -41,6 +41,7 @@ module rv_exec
input [31:0] rf_rs1_value_i,
input [31:0] rf_rs2_value_i,
input d_valid_i,
input d_load_hazard_i,
......@@ -48,18 +49,25 @@ module rv_exec
input [4:0] d_opcode_i,
input d_shifter_sign_i,
input d_is_csr_i,
input d_is_eret_i,
input [4:0] d_csr_imm_i,
input [11:0] d_csr_sel_i,
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,
input [1:0] d_rd_source_i,
input [2:0] d_rd_source_i,
input d_rd_write_i,
output reg [31:0] f_branch_target_o,
output f_branch_take_o,
output w_load_hazard_o,
input irq_i,
// Writeback stage I/F
output reg [2:0 ] w_fun_o,
......@@ -77,9 +85,16 @@ module rv_exec
output [3:0] dm_data_select_o,
output dm_store_o,
output dm_load_o,
input dm_ready_i
input dm_ready_i,
input [39:0] csr_time_i,
input [39:0] csr_cycles_i,
input timer_tick_i
);
parameter g_exception_vector = 'h40;
wire [31:0] rs1, rs2;
assign rs1 = rf_rs1_value_i;
......@@ -87,8 +102,7 @@ module rv_exec
reg [31:0] alu_op1, alu_op2, alu_result;
reg [31:0] rd_value;
reg branch_take;
reg branch_condition_met;
......@@ -106,6 +120,85 @@ module rv_exec
reg f_branch_take;
wire x_stall_req_shifter;
wire x_stall_req_multiply = 0;
wire x_stall_req_divide = 0;
wire [31:0] rd_shifter;
wire [31:0] rd_csr;
wire [31:0] rd_mul;
wire [31:0] rd_div;
wire exception;
wire [31:0] csr_mie, csr_mip, csr_mepc, csr_mstatus,csr_mcause;
wire [31:0] csr_write_value;
wire [31:0] exception_address;
rv_csr csr_regs
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i(x_stall_i),
.x_kill_i(x_kill_i),
.d_is_csr_i(d_is_csr_i),
.d_fun_i(d_fun_i),
.d_csr_imm_i(d_csr_imm_i),
.d_csr_sel_i (d_csr_sel_i),
.d_rs1_i(rs1),
.x_rd_o(rd_csr),
.x_csr_write_value_o(csr_write_value),
.csr_time_i(csr_time_i),
.csr_cycles_i(csr_cycles_i),
.csr_mstatus_i(csr_mstatus),
.csr_mip_i(csr_mip),
.csr_mie_i(csr_mie),
.csr_mepc_i(csr_mepc),
.csr_mcause_i(csr_mmause)
);
rv_exceptions exception_unit
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i (x_stall_i),
.x_kill_i (x_kill_i),
.d_is_csr_i(d_is_csr_i),
.d_is_eret_i (d_is_eret_i),
.d_fun_i(d_fun_i),
.d_csr_imm_i(d_csr_imm_i),
.d_csr_sel_i(d_csr_sel_i),
.x_csr_write_value_i(csr_write_value),
.exp_irq_i(irq_i),
.exp_tick_i(timer_tick_i),
.exp_breakpoint_i(1'b0),
.exp_unaligned_load_i(1'b0),
.exp_unaligned_store_i(1'b0),
.exp_invalid_insn_i(1'b0),
.x_exception_o(exception),
.x_exception_pc_i(d_pc_i),
.x_exception_pc_o(exception_address),
.csr_mstatus_o(csr_mstatus),
.csr_mip_o(csr_mip),
.csr_mie_o(csr_mie),
.csr_mepc_o(csr_mepc),
.csr_mcause_o(csr_mcause)
);
// branch condition decoding
always@*
......@@ -120,13 +213,16 @@ module rv_exec
endcase // case (d_fun_i)
always@*
case (d_opcode_i)
`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;
default: branch_target<= 32'hx;
endcase // case (d_opcode_i)
if(d_is_eret_i )
branch_target <= exception_address;
else if ( exception )
branch_target <= g_exception_vector;
else case (d_opcode_i)
`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;
default: branch_target<= 32'hx;
endcase // case (d_opcode_i)
// decode ALU operands
always@*
......@@ -185,12 +281,6 @@ module rv_exec
endcase // case (d_fun_i)
end // always@ *
wire x_stall_req_shifter;
wire x_stall_req_multiply = 0;
wire x_stall_req_divide = 0;
wire [31:0] rd_shifter;
rv_shifter shifter
(
......@@ -215,6 +305,7 @@ module rv_exec
case (d_rd_source_i)
`RD_SOURCE_ALU: rd_value <= alu_result;
`RD_SOURCE_SHIFTER : rd_value <= rd_shifter;
`RD_SOURCE_CSR: rd_value <= rd_csr;
default: rd_value <= 32'hx;
endcase // case (x_rd_source_i)
......@@ -266,14 +357,17 @@ module rv_exec
//branch decision
always@*
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)
if( exception || d_is_eret_i)
branch_take <= 1;
else
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)
// generate load/store requests
......@@ -287,6 +381,7 @@ module rv_exec
assign dm_load_o = is_load;
assign dm_store_o = is_store;
always@(posedge clk_i)
if (rst_i) begin
......@@ -308,12 +403,11 @@ module rv_exec
// if(!shifter_stall_req)
w_rd_value_o <= rd_value;
w_rd_write_o <= d_rd_write_i && !x_kill_i && d_valid_i;
w_rd_write_o <= d_rd_write_i && !x_kill_i && d_valid_i && !exception;
w_fun_o <= d_fun_i;
w_load_o <= is_load;
w_store_o <= is_store;
w_load_o <= is_load && !exception;
w_store_o <= is_store && !exception;
w_dm_addr_o <= dm_addr;
......
......@@ -51,13 +51,12 @@ module rv_fetch
always@*
if( x_bra_i )
pc_next <= x_pc_bra_i;
else if (f_stall_i || !im_valid_i)
else if (!rst_d || f_stall_i || !im_valid_i)
pc_next <= pc;
else
pc_next <= pc + 4;
assign f_ir_o = ir;
assign im_addr_o = pc_next;
......@@ -78,7 +77,7 @@ module rv_fetch
f_pc_o <= pc;
if(im_valid_i) begin
ir <= im_data_i; // emit nop
ir <= im_data_i;
f_valid_o <= (rst_d && !f_kill_i);
end else begin// if (i_valid_i)
f_valid_o <= 0;
......
/*
`include "rv_defs.v"
`timescale 1ns/1ps
......@@ -8,60 +7,48 @@ module rv_multiply
input clk_i,
input rst_i,
input x_stall_i,
input w_stall_req_i,
input d_valid_i,
input d_is_mul_i,
input [31:0] x_rs1_i,
input [31:0] x_rs2_i,
input [31:0] d_rs1_i,
input [31:0] d_rs2_i,
input [4:0] x_opcode_i,
input [2:0] x_fun_i,
input [4:0] d_opcode_i,
input [2:0] d_fun_i,
output [31:0] x_rd_o,
output x_rd_valid_o,
output reg [31:0] x_rd_o,
output x_stall_req_o
);
parameter g_latency = 2;
wire sign_a = ( x_fun_i == `FUNC_MUL || x_fun_i == `FUNC_MULHSU ) ? x_rs1_i[31] : 1'b0;
wire sign_b = ( x_fun_i == `FUNC_MUL ) ? x_rs2_i[31] : 1'b0;
wire sign_a = ( d_fun_i == `FUNC_MUL || d_fun_i == `FUNC_MULHSU ) ? d_rs1_i[31] : 1'b0;
wire sign_b = ( d_fun_i == `FUNC_MUL ) ? d_rs2_i[31] : 1'b0;
wire [32:0] a = { sign_a, x_rs1_i };
wire [32:0] b = { sign_b, x_rs2_i };
reg [65:0] stage0;
wire [32:0] a = { sign_a, d_rs1_i };
wire [32:0] b = { sign_b, d_rs2_i };
reg [3:0] pipe;
always@(posedge clk_i)
if(rst_i)
pipe <= 0;
else if (x_opcode_i = `OPC_MUL )
pipe <= (1<<g_latency);
else
pipe <= {1'b0, pipe [3:1]};
reg [65:0] stage0, stage1;
always@(posedge clk_i)
begin
stage0 <= $signed(a) * $signed(b);
if( d_fun_i != `FUNC_MUL )
x_rd_o <= stage0[63:32];
else
x_rd_o <= stage0[31:0];
end
if(!x_stall_i)
begin
stage0 <= $signed(a) * $signed(b);
stage1 <= stage0;
end
always@*
if( d_fun_i != `FUNC_MUL )
x_rd_o <= stage1[63:32];
else
x_rd_o <= stage1[31:0];
endmodule // rv_multiply
*/
......@@ -60,9 +60,14 @@ module rv_decode
output reg x_is_signed_alu_op_o,
output reg x_is_add_o,
output reg x_is_shift_o,
output reg [1:0] x_rd_source_o,
output reg x_rd_write_o
output reg [2:0] x_rd_source_o,
output reg x_rd_write_o,
output reg [11:0] x_csr_sel_o,
output reg [4:0] x_csr_imm_o,
output reg x_is_csr_o,
output reg x_is_eret_o
);
......@@ -181,6 +186,8 @@ module rv_decode
if(d_is_shift)
x_rd_source_o <= `RD_SOURCE_SHIFTER;
else if (d_opcode == `OPC_SYSTEM)
x_rd_source_o <= `RD_SOURCE_CSR;
else
x_rd_source_o <= `RD_SOURCE_ALU;
......@@ -188,12 +195,28 @@ module rv_decode
case (d_opcode)
`OPC_OP_IMM, `OPC_OP, `OPC_JAL, `OPC_JALR, `OPC_LUI, `OPC_AUIPC:
x_rd_write_o <= 1;
`OPC_SYSTEM:
x_rd_write_o <= (d_fun != 0); // CSR instructions write to RD
default:
x_rd_write_o <= 0;
endcase // case (d_opcode)
end // if (!d_stall_i)
// CSR/supervisor instructions
always@(posedge clk_i)
if (!d_stall_i)
begin
x_csr_imm_o <= f_ir_i[19:15];
x_csr_sel_o <= f_ir_i[31:20];
x_is_csr_o <= (d_opcode == `OPC_SYSTEM) && (d_fun != 0);
x_is_eret_o <= (d_opcode == `OPC_SYSTEM) && (d_fun == 0) && (f_ir_i [31:20] == 12'b000100000000);
end
......
......@@ -101,3 +101,98 @@ module rv_shifter
endmodule // rv_shifter
module rv_shifter2
(
input clk_i,
input rst_i,