@dataclass class QSPIControllerConfig: sck: Pin(1) io: Pin(4) cs: Pin(range(1, 16)) frequency: Frequency class QSPIControllerCore(wiring.Component): o_fifo: In(stream.Signature(8)) i_fifo: Out(stream.Signature(8)) def __init__(self, pins): self.pins = pins super().__init__() def elaborate(self, platform): ... # drive `pins` based on `self.[io]_fifo` class QSPIControllerInterface: def __init__(self, builder, config: QSPIControllerConfig): pins = builder.get_pins(sck=config.sck, io=config.io, cs=config.cs) core = builder.add_core(QSPIControllerCore(pins)) self.fifo = builder.add_fifo_bidir(core.o_fifo, core.i_fifo) def write(self, data): self.fifo.write([CMD_DATA]) self.fifo.write(data) class QSPIControllerApplet: @arguments(QSPIControllerConfig) async def repl(self, builder, config): return QSPIControllerInterface(builder, config) @arguments(QSPIControllerConfig, data=list[bytearray]) async def cli(self, builder, config, data): iface = QSPIControllerInterface(builder, config) await builder.materialize() for chunk in data: chunk = await iface.exchange(chunk) print(chunk)