def __init__(self, platform, sys_clk_freq): self.reset = CSR() self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) self.clock_domains.cd_clk200 = ClockDomain() self.clock_domains.cd_clk100 = ClockDomain() self.clock_domains.cd_eth = ClockDomain() clk50 = platform.request("clk50") platform.add_period_constraint(clk50, period_ns(50e6)) soft_reset = Signal() self.sync += timeline(self.reset.re, [(1024, [soft_reset.eq(1)])]) self.submodules.pll = pll = S7PLL() pll.register_clkin(clk50, 50e6) pll.create_clkout(self.cd_sys, sys_clk_freq) pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) pll.create_clkout(self.cd_clk200, 200e6) pll.create_clkout(self.cd_clk100, 100e6) pll.create_clkout(self.cd_eth, 50e6) self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_clk200)
def __init__(self, cmd, trp, trfc): self.start = Signal() self.done = Signal() # # # self.sync += [ cmd.a.eq(2**10), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(0), cmd.we.eq(0), ] self.sync += [ self.done.eq(0), # Wait start timeline( self.start, [ # Precharge All (0, [cmd.ras.eq(1), cmd.we.eq(1)]), # Auto Refresh after tRP (trp, [cmd.cas.eq(1), cmd.ras.eq(1)]), # Done after tRP + tRFC (trp + trfc, [self.done.eq(1)]) ]) ]
def __init__(self): # Pins self.o_nCS = Signal( reset=1) # A conversion process begins on the falling edge of CS. self.i_SDATA = Signal() # The output words are clocked out of this pin self.o_SCLK = Signal() # guaranteed performance at 20 MHz # Samples self.o_dat = Signal(12) self.o_valid = Signal() # Single cycle pulse when o_dat is valid self.i_trig = Signal( ) # Start a conversion (can be hardwired to 1 for continuous mode) ### self.peekReg = CSR(size=12) shiftReg = Signal(12) self.comb += [ self.o_SCLK.eq(ClockSignal()), self.peekReg.w.eq(self.o_dat) ] self.sync += [ self.o_valid.eq(0), shiftReg.eq(Cat(self.i_SDATA, shiftReg[:-1])), timeline(self.i_trig, [(0, [self.o_nCS.eq(0), shiftReg.eq(0)]), (16, [ self.o_nCS.eq(1), self.o_dat.eq(shiftReg), self.o_valid.eq(1) ])]) ]
def __init__(self, with_csr=True, simulation=False): self.addr = Signal(5) self.data = Signal(32) self.send = Signal() self.done = Signal() # # # # Create slow icap clk (sys_clk/16) --------------------------------------------------------- self.clock_domains.cd_icap = ClockDomain() icap_clk_counter = Signal(4) self.sync += icap_clk_counter.eq(icap_clk_counter + 1) self.sync += self.cd_icap.clk.eq(icap_clk_counter[3]) # Resynchronize send pulse to icap domain --------------------------------------------------- ps_send = PulseSynchronizer("sys", "icap") self.submodules += ps_send self.comb += ps_send.i.eq(self.send) # Generate icap bitstream write sequence self._csib = _csib = Signal(reset=1) self._i = _i = Signal(32) _addr = self.addr << 13 _data = self.data self.sync.icap += [ _i.eq(0xffffffff), # dummy timeline( ps_send.o, [ (1, [_csib.eq(1), self.done.eq(0)]), (2, [_csib.eq(0), _i.eq(0x20000000)]), # noop (3, [_csib.eq(0), _i.eq(0xaa995566)]), # sync word (4, [_csib.eq(0), _i.eq(0x20000000)]), # noop (5, [_csib.eq(0), _i.eq(0x20000000)]), # noop (6, [_csib.eq(0), _i.eq(0x30000001 | _addr) ]), # write command (7, [_csib.eq(0), _i.eq(_data)]), # write value (8, [_csib.eq(0), _i.eq(0x20000000)]), # noop (9, [_csib.eq(0), _i.eq(0x20000000)]), # noop (10, [_csib.eq(0), _i.eq(0x30008001) ]), # write to cmd register (11, [_csib.eq(0), _i.eq(0x0000000d)]), # desync command (12, [_csib.eq(0), _i.eq(0x20000000)]), # noop (13, [_csib.eq(0), _i.eq(0x20000000)]), # noop (14, [_csib.eq(1), self.done.eq(1)]), ]) ] # ICAP instance if not simulation: self.specials += [ Instance( "ICAPE2", p_ICAP_WIDTH="X32", i_CLK=ClockSignal("icap"), i_CSIB=_csib, i_RDWRB=0, i_I=Cat(*[_i[8 * i:8 * (i + 1)][::-1] for i in range(4)]), ) ]
def __init__(self, cmd, trp, trfc): self.start = Signal() self.done = Signal() # # # self.sync += [ cmd.a.eq(2**10), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(0), cmd.we.eq(0), ] self.sync += [ self.done.eq(0), # Wait start timeline( self.start, [ # Precharge all (1, [cmd.ras.eq(1), cmd.we.eq(1)]), # Wait tRP then Auto Refresh (1 + trp, [cmd.cas.eq(1), cmd.ras.eq(1)]), # Wait tRFC then done (1 + trp + trfc, [self.done.eq(1)]) ]) ]
def __init__(self, settings): # 1st command 1 cycle after assertion of ready self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(settings.geom.addressbits, settings.geom.bankbits)) # # # # Refresh sequence generator: # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done seq_start = Signal() seq_done = Signal() self.sync += [ cmd.a.eq(2**10), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(0), cmd.we.eq(0), seq_done.eq(0) ] self.sync += timeline(seq_start, [ (1, [ cmd.ras.eq(1), cmd.we.eq(1) ]), (1+settings.timing.tRP, [ cmd.cas.eq(1), cmd.ras.eq(1) ]), (1+settings.timing.tRP+settings.timing.tRFC, [ seq_done.eq(1) ]) ]) # Periodic refresh counter self.submodules.timer = WaitTimer(settings.timing.tREFI) self.comb += self.timer.wait.eq(settings.with_refresh & ~self.timer.done) # Control FSM self.submodules.fsm = fsm = FSM() fsm.act("IDLE", If(self.timer.done, NextState("WAIT_GRANT") ) ) fsm.act("WAIT_GRANT", cmd.valid.eq(1), If(cmd.ready, seq_start.eq(1), NextState("WAIT_SEQ") ) ) fsm.act("WAIT_SEQ", If(seq_done, cmd.last.eq(1), NextState("IDLE") ).Else( cmd.valid.eq(1) ) )
def __init__(self): self.pause = Signal() self.stop = Signal() self.delay = Signal() self.reset = Signal() # # # new_lock = Signal() update = Signal() stop = Signal() freeze = Signal() pause = Signal() reset = Signal() # DDRDLLA instance ------------------------------------------------------------------------- _lock = Signal() delay = Signal() self.specials += Instance("DDRDLLA", i_RST=ResetSignal("init"), i_CLK=ClockSignal("sys2x"), i_UDDCNTLN=~update, i_FREEZE=freeze, o_DDRDEL=delay, o_LOCK=_lock) lock = Signal() lock_d = Signal() self.specials += MultiReg(_lock, lock, "init") self.sync.init += lock_d.eq(lock) self.comb += new_lock.eq(lock & ~lock_d) # DDRDLLA/DDQBUFM/ECLK initialization sequence --------------------------------------------- t = 8 # in cycles self.sync.init += [ # Wait DDRDLLA Lock timeline( new_lock, [ (1 * t, [freeze.eq(1)]), # Freeze DDRDLLA (2 * t, [stop.eq(1)]), # Stop ECLK domain (3 * t, [reset.eq(1)]), # Reset ECLK domain (4 * t, [reset.eq(0)]), # Release ECLK domain reset (5 * t, [stop.eq(0)]), # Release ECLK domain stop (6 * t, [freeze.eq(0)]), # Release DDRDLLA freeze (7 * t, [pause.eq(1)]), # Pause DQSBUFM (8 * t, [update.eq(1)]), # Update DDRDLLA (9 * t, [update.eq(0)]), # Release DDRDMMA update (10 * t, [pause.eq(0)]), # Release DQSBUFM pause ]) ] # ------------------------------------------------------------------------------------------ self.comb += [ self.pause.eq(pause), self.stop.eq(stop), self.delay.eq(delay), self.reset.eq(reset), ]
def get_fragment(self): sync = [ self.csr.we.eq(0), self.csr.dat_w.eq(self.wishbone.dat_w[:csr.data_width]), self.csr.adr.eq(self.wishbone.adr[:14]), self.wishbone.dat_r.eq(self.csr.dat_r) ] sync += timeline(self.wishbone.cyc & self.wishbone.stb, [ (1, [self.csr.we.eq(self.wishbone.we)]), (2, [self.wishbone.ack.eq(1)]), (3, [self.wishbone.ack.eq(0)]) ]) return Fragment(sync=sync)
def __init__(self, cmd, trp, trfc): self.start = Signal() self.done = Signal() # # # self.sync += [ cmd.a.eq(0), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(0), cmd.we.eq(0), self.done.eq(0), # Wait start timeline( self.start, [ # Precharge All (0, [ cmd.a.eq(2**10), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(1), cmd.we.eq(1) ]), # Auto Refresh after tRP ( trp, [ cmd.a.eq( 2**10 ), # all banks in LPDDR4/DDR5, ignored in other memories cmd.ba.eq(0), cmd.cas.eq(1), cmd.ras.eq(1), cmd.we.eq(0), ]), # Done after tRP + tRFC (trp + trfc, [ cmd.a.eq(0), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(0), cmd.we.eq(0), self.done.eq(1), ]), ]) ]
def __init__(self, platform): self.clock_domains.cd_sys = ClockDomain("sys") self.clock_domains.cd_clk125 = ClockDomain("clk125") # soft reset generaton self._soft_rst = CSR() soft_rst = Signal() # trigger soft reset 1us after CSR access to terminate # Wishbone access when reseting from PCIe self.sync += [ timeline(self._soft_rst.re & self._soft_rst.r, [(125, [soft_rst.eq(1)])]), ] # sys_clk / sys_rst (from PCIe) self.comb += self.cd_sys.clk.eq(self.cd_clk125.clk) self.specials += AsyncResetSynchronizer(self.cd_sys, self.cd_clk125.rst | soft_rst)
def __init__(self, pads, clk=10.): self.source = do = Endpoint(bus_layout) self.busy = Signal() # t_RDLl_Dv = 50 ns (setup) # t_RDLh_Di = 0ns (hold) # t_RDLl_RDLh = 50 ns (redundant, <= r_RDLl_Dv) # t_RDLh_RXFLh = 25ns (from FT245R) (redundant, <= t_RDLh_RDLl) # t_RXFLh_RXFLl = 80ns (from FT245R) # t_RDLh_RDLl = 50ns + t_RXh_RXl (we understand this as a # conditional addition) # we read every t_hold + t_precharge + t_setup + 2 cycles # can only sustain 1MByte/s anyway at full speed USB # stb implicitly needs to be acked within a read cycle #clk /= 4 # slow it down t_latch = int(ceil(50 / clk)) + 2 # t_RDLl_Dv + slave skew t_drop = t_latch + 2 # slave skew t_refill = t_drop + int(ceil(50 / clk)) # t_RDLh_RDLl reading = Signal() rxfl = Signal() rd_in = Signal() # proxy rxfl to slaves, drive rdl self.comb += [ pads.rdl.eq(~pads.g1_out), self.busy.eq(~do.stb | do.ack) ] self.specials += [ MultiReg(pads.rxfl, rxfl), MultiReg(pads.g1_in, rd_in), ] self.sync += [ If( ~reading & ~rd_in, pads.g1_out.eq(~rxfl), ), do.stb.eq(do.stb & ~do.ack), timeline(rd_in, [ (0, [reading.eq(1)]), (t_latch, [do.stb.eq(1), do.payload.data.eq(pads.data)]), (t_drop, [pads.g1_out.eq(0)]), (t_refill, [reading.eq(0)]), ]) ]
def __init__(self): self.wishbone = wishbone.Interface() self.csr = csr.Interface() ### self.sync += [ self.csr.we.eq(0), self.csr.dat_w.eq(self.wishbone.dat_w[:csr.data_width]), self.csr.adr.eq(self.wishbone.adr[:14]), self.wishbone.dat_r.eq(self.csr.dat_r) ] self.sync += timeline(self.wishbone.cyc & self.wishbone.stb, [ (1, [self.csr.we.eq(self.wishbone.we)]), (2, [self.wishbone.ack.eq(1)]), (3, [self.wishbone.ack.eq(0)]) ])
def __init__(self, pads, clk=10.): self.source = do = Endpoint(bus_layout) self.busy = Signal() # t_RDLl_Dv = 50 ns (setup) # t_RDLh_Di = 0ns (hold) # t_RDLl_RDLh = 50 ns (redundant, <= r_RDLl_Dv) # t_RDLh_RXFLh = 25ns (from FT245R) (redundant, <= t_RDLh_RDLl) # t_RXFLh_RXFLl = 80ns (from FT245R) # t_RDLh_RDLl = 50ns + t_RXh_RXl (we understand this as a # conditional addition) # we read every t_hold + t_precharge + t_setup + 2 cycles # can only sustain 1MByte/s anyway at full speed USB # stb implicitly needs to be acked within a read cycle #clk /= 4 # slow it down t_latch = int(ceil(50/clk)) + 2 # t_RDLl_Dv + slave skew t_drop = t_latch + 2 # slave skew t_refill = t_drop + int(ceil(50/clk)) # t_RDLh_RDLl reading = Signal() rxfl = Signal() rd_in = Signal() # proxy rxfl to slaves, drive rdl self.comb += [ pads.rdl.eq(~pads.g1_out), self.busy.eq(~do.stb | do.ack) ] self.specials += [ MultiReg(pads.rxfl, rxfl), MultiReg(pads.g1_in, rd_in), ] self.sync += [ If(~reading & ~rd_in, pads.g1_out.eq(~rxfl), ), do.stb.eq(do.stb & ~do.ack), timeline(rd_in, [ (0, [reading.eq(1)]), (t_latch, [do.stb.eq(1), do.payload.data.eq(pads.data)]), (t_drop, [pads.g1_out.eq(0)]), (t_refill, [reading.eq(0)]), ]) ]
def __init__(self, pads, rd_timing): self.bus = wishbone.Interface() ### adr_width = len(pads.adr) + 1 self.comb += [pads.oe_n.eq(0), pads.we_n.eq(1), pads.ce_n.eq(0)] self.sync += timeline(self.bus.cyc & self.bus.stb, [ (0, [pads.adr.eq(Cat(0, self.bus.adr[:adr_width-2]))]), (rd_timing, [ self.bus.dat_r[16:].eq(pads.d), pads.adr.eq(Cat(1, self.bus.adr[:adr_width-2]))]), (2*rd_timing, [ self.bus.dat_r[:16].eq(pads.d), self.bus.ack.eq(1)]), (2*rd_timing + 1, [ self.bus.ack.eq(0)]) ])
def __init__(self, a, ba, tRP, tREFI, tRFC): self.req = Signal() self.ack = Signal() # 1st command 1 cycle after assertion of ack self.cmd = CommandRequest(a, ba) ### # Refresh sequence generator: # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done seq_start = Signal() seq_done = Signal() self.sync += [ self.cmd.a.eq(2**10), self.cmd.ba.eq(0), self.cmd.cas_n.eq(1), self.cmd.ras_n.eq(1), self.cmd.we_n.eq(1), seq_done.eq(0) ] self.sync += timeline( seq_start, [(1, [self.cmd.ras_n.eq(0), self.cmd.we_n.eq(0)]), (1 + tRP, [self.cmd.cas_n.eq(0), self.cmd.ras_n.eq(0)]), (1 + tRP + tRFC, [seq_done.eq(1)])]) # Periodic refresh counter counter = Signal(max=tREFI) start = Signal() self.sync += [ start.eq(0), If(counter == 0, start.eq(1), counter.eq(tREFI - 1)).Else(counter.eq(counter - 1)) ] # Control FSM fsm = FSM() self.submodules += fsm fsm.act("IDLE", If(start, NextState("WAIT_GRANT"))) fsm.act("WAIT_GRANT", self.req.eq(1), If(self.ack, seq_start.eq(1), NextState("WAIT_SEQ"))) fsm.act("WAIT_SEQ", self.req.eq(1), If(seq_done, NextState("IDLE")))
def __init__(self, bus_wishbone=None, bus_csr=None): if bus_wishbone is None: bus_wishbone = wishbone.Interface() self.wishbone = bus_wishbone if bus_csr is None: bus_csr = csr_bus.Interface() self.csr = bus_csr ### self.sync += [ self.csr.we.eq(0), self.csr.dat_w.eq(self.wishbone.dat_w), self.csr.adr.eq(self.wishbone.adr), self.wishbone.dat_r.eq(self.csr.dat_r) ] self.sync += timeline(self.wishbone.cyc & self.wishbone.stb, [(1, [self.csr.we.eq(self.wishbone.we)]), (2, [self.wishbone.ack.eq(1)]), (3, [self.wishbone.ack.eq(0)])])
def __init__(self, platform): self.clock_domains.cd_sys = ClockDomain("sys") self.clock_domains.cd_clk125 = ClockDomain("clk125") # soft reset generaton self._soft_rst = CSR() soft_rst = Signal() # trigger soft reset 1us after CSR access to terminate # Wishbone access when reseting from PCIe self.sync += [ timeline(self._soft_rst.re & self._soft_rst.r, [(125, [soft_rst.eq(1)])]), ] # sys_clk / sys_rst (from PCIe) self.comb += self.cd_sys.clk.eq(self.cd_clk125.clk) self.specials += AsyncResetSynchronizer(self.cd_sys, self.cd_clk125.rst | soft_rst) # scratch register self._scratch = CSR(32) self.sync += If(self._scratch.re, self._scratch.w.eq(self._scratch.r))
def __init__(self, bus_wishbone=None, bus_csr=None): if bus_wishbone is None: bus_wishbone = wishbone.Interface() self.wishbone = bus_wishbone if bus_csr is None: bus_csr = csr.Interface() self.csr = bus_csr ### self.sync += [ self.csr.we.eq(0), self.csr.dat_w.eq(self.wishbone.dat_w), self.csr.adr.eq(self.wishbone.adr), self.wishbone.dat_r.eq(self.csr.dat_r) ] self.sync += timeline(self.wishbone.cyc & self.wishbone.stb, [ (1, [self.csr.we.eq(self.wishbone.we)]), (2, [self.wishbone.ack.eq(1)]), (3, [self.wishbone.ack.eq(0)]) ])
def __init__(self, cmd, trp, tzqcs): self.start = Signal() self.done = Signal() # # # self.sync += [ # Note: Don't set cmd to 0 since already done in RefreshExecuter self.done.eq(0), # Wait start timeline( self.start, [ # Precharge All (0, [ cmd.a.eq(2**10), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(1), cmd.we.eq(1) ]), # ZQ Short Calibration after tRP (trp, [ cmd.a.eq(0), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(0), cmd.we.eq(1), ]), # Done after tRP + tZQCS (trp + tzqcs, [ cmd.a.eq(0), cmd.ba.eq(0), cmd.cas.eq(0), cmd.ras.eq(0), cmd.we.eq(0), self.done.eq(1) ]), ]) ]
def __init__(self, bus_wishbone=None, bus_csr=None, wb_bus_dw=32): if bus_wishbone is None: bus_wishbone = wishbone.Interface(data_width=wb_bus_dw, adr_width=32 - log2_int(wb_bus_dw // 8)) self.wishbone = bus_wishbone if bus_csr is None: bus_csr = csr_bus.Interface() self.csr = bus_csr ### self.sync += [ self.csr.we.eq(0), self.csr.dat_w.eq(self.wishbone.dat_w), self.csr.adr.eq(self.wishbone.adr), self.wishbone.dat_r.eq(self.csr.dat_r) ] self.sync += timeline(self.wishbone.cyc & self.wishbone.stb, [(1, [self.csr.we.eq(self.wishbone.we)]), (2, [self.wishbone.ack.eq(1)]), (3, [self.wishbone.ack.eq(0)])])
def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"): """ Simple SPI flash. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode3 (cpol=1, cpha=1). """ SpiFlashCommon.__init__(self, pads) self.bus = bus = wishbone.Interface() spi_width = len(pads.dq) max_transfer_size = 8 * 8 assert spi_width >= 2 if with_bitbang: self.bitbang = CSRStorage( 4, reset_less=True, fields=[ CSRField( "mosi", description= "Output value for MOSI pin, valid whenever ``dir`` is ``0``." ), CSRField("clk", description="Output value for SPI CLK pin."), CSRField("cs_n", description="Output value for SPI CSn pin."), CSRField( "dir", description= "Sets the direction for *ALL* SPI data pins except CLK and CSn.", values=[ ("0", "OUT", "SPI pins are all output"), ("1", "IN", "SPI pins are all input"), ]) ], description=""" Bitbang controls for SPI output. Only standard 1x SPI is supported, and as a result all four wires are ganged together. This means that it is only possible to perform half-duplex operations, using this SPI core. """) self.miso = CSRStatus(description="Incoming value of MISO signal.") self.bitbang_en = CSRStorage( description= "Write a ``1`` here to disable memory-mapped mode and enable bitbang mode." ) queue = self.queue = CSRStatus(4) in_len = self.in_len = CSRStorage(4) out_len = self.out_len = CSRStorage(4) in_left = self.in_left = Signal(max=2**8) out_left = self.out_left = Signal(max=2**8) self.quad_transfer = Signal(reset=0) spi_in = self.spi_in = CSRStorage(max_transfer_size) spi_out = self.spi_out = CSRStatus(max_transfer_size) cs_n = Signal(reset=1) clk = Signal() dq_oe = Signal() wbone_width = len(bus.dat_r) cmd_width = 8 addr_width = 24 dq = TSTriple(spi_width) sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) self.specials.dq0 = Tristate(pads.dq[0], o=dq.o[0], i=dq.i[0], oe=dq.oe) self.specials.dq1 = Tristate(pads.dq[1], o=dq.o[1], i=dq.i[1], oe=dq.oe) if with_bitbang: # Keep DQ2,DQ3 as outputs during bitbang, this ensures they activate ~WP or ~HOLD functions self.specials.dq2 = Tristate(pads.dq[2], o=dq.o[2], i=dq.i[2], oe=(dq.oe | self.bitbang_en.storage)) self.specials.dq3 = Tristate(pads.dq[3], o=dq.o[3], i=dq.i[3], oe=(dq.oe | self.bitbang_en.storage)) else: self.specials.dq2 = Tristate(pads.dq[2], o=dq.o[2], i=dq.i[2], oe=dq.oe) self.specials.dq3 = Tristate(pads.dq[3], o=dq.o[3], i=dq.i[3], oe=dq.oe) sr = Signal(max(cmd_width, addr_width, wbone_width, max_transfer_size)) if endianness == "big": self.comb += bus.dat_r.eq(sr[:wbone_width]) else: self.comb += bus.dat_r.eq(reverse_bytes(sr[:wbone_width])) hw_read_logic_single = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] hw_read_logic_quad = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(Cat(sr[-1:], Replicate(1, 3))), dq.oe.eq(dq_oe) ] if with_bitbang: bitbang_logic = [ pads.clk.eq(self.bitbang.storage[1]), pads.cs_n.eq(self.bitbang.storage[2]), # In Dual/Quad mode, no single data pin is consistently # an input or output thanks to dual/quad reads, so we need a bit # to swap direction of the pins. Aside from this additional bit, # bitbang mode is identical for Single/Dual/Quad; dq[0] is mosi # and dq[1] is miso, meaning remaining data pin values don't # appear in CSR registers. If(self.bitbang.storage[3], dq.oe.eq(0)).Else(dq.oe.eq(1)), If( self.bitbang. storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only. self.miso.status.eq(dq.i[1])), dq.o.eq( Cat(self.bitbang.storage[0], Replicate(1, spi_width - 1))) ] self.comb += [ If(self.bitbang_en.storage, bitbang_logic).Elif( self.quad_transfer, hw_read_logic_single).Else(hw_read_logic_quad) ] else: self.comb += [ If(self.quad_transfer, hw_read_logic_single).Else(hw_read_logic_quad) ] if div < 2: raise ValueError( "Unsupported value \'{}\' for div parameter for SpiFlash core". format(div)) # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width // 8)) i = Signal(max=div) dqi = Signal(spi_width) # SPI or memmap mode self.mode = Signal() self.sync += [ If( i == div // 2 - 1, clk.eq(1), dqi.eq(dq.i), ), If( i == div - 1, i.eq(0), clk.eq(0), If(self.quad_transfer, sr.eq(Cat(dqi, sr[:-spi_width]))).Else( sr.eq(Cat(dqi[1], sr[:-1])))).Else(i.eq(i + 1), ), ] read_seq = [ (4 * cmd_width // spi_width * div, [ dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(_QIOFR), self.quad_transfer.eq(0) ]), (addr_width // spi_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr)), self.quad_transfer.eq(1)]), ((1 + dummy + wbone_width // spi_width) * div, [dq_oe.eq(0)]), (1, [bus.ack.eq(1), cs_n.eq(1)]), ( div, # tSHSL! [bus.ack.eq(0)]), (0, [queue.status[0].eq(0)]), ] write_seq = [ (4 * cmd_width // spi_width * div, [ dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(_QIOPP), self.quad_transfer.eq(0) ]), (addr_width // spi_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr)), self.quad_transfer.eq(1)]), ((wbone_width // spi_width) * div, [sr[-wbone_width:].eq(reverse_bytes(bus.dat_w))]), (1, [bus.ack.eq(1), cs_n.eq(1)]), (div, [bus.ack.eq(0)]), (0, [queue.status[1].eq(0)]), ] # prepare spi transfer self.sync += If( self.out_len.re & (self.out_len.storage != 0) & self.en_quad.storage[0], self.out_left.eq(Cat(1, self.out_len.storage))) self.sync += If(self.out_len.re & (self.out_len.storage == 0), self.out_left.eq(0)) self.sync += If( self.out_len.re & (self.out_len.storage != 0) & ~self.en_quad.storage[0], self.out_left.eq(Cat(1, Replicate(0, 2), self.out_len.storage))) self.sync += If( self.in_len.re & (self.in_len.storage != 0) & ~self.en_quad.storage[0], [ queue.status[2].eq(1), self.in_left.eq(Cat(Replicate(0, 3), in_len.storage)), self.quad_transfer.eq(0) ]) # write data to sr self.sync += If( queue.status[2] & (i == div - 1) & ~self.en_quad.storage[0], sr[-max_transfer_size:].eq(self.spi_in.storage), queue.status[2].eq(0), queue.status[3].eq(1), cs_n.eq(0), dq_oe.eq(1)) # count spi to slave transfer cycles self.sync += If(queue.status[3] & (self.in_left > 0) & (i == div - 1), self.in_left.eq(self.in_left - 1), dq_oe.eq(1)) # count spi to master transfer cycles self.sync += If( queue.status[3] & (self.in_left < 1) & (self.out_left > 0) & (i == div - 1), self.out_left.eq(self.out_left - 1), dq_oe.eq(0)) #end transmision and read data from sr self.sync += If( ~self.in_len.re & (in_left < 1) & (out_left < 1) & queue.status[3], queue.status[3].eq(0), cs_n.eq(1), If(self.out_len.storage == 1, self.spi_out.status.eq(Cat(Replicate(0, 8 * 7), sr))).Elif( self.out_len.storage == 2, self.spi_out.status.eq(Cat(Replicate(0, 8 * 6), sr))).Elif( self.out_len.storage == 3, self.spi_out.status.eq(Cat(Replicate( 0, 8 * 5), sr))).Elif( self.out_len.storage == 4, self.spi_out.status.eq( Cat(Replicate(0, 8 * 4), sr))).Elif( self.out_len.storage == 5, self.spi_out.status.eq( Cat(Replicate(0, 8 * 3), sr))). Elif( self.out_len.storage == 6, self.spi_out.status.eq(Cat(Replicate(0, 8 * 2), sr))).Elif( self.out_len.storage == 7, self.spi_out.status.eq(Cat(Replicate(0, 8 * 1), sr))).Else( self.spi_out.status.eq(sr))) # detect mem map access self.sync += If(~self.mode & bus.cyc & bus.stb & ~bus.we, queue.status[0].eq(1)) self.sync += If(~self.mode & bus.cyc & bus.stb & bus.we, queue.status[1].eq(1)) self.sync += timeline( queue.status[0] & ~self.en_quad.storage[0] & (i == div - 1), accumulate_timeline_deltas(read_seq)) self.sync += timeline( queue.status[1] & ~self.en_quad.storage[0] & (i == div - 1), accumulate_timeline_deltas(write_seq))
def __init__(self, pads, dummy=15, div=2, with_bitbang=True): """ Simple SPI flash, e.g. N25Q128 on the LX9 Microboard. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode0 (cpol=0, cpha=0). Optionally supports software bitbanging (for write, erase, or other commands). """ self.bus = bus = wishbone.Interface() spi_width = flen(pads.dq) if with_bitbang: self.bitbang = CSRStorage(4) self.miso = CSRStatus() self.bitbang_en = CSRStorage() ### cs_n = Signal(reset=1) clk = Signal() dq_oe = Signal() wbone_width = flen(bus.dat_r) read_cmd_params = { 4: (_format_cmd(_QIOFR, 4), 4*8), 2: (_format_cmd(_DIOFR, 2), 2*8), 1: (_format_cmd(_FAST_READ, 1), 1*8) } read_cmd, cmd_width = read_cmd_params[spi_width] addr_width = 24 pads.cs_n.reset = 1 dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) dqs = Replicate(1, spi_width-1) self.comb += bus.dat_r.eq(sr) hw_read_logic = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] if with_bitbang: bitbang_logic = [ pads.clk.eq(self.bitbang.storage[1]), pads.cs_n.eq(self.bitbang.storage[2]), dq.o.eq(Cat(self.bitbang.storage[0], dqs)), If(self.bitbang.storage[3], dq.oe.eq(0) ).Else( dq.oe.eq(1) ), If(self.bitbang.storage[1], self.miso.status.eq(dq.i[1]) ) ] self.comb += \ If(self.bitbang_en.storage, bitbang_logic ).Else( hw_read_logic ) else: self.comb += hw_read_logic if div < 2: raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) else: i = Signal(max=div) dqi = Signal(spi_width) self.sync += [ If(i == div//2 - 1, clk.eq(1), dqi.eq(dq.i), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(dqi, sr[:-spi_width])) ).Else( i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width//8)) seq = [ (cmd_width//spi_width*div, [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width//spi_width*div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width//spi_width)*div, [dq_oe.eq(0)]), (1, [bus.ack.eq(1), cs_n.eq(1)]), (div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"): """ Simple SPI flash. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode0 (cpol=0, cpha=0). """ self.bus = bus = wishbone.Interface() spi_width = len(pads.dq) assert spi_width >= 2 if with_bitbang: self.bitbang = CSRStorage(4) self.miso = CSRStatus() self.bitbang_en = CSRStorage() # # # cs_n = Signal(reset=1) clk = Signal() dq_oe = Signal() wbone_width = len(bus.dat_r) read_cmd_params = { 4: (_format_cmd(_QIOFR, 4), 4 * 8), 2: (_format_cmd(_DIOFR, 2), 2 * 8), } read_cmd, cmd_width = read_cmd_params[spi_width] addr_width = 24 dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) hw_read_logic = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] if with_bitbang: bitbang_logic = [ pads.clk.eq(self.bitbang.storage[1]), pads.cs_n.eq(self.bitbang.storage[2]), # In Dual/Quad mode, no single data pin is consistently # an input or output thanks to dual/quad reads, so we need a bit # to swap direction of the pins. Aside from this additional bit, # bitbang mode is identical for Single/Dual/Quad; dq[0] is mosi # and dq[1] is miso, meaning remaining data pin values don't # appear in CSR registers. If(self.bitbang.storage[3], dq.oe.eq(0)).Else(dq.oe.eq(1)), If( self.bitbang. storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only. self.miso.status.eq(dq.i[1])), dq.o.eq( Cat(self.bitbang.storage[0], Replicate(1, spi_width - 1))) ] self.comb += [ If(self.bitbang_en.storage, bitbang_logic).Else(hw_read_logic) ] else: self.comb += hw_read_logic if div < 2: raise ValueError( "Unsupported value \'{}\' for div parameter for SpiFlash core". format(div)) else: i = Signal(max=div) dqi = Signal(spi_width) self.sync += [ If( i == div // 2 - 1, clk.eq(1), dqi.eq(dq.i), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(dqi, sr[:-spi_width]))).Else(i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width // 8)) seq = [ (cmd_width // spi_width * div, [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width // spi_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width // spi_width) * div, [dq_oe.eq(0)]), (1, [bus.ack.eq(1), cs_n.eq(1)]), ( div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"): """ Simple SPI flash. Supports 1-bit reads. Only supports mode0 (cpol=0, cpha=0). """ self.bus = bus = wishbone.Interface() if with_bitbang: self.bitbang = CSRStorage(4) self.miso = CSRStatus() self.bitbang_en = CSRStorage() # # # if hasattr(pads, "wp"): self.comb += pads.wp.eq(1) if hasattr(pads, "hold"): self.comb += pads.hold.eq(1) cs_n = Signal(reset=1) clk = Signal() wbone_width = len(bus.dat_r) read_cmd = _FAST_READ cmd_width = 8 addr_width = 24 sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) hw_read_logic = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), pads.mosi.eq(sr[-1:]) ] if with_bitbang: bitbang_logic = [ pads.clk.eq(self.bitbang.storage[1]), pads.cs_n.eq(self.bitbang.storage[2]), If( self.bitbang. storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only. self.miso.status.eq(pads.miso)), pads.mosi.eq(self.bitbang.storage[0]) ] self.comb += [ If(self.bitbang_en.storage, bitbang_logic).Else(hw_read_logic) ] else: self.comb += hw_read_logic if div < 2: raise ValueError( "Unsupported value \'{}\' for div parameter for SpiFlash core". format(div)) else: i = Signal(max=div) miso = Signal() self.sync += [ If( i == div // 2 - 1, clk.eq(1), miso.eq(pads.miso), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(miso, sr[:-1]))).Else(i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width // 8)) seq = [ (cmd_width * div, [cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width) * div, []), (1, [bus.ack.eq(1), cs_n.eq(1)]), ( div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, pads): self.pads = pads self.bus = bus = wishbone.Interface() # # # clk = Signal() clk_phase = Signal(2) cs = Signal() ca = Signal(48) sr = Signal(48) dq = self.add_tristate(pads.dq) if not hasattr(pads.dq, "oe") else pads.dq rwds = self.add_tristate(pads.rwds) if not hasattr(pads.rwds, "oe") else pads.rwds # Drive rst_n, cs_n, clk from internal signals --------------------------------------------- if hasattr(pads, "rst_n"): self.comb += pads.rst_n.eq(1) self.comb += pads.cs_n[0].eq(~cs) assert len(pads.cs_n) <= 2 if len(pads.cs_n) == 2: self.comb += pads.cs_n[1].eq(1) if hasattr(pads, "clk"): self.comb += pads.clk.eq(clk) else: self.specials += DifferentialOutput(clk, pads.clk_p, pads.clk_n) # Clock Generation (sys_clk/4) ------------------------------------------------------------- self.sync += clk_phase.eq(clk_phase + 1) cases = {} cases[1] = clk.eq(cs) # Set pads clk on 90° (if cs is set) cases[3] = clk.eq(0) # Clear pads clk on 270° self.sync += Case(clk_phase, cases) # Data Shift Register (for write and read) ------------------------------------------------- dqi = Signal(8) self.sync += dqi.eq(dq.i) # Sample on 90° and 270° cases = {} cases[0] = sr.eq(Cat(dqi, sr[:-8])) # Shift on 0° cases[2] = sr.eq(Cat(dqi, sr[:-8])) # Shift on 180° self.sync += Case(clk_phase, cases) self.comb += [ bus.dat_r.eq(sr), # To Wisbone dq.o.eq(sr[-8:]), # To HyperRAM ] # Command generation ----------------------------------------------------------------------- self.comb += [ ca[47].eq(~self.bus.we), # R/W# ca[45].eq(1), # Burst Type (Linear) ca[16:35].eq(self.bus.adr[2:21]), # Row & Upper Column Address ca[1:3].eq(self.bus.adr[0:2]), # Lower Column Address ca[0].eq(0), # Lower Column Address ] # Sequencer -------------------------------------------------------------------------------- dt_seq = [ # DT, Action (3, []), (12, [cs.eq(1), dq.oe.eq(1), sr.eq(ca)]), # Command: 6 clk (44, [dq.oe.eq(0)]), # Latency(default): 2*6 clk (2, [dq.oe.eq(self.bus.we), # Write/Read data byte: 2 clk sr[:16].eq(0), sr[16:].eq(self.bus.dat_w), rwds.oe.eq(self.bus.we), rwds.o.eq(~bus.sel[0])]), (2, [rwds.o.eq(~bus.sel[1])]), # Write/Read data byte: 2 clk (2, [rwds.o.eq(~bus.sel[2])]), # Write/Read data byte: 2 clk (2, [rwds.o.eq(~bus.sel[3])]), # Write/Read data byte: 2 clk (2, [cs.eq(0), rwds.oe.eq(0), dq.oe.eq(0)]), (1, [bus.ack.eq(1)]), (1, [bus.ack.eq(0)]), (0, []), ] # Convert delta-time sequencer to time sequencer t_seq = [] t_seq_start = (clk_phase == 1) t = 0 for dt, a in dt_seq: t_seq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & t_seq_start, t_seq)
def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"): """ Simple memory-mapped SPI flash. Supports 1-bit reads. Only supports mode3 (cpol=1, cpha=1). """ SpiFlashCommon.__init__(self, pads) self.bus = bus = wishbone.Interface() if with_bitbang: self.bitbang = CSRStorage( 4, fields=[ CSRField("mosi", description="Output value for SPI MOSI pin."), CSRField("clk", description="Output value for SPI CLK pin."), CSRField("cs_n", description="Output value for SPI CSn pin."), CSRField("dir", description="Unused in this design.") ], description="""Bitbang controls for SPI output.""") self.miso = CSRStatus(description="Incoming value of MISO pin.") self.bitbang_en = CSRStorage( description= "Write a ``1`` here to disable memory-mapped mode and enable bitbang mode." ) # # # if hasattr(pads, "wp"): self.comb += pads.wp.eq(1) if hasattr(pads, "hold"): self.comb += pads.hold.eq(1) cs_n = Signal(reset=1) clk = Signal() wbone_width = len(bus.dat_r) read_cmd = _FAST_READ cmd_width = 8 addr_width = 24 sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) hw_read_logic = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), pads.mosi.eq(sr[-1:]) ] if with_bitbang: bitbang_logic = [ pads.clk.eq(self.bitbang.storage[1]), pads.cs_n.eq(self.bitbang.storage[2]), If( self.bitbang. storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only. self.miso.status.eq(pads.miso)), pads.mosi.eq(self.bitbang.storage[0]) ] self.comb += [ If(self.bitbang_en.storage, bitbang_logic).Else(hw_read_logic) ] else: self.comb += hw_read_logic if div < 2: raise ValueError( "Unsupported value \'{}\' for div parameter for SpiFlash core". format(div)) else: i = Signal(max=div) miso = Signal() self.sync += [ If( i == div // 2 - 1, clk.eq(1), miso.eq(pads.miso), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(miso, sr[:-1]))).Else(i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width // 8)) seq = [ (cmd_width * div, [cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width) * div, []), (1, [bus.ack.eq(1), cs_n.eq(1)]), ( div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, pads): """ HyperRAM simple core for LiteX This core should always just work on any FPGA platorm it is fully vendor neutral No configuration, no software setup, ready after poweron, fixed latency """ HyperMemporyCommon.__init__(self, pads) if hasattr(pads, "rst_n"): self.comb += pads.rst_n.eq(1) if hasattr(pads, "cs1_n"): self.comb += pads.cs1_n.eq(1) # Tristate pads dq = TSTriple(8) self.specials.dq = dq.get_tristate(pads.dq) rwds = TSTriple(1) self.specials.rwds = rwds.get_tristate(pads.rwds) # Wishbone self.bus = bus = wishbone.Interface() sr = Signal(48) dq_oe = Signal(reset=0) rwds_oe = Signal(reset=0) cs_int = Signal(reset=1) self.comb += [ bus.dat_r.eq(sr), dq.oe.eq(dq_oe), dq.o.eq(sr[-8:]), rwds.oe.eq(rwds_oe), pads.cs0_n.eq(cs_int) ] # we generate complementaty clk out for emulated differential output clk_p = Signal(1) clk_n = Signal(1) self.comb += pads.clk.eq(clk_p) # if negative is defined drive complementary clock out if hasattr(pads, "clk_n"): self.comb += pads.clk_n.eq(clk_n) # 1 sys clock delay needed to adjust input timings? dqi = Signal(8) self.sync += [dqi.eq(dq.i)] # hyper RAM clock generator and 48 bit byte shifter i = Signal(max=4) self.sync += [ If( i == 0, sr.eq(Cat(dqi, sr[:-8])), ), If( i == 1, clk_p.eq(~cs_int), # 1 clk_n.eq(cs_int) # 0 ), If(i == 2, sr.eq(Cat(dqi, sr[:-8]))), If( i == 3, i.eq(0), clk_p.eq(0), # 1 clk_n.eq(1) # 0 ).Else(i.eq(i + 1)) ] # signals to use CA or data to write CA = Signal(48) # combine bits to create CA bytes self.comb += [ CA[47].eq(~self.bus.we), CA[45].eq(1), CA[16:35].eq(self.bus.adr[2:21]), CA[1:3].eq(self.bus.adr[0:2]), CA[0].eq(0), ] z = Replicate(0, 16) seq = [ (3, []), (12, [cs_int.eq(0), dq_oe.eq(1), sr.eq(CA)]), # 6 clock edges for command transmit (44, [dq_oe.eq(0)]), # 6+6 latency default (2, [ dq_oe.eq(self.bus.we), rwds_oe.eq(self.bus.we), rwds.o.eq(~bus.sel[0]), sr.eq(Cat(z, self.bus.dat_w)) ]), # 4 edges to write data (2, [rwds.o.eq(~bus.sel[1])]), # 4 edges to write data (2, [rwds.o.eq(~bus.sel[2])]), # 4 edges to write data (2, [rwds.o.eq(~bus.sel[3])]), # 4 edges to write data (2, [cs_int.eq(1), rwds_oe.eq(0), dq_oe.eq(0)]), (1, [bus.ack.eq(1)]), # is 1 also OK? (1, [bus.ack.eq(0)]), # (0, []), ] t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == 1), tseq)
def __init__(self, simulation=False): self.addr = CSRStorage(5, description="ICAP Write Address.") self.data = CSRStorage(32, description="ICAP Write Data.") self.send = CSRStorage( description= "ICAP Control.\n\n Write ``1`` send a write command to the ICAP.") self.done = CSRStatus( reset=1, description= "ICAP Status.\n\n Write command done when read as ``1``.") # # # # Create slow icap clk (sys_clk/16) --------------------------------------------------------- self.clock_domains.cd_icap = ClockDomain() icap_clk_counter = Signal(4) self.sync += icap_clk_counter.eq(icap_clk_counter + 1) self.sync += self.cd_icap.clk.eq(icap_clk_counter[3]) # Resynchronize send pulse to icap domain --------------------------------------------------- ps_send = PulseSynchronizer("sys", "icap") self.submodules += ps_send self.comb += [ps_send.i.eq(self.send.re)] # Generate icap bitstream write sequence self._csib = _csib = Signal(reset=1) self._i = _i = Signal(32) _addr = self.addr.storage << 13 _data = self.data.storage self.sync.icap += [ _i.eq(0xffffffff), # dummy timeline( ps_send.o, [ (1, [_csib.eq(1), self.done.status.eq(0)]), (2, [_csib.eq(0), _i.eq(0x20000000)]), # noop (3, [_csib.eq(0), _i.eq(0xaa995566)]), # sync word (4, [_csib.eq(0), _i.eq(0x20000000)]), # noop (5, [_csib.eq(0), _i.eq(0x20000000)]), # noop (6, [_csib.eq(0), _i.eq(0x30000001 | _addr) ]), # write command (7, [_csib.eq(0), _i.eq(_data)]), # write value (8, [_csib.eq(0), _i.eq(0x20000000)]), # noop (9, [_csib.eq(0), _i.eq(0x20000000)]), # noop (10, [_csib.eq(0), _i.eq(0x30008001) ]), # write to cmd register (11, [_csib.eq(0), _i.eq(0x0000000d)]), # desync command (12, [_csib.eq(0), _i.eq(0x20000000)]), # noop (13, [_csib.eq(0), _i.eq(0x20000000)]), # noop (14, [_csib.eq(1), self.done.status.eq(1)]), ]) ] # ICAP instance if not simulation: self.specials += [ Instance( "ICAPE2", p_ICAP_WIDTH="X32", i_CLK=ClockSignal("icap"), i_CSIB=_csib, i_RDWRB=0, i_I=Cat(*[_i[8 * i:8 * (i + 1)][::-1] for i in range(4)]), ) ]
def __init__(self, pads, exclude): """ BBIO simple core for LiteX TODO expose seladr, input mux out, and write enable, and value to external IP cores This would "connect" the last access BBIO pin to external time multipexed IP's TODO can we update the .h files from here? """ bbioCommon.__init__(self, pads, exclude) bbio_width = len(pads) # bbio_o = Signal(bbio_width) bbio_oe = Signal(bbio_width) bbio_i = Signal(bbio_width) # create single pin tristate buffers for b in range(bbio_width): self.submodules += bbioSinglePin(pads, b, bbio_i[b], bbio_o[b], bbio_oe[b]) # Wishbone self.bus = bus = wishbone.Interface() # sel = Signal(bbio_width) inbit = Signal(1) # todo: dynamic address width calc to optimize the decode logic addr_width = 12 # 1024 IO max? # expose sel address to external IP Cores seladr = Signal(10) # 10 bits of address = 1024 pins max # self.comb += seladr.eq(self.bus.adr[:10]) # address decoder for b in range(bbio_width): self.comb += sel[b].eq(seladr == b) self.comb += inbit.eq((bbio_i & sel) != 0) # Read bit rdbus = Signal(32) self.comb += [rdbus[0].eq(inbit), bus.dat_r.eq(rdbus)] # process output # todo. multiplex them to external IP core use outbit = Signal(1) oebit = Signal(1) wren = Signal(1) # PINAPI 1.0 compatible: 0 = drive 0, 1 drive 1, 3 = HiZ self.comb += outbit.eq(bus.dat_w[0]) self.comb += oebit.eq(~bus.dat_w[1]) # write enables # self.comb += wren.eq(self.bus.stb & self.bus.cyc & self.bus.we) for b in range(bbio_width): self.sync += If(wren & sel[b], bbio_o[b].eq(outbit), bbio_oe[b].eq(oebit)) # todo optimize 1 cycle away? seq = [ (1, [ bus.ack.eq(0), seladr.eq(self.bus.adr[:10]), wren.eq(self.bus.we) ]), # latch IO address and wren bit (1, [bus.ack.eq(1), wren.eq(0) ]), # ack transfer, clear wren, KEEP select address! (1, [bus.ack.eq(0)]), # done (0, []), ] t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb, tseq)
def __init__(self, S=8, D=2, INITIAL_IDELAY=15, clock_regions=[0, 1]): """ S = serialization factor (bits per frame) D = number of parallel lanes clock_regions: list of D integers specifying how to assign the lvds_data input pins to specific clock regions. Each clock_region will be treated as a separate clock domain, having its own BUFR, BUFIO, FIFO and reset sync. logic Example for 3 signals, where the last one is in a separate region: clock_regions = [0, 0, 1] """ self.CLOCK_REGIONS = Counter(clock_regions) # = {0: 2, 1: 1} # LVDS DDR bit clock self.dco_p = Signal() self.dco_n = Signal() # data (+frame) lanes self.lvds_data_p = Signal(D) self.lvds_data_n = Signal(D) # Pulse to rotate bits (sys clock domain) # Will be synchronized to all clock regions and applied to all ISERDES self.bitslip = Signal() # IDELAY control for DCO clock input # on sys clock domain self.id_inc = Signal() self.id_dec = Signal() self.id_value = Signal(5) # parallel data out, S-bit serdes on D-lanes # on `sample` clock domain self.data_outs = [Signal(S) for i in range(D)] ### # recovered ADC sampling clock self.clock_domains.cd_sample = ClockDomain("sample") self.init_running = Signal(reset=1) self.iserdes_default = { "p_DATA_WIDTH": S, "p_DATA_RATE": "DDR", "p_SERDES_MODE": "MASTER", "p_INTERFACE_TYPE": "NETWORKING", "p_NUM_CE": 1, "p_IOBDELAY": "NONE", "i_DDLY": 0, "i_CE1": 1, "i_CE2": 1, "i_DYNCLKDIVSEL": 0, "i_DYNCLKSEL": 0 } # ------------------------------------------------- # DCO input clock --> IDELAYE2 --> BUFMRCE # ------------------------------------------------- dco = Signal() dco_delay = Signal() dco_delay_2 = Signal() id_CE = Signal() self.comb += id_CE.eq(self.id_inc ^ self.id_dec) self.specials += DifferentialInput(self.dco_p, self.dco_n, dco) self.specials += Instance("IDELAYE2", p_DELAY_SRC="IDATAIN", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=INITIAL_IDELAY, i_C=ClockSignal("sys"), i_LD=ResetSignal("sys"), i_INC=self.id_inc, i_CE=id_CE, i_LDPIPEEN=0, i_CINVCTRL=0, i_CNTVALUEIN=Constant(0, 5), i_DATAIN=0, i_REGRST=0, i_IDATAIN=dco, o_DATAOUT=dco_delay, o_CNTVALUEOUT=self.id_value) bufmr_ce = Signal() bufr_clr = Signal(reset=1) self.specials += Instance("BUFMRCE", i_CE=bufmr_ce, i_I=dco_delay, o_O=dco_delay_2) # ------------------------------------------------- # Reset sequence # ------------------------------------------------- # Sample clock domain will reset on sys clock reset. # ... which will also trigger the init sequence below # # synchronize BUFR dividers on sys_clk reset # a symptom of screwing this up is: # * different number of bitslips are required # for ISERDES in different clock regions # # __Note:__ # The sequence suggested in [1] releases `bufr_clr` last, # which for me did not align the BUFR dividers reliably. # However releasing `bufmr_ce` last did the tick. # Error in the Xilinx documentation? # # [1] UG472 p. 110 `BUFR Alignment` self.sync.sys += timeline( self.init_running, [ # Shut down sample_clk at BUFMRCE, clear regional dividers ... (0, [bufr_clr.eq(1), bufmr_ce.eq(0)]), (4, [bufr_clr.eq(0)]), # Re-enable regional clocks (8, [bufmr_ce.eq(1)]), # Regional clocks are running and synced, # release `cd_sample` reset (16, [self.init_running.eq(0)]) ]) # Only release all resets on sample_clk domain after step 16 self.specials += AsyncResetSynchronizer(self.cd_sample, self.init_running) # ------------------------------------------------- # generate a separate CD for each clock region # ------------------------------------------------- # each one having its own BUFR, BUFIO and reset sync. r_ioclks = {} # Regional IO clocks driven by BUFIO r_clks = {} # Regional fabric clocks driven by BUFR r_bitslips = {} # Regional bitslip pulses for cr_i, cr_n in self.CLOCK_REGIONS.items(): print(f"Clock region: {cr_i}, inputs: {cr_n}") # regional buffer for the fast IO clock ioclk = Signal() self.specials += Instance("BUFIO", i_I=dco_delay_2, o_O=ioclk) # regional clock domain for ISERDES output + interface fabric cd_name = f'bufr_{cr_i}' cd = ClockDomain(cd_name) self.clock_domains += cd self.specials += Instance( "BUFR", p_BUFR_DIVIDE=str(S // 2), # div by 2 due to DDR i_I=dco_delay_2, i_CE=1, i_CLR=bufr_clr, o_O=cd.clk) # Releasing global `sample` reset releases local `bufr_N` reset AsyncResetSynchronizer(cd, ResetSignal('sample')) # Move bitslip pulse into regional CD ps = PulseSynchronizer('sys', cd_name) self.submodules += ps self.comb += ps.i.eq(self.bitslip) # Collect all region specific items in dicts r_ioclks[cr_i] = ioclk r_clks[cr_i] = cd.clk r_bitslips[cr_i] = ps.o # Make last regional clock available to rest of the design # Note that the output of the BUFG is not phase matched with the # output of the BUFR. I'll use elastic buffers to move over the data # TODO get sample clock from IBUFDS --> MMCM --> BUFG ??? # The BUFG cell BUFG_1 I pin is driven by a BUFR cell BUFR_1. For 7-Series devices, this is not a recommended clock topology. Please analyze your clock network and remove the BUFR to BUFG cascade. self.specials += Instance("BUFG", i_I=cd.clk, o_O=ClockSignal("sample")) # ------------------------------------------------- # Generate an IDERDES for each data lane # ------------------------------------------------- r_dos = defaultdict(list) # Regional data-outs, key = clock region for d_p, d_n, c_reg in zip(self.lvds_data_p, self.lvds_data_n, clock_regions): d_i = Signal() self.specials += DifferentialInput(d_p, d_n, d_i) # Collect parallel output data do = Signal(S) self.specials += Instance("ISERDESE2", **self.iserdes_default, i_CLK=r_ioclks[c_reg], i_CLKB=~r_ioclks[c_reg], i_CLKDIV=r_clks[c_reg], i_D=d_i, i_BITSLIP=r_bitslips[c_reg], i_RST=ResetSignal(cd_name), o_Q1=do[0], o_Q2=do[1], o_Q3=do[2], o_Q4=do[3], o_Q5=do[4], o_Q6=do[5], o_Q7=do[6], o_Q8=do[7]) r_dos[c_reg].append(do) # ------------------------------------------------- # Generate elastic-buffer for each clock region # ------------------------------------------------- fifo_outs = [] for cr_i, r_dos in r_dos.items(): dos = Cat(r_dos) cd_name = f'bufr_{cr_i}' ebuf_name = f'ebuf_{cr_i}' # Regional FIFO ebuf = ElasticBuffer(len(dos), 2, cd_name, 'sample') setattr(self.submodules, ebuf_name, ebuf) self.comb += ebuf.din.eq(dos) fifo_outs.append(ebuf.dout) self.comb += Cat(self.data_outs).eq(Cat(fifo_outs))
def __init__(self, S, D, MIRROR_BITS, BITSLIPS, idelay_overrides={}, iserdes_overrides={}): """ Generates all logic necessary for the data lanes, calibration and phase detection / adjustment Does not do anything related to clocking. Inherit and add you own clock. """ # LVDS DDR bit clock self.dco_p = Signal() self.dco_n = Signal() # data lanes self.lvds_data_p = Signal(D) self.lvds_data_n = Signal(D) # Control signals (on sample clock domain) self.bitslip = Signal() # Pulse to rotate # Phase detector readout (on sample clock domain) # input for number of sample clock cycles to integrate self.pd_int_period = Signal(32, reset=2**23) # outputs integrated Phase detector values (int32) self.pd_int_phases = [Signal((32, True)) for i in range(D)] # input to enable auto increment / decrement IDELAY based on PD value self.id_auto_control = Signal() # Idelay control inputs (on sample clock domain) self.id_mux = Signal(max=D + 1) # select a LVDS lane self.id_inc = Signal(1) self.id_dec = Signal(1) # parallel data out, S-bit serdes on D-lanes (on sample clock domain) self.data_outs = [Signal(S) for i in range(D)] # Async Reset for clock generation and `sample` clock domain self.reset = Signal(reset=1) ### # Common internal signals which must be driven by child self.clock_domains.sample = ClockDomain( "sample") # received ADC sample clock self.ioclk_p = Signal() self.ioclk_n = Signal() self.serdesstrobe = Signal() # ----------------------------- # IDELAY calibration # ----------------------------- self.idelay_rst = Signal() self.idelay_cal_m = Signal() self.idelay_cal_s = Signal() # High when IDELAY initialization complete self.initial_tl_done = Signal() bitslip_initial = Signal() self.sync.sample += [ self.idelay_cal_m.eq(0), self.idelay_cal_s.eq(0), self.idelay_rst.eq(0), bitslip_initial.eq(0) ] # Initially calibrate and reset all IDELAY2s tl = [ (20, [self.idelay_cal_m.eq(1), self.idelay_cal_s.eq(1)]), (40, [self.idelay_rst.eq(1)]), (60, [self.initial_tl_done.eq(1)]), # Add initial bitslips starting from clk 100. Have I gone too far? *zip([100 + i * 10 for i in range(BITSLIPS)], [[bitslip_initial.eq(1)]] * BITSLIPS) ] # print(tl) self.sync.sample += timeline(~self.initial_tl_done, tl) # Periodically re-calibrate all slave IDELAY2s self.sync.sample += timeline( self.initial_tl_done, [(2**26, [self.idelay_cal_s.eq(1)]) # every 0.54 s at 125 MHz ]) # Accumulator regs for phase detector pd_int_accus = [Signal.like(s) for s in self.pd_int_phases] pd_int_cnt = Signal(32) self.sync.sample += [ If( pd_int_cnt >= self.pd_int_period, pd_int_cnt.eq(0), ).Elif( self. initial_tl_done, # only start counting when idelays are calibrated pd_int_cnt.eq(pd_int_cnt + 1)) ] # ----------------------------- # Default block parameters # ----------------------------- self.idelay_default = { "p_SIM_TAPDELAY_VALUE": 49, "p_IDELAY_VALUE": 0, # A faire: make CSR "p_IDELAY2_VALUE": 0, "p_ODELAY_VALUE": 0, "p_IDELAY_MODE": "NORMAL", "p_COUNTER_WRAPAROUND": "WRAPAROUND", "p_DELAY_SRC": "IDATAIN", "i_T": 1, "i_ODATAIN": 0, "i_IOCLK0": self.ioclk_p, "i_IOCLK1": self.ioclk_n, "i_CLK": ClockSignal("sample"), "i_RST": self.idelay_rst } self.idelay_default.update(idelay_overrides) self.iserdes_default = { "p_DATA_WIDTH": S, "p_BITSLIP_ENABLE": "TRUE", "p_INTERFACE_TYPE": "RETIMED", "i_CE0": 1, "i_CLK0": self.ioclk_p, "i_CLK1": self.ioclk_n, "i_IOCE": self.serdesstrobe, "i_RST": ~self.initial_tl_done, "i_CLKDIV": ClockSignal("sample"), "i_BITSLIP": self.bitslip | bitslip_initial } self.iserdes_default.update(iserdes_overrides) for i in range(D): lvds_data = Signal() lvds_data_m = Signal() lvds_data_s = Signal() id_CE = Signal() id_INC = Signal() # ------------------------------------- # Idelay control (auto / manual) # ------------------------------------- self.sync.sample += [ # Mux the IDELAY control inputs If( self.id_auto_control, id_CE. eq((pd_int_cnt == 1) & # Adjust IDELAYS at end of each accumulator cycle (self.pd_int_phases[i] != 0) # Adjust IDELAYs when consistently early / late # during _all_ accumulator cycles # ((self.pd_int_phases[i] >= self.pd_int_period) | # (self.pd_int_phases[i] <= -self.pd_int_period)) ), id_INC.eq(self.pd_int_phases[i] < 0)).Else( id_CE.eq((self.id_mux == i) & (self.id_inc ^ self.id_dec)), id_INC.eq(self.id_inc)) ] self.specials += DifferentialInput(self.lvds_data_p[i], self.lvds_data_n[i], lvds_data) self.specials += Instance("IODELAY2", p_SERDES_MODE="MASTER", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", i_IDATAIN=lvds_data, i_CAL=self.idelay_cal_m, i_CE=id_CE, i_INC=id_INC, o_DATAOUT=lvds_data_m, **self.idelay_default) self.specials += Instance("IODELAY2", p_SERDES_MODE="SLAVE", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", i_IDATAIN=lvds_data, i_CAL=self.idelay_cal_s, i_CE=id_CE, i_INC=id_INC, o_DATAOUT=lvds_data_s, **self.idelay_default) cascade_up = Signal() cascade_down = Signal() tempData = Signal(8) pdValid = Signal() pdInc = Signal() pdAcc = pd_int_accus[i] self.specials += Instance( "ISERDES2", p_SERDES_MODE="MASTER", i_D=lvds_data_m, i_SHIFTIN=cascade_up, o_Q4=tempData[7], o_Q3=tempData[6], o_Q2=tempData[5], o_Q1=tempData[4], o_SHIFTOUT=cascade_down, # The phase detector outputs o_VALID=pdValid, o_INCDEC=pdInc, **self.iserdes_default) # Accumulate increment / decrement pulses self.sync.sample += [ If( pd_int_cnt >= self.pd_int_period, # Latch accumulator value into output registers self.pd_int_phases[i].eq(pdAcc), # Reset accumulators pdAcc.eq(0)).Elif( pdValid & self.initial_tl_done, # Accumulate If(pdInc, pdAcc.eq(pdAcc - 1)).Else(pdAcc.eq(pdAcc + 1))) ] self.specials += Instance("ISERDES2", p_SERDES_MODE="SLAVE", i_D=lvds_data_s, i_SHIFTIN=cascade_down, o_Q4=tempData[3], o_Q3=tempData[2], o_Q2=tempData[1], o_Q1=tempData[0], o_SHIFTOUT=cascade_up, **self.iserdes_default) if MIRROR_BITS: self.comb += self.data_outs[i].eq(tempData[::-1]) else: self.comb += self.data_outs[i].eq(tempData)
def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"): """ Simple SPI flash. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode3 (cpol=1, cpha=1). """ SpiFlashCommon.__init__(self, pads) self.bus = bus = wishbone.Interface() spi_width = len(pads.dq) assert spi_width >= 2 if with_bitbang: self.bitbang = CSRStorage( 4, fields=[ CSRField( "mosi", description= "Output value for MOSI pin, valid whenever ``dir`` is ``0``." ), CSRField("clk", description="Output value for SPI CLK pin."), CSRField("cs_n", description="Output value for SPI CSn pin."), CSRField( "dir", description= "Sets the direction for *ALL* SPI data pins except CLK and CSn.", values=[ ("0", "OUT", "SPI pins are all output"), ("1", "IN", "SPI pins are all input"), ]) ], description=""" Bitbang controls for SPI output. Only standard 1x SPI is supported, and as a result all four wires are ganged together. This means that it is only possible to perform half-duplex operations, using this SPI core. """) self.miso = CSRStatus(description="Incoming value of MISO signal.") self.bitbang_en = CSRStorage( description= "Write a ``1`` here to disable memory-mapped mode and enable bitbang mode." ) # # # cs_n = Signal(reset=1) clk = Signal() dq_oe = Signal() wbone_width = len(bus.dat_r) read_cmd_params = { 4: (_format_cmd(_QIOFR, 4), 4 * 8), 2: (_format_cmd(_DIOFR, 2), 2 * 8), 1: (_format_cmd(_FAST_READ, 1), 1 * 8) } read_cmd, cmd_width = read_cmd_params[spi_width] addr_width = 24 dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) hw_read_logic = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] if with_bitbang: bitbang_logic = [ pads.clk.eq(self.bitbang.storage[1]), pads.cs_n.eq(self.bitbang.storage[2]), # In Dual/Quad mode, no single data pin is consistently # an input or output thanks to dual/quad reads, so we need a bit # to swap direction of the pins. Aside from this additional bit, # bitbang mode is identical for Single/Dual/Quad; dq[0] is mosi # and dq[1] is miso, meaning remaining data pin values don't # appear in CSR registers. If(self.bitbang.storage[3], dq.oe.eq(0)).Else(dq.oe.eq(1)), If( self.bitbang. storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only. self.miso.status.eq(dq.i[1])), dq.o.eq( Cat(self.bitbang.storage[0], Replicate(1, spi_width - 1))) ] self.comb += [ If(self.bitbang_en.storage, bitbang_logic).Else(hw_read_logic) ] else: self.comb += hw_read_logic if div < 2: raise ValueError( "Unsupported value \'{}\' for div parameter for SpiFlash core". format(div)) else: i = Signal(max=div) dqi = Signal(spi_width) self.sync += [ If( i == div // 2 - 1, clk.eq(1), dqi.eq(dq.i), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(dqi, sr[:-spi_width]))).Else(i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width // 8)) seq = [ (cmd_width // spi_width * div, [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width // spi_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width // spi_width) * div, [dq_oe.eq(0)]), (1, [bus.ack.eq(1), cs_n.eq(1)]), ( div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, pads, dummy=15, div=2, endianness="big"): """ Simple SPI flash. Supports 1-bit reads. Only supports mode0 (cpol=0, cpha=0). """ self.bus = bus = wishbone.Interface() # # # if hasattr(pads, "wp"): self.comb += pads.wp.eq(1) if hasattr(pads, "hold"): self.comb += pads.hold.eq(1) cs_n = Signal(reset=1) clk = Signal() wbone_width = len(bus.dat_r) read_cmd = _FAST_READ cmd_width = 8 addr_width = 24 sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) self.comb += [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), pads.mosi.eq(sr[-1:]) ] if div < 2: raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) else: i = Signal(max=div) miso = Signal() self.sync += [ If(i == div//2 - 1, clk.eq(1), miso.eq(pads.miso), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(miso, sr[:-1])) ).Else( i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width//8)) seq = [ (cmd_width*div, [cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width*div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width)*div, []), (1, [bus.ack.eq(1), cs_n.eq(1)]), (div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, pads, dummy=15, div=2, endianness="big"): """ Simple SPI flash. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode0 (cpol=0, cpha=0). """ self.bus = bus = wishbone.Interface() spi_width = len(pads.dq) assert spi_width >= 2 # # # cs_n = Signal(reset=1) clk = Signal() dq_oe = Signal() wbone_width = len(bus.dat_r) read_cmd_params = { 4: (_format_cmd(_QIOFR, 4), 4*8), 2: (_format_cmd(_DIOFR, 2), 2*8), 1: (_format_cmd(_FAST_READ, 1), 1*8) } read_cmd, cmd_width = read_cmd_params[spi_width] addr_width = 24 dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) self.comb += [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] if div < 2: raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) else: i = Signal(max=div) dqi = Signal(spi_width) self.sync += [ If(i == div//2 - 1, clk.eq(1), dqi.eq(dq.i), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(dqi, sr[:-spi_width])) ).Else( i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width//8)) seq = [ (cmd_width//spi_width*div, [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width//spi_width*div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width//spi_width)*div, [dq_oe.eq(0)]), (1, [bus.ack.eq(1), cs_n.eq(1)]), (div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, pads, cmd=0xfffefeff, cmd_width=32, addr_width=24, dummy=15, div=2): """ Simple read-only SPI flash, e.g. N25Q128 on the LX9 Microboard. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode0 (cpol=0, cpha=0). `cmd` is the read instruction. Since everything is transmitted on all dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq width even if dq1-dq3 are don't care during the command phase: For example, for N25Q128, 0xeb is the quad i/o fast read, and extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff """ self.bus = bus = wishbone.Interface() ## wbone_width = flen(bus.dat_r) spi_width = flen(pads.dq) pads.cs_n.reset = 1 dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) self.comb += [ bus.dat_r.eq(sr), dq.o.eq(sr[-spi_width:]), ] if div == 1: i = 0 self.comb += pads.clk.eq(~ClockSignal()) self.sync += sr.eq(Cat(dq.i, sr[:-spi_width])) else: i = Signal(max=div) dqi = Signal(spi_width) self.sync += [ If(i == div//2 - 1, pads.clk.eq(1), dqi.eq(dq.i), ), If(i == div - 1, i.eq(0), pads.clk.eq(0), sr.eq(Cat(dqi, sr[:-spi_width])) ).Else( i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width//8)) seq = [ (cmd_width//spi_width*div, [dq.oe.eq(1), pads.cs_n.eq(0), sr[-cmd_width:].eq(cmd)]), (addr_width//spi_width*div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width//spi_width)*div, [dq.oe.eq(0)]), (1, [bus.ack.eq(1), pads.cs_n.eq(1)]), (div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, a, ba, tRP, tREFI, tRFC): self.req = Signal() self.ack = Signal() # 1st command 1 cycle after assertion of ack self.cmd = CommandRequest(a, ba) ### # Refresh sequence generator: # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done seq_start = Signal() seq_done = Signal() self.sync += [ self.cmd.a.eq(2**10), self.cmd.ba.eq(0), self.cmd.cas_n.eq(1), self.cmd.ras_n.eq(1), self.cmd.we_n.eq(1), seq_done.eq(0) ] self.sync += timeline(seq_start, [ (1, [ self.cmd.ras_n.eq(0), self.cmd.we_n.eq(0) ]), (1+tRP, [ self.cmd.cas_n.eq(0), self.cmd.ras_n.eq(0) ]), (1+tRP+tRFC, [ seq_done.eq(1) ]) ]) # Periodic refresh counter counter = Signal(max=tREFI) start = Signal() self.sync += [ start.eq(0), If(counter == 0, start.eq(1), counter.eq(tREFI - 1) ).Else( counter.eq(counter - 1) ) ] # Control FSM fsm = FSM() self.submodules += fsm fsm.act("IDLE", If(start, NextState("WAIT_GRANT"))) fsm.act("WAIT_GRANT", self.req.eq(1), If(self.ack, seq_start.eq(1), NextState("WAIT_SEQ") ) ) fsm.act("WAIT_SEQ", self.req.eq(1), If(seq_done, NextState("IDLE")) )
def __init__(self, pads, dummy=5, div=2, endianness="big"): """ Simple SPI flash. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode0 (cpol=0, cpha=0). """ self.bus = bus = wishbone.Interface() spi_width = len(pads.dq) assert spi_width >= 2 # # # cs_n = Signal(reset=1) clk = Signal() dq_oe = Signal() wbone_width = len(bus.dat_r) read_cmd_params = { 4: (_format_cmd(_QIOFR, 4), 4 * 8), 2: (_format_cmd(_DIOFR, 2), 2 * 8), 1: (_format_cmd(_FAST_READ, 1), 1 * 8) } read_cmd, cmd_width = read_cmd_params[spi_width] write_cmd_params = { 4: _format_cmd(_QIOW, 4), 1: _format_cmd(_WRITE, 1), } write_cmd = write_cmd_params[spi_width] write_stage = Signal() # 0 during address stage, 1 during write stage addr_width = 24 dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) if endianness == "big": self.comb += bus.dat_r.eq(sr) else: self.comb += bus.dat_r.eq(reverse_bytes(sr)) hw_read_logic = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] self.comb += hw_read_logic if div < 2: raise ValueError( "Unsupported value \'{}\' for div parameter for SpiFlash core". format(div)) else: i = Signal(max=div) dqi = Signal(spi_width) dqo = Signal(spi_width) self.sync += [ If( i == div // 2 - 1, clk.eq(1), dqi.eq(dq.i), ), If( i == div - 1, i.eq(0), clk.eq(0), If( bus.we & write_stage, # If we're writing, reuse the `dat_r` lines # as a temporary buffer to shift out the data. sr.eq(Cat(Signal(spi_width), sr[:-spi_width])), ).Else(sr.eq(Cat(dqi, sr[:-spi_width])))).Else(i.eq(i + 1), ), ] # spi is byte-addressed, prefixed by zeroes z = Replicate(0, log2_int(wbone_width // 8)) seq = [ # Send the `read_cmd` out the port, reusing the # Wishbone `rx` line as a temporary buffer (cmd_width // spi_width * div, [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), # Write the address out the port, again by reusing the # Wishbone `rx` line as a temporary buffer (addr_width // spi_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), # Wait for 8 clock cycles for the read to appear ((dummy + wbone_width // spi_width) * div, [dq_oe.eq(0)]), (1, [bus.ack.eq(1), cs_n.eq(1)]), ( div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, rd_tseq = 0, [] for dt, a in seq: rd_tseq.append((t, a)) t += dt addr_stage = Signal() seq = [ # Send the `write_cmd` out the port (cmd_width // spi_width * div, [ dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(write_cmd), write_stage.eq(0), addr_stage.eq(0) ]), # Write the address out the port, again by reusing the # Wishbone `rx` line as a temporary buffer (addr_width // spi_width * div, [sr[-addr_width:].eq(Cat(z, bus.adr)), addr_stage.eq(1)]), # Immediately write the data out (1, [write_stage.eq(1), sr.eq(bus.dat_w)]), ((wbone_width // spi_width) * div, []), (1, [bus.ack.eq(1), cs_n.eq(1), dq_oe.eq(0)]), ( div, # tSHSL! [ bus.ack.eq(0), ]), (0, []), ] # accumulate timeline deltas t, wr_tseq = 0, [] for dt, a in seq: wr_tseq.append((t, a)) t += dt self.sync += [ timeline(bus.cyc & bus.stb & ~bus.we & (i == div - 1), rd_tseq), timeline(bus.cyc & bus.stb & bus.we & (i == div - 1), wr_tseq), ]
def __init__(self, order=1, mode="pipelined", width=25, coeff_width=18, shift=16, intermediate_width=None): Filter.__init__(self, width) assert mode in ("pipelined", "iterative") if intermediate_width is None: intermediate_width = width + coeff_width # + bits_for(2*(order + 1)) self.z0 = CSRStorage(intermediate_width - shift, reset=0) self.shift = CSRConstant(shift) self.width = CSRConstant(coeff_width) self.interval = CSRConstant(0, 8) self.latency = CSRConstant(0, 8) self.order = CSRConstant(order, 8) self.iterative = CSRConstant(mode == "iterative", 1) self.c = c = {} for i in "ab": for j in range(order + 1): name = "%s%i" % (i, j) if name == "a0": continue ci = Signal((coeff_width, True), name=name) rci = CSRStorage(len(ci), name=name) self.sync += ci.eq(rci.storage) c[name] = ci setattr(self, "r_" + name, rci) ### z = Signal((intermediate_width, True), name="z0r") self.sync += z.eq(self.z0.storage << shift) y_lim = Signal.like(self.y) y_next = Signal.like(z) y_over = y_next[shift+width-1:] y_pat = Signal.like(y_over, reset=-1) y = Signal.like(self.y) railed = Signal() self.comb += [ railed.eq(~((y_over == y_pat) | (y_over == ~y_pat))), If(railed, y_lim.eq(self.y) ).Else( y_lim.eq(y_next[shift:]) ) ] self.sync += [ self.error.eq(railed), self.y.eq(y_lim), If(self.clear, y.eq(0) ).Elif(~self.hold, y.eq(y_lim) ) ] if mode == "pipelined": r = [("b%i" % i, self.x) for i in reversed(range(order + 1))] r += [("a%i" % i, y) for i in reversed(range(1, order + 1))] for coeff, signal in r: zr = Signal.like(z) self.sync += zr.eq(z) z = Signal.like(zr) self.comb += z.eq(zr + signal*c[coeff]) self.comb += y_next.eq(z) self.latency.value = Constant(order + 1) self.interval.value = Constant(1) elif mode == "iterative": ma = Signal.like(self.y) mb = Signal.like(c["a1"]) mm = Signal.like(z) mc = Signal.like(z) mp = Signal.like(z) self.sync += mm.eq(ma*mb), mc.eq(mp) self.comb += mp.eq(mm + mc) steps = [] x = [self.x] + [Signal.like(self.x) for i in range(order + 1)] for i in reversed(range(order + 1)): steps.append([ x[i + 1].eq(x[i]), ma.eq(x[i]), mb.eq(c["b%i" % i]) ]) y = [None, y] + [Signal.like(y) for i in range(1, order + 1)] for i in reversed(range(1, order + 1)): steps.append([ y[i + 1].eq(y[i]), ma.eq(y[i]), mb.eq(c["a%i" % i]) ]) steps[1].append(mc.eq(z)) latency = order + 4 if order == 1: steps.append([]) latency += 1 self.latency.value = Constant(latency) steps[int(order > 1)].append(y_next.eq(mp)) self.sync += timeline(1, list(enumerate(steps))) self.interval.value = Constant(len(steps)) else: raise ValueError
def __init__(self, pads): """ MFIO simple core for LiteX """ mfioCommon.__init__(self, pads) mfio_width = len(pads) # mfio_o = Signal(mfio_width) mfio_oe = Signal(mfio_width) mfio_i = Signal(mfio_width) # create single pin tristate buffers for b in range(mfio_width): self.submodules += mfioSinglePin(pads, b, mfio_i[b], mfio_o[b], mfio_oe[b]) # Wishbone self.bus = bus = wishbone.Interface() # sel = Signal(mfio_width) inbit = Signal(1) # todo: dynamic address width calc to optimize the decode logic addr_width = 12 # 1024 IO max seladr = Signal(10) # 10 bits of address = 1024 pins max self.comb += seladr.eq(self.bus.adr[:10]) # address decoder for b in range(mfio_width): self.comb += sel[b].eq(seladr == b) self.comb += inbit.eq((mfio_i & sel) != 0) # Read bit rdbus = Signal(32) self.comb += [rdbus[0].eq(inbit), bus.dat_r.eq(rdbus)] # process output outbit = Signal(1) oebit = Signal(1) wren = Signal(1) # PINAPI 1.0 compatible: 0 = drive 0, 1 drive 1, 3 = HiZ self.comb += outbit.eq(bus.dat_w[0]) self.comb += oebit.eq(~bus.dat_w[1]) # write enable self.comb += wren.eq(self.bus.stb & self.bus.cyc & self.bus.we) for b in range(mfio_width): self.sync += If(wren & sel[b], mfio_o[b].eq(outbit), mfio_oe[b].eq(oebit)) seq = [ (1, [bus.ack.eq(1)]), # (1, [bus.ack.eq(0)]), # (0, []), ] t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb, tseq)