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
/*
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_cpu
--
-- description: uRV CPU: top-level
--
--------------------------------------------------------------------------------
-- 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"
......@@ -27,54 +32,81 @@ module urv_cpu
#(
parameter g_timer_frequency = 1000,
parameter g_clock_frequency = 100000000,
parameter g_with_hw_divide = 0,
parameter g_with_hw_div = 1,
parameter g_with_hw_mulh = 1, // Force mulh if mul is > 0 (for compatibility).
parameter g_with_hw_mul = 1, // 0: no multiply, 1: 32x32 mul. 2: mulh
parameter g_with_hw_debug = 0,
parameter g_debug_breakpoints = 6
)
parameter g_with_ecc = 0,
parameter g_with_compressed_insns = 0
)
(
input clk_i,
input rst_i,
input irq_i,
// For ECC double error
output fault_o,
// instruction mem I/F
output [31:0] im_addr_o,
output im_rd_o,
input [31:0] im_data_i,
input im_valid_i,
// data mem I/F
// The interface is pipelined: store/load are asserted for one cycle
// and then store_done/load_done is awaited.
output [31:0] dm_addr_o,
output [31:0] dm_data_s_o,
input [31:0] dm_data_l_i,
output [3:0] dm_data_select_o,
input dm_ready_i,
output dm_store_o,
output dm_load_o,
input dm_load_done_i,
input dm_store_done_i
input dm_store_done_i,
// 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.
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 [31:0] dbg_mbx_data_i,
input dbg_mbx_write_i,
output [31:0] dbg_mbx_data_o
);
// pipeline control
wire f_stall;
wire w_stall;
wire x_stall;
wire x_kill;
wire f_kill;
wire d_stall;
wire d_kill;
wire d_stall_req;
wire w_stall_req;
wire x_stall_req;
wire x_fault;
// X1->F stage interface
wire [31:0] x2f_pc_bra;
wire x2f_bra;
wire x2f_dbg_toggle;
// F->D stage interface
wire [31:0] f2d_pc, f2d_ir;
wire f2d_ir_valid;
wire f2d_valid;
// D->RF interface
......@@ -83,31 +115,34 @@ module urv_cpu
// X2/W->RF interface
wire [4:0] rf_rd;
wire [31:0] rf_rd_value;
wire [6:0] rf_rd_ecc;
wire [1:0] rf_rd_ecc_flip;
wire rf_rd_write;
// D->X1 stage interface
wire d2x_valid;
wire [31:0] d2x_pc;
wire [4:0] d2x_rs1;
wire [4:0] d2x_rs2;
wire [4:0] d2x_rd;
wire [4:0] d2x_shamt;
wire [2:0] d2x_fun;
wire [4:0] d2x_opcode;
wire d2x_shifter_sign;
wire d2x_is_load, d2x_is_store, d2x_is_undef;
wire d2x_is_write_ecc;
wire d2x_is_fix_ecc;
wire [31:0] d2x_imm;
wire d2x_is_signed_compare;
wire d2x_is_signed_alu_op;
wire d2x_is_add_o;
wire d2x_is_shift_o;
wire [2:0] d2x_rd_source;
wire d2x_rd_write;
wire [11:0] d2x_csr_sel;
wire [4:0] d2x_csr_imm;
wire d2x_is_csr, d2x_is_eret, d2x_csr_load_en;
wire d2x_is_csr, d2x_is_mret, d2x_is_ebreak, d2x_csr_load_en;
wire [31:0] d2x_alu_op1, d2x_alu_op2;
wire d2x_use_op1, d2x_use_op2;
wire d2x_use_rs1, d2x_use_rs2;
wire d2x_is_multiply, d2x_is_divide;
// X1/M->X2/W interface
wire [4:0] x2w_rd;
......@@ -121,26 +156,38 @@ module urv_cpu
wire x2w_load;
wire [1:0] x2w_rd_source;
wire x2w_valid;
wire [1:0] x2w_ecc_flip;
// Register file signals
wire [31:0] x_rs2_value, x_rs1_value;
wire x_rs1_ecc_err, x_rs2_ecc_err;
wire [31:0] rf_bypass_rd_value = x2w_rd_value;
wire rf_bypass_rd_write = rf_rd_write && !x2w_load; // multiply/shift too?
// misc stuff
wire [39:0] csr_time, csr_cycles;
urv_fetch fetch
// 0: no multiply, 1: 32 bit multiply, 2: mulh.
localparam p_with_hw_mul = g_with_hw_mul ? (g_with_hw_mul | (g_with_hw_mulh ? 2 : 0)) : 0;
urv_fetch
#(
.g_with_hw_debug(g_with_hw_debug),
.g_with_compressed_insns(g_with_compressed_insns)
)
fetch
(
.clk_i(clk_i),
.rst_i(rst_i),
// instruction memory
.im_addr_o(im_addr_o),
.im_rd_o(im_rd_o),
.im_data_i(im_data_i),
.im_valid_i(im_valid_i),
// pipe control
.f_stall_i(f_stall),
.f_kill_i(f_kill),
// to D stage
.f_valid_o(f2d_valid),
......@@ -149,11 +196,24 @@ module urv_cpu
// from X1 stage (jumps)
.x_pc_bra_i(x2f_pc_bra),
.x_bra_i(x2f_bra)
.x_bra_i(x2f_bra),
.dbg_force_i(dbg_force_i),
.dbg_enabled_o(dbg_enabled_o),
.dbg_insn_i(dbg_insn_i),
.dbg_insn_set_i(dbg_insn_set_i),
.dbg_insn_ready_o(dbg_insn_ready_o),
.x_dbg_toggle_i(x2f_dbg_toggle)
);
urv_decode decode
urv_decode
#(
.g_with_hw_div(g_with_hw_div),
.g_with_hw_mul(p_with_hw_mul),
.g_with_hw_debug(g_with_hw_debug)
)
decode
(
.clk_i(clk_i),
.rst_i(rst_i),
......@@ -177,25 +237,29 @@ module urv_cpu
.x_pc_o(d2x_pc),
.x_rs1_o(d2x_rs1),
.x_rs2_o(d2x_rs2),
.x_use_rs1_o(d2x_use_rs1),
.x_use_rs2_o(d2x_use_rs2),
.x_imm_o(d2x_imm),
.x_rd_o(d2x_rd),
.x_shamt_o(d2x_shamt),
.x_fun_o(d2x_fun),
.x_opcode_o(d2x_opcode),
.x_shifter_sign_o(d2x_shifter_sign),
.x_is_signed_compare_o(d2x_is_signed_compare),
.x_is_signed_alu_op_o(d2x_is_signed_alu_op),
.x_is_add_o(d2x_is_add),
.x_is_shift_o(d2x_is_shift),
.x_is_load_o(d2x_is_load),
.x_is_store_o(d2x_is_store),
.x_is_undef_o(d2x_is_undef),
.x_is_write_ecc_o(d2x_is_write_ecc),
.x_is_fix_ecc_o(d2x_is_fix_ecc),
.x_is_multiply_o(d2x_is_multiply),
.x_is_divide_o(d2x_is_divide),
.x_rd_source_o(d2x_rd_source),
.x_rd_write_o(d2x_rd_write),
.x_csr_sel_o (d2x_csr_sel),
.x_csr_imm_o (d2x_csr_imm),
.x_is_csr_o (d2x_is_csr),
.x_is_eret_o (d2x_is_eret),
.x_csr_sel_o(d2x_csr_sel),
.x_csr_imm_o(d2x_csr_imm),
.x_is_csr_o(d2x_is_csr),
.x_is_mret_o(d2x_is_mret),
.x_is_ebreak_o(d2x_is_ebreak),
.x_alu_op1_o(d2x_alu_op1),
.x_alu_op2_o(d2x_alu_op2),
.x_use_op1_o(d2x_use_op1),
......@@ -203,7 +267,11 @@ module urv_cpu
);
// Register File (RF)
urv_regfile regfile
urv_regfile
#(
.g_with_ecc(g_with_ecc)
)
regfile
(
.clk_i(clk_i),
.rst_i(rst_i),
......@@ -218,61 +286,82 @@ module urv_cpu
.x_rs1_value_o(x_rs1_value),
.x_rs2_value_o(x_rs2_value),
.x_rs1_ecc_err_o(x_rs1_ecc_err),
.x_rs2_ecc_err_o(x_rs2_ecc_err),
.w_rd_i(rf_rd),
.w_rd_value_i(rf_rd_value),
.w_rd_ecc_i(rf_rd_ecc),
.w_rd_ecc_flip_i(rf_rd_ecc_flip),
.w_rd_store_i(rf_rd_write),
.w_bypass_rd_write_i(rf_bypass_rd_write),
.w_bypass_rd_value_i(rf_bypass_rd_value)
);
// Execute 1/Memory stage (X1/M)
urv_exec execute
urv_exec
#(
.g_with_hw_div(g_with_hw_div),
.g_with_hw_mul(p_with_hw_mul),
.g_with_hw_debug(g_with_hw_debug)
)
execute
(
.clk_i(clk_i),
.rst_i(rst_i),
.irq_i ( irq_i ),
.irq_i(irq_i),
// pipe control
.x_stall_i(x_stall),
.x_kill_i(x_kill),
.x_stall_req_o(x_stall_req),
.x_fault_o(x_fault),
// from register file
.rf_rs1_value_i(x_rs1_value),
.rf_rs2_value_i(x_rs2_value),
.rf_rs1_ecc_err_i(x_rs1_ecc_err),
.rf_rs2_ecc_err_i(x_rs2_ecc_err),
// from D stage
.d_valid_i(d2x_valid),
.d_is_csr_i ( d2x_is_csr ),
.d_is_eret_i ( d2x_is_eret ),
.d_csr_imm_i ( d2x_csr_imm ),
.d_csr_sel_i (d2x_csr_sel),
.d_is_csr_i(d2x_is_csr),
.d_is_mret_i(d2x_is_mret),
.d_is_ebreak_i(d2x_is_ebreak),
.d_dbg_mode_i(dbg_enabled_o),
.d_csr_imm_i(d2x_csr_imm),
.d_csr_sel_i(d2x_csr_sel),
.d_pc_i(d2x_pc),
.d_rd_i(d2x_rd),
.d_fun_i(d2x_fun),
.d_imm_i(d2x_imm),
.d_is_signed_compare_i(d2x_is_signed_compare),
.d_is_signed_alu_op_i(d2x_is_signed_alu_op),
.d_is_add_i(d2x_is_add),
.d_is_shift_i(d2x_is_shift),
.d_is_load_i(d2x_is_load),
.d_is_store_i(d2x_is_store),
.d_is_undef_i(d2x_is_undef),
.d_is_write_ecc_i(d2x_is_write_ecc),
.d_is_fix_ecc_i(d2x_is_fix_ecc),
.d_is_multiply_i(d2x_is_multiply),
.d_is_divide_i(d2x_is_divide),
.d_alu_op1_i(d2x_alu_op1),
.d_alu_op2_i(d2x_alu_op2),
.d_use_op1_i(d2x_use_op1),
.d_use_op2_i(d2x_use_op2),
.d_use_rs1_i(d2x_use_rs1),
.d_use_rs2_i(d2x_use_rs2),
.d_rd_source_i(d2x_rd_source),
.d_rd_write_i(d2x_rd_write),
.d_rd_write_i(d2x_rd_write),
.d_opcode_i(d2x_opcode),
.d_shifter_sign_i(d2x_shifter_sign),
// to F stage (branches)
.f_branch_target_o (x2f_pc_bra), // fixme: consistent naming
.f_branch_take_o (x2f_bra),
.f_branch_target_o(x2f_pc_bra), // fixme: consistent naming
.f_branch_take_o(x2f_bra),
.f_dbg_toggle_o(x2f_dbg_toggle),
// to X2/W stage
.w_fun_o(x2w_fun),
......@@ -283,9 +372,10 @@ module urv_cpu
.w_rd_o(x2w_rd),
.w_rd_value_o(x2w_rd_value),
.w_rd_write_o(x2w_rd_write),
.w_rd_source_o ( x2w_rd_source),
.w_rd_shifter_o ( x2w_rd_shifter),
.w_rd_multiply_o ( x2w_rd_multiply),
.w_rd_source_o(x2w_rd_source),
.w_rd_shifter_o(x2w_rd_shifter),
.w_rd_multiply_o(x2w_rd_multiply),
.w_ecc_flip_o(x2w_ecc_flip),
// Data memory I/F
.dm_addr_o(dm_addr_o),
......@@ -293,22 +383,27 @@ module urv_cpu
.dm_data_select_o(dm_data_select_o),
.dm_store_o(dm_store_o),
.dm_load_o(dm_load_o),
.dm_ready_i(dm_ready_i),
// CSR registers/timer stuff
.csr_time_i (csr_time),
.csr_cycles_i (csr_cycles),
.timer_tick_i (sys_tick)
.csr_time_i(csr_time),
.csr_cycles_i(csr_cycles),
.timer_tick_i(sys_tick),
// Debug mailboxes
.dbg_mbx_data_i(dbg_mbx_data_i),
.dbg_mbx_write_i(dbg_mbx_write_i),
.dbg_mbx_data_o(dbg_mbx_data_o)
);
// Execute 2/Writeback stage
urv_writeback writeback
urv_writeback
#(.g_with_ecc(g_with_ecc))
writeback
(
.clk_i(clk_i),
.rst_i(rst_i),
// pipe control
.w_stall_i(w_stall),
.w_stall_req_o(w_stall_req),
// from X1 stage
......@@ -320,37 +415,47 @@ module urv_cpu
.x_rd_source_i(x2w_rd_source),
.x_rd_value_i(x2w_rd_value),
.x_rd_write_i(x2w_rd_write),
.x_shifter_rd_value_i ( x2w_rd_shifter),
.x_multiply_rd_value_i ( x2w_rd_multiply),
.x_shifter_rd_value_i(x2w_rd_shifter),
.x_multiply_rd_value_i(x2w_rd_multiply),
.x_dm_addr_i(x2w_dm_addr),
.x_ecc_flip_i(x2w_ecc_flip),
// Data memory I/F
.dm_data_l_i(dm_data_l_i),
.dm_load_done_i(dm_load_done_i),
.dm_store_done_i(dm_store_done_i),
// to register file
.rf_rd_value_o(rf_rd_value),
.rf_rd_ecc_o(rf_rd_ecc),
.rf_rd_ecc_flip_o(rf_rd_ecc_flip),
.rf_rd_o(rf_rd),
.rf_rd_write_o(rf_rd_write)
);
// Built-in timer
urv_timer
#(
.g_timer_frequency(g_timer_frequency),
.g_clock_frequency(g_clock_frequency)
)
ctimer
(
.clk_i(clk_i),
.rst_i(rst_i),
assign fault_o = x_fault & g_with_ecc;
.csr_time_o(csr_time),
.csr_cycles_o(csr_cycles),
.sys_tick_o(sys_tick)
);
// Built-in timer
generate
if (g_timer_frequency > 0)
urv_timer
#(
.g_timer_frequency(g_timer_frequency),
.g_clock_frequency(g_clock_frequency)
)
ctimer
(
.clk_i(clk_i),
.rst_i(rst_i),
.csr_time_o(csr_time),
.csr_cycles_o(csr_cycles),
.sys_tick_o(sys_tick)
);
else
assign sys_tick = 0;
endgenerate
// pipeline invalidation logic after a branch
reg x2f_bra_d0, x2f_bra_d1;
......@@ -363,19 +468,13 @@ module urv_cpu
x2f_bra_d0 <= x2f_bra;
x2f_bra_d1 <= x2f_bra_d0;
end
// pipeline control
assign f_stall = x_stall_req || w_stall_req || d_stall_req;
assign x_stall = x_stall_req || w_stall_req;
assign d_stall = x_stall_req || w_stall_req;
assign w_stall = 0;
assign x_stall = x_stall_req || w_stall_req;
assign x_kill = x2f_bra || x2f_bra_d0 || x2f_bra_d1;
assign d_kill = x2f_bra || x2f_bra_d0;
assign f_kill = x2f_bra;
endmodule // urv_cpu
endmodule // urv_cpu
/*
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
/*
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_exec
--
-- description: uRV CPU: instruction execute 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"
......@@ -31,16 +36,19 @@ module urv_exec
input x_stall_i,
input x_kill_i,
output reg x_stall_req_o,
// Unfixable ecc error
output reg x_fault_o,
input [31:0] d_pc_i,
input [4:0] d_rd_i,
input [2:0] d_fun_i,
input [31:0] rf_rs1_value_i,
input [31:0] rf_rs2_value_i,
input rf_rs1_ecc_err_i,
input rf_rs2_ecc_err_i,
input d_valid_i,
......@@ -48,35 +56,41 @@ module urv_exec
input d_shifter_sign_i,
input d_is_csr_i,
input d_is_eret_i,
input d_is_mret_i,
input d_is_ebreak_i,
input d_dbg_mode_i,
input [4:0] d_csr_imm_i,
input [11:0] d_csr_sel_i,
input [31:0] d_imm_i,
input d_is_signed_compare_i,
input d_is_signed_alu_op_i,
input d_is_add_i,
input d_is_shift_i,
input d_is_load_i,
input d_is_store_i,
input d_is_divide_i,
input d_is_multiply_i,
input d_is_undef_i,
input d_is_write_ecc_i,
input d_is_fix_ecc_i,
input [31:0] d_alu_op1_i,
input [31:0] d_alu_op2_i,
input d_use_op1_i,
input d_use_op2_i,
input d_use_rs1_i,
input d_use_rs2_i,
input [2:0] d_rd_source_i,
input d_rd_write_i,
output reg [31:0] f_branch_target_o,
output f_branch_take_o,
output reg f_dbg_toggle_o,
input irq_i,
// Writeback stage I/F
output reg [2:0 ] w_fun_o,
output reg w_load_o,
......@@ -90,38 +104,49 @@ module urv_exec
output reg [1:0] w_rd_source_o,
output [31:0] w_rd_shifter_o,
output [31:0] w_rd_multiply_o,
output reg [1:0] w_ecc_flip_o,
// Data memory I/F (address/store)
output [31:0] dm_addr_o,
output [31:0] dm_data_s_o,
output [3:0] dm_data_select_o,
output dm_store_o,
output dm_load_o,
input dm_ready_i,
input [39:0] csr_time_i,
input [39:0] csr_cycles_i,
input timer_tick_i
input timer_tick_i,
// Debug mailboxes.
input [31:0] dbg_mbx_data_i,
input dbg_mbx_write_i,
output [31:0] dbg_mbx_data_o
);
wire [31:0] rs1, rs2;
parameter g_with_hw_mul = 0;
parameter g_with_hw_div = 0;
parameter g_with_hw_debug = 0;
// Use rs1 and rs2, it's shorter; but keep long name for the ports.
wire [31:0] rs1, rs2;
assign rs1 = rf_rs1_value_i;
assign rs2 = rf_rs2_value_i;
reg [31:0] alu_op1, alu_op2, alu_result;
reg [31:0] rd_value;
wire exception_taken;
wire [31:0] alu_op1, alu_op2;
reg [31:0] alu_result, rd_value;
reg x_exception;
reg [3:0] x_exception_cause;
reg x_interrupt;
reg branch_take;
reg branch_condition_met;
reg [31:0] branch_target;
reg [31:0] dm_addr, dm_data_s, dm_select_s;
wire [31:0] dm_addr;
reg [31:0] dm_data_s;
reg [3:0] dm_select_s;
// Comparator
wire [32:0] cmp_op1 = { d_is_signed_alu_op_i ? rs1[31] : 1'b0, rs1 };
......@@ -131,31 +156,35 @@ module urv_exec
wire cmp_lt = cmp_rs[32];
reg f_branch_take;
wire [31:0] rd_csr;
wire [31:0] rd_div;
wire [31:0] rd_mulh;
wire exception;
wire [31:0] csr_mie, csr_mip, csr_mepc, csr_mstatus,csr_mcause;
wire [31:0] csr_write_value;
wire [31:0] exception_address, exception_vector;
reg [31:0] exception_pc;
urv_csr csr_regs
wire [31:0] exception_address;
wire [31:0] exception_pc;
wire irq_pending;
wire timer_pending;
urv_csr
#(
.g_with_hw_debug(g_with_hw_debug)
)
csr_regs
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i(x_stall_i),
.x_kill_i(x_kill_i),
.d_is_csr_i(d_is_csr_i),
.d_fun_i(d_fun_i),
.d_csr_imm_i(d_csr_imm_i),
.d_csr_sel_i (d_csr_sel_i),
.d_rs1_i(rs1),
.x_rd_o(rd_csr),
......@@ -168,36 +197,37 @@ module urv_exec
.csr_mip_i(csr_mip),
.csr_mie_i(csr_mie),
.csr_mepc_i(csr_mepc),
.csr_mcause_i(csr_mcause)
.csr_mcause_i(csr_mcause),
.dbg_mbx_data_i(dbg_mbx_data_i),
.dbg_mbx_write_i(dbg_mbx_write_i),
.dbg_mbx_data_o(dbg_mbx_data_o)
);
urv_exceptions exception_unit
urv_exceptions exception_unit
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i (x_stall_i),
.x_kill_i (x_kill_i),
.d_is_csr_i(d_is_csr_i),
.d_is_eret_i (d_is_eret_i),
.d_fun_i(d_fun_i),
.d_is_mret_i (d_is_mret_i),
.d_csr_imm_i(d_csr_imm_i),
.d_csr_sel_i(d_csr_sel_i),
.x_csr_write_value_i(csr_write_value),
.exp_irq_i(irq_i),
.exp_tick_i(timer_tick_i),
.exp_breakpoint_i(1'b0),
.exp_unaligned_load_i(1'b0),
.exp_unaligned_store_i(1'b0),
.exp_invalid_insn_i(d_is_undef_i && !x_stall_i && !x_kill_i && d_valid_i),
.exp_ei_pending_o(irq_pending),
.exp_ti_pending_o(timer_pending),
.x_exception_o(exception),
.x_exception_i(x_exception),
.x_exception_cause_i(x_exception_cause),
.x_interrupt_i(x_interrupt),
.x_exception_pc_i(exception_pc),
.x_exception_pc_o(exception_address),
.x_exception_vector_o(exception_vector),
.x_exception_taken_i(exception_taken),
.csr_mstatus_o(csr_mstatus),
.csr_mip_o(csr_mip),
......@@ -205,75 +235,60 @@ module urv_exec
.csr_mepc_o(csr_mepc),
.csr_mcause_o(csr_mcause)
);
// branch condition decoding
// branch condition decoding
always@*
case (d_fun_i) // synthesis parallel_case full_case
`BRA_EQ: branch_condition_met <= cmp_equal;
`BRA_EQ: branch_condition_met <= cmp_equal;
`BRA_NEQ: branch_condition_met <= ~cmp_equal;
`BRA_GE: branch_condition_met <= ~cmp_lt | cmp_equal;
`BRA_LT: branch_condition_met <= cmp_lt;
`BRA_GE: branch_condition_met <= ~cmp_lt | cmp_equal;
`BRA_LT: branch_condition_met <= cmp_lt;
`BRA_GEU: branch_condition_met <= ~cmp_lt | cmp_equal;
`BRA_LTU: branch_condition_met <= cmp_lt;
default: branch_condition_met <= 0;
default: branch_condition_met <= 0;
endcase // case (d_fun_i)
// generate load/store address
always@*
dm_addr <= d_imm_i + ( ( d_opcode_i == `OPC_JALR || d_opcode_i == `OPC_LOAD || d_opcode_i == `OPC_STORE) ? rs1 : d_pc_i );
// calculate branch target address
// calculate branch target address
always@*
if(d_is_eret_i )
if (d_is_mret_i)
branch_target <= exception_address;
else if ( exception )
branch_target <= exception_vector;
else
branch_target <= dm_addr;
else if (x_exception)
branch_target <= `URV_TRAP_VECTOR;
else if (d_is_ebreak_i && g_with_hw_debug)
branch_target <= d_pc_i;
else
branch_target <= d_imm_i + (d_opcode_i == `OPC_JALR ? rs1 : d_pc_i);
// decode ALU operands
always@*
begin
alu_op1 <= d_use_op1_i ? d_alu_op1_i : rs1;
alu_op2 <= d_use_op2_i ? d_alu_op2_i : rs2;
end
assign alu_op1 = d_use_op1_i ? d_alu_op1_i : rs1;
assign alu_op2 = d_use_op2_i ? d_alu_op2_i : rs2;
// ALU adder/subtractor
// Sign extension
wire [32:0] alu_addsub_op1 = {d_is_signed_alu_op_i ? alu_op1[31] : 1'b0, alu_op1 };
wire [32:0] alu_addsub_op2 = {d_is_signed_alu_op_i ? alu_op2[31] : 1'b0, alu_op2 };
reg [32:0] alu_addsub_result;
always@*
if(d_is_add_i)
alu_addsub_result <= alu_addsub_op1 + alu_addsub_op2;
else
alu_addsub_result <= alu_addsub_op1 - alu_addsub_op2;
// ALU adder/subtractor
wire [32:0] alu_add = alu_addsub_op1 + alu_addsub_op2;
wire [32:0] alu_sub = alu_addsub_op1 - alu_addsub_op2;
// the rest of the ALU
// FIXECC and WRECC uses 'fun' bits used by shift
always@*
begin
case (d_fun_i)
`FUNC_ADD:
alu_result <= alu_addsub_result[31:0];
`FUNC_XOR:
alu_result <= alu_op1 ^ alu_op2;
`FUNC_OR:
alu_result <= alu_op1 | alu_op2;
`FUNC_AND:
alu_result <= alu_op1 & alu_op2;
`FUNC_SLT:
alu_result <= alu_addsub_result[32]?1:0;
`FUNC_SLTU:
alu_result <= alu_addsub_result[32]?1:0;
default: alu_result <= 32'hx;
endcase // case (d_fun_i)
end // always@ *
case (d_fun_i)
`FUNC_ADD: alu_result <= d_is_add_i ? alu_add[31:0] : alu_sub[31:0];
`FUNC_XOR: alu_result <= alu_op1 ^ alu_op2;
`FUNC_OR: alu_result <= alu_op1 | alu_op2;
`FUNC_AND: alu_result <= alu_op1 & alu_op2;
`FUNC_FIXECC: alu_result <= rf_rs1_ecc_err_i ? alu_op2 : alu_op1;
`FUNC_WRECC: alu_result <= alu_op1;
`FUNC_SLT,
`FUNC_SLTU: alu_result <= {31'b0, alu_sub[32]};
default: alu_result <= 32'hx;
endcase // case (d_fun_i)
// barel shifter
urv_shifter shifter
urv_shifter shifter
(
.clk_i(clk_i),
.rst_i(rst_i),
......@@ -284,84 +299,155 @@ module urv_exec
.d_shamt_i(alu_op2[4:0]),
.d_fun_i(d_fun_i),
.d_shifter_sign_i(d_shifter_sign_i),
.d_is_shift_i(d_is_shift_i),
.w_rd_o(w_rd_shifter_o)
);
wire divider_stall_req = 0;
urv_multiply multiplier
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i(x_stall_i),
.d_rs1_i(rs1),
.d_rs2_i(rs2),
.d_fun_i(d_fun_i),
.w_rd_o (w_rd_multiply_o)
);
wire divider_stall_req;
wire multiply_stall_req;
generate
if (g_with_hw_mul)
urv_multiply
#(
.g_with_hw_mulh( g_with_hw_mul > 1)
)
multiplier
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i(x_stall_i),
.x_kill_i(x_kill_i),
.x_stall_req_o(multiply_stall_req),
.d_rs1_i(rs1),
.d_rs2_i(rs2),
.d_fun_i(d_fun_i),
.d_is_multiply_i(d_is_multiply_i),
.w_rd_o (w_rd_multiply_o),
.x_rd_o (rd_mulh)
);
else begin
assign multiply_stall_req = 0;
assign w_rd_multiply_o = 0;
end
endgenerate
/* wire divider_stall_req;
wire [31:0] rd_divide;
urv_divide divider
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i(x_stall_i),
.x_kill_i(x_kill_i),
.x_stall_req_o(divider_stall_req),
.d_valid_i(d_valid_i),
.d_is_divide_i(d_is_divide_i),
.d_rs1_i(rs1),
.d_rs2_i(rs2),
generate
if(g_with_hw_div)
urv_divide divider
(
.clk_i(clk_i),
.rst_i(rst_i),
.x_stall_i(x_stall_i),
.x_kill_i(x_kill_i),
.x_stall_req_o(divider_stall_req),
.d_fun_i(d_fun_i),
.d_valid_i(d_valid_i),
.d_is_divide_i(d_is_divide_i),
.x_rd_o(rd_divide)
);
.d_rs1_i(rs1),
.d_rs2_i(rs2),
-----/\----- EXCLUDED -----/\----- */
.d_fun_i(d_fun_i),
always@*
.x_rd_o(rd_divide)
);
else
assign divider_stall_req = 1'b0;
endgenerate
always@*
case (d_rd_source_i)
`RD_SOURCE_ALU: rd_value <= alu_result;
`RD_SOURCE_CSR: rd_value <= rd_csr;
// `RD_SOURCE_DIVIDE: rd_value <= rd_divide;
default: rd_value <= 32'hx;
endcase // case (x_rd_source_i)
`RD_SOURCE_ALU: rd_value <= alu_result;
`RD_SOURCE_CSR: rd_value <= rd_csr;
`RD_SOURCE_DIVIDE: rd_value <= g_with_hw_div ? rd_divide : 32'hx;
`RD_SOURCE_MULH: rd_value <= g_with_hw_mul > 1 ? rd_mulh : 32'hx;
default: rd_value <= 32'hx;
endcase
// generate load/store address
assign dm_addr = d_imm_i + rs1;
reg unaligned_addr;
always@*
case (d_fun_i)
`LDST_B,
`LDST_BU:
unaligned_addr <= 0;
`LDST_H,
`LDST_HU:
unaligned_addr <= (dm_addr[0]);
`LDST_L:
unaligned_addr <= (dm_addr[1:0] != 2'b00);
default:
unaligned_addr <= 0;
endcase // case (d_fun_i)
case (d_fun_i)
`LDST_B,
`LDST_BU:
unaligned_addr <= 0;
`LDST_H,
`LDST_HU:
unaligned_addr <= (dm_addr[0]);
`LDST_L:
unaligned_addr <= (dm_addr[1:0] != 2'b00);
default:
unaligned_addr <= 0;
endcase // case (d_fun_i)
// x_exception: exception due to execution
always@*
begin
x_exception <= 0;
x_interrupt <= 0;
x_exception_cause <= 4'hx;
if (x_stall_i || x_kill_i || !d_valid_i)
begin
// If the current instruction is not valid, there is no exception.
end
else if (d_is_undef_i)
begin
x_exception <= 1;
x_interrupt <= 0;
x_exception_cause <= `CAUSE_ILLEGAL_INSN;
end
else if (!d_is_fix_ecc_i
&& ((d_use_rs1_i && rf_rs1_ecc_err_i)
|| (d_use_rs2_i && rf_rs2_ecc_err_i)))
begin
// Ecc error
x_exception <= 1;
x_interrupt <= 0;
x_exception_cause <= `CAUSE_ECC_ERROR;
end
else if (unaligned_addr
&& (d_opcode_i == `OPC_LOAD || d_opcode_i == `OPC_STORE))
begin
x_exception <= 1;
x_interrupt <= 0;
case (d_opcode_i)
`OPC_LOAD:
x_exception_cause <= `CAUSE_UNALIGNED_LOAD;
`OPC_STORE:
x_exception_cause <= `CAUSE_UNALIGNED_STORE;
default:
x_exception_cause <= 4'hx;
endcase // case (d_opcode_i)
end
else if (timer_pending && !d_dbg_mode_i)
begin
x_exception <= 1;
x_interrupt <= 1;
x_exception_cause <= `CAUSE_MACHINE_TIMER;
end
else if (irq_pending && !d_dbg_mode_i)
begin
x_exception <= 1;
x_interrupt <= 1;
x_exception_cause <= `CAUSE_MACHINE_IRQ;
end
end
// generate store value/select
always@*
begin
case (d_fun_i)
`LDST_B:
`LDST_B:
begin
dm_data_s <= { rs2[7:0], rs2[7:0], rs2[7:0], rs2[7:0] };
dm_select_s[0] <= (dm_addr [1:0] == 2'b00);
......@@ -369,7 +455,7 @@ module urv_exec
dm_select_s[2] <= (dm_addr [1:0] == 2'b10);
dm_select_s[3] <= (dm_addr [1:0] == 2'b11);
end
`LDST_H:
begin
dm_data_s <= { rs2[15:0], rs2[15:0] };
......@@ -384,7 +470,7 @@ module urv_exec
dm_data_s <= rs2;
dm_select_s <= 4'b1111;
end
default:
begin
dm_data_s <= 32'hx;
......@@ -395,78 +481,90 @@ module urv_exec
//branch decision
always@*
if( exception || d_is_eret_i)
if (x_exception)
branch_take <= 1;
else
case (d_opcode_i)
`OPC_JAL, `OPC_JALR:
`OPC_JAL, `OPC_JALR:
branch_take <= 1;
`OPC_BRANCH:
branch_take <= branch_condition_met;
default:
`OPC_SYSTEM:
branch_take <= d_is_mret_i || (g_with_hw_debug && d_is_ebreak_i && !d_dbg_mode_i);
default:
branch_take <= 0;
endcase // case (d_opcode_i)
// generate load/store requests
assign dm_addr_o = dm_addr;
assign dm_data_s_o = dm_data_s;
assign dm_data_select_o = dm_select_s;
assign dm_load_o = d_is_load_i & d_valid_i & !x_kill_i & !x_stall_i & !exception;
assign dm_store_o = d_is_store_i & d_valid_i & !x_kill_i & !x_stall_i & !exception;
assign dm_load_o = d_is_load_i & d_valid_i & !x_kill_i & !x_stall_i & !x_exception;
assign dm_store_o = d_is_store_i & d_valid_i & !x_kill_i & !x_stall_i & !x_exception;
// X/W pipeline registers
always@(posedge clk_i)
if (rst_i) begin
f_branch_take <= 0;
w_load_o <= 0;
w_store_o <= 0;
w_valid_o <= 0;
end else if (!x_stall_i) begin
f_branch_target_o <= branch_target;
f_branch_take <= branch_take && !x_kill_i && (d_valid_i || exception);
w_rd_o <= d_rd_i;
w_rd_value_o <= rd_value;
w_rd_write_o <= d_rd_write_i && !x_kill_i && d_valid_i && !exception && !d_is_undef_i;
w_load_o <= d_is_load_i && !x_kill_i && d_valid_i && !exception && !d_is_undef_i;
w_store_o <= d_is_store_i && !x_kill_i && d_valid_i && !exception && !d_is_undef_i;
w_rd_source_o <= d_rd_source_i;
w_fun_o <= d_fun_i;
w_dm_addr_o <= dm_addr;
w_valid_o <= !exception;
end // else: !if(rst_i)
always@(posedge clk_i)
if (rst_i)
begin
f_branch_take <= 0;
f_dbg_toggle_o <= 0;
w_load_o <= 0;
w_store_o <= 0;
w_ecc_flip_o <= 2'b0;
x_fault_o <= 0;
// Values so that 0 could be written to register 0.
w_rd_value_o <= 0;
w_rd_o <= 0;
w_rd_source_o <= `RD_SOURCE_ALU;
w_rd_write_o <= 1;
w_valid_o <= 1;
end
else
begin
if (!x_stall_i)
begin
// Stay valid for memory operations
w_valid_o <= !x_exception;
f_branch_target_o <= branch_target;
w_rd_o <= d_rd_i;
w_rd_value_o <= rd_value;
w_ecc_flip_o <= {2{d_is_write_ecc_i}} & rs2[1:0];
x_fault_o <= d_is_fix_ecc_i & rf_rs1_ecc_err_i & rf_rs2_ecc_err_i;
f_branch_take <= branch_take && !x_kill_i && d_valid_i;
f_dbg_toggle_o <= g_with_hw_debug && d_is_ebreak_i && !x_kill_i && d_valid_i;
w_rd_write_o <= d_rd_write_i && !x_kill_i && d_valid_i && !x_exception;
w_load_o <= d_is_load_i && !x_kill_i && d_valid_i && !x_exception;
w_store_o <= d_is_store_i && !x_kill_i && d_valid_i && !x_exception;
w_rd_source_o <= d_rd_source_i;
w_fun_o <= d_fun_i;
w_dm_addr_o <= dm_addr;
end
else if (divider_stall_req || multiply_stall_req)
begin
// Do not be valid while the mul/div is working
w_valid_o <= 0;
end
end
assign exception_pc = d_pc_i;
always@*
exception_pc <= d_pc_i;
assign f_branch_take_o = f_branch_take;
assign exception_taken = exception && (branch_take && !x_kill_i && (d_valid_i || exception));
// pipeline control: generate stall request signal
always@*
// never stall on taken branch
if(f_branch_take)
x_stall_req_o <= 0;
else if(divider_stall_req)
x_stall_req_o <= 1;
// stall if memory request pending, but memory not ready
else if ((d_is_load_i || d_is_store_i) && d_valid_i && !x_kill_i && !dm_ready_i)
else if(divider_stall_req || multiply_stall_req)
x_stall_req_o <= 1;
else
x_stall_req_o <= 0;
endmodule // urv_exec
/*
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
# 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 TESTNUM, 2
li t2, 2
li t1, 1
# Write bad ECC for t2
write_ecc t2,t2,t1
nop # avoid bypass
nop
nop
# Use t2
addi t2,t2,1
j fail # Skipped by handler
# Check t2 has not been modified
addi t2,t2,1
j fail # Skipped by handler
# Fix t2
fix_ecc t2,t2,t2
j 1f # Handler not executed, so this is executed
j fail
1: addi t2,t2,1
j 1f
j fail
1: j pass
TEST_PASSFAIL
.globl trap_entry
trap_entry:
# Destroy t1, t0
li t1, CAUSE_ECC_ERROR
csrr t0, mcause
bne t0, t1, fail
# Inc address by 8
csrr t0, mepc
addi t0, t0, 8
csrw mepc, t0
mret
RVTEST_CODE_END
.data
RVTEST_DATA_BEGIN
TEST_DATA
RVTEST_DATA_END
# 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 TESTNUM, 2
li t2, 2
li t1, 2
# Write bad ECC for t2
write_ecc t2,t2,t1
nop # avoid bypass
nop
nop
# Use t2
add t3,t1,t2
j fail # Skipped by handler
# Check t2 has not been modified
add t3,t1,t2
j fail # Skipped by handler
# Fix t2
fix_ecc t2,t2,t2
j 1f # Handler not executed, so this is executed
j fail
1: add t3,t2,t2
j 1f
j fail
1: j pass
TEST_PASSFAIL
.globl trap_entry
trap_entry:
# Destroy t1, t0
li t1, CAUSE_ECC_ERROR
csrr t0, mcause
bne t0, t1, fail
# Inc address by 8
csrr t0, mepc
addi t0, t0, 8
csrw mepc, t0
mret
RVTEST_CODE_END
.data
RVTEST_DATA_BEGIN
TEST_DATA
RVTEST_DATA_END
# 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 TESTNUM, 2
li t2, 2
li t1, 3
# Write bad ECC for t2
write_ecc t2,t2,t1
nop # avoid bypass
nop
nop
# Use t2
add t3,t1,t2
j fail # Skipped by handler
# Check t2 has not been modified
add t3,t1,t2
j fail # Skipped by handler
# Expect error from fix_ecc
lui t0, %hi(0x100008)
sw t0, %lo(0x100008)(t0)
# Try to fix t2
fix_ecc t2,t2,t2
nop # Handler not executed, so this is executed
# Double error must have been detected
j fail
TEST_PASSFAIL
.globl trap_entry
trap_entry:
# Destroy t1, t0
li t1, CAUSE_ECC_ERROR
csrr t0, mcause
bne t0, t1, fail
# Inc address by 8
csrr t0, mepc
addi t0, t0, 8
csrw mepc, t0
mret
RVTEST_CODE_END
.data
RVTEST_DATA_BEGIN
TEST_DATA
RVTEST_DATA_END
.macro write_ecc rd rs1 rs2
.insn r 0x5b, 0x1, 0, \rd, \rs1, \rs2
.endm
.macro fix_ecc rd rs1 rs2
.insn r 0x5b, 0x5, 0, \rd, \rs1, \rs2
.endm
# 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 TESTNUM, 2
li t2, 0
# No bad ECC
write_ecc t2,t2,t2
nop # avoid bypass
nop
nop
# Use t2
addi t2,t2,1
j 1f # Not skipped
j fail
1: li t2, 2
li t1, 1 #t1 is reg 6
# Write bad ECC for t2
write_ecc t2,t2,t1
nop # avoid bypass
nop
nop
# Use t2
addi t2,t2,1
j fail # Skipped by handler
li t1, 2
li t2, 3
# Write bad ECC for t2
write_ecc t2,t2,t1
nop # avoid bypass
nop
nop
# Use t2
add t3,t1,t2
j fail # Skipped by handler
j pass
TEST_PASSFAIL
.globl trap_entry
trap_entry:
# Destroy t1, t0
li t1, CAUSE_ECC_ERROR
csrr t0, mcause
bne t0, t1, fail
# Inc address by 8
csrr t0, mepc
addi t0, t0, 8
csrw mepc, t0
mret
RVTEST_CODE_END
.data
RVTEST_DATA_BEGIN
TEST_DATA
RVTEST_DATA_END
sim_tool = "modelsim"
top_module="main"
sim_top="main"
syn_device="xc6slx150t"
action = "simulation"
target = "xilinx"
include_dirs=["../../rtl"]
fetchto = "../../ip_cores"
vcom_opt="-mixedsvvh l"
files = [ "main.sv" ];
modules = {"local" : [ "../../rtl" ] }
\ No newline at end of file
modules = {"local" : [ "../../rtl"],
"git" : ["https://ohwr.org/project/general-cores.git"]}
/*
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 twl <twlostow@printf.cc>.
......@@ -15,10 +15,10 @@
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
`include "rv_defs.v"
`include "urv_defs.v"
`timescale 1ns/1ps
......@@ -26,15 +26,15 @@ module main;
const int dump_insns = 1;
const int dump_mem_accesses = 1;
reg clk = 0;
reg rst = 1;
wire [31:0] im_addr;
reg [31:0] im_data;
reg im_valid;
wire [31:0] dm_addr;
wire [31:0] dm_data_s;
......@@ -42,101 +42,147 @@ module main;
wire [3:0] dm_data_select;
wire dm_write;
reg dm_valid_l = 1;
reg dm_ready;
localparam int mem_size = 16384;
reg [31:0] mem[0:mem_size - 1];
reg [7:0] irq_counter = 0;
task automatic load_ram(string filename);
int f = $fopen(filename,"r");
int n, i;
if (f == 0)
$stop;
$display("Open %s -> %x", filename, f);
while(!$feof(f))
begin
int addr, data;
string cmd;
$fscanf(f,"%s %08x %08x", cmd,addr,data);
if(cmd == "write")
begin
mem[addr % mem_size] = data;
end
int addr, data, len;
string cmd, line;
byte c;
int arg;
line = "";
arg = 0;
while(!$feof(f)) begin
c = $fgetc(f);
if (c == 8'hff)
break;
if (c == "\n" || c == " ") begin
//$display("got |%s|, arg=%d", line, arg);
case (arg)
0:
if (line != "write") begin
$display("bad command: %s", line);
$fatal;
end
1: addr = line.atohex();
2:
begin
data = line.atohex();
if (dump_insns && addr < 64)
$display("mem[%h]=%h", addr, data);
mem[addr % mem_size] = data;
if (c != "\n") begin
$display("eol expected");
$fatal;
end
break;
end
default:
begin
$display("bad line: %s", line);
$fatal;
end
endcase // case (arg)
line="";
arg++;
end
else
line = {line, c};
end // while (1)
end
$fclose(f);
$display("RAM loaded");
endtask // load_ram
int seed;
always@(posedge clk)
begin
if( $dist_uniform(seed, 0, 100 ) <= 100) begin
if ($dist_uniform(seed, 0, 100 ) <= 100) begin
im_data <= mem[(im_addr / 4) % mem_size];
//$display("insn @0x%x: %08x", im_addr, im_data);
im_valid <= 1;
end else
im_valid <= 0;
if(dm_write && dm_data_select[0])
mem [(dm_addr / 4) % mem_size][7:0] <= dm_data_s[7:0];
if(dm_write && dm_data_select[1])
mem [(dm_addr / 4) % mem_size][15:8] <= dm_data_s[15:8];
if(dm_write && dm_data_select[2])
mem [(dm_addr / 4) % mem_size][23:16] <= dm_data_s[23:16];
if(dm_write && dm_data_select[3])
mem [(dm_addr / 4) % mem_size][31:24] <= dm_data_s[31:24];
// dm_data_l <= mem[(dm_addr/4) % mem_size];
end // always@ (posedge clk)
always@(posedge clk)
begin
dm_ready <= 1'b1; // $dist_uniform(seed, 0, 100 ) <= 50;
dm_data_l <= mem[(dm_addr/4) % mem_size];
end
if (dm_write)
begin
if (dm_addr == 'h100000)
begin
$display(" ****** TX '%c'", dm_data_s[7:0]) ;
$fwrite(f_console,"%c", dm_data_s[7:0]);
$fflush(f_console);
end
else if (dm_addr == 'h100004)
$stop;
else if (dm_addr < 'h100000)
begin
if(dm_data_select[0])
mem [(dm_addr / 4) % mem_size][7:0] <= dm_data_s[7:0];
if(dm_data_select[1])
mem [(dm_addr / 4) % mem_size][15:8] <= dm_data_s[15:8];
if(dm_data_select[2])
mem [(dm_addr / 4) % mem_size][23:16] <= dm_data_s[23:16];
if(dm_data_select[3])
mem [(dm_addr / 4) % mem_size][31:24] <= dm_data_s[31:24];
end // else: !if(dm_addr == 'h100004)
end // if (dm_write)
end
always@(posedge clk)
dm_data_l <= mem[(dm_addr/4) % mem_size];
reg irq = 0;
wire irq_ack;
initial begin
repeat(100)
@(posedge clk);
irq<=1;
@(posedge clk);
irq <= 0;
@(posedge clk);
end // initial begin
rv_cpu DUT
always @(posedge clk)
if (dm_write && dm_addr == 'h100004)
begin
irq <= 0;
irq_counter <= dm_data_s[7:0];
end
else if (irq_counter == 1)
begin
irq <= 1;
irq_counter <= 0;
end
else if (irq_counter != 0)
irq_counter <= irq_counter - 1;
urv_cpu
#(
.g_with_hw_mulh(1),
.g_with_hw_div(0),
.g_with_hw_debug(1),
.g_with_ecc(1)
)
DUT
(
.clk_i(clk),
.rst_i(rst),
.irq_i ( irq ),
.irq_i(irq),
.fault_o(),
// instruction mem I/F
.im_addr_o(im_addr),
.im_data_i(im_data),
.im_rd_o(),
.im_valid_i(im_valid),
// data mem I/F
......@@ -148,60 +194,67 @@ module main;
.dm_load_o(),
.dm_store_done_i(1'b1),
.dm_load_done_i(1'b1),
.dm_ready_i(dm_ready)
// Debug
.dbg_force_i(1'b0),
.dbg_enabled_o(),
.dbg_insn_i(32'h0),
.dbg_insn_set_i(1'b0),
.dbg_insn_ready_o(),
// Debug mailbox
.dbg_mbx_data_i(0),
.dbg_mbx_write_i(1'b0),
.dbg_mbx_data_o()
);
always #5ns clk <= ~clk;
initial begin
// load_ram("../../sw/test3/test3.ram");
// load_ram("../../sw/testsuite/benchmarks/dhrystone/dhrystone.ram");
load_ram("../../sw/testsuite/isa/rv32ui-p-mul.ram");
//load_ram("../../sw/testsuite/isa/rv32ui-p-simple.ram");
load_ram("../../sw/testsuite/isa/urv-p-write_ecc.ram");
// load_ram("../../sw/test.ram");
repeat(3) @(posedge clk);
rst = 0;
end
function string decode_op(bit[2:0] fun);
case(fun)
`FUNC_ADD: return "add";
`FUNC_XOR:return "xor";
`FUNC_OR: return "or";
`FUNC_AND:return "and";
`FUNC_SLT:return "slt";
`FUNC_XOR: return "xor";
`FUNC_OR: return "or";
`FUNC_AND: return "and";
`FUNC_SLT: return "slt";
`FUNC_SLTU:return "sltu";
`FUNC_SL: return "sl";
`FUNC_SR:return"sr";
`FUNC_SL: return "sl";
`FUNC_SR: return "sr";
endcase // case (fun)
endfunction // decode_op
function string decode_cond(bit[2:0] fun);
function string decode_cond(bit[2:0] fun);
case(fun)
`BRA_EQ: return "eq";
`BRA_EQ: return "eq";
`BRA_NEQ: return "neq";
`BRA_LT: return "lt";
`BRA_GE: return "ge";
`BRA_LTU:return "ltu";
`BRA_GEU:return "geu";
`BRA_LT: return "lt";
`BRA_GE: return "ge";
`BRA_LTU: return "ltu";
`BRA_GEU: return "geu";
endcase // case (fun)
endfunction // decode_op
endfunction
function string decode_size(bit[2:0] fun);
function string decode_size(bit[2:0] fun);
case(fun)
`LDST_B: return "s8";
`LDST_B: return "s8";
`LDST_BU: return "u8";
`LDST_H: return "s16";
`LDST_H: return "s16";
`LDST_HU: return "u16";
`LDST_L:return "32";
`LDST_L: return "32";
endcase // case (fun)
endfunction // decode_op
endfunction
function string decode_regname(bit[4:0] r);
case(r)
......@@ -242,20 +295,25 @@ module main;
function string decode_csr(bit[11:0] csr);
case(csr)
`CSR_ID_CYCLESH: return "cyclesh";
`CSR_ID_CYCLESL: return "cyclesl";
`CSR_ID_TIMEH: return "timeh";
`CSR_ID_TIMEL: return "timel";
`CSR_ID_CYCLESH: return "cyclesh";
`CSR_ID_CYCLESL: return "cyclesl";
`CSR_ID_TIMEH: return "timeh";
`CSR_ID_TIMEL: return "timel";
`CSR_ID_MSCRATCH: return "mscratch";
`CSR_ID_MEPC: return "mepc";
`CSR_ID_MSTATUS: return "mstatus";
`CSR_ID_MCAUSE: return "mcause";
`CSR_ID_MEPC: return "mepc";
`CSR_ID_MSTATUS: return "mstatus";
`CSR_ID_MCAUSE: return "mcause";
default: return "???";
endcase // case (csr)
endfunction // decode_csr
function string decode_cust2(bit[2:0] fun);
case(fun)
`FUNC_WRECC: return "wrecc";
`FUNC_FIXECC: return "fixecc";
default: return "???";
endcase
endfunction
task automatic verify_branch(input [31:0] rs1, input[31:0] rs2, input take, input [2:0] fun);
int do_take;
......@@ -272,37 +330,28 @@ module main;
$error("illegal branch func");
$stop;
end
endcase // case (func)
if(do_take != take)
begin
$error("fucked up jump");
$stop;
end
endtask // verify_branch
function automatic string s_hex(int x);
return $sformatf("%s0x%-08x", x<0?"-":" ", (x<0)?(-x):x);
return $sformatf("%s0x%-08x", x<0?"-":"", (x<0)?(-x):x);
endfunction // s_hex
reg[31:0] dm_addr_d0;
integer f_console, f_exec_log;
integer f_console, f_exec_log;
initial begin
f_console = $fopen("console.txt","wb");
f_exec_log = $fopen("exec_log.txt","wb");
#500us;
#500us;
// $fclose(f_console);
end
always@(posedge clk)
......@@ -310,12 +359,12 @@ module main;
if(dump_mem_accesses)
begin
dm_addr_d0 <= dm_addr;
if(dm_write)begin
$display("DM Write addr %x data %x", dm_addr, dm_data_s);
// $fwrite(f_exec_log,"DM Write addr %x data %x\n", dm_addr, dm_data_s);
end
if (DUT.writeback.x_load_i && DUT.writeback.rf_rd_write_o)
begin
/* -----\/----- EXCLUDED -----\/-----
......@@ -325,7 +374,7 @@ module main;
$stop;
end
-----/\----- EXCLUDED -----/\----- */
$display("DM Load addr %x data %x -> %s", dm_addr_d0, DUT.writeback.rf_rd_value_o, decode_regname(DUT.writeback.x_rd_i));
/* -----\/----- EXCLUDED -----\/-----
......@@ -334,27 +383,15 @@ module main;
end
end
end
always@(posedge clk)
if(dm_write && dm_addr == 'h100000)
begin
$display("\n ****** TX '%c' \n", dm_data_s[7:0]) ;
// $fwrite(f_exec_log,"\n ****** TX '%c' \n", dm_data_s[7:0]) ;
$fwrite(f_console,"%c", dm_data_s[7:0]);
$fflush(f_console);
end
int cycles = 0;
always@(posedge clk)
if(dump_insns && DUT.execute.d_valid_i && !DUT.execute.x_stall_i && !DUT.execute.x_kill_i && !DUT.decode.load_hazard_d)
if(dump_insns && DUT.execute.d_valid_i && !DUT.execute.x_stall_i && !DUT.execute.x_kill_i)
begin
automatic string opc="<unk>", fun="", args="";
......@@ -362,118 +399,140 @@ module main;
automatic string rs2 = decode_regname(DUT.d2x_rs2);
automatic string rd = decode_regname(DUT.d2x_rd);
reg [31:0] imm;
// $display("Opcode %x", DUT.d2x_opcode);
case (DUT.d2x_opcode)
`OPC_AUIPC:
begin
opc = "auipc";
fun = "";
args = $sformatf("%-3s %-3s %s", rd, " ", s_hex(DUT.d2x_imm));
`OPC_AUIPC:
begin
opc = "auipc";
fun = "";
args = $sformatf("%-4s %-4s %s", rd, " ", s_hex(DUT.d2x_imm));
end
`OPC_LUI:
begin
opc = "lui";
fun = "";
args = $sformatf("%-3s %-3s %s", rd, " ", s_hex(DUT.d2x_imm));
`OPC_LUI:
begin
opc = "lui";
fun = "";
args = $sformatf("%-4s %-4s %s", rd, " ", s_hex(DUT.d2x_imm));
end
`OPC_OP_IMM:
begin
`OPC_OP_IMM:
begin
opc = "op-imm";
fun = decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s %s", rd, rs1, s_hex(DUT.d2x_imm));
args = $sformatf("%-4s %-4s %s", rd, rs1, s_hex(DUT.d2x_imm));
end
`OPC_OP:
begin
opc = "op-imm";
`OPC_OP:
begin
opc = "op";
fun = decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s %-3s", rd, rs1, rs2);
args = $sformatf("%-4s %-4s %-4s", rd, rs1, rs2);
end
`OPC_JAL:
begin
`OPC_JAL:
begin
opc = "jal";
fun = "";
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s 0x%-08x", rd, DUT.execute.branch_target);
args = $sformatf("%-4s 0x%-08x", rd, DUT.execute.branch_target);
end
`OPC_JALR:
begin
`OPC_JALR:
begin
opc = "jalr";
fun = "";
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s 0x%-08x", rd, rs1, DUT.execute.branch_target);
args = $sformatf("%-4s %-4s 0x%-08x", rd, rs1, DUT.execute.branch_target);
end
`OPC_BRANCH:
begin
`OPC_BRANCH:
begin
opc = "branch";
fun = decode_cond(DUT.d2x_fun);
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s 0x%-08x rs1 %s", rs1, rs2, DUT.execute.branch_target, DUT.execute.branch_take?"TAKE":"IGNORE");
args = $sformatf("%-4s %-4s 0x%-08x rs1 %s", rs1, rs2, DUT.execute.branch_target, DUT.execute.branch_take?"TAKE":"IGNORE");
verify_branch(DUT.execute.rs1, DUT.execute.rs2, DUT.execute.branch_take,DUT.d2x_fun);
end
`OPC_LOAD:
begin
`OPC_LOAD:
begin
opc = "ld";
fun = decode_size(DUT.d2x_fun);
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s [0x%-08x + %s]", rd, rs1, DUT.execute.rs1, s_hex($signed(DUT.execute.d_imm_i)));
args = $sformatf("%-4s %-4s [0x%-08x + %s]", rd, rs1, DUT.execute.rs1, s_hex($signed(DUT.execute.d_imm_i)));
end
`OPC_STORE:
begin
`OPC_STORE:
begin
opc = "st";
fun = decode_size(DUT.d2x_fun);
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s [0x%-08x + %s]", rs2, rs1, DUT.execute.rs1, s_hex($signed(DUT.execute.d_imm_i)));
args = $sformatf("%-4s %-4s [0x%-08x + %s]", rs2, rs1, DUT.execute.rs1, s_hex($signed(DUT.execute.d_imm_i)));
end
`OPC_SYSTEM:
begin
opc = "sys";
case (DUT.d2x_fun)
`CSR_OP_PRIV: begin
args = "";
case (DUT.d2x_csr_sel)
`SYS_IMM_MRET:
fun = "mret";
`SYS_IMM_EBREAK:
fun = "ebreak";
default:
fun = $sformatf("%x", DUT.d2x_csr_sel);
endcase
end
`CSR_OP_CSRRWI: begin
opc = "csrrwi";
args = $sformatf("%-3s %-3s 0x%08x", rd, decode_csr(DUT.d2x_csr_sel), ((DUT.d2x_csr_imm)));
fun = "csrrwi";
args = $sformatf("%-4s %-4s 0x%08x", rd, decode_csr(DUT.d2x_csr_sel), ((DUT.d2x_csr_imm)));
end
`CSR_OP_CSRRSI: begin
opc = "csrrsi";
args = $sformatf("%-3s %-3s 0x%08x", rd, decode_csr(DUT.d2x_csr_sel), ((DUT.d2x_csr_imm)));
fun = "csrrsi";
args = $sformatf("%-4s %-4s 0x%08x", rd, decode_csr(DUT.d2x_csr_sel), ((DUT.d2x_csr_imm)));
end
`CSR_OP_CSRRCI: begin
opc = "csrrci";
args = $sformatf("%-3s %-3s 0x%08x", rd, decode_csr(DUT.d2x_csr_sel), ((DUT.d2x_csr_imm)));
fun = "csrrci";
args = $sformatf("%-4s %-4s 0x%08x", rd, decode_csr(DUT.d2x_csr_sel), ((DUT.d2x_csr_imm)));
end
`CSR_OP_CSRRW: begin
opc = "csrrw";
args = $sformatf("%-3s %-3s %-3s [0x%08x]", rd, decode_csr(DUT.d2x_csr_sel), rs1, DUT.execute.rs1);
fun = "csrrw";
args = $sformatf("%-4s %-4s %-4s [0x%08x]", rd, decode_csr(DUT.d2x_csr_sel), rs1, DUT.execute.rs1);
end
`CSR_OP_CSRRS: begin
fun = "csrrs";
args = $sformatf("%-4s %-4s %-4s [0x%08x]", rd, decode_csr(DUT.d2x_csr_sel), rs1, DUT.execute.rs1);
end
`CSR_OP_CSRRC: begin
fun = "csrrc";
args = $sformatf("%-4s %-4s %-4s [0x%08x]", rd, decode_csr(DUT.d2x_csr_sel), rs1, DUT.execute.rs1);
end
endcase // case (d_fun_i)
endcase // case (d_fun_i)
end
`OPC_CUST2:
begin
opc = "cust2";
fun = decode_cust2(DUT.d2x_fun);
// fun = $sformatf("%03b", DUT.d2x_fun);
args = $sformatf("%-4s %-4s %-4s", rd, rs1, rs2);
end
default:
begin
opc = "???";
fun = "";
args = $sformatf("opc: 0x%02x", DUT.d2x_opcode);
end
endcase // case (d2x_opcode)
$display("%08x [%d]: %-8s %-3s %s", DUT.execute.d_pc_i, cycles, opc, fun, args);
// $fwrite(f_exec_log,"%08x: %-8s %-3s %s\n", DUT.execute.d_pc_i, opc, fun, args);
$fwrite(f_exec_log,": PC %08x OP %08x CYCLES %-0d RS1 %08x RS2 %08x\n", DUT.execute.d_pc_i, DUT.decode.x_ir, cycles++, DUT.execute.rs1, DUT.execute.rs2);
$display("%08x [%d]: %-8s %-6s %s",
DUT.execute.d_pc_i, cycles, opc, fun, args);
// $fwrite(f_exec_log,"%08x: %-8s %-4s %s\n",
// DUT.execute.d_pc_i, opc, fun, args);
$fwrite(f_exec_log,
": PC %08x OP %08x CYCLES %-0d RS1 %08x RS2 %08x\n",
DUT.execute.d_pc_i, DUT.decode.f_ir_i, cycles++,
DUT.execute.rs1, DUT.execute.rs2);
end
endmodule // main
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -group D /main/DUT/decode/clk_i
add wave -noupdate -group D /main/DUT/decode/rst_i
add wave -noupdate -group D /main/DUT/decode/d_stall_i
add wave -noupdate -group D /main/DUT/decode/d_kill_i
add wave -noupdate -group D /main/DUT/decode/d_stall_req_o
add wave -noupdate -group D /main/DUT/decode/x_load_hazard_o
add wave -noupdate -group D /main/DUT/decode/f_ir_i
add wave -noupdate -group D /main/DUT/decode/f_pc_i
add wave -noupdate -group D /main/DUT/decode/f_valid_i
add wave -noupdate -group D /main/DUT/decode/x_valid_o
add wave -noupdate -group D /main/DUT/decode/x_pc_o
add wave -noupdate -group D /main/DUT/decode/rf_rs1_o
add wave -noupdate -group D /main/DUT/decode/rf_rs2_o
add wave -noupdate -group D /main/DUT/decode/x_rs1_o
add wave -noupdate -group D /main/DUT/decode/x_rs2_o
add wave -noupdate -group D /main/DUT/decode/x_rd_o
add wave -noupdate -group D /main/DUT/decode/x_shamt_o
add wave -noupdate -group D /main/DUT/decode/x_fun_o
add wave -noupdate -group D /main/DUT/decode/x_opcode_o
add wave -noupdate -group D /main/DUT/decode/x_shifter_sign_o
add wave -noupdate -group D /main/DUT/decode/x_is_signed_compare_o
add wave -noupdate -group D /main/DUT/decode/x_is_signed_alu_op_o
add wave -noupdate -group D /main/DUT/decode/x_is_add_o
add wave -noupdate -group D /main/DUT/decode/x_is_shift_o
add wave -noupdate -group D /main/DUT/decode/x_is_load_o
add wave -noupdate -group D /main/DUT/decode/x_is_store_o
add wave -noupdate -group D /main/DUT/decode/x_is_undef_o
add wave -noupdate -group D /main/DUT/decode/x_rd_source_o
add wave -noupdate -group D /main/DUT/decode/x_rd_write_o
add wave -noupdate -group D /main/DUT/decode/x_csr_sel_o
add wave -noupdate -group D /main/DUT/decode/x_csr_imm_o
add wave -noupdate -group D /main/DUT/decode/x_is_csr_o
add wave -noupdate -group D /main/DUT/decode/x_is_eret_o
add wave -noupdate -group D /main/DUT/decode/x_alu_op1_o
add wave -noupdate -group D /main/DUT/decode/x_alu_op2_o
add wave -noupdate -group D /main/DUT/decode/x_use_op1_o
add wave -noupdate -group D /main/DUT/decode/x_use_op2_o
add wave -noupdate -group D /main/DUT/decode/f_rs1
add wave -noupdate -group D /main/DUT/decode/f_rs2
add wave -noupdate -group D /main/DUT/decode/x_rs1
add wave -noupdate -group D /main/DUT/decode/x_rs2
add wave -noupdate -group D /main/DUT/decode/x_rd
add wave -noupdate -group D /main/DUT/decode/x_opcode
add wave -noupdate -group D /main/DUT/decode/x_valid
add wave -noupdate -group D /main/DUT/decode/x_is_shift
add wave -noupdate -group D /main/DUT/decode/x_rd_write
add wave -noupdate -group D /main/DUT/decode/x_ir
add wave -noupdate -group D /main/DUT/decode/d_opcode
add wave -noupdate -group D /main/DUT/decode/load_hazard
add wave -noupdate -group D /main/DUT/decode/d_fun
add wave -noupdate -group D /main/DUT/decode/d_is_shift
add wave -noupdate -group D /main/DUT/decode/x_is_mul
add wave -noupdate -group D /main/DUT/decode/d_is_mul
add wave -noupdate -group D /main/DUT/decode/inserting_nop
add wave -noupdate -group D /main/DUT/decode/load_hazard_d
add wave -noupdate -group D /main/DUT/decode/d_imm_i
add wave -noupdate -group D /main/DUT/decode/d_imm_s
add wave -noupdate -group D /main/DUT/decode/d_imm_b
add wave -noupdate -group D /main/DUT/decode/d_imm_u
add wave -noupdate -group D /main/DUT/decode/d_imm_j
add wave -noupdate -group D /main/DUT/decode/x_imm
add wave -noupdate -expand -group D /main/DUT/decode/clk_i
add wave -noupdate -expand -group D /main/DUT/decode/rst_i
add wave -noupdate -expand -group D /main/DUT/decode/d_stall_i
add wave -noupdate -expand -group D /main/DUT/decode/d_kill_i
add wave -noupdate -expand -group D /main/DUT/decode/d_stall_req_o
add wave -noupdate -expand -group D /main/DUT/decode/f_ir_i
add wave -noupdate -expand -group D /main/DUT/decode/f_pc_i
add wave -noupdate -expand -group D /main/DUT/decode/f_valid_i
add wave -noupdate -expand -group D /main/DUT/decode/x_valid_o
add wave -noupdate -expand -group D /main/DUT/decode/x_pc_o
add wave -noupdate -expand -group D /main/DUT/decode/rf_rs1_o
add wave -noupdate -expand -group D /main/DUT/decode/rf_rs2_o
add wave -noupdate -expand -group D /main/DUT/decode/x_rs1_o
add wave -noupdate -expand -group D /main/DUT/decode/x_rs2_o
add wave -noupdate -expand -group D /main/DUT/decode/x_rd_o
add wave -noupdate -expand -group D /main/DUT/decode/x_shamt_o
add wave -noupdate -expand -group D /main/DUT/decode/x_fun_o
add wave -noupdate -expand -group D /main/DUT/decode/x_opcode_o
add wave -noupdate -expand -group D /main/DUT/decode/x_shifter_sign_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_signed_compare_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_signed_alu_op_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_add_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_shift_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_load_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_store_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_undef_o
add wave -noupdate -expand -group D /main/DUT/decode/x_rd_source_o
add wave -noupdate -expand -group D /main/DUT/decode/x_rd_write_o
add wave -noupdate -expand -group D /main/DUT/decode/x_csr_sel_o
add wave -noupdate -expand -group D /main/DUT/decode/x_csr_imm_o
add wave -noupdate -expand -group D /main/DUT/decode/x_is_csr_o
add wave -noupdate -expand -group D /main/DUT/decode/x_alu_op1_o
add wave -noupdate -expand -group D /main/DUT/decode/x_alu_op2_o
add wave -noupdate -expand -group D /main/DUT/decode/x_use_op1_o
add wave -noupdate -expand -group D /main/DUT/decode/x_use_op2_o
add wave -noupdate -expand -group D /main/DUT/decode/f_rs1
add wave -noupdate -expand -group D /main/DUT/decode/f_rs2
add wave -noupdate -expand -group D /main/DUT/decode/x_rs1
add wave -noupdate -expand -group D /main/DUT/decode/x_rs2
add wave -noupdate -expand -group D /main/DUT/decode/x_rd
add wave -noupdate -expand -group D /main/DUT/decode/x_opcode
add wave -noupdate -expand -group D /main/DUT/decode/x_valid
add wave -noupdate -expand -group D /main/DUT/decode/x_is_shift
add wave -noupdate -expand -group D /main/DUT/decode/x_rd_write
add wave -noupdate -expand -group D /main/DUT/decode/d_opcode
add wave -noupdate -expand -group D /main/DUT/decode/load_hazard
add wave -noupdate -expand -group D /main/DUT/decode/d_fun
add wave -noupdate -expand -group D /main/DUT/decode/d_is_shift
add wave -noupdate -expand -group D /main/DUT/decode/x_is_mul
add wave -noupdate -expand -group D /main/DUT/decode/d_is_mul
add wave -noupdate -expand -group D /main/DUT/decode/inserting_nop
add wave -noupdate -expand -group D /main/DUT/decode/d_imm_i
add wave -noupdate -expand -group D /main/DUT/decode/d_imm_s
add wave -noupdate -expand -group D /main/DUT/decode/d_imm_b
add wave -noupdate -expand -group D /main/DUT/decode/d_imm_u
add wave -noupdate -expand -group D /main/DUT/decode/d_imm_j
add wave -noupdate -expand -group X /main/DUT/execute/clk_i
add wave -noupdate -expand -group X /main/DUT/execute/rst_i
add wave -noupdate -expand -group X /main/DUT/execute/x_stall_i
......@@ -72,11 +67,9 @@ add wave -noupdate -expand -group X /main/DUT/execute/d_fun_i
add wave -noupdate -expand -group X /main/DUT/execute/rf_rs1_value_i
add wave -noupdate -expand -group X /main/DUT/execute/rf_rs2_value_i
add wave -noupdate -expand -group X /main/DUT/execute/d_valid_i
add wave -noupdate -expand -group X /main/DUT/execute/d_load_hazard_i
add wave -noupdate -expand -group X /main/DUT/execute/d_opcode_i
add wave -noupdate -expand -group X /main/DUT/execute/d_shifter_sign_i
add wave -noupdate -expand -group X /main/DUT/execute/d_is_csr_i
add wave -noupdate -expand -group X /main/DUT/execute/d_is_eret_i
add wave -noupdate -expand -group X /main/DUT/execute/d_csr_imm_i
add wave -noupdate -expand -group X /main/DUT/execute/d_csr_sel_i
add wave -noupdate -expand -group X /main/DUT/execute/d_imm_i
......@@ -86,7 +79,6 @@ add wave -noupdate -expand -group X /main/DUT/execute/d_is_add_i
add wave -noupdate -expand -group X /main/DUT/execute/d_is_shift_i
add wave -noupdate -expand -group X /main/DUT/execute/d_is_load_i
add wave -noupdate -expand -group X /main/DUT/execute/d_is_store_i
add wave -noupdate -expand -group X /main/DUT/execute/d_is_divide_i
add wave -noupdate -expand -group X /main/DUT/execute/d_is_undef_i
add wave -noupdate -expand -group X /main/DUT/execute/d_alu_op1_i
add wave -noupdate -expand -group X /main/DUT/execute/d_alu_op2_i
......@@ -96,7 +88,6 @@ add wave -noupdate -expand -group X /main/DUT/execute/d_rd_source_i
add wave -noupdate -expand -group X /main/DUT/execute/d_rd_write_i
add wave -noupdate -expand -group X /main/DUT/execute/f_branch_target_o
add wave -noupdate -expand -group X /main/DUT/execute/f_branch_take_o
add wave -noupdate -expand -group X /main/DUT/execute/w_load_hazard_o
add wave -noupdate -expand -group X /main/DUT/execute/irq_i
add wave -noupdate -expand -group X /main/DUT/execute/w_fun_o
add wave -noupdate -expand -group X /main/DUT/execute/w_load_o
......@@ -136,9 +127,7 @@ add wave -noupdate -expand -group X /main/DUT/execute/cmp_rs
add wave -noupdate -expand -group X /main/DUT/execute/cmp_equal
add wave -noupdate -expand -group X /main/DUT/execute/cmp_lt
add wave -noupdate -expand -group X /main/DUT/execute/f_branch_take
add wave -noupdate -expand -group X /main/DUT/execute/rd_shifter
add wave -noupdate -expand -group X /main/DUT/execute/rd_csr
add wave -noupdate -expand -group X /main/DUT/execute/rd_mul
add wave -noupdate -expand -group X /main/DUT/execute/rd_div
add wave -noupdate -expand -group X /main/DUT/execute/exception
add wave -noupdate -expand -group X /main/DUT/execute/csr_mie
......@@ -153,10 +142,45 @@ add wave -noupdate -expand -group X /main/DUT/execute/alu_addsub_op1
add wave -noupdate -expand -group X /main/DUT/execute/alu_addsub_op2
add wave -noupdate -expand -group X /main/DUT/execute/alu_addsub_result
add wave -noupdate -expand -group X /main/DUT/execute/divider_stall_req
add wave -noupdate -expand -group X /main/DUT/execute/d_fun
add wave -noupdate -expand -group X /main/DUT/execute/unaligned_addr
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/cause
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/clk_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_ie
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mcause
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mcause_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mepc
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mepc_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mie
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mie_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mip
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mip_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/csr_mstatus_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/d_csr_imm_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/d_csr_sel_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/d_fun_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/d_is_csr_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/d_is_sret_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/except_vec_masked
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exception
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exception_pending
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exp_breakpoint_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exp_invalid_insn_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exp_irq_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exp_tick_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exp_unaligned_load_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/exp_unaligned_store_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/rst_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_csr_write_value_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_exception_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_exception_pc_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_exception_pc_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_exception_taken_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_exception_vector_o
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_kill_i
add wave -noupdate -expand -group except /main/DUT/execute/exception_unit/x_stall_i
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {58892 ps} 0}
WaveRestoreCursors {{Cursor 1} {2279499 ps} 0}
quietly wave cursor active 1
configure wave -namecolwidth 250
configure wave -valuecolwidth 100
configure wave -justifyvalue left
......@@ -171,4 +195,4 @@ configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ps
update
WaveRestoreZoom {0 ps} {144640 ps}
WaveRestoreZoom {2238876 ps} {2383516 ps}
RISCV_PREFIX=riscv32-elf-
RISCV_GCC = $(RISCV_PREFIX)gcc
SW_DIR=../../sw
CFLAGS = -march=rv32im -mabi=ilp32 -O
all: app1.bin
app1: crt0.o app1.o
$(RISCV_GCC) -o $@ $^ -nostdlib -T $(SW_DIR)/common/ram2.ld -Wl,-Map,$@.map
app1.bin: app1
$(RISCV_PREFIX)objcopy -O binary $< $<.bin
crt0.o: $(SW_DIR)/crt0.S
$(RISCV_GCC) -c $(CFLAGS) -o $@ $<
uart.o: $(SW_DIR)/common/uart.c
$(RISCV_GCC) -c $(CFLAGS) -o $@ $<
app1.o: app1.c
$(RISCV_GCC) -c $(CFLAGS) -o $@ $<
clean:
$(RM) -f app1 *.o *.bin
sim_tool = "modelsim"
sim_top="main"
syn_device="xc6slx150t"
action = "simulation"
target = "xilinx"
include_dirs=["../../rtl"]
vcom_opt="-mixedsvvh l"
files = [ "main.sv" ];
modules = {"local" : [ "../../rtl", "../../ip_cores/general-cores" ] }
static int cnt;
int puts(const char *s);
int putchar(int b)
{
*(volatile int *)0x100000 = b;
return 0;
}
int main(void)
{
puts("Hello world\n");
asm volatile("nop; nop; ebreak");
while (1)
{
cnt++;
putchar('0' + (cnt & 0x7));
puts(" count\n");
}
return 0;
}
int puts(const char *s)
{
char c;
while (c = *s++)
putchar (c);
}
.text
# Set dest address
li a0, 0
# Read count (in bytes)
1: csrr t0, 0x7c0 # dbg status
andi t0, t0, 1
beq t0, zero, 1b
csrr a1, 0x7d0 # mbxi
# Read data
1: csrr t0, 0x7c0 # dbg status
andi t0, t0, 1
beq t0, zero, 1b
csrr t1, 0x7d0 # mbxi
sw t1, 0(a0)
addi a0, a0, 4
blt a0, a1, 1b
# Start at 0
done: li a0, 0
jr a0
.text
# Init
nop
# Write one word
csrr t0, 0x7d0
csrr t1, 0x7d0
sw t1, 0(t0)
# Jump to t0
jalr x0, t0, 0
ebreak
/*
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 twl <twlostow@printf.cc>.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
`include "urv_defs.v"
`timescale 1ns/1ps
module main;
const int dump_insns = 1;
const int dump_mem_accesses = 1;
reg clk = 0;
reg rst = 1;
wire [31:0] im_addr;
reg [31:0] im_data;
reg im_valid;
wire [31:0] dm_addr;
wire [31:0] dm_data_s;
reg [31:0] dm_data_l;
wire [3:0] dm_data_select;
wire dm_write;
reg dm_valid_l = 1;
reg dm_ready;
reg dbg_force = 1;
wire dbg_enabled;
reg [31:0] dbg_insn;
reg dbg_insn_set;
wire dbg_insn_ready;
reg [31:0] mbxi_data;
reg mbxi_write;
wire [31:0] mbxo_data;
const var [31:0] insn_nop = 32'h13;
const var [31:0] insn_csrr_t0_mbxi = 32'h7d0022f3;
const var [31:0] insn_csrr_t1_mbxi = 32'h7d002373;
const var [31:0] insn_sw_t1_t0 = 32'h0062a023;
const var [31:0] insn_jr_t0 = 32'h00028067;
const var [31:0] insn_ebreak = 32'h00100073;
const var [31:0] insn_csrw_mbxo_ra = 32'h7d409073;
const var [31:0] insn_mov_ra_pc4 = 32'h000000ef;
const var [31:0] insn_csrr_ra_mbxi = 32'h7d0020f3;
const var [31:0] insn_ret = 32'h00008067; // Use a different reg?
const var [31:0] insn_jmp_4 = 32'h0040006f;
const var [31:0] loader [14] = '{ 32'h00000513, // li a0,0
32'h7c0022f3, // csrr t0,0x7c0
32'h0012f293, // andi t0,t0,1
32'hfe028ce3, // beqz t0,-8
32'h7d0025f3, // csrr a1,0x7d0
32'h7c0022f3, // csrr t0,0x7c0
32'h0012f293, // andi t0,t0,1
32'hfe028ce3, // beqz t0,-8
32'h7d002373, // csrr t1,0x7d0
32'h00652023, // sw t1,0(a0)
32'h00450513, // addi a0,a0,4
32'hfeb544e3, // blt a0,a1,-24
32'h00000513, // li a0,0
32'h00050067}; // jr a0
localparam int mem_size = 16384;
reg [31:0] mem[0:mem_size - 1];
task automatic load_ram(string filename);
int f = $fopen(filename,"r");
int n, i;
while(!$feof(f))
begin
int addr, data;
string cmd;
void'($fscanf(f,"%s %08x %08x", cmd,addr,data));
if(cmd == "write")
begin
mem[addr % mem_size] = data;
end
end
endtask // load_ram
int seed;
always@(posedge clk)
begin
if ($dist_uniform(seed, 0, 100 ) <= 100) begin
im_data <= mem[(im_addr / 4) % mem_size];
im_valid <= 1;
end else
im_valid <= 0;
if(dm_write && dm_data_select[0])
mem [(dm_addr / 4) % mem_size][7:0] <= dm_data_s[7:0];
if(dm_write && dm_data_select[1])
mem [(dm_addr / 4) % mem_size][15:8] <= dm_data_s[15:8];
if(dm_write && dm_data_select[2])
mem [(dm_addr / 4) % mem_size][23:16] <= dm_data_s[23:16];
if(dm_write && dm_data_select[3])
mem [(dm_addr / 4) % mem_size][31:24] <= dm_data_s[31:24];
end
always@(posedge clk)
begin
dm_ready <= 1'b1; // $dist_uniform(seed, 0, 100 ) <= 50;
dm_data_l <= mem[(dm_addr/4) % mem_size];
end
reg irq = 0;
urv_cpu #(.g_with_hw_debug(1)) DUT
(
.clk_i(clk),
.rst_i(rst),
.irq_i(irq),
// instruction mem I/F
.im_addr_o(im_addr),
.im_data_i(im_data),
.im_valid_i(im_valid),
// data mem I/F
.dm_addr_o(dm_addr),
.dm_data_s_o(dm_data_s),
.dm_data_l_i(dm_data_l),
.dm_data_select_o(dm_data_select),
.dm_store_o(dm_write),
.dm_load_o(),
.dm_store_done_i(1'b1),
.dm_load_done_i(1'b1),
.dm_ready_i(dm_ready),
// Debug
.dbg_force_i(dbg_force),
.dbg_enabled_o(dbg_enabled),
.dbg_insn_i(dbg_insn),
.dbg_insn_set_i(dbg_insn_set),
.dbg_insn_ready_o(dbg_insn_ready),
// Debug mailboxes
.dbg_mbx_data_i(mbxi_data),
.dbg_mbx_write_i(mbxi_write),
.dbg_mbx_data_o(mbxo_data)
);
always #5ns clk <= ~clk;
task send_insn (input [31:0] insn);
dbg_insn <= insn;
dbg_insn_set <= 1'b1;
@(posedge clk);
dbg_insn_set <= 1'b0;
dbg_insn <= insn_nop;
@(posedge clk);
while (!dbg_insn_ready)
@(posedge clk);
endtask // send_insn
task send_mbxi(input [31:0] data);
mbxi_data <= data;
mbxi_write <= 1;
@(posedge clk);
mbxi_write <= 0;
@(posedge clk);
@(posedge clk);
endtask
task read_pc;
reg [31:0] pc, ra;
// write x1 to mbxo, jal x1, 0, write x1 to mbxo, read x1 from mbxi
send_insn(insn_csrw_mbxo_ra);
send_insn(insn_mov_ra_pc4);
send_insn(insn_nop);
send_insn(insn_nop);
// Read ra only once the csrw has been executed.
ra <= mbxo_data;
send_insn(insn_csrw_mbxo_ra);
mbxi_data <= ra;
mbxi_write <= 1;
send_insn(insn_csrr_ra_mbxi);
mbxi_write <= 0;
send_insn(insn_nop);
send_insn(insn_nop);
pc <= mbxo_data - 4; // Jal save pc + 4
send_insn(insn_nop);
$display("Break: pc=%x, ra=%x\n", pc, ra);
endtask
initial begin
// load_ram("../../sw/test3/test3.ram");
// load_ram("../../sw/testsuite/benchmarks/dhrystone/dhrystone.ram");
// load_ram("../../sw/testsuite/isa/rv32ui-p-mulh.ram");
const var [31:0] loader_addr = 16'h3f80;
dbg_insn = insn_nop;
dbg_insn_set = 1'b0;
mbxi_data <= 0;
mbxi_write <= 0;
repeat(3) @(posedge clk);
rst = 0;
dbg_force = 0;
while (!dbg_insn_ready)
@(posedge clk);
$display("Load application");
begin
int fd;
int filelen;
fd = $fopen("app1.bin", "rb");
void'($fseek(fd, 0, 2));
filelen = $ftell(fd);
void'($rewind(fd));
filelen = (filelen + 3) / 4;
for(int i = 0; i < filelen; i++)
begin
var [7:0] b0, b1, b2, b3;
int l;
l = $fread(b0, fd);
l += $fread(b1, fd);
l += $fread(b2, fd);
l += $fread(b3, fd);
// Address
mbxi_data <= i * 4;
mbxi_write <= 1;
send_insn (insn_csrr_t0_mbxi);
// Data
mbxi_data <= {b3, b2, b1, b0};
mbxi_write <= 1;
send_insn (insn_csrr_t1_mbxi);
// Store
send_insn (insn_sw_t1_t0);
end
$fclose(fd);
end
// Set PC address
mbxi_data <= 0;
mbxi_write <= 1;
send_insn (insn_csrr_t0_mbxi);
// Branch and be sure it is executed.
mbxi_write <= 0;
send_insn (insn_jr_t0);
send_insn (insn_ebreak);
// Wait until debug mode is enabled again.
while (!dbg_enabled)
@(posedge clk) ;
// Read pc
read_pc;
// Continue
send_insn (insn_jmp_4);
send_insn (insn_ebreak);
while (1)
begin
repeat(100) @(posedge clk);
// Stop
dbg_force = 1;
while (!dbg_enabled)
@(posedge clk) ;
dbg_force = 0;
// Read pc
read_pc;
// Continue
send_insn (insn_ebreak);
send_insn (insn_nop);
send_insn (insn_nop);
end
end
function string decode_op(bit[2:0] fun);
case(fun)
`FUNC_ADD: return "add";
`FUNC_XOR: return "xor";
`FUNC_OR: return "or";
`FUNC_AND: return "and";
`FUNC_SLT: return "slt";
`FUNC_SLTU:return "sltu";
`FUNC_SL: return "sl";
`FUNC_SR: return "sr";
endcase // case (fun)
endfunction // decode_op
function string decode_cond(bit[2:0] fun);
case(fun)
`BRA_EQ: return "eq";
`BRA_NEQ: return "neq";
`BRA_LT: return "lt";
`BRA_GE: return "ge";
`BRA_LTU: return "ltu";
`BRA_GEU: return "geu";
endcase // case (fun)
endfunction
function string decode_size(bit[2:0] fun);
case(fun)
`LDST_B: return "s8";
`LDST_BU: return "u8";
`LDST_H: return "s16";
`LDST_HU: return "u16";
`LDST_L: return "32";
endcase // case (fun)
endfunction
function string decode_regname(bit[4:0] r);
case(r)
0: return "zero";
1: return "ra";
2: return "sp";
3: return "gp";
4: return "tp";
5: return "t0";
6: return "t1";
7: return "t2";
8: return "s0";
9: return "s1";
10: return "a0";
11: return "a1";
12: return "a2";
13: return "a3";
14: return "a4";
15: return "a5";
16: return "a6";
17: return "a7";
18: return "s2";
19: return "s3";
20: return "s4";
21: return "s5";
22: return "s6";
23: return "s7";
24: return "s8";
25: return "s9";
26: return "s10";
27: return "s11";
28: return "t3";
29: return "t4";
30: return "t5";
31: return "t6";
endcase // case (fun)
endfunction // decode_regname
function string decode_csr(bit[11:0] csr);
case(csr)
`CSR_ID_CYCLESH: return "cyclesh";
`CSR_ID_CYCLESL: return "cyclesl";
`CSR_ID_TIMEH: return "timeh";
`CSR_ID_TIMEL: return "timel";
`CSR_ID_MSCRATCH: return "mscratch";
`CSR_ID_MEPC: return "mepc";
`CSR_ID_MSTATUS: return "mstatus";
`CSR_ID_MCAUSE: return "mcause";
default: return "???";
endcase // case (csr)
endfunction // decode_csr
task automatic verify_branch(input [31:0] rs1, input[31:0] rs2, input take, input [2:0] fun);
int do_take;
case(fun)
`BRA_EQ: do_take = (rs1 == rs2);
`BRA_NEQ: do_take = (rs1 != rs2);
`BRA_GE: do_take = $signed(rs1) >= $signed(rs2);
`BRA_LT: do_take = $signed(rs1) < $signed(rs2);
`BRA_GEU: do_take = rs1 >= rs2;
`BRA_LTU: do_take = rs1 < rs2;
default:
begin
$error("illegal branch func");
$stop;
end
endcase // case (func)
if(do_take != take)
begin
$error("fucked up jump");
$stop;
end
endtask // verify_branch
function automatic string s_hex(int x);
return $sformatf("%s0x%-08x", x<0?"-":" ", (x<0)?(-x):x);
endfunction // s_hex
reg[31:0] dm_addr_d0;
integer f_console, f_exec_log;
initial begin
f_console = $fopen("console.txt","wb");
f_exec_log = $fopen("exec_log.txt","wb");
#500us;
// $fclose(f_console);
end
always@(posedge clk)
begin
if(dump_mem_accesses)
begin
dm_addr_d0 <= dm_addr;
if(dm_write)begin
$display("DM Write addr %x data %x", dm_addr, dm_data_s);
// $fwrite(f_exec_log,"DM Write addr %x data %x\n", dm_addr, dm_data_s);
end
if (DUT.writeback.x_load_i && DUT.writeback.rf_rd_write_o)
begin
/* -----\/----- EXCLUDED -----\/-----
if ($isunknown(dm_data_l))
begin
$error("Attempt to load uninitialized entry from memory");
$stop;
end
-----/\----- EXCLUDED -----/\----- */
$display("DM Load addr %x data %x -> %s", dm_addr_d0, DUT.writeback.rf_rd_value_o, decode_regname(DUT.writeback.x_rd_i));
/* -----\/----- EXCLUDED -----\/-----
$fwrite(f_exec_log, "DM Load addr %x data %x -> %s\n", dm_addr_d0, DUT.writeback.rf_rd_value_o, decode_regname(DUT.writeback.x_rd_i));
-----/\----- EXCLUDED -----/\----- */
end
end
end
always@(posedge clk)
if(dm_write && dm_addr == 'h100000)
begin
$display("\n ****** TX '%c' \n", dm_data_s[7:0]) ;
// $fwrite(f_exec_log,"\n ****** TX '%c' \n", dm_data_s[7:0]) ;
$fwrite(f_console,"%c", dm_data_s[7:0]);
$fflush(f_console);
end
int cycles = 0;
always@(posedge clk)
if(dump_insns && DUT.execute.d_valid_i && !DUT.execute.x_stall_i && !DUT.execute.x_kill_i)
begin
automatic string opc="<unk>", fun="", args="";
automatic string rs1 = decode_regname(DUT.d2x_rs1);
automatic string rs2 = decode_regname(DUT.d2x_rs2);
automatic string rd = decode_regname(DUT.d2x_rd);
reg [31:0] imm;
// $display("Opcode %x", DUT.d2x_opcode);
case (DUT.d2x_opcode)
`OPC_AUIPC:
begin
opc = "auipc";
fun = "";
args = $sformatf("%-3s %-3s %s", rd, " ", s_hex(DUT.d2x_imm));
end
`OPC_LUI:
begin
opc = "lui";
fun = "";
args = $sformatf("%-3s %-3s %s", rd, " ", s_hex(DUT.d2x_imm));
end
`OPC_OP_IMM:
begin
opc = "op-imm";
fun = decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s %s", rd, rs1, s_hex(DUT.d2x_imm));
end
`OPC_OP:
begin
opc = "op";
fun = decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s %-3s", rd, rs1, rs2);
end
`OPC_JAL:
begin
opc = "jal";
fun = "";
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s 0x%-08x", rd, DUT.execute.branch_target);
end
`OPC_JALR:
begin
opc = "jalr";
fun = "";
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s 0x%-08x", rd, rs1,
DUT.execute.branch_target);
end
`OPC_BRANCH:
begin
opc = "branch";
fun = decode_cond(DUT.d2x_fun);
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s 0x%-08x rs1 %s", rs1, rs2,
DUT.execute.branch_target,
DUT.execute.branch_take?"TAKE":"IGNORE");
verify_branch(DUT.execute.rs1, DUT.execute.rs2, DUT.execute.branch_take,DUT.d2x_fun);
end
`OPC_LOAD:
begin
opc = "ld";
fun = decode_size(DUT.d2x_fun);
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s [0x%-08x + %s]", rd, rs1,
DUT.execute.rs1,
s_hex($signed(DUT.execute.d_imm_i)));
end
`OPC_STORE:
begin
opc = "st";
fun = decode_size(DUT.d2x_fun);
//decode_op(DUT.d2x_fun);
args = $sformatf("%-3s %-3s [0x%-08x + %s]", rs2, rs1,
DUT.execute.rs1,
s_hex($signed(DUT.execute.d_imm_i)));
end
`OPC_SYSTEM:
case (DUT.d2x_fun)
`CSR_OP_CSRRWI: begin
opc = "csrrwi";
args = $sformatf("%-3s %-3s 0x%08x",
rd, decode_csr(DUT.d2x_csr_sel),
DUT.d2x_csr_imm);
end
`CSR_OP_CSRRSI: begin
opc = "csrrsi";
args = $sformatf("%-3s %-3s 0x%08x",
rd, decode_csr(DUT.d2x_csr_sel),
DUT.d2x_csr_imm);
end
`CSR_OP_CSRRCI: begin
opc = "csrrci";
args = $sformatf("%-3s %-3s 0x%08x",
rd, decode_csr(DUT.d2x_csr_sel),
DUT.d2x_csr_imm);
end
`CSR_OP_CSRRW: begin
opc = "csrrw";
args = $sformatf("%-3s %-3s %-3s [0x%08x]",
rd, decode_csr(DUT.d2x_csr_sel),
rs1, DUT.execute.rs1);
end
`CSR_OP_CSRRS: begin
opc = "csrrs";
args = $sformatf("%-3s %-3s %-3s [0x%08x]",
rd, decode_csr(DUT.d2x_csr_sel),
rs1, DUT.execute.rs1);
end
`CSR_OP_CSRRC: begin
opc = "csrrc";
args = $sformatf("%-3s %-3s %-3s [0x%08x]",
rd, decode_csr(DUT.d2x_csr_sel),
rs1, DUT.execute.rs1);
end
default: begin
opc = "system";
end
endcase // case (d_fun_i)
default:
begin
fun = "";
args = $sformatf("opc: 0x%02x", DUT.d2x_opcode);
end
endcase // case (d2x_opcode)
$display("%08x [%d]: %-8s %-3s %s",
DUT.execute.d_pc_i, cycles, opc, fun, args);
// $fwrite(f_exec_log,"%08x: %-8s %-3s %s\n",
// DUT.execute.d_pc_i, opc, fun, args);
$fwrite(f_exec_log,
": PC %08x OP %08x CYCLES %-0d RS1 %08x RS2 %08x\n",
DUT.execute.d_pc_i, DUT.decode.f_ir_i, cycles++,
DUT.execute.rs1, DUT.execute.rs2);
end
endmodule // main
#vlog -sv main.sv +incdir+. +incdir+../../include/wb +incdir+../../include/vme64x_bfm +incdir+../../include +incdir+../include +incdir+../../sim
vsim -L unisim -t 1ps work.main -novopt
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
# do wave.do
radix -hexadecimal
#run 1.7us
\ No newline at end of file
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -expand -group Fetch /main/DUT/fetch/clk_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/dbg_enabled_o
add wave -noupdate -expand -group Fetch /main/DUT/fetch/dbg_force_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/dbg_insn_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/dbg_insn_ready_o
add wave -noupdate -expand -group Fetch /main/DUT/fetch/dbg_mode
add wave -noupdate -expand -group Fetch /main/DUT/fetch/f_ir_o
add wave -noupdate -expand -group Fetch /main/DUT/fetch/f_pc_o
add wave -noupdate -expand -group Fetch /main/DUT/fetch/f_stall_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/f_valid_o
add wave -noupdate -expand -group Fetch /main/DUT/fetch/im_addr_o
add wave -noupdate -expand -group Fetch /main/DUT/fetch/im_data_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/im_valid_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/pc
add wave -noupdate -expand -group Fetch /main/DUT/fetch/pc_next
add wave -noupdate -expand -group Fetch /main/DUT/fetch/pc_plus_4
add wave -noupdate -expand -group Fetch /main/DUT/fetch/pipeline_cnt
add wave -noupdate -expand -group Fetch /main/DUT/fetch/rst_d
add wave -noupdate -expand -group Fetch /main/DUT/fetch/rst_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/x_bra_i
add wave -noupdate -expand -group Fetch /main/DUT/fetch/x_dbg_toggle
add wave -noupdate -expand -group Fetch /main/DUT/fetch/x_pc_bra_i
add wave -noupdate -expand -group Main /main/dbg_enabled
add wave -noupdate -expand -group Main /main/dbg_force
add wave -noupdate -expand -group Main /main/dbg_insn
add wave -noupdate -expand -group Main /main/dbg_insn_ready
add wave -noupdate /main/DUT/execute/f_dbg_toggle_o
add wave -noupdate /main/DUT/x2f_dbg_toggle
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {14447 ps} 0}
quietly wave cursor active 1
configure wave -namecolwidth 164
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {3518287 ps} {4025354 ps}
/*
* This program source code file is part of MasterFip project.
*
* Copyright (C) 2013-2017 CERN
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* logger.svh - implementation of test result logging classes */
`ifndef __LOGGER_SVH
`define __LOGGER_SVH
`include "serializable.svh"
// converts an array of bytes to a string with given format
function automatic string array2str(string fmt, uint8_t data[$]);
string rv ="";
for(int i =0 ;i<data.size();i++)
rv = {rv, $sformatf(fmt, data[i]) };
return rv;
endfunction // str
// represents a single test log:
class UnitTestMessage;
string m_msg;
int m_slot;
function new ( int slot, string msg );
m_msg = msg;
m_slot = slot;
endfunction // new
endclass // UnitTestMessage
typedef enum
{
TR_UNKNOWN,
TR_FAIL,
TR_PASS
} TestResult;
// represents a single test log:
class UnitTest;
// test ID
int m_id;
// final result (failure, pass, unknown)
TestResult m_result;
// name of the test
string m_name;
// detailed reason for the failure
string m_failureReason;
// message buffer
UnitTestMessage m_messages[$];
function automatic void msg( int slot, string str );
UnitTestMessage m = new( slot, str );
m_messages.push_back(m);
endfunction // msg
function new ( int id, string name );
m_id = id;
m_name = name;
m_result = TR_UNKNOWN;
endfunction // new
endclass // UnitTest
// class Logger
//
// A singleton class that handles all test result logging activities.
class Logger;
int m_id;
protected static Logger m_self;
protected int m_loggerId;
protected UnitTest m_currentTest;
protected UnitTest m_tests[$];
protected int m_passedTests;
protected int m_failedTests;
function new ( string log_file, int id = -1 );
m_id = 1;
m_loggerId = id;
m_currentTest = null;
m_passedTests = 0;
m_failedTests = 0;
endfunction
// returns the singleton instance
static function Logger get();
if (m_self == null) begin
m_self = new( "sim_log.txt" );
end
return m_self;
endfunction // get
// begins a test
function automatic void startTest( string name );
m_currentTest = new( m_id, name );
m_tests.push_back(m_currentTest);
$display("[*] Running test %d: %s", m_id, name);
m_id++;
endfunction // startTest
// marks the current test as passed
function automatic void pass();
if( m_currentTest.m_result == TR_UNKNOWN)
begin
$display("[*] Test %d PASSED", m_id);
m_currentTest.m_result = TR_PASS;
end
endfunction // pass
// marks the current test as failed
function automatic void fail ( string reason );
$display("[*] Test %d FAILED: %s", m_id, reason);
m_currentTest.m_result = TR_FAIL;
m_currentTest.m_failureReason = reason;
endfunction
// logs a message within the scope of the current test
function automatic void msg ( int slot, string m );
if(m_currentTest)
m_currentTest.msg(slot, m);
$display(" %s", m);
endfunction // msg
function automatic int getPassedTestCount();
automatic int cnt = 0;
foreach(m_tests[i])
if (m_tests[i].m_result == TR_PASS)
cnt++;
return cnt;
endfunction // getPassedTestCount
function automatic int getFailedTestCount();
automatic int cnt = 0;
foreach(m_tests[i])
if (m_tests[i].m_result == TR_FAIL)
cnt++;
return cnt;
endfunction // getPassedTestCount
function automatic void fprint(int fd, string str);
$fdisplay(fd, str);
$display(str);
endfunction // fprint
function automatic string getSystemDate();
automatic int fd;
string t;
/*
void'($system("date +%X--%x > sys_time.tmp"));
fd = $fopen("sys_time.tmp","r");
void'($fscanf(fd,"%s",t));
$fclose(fd);
void'($system("rm sys_time.tmp"));
return t;
*/
return "00:00:00 1970/01/01";
endfunction // getSystemDate
function automatic void writeTestReport( string filename );
automatic int fd = $fopen(filename,"wb");
fprint(fd, "MasterFIP SV Test Report");
fprint(fd, $sformatf("Test date: %s\n\n", getSystemDate() ));
fprint(fd, "Test Summary ");
fprint(fd, "-------------");
fprint(fd, $sformatf("%-02d tests PASSED", getPassedTestCount() ) );
fprint(fd, $sformatf("%-02d tests FAILED", getFailedTestCount() ) );
fprint(fd, "\nIndividual Test Results:" );
fprint(fd, "ID | Test Name | Status | Failure Reason" );
fprint(fd, "----------------------------------------------------------------------------------------------------------" );
foreach(m_tests[i])
begin
fprint(fd, $sformatf("%-3d | %-74s | %-6s | %s" , m_tests[i].m_id, m_tests[i].m_name, m_tests[i].m_result == TR_PASS ? "PASS" : "FAIL", m_tests[i].m_failureReason ) );
end
fprint(fd,"\n\n");
foreach(m_tests[i])
begin
automatic UnitTest test = m_tests[i];
$fdisplay(fd, "Test messages for test %d", test.m_id );
$fdisplay(fd, "---------------------------\n" );
foreach(test.m_messages[j])
begin
$fdisplay(fd, test.m_messages[j].m_msg);
end
$fdisplay(fd, "\n---------------------------\n" );
end
endfunction
endclass // Logger
class LoggerClient;
function automatic void startTest( string name );
automatic Logger l = Logger::get();
l.startTest( name );
endfunction // startTest
function automatic void pass();
automatic Logger l = Logger::get();
l.pass();
endfunction // pass
function automatic void fail ( string reason );
automatic Logger l = Logger::get();
l.fail(reason);
endfunction
function automatic void msg ( int slot, string m );
automatic Logger l = Logger::get();
l.msg(slot, m);
endfunction // msg
endclass // LoggerClient
`endif // `ifndef __LOGGER_SVH
`ifndef __SERIALIZABLE_SVH
`define __SERIALIZABLE_SVH
`include "simdrv_defs.svh"
typedef byte int8_t;
typedef byte unsigned uint8_t;
typedef uint8_t uint8_array_t[$];
class ByteBuffer;
uint8_t data[$];
int pos;
function new();
pos = 0;
endfunction // new
function ByteBuffer copy();
copy = new();
copy.pos = this.pos;
copy.data = this.data;
return copy;
endfunction // copy
task automatic clear();
data = '{};
pos = 0;
endtask
task dump();
int i;
$display("buffer has %d bytes", data.size());
for (i=0;i<data.size();i++)
$display("%d: %x", i, data[i]);
endtask // dump
function int size();
return data.size();
endfunction // size
function int getPos();
return pos;
endfunction // getPos
function automatic void setPos( int pos_ );
pos = pos_;
endfunction // setPos
function automatic void addByte ( uint8_t c );
data.push_back(c);
endfunction // addByte
function automatic void addShort ( uint32_t c );
data.push_back((c >> 8) & 'hff);
data.push_back(c & 'hff);
endfunction // addShort
function automatic void addWord ( uint32_t c );
data.push_back((c >> 24) & 'hff);
data.push_back((c >> 16) & 'hff);
data.push_back((c >> 8) & 'hff);
data.push_back(c & 'hff);
endfunction // addWord
function automatic void addBytes ( uint8_t d[$] );
for (int i=0;i<d.size();i++)
data.push_back(d[i]);
endfunction // addBytes
function automatic uint8_t getByte();
automatic uint8_t rv = data[pos++];
return rv;
endfunction // getByte
function automatic uint8_t at(int pos_);
return data[pos_];
endfunction
function automatic uint8_array_t getBytes(int count);
automatic uint8_array_t rv;
for (int i=0;i<count;i++)
rv.push_back(data[pos++]);
return rv;
endfunction // getBytes
function automatic uint32_t getWord();
automatic uint32_t rv;
rv = data[pos++];
rv <<= 8;
rv |= data[pos++];
rv <<= 8;
rv |= data[pos++];
rv <<= 8;
rv |= data[pos++];
return rv;
endfunction // getWord
function automatic void reset();
pos = 0;
endfunction
// reset
endclass // ByteBuffer
class Serializable;
protected ByteBuffer m_data;
virtual function automatic void serialize( ByteBuffer data );
endfunction // serialize
virtual function automatic void deserialize ( ByteBuffer data );
m_data = data;
endfunction // deserialize
virtual task automatic dump();
if(!m_data)
return;
m_data.dump();
endtask // dump
function automatic void deserializeBytes ( uint8_t data[$]);
automatic ByteBuffer b = new ;
b.data = data;
deserialize( b );
endfunction // deserializeBytes
endclass // Serializable
`endif // `ifndef __SERIALIZABLE_SVH
`ifndef SIMDRV_DEFS_SV
`define SIMDRV_DEFS_SV 1
typedef longint unsigned uint64_t;
typedef int unsigned uint32_t;
typedef shortint unsigned uint16_t;
typedef uint64_t u64_array_t[];
typedef byte byte_array_t[];
virtual class CBusAccessor;
static int _null = 0;
int m_default_xfer_size;
task set_default_xfer_size(int default_size);
m_default_xfer_size = default_size;
endtask // set_default_xfer_size
pure virtual task writem(uint64_t addr[], uint64_t data[], input int size, ref int result);
pure virtual task readm(uint64_t addr[], ref uint64_t data[], input int size, ref int result);
virtual task read(uint64_t addr, ref uint64_t data, input int size = m_default_xfer_size, ref int result = _null);
int res;
uint64_t aa[1], da[];
da= new[1];
aa[0] = addr;
readm(aa, da, size, res);
data = da[0];
endtask
virtual task write(uint64_t addr, uint64_t data, input int size = m_default_xfer_size, ref int result = _null);
uint64_t aa[1], da[1];
aa[0] = addr;
da[0] = data;
writem(aa, da, size, result);
endtask
endclass // CBusAccessor
class CSimUtils;
static function automatic u64_array_t pack(byte x[], int size, int big_endian = 1);
u64_array_t tmp;
int i, j;
int nwords, nbytes;
nwords = (x.size() + size - 1) / size;
tmp = new [nwords];
for(i=0;i<nwords;i++)
begin
uint64_t d;
d =0;
nbytes = (x.size() - i * nbytes > size ? size : x.size() - i*nbytes);
for(j=0;j<nbytes;j++)
begin
if(big_endian)
d = d | ((x[i*size+j] << (8*(size-1-j))));
else
d = d | ((x[i*size+j] << (8*j)));
end
tmp[i] = d;
end
return tmp;
endfunction // pack
static function automatic byte_array_t unpack(u64_array_t x, int entry_size, int size, int big_endian = 1);
byte_array_t tmp;
int i, n;
tmp = new[size];
n = 0;
i = 0;
while(n < size)
begin
tmp[n] = x[i] >> (8*(entry_size-1 - (n % entry_size)));
n++;
if(n % entry_size == 0)
i++;
end
return tmp;
endfunction // unpack
endclass // CSimUtils
//static CSimUtils SimUtils;
`endif
sim_tool = "modelsim"
top_module="main"
sim_top="main"
syn_device="xc6slx150t"
sim_top="main"
action = "simulation"
target = "xilinx"
include_dirs=["../../rtl"]
include_dirs=["../../rtl", "../include"]
fetchto = "../../ip_cores"
vcom_opt="-mixedsvvh l"
files = [ "main.sv" ];
modules = {"local" : [ "../../rtl" ] }
\ No newline at end of file
modules = {"local" : [ "../../rtl"],
"git" : ["https://ohwr.org/project/general-cores.git"]}
/*
uRV - a tiny and dumb RISC-V core
Copyright (c) 2015 twl <twlostow@printf.cc>.
......@@ -15,177 +15,398 @@
You should have received a copy of the GNU Lesser General Public
License along with this library.
*/
`define URV_PLATFORM_SPARTAN6
`include "urv_defs.v"
`include "logger.svh"
`timescale 1ns/1ps
module main;
localparam struct {
bit mul;
bit div;
bit dbg;
bit ws;
bit ecc;
} configs[6] = '{ '{ mul: 0, div: 0, dbg: 0, ws: 0, ecc: 0 },
'{ mul: 0, div: 0, dbg: 0, ws: 1, ecc: 1 },
'{ mul: 1, div: 0, dbg: 0, ws: 0, ecc: 1 },
'{ mul: 1, div: 1, dbg: 0, ws: 0, ecc: 1 },
'{ mul: 1, div: 1, dbg: 1, ws: 0, ecc: 1 },
'{ mul: 1, div: 1, dbg: 1, ws: 1, ecc: 1 }};
localparam int n_configs = $size(configs);
module ICpuTestWrapper
(
input clk_i
);
reg clk = 0;
reg rst = 1;
wire [31:0] im_addr;
reg [31:0] im_data;
reg im_valid;
wire [31:0] dm_addr;
wire [31:0] dm_data_s;
reg [31:0] dm_data_l;
wire [3:0] dm_data_select;
wire dm_write;
reg r_with_hw_mulh = 0;
reg r_with_hw_divide = 0;
reg r_with_hw_debug = 0;
reg irq = 0;
parameter int mem_size = 16384;
wire cpu_fault[n_configs];
wire [31:0] im_addr_m[n_configs];
wire [31:0] dm_addr_m[n_configs];
wire [31:0] dm_data_s_m[n_configs];
wire [3:0] dm_data_select_m[n_configs];
wire dm_store_m[n_configs];
wire dm_load_m[n_configs];
reg [1:0] dm_store_done_d; // Delay line
reg [1:0] dm_load_done_d; // Delay line
wire irq_m[n_configs];
int r_active_cpu = 0;
wire fault = cpu_fault[r_active_cpu];
wire [31:0] im_addr = im_addr_m[r_active_cpu];
reg [31:0] im_data;
reg im_valid;
wire [31:0] dm_addr = dm_addr_m[r_active_cpu];
wire [31:0] dm_data_s = dm_data_s_m[r_active_cpu];
reg [31:0] dm_data_l_d[1:0];
wire [3:0] dm_data_select = dm_data_select_m[r_active_cpu];
wire dm_store = dm_store_m[r_active_cpu];
wire dm_load = dm_load_m[r_active_cpu];
reg dm_valid_l = 1;
reg dm_ready;
wire irq = 0;
localparam int mem_size = 16384;
wire dm_delay = configs[r_active_cpu].ws;
wire dm_store_done = dm_store_done_d[dm_delay];
wire dm_load_done = dm_load_done_d[dm_delay];
wire [31:0] dm_data_l = dm_data_l_d[dm_delay];
reg [31:0] mem[0:mem_size - 1];
// loads memory contents from a text file
task automatic load_ram(string filename);
string current_msg;
int test_complete = 0;
int fault_expected = 0;
task automatic selectConfiguration( int cpu );
r_active_cpu = cpu;
endtask // selectConfiguration
function automatic string getConfigurationString();
automatic string rv;
if(configs[r_active_cpu].mul)
rv = {rv, " hw_mulh"};
if(configs[r_active_cpu].div)
rv = {rv, " hw_div"};
if(configs[r_active_cpu].dbg)
rv = {rv, " hw_debug"};
if(configs[r_active_cpu].ws)
rv = {rv, " wait_state"};
if(configs[r_active_cpu].ecc)
rv = {rv, " ecc"};
return rv;
endfunction // getConfigurationString
task automatic runTest(string filename);
int f = $fopen(filename,"r");
int n, i;
int n, i;
// $display("load %s %x", filename, f);
current_msg = "";
test_complete = 0;
fault_expected = 0;
rst <= 1;
@(posedge clk_i);
@(posedge clk_i);
if( f == 0)
begin
$error("can't open: %s", filename);
$stop;
end
while(!$feof(f))
begin
int addr, data;
int addr, data, r;
string cmd;
$fscanf(f,"%s %08x %08x", cmd,addr,data);
r = $fscanf(f,"%s %08x %08x", cmd,addr,data);
if ( r < 0 )
break;
if(cmd == "write")
begin
mem[addr % mem_size] = data;
end
end
endtask // load_ram
$fclose(f);
@(posedge clk_i);
rst <= 0;
@(posedge clk_i);
endtask // runProgram
function automatic string getTestResult();
return current_msg;
endfunction // getTestResult
function automatic int isTestComplete();
return test_complete;
endfunction // isTestComplete
int seed;
int seed = 0;
// instruction and data memories
always@(posedge clk)
always@(posedge clk_i)
begin
// Read memory for insn
if( $dist_uniform(seed, 0, 100 ) <= 100) begin
im_data <= mem[(im_addr / 4) % mem_size];
logic [31:0] dat;
dat = mem[(im_addr / 4) % mem_size];
// $display("imem @%h: %08x", im_addr, dat);
im_data <= dat;
im_valid <= 1;
end else
im_valid <= 0;
if(dm_write && dm_data_select[0])
mem [(dm_addr / 4) % mem_size][7:0] <= dm_data_s[7:0];
if(dm_write && dm_data_select[1])
mem [(dm_addr / 4) % mem_size][15:8] <= dm_data_s[15:8];
if(dm_write && dm_data_select[2])
mem [(dm_addr / 4) % mem_size][23:16] <= dm_data_s[23:16];
if(dm_write && dm_data_select[3])
mem [(dm_addr / 4) % mem_size][31:24] <= dm_data_s[31:24];
end // always@ (posedge clk)
// Write data memory
if (dm_store)
begin
if(dm_data_select[0])
mem [(dm_addr / 4) % mem_size][7:0] <= dm_data_s[7:0];
if(dm_data_select[1])
mem [(dm_addr / 4) % mem_size][15:8] <= dm_data_s[15:8];
if(dm_data_select[2])
mem [(dm_addr / 4) % mem_size][23:16] <= dm_data_s[23:16];
if(dm_data_select[3])
mem [(dm_addr / 4) % mem_size][31:24] <= dm_data_s[31:24];
// $display("dmem @%h: <- %08x", dm_addr, dm_data_s);
end
dm_store_done_d <= {dm_store_done_d[0], dm_store};
// Read data memory
dm_data_l_d[1] <= dm_data_l_d[0];
dm_data_l_d[0] <= dm_load ? mem[(dm_addr/4) % mem_size] : 'x;
dm_load_done_d <= {dm_load_done_d[0], dm_load};
end // always@ (posedge clk)
always@(posedge clk)
for(genvar i = 0; i < n_configs; i++)
begin
dm_ready <= 1'b1; // $dist_uniform(seed, 0, 100 ) <= 50;
dm_data_l <= mem[(dm_addr/4) % mem_size];
end
urv_cpu DUT
(
.clk_i(clk),
.rst_i(rst),
.irq_i ( irq ),
// instruction mem I/F
.im_addr_o(im_addr),
.im_data_i(im_data),
.im_valid_i(im_valid),
// data mem I/F
.dm_addr_o(dm_addr),
.dm_data_s_o(dm_data_s),
.dm_data_l_i(dm_data_l),
.dm_data_select_o(dm_data_select),
.dm_store_o(dm_write),
.dm_load_o(),
.dm_store_done_i(1'b1),
.dm_load_done_i(1'b1),
.dm_ready_i(dm_ready)
);
urv_cpu
#(
.g_with_hw_mulh(configs[i].mul),
.g_with_hw_div(configs[i].div),
.g_with_hw_debug(configs[i].dbg),
.g_with_ecc(configs[i].ecc)
)
DUTx
(
.clk_i(i == r_active_cpu ? clk_i : 1'b0 ),
.rst_i(i == r_active_cpu ? rst : 1'b1 ),
.irq_i ( irq ),
.fault_o (cpu_fault[i]),
// instruction mem I/F
.im_addr_o(im_addr_m[i]),
.im_rd_o(),
.im_data_i(im_data),
.im_valid_i(im_valid),
// data mem I/F
.dm_addr_o(dm_addr_m[i]),
.dm_data_s_o(dm_data_s_m[i]),
.dm_data_l_i(dm_data_l),
.dm_data_select_o(dm_data_select_m[i]),
.dm_store_o(dm_store_m[i]),
.dm_load_o(dm_load_m[i]),
.dm_store_done_i(dm_store_done),
.dm_load_done_i(dm_load_done),
// Debug
.dbg_force_i(1'b0),
.dbg_enabled_o(),
.dbg_insn_i(32'h0),
.dbg_insn_set_i(1'b0),
.dbg_insn_ready_o(),
// Debug mailbox
.dbg_mbx_data_i(0),
.dbg_mbx_write_i(1'b0),
.dbg_mbx_data_o()
);
end
always@(posedge clk_i) begin
if(dm_store)
begin
automatic bit [7:0] chr = dm_data_s[7:0];
if(dm_addr == 'h100000)
current_msg = {current_msg, chr};
else if(dm_addr == 'h100004)
test_complete = 1;
else if(dm_addr == 'h100008)
fault_expected = 1;
end
if (fault) begin
current_msg = {current_msg, fault_expected ? "Test passed\n" : "Fault" };
test_complete = 1;
end
end
endmodule // ICpuTestWrapper
module main;
reg clk = 0;
always #5ns clk <= ~clk;
integer f_console, f_exec_log;
reg test_complete = 0;
initial begin
string tests[$];
string test_dir = "../../sw/testsuite/isa";
// load all tests listed in the file
int f = $fopen( {test_dir,"/tests.lst"} ,"r");
int n, i;
ICpuTestWrapper DUT ( clk );
class ISATestRunner extends LoggerClient;
typedef enum
{
R_OK = 0,
R_FAIL = 1,
R_TIMEOUT = 2
} TestStatus;
task automatic runTest(string filename, ref TestStatus status, ref int failedTest );
automatic integer cnt = 0;
// $display("runTest task");
DUT.runTest(filename);
failedTest = 0;
while(!DUT.isTestComplete() )
begin
#1us;
if ( cnt > 10000)
begin
status = R_TIMEOUT;
$display("timeout, time=%t, msg=%s",
$time, DUT.getTestResult());
return;
end
cnt++;
end
if (DUT.getTestResult() == "Test passed\n")
status = R_OK;
else
status = R_FAIL;
endtask // runTest
task automatic runAllTests( string test_dir, string list_file, inout int failCount);
automatic string tests[$];
automatic int n, i, f;
automatic string failedTests = "";
f_console = $fopen("console.txt","wb");
f = $fopen( $sformatf("%s/%s", test_dir, list_file ) ,"r");
if (f == 0)
$fatal;
while(!$feof(f))
begin
string fname;
$fscanf(f,"%s", fname);
automatic string fname;
void'($fscanf(f,"%s", fname));
if (fname[0] == "#" || fname == "")
continue;
tests.push_back(fname);
end
for (i=0;i<tests.size();i++)
begin
rst = 1;
repeat(3) @(posedge clk);
$display("Loading %s", {test_dir,"/",tests[i]} );
load_ram({test_dir,"/",tests[i]});
repeat(3) @(posedge clk);
rst = 0;
test_complete= 0;
while(!test_complete)
#1us;
automatic int failedTest;
automatic TestStatus status;
automatic string s;
// $display("Run %s", tests[i]);
runTest({test_dir,"/",tests[i]}, status, failedTest );
if ( status == R_OK )
s = "PASS";
else if ( status == R_TIMEOUT )
begin
s = "Timeout (likely fail due to CPU freeze)";
failCount++;
break;
end else begin
s = $sformatf ("FAIL (subtest %d)", failedTest );
failCount++;
end
msg(0, $sformatf("%s: %s", tests[i], s ) );
end
end // initial begin
endtask // runAllTests
task automatic testsResult(int failCount);
if(failCount)
fail ( $sformatf( "%d tests FAILED", failCount ) );
else
pass();
endtask
endclass // ISATestRunner
initial begin
automatic int i;
automatic ISATestRunner testRunner = new;
automatic Logger l = Logger::get();
automatic int failCount;
for(i=0;i<n_configs;i++)
begin
DUT.selectConfiguration(i);
l.startTest($sformatf( "Full ISA Test for feature set:%s", DUT.getConfigurationString() ) );
failCount = 0;
testRunner.runAllTests("../../sw/testsuite/isa", "tests.lst", failCount );
if (configs[i].ecc)
testRunner.runAllTests("../../sw/testsuite/isa", "tests-urv.lst", failCount );
testRunner.testsResult(failCount);
end
l.writeTestReport("report.txt");
$stop;
end
// report test completeness/status. The test applets indicate this by writing predefined
// memory locations.
always@(posedge clk)
if(dm_write)
begin
if(dm_addr == 'h100000)
begin
$write("%c", dm_data_s[7:0]);
$fwrite(f_console,"%c", dm_data_s[7:0]);
$fflush(f_console);
end
else if(dm_addr == 'h100004)
begin
test_complete = 1;
end
end
endmodule // main
......@@ -4,6 +4,6 @@ vsim -L unisim -t 1ps work.main -novopt
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
do wave.do
#do wave.do
radix -hexadecimal
run 1.7us
\ No newline at end of file
run 8ms
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -expand -group Exec /main/DUT/execute/clk_i
add wave -noupdate -expand -group Exec /main/DUT/execute/rst_i
add wave -noupdate -expand -group Exec /main/DUT/execute/x_stall_i
add wave -noupdate -expand -group Exec /main/DUT/execute/x_kill_i
add wave -noupdate -expand -group Exec /main/DUT/execute/x_stall_req_o
add wave -noupdate -expand -group Exec /main/DUT/execute/d_pc_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_rd_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_fun_i
add wave -noupdate -expand -group Exec /main/DUT/execute/rf_rs1_value_i
add wave -noupdate -expand -group Exec /main/DUT/execute/rf_rs2_value_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_valid_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_opcode_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_shifter_sign_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_csr_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_eret_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_csr_imm_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_csr_sel_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_imm_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_signed_compare_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_signed_alu_op_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_add_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_shift_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_load_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_store_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_divide_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_is_undef_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_alu_op1_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_alu_op2_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_use_op1_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_use_op2_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_rd_source_i
add wave -noupdate -expand -group Exec /main/DUT/execute/d_rd_write_i
add wave -noupdate -expand -group Exec /main/DUT/execute/f_branch_target_o
add wave -noupdate -expand -group Exec /main/DUT/execute/f_branch_take_o
add wave -noupdate -expand -group Exec /main/DUT/execute/irq_i
add wave -noupdate -expand -group Exec /main/DUT/execute/w_fun_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_load_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_store_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_valid_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_rd_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_rd_value_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_rd_write_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_dm_addr_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_rd_source_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_rd_shifter_o
add wave -noupdate -expand -group Exec /main/DUT/execute/w_rd_multiply_o
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_addr_o
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_data_s_o
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_data_select_o
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_store_o
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_load_o
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_ready_i
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_time_i
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_cycles_i
add wave -noupdate -expand -group Exec /main/DUT/execute/timer_tick_i
add wave -noupdate -expand -group Exec /main/DUT/execute/rs1
add wave -noupdate -expand -group Exec /main/DUT/execute/rs2
add wave -noupdate -expand -group Exec /main/DUT/execute/alu_op1
add wave -noupdate -expand -group Exec /main/DUT/execute/alu_op2
add wave -noupdate -expand -group Exec /main/DUT/execute/alu_result
add wave -noupdate -expand -group Exec /main/DUT/execute/rd_value
add wave -noupdate -expand -group Exec /main/DUT/execute/exception_taken
add wave -noupdate -expand -group Exec /main/DUT/execute/branch_take
add wave -noupdate -expand -group Exec /main/DUT/execute/branch_condition_met
add wave -noupdate -expand -group Exec /main/DUT/execute/branch_target
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_addr
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_data_s
add wave -noupdate -expand -group Exec /main/DUT/execute/dm_select_s
add wave -noupdate -expand -group Exec /main/DUT/execute/cmp_op1
add wave -noupdate -expand -group Exec /main/DUT/execute/cmp_op2
add wave -noupdate -expand -group Exec /main/DUT/execute/cmp_rs
add wave -noupdate -expand -group Exec /main/DUT/execute/cmp_equal
add wave -noupdate -expand -group Exec /main/DUT/execute/cmp_lt
add wave -noupdate -expand -group Exec /main/DUT/execute/f_branch_take
add wave -noupdate -expand -group Exec /main/DUT/execute/rd_csr
add wave -noupdate -expand -group Exec /main/DUT/execute/rd_div
add wave -noupdate -expand -group Exec /main/DUT/execute/exception
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_mie
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_mip
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_mepc
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_mstatus
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_mcause
add wave -noupdate -expand -group Exec /main/DUT/execute/csr_write_value
add wave -noupdate -expand -group Exec /main/DUT/execute/exception_address
add wave -noupdate -expand -group Exec /main/DUT/execute/exception_vector
add wave -noupdate -expand -group Exec /main/DUT/execute/exception_pc
add wave -noupdate -expand -group Exec /main/DUT/execute/alu_addsub_op1
add wave -noupdate -expand -group Exec /main/DUT/execute/alu_addsub_op2
add wave -noupdate -expand -group Exec /main/DUT/execute/alu_addsub_result
add wave -noupdate -expand -group Exec /main/DUT/execute/divider_stall_req
add wave -noupdate -expand -group Exec /main/DUT/execute/unaligned_addr
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/clk_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/rst_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_stall_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_kill_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/d_is_csr_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/d_is_eret_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/d_fun_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/d_csr_imm_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/d_csr_sel_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exp_irq_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exp_tick_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exp_breakpoint_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exp_unaligned_load_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exp_unaligned_store_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exp_invalid_insn_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_csr_write_value_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_exception_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_exception_pc_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_exception_pc_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_exception_vector_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/x_exception_taken_i
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mstatus_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mip_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mie_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mepc_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mcause_o
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mepc
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mie
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_ie
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mcause
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exception
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/cause
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/except_vec_masked
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/exception_pending
add wave -noupdate -expand -group Except /main/DUT/execute/exception_unit/csr_mip
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/clk_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/rst_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/im_addr_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/im_data_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/im_valid_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_addr_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_data_s_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_data_l_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_data_select_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_ready_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_store_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_load_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_load_done_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/dm_store_done_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/d_pc_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/d_valid_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/d_is_load_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/d_is_store_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/d_opcode_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/d_imm_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/x_kill_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/x_stall_req_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/x_stall_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/writeback/x_valid_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/x_rd_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/x_rs1_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/x_rs2_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/rs1}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/rs2}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/d_stall_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/d_kill_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/d_stall_req_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/rf_rs1_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/decode/rf_rs2_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/rf_rs1_value_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/rf_rs2_value_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/rs1_bypass_x}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/rs2_bypass_x}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/rs1_bypass_w}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/rs2_bypass_w}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/x_rs1_value_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/x_rs2_value_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/w_bypass_rd_write_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/w_rd_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/w_rd_value_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/w_rd_store_i}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/regfile/bank0/ram}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/w_valid_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/w_rd_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/w_rd_value_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/w_rd_write_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/w_rd_source_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/w_rd_shifter_o}
add wave -noupdate {/main/DUT/genblk1[0]/DUTx/execute/w_rd_multiply_o}
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {2308604 ps} 0}
configure wave -namecolwidth 250
WaveRestoreCursors {{Cursor 1} {2765000 ps} 0}
quietly wave cursor active 1
configure wave -namecolwidth 237
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -justifyvalue right
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
......@@ -142,4 +71,4 @@ configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ps
update
WaveRestoreZoom {0 ps} {7564032 ps}
WaveRestoreZoom {2640264 ps} {2759971 ps}
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