Compare commits

..

No commits in common. "main" and "1.3.0" have entirely different histories.
main ... 1.3.0

39 changed files with 230 additions and 861 deletions

View file

@ -14,7 +14,7 @@ jobs:
uses: actions/checkout@v4
with:
path: cores/serv/serv-src
- uses: YosysHQ/setup-oss-cad-suite@v3
- uses: YosysHQ/setup-oss-cad-suite@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare formal tests

View file

@ -2,23 +2,19 @@ name: Build GDS using OpenLANE and sky130 PDK
on: [push]
jobs:
build-openlane-sky130:
build-openlane:
runs-on: ubuntu-latest
env:
REPO : serv
VLNV : serv
steps:
- name: Checkout repo
- name: Checkout subservient
uses: actions/checkout@v4
- name: Build with Openlane
uses: librecores/ci-fusesoc-action@migrate-dockerized
with:
path: serv
- run: echo "EDALIZE_LAUNCHER=el_docker" >> $GITHUB_ENV
- run: pip3 install fusesoc
- run: fusesoc library add $REPO $GITHUB_WORKSPACE/$REPO
- run: fusesoc run --target=sky130 $VLNV
- run: find -name *.gds
core: serv
target: sky130
tool: openlane
- name: Store artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: serv.gds
path: /home/runner/work/serv/serv/serv/build/serv_1.3.0/sky130-openlane/runs/serv_synth_wrapper/results/final/gds/serv_synth_wrapper.gds
path: /home/runner/work/serv/serv/build/serv_1.3.0/sky130-openlane/gds/serv_synth_wrapper.gds

View file

