Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ec7a63d
Update gitignore
robtaylor Oct 16, 2025
da89304
Start of experiment with toml binding of verilog/generated verilog
robtaylor Nov 7, 2025
1de7360
Sort out typing
robtaylor Nov 9, 2025
901f2e5
wip: verilog binding
robtaylor Nov 9, 2025
3a5b13b
More typing
robtaylor Nov 10, 2025
4caec9e
mergeme: typing
robtaylor Nov 10, 2025
7406bac
wip: more autobinding
robtaylor Nov 12, 2025
98493a0
feat: complete TOML-based Verilog wrapper system
claude Dec 17, 2025
5dc106f
feat: add SystemVerilog support with sv2v conversion
claude Dec 17, 2025
1f6b759
feat: add SoftwareDriverSignature and port direction support
claude Dec 30, 2025
701c7ac
feat: add auto-mapping for well-known interfaces
claude Dec 30, 2025
24b15f9
refactor: auto-mapping infers from Verilog signal names
claude Dec 30, 2025
262ec97
feat: add integration tests for wb_timer peripheral
claude Dec 30, 2025
c678b0f
feat: add yosys-slang generator for SystemVerilog conversion
claude Dec 30, 2025
6e8d5f0
fix: yowasp-yosys has slang built-in, no plugin loading needed
claude Dec 30, 2025
ed64920
feat: add yowasp-yosys dependency for SystemVerilog support
claude Jan 2, 2026
e756e72
fix: resolve path relative to TOML file, fix tests for yowasp-yosys
claude Jan 2, 2026
c368f05
chore: ignore .python-version file
claude Jan 2, 2026
12f89e7
fix: use commit hash instead of branch name for pythondata-misc-usb_ohci
robtaylor Jan 13, 2026
321b783
fix: add amaranth-stubs as runtime dependency
robtaylor Jan 14, 2026
29b4eb0
fix: add signal binding validation and fix Verilog port parsing
robtaylor Jan 14, 2026
1bee88a
fix: resolve ruff linting errors
robtaylor Jan 14, 2026
e4855fe
docs: add simulation architecture analysis with validated CXXRTL pipe…
robtaylor Jan 14, 2026
6741d8c
fix: resolve pre-existing ruff lint errors
robtaylor Jan 14, 2026
205247a
docs: move simulation architecture analysis to Google Docs
robtaylor Jan 14, 2026
679d9d3
feat(sim): integrate CXXRTL simulation with VerilogWrapper
robtaylor Jan 16, 2026
7a1ef07
docs: add CXXRTL simulation example with wb_timer
robtaylor Jan 16, 2026
426cc8a
docs: add Verilog/SystemVerilog integration documentation
robtaylor Jan 16, 2026
54fe522
ci: trigger rebuild with updated chipflow-lib
robtaylor Jan 17, 2026
e75569b
examples: add sv_soc full SoC example with SystemVerilog timer
robtaylor Jan 17, 2026
5a64f76
fix(examples): fix lint errors in sv_soc example
robtaylor Jan 17, 2026
2aacf89
refactor(examples): use package wb_timer instead of local copy
robtaylor Jan 17, 2026
f8f3305
fix(verilog-wrapper): add memory map support and driver path resolution
robtaylor Jan 17, 2026
9c1a725
refactor: move VerilogWrapper to chipflow.rtl in chipflow-lib
robtaylor Jan 20, 2026
8434dbc
fix(tests): update remaining imports in test_wb_timer.py
robtaylor Jan 20, 2026
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ __pycache__/

# build outputs
build
/overrides.txt
.python-version
7 changes: 6 additions & 1 deletion chipflow_digital_ip/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@
from ._i2c import I2CPeripheral
from ._spi import SPIPeripheral

__all__ = ['GPIOPeripheral', 'UARTPeripheral', 'I2CPeripheral', 'SPIPeripheral']
__all__ = [
'GPIOPeripheral',
'UARTPeripheral',
'I2CPeripheral',
'SPIPeripheral',
]
20 changes: 12 additions & 8 deletions chipflow_digital_ip/io/_glasgow_iostream.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
from amaranth.lib import data, wiring, stream, io
from amaranth.lib.wiring import In, Out

from amaranth_types.types import ShapeLike


__all__ = ["IOStreamer", "PortGroup"]


class PortGroup:
"""Group of Amaranth library I/O ports.

Expand Down Expand Up @@ -118,7 +122,7 @@ class IOStreamer(wiring.Component):
"""

@staticmethod
def o_stream_signature(ioshape, /, *, ratio=1, meta_layout=0):
def o_stream_signature(ioshape, /, *, ratio=1, meta_layout: ShapeLike = 0):
return stream.Signature(data.StructLayout({
"port": _map_ioshape("o", ioshape, lambda width: data.StructLayout({
"o": width if ratio == 1 else data.ArrayLayout(width, ratio),
Expand All @@ -129,16 +133,16 @@ def o_stream_signature(ioshape, /, *, ratio=1, meta_layout=0):
}))

@staticmethod
def i_stream_signature(ioshape, /, *, ratio=1, meta_layout=0):
def i_stream_signature(ioshape, /, *, ratio=1, meta_layout: ShapeLike = 0):
return stream.Signature(data.StructLayout({
"port": _map_ioshape("i", ioshape, lambda width: data.StructLayout({
"i": width if ratio == 1 else data.ArrayLayout(width, ratio),
})),
"meta": meta_layout,
}))

def __init__(self, ioshape, ports, /, *, ratio=1, init=None, meta_layout=0):
assert isinstance(ioshape, (int, dict))
def __init__(self, ioshape: dict, ports, /, *, ratio=1, init=None, meta_layout: ShapeLike = 0):
assert isinstance(ioshape, dict)
assert ratio in (1, 2)

self._ioshape = ioshape
Expand All @@ -161,7 +165,7 @@ def elaborate(self, platform):
buffer_cls, latency = SimulatableDDRBuffer, 3

if isinstance(self._ports, io.PortLike):
m.submodules.buffer = buffer = buffer_cls("io", self._ports)
m.submodules.buffer = buffer = buffer_cls(io.Direction.Bidir, self._ports)
if isinstance(self._ports, PortGroup):
buffer = {}
for name, sub_port in self._ports.__dict__.items():
Expand Down Expand Up @@ -231,7 +235,7 @@ def delay(value, name):

class IOClocker(wiring.Component):
@staticmethod
def i_stream_signature(ioshape, /, *, _ratio=1, meta_layout=0):
def i_stream_signature(ioshape, /, *, _ratio=1, meta_layout: ShapeLike = 0):
# Currently the only supported ratio is 1, but this will change in the future for
# interfaces like HyperBus.
return stream.Signature(data.StructLayout({
Expand All @@ -245,10 +249,10 @@ def i_stream_signature(ioshape, /, *, _ratio=1, meta_layout=0):
}))

@staticmethod
def o_stream_signature(ioshape, /, *, ratio=1, meta_layout=0):
def o_stream_signature(ioshape, /, *, ratio=1, meta_layout: ShapeLike = 0):
return IOStreamer.o_stream_signature(ioshape, ratio=ratio, meta_layout=meta_layout)

def __init__(self, ioshape, *, clock, o_ratio=1, meta_layout=0, divisor_width=16):
def __init__(self, ioshape, *, clock, o_ratio=1, meta_layout: ShapeLike = 0, divisor_width=16):
assert isinstance(ioshape, dict)
assert isinstance(clock, str)
assert o_ratio in (1, 2)
Expand Down
1 change: 0 additions & 1 deletion chipflow_digital_ip/io/_gpio.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

from amaranth import Module, unsigned
from amaranth.lib import wiring
from amaranth.lib.wiring import In, Out, flipped, connect
Expand Down
43 changes: 26 additions & 17 deletions chipflow_digital_ip/io/_rfc_uart.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@
The Amaranth SoC RFC UART from https://github.com/ChipFlow/chipflow-digital-ip
"""

from typing import Generic, TypeVar

from amaranth import *
from amaranth.lib import stream, wiring
from amaranth.lib.wiring import In, Out, flipped, connect
from amaranth.hdl import ValueCastable

from amaranth_types.types import ShapeLike

from amaranth_soc import csr


__all__ = ["RxPhySignature", "TxPhySignature", "RxPeripheral", "TxPeripheral", "Peripheral"]

_T_ValueOrValueCastable = TypeVar("_T_ValueOrValueCastable", bound=Value | ValueCastable, covariant=True)
_T_ShapeLike = TypeVar("_T_ShapeLike", bound=ShapeLike, covariant=True)
_T_Symbol_ShapeLike = TypeVar("_T_Symbol_ShapeLike", bound=ShapeLike, covariant=True)


class RxPhySignature(wiring.Signature):
class RxPhySignature(wiring.Signature, Generic[_T_ShapeLike, _T_Symbol_ShapeLike]):
"""Receiver PHY signature.

Parameters
Expand All @@ -38,7 +47,7 @@ class RxPhySignature(wiring.Signature):
Receiver error flag. Pulsed for one clock cycle in case of an implementation-specific error
(e.g. wrong parity bit).
"""
def __init__(self, phy_config_shape, symbol_shape):
def __init__(self, phy_config_shape: _T_ShapeLike, symbol_shape: _T_Symbol_ShapeLike):
super().__init__({
"rst": Out(1),
"config": Out(phy_config_shape),
Expand All @@ -48,7 +57,7 @@ def __init__(self, phy_config_shape, symbol_shape):
})


class TxPhySignature(wiring.Signature):
class TxPhySignature(wiring.Signature, Generic[_T_ShapeLike, _T_Symbol_ShapeLike]):
"""Transmitter PHY signature.

Parameters
Expand All @@ -68,7 +77,7 @@ class TxPhySignature(wiring.Signature):
symbols : :py:`Out(stream.Signature(symbol_shape))`
Symbol stream. The shape of its payload is given by the `symbol_shape` parameter.
"""
def __init__(self, phy_config_shape, symbol_shape):
def __init__(self, phy_config_shape: _T_ShapeLike, symbol_shape: _T_Symbol_ShapeLike):
super().__init__({
"rst": Out(1),
"config": Out(phy_config_shape),
Expand Down Expand Up @@ -98,7 +107,7 @@ def elaborate(self, platform):
return m


class RxPeripheral(wiring.Component):
class RxPeripheral(wiring.Component, Generic[_T_ShapeLike, _T_ValueOrValueCastable, _T_Symbol_ShapeLike]):
class Config(csr.Register, access="rw"):
"""Peripheral configuration register.

Expand Down Expand Up @@ -141,7 +150,7 @@ class PhyConfig(csr.Register, access="rw"):
phy_config_init : :class:`int`
Initial value of the PHY configuration word.
"""
def __init__(self, phy_config_shape, phy_config_init):
def __init__(self, phy_config_shape: _T_ShapeLike, phy_config_init: _T_ValueOrValueCastable):
super().__init__(csr.Field(_PhyConfigFieldAction, phy_config_shape,
init=phy_config_init))

Expand Down Expand Up @@ -199,7 +208,7 @@ class Data(csr.Register, access="r"):
symbol_shape : :ref:`shape-like <lang-shapelike>`
Shape of a symbol.
"""
def __init__(self, symbol_shape):
def __init__(self, symbol_shape: _T_Symbol_ShapeLike):
super().__init__(csr.Field(csr.action.R, symbol_shape))

"""UART receiver peripheral.
Expand All @@ -224,8 +233,8 @@ def __init__(self, symbol_shape):
phy : :py:`Out(RxPhySignature(phy_config_shape, symbol_shape))`
Interface between the peripheral and its PHY.
"""
def __init__(self, *, addr_width, data_width, phy_config_shape=unsigned(16),
phy_config_init=0, symbol_shape=unsigned(8)):
def __init__(self, *, addr_width, data_width, phy_config_shape:_T_ShapeLike = unsigned(16),
phy_config_init: _T_ValueOrValueCastable = Value.cast(0), symbol_shape: _T_Symbol_ShapeLike = unsigned(8)):
regs = csr.Builder(addr_width=addr_width, data_width=data_width)

self._config = regs.add("Config", self.Config())
Expand Down Expand Up @@ -298,7 +307,7 @@ def elaborate(self, platform):
return m


class TxPeripheral(wiring.Component):
class TxPeripheral(wiring.Component, Generic[_T_ShapeLike, _T_Symbol_ShapeLike, _T_ValueOrValueCastable]):
class Config(csr.Register, access="rw"):
"""Peripheral configuration register.

Expand Down Expand Up @@ -341,7 +350,7 @@ class PhyConfig(csr.Register, access="rw"):
phy_config_init : :class:`int`
Initial value of the PHY configuration word.
"""
def __init__(self, phy_config_shape, phy_config_init):
def __init__(self, phy_config_shape: _T_ShapeLike, phy_config_init: _T_ValueOrValueCastable):
super().__init__(csr.Field(_PhyConfigFieldAction, phy_config_shape,
init=phy_config_init))

Expand Down Expand Up @@ -391,7 +400,7 @@ class Data(csr.Register, access="w"):
symbol_shape : :ref:`shape-like <lang-shapelike>`
Shape of a symbol.
"""
def __init__(self, symbol_shape):
def __init__(self, symbol_shape: _T_Symbol_ShapeLike):
super().__init__(csr.Field(csr.action.W, symbol_shape))

"""UART transmitter peripheral.
Expand All @@ -416,8 +425,8 @@ def __init__(self, symbol_shape):
phy : :py:`Out(TxPhySignature(phy_config_shape, symbol_shape))`
Interface between the peripheral and its PHY.
"""
def __init__(self, *, addr_width, data_width=8, phy_config_shape=unsigned(16),
phy_config_init=0, symbol_shape=unsigned(8)):
def __init__(self, *, addr_width, data_width=8, phy_config_shape: _T_ShapeLike = unsigned(16),
phy_config_init: _T_ValueOrValueCastable = Value.cast(0), symbol_shape: _T_Symbol_ShapeLike = unsigned(8)):
regs = csr.Builder(addr_width=addr_width, data_width=data_width)

self._config = regs.add("Config", self.Config())
Expand Down Expand Up @@ -487,7 +496,7 @@ def elaborate(self, platform):
return m


class Peripheral(wiring.Component):
class Peripheral(wiring.Component, Generic[_T_ShapeLike, _T_Symbol_ShapeLike, _T_ValueOrValueCastable]):
"""UART transceiver peripheral.

This peripheral is composed of two subordinate peripherals. A :class:`RxPeripheral` occupies
Expand Down Expand Up @@ -522,8 +531,8 @@ class Peripheral(wiring.Component):
:exc:`TypeError`
If ``addr_width`` is not a positive integer.
"""
def __init__(self, *, addr_width, data_width=8, phy_config_shape=unsigned(16),
phy_config_init=0, symbol_shape=unsigned(8)):
def __init__(self, *, addr_width, data_width=8, phy_config_shape: _T_ShapeLike = unsigned(16),
phy_config_init: _T_ValueOrValueCastable = Value.cast(0), symbol_shape: _T_Symbol_ShapeLike = unsigned(8)):
if not isinstance(addr_width, int) or addr_width <= 0:
raise TypeError(f"Address width must be a positive integer, not {addr_width!r}")

Expand Down
2 changes: 1 addition & 1 deletion chipflow_digital_ip/io/_spi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from amaranth import Module, Signal, Cat, C, unsigned
from amaranth import *
from amaranth.lib import wiring
from amaranth.lib.wiring import In, Out, connect, flipped

Expand Down
64 changes: 64 additions & 0 deletions chipflow_digital_ip/io/sv_timer/drivers/wb_timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: BSD-2-Clause
// Wishbone Timer Driver Header

#ifndef WB_TIMER_H
#define WB_TIMER_H

#include <stdint.h>

// Register offsets
#define WB_TIMER_CTRL 0x00
#define WB_TIMER_COMPARE 0x04
#define WB_TIMER_COUNTER 0x08
#define WB_TIMER_STATUS 0x0C

// Control register bits
#define WB_TIMER_CTRL_ENABLE (1 << 0)
#define WB_TIMER_CTRL_IRQ_EN (1 << 1)
#define WB_TIMER_CTRL_PRESCALER_SHIFT 16

// Status register bits
#define WB_TIMER_STATUS_IRQ_PENDING (1 << 0)
#define WB_TIMER_STATUS_MATCH (1 << 1)

// Register structure for SoftwareDriverSignature
typedef struct {
volatile uint32_t ctrl; // Control: [31:16] prescaler, [1] irq_en, [0] enable
volatile uint32_t compare; // Compare value for match interrupt
volatile uint32_t counter; // Current counter (read) / Reload value (write)
volatile uint32_t status; // Status: [1] match, [0] irq_pending (write 1 to clear)
} wb_timer_regs_t;

static inline void wb_timer_init(wb_timer_regs_t *regs, uint16_t prescaler, uint32_t compare) {
regs->compare = compare;
regs->counter = 0;
regs->ctrl = ((uint32_t)prescaler << WB_TIMER_CTRL_PRESCALER_SHIFT)
| WB_TIMER_CTRL_ENABLE
| WB_TIMER_CTRL_IRQ_EN;
}

static inline void wb_timer_enable(wb_timer_regs_t *regs) {
regs->ctrl |= WB_TIMER_CTRL_ENABLE;
}

static inline void wb_timer_disable(wb_timer_regs_t *regs) {
regs->ctrl &= ~WB_TIMER_CTRL_ENABLE;
}

static inline void wb_timer_set_compare(wb_timer_regs_t *regs, uint32_t value) {
regs->compare = value;
}

static inline uint32_t wb_timer_get_counter(wb_timer_regs_t *regs) {
return regs->counter;
}

static inline void wb_timer_clear_irq(wb_timer_regs_t *regs) {
regs->status = WB_TIMER_STATUS_IRQ_PENDING | WB_TIMER_STATUS_MATCH;
}

static inline int wb_timer_irq_pending(wb_timer_regs_t *regs) {
return (regs->status & WB_TIMER_STATUS_IRQ_PENDING) != 0;
}

#endif // WB_TIMER_H
Loading
Loading