Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 34 additions & 34 deletions hdl/rtl/hamster/r5p_hamster.sv
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ assign add_zro = add_sum[32-1:0] == 32'd0;
///////////////////////////////////////////////////////////////////////////////

always_comb
unique case (idu_buf.alu.fn3)
unique case (idu_buf.fn3)
// bitwise logical operations
AND : log_val = log_op1 & log_op2;
OR : log_val = log_op1 | log_op2;
Expand All @@ -283,7 +283,7 @@ endfunction

// bit inversion
always_comb
unique case (idu_buf.alu.fn3)
unique case (idu_buf.fn3)
// barrel shifter
SR : shf_tmp = shf_op1 ;
SL : shf_tmp = bitrev(shf_op1);
Expand All @@ -292,7 +292,7 @@ endcase

// sign extension to (32+1)
always_comb
unique case (idu_buf.alu.fn7[5])
unique case (idu_buf.fn7[5])
1'b1 : shf_ext = {shf_tmp[32-1], shf_tmp};
1'b0 : shf_ext = {1'b0 , shf_tmp};
endcase
Expand Down Expand Up @@ -341,7 +341,7 @@ end else begin
// progress into the next state
if (ctl_run & (bus_trn | ~bus_vld)) begin
// GPR (write rd)
gpr_wad <= idu_buf.gpr.adr.rd;
gpr_wad <= idu_buf.rd;
// system bus
unique case (ctl_fsm)
// instruction fetch state
Expand All @@ -350,7 +350,7 @@ end else begin
ctl_fsm <= SLS;
// PC: program counter
// TODO: PC is only reloaded if the prediction is correct
if ((idu_buf.opc == BRANCH) && (idu_buf.bru.imm[12] != bru_tkn)) begin
if ((idu_buf.opc == BRANCH) && (idu_buf.i_b[12] != bru_tkn)) begin
// on mispredicted branch ignore the fetched instruction
end else begin
ifu_pcr <= bus_adr;
Expand All @@ -370,7 +370,7 @@ end else begin
bus_vld <= 1'b0;
// GPR
gpr_wen <= 1'b1;
bus_wdt <= idu_buf.uiu;
bus_wdt <= idu_buf.i_u;
end
AUIPC : begin
// TCB
Expand All @@ -384,7 +384,7 @@ end else begin
bus_vld <= 1'b1;
bus_wen <= 1'b0;
bus_adr <= {add_sum[32-1:2], 2'b00};
case (idu_buf.ldu.fn3)
case (idu_buf.fn3)
LB, LBU: case (add_sum[1:0])
2'b00: bus_ben <= 4'b0001;
2'b01: bus_ben <= 4'b0010;
Expand All @@ -403,14 +403,14 @@ end else begin
gpr_wen <= 1'b0;
// read data multiplexer
rdm_adr <= add_sum[ 2-1:0];
rdm_fn3 <= idu_buf.ldu.fn3;
rdm_fn3 <= fn3_ldu_et'(idu_buf.fn3);
end
STORE : begin
// TCB
bus_vld <= 1'b1;
bus_wen <= 1'b1;
bus_adr <= {add_sum[32-1:2], 2'b00};
case (idu_buf.stu.fn3)
case (idu_buf.fn3)
SB : case (add_sum[1:0])
2'b00: begin bus_wdt[ 7: 0] <= gpr_rdt[ 7: 0]; bus_ben <= 4'b0001; end
2'b01: begin bus_wdt[15: 8] <= gpr_rdt[ 7: 0]; bus_ben <= 4'b0010; end
Expand Down Expand Up @@ -454,7 +454,7 @@ end else begin
// FSM control (go to the next state)
ctl_fsm <= SIF;
// instruction buffer
if ((idu_buf.opc == BRANCH) && (idu_buf.bru.imm[12] != buf_tkn)) begin
if ((idu_buf.opc == BRANCH) && (idu_buf.i_b[12] != buf_tkn)) begin
// on mispredicted branch ignore the fetched instruction
ifu_buf <= NOP;
end else begin
Expand Down Expand Up @@ -522,7 +522,7 @@ begin
SIF: begin
// GPR (read rs1)
gpr_ren = 1'b1;
gpr_rad = idu_buf.gpr.adr.rs2;
gpr_rad = idu_buf.rs2;
// LOAD: read data multiplexer
rdm_dtw = bus_rdt[31: 0];
rdm_dth = rdm_adr[1] ? rdm_dtw[31:16] : rdm_dtw[15: 0];
Expand Down Expand Up @@ -552,27 +552,27 @@ begin
// adder
add_inc = 1'b0;
add_op1 = ext_sgn(bus_wdt);
add_op2 = ext_sgn(idu_buf.uiu.imm);
add_op2 = ext_sgn(idu_buf.i_u);
end
LOAD : begin
// adder for load address
add_inc = 1'b0;
add_op1 = ext_sgn(bus_wdt);
add_op2 = ext_sgn(32'(idu_buf.ldu.imm));
add_op2 = ext_sgn(32'(idu_buf.i_l));
end
STORE : begin
// adder for store address
add_inc = 1'b0;
add_op1 = ext_sgn(bus_wdt);
add_op2 = ext_sgn(32'(idu_buf.stu.imm));
add_op2 = ext_sgn(32'(idu_buf.i_s));
end
OP : begin
// arithmetic operations
case (idu_buf.alu.fn3)
case (idu_buf.fn3)
ADD : begin
add_inc = idu_buf.alu.fn7[5];
add_inc = idu_buf.fn7[5];
add_op1 = ext_sgn(bus_wdt);
add_op2 = ext_sgn(gpr_rdt ^ {32{idu_buf.alu.fn7[5]}});
add_op2 = ext_sgn(gpr_rdt ^ {32{idu_buf.fn7[5]}});
end
SLT : begin
add_inc = 1'b1;
Expand All @@ -596,36 +596,36 @@ begin
end
OP_IMM : begin
// arithmetic operations
case (idu_buf.alu.fn3)
case (idu_buf.fn3)
ADD : begin
add_inc = 1'b0;
add_op1 = ext_sgn(bus_wdt);
add_op2 = ext_sgn(32'(idu_buf.alu.imm));
add_op2 = ext_sgn(32'(idu_buf.i_i));
end
SLT : begin
add_inc = 1'b1;
add_op1 = ext_sgn( bus_wdt);
add_op2 = ext_sgn(~32'(idu_buf.alu.imm));
add_op2 = ext_sgn(~32'(idu_buf.i_i));
end
SLTU : begin
add_inc = 1'b1;
add_op1 = {1'b0, bus_wdt};
add_op2 = {1'b1, ~32'(idu_buf.alu.imm)};
add_op2 = {1'b1, ~32'(idu_buf.i_i)};
end
default: begin
end
endcase
// logic operations
log_op1 = bus_wdt;
log_op2 = 32'(idu_buf.alu.imm);
log_op2 = 32'(idu_buf.i_i);
// shift operations
shf_op1 = bus_wdt;
shf_op2 = idu_buf.alu.imm[5-1:0];
shf_op2 = idu_buf.i_i[5-1:0];
end
BRANCH : begin
// subtraction
add_inc = 1'b1;
unique case (idu_buf.bru.fn3)
unique case (idu_buf.fn3)
BEQ ,
BNE ,
BLT ,
Expand All @@ -643,7 +643,7 @@ begin
add_op2 = 33'dx;
end
endcase
unique case (idu_buf.bru.fn3)
unique case (idu_buf.fn3)
BEQ : bru_tkn = add_zro;
BNE : bru_tkn = ~add_zro;
BLT : bru_tkn = add_sgn;
Expand All @@ -657,7 +657,7 @@ begin
end
endcase
// ALU output
case (idu_buf.alu.fn3)
case (idu_buf.fn3)
// adder based inw_bufuctions
ADD : alu_out = add_sum[32-1:0];
SLT ,
Expand All @@ -677,16 +677,16 @@ begin
SLS: begin
// GPR (read rs1)
gpr_ren = 1'b1;
gpr_rad = idu_rdt.gpr.adr.rs1;
gpr_rad = idu_rdt.rs1;
gpr_wdt = bus_wdt;
// decode operation code
if ((idu_buf.opc == BRANCH) && (idu_buf.bru.imm[12] != buf_tkn)) begin
if ((idu_buf.opc == BRANCH) && (idu_buf.i_b[12] != buf_tkn)) begin
// on mispredicted branch reverse static branch prediction decisions
if (~idu_buf.bru.imm[12]) begin
if (~idu_buf.i_b[12]) begin
// backward branches are predicted taken
add_inc = 1'b0;
add_op1 = 33'(ifu_pcr);
add_op2 = 33'(idu_buf.bru.imm);
add_op2 = 33'(idu_buf.i_b);
end else begin
// forward branches are predicted not taken
add_inc = 1'b0;
Expand All @@ -702,20 +702,20 @@ begin
JAL : begin
add_inc = 1'b0;
add_op1 = 33'(ifu_pcr);
add_op2 = 33'(idu_rdt.jmp.jmp);
add_op2 = 33'(idu_rdt.i_j);
end
JALR : begin
add_inc = 1'b0;
add_op1 = 33'(gpr_rdt);
add_op2 = 33'(idu_rdt.jmp.imm);
add_op2 = 33'(idu_rdt.i_i);
end
BRANCH : begin
// static branch prediction
if (idu_rdt.bru.imm[12]) begin
if (idu_rdt.i_b[12]) begin
// backward branches are predicted taken
add_inc = 1'b0;
add_op1 = 33'(ifu_pcr);
add_op2 = 33'(idu_rdt.bru.imm);
add_op2 = 33'(idu_rdt.i_b);
end else begin
// forward branches are predicted not taken
add_inc = 1'b0;
Expand Down
8 changes: 6 additions & 2 deletions hdl/rtl/riscv/riscv_isa_i_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,14 @@ typedef enum {
// decoder structure
///////////////////////////////////////////////////////////////////////////////

typedef struct {
// `packed` (and `siz` a fixed-width vector rather than `integer`) so the
// decoder struct is a bit-addressable type: r5p_* modules take `dec_t` as a
// PORT, and synthesis / Yosys can only map a flat netlist port onto a struct
// port when the struct is packed.
typedef struct packed {
// instruction encodings
ill_t ill; // illegal
integer siz; // instruction size
logic signed [31:0] siz; // instruction size
opc_t opc; // operation code
fn3_t fn3; // func3
fn7_t fn7; // func7
Expand Down
6 changes: 4 additions & 2 deletions hdl/rtl/riscv/riscv_isa_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ typedef enum logic [$bits(isa_ext_t)-1:0] {
} isa_ext_et;

// ISA specification configuration
// TODO: change when Verilator supports unpacked structures
typedef struct {
// made `packed` so the enum below can use `logic [$bits(isa_spec_t)-1:0]` as
// its base and drive it through synthesis / Yosys as a flat vector (the
// upstream "change when Verilator supports unpacked structures" TODO).
typedef struct packed {
isa_base_t base;
isa_ext_t ext;
} isa_spec_t;
Expand Down
5 changes: 5 additions & 0 deletions syn/uhdm2rtlil/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# build / run artifacts
work/
mem_if.mem
*.log
slpp_all/
104 changes: 104 additions & 0 deletions syn/uhdm2rtlil/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# rp32 — Yosys synthesis via UHDM/Surelog (uhdm2rtlil)

This directory adds a **Yosys synthesis flow driven by the Surelog SystemVerilog
front end** ([uhdm2rtlil](https://github.com/alainmarcel/uhdm2rtlil)), alongside
the existing `syn/` (Yosys‑slang) and `fpga/*/yosys` flows.

Surelog parses the design to UHDM and the uhdm2rtlil plugin imports it to Yosys
RTLIL (`read_sv`), so the full IEEE‑1800 SystemVerilog the rp32 cores use
(packages, structs, interfaces) is synthesisable through Yosys.

The gate‑level result is **verified by co‑simulation**: the synthesized netlist
is run against the original RTL under Verilator and the outputs are compared
every cycle — the same methodology uhdm2rtlil uses for designs the native Yosys
Verilog front end cannot parse.

## Prerequisites

* A **built** [uhdm2rtlil](https://github.com/alainmarcel/uhdm2rtlil) checkout
(provides `out/current/bin/yosys`, `build/uhdm2rtlil.so`, and the Yosys
`simcells.v`). Point `UHDM2RTLIL_ROOT` at it (defaults to `~/uhdm2rtlil`):

```bash
export UHDM2RTLIL_ROOT=/path/to/uhdm2rtlil
```

* **Verilator 5.x** in `PATH` (for the co‑simulation) — the repo's
`submodules/verilator` build works; see `settings-verilator.sh`.

## Usage

```bash
cd syn/uhdm2rtlil

./build.sh --list # list the catalogued designs
./build.sh mouse_soc_simple # synthesise one design (work/<top>_uhdm.v/.json)
./cosim.sh # gate-level co-sim of the Mouse simple SoC
./run.sh # synthesise ALL designs + co-sim, print a table
```

The design catalog (cores + SoCs) lives in `designs.sh`; `build.sh <name>` picks
one. The full SoCs need the TCB submodule:

```bash
git submodule update --init submodules/tcb
```

## Design status

`./run.sh` synthesises every design and co-simulates the ones with a
deterministic self-contained testbench:

| design | synth | co-sim | notes |
|---------------------|:-----:|:------:|-------|
| `mouse` | ✅ | (det.) | standalone core; only deterministic streams are equiv-able |
| `mouse_soc_simple` | ✅ | ✅ **PASS** | complete Mouse SoC, inline RAM — 0 mismatches / 6000 cyc |
| `mouse_soc` | ⚠️ | n/a | full Mouse SoC synthesises but is functionally stuck — the TCB **interface-config** struct refs (`sub.CFG.HSK.DLY`, `sub.MOD`) are unresolved (front-end limitation); Verilator can't build the interface RTL either, so no co-sim |
| `degu` | ⚠️ | n/a | core synthesises with unresolved TCB interface-config reads |
| `degu_soc` | ⚠️ | n/a | as above |
| `hamster` | ⚠️ | n/a | core synthesises with unresolved decoder-struct reads (`idu_rdt.jmp.jmp`) |

✅ = clean; ⚠️ = produces a netlist but with unresolved struct/interface reads
(undriven wires ⇒ not functionally correct yet). The remaining gaps are all
SystemVerilog-interface-config resolution in the UHDM front end.

## The memory‑preserving synthesis flow

A design with an initialised ROM/RAM (`$readmemh`) **must not** be run through
the plain `synth` / `synth_*` shortcut: those run `opt_mem`, which trims an
initialised memory to its "used" width and mangles the `$meminit` constant
(e.g. `0x800200B7` → garbage), so the fetched program reads back wrong and the
CPU never boots. `build.sh` therefore drives the passes explicitly:

```
read_sv → proc → flatten → memory_collect (no opt_mem / memory -nomap)
→ opt -full → techmap → dfflegalize → abc → opt_clean
```

`flatten` **before** `memory_collect` is what lets the `$readmemh` init reach
the combinational read port.

## Files

| file | purpose |
|-----------------|------------------------------------------------------------------|
| `designs.sh` | design catalog: name → sources + top (cores + SoCs) |
| `build.sh` | synthesise one design through uhdm2rtlil (memory‑preserving flow)|
| `run.sh` | synthesise all designs + co‑sim, print a status table |
| `cosim.sh` | synth + Verilator co‑simulation (RTL vs gate netlist) |
| `cosim_tb.sv` | testbench: RTL and gate netlist side by side, per‑cycle compare |
| `cosim_main.cpp`| Verilator driver (reset, free‑run, exit non‑zero on mismatch) |
| `boot.hex` | tiny deterministic boot program (GPIO writes) for the SoC RAM |

`work/` (netlists, logs, Verilator objects) is generated and git‑ignored.

## Notes

* The **complete Mouse SoC** co‑simulates cleanly because its boot program is
deterministic. The **standalone `r5p_mouse` core** synthesises correctly too,
but under *random* instruction stimulus it diverges on the design's own `'x`
don't‑cares (illegal opcodes), so only a deterministic instruction stream is a
meaningful equivalence check for it — use the SoC for the end‑to‑end gate check.
* This flow depends on two uhdm2rtlil front‑end fixes for the rp32 cores: comb
`case` blocking‑read value threading, and byte‑enable (`mem[a][hi:lo] <= …`)
memory‑write emission. Use a uhdm2rtlil build that includes them.
6 changes: 6 additions & 0 deletions syn/uhdm2rtlil/boot.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
800200b7
05a00113
0020a023
0ff00113
0020a023
0000006f
Loading