def migen_body(self, template): inp = template.add_pa_in_port('inp', DOptional(DInt())) trigger = template.add_pa_in_port('trigger', DOptional(DInt())) out = template.add_pa_out_port('out', DInt()) # Declare input and output ports always happy to receive/transmit data self.comb += ( inp.ready.eq(1), trigger.ready.eq(1), out.ready.eq(1), ) commander_fsm = FSM(reset_state="IDLE") self.submodules.commander_fsm = commander_fsm commander_fsm.act("IDLE", If(inp.valid == 1, NextState("LOADING"))) commander_fsm.act( "LOADING", If(trigger.valid & trigger.data == 1, NextState("RETURN")).Else( NextValue(out.data, out.data + inp.data), )) commander_fsm.act("RETURN", NextValue(out.valid, 1), NextState("IDLE"))
def __init__(self, counter_width=10): """Define the state machine logic for running the input & output sequences.""" self.m = Signal(counter_width) # Global cycle-relative time. self.time_remaining = Signal( 32) # Clock cycles remaining before timeout self.time_remaining_buf = Signal(32) self.cycles_completed = Signal( 14 ) # How many iterations of the loop have completed since last start self.run_stb = Signal( ) # Pulsed to start core running until timeout or success self.done_stb = ( Signal()) # Pulsed when core has finished (on timeout or success) self.running = Signal() # Asserted on run_stb, cleared on done_stb self.timeout = Signal() self.success = Signal() self.ready = Signal() self.herald = Signal() self.is_master = Signal() self.standalone = Signal( ) # Ignore state of partner for single-device testing. self.act_as_master = Signal() self.comb += self.act_as_master.eq(self.is_master | self.standalone) self.trigger_out = Signal() # Trigger to slave # Unregistered inputs from master self.trigger_in_raw = Signal() self.success_in_raw = Signal() self.timeout_in_raw = Signal() # Unregistered input from slave self.slave_ready_raw = Signal() self.m_end = Signal( counter_width) # Number of clock cycles to run main loop for # Asserted while the entangler is idling, waiting for the entanglement cycle to # start. self.cycle_starting = Signal() self.cycle_ending = Signal() # # # self.comb += self.cycle_ending.eq(self.m == self.m_end) self.trigger_in = Signal() self.success_in = Signal() self.slave_ready = Signal() self.timeout_in = Signal() self.sync += [ self.trigger_in.eq(self.trigger_in_raw), self.success_in.eq(self.success_in_raw), self.slave_ready.eq(self.slave_ready_raw), self.timeout_in.eq(self.timeout_in_raw), ] self.sync += [ If(self.run_stb, self.running.eq(1)), If(self.done_stb, self.running.eq(0)), ] # The core times out if time_remaining countdown reaches zero, or, # if we are a slave, if the master has timed out. # This is required to ensure the slave syncs with the master self.comb += self.timeout.eq((self.time_remaining == 0) | (~self.act_as_master & self.timeout_in)) self.sync += [ If(self.run_stb, self.time_remaining.eq(self.time_remaining_buf)).Else( If(~self.timeout, self.time_remaining.eq(self.time_remaining - 1))) ] done = Signal() done_d = Signal() finishing = Signal() self.comb += finishing.eq(~self.run_stb & self.running & (self.timeout | self.success)) # Done asserted at the at the end of the successful / timedout cycle self.comb += done.eq(finishing & self.cycle_starting) self.comb += self.done_stb.eq(done & ~done_d) # Ready asserted when run_stb is pulsed, and cleared on success or timeout self.sync += [ If( self.run_stb, self.ready.eq(1), self.cycles_completed.eq(0), self.success.eq(0), ), done_d.eq(done), If(finishing, self.ready.eq(0)), ] fsm = FSM() self.submodules += fsm fsm.act( "IDLE", self.cycle_starting.eq(1), If( self.act_as_master, If( ~finishing & self.ready & (self.slave_ready | self.standalone), NextState("TRIGGER_SLAVE"), ), ).Else( If(~finishing & self.ready & self.trigger_in, NextState("COUNTER"))), NextValue(self.m, 0), self.trigger_out.eq(0), ) fsm.act("TRIGGER_SLAVE", NextState("TRIGGER_SLAVE2"), self.trigger_out.eq(1)) fsm.act("TRIGGER_SLAVE2", NextState("COUNTER"), self.trigger_out.eq(1)) fsm.act( "COUNTER", NextValue(self.m, self.m + 1), If( self.cycle_ending, NextValue(self.cycles_completed, self.cycles_completed + 1), If( self.act_as_master, If(self.herald, NextValue(self.success, 1)), NextState("IDLE"), ).Else(NextState("SLAVE_SUCCESS_WAIT")), ), self.trigger_out.eq(0), ) fsm.act("SLAVE_SUCCESS_WAIT", NextState("SLAVE_SUCCESS_CHECK")) fsm.act( "SLAVE_SUCCESS_CHECK", # On slave, checking if master broadcast success If(self.success_in, NextValue(self.success, 1)), NextState("IDLE"), )
def __init__(self, c2): txwidth = 13 txlen = Signal(max=txwidth + 1) txbuf = Signal(txwidth) rxbuf = Signal(8) rxlen = Signal(4) waitlen = Signal(7) rfull = Signal() readerror = Signal() reset_count = Signal(max=961) self._cmd = CSRStorage(8) self._stat = CSRStatus(8) self._rxbuf = CSRStatus(8) self.comb += self._rxbuf.status.eq(rxbuf) self._txdat = CSRStorage(8) c2d = TSTriple() c2ck = Signal(reset=1) self.comb += c2.c2ck.eq(c2ck) self.specials += c2d.get_tristate(c2.c2d) self._pwcon = CSRStorage(8, reset=1) self._glitchoff = CSRStorage(32) self._glitchlen = CSRStorage(8) glitchout = Signal() glitchmode = Signal() glitchtmr = Signal(32) self.comb += c2.power.eq(self._pwcon.storage[0] & glitchout) self.sync += If(self._pwcon.storage[1], self._pwcon.storage[1].eq(0), glitchmode.eq(0), glitchtmr.eq(self._glitchoff.storage)) self.sync += If(glitchtmr == 0, glitchout.eq(1)).Else( glitchtmr.eq(glitchtmr - 1), glitchout.eq(~glitchmode), If( glitchtmr == 1, If(glitchmode == 0, glitchtmr[:8].eq(self._glitchlen.storage), glitchmode.eq(1)))) # when rxbuf is read, reset the buffer full flag self.sync += If(self._rxbuf.we, rfull.eq(0)) fsm = FSM(reset_state="IDLE") self.submodules.fsm = fsm fsm.act( "IDLE", c2d.oe.eq(0), NextValue(c2ck, 1), If( self._cmd.storage == 1, # data read NextValue(self._cmd.storage, 0), NextValue(txbuf, 1), # start(1), data read (00), length (00) NextValue(txlen, 5), NextValue(rxlen, 8), NextValue(readerror, 0), NextValue(waitlen, 127), NextState("TX")).Elif( self._cmd.storage == 2, # address write NextValue(self._cmd.storage, 0), # start (1), address write (11), address NextValue(txbuf, (self._txdat.storage << 3) | 7), NextValue(txlen, 11), NextValue(rxlen, 0), NextValue(waitlen, 0), NextState("TX")).Elif( self._cmd.storage == 3, # address read NextValue(self._cmd.storage, 0), NextValue(waitlen, 0), NextValue(txbuf, 5), # start (1), address read (01) NextValue(txlen, 3), NextValue(waitlen, 0), # no wait NextValue(rxlen, 8), # read 8 bits NextValue(readerror, 0), NextState("TX")).Elif( self._cmd.storage == 4, # data write NextValue(self._cmd.storage, 0), NextValue(waitlen, 0), # start (1), data write (10), length (00), data NextValue(txbuf, (self._txdat.storage << 5) | 3), NextValue(txlen, 13), NextValue(waitlen, 127), # wait at the end NextValue(rxlen, 0), # no read NextState("TX")).Elif( self._cmd.storage == 5, # reset NextValue(self._cmd.storage, 0), NextValue(reset_count, 960), # 20us at 48MHz NextValue(c2ck, 0), NextState("RESET"))) fsm.act( "RESET", # 20us reset line low NextValue(c2ck, 0), If( reset_count == 0, NextValue(reset_count, 96), # 2us at 48MHz NextState("RESET2")).Else( NextValue(reset_count, reset_count - 1), )) fsm.act( "RESET2", # 2us reset line high NextValue(c2ck, 1), If(reset_count == 0, NextState("IDLE")).Else(NextValue(reset_count, reset_count - 1), )) fsm.act( "TX", # clk initially 1 here c2d.oe.eq(1), If( txlen == 0, If( waitlen != 0, NextState("WAIT"), ).Elif( rxlen != 0, NextState("RX"), ).Else(NextState("STOP")), NextValue(c2ck, 0)). Else( If( c2ck == 1, # clock is high, about to drop the next bit NextValue(c2d.o, txbuf[0]), NextValue(txbuf, txbuf[1:])). Else( # clock is low, about to raise it and potentially advance to the next state NextValue(txlen, txlen - 1)), NextValue(c2ck, ~c2ck))) fsm.act( "WAIT", # must enter state with c2ck already at 0 c2d.oe.eq(0), If((c2ck == 1) & (c2d.i == 1), If(rxlen != 0, NextState("RX")).Else(NextState("STOP")), NextValue(c2ck, 0)).Else( If(waitlen == 0, NextValue(readerror, 1), NextState("IDLE")).Else(NextValue(waitlen, waitlen - 1), NextValue(c2ck, ~c2ck)))) fsm.act( "RX", # must enter state with c2ck already at 0 c2d.oe.eq(0), If( c2ck == 1, # clock is high, shift in bit as it falls NextValue(rxbuf, Cat(rxbuf[1:], c2d.i)), If(rxlen == 1, NextValue(rfull, 1), NextState("STOP")), NextValue(c2ck, 0), NextValue(rxlen, rxlen - 1), ).Else(NextValue(c2ck, 1))) fsm.act( "STOP", # must enter state with c2ck already at 0 c2d.oe.eq(0), If( c2ck == 1, # stop done NextState("IDLE")).Else(NextValue(c2ck, 1))) # status register byte: # | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | # | ERR | RRDY | . | . | WAIT | RX | TX | IDLE | self.comb += self._stat.status.eq( fsm.ongoing("IDLE") | (fsm.ongoing("TX") << 1) | (fsm.ongoing("RX") << 2) | (fsm.ongoing("WAIT") << 3) | (rfull << 6) | (readerror << 7)) # for debugging, expose internals self._txlen = CSRStatus(5) self._txbuf = CSRStatus(12) self._rxlen = CSRStatus(4) self._waitlen = CSRStatus(7) self.comb += self._txlen.status.eq(txlen) self.comb += self._txbuf.status.eq(txbuf) self.comb += self._rxlen.status.eq(rxlen) self.comb += self._waitlen.status.eq(waitlen)