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
6 changes: 3 additions & 3 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ variables:
VSIM: 'questa-2025.1 vsim'
VCS: 'vcs-2025.06 vcs'
VLOGAN: 'vcs-2025.06 vlogan'
PEAKRDL: '/home/fischeti/.local/bin/uv run peakrdl'
PEAKRDL: '/usr/local/uv/uv run peakrdl'
UV_LINK_MODE: copy

stages:
Expand All @@ -18,7 +18,7 @@ stages:
build-vsim:
stage: build
script:
- make slink-gen-regs-all SLINK_NUM_CHANNELS=${NUM_CHANNELS}
- make slink-gen-regs SLINK_NUM_CHANNELS=${NUM_CHANNELS}
- make vsim-compile WORK=work_${NUM_CHANNELS} | tee compile.log 2>&1
- '! grep "\*\* Error" compile.log'
parallel:
Expand All @@ -31,7 +31,7 @@ build-vsim:
build-vcs:
stage: build
script:
- make slink-gen-regs-all SLINK_NUM_CHANNELS=${NUM_CHANNELS}
- make slink-gen-regs SLINK_NUM_CHANNELS=${NUM_CHANNELS}
- make bin/${TB_DUT}_${NUM_CHANNELS}.vcs
parallel:
matrix:
Expand Down
5 changes: 4 additions & 1 deletion Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ sources:
- src/slink_phys_layer.sv

# Serial Link main module
- src/slink.sv
- include_dirs:
- src/include
files:
- src/slink.sv