@ -3,7 +3,7 @@
# SERV
[![Join the chat at https://gitter.im/librecores/serv](https://badges.gitter.im/librecores/serv.svg)](https://gitter.im/librecores/serv?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Compliance tests](https://github.com/olofk/serv/actions/workflows/ci.yml/badge.svg)](https://github.com/olofk/serv/actions/workflows/ci.yml)
[![CI status](https://github.com/olofk/serv/workflows/CI/badge.svg)](https://github.com/olofk/serv/actions?query=workflow%3ACI)
[![Documentation Status](https://readthedocs.org/projects/serv/badge/?version=latest)](https://serv.readthedocs.io/en/latest/?badge=latest)
SERV is an award-winning bit-serial RISC-V core
@ -158,7 +158,7 @@ This will synthesize for the default Vivado part. To synthesise for a specific d
SERV, or rather the Servant SoC, can run the [Zephyr RTOS](https://www.zephyrproject.org). The Servant-specific drivers and BSP is located in the zephyr subdirectory of the SERV repository. In order to use Zephyr on Servant, a project directory structure must be set up that allows Zephyr to load the Servant-specific files as a module.
First, the Zephyr SDK and the "west" build tool must be installed. The [Zephyr getting started guide](https://docs.zephyrproject.org/latest/getting_started/index.html) describes these steps in more detail.
First, the Zephyr SDK and the "west" build too must be installed. The [Zephyr getting started guide](https://docs.zephyrproject.org/latest/getting_started/index.html) describes these steps in more detail.
Assuming that SERV was installed into `$WORKSPACE/fusesoc_libraries/serv` as per the prerequisites, run the following command to make the workspace also work as a Zephyr workspace.

View file

@ -8,7 +8,6 @@ module servant_sim
parameter memfile = "";
parameter memsize = 8192;
parameter width = 1;
parameter with_csr = 1;
parameter compressed = 0;
parameter align = compressed;
@ -23,8 +22,6 @@ module servant_sim
servant
#(.memfile (memfile),
.memsize (memsize),
.width (width),
.debug (1'b1),
.sim (1),
.with_csr (with_csr),
.compress (compressed[0:0]),

View file

@ -154,7 +154,7 @@ int main(int argc, char **argv, char **env)
do_gpio(&gpio_context, top->q);
}
if (tf && top->wb_clk && top->pc_vld)
if (write(tf, (void *)&top->pc_adr, 4) < 0) exit(1);
write(tf, (void *)&top->pc_adr, 4);
if (timeout && (main_time >= timeout)) {
printf("Timeout: Exiting at time %lu\n", main_time);
done = true;

View file

@ -3,13 +3,8 @@ module servant_tb;
parameter memfile = "hello_uart.hex";
parameter memsize = 8192;
parameter width = 1;
parameter with_csr = 1;
localparam baud_rate =
(width == 4) ? 57600*3 :
57600;
reg wb_clk = 1'b0;
reg wb_rst = 1'b1;
@ -20,12 +15,11 @@ module servant_tb;
vlog_tb_utils vtu();
uart_decoder #(baud_rate) uart_decoder (q);
uart_decoder #(57600) uart_decoder (q);
servant_sim
#(.memfile (memfile),
.memsize (memsize),
.width (width),
.with_csr (with_csr))
dut
(.wb_clk (wb_clk),

View file

@ -1,22 +0,0 @@
## Clock signal
set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS18 } [get_ports i_clk];
create_clock -add -name sys_clk_pin -period 40.00 [get_ports i_clk];
## LED 0
set_property -dict { PACKAGE_PIN P1 IOSTANDARD LVCMOS18 } [get_ports o_led_0];
# PMOD A, Connector J5
# Connector pin, Package pin, PMOD type 4 UART
# 1, F8, CTS
# 2, F7, TXD
# 3, E6, RXD
# 4, E5, RTS
# 5, GND
# 6, VCC
# 7, G6,
# 8, G5,
# 9, C8,
# 10, C7,
# 11, GND
# 12, VCC
set_property -dict { PACKAGE_PIN F7 IOSTANDARD LVCMOS33 } [get_ports o_uart_tx]

View file

@ -1,12 +1,14 @@
`verilator_config
// Bits [1:0] in i_wb_rdt are not used at all
lint_off -rule UNUSED -file "*/serv_top.v" -lines 179
lint_off -rule UNUSED -file "*/serv_top.v" -lines 178
//Some bits in the instruction word are not used in serv_decode but it's easier
//to just send in the whole word than picking out bits
lint_off -rule UNUSED -file "*/serv_decode.v" -lines 8
lint_off -rule UNUSED -file "*/serv_top.v" -lines 177
//Some variables are only used when we connect an Extension with serv_decode
lint_off -rule UNUSED -file "*/serv_top.v" -lines 70
lint_off -rule UNUSED -file "*/serv_top.v" -lines 67

View file

@ -2,5 +2,4 @@
Datasheet
*********
.. include:: overview.rst
.. include:: interface.rst

View file

@ -1,9 +1,6 @@
Interface
=========
Top level
---------
Users of SERV can choose to use either serv_top or serv_rf_top depending on what best fits the application. serv_top contains all the main logic of SERV except for the actual storage for the register file (RF).
.. image:: serv_top.png
@ -194,29 +191,3 @@ Signals
- 1
- in
- RF interface channel 1 read data
Extension interface
-------------------
The SERV CPU, being the smallest RISC-V CPU, has a design that is primarily focused on simplicity and minimalism. However, to increase its utility without complicating the core design, it can be extended using an extension interface. The extension interface allows additional functionality to be added to the SERV CPU core through custom accelerators that are called for when specific instructions are encountered. SERV has built-in support for connecting an MDU (Multiplication/Division Unit) that implements the M ISA extension by setting the MDU parameter. Other accelerators need changes to the decoder.
When SERV detects instructions to be executed by an external accelerator through the extension interface, it will treat them as :ref:`two-stage operations`. In stage 1, the values in `o_ext_rs1` and `o_ext_rs2` are prepared to be sent to the accelerator. Once stage 1 is completed, SERV will assert the corresponding valid signal for the accelerator (e.g. `o_mdu_valid` for the M extension accelerator). The accelerator can now perform its work and when it has completed its result it will return that value in `i_ext_rd` and strobe `i_ext_ready` for one cycle. The following cycle, SERV will start stage two and store the received result. The waveform below explains this in more detail.
.. wavedrom::
{ signal: [
{ name: "clk" , wave: "P...|...|...|..."},
{ name: "init" , wave: "1...|..0|...|...", node: ".......d..", data: "r0"},
{ name: "o_rf_wreq" , wave: "0...|...|10.|...", node: ".........g", data: "r1"},
{ name: "i_rf_ready" , wave: "010.|...|10.|...", node: ".a.......h.", data: "r1"},
{ name: "cnt_en" , wave: "0.1.|..0|.1.|..0", node: "..b.......i"},
{ name: "cnt_done" , wave: "0...|.10|...|.10", node: "......c.."},
{ name: "o_ext_rs1" , wave: ".234567x|...|...", node: "..", data: "d0 d1 ... d30 d31"},
{ name: "o_ext_rs2" , wave: ".234567x|...|...", node: "..", data: "d0 d1 ... d30 d31"},
{ name: "o_mdu_valid", wave: "0...|..1|.0.|...", node: ".......e", data: "0 1 ... 30 31"},
{ name: "i_ext_ready", wave: "0...|...|10.|...", node: ".........f", data: "0 1 ... 30 31"},
{ name: "i_ext_rd" , wave: "....|...|234567x", node: "..", data: "d0 d1 ... d30 d31"},
],
edge : [
"a~>b", "c~>d", "e~>f", "f~>g", "h~>i"]
}

View file

@ -1,42 +0,0 @@
Overview
========
The SERV RISC-V CPU is an award-winning and highly compact processor core based on the RISC-V instruction set architecture (ISA). It is designed to be the smallest possible RISC-V compliant CPU and is particularly well-suited for embedded systems and applications where silicon area is critical.
Key Features
------------
* **ISA:** RISC-V RV32IZifencei
* **Optional ISA extensions:** C, M, Zicsr
* **Optional features:** Timer interrupts, Extension interface
* **Architecture:** Bit-serial (one bit processed per clock cycle)
* **License:** ISC (available under other commercial licenses upon request)
* **OS support:** Zephyr 3.7
* **SW support:** Compatible with standard RISC-V toolchains
* **Area:** Smallest RISC-V core available
Applications
------------
* **Embedded Systems:** Ideal for minimalistic embedded control tasks
* **IoT Devices:** Suitable for Internet of Things devices where space and power are limited
* **Education:** Excellent resource for teaching and understanding the RISC-V architecture and CPU design
* **Research:** Platform for research in minimalistic computing designs and for bringing up new fabrication processes
Area
----
.. list-table:: Area for minimal configuration [#]_
:widths: 25 25 25 25
:header-rows: 1
* - Lattice iCE40
- Altera Cyclone10LP
- AMD Artix-7
- CMOS
* - 198LUT/164FF
- 239LUT/164FF
- 125LUT/164FF
- 2.1kGE
.. [#] Excluding register file

View file

@ -9,4 +9,3 @@ Welcome to the reservoir, a pool of ready-made designs and subsystems for differ
.. include:: servile.rst
.. include:: serving.rst
.. include:: servant.rst
.. include:: subservient.rst

View file

@ -184,7 +184,7 @@ Pin B1 is used for UART output with 115200 baud rate. The serial port on Kolibri
ldprog -Ks build/servant_1.3.0/machdyne_kolibri-icestorm/servant_1.3.0.bin
MAX10 10M08 Evaluation Kit
^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^
FPGA Pin 75 (Arduino_IO01 J5 pin 7) is used for UART output with 57600 baud rate. SW1 is reset and Led 1 q output.
@ -248,13 +248,6 @@ FPGA Pin F14 (HSTC GPIO addon connector J2, pin 2) is used for UART output with
fusesoc run --target=sockit servant
Trenz Electronic TE0802
^^^^^^^^^^^^^^^^^^^^^^^
PMOD A marked J5, pin two, on the board is used for UART output with 115200 baud rate.
fusesoc run --target=te0802 servant
TinyFPGA BX
^^^^^^^^^^^

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View file

@ -1,10 +0,0 @@
Subservient : SERV ASIC macro
=============================
.. figure:: subservient.png
Subservient ASIC macro
`Subservient <https://github.com/olofk/subservient>`_ is a minimal reference system that just requires connecting one single-port SRAM for data, instructions and RF. It is intended to make ASIC integration easier.

View file

@ -4,12 +4,11 @@ module serv_bufreg2
//State
input wire i_en,
input wire i_init,
input wire i_cnt7,
input wire i_cnt_done,
input wire i_sh_right,
input wire [1:0] i_lsb,
input wire [1:0] i_bytecnt,
input wire i_byte_valid,
output wire o_sh_done,
output wire o_sh_done_r,
//Control
input wire i_op_b_sel,
input wire i_shift_op,
@ -25,46 +24,30 @@ module serv_bufreg2
reg [31:0] dat;
/*
Before a store operation, the data to be written needs to be shifted into
place. Depending on the address alignment, we need to shift different
amounts. One formula for calculating this is to say that we shift when
i_lsb + i_bytecnt < 4. Unfortunately, the synthesis tools don't seem to be
clever enough so the hideous expression below is used to achieve the same
thing in a more optimal way.
*/
wire byte_valid
= (!i_lsb[0] & !i_lsb[1]) |
(!i_bytecnt[0] & !i_bytecnt[1]) |
(!i_bytecnt[1] & !i_lsb[1]) |
(!i_bytecnt[1] & !i_lsb[0]) |
(!i_bytecnt[0] & !i_lsb[1]);
assign o_op_b = i_op_b_sel ? i_rs2 : i_imm;
wire shift_en = i_shift_op ? (i_en & i_init & (i_bytecnt == 2'b00)) : (i_en & byte_valid);
wire cnt_en = (i_shift_op & (!i_init | (i_cnt_done & i_sh_right)));
wire dat_en = i_shift_op | (i_en & i_byte_valid);
/* The dat register has three different use cases for store, load and
shift operations.
store : Data to be written is shifted to the correct position in dat during
init by shift_en and is presented on the data bus as o_wb_dat
init by dat_en and is presented on the data bus as o_wb_dat
load : Data from the bus gets latched into dat during i_wb_ack and is then
shifted out at the appropriate time to end up in the correct
position in rd
shift : Data is shifted in during init. After that, the six LSB are used as
a downcounter (with bit 5 initially set to 0) that trigger
o_sh_done when they wrap around to indicate that
a downcounter (with bit 5 initially set to 0) that triggers
o_sh_done and o_sh_done_r when they wrap around to indicate that
the requested number of shifts have been performed
*/
wire [5:0] dat_shamt = cnt_en ?
wire [5:0] dat_shamt = (i_shift_op & !i_init) ?
//Down counter mode
dat[29:24]-1 :
dat[5:0]-1 :
//Shift reg mode with optional clearing of bit 5
{dat[30] & !(i_shift_op & i_cnt7),dat[29:25]};
{dat[6] & !(i_shift_op & i_cnt_done),dat[5:1]};
assign o_sh_done = dat_shamt[5];
assign o_sh_done_r = dat[5];
assign o_q =
((i_lsb == 2'd3) & dat[24]) |
@ -75,8 +58,8 @@ module serv_bufreg2
assign o_dat = dat;
always @(posedge i_clk) begin
if (shift_en | cnt_en | i_load)
dat <= i_load ? i_dat : {o_op_b, dat[31], dat_shamt, dat[24:1]};
if (dat_en | i_load)
dat <= i_load ? i_dat : {o_op_b, dat[31:7], dat_shamt};
end
endmodule

View file

@ -14,8 +14,6 @@ module serv_csr
input wire i_cnt0to3,
input wire i_cnt3,
input wire i_cnt7,
input wire i_cnt11,
input wire i_cnt12,
input wire i_cnt_done,
input wire i_mem_op,
input wire i_mtip,
@ -65,17 +63,7 @@ module serv_csr
(i_csr_source == CSR_SOURCE_CSR) ? csr_out :
{W{1'bx}};
wire [B:0] mstatus;
generate
if (W==1) begin : gen_mstatus_w1
assign mstatus = ((mstatus_mie & i_cnt3) | (i_cnt11 | i_cnt12));
end else if (W==4) begin : gen_mstatus_w4
assign mstatus = {i_cnt11 | (mstatus_mie & i_cnt3), 2'b00, i_cnt12};
end
endgenerate
assign csr_out = ({W{i_mstatus_en & i_en}} & mstatus) |
assign csr_out = ({i_mstatus_en & mstatus_mie & i_cnt3 & i_en,{B{1'b0}}}) |
i_rf_csr_out |
({W{i_mcause_en & i_en}} & mcause);

View file

@ -1,345 +0,0 @@
module serv_debug
#(parameter W = 1,
parameter RESET_PC = 0,
//Internally calculated. Do not touch
parameter B=W-1)
(
`ifdef RISCV_FORMAL
output reg rvfi_valid = 1'b0,
output reg [63:0] rvfi_order = 64'd0,
output reg [31:0] rvfi_insn = 32'd0,
output reg rvfi_trap = 1'b0,
output reg rvfi_halt = 1'b0, // Not used
output reg rvfi_intr = 1'b0, // Not used
output reg [1:0] rvfi_mode = 2'b11, // Not used
output reg [1:0] rvfi_ixl = 2'b01, // Not used
output reg [4:0] rvfi_rs1_addr,
output reg [4:0] rvfi_rs2_addr,
output reg [31:0] rvfi_rs1_rdata,
output reg [31:0] rvfi_rs2_rdata,
output reg [4:0] rvfi_rd_addr,
output wire [31:0] rvfi_rd_wdata,
output reg [31:0] rvfi_pc_rdata,
output wire [31:0] rvfi_pc_wdata,
output reg [31:0] rvfi_mem_addr,
output reg [3:0] rvfi_mem_rmask,
output reg [3:0] rvfi_mem_wmask,
output reg [31:0] rvfi_mem_rdata,
output reg [31:0] rvfi_mem_wdata,
input wire [31:0] i_dbus_adr,
input wire [31:0] i_dbus_dat,
input wire [3:0] i_dbus_sel,
input wire i_dbus_we,
input wire [31:0] i_dbus_rdt,
input wire i_dbus_ack,
input wire i_ctrl_pc_en,
input wire [B:0] rs1,
input wire [B:0] rs2,
input wire [4:0] rs1_addr,
input wire [4:0] rs2_addr,
input wire [3:0] immdec_en,
input wire rd_en,
input wire trap,
input wire i_rf_ready,
input wire i_ibus_cyc,
input wire two_stage_op,
input wire init,
input wire [31:0] i_ibus_adr,
`endif
input wire i_clk,
input wire i_rst,
input wire [31:0] i_ibus_rdt,
input wire i_ibus_ack,
input wire [4:0] i_rd_addr,
input wire i_cnt_en,
input wire [B:0] i_csr_in,
input wire i_csr_mstatus_en,
input wire i_csr_mie_en,
input wire i_csr_mcause_en,
input wire i_csr_en,
input wire [1:0] i_csr_addr,
input wire i_wen0,
input wire [B:0] i_wdata0,
input wire i_cnt_done);
reg update_rd = 1'b0;
reg update_mscratch;
reg update_mtvec;
reg update_mepc;
reg update_mtval;
reg update_mstatus;
reg update_mie;
reg update_mcause;
reg [31:0] dbg_rd = 32'hxxxxxxxx;
reg [31:0] dbg_csr = 32'hxxxxxxxx;
reg [31:0] dbg_mstatus = 32'hxxxxxxxx;
reg [31:0] dbg_mie = 32'hxxxxxxxx;
reg [31:0] dbg_mcause = 32'hxxxxxxxx;
reg [31:0] dbg_mscratch = 32'hxxxxxxxx;
reg [31:0] dbg_mtvec = 32'hxxxxxxxx;
reg [31:0] dbg_mepc = 32'hxxxxxxxx;
reg [31:0] dbg_mtval = 32'hxxxxxxxx;
reg [31:0] x1 = 32'hxxxxxxxx;
reg [31:0] x2 = 32'hxxxxxxxx;
reg [31:0] x3 = 32'hxxxxxxxx;
reg [31:0] x4 = 32'hxxxxxxxx;
reg [31:0] x5 = 32'hxxxxxxxx;
reg [31:0] x6 = 32'hxxxxxxxx;
reg [31:0] x7 = 32'hxxxxxxxx;
reg [31:0] x8 = 32'hxxxxxxxx;
reg [31:0] x9 = 32'hxxxxxxxx;
reg [31:0] x10 = 32'hxxxxxxxx;
reg [31:0] x11 = 32'hxxxxxxxx;
reg [31:0] x12 = 32'hxxxxxxxx;
reg [31:0] x13 = 32'hxxxxxxxx;
reg [31:0] x14 = 32'hxxxxxxxx;
reg [31:0] x15 = 32'hxxxxxxxx;
reg [31:0] x16 = 32'hxxxxxxxx;
reg [31:0] x17 = 32'hxxxxxxxx;
reg [31:0] x18 = 32'hxxxxxxxx;
reg [31:0] x19 = 32'hxxxxxxxx;
reg [31:0] x20 = 32'hxxxxxxxx;
reg [31:0] x21 = 32'hxxxxxxxx;
reg [31:0] x22 = 32'hxxxxxxxx;
reg [31:0] x23 = 32'hxxxxxxxx;
reg [31:0] x24 = 32'hxxxxxxxx;
reg [31:0] x25 = 32'hxxxxxxxx;
reg [31:0] x26 = 32'hxxxxxxxx;
reg [31:0] x27 = 32'hxxxxxxxx;
reg [31:0] x28 = 32'hxxxxxxxx;
reg [31:0] x29 = 32'hxxxxxxxx;
reg [31:0] x30 = 32'hxxxxxxxx;
reg [31:0] x31 = 32'hxxxxxxxx;
always @(posedge i_clk) begin
update_rd <= i_cnt_done & i_wen0;
if (i_wen0)
dbg_rd <= {i_wdata0,dbg_rd[31:W]};
//End of instruction that writes to RF
if (update_rd) begin
case (i_rd_addr)
5'd1 : x1 <= dbg_rd;
5'd2 : x2 <= dbg_rd;
5'd3 : x3 <= dbg_rd;
5'd4 : x4 <= dbg_rd;
5'd5 : x5 <= dbg_rd;
5'd6 : x6 <= dbg_rd;
5'd7 : x7 <= dbg_rd;
5'd8 : x8 <= dbg_rd;
5'd9 : x9 <= dbg_rd;
5'd10 : x10 <= dbg_rd;
5'd11 : x11 <= dbg_rd;
5'd12 : x12 <= dbg_rd;
5'd13 : x13 <= dbg_rd;
5'd14 : x14 <= dbg_rd;
5'd15 : x15 <= dbg_rd;
5'd16 : x16 <= dbg_rd;
5'd17 : x17 <= dbg_rd;
5'd18 : x18 <= dbg_rd;
5'd19 : x19 <= dbg_rd;
5'd20 : x20 <= dbg_rd;
5'd21 : x21 <= dbg_rd;
5'd22 : x22 <= dbg_rd;
5'd23 : x23 <= dbg_rd;
5'd24 : x24 <= dbg_rd;
5'd25 : x25 <= dbg_rd;
5'd26 : x26 <= dbg_rd;
5'd27 : x27 <= dbg_rd;
5'd28 : x28 <= dbg_rd;
5'd29 : x29 <= dbg_rd;
5'd30 : x30 <= dbg_rd;
5'd31 : x31 <= dbg_rd;
default : ;
endcase
end
update_mscratch <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b00);
update_mtvec <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b01);
update_mepc <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b10);
update_mtval <= i_cnt_done & i_csr_en & (i_csr_addr == 2'b11);
update_mstatus <= i_cnt_done & i_csr_mstatus_en;
update_mie <= i_cnt_done & i_csr_mie_en;
update_mcause <= i_cnt_done & i_csr_mcause_en;
if (i_cnt_en)
dbg_csr <= {i_csr_in, dbg_csr[31:W]};
if (update_mscratch) dbg_mscratch <= dbg_csr;
if (update_mtvec) dbg_mtvec <= dbg_csr;
if (update_mepc ) dbg_mepc <= dbg_csr;
if (update_mtval) dbg_mtval <= dbg_csr;
if (update_mstatus) dbg_mstatus <= dbg_csr;
if (update_mie) dbg_mie <= dbg_csr;
if (update_mcause) dbg_mcause <= dbg_csr;
end
reg LUI, AUIPC, JAL, JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, XORI, ORI, ANDI,SLLI, SRLI, SRAI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, FENCE, ECALL, EBREAK;
reg CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI;
reg OTHER;
always @(posedge i_clk) begin
if (i_ibus_ack) begin
LUI <= 1'b0;
AUIPC <= 1'b0;
JAL <= 1'b0;
JALR <= 1'b0;
BEQ <= 1'b0;
BNE <= 1'b0;
BLT <= 1'b0;
BGE <= 1'b0;
BLTU <= 1'b0;
BGEU <= 1'b0;
LB <= 1'b0;
LH <= 1'b0;
LW <= 1'b0;
LBU <= 1'b0;
LHU <= 1'b0;
SB <= 1'b0;
SH <= 1'b0;
SW <= 1'b0;
ADDI <= 1'b0;
SLTI <= 1'b0;
SLTIU <= 1'b0;
XORI <= 1'b0;
ORI <= 1'b0;
ANDI <= 1'b0;
SLLI <= 1'b0;
SRLI <= 1'b0;
SRAI <= 1'b0;
ADD <= 1'b0;
SUB <= 1'b0;
SLL <= 1'b0;
SLT <= 1'b0;
SLTU <= 1'b0;
XOR <= 1'b0;
SRL <= 1'b0;
SRA <= 1'b0;
OR <= 1'b0;
AND <= 1'b0;
FENCE <= 1'b0;
ECALL <= 1'b0;
EBREAK <= 1'b0;
CSRRW <= 1'b0;
CSRRS <= 1'b0;
CSRRC <= 1'b0;
CSRRWI <= 1'b0;
CSRRSI <= 1'b0;
CSRRCI <= 1'b0;
OTHER <= 1'b0;
casez(i_ibus_rdt)
// 3322222_22222 11111_111 11
// 1098765_43210 98765_432 10987_65432_10
32'b???????_?????_?????_???_?????_01101_11 : LUI <= 1'b1;
32'b???????_?????_?????_???_?????_00101_11 : AUIPC <= 1'b1;
32'b???????_?????_?????_???_?????_11011_11 : JAL <= 1'b1;
32'b???????_?????_?????_000_?????_11001_11 : JALR <= 1'b1;
32'b???????_?????_?????_000_?????_11000_11 : BEQ <= 1'b1;
32'b???????_?????_?????_001_?????_11000_11 : BNE <= 1'b1;
32'b???????_?????_?????_100_?????_11000_11 : BLT <= 1'b1;
32'b???????_?????_?????_101_?????_11000_11 : BGE <= 1'b1;
32'b???????_?????_?????_110_?????_11000_11 : BLTU <= 1'b1;
32'b???????_?????_?????_111_?????_11000_11 : BGEU <= 1'b1;
32'b???????_?????_?????_000_?????_00000_11 : LB <= 1'b1;
32'b???????_?????_?????_001_?????_00000_11 : LH <= 1'b1;
32'b???????_?????_?????_010_?????_00000_11 : LW <= 1'b1;
32'b???????_?????_?????_100_?????_00000_11 : LBU <= 1'b1;
32'b???????_?????_?????_101_?????_00000_11 : LHU <= 1'b1;
32'b???????_?????_?????_000_?????_01000_11 : SB <= 1'b1;
32'b???????_?????_?????_001_?????_01000_11 : SH <= 1'b1;
32'b???????_?????_?????_010_?????_01000_11 : SW <= 1'b1;
32'b???????_?????_?????_000_?????_00100_11 : ADDI <= 1'b1;
32'b???????_?????_?????_010_?????_00100_11 : SLTI <= 1'b1;
32'b???????_?????_?????_011_?????_00100_11 : SLTIU <= 1'b1;
32'b???????_?????_?????_100_?????_00100_11 : XORI <= 1'b1;
32'b???????_?????_?????_110_?????_00100_11 : ORI <= 1'b1;
32'b???????_?????_?????_111_?????_00100_11 : ANDI <= 1'b1;
32'b0000000_?????_?????_001_?????_00100_11 : SLLI <= 1'b1;
32'b0000000_?????_?????_101_?????_00100_11 : SRLI <= 1'b1;
32'b0100000_?????_?????_101_?????_00100_11 : SRAI <= 1'b1;
32'b0000000_?????_?????_000_?????_01100_11 : ADD <= 1'b1;
32'b0100000_?????_?????_000_?????_01100_11 : SUB <= 1'b1;
32'b0000000_?????_?????_001_?????_01100_11 : SLL <= 1'b1;
32'b0000000_?????_?????_010_?????_01100_11 : SLT <= 1'b1;
32'b0000000_?????_?????_011_?????_01100_11 : SLTU <= 1'b1;
32'b???????_?????_?????_100_?????_01100_11 : XOR <= 1'b1;
32'b0000000_?????_?????_101_?????_01100_11 : SRL <= 1'b1;
32'b0100000_?????_?????_101_?????_01100_11 : SRA <= 1'b1;
32'b???????_?????_?????_110_?????_01100_11 : OR <= 1'b1;
32'b???????_?????_?????_111_?????_01100_11 : AND <= 1'b1;
32'b???????_?????_?????_000_?????_00011_11 : FENCE <= 1'b1;
32'b0000000_00000_00000_000_00000_11100_11 : ECALL <= 1'b1;
32'b0000000_00001_00000_000_00000_11100_11 : EBREAK <= 1'b1;
32'b???????_?????_?????_001_?????_11100_11 : CSRRW <= 1'b1;
32'b???????_?????_?????_010_?????_11100_11 : CSRRS <= 1'b1;
32'b???????_?????_?????_011_?????_11100_11 : CSRRC <= 1'b1;
32'b???????_?????_?????_101_?????_11100_11 : CSRRWI <= 1'b1;
32'b???????_?????_?????_110_?????_11100_11 : CSRRSI <= 1'b1;
32'b???????_?????_?????_111_?????_11100_11 : CSRRCI <= 1'b1;
default : OTHER <= 1'b1;
endcase
end
end
`ifdef RISCV_FORMAL
reg [31:0] pc = RESET_PC;
wire rs_en = two_stage_op ? init : i_ctrl_pc_en;
assign rvfi_rd_wdata = update_rd ? dbg_rd : 32'd0;
always @(posedge i_clk) begin
/* End of instruction */
rvfi_valid <= i_cnt_done & i_ctrl_pc_en & !i_rst;
rvfi_order <= rvfi_order + {63'd0,rvfi_valid};
/* Get instruction word when it's fetched from ibus */
if (i_ibus_cyc & i_ibus_ack)
rvfi_insn <= i_ibus_rdt;
if (i_cnt_done & i_ctrl_pc_en) begin
rvfi_pc_rdata <= pc;
if (!(rd_en & (|i_rd_addr))) begin
rvfi_rd_addr <= 5'd0;
end
end
rvfi_trap <= trap;
if (rvfi_valid) begin
rvfi_trap <= 1'b0;
pc <= rvfi_pc_wdata;
end
/* RS1 not valid during J, U instructions (immdec_en[1]) */
/* RS2 not valid during I, J, U instructions (immdec_en[2]) */
if (i_rf_ready) begin
rvfi_rs1_addr <= !immdec_en[1] ? rs1_addr : 5'd0;
rvfi_rs2_addr <= !immdec_en[2] /*rs2_valid*/ ? rs2_addr : 5'd0;
rvfi_rd_addr <= i_rd_addr;
end
if (rs_en) begin
rvfi_rs1_rdata <= {(!immdec_en[1] ? rs1 : {W{1'b0}}),rvfi_rs1_rdata[31:W]};
rvfi_rs2_rdata <= {(!immdec_en[2] ? rs2 : {W{1'b0}}),rvfi_rs2_rdata[31:W]};
end
if (i_dbus_ack) begin
rvfi_mem_addr <= i_dbus_adr;
rvfi_mem_rmask <= i_dbus_we ? 4'b0000 : i_dbus_sel;
rvfi_mem_wmask <= i_dbus_we ? i_dbus_sel : 4'b0000;
rvfi_mem_rdata <= i_dbus_rdt;
rvfi_mem_wdata <= i_dbus_dat;
end
if (i_ibus_ack) begin
rvfi_mem_rmask <= 4'b0000;
rvfi_mem_wmask <= 4'b0000;
end
end
assign rvfi_pc_wdata = i_ibus_adr;
`endif
endmodule

View file

@ -15,6 +15,7 @@ module serv_decode
output reg o_ebreak,
output reg o_branch_op,
output reg o_shift_op,
output reg o_slt_or_branch,
output reg o_rd_op,
output reg o_two_stage_op,
output reg o_dbus_en,
@ -78,6 +79,7 @@ module serv_decode
~opcode[2] | (funct3[0] & ~funct3[1] & ~opcode[0] & ~opcode[4]) |
(funct3[1] & ~funct3[2] & ~opcode[0] & ~opcode[4]) | co_mdu_op;
wire co_shift_op = (opcode[2] & ~funct3[1]) & !co_mdu_op;
wire co_slt_or_branch = (opcode[4] | (funct3[1] & opcode[2]) | (imm30 & opcode[2] & opcode[3] & ~funct3[2])) & !co_mdu_op;
wire co_branch_op = opcode[4];
wire co_dbus_en = ~opcode[2] & ~opcode[4];
wire co_mtval_pc = opcode[4];
@ -186,7 +188,7 @@ module serv_decode
wire co_rd_csr_en = csr_op;
wire co_csr_en = csr_op & csr_valid;
wire co_csr_mstatus_en = csr_op & !op26 & !op22 & !op20;
wire co_csr_mstatus_en = csr_op & !op26 & !op22;
wire co_csr_mie_en = csr_op & !op26 & op22 & !op20;
wire co_csr_mcause_en = csr_op & op21 & !op20;
@ -257,6 +259,7 @@ module serv_decode
o_ebreak = co_ebreak;
o_branch_op = co_branch_op;
o_shift_op = co_shift_op;
o_slt_or_branch = co_slt_or_branch;
o_rd_op = co_rd_op;
o_mdu_op = co_mdu_op;
o_ext_funct3 = co_ext_funct3;
@ -318,6 +321,7 @@ module serv_decode
o_mtval_pc <= co_mtval_pc;
o_branch_op <= co_branch_op;
o_shift_op <= co_shift_op;
o_slt_or_branch <= co_slt_or_branch;
o_rd_op <= co_rd_op;
o_mdu_op <= co_mdu_op;
o_ext_funct3 <= co_ext_funct3;

View file

@ -10,6 +10,7 @@ module serv_mem_if
//State
input wire [1:0] i_bytecnt,
input wire [1:0] i_lsb,
output wire o_byte_valid,
output wire o_misalign,
//Control
input wire i_signed,
@ -25,6 +26,21 @@ module serv_mem_if
reg signbit;
/*
Before a store operation, the data to be written needs to be shifted into
place. Depending on the address alignment, we need to shift different
amounts. One formula for calculating this is to say that we shift when
i_lsb + i_bytecnt < 4. Unfortunately, the synthesis tools don't seem to be
clever enough so the hideous expression below is used to achieve the same
thing in a more optimal way.
*/
assign o_byte_valid
= (!i_lsb[0] & !i_lsb[1]) |
(!i_bytecnt[0] & !i_bytecnt[1]) |
(!i_bytecnt[1] & !i_lsb[1]) |
(!i_bytecnt[1] & !i_lsb[0]) |
(!i_bytecnt[0] & !i_lsb[1]);
wire dat_valid =
i_mdu_op |
i_word |

View file

@ -27,10 +27,8 @@ module serv_rf_top
restart execution from the instruction at RESET_PC
*/
parameter RESET_STRATEGY = "MINI",
parameter [0:0] DEBUG = 1'b0,
parameter WITH_CSR = 1,
parameter W = 1,
parameter RF_WIDTH = W * 2,
parameter RF_WIDTH = 2,
parameter RF_L2D = $clog2((32+(WITH_CSR*4))*32/RF_WIDTH))
(
input wire clk,
@ -88,13 +86,13 @@ module serv_rf_top
wire [4+WITH_CSR:0] wreg1;
wire wen0;
wire wen1;
wire [W-1:0] wdata0;
wire [W-1:0] wdata1;
wire wdata0;
wire wdata1;
wire [4+WITH_CSR:0] rreg0;
wire [4+WITH_CSR:0] rreg1;
wire rf_ready;
wire [W-1:0] rdata0;
wire [W-1:0] rdata1;
wire rdata0;
wire rdata1;
wire [RF_L2D-1:0] waddr;
wire [RF_WIDTH-1:0] wdata;
@ -106,8 +104,7 @@ module serv_rf_top
serv_rf_ram_if
#(.width (RF_WIDTH),
.reset_strategy (RESET_STRATEGY),
.csr_regs (CSR_REGS),
.W(W))
.csr_regs (CSR_REGS))
rf_ram_if
(.i_clk (clk),
.i_rst (i_rst),
@ -148,11 +145,9 @@ module serv_rf_top
.PRE_REGISTER (PRE_REGISTER),
.RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR),
.DEBUG (DEBUG),
.MDU(MDU),
.COMPRESSED(COMPRESSED),
.ALIGN(ALIGN),
.W(W))
.ALIGN(ALIGN))
cpu
(
.clk (clk),

View file

@ -20,8 +20,6 @@ module serv_state
output wire o_cnt2,
output wire o_cnt3,
output wire o_cnt7,
output wire o_cnt11,
output wire o_cnt12,
output wire o_cnt_done,
output wire o_bufreg_en,
output wire o_ctrl_pc_en,
@ -29,6 +27,7 @@ module serv_state
output wire o_ctrl_trap,
input wire i_ctrl_misalign,
input wire i_sh_done,
input wire i_sh_done_r,
output wire [1:0] o_mem_bytecnt,
input wire i_mem_misalign,
//Control
@ -39,8 +38,7 @@ module serv_state
input wire i_branch_op,
input wire i_shift_op,
input wire i_sh_right,
input wire i_alu_rd_sel1,
input wire i_rd_alu_en,
input wire i_slt_or_branch,
input wire i_e_op,
input wire i_rd_op,
//MDU
@ -59,6 +57,7 @@ module serv_state
input wire i_rf_ready,
output wire o_rf_rd_en);
reg stage_two_req;
reg init_done;
wire misalign_trap_sync;
@ -78,8 +77,6 @@ module serv_state
assign o_cnt2 = (o_cnt[4:2] == 3'd0) & cnt_r[2];
assign o_cnt3 = (o_cnt[4:2] == 3'd0) & cnt_r[3];
assign o_cnt7 = (o_cnt[4:2] == 3'd1) & cnt_r[3];
assign o_cnt11 = (o_cnt[4:2] == 3'd2) & cnt_r[3];
assign o_cnt12 = (o_cnt[4:2] == 3'd3) & cnt_r[0];
//Take branch for jump or branch instructions (opcode == 1x0xx) if
//a) It's an unconditional branch (opcode[0] == 1)
@ -89,27 +86,21 @@ module serv_state
//been calculated.
wire take_branch = i_branch_op & (!i_cond_branch | (i_alu_cmp^i_bne_or_bge));
wire last_init = o_cnt_done & o_init;
//valid signal for mdu
assign o_mdu_valid = MDU & !o_cnt_en & init_done & i_mdu_op;
//Prepare RF for writes when everything is ready to enter stage two
// and the first stage didn't cause a misalign exception
//Left shifts, SLT & Branch ops. First cycle after init
//Right shift. o_sh_done
//Mem ops. i_dbus_ack
//MDU ops. i_mdu_ready
assign o_rf_wreq = (i_shift_op & (i_sh_right ? (i_sh_done & (last_init | !o_cnt_en & init_done)) : last_init)) |
assign o_rf_wreq = !misalign_trap_sync & !o_cnt_en & init_done &
((i_shift_op & (i_sh_done | !i_sh_right)) |
i_dbus_ack | (MDU & i_mdu_ready) |
(i_branch_op & (last_init & !trap_pending)) |
(i_rd_alu_en & i_alu_rd_sel1 & last_init);
i_slt_or_branch);
assign o_dbus_cyc = !o_cnt_en & init_done & i_dbus_en & !i_mem_misalign;
//Prepare RF for reads when a new instruction is fetched
// or when stage one caused an exception (rreq implies a write request too)
assign o_rf_rreq = i_ibus_ack | (trap_pending & last_init);
assign o_rf_rreq = i_ibus_ack | (stage_two_req & misalign_trap_sync);
assign o_rf_rd_en = i_rd_op & !o_init;
@ -124,8 +115,7 @@ module serv_state
shift : Shift in during phase 1. Continue shifting between phases (except
for the first cycle after init). Shift out during phase 2
*/
assign o_bufreg_en = (o_cnt_en & (o_init | ((o_ctrl_trap | i_branch_op) & i_two_stage_op))) | (i_shift_op & init_done & (i_sh_right | i_sh_done));
assign o_bufreg_en = (o_cnt_en & (o_init | ((o_ctrl_trap | i_branch_op) & i_two_stage_op))) | (i_shift_op & !stage_two_req & (i_sh_right | i_sh_done_r) & init_done);
assign o_ibus_cyc = ibus_cyc & !i_rst;
@ -151,10 +141,14 @@ module serv_state
o_ctrl_jump <= o_init & take_branch;
end
//Need a strobe for the first cycle in the IDLE state after INIT
stage_two_req <= o_cnt_done & o_init;
if (i_rst) begin
if (RESET_STRATEGY != "NONE") begin
init_done <= 1'b0;
o_ctrl_jump <= 1'b0;
stage_two_req <= 1'b0;
end
end
end
@ -186,7 +180,7 @@ module serv_state
reg [3:0] cnt_lsb;
always @(posedge i_clk) begin
o_cnt <= o_cnt + {2'd0,cnt_r[3]};
cnt_lsb <= {cnt_lsb[2:0],(cnt_lsb[3] & !o_cnt_done) | i_rf_ready};
cnt_lsb <= {cnt_lsb[2:0],(cnt_lsb[3] & !o_cnt_done) | (i_rf_ready & !o_cnt_en)};
if (i_rst & (RESET_STRATEGY != "NONE")) begin
o_cnt <= 3'd0;
cnt_lsb <= 4'b0000;
@ -212,15 +206,15 @@ module serv_state
assign o_ctrl_trap = WITH_CSR & (i_e_op | i_new_irq | misalign_trap_sync);
generate
if (WITH_CSR) begin : gen_csr
reg misalign_trap_sync_r;
//trap_pending is only guaranteed to have correct value during the
// last cycle of the init stage
wire trap_pending = WITH_CSR & ((take_branch & i_ctrl_misalign & !ALIGN) |
(i_dbus_en & i_mem_misalign));
generate
if (WITH_CSR) begin : gen_csr
reg misalign_trap_sync_r;
always @(posedge i_clk) begin
if (i_ibus_ack | o_cnt_done | i_rst)
misalign_trap_sync_r <= !(i_ibus_ack | i_rst) & ((trap_pending & o_init) | misalign_trap_sync_r);

View file

@ -1,13 +1,10 @@
`default_nettype none
module serv_top
#(parameter WITH_CSR = 1,
parameter W = 1,
parameter B = W-1,
parameter PRE_REGISTER = 1,
parameter RESET_STRATEGY = "MINI",
parameter RESET_PC = 32'd0,
parameter [0:0] DEBUG = 1'b0,
#(parameter WITH_CSR = 1,
parameter PRE_REGISTER = 1,
parameter RESET_STRATEGY = "MINI",
parameter RESET_PC = 32'd0,
parameter [0:0] MDU = 1'b0,
parameter [0:0] COMPRESSED=0,
parameter [0:0] ALIGN = COMPRESSED)
@ -16,27 +13,27 @@ module serv_top
input wire i_rst,
input wire i_timer_irq,
`ifdef RISCV_FORMAL
output wire rvfi_valid,
output wire [63:0] rvfi_order,
output wire [31:0] rvfi_insn,
output wire rvfi_trap,
output wire rvfi_halt,
output wire rvfi_intr,
output wire [1:0] rvfi_mode,
output wire [1:0] rvfi_ixl,
output wire [4:0] rvfi_rs1_addr,
output wire [4:0] rvfi_rs2_addr,
output wire [31:0] rvfi_rs1_rdata,
output wire [31:0] rvfi_rs2_rdata,
output wire [4:0] rvfi_rd_addr,
output wire [31:0] rvfi_rd_wdata,
output wire [31:0] rvfi_pc_rdata,
output wire [31:0] rvfi_pc_wdata,
output wire [31:0] rvfi_mem_addr,
output wire [3:0] rvfi_mem_rmask,
output wire [3:0] rvfi_mem_wmask,
output wire [31:0] rvfi_mem_rdata,
output wire [31:0] rvfi_mem_wdata,
output reg rvfi_valid = 1'b0,
output reg [63:0] rvfi_order = 64'd0,
output reg [31:0] rvfi_insn = 32'd0,
output reg rvfi_trap = 1'b0,
output reg rvfi_halt = 1'b0,
output reg rvfi_intr = 1'b0,
output reg [1:0] rvfi_mode = 2'b11,
output reg [1:0] rvfi_ixl = 2'b01,
output reg [4:0] rvfi_rs1_addr,
output reg [4:0] rvfi_rs2_addr,
output reg [31:0] rvfi_rs1_rdata,
output reg [31:0] rvfi_rs2_rdata,
output reg [4:0] rvfi_rd_addr,
output reg [31:0] rvfi_rd_wdata,
output reg [31:0] rvfi_pc_rdata,
output reg [31:0] rvfi_pc_wdata,
output reg [31:0] rvfi_mem_addr,
output reg [3:0] rvfi_mem_rmask,
output reg [3:0] rvfi_mem_wmask,
output reg [31:0] rvfi_mem_rdata,
output reg [31:0] rvfi_mem_wdata,
`endif
//RF Interface
output wire o_rf_rreq,
@ -46,12 +43,12 @@ module serv_top
output wire [4+WITH_CSR:0] o_wreg1,
output wire o_wen0,
output wire o_wen1,
output wire [B:0] o_wdata0,
output wire [B:0] o_wdata1,
output wire o_wdata0,
output wire o_wdata1,
output wire [4+WITH_CSR:0] o_rreg0,
output wire [4+WITH_CSR:0] o_rreg1,
input wire [B:0] i_rdata0,
input wire [B:0] i_rdata1,
input wire i_rdata0,
input wire i_rdata1,
output wire [31:0] o_ibus_adr,
output wire o_ibus_cyc,
@ -88,16 +85,17 @@ module serv_top
wire ebreak;
wire branch_op;
wire shift_op;
wire slt_or_branch;
wire rd_op;
wire mdu_op;
wire rd_alu_en;
wire rd_csr_en;
wire rd_mem_en;
wire [B:0] ctrl_rd;
wire [B:0] alu_rd;
wire [B:0] mem_rd;
wire [B:0] csr_rd;
wire ctrl_rd;
wire alu_rd;
wire mem_rd;
wire csr_rd;
wire mtval_pc;
wire ctrl_pc_en;
@ -105,7 +103,7 @@ module serv_top
wire jal_or_jalr;
wire utype;
wire mret;
wire [B:0] imm;
wire imm;
wire trap;
wire pc_rel;
wire iscomp;
@ -119,8 +117,6 @@ module serv_top
wire cnt2;
wire cnt3;
wire cnt7;
wire cnt11;
wire cnt12;
wire cnt_done;
@ -129,8 +125,8 @@ module serv_top
wire bufreg_rs1_en;
wire bufreg_imm_en;
wire bufreg_clr_lsb;
wire [B:0] bufreg_q;
wire [B:0] bufreg2_q;
wire bufreg_q;
wire bufreg2_q;
wire [31:0] dbus_rdt;
wire dbus_ack;
@ -141,11 +137,11 @@ module serv_top
wire alu_cmp;
wire [2:0] alu_rd_sel;
wire [B:0] rs1;
wire [B:0] rs2;
wire rs1;
wire rs2;
wire rd_en;
wire [B:0] op_b;
wire op_b;
wire op_b_sel;
wire mem_signed;
@ -153,23 +149,25 @@ module serv_top
wire mem_half;
wire [1:0] mem_bytecnt;
wire sh_done;
wire sh_done_r;
wire byte_valid;
wire mem_misalign;
wire [B:0] bad_pc;
wire bad_pc;
wire csr_mstatus_en;
wire csr_mie_en;
wire csr_mcause_en;
wire [1:0] csr_source;
wire [B:0] csr_imm;
wire csr_imm;
wire csr_d_sel;
wire csr_en;
wire [1:0] csr_addr;
wire [B:0] csr_pc;
wire csr_pc;
wire csr_imm_en;
wire [B:0] csr_in;
wire [B:0] rf_csr_out;
wire csr_in;
wire rf_csr_out;
wire dbus_en;
wire new_irq;
@ -226,8 +224,7 @@ module serv_top
#(.RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR[0:0]),
.MDU(MDU),
.ALIGN(ALIGN),
.W(W))
.ALIGN(ALIGN))
state
(
.i_clk (clk),
@ -244,8 +241,6 @@ module serv_top
.o_cnt2 (cnt2),
.o_cnt3 (cnt3),
.o_cnt7 (cnt7),
.o_cnt11 (cnt11),
.o_cnt12 (cnt12),
.o_cnt_done (cnt_done),
.o_bufreg_en (bufreg_en),
.o_ctrl_pc_en (ctrl_pc_en),
@ -253,6 +248,7 @@ module serv_top
.o_ctrl_trap (trap),
.i_ctrl_misalign(lsb[1]),
.i_sh_done (sh_done),
.i_sh_done_r (sh_done_r),
.o_mem_bytecnt (mem_bytecnt),
.i_mem_misalign (mem_misalign),
//Control
@ -263,8 +259,7 @@ module serv_top
.i_branch_op (branch_op),
.i_shift_op (shift_op),
.i_sh_right (sh_right),
.i_alu_rd_sel1 (alu_rd_sel[1]),
.i_rd_alu_en (rd_alu_en),
.i_slt_or_branch (slt_or_branch),
.i_e_op (e_op),
.i_rd_op (rd_op),
//MDU
@ -300,6 +295,7 @@ module serv_top
.o_ebreak (ebreak),
.o_branch_op (branch_op),
.o_shift_op (shift_op),
.o_slt_or_branch (slt_or_branch),
.o_rd_op (rd_op),
.o_sh_right (sh_right),
.o_mdu_op (mdu_op),
@ -399,12 +395,11 @@ module serv_top
//State
.i_en (cnt_en),
.i_init (init),
.i_cnt7 (cnt7),
.i_cnt_done (cnt_done),
.i_sh_right (sh_right),
.i_lsb (lsb),
.i_bytecnt (mem_bytecnt),
.i_byte_valid (byte_valid),
.o_sh_done (sh_done),
.o_sh_done_r (sh_done_r),
//Control
.i_op_b_sel (op_b_sel),
.i_shift_op (shift_op),
@ -421,8 +416,7 @@ module serv_top
serv_ctrl
#(.RESET_PC (RESET_PC),
.RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR),
.W (W))
.WITH_CSR (WITH_CSR))
ctrl
(
.clk (clk),
@ -449,7 +443,7 @@ module serv_top
//External
.o_ibus_adr (wb_ibus_adr));
serv_alu #(.W (W)) alu
serv_alu alu
(
.clk (clk),
//State
@ -469,7 +463,7 @@ module serv_top
.o_rd (alu_rd));
serv_rf_if
#(.WITH_CSR (WITH_CSR), .W(W))
#(.WITH_CSR (WITH_CSR))
rf_if
(//RF interface
.i_cnt_en (cnt_en),
@ -487,7 +481,7 @@ module serv_top
//Trap interface
.i_trap (trap),
.i_mret (mret),
.i_mepc (wb_ibus_adr[B:0]),
.i_mepc (wb_ibus_adr[0]),
.i_mtval_pc (mtval_pc),
.i_bufreg_q (bufreg_q),
.i_bad_pc (bad_pc),
@ -518,14 +512,14 @@ module serv_top
.o_csr (rf_csr_out));
serv_mem_if
#(.WITH_CSR (WITH_CSR[0:0]),
.W (W))
#(.WITH_CSR (WITH_CSR[0:0]))
mem_if
(
.i_clk (clk),
//State
.i_bytecnt (mem_bytecnt),
.i_lsb (lsb),
.o_byte_valid (byte_valid),
.o_misalign (mem_misalign),
//Control
.i_mdu_op (mdu_op),
@ -541,8 +535,7 @@ module serv_top
generate
if (|WITH_CSR) begin : gen_csr
serv_csr
#(.RESET_STRATEGY (RESET_STRATEGY),
.W(W))
#(.RESET_STRATEGY (RESET_STRATEGY))
csr
(
.i_clk (clk),
@ -553,8 +546,6 @@ module serv_top
.i_cnt0to3 (cnt0to3),
.i_cnt3 (cnt3),
.i_cnt7 (cnt7),
.i_cnt11 (cnt11),
.i_cnt12 (cnt12),
.i_cnt_done (cnt_done),
.i_mem_op (!mtval_pc),
.i_mtip (i_timer_irq),
@ -577,76 +568,81 @@ module serv_top
.i_rs1 (rs1),
.o_q (csr_rd));
end else begin : gen_no_csr
assign csr_in = {W{1'b0}};
assign csr_rd = {W{1'b0}};
assign csr_in = 1'b0;
assign csr_rd = 1'b0;
assign new_irq = 1'b0;
end
endgenerate
generate
if (DEBUG) begin : gen_debug
serv_debug #(.W (W), .RESET_PC (RESET_PC)) debug
(
`ifdef RISCV_FORMAL
.rvfi_valid (rvfi_valid ),
.rvfi_order (rvfi_order ),
.rvfi_insn (rvfi_insn ),
.rvfi_trap (rvfi_trap ),
.rvfi_halt (rvfi_halt ),
.rvfi_intr (rvfi_intr ),
.rvfi_mode (rvfi_mode ),
.rvfi_ixl (rvfi_ixl ),
.rvfi_rs1_addr (rvfi_rs1_addr ),
.rvfi_rs2_addr (rvfi_rs2_addr ),
.rvfi_rs1_rdata (rvfi_rs1_rdata),
.rvfi_rs2_rdata (rvfi_rs2_rdata),
.rvfi_rd_addr (rvfi_rd_addr ),
.rvfi_rd_wdata (rvfi_rd_wdata ),
.rvfi_pc_rdata (rvfi_pc_rdata ),
.rvfi_pc_wdata (rvfi_pc_wdata ),
.rvfi_mem_addr (rvfi_mem_addr ),
.rvfi_mem_rmask (rvfi_mem_rmask),
.rvfi_mem_wmask (rvfi_mem_wmask),
.rvfi_mem_rdata (rvfi_mem_rdata),
.rvfi_mem_wdata (rvfi_mem_wdata),
.i_dbus_adr (o_dbus_adr),
.i_dbus_dat (o_dbus_dat),
.i_dbus_sel (o_dbus_sel),
.i_dbus_we (o_dbus_we ),
.i_dbus_rdt (i_dbus_rdt),
.i_dbus_ack (i_dbus_ack),
.i_ctrl_pc_en (ctrl_pc_en),
.rs1 (rs1),
.rs2 (rs2),
.rs1_addr (rs1_addr),
.rs2_addr (rs2_addr),
.immdec_en (immdec_en),
.rd_en (rd_en),
.trap (trap),
.i_rf_ready (i_rf_ready),
.i_ibus_cyc (o_ibus_cyc),
.two_stage_op (two_stage_op),
.init (init),
.i_ibus_adr (o_ibus_adr),
`endif
.i_clk (clk),
.i_rst (i_rst),
.i_ibus_rdt (i_ibus_rdt),
.i_ibus_ack (i_ibus_ack),
.i_rd_addr (rd_addr ),
.i_cnt_en (cnt_en ),
.i_csr_in (csr_in ),
.i_csr_mstatus_en (csr_mstatus_en),
.i_csr_mie_en (csr_mie_en ),
.i_csr_mcause_en (csr_mcause_en ),
.i_csr_en (csr_en ),
.i_csr_addr (csr_addr),
.i_wen0 (o_wen0),
.i_wdata0 (o_wdata0),
.i_cnt_done (cnt_done));
end
endgenerate
`ifdef RISCV_FORMAL
reg [31:0] pc = RESET_PC;
wire rs_en = two_stage_op ? init : ctrl_pc_en;
always @(posedge clk) begin
/* End of instruction */
rvfi_valid <= cnt_done & ctrl_pc_en & !i_rst;
rvfi_order <= rvfi_order + {63'd0,rvfi_valid};
/* Get instruction word when it's fetched from ibus */
if (wb_ibus_cyc & wb_ibus_ack)
rvfi_insn <= i_wb_rdt;
/* Store data written to rd */
if (o_wen0)
rvfi_rd_wdata <= {o_wdata0,rvfi_rd_wdata[31:1]};
if (cnt_done & ctrl_pc_en) begin
rvfi_pc_rdata <= pc;
if (!(rd_en & (|rd_addr))) begin
rvfi_rd_addr <= 5'd0;
rvfi_rd_wdata <= 32'd0;
end
end
rvfi_trap <= trap;
if (rvfi_valid) begin
rvfi_trap <= 1'b0;
pc <= rvfi_pc_wdata;
end
/* Not used */
rvfi_halt <= 1'b0;
rvfi_intr <= 1'b0;
rvfi_mode <= 2'd3;
rvfi_ixl = 2'd1;
/* RS1 not valid during J, U instructions (immdec_en[1]) */
/* RS2 not valid during I, J, U instructions (immdec_en[2]) */
if (i_rf_ready) begin
rvfi_rs1_addr <= !immdec_en[1] ? rs1_addr : 5'd0;
rvfi_rs2_addr <= !immdec_en[2] /*rs2_valid*/ ? rs2_addr : 5'd0;
rvfi_rd_addr <= rd_addr;
end
if (rs_en) begin
rvfi_rs1_rdata <= {!immdec_en[1] & rs1,rvfi_rs1_rdata[31:1]};
rvfi_rs2_rdata <= {!immdec_en[2] & rs2,rvfi_rs2_rdata[31:1]};
end
if (i_dbus_ack) begin
rvfi_mem_addr <= o_dbus_adr;
rvfi_mem_rmask <= o_dbus_we ? 4'b0000 : o_dbus_sel;
rvfi_mem_wmask <= o_dbus_we ? o_dbus_sel : 4'b0000;
rvfi_mem_rdata <= i_dbus_rdt;
rvfi_mem_wdata <= o_dbus_dat;
end
if (wb_ibus_ack) begin
rvfi_mem_rmask <= 4'b0000;
rvfi_mem_wmask <= 4'b0000;
end
end
/* verilator lint_off COMBDLY */
always @(wb_ibus_adr)
rvfi_pc_wdata <= wb_ibus_adr;
/* verilator lint_on COMBDLY */
`endif
generate
if (MDU) begin: gen_mdu

View file

@ -18,7 +18,6 @@ filesets:
- rtl/serv_rf_ram_if.v
- rtl/serv_rf_ram.v
- rtl/serv_state.v
- rtl/serv_debug.v
- rtl/serv_top.v
- rtl/serv_rf_top.v
- rtl/serv_aligner.v

View file

@ -218,12 +218,6 @@ filesets:
- servant/servive_clock_gen.v : {file_type : verilogSource}
- servant/servive.v : {file_type : verilogSource}
te0802:
files:
- servant/servant_te0802_clock_gen.v : {file_type : verilogSource}
- servant/servant_te0802.v : {file_type : verilogSource}
- data/te0802.xdc : {file_type : xdc}
tinyfpga_bx: {files: [data/tinyfpga_bx.pcf : {file_type : PCF}]}
ulx3s:
@ -490,6 +484,7 @@ targets:
description : Machdyne Kolibri FPGA Dongle
filesets : [mem_files, soc, machdyne_kolibri]
parameters : [memfile, memsize]
tools:
tools:
icestorm:
nextpnr_options : [--hx4k, --package, bg121, --freq, 48]
@ -585,7 +580,6 @@ targets:
filesets : [soc, servant_tb]
parameters :
- RISCV_FORMAL
- width
- "mdu? (MDU=1)"
- SERV_CLEAR_RAM=true
- firmware
@ -603,15 +597,6 @@ targets:
device : 5CSXFC6D6F31C6
toplevel: servive
te0802:
default_tool: vivado
description : Trenz Electronic TE0802
filesets : [mem_files, soc, te0802]
parameters : [memfile, memsize]
tools:
vivado: {part : xczu2cg-sbva484-1-e}
toplevel : servant_te0802
tinyfpga_bx:
description: TinyFPGA BX
filesets : [mem_files, soc, service, tinyfpga_bx]
@ -664,7 +649,6 @@ targets:
- uart_baudrate
- vcd
- vcd_start
- width
- compressed
- align
- with_csr=1
@ -760,11 +744,6 @@ parameters:
description : Delay start of VCD dumping until the specified time
paramtype : plusarg
width:
datatype : int
description : Interal datapath width (1=SERV, 4=QERV)
paramtype : vlogparam
with_csr:
datatype : int
description : Enable/Disable CSR support

View file

@ -8,9 +8,7 @@ module servant
parameter memfile = "zephyr_hello.hex";
parameter memsize = 8192;
parameter reset_strategy = "MINI";
parameter width = 1;
parameter sim = 0;
parameter [0:0] debug = 1'b0;
parameter with_csr = 1;
parameter [0:0] compress = 0;
parameter [0:0] align = compress;
@ -25,7 +23,7 @@ module servant
localparam aw = $clog2(memsize);
localparam csr_regs = with_csr*4;
localparam rf_width = width * 2;
localparam rf_width = 2;
localparam rf_l2d = $clog2((32+csr_regs)*32/rf_width);
wire timer_irq;
@ -135,9 +133,8 @@ module servant
.o_rdata (rf_rdata));
servile
#(.width (width),
#(.rf_width (rf_width),
.sim (sim[0]),
.debug (debug),
.with_c (compress[0]),
.with_csr (with_csr[0]),
.with_mdu (with_mdu))
@ -162,7 +159,7 @@ module servant
.o_wb_ext_stb (wb_ext_stb),
.i_wb_ext_rdt (wb_ext_rdt),
.i_wb_ext_ack (wb_ext_ack),
.o_rf_waddr (rf_waddr),
.o_rf_wdata (rf_wdata),
.o_rf_wen (rf_wen),

View file

@ -1,33 +0,0 @@
`default_nettype none
module servant_te0802
(
input wire i_clk,
output wire o_uart_tx,
output wire o_led_0
);
parameter memfile = "zephyr_hello.hex";
parameter memsize = 8192;
wire clk;
wire rst;
wire q;
assign o_uart_tx = q;
assign o_led_0 = q;
servant_te0802_clock_gen
clock_gen
(.i_clk (i_clk),
.o_clk (clk),
.o_rst (rst));
servant
#(.memfile (memfile),
.memsize (memsize))
servant
(.wb_clk (clk),
.wb_rst (rst),
.q (q));
endmodule

View file

@ -1,45 +0,0 @@
`default_nettype none
module servant_te0802_clock_gen
(input wire i_clk,
output wire o_clk,
output reg o_rst);
wire clkfb;
wire locked;
reg locked_r;
// Generate a 32 MHz clock from the 25MHz clock input
MMCME4_ADV
#(.DIVCLK_DIVIDE (1),
.CLKFBOUT_MULT_F (48.000),
.CLKOUT0_DIVIDE_F (37.5),
.CLKIN1_PERIOD (40.0), //25MHz
.STARTUP_WAIT ("FALSE"))
mmcm
(.CLKFBOUT (clkfb),
.CLKFBOUTB (),
.CLKOUT0 (o_clk),
.CLKOUT0B (),
.CLKOUT1 (),
.CLKOUT1B (),
.CLKOUT2 (),
.CLKOUT2B (),
.CLKOUT3 (),
.CLKOUT3B (),
.CLKOUT4 (),
.CLKOUT5 (),
.CLKOUT6 (),
.CLKIN1 (i_clk),
.CLKIN2 (1'b0),
.CLKINSEL (1'b1),
.LOCKED (locked),
.PWRDWN (1'b0),
.RST (1'b0),
.CLKFBIN (clkfb));
always @(posedge o_clk) begin
locked_r <= locked;
o_rst <= !locked_r;
end
endmodule

View file

@ -8,17 +8,14 @@
`default_nettype none
module servile
#(
parameter width = 1,
parameter reset_pc = 32'h00000000,
parameter reset_strategy = "MINI",
parameter rf_width = 2*width,
parameter rf_width = 8,
parameter [0:0] sim = 1'b0,
parameter [0:0] debug = 1'b0,
parameter [0:0] with_c = 1'b0,
parameter [0:0] with_csr = 1'b0,
parameter [0:0] with_mdu = 1'b0,
//Internally calculated. Do not touch
parameter B = width-1,
parameter regs = 32+with_csr*4,
parameter rf_l2d = $clog2(regs*32/rf_width))
(
@ -81,13 +78,13 @@ module servile
wire [$clog2(regs)-1:0] wreg1;
wire wen0;
wire wen1;
wire [B:0] wdata0;
wire [B:0] wdata1;
wire wdata0;
wire wdata1;
wire [$clog2(regs)-1:0] rreg0;
wire [$clog2(regs)-1:0] rreg1;
wire rf_ready;
wire [B:0] rdata0;
wire [B:0] rdata1;
wire rdata0;
wire rdata1;
wire [31:0] mdu_rs1;
wire [31:0] mdu_rs2;
@ -152,7 +149,6 @@ module servile
serv_rf_ram_if
#(.width (rf_width),
.W (width),
.reset_strategy (reset_strategy),
.csr_regs (with_csr*4))
rf_ram_if
@ -200,11 +196,9 @@ module servile
serv_top
#(
.WITH_CSR (with_csr?1:0),
.W (width),
.PRE_REGISTER (1'b1),
.RESET_STRATEGY (reset_strategy),
.RESET_PC (reset_pc),
.DEBUG (debug),
.MDU (with_mdu),
.COMPRESSED (with_c))
cpu

View file

@ -61,12 +61,11 @@ module servile_mux
generate
if (sim) begin
integer f = 0;
assign sig_en = |f & i_wb_cpu_we & (i_wb_cpu_adr == sim_sig_adr);
assign halt_en = i_wb_cpu_we & (i_wb_cpu_adr == sim_halt_adr);
reg [1023:0] signature_file;
integer f = 0;
initial
/* verilator lint_off WIDTH */

View file

@ -109,7 +109,6 @@ module serving
servile
#(.reset_pc (32'h0000_0000),
.reset_strategy (RESET_STRATEGY),
.rf_width (rf_width),
.sim (sim),
.with_csr (WITH_CSR))
servile

View file

@ -1,7 +1,7 @@
TOOLCHAIN_PREFIX?=riscv64-unknown-elf-
%.elf: %.S link.ld
$(TOOLCHAIN_PREFIX)gcc -nostartfiles -nostdlib -march=rv32i_zicsr -mabi=ilp32 -Tlink.ld -o$@ $<
$(TOOLCHAIN_PREFIX)gcc -nostartfiles -nostdlib -march=rv32i -mabi=ilp32 -Tlink.ld -o$@ $<
%.bin: %.elf
$(TOOLCHAIN_PREFIX)objcopy -O binary $< $@
%.hex: %.bin

View file

@ -1,12 +1,15 @@
OUTPUT_ARCH( "riscv" )
ENTRY(rvtest_entry_point)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);
.tohost : { *(.tohost) }
. = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(0x1000);
.data : { *(.data) }
.data.string : { *(.data.string)}
.bss : { *(.bss) }

View file

@ -48,7 +48,12 @@
.align 4; .global end_signature; end_signature: \
#define RVMODEL_BOOT
#define RVMODEL_BOOT \
.section .text.init; \
.align 4; \
.globl _start; \
_start:
#define LOCAL_IO_WRITE_STR(_STR) RVMODEL_IO_WRITE_STR(x31, _STR)
#define RVMODEL_IO_WRITE_STR(_SP, _STR)
@ -63,4 +68,4 @@
#define RVMODEL_CLEAR_MTIMER_INT
#define RVMODEL_CLEAR_MEXT_INT
#endif // _COMPLIANCE_MODEL_H
#endif // _COMPLIANCE_MODEL_H

View file

@ -5,5 +5,5 @@ manifest:
projects:
- name: zephyr
remote: zephyrproject-rtos
revision: v4.0.0
revision: v3.5.0
import: true

View file

@ -8,7 +8,6 @@
#include <zephyr/arch/cpu.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <soc.h>
#define DT_DRV_COMPAT olofk_serial

View file

@ -4,5 +4,4 @@
zephyr_sources(
soc_irq.S
vector.S
cpu_idle.c
irq.c)

View file

@ -23,16 +23,4 @@ config SERV_TIMER
bool
default y
config ARCH_HAS_CUSTOM_CPU_IDLE
bool
default y
config ARCH_HAS_CUSTOM_CPU_ATOMIC_IDLE
bool
default y
config RISCV_SOC_EXCEPTION_FROM_IRQ
bool
default y
endif # SOC_RISCV32_SERVANT

View file

@ -1,22 +0,0 @@
#include <zephyr/irq.h>
#include <zephyr/tracing/tracing.h>
// Override arch_cpu_idle() and arch_cpu_atomic_idle() to prevent insertion
// of `wfi` instructions, which lock up our system. This was introduced in
// Zephyr 3.6.0 with commit 5fb6e267f629dedb8382da6bcad8018b1bb8930a.
//
// This is probably a hardware bug in SERV. This issue is tracked as #131.
// https://github.com/olofk/serv/issues/131
void arch_cpu_idle(void)
{
sys_trace_idle();
irq_unlock(MSTATUS_IEN);
}
void arch_cpu_atomic_idle(unsigned int key)
{
sys_trace_idle();
irq_unlock(key);
}