cores/icap/ICAP: Rewrite using with an FSM instead of Timeline (will be easier to extend).

This commit is contained in:
Florent Kermarrec 2021-10-04 15:06:03 +02:00
parent 9416e30249
commit 3504904c09
2 changed files with 76 additions and 32 deletions

View File

@ -8,7 +8,6 @@ from enum import IntEnum
from migen import * from migen import *
from migen.genlib.misc import timeline
from migen.genlib.cdc import PulseSynchronizer from migen.genlib.cdc import PulseSynchronizer
from litex.soc.interconnect.csr import * from litex.soc.interconnect.csr import *
@ -97,50 +96,95 @@ class ICAP(Module, AutoCSR):
self.submodules += ps_send self.submodules += ps_send
self.comb += ps_send.i.eq(self.send) self.comb += ps_send.i.eq(self.send)
# Generate ICAP bitstream write sequence. # Generate ICAP bitstream sequence.
self._csib = _csib = Signal(reset=1) self._csib = _csib = Signal(reset=1)
self._rdwrb = _rdwrb = Signal() self._rdwrb = _rdwrb = Signal()
self._i = _i = Signal(32) self._i = _i = Signal(32)
self.sync.icap += [
_i.eq(ICAP_DUMMY), # Dummy (Default).
timeline(ps_send.o, [
# Clear Done.
(1, [_csib.eq(1), self.done.eq(0)]),
# Synchronize. count = Signal(4)
(2, [_csib.eq(0), _i.eq(ICAP_NOOP)]), # No Op. fsm = FSM(reset_state="WAIT")
(3, [_csib.eq(0), _i.eq(ICAP_SYNC)]), # Sync Word. fsm = ClockDomainsRenamer("icap")(fsm)
(4, [_csib.eq(0), _i.eq(ICAP_NOOP)]), # No Op. self.submodules += fsm
(5, [_csib.eq(0), _i.eq(ICAP_NOOP)]), # No Op.
# Write User's data to addr Register. # Wait User Command.
(6, [_csib.eq(0), _i.eq(ICAP_WRITE | (self.addr << 13) | 1)]), # Set Register. fsm.act("WAIT",
(7, [_csib.eq(0), _i.eq(self.data)]), # Set Register Data. # Set ICAP in IDLE state.
(8, [_csib.eq(0), _i.eq(ICAP_NOOP)]), # No Op. _csib.eq(1),
(9, [_csib.eq(0), _i.eq(ICAP_NOOP)]), # No Op. _rdwrb.eq(0),
_i.eq(ICAP_DUMMY),
# De-Synchronize. # Set Done.
(10, [_csib.eq(0), _i.eq(ICAP_WRITE | (ICAPRegisters.CMD << 13) | 1)]), # Write to CMD Register. self.done.eq(1),
(11, [_csib.eq(0), _i.eq(ICAPCMDs.DESYNC)]), # DESYNC CMD.
(12, [_csib.eq(0), _i.eq(ICAP_NOOP)]), # No Op.
(13, [_csib.eq(0), _i.eq(ICAP_NOOP)]), # No Op.
# Set Done. # Wait User Command.
(14, [_csib.eq(1), self.done.eq(1)]), If(ps_send.o,
]) NextValue(count, 0),
] NextState("SYNC")
)
)
# ICAP instance # Send ICAP Synchronization sequence.
fsm.act("SYNC",
_csib.eq(0),
_rdwrb.eq(0),
Case(count, {
0 : _i.eq(ICAP_NOOP), # No Op.
1 : _i.eq(ICAP_SYNC), # Sync Word.
2 : _i.eq(ICAP_NOOP), # No Op.
3 : _i.eq(ICAP_NOOP), # No Op.
}),
NextValue(count, count + 1),
If(count == (4-1),
NextValue(count, 0),
NextState("WRITE")
)
)
# Send ICAP Write sequence.
fsm.act("WRITE",
_csib.eq(0),
_rdwrb.eq(0),
Case(count, {
0 : _i.eq(ICAP_WRITE | (self.addr << 13) | 1), # Set Register.
1 : _i.eq(self.data), # Set Register Data.
2 : _i.eq(ICAP_NOOP), # No Op.
3 : _i.eq(ICAP_NOOP), # No Op.
}),
NextValue(count, count + 1),
If(count == (4-1),
NextValue(count, 0),
NextState("DESYNC")
)
)
# Send ICAP Desynchronization sequence.
fsm.act("DESYNC",
_csib.eq(0),
_rdwrb.eq(0),
Case(count, {
0 : _i.eq(ICAP_WRITE | (ICAPRegisters.CMD << 13) | 1), # Write to CMD Register.
1 : _i.eq(ICAPCMDs.DESYNC), # DESYNC CMD.
2 : _i.eq(ICAP_NOOP), # No Op.
3 : _i.eq(ICAP_NOOP), # No Op.
}),
NextValue(count, count + 1),
If(count == (4-1),
NextValue(count, 0),
NextState("WAIT")
)
)
# ICAP Instance.
if not simulation: if not simulation:
self.specials += Instance("ICAPE2", self.specials += Instance("ICAPE2",
p_ICAP_WIDTH = "X32", p_ICAP_WIDTH = "X32",
i_CLK = ClockSignal("icap"), i_CLK = ClockSignal("icap"),
i_CSIB = _csib, i_CSIB = _csib,
i_RDWRB = 0, i_RDWRB = _rdwrb,
i_I = Cat(*[_i[8*i:8*(i+1)][::-1] for i in range(4)]), i_I = Cat(*[_i[8*i:8*(i+1)][::-1] for i in range(4)]),
) )
# CSR # CSR.
if with_csr: if with_csr:
self.add_csr() self.add_csr()
@ -167,8 +211,8 @@ class ICAP(Module, AutoCSR):
) )
) )
fsm.act("RELOAD", fsm.act("RELOAD",
self.addr.eq(0x4), self.addr.eq(ICAPRegisters.CMD),
self.data.eq(0xf), self.data.eq(ICAPCMDs.IPROG),
self.send.eq(1), self.send.eq(1),
) )

View File

@ -42,7 +42,7 @@ class TestICAP(unittest.TestCase):
for ref_w in iprog_sequence: for ref_w in iprog_sequence:
cur_w = f"{(yield dut._csib)} {(yield dut._rdwrb)} 0x{(yield dut._i):08x}" cur_w = f"{(yield dut._csib)} {(yield dut._rdwrb)} 0x{(yield dut._i):08x}"
self.assertEqual(ref_w, cur_w) self.assertEqual(ref_w, cur_w)
# print(cur_w) #print(cur_w)
yield yield