Commit 014209e9 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

code cleanup & relicensing

parent 695e8467
sim_tool = "modelsim"
top_module="main"
syn_device="xc6slx150t"
action = "simulation"
target = "xilinx"
include_dirs=["."]
files = [ "rv_cpu.v",
"rv_exec.v",
"rv_fetch.v",
"rv_predecode.v",
"rv_regfile.v",
"rv_writeback.v",
"rv_shifter.v",
"rv_multiply.v",
"rv_divide.v",
"rv_csr.v",
"rv_timer.v",
"rv_exceptions.v",
files = [ "urv_cpu.v",
"urv_exec.v",
"urv_fetch.v",
"urv_decode.v",
"urv_regfile.v",
"urv_writeback.v",
"urv_shifter.v",
"urv_multiply.v",
"urv_divide.v",
"urv_csr.v",
"urv_timer.v",
"urv_exceptions.v",
"urv_iram.v",
"xrv_core.vhd" ];
"xurv_core.vhd" ];
# "../sim/rv_icache_model.sv"];
This diff is collapsed.
/*
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 twl <twlostow@printf.cc>.
Copyright (c) 2015 CERN
Author: Tomasz Włostowski <tomasz.wlostowski@cern.ch>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
......@@ -18,11 +19,11 @@
*/
`include "rv_defs.v"
`include "urv_defs.v"
`timescale 1ns/1ps
module rv_csr
module urv_csr
(
input clk_i,
input rst_i,
......
`timescale 1ns/1ps
`include "urv_defs.v"
module urv_debug
(
input clk_i,
input rst_i,
input x_kill_i,
input x_stall_i,
output x_stall_req_o,
output d_kill_req_o,
output f_kill_req_o,
output halt_o,
input x_valid_i,
input [31:0] x_pc_i,
input x_dm_load_i,
input x_dm_store_i,
input [31:0] x_dm_addr_i,
input [31:0] x_dm_data_s_i,
input [3:0] x_dm_data_select_i,
output [31:0] w_dm_data_l_o,
output w_dm_store_done_o,
output w_dm_load_done_o,
output x_dm_ready_o,
output dm_load_o,
output dm_store_o,
output [31:0] dm_addr_o,
output [31:0] dm_data_s_o,
output [3:0] dm_data_select_o,
input [31:0] dm_data_l_i,
input dm_store_done_i,
input dm_load_done_i,
input dm_ready_i,
output [4:0] rf_index_o,
input [31:0] rf_data_r_i
output [31:0] rf_data_w_o,
output rf_write_o,
output [31:0] f_pc_restore_o,
output f_pc_restore_load_o,
input [6:0] dbg_adr_i,
input [7:0] dbg_dat_i,
input dbg_stb_i,
input dbg_we_i,
output [7:0] dbg_dat_o,
output dbg_irq_o
);
parameter g_num_breakpoints = 4;
`define BREAK_SRC_PC 0
`define BREAK_SRC_MEM_ADDR 1
`define BREAK_SRC_MEM_ST_DATA 2
`define BREAK_SRC_MEM_LD_DATA 3
reg [31:0] break_compare_hi [0:g_num_breakpoints-1];
reg [31:0] break_compare_lo [0:g_num_breakpoints-1];
reg [1:0] break_src [0:g_num_breakpoints-1];
reg break_valid[0:g_num_breakpoints-1];
reg [31:0] in_muxed[0 : g_num_breakpoints-1];
reg in_valid[0:g_num_breakpoints-1];
reg break_hit[0: g_num_breakpoints-1];
`define ST_IDLE 0
generate
genvar gg;
for (gg = 0; gg < g_num_breakpoints; gg = gg + 1)
begin
always@*
case (break_src[gg])
`BREAK_SRC_PC: in_muxed[gg] <= x_pc_i;
`BREAK_SRC_MEM_ADDR: in_muxed[gg] <= x_dm_addr_i;
`BREAK_SRC_MEM_ST_DATA: in_muxed[gg] <= x_dm_data_s_i;
`BREAK_SRC_MEM_ST_DATA: in_muxed[gg] <= dm_data_l_i;
endcase // case (break_src[gg])
case (break_src[gg])
`BREAK_SRC_PC:
begin
in_muxed[gg] <= x_pc_i;
in_valid[gg] <= x_valid_i;
end
`BREAK_SRC_MEM_ADDR:
begin
in_muxed[gg] <= x_dm_addr_i;
in_valid[gg] <= x_dm_load_i || x_dm_store_i;
end
`BREAK_SRC_MEM_ST_DATA:
begin
in_muxed[gg] <= x_dm_data_s_i;
in_valid[gg] <= x_dm_store_i;
end
`BREAK_SRC_MEM_LD_DATA:
begin
in_muxed[gg] <= dm_data_l_i;
in_valid[gg] <= dm_load_done_i;
end
endcase // case (break_src[gg])
break_hit[gg] <= ( in_muxed[gg] >= break_comp1[gg] && in_muxed[gg] <= break_comp[gg] ) ? in_valid[gg] : 1'b0;
end
endgenerate
reg trigger_reload_pc;
reg trigger_halt;
reg trigger_resume;
reg [31:0] reload_pc_value;
`define DBG_REG_PC0 0
`define DBG_REG_PC1 1
`define DBG_REG_PC2 2
`define DBG_REG_PC3 3
always@(posedge clk_i)
if(rst_i) begin
reload_pc <= 0;
end else begin
trigger_halt <= 0;
trigger_resume <= 0;
trigger_reload_pc <= 0;
if ( dbg_we_i ) begin
case (dbg_adr_i)
`DBG_REG_PCO: reload_pc_value[7:0] <= dbg_dat_i;
`DBG_REG_PC1: reload_pc_value[15:8] <= dbg_dat_i;
`DBG_REG_PC2: reload_pc_value[23:16] <= dbg_dat_i;
`DBG_REG_PC3: reload_pc_value[31:24] <= dbg_dat_i;
`DBG_CTL:
begin
trigger_halt <= dbg_dat_i[0];
trigger_resume <= dbg_dat_i[1];
trigger_reload_pc <= dbg_dat_i[2];
end
endcase // case (dbg_adr_i)
end else begin // if ( dbg_we_i )
case (dbg_adr_i)
`DBG_REG_PCO: dbg_dat_o <= x_pc_i[7:0];
`DBG_REG_PC1: dbg_dat_o <= x_pc_i[15:8];
`DBG_REG_PC2: dbg_dat_o <= x_pc_i[23:16];
`DBG_REG_PC3: dbg_dat_o <= x_pc_i[31:24];
end // else: !if( dbg_we_i )
end // else: !if( dbg_we_i )
end
end
/*
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 twl <twlostow@printf.cc>.
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 CERN
Author: Tomasz Włostowski <tomasz.wlostowski@cern.ch>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
......@@ -18,50 +19,40 @@
*/
`include "rv_defs.v"
`include "urv_defs.v"
`timescale 1ns/1ps
module rv_decode
module urv_decode
(
input clk_i,
input rst_i,
// pipeline control
input d_stall_i,
input d_kill_i,
output d_stall_req_o,
output reg x_load_hazard_o,
// from Fetch stage
input [31:0] f_ir_i,
input [31:0] f_pc_i,
input f_valid_i,
output x_valid_o,
output reg [31:0] x_pc_o,
input d_x_rs1_bypass_i,
input d_x_rs2_bypass_i,
input d_w_rs1_bypass_i,
input d_w_rs2_bypass_i,
// to Register File
output [4:0] rf_rs1_o,
output [4:0] rf_rs2_o,
// to Execute 1 stage
output x_valid_o,
output reg [31:0] x_pc_o,
output [4:0] x_rs1_o,
output [4:0] x_rs2_o,
output [4:0] x_rd_o,
output reg [4:0] x_shamt_o,
output reg [2:0] x_fun_o,
output [4:0] x_opcode_o,
output reg x_shifter_sign_o,
output reg x_is_signed_compare_o,
output reg x_is_signed_alu_op_o,
output reg x_is_add_o,
......@@ -69,40 +60,35 @@ module rv_decode
output reg x_is_load_o,
output reg x_is_store_o,
output reg x_is_undef_o,
output reg [2:0] x_rd_source_o,
output 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,
output reg [31:0] x_imm_o,
output reg [31:0] x_alu_op1_o,
output reg [31:0] x_alu_op2_o,
output reg x_use_op1_o,
output reg x_use_op2_o,
output reg [1:0] x_op1_sel_o,
output reg [1:0] x_op2_sel_o
output reg [1:0] x_op1_sel_o,
output reg [1:0] x_op2_sel_o
);
wire [4:0] f_rs1 = f_ir_i[19:15];
wire [4:0] f_rs2 = f_ir_i[24:20];
wire [4:0] f_rd = f_ir_i[11:7];
wire [4:0] d_opcode = f_ir_i[6:2];
wire [2:0] d_fun = f_ir_i[14:12];
reg [4:0] x_rs1;
reg [4:0] x_rs2;
reg [4:0] x_rd;
reg [4:0] x_opcode;
reg x_valid;
reg x_is_shift;
reg x_rd_write;
reg [4:0] x_rs2;
reg [4:0] x_rd;
reg [4:0] x_opcode;
reg x_valid;
reg x_is_shift;
reg x_rd_write;
assign x_rs1_o = x_rs1;
......@@ -114,26 +100,19 @@ module rv_decode
assign rf_rs2_o = f_rs2;
reg [31:0] x_ir;
wire [4:0] d_opcode = f_ir_i[6:2];
reg load_hazard;
// attempt to reuse ALU for jump address generation
wire [2:0] d_fun = f_ir_i[14:12];
// attempt to reuse ALU for jump address generation
wire d_is_shift = (d_fun == `FUNC_SL || d_fun == `FUNC_SR) &&
(d_opcode == `OPC_OP || d_opcode == `OPC_OP_IMM );
reg x_is_mul;
wire d_is_mul = (f_ir_i[25] && d_fun == 3'b000);
wire d_is_mul = (f_ir_i[25] && d_fun == `FUNC_MUL);
// hazzard detect combinatorial logic
always@*
if (x_valid && f_valid_i && ( (f_rs1 == x_rd) || (f_rs2 == x_rd) ) && (!d_kill_i) )
if ( x_valid && f_valid_i && ( (f_rs1 == x_rd) || (f_rs2 == x_rd) ) && (!d_kill_i) )
begin
case (x_opcode)
`OPC_LOAD:
......@@ -149,13 +128,13 @@ module rv_decode
load_hazard <= 0;
reg inserting_nop;
// bubble insertion following a hazzard
always@(posedge clk_i)
if(rst_i) begin
if(rst_i)
inserting_nop <= 0;
end else if (!d_stall_i)
begin
else if (!d_stall_i)
begin
if (inserting_nop)
inserting_nop <= 0;
else
......@@ -164,9 +143,7 @@ module rv_decode
assign d_stall_req_o = load_hazard && !inserting_nop;
wire [4:0] f_rd = f_ir_i[11:7];
assign x_valid_o = x_valid;
always@(posedge clk_i)
......@@ -174,7 +151,7 @@ module rv_decode
begin
x_pc_o <= 0;
x_valid <= 0;
end else if(!d_stall_i) begin
end else if(!d_stall_i) begin
x_pc_o <= f_pc_i;
if (load_hazard && !inserting_nop)
......@@ -182,8 +159,6 @@ module rv_decode
else
x_valid <= f_valid_i;
x_ir <= f_ir_i;
x_rs1 <= f_rs1;
x_rs2 <= f_rs2;
x_rd <= f_rd;
......@@ -192,7 +167,7 @@ module rv_decode
x_shamt_o <= f_ir_i[24:20];
end
// ALU function decoding
always@(posedge clk_i)
if(!d_stall_i)
case (d_opcode)
......@@ -200,7 +175,7 @@ module rv_decode
x_fun_o <= `FUNC_ADD;
default:
x_fun_o <= d_fun;
endcase // case (f_opcode)
endcase // case (f_opcode)
always@(posedge clk_i)
if(!d_stall_i)
......@@ -217,7 +192,8 @@ module rv_decode
reg [31:0] d_imm;
// Immediate decode, comb part
always@*
case(d_opcode)
`OPC_LUI, `OPC_AUIPC: d_imm <= d_imm_u;
......@@ -229,11 +205,13 @@ module rv_decode
default: d_imm <= 32'hx;
endcase // case (opcode)
// Immediate decode, seq part
always@(posedge clk_i)
if(!d_stall_i)
x_imm_o <= d_imm;
// ALU operand decoding
always@(posedge clk_i)
if(!d_stall_i)
begin
......@@ -295,7 +273,6 @@ module rv_decode
x_is_store_o <= ( d_opcode == `OPC_STORE && !load_hazard) ? 1'b1 : 1'b0;
x_is_mul <= d_is_mul;
case (d_opcode)
`OPC_BRANCH:
......@@ -303,9 +280,6 @@ module rv_decode
default:
x_is_signed_alu_op_o <= (d_fun == `FUNC_SLT);
endcase // case (d_opcode)
case (d_opcode)
`OPC_OP:
......@@ -317,10 +291,9 @@ module rv_decode
default:
x_is_add_o <= 1;
endcase // case (d_opcode)
// all multiply/divide instructions except MUL
x_is_undef_o <= (d_opcode == `OPC_OP && f_ir_i[25] && d_fun != 3'b000);
x_is_undef_o <= (d_opcode == `OPC_OP && f_ir_i[25] && d_fun != `FUNC_MUL);
if(d_is_shift)
x_rd_source_o <= `RD_SOURCE_SHIFTER;
......@@ -330,8 +303,6 @@ module rv_decode
x_rd_source_o <= `RD_SOURCE_MULTIPLY;
else
x_rd_source_o <= `RD_SOURCE_ALU;
// rdest write value
case (d_opcode)
......@@ -345,26 +316,20 @@ module rv_decode
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
assign x_is_shift_o = x_is_shift;
assign x_rd_write_o = x_rd_write;
endmodule // rv_predecode
endmodule // rv_decode
/*
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 twl <twlostow@printf.cc>.
Copyright (c) 2015 CERN
Author: Tomasz Włostowski <tomasz.wlostowski@cern.ch>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
......@@ -18,6 +19,8 @@
*/
`include "urv_config.v"
`define OPC_OP_IMM 5'b00100
`define OPC_LUI 5'b01101
`define OPC_AUIPC 5'b00101
......
`include "rv_defs.v"
/*
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 CERN
Author: Tomasz Włostowski <tomasz.wlostowski@cern.ch>
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 "urv_defs.v"
`timescale 1ns/1ps
module rv_divide
module urv_divide
(
input clk_i,
input rst_i,
input x_stall_i,
input x_kill_i,
output x_stall_req_o,
input d_valid_i,
input d_is_divide_i,
input [31:0] d_rs1_i,
input [31:0] d_rs2_i,
......@@ -120,132 +142,3 @@ module rv_divide
endmodule // rv_divide
module rv_divide_nonrestoring
(
input clk_i,
input rst_i,
input x_stall_i,
input x_kill_i,
output x_stall_req_o,
input d_valid_i,
input d_is_divide_i,
input [31:0] d_rs1_i,
input [31:0] d_rs2_i,
input [2:0] d_fun_i,
output reg [31:0] x_rd_o
);
reg [31:0] a,n,d,q;
reg n_sign, d_sign;
reg [5:0] state;
wire [32:0] alu_result;
reg [31:0] alu_op1;
reg [31:0] alu_op2;
reg is_rem;
wire [31:0] a_next = { a[30:0], 1'b0 };
always@*
case(state) // synthesis full_case parallel_case
0: begin alu_op1 <= 'hx; alu_op2 <= 'hx; end
1: begin alu_op1 <= 0; alu_op2 <= d_rs1_i; end
2: begin alu_op1 <= 0; alu_op2 <= d_rs2_i; end
35: begin alu_op1 <= a; alu_op2 <= d; end
36: begin alu_op1 <= 0; alu_op2 <= q; end
37: begin alu_op1 <= 0; alu_op2 <= a; end
default: begin alu_op1 <= a_next; alu_op2 <= d; end
endcase // case (state)
reg alu_sub;
assign alu_result = alu_sub ? {1'b0, alu_op1} - {1'b0, alu_op2} : {1'b0, alu_op1} + {1'b0, alu_op2};
wire alu_ge = ~alu_result [32];
wire start_divide = !x_stall_i && !x_kill_i && d_valid_i && d_is_divide_i;
wire done = (is_rem ? state == 38 : state == 37 );
assign x_stall_req_o = (start_divide || !done);
always@*
case (state) // synthesis full_case parallel_case
1:
alu_sub <= n_sign;
2:
alu_sub <= d_sign;
35:
alu_sub <= 0;
36:
alu_sub <= n_sign ^ d_sign;
37:
alu_sub <= n_sign;
default:
alu_sub <= ~a_next[31];
endcase // case (state)
always@(posedge clk_i)
if(rst_i || done)
state <= 0;
else if (state != 0 || start_divide)
state <= state + 1;
always@(posedge clk_i)
case ( state ) // synthesis full_case parallel_case
0:
if(start_divide)
begin
//q <= 0;
a <= 0;
is_rem <= (d_fun_i == `FUNC_REM || d_fun_i ==`FUNC_REMU);
n_sign <= d_rs1_i[31];
d_sign <= d_rs2_i[31];
end
1:
q <= alu_result[31:0];
2:
d <= alu_result[31:0];
35: // correction step
if(a[31])
a <= alu_result;
36:
x_rd_o <= alu_result; // quotient
37:
x_rd_o <= alu_result; // remainder
default: // 3..34: 32 divider iterations
begin
a <= alu_result;
q <= { q[30:0], ~alu_result[31] };