def __init__(self, pads, cl=2): pads = PHYPadsCombiner(pads) addressbits = len(pads.a) bankbits = len(pads.ba) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) assert databits % 8 == 0 # PHY settings ----------------------------------------------------------------------------- self.settings = PhySettings(memtype="SDR", databits=databits, dfi_databits=databits, nranks=nranks, nphases=1, rdphase=0, wrphase=0, rdcmdphase=0, wrcmdphase=0, cl=cl, read_latency=cl + 2, write_latency=0) # DFI Interface ---------------------------------------------------------------------------- self.dfi = dfi = Interface(addressbits, bankbits, nranks, databits) # # # # Iterate on pads groups ------------------------------------------------------------------- for pads_group in range(len(pads.groups)): pads.sel_group(pads_group) # Addresses and Commands --------------------------------------------------------------- self.sync += [ pads.a.eq(dfi.p0.address), pads.ba.eq(dfi.p0.bank), pads.cas_n.eq(dfi.p0.cas_n), pads.ras_n.eq(dfi.p0.ras_n), pads.we_n.eq(dfi.p0.we_n) ] if hasattr(pads, "cke"): self.sync += pads.cke.eq(dfi.p0.cke) if hasattr(pads, "cs_n"): self.sync += pads.cs_n.eq(dfi.p0.cs_n) # DQ/DQS/DM Data --------------------------------------------------------------------------- dq_o = Signal(databits) dq_oe = Signal() dq_i = Signal(databits) self.sync += dq_o.eq(dfi.p0.wrdata) for i in range(len(pads.dq)): self.specials += Tristate(pads.dq[i], dq_o[i], dq_oe, dq_i[i]) if hasattr(pads, "dm"): assert len(pads.dm) * 8 == databits for i in range(len(pads.dm)): self.sync += \ If(dfi.p0.wrdata_en, pads.dm[i].eq(dfi.p0.wrdata_mask) ).Else( pads.dm[i].eq(0) ) dq_in = Signal(databits) self.sync.sys_ps += dq_in.eq(dq_i) self.sync += dfi.p0.rddata.eq(dq_in) # DQ/DM Control ---------------------------------------------------------------------------- wrdata_en = Signal() self.sync += wrdata_en.eq(dfi.p0.wrdata_en) self.comb += dq_oe.eq(wrdata_en) rddata_en = Signal(cl + 2) self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en[:cl + 1])) self.comb += dfi.p0.rddata_valid.eq(rddata_en[cl + 1])
def __init__(self, pads, sys_clk_freq=100e6, cl=None, cwl=None, cmd_delay=0, clk_polarity=0): assert isinstance(cmd_delay, int) and cmd_delay < 128 pads = PHYPadsCombiner(pads) memtype = "DDR3" tck = 2 / (2 * 2 * sys_clk_freq) addressbits = len(pads.a) bankbits = len(pads.ba) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) nphases = 2 assert databits % 8 == 0 # Init ------------------------------------------------------------------------------------- self.submodules.init = ECP5DDRPHYInit() # Parameters ------------------------------------------------------------------------------- cl = get_default_cl(memtype, tck) if cl is None else cl cwl = get_default_cwl(memtype, tck) if cwl is None else cwl cl_sys_latency = get_sys_latency(nphases, cl) cwl_sys_latency = get_sys_latency(nphases, cwl) # Registers -------------------------------------------------------------------------------- self._dly_sel = CSRStorage(databits // 8) self._rdly_dq_rst = CSR() self._rdly_dq_inc = CSR() self._rdly_dq_bitslip_rst = CSR() self._rdly_dq_bitslip = CSR() self._burstdet_clr = CSR() self._burstdet_seen = CSRStatus(databits // 8) # Observation self.datavalid = Signal(databits // 8) # PHY settings ----------------------------------------------------------------------------- rdphase = get_sys_phase(nphases, cl_sys_latency, cl) wrphase = get_sys_phase(nphases, cwl_sys_latency, cwl) self.settings = PhySettings(phytype="ECP5DDRPHY", memtype=memtype, databits=databits, dfi_databits=4 * databits, nranks=nranks, nphases=nphases, rdphase=rdphase, wrphase=wrphase, cl=cl, cwl=cwl, read_latency=cl_sys_latency + 10, write_latency=cwl_sys_latency) # DFI Interface ---------------------------------------------------------------------------- self.dfi = dfi = Interface(addressbits, bankbits, nranks, 4 * databits, nphases) # # # bl8_chunk = Signal() # Iterate on pads groups ------------------------------------------------------------------- for pads_group in range(len(pads.groups)): pads.sel_group(pads_group) # Clock -------------------------------------------------------------------------------- clk_pattern = {0: 0b1010, 1: 0b0101}[clk_polarity] for i in range(len(pads.clk_p)): pad_oddrx2f = Signal() self.specials += Instance( "ODDRX2F", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), **{f"i_D{n}": (clk_pattern >> n) & 0b1 for n in range(4)}, o_Q=pad_oddrx2f) self.specials += Instance("DELAYG", p_DEL_VALUE=cmd_delay, i_A=pad_oddrx2f, o_Z=pads.clk_p[i]) # Commands ----------------------------------------------------------------------------- commands = { # Pad name: (DFI name, Pad type (required or optional)) "reset_n": ("reset_n", "optional"), "cs_n": ("cs_n", "optional"), "a": ("address", "required"), "ba": ("bank", "required"), "ras_n": ("ras_n", "required"), "cas_n": ("cas_n", "required"), "we_n": ("we_n", "required"), "cke": ("cke", "optional"), "odt": ("odt", "optional"), } for pad_name, (dfi_name, pad_type) in commands.items(): pad = getattr(pads, pad_name, None) if (pad is None): if (pad_type == "required"): raise ValueError( f"DRAM pad {pad_name} required but not found in pads." ) continue for i in range(len(pad)): pad_oddrx2f = Signal() self.specials += Instance("ODDRX2F", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), **{ f"i_D{n}": getattr( dfi.phases[n // 2], dfi_name)[i] for n in range(4) }, o_Q=pad_oddrx2f) self.specials += Instance("DELAYG", p_DEL_VALUE=cmd_delay, i_A=pad_oddrx2f, o_Z=pad[i]) # DQS/DM/DQ -------------------------------------------------------------------------------- dq_oe = Signal() dqs_re = Signal() dqs_oe = Signal() dqs_postamble = Signal() dqs_preamble = Signal() for i in range(databits // 8): # DQSBUFM dqs_i = Signal() dqsr90 = Signal() dqsw270 = Signal() dqsw = Signal() rdpntr = Signal(3) wrpntr = Signal(3) rdly = Signal(7) burstdet = Signal() self.sync += [ If(self._dly_sel.storage[i] & self._rdly_dq_rst.re, rdly.eq(0)), If(self._dly_sel.storage[i] & self._rdly_dq_inc.re, rdly.eq(rdly + 1)) ] self.specials += Instance( "DQSBUFM", p_DQS_LI_DEL_ADJ="MINUS", p_DQS_LI_DEL_VAL=1, p_DQS_LO_DEL_ADJ="MINUS", p_DQS_LO_DEL_VAL=4, # Clocks / Reset i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_DDRDEL=self.init.delay, i_PAUSE=self.init.pause | self._dly_sel.storage[i], # Control # Assert LOADNs to use DDRDEL control i_RDLOADN=0, i_RDMOVE=0, i_RDDIRECTION=1, i_WRLOADN=0, i_WRMOVE=0, i_WRDIRECTION=1, # Reads (generate shifted DQS clock for reads) i_READ0=dqs_re, i_READ1=dqs_re, **{f"i_READCLKSEL{n}": rdly[n] for n in range(3)}, i_DQSI=dqs_i, o_DQSR90=dqsr90, **{f"o_RDPNTR{n}": rdpntr[n] for n in range(3)}, **{f"o_WRPNTR{n}": wrpntr[n] for n in range(3)}, o_DATAVALID=self.datavalid[i], o_BURSTDET=burstdet, # Writes (generate shifted ECLK clock for writes) o_DQSW270=dqsw270, o_DQSW=dqsw) burstdet_d = Signal() self.sync += [ burstdet_d.eq(burstdet), If(self._burstdet_clr.re, self._burstdet_seen.status[i].eq(0)), If(burstdet & ~burstdet_d, self._burstdet_seen.status[i].eq(1)), ] # DQS ---------------------------------------------------------------------------------- dqs = Signal() dqs_oe_n = Signal() self.specials += [ Instance("ODDRX2DQSB", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_DQSW=dqsw, **{f"i_D{n}": (0b1010 >> n) & 0b1 for n in range(4)}, o_Q=dqs), Instance("TSHX2DQSA", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_DQSW=dqsw, i_T0=~(dqs_oe | dqs_postamble), i_T1=~(dqs_oe | dqs_preamble), o_Q=dqs_oe_n), Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i) ] # DM ----------------------------------------------------------------------------------- dm_o_data = Signal(8) dm_o_data_d = Signal(8) dm_o_data_muxed = Signal(4) for n in range(8): self.comb += dm_o_data[n].eq( dfi.phases[n // 4].wrdata_mask[n % 4 * databits // 8 + i]) self.sync += dm_o_data_d.eq(dm_o_data) dm_bl8_cases = {} dm_bl8_cases[0] = dm_o_data_muxed.eq(dm_o_data[:4]) dm_bl8_cases[1] = dm_o_data_muxed.eq(dm_o_data_d[4:]) self.sync += Case(bl8_chunk, dm_bl8_cases) self.specials += Instance( "ODDRX2DQA", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_DQSW270=dqsw270, **{f"i_D{n}": dm_o_data_muxed[n] for n in range(4)}, o_Q=pads.dm[i]) # DQ ----------------------------------------------------------------------------------- for j in range(8 * i, 8 * (i + 1)): dq_o = Signal() dq_i = Signal() dq_oe_n = Signal() dq_i_delayed = Signal() dq_i_data = Signal(8) dq_o_data = Signal(8) dq_o_data_d = Signal(8) dq_o_data_muxed = Signal(4) for n in range(8): self.comb += dq_o_data[n].eq( dfi.phases[n // 4].wrdata[n % 4 * databits + j]) self.sync += dq_o_data_d.eq(dq_o_data) dq_bl8_cases = {} dq_bl8_cases[0] = dq_o_data_muxed.eq(dq_o_data[:4]) dq_bl8_cases[1] = dq_o_data_muxed.eq(dq_o_data_d[4:]) self.sync += Case(bl8_chunk, dq_bl8_cases) self.specials += [ Instance( "ODDRX2DQA", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_DQSW270=dqsw270, **{f"i_D{n}": dq_o_data_muxed[n] for n in range(4)}, o_Q=dq_o) ] dq_i_bitslip = BitSlip(4, rst=self._dly_sel.storage[i] & self._rdly_dq_bitslip_rst.re, slp=self._dly_sel.storage[i] & self._rdly_dq_bitslip.re, cycles=1) self.submodules += dq_i_bitslip self.specials += [ Instance("DELAYG", p_DEL_MODE="DQS_ALIGNED_X2", i_A=dq_i, o_Z=dq_i_delayed), Instance( "IDDRX2DQA", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_DQSR90=dqsr90, **{f"i_RDPNTR{n}": rdpntr[n] for n in range(3)}, **{f"i_WRPNTR{n}": wrpntr[n] for n in range(3)}, i_D=dq_i_delayed, **{f"o_Q{n}": dq_i_bitslip.i[n] for n in range(4)}, ) ] dq_i_bitslip_o_d = Signal(4) self.sync += dq_i_bitslip_o_d.eq(dq_i_bitslip.o) self.comb += dq_i_data.eq(Cat(dq_i_bitslip_o_d, dq_i_bitslip.o)) for n in range(8): self.comb += dfi.phases[n // 4].rddata[n % 4 * databits + j].eq(dq_i_data[n]) self.specials += [ Instance( "TSHX2DQA", i_RST=ResetSignal("sys"), i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_DQSW270=dqsw270, i_T0=~dq_oe, i_T1=~dq_oe, o_Q=dq_oe_n, ), Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i) ] # Read Control Path ------------------------------------------------------------------------ rdtap = cl_sys_latency # Creates a delay line of read commands coming from the DFI interface. The taps are used to # control DQS read (internal read pulse of the DQSBUF) and the output of the delay is used # signal a valid read data to the DFI interface. # # The DQS read must be asserted for 2 sys_clk cycles before the read data is coming back from # the DRAM (see 6.2.4 READ Pulse Positioning Optimization of FPGA-TN-02035-1.2) # # The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI # interface, the latency is the sum of the ODDRX2DQA, CAS, IDDRX2DQA latencies. rddata_en = TappedDelayLine(signal=reduce( or_, [dfi.phases[i].rddata_en for i in range(nphases)]), ntaps=self.settings.read_latency) self.submodules += rddata_en self.comb += [ phase.rddata_valid.eq(rddata_en.output) for phase in dfi.phases ] self.comb += dqs_re.eq(rddata_en.taps[rdtap] | rddata_en.taps[rdtap + 1]) # Write Control Path ----------------------------------------------------------------------- wrtap = cwl_sys_latency # Create a delay line of write commands coming from the DFI interface. This taps are used to # control DQ/DQS tristates and to select write data of the DRAM burst from the DFI interface. # The PHY is operating in halfrate mode (so provide 4 datas every sys_clk cycles: 2x for DDR, # 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency. Writes are # then performed in 2 sys_clk cycles and data needs to be selected for each cycle. wrdata_en = TappedDelayLine(signal=reduce( or_, [dfi.phases[i].wrdata_en for i in range(nphases)]), ntaps=wrtap + 4) self.submodules += wrdata_en self.comb += dq_oe.eq(wrdata_en.taps[wrtap] | wrdata_en.taps[wrtap + 1]) self.comb += bl8_chunk.eq(wrdata_en.taps[wrtap]) self.comb += dqs_oe.eq(dq_oe) # Write DQS Postamble/Preamble Control Path ------------------------------------------------ # Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last # write. During writes, DQS tristate is configured as output for at least 4 sys_clk cycles: # 1 for Preamble, 2 for the Write and 1 for the Postamble. self.comb += dqs_preamble.eq(wrdata_en.taps[wrtap - 1] & ~wrdata_en.taps[wrtap + 0]) self.comb += dqs_postamble.eq(wrdata_en.taps[wrtap + 2] & ~wrdata_en.taps[wrtap + 1])
def __init__(self, pads, dw=32, timeout=1024): read_fifo = ClockDomainsRenamer({ "write": "usb", "read": "sys" })(stream.AsyncFIFO(phy_description(dw), 128)) write_fifo = ClockDomainsRenamer({ "write": "sys", "read": "usb" })(stream.AsyncFIFO(phy_description(dw), 128)) read_buffer = ClockDomainsRenamer("usb")(stream.SyncFIFO( phy_description(dw), 4)) self.comb += read_buffer.source.connect(read_fifo.sink) self.submodules += read_fifo self.submodules += read_buffer self.submodules += write_fifo self.read_buffer = read_buffer self.sink = write_fifo.sink self.source = read_fifo.source self.tdata_w = tdata_w = Signal(dw) self.data_r = data_r = Signal(dw) self.data_oe = data_oe = Signal() self.specials += Tristate(pads.data, tdata_w, data_oe, data_r) data_w = Signal(dw) _data_w = Signal(dw) self.sync.usb += [_data_w.eq(data_w)] for i in range(dw): self.specials += [ Instance("ODDR", p_DDR_CLK_EDGE="SAME_EDGE", i_C=ClockSignal("usb"), i_CE=1, i_S=0, i_R=0, i_D1=_data_w[i], i_D2=data_w[i], o_Q=tdata_w[i]) ] self.rd_n = rd_n = Signal() _rd_n = Signal(reset=1) self.wr_n = wr_n = Signal() _wr_n = Signal(reset=1) self.oe_n = oe_n = Signal() _oe_n = Signal(reset=1) self.sync.usb += [ _rd_n.eq(rd_n), _wr_n.eq(wr_n), _oe_n.eq(oe_n), ] self.specials += [ Instance("ODDR", p_DDR_CLK_EDGE="SAME_EDGE", i_C=ClockSignal("usb"), i_CE=1, i_S=0, i_R=0, i_D1=_rd_n, i_D2=rd_n, o_Q=pads.rd_n), Instance("ODDR", p_DDR_CLK_EDGE="SAME_EDGE", i_C=ClockSignal("usb"), i_CE=1, i_S=0, i_R=0, i_D1=_wr_n, i_D2=wr_n, o_Q=pads.wr_n), Instance("ODDR", p_DDR_CLK_EDGE="SAME_EDGE", i_C=ClockSignal("usb"), i_CE=1, i_S=0, i_R=0, i_D1=_oe_n, i_D2=oe_n, o_Q=pads.oe_n) ] self.comb += [ pads.rst.eq(~ResetSignal("usb")), pads.be.eq(0xf), pads.siwua.eq(1), data_oe.eq(oe_n), ] fsm = FSM() self.submodules.fsm = ClockDomainsRenamer("usb")(fsm) self.tempsendval = tempsendval = Signal(dw) self.temptosend = temptosend = Signal() self.tempreadval = tempreadval = Signal(dw) self.temptoread = temptoread = Signal() self.wants_read = wants_read = Signal() self.wants_write = wants_write = Signal() self.cnt_write = cnt_write = Signal(max=timeout + 1) self.cnt_read = cnt_read = Signal(max=timeout + 1) first_write = Signal() self.comb += [ wants_read.eq(~temptoread & ~pads.rxf_n), wants_write.eq((temptosend | write_fifo.source.valid) & (pads.txe_n == 0)), ] self.fsmstate = Signal(4) self.comb += [ self.fsmstate.eq( Cat(fsm.ongoing("IDLE"), fsm.ongoing("WRITE"), fsm.ongoing("RDWAIT"), fsm.ongoing("READ"))) ] self.sync.usb += [ If(~fsm.ongoing("READ"), If(temptoread, If(read_buffer.sink.ready, temptoread.eq(0)))) ] self.comb += [ If( ~fsm.ongoing("READ"), If( temptoread, read_buffer.sink.data.eq(tempreadval), read_buffer.sink.valid.eq(1), )) ] fsm.act( "IDLE", rd_n.eq(1), wr_n.eq(1), If( wants_write, oe_n.eq(1), NextValue(cnt_write, 0), NextValue(first_write, 1), NextState("WRITE"), ).Elif(wants_read, oe_n.eq(0), NextState("RDWAIT")).Else(oe_n.eq(1), )) fsm.act( "WRITE", If( wants_read, NextValue(cnt_write, cnt_write + 1), ), NextValue(first_write, 0), rd_n.eq(1), If( pads.txe_n, oe_n.eq(1), wr_n.eq(1), write_fifo.source.ready.eq(0), If(write_fifo.source.valid & ~first_write, NextValue(temptosend, 1)), NextState("IDLE")).Elif( temptosend, oe_n.eq(1), data_w.eq(tempsendval), wr_n.eq(0), NextValue(temptosend, 0)).Elif(cnt_write > timeout, oe_n.eq(0), NextState("RDWAIT")).Elif( write_fifo.source.valid, oe_n.eq(1), data_w.eq(write_fifo.source.data), write_fifo.source.ready.eq(1), NextValue(tempsendval, write_fifo.source.data), NextValue(temptosend, 0), wr_n.eq(0), ).Else(oe_n.eq(1), wr_n.eq(1), NextValue(temptosend, 0), NextState("IDLE"))) fsm.act("RDWAIT", rd_n.eq(0), oe_n.eq(0), wr_n.eq(1), NextValue(cnt_read, 0), NextState("READ")) fsm.act( "READ", If( wants_write, NextValue(cnt_read, cnt_read + 1), ), wr_n.eq(1), If( pads.rxf_n, oe_n.eq(0), rd_n.eq(1), NextState("IDLE"), ).Elif( cnt_read > timeout, NextValue(cnt_write, 0), NextValue(first_write, 1), NextState("WRITE"), oe_n.eq(1), ).Else( oe_n.eq(0), read_buffer.sink.valid.eq(1), read_buffer.sink.data.eq(data_r), NextValue(tempreadval, data_r), If(read_buffer.sink.ready, rd_n.eq(0)).Else(NextValue(temptoread, 1), NextState("IDLE"), rd_n.eq(1))))
def __init__(self, pads, sys_clk_freq=100e6): memtype = "DDR3" tck = 2/(2*2*sys_clk_freq) addressbits = len(pads.a) bankbits = len(pads.ba) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) nphases = 2 # Init ------------------------------------------------------------------------------------- self.submodules.init = ClockDomainsRenamer("init")(ECP5DDRPHYInit("sys2x")) # Registers -------------------------------------------------------------------------------- self._dly_sel = CSRStorage(databits//8) self._rdly_dq_rst = CSR() self._rdly_dq_inc = CSR() self._rdly_dq_bitslip_rst = CSR() self._rdly_dq_bitslip = CSR() self._burstdet_clr = CSR() self._burstdet_seen = CSRStatus(databits//8) # Observation self.datavalid = Signal(databits//8) # PHY settings ----------------------------------------------------------------------------- cl, cwl = get_cl_cw(memtype, tck) cl_sys_latency = get_sys_latency(nphases, cl) cwl_sys_latency = get_sys_latency(nphases, cwl) rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings( memtype=memtype, databits=databits, dfi_databits=4*databits, nranks=nranks, nphases=nphases, rdphase=rdphase, wrphase=wrphase, rdcmdphase=rdcmdphase, wrcmdphase=wrcmdphase, cl=cl, cwl=cwl, read_latency=2 + cl_sys_latency + 2 + log2_int(4//nphases) + 6, write_latency=cwl_sys_latency ) # DFI Interface ---------------------------------------------------------------------------- self.dfi = Interface(addressbits, bankbits, nranks, 4*databits, 4) # # # bl8_sel = Signal() # Clock ------------------------------------------------------------------------------------ for i in range(len(pads.clk_p)): sd_clk_se = Signal() self.specials += [ Instance("ODDRX2F", i_D0=0, i_D1=1, i_D2=0, i_D3=1, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal("sys2x"), o_Q=pads.clk_p[i] ), ] # Addresses and Commands ------------------------------------------------------------------- for i in range(addressbits): self.specials += \ Instance("ODDRX2F", i_D0=self.dfi.phases[0].address[i], i_D1=self.dfi.phases[0].address[i], i_D2=self.dfi.phases[1].address[i], i_D3=self.dfi.phases[1].address[i], i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal("sys2x"), o_Q=pads.a[i] ) for i in range(bankbits): self.specials += \ Instance("ODDRX2F", i_D0=self.dfi.phases[0].bank[i], i_D1=self.dfi.phases[0].bank[i], i_D2=self.dfi.phases[1].bank[i], i_D3=self.dfi.phases[1].bank[i], i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal("sys2x"), o_Q=pads.ba[i] ) controls = ["ras_n", "cas_n", "we_n", "cke", "odt"] if hasattr(pads, "reset_n"): controls.append("reset_n") if hasattr(pads, "cs_n"): controls.append("cs_n") for name in controls: for i in range(len(getattr(pads, name))): self.specials += \ Instance("ODDRX2F", i_D0=getattr(self.dfi.phases[0], name)[i], i_D1=getattr(self.dfi.phases[0], name)[i], i_D2=getattr(self.dfi.phases[1], name)[i], i_D3=getattr(self.dfi.phases[1], name)[i], i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal("sys2x"), o_Q=getattr(pads, name)[i] ) # DQ --------------------------------------------------------------------------------------- oe_dq = Signal() oe_dqs = Signal() dqs_postamble = Signal() dqs_preamble = Signal() dqs_read = Signal() for i in range(databits//8): # DQSBUFM dqs_i = Signal() dqsr90 = Signal() dqsw270 = Signal() dqsw = Signal() rdpntr = Signal(3) wrpntr = Signal(3) rdly = Signal(7) self.sync += \ If(self._dly_sel.storage[i], If(self._rdly_dq_rst.re, rdly.eq(0), ).Elif(self._rdly_dq_inc.re, rdly.eq(rdly + 1), ) ) datavalid = Signal() burstdet = Signal() self.specials += Instance("DQSBUFM", p_DQS_LI_DEL_ADJ="MINUS", p_DQS_LI_DEL_VAL=1, p_DQS_LO_DEL_ADJ="MINUS", p_DQS_LO_DEL_VAL=4, # Clocks / Reset i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_RST=ResetSignal("sys2x"), i_DDRDEL=self.init.delay, i_PAUSE=self.init.pause | self._dly_sel.storage[i], # Control # Assert LOADNs to use DDRDEL control i_RDLOADN=0, i_RDMOVE=0, i_RDDIRECTION=1, i_WRLOADN=0, i_WRMOVE=0, i_WRDIRECTION=1, # Reads (generate shifted DQS clock for reads) i_READ0=dqs_read, i_READ1=dqs_read, i_READCLKSEL0=rdly[0], i_READCLKSEL1=rdly[1], i_READCLKSEL2=rdly[2], i_DQSI=dqs_i, o_DQSR90=dqsr90, o_RDPNTR0=rdpntr[0], o_RDPNTR1=rdpntr[1], o_RDPNTR2=rdpntr[2], o_WRPNTR0=wrpntr[0], o_WRPNTR1=wrpntr[1], o_WRPNTR2=wrpntr[2], o_DATAVALID=self.datavalid[i], o_BURSTDET=burstdet, # Writes (generate shifted ECLK clock for writes) o_DQSW270=dqsw270, o_DQSW=dqsw ) burstdet_d = Signal() self.sync += [ burstdet_d.eq(burstdet), If(self._burstdet_clr.re, self._burstdet_seen.status[i].eq(0) ).Elif(burstdet & ~burstdet_d, self._burstdet_seen.status[i].eq(1) ) ] # DQS and DM --------------------------------------------------------------------------- dqs_serdes_pattern = Signal(8, reset=0b1010) dm_o_data = Signal(8) dm_o_data_d = Signal(8) dm_o_data_muxed = Signal(4) self.comb += dm_o_data.eq(Cat( self.dfi.phases[0].wrdata_mask[0*databits//8+i], self.dfi.phases[0].wrdata_mask[1*databits//8+i], self.dfi.phases[0].wrdata_mask[2*databits//8+i], self.dfi.phases[0].wrdata_mask[3*databits//8+i], self.dfi.phases[1].wrdata_mask[0*databits//8+i], self.dfi.phases[1].wrdata_mask[1*databits//8+i], self.dfi.phases[1].wrdata_mask[2*databits//8+i], self.dfi.phases[1].wrdata_mask[3*databits//8+i]), ) self.sync += dm_o_data_d.eq(dm_o_data) self.sync += \ If(bl8_sel, dm_o_data_muxed.eq(dm_o_data_d[4:]) ).Else( dm_o_data_muxed.eq(dm_o_data[:4]) ) self.specials += \ Instance("ODDRX2DQA", i_D0=dm_o_data_muxed[0], i_D1=dm_o_data_muxed[1], i_D2=dm_o_data_muxed[2], i_D3=dm_o_data_muxed[3], i_RST=ResetSignal("sys2x"), i_DQSW270=dqsw270, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), o_Q=pads.dm[i] ) dqs = Signal() dqs_oe_n = Signal() self.specials += \ Instance("ODDRX2DQSB", i_D0=dqs_serdes_pattern[0], i_D1=dqs_serdes_pattern[1], i_D2=dqs_serdes_pattern[2], i_D3=dqs_serdes_pattern[3], i_RST=ResetSignal("sys2x"), i_DQSW=dqsw, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), o_Q=dqs ) self.specials += \ Instance("TSHX2DQSA", i_T0=~(oe_dqs|dqs_postamble), i_T1=~(oe_dqs|dqs_preamble), i_SCLK=ClockSignal(), i_ECLK=ClockSignal("sys2x"), i_DQSW=dqsw, i_RST=ResetSignal("sys2x"), o_Q=dqs_oe_n, ) self.specials += Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i) for j in range(8*i, 8*(i+1)): dq_o = Signal() dq_i = Signal() dq_oe_n = Signal() dq_i_delayed = Signal() dq_i_data = Signal(4) dq_o_data = Signal(8) dq_o_data_d = Signal(8) dq_o_data_muxed = Signal(4) self.comb += dq_o_data.eq(Cat( self.dfi.phases[0].wrdata[0*databits+j], self.dfi.phases[0].wrdata[1*databits+j], self.dfi.phases[0].wrdata[2*databits+j], self.dfi.phases[0].wrdata[3*databits+j], self.dfi.phases[1].wrdata[0*databits+j], self.dfi.phases[1].wrdata[1*databits+j], self.dfi.phases[1].wrdata[2*databits+j], self.dfi.phases[1].wrdata[3*databits+j]) ) self.sync += dq_o_data_d.eq(dq_o_data) self.sync += \ If(bl8_sel, dq_o_data_muxed.eq(dq_o_data_d[4:]) ).Else( dq_o_data_muxed.eq(dq_o_data[:4]) ) self.specials += \ Instance("ODDRX2DQA", i_D0=dq_o_data_muxed[0], i_D1=dq_o_data_muxed[1], i_D2=dq_o_data_muxed[2], i_D3=dq_o_data_muxed[3], i_RST=ResetSignal("sys2x"), i_DQSW270=dqsw270, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), o_Q=dq_o ) self.specials += \ Instance("DELAYF", i_A=dq_i, i_LOADN=1, i_MOVE=0, i_DIRECTION=0, o_Z=dq_i_delayed, p_DEL_MODE="DQS_ALIGNED_X2" ) self.specials += \ Instance("IDDRX2DQA", i_D=dq_i_delayed, i_RST=ResetSignal("sys2x"), i_DQSR90=dqsr90, i_SCLK=ClockSignal(), i_ECLK=ClockSignal("sys2x"), i_RDPNTR0=rdpntr[0], i_RDPNTR1=rdpntr[1], i_RDPNTR2=rdpntr[2], i_WRPNTR0=wrpntr[0], i_WRPNTR1=wrpntr[1], i_WRPNTR2=wrpntr[2], o_Q0=dq_i_data[0], o_Q1=dq_i_data[1], o_Q2=dq_i_data[2], o_Q3=dq_i_data[3], ) dq_bitslip = BitSlip(4) self.comb += dq_bitslip.i.eq(dq_i_data) self.sync += \ If(self._dly_sel.storage[i], If(self._rdly_dq_bitslip_rst.re, dq_bitslip.value.eq(0) ).Elif(self._rdly_dq_bitslip.re, dq_bitslip.value.eq(dq_bitslip.value + 1) ) ) self.submodules += dq_bitslip dq_bitslip_o_d = Signal(4) self.sync += dq_bitslip_o_d.eq(dq_bitslip.o) self.comb += [ self.dfi.phases[0].rddata[0*databits+j].eq(dq_bitslip_o_d[0]), self.dfi.phases[0].rddata[1*databits+j].eq(dq_bitslip_o_d[1]), self.dfi.phases[0].rddata[2*databits+j].eq(dq_bitslip_o_d[2]), self.dfi.phases[0].rddata[3*databits+j].eq(dq_bitslip_o_d[3]), self.dfi.phases[1].rddata[0*databits+j].eq(dq_bitslip.o[0]), self.dfi.phases[1].rddata[1*databits+j].eq(dq_bitslip.o[1]), self.dfi.phases[1].rddata[2*databits+j].eq(dq_bitslip.o[2]), self.dfi.phases[1].rddata[3*databits+j].eq(dq_bitslip.o[3]), ] self.specials += \ Instance("TSHX2DQA", i_T0=~oe_dq, i_T1=~oe_dq, i_SCLK=ClockSignal(), i_ECLK=ClockSignal("sys2x"), i_DQSW270=dqsw270, i_RST=ResetSignal("sys2x"), o_Q=dq_oe_n, ) self.specials += Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i) # Flow control ----------------------------------------------------------------------------- # # total read latency: # ODDRX2DQA latency # cl_sys_latency # IDDRX2DQA latency rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en rddata_ens = Array([Signal() for i in range(self.settings.read_latency-1)]) for i in range(self.settings.read_latency-1): n_rddata_en = Signal() self.sync += n_rddata_en.eq(rddata_en) self.comb += rddata_ens[i].eq(rddata_en) rddata_en = n_rddata_en self.sync += [phase.rddata_valid.eq(rddata_en) for phase in self.dfi.phases] self.comb += dqs_read.eq(rddata_ens[cl_sys_latency+1] | rddata_ens[cl_sys_latency+2]) oe = Signal() last_wrdata_en = Signal(cwl_sys_latency+3) wrphase = self.dfi.phases[self.settings.wrphase] self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:-1])) self.comb += oe.eq( last_wrdata_en[cwl_sys_latency-1] | last_wrdata_en[cwl_sys_latency] | last_wrdata_en[cwl_sys_latency+1] | last_wrdata_en[cwl_sys_latency+2]) self.sync += oe_dqs.eq(oe), oe_dq.eq(oe) self.sync += bl8_sel.eq(last_wrdata_en[cwl_sys_latency-1]) self.sync += dqs_preamble.eq(last_wrdata_en[cwl_sys_latency-2]) self.sync += dqs_postamble.eq(oe_dqs)
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, 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.") # # # 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) # Keep DQ2,DQ3 as outputs during bitbang, this ensures they activate ~WP or ~HOLD functions 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) 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)) 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): addressbits = len(pads.a) bankbits = len(pads.ba) databits = len(pads.dq) self.settings = sdram_settings.PhySettings(memtype="SDR", dfi_databits=databits, nphases=1, rdphase=0, wrphase=0, rdcmdphase=0, wrcmdphase=0, cl=2, read_latency=4, write_latency=0) self.dfi = Interface(addressbits, bankbits, databits) ### # # Command/address # self.sync += [ pads.a.eq(self.dfi.p0.address), pads.ba.eq(self.dfi.p0.bank), pads.cke.eq(self.dfi.p0.cke), pads.cas_n.eq(self.dfi.p0.cas_n), pads.ras_n.eq(self.dfi.p0.ras_n), pads.we_n.eq(self.dfi.p0.we_n) ] if hasattr(pads, "cs_n"): self.sync += pads.cs_n.eq(self.dfi.p0.cs_n) # # DQ/DQS/DM data # sd_dq_out = Signal(databits) drive_dq = Signal() self.sync += sd_dq_out.eq(self.dfi.p0.wrdata) self.specials += Tristate(pads.dq, sd_dq_out, drive_dq) self.sync += \ If(self.dfi.p0.wrdata_en, pads.dm.eq(self.dfi.p0.wrdata_mask) ).Else( pads.dm.eq(0) ) sd_dq_in_ps = Signal(databits) self.sync.sys_ps += sd_dq_in_ps.eq(pads.dq) self.sync += self.dfi.p0.rddata.eq(sd_dq_in_ps) # # DQ/DM control # d_dfi_wrdata_en = Signal() self.sync += d_dfi_wrdata_en.eq(self.dfi.p0.wrdata_en) self.comb += drive_dq.eq(d_dfi_wrdata_en) rddata_sr = Signal(4) self.comb += self.dfi.p0.rddata_valid.eq(rddata_sr[3]) self.sync += rddata_sr.eq(Cat(self.dfi.p0.rddata_en, rddata_sr[:3]))
def __init__(self, pads, clk_freq, fifo_depth=32, read_time=128, write_time=128): dw = len(pads.data) # read fifo (FTDI --> SoC) read_fifo = ClockDomainsRenamer({ "write": "usb", "read": "sys" })(stream.AsyncFIFO(phy_description(dw), fifo_depth)) read_buffer = ClockDomainsRenamer("usb")(stream.SyncFIFO( phy_description(dw), 4)) self.comb += read_buffer.source.connect(read_fifo.sink) # write fifo (SoC --> FTDI) write_fifo = ClockDomainsRenamer({ "write": "sys", "read": "usb" })(stream.AsyncFIFO(phy_description(dw), fifo_depth)) self.submodules += read_fifo, read_buffer, write_fifo # sink / source interfaces self.sink = write_fifo.sink self.source = read_fifo.source # read / write arbitration wants_write = Signal() wants_read = Signal() txe_n = Signal() rxf_n = Signal() self.comb += [ txe_n.eq(pads.txe_n), rxf_n.eq(pads.rxf_n), wants_write.eq(~txe_n & write_fifo.source.valid), wants_read.eq(~rxf_n & read_fifo.sink.ready), ] read_time_en, max_read_time = anti_starvation(self, read_time) write_time_en, max_write_time = anti_starvation(self, write_time) data_w_accepted = Signal(reset=1) fsm = FSM(reset_state="READ") self.submodules += ClockDomainsRenamer("usb")(fsm) fsm.act( "READ", read_time_en.eq(1), If(wants_write, If(~wants_read | max_read_time, NextState("RTW")))) fsm.act("RTW", NextState("WRITE")) fsm.act( "WRITE", write_time_en.eq(1), If(wants_read, If(~wants_write | max_write_time, NextState("WTR"))), write_fifo.source.ready.eq(wants_write & data_w_accepted)) fsm.act("WTR", NextState("READ")) # databus tristate data_w = Signal(dw) data_r = Signal(dw) data_oe = Signal() self.specials += Tristate(pads.data, data_w, data_oe, data_r) # read / write actions pads.oe_n.reset = 1 pads.rd_n.reset = 1 pads.wr_n.reset = 1 self.sync.usb += [ If(fsm.ongoing("READ"), data_oe.eq(0), pads.oe_n.eq(0), pads.rd_n.eq(~wants_read), pads.wr_n.eq(1)).Elif(fsm.ongoing("WRITE"), data_oe.eq(1), pads.oe_n.eq(1), pads.rd_n.eq(1), pads.wr_n.eq(~wants_write), data_w_accepted.eq(~txe_n)).Else( data_oe.eq(1), pads.oe_n.eq(~fsm.ongoing("WTR")), pads.rd_n.eq(1), pads.wr_n.eq(1)), read_buffer.sink.valid.eq(~pads.rd_n & ~rxf_n), read_buffer.sink.data.eq(data_r), If(~txe_n & data_w_accepted, data_w.eq(write_fifo.source.data)) ]
def __init__(self, pads, sys_clk_freq=100e6): pads = PHYPadsCombiner(pads) memtype = "DDR3" tck = 2 / (2 * 2 * sys_clk_freq) addressbits = len(pads.a) bankbits = len(pads.ba) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) nphases = 2 assert databits % 8 == 0 # Init ------------------------------------------------------------------------------------- self.submodules.init = ClockDomainsRenamer("init")( ECP5DDRPHYInit("sys2x")) # Parameters ------------------------------------------------------------------------------- cl, cwl = get_cl_cw(memtype, tck) cl_sys_latency = get_sys_latency(nphases, cl) cwl_sys_latency = get_sys_latency(nphases, cwl) # Registers -------------------------------------------------------------------------------- self._dly_sel = CSRStorage(databits // 8) self._rdly_dq_rst = CSR() self._rdly_dq_inc = CSR() self._rdly_dq_bitslip_rst = CSR() self._rdly_dq_bitslip = CSR() self._burstdet_clr = CSR() self._burstdet_seen = CSRStatus(databits // 8) # Observation self.datavalid = Signal(databits // 8) # PHY settings ----------------------------------------------------------------------------- rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings(phytype="ECP5DDRPHY", memtype=memtype, databits=databits, dfi_databits=4 * databits, nranks=nranks, nphases=nphases, rdphase=rdphase, wrphase=wrphase, rdcmdphase=rdcmdphase, wrcmdphase=wrcmdphase, cl=cl, cwl=cwl, read_latency=2 + cl_sys_latency + 2 + log2_int(4 // nphases) + 4, write_latency=cwl_sys_latency) # DFI Interface ---------------------------------------------------------------------------- self.dfi = dfi = Interface(addressbits, bankbits, nranks, 4 * databits, 4) # # # bl8_chunk = Signal() rddata_en = Signal(self.settings.read_latency) # Iterate on pads groups ------------------------------------------------------------------- for pads_group in range(len(pads.groups)): pads.sel_group(pads_group) # Clock -------------------------------------------------------------------------------- for i in range(len(pads.clk_p)): sd_clk_se = Signal() self.specials += Instance("ODDRX2F", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_D0=0, i_D1=1, i_D2=0, i_D3=1, o_Q=pads.clk_p[i]) # Addresses and Commands --------------------------------------------------------------- for i in range(addressbits): self.specials += Instance("ODDRX2F", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_D0=dfi.phases[0].address[i], i_D1=dfi.phases[0].address[i], i_D2=dfi.phases[1].address[i], i_D3=dfi.phases[1].address[i], o_Q=pads.a[i]) for i in range(bankbits): self.specials += Instance("ODDRX2F", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_D0=dfi.phases[0].bank[i], i_D1=dfi.phases[0].bank[i], i_D2=dfi.phases[1].bank[i], i_D3=dfi.phases[1].bank[i], o_Q=pads.ba[i]) controls = ["ras_n", "cas_n", "we_n", "cke", "odt"] if hasattr(pads, "reset_n"): controls.append("reset_n") if hasattr(pads, "cs_n"): controls.append("cs_n") for name in controls: for i in range(len(getattr(pads, name))): self.specials += Instance( "ODDRX2F", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_D0=getattr(dfi.phases[0], name)[i], i_D1=getattr(dfi.phases[0], name)[i], i_D2=getattr(dfi.phases[1], name)[i], i_D3=getattr(dfi.phases[1], name)[i], o_Q=getattr(pads, name)[i]) # DQ --------------------------------------------------------------------------------------- dq_oe = Signal() dqs_oe = Signal() dqs_pattern = DQSPattern() self.submodules += dqs_pattern for i in range(databits // 8): # DQSBUFM dqs_i = Signal() dqsr90 = Signal() dqsw270 = Signal() dqsw = Signal() rdpntr = Signal(3) wrpntr = Signal(3) rdly = Signal(7) self.sync += \ If(self._dly_sel.storage[i], If(self._rdly_dq_rst.re, rdly.eq(0), ).Elif(self._rdly_dq_inc.re, rdly.eq(rdly + 1), ) ) datavalid = Signal() burstdet = Signal() dqs_read = Signal() dqs_bitslip = Signal(2) self.sync += [ If( self._dly_sel.storage[i], If(self._rdly_dq_bitslip_rst.re, dqs_bitslip.eq(0)).Elif( self._rdly_dq_bitslip.re, dqs_bitslip.eq(dqs_bitslip + 1))) ] dqs_cases = {} for j, b in enumerate(range(-2, 2)): dqs_cases[j] = dqs_read.eq( rddata_en[cl_sys_latency + b:cl_sys_latency + b + 2] != 0) self.sync += Case(dqs_bitslip, dqs_cases) self.specials += Instance( "DQSBUFM", p_DQS_LI_DEL_ADJ="MINUS", p_DQS_LI_DEL_VAL=1, p_DQS_LO_DEL_ADJ="MINUS", p_DQS_LO_DEL_VAL=4, # Clocks / Reset i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), i_RST=ResetSignal("sys2x"), i_DDRDEL=self.init.delay, i_PAUSE=self.init.pause | self._dly_sel.storage[i], # Control # Assert LOADNs to use DDRDEL control i_RDLOADN=0, i_RDMOVE=0, i_RDDIRECTION=1, i_WRLOADN=0, i_WRMOVE=0, i_WRDIRECTION=1, # Reads (generate shifted DQS clock for reads) i_READ0=dqs_read, i_READ1=dqs_read, i_READCLKSEL0=rdly[0], i_READCLKSEL1=rdly[1], i_READCLKSEL2=rdly[2], i_DQSI=dqs_i, o_DQSR90=dqsr90, o_RDPNTR0=rdpntr[0], o_RDPNTR1=rdpntr[1], o_RDPNTR2=rdpntr[2], o_WRPNTR0=wrpntr[0], o_WRPNTR1=wrpntr[1], o_WRPNTR2=wrpntr[2], o_DATAVALID=self.datavalid[i], o_BURSTDET=burstdet, # Writes (generate shifted ECLK clock for writes) o_DQSW270=dqsw270, o_DQSW=dqsw) burstdet_d = Signal() self.sync += [ burstdet_d.eq(burstdet), If(self._burstdet_clr.re, self._burstdet_seen.status[i].eq(0)), If(burstdet & ~burstdet_d, self._burstdet_seen.status[i].eq(1)), ] # DQS and DM --------------------------------------------------------------------------- dm_o_data = Signal(8) dm_o_data_d = Signal(8) dm_o_data_muxed = Signal(4) self.comb += dm_o_data.eq( Cat(dfi.phases[0].wrdata_mask[0 * databits // 8 + i], dfi.phases[0].wrdata_mask[1 * databits // 8 + i], dfi.phases[0].wrdata_mask[2 * databits // 8 + i], dfi.phases[0].wrdata_mask[3 * databits // 8 + i], dfi.phases[1].wrdata_mask[0 * databits // 8 + i], dfi.phases[1].wrdata_mask[1 * databits // 8 + i], dfi.phases[1].wrdata_mask[2 * databits // 8 + i], dfi.phases[1].wrdata_mask[3 * databits // 8 + i]), ) self.sync += dm_o_data_d.eq(dm_o_data) dm_bl8_cases = {} dm_bl8_cases[0] = dm_o_data_muxed.eq(dm_o_data[:4]) dm_bl8_cases[1] = dm_o_data_muxed.eq(dm_o_data_d[4:]) self.sync += Case(bl8_chunk, dm_bl8_cases) # FIXME: use self.comb? self.specials += Instance("ODDRX2DQA", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_DQSW270=dqsw270, i_D0=dm_o_data_muxed[0], i_D1=dm_o_data_muxed[1], i_D2=dm_o_data_muxed[2], i_D3=dm_o_data_muxed[3], o_Q=pads.dm[i]) dqs = Signal() dqs_oe_n = Signal() self.specials += [ Instance( "ODDRX2DQSB", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_DQSW=dqsw, i_D0=0, # FIXME: dqs_pattern.o[3], i_D1=1, # FIXME: dqs_pattern.o[2], i_D2=0, # FIXME: dqs_pattern.o[1], i_D3=1, # FIXME: dqs_pattern.o[0], o_Q=dqs), Instance("TSHX2DQSA", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_DQSW=dqsw, i_T0=~(dqs_pattern.preamble | dqs_oe | dqs_pattern.postamble), i_T1=~(dqs_pattern.preamble | dqs_oe | dqs_pattern.postamble), o_Q=dqs_oe_n), Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i) ] for j in range(8 * i, 8 * (i + 1)): dq_o = Signal() dq_i = Signal() dq_oe_n = Signal() dq_i_delayed = Signal() dq_i_data = Signal(8) dq_o_data = Signal(8) dq_o_data_d = Signal(8) dq_o_data_muxed = Signal(4) self.comb += dq_o_data.eq( Cat(dfi.phases[0].wrdata[0 * databits + j], dfi.phases[0].wrdata[1 * databits + j], dfi.phases[0].wrdata[2 * databits + j], dfi.phases[0].wrdata[3 * databits + j], dfi.phases[1].wrdata[0 * databits + j], dfi.phases[1].wrdata[1 * databits + j], dfi.phases[1].wrdata[2 * databits + j], dfi.phases[1].wrdata[3 * databits + j])) self.sync += dq_o_data_d.eq(dq_o_data) dq_bl8_cases = {} dq_bl8_cases[0] = dq_o_data_muxed.eq(dq_o_data[:4]) dq_bl8_cases[1] = dq_o_data_muxed.eq(dq_o_data_d[4:]) self.sync += Case(bl8_chunk, dq_bl8_cases) # FIXME: use self.comb? _dq_i_data = Signal(4) self.specials += [ Instance("ODDRX2DQA", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_DQSW270=dqsw270, i_D0=dq_o_data_muxed[0], i_D1=dq_o_data_muxed[1], i_D2=dq_o_data_muxed[2], i_D3=dq_o_data_muxed[3], o_Q=dq_o), Instance("DELAYF", p_DEL_MODE="DQS_ALIGNED_X2", i_LOADN=1, i_MOVE=0, i_DIRECTION=0, i_A=dq_i, o_Z=dq_i_delayed), Instance( "IDDRX2DQA", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_DQSR90=dqsr90, i_RDPNTR0=rdpntr[0], i_RDPNTR1=rdpntr[1], i_RDPNTR2=rdpntr[2], i_WRPNTR0=wrpntr[0], i_WRPNTR1=wrpntr[1], i_WRPNTR2=wrpntr[2], i_D=dq_i_delayed, o_Q0=_dq_i_data[0], o_Q1=_dq_i_data[1], o_Q2=_dq_i_data[2], o_Q3=_dq_i_data[3], ) ] self.sync += dq_i_data[:4].eq(dq_i_data[4:]) self.sync += dq_i_data[4:].eq(_dq_i_data) self.comb += [ dfi.phases[0].rddata[0 * databits + j].eq(dq_i_data[0]), dfi.phases[0].rddata[1 * databits + j].eq(dq_i_data[1]), dfi.phases[0].rddata[2 * databits + j].eq(dq_i_data[2]), dfi.phases[0].rddata[3 * databits + j].eq(dq_i_data[3]), dfi.phases[1].rddata[0 * databits + j].eq(dq_i_data[4]), dfi.phases[1].rddata[1 * databits + j].eq(dq_i_data[5]), dfi.phases[1].rddata[2 * databits + j].eq(dq_i_data[6]), dfi.phases[1].rddata[3 * databits + j].eq(dq_i_data[7]), ] self.specials += [ Instance( "TSHX2DQA", i_RST=ResetSignal("sys2x"), i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_DQSW270=dqsw270, i_T0=~(dqs_pattern.preamble | dq_oe | dqs_pattern.postamble), i_T1=~(dqs_pattern.preamble | dq_oe | dqs_pattern.postamble), o_Q=dq_oe_n, ), Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i) ] # Read Control Path ------------------------------------------------------------------------ # Creates a shift register of read commands coming from the DFI interface. This shift register # is used to control DQS read (internal read pulse of the DQSBUF) and to indicate to the # DFI interface that the read data is valid. # # The DQS read must be asserted for 2 sys_clk cycles before the read data is coming back from # the DRAM (see 6.2.4 READ Pulse Positioning Optimization of FPGA-TN-02035-1.2) # # The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI # interface, the latency is the sum of the ODDRX2DQA, CAS, IDDRX2DQA latencies. rddata_en_last = Signal.like(rddata_en) self.comb += rddata_en.eq( Cat(dfi.phases[self.settings.rdphase].rddata_en, rddata_en_last)) self.sync += rddata_en_last.eq(rddata_en) self.sync += [ phase.rddata_valid.eq(rddata_en[-1]) for phase in dfi.phases ] # Write Control Path ----------------------------------------------------------------------- # Creates a shift register of write commands coming from the DFI interface. This shift register # is used to control DQ/DQS tristates and to select write data of the DRAM burst from the DFI # interface: The PHY is operating in halfrate mode (so provide 4 datas every sys_clk cycles: # 2x for DDR, 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency. # Writes are then performed in 2 sys_clk cycles and data needs to be selected for each cycle. # FIXME: understand +2 wrdata_en = Signal(cwl_sys_latency + 5) wrdata_en_last = Signal.like(wrdata_en) self.comb += wrdata_en.eq( Cat(dfi.phases[self.settings.wrphase].wrdata_en, wrdata_en_last)) self.sync += wrdata_en_last.eq(wrdata_en) self.comb += dq_oe.eq(wrdata_en[cwl_sys_latency + 2] | wrdata_en[cwl_sys_latency + 3]) self.comb += bl8_chunk.eq(wrdata_en[cwl_sys_latency + 1]) self.comb += dqs_oe.eq(dq_oe) # Write DQS Postamble/Preamble Control Path ------------------------------------------------ # Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last # write. During writes, DQS tristate is configured as output for at least 4 sys_clk cycles: # 1 for Preamble, 2 for the Write and 1 for the Postamble. self.comb += dqs_pattern.preamble.eq(wrdata_en[cwl_sys_latency + 1] & ~wrdata_en[cwl_sys_latency + 2]) self.comb += dqs_pattern.postamble.eq( wrdata_en[cwl_sys_latency + 4] & ~wrdata_en[cwl_sys_latency + 3])
def __init__(self, pads, default=_default_edid): self._hpd_notif = CSRStatus() self._hpd_en = CSRStorage() self.specials.mem = Memory(8, 128, init=default) ### # HPD if hasattr(pads, "hpd_notif"): self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status) else: self.comb += self._hpd_notif.status.eq(1) if hasattr(pads, "hpd_en"): self.comb += pads.hpd_en.eq(self._hpd_en.storage) # EDID scl_raw = Signal() sda_i = Signal() sda_raw = Signal() sda_drv = Signal() _sda_drv_reg = Signal() _sda_i_async = Signal() self.sync += _sda_drv_reg.eq(sda_drv) self.specials += [ MultiReg(pads.scl, scl_raw), Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async), MultiReg(_sda_i_async, sda_raw) ] # for debug self.scl = scl_raw self.sda_i = sda_i self.sda_o = Signal() self.comb += self.sda_o.eq(~_sda_drv_reg) self.sda_oe = _sda_drv_reg scl_i = Signal() samp_count = Signal(6) samp_carry = Signal() self.sync += [ Cat(samp_count, samp_carry).eq(samp_count + 1), If(samp_carry, scl_i.eq(scl_raw), sda_i.eq(sda_raw) ) ] scl_r = Signal() sda_r = Signal() scl_rising = Signal() sda_rising = Signal() sda_falling = Signal() self.sync += [ scl_r.eq(scl_i), sda_r.eq(sda_i) ] self.comb += [ scl_rising.eq(scl_i & ~scl_r), sda_rising.eq(sda_i & ~sda_r), sda_falling.eq(~sda_i & sda_r) ] start = Signal() self.comb += start.eq(scl_i & sda_falling) din = Signal(8) counter = Signal(max=9) self.sync += [ If(start, counter.eq(0)), If(scl_rising, If(counter == 8, counter.eq(0) ).Else( counter.eq(counter + 1), din.eq(Cat(sda_i, din[:7])) ) ) ] self.din = din self.counter = counter is_read = Signal() update_is_read = Signal() self.sync += If(update_is_read, is_read.eq(din[0])) offset_counter = Signal(max=128) oc_load = Signal() oc_inc = Signal() self.sync += [ If(oc_load, offset_counter.eq(din) ).Elif(oc_inc, offset_counter.eq(offset_counter + 1) ) ] rdport = self.mem.get_port() self.specials += rdport self.comb += rdport.adr.eq(offset_counter) data_bit = Signal() zero_drv = Signal() data_drv = Signal() self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit)) data_drv_en = Signal() data_drv_stop = Signal() self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0)) self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True)) self.submodules.fsm = fsm = FSM() fsm.act("WAIT_START") fsm.act("RCV_ADDRESS", If(counter == 8, If(din[1:] == 0x50, update_is_read.eq(1), NextState("ACK_ADDRESS0") ).Else( NextState("WAIT_START") ) ) ) fsm.act("ACK_ADDRESS0", If(~scl_i, NextState("ACK_ADDRESS1")) ) fsm.act("ACK_ADDRESS1", zero_drv.eq(1), If(scl_i, NextState("ACK_ADDRESS2")) ) fsm.act("ACK_ADDRESS2", zero_drv.eq(1), If(~scl_i, If(is_read, NextState("READ") ).Else( NextState("RCV_OFFSET") ) ) ) fsm.act("RCV_OFFSET", If(counter == 8, oc_load.eq(1), NextState("ACK_OFFSET0") ) ) fsm.act("ACK_OFFSET0", If(~scl_i, NextState("ACK_OFFSET1")) ) fsm.act("ACK_OFFSET1", zero_drv.eq(1), If(scl_i, NextState("ACK_OFFSET2")) ) fsm.act("ACK_OFFSET2", zero_drv.eq(1), If(~scl_i, NextState("RCV_ADDRESS")) ) fsm.act("READ", If(~scl_i, If(counter == 8, data_drv_stop.eq(1), NextState("ACK_READ") ).Else( data_drv_en.eq(1) ) ) ) fsm.act("ACK_READ", If(scl_rising, oc_inc.eq(1), If(sda_i, NextState("WAIT_START") ).Else( NextState("READ") ) ) ) for state in fsm.actions.keys(): fsm.act(state, If(start, NextState("RCV_ADDRESS"))) fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START")))
def __init__(self, pads, clk_freq, fifo_depth=32, read_time=128, write_time=128): dw = len(pads.data) self.clk_freq = clk_freq # timings tRD = self.ns(30) # RD# active pulse width (t4) tRDDataSetup = self.ns(14) # RD# to DATA (t3) tWRDataSetup = self.ns(5) # DATA to WR# active setup time (t8) tWR = self.ns(30) # WR# active pulse width (t10) tMultiReg = 2 # read fifo (FTDI --> SoC) read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) # write fifo (SoC --> FTDI) write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) self.submodules += read_fifo, write_fifo # sink / source interfaces self.sink = write_fifo.sink self.source = read_fifo.source # read / write arbitration wants_write = Signal() wants_read = Signal() txe_n = Signal() rxf_n = Signal() self.specials += [ MultiReg(pads.txe_n, txe_n), MultiReg(pads.rxf_n, rxf_n) ] self.comb += [ wants_write.eq(~txe_n & write_fifo.source.valid), wants_read.eq(~rxf_n & read_fifo.sink.ready), ] read_time_en, max_read_time = anti_starvation(self, read_time) write_time_en, max_write_time = anti_starvation(self, write_time) fsm = FSM(reset_state="READ") self.submodules += fsm read_done = Signal() write_done = Signal() commuting = Signal() fsm.act( "READ", read_time_en.eq(1), If( wants_write & read_done, If(~wants_read | max_read_time, commuting.eq(1), NextState("RTW")))) fsm.act("RTW", NextState("WRITE")) fsm.act( "WRITE", write_time_en.eq(1), If( wants_read & write_done, If(~wants_write | max_write_time, commuting.eq(1), NextState("WTR")))) fsm.act("WTR", NextState("READ")) # databus tristate data_w = Signal(dw) data_r_async = Signal(dw) data_r = Signal(dw) data_oe = Signal() self.specials += [ Tristate(pads.data, data_w, data_oe, data_r_async), MultiReg(data_r_async, data_r) ] # read actions pads.rd_n.reset = 1 read_fsm = FSM(reset_state="IDLE") self.submodules += read_fsm read_counter = Signal(8) read_counter_reset = Signal() read_counter_ce = Signal() self.sync += \ If(read_counter_reset, read_counter.eq(0) ).Elif(read_counter_ce, read_counter.eq(read_counter + 1) ) read_fsm.act( "IDLE", read_done.eq(1), read_counter_reset.eq(1), If( fsm.ongoing("READ") & wants_read, If(~commuting, NextState("PULSE_RD_N")))) read_fsm.act( "PULSE_RD_N", pads.rd_n.eq(0), read_counter_ce.eq(1), If(read_counter == max((tRD - 1), (tRDDataSetup + tMultiReg - 1)), NextState("ACQUIRE_DATA"))) read_fsm.act("ACQUIRE_DATA", read_fifo.sink.valid.eq(1), read_fifo.sink.data.eq(data_r), NextState("WAIT_RXF_N")) read_fsm.act("WAIT_RXF_N", If(rxf_n, NextState("IDLE"))) # write actions pads.wr_n.reset = 1 write_fsm = FSM(reset_state="IDLE") self.submodules += write_fsm write_counter = Signal(8) write_counter_reset = Signal() write_counter_ce = Signal() self.sync += \ If(write_counter_reset, write_counter.eq(0) ).Elif(write_counter_ce, write_counter.eq(write_counter + 1) ) write_fsm.act( "IDLE", write_done.eq(1), write_counter_reset.eq(1), If( fsm.ongoing("WRITE") & wants_write, If(~commuting, NextState("SET_DATA")))) write_fsm.act( "SET_DATA", data_oe.eq(1), data_w.eq(write_fifo.source.data), write_counter_ce.eq(1), If(write_counter == (tWRDataSetup - 1), write_counter_reset.eq(1), NextState("PULSE_WR_N"))) write_fsm.act("PULSE_WR_N", data_oe.eq(1), data_w.eq(write_fifo.source.data), pads.wr_n.eq(0), write_counter_ce.eq(1), If(write_counter == (tWR - 1), NextState("WAIT_TXE_N"))) write_fsm.act( "WAIT_TXE_N", If(txe_n, write_fifo.source.ready.eq(1), NextState("IDLE")))
def __init__(self, platform, usb_connector=0, with_usb3=True, with_usb3_analyzer=False): BaseSoC.__init__(self, platform) # fmc vadj (2.5V) self.comb += platform.request("vadj").eq(0b10) # usb ios usb_reset_n = platform.request("usb_reset_n", usb_connector) if with_usb3: usb_pipe_ctrl = platform.request("usb_pipe_ctrl", usb_connector) usb_pipe_status = platform.request("usb_pipe_status", usb_connector) usb_pipe_data = platform.request("usb_pipe_data", usb_connector) usb3_reset_n = Signal(reset=1) self.comb += usb_reset_n.eq(usb3_reset_n) # usb3 core if with_usb3: class USB3Control(Module, AutoCSR): def __init__(self): self._phy_enable = CSRStorage() self._core_enable = CSRStorage() # probably not working but prevent synthesis optimizations self._buf_in_addr = CSRStorage(9) self._buf_in_data = CSRStorage(32) self._buf_in_wren = CSR() self._buf_in_request = CSRStatus() self._buf_in_ready = CSRStatus() self._buf_in_commit = CSR() self._buf_in_commit_len = CSRStorage(11) self._buf_in_commit_ack = CSRStatus() self._buf_out_addr = CSRStorage(9) self._buf_out_q = CSRStatus(32) self._buf_out_len = CSRStatus(11) self._buf_out_hasdata = CSRStatus() self._buf_out_arm = CSR() self._buf_out_arm_ack = CSRStatus() # # # self.phy_enable = self._phy_enable.storage self.core_enable = self._core_enable.storage self.buf_in_addr = self._buf_in_addr.storage self.buf_in_data = self._buf_in_data.storage self.buf_in_wren = self._buf_in_wren.re & self._buf_in_wren.r self.buf_in_request = self._buf_in_request.status self.buf_in_ready = self._buf_in_ready.status self.buf_in_commit = self._buf_in_commit.re & self._buf_in_commit.r self.buf_in_commit_len = self._buf_in_commit_len.storage self.buf_in_commit_ack = self._buf_in_commit_ack.status self.buf_out_addr = self._buf_out_addr.storage self.buf_out_q = self._buf_out_q.status self.buf_out_len = self._buf_out_len.status self.buf_out_hasdata = self._buf_out_hasdata.status self.buf_out_arm = self._buf_out_arm.re & self._buf_out_arm.r self.buf_out_arm_ack = self._buf_out_arm_ack.status self.submodules.usb3_control = USB3Control() phy_pipe_pll_locked = Signal() phy_pipe_pll_fb = Signal() phy_pipe_half_clk_pll = Signal() phy_pipe_half_clk_phase_pll = Signal() phy_pipe_quarter_clk_pll = Signal() phy_pipe_tx_clk_phase_pll = Signal() phy_pipe_half_clk = Signal() phy_pipe_half_clk_phase = Signal() phy_pipe_quarter_clk = Signal() phy_pipe_tx_clk_phase = Signal() self.specials += [ Instance( "PLLE2_BASE", p_STARTUP_WAIT="FALSE", o_LOCKED=phy_pipe_pll_locked, # VCO @ 1GHz p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=4.0, p_CLKFBOUT_MULT=4, p_DIVCLK_DIVIDE=1, i_CLKIN1=usb_pipe_data.rx_clk, i_CLKFBIN=phy_pipe_pll_fb, o_CLKFBOUT=phy_pipe_pll_fb, # 125MHz: 1/2 PCLK p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=phy_pipe_half_clk_pll, # 125MHz: 1/2 PCLK, phase shift 90 p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=90.0, o_CLKOUT1=phy_pipe_half_clk_phase_pll, # 62.5MHz: 1/4 PCLK p_CLKOUT2_DIVIDE=16, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=phy_pipe_quarter_clk_pll, # 250Mhz: TX CLK, phase shift 90 p_CLKOUT3_DIVIDE=4, p_CLKOUT3_PHASE=90.0, o_CLKOUT3=phy_pipe_tx_clk_phase_pll), Instance("BUFG", i_I=phy_pipe_half_clk_pll, o_O=phy_pipe_half_clk), Instance("BUFG", i_I=phy_pipe_half_clk_phase_pll, o_O=phy_pipe_half_clk_phase), Instance("BUFG", i_I=phy_pipe_quarter_clk_pll, o_O=phy_pipe_quarter_clk), Instance("BUFG", i_I=phy_pipe_tx_clk_phase_pll, o_O=phy_pipe_tx_clk_phase), ] self.clock_domains.cd_phy_pipe_half = ClockDomain() self.clock_domains.cd_phy_pipe_half_phase = ClockDomain() self.clock_domains.cd_phy_pipe_quarter = ClockDomain() self.clock_domains.cd_phy_pipe_tx_phase = ClockDomain() self.comb += [ self.cd_phy_pipe_half.clk.eq(phy_pipe_half_clk), self.cd_phy_pipe_half_phase.clk.eq(phy_pipe_half_clk_phase), self.cd_phy_pipe_quarter.clk.eq(phy_pipe_quarter_clk), self.cd_phy_pipe_tx_phase.clk.eq(phy_pipe_tx_clk_phase) ] self.specials += [ AsyncResetSynchronizer(self.cd_phy_pipe_half, ~phy_pipe_pll_locked), AsyncResetSynchronizer(self.cd_phy_pipe_half_phase, ~phy_pipe_pll_locked), AsyncResetSynchronizer(self.cd_phy_pipe_quarter, ~phy_pipe_pll_locked), AsyncResetSynchronizer(self.cd_phy_pipe_tx_phase, ~phy_pipe_pll_locked) ] self.cd_phy_pipe_half.clk.attr.add("keep") self.cd_phy_pipe_half_phase.clk.attr.add("keep") self.cd_phy_pipe_quarter.clk.attr.add("keep") self.cd_phy_pipe_tx_phase.clk.attr.add("keep") self.platform.add_period_constraint(self.cd_phy_pipe_half.clk, 8.0) self.platform.add_period_constraint( self.cd_phy_pipe_half_phase.clk, 8.0) self.platform.add_period_constraint(self.cd_phy_pipe_quarter.clk, 16.0) self.platform.add_period_constraint(self.cd_phy_pipe_tx_phase.clk, 4.0) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, self.cd_phy_pipe_half.clk, self.cd_phy_pipe_half_phase.clk, self.cd_phy_pipe_quarter.clk, self.cd_phy_pipe_tx_phase.clk) phy_pipe_rx_data = Signal(32) phy_pipe_rx_datak = Signal(4) phy_pipe_rx_valid = Signal(2) phy_pipe_tx_data = Signal(32) phy_pipe_tx_datak = Signal(4) phy_rx_status = Signal(6) phy_phy_status = Signal(2) dbg_pipe_state = Signal(6) dbg_ltssm_state = Signal(5) usb_pipe_status_phy_status = Signal() self.specials += Tristate(usb_pipe_status.phy_status, 0, ~usb3_reset_n, usb_pipe_status_phy_status) self.comb += usb3_reset_n.eq(self.usb3_control.phy_enable | platform.request("user_sw", 0)) self.specials += Instance( "usb3_top", i_ext_clk=ClockSignal(), i_reset_n=self.usb3_control.core_enable | platform.request("user_sw", 1), i_phy_pipe_half_clk=ClockSignal("phy_pipe_half"), i_phy_pipe_half_clk_phase=ClockSignal("phy_pipe_half_phase"), i_phy_pipe_quarter_clk=ClockSignal("phy_pipe_quarter"), i_phy_pipe_rx_data=phy_pipe_rx_data, i_phy_pipe_rx_datak=phy_pipe_rx_datak, i_phy_pipe_rx_valid=phy_pipe_rx_valid, o_phy_pipe_tx_data=phy_pipe_tx_data, o_phy_pipe_tx_datak=phy_pipe_tx_datak, #o_phy_reset_n=, #o_phy_out_enable=, o_phy_phy_reset_n=usb_pipe_ctrl.phy_reset_n, o_phy_tx_detrx_lpbk=usb_pipe_ctrl.tx_detrx_lpbk, o_phy_tx_elecidle=usb_pipe_ctrl.tx_elecidle, io_phy_rx_elecidle=usb_pipe_status.rx_elecidle, i_phy_rx_status=phy_rx_status, o_phy_power_down=usb_pipe_ctrl.power_down, i_phy_phy_status_i=phy_phy_status, #o_phy_phy_status_o=, i_phy_pwrpresent=usb_pipe_status.pwr_present, o_phy_tx_oneszeros=usb_pipe_ctrl.tx_oneszeros, o_phy_tx_deemph=usb_pipe_ctrl.tx_deemph, o_phy_tx_margin=usb_pipe_ctrl.tx_margin, o_phy_tx_swing=usb_pipe_ctrl.tx_swing, o_phy_rx_polarity=usb_pipe_ctrl.rx_polarity, o_phy_rx_termination=usb_pipe_ctrl.rx_termination, o_phy_rate=usb_pipe_ctrl.rate, o_phy_elas_buf_mode=usb_pipe_ctrl.elas_buf_mode, i_buf_in_addr=self.usb3_control.buf_in_addr, i_buf_in_data=self.usb3_control.buf_in_data, i_buf_in_wren=self.usb3_control.buf_in_wren, o_buf_in_request=self.usb3_control.buf_in_request, o_buf_in_ready=self.usb3_control.buf_in_ready, i_buf_in_commit=self.usb3_control.buf_in_commit, i_buf_in_commit_len=self.usb3_control.buf_in_commit_len, o_buf_in_commit_ack=self.usb3_control.buf_in_commit_ack, i_buf_out_addr=self.usb3_control.buf_out_addr, o_buf_out_q=self.usb3_control.buf_out_q, o_buf_out_len=self.usb3_control.buf_out_len, o_buf_out_hasdata=self.usb3_control.buf_out_hasdata, i_buf_out_arm=self.usb3_control.buf_out_arm, o_buf_out_arm_ack=self.usb3_control.buf_out_arm_ack, #o_vend_req_act=, #o_vend_req_request=, #o_vend_req_val=, o_dbg_pipe_state=dbg_pipe_state, o_dbg_ltssm_state=dbg_ltssm_state) platform.add_verilog_include_path(os.path.join("core")) platform.add_verilog_include_path(os.path.join("core", "usb3")) platform.add_source_dir(os.path.join("core", "usb3")) # ddr inputs self.specials += Instance( "IDDR", p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED", i_C=ClockSignal("phy_pipe_half"), i_CE=1, i_S=0, i_R=0, i_D=usb_pipe_data.rx_valid, o_Q1=phy_pipe_rx_valid[0], o_Q2=phy_pipe_rx_valid[1], ) for i in range(16): self.specials += Instance( "IDDR", p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED", i_C=ClockSignal("phy_pipe_half"), i_CE=1, i_S=0, i_R=0, i_D=usb_pipe_data.rx_data[i], o_Q1=phy_pipe_rx_data[i], o_Q2=phy_pipe_rx_data[16 + i], ) for i in range(2): self.specials += Instance( "IDDR", p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED", i_C=ClockSignal("phy_pipe_half"), i_CE=1, i_S=0, i_R=0, i_D=usb_pipe_data.rx_datak[i], o_Q1=phy_pipe_rx_datak[i], o_Q2=phy_pipe_rx_datak[2 + i], ) for i in range(3): self.specials += Instance( "IDDR", p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED", i_C=ClockSignal("phy_pipe_half"), i_CE=1, i_S=0, i_R=0, i_D=usb_pipe_status.rx_status[i], o_Q1=phy_rx_status[i], o_Q2=phy_rx_status[3 + i], ) self.specials += Instance( "IDDR", p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED", i_C=ClockSignal("phy_pipe_half"), i_CE=1, i_S=0, i_R=0, i_D=usb_pipe_status_phy_status, o_Q1=phy_phy_status[0], o_Q2=phy_phy_status[1], ) # ddr outputs self.specials += Instance( "ODDR", p_DDR_CLK_EDGE="SAME_EDGE", i_C=ClockSignal("phy_pipe_tx_phase"), i_CE=1, i_S=0, i_R=0, i_D1=1, i_D2=0, o_Q=usb_pipe_data.tx_clk, ) for i in range(16): self.specials += Instance( "ODDR", p_DDR_CLK_EDGE="SAME_EDGE", i_C=ClockSignal("phy_pipe_half_phase"), i_CE=1, i_S=0, i_R=0, i_D1=phy_pipe_tx_data[i], i_D2=phy_pipe_tx_data[16 + i], o_Q=usb_pipe_data.tx_data[i], ) for i in range(2): self.specials += Instance( "ODDR", p_DDR_CLK_EDGE="SAME_EDGE", i_C=ClockSignal("phy_pipe_half_phase"), i_CE=1, i_S=0, i_R=0, i_D1=phy_pipe_tx_datak[i], i_D2=phy_pipe_tx_datak[2 + i], o_Q=usb_pipe_data.tx_datak[i], ) # usb3 debug if with_usb3_analyzer: analyzer_signals = [ dbg_pipe_state, dbg_ltssm_state, usb_pipe_ctrl.tx_detrx_lpbk, usb_pipe_ctrl.tx_elecidle, usb_pipe_status.rx_elecidle, usb_pipe_ctrl.power_down, usb_pipe_status.phy_status, usb_pipe_status.pwr_present, usb_pipe_ctrl.tx_oneszeros, usb_pipe_ctrl.tx_deemph, usb_pipe_ctrl.tx_margin, usb_pipe_ctrl.tx_swing, usb_pipe_ctrl.rx_polarity, usb_pipe_ctrl.rx_termination, usb_pipe_ctrl.rate, usb_pipe_ctrl.elas_buf_mode, phy_pipe_rx_valid, phy_pipe_rx_data, phy_pipe_rx_datak, phy_pipe_tx_data, phy_pipe_tx_datak ] self.submodules.analyzer = LiteScopeAnalyzer( analyzer_signals, 2048, cd="phy_pipe_half")
def __init__(self, pads, wires=4, with_tristate=True): self.wishbone = wishbone.Interface() # # # self.__doc__ = self.__doc__.format(wires) if wires == 4: self.mod_doc = Spi4WireDocumentation() elif wires == 3: self.mod_doc = Spi3WireDocumentation() elif wires == 2: self.mod_doc = Spi2WireDocumentation() clk = Signal() cs_n = Signal() mosi = Signal() miso = Signal() miso_en = Signal() counter = Signal(8) write_offset = Signal(5) command = Signal(8) address = Signal(32) value = Signal(32) wr = Signal() sync_byte = Signal(8) self.specials += [ MultiReg(pads.clk, clk), ] if wires == 2: io = TSTriple() self.specials += io.get_tristate(pads.mosi) self.specials += MultiReg(io.i, mosi) self.comb += io.o.eq(miso) self.comb += io.oe.eq(miso_en) elif wires == 3: self.specials += MultiReg(pads.cs_n, cs_n), io = TSTriple() self.specials += io.get_tristate(pads.mosi) self.specials += MultiReg(io.i, mosi) self.comb += io.o.eq(miso) self.comb += io.oe.eq(miso_en) elif wires == 4: self.specials += MultiReg(pads.cs_n, cs_n), self.specials += MultiReg(pads.mosi, mosi) if with_tristate: self.specials += Tristate(pads.miso, miso, ~cs_n) else: self.comb += pads.miso.eq(miso) else: raise ValueError("`wires` must be 2, 3, or 4") clk_last = Signal() clk_rising = Signal() clk_falling = Signal() self.sync += clk_last.eq(clk) self.comb += clk_rising.eq(clk & ~clk_last) self.comb += clk_falling.eq(~clk & clk_last) fsm = FSM(reset_state="IDLE") fsm = ResetInserter()(fsm) self.submodules += fsm self.comb += fsm.reset.eq(cs_n) # Connect the Wishbone bus up to our values self.comb += [ self.wishbone.adr.eq(address[2:]), self.wishbone.dat_w.eq(value), self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1) ] # Constantly have the counter increase, except when it's reset # in the IDLE state self.sync += If(cs_n, counter.eq(0)).Elif(clk_rising, counter.eq(counter + 1)) if wires == 2: fsm.act( "IDLE", miso_en.eq(0), NextValue(miso, 1), If(clk_rising, NextValue(sync_byte, Cat(mosi, sync_byte))), If( sync_byte[0:7] == 0b101011, NextState("GET_TYPE_BYTE"), NextValue(counter, 0), NextValue(command, mosi), )) elif wires == 3 or wires == 4: fsm.act( "IDLE", miso_en.eq(0), NextValue(miso, 1), If( clk_rising, NextState("GET_TYPE_BYTE"), NextValue(command, mosi), ), ) else: raise ValueError("invalid `wires` count: {}".format(wires)) # Determine if it's a read or a write fsm.act( "GET_TYPE_BYTE", miso_en.eq(0), NextValue(miso, 1), If( counter == 8, # Write value If( command == 0, NextValue(wr, 1), NextState("READ_ADDRESS"), # Read value ).Elif( command == 1, NextValue(wr, 0), NextState("READ_ADDRESS"), ).Else(NextState("END"), ), ), If( clk_rising, NextValue(command, Cat(mosi, command)), ), ) fsm.act( "READ_ADDRESS", miso_en.eq(0), If( counter == 32 + 8, If( wr, NextState("READ_VALUE"), ).Else(NextState("READ_WISHBONE"), )), If( clk_rising, NextValue(address, Cat(mosi, address)), ), ) fsm.act( "READ_VALUE", miso_en.eq(0), If( counter == 32 + 32 + 8, NextState("WRITE_WISHBONE"), ), If( clk_rising, NextValue(value, Cat(mosi, value)), ), ) fsm.act( "WRITE_WISHBONE", self.wishbone.stb.eq(1), self.wishbone.we.eq(1), self.wishbone.cyc.eq(1), miso_en.eq(1), If( self.wishbone.ack | self.wishbone.err, NextState("WAIT_BYTE_BOUNDARY"), ), ) fsm.act( "READ_WISHBONE", self.wishbone.stb.eq(1), self.wishbone.we.eq(0), self.wishbone.cyc.eq(1), miso_en.eq(1), If( self.wishbone.ack | self.wishbone.err, NextState("WAIT_BYTE_BOUNDARY"), NextValue(value, self.wishbone.dat_r), ), ) fsm.act( "WAIT_BYTE_BOUNDARY", miso_en.eq(1), If( clk_falling, If( counter[0:3] == 0, NextValue(miso, 0), # For writes, fill in the 0 byte response If( wr, NextState("WRITE_WR_RESPONSE"), ).Else(NextState("WRITE_RESPONSE"), ), ), ), ) # Write the "01" byte that indicates a response fsm.act( "WRITE_RESPONSE", miso_en.eq(1), If( clk_falling, If( counter[0:3] == 0b111, NextValue(miso, 1), ).Elif(counter[0:3] == 0, NextValue(write_offset, 31), NextState("WRITE_VALUE")), ), ) # Write the actual value fsm.act( "WRITE_VALUE", miso_en.eq(1), NextValue(miso, value >> write_offset), If( clk_falling, NextValue(write_offset, write_offset - 1), If( write_offset == 0, NextValue(miso, 0), NextState("END"), ), ), ) fsm.act( "WRITE_WR_RESPONSE", miso_en.eq(1), If( clk_falling, If( counter[0:3] == 0, NextState("END"), ), ), ) if wires == 3 or wires == 4: fsm.act( "END", miso_en.eq(1), ) elif wires == 2: fsm.act("END", miso_en.eq(0), NextValue(sync_byte, 0), NextState("IDLE")) else: raise ValueError("invalid `wires` count: {}".format(wires))
def __init__(self, pads, sys_clk_freq=100e6): memtype = "DDR3" tck = 2 / (2 * 2 * sys_clk_freq) addressbits = len(pads.a) bankbits = len(pads.ba) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) nphases = 2 self._wlevel_en = CSRStorage() self._wlevel_strobe = CSR() self._dly_sel = CSRStorage(databits // 8) self._rdly_dq_rst = CSR() self._rdly_dq_inc = CSR() self._rdly_dq_bitslip_rst = CSR() self._rdly_dq_bitslip = CSR() self._wdly_dq_rst = CSR() self._wdly_dq_inc = CSR() self._wdly_dqs_rst = CSR() self._wdly_dqs_inc = CSR() # compute phy settings cl, cwl = get_cl_cw(memtype, tck) cl_sys_latency = get_sys_latency(nphases, cl) cwl_sys_latency = get_sys_latency(nphases, cwl) rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings( memtype=memtype, dfi_databits=4 * databits, nranks=nranks, nphases=nphases, rdphase=rdphase, wrphase=wrphase, rdcmdphase=rdcmdphase, wrcmdphase=wrcmdphase, cl=cl, cwl=cwl, read_latency=2 + cl_sys_latency + 2 + log2_int(4 // nphases) + 3, # FIXME write_latency=cwl_sys_latency) self.dfi = Interface(addressbits, bankbits, nranks, 4 * databits, 4) # # # bl8_sel = Signal() # Clock for i in range(len(pads.clk_p)): sd_clk_se = Signal() self.specials += [ Instance("ODDRX2F", i_D0=0, i_D1=1, i_D2=0, i_D3=1, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal(), o_Q=pads.clk_p[i]), ] # Addresses and commands for i in range(addressbits): self.specials += \ Instance("ODDRX2F", i_D0=self.dfi.phases[0].address[i], i_D1=self.dfi.phases[0].address[i], i_D2=self.dfi.phases[1].address[i], i_D3=self.dfi.phases[1].address[i], i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal(), o_Q=pads.a[i] ) for i in range(bankbits): self.specials += \ Instance("ODDRX2F", i_D0=self.dfi.phases[0].bank[i], i_D1=self.dfi.phases[0].bank[i], i_D2=self.dfi.phases[1].bank[i], i_D3=self.dfi.phases[1].bank[i], i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal(), o_Q=pads.ba[i] ) controls = ["ras_n", "cas_n", "we_n", "cke", "odt"] if hasattr(pads, "reset_n"): controls.append("reset_n") if hasattr(pads, "cs_n"): controls.append("cs_n") for name in controls: for i in range(len(getattr(pads, name))): self.specials += \ Instance("ODDRX2F", i_D0=getattr(self.dfi.phases[0], name)[i], i_D1=getattr(self.dfi.phases[0], name)[i], i_D2=getattr(self.dfi.phases[1], name)[i], i_D3=getattr(self.dfi.phases[1], name)[i], i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), i_RST=ResetSignal(), o_Q=getattr(pads, name)[i] ) # DQSBUFM dqsr90 = Signal() dqsw270 = Signal() dqsw = Signal() rdpntr = Signal(3) wrpntr = Signal(3) self.specials += Instance( "DQSBUFM", i_DDRDEL=0b0, i_PAUSE=0b0, i_DQSI=pads.dqs_p[0], i_READ0=0b0, i_READ1=0b0, i_READCLKSEL0=0b0, i_READCLKSEL1=0b0, i_READCLKSEL2=0b0, i_DYNDELAY0=0b0, i_DYNDELAY1=0b0, i_DYNDELAY2=0b0, i_DYNDELAY3=0b0, i_DYNDELAY4=0b0, i_DYNDELAY5=0b0, i_DYNDELAY6=0b0, i_DYNDELAY7=0b0, i_RDLOADN=0, i_RDMOVE=0, i_RDDIRECTION=0, i_WRLOADN=0, i_WRMOVE=0, i_WRDIRECTION=0, #o_RDCFLAG=, #o_WRCFLAG=, #o_DATAVALID=, #o_BURSTDET=, o_DQSR90=dqsr90, o_RDPNTR0=rdpntr[0], o_RDPNTR1=rdpntr[1], o_RDPNTR2=rdpntr[2], o_WRPNTR0=wrpntr[0], o_WRPNTR1=wrpntr[1], o_WRPNTR2=wrpntr[2], i_SCLK=ClockSignal("sys"), i_ECLK=ClockSignal("sys2x"), o_DQSW270=dqsw270, o_DQSW=dqsw) # DQS and DM oe_dqs = Signal() dqs_preamble = Signal() dqs_postamble = Signal() dqs_serdes_pattern = Signal(8, reset=0b01010101) self.comb += \ If(self._wlevel_en.storage, If(self._wlevel_strobe.re, dqs_serdes_pattern.eq(0b00000001) ).Else( dqs_serdes_pattern.eq(0b00000000) ) ).Elif(dqs_preamble | dqs_postamble, dqs_serdes_pattern.eq(0b0000000) ).Else( dqs_serdes_pattern.eq(0b01010101) ) for i in range(databits // 8): dm_o_nodelay = Signal() dm_data = Signal(8) dm_data_d = Signal(8) dm_data_muxed = Signal(4) self.comb += dm_data.eq( Cat(self.dfi.phases[0].wrdata_mask[0 * databits // 8 + i], self.dfi.phases[0].wrdata_mask[1 * databits // 8 + i], self.dfi.phases[0].wrdata_mask[2 * databits // 8 + i], self.dfi.phases[0].wrdata_mask[3 * databits // 8 + i], self.dfi.phases[1].wrdata_mask[0 * databits // 8 + i], self.dfi.phases[1].wrdata_mask[1 * databits // 8 + i], self.dfi.phases[1].wrdata_mask[2 * databits // 8 + i], self.dfi.phases[1].wrdata_mask[3 * databits // 8 + i]), ) self.sync += dm_data_d.eq(dm_data) self.comb += \ If(bl8_sel, dm_data_muxed.eq(dm_data_d[4:]) ).Else( dm_data_muxed.eq(dm_data[:4]) ) self.specials += \ Instance("ODDRX2DQA", i_D0=dm_data_muxed[0], i_D1=dm_data_muxed[1], i_D2=dm_data_muxed[2], i_D3=dm_data_muxed[3], i_RST=ResetSignal(), i_DQSW270=dqsw270, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), o_Q=dm_o_nodelay ) self.specials += \ Instance("DELAYF", i_A=dm_o_nodelay, i_LOADN=self._dly_sel.storage[i] & self._wdly_dq_rst.re, i_MOVE=self._dly_sel.storage[i] & self._wdly_dq_inc.re, i_DIRECTION=0, o_Z=pads.dm[i], #o_CFLAG=, ) dqs_nodelay = Signal() dqs_delayed = Signal() dqs_oe = Signal() self.specials += \ Instance("ODDRX2DQSB", i_D0=dqs_serdes_pattern[0], i_D1=dqs_serdes_pattern[1], i_D2=dqs_serdes_pattern[2], i_D3=dqs_serdes_pattern[3], i_RST=ResetSignal(), i_DQSW=dqsw, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), o_Q=dqs_nodelay ) self.specials += \ Instance("DELAYF", i_A=dqs_nodelay, i_LOADN=self._dly_sel.storage[i] & self._wdly_dqs_rst.re, i_MOVE=self._dly_sel.storage[i] & self._wdly_dqs_inc.re, i_DIRECTION=0, o_Z=dqs_delayed, #o_CFLAG=, ) self.specials += \ Instance("TSHX2DQSA", i_T0=oe_dqs, i_T1=oe_dqs, i_SCLK=ClockSignal(), i_ECLK=ClockSignal("sys2x"), i_DQSW=dqsw, i_RST=ResetSignal(), o_Q=dqs_oe, ) self.specials += Tristate(pads.dqs_p[i], dqs_delayed, dqs_oe) # DQ oe_dq = Signal() for i in range(databits): dq_o_nodelay = Signal() dq_o_delayed = Signal() dq_i_nodelay = Signal() dq_i_delayed = Signal() dq_oe = Signal() dq_data = Signal(8) dq_data_d = Signal(8) dq_data_muxed = Signal(4) self.comb += dq_data.eq( Cat(self.dfi.phases[0].wrdata[0 * databits + i], self.dfi.phases[0].wrdata[1 * databits + i], self.dfi.phases[0].wrdata[2 * databits + i], self.dfi.phases[0].wrdata[3 * databits + i], self.dfi.phases[1].wrdata[0 * databits + i], self.dfi.phases[1].wrdata[1 * databits + i], self.dfi.phases[1].wrdata[2 * databits + i], self.dfi.phases[1].wrdata[3 * databits + i])) self.sync += dq_data_d.eq(dq_data) self.comb += \ If(bl8_sel, dq_data_muxed.eq(dq_data_d[4:]) ).Else( dq_data_muxed.eq(dq_data[:4]) ) self.specials += \ Instance("ODDRX2DQA", i_D0=dq_data_muxed[0], i_D1=dq_data_muxed[1], i_D2=dq_data_muxed[2], i_D3=dq_data_muxed[3], i_RST=ResetSignal(), i_DQSW270=dqsw270, i_ECLK=ClockSignal("sys2x"), i_SCLK=ClockSignal(), o_Q=dq_o_nodelay ) self.specials += \ Instance("DELAYF", i_A=dq_o_nodelay, i_LOADN=self._dly_sel.storage[i//8] & self._wdly_dq_rst.re, i_MOVE=self._dly_sel.storage[i//8] & self._wdly_dq_inc.re, i_DIRECTION=0, o_Z=dq_o_delayed, #o_CFLAG=, ) dq_i_data = Signal(8) dq_i_data_d = Signal(8) self.specials += \ Instance("IDDRX2DQA", i_D=dq_i_delayed, i_RST=ResetSignal(), i_DQSR90=dqsr90, i_SCLK=ClockSignal(), i_ECLK=ClockSignal("sys2x"), i_RDPNTR0=rdpntr[0], i_RDPNTR1=rdpntr[1], i_RDPNTR2=rdpntr[2], i_WRPNTR0=wrpntr[0], i_WRPNTR1=wrpntr[1], i_WRPNTR2=wrpntr[2], o_Q0=dq_i_data[0], o_Q1=dq_i_data[1], o_Q2=dq_i_data[2], o_Q3=dq_i_data[3], ) dq_bitslip = BitSlip(4) self.comb += dq_bitslip.i.eq(dq_i_data) self.sync += \ If(self._dly_sel.storage[i//8], If(self._rdly_dq_bitslip_rst.re, dq_bitslip.value.eq(0) ).Elif(self._rdly_dq_bitslip.re, dq_bitslip.value.eq(dq_bitslip.value + 1) ) ) self.submodules += dq_bitslip self.sync += dq_i_data_d.eq(dq_i_data) self.comb += [ self.dfi.phases[0].rddata[i].eq(dq_bitslip.o[0]), self.dfi.phases[0].rddata[databits + i].eq(dq_bitslip.o[1]), self.dfi.phases[1].rddata[i].eq(dq_bitslip.o[2]), self.dfi.phases[1].rddata[databits + i].eq(dq_bitslip.o[3]) ] #self.specials += \ # Instance("DELAYF", # i_A=dq_i_nodelay, # i_LOADN=self._dly_sel.storage[i//8] & self._rdly_dq_rst.re, # i_MOVE=self._dly_sel.storage[i//8] & self._wdly_dq_inc.re, # i_DIRECTION=0, # o_Z=dq_i_delayed, # #o_CFLAG=, # ) self.specials += \ Instance("TSHX2DQA", i_T0=oe_dq, i_T1=oe_dq, i_SCLK=ClockSignal(), i_ECLK=ClockSignal("sys2x"), i_DQSW270=dqsw270, i_RST=ResetSignal(), o_Q=dq_oe, ) self.specials += Tristate(pads.dq[i], dq_o_delayed, dq_oe, dq_i_delayed) # Flow control # # total read latency: # N cycles through ODDRX2DQA FIXME # cl_sys_latency cycles CAS # M cycles through IDDRX2DQA FIXME rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en for i in range(self.settings.read_latency - 1): n_rddata_en = Signal() self.sync += n_rddata_en.eq(rddata_en) rddata_en = n_rddata_en self.sync += [ phase.rddata_valid.eq(rddata_en | self._wlevel_en.storage) for phase in self.dfi.phases ] oe = Signal() last_wrdata_en = Signal(cwl_sys_latency + 3) wrphase = self.dfi.phases[self.settings.wrphase] self.sync += last_wrdata_en.eq( Cat(wrphase.wrdata_en, last_wrdata_en[:-1])) self.comb += oe.eq(last_wrdata_en[cwl_sys_latency - 1] | last_wrdata_en[cwl_sys_latency] | last_wrdata_en[cwl_sys_latency + 1] | last_wrdata_en[cwl_sys_latency + 2]) self.sync += \ If(self._wlevel_en.storage, oe_dqs.eq(1), oe_dq.eq(0) ).Else( oe_dqs.eq(oe), oe_dq.eq(oe) ) self.sync += bl8_sel.eq(last_wrdata_en[cwl_sys_latency - 1])
def __init__(self, pads=None): if pads is None: pads = Record(self.jtag_layout) self.pads = pads self.dmbus = wishbone.Interface() self.sbbus = wishbone.Interface() dmbus = Record(obi_layout) sbbus = Record(obi_layout) self.submodules.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus) self.submodules.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus) self.debug_req = Signal() self.ndmreset = Signal() tdo_i = Signal() tdo_o = Signal() tdo_oe = Signal() self.specials += Tristate(pads.tdo, tdo_o, tdo_oe, tdo_i) self.dm_params = dict( # Clk / Rst. i_clk=ClockSignal("sys"), i_rst_n=~ResetSignal("sys"), o_ndmreset=self.ndmreset, o_debug_req=self.debug_req, # Slave Bus. i_dm_req=dmbus.req, i_dm_we=dmbus.we, i_dm_addr=dmbus.addr, i_dm_be=dmbus.be, i_dm_wdata=dmbus.wdata, o_dm_rdata=dmbus.rdata, # Master Bus. o_sb_req=sbbus.req, o_sb_addr=sbbus.addr, o_sb_we=sbbus.we, o_sb_wdata=sbbus.wdata, o_sb_be=sbbus.be, i_sb_gnt=sbbus.gnt, i_sb_rvalid=sbbus.rvalid, i_sb_rdata=sbbus.rdata, # JTAG. i_tck=pads.tck, i_tms=pads.tms, i_trst_n=pads.trst, i_tdi=pads.tdi, o_tdo=tdo_o, o_tdo_oe=tdo_oe, ) self.comb += [ dmbus.gnt.eq(dmbus.req), dmbus.rvalid.eq(dmbus.gnt), ] self.specials += Instance("dm_wrap", **self.dm_params)
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 test_tristate(triple, expected): assert Tristate.emit_vhdl( triple.get_tristate(foo), NameSpace(), None) == expected
def __init__(self, pads, cl=2): addressbits = len(pads.a) bankbits = len(pads.ba) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) assert databits % 8 == 0 self.settings = PhySettings(memtype="SDR", databits=databits, dfi_databits=databits, nranks=nranks, nphases=1, rdphase=0, wrphase=0, rdcmdphase=0, wrcmdphase=0, cl=cl, read_latency=cl + 2, write_latency=0) self.dfi = dfi = Interface(addressbits, bankbits, nranks, databits) # # # # Command/address self.sync += [ pads.a.eq(dfi.p0.address), pads.ba.eq(dfi.p0.bank), pads.cas_n.eq(dfi.p0.cas_n), pads.ras_n.eq(dfi.p0.ras_n), pads.we_n.eq(dfi.p0.we_n) ] if hasattr(pads, "cke"): self.sync += pads.cke.eq(dfi.p0.cke) if hasattr(pads, "cs_n"): self.sync += pads.cs_n.eq(dfi.p0.cs_n) # DQ/DQS/DM data dq_o = Signal(databits) dq_oe = Signal() dq_i = Signal(databits) self.sync += dq_o.eq(dfi.p0.wrdata) self.specials += Tristate(pads.dq, dq_o, dq_oe, dq_i) if hasattr(pads, "dm"): assert len(pads.dm) * 8 == databits self.sync += \ If(dfi.p0.wrdata_en, pads.dm.eq(dfi.p0.wrdata_mask) ).Else( pads.dm.eq(0) ) dq_in = Signal(databits) self.sync.sys_ps += dq_in.eq(dq_i) self.sync += dfi.p0.rddata.eq(dq_in) # DQ/DM control wrdata_en = Signal() self.sync += wrdata_en.eq(dfi.p0.wrdata_en) self.comb += dq_oe.eq(wrdata_en) rddata_en = Signal(cl + 2) self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en[:cl + 1])) self.comb += dfi.p0.rddata_valid.eq(rddata_en[cl + 1])