Commit 54104d93 authored by Tristan Gingold's avatar Tristan Gingold

Merge branch 'proposed_master'

parents 9016844b fa17e819
......@@ -11,4 +11,6 @@ files = [ "urv_cpu.v",
"urv_timer.v",
"urv_exceptions.v",
"urv_iram.v",
"xurv_core.vhd" ];
"urv_ecc.v",
"xurv_core.vhd",
"urv_pkg.vhd" ]
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: na
--
-- description: uRV configuration
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
// Platform definition. Currently supported ones are:
// SPARTAN6 - Xilinx Spartan-6 FPGA
// GENERIC - Generic, HW-independent
`define URV_PLATFORM_SPARTAN6 1
`define URV_PLATFORM_GENERIC 1
//`define URV_PLATFORM_SPARTAN6 1
//`define URV_PLATFORM_ALTERA 1
This diff is collapsed.
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_csr
--
-- description: uRV CSR
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -39,7 +44,7 @@ module urv_csr
input [31:0] d_rs1_i,
output reg [31:0] x_rd_o,
output [31:0] x_rd_o,
input [39:0] csr_time_i,
input [39:0] csr_cycles_i,
......@@ -52,12 +57,19 @@ module urv_csr
input [31:0] csr_mip_i,
input [31:0] csr_mie_i,
input [31:0] csr_mepc_i,
input [31:0] csr_mcause_i
input [31:0] csr_mcause_i,
// Debug mailboxes
input [31:0] dbg_mbx_data_i,
input dbg_mbx_write_i,
output [31:0] dbg_mbx_data_o
);
parameter g_with_hw_debug = 0;
reg [31:0] csr_mscratch;
reg [31:0] mbx_data;
reg [31:0] csr_in1;
reg [31:0] csr_in2;
reg [31:0] csr_out;
......@@ -75,11 +87,12 @@ module urv_csr
`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;
`CSR_ID_DBGMBX: csr_in1 <= g_with_hw_debug ? mbx_data : 32'h0;
`CSR_ID_MIMPID: csr_in1 <= 32'h20190131;
default: csr_in1 <= 32'h0;
endcase // case (d_csr_sel_i)
always@*
x_rd_o <= csr_in1;
assign x_rd_o = csr_in1;
genvar i;
......@@ -95,8 +108,6 @@ module urv_csr
endcase // case (d_fun_i)
generate
for (i=0;i<32;i=i+1)
begin : gen_csr_bits
......@@ -115,28 +126,31 @@ module urv_csr
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)
endgenerate
always@(posedge clk_i)
if(rst_i)
begin
csr_mscratch <= 0;
mbx_data <= 0;
end
else
begin
if (dbg_mbx_write_i && g_with_hw_debug)
mbx_data <= dbg_mbx_data_i;
if(!x_stall_i && !x_kill_i && d_is_csr_i)
case (d_csr_sel_i)
`CSR_ID_MSCRATCH:
csr_mscratch <= csr_out;
`CSR_ID_DBGMBX:
if(g_with_hw_debug)
mbx_data <= csr_out;
endcase // case (d_csr_sel_i)
end // else: !if(rst_i)
assign dbg_mbx_data_o = mbx_data;
assign x_csr_write_value_o = csr_out;
endmodule
......@@ -17,7 +17,7 @@ module urv_debug
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,
......@@ -46,7 +46,7 @@ module urv_debug
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,
......@@ -62,22 +62,22 @@ module urv_debug
`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];
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@*
......@@ -90,30 +90,30 @@ module urv_debug
endcase // case (break_src[gg])
case (break_src[gg])
`BREAK_SRC_PC:
`BREAK_SRC_PC:
begin
in_muxed[gg] <= x_pc_i;
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:
`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:
`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;
......@@ -125,14 +125,14 @@ module urv_debug
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
......@@ -142,25 +142,25 @@ module urv_debug
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
`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)
......@@ -169,23 +169,21 @@ module urv_debug
`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
end
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_decode
--
-- description: uRV CPU: instruction decode stage
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -49,32 +54,38 @@ module urv_decode
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,
output x_is_shift_o,
output reg x_is_load_o,
output reg x_is_store_o,
output reg x_is_undef_o,
output reg x_is_write_ecc_o,
output reg x_is_fix_ecc_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 x_is_mret_o,
output reg x_is_ebreak_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 x_use_rs1_o,
output reg x_use_rs2_o,
output reg x_is_divide_o,
output reg x_is_multiply_o
);
parameter g_with_hw_div = 0;
parameter g_with_hw_mul = 0;
parameter g_with_hw_debug = 0;
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];
......@@ -102,13 +113,11 @@ module urv_decode
reg load_hazard;
// attempt to reuse ALU for jump address generation
wire d_is_shift = (d_fun == `FUNC_SL || d_fun == `FUNC_SR) &&
wire d_is_shift = !f_ir_i[25] && (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 == `FUNC_MUL);
wire d_is_mul = (f_ir_i[25] && (d_fun == `FUNC_MUL || d_fun == `FUNC_MULH || d_fun == `FUNC_MULHU || d_fun == `FUNC_MULHSU) );
// hazzard detect combinatorial logic
always@*
......@@ -118,28 +127,26 @@ module urv_decode
`OPC_LOAD:
load_hazard <= 1;
`OPC_OP:
// 2 cycles instructions
load_hazard <= x_is_shift | x_is_mul;
`OPC_OP_IMM:
// 2 cycles instructions
load_hazard <= x_is_shift;
default:
load_hazard <= 0;
endcase // case (x_opcode)
end else
end
else
load_hazard <= 0;
reg inserting_nop;
// bubble insertion following a hazzard
// bubble insertion following a hazard (only 1 bubble).
always@(posedge clk_i)
if(rst_i)
inserting_nop <= 0;
else if (!d_stall_i)
begin
if (inserting_nop)
inserting_nop <= 0;
else
inserting_nop <= load_hazard;
end
inserting_nop <= load_hazard && !inserting_nop;
assign d_stall_req_o = load_hazard && !inserting_nop;
......@@ -151,7 +158,9 @@ module urv_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)
......@@ -163,11 +172,10 @@ module urv_decode
x_rs2 <= f_rs2;
x_rd <= f_rd;
x_opcode <= d_opcode;
x_shamt_o <= f_ir_i[24:20];
end
// ALU function decoding
// attempt to reuse ALU for jump address generation
always@(posedge clk_i)
if(!d_stall_i)
case (d_opcode)
......@@ -260,6 +268,31 @@ module urv_decode
endcase // case (d_opcode_i)
end // if (!d_stall_i)
always@(posedge clk_i)
if(!d_stall_i)
case (d_opcode)
`OPC_JALR, `OPC_LOAD, `OPC_OP_IMM:
begin
x_use_rs1_o <= 1'b1;
x_use_rs2_o <= 1'b0;
end
`OPC_STORE, `OPC_BRANCH, `OPC_OP, `OPC_CUST2:
begin
x_use_rs1_o <= 1'b1;
x_use_rs2_o <= 1'b1;
end
`OPC_SYSTEM:
begin
x_use_rs1_o <= d_fun[2] == 1'b0 && d_fun[1:0] != 2'b0;
x_use_rs2_o <= 1'b0;
end
default:
begin
x_use_rs1_o <= 1'b0;
x_use_rs2_o <= 1'b0;
end
endcase
wire d_rd_nonzero = (f_rd != 0);
......@@ -269,10 +302,13 @@ module urv_decode
begin
x_is_shift <= d_is_shift;
x_is_load_o <= ( d_opcode == `OPC_LOAD && !load_hazard) ? 1'b1 : 1'b0;
x_is_store_o <= ( d_opcode == `OPC_STORE && !load_hazard) ? 1'b1 : 1'b0;
x_is_mul <= d_is_mul;
x_is_load_o <= d_opcode == `OPC_LOAD && !load_hazard;
x_is_store_o <= d_opcode == `OPC_STORE && !load_hazard;
x_is_mul <= d_is_mul && g_with_hw_mul;
x_is_write_ecc_o <= d_opcode == `OPC_CUST2 && d_fun == `FUNC_WRECC;
x_is_fix_ecc_o <= d_opcode == `OPC_CUST2 && d_fun == `FUNC_FIXECC;
case (d_opcode)
`OPC_BRANCH:
......@@ -283,24 +319,73 @@ module urv_decode
case (d_opcode)
`OPC_OP:
x_is_add_o <= ~f_ir_i[30] && !(d_fun == `FUNC_SLT || d_fun == `FUNC_SLTU);
x_is_add_o <= ~f_ir_i[30];
`OPC_OP_IMM:
x_is_add_o <= !(d_fun == `FUNC_SLT || d_fun == `FUNC_SLTU);
x_is_add_o <= 1;
`OPC_BRANCH:
x_is_add_o <= 0;
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 != `FUNC_MUL);
// all multiply/divide instructions except
if( d_opcode == `OPC_OP && f_ir_i[25] )
begin
case (d_fun)
`FUNC_MUL:
begin
x_is_multiply_o <= g_with_hw_mul != 0;
x_is_divide_o <= 0;
x_is_undef_o <= g_with_hw_mul == 0;
end
`FUNC_MULH, `FUNC_MULHU, `FUNC_MULHSU:
begin
x_is_multiply_o <= g_with_hw_mul > 1;
x_is_divide_o <= 0;
x_is_undef_o <= g_with_hw_mul <= 1;
end
`FUNC_DIV, `FUNC_DIVU, `FUNC_REM, `FUNC_REMU:
begin
x_is_multiply_o <= 0;
x_is_divide_o <= 1;
x_is_undef_o <= !g_with_hw_div;
end
default:
begin
x_is_multiply_o <= 0;
x_is_divide_o <= 0;
x_is_undef_o <= 0;
end
endcase // case (d_fun)
end else begin // if ( d_opcode == `OPC_OP && f_ir_i[25] )
x_is_multiply_o <= 0;
x_is_divide_o <= 0;
x_is_undef_o <= 0;
end // else: !if( d_opcode == `OPC_OP && f_ir_i[25] )
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 if (d_opcode == `OPC_OP && !d_fun[2] && f_ir_i[25])
x_rd_source_o <= `RD_SOURCE_MULTIPLY;
else if (d_opcode == `OPC_OP && f_ir_i[25])
begin
// mul/div
if( !d_fun[2] )
begin
if( d_fun == `FUNC_MUL )
x_rd_source_o <= `RD_SOURCE_MULTIPLY;
else
x_rd_source_o <= `RD_SOURCE_MULH;
end
else
x_rd_source_o <= `RD_SOURCE_DIVIDE;
end
else
x_rd_source_o <= `RD_SOURCE_ALU;
......@@ -310,6 +395,8 @@ module urv_decode
x_rd_write <= d_rd_nonzero;
`OPC_SYSTEM:
x_rd_write <= d_rd_nonzero && (d_fun != 0); // CSR instructions write to RD
`OPC_CUST2:
x_rd_write <= 1'b1;
default:
x_rd_write <= 0;
endcase // case (d_opcode)
......@@ -323,13 +410,14 @@ module urv_decode
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);
x_is_mret_o <= (d_opcode == `OPC_SYSTEM) && (d_fun == 0) && (f_ir_i [31:20] == `SYS_IMM_MRET);
if(g_with_hw_debug)
x_is_ebreak_o <= (d_opcode == `OPC_SYSTEM) && (d_fun == 0) && (f_ir_i [31:20] == `SYS_IMM_EBREAK);
else
x_is_ebreak_o <= 1'b0;
end
assign x_is_shift_o = x_is_shift;
assign x_rd_write_o = x_rd_write;
endmodule // rv_decode
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: na
--
-- description: uRV definitions
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_config.v"
// opcodes (bits[6:2], bits[1:0] == 2'b11)
`define OPC_LOAD 5'b00000
`define OPC_OP_IMM 5'b00100
`define OPC_LUI 5'b01101
`define OPC_AUIPC 5'b00101
`define OPC_OP 5'b01100
`define OPC_JAL 5'b11011
`define OPC_JALR 5'b11001
`define OPC_AUIPC 5'b00101
`define OPC_STORE 5'b01000
`define OPC_OP 5'b01100
`define OPC_LUI 5'b01101
`define OPC_CUST2 5'b10110
`define OPC_BRANCH 5'b11000
`define OPC_LOAD 5'b00000
`define OPC_STORE 5'b01000
`define OPC_JALR 5'b11001
`define OPC_JAL 5'b11011
`define OPC_SYSTEM 5'b11100
`define OPC_MULDIV 5'b
// funct3 for OPC_BRANCH
`define BRA_EQ 3'b000
`define BRA_NEQ 3'b001
`define BRA_LT 3'b100
......@@ -40,12 +47,14 @@
`define BRA_LTU 3'b110
`define BRA_GEU 3'b111
// funct3 for OPC_LOAD and OPC_STORE
`define LDST_B 3'b000
`define LDST_H 3'b001
`define LDST_L 3'b010
`define LDST_BU 3'b100
`define LDST_HU 3'b101
// funct3 for OPC_OP and OPC_OP_IMM
`define FUNC_ADD 3'b000
`define FUNC_SLT 3'b010
`define FUNC_SLTU 3'b011
......@@ -55,49 +64,75 @@
`define FUNC_SL 3'b001
`define FUNC_SR 3'b101
// funct3 for OPC_OP, funct7=1
`define FUNC_MUL 3'b000
`define FUNC_MULH 3'b001
`define FUNC_MULHSU 3'b010
`define FUNC_MULHU 3'b011
`define FUNC_DIV 3'b100
`define FUNC_DIVU 3'b101
`define FUNC_REM 3'b110
`define FUNC_REMU 3'b111
`define RD_SOURCE_ALU 3'b000
// funct3 for OPC_SYSTEM
`define CSR_OP_PRIV 3'b000
`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
// funct3 for OPC_CUST2
// (they use shifter functions)
`define FUNC_WRECC `FUNC_SL
`define FUNC_FIXECC `FUNC_SR
// Imm for OPC_SYSTEM, fun3 = 0
`define SYS_IMM_MRET 12'b0011000_00010
`define SYS_IMM_EBREAK 12'b0000000_00001
`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_DIVIDE 3'b100
`define RD_SOURCE_CSR 3'b011
`define RD_SOURCE_MULH 3'b111
`define CSR_ID_CYCLESH 12'hc80
`define CSR_ID_CYCLESL 12'hc00
`define CSR_ID_CYCLESL 12'hc00
`define CSR_ID_TIMEH 12'hc81
`define CSR_ID_TIMEL 12'hc01
`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_ID_DBGMBX 12'h7d0
`define CSR_ID_MIMPID 12'hf13
`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
/* History for MIMPID:
0000_0000: mimpid not implemented
2019_0125: mimpid added.
2019_0131: data memory wait state.
*/
`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
`define URV_TRAP_VECTOR 32'h00000008
// Bits in mie/mip for machine mode
`define EXCEPT_TIMER 7
`define EXCEPT_IRQ 11
// Cause
`define CAUSE_ILLEGAL_INSN 2
`define CAUSE_BREAKPOINT 3
`define CAUSE_UNALIGNED_LOAD 4
`define CAUSE_UNALIGNED_STORE 6
`define CAUSE_MACHINE_TIMER 7
`define CAUSE_MACHINE_IRQ 11
`define CAUSE_ECC_ERROR 15
`define OP_SEL_BYPASS_X 0
`define OP_SEL_BYPASS_W 1
......
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_divide
--
-- description: uRV division unit
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -34,7 +39,7 @@ module urv_divide
input d_valid_i,
input d_is_divide_i,
input [31:0] d_rs1_i,
input [31:0] d_rs2_i,
......@@ -49,7 +54,7 @@ module urv_divide
wire [32:0] alu_result;
reg [31:0] alu_op1;
reg [31:0] alu_op2;
......@@ -57,32 +62,32 @@ module urv_divide
wire [31:0] r_next = { r[30:0], n[31 - (state - 3)] };
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
1: begin alu_op1 <= 0; alu_op2 <= n; end
2: begin alu_op1 <= 0; alu_op2 <= d; end
35: begin alu_op1 <= 0; alu_op2 <= q; end
36: begin alu_op1 <= 0; alu_op2 <= r; end
default: begin alu_op1 <= r_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 alu_ge = ~alu_result [32];
wire alu_eq = alu_result == 0;
wire done = (is_rem ? state == 37 : state == 36 );
wire busy = ( state != 0 && !done );
wire start_divide = !x_kill_i && d_valid_i && d_is_divide_i && !busy;
assign x_stall_req_o = (start_divide || !done);
assign x_stall_req_o = (d_valid_i && d_is_divide_i && !done);
always@*
case (state) // synthesis full_case parallel_case
case (state)
1:
alu_sub <= n_sign;
2:
......@@ -94,51 +99,65 @@ module urv_divide
default:
alu_sub <= 1;
endcase // case (state)
always@(posedge clk_i)
if(rst_i || done)
state <= 0;
else if (state != 0 || start_divide)
state <= state + 1;
reg is_div_by_zero;
always@(posedge clk_i)
case ( state ) // synthesis full_case parallel_case
case ( state )
0:
if(start_divide)
begin
begin
is_div_by_zero <= 0;
q <= 0;
r <= 0;
is_rem <= (d_fun_i == `FUNC_REM || d_fun_i ==`FUNC_REMU);
n <= d_rs1_i;
d <= d_rs2_i;
if( d_fun_i == `FUNC_DIVU || d_fun_i == `FUNC_REMU )
begin
n_sign <= 0;
d_sign <= 0;
end else begin
n_sign <= d_rs1_i[31];
d_sign <= d_rs2_i[31];
end
n_sign <= d_rs1_i[31];
d_sign <= d_rs2_i[31];
end
1:
n <= alu_result[31:0];
2:
d <= alu_result[31:0];
2:
begin
d <= alu_result[31:0];
is_div_by_zero <= alu_eq && (d_fun_i == `FUNC_DIV);
end
35:
x_rd_o <= alu_result; // quotient
x_rd_o <= is_div_by_zero ? -1 : alu_result; // quotient
36:
x_rd_o <= alu_result; // remainder
default: // 3..34: 32 divider iterations
default: // 3..345 32 divider iterations
begin
q <= { q[30:0], alu_ge };
r <= alu_ge ? alu_result : r_next;
end
endcase // case ( state )
endmodule // rv_divide
endmodule // rv_divide
/*
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_ecc
--
-- description: uRV CPU: compute ecc
--
--------------------------------------------------------------------------------
-- Copyright CERN 2022
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`timescale 1ns/1ps
module urv_ecc
(
input [31:0] dat_i,
output [6:0] ecc_o
);
assign ecc_o[0] = ^(dat_i & 32'b11000001010010000100000011111111);
assign ecc_o[1] = ^(dat_i & 32'b00100001001001001111111110010000);
assign ecc_o[2] = ^(dat_i & 32'b01101100111111110000100000001000);
assign ecc_o[3] = ^(dat_i & 32'b11111111000000011010010001000100);
assign ecc_o[4] = ^(dat_i & 32'b00010110111100001001001010100110);
assign ecc_o[5] = ^(dat_i & 32'b00010000000111110111000101100001);
assign ecc_o[6] = ^(dat_i & 32'b10001010100000100000111100011011);
endmodule // urv_ecc
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_exceptions
--
-- description: uRV exceptions unit
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -25,34 +30,32 @@
module urv_exceptions
(
input clk_i,
input rst_i,
input x_stall_i,
input x_kill_i,
input d_is_csr_i,
input d_is_eret_i,
input [2:0] d_fun_i,
input [4:0] d_csr_imm_i,
input clk_i,
input rst_i,
input x_stall_i,
input x_kill_i,
input d_is_csr_i,
input d_is_mret_i,
input [4:0] d_csr_imm_i,
input [11:0] d_csr_sel_i,
input exp_irq_i,
input exp_tick_i,
input exp_breakpoint_i,
input exp_unaligned_load_i,
input exp_unaligned_store_i,
input exp_invalid_insn_i,
input exp_irq_i,
input exp_tick_i,
output exp_ei_pending_o,
output exp_ti_pending_o,
input [31:0] x_csr_write_value_i,
output reg x_exception_o,
input x_exception_i,
input [3:0] x_exception_cause_i,
input x_interrupt_i,
input [31:0] x_exception_pc_i,
output [31:0] x_exception_pc_o,
output [31:0] x_exception_vector_o,
input x_exception_taken_i,
output [31:0] csr_mstatus_o,
output [31:0] csr_mip_o,
output [31:0] csr_mie_o,
......@@ -60,150 +63,73 @@ module urv_exceptions
output [31:0] csr_mcause_o
);
reg [31:0] csr_mepc;
reg [31:0] csr_mie;
reg csr_ie;
reg [31:0] csr_mie;
reg csr_status_mie;
reg csr_status_mpie;
reg [3:0] csr_mcause_code;
reg csr_mcause_interrupt;
reg [3:0] csr_mcause;
reg exception;
reg [3:0] cause;
assign csr_mcause_o = {csr_mcause_interrupt, 27'h0, csr_mcause_code};
assign csr_mepc_o = csr_mepc;
assign csr_mie_o = csr_mie;
reg [5:0] except_vec_masked;
reg exception_pending;
assign csr_mstatus_o[2:0] = 0;
assign csr_mstatus_o[3] = csr_status_mie;
assign csr_mstatus_o[6:4] = 0;
assign csr_mstatus_o[7] = csr_status_mpie;
assign csr_mstatus_o[31:8] = 0;
reg [31:0] x_exception_pc_d;
assign csr_mip_o = 0;
assign exp_ei_pending_o = exp_irq_i & csr_mie[`EXCEPT_IRQ] & csr_status_mie;
assign exp_ti_pending_o = exp_tick_i & csr_mie[`EXCEPT_TIMER] & csr_status_mie;
assign csr_mcause_o = {28'h0, csr_mcause};
assign csr_mepc_o = csr_mepc;
assign csr_mie_o = csr_mie;
assign csr_mstatus_o[0] = csr_ie;
assign csr_mstatus_o[31:1] = 0;
reg [31:0] csr_mip;
always@*
begin
csr_mip <= 0;
csr_mip[`EXCEPT_ILLEGAL_INSN] <= except_vec_masked[0];
csr_mip[`EXCEPT_BREAKPOINT] <= except_vec_masked[1];
csr_mip[`EXCEPT_UNALIGNED_LOAD]<= except_vec_masked[2];
csr_mip[`EXCEPT_UNALIGNED_STORE] <= except_vec_masked[3];
csr_mip[`EXCEPT_TIMER] <= except_vec_masked[4];
csr_mip[`EXCEPT_IRQ] <= except_vec_masked[5];
end
assign csr_mip_o = csr_mip;
always@(posedge clk_i)
if (rst_i)
except_vec_masked <= 0;
else begin
if(!x_stall_i && !x_kill_i && d_is_csr_i && d_csr_sel_i == `CSR_ID_MIP) begin
except_vec_masked[0] <= x_csr_write_value_i [`EXCEPT_ILLEGAL_INSN];
except_vec_masked[1] <= x_csr_write_value_i [`EXCEPT_BREAKPOINT];
except_vec_masked[2] <= x_csr_write_value_i [`EXCEPT_UNALIGNED_LOAD];
except_vec_masked[3] <= x_csr_write_value_i [`EXCEPT_UNALIGNED_STORE];
except_vec_masked[4] <= x_csr_write_value_i [`EXCEPT_TIMER];
except_vec_masked[5] <= x_csr_write_value_i [`EXCEPT_IRQ];
end else begin
if ( exp_invalid_insn_i )
except_vec_masked[0] <= 1'b1;
if ( exp_breakpoint_i )
except_vec_masked[1] <= 1'b1;
if ( exp_unaligned_load_i )
except_vec_masked[2] <= 1'b1;
if ( exp_unaligned_store_i )
except_vec_masked[3] <= 1'b1;
if ( exp_tick_i )
except_vec_masked[4] <= csr_mie[`EXCEPT_TIMER] & csr_ie;
if( exp_irq_i )
except_vec_masked[5] <= csr_mie[`EXCEPT_IRQ] & csr_ie;
end // else: !if(!x_stall_i && !x_kill_i && d_is_csr_i && d_csr_sel_i == `CSR_ID_MIP)
end // else: !if(rst_i)
always@*
exception <= |except_vec_masked | exp_invalid_insn_i;
assign x_exception_vector_o = 'h8;
always@*
if(exp_invalid_insn_i || except_vec_masked[0])
cause <= `EXCEPT_ILLEGAL_INSN;
else if (except_vec_masked[1])
cause <= `EXCEPT_BREAKPOINT;
else if (except_vec_masked[2])
cause <= `EXCEPT_UNALIGNED_LOAD;
else if (except_vec_masked[3])
cause <= `EXCEPT_UNALIGNED_STORE;
else if (except_vec_masked[4])
cause <= `EXCEPT_TIMER;
else
cause <= `EXCEPT_IRQ;
always@(posedge clk_i)
if(rst_i)
if(rst_i)
begin
csr_mcause_code <= 0;
csr_mcause_interrupt <= 0;
csr_mepc <= 0;
csr_mie <= 0;
csr_ie <= 0;
exception_pending <= 0;
end else if(!x_stall_i && !x_kill_i) begin
x_exception_pc_d <= x_exception_pc_i;
if ( d_is_eret_i )
exception_pending <= 0;
else if ( x_exception_taken_i )
csr_status_mie <= 0;
csr_status_mpie <= 0;
end
else
begin
if (x_exception_i)
begin
csr_mepc <= x_exception_pc_d;
csr_mcause <= cause;
exception_pending <= 1;
end
if(d_is_csr_i) begin
case (d_csr_sel_i)
`CSR_ID_MSTATUS:
csr_ie <= x_csr_write_value_i[0];
`CSR_ID_MEPC:
csr_mepc <= x_csr_write_value_i;
`CSR_ID_MIE:
begin
csr_mie[`EXCEPT_ILLEGAL_INSN] <= 1;
csr_mie[`EXCEPT_BREAKPOINT] <= 1;
csr_mie[`EXCEPT_UNALIGNED_LOAD] <= 1;
csr_mie[`EXCEPT_UNALIGNED_STORE] <= 1;
csr_mie[`EXCEPT_TIMER] <= x_csr_write_value_i [`EXCEPT_TIMER];
csr_mie[`EXCEPT_IRQ] <= x_csr_write_value_i [`EXCEPT_IRQ];
end
endcase // case (d_csr_sel_i)
end // if (d_is_csr_i)
end // if (!x_stall_i && !x_kill_i)
csr_mepc <= x_exception_pc_i;
csr_mcause_code <= x_exception_cause_i;
csr_mcause_interrupt <= x_interrupt_i;
// Mask interrupts during exceptions
csr_status_mpie <= csr_status_mie;
csr_status_mie <= 0;
end
if (!x_stall_i && !x_kill_i)
begin
if (d_is_csr_i)
case (d_csr_sel_i)
`CSR_ID_MSTATUS:
csr_status_mie <= x_csr_write_value_i[3];
`CSR_ID_MEPC:
csr_mepc <= x_csr_write_value_i;
`CSR_ID_MIE:
begin
csr_mie[`EXCEPT_TIMER] <=
x_csr_write_value_i[`EXCEPT_TIMER];
csr_mie[`EXCEPT_IRQ] <=
x_csr_write_value_i[`EXCEPT_IRQ];
end
endcase
if (d_is_mret_i)
csr_status_mie <= csr_status_mpie;
end
end
assign x_exception_pc_o = csr_mepc;
always@(posedge clk_i)
if (rst_i)
x_exception_o <= 0;
else if (x_exception_taken_i)
x_exception_o <= 0;
else if (exception && !exception_pending)
x_exception_o <= 1;
endmodule // urv_exceptions
This diff is collapsed.
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_fetch
--
-- description: uRV CPU: instruction fetch stage
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`timescale 1ns/1ps
module urv_fetch
module urv_fetch
(
input clk_i,
input rst_i,
input f_stall_i,
input f_kill_i,
output [31:0] im_addr_o,
input [31:0] im_data_i,
input im_valid_i,
output reg f_valid_o,
output [31:0] f_ir_o,
input clk_i,
input rst_i,
input f_stall_i,
// Instruction memory
// im_rd_o is maintained as long as the instruction is needed.
output [31:0] im_addr_o,
output im_rd_o,
input [31:0] im_data_i,
input im_valid_i,
// Fetched instruction - set on the next cycle.
output reg f_valid_o,
output reg [31:0] f_ir_o,
output reg [31:0] f_pc_o,
output reg [31:0] f_pc_plus_4_o,
input [31:0] x_pc_bra_i,
input x_bra_i
// Branch control
input [31:0] x_pc_bra_i,
input x_bra_i,
// Debug mode
input dbg_force_i,
output dbg_enabled_o,
input [31:0] dbg_insn_i,
input dbg_insn_set_i,
output dbg_insn_ready_o,
input x_dbg_toggle_i
);
parameter g_with_compressed_insns = 0;
parameter g_with_hw_debug = 0;
reg [31:0] pc;
reg [31:0] ir ,ir_prev;
reg rst_d;
reg [31:0] pc_next;
reg [31:0] pc_plus_4;
reg dbg_mode;
reg [2:0] pipeline_cnt;
wire frozen;
// Set by x_bra_i until the next instruction has been fetched.
// The instruction being fetched before the branch has to be discarded.
reg f_kill;
// Set as long as no instruction has to be fetched.
assign frozen = (f_stall_i
|| dbg_mode || dbg_force_i || pipeline_cnt != 0);
always@*
if( x_bra_i )
if (x_bra_i)
pc_next <= x_pc_bra_i;
else if (!rst_d || f_stall_i || !im_valid_i)
else if (rst_d || frozen || f_kill || !im_valid_i)
pc_next <= pc;
else
pc_next <= pc_plus_4;
assign f_ir_o = ir;
pc_next <= pc + 4;
// Start fetching the next instruction
assign im_addr_o = pc_next;
assign im_rd_o = x_bra_i || !(frozen || rst_i);
assign dbg_enabled_o = dbg_mode;
assign dbg_insn_ready_o = pipeline_cnt == 4;
always@(posedge clk_i)
if (rst_i) begin
pc <= 0;
pc_plus_4 <= 4;
ir <= 0;
f_valid_o <= 0;
rst_d <= 0;
end else begin
rst_d <= 1;
if (!f_stall_i) begin
if(im_valid_i)
pc_plus_4 <= (x_bra_i ? x_pc_bra_i : pc_plus_4) + 4;
pc <= pc_next;
f_pc_o <= pc;
if(im_valid_i) begin
ir <= im_data_i;
f_valid_o <= (rst_d && !f_kill_i);
end else begin// if (i_valid_i)
f_valid_o <= 0;
end
end
end // else: !if(rst_i)
if (rst_i)
begin
// PC = 0 at reset.
pc <= 0;
endmodule // urv_fetch
f_pc_o <= 0;
f_ir_o <= 0;
f_valid_o <= 0;
f_kill <= 0;
// Allow to start in debug mode.
dbg_mode <= dbg_force_i;
pipeline_cnt <= 0;
// The instruction won't be valid on the next cycle, as the
// instruction memory is registered.
rst_d <= 1;
end
else
begin
rst_d <= 0;
if (!f_stall_i)
begin
f_pc_o <= pc;
pc <= pc_next;
if(g_with_hw_debug
&& !dbg_mode
&& (dbg_force_i || x_dbg_toggle_i || pipeline_cnt != 0))
begin
// Enter or entering in debug mode
// Stall until the debug mode is set (pipeline flushed).
f_valid_o <= 0;
// Ebreak enters directly in the debug mode. As it is
// considered as a branch, stages are killed.
if (pipeline_cnt == 4 || x_dbg_toggle_i)
begin
dbg_mode <= 1;
pipeline_cnt <= 0;
end
else
pipeline_cnt <= pipeline_cnt + 1'b1;
end
else if(g_with_hw_debug && dbg_mode)
begin
// In debug mode
if (x_dbg_toggle_i)
begin
// Leave debug mode immediately.
dbg_mode <= 0;
f_valid_o <= 0;
end
else
begin
// Use instruction from the debug port.
f_ir_o <= dbg_insn_i;
f_valid_o <= 1;
end
if (x_dbg_toggle_i || dbg_insn_set_i)
pipeline_cnt <= 0;
else if (pipeline_cnt != 4)
pipeline_cnt <= pipeline_cnt + 1'b1;
end
else if(im_valid_i)
begin
f_ir_o <= im_data_i;
// A branch invalidate the current instruction.
// Not valid on the first cycle
f_valid_o <= (!rst_d && !x_bra_i && !f_kill);
// The instruction has been killed.
f_kill <= 0;
end
else
begin
// If a branch has been executed, the instruction being
// fetch must not be executed. Kill it.
f_kill <= f_kill | x_bra_i;
f_valid_o <= 0;
end
end
end
endmodule // urv_fetch
......@@ -16,7 +16,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
`timescale 1ns/1ps
......@@ -30,7 +30,7 @@ module urv_iram
parameter g_size = 65536,
parameter g_init_file = "",
parameter g_simulation = 0
)
)
(
input clk_i,
......@@ -39,7 +39,7 @@ module urv_iram
input [31:0] aa_i,
input [3:0] bwea_i,
input [31:0] da_i,
output [31:0] qa_o,
output [31:0] qa_o,
input enb_i,
input web_i,
input [31:0] ab_i,
......@@ -53,12 +53,12 @@ module urv_iram
// synthesis translate_off
reg [31:0] mem[0:g_size/4-1];
reg [31:0] qa_int, qb_int;
// synthesis translate_on
`define RAM_INST(id, entity, range_a, range_d, range_bw) \
entity RV_IRAM_BLK_``id \
( \
......@@ -97,9 +97,9 @@ module urv_iram
.WEB((enb) & web_i & bweb_i[range_bw]) \
);
generate
generate
if (!g_simulation) begin
if (g_size == 65536) begin
`RAM_INST(64K_0, RAMB16_S1_S1, 15:2, 0, 0)
......@@ -138,7 +138,7 @@ module urv_iram
else if(g_size == 32768) begin
wire[31:0] qa_h, qb_h, qa_l, qb_l;
reg a14a_d, a14b_d;
`RAM_INST_MUXED(32K_H0, RAMB16_S4_S4, 13:2, 3:0, 0, qa_h, qb_h, aa_i[14], ab_i[14])
`RAM_INST_MUXED(32K_H1, RAMB16_S4_S4, 13:2, 7:4, 0, qa_h, qb_h, aa_i[14], ab_i[14])
`RAM_INST_MUXED(32K_H2, RAMB16_S4_S4, 13:2, 11:8, 1, qa_h, qb_h, aa_i[14], ab_i[14])
......@@ -147,7 +147,7 @@ module urv_iram
`RAM_INST_MUXED(32K_H5, RAMB16_S4_S4, 13:2, 23:20, 2, qa_h, qb_h, aa_i[14], ab_i[14])
`RAM_INST_MUXED(32K_H6, RAMB16_S4_S4, 13:2, 27:24, 3, qa_h, qb_h, aa_i[14], ab_i[14])
`RAM_INST_MUXED(32K_H7, RAMB16_S4_S4, 13:2, 31:28, 3, qa_h, qb_h, aa_i[14], ab_i[14])
`RAM_INST_MUXED(32K_L0, RAMB16_S4_S4, 13:2, 3:0, 0, qa_l, qb_l, ~aa_i[14], ~ab_i[14])
`RAM_INST_MUXED(32K_L1, RAMB16_S4_S4, 13:2, 7:4, 0, qa_l, qb_l, ~aa_i[14], ~ab_i[14])
`RAM_INST_MUXED(32K_L2, RAMB16_S4_S4, 13:2, 11:8, 1, qa_l, qb_l, ~aa_i[14], ~ab_i[14])
......@@ -165,12 +165,12 @@ module urv_iram
assign qa_o = a14a_d ? qa_h : qa_l;
assign qb_o = a14b_d ? qb_h : qb_l;
end else if(g_size == 16384) begin
`RAM_INST(16K_0, RAMB16_S4_S4, 13:2, 3:0, 0)
`RAM_INST(16K_1, RAMB16_S4_S4, 13:2, 7:4, 0)
`RAM_INST(16K_2, RAMB16_S4_S4, 13:2, 11:8, 1)
`RAM_INST(16K_3, RAMB16_S4_S4, 13:2, 15:12, 1)
`RAM_INST(16K_3, RAMB16_S4_S4, 13:2, 15:12, 1)
`RAM_INST(16K_4, RAMB16_S4_S4, 13:2, 19:16, 2)
`RAM_INST(16K_5, RAMB16_S4_S4, 13:2, 23:20, 2)
`RAM_INST(16K_6, RAMB16_S4_S4, 13:2, 27:24, 3)
......@@ -180,18 +180,18 @@ module urv_iram
$error("Unsupported Spartan-6 IRAM size: %d", g_size);
$stop;
end
end // else: !if(g_size == 16384)
end else begin // if (!g_simulation)
// synthesis translate_off
always@(posedge clk_i)
begin
if(ena_i)
begin
......@@ -221,14 +221,14 @@ module urv_iram
mem [(ab_i / 4) % g_size][31:24] <= db_i[31:24];
end
end // always@ (posedge clk_i)
assign qa_o = qa_int;
assign qb_o = qb_int;
// synthesis translate_on
end // else: !if(!g_simulation)
......@@ -237,38 +237,37 @@ module urv_iram
endgenerate
// synthesis translate_off
integer f, addr;
integer tmp, f, addr;
reg[31:0] data;
reg [8*20-1:0] cmd;
initial begin
if(g_simulation && g_init_file != "") begin : init_ram_contents
$display("Initializing RAM contents from %s", g_init_file);
f = $fopen(g_init_file,"r");
if( f == 0)
begin
$error("can't open: %s", g_init_file);
$stop;
end
while(!$feof(f))
begin
$fscanf(f,"%s %08x %08x", cmd,addr,data);
tmp = $fscanf(f, "%s %08x %08x", cmd, addr, data);
if(cmd == "write")
begin
mem[addr % g_size][31:24] = data[31:24];
......@@ -279,10 +278,10 @@ module urv_iram
end
end // if (g_simulation && g_init_file != "")
end
// synthesis translate_on
endmodule // urv_iram
......@@ -295,7 +294,7 @@ module urv_iram
parameter g_size = 65536,
parameter g_init_file = "",
parameter g_simulation = 0
)
)
(
input clk_i,
......@@ -304,7 +303,7 @@ module urv_iram
input [31:0] aa_i,
input [3:0] bwea_i,
input [31:0] da_i,
output [31:0] qa_o,
output [31:0] qa_o,
input enb_i,
input web_i,
input [31:0] ab_i,
......@@ -317,11 +316,11 @@ module urv_iram
reg [31:0] mem[0:g_size/4-1];
reg [31:0] qa_int, qb_int;
always@(posedge clk_i)
begin
if(ena_i)
begin
......@@ -351,17 +350,17 @@ module urv_iram
mem [(ab_i / 4)][31:24] <= db_i[31:24];
end
end // always@ (posedge clk_i)
assign qa_o = qa_int;
assign qb_o = qb_int;
// end // else: !if(!g_simulation)
endmodule
endmodule
`endif
`ifdef URV_PLATFORM_ALTERA
......@@ -370,7 +369,7 @@ module urv_iram
parameter g_size = 65536,
parameter g_init_file = "",
parameter g_simulation = 0
)
)
(
input clk_i,
......@@ -379,7 +378,7 @@ module urv_iram
input [31:0] aa_i,
input [3:0] bwea_i,
input [31:0] da_i,
output [31:0] qa_o,
output [31:0] qa_o,
input enb_i,
input web_i,
input [31:0] ab_i,
......@@ -389,7 +388,7 @@ module urv_iram
);
localparam g_addr_width = (g_size==65536?14:0);
altsyncram
ram (
.address_a (aa_i[g_addr_width+1:2]),
......@@ -454,4 +453,3 @@ endmodule // urv_iram
`endif // `ifdef URV_PLATFORM_ALTERA
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_multiply
--
-- description: uRV multiplication unit
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -29,9 +34,9 @@ module urv_mult18x18
(
input clk_i,
input rst_i,
input stall_i,
input [17:0] x_i,
input [17:0] y_i,
......@@ -67,9 +72,9 @@ module urv_mult18x18
.C(48'h0),
.CARRYIN(),
.D(18'b0),
.CEA(1'b0),
.CEB(1'b0),
.CEC(1'b0),
.CEA(1'b1),
.CEB(1'b1),
.CEC(1'b1),
.CECARRYIN(1'b0),
.CED(1'b0),
.CEM(~stall_i),
......@@ -90,6 +95,7 @@ module urv_mult18x18
initial force D1.OPMODE_dly = 8'd1;
// synthesis translate_on
endmodule // urv_mult18x18
`endif // `ifdef PLATFORM_SPARTAN6
......@@ -99,20 +105,20 @@ module urv_mult18x18
(
input clk_i,
input rst_i,
input stall_i,
input [17:0] x_i,
input [17:0] y_i,
output reg [35:0] q_o
input signed [17:0] x_i,
input signed [17:0] y_i,
output reg signed [35:0] q_o
);
always@(posedge clk_i)
if(!stall_i)
q_o <= x_i * y_i;
endmodule // urv_mult18x18
`endif // `ifdef URV_PLATFORM_GENERIC
......@@ -122,9 +128,9 @@ module urv_mult18x18
(
input clk_i,
input rst_i,
input stall_i,
input [17:0] x_i,
input [17:0] y_i,
......@@ -155,36 +161,53 @@ endmodule // urv_mult18x18
`endif
module urv_multiply
module urv_multiply
(
input clk_i,
input rst_i,
input x_stall_i,
input clk_i,
input rst_i,
input x_stall_i,
input x_kill_i,
output x_stall_req_o,
input [31:0] d_rs1_i,
input [31:0] d_rs2_i,
input [2:0] d_fun_i,
output reg [31:0] w_rd_o
input [31:0] d_rs1_i,
input [31:0] d_rs2_i,
input [2:0] d_fun_i,
input d_is_multiply_i,
// multiply result for MUL instructions, bypassed to W-stage to achieve 1-cycle performance
// without much penalty on clock speed
output [31:0] w_rd_o,
// multiply result for MULH(S)(U) instructions. Goes to the X stage
// destination value mux.
output reg [31:0] x_rd_o
);
parameter g_with_hw_mulh = 0;
wire[17:0] xl_u = {1'b0, d_rs1_i[16:0] };
wire[17:0] xl_u = {1'b0, d_rs1_i[16:0] }; // 17 bits
wire[17:0] yl_u = {1'b0, d_rs2_i[16:0] };
wire[17:0] xl_s = {d_rs1_i[16], d_rs1_i[16:0] };
wire[17:0] yl_s = {d_rs2_i[16], d_rs2_i[16:0] };
wire[17:0] xh = { {3{d_rs1_i[31]}}, d_rs1_i[31:17] };
wire[17:0] yh = { {3{d_rs2_i[31]}}, d_rs2_i[31:17] };
wire [35:0] yl_xl, yl_xh, yh_xl;
wire sign_extend_xh = (d_fun_i == `FUNC_MULH || d_fun_i == `FUNC_MULHSU) ? d_rs1_i[31] : 1'b0 ;
wire sign_extend_yh = (d_fun_i == `FUNC_MULH) ? d_rs2_i[31] : 1'b0 ;
urv_mult18x18 mul0
wire signed [17:0] xh = { {3{sign_extend_xh}}, d_rs1_i[31:17] }; // 15 bits
wire signed [17:0] yh = { {3{sign_extend_yh}}, d_rs2_i[31:17] };
wire signed [35:0] xh_yh;
wire signed [35:0] yl_xl, yl_xh, yh_xl;
wire mul_stall_req;
reg mul_stall_req_d0;
reg mul_stall_req_d1;
urv_mult18x18 mul0
(
.clk_i(clk_i),
.rst_i(rst_i),
.stall_i(x_stall_i),
.stall_i(1'b0),
.x_i(xl_u),
.y_i(yl_u),
......@@ -195,9 +218,9 @@ module urv_multiply
(
.clk_i(clk_i),
.rst_i(rst_i),
.stall_i(x_stall_i),
.stall_i(1'b0),
.x_i(xl_s),
.x_i(xl_u),
.y_i(yh),
.q_o(yh_xl)
);
......@@ -206,19 +229,69 @@ module urv_multiply
(
.clk_i(clk_i),
.rst_i(rst_i),
.stall_i(x_stall_i),
.stall_i(1'b0),
.x_i(yl_s),
.x_i(yl_u),
.y_i(xh),
.q_o(yl_xh)
);
always@*
w_rd_o <= yl_xl + {yl_xh[14:0], 17'h0} + {yh_xl[14:0], 17'h0};
endmodule // urv_multiply
generate
if (g_with_hw_mulh)
begin
urv_mult18x18 mul3
(
.clk_i(clk_i),
.rst_i(rst_i),
.stall_i(1'b0),
.x_i(yh),
.y_i(xh),
.q_o(xh_yh)
);
end
endgenerate
wire [63:0] mul_result;
wire [63:0] yl_xl_ext = yl_xl;
wire [63:0] yh_xl_ext = { {15{yh_xl[35] } }, yh_xl, 17'h0 };
wire [63:0] yl_xh_ext = { {15{yl_xh[35] } }, yl_xh, 17'h0 };
wire [63:0] yh_xh_ext = { xh_yh, 34'h0 };
generate
if (g_with_hw_mulh)
begin
assign mul_result = yl_xl_ext + yh_xl_ext + yl_xh_ext + yh_xh_ext;
assign mul_stall_req = !x_kill_i && !mul_stall_req_d1 && d_is_multiply_i && d_fun_i != `FUNC_MUL;
always@(posedge clk_i)
x_rd_o <= mul_result[63:32];
always@(posedge clk_i)
if (rst_i)
begin
mul_stall_req_d0 <= 0;
mul_stall_req_d1 <= 0;
end else begin
mul_stall_req_d0 <= mul_stall_req;
mul_stall_req_d1 <= mul_stall_req_d0;
end
end
else // no hardware multiply high
begin
assign mul_result = yl_xl + {yl_xh[14:0], 17'h0} + {yh_xl[14:0], 17'h0};
assign mul_stall_req = 1'b0;
end // else: !if(g_with_hw_mulh)
endgenerate
assign x_stall_req_o = mul_stall_req;
assign w_rd_o = mul_result[31:0];
endmodule // urv_multiply
library ieee;
use ieee.std_logic_1164.all;
package urv_pkg is
component urv_cpu is
generic (
g_timer_frequency : natural := 1000;
g_clock_frequency : natural := 100000000;
g_with_hw_div : natural := 1;
g_with_hw_mul : natural := 1;
g_with_hw_debug : natural := 0;
g_with_compressed_insns : natural := 0);
port (
clk_i : in std_logic;
rst_i : in std_logic;
irq_i : in std_logic;
-- instruction mem I/F
im_addr_o : out std_logic_vector (31 downto 0);
im_rd_o : out std_logic;
im_data_i : in std_logic_vector (31 downto 0);
im_valid_i : in std_logic;
-- data mem I/F
-- The interface is pipelined: store/load are asserted for one cycle
-- and then store_done/load_done is awaited.
dm_addr_o : out std_logic_vector (31 downto 0);
dm_data_s_o : out std_logic_vector (31 downto 0);
dm_data_l_i : in std_logic_vector (31 downto 0);
dm_data_select_o : out std_logic_vector (3 downto 0);
dm_store_o : out std_logic;
dm_load_o : out std_logic;
dm_load_done_i : in std_logic;
dm_store_done_i : in std_logic;
-- Debug I/F
-- Debug mode is entered either when dbg_force_i is set, or when the ebreak
-- instructions is executed. Debug mode is left when the ebreak instruction
-- is executed (from the dbg_insn_i port).
-- When debug mode is entered, dbg_enabled_o is set. This may not be
-- immediate. Interrupts are disabled in debug mode.
-- In debug mode, instructions are executed from dbg_insn_i.
-- As instructions are always fetched, they must be always valid. Use
-- a nop (0x13) if nothing should be executed.
dbg_force_i : in std_logic;
dbg_enabled_o : out std_logic;
dbg_insn_i : in std_logic_vector (31 downto 0);
dbg_insn_set_i : in std_logic;
dbg_insn_ready_o : out std_logic;
dbg_mbx_data_i : in std_logic_vector (31 downto 0);
dbg_mbx_write_i : in std_logic;
dbg_mbx_data_o : out std_logic_vector (31 downto 0));
end component;
end urv_pkg;
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_regfile
--
-- description: uRV CPU: register file
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -24,21 +29,23 @@
`timescale 1ns/1ps
module urv_regmem
#(
parameter g_width = 32
)
(
input clk_i,
input rst_i,
input clk_i,
input en1_i,
input [4:0] a1_i,
output reg [31:0] q1_o,
input en1_i,
input [4:0] a1_i,
output reg [g_width-1:0] q1_o,
input [4:0] a2_i,
input [31:0] d2_i,
input we2_i
input [4:0] a2_i,
input [g_width-1:0] d2_i,
input we2_i
);
reg [31:0] ram [0:31];
reg [g_width-1:0] ram [0:31];
always@(posedge clk_i)
if(en1_i)
q1_o <= ram[a1_i];
......@@ -52,74 +59,121 @@ module urv_regmem
integer i;
for(i=0;i<32; i=i+1) begin
ram[i] = 0;
ram[i] = 32'h0;
end
end
// synthesis translate_on
endmodule
module urv_regfile
(
input clk_i,
input rst_i,
input d_stall_i,
#(
parameter g_with_ecc = 0
)
(
input clk_i,
input rst_i,
input d_stall_i,
input [4:0] rf_rs1_i,
input [4:0] rf_rs2_i,
input [4:0] rf_rs1_i,
input [4:0] rf_rs2_i,
input [4:0] d_rs1_i,
input [4:0] d_rs2_i,
input [4:0] d_rs1_i,
input [4:0] d_rs2_i,
output reg [31:0] x_rs1_value_o,
output reg [31:0] x_rs2_value_o,
output reg [31:0] x_rs1_value_o,
output reg [31:0] x_rs2_value_o,
output reg x_rs1_ecc_err_o,
output reg x_rs2_ecc_err_o,
input [4:0] w_rd_i,
input [31:0] w_rd_value_i,
input w_rd_store_i,
input [4:0] w_rd_i,
input [31:0] w_rd_value_i,
input [6:0] w_rd_ecc_i,
input [1:0] w_rd_ecc_flip_i,
input w_rd_store_i,
input w_bypass_rd_write_i,
input [31:0] w_bypass_rd_value_i
input w_bypass_rd_write_i,
input [31:0] w_bypass_rd_value_i
);
localparam g_width = 32 + (g_with_ecc ? 7 : 0);
wire [g_width-1:0] w_rd_value_1;
wire [g_width-1:0] w_rd_value_2;
wire [g_width-1:0] rs1_regfile;
wire [g_width-1:0] rs2_regfile;
wire write = w_rd_store_i;
wire [31:0] rs1_regfile;
wire [31:0] rs2_regfile;
wire write = (w_rd_store_i && (w_rd_i != 0));
wire rs1_ecc_err;
wire rs2_ecc_err;
urv_regmem bank0
// Value to be written in the register file
wire [g_width-1:0] w_rd_value;
generate
if (g_with_ecc) begin
assign w_rd_value_1 = {w_rd_ecc_i ^ w_rd_ecc_flip_i[0], w_rd_value_i};
assign w_rd_value_2 = {w_rd_ecc_i ^ w_rd_ecc_flip_i[1], w_rd_value_i};
end
else begin
assign w_rd_value_1 = w_rd_value_i;
assign w_rd_value_2 = w_rd_value_i;
end
endgenerate
urv_regmem
#(.g_width(g_width))
bank1
(
.clk_i(clk_i),
.rst_i (rst_i ),
.en1_i(!d_stall_i),
.a1_i(rf_rs1_i),
.q1_o(rs1_regfile),
.a2_i(w_rd_i),
.d2_i(w_rd_value_i),
.d2_i(w_rd_value_1),
.we2_i (write));
urv_regmem bank1
urv_regmem
#(.g_width(g_width))
bank2
(
.clk_i(clk_i),
.rst_i (rst_i ),
.en1_i(!d_stall_i),
.a1_i(rf_rs2_i),
.q1_o(rs2_regfile),
.a2_i (w_rd_i),
.d2_i (w_rd_value_i),
.d2_i (w_rd_value_2),
.we2_i (write)
);
wire rs1_bypass_x = w_bypass_rd_write_i && (w_rd_i == d_rs1_i) && (w_rd_i != 0);
wire rs2_bypass_x = w_bypass_rd_write_i && (w_rd_i == d_rs2_i) && (w_rd_i != 0);
reg rs1_bypass_w, rs2_bypass_w;
generate
if (g_with_ecc) begin
wire [6:0] rs1_ecc;
wire [6:0] rs2_ecc;
urv_ecc ecc_rs1
(.dat_i(rs1_regfile[31:0]),
.ecc_o(rs1_ecc));
urv_ecc ecc_rs2
(.dat_i(rs2_regfile[31:0]),
.ecc_o(rs2_ecc));
assign rs1_ecc_err = |(rs1_ecc ^ rs1_regfile[38:32]);
assign rs2_ecc_err = |(rs2_ecc ^ rs2_regfile[38:32]);
end
else begin
assign rs1_ecc_err = 1'b0;
assign rs2_ecc_err = 1'b0;
end
endgenerate
wire rs1_bypass_x = w_bypass_rd_write_i && (w_rd_i == d_rs1_i) && (w_rd_i != 0);
wire rs2_bypass_x = w_bypass_rd_write_i && (w_rd_i == d_rs2_i) && (w_rd_i != 0);
reg rs1_bypass_w, rs2_bypass_w;
always@(posedge clk_i)
if(rst_i)
begin
......@@ -129,7 +183,7 @@ module urv_regfile
rs1_bypass_w <= write && (rf_rs1_i == w_rd_i);
rs2_bypass_w <= write && (rf_rs2_i == w_rd_i);
end
reg [31:0] bypass_w;
always@(posedge clk_i)
......@@ -140,22 +194,39 @@ module urv_regfile
begin
case ( {rs1_bypass_x, rs1_bypass_w } ) // synthesis parallel_case full_case
2'b10, 2'b11:
x_rs1_value_o <= w_bypass_rd_value_i;
begin
x_rs1_value_o <= w_bypass_rd_value_i;
x_rs1_ecc_err_o <= 1'b0;
end
2'b01:
x_rs1_value_o <= bypass_w;
begin
x_rs1_value_o <= bypass_w;
x_rs1_ecc_err_o <= 1'b0;
end
default:
x_rs1_value_o <= rs1_regfile;
begin
x_rs1_value_o <= rs1_regfile[31:0];
x_rs1_ecc_err_o <= rs1_ecc_err;
end
endcase // case ( {rs1_bypass_x, rs1_bypass_w } )
case ( {rs2_bypass_x, rs2_bypass_w } ) // synthesis parallel_case full_case
2'b10, 2'b11:
x_rs2_value_o <= w_bypass_rd_value_i;
begin
x_rs2_value_o <= w_bypass_rd_value_i;
x_rs2_ecc_err_o <= 1'b0;
end
2'b01:
x_rs2_value_o <= bypass_w;
begin
x_rs2_value_o <= bypass_w;
x_rs2_ecc_err_o <= 1'b0;
end
default:
x_rs2_value_o <= rs2_regfile;
begin
x_rs2_value_o <= rs2_regfile[31:0];
x_rs2_ecc_err_o <= rs2_ecc_err;
end
endcase // case ( {rs2_bypass_x, rs2_bypass_w } )
end // always@ *
endmodule // urv_regfile
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_shifter
--
-- description: uRV shifter unit
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -39,11 +44,10 @@ module urv_shifter
input d_valid_i,
input [31:0] d_rs1_i,
output reg [31:0] w_rd_o,
input [4:0] d_shamt_i,
input [2:0] d_fun_i,
input d_shifter_sign_i,
input d_is_shift_i
input d_shifter_sign_i
);
wire extend_sign = ((d_fun_i == `FUNC_SR) && d_shifter_sign_i) ? d_rs1_i[31] : 1'b0;
......@@ -61,9 +65,9 @@ module urv_shifter
reg s2_extend_sign;
reg [4:0] s2_shift;
reg [2:0] s2_func;
// stage 1 pipe register
always@(posedge clk_i)
if (!x_stall_i)
......@@ -73,9 +77,9 @@ module urv_shifter
s2_func <= d_fun_i;
s1_out <= shift_8;
end
reg [31:0] shift_4, shift_2, shift_1, shift_post;
// stage 2
always@*
begin
......@@ -89,4 +93,3 @@ module urv_shifter
w_rd_o <= shift_post;
endmodule // urv_shifter
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_timer
--
-- description: uRV timer unit
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -30,7 +35,7 @@ module urv_timer
output [39:0] csr_time_o,
output [39:0] csr_cycles_o,
output sys_tick_o
);
......@@ -38,13 +43,13 @@ module urv_timer
parameter g_clock_frequency = 62500000;
localparam g_prescaler = (g_clock_frequency / g_timer_frequency ) - 1;
reg [23:0] presc;
reg presc_tick;
reg [39:0] cycles;
reg [39:0] ticks;
always@(posedge clk_i)
if(rst_i)
begin
......@@ -65,16 +70,16 @@ module urv_timer
ticks <= 0;
else if (presc_tick)
ticks <= ticks + 1;
always @(posedge clk_i)
if (rst_i)
cycles <= 0;
else
cycles <= cycles + 1;
assign csr_time_o = ticks;
assign csr_cycles_o = cycles;
assign sys_tick_o = presc_tick;
endmodule // urv_timer
/*
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.
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- uRV - a tiny and dumb RISC-V core
-- https://www.ohwr.org/projects/urv-core
--------------------------------------------------------------------------------
--
-- unit name: urv_writeback
--
-- description: uRV CPU: instruction write-back stage
--
--------------------------------------------------------------------------------
-- Copyright CERN 2015-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
*/
`include "urv_defs.v"
......@@ -24,84 +29,87 @@
`timescale 1ns/1ps
module urv_writeback
#(
parameter g_with_ecc = 0
)
(
input clk_i,
input rst_i,
input w_stall_i,
output w_stall_req_o,
input [2:0] x_fun_i,
input x_load_i,
input x_store_i,
input [31:0] x_dm_addr_i,
input [4:0] x_rd_i,
input [31:0] x_rd_value_i,
input x_rd_write_i,
input x_valid_i,
input [31:0] x_shifter_rd_value_i,
input [31:0] x_multiply_rd_value_i,
input [1:0] x_rd_source_i,
input [31:0] dm_data_l_i,
input dm_load_done_i,
input dm_store_done_i,
output [31:0] rf_rd_value_o,
output [4:0] rf_rd_o,
output rf_rd_write_o
input clk_i,
input rst_i,
output w_stall_req_o,
input [2:0] x_fun_i,
input x_load_i,
input x_store_i,
input [31:0] x_dm_addr_i,
input [4:0] x_rd_i,
input [31:0] x_rd_value_i,
input x_rd_write_i,
input x_valid_i,
input [31:0] x_shifter_rd_value_i,
input [31:0] x_multiply_rd_value_i,
input [1:0] x_rd_source_i,
input [1:0] x_ecc_flip_i,
input [31:0] dm_data_l_i,
input dm_load_done_i,
input dm_store_done_i,
output [31:0] rf_rd_value_o,
output [4:0] rf_rd_o,
output [6:0] rf_rd_ecc_o,
output [1:0] rf_rd_ecc_flip_o,
output rf_rd_write_o
);
reg [31:0] load_value;
// generate load value
always@*
begin
case (x_fun_i)
`LDST_B:
case ( x_dm_addr_i [1:0] )
2'b00: load_value <= {{24{dm_data_l_i[7]}}, dm_data_l_i[7:0] };
2'b01: load_value <= {{24{dm_data_l_i[15]}}, dm_data_l_i[15:8] };
2'b10: load_value <= {{24{dm_data_l_i[23]}}, dm_data_l_i[23:16] };
2'b11: load_value <= {{24{dm_data_l_i[31]}}, dm_data_l_i[31:24] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_BU:
case ( x_dm_addr_i [1:0] )
2'b00: load_value <= {24'h0, dm_data_l_i[7:0] };
2'b01: load_value <= {24'h0, dm_data_l_i[15:8] };
2'b10: load_value <= {24'h0, dm_data_l_i[23:16] };
2'b11: load_value <= {24'h0, dm_data_l_i[31:24] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_H:
case ( x_dm_addr_i [1:0] )
2'b00, 2'b01: load_value <= {{16{dm_data_l_i[15]}}, dm_data_l_i[15:0] };
2'b10, 2'b11: load_value <= {{16{dm_data_l_i[31]}}, dm_data_l_i[31:16] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_HU:
case ( x_dm_addr_i [1:0] )
2'b00, 2'b01: load_value <= {16'h0, dm_data_l_i[15:0] };
2'b10, 2'b11: load_value <= {16'h0, dm_data_l_i[31:16] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_L: load_value <= dm_data_l_i;
default: load_value <= 32'hx;
endcase // case (d_fun_i)
end // always@ *
case (x_fun_i)
`LDST_B:
case ( x_dm_addr_i [1:0] )
2'b00: load_value <= {{24{dm_data_l_i[7]}}, dm_data_l_i[7:0] };
2'b01: load_value <= {{24{dm_data_l_i[15]}}, dm_data_l_i[15:8] };
2'b10: load_value <= {{24{dm_data_l_i[23]}}, dm_data_l_i[23:16] };
2'b11: load_value <= {{24{dm_data_l_i[31]}}, dm_data_l_i[31:24] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_BU:
case ( x_dm_addr_i [1:0] )
2'b00: load_value <= {24'h0, dm_data_l_i[7:0] };
2'b01: load_value <= {24'h0, dm_data_l_i[15:8] };
2'b10: load_value <= {24'h0, dm_data_l_i[23:16] };
2'b11: load_value <= {24'h0, dm_data_l_i[31:24] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_H:
case ( x_dm_addr_i [1] )
1'b0: load_value <= {{16{dm_data_l_i[15]}}, dm_data_l_i[15:0] };
1'b1: load_value <= {{16{dm_data_l_i[31]}}, dm_data_l_i[31:16] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_HU:
case ( x_dm_addr_i [1] )
1'b0: load_value <= {16'h0, dm_data_l_i[15:0] };
1'b1: load_value <= {16'h0, dm_data_l_i[31:16] };
default: load_value <= 32'hx;
endcase // case ( x_dm_addr_i [1:0] )
`LDST_L: load_value <= dm_data_l_i;
default: load_value <= 32'hx;
endcase // case (d_fun_i)
reg rf_rd_write;
reg [31:0] rf_rd_value;
always@*
if( x_load_i )
rf_rd_value <= load_value;
......@@ -113,13 +121,31 @@ module urv_writeback
rf_rd_value <= x_rd_value_i;
always@*
if (w_stall_i)
rf_rd_write <= 0;
else if (x_load_i && dm_load_done_i)
if (x_load_i && dm_load_done_i)
rf_rd_write <= x_valid_i;
else
rf_rd_write <= x_rd_write_i & x_valid_i;
// synthesis translate_off
always@(posedge clk_i)
if(!rst_i)
if(rf_rd_write && (^rf_rd_value === 1'hx) )
$error("Attempt to write unknown value to reg %x", x_rd_i);
// synthesis translate_on
generate
if (g_with_ecc) begin
wire [6:0] rf_rd_ecc;
urv_ecc gen_ecc
(.dat_i(rf_rd_value),
.ecc_o(rf_rd_ecc));
assign rf_rd_ecc_o = rf_rd_ecc;
assign rf_rd_ecc_flip_o = x_ecc_flip_i;
end
else
assign rf_rd_ecc_o = 6'bx;
endgenerate
assign rf_rd_write_o = rf_rd_write;
assign rf_rd_value_o = rf_rd_value;
......
--
--
-- 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.
--
......@@ -82,7 +82,7 @@ architecture wrapper of xurv_core is
g_size : integer;
g_init_file : string;
g_simulation : boolean
);
);
port (
clk_i : in std_logic;
......@@ -123,7 +123,7 @@ architecture wrapper of xurv_core is
signal dm_mem_rdata, dm_wb_rdata : std_logic_vector(31 downto 0);
signal dm_wb_write, dm_select_wb : std_logic;
signal dm_data_write : std_logic;
begin
cpu_rst <= (not rst_n_i) or cpu_rst_i;
......@@ -137,7 +137,7 @@ begin
ha_im_access_d <= '0';
ha_im_write <= '0';
else
ha_im_access <= host_slave_i.cyc and host_slave_i.stb;
ha_im_access_d <= ha_im_access;
......@@ -169,7 +169,7 @@ begin
dm_store_done <= '0';
dm_select_wb <= '0';
else
if(dm_cycle_in_progress = '0') then -- access to internal memory
if(dm_is_wishbone = '0') then
if(dm_store = '1') then
......@@ -294,7 +294,5 @@ begin
host_slave_o.err <= '0';
host_slave_o.rty <= '0';
end wrapper;
end wrapper;
# and don't touch the rest unless you know what you're doing.
CROSS_COMPILE ?= /opt/gcc-riscv/bin/riscv64-unknown-elf-
CC = $(CROSS_COMPILE)gcc
XCC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
CFLAGS = -m32
OBJS = crt0.o main.o
LDS = ram.ld
OUTPUT=hello
$(OUTPUT): $(LDS) $(OBJS)
${CC} -m32 -o $(OUTPUT).elf -nostartfiles $(OBJS) -T $(LDS)
CFLAGS = -mabi=ilp32 -march=rv32im
OBJS = crt0.o $(OUTPUT).o
LDS = ram.ld
$(OUTPUT): $(LDS) $(OBJS) genraminit
${XCC} $(CFLAGS) -o $(OUTPUT).elf -nostartfiles $(OBJS) -T $(LDS)
${OBJCOPY} -O binary $(OUTPUT).elf $(OUTPUT).bin
${OBJDUMP} -D $(OUTPUT).elf > disasm.S
$(SIZE) $(OUTPUT).elf
......@@ -23,5 +25,11 @@ $(OUTPUT): $(LDS) $(OBJS)
clean:
rm -f $(OUTPUT).elf $(OUTPUT).bin $(OBJS)
%.o: %.S
${CC} -c -m32 $^ -o $@
\ No newline at end of file
%.o: %.S
${XCC} -c $(CFLAGS) $< -o $@
%.o: %.c
${XCC} -c $(CFLAGS) $< -o $@
genraminit: genraminit.c
$(CC) -o $@ $<
......@@ -26,7 +26,12 @@ void undefined_insn_handler( struct rv_trap_context *ctx )
else if ( (insn & 0xfe00707f) == 0x2003033 ) // MULHU
ctx->r[rdi] = ((uint64_t) rs1 * (uint64_t) rs2) >> 32;
else if ( (insn & 0xfe00707f) == 0x2004033 ) // DIV
{
if( rs2 == 0 )
ctx->r[rdi] = 0xffffffff;
else
ctx->r[rdi] = (int32_t)rs1 / (int32_t) rs2;
}
else if ( (insn & 0xfe00707f) == 0x2005033 ) // DIVU
ctx->r[rdi] = (uint32_t)rs1 / (uint32_t) rs2;
else if ( (insn & 0xfe00707f) == 0x2006033 ) // REM
......
.section .text
.global trap_entry
.global trap_entry
.weak trap_entry
trap_entry:
csrrw sp,mscratch,sp
addi sp,sp,-320
......@@ -48,35 +49,19 @@ trap_entry:
sw t0,144(sp)
mv a0,sp
la t0, jump_table
sll t3, t3, 2
add t0, t0, t3
lw t0, 0(t0)
la ra, jump_table_return
jr t0
bgez t3, .Lexcept
jal irq_handler
j .Lret
jump_table:
.word undefined_handler
.word undefined_handler
.word undefined_insn_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
jump_table_return:
mv a0,sp
.Lexcept:
la t0, jump_table
sll t3, t3, 2
add t0, t0, t3
lw t0, 0(t0)
jalr t0
.Lret:
mv a0,sp
lw t1,128(a0)
lw t2,132(a0)
addi sp,sp,320
......@@ -113,12 +98,38 @@ jump_table_return:
lw t5,120(a0)
lw t6,124(a0)
lw a0,40(a0)
eret
mret
.text
.weak undefined_handler
.weak undefined_handler
undefined_handler:
j undefined_handler
.weak undefined_insn_handler
.weak undefined_insn_handler
undefined_insn_handler:
j undefined_insn_handler
j undefined_insn_handler
.data
jump_table:
.word undefined_handler # 0: Insn address misaligned
.word undefined_handler
.word undefined_insn_handler # 2: Illegal insn
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.weak irq_handler
irq_handler:
j irq_handler
#include <stdint.h>
static const char hex[] = "0123456789abcdef";
static void uart_write_byte(int b)
{
*(volatile int *)0x100000 = b;
}
int puts(const char *s)
{
char c;
while(c=*s++)
uart_write_byte(c);
}
void rv_test_pass(int num)
{
pp_printf("Test passed\n");
puts("Test passed\n");
}
void rv_test_fail(int num)
{
pp_printf("Test %d failed\n", num);
}
\ No newline at end of file
puts ("Test 0x");
uart_write_byte(hex[(num >> 4) & 0xf]);
uart_write_byte(hex[(num >> 0) & 0xf]);
puts (" failed\n");
}
......@@ -46,18 +46,10 @@ void uart_init_hw()
}
volatile int *TX_REG = 0x100000;
void putc(char c)
{
*TX_REG = c;
}
void uart_write_byte(int b)
{
#ifdef SIM
putc(b);
*(volatile int *)0x100000 = b;
#else
if (b == '\n')
uart_write_byte('\r');
......@@ -85,4 +77,3 @@ int puts(const char *s)
while(c=*s++)
uart_write_byte(c);
}
hello.elf: file format elf32-littleriscv
Disassembly of section .boot:
00000000 <_start>:
0: 00000197 auipc gp,0x0
4: 07018193 addi gp,gp,112 # 70 <_gp>
8: 00010117 auipc sp,0x10
c: ff410113 addi sp,sp,-12 # fffc <_fstack>
10: 00000297 auipc t0,0x0
14: 07828293 addi t0,t0,120 # 88 <_fbss>
18: 00000317 auipc t1,0x0
1c: 0b030313 addi t1,t1,176 # c8 <_ebss>
20: 0002a023 sw zero,0(t0)
24: 00428293 addi t0,t0,4
28: fe62ece3 bltu t0,t1,20 <_start+0x20>
2c: 004000ef jal 30 <main>
Disassembly of section .text:
00000030 <main>:
30: fe010113 addi sp,sp,-32
34: 00812e23 sw s0,28(sp)
38: 02010413 addi s0,sp,32
3c: 08002783 lw a5,128(zero)
40: fef42623 sw a5,-20(s0)
44: 01c0006f j 60 <main+0x30>
48: 08402703 lw a4,132(zero)
4c: fec42783 lw a5,-20(s0)
50: 00178693 addi a3,a5,1
54: fed42623 sw a3,-20(s0)
58: 0007c783 lbu a5,0(a5)
5c: 00f72023 sw a5,0(a4)
60: fec42783 lw a5,-20(s0)
64: 0007c783 lbu a5,0(a5)
68: fe0790e3 bnez a5,48 <main+0x18>
6c: 0000006f j 6c <main+0x3c>
Disassembly of section .rodata:
00000070 <.rodata>:
70: 6548 add a0,a0,s2
72: 6c6c add s8,s8,s11
74: 77202c6f jal s8,27e6 <_ebss+0x271e>
78: 646c726f jal tp,c76be <_fstack+0xb76c2>
...
Disassembly of section .sdata:
00000080 <hello>:
80: 0070 li zero,28
...
00000084 <TX_REG>:
84: 0000 unimp
86: 0010 li zero,4
Disassembly of section .bss:
00000088 <_fbss>:
...
Disassembly of section .comment:
00000000 <.comment>:
0: 3a434347 fmsub.d ft6,ft6,ft4,ft7,rmm
4: 2820 lui a6,0x8
6: 29554e47 fmsub.s ft8,fa0,fs5,ft5,rmm
a: 3520 lui a0,0xfffe8
c: 312e beqz a1,b4 <_fbss+0x2c>
e: 302e beqz a1,36 <main+0x6>
...
......@@ -2,10 +2,12 @@ char dupa[64];
const char *hello="Hello, world";
volatile int *TX_REG = 0x100000;
main()
volatile int *TX_REG = (volatile int *)0x100000;
void
main(void)
{
char *s = hello;
const char *s = hello;
while(*s) { *TX_REG = *s++; }
for(;;);
}
\ No newline at end of file
}
# and don't touch the rest unless you know what you're doing.
CROSS_COMPILE ?= /opt/gcc-riscv/bin/riscv64-unknown-elf-
XCC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
OUTPUT=test_irq
CFLAGS = -mabi=ilp32 -march=rv32im
OBJS = ../common/crt0.o ../common/irq.o $(OUTPUT).o
LDS = ../common/ram2.ld
$(OUTPUT): $(LDS) $(OBJS) ../genraminit
${XCC} $(CFLAGS) -o $(OUTPUT).elf -nostartfiles $(OBJS) -T $(LDS)
${OBJCOPY} -O binary $(OUTPUT).elf $(OUTPUT).bin
${OBJDUMP} -D $(OUTPUT).elf > disasm.S
$(SIZE) $(OUTPUT).elf
# ../genramvhd -p wrc_simulation_firmware $(OUTPUT).bin > wrc_simulation_firmware_pkg.vhd
../genraminit $(OUTPUT).bin 1000 > $(OUTPUT).ram
clean:
rm -f $(OUTPUT).elf $(OUTPUT).bin $(OBJS)
%.o: %.S
${XCC} -c $(CFLAGS) $< -o $@
%.o: %.c
${XCC} -c $(CFLAGS) $< -o $@
static const char *hello="Hello, world";
static const char *ptr;
static int irq_cnt = 0;
volatile int *TX_REG = (volatile int *)0x100000;
volatile int *IRQ_REG = (volatile int *)0x100004;
void
irq_handler(void)
{
irq_cnt++;
if (*ptr) {
*TX_REG = *ptr++;
if (irq_cnt < 2)
*IRQ_REG = 100;
else
*IRQ_REG = 10;
}
else
*IRQ_REG = 0;
}
void
main(void)
{
unsigned t;
ptr = hello;
/* Enable irq: set mie.meie */
asm volatile ("csrrs %0, mie, %1" : "=r"(t) : "r"(1 << 11));
/* Enable interrupts: set mstatus.mie */
asm volatile ("csrrsi %0, mstatus, %1" : "=r"(t) : "i"(1 << 3));
/* Generate an interrupt after 10 cycles. */
*IRQ_REG = 10;
for(;;);
}
......@@ -619,6 +619,7 @@
#define CAUSE_SUPERVISOR_ECALL 0x9
#define CAUSE_HYPERVISOR_ECALL 0xa
#define CAUSE_MACHINE_ECALL 0xb
#define CAUSE_ECC_ERROR 0xf // urv specific
#endif
#ifdef DECLARE_INSN
DECLARE_INSN(add, MATCH_ADD, MASK_ADD)
......
......@@ -121,11 +121,11 @@ ecall: ecall; \
#define RVTEST_PASS \
la sp, _fstack; la gp, _gp; jal rv_test_pass; \
la t0, 0x100004; sw t0, 0(t0); j ecall;
lui t0, %hi(0x100004); sw t0, %lo(0x100004)(t0); j ecall;
#define RVTEST_FAIL \
la sp, _fstack; la gp, _gp; mv a0, TESTNUM; jal rv_test_fail;\
la t0, 0x100004; sw t0, 0(t0); j ecall;
lui t0, %hi(0x100004); sw t0, %lo(0x100004)(t0); j ecall;
//-----------------------------------------------------------------------
// Data Section Macro
......
......@@ -13,6 +13,7 @@ isa_src_dir := .
include $(isa_src_dir)/rv32ui/Makefrag
#include $(isa_src_dir)/rv32si/Makefrag
include $(isa_src_dir)/rv32mi/Makefrag
include $(isa_src_dir)/urv/Makefrag
default: all
......@@ -20,23 +21,26 @@ default: all
# Build rules
#--------------------------------------------------------------------
RISCV_PREFIX=riscv64-unknown-elf-
RISCV_PREFIX=riscv32-elf-
RISCV_GCC = $(RISCV_PREFIX)gcc
ENTROPY = -DENTROPY=$(shell echo $$$$)
RISCV_GCC_OPTS = $(ENTROPY) -mcmodel=medany -nostartfiles -fvisibility=hidden -Wa,-march=RV32IM -DSIM -I../../common
RISCV_GCC_OPTS = $(ENTROPY) -mcmodel=medany -nostartfiles -fvisibility=hidden -march=rv32im -mabi=ilp32 -DSIM -I../../common
RISCV_OBJDUMP = $(RISCV_PREFIX)objdump --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data
RISCV_SIM = spike --extension=hwacha
COMMON_SRCS = ../../common/crt0.S ../../common/irq.S ../../common/_emulate.o ../../common/test-common.c ../../common/printf.c ../../common/uart.c ../../common/vsprintf-xint.c
COMMON_SRCS = ../../common/crt0.S ../../common/irq.S emulate.o ../../common/test-common.c
vpath %.S $(isa_src_dir)
emulate.o: ../../common/emulate.c
$(RISCV_GCC) -c $(RISCV_GCC_OPTS) -mabi=ilp32 -march=rv32i -o $@ $<
#------------------------------------------------------------
# Build assembly tests
%.ram: %
riscv64-unknown-elf-objcopy -O binary $< tmp.bin
../../genraminit tmp.bin 16384 > $@
$(RISCV_PREFIX)objcopy -O binary $< tmp.bin
../../genraminit tmp.bin 4096 > $@
%.dump: %
$(RISCV_OBJDUMP) $< > $@
......@@ -49,7 +53,7 @@ vpath %.S $(isa_src_dir)
define compile_template
$$($(1)_p_tests): $(1)-p-%: $(1)/%.S
$$($(1)_p_tests): $(1)-p-%: $(1)/%.S emulate.o
$$(RISCV_GCC) $(2) $$(RISCV_GCC_OPTS) -I$(isa_src_dir)/../env/p -I$(isa_src_dir)/macros/scalar $(COMMON_SRCS) -T ../../common/ram2.ld $$< -o $$@
$(1)_tests += $$($(1)_p_tests)
......@@ -64,7 +68,8 @@ tests += $$($(1)_tests)
endef
$(eval $(call compile_template,rv32ui,-m32))
$(eval $(call compile_template,rv32ui,))
$(eval $(call compile_template,urv,))
tests_dump = $(addsuffix .dump, $(tests))
tests_ram = $(addsuffix .ram, $(tests))
......
......@@ -249,7 +249,7 @@ test_ ## testnum: \
#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \
TEST_CASE( testnum, x3, result, \
la x1, base; \
lui x1, %hi(base); addi x1, x1, %lo(base) ; \
li x2, result; \
store_inst x2, offset(x1); \
load_inst x3, offset(x1); \
......@@ -286,9 +286,9 @@ test_ ## testnum: \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x1, result; \
1: lui x1, %hi(result); addi x1, x1, %lo(result) ; \
TEST_INSERT_NOPS_ ## src1_nops \
la x2, base; \
lui x2, %hi(base); addi x2, x2, %lo(base) ; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x1, offset(x2); \
load_inst x3, offset(x2); \
......@@ -302,9 +302,9 @@ test_ ## testnum: \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x2, base; \
1: lui x2, %hi(base); addi x2, x2, %lo(base) ; \
TEST_INSERT_NOPS_ ## src1_nops \
la x1, result; \
lui x1, %hi(result); addi x1, x1, %lo(result) ; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x1, offset(x2); \
load_inst x3, offset(x2); \
......
......@@ -22,7 +22,8 @@ rv32ui_sc_tests = \
srl srli \
sub \
xor xori \
csr
csr \
urv-mul-mulh
rv32ui_mc_tests =
# lrsc
......
......@@ -22,10 +22,10 @@ RVTEST_CODE_BEGIN
TEST_RR_OP( 4, div, -3, 20, -6 );
TEST_RR_OP( 5, div, 3, -20, -6 );
TEST_RR_OP( 6, div, -1<<63, -1<<63, 1 );
TEST_RR_OP( 7, div, -1<<63, -1<<63, -1 );
TEST_RR_OP( 6, div, -1<<31, -1<<31, 1 );
TEST_RR_OP( 7, div, -1<<31, -1<<31, -1 );
TEST_RR_OP( 8, div, -1, -1<<63, 0 );
TEST_RR_OP( 8, div, -1, -1<<31, 0 );
TEST_RR_OP( 9, div, -1, 1, 0 );
TEST_RR_OP(10, div, -1, 0, 0 );
......
......@@ -22,10 +22,10 @@ RVTEST_CODE_BEGIN
TEST_RR_OP( 4, rem, 2, 20, -6 );
TEST_RR_OP( 5, rem, -2, -20, -6 );
TEST_RR_OP( 6, rem, 0, -1<<63, 1 );
TEST_RR_OP( 7, rem, 0, -1<<63, -1 );
TEST_RR_OP( 6, rem, 0, -1<<31, 1 );
TEST_RR_OP( 7, rem, 0, -1<<31, -1 );
TEST_RR_OP( 8, rem, -1<<63, -1<<63, 0 );
TEST_RR_OP( 8, rem, -1<<31, -1<<31, 0 );
TEST_RR_OP( 9, rem, 1, 1, 0 );
TEST_RR_OP(10, rem, 0, 0, 0 );
......
......@@ -22,10 +22,10 @@ RVTEST_CODE_BEGIN
TEST_RR_OP( 4, remu, 20, 20, -6 );
TEST_RR_OP( 5, remu, -20, -20, -6 );
TEST_RR_OP( 6, remu, 0, -1<<63, 1 );
TEST_RR_OP( 7, remu, -1<<63, -1<<63, -1 );
TEST_RR_OP( 6, remu, 0, -1<<31, 1 );
TEST_RR_OP( 7, remu, -1<<31, -1<<31, -1 );
TEST_RR_OP( 8, remu, -1<<63, -1<<63, 0 );
TEST_RR_OP( 8, remu, -1<<31, -1<<31, 0 );
TEST_RR_OP( 9, remu, 1, 1, 0 );
TEST_RR_OP(10, remu, 0, 0, 0 );
......
......@@ -19,13 +19,7 @@ RVTEST_CODE_BEGIN
TEST_ST_OP( 2, lb, sb, 0xffffffaa, 0, tdat );
TEST_ST_OP( 3, lb, sb, 0x00000000, 1, tdat );
#ifdef __RISCVEL
TEST_ST_OP( 4, lh, sb, 0xffffefa0, 2, tdat );
#elif defined(__RISCVEB)
#else
TEST_ST_OP( 4, lh, sb, 0xffffa0ef, 2, tdat );
#error unknown endianness!
#endif
TEST_ST_OP( 5, lb, sb, 0x0000000a, 3, tdat );
# Test with negative offset
......
......@@ -19,13 +19,7 @@ RVTEST_CODE_BEGIN
TEST_ST_OP( 2, lh, sh, 0x000000aa, 0, tdat );
TEST_ST_OP( 3, lh, sh, 0xffffaa00, 2, tdat );
#ifdef __RISCVEL
TEST_ST_OP( 4, lw, sh, 0xbeef0aa0, 4, tdat );
#elif defined(__RISCVEB)
#else
TEST_ST_OP( 4, lw, sh, 0x0aa0beef, 4, tdat );
#error unknown endianness!
#endif
TEST_ST_OP( 5, lh, sh, 0xffffa00a, 6, tdat );
# Test with negative offset
......
#*****************************************************************************
# urv-mul-mulh.S
#-----------------------------------------------------------------------------
#
# Test mul/mulh stall condition (a.k.a. John's bug)
#
#include "riscv_test.h"
#include "test_macros.h"
RVTEST_RV32U
RVTEST_CODE_BEGIN
# before the multiply:
# a2 = 0x2833
# a3 = 0x3
# a5 = 0xcafebabe
li a2, 0x2833
li a3, 0x3
li a5, 0xcafebabe
mul a5,a3,a5
mulhu a3,a3,a2
#after the multiply (correct case)
# a3 = 0x0
# a5 = 0x60fc303a
li s0, 0x60fc303a
bne a3, zero, fail
bne a5, s0, fail
j pass
TEST_PASSFAIL
RVTEST_CODE_END
.data
RVTEST_DATA_BEGIN
TEST_DATA
RVTEST_DATA_END
urv-p-write_ecc.ram
urv-p-fix_ecc_1.ram
urv-p-fix_ecc_2.ram
urv-p-fix_ecc_dbl_err.ram
urv-p-ecc_ori.ram
......@@ -44,3 +44,4 @@ rv32ui-p-sub.ram
rv32ui-p-sw.ram
rv32ui-p-xori.ram
rv32ui-p-xor.ram
rv32ui-p-urv-mul-mulh.ram
\ No newline at end of file
#=======================================================================
# Makefrag for rv32ui tests
#-----------------------------------------------------------------------
urv_ecc_tests = \
write_ecc \
fix_ecc_1 \
fix_ecc_2 \
fix_ecc_dbl_err \
ecc_ori
urv_p_tests = $(addprefix urv-p-, $(urv_ecc_tests))
spike_tests += $(urv_p_tests)
# See LICENSE for license details.
#*****************************************************************************
# write_ecc.S
#-----------------------------------------------------------------------------
#
# Test write_ecc trap.
#
#include "riscv_test.h"
#include "test_macros.h"
#include "urv_asm.h"
RVTEST_RV32S
RVTEST_CODE_BEGIN
li a0, 0xff00ff00
# Corrupt a0 (bank 1)
li t1, 1
write_ecc a0, a0, t1
nop
nop
nop
# Test ori
ori a1, a0, 0xffffff0f
# Check result
li a2, 0xffffff0f
bne a1, a2, fail
# Check handler was called
bne t1, zero, fail
li a0, 0xff00ff00
# Corrupt a0 (bank 2)
li t1, 2
write_ecc a0, a0, t1
nop
nop
nop
# Test ori
ori a1, a0, 0xffffff0f
# Check result
li a2, 0xffffff0f
bne a1, a2, fail
# Check handler was not called
beq t1, zero, fail
j pass
TEST_PASSFAIL
.globl trap_entry
trap_entry:
fix_ecc x0,x0,x0
fix_ecc x1,x1,x1
fix_ecc x2,x2,x2
fix_ecc x3,x3,x3
fix_ecc x4,x4,x4
fix_ecc x5,x5,x5
fix_ecc x6,x6,x6
fix_ecc x7,x7,x7
fix_ecc x8,x8,x8
fix_ecc x9,x9,x9
fix_ecc x10,x10,x10
fix_ecc x11,x11,x11
fix_ecc x12,x12,x12
fix_ecc x13,x13,x13
fix_ecc x14,x14,x14
fix_ecc x15,x15,x15
fix_ecc x16,x16,x16
fix_ecc x17,x17,x17
fix_ecc x18,x18,x18
fix_ecc x19,x19,x19
fix_ecc x20,x20,x20
fix_ecc x21,x21,x21
fix_ecc x22,x22,x22
fix_ecc x23,x23,x23
fix_ecc x24,x24,x24
fix_ecc x25,x25,x25
fix_ecc x26,x26,x26
fix_ecc x27,x27,x27
fix_ecc x28,x28,x28
fix_ecc x29,x29,x29
fix_ecc x30,x30,x30
fix_ecc x31,x31,x31
# Clear t1
lui t1,0
mret
RVTEST_CODE_END
.data
RVTEST_DATA_BEGIN
TEST_DATA
RVTEST_DATA_END
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment