def __init__(self): self._cfg = CSRStorage(8) self._stat = CSRStatus(8) self.sink = Sink(ULPI_DATA) self.source = Source([("d", 8), ("last", 1)]) latch_d = Signal() latched = Signal(8) self.sync += If(latch_d, latched.eq(self.sink.payload.d)) self.submodules.fsm = FSM() self.fsm.act("IDLE", self.sink.ack.eq(1), If(self.sink.stb & self._cfg.storage[0], latch_d.eq(1), If(self.sink.payload.rxcmd, NextState("RXCMD") ).Else(NextState("UDATA")))) self.fsm.act("RXCMD", self.source.payload.d.eq(0xAC), self.source.stb.eq(1), If(self.source.ack, NextState("SENDB")) ) self.fsm.act("UDATA", self.source.payload.d.eq(0xAD), self.source.stb.eq(1), If(self.source.ack, NextState("SENDB")) ) self.fsm.act("SENDB", self.source.payload.d.eq(latched), self.source.payload.last.eq(1), self.source.stb.eq(1), If(self.source.ack, NextState("IDLE")))
def __init__(self, pads, dummy=15, div=2, with_bitbang=True): """ Simple SPI flash, e.g. N25Q128 on the LX9 Microboard. Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast Read). Only supports mode0 (cpol=0, cpha=0). Optionally supports software bitbanging (for write, erase, or other commands). """ self.bus = bus = wishbone.Interface() spi_width = flen(pads.dq) if with_bitbang: self.bitbang = CSRStorage(4) self.miso = CSRStatus() self.bitbang_en = CSRStorage() ### cs_n = Signal(reset=1) clk = Signal() dq_oe = Signal() wbone_width = flen(bus.dat_r) read_cmd_params = { 4: (_format_cmd(_QIOFR, 4), 4*8), 2: (_format_cmd(_DIOFR, 2), 2*8), 1: (_format_cmd(_FAST_READ, 1), 1*8) } read_cmd, cmd_width = read_cmd_params[spi_width] addr_width = 24 pads.cs_n.reset = 1 dq = TSTriple(spi_width) self.specials.dq = dq.get_tristate(pads.dq) sr = Signal(max(cmd_width, addr_width, wbone_width)) dqs = Replicate(1, spi_width-1) self.comb += bus.dat_r.eq(sr) hw_read_logic = [ pads.clk.eq(clk), pads.cs_n.eq(cs_n), dq.o.eq(sr[-spi_width:]), dq.oe.eq(dq_oe) ] if with_bitbang: bitbang_logic = [ pads.clk.eq(self.bitbang.storage[1]), pads.cs_n.eq(self.bitbang.storage[2]), dq.o.eq(Cat(self.bitbang.storage[0], dqs)), If(self.bitbang.storage[3], dq.oe.eq(0) ).Else( dq.oe.eq(1) ), If(self.bitbang.storage[1], self.miso.status.eq(dq.i[1]) ) ] self.comb += \ If(self.bitbang_en.storage, bitbang_logic ).Else( hw_read_logic ) else: self.comb += hw_read_logic if div < 2: raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) else: i = Signal(max=div) dqi = Signal(spi_width) self.sync += [ If(i == div//2 - 1, clk.eq(1), dqi.eq(dq.i), ), If(i == div - 1, i.eq(0), clk.eq(0), sr.eq(Cat(dqi, sr[:-spi_width])) ).Else( i.eq(i + 1), ), ] # spi is byte-addressed, prefix by zeros z = Replicate(0, log2_int(wbone_width//8)) seq = [ (cmd_width//spi_width*div, [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), (addr_width//spi_width*div, [sr[-addr_width:].eq(Cat(z, bus.adr))]), ((dummy + wbone_width//spi_width)*div, [dq_oe.eq(0)]), (1, [bus.ack.eq(1), cs_n.eq(1)]), (div, # tSHSL! [bus.ack.eq(0)]), (0, []), ] # accumulate timeline deltas t, tseq = 0, [] for dt, a in seq: tseq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
def __init__(self, mem_or_size, address, read_only=None, init=None, bus=None): if bus is None: bus = Interface() self.bus = bus data_width = flen(self.bus.dat_w) if isinstance(mem_or_size, Memory): mem = mem_or_size else: mem = Memory(data_width, mem_or_size // (data_width // 8), init=init) csrw_per_memw = (mem.width + data_width - 1) // data_width word_bits = log2_int(csrw_per_memw) page_bits = log2_int((mem.depth * csrw_per_memw + 511) // 512, False) if page_bits: self._page = CSRStorage(page_bits, name=mem.name_override + "_page") else: self._page = None if read_only is None: if hasattr(mem, "bus_read_only"): read_only = mem.bus_read_only else: read_only = False ### port = mem.get_port(write_capable=not read_only) self.specials += mem, port sel = Signal() sel_r = Signal() self.sync += sel_r.eq(sel) self.comb += sel.eq(self.bus.adr[9:] == address) if word_bits: word_index = Signal(word_bits) word_expanded = Signal(csrw_per_memw * data_width) self.sync += word_index.eq(self.bus.adr[:word_bits]) self.comb += [ word_expanded.eq(port.dat_r), If( sel_r, chooser(word_expanded, word_index, self.bus.dat_r, n=csrw_per_memw, reverse=True)) ] if not read_only: wregs = [] for i in range(csrw_per_memw - 1): wreg = Signal(data_width) self.sync += If( sel & self.bus.we & (self.bus.adr[:word_bits] == i), wreg.eq(self.bus.dat_w)) wregs.append(wreg) memword_chunks = [self.bus.dat_w] + list(reversed(wregs)) self.comb += [ port.we.eq(sel & self.bus.we & (self.bus.adr[:word_bits] == csrw_per_memw - 1)), port.dat_w.eq(Cat(*memword_chunks)) ] else: self.comb += If(sel_r, self.bus.dat_r.eq(port.dat_r)) if not read_only: self.comb += [ port.we.eq(sel & self.bus.we), port.dat_w.eq(self.bus.dat_w) ] if self._page is None: self.comb += port.adr.eq(self.bus.adr[word_bits:word_bits + flen(port.adr)]) else: pv = self._page.storage self.comb += port.adr.eq( Cat( self.bus.adr[word_bits:word_bits + flen(port.adr) - flen(pv)], pv))
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): super(CycleControl, self).__init__() time_width = ventilator_layout[0][1] self._start = CSR() self._prohibit = CSRStorage() self._clear = CSR() self._run = CSRStatus() self._cycle = CSRStatus(time_width) self._update = CSR() self.have_out = Signal() self.have_in = Signal() self.cycle = Signal(time_width) self.run = Signal() ### start_in = Signal() start_out = Signal() prohibit_underflow = Signal() stop_once = Signal() clear_force = Signal() clear_force0 = Signal() stop = Signal() start = Signal() clear = Signal() run0 = Signal() self.comb += [ self._run.status.eq(run0), start.eq(self._start.re | (start_out & self.have_out)), stop.eq(self._prohibit.storage | (prohibit_underflow & ~self.have_out)), clear.eq(self._clear.re | clear_force | clear_force0), If( stop, self.run.eq(0), ).Elif( start, self.run.eq(1), ).Else(self.run.eq(run0), ), ] self.comb += [ self.dout.ack.eq(1), self.din.payload.addr.eq(self.dout.payload.addr), self.din.payload.data.eq(self.dout.payload.data), If( self.dout.stb, Case( self.dout.payload.addr[:8], { 0x00: self.din.stb.eq(1), 0x04: stop_once.eq(1), 0x05: clear_force.eq(self.dout.payload.data), }), ) ] self.sync += [ If( self.dout.stb, Case( self.dout.payload.addr[:8], { 0x01: start_in.eq(self.dout.payload.data), 0x02: start_out.eq(self.dout.payload.data), 0x03: prohibit_underflow.eq(self.dout.payload.data), 0x05: clear_force0.eq(self.dout.payload.data), }), ), If( stop_once, run0.eq(0), ).Elif( start_in & self.have_in, run0.eq(1), ).Else(run0.eq(self.run), ), If( clear, self.cycle.eq(0), ).Elif( self.run, self.cycle.eq(self.cycle + 1), ), If( self._update.re, self._cycle.status.eq(self.cycle), ), ]
def __init__(self, slaves, depth=256, bus=None, with_wishbone=True): time_width, addr_width, data_width = [_[1] for _ in ventilator_layout] self.submodules.ctrl = CycleControl() self.submodules.ev = ev = EventManager() ev.in_readable = EventSourceLevel() ev.out_overflow = EventSourceProcess() ev.in_overflow = EventSourceLevel() ev.out_readable = EventSourceProcess() ev.stopped = EventSourceProcess() ev.started = EventSourceProcess() ev.finalize() self._in_time = CSRStatus(time_width) self._in_addr = CSRStatus(addr_width) self._in_data = CSRStatus(data_width) self._in_next = CSR() self._in_flush = CSR() self._out_time = CSRStorage(time_width, write_from_dev=with_wishbone) self._out_addr = CSRStorage(addr_width, write_from_dev=with_wishbone) self._out_data = CSRStorage(data_width, write_from_dev=with_wishbone) self._out_next = CSR() self._out_flush = CSR() self.busy = Signal() ### if with_wishbone: if bus is None: bus = wishbone.Interface() self.bus = bus slaves = [(self.ctrl, 0x00000000, 0xffffff00)] + slaves self.submodules.in_fifo = in_fifo = SyncFIFOBuffered( ventilator_layout, depth) self.submodules.out_fifo = out_fifo = SyncFIFOBuffered( ventilator_layout, depth) self.submodules.enc = PriorityEncoder(len(slaves)) wb_in_next = Signal() wb_out_next = Signal() out_request = Signal() in_request = Signal() # CSRs and Events self.comb += [ ev.in_readable.trigger.eq(in_fifo.readable), ev.out_overflow.trigger.eq(~out_fifo.writable), ev.in_overflow.trigger.eq(~in_fifo.writable), ev.out_readable.trigger.eq(out_fifo.readable), ev.started.trigger.eq(~self.ctrl.run), ev.stopped.trigger.eq(self.ctrl.run), self.ctrl.have_in.eq(~self.enc.n), self.ctrl.have_out.eq(out_fifo.readable), self._in_time.status.eq(in_fifo.dout.time), self._in_addr.status.eq(in_fifo.dout.addr), self._in_data.status.eq(in_fifo.dout.data), in_fifo.re.eq(self._in_next.re | wb_in_next), in_fifo.flush.eq(self._in_flush.re), out_fifo.din.time.eq(self._out_time.storage), out_fifo.din.addr.eq(self._out_addr.storage), out_fifo.din.data.eq(self._out_data.storage), out_fifo.we.eq(self._out_next.re | wb_out_next), out_fifo.flush.eq(self._out_flush.re), ] # din dout strobing self.comb += [ # TODO: 0 <= diff <= plausibility range out_request.eq(out_fifo.readable & self.ctrl.run & (self.ctrl.cycle == out_fifo.dout.time)), # ignore in_fifo.writable in_request.eq(~self.enc.n & self.ctrl.run), self.busy.eq(out_request | in_request), ] # to slaves addrs = [] datas = [] stbs = [] acks = [] for i, (slave, prefix, mask) in enumerate(slaves): prefix &= mask source = Source(slave_layout) sink = Sink(slave_layout) self.comb += [ source.connect(slave.dout), sink.connect(slave.din), ] sel = Signal() acks.append(sel & source.ack) addrs.append(prefix | (sink.payload.addr & (~mask & 0xffffffff))) datas.append(sink.payload.data) stbs.append(sink.stb) self.comb += [ sel.eq(out_fifo.dout.addr & mask == prefix), source.payload.addr.eq(out_fifo.dout.addr), source.payload.data.eq(out_fifo.dout.data), source.stb.eq(sel & out_request), sink.ack.eq((self.enc.o == i) & in_request), ] self.comb += out_fifo.re.eq(out_request & optree("|", acks)) # from slaves self.comb += [ self.enc.i.eq(Cat(stbs)), in_fifo.din.time.eq(self.ctrl.cycle), in_fifo.din.addr.eq(Array(addrs)[self.enc.o]), in_fifo.din.data.eq(Array(datas)[self.enc.o]), in_fifo.we.eq(in_request), ] # optional high throughput wishbone access if with_wishbone: self.comb += [ self._out_time.dat_w.eq(bus.dat_w), self._out_addr.dat_w.eq(bus.dat_w), self._out_data.dat_w.eq(bus.dat_w), If( bus.cyc & bus.stb, If( bus.we, Case( bus.adr[:4], { 0x5: wb_in_next.eq(1), 0x6: self._out_time.we.eq(1), 0x7: self._out_addr.we.eq(1), 0x8: self._out_data.we.eq(1), 0x9: wb_out_next.eq(1), }), ), Case( bus.adr[:4], { 0x0: bus.dat_r.eq(self.ctrl.cycle), 0x1: bus.dat_r.eq(self.ev.status.w), 0x2: bus.dat_r.eq(in_fifo.dout.time), 0x3: bus.dat_r.eq(in_fifo.dout.addr), 0x4: bus.dat_r.eq(in_fifo.dout.data), }), ) ] self.sync += bus.ack.eq(bus.cyc & bus.stb & ~bus.ack)
def __init__(self, depth): self._cfg = CSRStorage(1) debug_signals = 1 storage = Memory(8, depth) self.specials += storage wrport = storage.get_port(write_capable=True) self.specials += wrport rdport = storage.get_port(async_read=False) self.specials += rdport self.submodules.consumer = Consumer(rdport, depth) self.submodules.producer = Producer(wrport, depth, self.consumer.pos, self._cfg.storage[0]) self.sink = self.producer.ulpi_sink self.comb += self.consumer.sink.connect(self.producer.out_addr) self.source = self.consumer.source # Debug signals for state tracing if debug_signals: self._cons_lo = CSRStatus(8) self._cons_hi = CSRStatus(8) self._prod_lo = CSRStatus(8) self._prod_hi = CSRStatus(8) self._prod_hd_lo = CSRStatus(8) self._prod_hd_hi = CSRStatus(8) self._size_lo = CSRStatus(8) self._size_hi = CSRStatus(8) self._prod_state = CSRStatus(8) self._cons_status = CSRStatus(8) self._last_start_lo = CSRStatus(8) self._last_start_hi = CSRStatus(8) self._last_count_lo = CSRStatus(8) self._last_count_hi = CSRStatus(8) self._last_pw_lo = CSRStatus(8) self._last_pw_hi = CSRStatus(8) self.sync += [ self._cons_lo.status.eq(self.consumer.pos[:8]), self._cons_hi.status.eq(self.consumer.pos[8:]), self._prod_lo.status.eq(self.producer.produce_write.v[:8]), self._prod_hi.status.eq(self.producer.produce_write.v[8:]), self._prod_hd_lo.status.eq(self.producer.produce_header.v[:8]), self._prod_hd_hi.status.eq(self.producer.produce_header.v[8:]), self._size_lo.status.eq(self.producer.size.v[:8]), self._size_hi.status.eq(self.producer.size.v[8:]), self._cons_status.status[0].eq(self.consumer.busy), #self._prod_state.status.eq(self.producer.fsm.state), If( self.producer.out_addr.stb & self.producer.out_addr.ack, self._last_start_lo.status.eq( self.producer.out_addr.payload.start[:8]), self._last_start_hi.status.eq( self.producer.out_addr.payload.start[8:]), self._last_count_lo.status.eq( self.producer.out_addr.payload.count[:8]), self._last_count_hi.status.eq( self.producer.out_addr.payload.count[8:]), self._last_pw_lo.status.eq( self.producer.produce_write.v[:8]), self._last_pw_hi.status.eq( self.producer.produce_write.v[8:]), ) ]