Add uriscv, a smallest riscv implementation.
This commit is contained in:
parent
15467611cf
commit
1dfaaa39ef
|
@ -0,0 +1,2 @@
|
|||
tb/build
|
||||
tb/*.vcd
|
|
@ -0,0 +1,84 @@
|
|||
### uriscv - Another tiny RISC-V implementation
|
||||
|
||||
Github: [https://github.com/ultraembedded/core_uriscv](https://github.com/ultraembedded/core_uriscv)
|
||||
|
||||
Simple, small, multi-cycle 32-bit RISC-V CPU implementation.
|
||||
Most instructions take 2 cycles, apart from load/stores which take 4+ cycles (depending on memory latency), and division which can take up-to 34 cycles.
|
||||
|
||||
## Features
|
||||
* 32-bit RISC-V ISA CPU core.
|
||||
* Support RISC-V’s integer (I), multiplication and division (M), and CSR instructions (Z) extensions (RV32IMZicsr).
|
||||
* Implements base ISA spec v2.1 and parts of the privileged ISA spec v1.11.
|
||||
* Supports machine mode privilege level only.
|
||||
* Configurable support for exceptions, interrupts, timers, multiplication, division and error traps.
|
||||
* Verified using random instruction sequences using cosimulation against [C++ ISA model](https://github.com/ultraembedded/exactstep).
|
||||
* Synthesizable Verilog 2001, Verilator and FPGA friendly.
|
||||
* Coremark: **1.48 CoreMark/MHz** (with HW mul/div)
|
||||
* Dhrystone: **0.58 DMIPS/MHz** ('legal compile options' / 337 instructions per iteration / with HW mul/div)
|
||||
|
||||
**For my higher performance pipelined cores, see here:**
|
||||
* Coremark: **2.94CM/MHZ** - [http://github.com/ultraembedded/riscv](http://github.com/ultraembedded/riscv)
|
||||
* Coremark: **4.1CM/MHz** - [http://github.com/ultraembedded/biriscv](http://github.com/ultraembedded/biriscv)
|
||||
|
||||
## Getting Started
|
||||
|
||||
#### Cloning
|
||||
|
||||
To clone this project and its dependencies;
|
||||
|
||||
```
|
||||
git clone https://github.com/ultraembedded/core_uriscv.git
|
||||
|
||||
```
|
||||
|
||||
#### Running Helloworld
|
||||
|
||||
To run a simple test image on the core RTL using Icarus Verilog;
|
||||
|
||||
```
|
||||
# Install Icarus Verilog (Debian / Ubuntu / Linux Mint)
|
||||
sudo apt-get install iverilog
|
||||
|
||||
# [or] Install Icarus Verilog (Redhat / Centos)
|
||||
#sudo yum install iverilog
|
||||
|
||||
# Run a simple test image (test.elf)
|
||||
cd tb/tb_core_icarus
|
||||
make
|
||||
```
|
||||
|
||||
The expected output is;
|
||||
```
|
||||
Starting bench
|
||||
VCD info: dumpfile waveform.vcd opened for output.
|
||||
|
||||
Test:
|
||||
1. Initialised data
|
||||
2. Multiply
|
||||
3. Divide
|
||||
4. Shift left
|
||||
5. Shift right
|
||||
6. Shift right arithmetic
|
||||
7. Signed comparision
|
||||
8. Word access
|
||||
9. Byte access
|
||||
10. Comparision
|
||||
```
|
||||
#### Configuration
|
||||
|
||||
| Param Name | Valid Range | Description |
|
||||
| ------------------------- |:------------:| ------------------------------------------------------------|
|
||||
| SUPPORT_MUL | 1/0 | Enable multiplication instructions. |
|
||||
| SUPPORT_DIV | 1/0 | Enable division instructions. |
|
||||
| SUPPORT_CSR | 1/0 | Global enable for CSR/trap/interrupt handling. |
|
||||
| SUPPORT_TRAP_LSU_ALIGN | 1/0 | Enable unaligned memory load / store exception. |
|
||||
| SUPPORT_MTVEC | 1/0 | Configurable exception entry address. |
|
||||
| SUPPORT_MTVAL | 1/0 | Support MTVAL CSR (holds bad addr / opcode). |
|
||||
| SUPPORT_MIP_MIE | 1/0 | Support MIE and MIP CSR registers. |
|
||||
| SUPPORT_MSCRATCH | 1/0 | Support MSCRATCH CSR registers (SW read/write). |
|
||||
| SUPPORT_MCYCLE | 1/0 | Support cycle counter / rdtime. |
|
||||
| SUPPORT_MTIMECMP | 1/0 | Non-std - support timer compare interrupt. |
|
||||
| SUPPORT_TRAP_INVALID_OPC | 1/0 | Fault on invalid opcodes (enable SW emulation). |
|
||||
| SUPPORT_BRAM_REGFILE | 1/0 | FPGA BlockRAM friendly reg file (inst take 1 cycle longer). |
|
||||
| ISR_VECTOR | 'h0-FFFFFFFF | ISR addr = reset_vector + ISR_VECTOR (SUPPORT_MTVEC = 0). |
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,104 @@
|
|||
[*]
|
||||
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
|
||||
[*] Sat Jul 17 10:54:57 2021
|
||||
[*]
|
||||
[timestart] 0
|
||||
[size] 2560 1385
|
||||
[pos] -1 -1
|
||||
*-14.000000 146555 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
|
||||
[treeopen] tb_top.
|
||||
[treeopen] tb_top.u_dut.
|
||||
[sst_width] 202
|
||||
[signals_width] 245
|
||||
[sst_expanded] 1
|
||||
[sst_vpaned_height] 420
|
||||
@28
|
||||
tb_top.u_dut.clk_i
|
||||
tb_top.u_dut.rst_i
|
||||
@200
|
||||
-
|
||||
@800200
|
||||
-MEM_I
|
||||
@200
|
||||
-REQ
|
||||
@28
|
||||
tb_top.u_dut.mem_i_rd_o
|
||||
@22
|
||||
tb_top.u_dut.mem_i_pc_o[31:0]
|
||||
@28
|
||||
tb_top.u_dut.mem_i_accept_i
|
||||
@200
|
||||
-RESP
|
||||
@28
|
||||
tb_top.u_dut.mem_i_valid_i
|
||||
@22
|
||||
tb_top.u_dut.mem_i_inst_i[31:0]
|
||||
@1000200
|
||||
-MEM_I
|
||||
@200
|
||||
-
|
||||
@800200
|
||||
-MEM_D
|
||||
@200
|
||||
-REQ
|
||||
@28
|
||||
tb_top.u_dut.mem_d_rd_o
|
||||
@22
|
||||
tb_top.u_dut.mem_d_wr_o[3:0]
|
||||
tb_top.u_dut.mem_d_addr_o[31:0]
|
||||
tb_top.u_dut.mem_d_data_wr_o[31:0]
|
||||
@28
|
||||
tb_top.u_dut.mem_d_accept_i
|
||||
@200
|
||||
-RESP
|
||||
@28
|
||||
tb_top.u_dut.mem_d_ack_i
|
||||
@22
|
||||
tb_top.u_dut.mem_d_data_rd_i[31:0]
|
||||
@1000200
|
||||
-MEM_D
|
||||
@200
|
||||
-
|
||||
@23
|
||||
tb_top.u_dut.pc_q[31:0]
|
||||
@200
|
||||
-
|
||||
@800200
|
||||
-REGFILE
|
||||
@22
|
||||
tb_top.u_dut.x0_zero_w[31:0]
|
||||
tb_top.u_dut.x1_ra_w[31:0]
|
||||
tb_top.u_dut.x2_sp_w[31:0]
|
||||
tb_top.u_dut.x3_gp_w[31:0]
|
||||
tb_top.u_dut.x4_tp_w[31:0]
|
||||
tb_top.u_dut.x5_t0_w[31:0]
|
||||
tb_top.u_dut.x6_t1_w[31:0]
|
||||
tb_top.u_dut.x7_t2_w[31:0]
|
||||
tb_top.u_dut.x8_s0_w[31:0]
|
||||
tb_top.u_dut.x9_s1_w[31:0]
|
||||
tb_top.u_dut.x10_a0_w[31:0]
|
||||
tb_top.u_dut.x11_a1_w[31:0]
|
||||
tb_top.u_dut.x12_a2_w[31:0]
|
||||
tb_top.u_dut.x13_a3_w[31:0]
|
||||
tb_top.u_dut.x14_a4_w[31:0]
|
||||
tb_top.u_dut.x15_a5_w[31:0]
|
||||
tb_top.u_dut.x16_a6_w[31:0]
|
||||
tb_top.u_dut.x17_a7_w[31:0]
|
||||
tb_top.u_dut.x18_s2_w[31:0]
|
||||
tb_top.u_dut.x19_s3_w[31:0]
|
||||
tb_top.u_dut.x20_s4_w[31:0]
|
||||
tb_top.u_dut.x21_s5_w[31:0]
|
||||
tb_top.u_dut.x22_s6_w[31:0]
|
||||
tb_top.u_dut.x23_s7_w[31:0]
|
||||
tb_top.u_dut.x24_s8_w[31:0]
|
||||
tb_top.u_dut.x25_s9_w[31:0]
|
||||
tb_top.u_dut.x26_s10_w[31:0]
|
||||
tb_top.u_dut.x27_s11_w[31:0]
|
||||
tb_top.u_dut.x28_t3_w[31:0]
|
||||
tb_top.u_dut.x29_t4_w[31:0]
|
||||
tb_top.u_dut.x30_t5_w[31:0]
|
||||
tb_top.u_dut.x31_t6_w[31:0]
|
||||
@1000200
|
||||
-REGFILE
|
||||
[pattern_trace] 1
|
||||
[pattern_trace] 0
|
|
@ -0,0 +1,62 @@
|
|||
###############################################################################
|
||||
# Variables: Program ELF
|
||||
###############################################################################
|
||||
ELF_FILE ?= test.elf
|
||||
|
||||
OBJCOPY ?= /opt/riscv/bin/riscv32-unknown-elf-objcopy
|
||||
ifeq ($(shell which $(OBJCOPY)),)
|
||||
${error $(OBJCOPY) missing from PATH}
|
||||
endif
|
||||
ifeq ($(shell which iverilog),)
|
||||
${error iverilog missing from PATH - Icarus Verilog required}
|
||||
endif
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Variables: Defaults
|
||||
###############################################################################
|
||||
TRACE ?= 1
|
||||
|
||||
SRC_V_DIR ?= ../src .
|
||||
SRC_DIR ?= .
|
||||
|
||||
EXE ?= output.out
|
||||
|
||||
###############################################################################
|
||||
# Variables: Verilog
|
||||
###############################################################################
|
||||
SRC_V ?= $(foreach src,$(SRC_V_DIR),$(wildcard $(src)/*.v))
|
||||
|
||||
VFLAGS += $(patsubst %,-I%,$(SRC_V_DIR))
|
||||
VFLAGS += -DTRACE=$(TRACE)
|
||||
VFLAGS += -Dverilog_sim
|
||||
|
||||
###############################################################################
|
||||
# Variables: Lists of objects, source and deps
|
||||
###############################################################################
|
||||
BUILD_DIR ?= build/
|
||||
|
||||
###############################################################################
|
||||
# Rules
|
||||
###############################################################################
|
||||
all: run
|
||||
|
||||
$(BUILD_DIR):
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_DIR)/tcm.bin: $(ELF_FILE) | $(BUILD_DIR)
|
||||
$(OBJCOPY) $< -O binary $@
|
||||
|
||||
$(BUILD_DIR)/$(EXE): $(SRC_V) | $(BUILD_DIR)
|
||||
@echo "# Compiling verilog"
|
||||
iverilog $(VFLAGS) -o $@ $(SRC_V)
|
||||
|
||||
run: $(BUILD_DIR)/$(EXE) $(BUILD_DIR)/tcm.bin
|
||||
vvp $(BUILD_DIR)/$(EXE) -vcd
|
||||
|
||||
view:
|
||||
gtkwave waveform.vcd gtksettings.sav
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR) *.vcd
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
module tb_top;
|
||||
|
||||
reg clk;
|
||||
reg rst;
|
||||
|
||||
reg [7:0] mem[65535:0];
|
||||
integer i;
|
||||
integer f;
|
||||
|
||||
initial
|
||||
begin
|
||||
$display("Starting bench");
|
||||
|
||||
if (`TRACE)
|
||||
begin
|
||||
$dumpfile("waveform.vcd");
|
||||
$dumpvars(0, tb_top);
|
||||
end
|
||||
|
||||
// Reset
|
||||
clk = 0;
|
||||
rst = 1;
|
||||
repeat (5) @(posedge clk);
|
||||
rst = 0;
|
||||
|
||||
// Load TCM memory
|
||||
for (i=0;i<65535;i=i+1)
|
||||
mem[i] = 0;
|
||||
|
||||
f = $fopenr("./build/tcm.bin");
|
||||
i = $fread(mem, f);
|
||||
for (i=0;i<65535;i=i+1)
|
||||
u_mem.write(i, mem[i]);
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
forever
|
||||
begin
|
||||
clk = #5 ~clk;
|
||||
end
|
||||
end
|
||||
|
||||
wire mem_i_rd_w;
|
||||
wire mem_i_flush_w;
|
||||
wire mem_i_invalidate_w;
|
||||
wire [ 31:0] mem_i_pc_w;
|
||||
wire [ 31:0] mem_d_addr_w;
|
||||
wire [ 31:0] mem_d_data_wr_w;
|
||||
wire mem_d_rd_w;
|
||||
wire [ 3:0] mem_d_wr_w;
|
||||
wire mem_d_cacheable_w;
|
||||
wire [ 10:0] mem_d_req_tag_w;
|
||||
wire mem_d_invalidate_w;
|
||||
wire mem_d_writeback_w;
|
||||
wire mem_d_flush_w;
|
||||
wire mem_i_accept_w;
|
||||
wire mem_i_valid_w;
|
||||
wire mem_i_error_w;
|
||||
wire [ 31:0] mem_i_inst_w;
|
||||
wire [ 31:0] mem_d_data_rd_w;
|
||||
wire mem_d_accept_w;
|
||||
wire mem_d_ack_w;
|
||||
wire mem_d_error_w;
|
||||
wire [ 10:0] mem_d_resp_tag_w;
|
||||
|
||||
riscv_core
|
||||
u_dut
|
||||
//-----------------------------------------------------------------
|
||||
// Ports
|
||||
//-----------------------------------------------------------------
|
||||
(
|
||||
// Inputs
|
||||
.clk_i(clk)
|
||||
,.rst_i(rst)
|
||||
,.mem_d_data_rd_i(mem_d_data_rd_w)
|
||||
,.mem_d_accept_i(mem_d_accept_w)
|
||||
,.mem_d_ack_i(mem_d_ack_w)
|
||||
,.mem_d_error_i(mem_d_error_w)
|
||||
,.mem_d_resp_tag_i(mem_d_resp_tag_w)
|
||||
,.mem_i_accept_i(mem_i_accept_w)
|
||||
,.mem_i_valid_i(mem_i_valid_w)
|
||||
,.mem_i_error_i(mem_i_error_w)
|
||||
,.mem_i_inst_i(mem_i_inst_w)
|
||||
,.intr_i(1'b0)
|
||||
,.reset_vector_i(32'h80000000)
|
||||
,.cpu_id_i('b0)
|
||||
|
||||
// Outputs
|
||||
,.mem_d_addr_o(mem_d_addr_w)
|
||||
,.mem_d_data_wr_o(mem_d_data_wr_w)
|
||||
,.mem_d_rd_o(mem_d_rd_w)
|
||||
,.mem_d_wr_o(mem_d_wr_w)
|
||||
,.mem_d_cacheable_o(mem_d_cacheable_w)
|
||||
,.mem_d_req_tag_o(mem_d_req_tag_w)
|
||||
,.mem_d_invalidate_o(mem_d_invalidate_w)
|
||||
,.mem_d_writeback_o(mem_d_writeback_w)
|
||||
,.mem_d_flush_o(mem_d_flush_w)
|
||||
,.mem_i_rd_o(mem_i_rd_w)
|
||||
,.mem_i_flush_o(mem_i_flush_w)
|
||||
,.mem_i_invalidate_o(mem_i_invalidate_w)
|
||||
,.mem_i_pc_o(mem_i_pc_w)
|
||||
);
|
||||
|
||||
tcm_mem
|
||||
u_mem
|
||||
(
|
||||
// Inputs
|
||||
.clk_i(clk)
|
||||
,.rst_i(rst)
|
||||
,.mem_i_rd_i(mem_i_rd_w)
|
||||
,.mem_i_flush_i(mem_i_flush_w)
|
||||
,.mem_i_invalidate_i(mem_i_invalidate_w)
|
||||
,.mem_i_pc_i(mem_i_pc_w)
|
||||
,.mem_d_addr_i(mem_d_addr_w)
|
||||
,.mem_d_data_wr_i(mem_d_data_wr_w)
|
||||
,.mem_d_rd_i(mem_d_rd_w)
|
||||
,.mem_d_wr_i(mem_d_wr_w)
|
||||
,.mem_d_cacheable_i(mem_d_cacheable_w)
|
||||
,.mem_d_req_tag_i(mem_d_req_tag_w)
|
||||
,.mem_d_invalidate_i(mem_d_invalidate_w)
|
||||
,.mem_d_writeback_i(mem_d_writeback_w)
|
||||
,.mem_d_flush_i(mem_d_flush_w)
|
||||
|
||||
// Outputs
|
||||
,.mem_i_accept_o(mem_i_accept_w)
|
||||
,.mem_i_valid_o(mem_i_valid_w)
|
||||
,.mem_i_error_o(mem_i_error_w)
|
||||
,.mem_i_inst_o(mem_i_inst_w)
|
||||
,.mem_d_data_rd_o(mem_d_data_rd_w)
|
||||
,.mem_d_accept_o(mem_d_accept_w)
|
||||
,.mem_d_ack_o(mem_d_ack_w)
|
||||
,.mem_d_error_o(mem_d_error_w)
|
||||
,.mem_d_resp_tag_o(mem_d_resp_tag_w)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,120 @@
|
|||
|
||||
module tcm_mem
|
||||
(
|
||||
// Inputs
|
||||
input clk_i
|
||||
,input rst_i
|
||||
,input mem_i_rd_i
|
||||
,input mem_i_flush_i
|
||||
,input mem_i_invalidate_i
|
||||
,input [ 31:0] mem_i_pc_i
|
||||
,input [ 31:0] mem_d_addr_i
|
||||
,input [ 31:0] mem_d_data_wr_i
|
||||
,input mem_d_rd_i
|
||||
,input [ 3:0] mem_d_wr_i
|
||||
,input mem_d_cacheable_i
|
||||
,input [ 10:0] mem_d_req_tag_i
|
||||
,input mem_d_invalidate_i
|
||||
,input mem_d_writeback_i
|
||||
,input mem_d_flush_i
|
||||
|
||||
// Outputs
|
||||
,output mem_i_accept_o
|
||||
,output mem_i_valid_o
|
||||
,output mem_i_error_o
|
||||
,output [ 31:0] mem_i_inst_o
|
||||
,output [ 31:0] mem_d_data_rd_o
|
||||
,output mem_d_accept_o
|
||||
,output mem_d_ack_o
|
||||
,output mem_d_error_o
|
||||
,output [ 10:0] mem_d_resp_tag_o
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Dual Port RAM
|
||||
//-------------------------------------------------------------
|
||||
wire [31:0] data_r_w;
|
||||
|
||||
tcm_mem_ram
|
||||
u_ram
|
||||
(
|
||||
// Instruction fetch
|
||||
.clk0_i(clk_i)
|
||||
,.rst0_i(rst_i)
|
||||
,.addr0_i(mem_i_pc_i[15:2])
|
||||
,.data0_i(32'b0)
|
||||
,.wr0_i(4'b0)
|
||||
|
||||
// External access / Data access
|
||||
,.clk1_i(clk_i)
|
||||
,.rst1_i(rst_i)
|
||||
,.addr1_i(mem_d_addr_i[15:2])
|
||||
,.data1_i(mem_d_data_wr_i)
|
||||
,.wr1_i(mem_d_wr_i)
|
||||
|
||||
// Outputs
|
||||
,.data0_o(mem_i_inst_o)
|
||||
,.data1_o(data_r_w)
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Instruction Fetch
|
||||
//-------------------------------------------------------------
|
||||
reg mem_i_valid_q;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
mem_i_valid_q <= 1'b0;
|
||||
else
|
||||
mem_i_valid_q <= mem_i_rd_i;
|
||||
|
||||
assign mem_i_accept_o = 1'b1;
|
||||
assign mem_i_valid_o = mem_i_valid_q;
|
||||
assign mem_i_error_o = 1'b0;
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Data Access / Incoming external access
|
||||
//-------------------------------------------------------------
|
||||
reg mem_d_accept_q;
|
||||
reg mem_d_ack_q;
|
||||
reg [10:0] mem_d_tag_q;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
mem_d_ack_q <= 1'b0;
|
||||
mem_d_tag_q <= 11'b0;
|
||||
end
|
||||
else if ((mem_d_rd_i || mem_d_wr_i != 4'b0 || mem_d_flush_i || mem_d_invalidate_i || mem_d_writeback_i) && mem_d_accept_o)
|
||||
begin
|
||||
mem_d_ack_q <= 1'b1;
|
||||
mem_d_tag_q <= mem_d_req_tag_i;
|
||||
end
|
||||
else
|
||||
mem_d_ack_q <= 1'b0;
|
||||
|
||||
assign mem_d_ack_o = mem_d_ack_q;
|
||||
assign mem_d_resp_tag_o = mem_d_tag_q;
|
||||
assign mem_d_data_rd_o = data_r_w;
|
||||
assign mem_d_error_o = 1'b0;
|
||||
|
||||
assign mem_d_accept_o = 1'b1;
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// write: Write byte into memory
|
||||
//-------------------------------------------------------------
|
||||
task write; /*verilator public*/
|
||||
input [31:0] addr;
|
||||
input [7:0] data;
|
||||
begin
|
||||
case (addr[1:0])
|
||||
2'd0: u_ram.ram[addr/4][7:0] = data;
|
||||
2'd1: u_ram.ram[addr/4][15:8] = data;
|
||||
2'd2: u_ram.ram[addr/4][23:16] = data;
|
||||
2'd3: u_ram.ram[addr/4][31:24] = data;
|
||||
endcase
|
||||
end
|
||||
endtask
|
||||
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
module tcm_mem_ram
|
||||
(
|
||||
// Inputs
|
||||
input clk0_i
|
||||
,input rst0_i
|
||||
,input [ 13:0] addr0_i
|
||||
,input [ 31:0] data0_i
|
||||
,input [ 3:0] wr0_i
|
||||
,input clk1_i
|
||||
,input rst1_i
|
||||
,input [ 13:0] addr1_i
|
||||
,input [ 31:0] data1_i
|
||||
,input [ 3:0] wr1_i
|
||||
|
||||
// Outputs
|
||||
,output [ 31:0] data0_o
|
||||
,output [ 31:0] data1_o
|
||||
);
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Dual Port RAM 64KB
|
||||
// Mode: Read First
|
||||
//-----------------------------------------------------------------
|
||||
/* verilator lint_off MULTIDRIVEN */
|
||||
reg [31:0] ram [16383:0] /*verilator public*/;
|
||||
/* verilator lint_on MULTIDRIVEN */
|
||||
|
||||
reg [31:0] ram_read0_q;
|
||||
reg [31:0] ram_read1_q;
|
||||
|
||||
|
||||
// Synchronous write
|
||||
always @ (posedge clk0_i)
|
||||
begin
|
||||
if (wr0_i[0])
|
||||
ram[addr0_i][7:0] <= data0_i[7:0];
|
||||
if (wr0_i[1])
|
||||
ram[addr0_i][15:8] <= data0_i[15:8];
|
||||
if (wr0_i[2])
|
||||
ram[addr0_i][23:16] <= data0_i[23:16];
|
||||
if (wr0_i[3])
|
||||
ram[addr0_i][31:24] <= data0_i[31:24];
|
||||
|
||||
ram_read0_q <= ram[addr0_i];
|
||||
end
|
||||
|
||||
always @ (posedge clk1_i)
|
||||
begin
|
||||
if (wr1_i[0])
|
||||
ram[addr1_i][7:0] <= data1_i[7:0];
|
||||
if (wr1_i[1])
|
||||
ram[addr1_i][15:8] <= data1_i[15:8];
|
||||
if (wr1_i[2])
|
||||
ram[addr1_i][23:16] <= data1_i[23:16];
|
||||
if (wr1_i[3])
|
||||
ram[addr1_i][31:24] <= data1_i[31:24];
|
||||
|
||||
ram_read1_q <= ram[addr1_i];
|
||||
end
|
||||
|
||||
assign data0_o = ram_read0_q;
|
||||
assign data1_o = ram_read1_q;
|
||||
|
||||
|
||||
|
||||
endmodule
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,924 @@
|
|||
//-----------------------------------------------------------------
|
||||
// uRISC-V CPU
|
||||
// V0.5.0
|
||||
// github.com/ultraembedded/core_uriscv
|
||||
// Copyright 2015-2021
|
||||
//
|
||||
// admin@ultra-embedded.com
|
||||
//
|
||||
// License: Apache 2.0
|
||||
//-----------------------------------------------------------------
|
||||
// Copyright 2015-2021 github.com/ultraembedded
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the 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.
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
module riscv_core
|
||||
//-----------------------------------------------------------------
|
||||
// Params
|
||||
//-----------------------------------------------------------------
|
||||
#(
|
||||
parameter SUPPORT_MUL = 1
|
||||
,parameter SUPPORT_DIV = 1
|
||||
,parameter SUPPORT_CSR = 1
|
||||
,parameter SUPPORT_TRAP_LSU_ALIGN = 1
|
||||
,parameter SUPPORT_MTVEC = 0
|
||||
,parameter SUPPORT_MTVAL = 0
|
||||
,parameter SUPPORT_MIP_MIE = 0
|
||||
,parameter SUPPORT_MSCRATCH = 0
|
||||
,parameter SUPPORT_MCYCLE = 1
|
||||
,parameter SUPPORT_MTIMECMP = 0
|
||||
,parameter SUPPORT_TRAP_INVALID_OPC = 1
|
||||
,parameter SUPPORT_BRAM_REGFILE = 0
|
||||
,parameter ISR_VECTOR = 32'h00000010
|
||||
)
|
||||
//-----------------------------------------------------------------
|
||||
// Ports
|
||||
//-----------------------------------------------------------------
|
||||
(
|
||||
// Clock
|
||||
input clk_i
|
||||
|
||||
// Reset (active high)
|
||||
,input rst_i
|
||||
|
||||
// External interrupt (M_EXT)
|
||||
,input intr_i
|
||||
|
||||
// Initial boot address
|
||||
,input [ 31:0] reset_vector_i
|
||||
|
||||
// MHARTID value
|
||||
,input [ 31:0] cpu_id_i
|
||||
|
||||
// Instruction Fetch
|
||||
,output mem_i_rd_o
|
||||
,output [ 31:0] mem_i_pc_o
|
||||
,input mem_i_accept_i
|
||||
,input mem_i_valid_i
|
||||
,input [ 31:0] mem_i_inst_i
|
||||
|
||||
// Instruction fetch: Unused on this core
|
||||
,output mem_i_flush_o
|
||||
,output mem_i_invalidate_o
|
||||
|
||||
// Instruction fetch: Unused (tie low)
|
||||
,input mem_i_error_i
|
||||
|
||||
// Data Access
|
||||
,output [ 31:0] mem_d_addr_o
|
||||
,output [ 31:0] mem_d_data_wr_o
|
||||
,output mem_d_rd_o
|
||||
,output [ 3:0] mem_d_wr_o
|
||||
,input [ 31:0] mem_d_data_rd_i
|
||||
,input mem_d_accept_i
|
||||
,input mem_d_ack_i
|
||||
|
||||
// Instruction fetch: Unused on this core
|
||||
,output mem_d_cacheable_o
|
||||
,output [ 10:0] mem_d_req_tag_o
|
||||
,output mem_d_invalidate_o
|
||||
,output mem_d_writeback_o
|
||||
,output mem_d_flush_o
|
||||
|
||||
// Data Access: Unused (tie low)
|
||||
,input mem_d_error_i
|
||||
,input [ 10:0] mem_d_resp_tag_i
|
||||
);
|
||||
|
||||
|
||||
|
||||
`include "uriscv_defs.v"
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Params
|
||||
//-----------------------------------------------------------------
|
||||
`define PC_W 32
|
||||
`define ADDR_W 32
|
||||
|
||||
localparam PC_W = `PC_W;
|
||||
localparam PC_PAD_W = 0;
|
||||
localparam PC_EXT_W = 0;
|
||||
|
||||
localparam ADDR_W = `ADDR_W;
|
||||
localparam ADDR_PAD_W = 0;
|
||||
|
||||
// Current state
|
||||
localparam STATE_W = 3;
|
||||
localparam STATE_RESET = 0;
|
||||
localparam STATE_FETCH_WB = 1;
|
||||
localparam STATE_EXEC = 2;
|
||||
localparam STATE_MEM = 3;
|
||||
localparam STATE_DECODE = 4; // Only if SUPPORT_BRAM_REGFILE = 1
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Registers
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
// Current state
|
||||
reg [STATE_W-1:0] state_q;
|
||||
|
||||
// Executing PC
|
||||
reg [PC_W-1:0] pc_q;
|
||||
|
||||
// Destination register
|
||||
reg [4:0] rd_q;
|
||||
|
||||
// Destination writeback enable
|
||||
reg rd_wr_en_q;
|
||||
|
||||
// ALU inputs
|
||||
reg [31:0] alu_a_q;
|
||||
reg [31:0] alu_b_q;
|
||||
|
||||
// ALU operation selection
|
||||
reg [3:0] alu_func_q;
|
||||
|
||||
// CSR read data
|
||||
wire [31:0] csr_data_w;
|
||||
|
||||
// Instruction decode fault
|
||||
reg invalid_inst_r;
|
||||
|
||||
// Register indexes
|
||||
wire [4:0] rd_w;
|
||||
wire [4:0] rs1_w;
|
||||
wire [4:0] rs2_w;
|
||||
|
||||
// Operand values
|
||||
wire [31:0] rs1_val_w;
|
||||
wire [31:0] rs2_val_w;
|
||||
|
||||
// Opcode (memory bus)
|
||||
wire [31:0] opcode_w;
|
||||
|
||||
wire opcode_valid_w;
|
||||
wire opcode_fetch_w = mem_i_rd_o & mem_i_accept_i;
|
||||
|
||||
// Execute exception (or interrupt)
|
||||
wire exception_w;
|
||||
wire [5:0] exception_type_w;
|
||||
wire [31:0] exception_target_w;
|
||||
|
||||
wire [31:0] csr_mepc_w;
|
||||
|
||||
// Load result (formatted based on load type)
|
||||
reg [31:0] load_result_r;
|
||||
|
||||
// Writeback enable / value
|
||||
wire rd_writeen_w;
|
||||
wire [31:0] rd_val_w;
|
||||
|
||||
// Memory interface
|
||||
wire mem_misaligned_w;
|
||||
reg [ADDR_W-1:0] mem_addr_q;
|
||||
reg [31:0] mem_data_q;
|
||||
reg [3:0] mem_wr_q;
|
||||
reg mem_rd_q;
|
||||
|
||||
// Load type / byte / half index
|
||||
reg [1:0] load_offset_q;
|
||||
reg load_signed_q;
|
||||
reg load_byte_q;
|
||||
reg load_half_q;
|
||||
|
||||
wire enable_w = 1'b1;
|
||||
|
||||
wire [31:0] muldiv_result_w;
|
||||
wire muldiv_ready_w;
|
||||
wire muldiv_inst_w;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ALU
|
||||
//-----------------------------------------------------------------
|
||||
uriscv_alu alu
|
||||
(
|
||||
// ALU operation select
|
||||
.op_i(alu_func_q),
|
||||
|
||||
// Operands
|
||||
.a_i(alu_a_q),
|
||||
.b_i(alu_b_q),
|
||||
|
||||
// Result
|
||||
.p_o(rd_val_w)
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Register file
|
||||
//-----------------------------------------------------------------
|
||||
reg [31:0] reg_file[0:31];
|
||||
|
||||
always @ (posedge clk_i)
|
||||
if (rd_writeen_w)
|
||||
reg_file[rd_q] <= rd_val_w;
|
||||
|
||||
wire [31:0] rs1_val_gpr_w = reg_file[mem_i_inst_i[19:15]];
|
||||
wire [31:0] rs2_val_gpr_w = reg_file[mem_i_inst_i[24:20]];
|
||||
|
||||
reg [31:0] rs1_val_gpr_q;
|
||||
reg [31:0] rs2_val_gpr_q;
|
||||
|
||||
always @ (posedge clk_i)
|
||||
begin
|
||||
rs1_val_gpr_q <= rs1_val_gpr_w;
|
||||
rs2_val_gpr_q <= rs2_val_gpr_w;
|
||||
end
|
||||
|
||||
assign rs1_val_w = SUPPORT_BRAM_REGFILE ? rs1_val_gpr_q : rs1_val_gpr_w;
|
||||
assign rs2_val_w = SUPPORT_BRAM_REGFILE ? rs2_val_gpr_q : rs2_val_gpr_w;
|
||||
|
||||
// Writeback enable
|
||||
assign rd_writeen_w = rd_wr_en_q & (state_q == STATE_FETCH_WB);
|
||||
|
||||
|
||||
`ifdef verilator
|
||||
`define HAS_REGFILE_WIRES
|
||||
`endif
|
||||
`ifdef verilog_sim
|
||||
`define HAS_REGFILE_WIRES
|
||||
`endif
|
||||
|
||||
// Simulation friendly names
|
||||
`ifdef HAS_REGFILE_WIRES
|
||||
wire [31:0] x0_zero_w = reg_file[0];
|
||||
wire [31:0] x1_ra_w = reg_file[1];
|
||||
wire [31:0] x2_sp_w = reg_file[2];
|
||||
wire [31:0] x3_gp_w = reg_file[3];
|
||||
wire [31:0] x4_tp_w = reg_file[4];
|
||||
wire [31:0] x5_t0_w = reg_file[5];
|
||||
wire [31:0] x6_t1_w = reg_file[6];
|
||||
wire [31:0] x7_t2_w = reg_file[7];
|
||||
wire [31:0] x8_s0_w = reg_file[8];
|
||||
wire [31:0] x9_s1_w = reg_file[9];
|
||||
wire [31:0] x10_a0_w = reg_file[10];
|
||||
wire [31:0] x11_a1_w = reg_file[11];
|
||||
wire [31:0] x12_a2_w = reg_file[12];
|
||||
wire [31:0] x13_a3_w = reg_file[13];
|
||||
wire [31:0] x14_a4_w = reg_file[14];
|
||||
wire [31:0] x15_a5_w = reg_file[15];
|
||||
wire [31:0] x16_a6_w = reg_file[16];
|
||||
wire [31:0] x17_a7_w = reg_file[17];
|
||||
wire [31:0] x18_s2_w = reg_file[18];
|
||||
wire [31:0] x19_s3_w = reg_file[19];
|
||||
wire [31:0] x20_s4_w = reg_file[20];
|
||||
wire [31:0] x21_s5_w = reg_file[21];
|
||||
wire [31:0] x22_s6_w = reg_file[22];
|
||||
wire [31:0] x23_s7_w = reg_file[23];
|
||||
wire [31:0] x24_s8_w = reg_file[24];
|
||||
wire [31:0] x25_s9_w = reg_file[25];
|
||||
wire [31:0] x26_s10_w = reg_file[26];
|
||||
wire [31:0] x27_s11_w = reg_file[27];
|
||||
wire [31:0] x28_t3_w = reg_file[28];
|
||||
wire [31:0] x29_t4_w = reg_file[29];
|
||||
wire [31:0] x30_t5_w = reg_file[30];
|
||||
wire [31:0] x31_t6_w = reg_file[31];
|
||||
`endif
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Next State Logic
|
||||
//-----------------------------------------------------------------
|
||||
reg [STATE_W-1:0] next_state_r;
|
||||
always @ *
|
||||
begin
|
||||
next_state_r = state_q;
|
||||
|
||||
case (state_q)
|
||||
// RESET - First cycle after reset
|
||||
STATE_RESET:
|
||||
begin
|
||||
next_state_r = STATE_FETCH_WB;
|
||||
end
|
||||
// FETCH_WB - Writeback / Fetch next isn
|
||||
STATE_FETCH_WB :
|
||||
begin
|
||||
if (opcode_fetch_w)
|
||||
next_state_r = SUPPORT_BRAM_REGFILE ? STATE_DECODE : STATE_EXEC;
|
||||
end
|
||||
// DECODE - Used to access register file if SUPPORT_BRAM_REGFILE=1
|
||||
STATE_DECODE:
|
||||
begin
|
||||
if (mem_i_valid_i)
|
||||
next_state_r = STATE_EXEC;
|
||||
end
|
||||
// EXEC - Execute instruction (when ready)
|
||||
STATE_EXEC :
|
||||
begin
|
||||
// Instruction ready
|
||||
if (opcode_valid_w)
|
||||
begin
|
||||
if (exception_w)
|
||||
next_state_r = STATE_FETCH_WB;
|
||||
else if (type_load_w || type_store_w)
|
||||
next_state_r = STATE_MEM;
|
||||
// Multiplication / division - stay in exec state until result ready
|
||||
else if (muldiv_inst_w)
|
||||
;
|
||||
else
|
||||
next_state_r = STATE_FETCH_WB;
|
||||
end
|
||||
else if (muldiv_ready_w)
|
||||
next_state_r = STATE_FETCH_WB;
|
||||
end
|
||||
// MEM - Perform load or store
|
||||
STATE_MEM :
|
||||
begin
|
||||
// Memory access complete
|
||||
if (mem_d_ack_i)
|
||||
next_state_r = STATE_FETCH_WB;
|
||||
end
|
||||
default:
|
||||
;
|
||||
endcase
|
||||
|
||||
if (!enable_w)
|
||||
next_state_r = STATE_RESET;
|
||||
end
|
||||
|
||||
// Update state
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
state_q <= STATE_RESET;
|
||||
else
|
||||
state_q <= next_state_r;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Instruction Decode
|
||||
//-----------------------------------------------------------------
|
||||
reg [31:0] opcode_q;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
opcode_q <= 32'b0;
|
||||
else if (state_q == STATE_DECODE)
|
||||
opcode_q <= mem_i_inst_i;
|
||||
|
||||
reg opcode_valid_q;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
opcode_valid_q <= 1'b0;
|
||||
else if (state_q == STATE_DECODE)
|
||||
opcode_valid_q <= mem_i_valid_i;
|
||||
else
|
||||
opcode_valid_q <= 1'b0;
|
||||
|
||||
assign opcode_w = SUPPORT_BRAM_REGFILE ? opcode_q : mem_i_inst_i;
|
||||
assign opcode_valid_w = SUPPORT_BRAM_REGFILE ? opcode_valid_q : mem_i_valid_i;
|
||||
|
||||
assign rs1_w = opcode_w[19:15];
|
||||
assign rs2_w = opcode_w[24:20];
|
||||
assign rd_w = opcode_w[11:7];
|
||||
|
||||
wire type_rvc_w = (opcode_w[1:0] != 2'b11);
|
||||
|
||||
wire type_load_w = (opcode_w[6:2] == 5'b00000);
|
||||
wire type_opimm_w = (opcode_w[6:2] == 5'b00100);
|
||||
wire type_auipc_w = (opcode_w[6:2] == 5'b00101);
|
||||
wire type_store_w = (opcode_w[6:2] == 5'b01000);
|
||||
wire type_op_w = (opcode_w[6:2] == 5'b01100);
|
||||
wire type_lui_w = (opcode_w[6:2] == 5'b01101);
|
||||
wire type_branch_w = (opcode_w[6:2] == 5'b11000);
|
||||
wire type_jalr_w = (opcode_w[6:2] == 5'b11001);
|
||||
wire type_jal_w = (opcode_w[6:2] == 5'b11011);
|
||||
wire type_system_w = (opcode_w[6:2] == 5'b11100);
|
||||
wire type_miscm_w = (opcode_w[6:2] == 5'b00011);
|
||||
|
||||
wire [2:0] func3_w = opcode_w[14:12]; // R, I, S
|
||||
wire [6:0] func7_w = opcode_w[31:25]; // R
|
||||
|
||||
// ALU operations excluding mul/div
|
||||
wire type_alu_op_w = (type_op_w && (func7_w == 7'b0000000)) ||
|
||||
(type_op_w && (func7_w == 7'b0100000));
|
||||
|
||||
// Loose decoding - gate with type_load_w on use
|
||||
wire inst_lb_w = (func3_w == 3'b000);
|
||||
wire inst_lh_w = (func3_w == 3'b001);
|
||||
wire inst_lbu_w = (func3_w == 3'b100);
|
||||
wire inst_lhu_w = (func3_w == 3'b101);
|
||||
|
||||
wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h000000);
|
||||
wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h002000);
|
||||
wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h604000);
|
||||
|
||||
wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100);
|
||||
|
||||
wire mul_inst_w = SUPPORT_MUL && type_op_w && (func7_w == 7'b0000001) && ~func3_w[2];
|
||||
wire div_inst_w = SUPPORT_DIV && type_op_w && (func7_w == 7'b0000001) && func3_w[2];
|
||||
wire inst_mul_w = mul_inst_w && (func3_w == 3'b000);
|
||||
wire inst_mulh_w = mul_inst_w && (func3_w == 3'b001);
|
||||
wire inst_mulhsu_w = mul_inst_w && (func3_w == 3'b010);
|
||||
wire inst_mulhu_w = mul_inst_w && (func3_w == 3'b011);
|
||||
wire inst_div_w = div_inst_w && (func3_w == 3'b100);
|
||||
wire inst_divu_w = div_inst_w && (func3_w == 3'b101);
|
||||
wire inst_rem_w = div_inst_w && (func3_w == 3'b110);
|
||||
wire inst_remu_w = div_inst_w && (func3_w == 3'b111);
|
||||
wire inst_nop_w = (type_miscm_w && (func3_w == 3'b000)) | // fence
|
||||
(type_miscm_w && (func3_w == 3'b001)); // fence.i
|
||||
|
||||
assign muldiv_inst_w = mul_inst_w | div_inst_w;
|
||||
|
||||
reg [31:0] imm20_r;
|
||||
reg [31:0] imm12_r;
|
||||
|
||||
always @ *
|
||||
begin
|
||||
imm20_r = {opcode_w[31:12], 12'b0};
|
||||
imm12_r = {{20{opcode_w[31]}}, opcode_w[31:20]};
|
||||
end
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ALU inputs
|
||||
//-----------------------------------------------------------------
|
||||
// ALU operation selection
|
||||
reg [3:0] alu_func_r;
|
||||
|
||||
// ALU operands
|
||||
reg [31:0] alu_input_a_r;
|
||||
reg [31:0] alu_input_b_r;
|
||||
reg write_rd_r;
|
||||
|
||||
always @ *
|
||||
begin
|
||||
alu_func_r = `RV_ALU_NONE;
|
||||
alu_input_a_r = rs1_val_w;
|
||||
alu_input_b_r = rs2_val_w;
|
||||
write_rd_r = 1'b0;
|
||||
|
||||
case (1'b1)
|
||||
type_alu_op_w:
|
||||
begin
|
||||
alu_input_a_r = rs1_val_w;
|
||||
alu_input_b_r = rs2_val_w;
|
||||
end
|
||||
type_opimm_w:
|
||||
begin
|
||||
alu_input_a_r = rs1_val_w;
|
||||
alu_input_b_r = imm12_r;
|
||||
end
|
||||
type_lui_w:
|
||||
begin
|
||||
alu_input_a_r = 32'b0;
|
||||
alu_input_b_r = imm20_r;
|
||||
end
|
||||
type_auipc_w:
|
||||
begin
|
||||
alu_input_a_r[PC_W-1:0] = pc_q;
|
||||
alu_input_b_r = imm20_r;
|
||||
end
|
||||
type_jal_w,
|
||||
type_jalr_w:
|
||||
begin
|
||||
alu_input_a_r[PC_W-1:0] = pc_q;
|
||||
alu_input_b_r = 32'd4;
|
||||
end
|
||||
default : ;
|
||||
endcase
|
||||
|
||||
if (muldiv_inst_w)
|
||||
write_rd_r = 1'b1;
|
||||
else if (type_opimm_w || type_alu_op_w)
|
||||
begin
|
||||
case (func3_w)
|
||||
3'b000: alu_func_r = (type_op_w & opcode_w[30]) ?
|
||||
`RV_ALU_SUB: // SUB
|
||||
`RV_ALU_ADD; // ADD / ADDI
|
||||
3'b001: alu_func_r = `RV_ALU_SHIFTL; // SLL / SLLI
|
||||
3'b010: alu_func_r = `RV_ALU_LESS_THAN_SIGNED; // SLT / SLTI
|
||||
3'b011: alu_func_r = `RV_ALU_LESS_THAN; // SLTU / SLTIU
|
||||
3'b100: alu_func_r = `RV_ALU_XOR; // XOR / XORI
|
||||
3'b101: alu_func_r = opcode_w[30] ?
|
||||
`RV_ALU_SHIFTR_ARITH: // SRA / SRAI
|
||||
`RV_ALU_SHIFTR; // SRL / SRLI
|
||||
3'b110: alu_func_r = `RV_ALU_OR; // OR / ORI
|
||||
3'b111: alu_func_r = `RV_ALU_AND; // AND / ANDI
|
||||
endcase
|
||||
|
||||
write_rd_r = 1'b1;
|
||||
end
|
||||
else if (inst_csr_w)
|
||||
begin
|
||||
alu_func_r = `RV_ALU_ADD;
|
||||
alu_input_a_r = 32'b0;
|
||||
alu_input_b_r = csr_data_w;
|
||||
write_rd_r = 1'b1;
|
||||
end
|
||||
else if (type_auipc_w || type_lui_w || type_jalr_w || type_jal_w)
|
||||
begin
|
||||
write_rd_r = 1'b1;
|
||||
alu_func_r = `RV_ALU_ADD;
|
||||
end
|
||||
else if (type_load_w)
|
||||
write_rd_r = 1'b1;
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Load result resolve
|
||||
//-------------------------------------------------------------------
|
||||
always @ *
|
||||
begin
|
||||
load_result_r = 32'b0;
|
||||
|
||||
if (load_byte_q)
|
||||
begin
|
||||
case (load_offset_q[1:0])
|
||||
2'h3:
|
||||
load_result_r = {24'b0, mem_d_data_rd_i[31:24]};
|
||||
2'h2:
|
||||
load_result_r = {24'b0, mem_d_data_rd_i[23:16]};
|
||||
2'h1:
|
||||
load_result_r = {24'b0, mem_d_data_rd_i[15:8]};
|
||||
2'h0:
|
||||
load_result_r = {24'b0, mem_d_data_rd_i[7:0]};
|
||||
endcase
|
||||
|
||||
if (load_signed_q && load_result_r[7])
|
||||
load_result_r = {24'hFFFFFF, load_result_r[7:0]};
|
||||
end
|
||||
else if (load_half_q)
|
||||
begin
|
||||
if (load_offset_q[1])
|
||||
load_result_r = {16'b0, mem_d_data_rd_i[31:16]};
|
||||
else
|
||||
load_result_r = {16'b0, mem_d_data_rd_i[15:0]};
|
||||
|
||||
if (load_signed_q && load_result_r[15])
|
||||
load_result_r = {16'hFFFF, load_result_r[15:0]};
|
||||
end
|
||||
else
|
||||
load_result_r = mem_d_data_rd_i;
|
||||
end
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Branches
|
||||
//-----------------------------------------------------------------
|
||||
wire branch_w;
|
||||
wire [31:0] branch_target_w;
|
||||
wire [31:0] pc_ext_w = {{PC_EXT_W{1'b0}}, pc_q};
|
||||
|
||||
uriscv_branch
|
||||
u_branch
|
||||
(
|
||||
.pc_i(pc_ext_w)
|
||||
,.opcode_i(opcode_w)
|
||||
,.rs1_val_i(rs1_val_w)
|
||||
,.rs2_val_i(rs2_val_w)
|
||||
,.branch_o(branch_w)
|
||||
,.branch_target_o(branch_target_w)
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Invalid instruction
|
||||
//-----------------------------------------------------------------
|
||||
always @ *
|
||||
begin
|
||||
invalid_inst_r = SUPPORT_TRAP_INVALID_OPC;
|
||||
|
||||
if ( type_load_w
|
||||
| type_opimm_w
|
||||
| type_auipc_w
|
||||
| type_store_w
|
||||
| type_alu_op_w
|
||||
| type_lui_w
|
||||
| type_branch_w
|
||||
| type_jalr_w
|
||||
| type_jal_w
|
||||
| inst_ecall_w
|
||||
| inst_ebreak_w
|
||||
| inst_mret_w
|
||||
| inst_csr_w
|
||||
| inst_nop_w
|
||||
| muldiv_inst_w)
|
||||
invalid_inst_r = SUPPORT_TRAP_INVALID_OPC && type_rvc_w;
|
||||
end
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Execute: ALU control
|
||||
//-----------------------------------------------------------------
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
alu_func_q <= `RV_ALU_NONE;
|
||||
alu_a_q <= 32'h00000000;
|
||||
alu_b_q <= 32'h00000000;
|
||||
rd_q <= 5'b00000;
|
||||
|
||||
// Reset x0 in-case of RAM
|
||||
rd_wr_en_q <= 1'b1;
|
||||
end
|
||||
// Load result ready
|
||||
else if ((state_q == STATE_MEM) && mem_d_ack_i)
|
||||
begin
|
||||
// Update ALU input with load result
|
||||
alu_func_q <= `RV_ALU_NONE;
|
||||
alu_a_q <= load_result_r;
|
||||
alu_b_q <= 32'b0;
|
||||
end
|
||||
// Multiplier / Divider result
|
||||
else if (muldiv_ready_w)
|
||||
begin
|
||||
// Update ALU input with load result
|
||||
alu_func_q <= `RV_ALU_NONE;
|
||||
alu_a_q <= muldiv_result_w;
|
||||
alu_b_q <= 32'b0;
|
||||
end
|
||||
// Execute instruction
|
||||
else if (opcode_valid_w)
|
||||
begin
|
||||
// Update ALU input flops
|
||||
alu_func_q <= alu_func_r;
|
||||
alu_a_q <= alu_input_a_r;
|
||||
alu_b_q <= alu_input_b_r;
|
||||
|
||||
// Take exception
|
||||
if (exception_w)
|
||||
begin
|
||||
// No register writeback
|
||||
rd_q <= 5'b0;
|
||||
rd_wr_en_q <= 1'b0;
|
||||
end
|
||||
// Valid instruction
|
||||
else
|
||||
begin
|
||||
// Instruction with register writeback
|
||||
rd_q <= rd_w;
|
||||
rd_wr_en_q <= write_rd_r & (rd_w != 5'b0);
|
||||
end
|
||||
end
|
||||
else if (state_q == STATE_FETCH_WB)
|
||||
rd_wr_en_q <= 1'b0;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Execute: Branch / exceptions
|
||||
//-----------------------------------------------------------------
|
||||
wire [31:0] boot_vector_w = reset_vector_i;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
pc_q <= boot_vector_w[PC_W-1:0];
|
||||
else if (state_q == STATE_RESET)
|
||||
pc_q <= boot_vector_w[PC_W-1:0];
|
||||
else if (opcode_valid_w)
|
||||
begin
|
||||
// Exception / Break / ecall (branch to ISR)
|
||||
if (exception_w || inst_ebreak_w || inst_ecall_w)
|
||||
pc_q <= exception_target_w[PC_W-1:0];
|
||||
// MRET (branch to EPC)
|
||||
else if (inst_mret_w)
|
||||
pc_q <= csr_mepc_w;
|
||||
// Branch
|
||||
else if (branch_w)
|
||||
pc_q <= branch_target_w[PC_W-1:0];
|
||||
else
|
||||
pc_q <= pc_q + `PC_W'd4;
|
||||
end
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Writeback/Fetch: Instruction Fetch
|
||||
//-----------------------------------------------------------------
|
||||
assign mem_i_rd_o = (state_q == STATE_FETCH_WB);
|
||||
assign mem_i_pc_o = pc_ext_w;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Execute: Memory operations
|
||||
//-----------------------------------------------------------------
|
||||
wire mem_rd_w;
|
||||
wire [3:0] mem_wr_w;
|
||||
wire [31:0] mem_addr_w;
|
||||
wire [31:0] mem_data_w;
|
||||
|
||||
uriscv_lsu
|
||||
#( .SUPPORT_TRAP_LSU_ALIGN(SUPPORT_TRAP_LSU_ALIGN) )
|
||||
u_lsu
|
||||
(
|
||||
.opcode_i(opcode_w)
|
||||
,.rs1_val_i(rs1_val_w)
|
||||
,.rs2_val_i(rs2_val_w)
|
||||
|
||||
,.mem_rd_o(mem_rd_w)
|
||||
,.mem_wr_o(mem_wr_w)
|
||||
,.mem_addr_o(mem_addr_w)
|
||||
,.mem_data_o(mem_data_w)
|
||||
,.mem_misaligned_o(mem_misaligned_w)
|
||||
);
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
mem_addr_q <= {ADDR_W{1'b0}};
|
||||
mem_data_q <= 32'h00000000;
|
||||
mem_wr_q <= 4'b0000;
|
||||
mem_rd_q <= 1'b0;
|
||||
end
|
||||
// Valid instruction to execute
|
||||
else if (opcode_valid_w && !exception_w)
|
||||
begin
|
||||
mem_addr_q <= {mem_addr_w[ADDR_W-1:2], 2'b0};
|
||||
mem_data_q <= mem_data_w;
|
||||
mem_wr_q <= mem_wr_w;
|
||||
mem_rd_q <= mem_rd_w;
|
||||
end
|
||||
// No instruction, clear memory request
|
||||
else if (mem_d_accept_i)
|
||||
begin
|
||||
mem_wr_q <= 4'b0000;
|
||||
mem_rd_q <= 1'b0;
|
||||
end
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
load_signed_q <= 1'b0;
|
||||
load_byte_q <= 1'b0;
|
||||
load_half_q <= 1'b0;
|
||||
load_offset_q <= 2'b0;
|
||||
end
|
||||
// Valid instruction to execute
|
||||
else if (opcode_valid_w)
|
||||
begin
|
||||
load_signed_q <= inst_lh_w | inst_lb_w;
|
||||
load_byte_q <= inst_lb_w | inst_lbu_w;
|
||||
load_half_q <= inst_lh_w | inst_lhu_w;
|
||||
load_offset_q <= mem_addr_w[1:0];
|
||||
end
|
||||
|
||||
assign mem_d_addr_o = {{ADDR_PAD_W{1'b0}}, mem_addr_q};
|
||||
assign mem_d_data_wr_o = mem_data_q;
|
||||
assign mem_d_wr_o = mem_wr_q;
|
||||
assign mem_d_rd_o = mem_rd_q;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Execute: CSR Access
|
||||
//-----------------------------------------------------------------
|
||||
uriscv_csr
|
||||
#(
|
||||
.SUPPORT_CSR(SUPPORT_CSR)
|
||||
,.SUPPORT_MCYCLE(SUPPORT_MCYCLE)
|
||||
,.SUPPORT_MTIMECMP(SUPPORT_MTIMECMP)
|
||||
,.SUPPORT_MSCRATCH(SUPPORT_MSCRATCH)
|
||||
,.SUPPORT_MIP_MIE(SUPPORT_MIP_MIE)
|
||||
,.SUPPORT_MTVEC(SUPPORT_MTVEC)
|
||||
,.SUPPORT_MTVAL(SUPPORT_MTVAL)
|
||||
,.SUPPORT_MULDIV(SUPPORT_MUL || SUPPORT_DIV)
|
||||
)
|
||||
u_csr
|
||||
(
|
||||
.clk_i(clk_i)
|
||||
,.rst_i(rst_i)
|
||||
|
||||
// Reset vector (only used if SUPPORT_MTVEC=0)
|
||||
,.isr_vector_i(reset_vector_i + ISR_VECTOR)
|
||||
|
||||
// HartID
|
||||
,.cpu_id_i(cpu_id_i)
|
||||
|
||||
// External interrupt
|
||||
,.intr_i(intr_i)
|
||||
|
||||
// Executing instruction
|
||||
,.valid_i(opcode_valid_w)
|
||||
,.opcode_i(opcode_w)
|
||||
,.pc_i(pc_q)
|
||||
,.rs1_val_i(rs1_val_w)
|
||||
,.rs2_val_i(rs2_val_w)
|
||||
|
||||
// CSR read result
|
||||
,.csr_rdata_o(csr_data_w)
|
||||
|
||||
// Exception sources
|
||||
,.excpn_invalid_inst_i(invalid_inst_r)
|
||||
,.excpn_lsu_align_i(mem_misaligned_w)
|
||||
|
||||
// Used on memory alignment errors
|
||||
,.mem_addr_i(mem_addr_w)
|
||||
|
||||
// CSR registers
|
||||
,.csr_mepc_o(csr_mepc_w)
|
||||
|
||||
// Exception entry
|
||||
,.exception_o(exception_w)
|
||||
,.exception_type_o(exception_type_w)
|
||||
,.exception_pc_o(exception_target_w)
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Multiplier / Divider
|
||||
//-----------------------------------------------------------------
|
||||
generate
|
||||
if (SUPPORT_MUL != 0 || SUPPORT_DIV != 0)
|
||||
begin
|
||||
uriscv_muldiv
|
||||
u_muldiv
|
||||
(
|
||||
.clk_i(clk_i),
|
||||
.rst_i(rst_i),
|
||||
|
||||
// Operation select
|
||||
.valid_i(opcode_valid_w & ~exception_w),
|
||||
.inst_mul_i(inst_mul_w),
|
||||
.inst_mulh_i(inst_mulh_w),
|
||||
.inst_mulhsu_i(inst_mulhsu_w),
|
||||
.inst_mulhu_i(inst_mulhu_w),
|
||||
.inst_div_i(inst_div_w),
|
||||
.inst_divu_i(inst_divu_w),
|
||||
.inst_rem_i(inst_rem_w),
|
||||
.inst_remu_i(inst_remu_w),
|
||||
|
||||
// Operands
|
||||
.operand_ra_i(rs1_val_w),
|
||||
.operand_rb_i(rs2_val_w),
|
||||
|
||||
// Result
|
||||
.stall_o(),
|
||||
.ready_o(muldiv_ready_w),
|
||||
.result_o(muldiv_result_w)
|
||||
);
|
||||
end
|
||||
else
|
||||
begin
|
||||
assign muldiv_ready_w = 1'b0;
|
||||
assign muldiv_result_w = 32'b0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Unused
|
||||
//-----------------------------------------------------------------
|
||||
assign mem_i_flush_o = 1'b0;
|
||||
assign mem_i_invalidate_o = 1'b0;
|
||||
|
||||
assign mem_d_flush_o = 1'b0;
|
||||
assign mem_d_cacheable_o = 1'b0;
|
||||
assign mem_d_req_tag_o = 11'b0;
|
||||
assign mem_d_invalidate_o = 1'b0;
|
||||
assign mem_d_writeback_o = 1'b0;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Hooks for debug
|
||||
//-------------------------------------------------------------------
|
||||
`ifdef verilator
|
||||
reg v_dbg_valid_q;
|
||||
reg [31:0] v_dbg_pc_q;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
v_dbg_valid_q <= 1'b0;
|
||||
v_dbg_pc_q <= 32'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
v_dbg_valid_q <= opcode_valid_w;
|
||||
v_dbg_pc_q <= pc_ext_w;
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// get_valid: Instruction valid
|
||||
//-------------------------------------------------------------------
|
||||
function [0:0] get_valid; /*verilator public*/
|
||||
begin
|
||||
get_valid = v_dbg_valid_q;
|
||||
end
|
||||
endfunction
|
||||
//-------------------------------------------------------------------
|
||||
// get_pc: Get executed instruction PC
|
||||
//-------------------------------------------------------------------
|
||||
function [31:0] get_pc; /*verilator public*/
|
||||
begin
|
||||
get_pc = v_dbg_pc_q;
|
||||
end
|
||||
endfunction
|
||||
//-------------------------------------------------------------------
|
||||
// get_reg_valid: Register contents valid
|
||||
//-------------------------------------------------------------------
|
||||
function [0:0] get_reg_valid; /*verilator public*/
|
||||
input [4:0] r;
|
||||
begin
|
||||
get_reg_valid = opcode_valid_w;
|
||||
end
|
||||
endfunction
|
||||
//-------------------------------------------------------------------
|
||||
// get_register: Read register file
|
||||
//-------------------------------------------------------------------
|
||||
function [31:0] get_register; /*verilator public*/
|
||||
input [4:0] r;
|
||||
begin
|
||||
get_register = reg_file[r];
|
||||
end
|
||||
endfunction
|
||||
`endif
|
||||
|
||||
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,182 @@
|
|||
//-----------------------------------------------------------------
|
||||
// uRISC-V CPU
|
||||
// V0.5.0
|
||||
// github.com/ultraembedded/core_uriscv
|
||||
// Copyright 2015-2021
|
||||
//
|
||||
// admin@ultra-embedded.com
|
||||
//
|
||||
// License: Apache 2.0
|
||||
//-----------------------------------------------------------------
|
||||
// Copyright 2015-2021 github.com/ultraembedded
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the 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.
|
||||
//-----------------------------------------------------------------
|
||||
module uriscv_alu
|
||||
(
|
||||
// ALU operation select
|
||||
input [3:0] op_i,
|
||||
|
||||
// Operands
|
||||
input [31:0] a_i,
|
||||
input [31:0] b_i,
|
||||
|
||||
// Result
|
||||
output [31:0] p_o
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------
|
||||
`include "uriscv_defs.v"
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Registers
|
||||
//-----------------------------------------------------------------
|
||||
reg [31:0] result_r;
|
||||
|
||||
reg [31:16] shift_right_fill_r;
|
||||
reg [31:0] shift_right_1_r;
|
||||
reg [31:0] shift_right_2_r;
|
||||
reg [31:0] shift_right_4_r;
|
||||
reg [31:0] shift_right_8_r;
|
||||
|
||||
reg [31:0] shift_left_1_r;
|
||||
reg [31:0] shift_left_2_r;
|
||||
reg [31:0] shift_left_4_r;
|
||||
reg [31:0] shift_left_8_r;
|
||||
|
||||
wire [31:0] sub_res_w = a_i - b_i;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// ALU
|
||||
//-----------------------------------------------------------------
|
||||
always @ *
|
||||
begin
|
||||
case (op_i)
|
||||
//----------------------------------------------
|
||||
// Shift Left
|
||||
//----------------------------------------------
|
||||
`RV_ALU_SHIFTL :
|
||||
begin
|
||||
if (b_i[0] == 1'b1)
|
||||
shift_left_1_r = {a_i[30:0],1'b0};
|
||||
else
|
||||
shift_left_1_r = a_i;
|
||||
|
||||
if (b_i[1] == 1'b1)
|
||||
shift_left_2_r = {shift_left_1_r[29:0],2'b00};
|
||||
else
|
||||
shift_left_2_r = shift_left_1_r;
|
||||
|
||||
if (b_i[2] == 1'b1)
|
||||
shift_left_4_r = {shift_left_2_r[27:0],4'b0000};
|
||||
else
|
||||
shift_left_4_r = shift_left_2_r;
|
||||
|
||||
if (b_i[3] == 1'b1)
|
||||
shift_left_8_r = {shift_left_4_r[23:0],8'b00000000};
|
||||
else
|
||||
shift_left_8_r = shift_left_4_r;
|
||||
|
||||
if (b_i[4] == 1'b1)
|
||||
result_r = {shift_left_8_r[15:0],16'b0000000000000000};
|
||||
else
|
||||
result_r = shift_left_8_r;
|
||||
end
|
||||
//----------------------------------------------
|
||||
// Shift Right
|
||||
//----------------------------------------------
|
||||
`RV_ALU_SHIFTR, `RV_ALU_SHIFTR_ARITH:
|
||||
begin
|
||||
// Arithmetic shift? Fill with 1's if MSB set
|
||||
if (a_i[31] == 1'b1 && op_i == `RV_ALU_SHIFTR_ARITH)
|
||||
shift_right_fill_r = 16'b1111111111111111;
|
||||
else
|
||||
shift_right_fill_r = 16'b0000000000000000;
|
||||
|
||||
if (b_i[0] == 1'b1)
|
||||
shift_right_1_r = {shift_right_fill_r[31], a_i[31:1]};
|
||||
else
|
||||
shift_right_1_r = a_i;
|
||||
|
||||
if (b_i[1] == 1'b1)
|
||||
shift_right_2_r = {shift_right_fill_r[31:30], shift_right_1_r[31:2]};
|
||||
else
|
||||
shift_right_2_r = shift_right_1_r;
|
||||
|
||||
if (b_i[2] == 1'b1)
|
||||
shift_right_4_r = {shift_right_fill_r[31:28], shift_right_2_r[31:4]};
|
||||
else
|
||||
shift_right_4_r = shift_right_2_r;
|
||||
|
||||
if (b_i[3] == 1'b1)
|
||||
shift_right_8_r = {shift_right_fill_r[31:24], shift_right_4_r[31:8]};
|
||||
else
|
||||
shift_right_8_r = shift_right_4_r;
|
||||
|
||||
if (b_i[4] == 1'b1)
|
||||
result_r = {shift_right_fill_r[31:16], shift_right_8_r[31:16]};
|
||||
else
|
||||
result_r = shift_right_8_r;
|
||||
end
|
||||
//----------------------------------------------
|
||||
// Arithmetic
|
||||
//----------------------------------------------
|
||||
`RV_ALU_ADD :
|
||||
begin
|
||||
result_r = (a_i + b_i);
|
||||
end
|
||||
`RV_ALU_SUB :
|
||||
begin
|
||||
result_r = sub_res_w;
|
||||
end
|
||||
//----------------------------------------------
|
||||
// Logical
|
||||
//----------------------------------------------
|
||||
`RV_ALU_AND :
|
||||
begin
|
||||
result_r = (a_i & b_i);
|
||||
end
|
||||
`RV_ALU_OR :
|
||||
begin
|
||||
result_r = (a_i | b_i);
|
||||
end
|
||||
`RV_ALU_XOR :
|
||||
begin
|
||||
result_r = (a_i ^ b_i);
|
||||
end
|
||||
//----------------------------------------------
|
||||
// Comparision
|
||||
//----------------------------------------------
|
||||
`RV_ALU_LESS_THAN :
|
||||
begin
|
||||
result_r = (a_i < b_i) ? 32'h1 : 32'h0;
|
||||
end
|
||||
`RV_ALU_LESS_THAN_SIGNED :
|
||||
begin
|
||||
if (a_i[31] != b_i[31])
|
||||
result_r = a_i[31] ? 32'h1 : 32'h0;
|
||||
else
|
||||
result_r = sub_res_w[31] ? 32'h1 : 32'h0;
|
||||
end
|
||||
default :
|
||||
begin
|
||||
result_r = a_i;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign p_o = result_r;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,153 @@
|
|||
//-----------------------------------------------------------------
|
||||
// uRISC-V CPU
|
||||
// V0.5.0
|
||||
// github.com/ultraembedded/core_uriscv
|
||||
// Copyright 2015-2021
|
||||
//
|
||||
// admin@ultra-embedded.com
|
||||
//
|
||||
// License: Apache 2.0
|
||||
//-----------------------------------------------------------------
|
||||
// Copyright 2015-2021 github.com/ultraembedded
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the 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.
|
||||
//-----------------------------------------------------------------
|
||||
module uriscv_branch
|
||||
(
|
||||
input [31:0] pc_i
|
||||
,input [31:0] opcode_i
|
||||
,input [31:0] rs1_val_i
|
||||
,input [31:0] rs2_val_i
|
||||
,output branch_o
|
||||
,output [31:0] branch_target_o
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------
|
||||
`include "uriscv_defs.v"
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// less_than_signed: Less than operator (signed)
|
||||
// Inputs: x = left operand, y = right operand
|
||||
// Return: (int)x < (int)y
|
||||
//-----------------------------------------------------------------
|
||||
function [0:0] less_than_signed;
|
||||
input [31:0] x;
|
||||
input [31:0] y;
|
||||
reg [31:0] v;
|
||||
begin
|
||||
v = (x - y);
|
||||
if (x[31] != y[31])
|
||||
less_than_signed = x[31];
|
||||
else
|
||||
less_than_signed = v[31];
|
||||
end
|
||||
endfunction
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// greater_than_signed: Greater than operator (signed)
|
||||
// Inputs: x = left operand, y = right operand
|
||||
// Return: (int)x > (int)y
|
||||
//-----------------------------------------------------------------
|
||||
function [0:0] greater_than_signed;
|
||||
input [31:0] x;
|
||||
input [31:0] y;
|
||||
reg [31:0] v;
|
||||
begin
|
||||
v = (y - x);
|
||||
if (x[31] != y[31])
|
||||
greater_than_signed = y[31];
|
||||
else
|
||||
greater_than_signed = v[31];
|
||||
end
|
||||
endfunction
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Branch Decode
|
||||
//-----------------------------------------------------------------
|
||||
wire type_branch_w = (opcode_i[6:2] == 5'b11000);
|
||||
wire type_jalr_w = (opcode_i[6:2] == 5'b11001);
|
||||
wire type_jal_w = (opcode_i[6:2] == 5'b11011);
|
||||
|
||||
wire [2:0] func3_w = opcode_i[14:12]; // R, I, S
|
||||
wire [6:0] func7_w = opcode_i[31:25]; // R
|
||||
|
||||
wire branch_beq_w = (func3_w == 3'b000);
|
||||
wire branch_bne_w = (func3_w == 3'b001);
|
||||
wire branch_blt_w = (func3_w == 3'b100);
|
||||
wire branch_bge_w = (func3_w == 3'b101);
|
||||
wire branch_bltu_w = (func3_w == 3'b110);
|
||||
wire branch_bgeu_w = (func3_w == 3'b111);
|
||||
|
||||
reg branch_r;
|
||||
reg [31:0] branch_target_r;
|
||||
reg [31:0] imm12_r;
|
||||
reg [31:0] bimm_r;
|
||||
reg [31:0] jimm20_r;
|
||||
|
||||
always @ *
|
||||
begin
|
||||
branch_r = 1'b0;
|
||||
branch_target_r = 32'b0;
|
||||
|
||||
// Opcode decode
|
||||
imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]};
|
||||
bimm_r = {{19{opcode_i[31]}}, opcode_i[31], opcode_i[7], opcode_i[30:25], opcode_i[11:8], 1'b0};
|
||||
jimm20_r = {{12{opcode_i[31]}}, opcode_i[19:12], opcode_i[20], opcode_i[30:25], opcode_i[24:21], 1'b0};
|
||||
|
||||
// Default branch target is relative to current PC
|
||||
branch_target_r = (pc_i + bimm_r);
|
||||
|
||||
if (type_jal_w)
|
||||
begin
|
||||
branch_r = 1'b1;
|
||||
branch_target_r = pc_i + jimm20_r;
|
||||
end
|
||||
else if (type_jalr_w)
|
||||
begin
|
||||
branch_r = 1'b1;
|
||||
branch_target_r = rs1_val_i + imm12_r;
|
||||
branch_target_r[0] = 1'b0;
|
||||
end
|
||||
else if (type_branch_w)
|
||||
begin
|
||||
case (1'b1)
|
||||
branch_beq_w: // beq
|
||||
branch_r = (rs1_val_i == rs2_val_i);
|
||||
|
||||
branch_bne_w: // bne
|
||||
branch_r = (rs1_val_i != rs2_val_i);
|
||||
|
||||
branch_blt_w: // blt
|
||||
branch_r = less_than_signed(rs1_val_i, rs2_val_i);
|
||||
|
||||
branch_bge_w: // bge
|
||||
branch_r = greater_than_signed(rs1_val_i, rs2_val_i) | (rs1_val_i == rs2_val_i);
|
||||
|
||||
branch_bltu_w: // bltu
|
||||
branch_r = (rs1_val_i < rs2_val_i);
|
||||
|
||||
branch_bgeu_w: // bgeu
|
||||
branch_r = (rs1_val_i >= rs2_val_i);
|
||||
|
||||
default:
|
||||
;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign branch_o = branch_r;
|
||||
assign branch_target_o = branch_target_r;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,416 @@
|
|||
//-----------------------------------------------------------------
|
||||
// uRISC-V CPU
|
||||
// V0.5.0
|
||||
// github.com/ultraembedded/core_uriscv
|
||||
// Copyright 2015-2021
|
||||
//
|
||||
// admin@ultra-embedded.com
|
||||
//
|
||||
// License: Apache 2.0
|
||||
//-----------------------------------------------------------------
|
||||
// Copyright 2015-2021 github.com/ultraembedded
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the 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.
|
||||
//-----------------------------------------------------------------
|
||||
module uriscv_csr
|
||||
//-----------------------------------------------------------------
|
||||
// Params
|
||||
//-----------------------------------------------------------------
|
||||
#(
|
||||
parameter SUPPORT_CSR = 1
|
||||
,parameter SUPPORT_MCYCLE = 1
|
||||
,parameter SUPPORT_MTIMECMP = 1
|
||||
,parameter SUPPORT_MSCRATCH = 1
|
||||
,parameter SUPPORT_MIP_MIE = 1
|
||||
,parameter SUPPORT_MTVEC = 1
|
||||
,parameter SUPPORT_MTVAL = 1
|
||||
,parameter SUPPORT_MULDIV = 1
|
||||
)
|
||||
//-----------------------------------------------------------------
|
||||
// Ports
|
||||
//-----------------------------------------------------------------
|
||||
(
|
||||
input clk_i
|
||||
,input rst_i
|
||||
|
||||
,input intr_i
|
||||
,input [31:0] isr_vector_i
|
||||
|
||||
,input [31:0] cpu_id_i
|
||||
|
||||
,input valid_i
|
||||
,input [31:0] pc_i
|
||||
,input [31:0] opcode_i
|
||||
,input [31:0] rs1_val_i
|
||||
,input [31:0] rs2_val_i
|
||||
,output [31:0] csr_rdata_o
|
||||
|
||||
,input excpn_invalid_inst_i
|
||||
,input excpn_lsu_align_i
|
||||
|
||||
,input [31:0] mem_addr_i
|
||||
|
||||
,output [31:0] csr_mepc_o
|
||||
|
||||
,output exception_o
|
||||
,output [5:0] exception_type_o
|
||||
,output [31:0] exception_pc_o
|
||||
);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------
|
||||
`include "uriscv_defs.v"
|
||||
|
||||
wire take_interrupt_w;
|
||||
wire exception_w;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Instruction Decode
|
||||
//-----------------------------------------------------------------
|
||||
wire [2:0] func3_w = opcode_i[14:12]; // R, I, S
|
||||
wire [4:0] rs1_w = opcode_i[19:15];
|
||||
wire [4:0] rs2_w = opcode_i[24:20];
|
||||
wire [4:0] rd_w = opcode_i[11:7];
|
||||
|
||||
wire type_system_w = (opcode_i[6:2] == 5'b11100);
|
||||
wire type_store_w = (opcode_i[6:2] == 5'b01000);
|
||||
|
||||
wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100);
|
||||
wire inst_csrrw_w = inst_csr_w && (func3_w == 3'b001);
|
||||
wire inst_csrrs_w = inst_csr_w && (func3_w == 3'b010);
|
||||
wire inst_csrrc_w = inst_csr_w && (func3_w == 3'b011);
|
||||
wire inst_csrrwi_w = inst_csr_w && (func3_w == 3'b101);
|
||||
wire inst_csrrsi_w = inst_csr_w && (func3_w == 3'b110);
|
||||
wire inst_csrrci_w = inst_csr_w && (func3_w == 3'b111);
|
||||
|
||||
wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h000000);
|
||||
wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h002000);
|
||||
wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h604000);
|
||||
|
||||
wire [11:0] csr_addr_w = valid_i ? opcode_i[31:20] : 12'b0;
|
||||
wire [31:0] csr_data_w = (inst_csrrwi_w || inst_csrrsi_w || inst_csrrci_w) ? {27'b0, rs1_w} : rs1_val_i;
|
||||
wire csr_set_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrs_w || inst_csrrwi_w || inst_csrrsi_w): 1'b0;
|
||||
wire csr_clr_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrc_w || inst_csrrwi_w || inst_csrrci_w): 1'b0;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Execute: CSR Access
|
||||
//-----------------------------------------------------------------
|
||||
reg [31:0] csr_mepc_q;
|
||||
reg [31:0] csr_mepc_r;
|
||||
reg [31:0] csr_mcause_q;
|
||||
reg [31:0] csr_mcause_r;
|
||||
reg [31:0] csr_sr_q;
|
||||
reg [31:0] csr_sr_r;
|
||||
reg [31:0] csr_mcycle_q;
|
||||
reg [31:0] csr_mcycle_r;
|
||||
reg [31:0] csr_mtimecmp_q;
|
||||
reg [31:0] csr_mtimecmp_r;
|
||||
reg [31:0] csr_mscratch_q;
|
||||
reg [31:0] csr_mscratch_r;
|
||||
reg [31:0] csr_mip_q;
|
||||
reg [31:0] csr_mip_r;
|
||||
reg [31:0] csr_mie_q;
|
||||
reg [31:0] csr_mie_r;
|
||||
reg [31:0] csr_mtvec_q;
|
||||
reg [31:0] csr_mtvec_r;
|
||||
reg [31:0] csr_mtval_q;
|
||||
reg [31:0] csr_mtval_r;
|
||||
|
||||
always @ *
|
||||
begin
|
||||
csr_mepc_r = csr_mepc_q;
|
||||
csr_mcause_r = csr_mcause_q;
|
||||
csr_sr_r = csr_sr_q;
|
||||
|
||||
csr_mcycle_r = csr_mcycle_q + 32'd1;
|
||||
csr_mtimecmp_r = csr_mtimecmp_q;
|
||||
csr_mscratch_r = csr_mscratch_q;
|
||||
csr_mip_r = csr_mip_q;
|
||||
csr_mie_r = csr_mie_q;
|
||||
csr_mtvec_r = csr_mtvec_q;
|
||||
csr_mtval_r = csr_mtval_q;
|
||||
|
||||
// External interrupt
|
||||
if (intr_i)
|
||||
csr_mip_r[`IRQ_M_EXT] = 1'b1;
|
||||
|
||||
// Timer match - generate IRQ
|
||||
if (SUPPORT_MTIMECMP && csr_mcycle_r == csr_mtimecmp_r)
|
||||
csr_mip_r[`SR_IP_MTIP_R] = 1'b1;
|
||||
|
||||
// Execute instruction / exception
|
||||
if (valid_i)
|
||||
begin
|
||||
// Exception / break / ecall
|
||||
if (exception_w || inst_ebreak_w || inst_ecall_w)
|
||||
begin
|
||||
// Save interrupt / supervisor state
|
||||
csr_sr_r[`SR_MPIE_R] = csr_sr_q[`SR_MIE_R];
|
||||
csr_sr_r[`SR_MPP_R] = `PRIV_MACHINE;
|
||||
|
||||
// Disable interrupts and enter supervisor mode
|
||||
csr_sr_r[`SR_MIE_R] = 1'b0;
|
||||
|
||||
// Save PC of next instruction (not yet executed)
|
||||
csr_mepc_r = pc_i;
|
||||
|
||||
// Extra info (badaddr / fault opcode)
|
||||
csr_mtval_r = 32'b0;
|
||||
|
||||
// Exception source
|
||||
if (excpn_invalid_inst_i)
|
||||
begin
|
||||
csr_mcause_r = `MCAUSE_ILLEGAL_INSTRUCTION;
|
||||
csr_mtval_r = opcode_i;
|
||||
end
|
||||
else if (inst_ebreak_w)
|
||||
csr_mcause_r = `MCAUSE_BREAKPOINT;
|
||||
else if (inst_ecall_w)
|
||||
csr_mcause_r = `MCAUSE_ECALL_M;
|
||||
else if (excpn_lsu_align_i)
|
||||
begin
|
||||
csr_mcause_r = type_store_w ? `MCAUSE_MISALIGNED_STORE : `MCAUSE_MISALIGNED_LOAD;
|
||||
csr_mtval_r = mem_addr_i;
|
||||
end
|
||||
else if (take_interrupt_w)
|
||||
csr_mcause_r = `MCAUSE_INTERRUPT;
|
||||
end
|
||||
// MRET
|
||||
else if (inst_mret_w)
|
||||
begin
|
||||
// Interrupt enable pop
|
||||
csr_sr_r[`SR_MIE_R] = csr_sr_r[`SR_MPIE_R];
|
||||
csr_sr_r[`SR_MPIE_R] = 1'b1;
|
||||
|
||||
// This CPU only supports machine mode
|
||||
csr_sr_r[`SR_MPP_R] = `PRIV_MACHINE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
case (csr_addr_w)
|
||||
`CSR_MEPC:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_mepc_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_mepc_r = csr_mepc_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_mepc_r = csr_mepc_r & ~csr_data_w;
|
||||
end
|
||||
`CSR_MCAUSE:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_mcause_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_mcause_r = csr_mcause_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_mcause_r = csr_mcause_r & ~csr_data_w;
|
||||
end
|
||||
`CSR_MSTATUS:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_sr_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_sr_r = csr_sr_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_sr_r = csr_sr_r & ~csr_data_w;
|
||||
end
|
||||
`CSR_MTIMECMP:
|
||||
begin
|
||||
if (SUPPORT_MTIMECMP && csr_set_w && csr_data_w != 32'b0)
|
||||
begin
|
||||
csr_mtimecmp_r = csr_data_w;
|
||||
|
||||
// Clear interrupt pending
|
||||
csr_mip_r[`SR_IP_MTIP_R] = 1'b0;
|
||||
end
|
||||
end
|
||||
`CSR_MSCRATCH:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_mscratch_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_mscratch_r = csr_mscratch_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_mscratch_r = csr_mscratch_r & ~csr_data_w;
|
||||
end
|
||||
`CSR_MIP:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_mip_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_mip_r = csr_mip_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_mip_r = csr_mip_r & ~csr_data_w;
|
||||
end
|
||||
`CSR_MIE:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_mie_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_mie_r = csr_mie_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_mie_r = csr_mie_r & ~csr_data_w;
|
||||
end
|
||||
`CSR_MTVEC:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_mtvec_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_mtvec_r = csr_mtvec_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_mtvec_r = csr_mtvec_r & ~csr_data_w;
|
||||
end
|
||||
`CSR_MTVAL:
|
||||
begin
|
||||
if (csr_set_w && csr_clr_w)
|
||||
csr_mtval_r = csr_data_w;
|
||||
else if (csr_set_w)
|
||||
csr_mtval_r = csr_mtval_r | csr_data_w;
|
||||
else if (csr_clr_w)
|
||||
csr_mtval_r = csr_mtval_r & ~csr_data_w;
|
||||
end
|
||||
default:
|
||||
;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef verilator
|
||||
`define HAS_SIM_CTRL
|
||||
`endif
|
||||
`ifdef verilog_sim
|
||||
`define HAS_SIM_CTRL
|
||||
`endif
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
csr_mepc_q <= 32'b0;
|
||||
csr_mcause_q <= 32'b0;
|
||||
csr_sr_q <= 32'b0;
|
||||
csr_mcycle_q <= 32'b0;
|
||||
csr_mtimecmp_q <= 32'b0;
|
||||
csr_mscratch_q <= 32'b0;
|
||||
csr_mie_q <= 32'b0;
|
||||
csr_mip_q <= 32'b0;
|
||||
csr_mtvec_q <= 32'b0;
|
||||
csr_mtval_q <= 32'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
csr_mepc_q <= csr_mepc_r;
|
||||
csr_mcause_q <= csr_mcause_r;
|
||||
csr_sr_q <= csr_sr_r;
|
||||
csr_mcycle_q <= SUPPORT_MCYCLE ? csr_mcycle_r : 32'b0;
|
||||
csr_mtimecmp_q <= SUPPORT_MTIMECMP ? csr_mtimecmp_r : 32'b0;
|
||||
csr_mscratch_q <= SUPPORT_MSCRATCH ? csr_mscratch_r : 32'b0;
|
||||
csr_mie_q <= SUPPORT_MIP_MIE ? csr_mie_r : 32'b0;
|
||||
csr_mip_q <= SUPPORT_MIP_MIE ? csr_mip_r : 32'b0;
|
||||
csr_mtvec_q <= SUPPORT_MTVEC ? csr_mtvec_r : 32'b0;
|
||||
csr_mtval_q <= SUPPORT_MTVAL ? csr_mtval_r : 32'b0;
|
||||
|
||||
`ifdef HAS_SIM_CTRL
|
||||
if (valid_i && (csr_addr_w == `CSR_DSCRATCH || csr_addr_w == `CSR_SIM_CTRL) && inst_csr_w)
|
||||
begin
|
||||
case (csr_data_w & 32'hFF000000)
|
||||
`CSR_SIM_CTRL_EXIT:
|
||||
begin
|
||||
$finish;
|
||||
$finish;
|
||||
end
|
||||
`CSR_SIM_CTRL_PUTC:
|
||||
begin
|
||||
$write("%c", csr_data_w[7:0]);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
`endif
|
||||
end
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// CSR Read Data MUX
|
||||
//-----------------------------------------------------------------
|
||||
reg [31:0] csr_data_r;
|
||||
|
||||
always @ *
|
||||
begin
|
||||
csr_data_r = 32'b0;
|
||||
|
||||
case (csr_addr_w)
|
||||
`CSR_MEPC: csr_data_r = csr_mepc_q & `CSR_MEPC_MASK;
|
||||
`CSR_MCAUSE: csr_data_r = csr_mcause_q & `CSR_MCAUSE_MASK;
|
||||
`CSR_MSTATUS: csr_data_r = csr_sr_q & `CSR_MSTATUS_MASK;
|
||||
`CSR_MTVEC: csr_data_r = csr_mtvec_q & `CSR_MTVEC_MASK;
|
||||
`CSR_MTVAL: csr_data_r = csr_mtval_q & `CSR_MTVAL_MASK;
|
||||
`CSR_MTIME,
|
||||
`CSR_MCYCLE: csr_data_r = csr_mcycle_q & `CSR_MTIME_MASK;
|
||||
`CSR_MTIMECMP: csr_data_r = csr_mtimecmp_q & `CSR_MTIMECMP_MASK;
|
||||
`CSR_MSCRATCH: csr_data_r = csr_mscratch_q & `CSR_MSCRATCH_MASK;
|
||||
`CSR_MIP: csr_data_r = csr_mip_q & `CSR_MIP_MASK;
|
||||
`CSR_MIE: csr_data_r = csr_mie_q & `CSR_MIE_MASK;
|
||||
`CSR_MISA: csr_data_r = (SUPPORT_MULDIV ? `MISA_RVM : 32'b0) |
|
||||
`MISA_RV32 | `MISA_RVI;
|
||||
`CSR_MHARTID: csr_data_r = cpu_id_i;
|
||||
default: csr_data_r = 32'b0;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign csr_rdata_o = csr_data_r;
|
||||
|
||||
// Interrupt request and interrupt enabled
|
||||
assign take_interrupt_w = SUPPORT_MIP_MIE ? ((|(csr_mip_q & csr_mie_q)) & csr_sr_q[`SR_MIE_R]) : (intr_i & csr_sr_q[`SR_MIE_R]);
|
||||
assign exception_w = valid_i && (take_interrupt_w || excpn_invalid_inst_i || (SUPPORT_CSR && excpn_lsu_align_i));
|
||||
|
||||
assign exception_o = exception_w;
|
||||
assign exception_pc_o = SUPPORT_MTVEC ? csr_mtvec_q :
|
||||
SUPPORT_CSR ? isr_vector_i :
|
||||
pc_i + 32'd4;
|
||||
assign csr_mepc_o = csr_mepc_q;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Debug - exception type (checker use only)
|
||||
//-----------------------------------------------------------------
|
||||
reg [5:0] v_etype_r;
|
||||
|
||||
always @ *
|
||||
begin
|
||||
v_etype_r = 6'b0;
|
||||
|
||||
if (csr_mcause_r[`MCAUSE_INT])
|
||||
v_etype_r = `RV_EXCPN_INTERRUPT;
|
||||
else case (csr_mcause_r)
|
||||
`MCAUSE_MISALIGNED_FETCH : v_etype_r = `RV_EXCPN_MISALIGNED_FETCH;
|
||||
`MCAUSE_FAULT_FETCH : v_etype_r = `RV_EXCPN_FAULT_FETCH;
|
||||
`MCAUSE_ILLEGAL_INSTRUCTION: v_etype_r = `RV_EXCPN_ILLEGAL_INSTRUCTION;
|
||||
`MCAUSE_BREAKPOINT : v_etype_r = `RV_EXCPN_BREAKPOINT;
|
||||
`MCAUSE_MISALIGNED_LOAD : v_etype_r = `RV_EXCPN_MISALIGNED_LOAD;
|
||||
`MCAUSE_FAULT_LOAD : v_etype_r = `RV_EXCPN_FAULT_LOAD;
|
||||
`MCAUSE_MISALIGNED_STORE : v_etype_r = `RV_EXCPN_MISALIGNED_STORE;
|
||||
`MCAUSE_FAULT_STORE : v_etype_r = `RV_EXCPN_FAULT_STORE;
|
||||
`MCAUSE_ECALL_U : v_etype_r = `RV_EXCPN_ECALL_U;
|
||||
`MCAUSE_ECALL_S : v_etype_r = `RV_EXCPN_ECALL_S;
|
||||
`MCAUSE_ECALL_H : v_etype_r = `RV_EXCPN_ECALL_H;
|
||||
`MCAUSE_ECALL_M : v_etype_r = `RV_EXCPN_ECALL_M;
|
||||
`MCAUSE_PAGE_FAULT_INST : v_etype_r = `RV_EXCPN_PAGE_FAULT_INST;
|
||||
`MCAUSE_PAGE_FAULT_LOAD : v_etype_r = `RV_EXCPN_PAGE_FAULT_LOAD;
|
||||
`MCAUSE_PAGE_FAULT_STORE : v_etype_r = `RV_EXCPN_PAGE_FAULT_STORE;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign exception_type_o = v_etype_r;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,200 @@
|
|||
//-----------------------------------------------------------------
|
||||
// uRISC-V CPU
|
||||
// V0.5.0
|
||||
// github.com/ultraembedded/core_uriscv
|
||||
// Copyright 2015-2021
|
||||
//
|
||||
// admin@ultra-embedded.com
|
||||
//
|
||||
// License: Apache 2.0
|
||||
//-----------------------------------------------------------------
|
||||
// Copyright 2015-2021 github.com/ultraembedded
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the 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.
|
||||
//-----------------------------------------------------------------
|
||||
//--------------------------------------------------------------------
|
||||
// ALU Operations
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
`define RV_ALU_NONE 4'b0000
|
||||
`define RV_ALU_SHIFTL 4'b0001
|
||||
`define RV_ALU_SHIFTR 4'b0010
|
||||
`define RV_ALU_SHIFTR_ARITH 4'b0011
|
||||
`define RV_ALU_ADD 4'b0100
|
||||
`define RV_ALU_SUB 4'b0110
|
||||
`define RV_ALU_AND 4'b0111
|
||||
`define RV_ALU_OR 4'b1000
|
||||
`define RV_ALU_XOR 4'b1001
|
||||
`define RV_ALU_LESS_THAN 4'b1010
|
||||
`define RV_ALU_LESS_THAN_SIGNED 4'b1011
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Privilege levels
|
||||
//-----------------------------------------------------------------
|
||||
`define PRIV_USER 0
|
||||
`define PRIV_SUPER 1
|
||||
`define PRIV_MACHINE 3
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Status Register
|
||||
//-----------------------------------------------------------------
|
||||
`define SR_UIE (1 << 0)
|
||||
`define SR_UIE_R 0
|
||||
`define SR_SIE (1 << 1)
|
||||
`define SR_SIE_R 1
|
||||
`define SR_MIE (1 << 3)
|
||||
`define SR_MIE_R 3
|
||||
`define SR_UPIE (1 << 4)
|
||||
`define SR_UPIE_R 4
|
||||
`define SR_SPIE (1 << 5)
|
||||
`define SR_SPIE_R 5
|
||||
`define SR_MPIE (1 << 7)
|
||||
`define SR_MPIE_R 7
|
||||
`define SR_SPP (1 << 8)
|
||||
`define SR_SPP_R 8
|
||||
|
||||
`define SR_MPP_SHIFT 11
|
||||
`define SR_MPP_MASK 2'h3
|
||||
`define SR_MPP_R 12:11
|
||||
`define SR_MPP_U `PRIV_USER
|
||||
`define SR_MPP_S `PRIV_SUPER
|
||||
`define SR_MPP_M `PRIV_MACHINE
|
||||
|
||||
`define SR_SUM (1 << 18)
|
||||
`define SR_SUM_R 18
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// IRQ Numbers
|
||||
//-----------------------------------------------------------------
|
||||
`define IRQ_S_SOFT 1
|
||||
`define IRQ_M_SOFT 3
|
||||
`define IRQ_S_TIMER 5
|
||||
`define IRQ_M_TIMER 7
|
||||
`define IRQ_S_EXT 9
|
||||
`define IRQ_M_EXT 11
|
||||
`define IRQ_MIN (`IRQ_S_SOFT)
|
||||
`define IRQ_MAX (`IRQ_M_EXT + 1)
|
||||
`define IRQ_MASK ((1 << `IRQ_M_EXT) | (1 << `IRQ_M_TIMER) | (1 << `IRQ_M_SOFT))
|
||||
|
||||
`define SR_IP_MSIP_R `IRQ_M_SOFT
|
||||
`define SR_IP_MTIP_R `IRQ_M_TIMER
|
||||
`define SR_IP_MEIP_R `IRQ_M_EXT
|
||||
`define SR_IP_SSIP_R `IRQ_S_SOFT
|
||||
`define SR_IP_STIP_R `IRQ_S_TIMER
|
||||
`define SR_IP_SEIP_R `IRQ_S_EXT
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// CSR Registers - Machine
|
||||
//-----------------------------------------------------------------
|
||||
`define CSR_MSTATUS 12'h300
|
||||
`define CSR_MSTATUS_MASK 32'hFFFFFFFF
|
||||
`define CSR_MISA 12'h301
|
||||
`define CSR_MISA_MASK 32'hFFFFFFFF
|
||||
`define MISA_RV32 32'h40000000
|
||||
`define MISA_RVI 32'h00000100
|
||||
`define MISA_RVE 32'h00000010
|
||||
`define MISA_RVM 32'h00001000
|
||||
`define MISA_RVA 32'h00000001
|
||||
`define MISA_RVF 32'h00000020
|
||||
`define MISA_RVD 32'h00000008
|
||||
`define MISA_RVC 32'h00000004
|
||||
`define MISA_RVS 32'h00040000
|
||||
`define MISA_RVU 32'h00100000
|
||||
`define CSR_MEDELEG 12'h302
|
||||
`define CSR_MEDELEG_MASK 32'h0000FFFF
|
||||
`define CSR_MIDELEG 12'h303
|
||||
`define CSR_MIDELEG_MASK 32'h0000FFFF
|
||||
`define CSR_MIE 12'h304
|
||||
`define CSR_MIE_MASK `IRQ_MASK
|
||||
`define CSR_MTVEC 12'h305
|
||||
`define CSR_MTVEC_MASK 32'hFFFFFFFF
|
||||
`define CSR_MSCRATCH 12'h340
|
||||
`define CSR_MSCRATCH_MASK 32'hFFFFFFFF
|
||||
`define CSR_MEPC 12'h341
|
||||
`define CSR_MEPC_MASK 32'hFFFFFFFF
|
||||
`define CSR_MCAUSE 12'h342
|
||||
`define CSR_MCAUSE_MASK 32'h8000000F
|
||||
`define CSR_MTVAL 12'h343
|
||||
`define CSR_MTVAL_MASK 32'hFFFFFFFF
|
||||
`define CSR_MIP 12'h344
|
||||
`define CSR_MIP_MASK `IRQ_MASK
|
||||
`define CSR_MCYCLE 12'hc00
|
||||
`define CSR_MCYCLE_MASK 32'hFFFFFFFF
|
||||
`define CSR_MTIME 12'hc01
|
||||
`define CSR_MTIME_MASK 32'hFFFFFFFF
|
||||
`define CSR_MTIMEH 12'hc81
|
||||
`define CSR_MTIMEH_MASK 32'hFFFFFFFF
|
||||
`define CSR_MHARTID 12'hF14
|
||||
`define CSR_MHARTID_MASK 32'hFFFFFFFF
|
||||
|
||||
// Non-std
|
||||
`define CSR_MTIMECMP 12'h7c0
|
||||
`define CSR_MTIMECMP_MASK 32'hFFFFFFFF
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// CSR Registers - Simulation control
|
||||
//-----------------------------------------------------------------
|
||||
`define CSR_DSCRATCH 12'h7b2
|
||||
`define CSR_DSCRATCH_MASK 32'hFFFFFFFF
|
||||
`define CSR_SIM_CTRL 12'h8b2
|
||||
`define CSR_SIM_CTRL_MASK 32'hFFFFFFFF
|
||||
`define CSR_SIM_CTRL_EXIT (0 << 24)
|
||||
`define CSR_SIM_CTRL_PUTC (1 << 24)
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Exception Causes
|
||||
//-----------------------------------------------------------------
|
||||
`define MCAUSE_INT 31
|
||||
`define MCAUSE_MISALIGNED_FETCH ((0 << `MCAUSE_INT) | 0)
|
||||
`define MCAUSE_FAULT_FETCH ((0 << `MCAUSE_INT) | 1)
|
||||
`define MCAUSE_ILLEGAL_INSTRUCTION ((0 << `MCAUSE_INT) | 2)
|
||||
`define MCAUSE_BREAKPOINT ((0 << `MCAUSE_INT) | 3)
|
||||
`define MCAUSE_MISALIGNED_LOAD ((0 << `MCAUSE_INT) | 4)
|
||||
`define MCAUSE_FAULT_LOAD ((0 << `MCAUSE_INT) | 5)
|
||||
`define MCAUSE_MISALIGNED_STORE ((0 << `MCAUSE_INT) | 6)
|
||||
`define MCAUSE_FAULT_STORE ((0 << `MCAUSE_INT) | 7)
|
||||
`define MCAUSE_ECALL_U ((0 << `MCAUSE_INT) | 8)
|
||||
`define MCAUSE_ECALL_S ((0 << `MCAUSE_INT) | 9)
|
||||
`define MCAUSE_ECALL_H ((0 << `MCAUSE_INT) | 10)
|
||||
`define MCAUSE_ECALL_M ((0 << `MCAUSE_INT) | 11)
|
||||
`define MCAUSE_PAGE_FAULT_INST ((0 << `MCAUSE_INT) | 12)
|
||||
`define MCAUSE_PAGE_FAULT_LOAD ((0 << `MCAUSE_INT) | 13)
|
||||
`define MCAUSE_PAGE_FAULT_STORE ((0 << `MCAUSE_INT) | 15)
|
||||
`define MCAUSE_INTERRUPT (1 << `MCAUSE_INT)
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Debug defines for exception types
|
||||
//-----------------------------------------------------------------
|
||||
`define RV_EXCPN_W 6
|
||||
`define RV_EXCPN_MISALIGNED_FETCH 6'h10
|
||||
`define RV_EXCPN_FAULT_FETCH 6'h11
|
||||
`define RV_EXCPN_ILLEGAL_INSTRUCTION 6'h12
|
||||
`define RV_EXCPN_BREAKPOINT 6'h13
|
||||
`define RV_EXCPN_MISALIGNED_LOAD 6'h14
|
||||
`define RV_EXCPN_FAULT_LOAD 6'h15
|
||||
`define RV_EXCPN_MISALIGNED_STORE 6'h16
|
||||
`define RV_EXCPN_FAULT_STORE 6'h17
|
||||
`define RV_EXCPN_ECALL 6'h18
|
||||
`define RV_EXCPN_ECALL_U 6'h18
|
||||
`define RV_EXCPN_ECALL_S 6'h19
|
||||
`define RV_EXCPN_ECALL_H 6'h1a
|
||||
`define RV_EXCPN_ECALL_M 6'h1b
|
||||
`define RV_EXCPN_PAGE_FAULT_INST 6'h1c
|
||||
`define RV_EXCPN_PAGE_FAULT_LOAD 6'h1d
|
||||
`define RV_EXCPN_PAGE_FAULT_STORE 6'h1f
|
||||
`define RV_EXCPN_EXCEPTION 6'h10
|
||||
`define RV_EXCPN_INTERRUPT 6'h20
|
||||
`define RV_EXCPN_ERET 6'h30
|
||||
`define RV_EXCPN_FENCE 6'h31
|
||||
`define RV_EXCPN_TYPE_MASK 6'h30
|
||||
`define RV_EXCPN_SUBTYPE_R 3:0
|
|
@ -0,0 +1,173 @@
|
|||
//-----------------------------------------------------------------
|
||||
// uRISC-V CPU
|
||||
// V0.5.0
|
||||
// github.com/ultraembedded/core_uriscv
|
||||
// Copyright 2015-2021
|
||||
//
|
||||
// admin@ultra-embedded.com
|
||||
//
|
||||
// License: Apache 2.0
|
||||
//-----------------------------------------------------------------
|
||||
// Copyright 2015-2021 github.com/ultraembedded
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the 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.
|
||||
//-----------------------------------------------------------------
|
||||
module uriscv_lsu
|
||||
//-----------------------------------------------------------------
|
||||
// Params
|
||||
//-----------------------------------------------------------------
|
||||
#(
|
||||
parameter SUPPORT_TRAP_LSU_ALIGN = 1
|
||||
)
|
||||
//-----------------------------------------------------------------
|
||||
// Ports
|
||||
//-----------------------------------------------------------------
|
||||
(
|
||||
input [31:0] opcode_i
|
||||
,input [31:0] rs1_val_i
|
||||
,input [31:0] rs2_val_i
|
||||
|
||||
,output mem_rd_o
|
||||
,output [3:0] mem_wr_o
|
||||
,output [31:0] mem_addr_o
|
||||
,output [31:0] mem_data_o
|
||||
,output mem_misaligned_o
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------
|
||||
`include "uriscv_defs.v"
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Instruction Decode
|
||||
//-----------------------------------------------------------------
|
||||
wire type_load_w = (opcode_i[6:2] == 5'b00000);
|
||||
wire type_store_w = (opcode_i[6:2] == 5'b01000);
|
||||
|
||||
wire [2:0] func3_w = opcode_i[14:12]; // R, I, S
|
||||
|
||||
wire inst_lb_w = type_load_w && (func3_w == 3'b000);
|
||||
wire inst_lh_w = type_load_w && (func3_w == 3'b001);
|
||||
wire inst_lw_w = type_load_w && (func3_w == 3'b010);
|
||||
wire inst_lbu_w = type_load_w && (func3_w == 3'b100);
|
||||
wire inst_lhu_w = type_load_w && (func3_w == 3'b101);
|
||||
wire inst_sb_w = type_store_w && (func3_w == 3'b000);
|
||||
wire inst_sh_w = type_store_w && (func3_w == 3'b001);
|
||||
wire inst_sw_w = type_store_w && (func3_w == 3'b010);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Decode LSU operation
|
||||
//-----------------------------------------------------------------
|
||||
reg [31:0] imm12_r;
|
||||
reg [31:0] storeimm_r;
|
||||
|
||||
reg [31:0] mem_addr_r;
|
||||
reg [31:0] mem_data_r;
|
||||
reg [3:0] mem_wr_r;
|
||||
reg mem_rd_r;
|
||||
reg mem_misaligned_r;
|
||||
|
||||
always @ *
|
||||
begin
|
||||
imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]};
|
||||
storeimm_r = {{20{opcode_i[31]}}, opcode_i[31:25], opcode_i[11:7]};
|
||||
|
||||
// Memory address
|
||||
mem_addr_r = rs1_val_i + (type_store_w ? storeimm_r : imm12_r);
|
||||
|
||||
if (SUPPORT_TRAP_LSU_ALIGN)
|
||||
mem_misaligned_r = (inst_lh_w | inst_lhu_w | inst_sh_w) ? mem_addr_r[0]:
|
||||
(inst_lw_w | inst_sw_w) ? (|mem_addr_r[1:0]):
|
||||
1'b0;
|
||||
else
|
||||
mem_misaligned_r = 1'b0;
|
||||
|
||||
mem_data_r = 32'h00000000;
|
||||
mem_wr_r = 4'b0000;
|
||||
mem_rd_r = 1'b0;
|
||||
|
||||
case (1'b1)
|
||||
|
||||
type_load_w:
|
||||
mem_rd_r = 1'b1;
|
||||
|
||||
inst_sb_w:
|
||||
begin
|
||||
case (mem_addr_r[1:0])
|
||||
2'h3 :
|
||||
begin
|
||||
mem_data_r = {rs2_val_i[7:0], 24'h000000};
|
||||
mem_wr_r = 4'b1000;
|
||||
mem_rd_r = 1'b0;
|
||||
end
|
||||
2'h2 :
|
||||
begin
|
||||
mem_data_r = {8'h00,rs2_val_i[7:0],16'h0000};
|
||||
mem_wr_r = 4'b0100;
|
||||
mem_rd_r = 1'b0;
|
||||
end
|
||||
2'h1 :
|
||||
begin
|
||||
mem_data_r = {16'h0000,rs2_val_i[7:0],8'h00};
|
||||
mem_wr_r = 4'b0010;
|
||||
mem_rd_r = 1'b0;
|
||||
end
|
||||
2'h0 :
|
||||
begin
|
||||
mem_data_r = {24'h000000,rs2_val_i[7:0]};
|
||||
mem_wr_r = 4'b0001;
|
||||
mem_rd_r = 1'b0;
|
||||
end
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
inst_sh_w:
|
||||
begin
|
||||
case (mem_addr_r[1:0])
|
||||
2'h2 :
|
||||
begin
|
||||
mem_data_r = {rs2_val_i[15:0],16'h0000};
|
||||
mem_wr_r = 4'b1100;
|
||||
mem_rd_r = 1'b0;
|
||||
end
|
||||
default :
|
||||
begin
|
||||
mem_data_r = {16'h0000,rs2_val_i[15:0]};
|
||||
mem_wr_r = 4'b0011;
|
||||
mem_rd_r = 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
inst_sw_w:
|
||||
begin
|
||||
mem_data_r = rs2_val_i;
|
||||
mem_wr_r = 4'b1111;
|
||||
mem_rd_r = 1'b0;
|
||||
end
|
||||
|
||||
// Non load / store
|
||||
default:
|
||||
;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign mem_rd_o = mem_rd_r;
|
||||
assign mem_wr_o = mem_wr_r;
|
||||
assign mem_addr_o = mem_addr_r;
|
||||
assign mem_data_o = mem_data_r;
|
||||
assign mem_misaligned_o = mem_misaligned_r;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,246 @@
|
|||
//-----------------------------------------------------------------
|
||||
// uRISC-V CPU
|
||||
// V0.5.0
|
||||
// github.com/ultraembedded/core_uriscv
|
||||
// Copyright 2015-2021
|
||||
//
|
||||
// admin@ultra-embedded.com
|
||||
//
|
||||
// License: Apache 2.0
|
||||
//-----------------------------------------------------------------
|
||||
// Copyright 2015-2021 github.com/ultraembedded
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the 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.
|
||||
//-----------------------------------------------------------------
|
||||
module uriscv_muldiv
|
||||
(
|
||||
input clk_i,
|
||||
input rst_i,
|
||||
|
||||
// Operation select
|
||||
input valid_i,
|
||||
input inst_mul_i,
|
||||
input inst_mulh_i,
|
||||
input inst_mulhsu_i,
|
||||
input inst_mulhu_i,
|
||||
input inst_div_i,
|
||||
input inst_divu_i,
|
||||
input inst_rem_i,
|
||||
input inst_remu_i,
|
||||
|
||||
// Operands
|
||||
input [31:0] operand_ra_i,
|
||||
input [31:0] operand_rb_i,
|
||||
|
||||
// Result
|
||||
output stall_o,
|
||||
output ready_o,
|
||||
output [31:0] result_o
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------
|
||||
`include "uriscv_defs.v"
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Multiplier
|
||||
//-------------------------------------------------------------
|
||||
reg [32:0] mul_operand_a_q;
|
||||
reg [32:0] mul_operand_b_q;
|
||||
reg mulhi_sel_q;
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Multiplier
|
||||
//-------------------------------------------------------------
|
||||
wire [64:0] mult_result_w;
|
||||
reg [32:0] operand_b_r;
|
||||
reg [32:0] operand_a_r;
|
||||
reg [31:0] mul_result_r;
|
||||
|
||||
wire mult_inst_w = inst_mul_i |
|
||||
inst_mulh_i |
|
||||
inst_mulhsu_i |
|
||||
inst_mulhu_i;
|
||||
|
||||
|
||||
always @ *
|
||||
begin
|
||||
if (inst_mulhsu_i)
|
||||
operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]};
|
||||
else if (inst_mulh_i)
|
||||
operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]};
|
||||
else // MULHU || MUL
|
||||
operand_a_r = {1'b0, operand_ra_i[31:0]};
|
||||
end
|
||||
|
||||
always @ *
|
||||
begin
|
||||
if (inst_mulhsu_i)
|
||||
operand_b_r = {1'b0, operand_rb_i[31:0]};
|
||||
else if (inst_mulh_i)
|
||||
operand_b_r = {operand_rb_i[31], operand_rb_i[31:0]};
|
||||
else // MULHU || MUL
|
||||
operand_b_r = {1'b0, operand_rb_i[31:0]};
|
||||
end
|
||||
|
||||
// Pipeline flops for multiplier
|
||||
always @(posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
mul_operand_a_q <= 33'b0;
|
||||
mul_operand_b_q <= 33'b0;
|
||||
mulhi_sel_q <= 1'b0;
|
||||
end
|
||||
else if (valid_i && mult_inst_w)
|
||||
begin
|
||||
mul_operand_a_q <= operand_a_r;
|
||||
mul_operand_b_q <= operand_b_r;
|
||||
mulhi_sel_q <= ~inst_mul_i;
|
||||
end
|
||||
else
|
||||
begin
|
||||
mul_operand_a_q <= 33'b0;
|
||||
mul_operand_b_q <= 33'b0;
|
||||
mulhi_sel_q <= 1'b0;
|
||||
end
|
||||
|
||||
assign mult_result_w = {{ 32 {mul_operand_a_q[32]}}, mul_operand_a_q}*{{ 32 {mul_operand_b_q[32]}}, mul_operand_b_q};
|
||||
|
||||
always @ *
|
||||
begin
|
||||
mul_result_r = mulhi_sel_q ? mult_result_w[63:32] : mult_result_w[31:0];
|
||||
end
|
||||
|
||||
reg mul_busy_q;
|
||||
|
||||
always @(posedge clk_i )
|
||||
if (rst_i)
|
||||
mul_busy_q <= 1'b0;
|
||||
else
|
||||
mul_busy_q <= valid_i & mult_inst_w;
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Divider
|
||||
//-------------------------------------------------------------
|
||||
wire div_rem_inst_w = inst_div_i ||
|
||||
inst_divu_i ||
|
||||
inst_rem_i ||
|
||||
inst_remu_i;
|
||||
|
||||
wire signed_operation_w = inst_div_i || inst_rem_i;
|
||||
wire div_operation_w = inst_div_i || inst_divu_i;
|
||||
|
||||
reg [31:0] dividend_q;
|
||||
reg [62:0] divisor_q;
|
||||
reg [31:0] quotient_q;
|
||||
reg [31:0] q_mask_q;
|
||||
reg div_inst_q;
|
||||
reg div_busy_q;
|
||||
reg invert_res_q;
|
||||
|
||||
wire div_start_w = valid_i & div_rem_inst_w & !stall_o;
|
||||
wire div_complete_w = !(|q_mask_q) & div_busy_q;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
begin
|
||||
div_busy_q <= 1'b0;
|
||||
dividend_q <= 32'b0;
|
||||
divisor_q <= 63'b0;
|
||||
invert_res_q <= 1'b0;
|
||||
quotient_q <= 32'b0;
|
||||
q_mask_q <= 32'b0;
|
||||
div_inst_q <= 1'b0;
|
||||
end
|
||||
else if (div_start_w)
|
||||
begin
|
||||
div_busy_q <= 1'b1;
|
||||
div_inst_q <= div_operation_w;
|
||||
|
||||
if (signed_operation_w && operand_ra_i[31])
|
||||
dividend_q <= -operand_ra_i;
|
||||
else
|
||||
dividend_q <= operand_ra_i;
|
||||
|
||||
if (signed_operation_w && operand_rb_i[31])
|
||||
divisor_q <= {-operand_rb_i, 31'b0};
|
||||
else
|
||||
divisor_q <= {operand_rb_i, 31'b0};
|
||||
|
||||
invert_res_q <= (inst_div_i && (operand_ra_i[31] != operand_rb_i[31]) && |operand_rb_i) ||
|
||||
(inst_rem_i && operand_ra_i[31]);
|
||||
|
||||
quotient_q <= 32'b0;
|
||||
q_mask_q <= 32'h80000000;
|
||||
end
|
||||
else if (div_complete_w)
|
||||
begin
|
||||
div_busy_q <= 1'b0;
|
||||
end
|
||||
else if (div_busy_q)
|
||||
begin
|
||||
if (divisor_q <= {31'b0, dividend_q})
|
||||
begin
|
||||
dividend_q <= dividend_q - divisor_q[31:0];
|
||||
quotient_q <= quotient_q | q_mask_q;
|
||||
end
|
||||
|
||||
divisor_q <= {1'b0, divisor_q[62:1]};
|
||||
q_mask_q <= {1'b0, q_mask_q[31:1]};
|
||||
end
|
||||
|
||||
reg [31:0] div_result_r;
|
||||
always @ *
|
||||
begin
|
||||
div_result_r = 32'b0;
|
||||
|
||||
if (div_inst_q)
|
||||
div_result_r = invert_res_q ? -quotient_q : quotient_q;
|
||||
else
|
||||
div_result_r = invert_res_q ? -dividend_q : dividend_q;
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Shared logic
|
||||
//-------------------------------------------------------------
|
||||
|
||||
// Stall if divider logic is busy and new multiplier or divider op
|
||||
assign stall_o = (div_busy_q & (mult_inst_w | div_rem_inst_w)) ||
|
||||
(mul_busy_q & div_rem_inst_w);
|
||||
|
||||
reg [31:0] result_q;
|
||||
reg ready_q;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
ready_q <= 1'b0;
|
||||
else if (mul_busy_q)
|
||||
ready_q <= 1'b1;
|
||||
else if (div_complete_w)
|
||||
ready_q <= 1'b1;
|
||||
else
|
||||
ready_q <= 1'b0;
|
||||
|
||||
always @ (posedge clk_i )
|
||||
if (rst_i)
|
||||
result_q <= 32'b0;
|
||||
else if (div_complete_w)
|
||||
result_q <= div_result_r;
|
||||
else if (mul_busy_q)
|
||||
result_q <= mul_result_r;
|
||||
|
||||
assign result_o = result_q;
|
||||
assign ready_o = ready_q;
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue