def __init__(self, clocker, sdpads, pads): # Rst if hasattr(pads, "rst"): self.comb += pads.rst.eq(0) # Clk self.specials += SDROutput( clk = ClockSignal(), i = ~clocker.clk & sdpads.clk, o = pads.clk ) # Cmd self.specials += SDRTristate( clk = ClockSignal(), io = pads.cmd, o = sdpads.cmd.o, oe = sdpads.cmd.oe, i = sdpads.cmd.i, ) # Data for i in range(4): self.specials += SDRTristate( clk = ClockSignal(), io = pads.data[i], o = sdpads.data.o[i], oe = sdpads.data.oe, i = sdpads.data.i[i], ) # Direction (optional) if hasattr(pads, "cmd_dir"): self.specials += [ SDROutput( clk = ClockSignal(), i = sdpads.cmd.oe, o = pads.cmd_dir, ), SDROutput( clk = ClockSignal(), i = sdpads.data.oe, o = pads.dat0_dir, ), SDROutput( clk = ClockSignal(), i = sdpads.data.oe, o = pads.dat13_dir, ) ]
def __init__(self, pads, sys_clk_freq=100e6, cl=None): 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 # Parameters ------------------------------------------------------------------------------- cl = get_default_cl(memtype="SDR", tck=1 / sys_clk_freq) if cl is None else cl # PHY settings ----------------------------------------------------------------------------- self.settings = PhySettings(phytype="GENSDRPHY", memtype="SDR", databits=databits, dfi_databits=databits, nranks=nranks, nphases=1, rdphase=0, wrphase=0, cl=cl, read_latency=cl + 1, 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) # Commands ----------------------------------------------------------------------------- commands = { # Pad name: (DFI name, Pad type (required or 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"), } 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)): self.specials += SDROutput(i=getattr(dfi.p0, dfi_name)[i], o=pad[i]) # DQ/DM Data Path -------------------------------------------------------------------------- for i in range(len(pads.dq)): self.specials += SDRTristate( io=pads.dq[i], o=dfi.p0.wrdata[i], oe=dfi.p0.wrdata_en, i=dfi.p0.rddata[i], ) if hasattr(pads, "dm"): for i in range(len(pads.dm)): self.specials += SDROutput(i=dfi.p0.wrdata_en & dfi.p0.wrdata_mask[i], o=pads.dm[i]) # DQ/DM Control Path ----------------------------------------------------------------------- rddata_en = Signal(self.settings.read_latency) self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en)) self.sync += dfi.p0.rddata_valid.eq(rddata_en[-1])
def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay): self.source = source = stream.Endpoint(spi_phy2core_layout) self.sink = sink = stream.Endpoint(spi_core2phy_layout) self.cs = Signal() self._spi_clk_divisor = spi_clk_divisor = Signal(8) self._spi_dummy_bits = spi_dummy_bits = Signal(8) if flash.cmd_width == 1: self._default_dummy_bits = flash.dummy_bits if flash.fast_mode else 0 elif flash.cmd_width == 4: self._default_dummy_bits = flash.dummy_bits * 3 if flash.fast_mode else 0 else: raise NotImplementedError(f'Command width of {flash.cmd_width} bits is currently not supported!') self._default_divisor = default_divisor self.clk_divisor = clk_divisor = CSRStorage(8, reset=self._default_divisor) self.dummy_bits = dummy_bits = CSRStorage(8, reset=self._default_dummy_bits) # # # if clock_domain != "sys": self.specials += MultiReg(clk_divisor.storage, spi_clk_divisor, "litespi") self.specials += MultiReg(dummy_bits.storage, spi_dummy_bits, "litespi") else: self.comb += spi_clk_divisor.eq(clk_divisor.storage) self.comb += spi_dummy_bits.eq(dummy_bits.storage) if hasattr(pads, "miso"): bus_width = 1 pads.dq = [pads.mosi, pads.miso] else: bus_width = len(pads.dq) assert bus_width in [1, 2, 4, 8] # Check if number of pads matches configured mode. assert flash.check_bus_width(bus_width) addr_bits = flash.addr_bits cmd_width = flash.cmd_width addr_width = flash.addr_width data_width = flash.bus_width command = flash.read_opcode.code ddr = flash.ddr # For Output modes there is a constant 8 dummy cycles, for I/O and DTR modes there are # different number of dummy cycles and in some cases they can be configurable. # We control a number of dummy cycles by substracting addr_width value from spi_dummy_bits, # so to achieve a proper number of dummy cycles when using shift_out function we need to # calculate total dummy bits which depends on addr_width value. # NOTE: these values are just default ones, in case chip has different default dummy cycles # for these modes or dummy cycles can be configured, please adjust the dummy bits value via # CSR in liblitespi accordingly. if (addr_width > 1): # DTR mode. if (ddr): if (addr_width == 2): self.default_dummy_bits = 6 * addr_width elif (addr_width == 4): self.default_dummy_bits = 8 * addr_width else: self.default_dummy_bits = 16 * addr_width # I/O mode. else: if (addr_width == 2): self.default_dummy_bits = 4 * addr_width elif (addr_width == 4): self.default_dummy_bits = 6 * addr_width else: self.default_dummy_bits = 16 * addr_width # Clock Generator. self.submodules.clkgen = clkgen = LiteSPIClkGen(pads, device, with_ddr=ddr) self.comb += [ clkgen.div.eq(spi_clk_divisor), clkgen.sample_cnt.eq(1), clkgen.update_cnt.eq(1), ] # CS control. cs_timer = WaitTimer(cs_delay + 1) # Ensure cs_delay cycles between XFers. cs_out = Signal() self.submodules += cs_timer self.comb += cs_timer.wait.eq(self.cs) self.comb += cs_out.eq(cs_timer.done) self.comb += pads.cs_n.eq(~cs_out) # I/Os. data_bits = 32 cmd_bits = 8 dq_o = Signal(len(pads.dq)) dq_i = Signal(len(pads.dq)) dq_oe = Signal(len(pads.dq)) for i in range(len(pads.dq)): self.specials += SDRTristate( io = pads.dq[i], o = dq_o[i], oe = dq_oe[i], i = dq_i[i], ) # FSM. shift_cnt = Signal(8, reset_less=True) addr = Signal(addr_bits if not ddr else addr_bits + addr_width, reset_less=True) data = Signal(data_bits, reset_less=True) cmd = Signal(cmd_bits, reset_less=True) usr_dout = Signal(len(sink.data), reset_less=True) usr_din = Signal(len(sink.data), reset_less=True) usr_len = Signal(len(sink.len), reset_less=True) usr_width = Signal(len(sink.width), reset_less=True) usr_mask = Signal(len(sink.mask), reset_less=True) din_width_cases = {1: [NextValue(usr_din, Cat(dq_i[1], usr_din))]} for i in [2, 4, 8]: din_width_cases[i] = [NextValue(usr_din, Cat(dq_i[0:i], usr_din))] dout_width_cases = {} for i in [1, 2, 4, 8]: dout_width_cases[i] = [dq_o.eq(usr_dout[-i:])] self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", sink.ready.eq(cs_out), If(sink.valid & sink.ready, Case(sink.cmd, { CMD: [ NextValue(addr, sink.data), NextValue(cmd, command), NextState("CMD") ], READ: [ NextState("DATA") ], USER: [ NextValue(usr_dout, sink.data << (32-sink.len)), NextValue(usr_din, 0), NextValue(usr_len, sink.len), NextValue(usr_width, sink.width), NextValue(usr_mask, sink.mask), NextState("USER") ] }) ) ) def shift_out(width, bits, next_state, trigger=[], op=[], ddr=False): if type(trigger) is not list: trigger = [trigger] op = [op] edge = self.clkgen.negedge if not ddr else trigger[0] res = [ self.clkgen.en.eq(1), If(edge, NextValue(shift_cnt, shift_cnt+width), If(shift_cnt == (bits-width), NextValue(shift_cnt, 0), NextState(next_state), ), ), ] if len(trigger) == len(op): for i in range(len(trigger)): res += [If(trigger[i], *op[i])] return res fsm.act("CMD", dq_oe.eq(cmd_oe_mask[cmd_width]), dq_o.eq(cmd[-cmd_width:]), shift_out( width = cmd_width, bits = cmd_bits, next_state = "ADDR", op = [NextValue(cmd, cmd<<cmd_width)], trigger = clkgen.negedge, ddr = False, ), ) fsm.act("ADDR", dq_oe.eq(addr_oe_mask[addr_width]), dq_o.eq(addr[-addr_width:]), If(spi_dummy_bits != 0, shift_out( width = addr_width, bits = len(addr), next_state = "DUMMY", op = [NextValue(addr, addr<<addr_width)], trigger = clkgen.negedge if not ddr else clkgen.update, ddr = ddr ) ).Else( shift_out( width = addr_width, bits = len(addr), next_state = "IDLE", op = [NextValue(addr, addr<<addr_width)], trigger = clkgen.negedge if not ddr else clkgen.update, ddr = ddr ) ) ) fsm.act("DUMMY", If(shift_cnt < 8, dq_oe.eq(addr_oe_mask[addr_width])), # output 0's for the first dummy byte shift_out( width = addr_width, bits = spi_dummy_bits, next_state = "IDLE" ), ) fsm.act("DATA", shift_out( width = data_width, bits = data_bits, next_state = "DATA_END", op = [NextValue(data, Cat(dq_i[1] if data_width == 1 else dq_i[0:data_width], data))], trigger = clkgen.posedge_reg2 if not ddr else clkgen.sample, ddr = ddr ) ) fsm.act("DATA_END", If(spi_clk_divisor > 0, # Last data cycle was already captured in the DATA state. NextState("SEND_DATA"), ).Elif(clkgen.posedge_reg2, # Capture last data cycle. NextValue(data, Cat(dq_i[1] if data_width == 1 else dq_i[0:data_width], data)), NextState("SEND_DATA"), ) ) fsm.act("USER", dq_oe.eq(usr_mask), Case(usr_width, dout_width_cases), shift_out( width = usr_width, bits = usr_len, next_state = "USER_END", trigger = [ clkgen.posedge_reg2, # data sampling clkgen.negedge, # data update ], op = [ [Case(usr_width, din_width_cases)], [NextValue(usr_dout, usr_dout<<usr_width)], ], ddr = False) ) fsm.act("USER_END", If(spi_clk_divisor > 0, # Last data cycle was already captured in the USER state. NextState("SEND_USER_DATA"), ).Elif(clkgen.posedge_reg2, # Capture last data cycle. Case(usr_width, din_width_cases), NextState("SEND_USER_DATA"), ) ) fsm.act("SEND_USER_DATA", source.valid.eq(1), source.last.eq(1), source.data.eq(usr_din), If(source.ready, NextState("IDLE"), ) ) fsm.act("SEND_DATA", source.valid.eq(1), source.last.eq(1), source.data.eq(data), If(source.ready, NextState("IDLE"), ) )
def __init__(self, pads, sys_clk_freq=100e6, cl=None): 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 # Parameters ------------------------------------------------------------------------------- cl = get_default_cl(memtype="SDR", tck=1 / sys_clk_freq) if cl is None else cl # PHY settings ----------------------------------------------------------------------------- self.settings = PhySettings(phytype="GENSDRPHY", memtype="SDR", databits=databits, dfi_databits=databits, nranks=nranks, nphases=1, rdphase=0, wrphase=0, cl=cl, read_latency=cl + 1, 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) # Commands ----------------------------------------------------------------------------- commands = { "a": "address", "ba": "bank", "ras_n": "ras_n", "cas_n": "cas_n", "we_n": "we_n", } if hasattr(pads, "cke"): commands.update({"cke": "cke"}) if hasattr(pads, "cs_n"): commands.update({"cs_n": "cs_n"}) for pad_name, dfi_name in commands.items(): pad = getattr(pads, pad_name) for i in range(len(pad)): self.specials += SDROutput(i=getattr(dfi.p0, dfi_name)[i], o=pad[i]) # DQ/DM Data Path -------------------------------------------------------------------------- for i in range(len(pads.dq)): self.specials += SDRTristate( io=pads.dq[i], o=dfi.p0.wrdata[i], oe=dfi.p0.wrdata_en, i=dfi.p0.rddata[i], ) if hasattr(pads, "dm"): for i in range(len(pads.dm)): self.specials += SDROutput(i=dfi.p0.wrdata_en & dfi.p0.wrdata_mask[i], o=pads.dm[i]) # DQ/DM Control Path ----------------------------------------------------------------------- rddata_en = Signal(self.settings.read_latency) self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en)) self.sync += dfi.p0.rddata_valid.eq(rddata_en[-1])
def __init__(self, platform, pads, usb_clk_freq=48e6, dma_data_width=32): self.pads = pads self.usb_clk_freq = usb_clk_freq self.dma_data_width = dma_data_width self.wb_ctrl = wb_ctrl = wishbone.Interface(data_width=32) self.wb_dma = wb_dma = wishbone.Interface(data_width=dma_data_width) self.interrupt = Signal() # # # usb_ios = Record([ ("dp_i", 1), ("dp_o", 1), ("dp_oe", 1), ("dm_i", 1), ("dm_o", 1), ("dm_oe", 1), ]) self.specials += Instance( self.get_netlist_name(), # Clk / Rst. i_phy_clk=ClockSignal("usb"), i_phy_reset=ResetSignal("usb"), i_ctrl_clk=ClockSignal("sys"), i_ctrl_reset=ResetSignal("sys"), # Wishbone Control. i_io_ctrl_CYC=wb_ctrl.cyc, i_io_ctrl_STB=wb_ctrl.stb, o_io_ctrl_ACK=wb_ctrl.ack, i_io_ctrl_WE=wb_ctrl.we, i_io_ctrl_ADR=wb_ctrl.adr, o_io_ctrl_DAT_MISO=wb_ctrl.dat_r, i_io_ctrl_DAT_MOSI=wb_ctrl.dat_w, i_io_ctrl_SEL=wb_ctrl.sel, # Wishbone DMA. o_io_dma_CYC=wb_dma.cyc, o_io_dma_STB=wb_dma.stb, i_io_dma_ACK=wb_dma.ack, o_io_dma_WE=wb_dma.we, o_io_dma_ADR=wb_dma.adr, i_io_dma_DAT_MISO=wb_dma.dat_r, o_io_dma_DAT_MOSI=wb_dma.dat_w, o_io_dma_SEL=wb_dma.sel, i_io_dma_ERR=wb_dma.err, o_io_dma_CTI=wb_dma.cti, o_io_dma_BTE=wb_dma.bte, # Interrupt. o_io_interrupt=self.interrupt, # USB i_io_usb_0_dp_read=usb_ios.dp_i, o_io_usb_0_dp_write=usb_ios.dp_o, o_io_usb_0_dp_writeEnable=usb_ios.dp_oe, i_io_usb_0_dm_read=usb_ios.dm_i, o_io_usb_0_dm_write=usb_ios.dm_o, o_io_usb_0_dm_writeEnable=usb_ios.dm_oe, ) self.specials += SDRTristate( io=pads.dp, o=usb_ios.dp_o, oe=usb_ios.dp_oe, i=usb_ios.dp_i, ) self.specials += SDRTristate( io=pads.dm, o=usb_ios.dm_o, oe=usb_ios.dm_oe, i=usb_ios.dm_i, ) self.add_sources(platform)
def __init__(self, pads, flash, device, clock_domain, default_divisor): self.source = source = stream.Endpoint(spi_phy_data_layout) self.sink = sink = stream.Endpoint(spi_phy_ctl_layout) self.cs_n = Signal() self._spi_clk_divisor = spi_clk_divisor = Signal(8) self._spi_dummy_bits = spi_dummy_bits = Signal(8) self._default_dummy_bits = flash.dummy_bits if flash.fast_mode else 0 self._default_divisor = default_divisor self.clk_divisor = clk_divisor = CSRStorage( 8, reset=self._default_divisor) self.dummy_bits = dummy_bits = CSRStorage( 8, reset=self._default_dummy_bits) # # # if clock_domain != "sys": self.specials += MultiReg(clk_divisor.storage, spi_clk_divisor, "litespi") self.specials += MultiReg(dummy_bits.storage, spi_dummy_bits, "litespi") else: self.comb += spi_clk_divisor.eq(clk_divisor.storage) self.comb += spi_dummy_bits.eq(dummy_bits.storage) if hasattr(pads, "miso"): bus_width = 1 pads.dq = [pads.mosi, pads.miso] else: bus_width = len(pads.dq) assert bus_width in [1, 2, 4, 8] # Check if number of pads matches configured mode. assert flash.check_bus_width(bus_width) addr_bits = flash.addr_bits cmd_width = flash.cmd_width addr_width = flash.addr_width data_width = flash.bus_width command = flash.read_opcode.code ddr = flash.ddr # For Output modes there is a constant 8 dummy cycles, for I/O and DTR modes there are # different number of dummy cycles and in some cases they can be configurable. # We control a number of dummy cycles by substracting addr_width value from spi_dummy_bits, # so to achieve a proper number of dummy cycles when using shift_out function we need to # calculate total dummy bits which depends on addr_width value. # NOTE: these values are just default ones, in case chip has different default dummy cycles # for these modes or dummy cycles can be configured, please adjust the dummy bits value via # CSR in liblitespi accordingly. if (addr_width > 1): # DTR mode. if (ddr): if (addr_width == 2): self.default_dummy_bits = 6 * addr_width elif (addr_width == 4): self.default_dummy_bits = 8 * addr_width else: self.default_dummy_bits = 16 * addr_width # I/O mode. else: if (addr_width == 2): self.default_dummy_bits = 4 * addr_width elif (addr_width == 4): self.default_dummy_bits = 6 * addr_width else: self.default_dummy_bits = 16 * addr_width # Clock Generator. self.submodules.clkgen = clkgen = LiteSPIClkGen(pads, device, with_ddr=ddr) self.comb += [ clkgen.div.eq(spi_clk_divisor), clkgen.sample_cnt.eq(1), clkgen.update_cnt.eq(1), pads.cs_n.eq(self.cs_n), ] # I/Os. data_bits = 32 cmd_bits = 8 dq_o = Signal(len(pads.dq)) dq_i = Signal(len(pads.dq)) dq_oe = Signal(len(pads.dq)) for i in range(len(pads.dq)): self.specials += SDRTristate( io=pads.dq[i], o=dq_o[i], oe=dq_oe[i], i=dq_i[i], ) # FSM. self.fsm_cnt = fsm_cnt = Signal(8) addr = Signal(addr_bits if not ddr else addr_bits + addr_width) # Dummy data for the first register shift data = Signal(data_bits) cmd = Signal(cmd_bits) usr_dout = Signal().like(sink.data) usr_din = Signal().like(sink.data) usr_len = Signal().like(sink.len) usr_width = Signal().like(sink.width) usr_mask = Signal().like(sink.mask) din_width_cases = {1: [NextValue(usr_din, Cat(dq_i[1], usr_din))]} for i in [2, 4, 8]: din_width_cases[i] = [NextValue(usr_din, Cat(dq_i[0:i], usr_din))] dout_width_cases = {} for i in [1, 2, 4, 8]: dout_width_cases[i] = [dq_o.eq(usr_dout[-i:])] commands = { CMD: [ NextValue(addr, sink.data), NextValue(cmd, command), NextState("CMD") ], READ: [NextState("DATA")], USER: [ NextValue(usr_dout, sink.data << (32 - sink.len)), NextValue(usr_din, 0), NextValue(usr_len, sink.len), NextValue(usr_width, sink.width), NextValue(usr_mask, sink.mask), NextState("USER") ], } self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", sink.ready.eq(1), If( sink.valid, Case(sink.cmd, commands), ), ) fsm.act( "CMD", dq_oe.eq(cmd_oe_mask), dq_o.eq(cmd[-cmd_width:]), self.shift_out( width=cmd_width, bits=cmd_bits, next_state="ADDR", op=[NextValue(cmd, cmd << cmd_width)], trigger=clkgen.negedge, ddr=False, ), ) fsm.act( "ADDR", dq_oe.eq(addr_oe_mask[addr_width]), dq_o.eq(addr[-addr_width:]), If( spi_dummy_bits > 0, self.shift_out( width=addr_width, bits=len(addr), next_state="DUMMY", op=[NextValue(addr, addr << addr_width)], trigger=clkgen.negedge if not ddr else clkgen.update, ddr=ddr)).Else( self.shift_out( width=addr_width, bits=len(addr), next_state="IDLE", op=[NextValue(addr, addr << addr_width)], trigger=clkgen.negedge if not ddr else clkgen.update, ddr=ddr))) fsm.act( "DUMMY", If(fsm_cnt < 8, dq_oe.eq(addr_oe_mask[addr_width]) ), # output 0's for the first dummy byte self.shift_out(width=addr_width, bits=spi_dummy_bits, next_state="IDLE"), ) fsm.act( "DATA", self.shift_out( width=data_width, bits=data_bits, next_state="SEND_DATA", op=[ NextValue( data, Cat(dq_i[1] if data_width == 1 else dq_i[0:data_width], data)) ], trigger=clkgen.posedge if not ddr else clkgen.sample, ddr=ddr)) fsm.act( "USER", dq_oe.eq(usr_mask), Case(usr_width, dout_width_cases), self.shift_out( width=usr_width, bits=usr_len, next_state="SEND_USER_DATA", trigger=[ clkgen.posedge, # data sampling clkgen.negedge, # data update ], op=[ [Case(usr_width, din_width_cases)], [NextValue(usr_dout, usr_dout << usr_width)], ], ddr=False)), fsm.act("SEND_USER_DATA", source.valid.eq(1), source.last.eq(1), source.data.eq(usr_din), If( source.ready, NextState("IDLE"), )) fsm.act("SEND_DATA", source.valid.eq(1), source.last.eq(1), source.data.eq(data), If( source.ready, NextState("IDLE"), ))
def __init__(self, pads, cl=2, cmd_latency=1): 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 cl in [2, 3] assert databits % 8 == 0 # PHY settings ----------------------------------------------------------------------------- self.settings = PhySettings(phytype="GENSDRPHY", memtype="SDR", databits=databits, dfi_databits=databits, nranks=nranks, nphases=1, rdphase=0, wrphase=0, rdcmdphase=0, wrcmdphase=0, cl=cl, read_latency=cl + cmd_latency, 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.specials += [ SDROutput(i=dfi.p0.address[i], o=pads.a[i]) for i in range(len(pads.a)) ] self.specials += [ SDROutput(i=dfi.p0.bank[i], o=pads.ba[i]) for i in range(len(pads.ba)) ] self.specials += SDROutput(i=dfi.p0.cas_n, o=pads.cas_n) self.specials += SDROutput(i=dfi.p0.ras_n, o=pads.ras_n) self.specials += SDROutput(i=dfi.p0.we_n, o=pads.we_n) if hasattr(pads, "cke"): self.specials += SDROutput(i=dfi.p0.cke, o=pads.cke) if hasattr(pads, "cs_n"): self.specials += SDROutput(i=dfi.p0.cs_n, o=pads.cs_n) # DQ/DM Data Path -------------------------------------------------------------------------- for i in range(len(pads.dq)): self.specials += SDRTristate( io=pads.dq[i], o=dfi.p0.wrdata[i], oe=dfi.p0.wrdata_en, i=dfi.p0.rddata[i], ) if hasattr(pads, "dm"): for i in range(len(pads.dm)): self.comb += pads.dm[i].eq(0) # FIXME # DQ/DM Control Path ----------------------------------------------------------------------- rddata_en = Signal(cl + cmd_latency) self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en)) self.sync += dfi.p0.rddata_valid.eq(rddata_en[-1])
def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay): self.source = source = stream.Endpoint(spi_phy2core_layout) self.sink = sink = stream.Endpoint(spi_core2phy_layout) self.cs = Signal() self._spi_clk_divisor = spi_clk_divisor = Signal(8) self._default_divisor = default_divisor self.clk_divisor = clk_divisor = CSRStorage( 8, reset=self._default_divisor) # # # # Resynchronize CSR Clk Divisor to LiteSPI Clk Domain. self.submodules += ResyncReg(clk_divisor.storage, spi_clk_divisor, clock_domain) # Determine SPI Bus width and DQs. if hasattr(pads, "mosi"): bus_width = 1 else: bus_width = len(pads.dq) assert bus_width in [1, 2, 4, 8] # Check if number of pads matches configured mode. assert flash.check_bus_width(bus_width) self.addr_bits = addr_bits = flash.addr_bits self.cmd_width = cmd_width = flash.cmd_width self.addr_width = addr_width = flash.addr_width self.data_width = data_width = flash.bus_width self.ddr = ddr = flash.ddr self.command = command = flash.read_opcode.code # Clock Generator. self.submodules.clkgen = clkgen = LiteSPIClkGen(pads, device, with_ddr=ddr) self.comb += [ clkgen.div.eq(spi_clk_divisor), clkgen.sample_cnt.eq(1), clkgen.update_cnt.eq(1), ] # CS control. cs_timer = WaitTimer(cs_delay + 1) # Ensure cs_delay cycles between XFers. cs_enable = Signal() self.submodules += cs_timer self.comb += cs_timer.wait.eq(self.cs) self.comb += cs_enable.eq(cs_timer.done) self.comb += pads.cs_n.eq(~cs_enable) # I/Os. data_bits = 32 cmd_bits = 8 if hasattr(pads, "mosi"): dq_o = Signal() dq_i = Signal(2) dq_oe = Signal() # Unused. self.specials += SDROutput(i=dq_o, o=pads.mosi) self.specials += SDRInput(i=pads.miso, o=dq_i[1]) else: dq_o = Signal(len(pads.dq)) dq_i = Signal(len(pads.dq)) dq_oe = Signal(len(pads.dq)) for i in range(len(pads.dq)): self.specials += SDRTristate( io=pads.dq[i], o=dq_o[i], oe=dq_oe[i], i=dq_i[i], ) # Data Shift Registers. sr_cnt = Signal(8, reset_less=True) sr_out_load = Signal() sr_out_shift = Signal() sr_out = Signal(len(sink.data), reset_less=True) sr_in_shift = Signal() sr_in = Signal(len(sink.data), reset_less=True) # Data Out Generation/Load/Shift. self.comb += [ dq_oe.eq(sink.mask), Case( sink.width, { 1: dq_o.eq(sr_out[-1:]), 2: dq_o.eq(sr_out[-2:]), 4: dq_o.eq(sr_out[-4:]), 8: dq_o.eq(sr_out[-8:]), }) ] self.sync += If(sr_out_load, sr_out.eq(sink.data << (len(sink.data) - sink.len))) self.sync += If( sr_out_shift, Case( sink.width, { 1: sr_out.eq(Cat(Signal(1), sr_out)), 2: sr_out.eq(Cat(Signal(2), sr_out)), 4: sr_out.eq(Cat(Signal(4), sr_out)), 8: sr_out.eq(Cat(Signal(8), sr_out)), })) # Data In Shift. self.sync += If( sr_in_shift, Case( sink.width, { 1: sr_in.eq(Cat(dq_i[1], sr_in)), 2: sr_in.eq(Cat(dq_i[:2], sr_in)), 4: sr_in.eq(Cat(dq_i[:4], sr_in)), 8: sr_in.eq(Cat(dq_i[:8], sr_in)), })) # FSM. self.submodules.fsm = fsm = FSM(reset_state="WAIT-CMD-DATA") fsm.act( "WAIT-CMD-DATA", # Wait for CS and a CMD from the Core. If( cs_enable & sink.valid, # Load Shift Register Count/Data Out. NextValue(sr_cnt, sink.len - sink.width), sr_out_load.eq(1), # Start XFER. NextState("XFER"), ), ) fsm.act( "XFER", # Generate Clk. self.clkgen.en.eq(1), # Data In Shift. If(clkgen.posedge_reg2, sr_in_shift.eq(1)), # Data Out Shift. If(clkgen.negedge, sr_out_shift.eq(1)), # Shift Register Count Update/Check. If( self.clkgen.negedge, NextValue(sr_cnt, sr_cnt - sink.width), # End XFer. If( sr_cnt == 0, NextState("XFER-END"), ), ), ) fsm.act( "XFER-END", # Last data already captured in XFER when divisor > 0 so only capture for divisor == 0. If( (spi_clk_divisor > 0) | clkgen.posedge_reg2, # Accept CMD. sink.ready.eq(1), # Capture last data (only for spi_clk_divisor == 0). sr_in_shift.eq(spi_clk_divisor == 0), # Send Status/Data to Core. NextState("SEND-STATUS-DATA"), )) self.comb += source.data.eq(sr_in) fsm.act( "SEND-STATUS-DATA", # Send Data In to Core and return to WAIT when accepted. source.valid.eq(1), source.last.eq(1), If( source.ready, NextState("WAIT-CMD-DATA"), ))
def __init__(self, pads, clk_freq, fifo_depth = 64, read_time = 128, write_time = 128): self.dw = dw = len(pads.data) self.pads = pads self.sink = stream.Endpoint(phy_description(dw)) self.source = stream.Endpoint(phy_description(dw)) # # # # Pads Reset. # ----------- pads.oe_n.reset = 1 pads.rd_n.reset = 1 pads.wr_n.reset = 1 # Read CDC/FIFO (FTDI --> SoC). # ----------------------------- self.submodules.read_cdc = stream.ClockDomainCrossing(phy_description(dw), cd_from = "usb", cd_to = "sys", with_common_rst = True ) self.submodules.read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) self.comb += self.read_cdc.source.connect(self.read_fifo.sink) self.comb += self.read_fifo.source.connect(self.source) read_fifo_almost_full = (self.read_fifo.level > (fifo_depth - 4)) read_fifo_almost_full_usb = Signal() self.specials += MultiReg(read_fifo_almost_full, read_fifo_almost_full_usb) # Write FIFO/CDC (SoC --> FTDI). # ------------------------------ self.submodules.write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) self.submodules.write_cdc = stream.ClockDomainCrossing(phy_description(dw), cd_from = "sys", cd_to = "usb", with_common_rst = True ) self.comb += self.sink.connect(self.write_fifo.sink) self.comb += self.write_fifo.source.connect(self.write_cdc.sink) # Read / Write Anti-Starvation. # ----------------------------- read_time_en, max_read_time = anti_starvation(self, read_time) write_time_en, max_write_time = anti_starvation(self, write_time) # Read / Write Detection. # ----------------------- self.wants_write = wants_write = Signal() self.wants_read = wants_read = Signal() self.comb += [ wants_write.eq(~pads.txe_n & self.write_cdc.source.valid), wants_read.eq( ~pads.rxf_n & (self.read_cdc.sink.ready & ~read_fifo_almost_full_usb)), ] # Data Bus Tristate. # ------------------ self.data_w = data_w = Signal(dw) self.data_r = data_r = Signal(dw) self.data_oe = data_oe = Signal() for i in range(dw): self.specials += SDRTristate( io = pads.data[i], o = data_w[i], oe = data_oe, i = data_r[i], clk = ClockSignal("usb") ) if hasattr(pads, "be"): for i in range(dw//8): self.specials += SDRTristate( io = pads.be[i], o = Signal(reset=0b1), oe = data_oe, i = Signal(), clk = ClockSignal("usb") ) # Read / Write FSM. # ----------------- fsm = FSM(reset_state="READ") fsm = ClockDomainsRenamer("usb")(fsm) self.submodules.fsm = fsm fsm.act("READ", # Arbitration. read_time_en.eq(1), If(wants_write, If(~wants_read | max_read_time, NextState("READ-TO-WRITE") ) ), # Control/Data-Path. data_oe.eq(0), NextValue(pads.oe_n, ~wants_read), NextValue(pads.rd_n, pads.oe_n | ~wants_read), NextValue(pads.wr_n, 1), ) self.comb += self.read_cdc.sink.data.eq(data_r) self.sync.usb += self.read_cdc.sink.valid.eq(~pads.rd_n & ~pads.rxf_n) fsm.act("READ-TO-WRITE", NextState("WRITE") ) fsm.act("WRITE", # Arbitration. write_time_en.eq(1), If(wants_read, If(~wants_write | max_write_time, NextState("WRITE-TO-READ") ) ), # Control/Data-Path. data_oe.eq(1), NextValue(pads.oe_n, 1), NextValue(pads.rd_n, 1), NextValue(pads.wr_n, ~wants_write), #data_w.eq(write_fifo.source.data), NextValue(data_w, self.write_cdc.source.data), # FIXME: Add 1 cycle delay. self.write_cdc.source.ready.eq(wants_write), ) fsm.act("WRITE-TO-READ", NextState("READ") )