def __init__(self, cfg): self.pads = pads = _sdpads() self.sink = sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint([("data", 8), ("status", 3)]) # # # cmdrfb_reset = Signal() self.submodules.cmdrfb = SDPHYRFB(pads.cmd.i, False) self.submodules.fifo = ClockDomainsRenamer({"write": "sd_fb", "read": "sd"})( stream.AsyncFIFO(self.cmdrfb.source.description, 4) ) self.comb += self.cmdrfb.source.connect(self.fifo.sink) ctimeout = Signal(32) cread = Signal(10) ctoread = Signal(10) cnt = Signal(8) self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM(reset_state="IDLE")) fsm.act("IDLE", If(sink.valid, NextValue(ctimeout, 0), NextValue(cread, 0), NextValue(ctoread, sink.data), NextState("CMD_READSTART") ).Else( cmdrfb_reset.eq(1), self.fifo.source.ready.eq(1), ) ) self.specials += MultiReg(cmdrfb_reset, self.cmdrfb.reset, "sd_fb") fsm.act("CMD_READSTART", pads.cmd.oe.eq(0), pads.clk.eq(1), NextValue(ctimeout, ctimeout + 1), If(self.fifo.source.valid, NextState("CMD_READ") ).Elif(ctimeout > cfg.cmdtimeout, NextState("TIMEOUT") ) ) fsm.act("CMD_READ", pads.cmd.oe.eq(0), pads.clk.eq(1), source.valid.eq(self.fifo.source.valid), source.data.eq(self.fifo.source.data), source.status.eq(SDCARD_STREAM_STATUS_OK), source.last.eq(cread == ctoread), self.fifo.source.ready.eq(source.ready), If(source.valid & source.ready, NextValue(cread, cread + 1), If(cread == ctoread, If(sink.last, NextState("CMD_CLK8") ).Else( sink.ready.eq(1), NextState("IDLE") ) ) ) ) fsm.act("CMD_CLK8", If(cnt < 7, NextValue(cnt, cnt + 1), pads.clk.eq(1) ).Else( NextValue(cnt, 0), sink.ready.eq(1), NextState("IDLE") ) ) fsm.act("TIMEOUT", source.valid.eq(1), source.data.eq(0), source.status.eq(SDCARD_STREAM_STATUS_TIMEOUT), source.last.eq(1), If(source.valid & source.ready, sink.ready.eq(1), NextState("IDLE") ) )
def __init__(self, hres=800, vres=600, with_csi_interpreter=True): self.enable = Signal(reset=1) self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.uart_sink = uart_sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint(video_data_layout) # # # csi_width = 8 if with_csi_interpreter else 0 # Font Mem. # --------- os.system("wget https://github.com/enjoy-digital/litex/files/6076336/ter-u16b.txt") # FIXME: Store Font in LiteX? os.system("mv ter-u16b.txt ter-u16b.bdf") font = import_bdf_font("ter-u16b.bdf") font_width = 8 font_heigth = 16 font_mem = Memory(width=8, depth=4096, init=font) font_rdport = font_mem.get_port(has_re=True) self.specials += font_mem, font_rdport # Terminal Mem. # ------------- term_colums = 128 # 80 rounded to next power of two. term_lines = math.floor(vres/font_heigth) term_depth = term_colums * term_lines term_init = [ord(c) for c in [" "]*term_colums*term_lines] term_mem = Memory(width=font_width + csi_width, depth=term_depth, init=term_init) term_wrport = term_mem.get_port(write_capable=True) term_rdport = term_mem.get_port(has_re=True) self.specials += term_mem, term_wrport, term_rdport # UART Terminal Fill. # ------------------- # Optional CSI Interpreter. if with_csi_interpreter: self.submodules.csi_interpreter = CSIInterpreter() self.comb += uart_sink.connect(self.csi_interpreter.sink) uart_sink = self.csi_interpreter.source self.comb += term_wrport.dat_w[font_width:].eq(self.csi_interpreter.color) self.submodules.uart_fifo = stream.SyncFIFO([("data", 8)], 8) self.comb += uart_sink.connect(self.uart_fifo.sink) uart_sink = self.uart_fifo.source # UART Reception and Terminal Fill. x_term = term_wrport.adr[:7] y_term = term_wrport.adr[7:] y_term_rollover = Signal() self.submodules.uart_fsm = uart_fsm = FSM(reset_state="RESET") uart_fsm.act("RESET", NextValue(x_term, 0), NextValue(y_term, 0), NextState("CLEAR-XY") ) uart_fsm.act("CLEAR-XY", term_wrport.we.eq(1), term_wrport.dat_w[:font_width].eq(ord(" ")), NextValue(x_term, x_term + 1), If(x_term == (term_colums - 1), NextValue(x_term, 0), NextValue(y_term, y_term + 1), If(y_term == (term_lines - 1), NextValue(y_term, 0), NextState("IDLE") ) ) ) uart_fsm.act("IDLE", If(uart_sink.valid, If(uart_sink.data == ord("\n"), uart_sink.ready.eq(1), # Ack sink. NextState("INCR-Y") ).Elif(uart_sink.data == ord("\r"), uart_sink.ready.eq(1), # Ack sink. NextState("RST-X") ).Else( NextState("WRITE") ) ) ) uart_fsm.act("WRITE", uart_sink.ready.eq(1), term_wrport.we.eq(1), term_wrport.dat_w[:font_width].eq(uart_sink.data), NextState("INCR-X") ) uart_fsm.act("RST-X", NextValue(x_term, 0), NextState("CLEAR-X") ) uart_fsm.act("INCR-X", NextValue(x_term, x_term + 1), NextState("IDLE"), If(x_term == (80 - 1), NextValue(x_term, 0), NextState("INCR-Y") ) ) uart_fsm.act("RST-Y", NextValue(y_term, 0), NextState("CLEAR-X") ) uart_fsm.act("INCR-Y", NextValue(y_term, y_term + 1), NextState("CLEAR-X"), If(y_term == (term_lines - 1), NextValue(y_term_rollover, 1), NextState("RST-Y") ) ) uart_fsm.act("CLEAR-X", NextValue(x_term, x_term + 1), term_wrport.we.eq(1), term_wrport.dat_w[:font_width].eq(ord(" ")), If(x_term == (term_colums - 1), NextValue(x_term, 0), NextState("IDLE") ) ) # Video Generation. # ----------------- ce = (vtg_sink.valid & vtg_sink.ready) # Timing delay line. latency = 2 timing_bufs = [stream.Buffer(video_timing_layout) for i in range(latency)] self.comb += vtg_sink.connect(timing_bufs[0].sink) for i in range(len(timing_bufs) - 1): self.comb += timing_bufs[i].source.connect(timing_bufs[i+1].sink) self.comb += timing_bufs[-1].source.connect(source, keep={"valid", "ready", "last", "de", "hsync", "vsync"}) self.submodules += timing_bufs # Compute X/Y position. x = vtg_sink.hcount[int(math.log2(font_width)):] y = vtg_sink.vcount[int(math.log2(font_heigth)):] y_rollover = Signal(8) self.comb += [ If(~y_term_rollover, y_rollover.eq(y) ).Else( # FIXME: Use Modulo. If((y + y_term + 1) >= term_lines, y_rollover.eq(y + y_term + 1 - term_lines) ).Else( y_rollover.eq(y + y_term + 1) ), ) ] # Get character from Terminal Mem. term_dat_r = Signal(font_width) self.comb += term_rdport.re.eq(ce) self.comb += term_rdport.adr.eq(x + y_rollover*term_colums) self.comb += [ term_dat_r.eq(term_rdport.dat_r[:font_width]), If((x >= 80) | (y >= term_lines), term_dat_r.eq(ord(" ")), # Out of range, generate space. ) ] # Translate character to video data through Font Mem. self.comb += font_rdport.re.eq(ce) self.comb += font_rdport.adr.eq(term_dat_r*font_heigth + timing_bufs[0].source.vcount[:4]) bit = Signal() cases = {} for i in range(font_width): cases[i] = [bit.eq(font_rdport.dat_r[font_width-1-i])] self.comb += Case(timing_bufs[1].source.hcount[:int(math.log2(font_width))], cases) # FIXME: Add Palette. self.comb += [ If(bit, Case(term_rdport.dat_r[font_width:], { 0: [Cat(source.r, source.g, source.b).eq(0xffffff)], 1: [Cat(source.r, source.g, source.b).eq(0x34e289)], }) ).Else( Cat(source.r, source.g, source.b).eq(0x000000), ) ]
def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) self.header = Signal(header.length * 8) # # # dw = len(sink.data) header_reg = Signal(header.length * 8, reset_less=True) header_words = (header.length * 8) // dw shift = Signal() counter = Signal(max=max(header_words, 2)) counter_reset = Signal() counter_ce = Signal() self.sync += \ If(counter_reset, counter.eq(0) ).Elif(counter_ce, counter.eq(counter + 1) ) if header_words == 1: self.sync += \ If(shift, header_reg.eq(sink.data) ) else: self.sync += \ If(shift, header_reg.eq(Cat(header_reg[dw:], sink.data)) ) self.comb += self.header.eq(header_reg) fsm = FSM(reset_state="IDLE") self.submodules += fsm if header_words == 1: idle_next_state = "COPY" else: idle_next_state = "RECEIVE_HEADER" fsm.act("IDLE", sink.ready.eq(1), counter_reset.eq(1), If(sink.valid, shift.eq(1), NextState(idle_next_state))) if header_words != 1: fsm.act( "RECEIVE_HEADER", sink.ready.eq(1), If(sink.valid, counter_ce.eq(1), shift.eq(1), If(counter == header_words - 2, NextState("COPY")))) no_payload = Signal() self.sync += \ If(fsm.before_entering("COPY"), no_payload.eq(sink.last) ) if hasattr(sink, "error"): self.comb += source.error.eq(sink.error) self.comb += [ source.last.eq(sink.last | no_payload), source.data.eq(sink.data), header.decode(self.header, source) ] fsm.act( "COPY", sink.ready.eq(source.ready), source.valid.eq(sink.valid | no_payload), If(source.valid & source.ready & source.last, NextState("IDLE")))
def __init__(self, dram_port, mode="rgb", fifo_depth=512): try: dw = modes_dw[mode] except: raise ValueError("Unsupported {} video mode".format(mode)) assert dram_port.dw >= dw assert dram_port.dw == 2**log2_int(dw, need_pow2=False) self.source = source = stream.Endpoint(video_out_layout(dw)) self.underflow_enable = CSRStorage() self.underflow_update = CSR() self.underflow_counter = CSRStatus(32) # # # cd = dram_port.cd self.submodules.initiator = initiator = Initiator(cd) self.submodules.timing = timing = ClockDomainsRenamer(cd)( TimingGenerator()) self.submodules.dma = dma = ClockDomainsRenamer(cd)(DMAReader( dram_port, fifo_depth)) # ctrl path self.comb += [ # dispatch initiator parameters to timing & dma timing.sink.valid.eq(initiator.source.valid), dma.sink.valid.eq(initiator.source.valid), initiator.source.ready.eq(timing.sink.ready), # combine timing and dma source.valid.eq(timing.source.valid & (~timing.source.de | dma.source.valid)), # flush dma/timing when disabled If(~initiator.source.valid, timing.source.ready.eq(1), dma.source.ready.eq(1)).Elif( source.valid & source.ready, timing.source.ready.eq(1), dma.source.ready.eq(timing.source.de | (mode == "raw"))) ] # data path self.comb += [ # dispatch initiator parameters to timing & dma initiator.source.connect( timing.sink, keep=list_signals(frame_parameter_layout)), initiator.source.connect(dma.sink, keep=list_signals(frame_dma_layout)), # combine timing and dma source.de.eq(timing.source.de), source.hsync.eq(timing.source.hsync), source.vsync.eq(timing.source.vsync), source.data.eq(dma.source.data) ] # underflow detection underflow_enable = Signal() underflow_update = Signal() underflow_counter = Signal(32) self.specials += MultiReg(self.underflow_enable.storage, underflow_enable) underflow_update_synchronizer = PulseSynchronizer("sys", cd) self.submodules += underflow_update_synchronizer self.comb += [ underflow_update_synchronizer.i.eq(self.underflow_update.re), underflow_update.eq(underflow_update_synchronizer.o) ] sync = getattr(self.sync, cd) sync += [ If(underflow_enable, If(~source.valid, underflow_counter.eq(underflow_counter + 1))).Else( underflow_counter.eq(0)), If(underflow_update, self.underflow_counter.status.eq(underflow_counter)) ]
def __init__(self, flash, clock_domain="sys", endianness="big", with_csr=True): self.source = source = stream.Endpoint(spi_core2phy_layout) self.sink = sink = stream.Endpoint(spi_phy2core_layout) self.bus = bus = wishbone.Interface() self.cs = cs = Signal() # Burst Control. burst_cs = Signal() burst_adr = Signal(len(bus.adr), reset_less=True) burst_timeout = WaitTimer(MMAP_DEFAULT_TIMEOUT) self.submodules += burst_timeout cmd_bits = 8 data_bits = 32 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._spi_dummy_bits = spi_dummy_bits = Signal(8) if with_csr: self.dummy_bits = dummy_bits = CSRStorage( 8, reset=self._default_dummy_bits) if clock_domain != "sys": self.specials += MultiReg(dummy_bits.storage, spi_dummy_bits, clock_domain) else: self.comb += spi_dummy_bits.eq(dummy_bits.storage) else: self.comb += spi_dummy_bits.eq(self._default_dummy_bits) dummy = Signal(data_bits, reset=0xdead) # FSM. self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", # Keep CS active after Burst for Timeout. burst_timeout.wait.eq(1), NextValue(burst_cs, burst_cs & ~burst_timeout.done), cs.eq(burst_cs), # On Bus Read access... If( bus.cyc & bus.stb & ~bus.we, # If CS is still active and Bus address matches previous Burst address: # Just continue the current Burst. If(burst_cs & (bus.adr == burst_adr), NextState("BURST-REQ") # Otherwise initialize a new Burst. ).Else(cs.eq(0), NextState("BURST-CMD")))) fsm.act( "BURST-CMD", cs.eq(1), source.valid.eq(1), source.data.eq(flash.read_opcode.code), # send command. source.len.eq(cmd_bits), source.width.eq(flash.cmd_width), source.mask.eq(cmd_oe_mask[flash.cmd_width]), NextValue(burst_adr, bus.adr), If( source.ready, NextState("CMD-RET"), )) fsm.act("CMD-RET", cs.eq(1), sink.ready.eq(1), If( sink.valid, NextState("BURST-ADDR"), )) fsm.act( "BURST-ADDR", cs.eq(1), source.valid.eq(1), source.width.eq(flash.addr_width), source.mask.eq(addr_oe_mask[flash.addr_width]), source.data.eq(Cat(Signal(2), bus.adr)), # send address. source.len.eq(flash.addr_bits), NextValue(burst_cs, 1), NextValue(burst_adr, bus.adr), If( source.ready, NextState("ADDR-RET"), )) fsm.act( "ADDR-RET", cs.eq(1), sink.ready.eq(1), If( sink.valid, If( spi_dummy_bits == 0, NextState("BURST-REQ"), ).Else(NextState("DUMMY"), ))) fsm.act("DUMMY", cs.eq(1), source.valid.eq(1), source.width.eq(flash.addr_width), source.mask.eq(addr_oe_mask[flash.addr_width]), source.data.eq(dummy), source.len.eq(spi_dummy_bits), If( source.ready, NextState("DUMMY-RET"), )) fsm.act("DUMMY-RET", cs.eq(1), sink.ready.eq(1), If( sink.valid, NextState("BURST-REQ"), )) fsm.act("BURST-REQ", cs.eq(1), source.valid.eq(1), source.last.eq(1), source.width.eq(flash.bus_width), source.len.eq(data_bits), source.mask.eq(0), If( source.ready, NextState("BURST-DAT"), )) fsm.act( "BURST-DAT", cs.eq(1), sink.ready.eq(1), bus.dat_r.eq({ "big": sink.data, "little": reverse_bytes(sink.data) }[endianness]), If( sink.valid, bus.ack.eq(1), NextValue(burst_adr, burst_adr + 1), NextState("IDLE"), ))
def __init__(self): self.sink = sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint([("data", 8)]) self.color = Record([("r", 8), ("g", 8), ("b", 8)]) self.color.r.reset = 0xff self.color.g.reset = 0xff self.color.b.reset = 0xff # # # csi_count = Signal(3) csi_bytes = Array([Signal(8) for _ in range(8)]) csi_final = Signal(8) self.submodules.fsm = fsm = FSM(reset_state="RECOPY") fsm.act("RECOPY", sink.connect(source), If(sink.valid & (sink.data == self.esc_start), source.valid.eq(0), sink.ready.eq(1), NextState("GET-CSI-START") ) ) fsm.act("GET-CSI-START", sink.ready.eq(1), If(sink.valid, If(sink.data == self.csi_start, NextValue(csi_count, 0), NextState("GET-CSI-PARAMETERS") ).Else( NextState("RECOPY") ) ) ) fsm.act("GET-CSI-PARAMETERS", If(sink.valid, If((sink.data >= self.csi_param_min) & (sink.data <= self.csi_param_max), sink.ready.eq(1), NextValue(csi_count, csi_count + 1), NextValue(csi_bytes[csi_count], sink.data), ).Else( NextState("GET-CSI-FINAL") ) ) ) fsm.act("GET-CSI-FINAL", sink.ready.eq(1), NextValue(csi_final, sink.data), NextState("DECODE-CSI") ) fsm.act("DECODE-CSI", If(csi_final == ord("m"), # FIXME: Write color in Terminal Mem. If((csi_bytes[0] == ord("9")) and (csi_bytes[1] == ord("2")), NextValue(self.color.r, 0x89), NextValue(self.color.g, 0xe2), NextValue(self.color.b, 0x34), ).Else( NextValue(self.color.r, self.color.r.reset), NextValue(self.color.g, self.color.g.reset), NextValue(self.color.b, self.color.b.reset), ), ), NextState("RECOPY") )
def __init__(self, data_width, depth): self.sink = sink = stream.Endpoint(core_layout(data_width)) self.enable = CSRStorage() self.done = CSRStatus() self.length = CSRStorage(bits_for(depth)) self.offset = CSRStorage(bits_for(depth)) self.mem_valid = CSRStatus() self.mem_data = CSRStatus(data_width) # # # # Control re-synchronization enable = Signal() enable_d = Signal() self.specials += MultiReg(self.enable.storage, enable, "scope") self.sync.scope += enable_d.eq(enable) length = Signal().like(self.length.storage) offset = Signal().like(self.offset.storage) self.specials += MultiReg(self.length.storage, length, "scope") self.specials += MultiReg(self.offset.storage, offset, "scope") # Status re-synchronization done = Signal() self.specials += MultiReg(done, self.done.status) # Memory mem = stream.SyncFIFO([("data", data_width)], depth, buffered=True) mem = ClockDomainsRenamer("scope")(mem) cdc = stream.AsyncFIFO([("data", data_width)], 4) cdc = ClockDomainsRenamer({"write": "scope", "read": "sys"})(cdc) self.submodules += mem, cdc # Flush mem_flush = WaitTimer(depth) mem_flush = ClockDomainsRenamer("scope")(mem_flush) self.submodules += mem_flush # FSM fsm = FSM(reset_state="IDLE") fsm = ClockDomainsRenamer("scope")(fsm) self.submodules += fsm fsm.act("IDLE", done.eq(1), If(enable & ~enable_d, NextState("FLUSH")), sink.ready.eq(1), mem.source.connect(cdc.sink)) fsm.act("FLUSH", sink.ready.eq(1), mem_flush.wait.eq(1), mem.source.ready.eq(1), If(mem_flush.done, NextState("WAIT"))) fsm.act("WAIT", sink.connect(mem.sink, omit={"hit"}), If(sink.valid & sink.hit, NextState("RUN")), mem.source.ready.eq(mem.level >= offset)) fsm.act("RUN", sink.connect(mem.sink, omit={"hit"}), If( mem.level >= length, NextState("IDLE"), )) # Memory read self.comb += [ self.mem_valid.status.eq(cdc.source.valid), cdc.source.ready.eq(self.mem_data.we | ~self.enable.storage), self.mem_data.status.eq(cdc.source.data) ]
def __init__(self, channel): self.decval = stream.Endpoint(terc4_layout) # decoded values output self.data_in = Record(channel_layout) # data input from chansync self.valid_in = Signal() # valid input from chansync &| # decode the data path ### NOTE NOTE NOTE THIS IS UNTESTED for i, t in enumerate(terc4_tokens): self.sync.pix += If(self.data_in.raw == t, self.decval.d.eq(i)) # decode the control signals if channel != 1: self.sync.pix += [ If( self.valid_in, If(self.data_in.raw == control_tokens[0], self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)).Elif( self.data_in.raw == control_tokens[1], self.decval.c.eq(1), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)).Elif( self.data_in.raw == control_tokens[2], self.decval.c.eq(2), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)). Elif(self.data_in.raw == control_tokens[3], self.decval.c.eq(3), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)).Elif( self.data_in.raw == data_gb_tokens[0], self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq(1), self.decval.vgb.eq(0), self.decval.c_valid.eq(0)).Elif( self.data_in.raw == video_gb_tokens[channel], self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(1), self.decval.c_valid.eq(0)).Else( self.decval.de.eq(1), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(0))).Else( self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(0)) ] else: # green channel is special self.sync.pix += [ If( self.valid_in, If(self.data_in.raw == control_tokens[0], self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)).Elif( self.data_in.raw == control_tokens[1], self.decval.c.eq(1), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)).Elif( self.data_in.raw == control_tokens[2], self.decval.c.eq(2), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)). Elif( self.data_in.raw == control_tokens[3], self.decval.c.eq(3), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(1)).Elif( self.data_in.raw == data_gb_tokens[0], self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq( 1), # green channel gb tokens are ambiguous self.decval.vgb.eq(1), self.decval.c_valid.eq(0)).Elif( self.data_in.raw == video_gb_tokens[channel], self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq( 1), #green channel gb tokens are ambiguous self.decval.vgb.eq(1), self.decval.c_valid.eq(0)).Else( self.decval.de.eq(1), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(0))).Else( self.decval.c.eq(0), self.decval.de.eq(0), self.decval.dgb.eq(0), self.decval.vgb.eq(0), self.decval.c_valid.eq(0)) ]
def __init__(self): self.enable = Signal(reset=1) self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.source = source = stream.Endpoint(video_data_layout) # # # enable = Signal() self.specials += MultiReg(self.enable, enable) # Control Path. pix = Signal(hbits) bar = Signal(3) fsm = FSM(reset_state="IDLE") fsm = ResetInserter()(fsm) self.submodules.fsm = fsm self.comb += fsm.reset.eq(~self.enable) fsm.act("IDLE", NextValue(pix, 0), NextValue(bar, 0), vtg_sink.ready.eq(1), If(vtg_sink.valid & vtg_sink.first & (vtg_sink.hcount == 0) & (vtg_sink.vcount == 0), vtg_sink.ready.eq(0), NextState("RUN") ) ) fsm.act("RUN", vtg_sink.connect(source, keep={"valid", "ready", "last", "de", "hsync", "vsync"}), If(source.valid & source.ready & source.de, NextValue(pix, pix + 1), If(pix == (vtg_sink.hres[3:] -1), # 8 Color Bars. NextValue(pix, 0), NextValue(bar, bar + 1) ) ).Else( NextValue(pix, 0), NextValue(bar, 0) ) ) # Data Path. color_bar = [ # R G B [0xff, 0xff, 0xff], # White [0xff, 0xff, 0x00], # Yellow [0x00, 0xff, 0xff], # Cyan [0x00, 0xff, 0x00], # Green [0xff, 0x00, 0xff], # Purple [0xff, 0x00, 0x00], # Red [0x00, 0x00, 0xff], # Blue [0x00, 0x00, 0x00], # Black ] cases = {} for i in range(8): cases[i] = [ source.r.eq(color_bar[i][0]), source.g.eq(color_bar[i][1]), source.b.eq(color_bar[i][2]) ] self.comb += Case(bar, cases)
def __init__(self, ordered_set, n_ordered_sets=1): self.sink = stream.Endpoint([("data", 32), ("ctrl", 4)]) self.detected = Signal() # o self.error = Signal() # o self.reset = Signal() # o self.loopback = Signal() # o self.scrambling = Signal(reset=1) # o # # # self.comb += self.sink.ready.eq(1) # Memory ----------------------------------------------------------------------------------- mem_depth = len(ordered_set.to_bytes()) // 4 mem_init = [ int.from_bytes(ordered_set.to_bytes()[4 * i:4 * (i + 1)], "little") for i in range(mem_depth) ] mem = Memory(32, mem_depth, mem_init) port = mem.get_port(async_read=True) self.specials += mem, port # Data check ------------------------------------------------------------------------------- error = Signal() error_mask = Signal(32, reset=2**32 - 1) first_ctrl = 0b1111 self.comb += If(port.adr == 1, error_mask.eq(0xffff00ff)) self.comb += [ If( self.sink.valid, # Check Comma If((port.adr == 0) & (self.sink.ctrl != first_ctrl), error.eq(1)), If((port.adr != 0) & (self.sink.ctrl != 0), error.eq(1)), # Check Word If((self.sink.data & error_mask) != (port.dat_r & error_mask), error.eq(1))), self.error.eq(error) ] # Link Config ------------------------------------------------------------------------------ self.sync += [ If(self.sink.valid & (port.adr == 1), self.reset.eq(self.sink.data[8]), self.loopback.eq(self.sink.data[10]), self.scrambling.eq(~self.sink.data[11])) ] # Memory address generation ---------------------------------------------------------------- self.sync += [ If( self.sink.valid, If( ~error, If(port.adr == (mem_depth - 1), port.adr.eq(0)).Else( port.adr.eq(port.adr + 1))).Else(port.adr.eq(0))) ] # Count ------------------------------------------------------------------------------------ count = Signal(max=mem_depth * n_ordered_sets) count_done = (count == (mem_depth * n_ordered_sets - 1)) self.sync += [ If(self.sink.valid, If(~error & ~count_done, count.eq(count + 1)).Else(count.eq(0))) ] # Result ----------------------------------------------------------------------------------- self.comb += self.detected.eq(self.sink.valid & count_done)
def __init__(self, dram_port, nslots): bus_aw = dram_port.aw bus_dw = dram_port.dw alignment_bits = bits_for(bus_dw // 8) - 1 fifo_word_width = bus_dw self.frame = stream.Endpoint([("sof", 1), ("pixels", fifo_word_width)]) self._frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits) self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits) self.ev = self._slot_array.ev # # # # address generator + maximum memory word count to prevent DMA buffer # overrun reset_words = Signal() count_word = Signal() last_word = Signal() self.current_address = current_address = Signal(bus_aw) mwords_remaining = Signal(bus_aw) self.comb += [ self._slot_array.address_reached.eq(current_address), last_word.eq(mwords_remaining == 1) ] self.sync += [ If(reset_words, current_address.eq(self._slot_array.address), mwords_remaining.eq(self._frame_size.storage)).Elif( count_word, current_address.eq(current_address + 1), mwords_remaining.eq(mwords_remaining - 1)) ] memory_word = Signal(bus_dw) pixbits = [] for i in range(bus_dw // 16): pixbits.append(self.frame.pixels) self.comb += memory_word.eq(Cat(*pixbits)) # bus accessor self.submodules._bus_accessor = LiteDRAMDMAWriter(dram_port) self.comb += [ self._bus_accessor.sink.address.eq(current_address), self._bus_accessor.sink.data.eq(memory_word) ] # control FSM fsm = FSM() self.submodules += fsm fsm.act( "WAIT_SOF", reset_words.eq(1), self.frame.ready.eq(~self._slot_array.address_valid | ~self.frame.sof), If( self._slot_array.address_valid & self.frame.sof & self.frame.valid, NextState("TRANSFER_PIXELS"))) fsm.act( "TRANSFER_PIXELS", self.frame.ready.eq(self._bus_accessor.sink.ready), If( self.frame.valid, self._bus_accessor.sink.valid.eq(1), If(self._bus_accessor.sink.ready, count_word.eq(1), If(last_word, NextState("EOF"))))) fsm.act( "EOF", If(~dram_port.wdata.valid, self._slot_array.address_done.eq(1), NextState("WAIT_SOF")))
def __init__(self, ordered_set, n_ordered_sets=1): self.start = Signal() # i self.done = Signal() # o self.source = stream.Endpoint([("data", 32), ("ctrl", 4)]) if ordered_set.name in ["TS1", "TS2"]: self.reset = Signal() # i self.loopback = Signal() # i self.scrambling = Signal(reset=1) # i # # # run = Signal() # Memory -------------------------------------------------------------------------------- mem_depth = len(ordered_set.to_bytes()) // 4 mem_init = [ int.from_bytes(ordered_set.to_bytes()[4 * i:4 * (i + 1)], "little") for i in range(mem_depth) ] mem = Memory(32, mem_depth, mem_init) port = mem.get_port(async_read=True) self.specials += mem, port # Memory address generation ---------------------------------------------------------------- self.sync += [ If( self.source.valid, If( self.source.ready, If(port.adr == (mem_depth - 1), port.adr.eq(0)).Else( port.adr.eq(port.adr + 1)))).Else(port.adr.eq(0)) ] # Link Config ------------------------------------------------------------------------------ link_config = Signal(8) if ordered_set.name in ["TS1", "TS2"]: self.comb += [ link_config[0].eq(self.reset), link_config[2].eq(self.loopback), link_config[3].eq(~self.scrambling) ] # Data generation -------------------------------------------------------------------------- if ordered_set.name in ["TS1", "TS2"]: first_ctrl = 0b1111 else: first_ctrl = 0b0001 self.comb += [ self.source.valid.eq(self.start | run), If( port.adr == 0, self.source.ctrl.eq(first_ctrl), ).Else(self.source.ctrl.eq(0)), self.source.data.eq(port.dat_r) ] if ordered_set.name in ["TS1", "TS2"]: self.comb += If(port.adr == 1, self.source.data[8:16].eq(link_config)) # Count ------------------------------------------------------------------------------------ count = Signal(max=mem_depth * n_ordered_sets) count_done = (count == (mem_depth * n_ordered_sets - 1)) self.sync += [ If( run, If(self.source.ready, count.eq(count + 1), If(count_done, run.eq(0), count.eq(0)))).Elif( self.start, If(self.source.ready, run.eq(1), count.eq(1))) ] # Delimiters ------------------------------------------------------------------------------- self.comb += [ self.source.first.eq(count == 0), self.source.last.eq(count_done), ] # Result ----------------------------------------------------------------------------------- self.comb += self.done.eq(self.source.ready & run & count_done)
def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) self.header = Signal(header.length * 8) # # # # Parameters. data_width = len(sink.data) bytes_per_clk = data_width // 8 header_words = (header.length * 8) // data_width header_leftover = header.length % bytes_per_clk aligned = header_leftover == 0 # Signals. sr = Signal(header.length * 8, reset_less=True) sr_shift = Signal() sr_shift_leftover = Signal() count = Signal(max=max(header_words, 2)) sink_d = stream.Endpoint(sink_description) # Header Shift/Decode. if (header_words) == 1 and (header_leftover == 0): self.sync += If(sr_shift, sr.eq(sink.data)) else: self.sync += [ If(sr_shift, sr.eq(Cat(sr[bytes_per_clk * 8:], sink.data))), If(sr_shift_leftover, sr.eq(Cat(sr[header_leftover * 8:], sink.data))) ] self.comb += self.header.eq(sr) self.comb += header.decode(self.header, source) # FSM. self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm_from_idle = Signal() fsm.act( "IDLE", sink.ready.eq(1), NextValue(count, 1), If( sink.valid, sr_shift.eq(1), NextValue(fsm_from_idle, 1), If( header_words == 1, NextState("ALIGNED-DATA-COPY" if aligned else "UNALIGNED-DATA-COPY"), ).Else(NextState("HEADER-RECEIVE")))) fsm.act( "HEADER-RECEIVE", sink.ready.eq(1), If( sink.valid, NextValue(count, count + 1), sr_shift.eq(1), If( count == (header_words - 1), NextState("ALIGNED-DATA-COPY" if aligned else "UNALIGNED-DATA-COPY"), NextValue(count, count + 1), ))) fsm.act( "ALIGNED-DATA-COPY", source.valid.eq(sink.valid | sink_d.last), source.last.eq(sink.last | sink_d.last), sink.ready.eq(source.ready), source.data.eq(sink.data), If(source.valid & source.ready, If(source.last, NextState("IDLE")))) if not aligned: self.sync += If(sink.valid & sink.ready, sink_d.eq(sink)) fsm.act( "UNALIGNED-DATA-COPY", source.valid.eq(sink.valid | sink_d.last), source.last.eq(sink.last | sink_d.last), sink.ready.eq(source.ready), source.data.eq(sink_d.data[header_leftover * 8:]), source.data[min((bytes_per_clk - header_leftover) * 8, data_width - 1):].eq(sink.data), If( fsm_from_idle, source.valid.eq(sink_d.last), sink.ready.eq(1), If( sink.valid, NextValue(fsm_from_idle, 0), sr_shift_leftover.eq(1), )), If(source.valid & source.ready, If(source.last, NextState("IDLE")))) # Error. if hasattr(sink, "error") and hasattr(source, "error"): self.comb += source.error.eq(sink.error) # Last BE. if hasattr(sink, "last_be") and hasattr(source, "last_be"): x = [ sink.last_be[(i - (bytes_per_clk - header_leftover)) % bytes_per_clk] for i in range(bytes_per_clk) ] self.comb += source.last_be.eq(Cat(*x))
def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) self.header = Signal(header.length * 8) # # # # Parameters. data_width = len(self.sink.data) bytes_per_clk = data_width // 8 header_words = (header.length * 8) // data_width header_leftover = header.length % bytes_per_clk aligned = header_leftover == 0 # Signals. sr = Signal(header.length * 8, reset_less=True) sr_load = Signal() sr_shift = Signal() count = Signal(max=max(header_words, 2)) sink_d = stream.Endpoint(sink_description) # Header Encode/Load/Shift. self.comb += header.encode(sink, self.header) self.sync += If(sr_load, sr.eq(self.header)) if header_words != 1: self.sync += If(sr_shift, sr.eq(sr[data_width:])) # Last BE. last_be = Signal(data_width // 8) last_be_d = Signal(data_width // 8) if hasattr(sink, "last_be") and hasattr(source, "last_be"): rotate_by = header.length % bytes_per_clk x = [ sink.last_be[(i + rotate_by) % bytes_per_clk] for i in range(bytes_per_clk) ] self.comb += last_be.eq(Cat(*x)) self.sync += last_be_d.eq(last_be) # FSM. self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm_from_idle = Signal() fsm.act( "IDLE", sink.ready.eq(1), NextValue(count, 1), If( sink.valid, sink.ready.eq(0), source.valid.eq(1), source.last.eq(0), source.data.eq(self.header[:data_width]), If( source.valid & source.ready, sr_load.eq(1), NextValue(fsm_from_idle, 1), If( header_words == 1, NextState("ALIGNED-DATA-COPY" if aligned else "UNALIGNED-DATA-COPY")).Else( NextState("HEADER-SEND"))))) fsm.act( "HEADER-SEND", source.valid.eq(1), source.last.eq(0), source.data.eq(sr[min(data_width, len(sr) - 1):]), If( source.valid & source.ready, sr_shift.eq(1), If( count == (header_words - 1), sr_shift.eq(0), NextState("ALIGNED-DATA-COPY" if aligned else "UNALIGNED-DATA-COPY"), NextValue(count, count + 1)).Else(NextValue(count, count + 1), ))) source_last_be = getattr(source, "last_be", Signal()) fsm.act( "ALIGNED-DATA-COPY", source.valid.eq(sink.valid), source.last.eq(sink.last), source_last_be.eq(last_be), source.data.eq(sink.data), If(source.valid & source.ready, sink.ready.eq(1), If(source.last, NextState("IDLE")))) if not aligned: header_offset_multiplier = 1 if header_words == 1 else 2 self.sync += If(source.ready, sink_d.eq(sink)) fsm.act( "UNALIGNED-DATA-COPY", source.valid.eq(sink.valid | sink_d.last), source.last.eq(sink_d.last), source_last_be.eq(last_be_d), If( fsm_from_idle, source.data[:max(header_leftover * 8, 1)].eq( sr[min(header_offset_multiplier * data_width, len(sr) - 1):] )).Else(source.data[:max(header_leftover * 8, 1)].eq( sink_d.data[min((bytes_per_clk - header_leftover) * 8, data_width - 1):])), source.data[header_leftover * 8:].eq(sink.data), If(source.valid & source.ready, sink.ready.eq(~source.last), NextValue(fsm_from_idle, 0), If(source.last, NextState("IDLE")))) # Error. if hasattr(sink, "error") and hasattr(source, "error"): self.comb += source.error.eq(sink.error)
def __init__(self, n, aw, address_align, settings): self.req = req = Record(cmd_layout(aw)) self.refresh_req = Signal() self.refresh_gnt = Signal() a = settings.geom.addressbits ba = settings.geom.bankbits self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba)) # # # # Command buffer cmd_buffer_layout = [("we", 1), ("adr", len(req.adr))] cmd_buffer = stream.SyncFIFO(cmd_buffer_layout, settings.cmd_buffer_depth) self.submodules += cmd_buffer self.comb += [ req.connect(cmd_buffer.sink, omit=["wdata_valid", "wdata_ready", "rdata_valid", "rdata_ready", "lock"]), cmd_buffer.source.ready.eq(req.wdata_ready | req.rdata_valid), req.lock.eq(cmd_buffer.source.valid), ] slicer = _AddressSlicer(settings.geom.colbits, address_align) # Row tracking has_openrow = Signal() openrow = Signal(settings.geom.rowbits, reset_less=True) hit = Signal() self.comb += hit.eq(openrow == slicer.row(cmd_buffer.source.adr)) track_open = Signal() track_close = Signal() self.sync += \ If(track_close, has_openrow.eq(0) ).Elif(track_open, has_openrow.eq(1), openrow.eq(slicer.row(cmd_buffer.source.adr)) ) # Four Activate Window activate = Signal() activate_allowed = Signal(reset=1) tfaw = settings.timing.tFAW if tfaw is not None: activate_count = Signal(max=tfaw) activate_window = Signal(tfaw) self.sync += activate_window.eq(Cat(activate, activate_window)) for i in range(tfaw): next_activate_count = Signal(max=tfaw) self.comb += next_activate_count.eq(activate_count + activate_window[i]) activate_count = next_activate_count self.comb += If(activate_count >=4, activate_allowed.eq(0)) # CAS to CAS cas = Signal() cas_allowed = Signal(reset=1) tccd = settings.timing.tCCD if tccd is not None: cas_count = Signal(max=tccd+1) self.sync += \ If(cas, cas_count.eq(tccd-1) ).Elif(~cas_allowed, cas_count.eq(cas_count-1) ) self.comb += cas_allowed.eq(cas_count == 0) # Address generation sel_row_adr = Signal() self.comb += [ cmd.ba.eq(n), If(sel_row_adr, cmd.a.eq(slicer.row(cmd_buffer.source.adr)) ).Else( cmd.a.eq(slicer.col(cmd_buffer.source.adr)) ) ] # Respect write-to-precharge specification precharge_time = 2 + settings.timing.tWR - 1 + 1 self.submodules.precharge_timer = WaitTimer(precharge_time) self.comb += self.precharge_timer.wait.eq(~(cmd.valid & cmd.ready & cmd.is_write)) # Control and command generation FSM self.submodules.fsm = fsm = FSM() fsm.act("REGULAR", If(self.refresh_req, NextState("REFRESH") ).Elif(cmd_buffer.source.valid, If(has_openrow, If(hit, If(cas_allowed, cas.eq(1), # Note: write-to-read specification is enforced by # multiplexer cmd.valid.eq(1), If(cmd_buffer.source.we, req.wdata_ready.eq(cmd.ready), cmd.is_write.eq(1), cmd.we.eq(1), ).Else( req.rdata_valid.eq(cmd.ready), cmd.is_read.eq(1) ), cmd.cas.eq(1) ) ).Else( NextState("PRECHARGE") ) ).Else( If(activate_allowed, NextState("ACTIVATE") ) ) ) ) fsm.act("PRECHARGE", # Note: we are presenting the column address, A10 is always low If(self.precharge_timer.done, cmd.valid.eq(1), If(cmd.ready, NextState("TRP") ), cmd.ras.eq(1), cmd.we.eq(1), cmd.is_cmd.eq(1) ), track_close.eq(1) ) fsm.act("ACTIVATE", activate.eq(1), sel_row_adr.eq(1), track_open.eq(1), cmd.valid.eq(1), cmd.is_cmd.eq(1), If(cmd.ready, NextState("TRCD") ), cmd.ras.eq(1) ) fsm.act("REFRESH", If(self.precharge_timer.done, self.refresh_gnt.eq(1), ), track_close.eq(1), cmd.is_cmd.eq(1), If(~self.refresh_req, NextState("REGULAR") ) ) fsm.delayed_enter("TRP", "ACTIVATE", settings.timing.tRP-1) fsm.delayed_enter("TRCD", "REGULAR", settings.timing.tRCD-1)
def __init__(self, enable=True): self.sink = sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint([("data", 8)]) self.color = Signal(4) self.clear_xy = Signal() # # # if not enable: self.comb += self.sink.connect(self.source) return csi_count = Signal(3) csi_bytes = Array([Signal(8) for _ in range(8)]) csi_final = Signal(8) self.submodules.fsm = fsm = FSM(reset_state="RECOPY") fsm.act("RECOPY", sink.connect(source), If(sink.valid & (sink.data == self.esc_start), source.valid.eq(0), sink.ready.eq(1), NextState("GET-CSI-START") ) ) fsm.act("GET-CSI-START", sink.ready.eq(1), If(sink.valid, If(sink.data == self.csi_start, NextValue(csi_count, 0), NextState("GET-CSI-PARAMETERS") ).Else( NextState("RECOPY") ) ) ) fsm.act("GET-CSI-PARAMETERS", If(sink.valid, If((sink.data >= self.csi_param_min) & (sink.data <= self.csi_param_max), sink.ready.eq(1), NextValue(csi_count, csi_count + 1), NextValue(csi_bytes[csi_count], sink.data), ).Else( NextState("GET-CSI-FINAL") ) ) ) fsm.act("GET-CSI-FINAL", sink.ready.eq(1), NextValue(csi_final, sink.data), NextState("DECODE-CSI") ) fsm.act("DECODE-CSI", If(csi_final == ord("m"), If((csi_bytes[0] == ord("9")) and (csi_bytes[1] == ord("2")), NextValue(self.color, 1), # FIXME: Add Palette. ).Else( NextValue(self.color, 0), # FIXME: Add Palette. ), ), If(csi_final == ord("A"), # FIXME: Move Up. self.clear_xy.eq(1) ), NextState("RECOPY") )
def __init__(self, default_video_timings="800x600@60Hz"): vt = video_timings[default_video_timings] # MMAP Control/Status Registers. self._enable = CSRStorage(reset=1) self._hres = CSRStorage(hbits, vt["h_active"]) self._hsync_start = CSRStorage(hbits, vt["h_active"] + vt["h_sync_offset"]) self._hsync_end = CSRStorage(hbits, vt["h_active"] + vt["h_sync_offset"] + vt["h_sync_width"]) self._hscan = CSRStorage(hbits, vt["h_active"] + vt["h_blanking"]) self._vres = CSRStorage(vbits, vt["v_active"]) self._vsync_start = CSRStorage(vbits, vt["v_active"] + vt["v_sync_offset"]) self._vsync_end = CSRStorage(vbits, vt["v_active"] + vt["v_sync_offset"] + vt["v_sync_width"]) self._vscan = CSRStorage(vbits, vt["v_active"] + vt["v_blanking"]) # Video Timing Source self.source = source = stream.Endpoint(video_timing_layout) # # # # Resynchronize Enable to Video clock domain. self.enable = enable = Signal() self.specials += MultiReg(self._enable.storage, enable) # Resynchronize Horizontal Timings to Video clock domain. self.hres = hres = Signal(hbits) self.hsync_start = hsync_start = Signal(hbits) self.hsync_end = hsync_end = Signal(hbits) self.hscan = hscan = Signal(hbits) self.specials += MultiReg(self._hres.storage, hres) self.specials += MultiReg(self._hsync_start.storage, hsync_start) self.specials += MultiReg(self._hsync_end.storage, hsync_end) self.specials += MultiReg(self._hscan.storage, hscan) # Resynchronize Vertical Timings to Video clock domain. self.vres = vres = Signal(vbits) self.vsync_start = vsync_start = Signal(vbits) self.vsync_end = vsync_end = Signal(vbits) self.vscan = vscan = Signal(vbits) self.specials += MultiReg(self._vres.storage, vres) self.specials += MultiReg(self._vsync_start.storage, vsync_start) self.specials += MultiReg(self._vsync_end.storage, vsync_end) self.specials += MultiReg(self._vscan.storage, vscan) # Generate timings. hactive = Signal() vactive = Signal() self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(hactive, 0), NextValue(vactive, 0), NextValue(source.hres, hres), NextValue(source.vres, vres), NextValue(source.hcount, 0), NextValue(source.vcount, 0), If(enable, NextState("RUN") ) ) self.comb += source.de.eq(hactive & vactive) # DE when both HActive and VActive. self.sync += source.first.eq((source.hcount == 0) & (source.vcount == 0)), self.sync += source.last.eq( (source.hcount == hscan) & (source.vcount == vscan)), fsm.act("RUN", source.valid.eq(1), If(source.ready, # Increment HCount. NextValue(source.hcount, source.hcount + 1), # Generate HActive / HSync. If(source.hcount == 0, NextValue(hactive, 1)), # Start of HActive. If(source.hcount == hres, NextValue(hactive, 0)), # End of HActive. If(source.hcount == hsync_start, NextValue(source.hsync, 1)), # Start of HSync. If(source.hcount == hsync_end, NextValue(source.hsync, 0)), # End of HSync. # End of HScan. If(source.hcount == hscan, # Reset HCount. NextValue(source.hcount, 0), # Increment VCount. NextValue(source.vcount, source.vcount + 1), # Generate VActive / VSync. If(source.vcount == 0, NextValue(vactive, 1)), # Start of VActive. If(source.vcount == vres, NextValue(vactive, 0)), # End of HActive. If(source.vcount == vsync_start, NextValue(source.vsync, 1)), # Start of VSync. If(source.vcount == vsync_end, NextValue(source.vsync, 0)), # End of VSync. # End of VScan. If(source.vcount == vscan, # Reset VCount. NextValue(source.vcount, 0), ) ) ) )
def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False, format="rgb888"): self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.source = source = stream.Endpoint(video_data_layout) self.underflow = Signal() self.depth = depth = { "rgb888" : 32, "rgb565" : 16 }[format] # # # # Video DMA. from litedram.frontend.dma import LiteDRAMDMAReader self.submodules.dma = LiteDRAMDMAReader(dram_port, fifo_depth=fifo_depth//(dram_port.data_width//8), fifo_buffered=True) self.dma.add_csr( default_base = base, default_length = hres*vres*depth//8, # 32-bit RGB-888 or 16-bit RGB-565 default_enable = 0, default_loop = 1 ) # If DRAM Data Width > depth and Video clock is faster than sys_clk: if (dram_port.data_width > depth) and clock_faster_than_sys: # Do Clock Domain Crossing first... self.submodules.cdc = stream.ClockDomainCrossing([("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain) self.comb += self.dma.source.connect(self.cdc.sink) # ... and then Data-Width Conversion. self.submodules.conv = ClockDomainsRenamer(clock_domain)(stream.Converter(dram_port.data_width, depth)) self.comb += self.cdc.source.connect(self.conv.sink) video_pipe_source = self.conv.source # Elsif DRAM Data Width <= depth or Video clock is slower than sys_clk: else: # Do Data-Width Conversion first... self.submodules.conv = stream.Converter(dram_port.data_width, depth) self.comb += self.dma.source.connect(self.conv.sink) # ... and then Clock Domain Crossing. self.submodules.cdc = stream.ClockDomainCrossing([("data", depth)], cd_from="sys", cd_to=clock_domain) self.comb += self.conv.source.connect(self.cdc.sink) if (dram_port.data_width < depth) and (depth == 32): # FIXME. self.comb += [ self.cdc.sink.data[ 0: 8].eq(self.conv.source.data[16:24]), self.cdc.sink.data[16:24].eq(self.conv.source.data[ 0: 8]), ] video_pipe_source = self.cdc.source # Video Generation. self.comb += [ vtg_sink.ready.eq(1), If(vtg_sink.valid & vtg_sink.de, video_pipe_source.connect(source, keep={"valid", "ready"}), vtg_sink.ready.eq(source.valid & source.ready), ), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), ] if (depth == 32): self.comb += [ source.r.eq(video_pipe_source.data[16:24]), source.g.eq(video_pipe_source.data[ 8:16]), source.b.eq(video_pipe_source.data[ 0: 8]), ] else: # depth == 16 self.comb += [ source.r.eq(Cat(Signal(3, reset = 0), video_pipe_source.data[ 0: 5])), source.g.eq(Cat(Signal(2, reset = 0), video_pipe_source.data[ 5:11])), source.b.eq(Cat(Signal(3, reset = 0), video_pipe_source.data[11:16])), ] # Underflow. self.comb += self.underflow.eq(~source.valid)
def __init__(self, axi, axi_lite): assert axi.data_width == axi_lite.data_width assert axi.address_width == axi_lite.address_width ax_buffer = stream.Buffer( ax_description(axi.address_width, axi.id_width)) ax_burst = stream.Endpoint( ax_description(axi.address_width, axi.id_width)) ax_beat = stream.Endpoint( ax_description(axi.address_width, axi.id_width)) self.comb += ax_burst.connect(ax_buffer.sink) ax_burst2beat = AXIBurst2Beat(ax_buffer.source, ax_beat) self.submodules += ax_buffer, ax_burst2beat _data = Signal(axi.data_width) _cmd_done = Signal() _last_ar_aw_n = Signal() self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", NextValue(_cmd_done, 0), If( axi.ar.valid & axi.aw.valid, # If last access was a read, do a write If(_last_ar_aw_n, axi.aw.connect(ax_burst), NextValue(_last_ar_aw_n, 0), NextState("WRITE") # If last access was a write, do a read ).Else( axi.ar.connect(ax_burst), NextValue(_last_ar_aw_n, 1), NextState("READ"), )).Elif( axi.ar.valid, axi.ar.connect(ax_burst), NextValue(_last_ar_aw_n, 1), NextState("READ"), ).Elif(axi.aw.valid, axi.aw.connect(ax_burst), NextValue(_last_ar_aw_n, 0), NextState("WRITE"))) fsm.act( "READ", # ar (read command) axi_lite.ar.valid.eq(ax_beat.valid & ~_cmd_done), axi_lite.ar.addr.eq(ax_beat.addr), ax_beat.ready.eq(axi_lite.ar.ready & ~_cmd_done), If( ax_beat.valid & ax_beat.last, If(axi_lite.ar.ready, ax_beat.ready.eq(0), NextValue(_cmd_done, 1))), # r (read data & response) axi.r.valid.eq(axi_lite.r.valid), axi.r.last.eq(_cmd_done), axi.r.resp.eq(RESP_OKAY), axi.r.id.eq(ax_beat.id), axi.r.data.eq(axi_lite.r.data), axi_lite.r.ready.eq(axi.r.ready), # Exit If(axi.r.valid & axi.r.last & axi.r.ready, ax_beat.ready.eq(1), NextState("IDLE"))) # Always accept write responses. self.comb += axi_lite.b.ready.eq(1) fsm.act( "WRITE", # aw (write command) axi_lite.aw.valid.eq(ax_beat.valid & ~_cmd_done), axi_lite.aw.addr.eq(ax_beat.addr), ax_beat.ready.eq(axi_lite.aw.ready & ~_cmd_done), If( ax_beat.valid & ax_beat.last, If(axi_lite.aw.ready, ax_beat.ready.eq(0), NextValue(_cmd_done, 1))), # w (write data) axi_lite.w.valid.eq(axi.w.valid), axi_lite.w.data.eq(axi.w.data), axi_lite.w.strb.eq(axi.w.strb), axi.w.ready.eq(axi_lite.w.ready), # Exit If(axi.w.valid & axi.w.last & axi.w.ready, NextState("WRITE-RESP"))) fsm.act("WRITE-RESP", axi.b.valid.eq(1), axi.b.resp.eq(RESP_OKAY), axi.b.id.eq(ax_beat.id), If(axi.b.ready, ax_beat.ready.eq(1), NextState("IDLE")))
def __init__(self): self.pads = pads = _sdpads() self.sink = sink = stream.Endpoint([("data", 8)]) # # # isinit = Signal() cntinit = Signal(8) cnt = Signal(8) wrsel = Signal(3) wrtmpdata = Signal(8) wrcases = {} # For command write for i in range(8): wrcases[i] = pads.cmd.o.eq(wrtmpdata[7-i]) self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM(reset_state="IDLE")) fsm.act("IDLE", If(sink.valid, If(~isinit, NextState("INIT") ).Else( pads.clk.eq(1), pads.cmd.o.eq(sink.data[7]), NextValue(wrtmpdata, sink.data), NextValue(wrsel, 1), NextState("CMD_WRITE") ) ) ) fsm.act("INIT", # Initialize sdcard with 80 clock cycles pads.clk.eq(1), If(cntinit < 80, NextValue(cntinit, cntinit + 1), NextValue(pads.data.oe, 1), NextValue(pads.data.o, 0xf) ).Else( NextValue(cntinit, 0), NextValue(isinit, 1), NextValue(pads.data.oe, 0), NextState("IDLE") ) ) fsm.act("CMD_WRITE", Case(wrsel, wrcases), NextValue(wrsel, wrsel + 1), If(wrsel == 0, If(sink.last, pads.clk.eq(1), NextState("CMD_CLK8") ).Else( sink.ready.eq(1), NextState("IDLE") ) ).Else( pads.clk.eq(1) ) ) fsm.act("CMD_CLK8", If(cnt < 7, NextValue(cnt, cnt + 1), pads.clk.eq(1) ).Else( NextValue(cnt, 0), sink.ready.eq(1), NextState("IDLE") ) )
def __init__(self): self.sink = stream.Endpoint([("data", 8)]) self.source = stream.Endpoint([("data", 8)])
def __init__(self, cfg): self.pads = pads = _sdpads() self.sink = sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint([("data", 8), ("status", 3)]) # # # datarfb_reset = Signal() self.submodules.datarfb = SDPHYRFB(pads.data.i, True) self.submodules.cdc = ClockDomainsRenamer({"write": "sd_fb", "read": "sd"})( stream.AsyncFIFO(self.datarfb.source.description, 4) ) self.submodules.buffer = ClockDomainsRenamer("sd")(stream.Buffer(self.datarfb.source.description)) self.comb += self.datarfb.source.connect(self.buffer.sink) dtimeout = Signal(32) read = Signal(10) toread = Signal(10) cnt = Signal(8) self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM(reset_state="IDLE")) fsm.act("IDLE", pads.data.oe.eq(0), pads.clk.eq(1), datarfb_reset.eq(1), self.buffer.source.ready.eq(1), If(sink.valid, NextValue(dtimeout, 0), NextValue(read, 0), # Read 1 block + 8*8 == 64 bits CRC NextValue(toread, cfg.blocksize + 8), NextState("DATA_READSTART") ) ) self.specials += MultiReg(datarfb_reset, self.datarfb.reset, "sd_fb") fsm.act("DATA_READSTART", pads.data.oe.eq(0), pads.clk.eq(1), NextValue(dtimeout, dtimeout + 1), If(self.buffer.source.valid, NextState("DATA_READ") ).Elif(dtimeout > cfg.datatimeout, NextState("TIMEOUT") ) ) fsm.act("DATA_READ", pads.data.oe.eq(0), pads.clk.eq(1), source.valid.eq(self.buffer.source.valid), source.data.eq(self.buffer.source.data), source.status.eq(SDCARD_STREAM_STATUS_OK), source.last.eq(read == (toread - 1)), self.buffer.source.ready.eq(source.ready), If(source.valid & source.ready, NextValue(read, read + 1), If(read == (toread - 1), If(sink.last, NextState("DATA_CLK40") ).Else( sink.ready.eq(1), NextState("DATA_FLUSH") ) ) ) ) fsm.act("DATA_FLUSH", pads.data.oe.eq(0), datarfb_reset.eq(1), self.buffer.source.ready.eq(1), If(cnt < 5, NextValue(cnt, cnt + 1), ).Else( NextValue(cnt, 0), NextState("IDLE") ) ) fsm.act("DATA_CLK40", pads.data.oe.eq(1), pads.data.o.eq(0xf), If(cnt < 40, NextValue(cnt, cnt + 1), pads.clk.eq(1) ).Else( NextValue(cnt, 0), sink.ready.eq(1), NextState("IDLE") ) ) fsm.act("TIMEOUT", source.valid.eq(1), source.data.eq(0), source.status.eq(SDCARD_STREAM_STATUS_TIMEOUT), source.last.eq(1), If(source.valid & source.ready, sink.ready.eq(1), NextState("IDLE") ) )
def __init__(self, axi, port, buffer_depth): self.cmd_request = Signal() self.cmd_grant = Signal() # # # can_read = Signal() ashift = log2_int(port.data_width // 8) # Burst to Beat ar_buffer = stream.Buffer( ax_description(axi.address_width, axi.id_width)) self.submodules += ar_buffer self.comb += axi.ar.connect(ar_buffer.sink) ar = stream.Endpoint(ax_description(axi.address_width, axi.id_width)) ar_burst2beat = AXIBurst2Beat(ar_buffer.source, ar) self.submodules.ar_burst2beat = ar_burst2beat # Read buffer r_buffer = stream.SyncFIFO(r_description(axi.data_width, axi.id_width), buffer_depth, buffered=True) self.submodules.r_buffer = r_buffer # Read Buffer reservation # - Incremented when data is planned to be queued # - Decremented when data is dequeued r_buffer_queue = Signal() r_buffer_dequeue = Signal() r_buffer_level = Signal(max=buffer_depth + 1) self.comb += [ r_buffer_queue.eq(port.cmd.valid & port.cmd.ready & ~port.cmd.we), r_buffer_dequeue.eq(r_buffer.source.valid & r_buffer.source.ready) ] self.sync += [ If(r_buffer_queue, If(~r_buffer_dequeue, r_buffer_level.eq(r_buffer_level + 1))).Elif( r_buffer_dequeue, r_buffer_level.eq(r_buffer_level - 1)) ] self.comb += can_read.eq(r_buffer_level != buffer_depth) # Read ID Buffer id_buffer = stream.SyncFIFO([("id", axi.id_width)], buffer_depth) self.submodules += id_buffer self.comb += [ id_buffer.sink.valid.eq(ar.valid & ar.ready), id_buffer.sink.last.eq(ar.last), id_buffer.sink.id.eq(ar.id), axi.r.last.eq(id_buffer.source.last), axi.r.id.eq(id_buffer.source.id), id_buffer.source.ready.eq(axi.r.valid & axi.r.ready) ] # Command self.comb += [ self.cmd_request.eq(ar.valid & can_read), If(self.cmd_grant, port.cmd.valid.eq(ar.valid & can_read), ar.ready.eq(port.cmd.ready & can_read), port.cmd.we.eq(0), port.cmd.addr.eq(ar.addr >> ashift)) ] # Read data self.comb += [ port.rdata.connect(r_buffer.sink, omit={"bank"}), r_buffer.source.connect(axi.r, omit={"id", "last"}), axi.r.resp.eq(RESP_OKAY) ]
def __init__(self): self.pads = pads = _sdpads() self.sink = sink = stream.Endpoint([("data", 8)]) self.crc_clear = Signal() self.crc_valids = Signal(32) self.crc_errors = Signal(32) # # # wrstarted = Signal() cnt = Signal(8) self.submodules.crcfb = SDPHYCRCRFB(pads.data.i[0]) self.sync.sd += [ If(self.crc_clear, self.crc_valids.eq(0), self.crc_errors.eq(0) ), If(self.crcfb.valid, self.crc_valids.eq(self.crc_valids + 1) ), If(self.crcfb.error, self.crc_errors.eq(self.crc_errors + 1) ) ] self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM(reset_state="IDLE")) fsm.act("IDLE", If(sink.valid, pads.clk.eq(1), pads.data.oe.eq(1), If(wrstarted, pads.data.o.eq(sink.data[4:8]), NextState("DATA_WRITE") ).Else( pads.data.o.eq(0), NextState("DATA_WRITESTART") ) ) ) fsm.act("DATA_WRITESTART", pads.clk.eq(1), pads.data.oe.eq(1), pads.data.o.eq(sink.data[4:8]), NextValue(wrstarted, 1), NextState("DATA_WRITE") ) fsm.act("DATA_WRITE", pads.clk.eq(1), pads.data.oe.eq(1), pads.data.o.eq(sink.data[0:4]), If(sink.last, NextState("DATA_WRITESTOP") ).Else( sink.ready.eq(1), NextState("IDLE") ) ) fsm.act("DATA_WRITESTOP", pads.clk.eq(1), pads.data.oe.eq(1), pads.data.o.eq(0xf), NextValue(wrstarted, 0), self.crcfb.start.eq(1), NextState("DATA_RESPONSE") ) fsm.act("DATA_RESPONSE", pads.clk.eq(1), pads.data.oe.eq(0), If(cnt < 16, NextValue(cnt, cnt + 1), ).Else( # wait while busy If(pads.data.i[0], NextValue(cnt, 0), sink.ready.eq(1), NextState("IDLE") ) ) )
def __init__(self, default_video_timings="800x600@60Hz"): # Check / Get Video Timings (can be str or dict) if isinstance(default_video_timings, str): try: self.video_timings = vt = video_timings[default_video_timings] except KeyError: msg = [f"Video Timings {default_video_timings} not supported, availables:"] for video_timing in video_timings.keys(): msg.append(f" - {video_timing} / {video_timings[video_timing]['pix_clk']/1e6:3.2f}MHz.") raise ValueError("\n".join(msg)) else: self.video_timings = vt = default_video_timings # MMAP Control/Status Registers. self._enable = CSRStorage(reset=1) self._hres = CSRStorage(hbits, vt["h_active"]) self._hsync_start = CSRStorage(hbits, vt["h_active"] + vt["h_sync_offset"]) self._hsync_end = CSRStorage(hbits, vt["h_active"] + vt["h_sync_offset"] + vt["h_sync_width"]) self._hscan = CSRStorage(hbits, vt["h_active"] + vt["h_blanking"]) self._vres = CSRStorage(vbits, vt["v_active"]) self._vsync_start = CSRStorage(vbits, vt["v_active"] + vt["v_sync_offset"]) self._vsync_end = CSRStorage(vbits, vt["v_active"] + vt["v_sync_offset"] + vt["v_sync_width"]) self._vscan = CSRStorage(vbits, vt["v_active"] + vt["v_blanking"]) # Video Timing Source self.source = source = stream.Endpoint(video_timing_layout) # # # # Resynchronize Enable to Video clock domain. self.enable = enable = Signal() self.specials += MultiReg(self._enable.storage, enable) # Resynchronize Horizontal Timings to Video clock domain. self.hres = hres = Signal(hbits) self.hsync_start = hsync_start = Signal(hbits) self.hsync_end = hsync_end = Signal(hbits) self.hscan = hscan = Signal(hbits) self.specials += MultiReg(self._hres.storage, hres) self.specials += MultiReg(self._hsync_start.storage, hsync_start) self.specials += MultiReg(self._hsync_end.storage, hsync_end) self.specials += MultiReg(self._hscan.storage, hscan) # Resynchronize Vertical Timings to Video clock domain. self.vres = vres = Signal(vbits) self.vsync_start = vsync_start = Signal(vbits) self.vsync_end = vsync_end = Signal(vbits) self.vscan = vscan = Signal(vbits) self.specials += MultiReg(self._vres.storage, vres) self.specials += MultiReg(self._vsync_start.storage, vsync_start) self.specials += MultiReg(self._vsync_end.storage, vsync_end) self.specials += MultiReg(self._vscan.storage, vscan) # Generate timings. hactive = Signal() vactive = Signal() fsm = FSM(reset_state="IDLE") fsm = ResetInserter()(fsm) self.submodules.fsm = fsm self.comb += fsm.reset.eq(~enable) fsm.act("IDLE", NextValue(hactive, 0), NextValue(vactive, 0), NextValue(source.hres, hres), NextValue(source.vres, vres), NextValue(source.hcount, 0), NextValue(source.vcount, 0), NextState("RUN") ) self.comb += source.de.eq(hactive & vactive) # DE when both HActive and VActive. self.sync += source.first.eq((source.hcount == 0) & (source.vcount == 0)), self.sync += source.last.eq( (source.hcount == hscan) & (source.vcount == vscan)), fsm.act("RUN", source.valid.eq(1), If(source.ready, # Increment HCount. NextValue(source.hcount, source.hcount + 1), # Generate HActive / HSync. If(source.hcount == 0, NextValue(hactive, 1)), # Start of HActive. If(source.hcount == hres, NextValue(hactive, 0)), # End of HActive. If(source.hcount == hsync_start, NextValue(source.hsync, 1)), # Start of HSync. If(source.hcount == hsync_end, NextValue(source.hsync, 0)), # End of HSync. # End of HScan. If(source.hcount == hscan, # Reset HCount. NextValue(source.hcount, 0), # Increment VCount. NextValue(source.vcount, source.vcount + 1), # Generate VActive / VSync. If(source.vcount == 0, NextValue(vactive, 1)), # Start of VActive. If(source.vcount == vres, NextValue(vactive, 0)), # End of HActive. If(source.vcount == vsync_start, NextValue(source.vsync, 1)), # Start of VSync. If(source.vcount == vsync_end, NextValue(source.vsync, 0)), # End of VSync. # End of VScan. If(source.vcount == vscan, # Reset VCount. NextValue(source.vcount, 0), ) ) ) )
def __init__(self, pads, device, **kwargs): self.sink = sink = stream.Endpoint([("data", 8), ("cmd_data_n", 1), ("rd_wr_n", 1)]) self.source = source = stream.Endpoint([("data", 8), ("status", 3)]) if hasattr(pads, "sel"): self.voltage_sel = CSRStorage() self.comb += pads.sel.eq(self.voltage_sel.storage) # # # self.sdpads = sdpads = _sdpads() # IOs (device specific) if not hasattr(pads, "clkfb"): self.comb += [ ClockSignal("sd_fb").eq(ClockSignal("sd")), ResetSignal("sd_fb").eq(ResetSignal("sd")) ] if hasattr(pads, "cmd_t") and hasattr(pads, "dat_t"): # emulator phy self.comb += [ If(sdpads.clk, pads.clk.eq(~ClockSignal("sd"))), pads.cmd_i.eq(1), If(sdpads.cmd.oe, pads.cmd_i.eq(sdpads.cmd.o)), sdpads.cmd.i.eq(1), If(~pads.cmd_t, sdpads.cmd.i.eq(pads.cmd_o)), pads.dat_i.eq(0b1111), If(sdpads.data.oe, pads.dat_i.eq(sdpads.data.o)), sdpads.data.i.eq(0b1111), If(~pads.dat_t[0], sdpads.data.i[0].eq(pads.dat_o[0])), If(~pads.dat_t[1], sdpads.data.i[1].eq(pads.dat_o[1])), If(~pads.dat_t[2], sdpads.data.i[2].eq(pads.dat_o[2])), If(~pads.dat_t[3], sdpads.data.i[3].eq(pads.dat_o[3])) ] else: # real phy if device[:3] == "xc6": self.submodules.io = io = SDPHYIOS6(sdpads, pads, **kwargs) elif device[:3] == "xc7": self.submodules.io = io = SDPHYIOS7(sdpads, pads, **kwargs) else: raise NotImplementedError self.sync.sd += [ io.cmd_t.oe.eq(sdpads.cmd.oe), io.cmd_t.o.eq(sdpads.cmd.o), io.data_t.oe.eq(sdpads.data.oe), io.data_t.o.eq(sdpads.data.o) ] # PHY submodules self.submodules.cfg = cfg = SDPHYCFG() self.submodules.cmdw = cmdw = SDPHYCMDW() self.submodules.cmdr = cmdr = SDPHYCMDR(cfg) self.submodules.dataw = dataw = SDPHYDATAW() self.submodules.datar = datar = SDPHYDATAR(cfg) self.comb += \ If(sink.valid, # Command mode If(sink.cmd_data_n, # Write command If(~sink.rd_wr_n, sink.connect(cmdw.sink, omit=set(["cmd_data_n", "rd_wr_n"])), cmdw.pads.connect(sdpads) # Read command ).Else( sink.connect(cmdr.sink, omit=set(["cmd_data_n", "rd_wr_n"])), cmdr.pads.connect(sdpads), cmdr.source.connect(source) ) # Data mode ).Else( # Write data If(~sink.rd_wr_n, sink.connect(dataw.sink, omit=set(["cmd_data_n", "rd_wr_n"])), dataw.pads.connect(sdpads) # Read data ).Else( sink.connect(datar.sink, omit=set(["cmd_data_n", "rd_wr_n"])), datar.pads.connect(sdpads), datar.source.connect(source) ) ) )
def __init__(self, pads, sys_clk_freq, clock_domain="sys", clk_freq=148.5e6, refclk=None): assert sys_clk_freq >= clk_freq self.sink = sink = stream.Endpoint(video_data_layout) # # # from liteiclink.serdes.gtp_7series import GTPQuadPLL, GTP # Always ack Sink, no backpressure. self.comb += sink.ready.eq(1) # Clocking + Differential Signaling. pads_clk = Signal() self.specials += DDROutput(i1=1, i2=0, o=pads_clk, clk=ClockSignal(clock_domain)) self.specials += Instance("OBUFDS", i_I=pads_clk, o_O=pads.clk_p, o_OB=pads.clk_n) # GTP Quad PLL. if refclk is None: # No RefClk provided, use the Video Clk as GTP RefClk. refclk = ClockSignal(clock_domain) elif isinstance(refclk, Record): # Differential RefCLk provided, add an IBUFDS_GTE2. refclk_se = Signal() self.specials += Instance("IBUFDS_GTE2", i_CEB = 0, i_I = refclk.p, i_IB = refclk.n, o_O = refclk_se ) refclk = refclk_se self.submodules.pll = pll = GTPQuadPLL(refclk, clk_freq, 1.485e9) # Encode/Serialize Datas. for color in ["r", "g", "b"]: # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) self.submodules += encoder self.comb += encoder.d.eq(getattr(sink, color)) self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) self.comb += encoder.de.eq(sink.de) # 10:20 (SerDes has a minimal 20:1 Serialization ratio). converter = ClockDomainsRenamer(clock_domain)(stream.Converter(10, 20)) self.submodules += converter self.comb += converter.sink.valid.eq(1) self.comb += converter.sink.data.eq(encoder.out) # Clock Domain Crossing (video_clk --> gtp_tx) cdc = stream.ClockDomainCrossing([("data", 20)], cd_from=clock_domain, cd_to=f"gtp{color}_tx") self.submodules += cdc self.comb += converter.source.connect(cdc.sink) self.comb += cdc.source.ready.eq(1) # No backpressure. # 20:1 Serialization + Differential Signaling. c2d = {"r": 2, "g": 1, "b": 0} class GTPPads: def __init__(self, p, n): self.p = p self.n = n tx_pads = GTPPads(p=getattr(pads, f"data{c2d[color]}_p"), n=getattr(pads, f"data{c2d[color]}_n")) # FIXME: Find a way to avoid RX pads. rx_pads = GTPPads(p=getattr(pads, f"rx{c2d[color]}_p"), n=getattr(pads, f"rx{c2d[color]}_n")) gtp = GTP(pll, tx_pads, rx_pads=rx_pads, sys_clk_freq=sys_clk_freq, tx_polarity = 1, # FIXME: Specific to Decklink Mini 4K, make it configurable. tx_buffer_enable = True, rx_buffer_enable = True, clock_aligner = False ) setattr(self.submodules, f"gtp{color}", gtp) self.comb += gtp.tx_produce_pattern.eq(1) self.comb += gtp.tx_pattern.eq(cdc.source.data)
def __init__(self, buffer_depth=4): self.sink = sink = stream.Endpoint(etherbone_record_description(32)) self.source = source = stream.Endpoint(etherbone_mmap_description(32)) # # # fifo = stream.SyncFIFO(etherbone_record_description(32), buffer_depth, buffered=True) self.submodules += fifo self.comb += sink.connect(fifo.sink) base_addr = Signal(32) base_addr_update = Signal() self.sync += If(base_addr_update, base_addr.eq(fifo.source.data)) counter = Signal(max=512) counter_reset = Signal() counter_ce = Signal() self.sync += \ If(counter_reset, counter.eq(0) ).Elif(counter_ce, counter.eq(counter + 1) ) self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", fifo.source.ready.eq(1), counter_reset.eq(1), If( fifo.source.valid, base_addr_update.eq(1), If(fifo.source.wcount, NextState("RECEIVE_WRITES")).Elif( fifo.source.rcount, NextState("RECEIVE_READS")))) fsm.act( "RECEIVE_WRITES", source.valid.eq(fifo.source.valid), source.last.eq(counter == fifo.source.wcount - 1), source.count.eq(fifo.source.wcount), source.be.eq(fifo.source.byte_enable), source.addr.eq(base_addr[2:] + counter), source.we.eq(1), source.data.eq(fifo.source.data), fifo.source.ready.eq(source.ready), If( source.valid & source.ready, counter_ce.eq(1), If( source.last, If(fifo.source.rcount, NextState("RECEIVE_BASE_RET_ADDR")).Else( NextState("IDLE"))))) fsm.act( "RECEIVE_BASE_RET_ADDR", counter_reset.eq(1), If(fifo.source.valid, base_addr_update.eq(1), NextState("RECEIVE_READS"))) fsm.act( "RECEIVE_READS", source.valid.eq(fifo.source.valid), source.last.eq(counter == fifo.source.rcount - 1), source.count.eq(fifo.source.rcount), source.base_addr.eq(base_addr), source.addr.eq(fifo.source.data[2:]), fifo.source.ready.eq(source.ready), If(source.valid & source.ready, counter_ce.eq(1), If(source.last, NextState("IDLE"))))