# Wrapper for additional isolation
- src/slink_isolate.sv
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ The Serial Link is released under Solderpad v0.51 (SHL-0.51) see [`LICENSE`](LIC

### 🔗 Dependencies

The link uses [bender](https://github.com/pulp-platform/bender) to manage its dependencies and to automatically generate compilation scripts. If you want to change the configuration of the serial link, you need to regenerate the register files, which requires `Python >= 3.11` and the [peakrdl](https://peakrdl-regblock.readthedocs.io/en/latest/) package. For standalone usages of the link with the testbenches, you need additional dependencies (see [pyproject.toml](pyproject.toml)) and we recommend to use [uv](https://docs.astral.sh/uv/) to manage them (see also [CI configuration](.github/workflows/lint.yml)).
The link uses [bender](https://github.com/pulp-platform/bender) to manage its dependencies and to automatically generate compilation scripts. If you want to change the configuration of the serial link, you need to regenerate the register files, which requires `Python >= 3.11` and the [peakrdl](https://peakrdl-regblock.readthedocs.io/en/latest/) package. You can install the dependencies with pip:

```sh
pip install .
```

### 💡 Integration

Expand Down Expand Up @@ -64,8 +68,6 @@ The link can be parametrized with arbitrary AXI interfaces resp. structs (`axi_r
```sh
# Generates the registers for the desired configuration
make slink-gen-regs SLINK_NUM_CHANNELS=<num_channels> SLINK_NUM_LANES=<num_lanes>
# Additionall generates the address-map header file required for some testbenches
make slink-gen-regs-all SLINK_NUM_CHANNELS=<num_channels> SLINK_NUM_LANES=<num_lanes>
```

The registers are generated with [peakrdl](https://peakrdl-regblock.readthedocs.io/en/latest/) with the parametrized SystemRDL config file [`slink_reg.rdl`](src/regs/slink_reg.rdl).
Expand Down
6 changes: 1 addition & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ description = "A simple, scalable, source-synchronous, all-digital DDR link"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"mako>=1.3.10",
"peakrdl>=1.5.0",
"peakrdl-rawheader",
"peakrdl-rawheader>=0.1.1",
]

[tool.uv.sources]
peakrdl-rawheader = { git = "https://github.com/micprog/PeakRDL-rawheader.git" }
5 changes: 2 additions & 3 deletions slink.mk
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,5 @@ $(SLINK_ROOT)/src/regs/slink_addrmap.svh: $(SLINK_ROOT)/src/regs/slink_reg.rdl $
$(PEAKRDL) raw-header $< -o $@ --format svh $(SLINK_PEAKRDL_PARAMS)
@sed -i '1i$(SLINK_COPYRIGHT_NOTICE)' $@

.PHONY: slink-gen-regs slink-gen-regs-all
slink-gen-regs-all: $(SLINK_ROOT)/src/regs/slink_reg.sv $(SLINK_ROOT)/src/regs/slink_addrmap.svh
slink-gen-regs: $(SLINK_ROOT)/src/regs/slink_reg.sv
.PHONY: slink-gen-regs
slink-gen-regs: $(SLINK_ROOT)/src/regs/slink_reg.sv $(SLINK_ROOT)/src/regs/slink_addrmap.svh
15 changes: 15 additions & 0 deletions src/include/rdl_assign.svh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2025 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51

`define SLINK_ASSIGN_RDL_RD_ACK(field, hw2reg = hw2reg, reg2hw = reg2hw) \
assign hw2reg.field.rd_ack = reg2hw.field.req & ~reg2hw.field.req_is_wr;

`define SLINK_ASSIGN_RDL_WR_ACK(field, hw2reg = hw2reg, reg2hw = reg2hw) \
assign hw2reg.field.wr_ack = reg2hw.field.req & reg2hw.field.req_is_wr;

`define SLINK_SET_RDL_RD_ACK(field, hw2reg = hw2reg, reg2hw = reg2hw) \
hw2reg.field.rd_ack = reg2hw.field.req & ~reg2hw.field.req_is_wr;

`define SLINK_SET_RDL_WR_ACK(field, hw2reg = hw2reg, reg2hw = reg2hw) \
hw2reg.field.wr_ack = reg2hw.field.req & reg2hw.field.req_is_wr;
74 changes: 35 additions & 39 deletions src/slink.sv
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
`include "common_cells/registers.svh"
`include "common_cells/assertions.svh"
`include "axi_stream/typedef.svh"
`include "rdl_assign.svh"

/// A simple serial link to go off-chip
module slink
Expand Down Expand Up @@ -187,12 +188,14 @@ module slink
& reg2hw.raw_mode_out_data_fifo_ctrl.req_is_wr
& reg2hw.raw_mode_out_data_fifo_ctrl.wr_biten.clear;
for (genvar i = 0; i < NumChannels; i++) begin : gen_raw_mode_in_data_valid
assign hw2reg.raw_mode_in_data_valid[i].rd_data.raw_mode_in_data_valid =
raw_mode_in_data_valid[i];
assign raw_mode_out_ch_mask[i] =
reg2hw.raw_mode_out_ch_mask[i].raw_mode_out_ch_mask.value;
end

phy_data_t raw_mode_in_data_out;
logic [$clog2(RawModeFifoDepth)-1:0] raw_mode_out_data_fill_state;
logic raw_mode_out_data_is_full;

slink_link_layer #(
.axis_req_t ( axis_req_t ),
.axis_rsp_t ( axis_rsp_t ),
Expand Down Expand Up @@ -220,8 +223,7 @@ module slink
.cfg_raw_mode_en_i ( reg2hw.raw_mode_en.raw_mode_en.value ),
.cfg_raw_mode_in_ch_sel_i (
reg2hw.raw_mode_in_ch_sel.raw_mode_in_ch_sel.value[cf_math_pkg::idx_width(NumChannels)-1:0] ),
.cfg_raw_mode_in_data_o (
hw2reg.raw_mode_in_data.rd_data.raw_mode_in_data ),
.cfg_raw_mode_in_data_o ( raw_mode_in_data_out ),
.cfg_raw_mode_in_data_valid_o ( raw_mode_in_data_valid ),
.cfg_raw_mode_in_data_ready_i (
reg2hw.raw_mode_in_data.req & ~reg2hw.raw_mode_in_data.req_is_wr ),
Expand All @@ -232,12 +234,28 @@ module slink
.cfg_raw_mode_out_en_i (
reg2hw.raw_mode_out_en.raw_mode_out_en.value ),
.cfg_raw_mode_out_data_fifo_clear_i ( cfg_raw_mode_out_data_fifo_clear ),
.cfg_raw_mode_out_data_fifo_fill_state_o (
hw2reg.raw_mode_out_data_fifo_ctrl.rd_data.fill_state ),
.cfg_raw_mode_out_data_fifo_is_full_o (
hw2reg.raw_mode_out_data_fifo_ctrl.rd_data.is_full )
.cfg_raw_mode_out_data_fifo_fill_state_o ( raw_mode_out_data_fill_state ),
.cfg_raw_mode_out_data_fifo_is_full_o ( raw_mode_out_data_is_full )
);

always_comb begin
hw2reg.raw_mode_in_data.rd_data = '0;
hw2reg.raw_mode_in_data.rd_data.raw_mode_in_data = raw_mode_in_data_out;
hw2reg.raw_mode_out_data_fifo_ctrl.rd_data = '0;
hw2reg.raw_mode_out_data_fifo_ctrl.rd_data.fill_state = raw_mode_out_data_fill_state;
hw2reg.raw_mode_out_data_fifo_ctrl.rd_data.is_full = raw_mode_out_data_is_full;
for (int i = 0; i < NumChannels; i++) begin
hw2reg.raw_mode_in_data_valid[i].rd_data = '0;
hw2reg.raw_mode_in_data_valid[i].rd_data.raw_mode_in_data_valid = raw_mode_in_data_valid[i];
`SLINK_SET_RDL_RD_ACK(raw_mode_in_data_valid[i])
end
end

`SLINK_ASSIGN_RDL_RD_ACK(raw_mode_in_data)
`SLINK_ASSIGN_RDL_RD_ACK(raw_mode_out_data_fifo_ctrl)
`SLINK_ASSIGN_RDL_WR_ACK(raw_mode_out_data_fifo_ctrl)
`SLINK_ASSIGN_RDL_WR_ACK(flow_control_fifo_clear)

`FF(raw_mode_out_data_valid, reg2hw.raw_mode_out_data_fifo.raw_mode_out_data_fifo.swmod, '0)

///////////////////////
Expand Down Expand Up @@ -400,40 +418,18 @@ module slink
assign reset_no = reg2hw.ctrl.reset_n.value;
assign isolate_o = {reg2hw.ctrl.axi_out_isolate.value,
reg2hw.ctrl.axi_in_isolate.value};
assign hw2reg.isolated.rd_data.axi_in = isolated_i[0];
assign hw2reg.isolated.rd_data.axi_out = isolated_i[1];

assign hw2reg.isolated.rd_ack = reg2hw.isolated.req
& ~reg2hw.isolated.req_is_wr;
assign hw2reg.isolated.rd_data._reserved_31_2 = '0;
for (genvar i = 0; i < NumChannels; i++) begin : gen_static_raw_mode_in_data_valid
assign hw2reg.raw_mode_in_data_valid[i].rd_ack =
reg2hw.raw_mode_in_data_valid[i].req
& ~reg2hw.raw_mode_in_data_valid[i].req_is_wr;
assign hw2reg.raw_mode_in_data_valid[i].rd_data._reserved_31_1 = '0;

always_comb begin
hw2reg.isolated.rd_data = '0;
hw2reg.isolated.rd_data.axi_in = isolated_i[0];
hw2reg.isolated.rd_data.axi_out = isolated_i[1];
end
assign hw2reg.raw_mode_in_data.rd_ack = reg2hw.raw_mode_in_data.req
& ~reg2hw.raw_mode_in_data.req_is_wr;
assign hw2reg.raw_mode_in_data.rd_data._reserved_31_16 = '0;
assign hw2reg.raw_mode_out_data_fifo_ctrl.rd_ack =
reg2hw.raw_mode_out_data_fifo_ctrl.req
& ~reg2hw.raw_mode_out_data_fifo_ctrl.req_is_wr;
assign hw2reg.raw_mode_out_data_fifo_ctrl.wr_ack =
reg2hw.raw_mode_out_data_fifo_ctrl.req
& reg2hw.raw_mode_out_data_fifo_ctrl.req_is_wr;
assign hw2reg.raw_mode_out_data_fifo_ctrl.rd_data._reserved_7_0 = '0;
assign hw2reg.raw_mode_out_data_fifo_ctrl.rd_data._reserved_30_11 = '0;
assign hw2reg.flow_control_fifo_clear.wr_ack =
reg2hw.flow_control_fifo_clear.req
& reg2hw.flow_control_fifo_clear.req_is_wr;

`SLINK_ASSIGN_RDL_RD_ACK(isolated)

if (EnChAlloc) begin : gen_channel_alloc_regs
assign hw2reg.channel_alloc_tx_ctrl.wr_ack =
reg2hw.channel_alloc_tx_ctrl.req
& reg2hw.channel_alloc_tx_ctrl.req_is_wr;
assign hw2reg.channel_alloc_rx_ctrl.wr_ack =
reg2hw.channel_alloc_rx_ctrl.req
& reg2hw.channel_alloc_rx_ctrl.req_is_wr;
`SLINK_ASSIGN_RDL_WR_ACK(channel_alloc_tx_ctrl)
`SLINK_ASSIGN_RDL_WR_ACK(channel_alloc_rx_ctrl)
end else begin : gen_no_channel_alloc_regs
assign hw2reg.channel_alloc_tx_ctrl = '{default: '0};
assign hw2reg.channel_alloc_rx_ctrl = '{default: '0};
Expand Down
2 changes: 1 addition & 1 deletion util/wave.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ for {set i 1} {$i < 3} {incr i} {

add wave -noupdate -expand -group $group_name -ports /$tb_name/i_serial_link_$i/i_serial_link/*

add wave -noupdate -group $group_name -group {NETWORK} /$tb_name/i_serial_link_$i/i_serial_link/i_serial_link_network/*
add wave -noupdate -group $group_name -group {NETWORK} /$tb_name/i_serial_link_$i/i_serial_link/i_serial_link_protocol/*

add wave -noupdate -group $group_name -group {LINK} /$tb_name/i_serial_link_$i/i_serial_link/i_serial_link_data_link/*

Expand Down
Loading