cores/spi_mmap: add slot post transfer cs_wait

Also remove unused slot_status - maintains CSR alignment now that
slot_control is 64 bit (two 32bit registers).
This commit is contained in:
Andrew Dennison 2024-02-25 13:24:24 +11:00
parent f3b287addd
commit 416f1b4281
2 changed files with 39 additions and 8 deletions

View File

@ -244,10 +244,10 @@ class SPICtrl(LiteXModule):
default_slot_loopback = 0b1, default_slot_loopback = 0b1,
default_slot_divider = 2, default_slot_divider = 2,
default_enable = 0b1, default_enable = 0b1,
default_slot_wait = 0,
): ):
self.nslots = nslots self.nslots = nslots
self.slot_controls = [] self.slot_controls = []
self.slot_status = []
version = "SPI0" version = "SPI0"
self._version = CSRStatus(size=32, description="""SPI Module Version.""", self._version = CSRStatus(size=32, description="""SPI Module Version.""",
@ -354,13 +354,15 @@ class SPICtrl(LiteXModule):
("``0x0002``", "SPI-Clk = Sys-Clk/2."), ("``0x0002``", "SPI-Clk = Sys-Clk/2."),
("``0x0004``", "SPI-Clk = Sys-Clk/4."), ("``0x0004``", "SPI-Clk = Sys-Clk/4."),
("``0xxxxx``", "SPI-Clk = Sys-Clk/xxxxx."), ("``0xxxxx``", "SPI-Clk = Sys-Clk/xxxxx."),
], reset=default_slot_divider) ], reset=default_slot_divider),
CSRField("wait", size=16, offset=32, values=[
("``0x0000``", "No wait time."),
("``0x0001``", "wait = 1 / Sys-Clk."),
("``0xxxxx``", "wait = xxxx / Sys-Clk."),
], reset=default_slot_wait),
]) ])
status = CSRStatus(name=f"slot_status{slot}") # CHECKME: Useful?
setattr(self, f"slot_control{slot}", control) setattr(self, f"slot_control{slot}", control)
setattr(self, f"slot_status{slot}", status)
self.slot_controls.append(control) self.slot_controls.append(control)
self.slot_status.append(status)
def get_ctrl(self, name, slot=None, cs=None): def get_ctrl(self, name, slot=None, cs=None):
assert not ((slot is None) and (cs is None)) assert not ((slot is None) and (cs is None))
@ -556,8 +558,15 @@ class SPIEngine(LiteXModule):
) )
] ]
# Wait between transfers.
ctrl_wait = ctrl.get_ctrl("wait", cs=sink.cs)
wait_ticks = Signal.like(ctrl_wait)
wait_count = Signal.like(ctrl_wait)
self.comb += wait_ticks.eq(ctrl_wait)
cs_wait = Signal()
# SPI CS. (Use Manual CS to allow back-to-back Xfers). # SPI CS. (Use Manual CS to allow back-to-back Xfers).
self.comb += If(ctrl.engine.fields.enable & sink.valid, self.comb += If(ctrl.engine.fields.enable & sink.valid & ~cs_wait,
spi.cs.eq(sink.cs) spi.cs.eq(sink.cs)
) )
@ -584,6 +593,20 @@ class SPIEngine(LiteXModule):
source.be.eq(sink.be), source.be.eq(sink.be),
If(source.ready, If(source.ready,
sink.ready.eq(1), sink.ready.eq(1),
If(wait_ticks,
cs_wait.eq(1),
NextValue(wait_count, wait_ticks-1),
NextState("WAIT")
).Else(
NextState("START")
)
)
)
fsm.act("WAIT",
If(wait_count,
cs_wait.eq(1),
NextValue(wait_count, wait_count-1)
).Else(
NextState("START") NextState("START")
) )
) )

View File

@ -139,7 +139,7 @@ class TestSPIMMAP(unittest.TestCase):
run_simulation(dut, generator(dut), vcd_name="sim.vcd") run_simulation(dut, generator(dut), vcd_name="sim.vcd")
def mmap_test(self, length, bitorder, data, vcd_name=None, sel_override=None): def mmap_test(self, length, bitorder, data, vcd_name=None, sel_override=None, wait=0):
pads = Record([("clk", 1), ("cs_n", 4), ("mosi", 1), ("miso", 1)]) pads = Record([("clk", 1), ("cs_n", 4), ("mosi", 1), ("miso", 1)])
dut = SPIMMAP( dut = SPIMMAP(
pads=pads, pads=pads,
@ -151,7 +151,7 @@ class TestSPIMMAP(unittest.TestCase):
def generator(dut): def generator(dut):
# Minimal setup - spi_mmap ctrl defaults are everything enabled and: # Minimal setup - spi_mmap ctrl defaults are everything enabled and:
# SPI_SLOT_MODE_3, SPI_SLOT_LENGTH_32B, SPI_SLOT_BITORDER_MSB_FIRST, loopback, divider=2, # SPI_SLOT_MODE_3, SPI_SLOT_LENGTH_32B, SPI_SLOT_BITORDER_MSB_FIRST, loopback, divider=2, wait=0
version = yield dut.ctrl._version.status version = yield dut.ctrl._version.status
vprint(f"version: {version}") vprint(f"version: {version}")
vprint(f"slot_count: {(yield dut.ctrl.slot_count.status)}") vprint(f"slot_count: {(yield dut.ctrl.slot_count.status)}")
@ -162,6 +162,7 @@ class TestSPIMMAP(unittest.TestCase):
# yield dut.ctrl.slot_control0.fields.loopback.eq(1) # yield dut.ctrl.slot_control0.fields.loopback.eq(1)
# yield dut.ctrl.slot_control0.fields.divider.eq(2) # yield dut.ctrl.slot_control0.fields.divider.eq(2)
# yield dut.ctrl.slot_control0.fields.enable.eq(1) # yield dut.ctrl.slot_control0.fields.enable.eq(1)
yield dut.ctrl.slot_control0.fields.wait.eq(wait)
if length == SPI_SLOT_LENGTH_32B: if length == SPI_SLOT_LENGTH_32B:
spi_length = 32 spi_length = 32
sel = 0b1111 sel = 0b1111
@ -284,6 +285,13 @@ class TestSPIMMAP(unittest.TestCase):
data = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0] data = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]
self.mmap_test(SPI_SLOT_LENGTH_8B, SPI_SLOT_BITORDER_MSB_FIRST, data, "mmap_8_msb.vcd") self.mmap_test(SPI_SLOT_LENGTH_8B, SPI_SLOT_BITORDER_MSB_FIRST, data, "mmap_8_msb.vcd")
def test_spi_mmap_8_msb_wait1(self):
data = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]
self.mmap_test(SPI_SLOT_LENGTH_8B, SPI_SLOT_BITORDER_MSB_FIRST, data, "mmap_8_msb_wait1.vcd", wait=1)
def test_spi_mmap_8_msb_wait8(self):
data = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]
self.mmap_test(SPI_SLOT_LENGTH_8B, SPI_SLOT_BITORDER_MSB_FIRST, data, "mmap_8_msb_wait8.vcd", wait=8)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()