def __init__(self, step_width=None, step_shift=0, **kwargs): Filter.__init__(self, **kwargs) # required by tests self.step_shift = step_shift width = len(self.y) if step_width is None: step_width = width self.shift = CSRConstant(step_shift, bits_for(step_shift)) self.step = CSRStorage(step_width) self.min = CSRStorage(width, reset=1 << (width - 1)) self.max = CSRStorage(width, reset=(1 << (width - 1)) - 1) self.run = CSRStorage(1) ### self.submodules.sweep = Sweep(width + step_shift + 1) self.submodules.limit = Limit(width + 1) min, max = self.min.storage, self.max.storage self.comb += [ self.sweep.run.eq(~self.clear & self.run.storage), self.sweep.hold.eq(self.hold), self.limit.x.eq(self.sweep.y >> step_shift), self.sweep.step.eq(self.step.storage), ] self.sync += [ self.limit.min.eq(Cat(min, min[-1])), self.limit.max.eq(Cat(max, max[-1])), self.sweep.turn.eq(self.limit.railed), self.y.eq(self.limit.y), ]
def __init__(self, m, phy_ref, phy_sig): """Define the gateware to gate & latch inputs.""" self.clear = Signal() self.triggered = Signal() n_fine = len(phy_ref.fine_ts) full_timestamp_width = counter_width + n_fine self.ref_ts = Signal(full_timestamp_width) self.sig_ts = Signal(full_timestamp_width) # In mu self.gate_start = Signal(full_timestamp_width) self.gate_stop = Signal(full_timestamp_width) # # # self.got_ref = Signal() # Absolute gate times, calculated when we get the reference event abs_gate_start = Signal(full_timestamp_width) abs_gate_stop = Signal(full_timestamp_width) t_ref = Signal(full_timestamp_width) self.comb += t_ref.eq(Cat(phy_ref.fine_ts, m)) self.sync += [ If( phy_ref.stb_rising, self.got_ref.eq(1), self.ref_ts.eq(t_ref), abs_gate_start.eq(self.gate_start + t_ref), abs_gate_stop.eq(self.gate_stop + t_ref), ), If(self.clear, self.got_ref.eq(0), self.triggered.eq(0)), ] past_window_start = Signal() before_window_end = Signal() triggering = Signal() t_sig = Signal(full_timestamp_width) self.comb += [ t_sig.eq(Cat(phy_sig.fine_ts, m)), past_window_start.eq(t_sig >= abs_gate_start), before_window_end.eq(t_sig <= abs_gate_stop), triggering.eq(past_window_start & before_window_end), ] self.sync += [ If( phy_sig.stb_rising & ~self.triggered & triggering, self.triggered.eq(triggering), self.sig_ts.eq(t_sig), ) ]
def __init__(self, **kwargs): super().__init__(**kwargs) self.platform.add_extension(ltc.ltc_pads) self.submodules.lvds = LTCPhy(self.platform, self.sys_clk_freq, 120e6) self.platform.add_false_path_constraints(self.crg.cd_sys.clk, self.lvds.pads_dco) # Frequency counter for received sample clock self.submodules.f_sample = FreqMeter(self.sys_clk_freq) self.comb += self.f_sample.clk.eq(ClockSignal("sample")) spi_pads = self.platform.request("LTC_SPI") self.submodules.spi = spi.SPIMaster(spi_pads, 16, self.sys_clk_freq, self.sys_clk_freq / 32) width, depth = 16 * 2, 8192 storage = Memory(width, depth, init=[0x1234, 0xCAFECAFE, 0x00C0FFEE]) self.specials += storage self.submodules.adc_data_buffer = wishbone.SRAM(storage, read_only=True) port = storage.get_port(write_capable=True, clock_domain="sample") self.register_mem("adc_data_buffer", 0x10000000, self.adc_data_buffer.bus, depth * 8) self.specials += port self.submodules.acq = DumpToRAM(width, depth, port) self.sync.sample += self.acq.adc_data.eq( Cat(Signal(2), self.lvds.sample_outs[0], Signal(2), self.lvds.sample_outs[1])) self.sync += self.lvds.init_running.eq(self.ctrl.reset) for p in LTCSocDev.csr_peripherals: self.add_csr(p)
def cross_connect(gpio, chains): state_names = ["force"] + ["di%i" % i for i in range(len(gpio.i))] states = [1, gpio.i] signal_names = ["zero"] signals = Array([0]) for n, c in chains: for s in c.state_out: states.append(s) state_names.append("%s_%s" % (n, s.backtrace[-1][0])) for s in c.signal_out: signals.append(s) name = s.backtrace[-1][0] signal_names.append("%s_%s" % (n, name)) sig = CSRStatus(len(s), name=name) clr = CSR(name="%s_clr" % name) max = CSRStatus(len(s), name="%s_max" % name) min = CSRStatus(len(s), name="%s_min" % name) # setattr(c, sig.name, sig) setattr(c, clr.name, clr) setattr(c, max.name, max) setattr(c, min.name, min) c.comb += sig.status.eq(s) c.sync += If(clr.re | (max.status < s), max.status.eq(s)) c.sync += If(clr.re | (min.status > s), min.status.eq(s)) states = Cat(states) state = Signal(len(states)) gpio.comb += state.eq(states) gpio.state = CSRStatus(len(state)) gpio.state_clr = CSR() gpio.sync += [ If( gpio.state_clr.re, gpio.state.status.eq(0), ).Else(gpio.state.status.eq(gpio.state.status | state), ) ] # connect gpio output to "doi%i_en" for i, s in enumerate(gpio.o): csr = CSRStorage(len(state), name="do%i_en" % i) setattr(gpio, csr.name, csr) gpio.sync += s.eq((state & csr.storage) != 0) # connect state ins to "%s_en" and signal ins to "%s_sel" for n, c in chains: for s in c.state_in: csr = CSRStorage(len(state), name="%s_en" % s.backtrace[-1][0]) setattr(c, csr.name, csr) c.sync += s.eq((state & csr.storage) != 0) for s in c.signal_in: csr = CSRStorage(bits_for(len(signals) - 1), name="%s_sel" % s.backtrace[-1][0]) setattr(c, csr.name, csr) c.sync += s.eq(signals[csr.storage]) return state_names, signal_names
def __init__(self, vga, sin_t, col_t): pos1 = Signal(bits_sign=9) pos3 = Signal(bits_sign=9) tpos1 = Signal(bits_sign=9) tpos2 = Signal(bits_sign=9) tpos3 = Signal(bits_sign=9) tpos4 = Signal(bits_sign=9) index = Signal(bits_sign=6) count = Signal() self.specials.col_t = Memory(4, 256, init=col_t) self.specials.sin_t = Memory(32, 512, init=sin_t) sin_p = self.sin_t.get_port(async_read=True) col_p = self.col_t.get_port(async_read=True) self.specials += sin_p self.specials += col_p self.ios = {sin_p.adr, sin_p.dat_r, col_p.adr, col_p.dat_r} sin = Signal(bits_sign=(32, True)) self.sync += If(vga.hc < VGA.hpixels - 1, [ If((vga.hc >= VGA.hbp) & (vga.hc < VGA.hfp), [ tpos1.eq(tpos1 + 5), tpos2.eq(tpos2 + 3) ]) ]).Else([ If(vga.vc < VGA.vlines - 1, [ If((vga.vc >= VGA.vbp) & (vga.vc < VGA.vfp), [ tpos1.eq(pos1 + 5), tpos2.eq(3), tpos3.eq(tpos3 + 1), tpos4.eq(tpos4 + 3) ]) ]).Else([ pos1.eq(pos1 + 9), pos3.eq(pos3 + 8), tpos4.eq(0), tpos3.eq(0), count.eq(count + 1) ]) ]) self.sync += If((vga.vc >= VGA.vbp) & (vga.vc < VGA.vfp), [ If((vga.hc >= VGA.hbp) & (vga.hc < VGA.hfp), [ calc_index(tpos1, sin, sin_p, acc=False, zero=True), calc_index(tpos2, sin, sin_p), calc_index(tpos3, sin, sin_p), calc_index(tpos4, sin, sin_p), index.eq(sin >> 4), col_p.adr.eq(index), Cat(vga.color.g1, vga.color.g0, vga.color.r1, vga.color.r0).eq(col_p.dat_r) ]).Else(vga.color.black()) ]).Else(vga.color.black())
def _setup(self, platform): exp = platform.request("exp") gpio_pins = Cat(exp.p, exp.n) #[:width] ### self.submodules.gpio = MigenGpio( gpio_pins=gpio_pins, is_output=self.is_output, output=self.output, ) self.comb += self.input.eq(self.gpio.input)
def __init__(self, period=0, on=True, high_after_on=True): """ Pulse generator that emits a pulse every ``period + 2`` clock cycles. Args: period (int or Signal): period of low clock cycles between pulses. Set this to a negative number to indicate that the output should be constantly high. on (bool or Signal): enables the pulse generator sequence when high. high_after_on (bool): when True, the output goes high for a single clock cycle when ``on`` goes high, otherwise it only goes high after the first period. Output signals: out: the pulse sequence, 0 between pulses and 1 for a single clock cycle during a pulse. """ self.out = Signal(reset=0) ### try: count_reset = period.reset except AttributeError: count_reset = period try: width = len(period) except TypeError: width = count_reset.bit_length() self.count = Signal(width, reset=count_reset) self.carry = Signal(1, reset=high_after_on) self.sync += [ self.out.eq(self.carry & on), If( on == 0, # prepare for the first pulse when off self.carry.eq(high_after_on), self.count.eq(period), ).Elif( self.carry, # restart countdown self.carry.eq(0), self.count.eq(period), ).Else( # regular countdown Cat(self.count, self.carry).eq(Cat(self.count, 0) - 1), ) ]
def __init__(self, nch=4, bits=16, cycles_per_sample=1, ramp=True): self.dw = nch * bits self.source = source = stream.Endpoint([("data", self.dw)]) assert cycles_per_sample == 1 self.submodules.ramp = ramp = Counter(bits) valid = Signal(reset=0) self.sync += valid.eq(~valid) self.comb += [ source.data.eq(Cat(*[ramp.count + ch for ch in range(nch)])), source.valid.eq(valid) ]
def __init__(self, start=0, stop=None, step=1, reset=0, on=1, width=32, direction="up"): """ Counter that can count either "up" or "down". Args: start (int or Signal): value to start counting from. stop (int, Signal, or None): value at or beyond which to stop counting. If ``None``, the counter will wrap through zero. step (int or Signal): counting step. reset (bool or Signal): when high, the counter will to its starting configuration. on (bool or Signal): the counter will only keep counting when this signal is high. width (int): width of the count register. direction (str, "up" or "down"): the direction to count in. step should always be positive. Output signals: count: the current counter value. carry: the carry bit of the counter, which goes high every time the counter wraps through zero. done: high when the counter value is equal or beyond ``stop``. """ self.count = Signal(width + 1) self.carry = Signal(1) self.done = Signal(reset=0) ### if isinstance(start, int): initial_count = start else: initial_count = start.reset count_with_carry = Signal(width + 1, reset=initial_count) self.comb += [ self.count.eq(Cat(count_with_carry[:-1], 0)), self.carry.eq(count_with_carry[-1]), ] if stop is not None: self.comb += If((self.count == stop), self.done.eq(1)).Else(self.done.eq(0)) self.sync += [ If( reset == 1, count_with_carry.eq(start), ).Elif((~self.done & on) == 1, count_with_carry.eq(self.count + step) if direction == "up" else count_with_carry.eq(self.count - step)) ]
def _dac_settings(self, platform): dac = platform.request("dac") dac_dat_a = Signal(bits, reset=0) dac_dat_b = Signal(bits, reset=0) dac_rst = Signal() # convert output registers + signed to unsigned and to negative slope self.sync += [ dac_dat_a.eq(Cat(~self.out1[:-1], self.out1[-1])), dac_dat_b.eq(Cat(~self.out2[:-1], self.out2[-1])), ] self.specials += [ Instance("ODDR", o_Q=dac.clk, i_D1=0, i_D2=1, i_C=ClockSignal("clk_dac_2p"), i_CE=1, i_R=0, i_S=0), Instance("ODDR", o_Q=dac.wrt, i_D1=0, i_D2=1, i_C=ClockSignal("clk_dac_2x"), i_CE=1, i_R=0, i_S=0), Instance("ODDR", o_Q=dac.sel, i_D1=1, i_D2=0, i_C=ClockSignal("clk_dac_1p"), i_CE=1, i_R=dac_rst, i_S=0), Instance("ODDR", o_Q=dac.rst, i_D1=dac_rst, i_D2=dac_rst, i_C=ClockSignal("clk_dac_1p"), i_CE=1, i_R=0, i_S=0), ] self.specials += [ Instance("ODDR", o_Q=dac.data[i], i_D1=dac_dat_b[i], i_D2=dac_dat_a[i], i_C=ClockSignal("clk_dac_1p"), i_CE=1, i_R=dac_rst, i_S=0) for i in range(len(dac.data)) ]
def __init__(self, platform): serial = platform.request("fast_serial") clk12 = platform.request("clk12") self.clock_domains.cd_sys = ClockDomain() if True: self.specials.pll = Instance("pll_test", i_clock_in=clk12, o_clock_out=self.cd_sys.clk) else: self.comb += self.cd_sys.clk.eq(clk12) self.clock_domains.cd_por = ClockDomain(reset_less=True) reset_delay = Signal(max=1024) self.comb += [ self.cd_por.clk.eq(self.cd_sys.clk), self.cd_sys.rst.eq(reset_delay != 1023) ] self.sync.por += If(reset_delay != 1023, reset_delay.eq(reset_delay + 1)) self.submodules.tx = FastSerialTX(serial) self.submodules.packager = Packager(0x47) self.comb += self.packager.source.connect(self.tx.sink) self.comb += self.tx.sink.payload.port.eq(1) counter = Signal(5) self.comb += [ self.packager.sink.stb.eq(1), self.packager.sink.payload.data.eq(counter), self.packager.sink.eop.eq(counter == 2**counter.nbits - 1) ] self.sync += [ If(self.packager.sink.stb & self.packager.sink.ack, counter.eq(counter + 1)), ] debug = platform.request("debug") self.comb += [ debug.eq(Cat(serial.clk, serial.di, serial.cts)), ]
def __init__(self, clk_freq, baud_rate): self.data = Signal(8) self.ready = Signal() self.ack = Signal() self.error = Signal() self.rx = Signal(reset=1) divisor = clk_freq // baud_rate rx_counter = Signal(max=divisor) self.rx_strobe = Signal() self.comb += self.rx_strobe.eq(rx_counter == 0) self.sync += \ If(rx_counter == 0, rx_counter.eq(divisor - 1) ).Else( rx_counter.eq(rx_counter - 1) ) self.rx_bitno = Signal(3) self.submodules.rx_fsm = FSM(reset_state='IDLE') self.rx_fsm.act( 'IDLE', If(~self.rx, NextValue(rx_counter, divisor // 2), NextState('START'))) self.rx_fsm.act('START', If(self.rx_strobe, NextState('DATA'))) self.rx_fsm.act( 'DATA', If(self.rx_strobe, NextValue(self.data, Cat(self.data[1:8], self.rx)), NextValue(self.rx_bitno, self.rx_bitno + 1), If(self.rx_bitno == 7, NextState('STOP')))) self.rx_fsm.act( 'STOP', If(self.rx_strobe, If(~self.rx, NextState('ERROR')).Else(NextState('FULL'), ))) self.rx_fsm.act( 'FULL', self.ready.eq(1), If(self.ack, NextState('IDLE')).Elif(~self.rx, NextState('ERROR'))) self.rx_fsm.act('ERROR', self.error.eq(1))
def __init__(self, pads): self.sink = stream.Endpoint([ ("data", 8), ("port", 1), ]) ### cts = Signal() self.specials += MultiReg(pads.cts, cts) di = Signal(reset=1) self.comb += pads.di.eq(di) tx_reg = Signal(9) tx_bit = Signal(max=10) self.sync += [ self.sink.ack.eq(0), If( self.sink.stb & cts & (tx_bit == 0) & ~self.sink.ack, tx_reg.eq(Cat(self.sink.payload.data, self.sink.payload.port)), tx_bit.eq(9), di.eq(0), ).Elif( tx_bit > 0, tx_bit.eq(tx_bit - 1), di.eq(tx_reg[0]), tx_reg.eq(tx_reg[1:]), If( tx_bit == 1, self.sink.ack.eq(1), ), ).Else(di.eq(1), ) ] self.comb += [ pads.clk.eq(~ClockSignal()), ]
def __init__(self, plat, superunit): self.garbage = Cat([plat.request("user_led") for _ in range(3)]) self.bad_led = plat.request("user_led") self.good_led = plat.request("user_led") self.submodules += superunit self.comb += [ [g.eq(0) for g in self.garbage] ] self.sync += [ If(self.good_led == 0, self.good_led.eq(superunit.o_success & superunit.o_over)) .Else( self.good_led.eq(1)), If(self.bad_led == 0, self.bad_led.eq(~superunit.o_success & superunit.o_over)) .Else( self.bad_led.eq(0)) ]
def __init__(self, pads): self.intro = ModuleDoc("""Fomu Touchpads Fomu has four single-ended exposed pads on its side. These pads are designed to be connected to some captouch block, or driven in a resistive touch mode in order to get simple touchpad support. This block simply provides CPU-controlled GPIO support for this block. It has three registers which control the In, Out, and Output Enable functionality of each of these pins. """) touch1 = TSTriple() touch2 = TSTriple() touch3 = TSTriple() touch4 = TSTriple() self.specials += touch1.get_tristate(pads.t1) self.specials += touch2.get_tristate(pads.t2) self.specials += touch3.get_tristate(pads.t3) self.specials += touch4.get_tristate(pads.t4) self.o = CSRStorage(4, description="Output values for pads 1-4") self.oe = CSRStorage(4, description="Output enable control for pads 1-4") self.i = CSRStatus(4, description="Input value for pads 1-4") self.comb += [ touch1.o.eq(self.o.storage[0]), touch2.o.eq(self.o.storage[1]), touch3.o.eq(self.o.storage[2]), touch4.o.eq(self.o.storage[3]), touch1.oe.eq(self.oe.storage[0]), touch2.oe.eq(self.oe.storage[1]), touch3.oe.eq(self.oe.storage[2]), touch4.oe.eq(self.oe.storage[3]), self.i.status.eq(Cat(touch1.i, touch2.i, touch3.i, touch4.i)) ]
def __init__(self, platform, pads, size=16 * 1024 * 1024): self.size = size self.bus = bus = wishbone.Interface() self.reset = Signal() self.cfg1 = CSRStorage(fields=[ CSRField( "bb_out", size=4, description="Output bits in bit-bang mode"), CSRField("bb_clk", description="Serial clock line in bit-bang mode"), CSRField("bb_cs", description="Chip select line in bit-bang mode"), ]) self.cfg2 = CSRStorage(fields=[ CSRField("bb_oe", size=4, description="Output Enable bits in bit-bang mode"), ]) self.cfg3 = CSRStorage(fields=[ CSRField( "rlat", size=4, description="Read latency/dummy cycle count"), CSRField("crm", description="Continuous Read Mode enable bit"), CSRField("qspi", description="Quad-SPI enable bit"), CSRField("ddr", description="Double Data Rate enable bit"), ]) self.cfg4 = CSRStorage(fields=[ CSRField( "memio", offset=7, reset=1, description= "Enable memory-mapped mode (set to 0 to enable bit-bang mode)") ]) self.stat1 = CSRStatus(fields=[ CSRField( "bb_in", size=4, description="Input bits in bit-bang mode"), ]) self.stat2 = CSRStatus(8, description="Reserved") self.stat3 = CSRStatus(8, description="Reserved") self.stat4 = CSRStatus(8, description="Reserved") cfg = Signal(32) cfg_we = Signal(4) cfg_out = Signal(32) self.comb += [ cfg.eq( Cat(self.cfg1.storage, self.cfg2.storage, self.cfg3.storage, self.cfg4.storage)), cfg_we.eq( Cat(self.cfg1.re, self.cfg2.re, self.cfg3.re, self.cfg4.re)), self.stat1.status.eq(cfg_out[0:4]), self.stat2.status.eq(0), self.stat3.status.eq(0), self.stat4.status.eq(0), ] reset = Signal() mosi_pad = TSTriple() miso_pad = TSTriple() cs_n_pad = TSTriple() clk_pad = TSTriple() wp_pad = TSTriple() hold_pad = TSTriple() clk = Signal() if hasattr(pads, "clk"): clk = pads.clk self.specials += clk_pad.get_tristate(clk) self.comb += clk_pad.oe.eq(~reset) else: self.specials += Instance("USRMCLK", i_USRMCLKI=clk, i_USRMCLKTS=0) self.specials += mosi_pad.get_tristate(pads.mosi) self.specials += miso_pad.get_tristate(pads.miso) self.specials += cs_n_pad.get_tristate(pads.cs_n) self.specials += wp_pad.get_tristate(pads.wp) self.specials += hold_pad.get_tristate(pads.hold) self.comb += [ reset.eq(ResetSignal() | self.reset), cs_n_pad.oe.eq(~reset), ] flash_addr = Signal(24) # size/4 because data bus is 32 bits wide, -1 for base 0 mem_bits = bits_for(int(size / 4) - 1) pad = Signal(2) self.comb += flash_addr.eq(Cat(pad, bus.adr[0:mem_bits - 1])) read_active = Signal() spi_ready = Signal() self.sync += [ If( bus.stb & bus.cyc & ~read_active, read_active.eq(1), bus.ack.eq(0), ).Elif( read_active & spi_ready, read_active.eq(0), bus.ack.eq(1), ).Else( bus.ack.eq(0), read_active.eq(0), ) ] o_rdata = Signal(32) self.comb += bus.dat_r.eq(o_rdata) self.specials += Instance( "spimemio", o_flash_io0_oe=mosi_pad.oe, o_flash_io1_oe=miso_pad.oe, o_flash_io2_oe=wp_pad.oe, o_flash_io3_oe=hold_pad.oe, o_flash_io0_do=mosi_pad.o, o_flash_io1_do=miso_pad.o, o_flash_io2_do=wp_pad.o, o_flash_io3_do=hold_pad.o, o_flash_csb=cs_n_pad.o, o_flash_clk=clk, i_flash_io0_di=mosi_pad.i, i_flash_io1_di=miso_pad.i, i_flash_io2_di=wp_pad.i, i_flash_io3_di=hold_pad.i, i_resetn=~reset, i_clk=ClockSignal(), i_valid=bus.stb & bus.cyc, o_ready=spi_ready, i_addr=flash_addr, o_rdata=o_rdata, i_cfgreg_we=cfg_we, i_cfgreg_di=cfg, o_cfgreg_do=cfg_out, ) platform.add_source("rtl/spimemio.v")
def __init__(self, platform, mem, minimal=False): self.intro = ModuleDoc("""FOMU Apple II+ A virtual computer within a virtual computer inside a USB port. Instantiate 6502 processor with 1MHz core clock. Tie in to system memory as a wishbone master. Create virtual keyboard, video display and disk drive. """) addr = Signal(16) dout = Signal(8) din = Signal(8) wren = Signal() iosel = Signal() ior_addr = Signal(8) r_memsel = Signal() w_memsel = Signal() clk_en = Signal() # Clock divider limits CPU activity active = Signal() # CPU is active this cycle available = Signal() # Key press ready for reading div1M = 4 idlecount = Signal(div1M) # Counter to slow CPU clock # Disk II Controller Registers disk_phase = Signal(4) disk_motor = Signal() disk_drive = Signal() #disk_write = Signal() disk_reading = Signal() # DOS trying to read sector disk_data_available = Signal() # Data available for DOS to read disk_data_wanted = Signal() # Data wanted by DOS disk_read = Signal() # Data read by DOS so clear readable simulation = getenv("SIMULATION") synthesis = not simulation # Wishbone visible registers self.control = CSRStorage(fields=[ CSRField( "Reset", reset=1 if synthesis else 0, # auto-start in sim description="6502 Reset line - 1: Reset Asserted, 0: Running"), CSRField("RWROM", size=1, description="Allow writes to ROM"), #CSRField("Pause", description="Halt processor allowing stepping"), #CSRField("Step", description="Single step 6502 one clock cycle"), #CSRField("NMI", size=1, description="Non-maskable interrupt"), #CSRField("IRQ", size=1, description="Maskable interrupt request"), #CSRField("RDY", size=1, description=""), CSRField( "Divisor", size=div1M, offset=8, reset=11 if synthesis else 0, # Over-clock simulation description="Clock divider minius 1: 11 for 1MHz, 0 for 12MHz" ), #CSRField("DI", size=8, offset=16, description=""), ]) self.keyboard = CSRStorage(8, write_from_dev=True, description="Keyboard input ($C000)") self.strobe = CSR(1) #, description="Keyboard strobe ($C010)") self.screen = CSRStatus( fields=[ CSRField("Character", size=8, description="Character written to screen"), CSRField("Valid", size=1, description="Character is valid"), CSRField( "More", size=1, description="Additional characters are available to read"), #CSRField("Move", size=1, # description="Character is not adjacent to previous"), CSRField("Repeat", size=1, offset=11, description= "Previous character repeated to current position"), CSRField("ScrollStart", size=1, offset=12, description="Start of scroll region detected"), CSRField("ScrollEnd", size=1, offset=13, description="End of scroll region"), CSRField( "Horizontal", size=6, offset=16, description="Location of current character in screen memory" ), CSRField( "Vertical", size=5, offset=24, description="Location of current character in screen memory" ), ], description="Video Display Output") self.diskctrl = CSRStatus( fields=[ CSRField("Phase", size=4, description= "Four phases of the track selection stepper motor"), CSRField("Motor", size=1, description="Drive is spinning"), CSRField( "Drive", size=1, description="Drive select: drive 1 if clear, drive 2 if set" ), CSRField("Wanted", size=1, description="Drive is waiting for data"), CSRField("Pending", size=1, description="Drive has not yet read data written"), #CSRField("WriteMode", size=1, # description="Drive is reading when clear, writing when set"), ], description="Disk drive control ($C0EX)") self.diskdata = CSRStorage(8, description="Disk drive data ($C0EC)") #self.bus=CSRStatus(32, fields=[ # CSRField("Addr", size=16, description="Address bus"), # CSRField("Data", size=8, description="Data bus"), # CSRField("WrEn", size=1, description="Write enable"), # ], description="Address and data bus") #self.debug=CSRStatus(32, fields=[ # CSRField("PC", size=8, # description="Program counter"), # CSRField("A", size=8, # description="Accumulator"), # CSRField("X", size=8, # description="X index register"), # CSRField("Y", size=8, # description="Y index register"), # ], description="Address and data bus") if not minimal: # The minimal configuration provides all registers the host needs to # see so software can run unmodified. However, it does not implement # the 6502 to save gates. The video driver is also greatly reduced. # TODO eliminate wire [31:0] apple2_display_fifo_wrport_dat_r self.submodules.display_fifo = fifo.SyncFIFOBuffered(width=32, depth=256) self.comb += [ mem.addr6502.eq(addr), mem.din6502.eq(dout), mem.wren6502.eq(wren), self.strobe.w.eq(available), #self.bus.fields.Addr.eq(addr), #self.bus.fields.Data.eq(dout), #self.bus.fields.WrEn.eq(wren), If(addr[8:16] == 0xC0, iosel.eq(1), w_memsel.eq(0), mem.access6502.eq(0)).Else(iosel.eq(0), w_memsel.eq(1), mem.access6502.eq(active)), disk_read.eq(0), If( r_memsel, din.eq(mem.dout6502), ).Else( # I/O Read Address Decoder (reading but not from memory) If( ior_addr[4:8] == 0x0, din.eq(Cat(self.keyboard.storage[0:7], available)), ), # Disk II Controller Card in slot 6 (0x8 | 0x6) # The only data to be read are locations C and D. Simplify the # logic to only look at bit 0 of the address. If( ior_addr[4:8] == 0xE, din[0:7].eq(self.diskdata.storage[0:7]), # Write protect - TODO write is not supported #If(ior_addr[0], # # Return high bit set - protected # din[7].eq(1) #).Else( disk_read.eq(1), If( disk_data_available | self.diskdata.re, # Return byte given by host din[7].eq(self.diskdata.storage[7]), ).Else( # Return high bit clear - data not available din[7].eq(0), ), #), ), ), active.eq(clk_en & self.display_fifo.writable), ] self.sync += [ # Slow clock to prototypical speed or as configured by user If( idlecount == self.control.fields.Divisor, idlecount.eq(0), clk_en.eq(1), ).Else( idlecount.eq(idlecount + 1), clk_en.eq(0), ), # Read (DI) follows Write (AB/DO) by one clock cycle If( active, r_memsel.eq(w_memsel), ior_addr.eq(addr[0:8]), ), # Keyboard key available when written by host If( self.keyboard.re, available.eq(1), ), If( iosel, # I/O Write Address Decoder If( addr[4:8] == 0x1, # KBDSTRB # Strobe cleared on read or write to KBDSTRB # Any read or write to this address clears the pending key available.eq(0), ), ), ] self.specials += Instance( "cpu", i_clk=ClockSignal(), i_reset=ResetSignal() | self.control.storage[0], i_DI=din, # &(self.rand.we|self.cfg.storage[1])), o_AB=addr, # .dat_w, o_DO=dout, # .dat_w, o_WE=wren, i_IRQ=False, # self.control.fields.IRQ, i_NMI=False, # self.control.fields.NMI, # seed.re, i_RDY=active, # self.control.fields.RDY, ) platform.add_source("rtl/verilog-6502/cpu.v") platform.add_source("rtl/verilog-6502/ALU.v") #=============================================================================== # Disk Drive - Emulate Disk II controller in slot 6 #=============================================================================== # The Disk II controller card has 16 addressable locations. Eight of these are # dedicated to moving the arm, two for motor control, two for drive selection # and four that handle read, write, and write protection detection. #=============================================================================== self.comb += [ self.diskctrl.fields.Phase.eq(disk_phase), self.diskctrl.fields.Motor.eq(disk_motor), self.diskctrl.fields.Drive.eq(disk_drive), #self.diskctrl.fields.WriteMode.eq(disk_write), self.diskctrl.fields.Wanted.eq(disk_data_wanted), self.diskctrl.fields.Pending.eq(disk_data_available), ] self.sync += [ If( self.diskdata.re, disk_data_available.eq(1), ), # Set false again on read If( active & disk_read, disk_reading.eq(0), If( disk_data_available, disk_data_wanted.eq(0), ).Else(disk_data_wanted.eq(1), ), disk_data_available.eq(0), ), If( iosel, # Disk II Controller Card in slot 6 # C0E0 PHASEOFF Stepper motor phase 0 off. # C0E1 PHASEON Stepper motor phase 0 on. # C0E2 PHASE1OFF Stepper motor phase 1 off. # C0E3 PHASElON Stepper motor phase 1 on. # C0E4 PHASE2OFF Stepper motor phase 2 off. # C0E5 PHASE2ON Stepper notor phase 2 on. # C0E6 PHASE3OFF Stepper motor phase 3 off. # C0E7 PHASE3ON Stepper motor phase 3 on. # C0E8 MOTOROFF Turn motor off. # C0E9 MOTORON Turn motor on. # C0EA DRV0EN Engage drive 1. # C0EB DRV1EN Engage drive 2. # C0EC Q6L Strobe Data Latch for I/O. # C0ED Q6H Load Data Latch. # C0EE Q7H Prepare latch for input (read from disk). # C0EF Q7L Prepare latch for output (write to disk). # Q7L with Q6L = Read # Q7L with Q6H = Sense Write Protect # Q7H with Q6L = Write # Q7H with Q6H = Load Write Latch If( addr[4:8] == 0xE, # (8|6) # Addresses 0-7 simply update a bit in the status register If(addr[0:4] == 0x0, disk_phase[0].eq(0)), If(addr[0:4] == 0x1, disk_phase[0].eq(1)), If(addr[0:4] == 0x2, disk_phase[1].eq(0)), If(addr[0:4] == 0x3, disk_phase[1].eq(1)), If(addr[0:4] == 0x4, disk_phase[2].eq(0)), If(addr[0:4] == 0x5, disk_phase[2].eq(1)), If(addr[0:4] == 0x6, disk_phase[3].eq(0)), If(addr[0:4] == 0x7, disk_phase[3].eq(1)), # Likewise, motor active and drive select update status If(addr[0:4] == 0x8, disk_motor.eq(0)), If(addr[0:4] == 0x9, disk_motor.eq(1)), If(addr[0:4] == 0xA, disk_drive.eq(0)), If(addr[0:4] == 0xB, disk_drive.eq(1)), # Write is ignored and read must be delayed one clock tick If(addr[0:4] == 0xC, disk_reading.eq(1)), #If(addr[0:4]==0xD, disk_ior_wp.eq(1)), #If(addr[0:4]==0xE, disk_write.eq(0)), #If(addr[0:4]==0xF, disk_write.eq(1)), ), ), ] #=============================================================================== # Video Output - Text Mode #=============================================================================== # The Apple II screen memory contains 8 segments containing 3 rows each in a 128 # byte block leaving 8 unused bytes in each of the 8 blocks To assist with # scroll detection, we convert memory addresses to screen coordinates. #=============================================================================== # Video memory - Frame Buffer access shortcuts fbsel = Signal() fb_r = Signal() fb_w = Signal() # Conversion from memory address to X,Y screen coordinates segment = Signal(3) triple = Signal(7) third = Signal(2) horiz = Signal(6) vert = Signal(5) move = Signal() scroll_active = Signal() scroll_match = Signal() scroll_start = Signal() scroll_end = Signal() scroll_read = Signal() scroll_write_valid = Signal() scroll_next_col = Signal() scroll_next_row = Signal() scroll_sequential = Signal() read_horiz = Signal(6) read_vert = Signal(5) repeat_active = Signal() repeat_match = Signal() repeat_start = Signal() repeat_end = Signal() repeat_next_col = Signal() repeat_next_row = Signal() repeat_sequential = Signal() # Registers shared by scroll and repeat compression circuits #horiz_start = Signal(max=40) #vert_start = Signal(max=24) #horiz_end = Signal(max=40) #vert_end = Signal(max=24) prev_horiz = Signal(max=40) prev_vert = Signal(max=24) prev_char = Signal(8) prev_start = Signal() push_save = Signal() push_saving = Signal() fifo_out = Signal(32) self.comb += [ # Detect access to frame memory: Address range 0x0400-0x7ff fbsel.eq((addr[10:15] == 0x1) & active), fb_r.eq(fbsel & ~wren), fb_w.eq(fbsel & wren), # Convert memory address to X,Y coordinates segment.eq(addr[7:10]), triple.eq(addr[0:7]), # TODO This generates reg - change to cause only wire If( triple >= 80, third.eq(2), horiz.eq(addr[0:7] - 80), ).Else( If( triple >= 40, third.eq(1), horiz.eq(addr[0:7] - 40), ).Else( third.eq(0), horiz.eq(addr[0:7]), )), vert.eq(Cat(segment, third)), # TODO Detect scroll - frame buffer read immediately followed by # frame buffer write to character on previous line, directly above. # Scroll is Right to Left (asm: DEY at FC90 in Autostart ROM) scroll_match.eq((horiz == read_horiz) & (vert + 1 == read_vert)), # & (din==read_char)) <== TODO Need to delay din by 1 cycle scroll_write_valid.eq(scroll_read & fb_w & scroll_match), scroll_start.eq(scroll_write_valid & ~scroll_active), # Scroll ends on any write that does not follow the required pattern scroll_end.eq(scroll_active & fb_w & ~scroll_write_valid), scroll_next_col.eq((horiz + 1 == prev_horiz) & (vert == prev_vert)), scroll_next_row.eq((horiz == 39) & (prev_horiz == 0) & (vert == prev_vert + 1)), scroll_sequential.eq(scroll_next_col | scroll_next_row), # Detect repeated charaters (spaces) # Clear is Left to Right (asm: INY at FCA2 in Autostart ROM) # repeat_match.eq(fb_w & (dout==prev_char)), # repeat_start.eq(repeat_match & repeat_sequential & ~repeat_active), # repeat_end.eq(fb_w & repeat_active & # (~repeat_match |~repeat_sequential)), # repeat_next_col.eq((horiz==prev_horiz+1) & (vert==prev_vert)), # repeat_next_row.eq((horiz==0) & (prev_horiz==39) & # (vert==prev_vert+1)), # repeat_sequential.eq(repeat_next_col | repeat_next_row), # repeat_sequential.eq(repeat_next_col), # This or the previous one # Place writes in the fifo self.display_fifo.din[8].eq(0), # Valid is calculated self.display_fifo.din[9].eq(0), # More is calculated #self.display_fifo.din[ 10].eq(move), self.display_fifo.din[11].eq(repeat_end), If( push_save, self.display_fifo.din[0:8].eq(prev_char), self.display_fifo.din[12].eq(prev_start), self.display_fifo.din[13].eq(scroll_end), #self.display_fifo.din[14:16].eq(0), # Reserved self.display_fifo.din[16:22].eq(prev_horiz ), # 2 bits padding self.display_fifo.din[24:29].eq( prev_vert), # 3 bits padding ).Elif( push_saving, # push_save will be valid on the next cycle - so push previous self.display_fifo.din[0:8].eq(prev_char), #self.display_fifo.din[ 8].eq(0), # Valid is calculated #self.display_fifo.din[ 9].eq(0), # More is calculated #self.display_fifo.din[ 10].eq(move), #self.display_fifo.din[ 11].eq(repeat_end), self.display_fifo.din[12].eq(scroll_start), self.display_fifo.din[13].eq(scroll_end), #self.display_fifo.din[14:16].eq(0), # Reserved self.display_fifo.din[16:22].eq(prev_horiz ), # 2 bits padding self.display_fifo.din[24:29].eq( prev_vert), # 3 bits padding ).Else( #self.display_fifo.din.eq(Cat(dout, horiz, vert, # move, scroll_start, scroll_end, repeat_start, repeat_end)), self.display_fifo.din[0:8].eq(dout), #self.display_fifo.din[ 8].eq(0), # Valid is calculated #self.display_fifo.din[ 9].eq(0), # More is calculated #self.display_fifo.din[ 10].eq(move), #self.display_fifo.din[ 11].eq(repeat_end), self.display_fifo.din[12].eq(scroll_start), self.display_fifo.din[13].eq(scroll_end), #self.display_fifo.din[14:16].eq(0), # Reserved self.display_fifo.din[16:22].eq(horiz), # 2 bits padding self.display_fifo.din[24:29].eq(vert), # 3 bits padding ), self.display_fifo.we.eq(push_save | repeat_end | scroll_start | scroll_end | (fb_w & ~scroll_active & ~repeat_active & ~repeat_start)), push_saving.eq(((repeat_end & ~repeat_sequential) | scroll_end) & ~push_save), # Retrieve characters from fifo self.display_fifo.re.eq(self.screen.we), self.screen.we.eq(self.display_fifo.re), self.screen.fields.Valid.eq(self.display_fifo.readable), self.screen.fields.More.eq(self.display_fifo.readable), self.screen.fields.Character.eq(fifo_out[0:8]), self.screen.fields.Horizontal.eq(fifo_out[16:22]), self.screen.fields.Vertical.eq(fifo_out[24:29]), #self.screen.fields.Move.eq(fifo_out[10]), self.screen.fields.Repeat.eq(fifo_out[11]), self.screen.fields.ScrollStart.eq(fifo_out[12]), self.screen.fields.ScrollEnd.eq(fifo_out[13]), ] self.sync += [ fifo_out.eq(self.display_fifo.dout), # Scroll If( scroll_start, scroll_active.eq(1), #horiz_start.eq(horiz), #vert_start.eq(vert), #horiz_end.eq(horiz), #vert_end.eq(vert), ), If( scroll_end, push_save.eq(1), scroll_active.eq(0), # These happen on any write to the frame buffer #prev_horiz.eq(horiz), #prev_vert.eq(vert), #prev_char.eq(dout), prev_start.eq(scroll_start), ), If( fb_r, If((scroll_read & (scroll_sequential | ~scroll_active)) | (repeat_active & repeat_sequential), # A faithful 6502 model issues a read of the target # address before the write cycle of an indirect store # instruction. Do nothing if we suspect the current read is # actually part of a store instruction. ). Else( scroll_read.eq(1), read_horiz.eq(horiz), read_vert.eq(vert), # TODO read_char should be din on the next clock cycle # read_char.eq(dout), ), ), # Write to the frame buffer: remember the location and character # that generate the sequential and repeat signals which are used # by the scroll and clear functions. Also, update scroll signals. If( fb_w, scroll_read.eq(0), prev_vert.eq(vert), prev_horiz.eq(horiz), prev_char.eq(dout), # Repeat - Mostly needed for screen clearing operations but made # generic to conserve bandwidth and allow any character to be # repeated. If( repeat_match & repeat_sequential, # Supress output, begin sequence if not started already # Store location and character as this will be needed if the # following write is not sequential # Setting repeat is redundant if already active repeat_active.eq(1), ).Elif( repeat_active & ~repeat_sequential, # The cursor moved and we must terminate repeat mode # indicating the last character in the sequence. This is # required whether or not the same character is present. # Output saved location with Repeat flag set to mark end. # Then output current signal set on next cycle push_save.eq(1), prev_start.eq(scroll_start), repeat_active.eq(0), ).Else( # Push current character on stack either because: # a. character is different breaking repeat # b. character is different preventing repeat # c. location is not sequential breaking repeat # d. location is not sequential preventing repeat # Cases a,c need to clear repeat. This is irrelevant for b,d repeat_active.eq(0), ), ), # We can safely use the cycle after a write to frame memory as a # second push into the character fifo knowing that the only time the # 6502 has two consecutive write cycles is the JSR instruction which # writes the return address onto the stack, and the RMW instructions # INC, DEC, LSR, ASR, ROL, ROR which write the original and the new # values in two consecutive cycles. It is extremely poor programming # practice to keep the stack inside the frame buffer while clearing # or scrolling the screen so no special handling of these cases is # taken. If( push_save, # Auto-clear after one clock cycle push_save.eq(0), ), ]
def rescale(mod, sig_i, QI, QO): """ Change word length of input signal `sig_i` to `WO` bits, using the quantization and saturation methods specified by ``QO['quant']`` and ``QO['ovfl']``. Parameters ---------- mod: Module (migen) instance of migen module sig_i: Signal (migen) Signal to be requantized QI: dict Quantization dict for input word, only the keys 'WI' and 'WF' for integer and fractional wordlength are evaluated. QI['WI'] = 2 and QI['WF'] = 13 e.g. define Q-Format '2.13' with 2 integer, 13 fractional bits and 1 implied sign bit = 16 bits total. QO: dict Quantization dict for output word format; the keys 'WI' and 'WF' for integer and fractional wordlength are evaluated as well as the keys 'quant' and 'ovfl' describing requantization and overflow behaviour. **Input and output word are aligned at their binary points.** The following shows an example of rescaling an input word from Q2.4 to Q0.3 using wrap-around and truncation. It's easy to see that for simple wrap-around logic, the sign of the result may change. :: S | WI1 | WI0 * WF0 | WF1 | WF2 | WF3 : WI = 2, WF = 4, W = 7 0 | 1 | 0 * 1 | 0 | 1 | 1 = 43 (dec) or 43/16 = 2 + 11/16 (float) * | S * WF0 | WF1 | WF2 : WI = 0, WF = 3, W = 4 0 * 1 | 0 | 1 = 7 (dec) or 7/8 (float) The float or "real (world) value" is calculated by multiplying the integer value by 2 ** (-WF). For requantizing two numbers to the same WI and WF, imagine both binary numbers to be right-aligned. Changes in the number of integer bits `dWI` and fractional bits `dWF` are handled separately. Fractional Bits: - For reducing the number of fractional bits by `dWF`, simply right-shift the integer number by `dWF`. For rounding, add '1' to the bit below the truncation point before right-shifting. - Extend the number of fractional bits by left-shifting the integer by `dWF`, LSB's are filled with zeros. Integer Bits: - For reducing the number of integer bits by `dWI`, simply right-shift the integer by `dWI`. - The number of fractional bits is SIGN-EXTENDED by filling up the left-most bits with the sign bit. """ WI_I = QI['WI'] WI_F = QI['WF'] WI = WI_I + WI_F + 1 WO_I = QO['WI'] WO_F = QO['WF'] WO = WO_I + WO_F + 1 dWF = WI_F - WO_F # difference of fractional lengths dWI = WI_I - WO_I # difference of integer lengths # max. resp. min, output values MIN_o = -1 << (WO - 1) MAX_o = -MIN_o - 1 sig_i_q = Signal((max(WI, WO), True)) sig_o = Signal((WO, True)) logger.debug("rescale: dWI={0}, dWF={1}, QU:{2}, OV:{3}".format( dWI, dWF, QO['quant'], QO['ovfl'])) if dWF <= 0: # extend fractional word length of output word mod.comb += sig_i_q.eq(sig_i << -dWF) # shift input right by -dWF else: # dWF > 0, fractional output word length needs to be shortened if QO['quant'] == 'round': # add half an LSB (1 << (dWF - 1)) and divide by 2^dWF (shift left by dWF) mod.comb += sig_i_q.eq((sig_i + (1 << (dWF - 1))) >> dWF) elif QO['quant'] == 'floor': # just divide by 2^dWF (shift left by dWF) mod.comb += sig_i_q.eq(sig_i >> dWF) elif QO['quant'] == 'fix': # add sign bit as LSB (1 << dWF) and divide by 2^dWF (shift left by dWF) mod.comb += sig_i_q.eq((sig_i + (sig_i[-1] << dWF)) >> dWF) else: raise Exception(u'Unknown quantization method "%s"!' % (QI['quant'])) if dWI < 0: # WI_I < WO_I, sign extend integer part #mod.comb += sig_o.eq(sig_i_q >> -dWI) mod.comb += sig_o.eq(Cat(sig_i_q, Replicate(sig_i_q[-1], -dWI))) elif dWI == 0: # WI = WO, don't change integer part mod.comb += sig_o.eq(sig_i_q) elif QO['ovfl'] == 'sat': mod.comb += \ If(sig_i_q[-1] == 1, If(sig_i_q < MIN_o, #If(sig_i_q[-dWI-1:-1] != Replicate(sig_i_q[-1], dWI), sig_o.eq(MIN_o) ).Else(sig_o.eq(sig_i_q))#[:-dWI-1]))# >> dWI ).Elif(sig_i_q > MAX_o, #).Elif(sig_i_q[WO-1:] == 0b01, sig_o.eq(MAX_o) ).Else(sig_o.eq(sig_i_q)#[:-dWI-1])# >> dWI) ) elif QO['ovfl'] == 'wrap': # wrap around (shift left) mod.comb += sig_o.eq(sig_i_q) # >> dWI) #mod.comb += sig_o.eq(Replicate(sig_i_q[-1], abs(dWI))) #mod.comb += sig_o.eq(sig_i_q[-dWI-1:-1]) # ============================================================================= # If(sig_i_q[-1] == 1, # If(sig_i_q[-1:-dWI-1] != Replicate(sig_i_q[-1], dWI), # #If(sig_i_q < MIN_o, # #If(sig_i_q[WO-1:] == 0b10, # sig_o.eq(MIN_o) # ).Else(sig_o.eq(sig_i_q)# >> dWI # ).Elif(sig_i_q > MAX_o, # #).Elif(sig_i_q[WO-1:] == 0b01, # sig_o.eq(MAX_o) # ).Else(sig_o.eq(sig_i_q)# >> dWI) # ) # ============================================================================= else: raise Exception(u'Unknown overflow method "%s"!' % (QI['ovfl'])) return sig_o
def init_submodules( self, width, signal_width, coeff_width, chain_factor_bits, platform ): sys_double = ClockDomainsRenamer("sys_double") self.submodules.logic = LinienLogic(chain_factor_width=chain_factor_bits) self.submodules.analog = PitayaAnalog( platform.request("adc"), platform.request("dac") ) self.submodules.xadc = XADC(platform.request("xadc")) for i in range(4): pwm = platform.request("pwm", i) ds = sys_double(DeltaSigma(width=15)) self.comb += pwm.eq(ds.out) setattr(self.submodules, "ds%i" % i, ds) exp = platform.request("exp") self.submodules.gpio_n = Gpio(exp.n) self.submodules.gpio_p = Gpio(exp.p) leds = Cat(*(platform.request("user_led", i) for i in range(8))) self.comb += leds.eq(self.gpio_n.o) self.submodules.dna = DNA(version=2) self.submodules.fast_a = FastChain( width, signal_width, coeff_width, self.logic.mod, offset_signal=self.logic.chain_a_offset_signed, ) self.submodules.fast_b = FastChain( width, signal_width, coeff_width, self.logic.mod, offset_signal=self.logic.chain_b_offset_signed, ) sys_slow = ClockDomainsRenamer("sys_slow") sys_double = ClockDomainsRenamer("sys_double") max_decimation = 16 self.submodules.decimate = sys_double(Decimate(max_decimation)) self.clock_domains.cd_decimated_clock = ClockDomain() decimated_clock = ClockDomainsRenamer("decimated_clock") self.submodules.slow = decimated_clock(SlowChain()) self.submodules.scopegen = ScopeGen(signal_width) self.state_names, self.signal_names = cross_connect( self.gpio_n, [ ("fast_a", self.fast_a), ("fast_b", self.fast_b), ("slow", self.slow), ("scopegen", self.scopegen), ("logic", self.logic), ("robust", self.logic.autolock.robust), ], ) csr_map = { "dna": 28, "xadc": 29, "gpio_n": 30, "gpio_p": 31, "fast_a": 0, "fast_b": 1, "slow": 2, "scopegen": 6, "noise": 7, "logic": 8, } self.submodules.csrbanks = csr_bus.CSRBankArray( self, lambda name, mem: csr_map[ name if mem is None else name + "_" + mem.name_override ], ) self.submodules.sys2csr = Sys2CSR() self.submodules.csrcon = csr_bus.Interconnect( self.sys2csr.csr, self.csrbanks.get_buses() ) self.submodules.syscdc = SysCDC() self.comb += self.syscdc.target.connect(self.sys2csr.sys)
def add_xgmii(self): self.submodules.xgmii = XilinxXGMII(self.crg.cd_sys, self.platform) self.add_csr('xgmii') self.platform.add_period_constraint(self.xgmii.cd_clkmgt.clk, 1e9/156.25e6) self.platform.add_false_path_constraints(self.crg.cd_sys.clk, self.xgmii.cd_clkmgt.clk) self.submodules.xgmiiphy = LiteEthPHYXGMII(self.xgmii.pads, self.xgmii.pads) # Keeping this away from sys_clk domain, and strictly leaving it in 156.25e6 self.submodules.teng_udp_core = ClockDomainsRenamer("clkmgt")(LiteEthUDPIPCore(self.xgmiiphy, 0xaa1233445566, convert_ip("10.1.0.3"), self.sys_clk_freq, dw=64)) self.add_csr("xgmiiphy") self.udp_port = udp_port = self.teng_udp_core.udp.crossbar.get_port(3000, 64) send_pkt = Signal(reset=0) always_xmit = True if always_xmit: send_pkt_counter_d = Signal() self.sync.clkmgt += [ send_pkt_counter_d.eq(self.counter[26]), send_pkt.eq(send_pkt_counter_d ^ self.counter[26]) ] sink_counter = Signal(16) SINK_LENGTH = 64 # 8 words shift = log2_int(64 // 8) # bits required to represent bytes per word words_per_packet = SINK_LENGTH >> shift # Note the clkmgt domain self.sync.clkmgt += [ If(send_pkt, sink_counter.eq(words_per_packet)), If((sink_counter > 0) & (udp_port.sink.ready == 1), sink_counter.eq(sink_counter - 1) ).Else( udp_port.sink.valid.eq(0), udp_port.sink.last.eq(0) ), udp_port.sink.valid.eq(sink_counter > 0), udp_port.sink.last.eq(sink_counter == 1), If(sink_counter == 1, udp_port.sink.last_be.eq(0x80) ).Else( udp_port.sink.last_be.eq(0x0) ) ] self.comb += self.user_leds[1].eq(udp_port.sink.valid) self.comb += [ # param udp_port.sink.src_port.eq(3000), udp_port.sink.dst_port.eq(7778), udp_port.sink.ip_address.eq(convert_ip("10.1.0.4")), udp_port.sink.length.eq(SINK_LENGTH), # payload udp_port.sink.data.eq(Cat(0xc0ffeec1ffee, sink_counter)), udp_port.sink.error.eq(0) ] self.add_csr("teng_udp_core")
def __init__(self, pads): self.pads = pads self.bus = bus = Interface(adr_width=22) self.dly_io = delayf_pins() self.dly_clk = delayf_pins() # # # clk = Signal() cs = Signal() ca = Signal(48) sr_in = Signal(64) sr_out = Signal(64) sr_rwds_in = Signal(8) sr_rwds_out = Signal(8) timeout_counter = Signal(6) self.submodules.phy = phy = HyperBusPHY(pads) self.comb += [ phy.dly_io.eq(self.dly_io), phy.dly_clk.eq(self.dly_clk), ] # Drive rst_n, from internal signals --------------------------------------------- if hasattr(pads, "rst_n"): self.comb += pads.rst_n.eq(1) self.comb += [phy.cs.eq(~cs), phy.clk_enable.eq(clk)] # Data In/Out Shift Registers ------------------------------------------------- self.sync += [ sr_out.eq(Cat(Signal(32), sr_out[:32])), sr_in.eq(Cat(phy.dq.i, sr_in[:32])), sr_rwds_in.eq(Cat(phy.rwds.i, sr_rwds_in[:4])), sr_rwds_out.eq(Cat(phy.rwds.i, sr_rwds_out[:4])), ] self.comb += [ bus.dat_r.eq(Cat(phy.dq.i[-16:], sr_in[:16])), # To Wishbone phy.dq.o.eq(sr_out[-32:]), # To HyperRAM phy.rwds.o.eq(sr_rwds_out[-4:]) # To HyperRAM ] # Command generation ----------------------------------------------------------------------- self.comb += [ ca[47].eq(~self.bus.we), # R/W# ca[45].eq(1), # Burst Type (Linear) ca[16:35].eq(self.bus.adr[2:21]), # Row & Upper Column Address ca[1:3].eq(self.bus.adr[0:2]), # Lower Column Address ca[0].eq(0), # Lower Column Address ] # FSM Sequencer -------------------------------------------------------------------------------- self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(bus.cyc & bus.stb, NextValue(cs, 1), NextState("CA-SEND"))) fsm.act("CA-SEND", NextValue(clk, 1), NextValue(phy.dq.oe, 1), NextValue(sr_out, Cat(Signal(16), ca)), NextState("CA-WAIT")) fsm.act("CA-WAIT", NextValue(timeout_counter, 0), NextState("LATENCY")) fsm.act("LATENCY", NextValue(phy.dq.oe, 0), NextState("LATENCY-WAIT")) fsm.delayed_enter("LATENCY-WAIT", "READ-WRITE-SETUP", 3) fsm.act("READ-WRITE-SETUP", NextValue(phy.dq.oe, self.bus.we), NextValue(phy.rwds.oe, self.bus.we), NextState("READ-WRITE")) fsm.act( "READ-WRITE", NextState("READ-ACK"), If( self.bus.we, NextValue(phy.dq.oe, 1), # Write Cycle NextValue(sr_out[:32], 0), NextValue(sr_out[32:], self.bus.dat_w), NextValue(sr_rwds_out[:4], 0), NextValue(sr_rwds_out[4:], ~bus.sel[0:4]), bus.ack.eq(1), # Get next byte NextState("CLK-OFF"), If( bus.cti == 0b010, NextState("READ-WRITE"), ))) fsm.act( "READ-ACK", NextValue(timeout_counter, timeout_counter + 1), If(phy.rwds.i[3], NextValue(timeout_counter, 0), bus.ack.eq(1), If(bus.cti != 0b010, NextValue(clk, 0), NextState("CLEANUP"))), If(~self.bus.cyc | (timeout_counter > 20), NextState("CLK-OFF"))) fsm.act("CLK-OFF", NextValue(clk, 0), NextState("CLEANUP")) fsm.act("CLEANUP", NextValue(cs, 0), NextValue(phy.rwds.oe, 0), NextValue(phy.dq.oe, 0), NextState("HOLD-WAIT")) fsm.act("HOLD-WAIT", NextValue(sr_out, 0), NextValue(sr_rwds_out, 0), NextState("WAIT")) fsm.delayed_enter("WAIT", "IDLE", 10) # Signals that can be an ILA for debugging self.dbg = [ bus, sr_out, sr_in, sr_rwds_in, sr_rwds_out, cs, clk, phy.dq.i, phy.dq.o, phy.dq.oe, phy.rwds.i, phy.rwds.o, phy.rwds.oe, ]
def __init__(self, ddr_wr_port, ddr_rd_port, udp_port, adc_source, adc_dw): SIZE = 1024 * 1024 self.fifo_full = CSRStatus(reset=0) self.fifo_error = CSRStatus(reset=0) self.fifo_load = CSRStorage(reset=0) self.fifo_read = CSRStorage(reset=0) self.fifo_size = CSRStorage(32, reset=SIZE) self.dst_ip = CSRStorage(32, reset=convert_ip("192.168.1.114")) self.dst_port = CSRStorage(16, reset=7778) self.fifo_counter = fifo_counter = Signal(24) self.load_fifo = load_fifo = Signal() dw = ddr_wr_port.data_width print( f"Write port: A ({ddr_wr_port.address_width})/ D ({ddr_wr_port.data_width})" ) print( f"Read port: A ({ddr_rd_port.address_width})/ D ({ddr_rd_port.data_width})" ) print(f"dw: {dw}; adc_dw: {adc_dw}") self.submodules.dram_fifo = dram_fifo = LiteDRAMFIFO( data_width=dw, base=0, depth=SIZE * (dw // 8), # liteDRAM expects this in bytes write_port=ddr_wr_port, read_port=ddr_rd_port, ) self.adc_data = adc_data = Signal(dw) DW_RATIO = dw // adc_dw log_dw_ratio = log2_int(DW_RATIO) word_count = Signal(log_dw_ratio) word_count_d = Signal(log_dw_ratio) self.sync += [ If(adc_source.valid, adc_data.eq(Cat(adc_data[adc_dw:], adc_source.data)), word_count.eq(word_count + 1)), word_count_d.eq(word_count), ] self.comb += [ dram_fifo.sink.valid.eq((word_count == 0) & (word_count_d != 0) & load_fifo), dram_fifo.sink.data.eq(adc_data) ] fifo_size = Signal(32) self.sync += [ fifo_size.eq(self.fifo_size.storage), If(self.fifo_load.re & self.fifo_load.storage, fifo_counter.eq(0), load_fifo.eq(1)), If(load_fifo & adc_source.valid, self.fifo_full.status.eq(0), self.fifo_error.status.eq(~dram_fifo.dram_fifo.ctrl.writable), fifo_counter.eq(fifo_counter + 1)), If((fifo_counter == fifo_size - 1) & adc_source.valid, load_fifo.eq(0), self.fifo_full.status.eq(1)), ] # fifo --> stride converter self.submodules.stride_converter = sc = stream.Converter( dw, udp_port.dw) self.read_from_dram_fifo = read_from_dram_fifo = Signal() self.comb += [dram_fifo.source.connect(sc.sink)] self.receive_count = receive_count = Signal(24) self.sync += [ If(dram_fifo.source.valid & dram_fifo.source.ready, receive_count.eq(receive_count + 1)).Elif( read_from_dram_fifo == 0, receive_count.eq(0)) ] # --> udp fragmenter --> self.submodules.udp_fragmenter = udp_fragmenter = UDPFragmenter( udp_port.dw) self.sync += read_from_dram_fifo.eq(self.fifo_read.storage) self.comb += If( read_from_dram_fifo, # TODO: There is a bug somewhere in the converter, # its source.last somehow gets set, no idea why. That signal is of no real use # for the fragmenter anyways, so we live without it sc.source.connect(udp_fragmenter.sink, omit={'total_size', 'last'})) # TODO: 8 should be adcstream data width // 8 self.comb += udp_fragmenter.sink.length.eq( fifo_size << log2_int(adc_dw // 8)) self.comb += udp_fragmenter.source.connect(udp_port.sink) self.comb += [ # param udp_port.sink.src_port.eq(4321), udp_port.sink.dst_port.eq(self.dst_port.storage), udp_port.sink.ip_address.eq(self.dst_ip.storage), # udp_port.sink.ip_address.eq(convert_ip("192.168.88.101")), # payload udp_port.sink.error.eq(0) ]
def __init__(self, c2): txwidth = 13 txlen = Signal(max=txwidth + 1) txbuf = Signal(txwidth) rxbuf = Signal(8) rxlen = Signal(4) waitlen = Signal(7) rfull = Signal() readerror = Signal() reset_count = Signal(max=961) self._cmd = CSRStorage(8) self._stat = CSRStatus(8) self._rxbuf = CSRStatus(8) self.comb += self._rxbuf.status.eq(rxbuf) self._txdat = CSRStorage(8) c2d = TSTriple() c2ck = Signal(reset=1) self.comb += c2.c2ck.eq(c2ck) self.specials += c2d.get_tristate(c2.c2d) self._pwcon = CSRStorage(8, reset=1) self._glitchoff = CSRStorage(32) self._glitchlen = CSRStorage(8) glitchout = Signal() glitchmode = Signal() glitchtmr = Signal(32) self.comb += c2.power.eq(self._pwcon.storage[0] & glitchout) self.sync += If(self._pwcon.storage[1], self._pwcon.storage[1].eq(0), glitchmode.eq(0), glitchtmr.eq(self._glitchoff.storage)) self.sync += If(glitchtmr == 0, glitchout.eq(1)).Else( glitchtmr.eq(glitchtmr - 1), glitchout.eq(~glitchmode), If( glitchtmr == 1, If(glitchmode == 0, glitchtmr[:8].eq(self._glitchlen.storage), glitchmode.eq(1)))) # when rxbuf is read, reset the buffer full flag self.sync += If(self._rxbuf.we, rfull.eq(0)) fsm = FSM(reset_state="IDLE") self.submodules.fsm = fsm fsm.act( "IDLE", c2d.oe.eq(0), NextValue(c2ck, 1), If( self._cmd.storage == 1, # data read NextValue(self._cmd.storage, 0), NextValue(txbuf, 1), # start(1), data read (00), length (00) NextValue(txlen, 5), NextValue(rxlen, 8), NextValue(readerror, 0), NextValue(waitlen, 127), NextState("TX")).Elif( self._cmd.storage == 2, # address write NextValue(self._cmd.storage, 0), # start (1), address write (11), address NextValue(txbuf, (self._txdat.storage << 3) | 7), NextValue(txlen, 11), NextValue(rxlen, 0), NextValue(waitlen, 0), NextState("TX")).Elif( self._cmd.storage == 3, # address read NextValue(self._cmd.storage, 0), NextValue(waitlen, 0), NextValue(txbuf, 5), # start (1), address read (01) NextValue(txlen, 3), NextValue(waitlen, 0), # no wait NextValue(rxlen, 8), # read 8 bits NextValue(readerror, 0), NextState("TX")).Elif( self._cmd.storage == 4, # data write NextValue(self._cmd.storage, 0), NextValue(waitlen, 0), # start (1), data write (10), length (00), data NextValue(txbuf, (self._txdat.storage << 5) | 3), NextValue(txlen, 13), NextValue(waitlen, 127), # wait at the end NextValue(rxlen, 0), # no read NextState("TX")).Elif( self._cmd.storage == 5, # reset NextValue(self._cmd.storage, 0), NextValue(reset_count, 960), # 20us at 48MHz NextValue(c2ck, 0), NextState("RESET"))) fsm.act( "RESET", # 20us reset line low NextValue(c2ck, 0), If( reset_count == 0, NextValue(reset_count, 96), # 2us at 48MHz NextState("RESET2")).Else( NextValue(reset_count, reset_count - 1), )) fsm.act( "RESET2", # 2us reset line high NextValue(c2ck, 1), If(reset_count == 0, NextState("IDLE")).Else(NextValue(reset_count, reset_count - 1), )) fsm.act( "TX", # clk initially 1 here c2d.oe.eq(1), If( txlen == 0, If( waitlen != 0, NextState("WAIT"), ).Elif( rxlen != 0, NextState("RX"), ).Else(NextState("STOP")), NextValue(c2ck, 0)). Else( If( c2ck == 1, # clock is high, about to drop the next bit NextValue(c2d.o, txbuf[0]), NextValue(txbuf, txbuf[1:])). Else( # clock is low, about to raise it and potentially advance to the next state NextValue(txlen, txlen - 1)), NextValue(c2ck, ~c2ck))) fsm.act( "WAIT", # must enter state with c2ck already at 0 c2d.oe.eq(0), If((c2ck == 1) & (c2d.i == 1), If(rxlen != 0, NextState("RX")).Else(NextState("STOP")), NextValue(c2ck, 0)).Else( If(waitlen == 0, NextValue(readerror, 1), NextState("IDLE")).Else(NextValue(waitlen, waitlen - 1), NextValue(c2ck, ~c2ck)))) fsm.act( "RX", # must enter state with c2ck already at 0 c2d.oe.eq(0), If( c2ck == 1, # clock is high, shift in bit as it falls NextValue(rxbuf, Cat(rxbuf[1:], c2d.i)), If(rxlen == 1, NextValue(rfull, 1), NextState("STOP")), NextValue(c2ck, 0), NextValue(rxlen, rxlen - 1), ).Else(NextValue(c2ck, 1))) fsm.act( "STOP", # must enter state with c2ck already at 0 c2d.oe.eq(0), If( c2ck == 1, # stop done NextState("IDLE")).Else(NextValue(c2ck, 1))) # status register byte: # | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | # | ERR | RRDY | . | . | WAIT | RX | TX | IDLE | self.comb += self._stat.status.eq( fsm.ongoing("IDLE") | (fsm.ongoing("TX") << 1) | (fsm.ongoing("RX") << 2) | (fsm.ongoing("WAIT") << 3) | (rfull << 6) | (readerror << 7)) # for debugging, expose internals self._txlen = CSRStatus(5) self._txbuf = CSRStatus(12) self._rxlen = CSRStatus(4) self._waitlen = CSRStatus(7) self.comb += self._txlen.status.eq(txlen) self.comb += self._txbuf.status.eq(txbuf) self.comb += self._rxlen.status.eq(rxlen) self.comb += self._waitlen.status.eq(waitlen)
def __init__( self, core_link_pads: typing.Sequence[platform.Pins], output_pads: typing.Sequence[platform.Pins], passthrough_sigs: typing.Sequence[Signal], input_phys: typing.Sequence["PHY"], simulate: bool = False, ): """Define the submodules & connections between them to form an ``Entangler``. Args: core_link_pads (typing.Sequence[platform.Pins]): A list of 4 FPGA pins used to link a master & slave ``Entangler`` device. output_pads (typing.Sequence[platform.Pins]): The output pins that will be driven by the state machines to output the entanglement generation signals. passthrough_sigs (typing.Sequence[Signal]): The signals that should be passed through to the ``output_pads`` when the ``Entangler`` is not running. input_phys (typing.Sequence["PHY"]): TTLInput physical gateware modules that register an input TTL event. Expects a list of 4, with the first 4 being the input APD/TTL signals, and the last one as a sync signal with the entanglement laser. simulate (bool, optional): If this should be instantiated in simulation mode. If it is simulated, it disables several options like the passthrough_sigs. Defaults to False. """ self.enable = Signal() # # # phy_apds = input_phys[0:4] phy_422pulse = input_phys[4] self.submodules.msm = MainStateMachine() self.submodules.sequencers = [ ChannelSequencer(self.msm.m) for _ in range(4) ] self.submodules.apd_gaters = [ TriggeredInputGater(self.msm.m, phy_422pulse, phy_apd) for phy_apd in phy_apds ] self.submodules.heralder = PatternMatcher(num_inputs=4, num_patterns=4) if not simulate: # To be able to trigger the pulse picker from both systems without # re-plugging cables, we OR the output from the slave (transmitted over the # core link ribbon cable) into the master, as long as the entangler core is # not actually active. There is no mechanism to arbitrate between concurrent # users at this level; the application code must ensure only one experiment # requiring the pulsed laser runs at a time. local_422ps_out = Signal() slave_422ps_raw = Signal() # Connect output pads to sequencer output when enabled, otherwise use # the RTIO phy output for i, (sequencer, pad, passthrough_sig) in enumerate( zip(self.sequencers, output_pads, passthrough_sigs)): if i == SEQUENCER_IDX_422ps: local_422ps_out = Mux(self.enable, sequencer.output, passthrough_sig) passthrough_sig = passthrough_sig | (slave_422ps_raw & self.msm.is_master) self.specials += Instance( "OBUFDS", i_I=Mux(self.enable, sequencer.output, passthrough_sig), o_O=pad.p, o_OB=pad.n, ) # Connect the "running" output, which is asserted when the core is # running, or controlled by the passthrough signal when the core is # not running. self.specials += Instance( "OBUFDS", i_I=Mux(self.msm.running, 1, passthrough_sigs[4]), o_O=output_pads[4].p, o_OB=output_pads[4].n, ) def ts_buf(pad, sig_o, sig_i, en_out): # diff. IO. # sig_o: output from FPGA # sig_i: intput to FPGA # en_out: enable FPGA output driver self.specials += Instance( "IOBUFDS_INTERMDISABLE", p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", p_USE_IBUFDISABLE="TRUE", i_IBUFDISABLE=en_out, i_INTERMDISABLE=en_out, i_I=sig_o, o_O=sig_i, i_T=~en_out, io_IO=pad.p, io_IOB=pad.n, ) # Interface between master and slave core. # Slave -> master: ts_buf( core_link_pads[0], self.msm.ready, self.msm.slave_ready_raw, ~self.msm.is_master & ~self.msm.standalone, ) ts_buf(core_link_pads[4], local_422ps_out, slave_422ps_raw, ~self.msm.is_master) # Master -> slave: ts_buf( core_link_pads[1], self.msm.trigger_out, self.msm.trigger_in_raw, self.msm.is_master, ) ts_buf( core_link_pads[2], self.msm.success, self.msm.success_in_raw, self.msm.is_master, ) ts_buf( core_link_pads[3], self.msm.timeout, self.msm.timeout_in_raw, self.msm.is_master, ) # Connect heralder inputs. self.comb += self.heralder.sig.eq( Cat(*(g.triggered for g in self.apd_gaters))) # Clear gater and sequencer state at start of each cycle self.comb += [ gater.clear.eq(self.msm.cycle_starting) for gater in self.apd_gaters ] self.comb += [ sequencer.clear.eq(self.msm.cycle_starting) for sequencer in self.sequencers ] self.comb += self.msm.herald.eq(self.heralder.is_match) # 422ps trigger event counter. We use got_ref from the first gater for # convenience (any other channel would work just as well). self.triggers_received = Signal(14) self.sync += [ If(self.msm.run_stb, self.triggers_received.eq(0)).Else( If( self.msm.cycle_ending & self.apd_gaters[0].got_ref, self.triggers_received.eq(self.triggers_received + 1), )) ]
def __init__(self, cd_sys, platform, dw=64): self._reset = CSRStorage(reset=0) self._pcs_status = CSRStatus(fields=[ CSRField("pcs_fault", size=1, offset=1), CSRField("pcs_fault_rx", size=1, offset=2), CSRField("pcs_fault_tx", size=1, offset=3), ]) self._pcs_config = CSRStorage(reset=0, fields=[ CSRField("pcs_clear", size=1, offset=0, pulse=True), ]) self.clock_domains.cd_clkmgt = ClockDomain() self.tx_data = Signal(dw) self.tx_ctl = Signal(dw//8) self.rx_data = Signal(dw) self.rx_ctl = Signal(dw//8) self.pma_status = Signal(448) _pma_status = Signal(448) txusrclk = Signal() txusrclk2 = Signal() drp_req = Signal() drp_daddr_o = Signal(16) drp_den_o = Signal() drp_di_o = Signal(16) drp_dwe_o = Signal() drp_drpdo_i = Signal(16) drp_drdy_i = Signal() drp_den_i = Signal() refclk_pads = platform.request("user_sma_mgt_refclk") rx_pads = platform.request("sfp_rx") tx_pads = platform.request("sfp_tx") self.tx_disable = Signal() self.qplllock = Signal() self.gtrxreset = Signal() self.gttxreset = Signal() self.txusrrdy = Signal() self.coreclk = Signal() self.comb += [ platform.request("sfp_tx_disable_n").eq(~self.tx_disable), ] self.pcs_clear = pcs_clear = Signal() config_vector = Signal(536, reset=0) self.submodules.ps = PulseSynchronizer("sys", "clkmgt") self.pma_multi = pma_multi = Signal(3) self.specials += MultiReg(Cat(self.pma_status[250:252], self.pma_status[231]), pma_multi) self.comb += [ self.ps.i.eq(self._pcs_config.fields.pcs_clear), pcs_clear.eq(self.ps.o), self._pcs_status.fields.pcs_fault_rx.eq(pma_multi[0]), self._pcs_status.fields.pcs_fault_tx.eq(pma_multi[1]), self._pcs_status.fields.pcs_fault.eq(pma_multi[2]) ] self.comb += [ ClockSignal("clkmgt").eq(self.coreclk) ] self.sync.clkmgt += [ config_vector[517].eq(pcs_clear), self.pma_status.eq(_pma_status) ] self.specials += Instance( "ten_gig_eth_pcs_pma_0", i_refclk_p=refclk_pads.p, i_refclk_n=refclk_pads.n, i_reset=self._reset.storage, # o_resetdone_out= o_coreclk_out=self.coreclk, # rxrecclkout_0=rxrecclkout_0, # What is i_rxp=rx_pads.p, i_rxn=rx_pads.n, o_txp=tx_pads.p, o_txn=tx_pads.n, i_dclk=cd_sys.clk, i_sim_speedup_control=0, o_txusrclk_out=txusrclk, o_txusrclk2_out=txusrclk2, # UltraScale only #o_areset_datapathclk_out= o_qplllock_out=self.qplllock, o_txuserrdy_out=self.txusrrdy, #o_reset_counter_done=, # UltraScale only o_gttxreset_out=self.gttxreset, o_gtrxreset_out=self.gtrxreset, # TODO Set it to 5 seconds? o_xgmii_rxd=self.rx_data, o_xgmii_rxc=self.rx_ctl, i_xgmii_txd=self.tx_data, i_xgmii_txc=self.tx_ctl, i_configuration_vector=config_vector, o_status_vector=_pma_status, # o_core_status=, # tx_resetdone=, # rx_resetdone=, # Connects to sfp+ i_signal_detect=1, i_tx_fault=0, # Unused inside the core o_tx_disable=self.tx_disable, i_pma_pmd_type=0b111, # DRP Stuff o_drp_req=drp_req, i_drp_gnt=drp_req, o_drp_daddr_o=drp_daddr_o, o_drp_den_o=drp_den_o, o_drp_di_o=drp_di_o, o_drp_dwe_o=drp_dwe_o, i_drp_drpdo_i=drp_drpdo_i, i_drp_drdy_i=drp_drdy_i, i_drp_daddr_i=drp_daddr_o, i_drp_den_i=drp_den_o, i_drp_di_i=drp_di_o, i_drp_dwe_i=drp_dwe_o, o_drp_drpdo_o=drp_drpdo_i, o_drp_drdy_o=drp_drdy_i, ) class Pads: rx = ClockSignal("clkmgt") rx_ctl = self.rx_ctl rx_data = self.rx_data tx = ClockSignal("clkmgt") tx_ctl = self.tx_ctl tx_data = self.tx_data self.pads = Pads()
def __init__(self, core_link_pads, output_pads, passthrough_sigs, input_phys, simulate=False): """ Define the interface between an ARTIQ RTIO bus and low-level gateware. Args: core_link_pads: EEM pads for inter-Kasli link output_pads: pads for 4 output signals (422sigma, 1092, 422 ps trigger, aux) passthrough_sigs: signals from output phys, connected to output_pads when core not running input_phys: serdes phys for 5 inputs – APD0-3 and 422ps trigger in """ self.rtlink = rtlink.Interface( rtlink.OInterface(data_width=32, address_width=5, enable_replace=False), rtlink.IInterface(data_width=14, timestamped=True), ) # # # self.submodules.core = ClockDomainsRenamer("rio")(EntanglerCore( core_link_pads, output_pads, passthrough_sigs, input_phys, simulate=simulate, )) read_en = self.rtlink.o.address[4] write_timings = Signal() self.comb += [ self.rtlink.o.busy.eq(0), write_timings.eq(self.rtlink.o.address[3:5] == 1), ] output_t_starts = [seq.m_start for seq in self.core.sequencers] output_t_ends = [seq.m_stop for seq in self.core.sequencers] output_t_starts += [gater.gate_start for gater in self.core.apd_gaters] output_t_ends += [gater.gate_stop for gater in self.core.apd_gaters] cases = {} for i in range(len(output_t_starts)): cases[i] = [ output_t_starts[i].eq(self.rtlink.o.data[:16]), output_t_ends[i].eq(self.rtlink.o.data[16:]), ] # Write timeout counter and start core running self.comb += [ self.core.msm.time_remaining_buf.eq(self.rtlink.o.data), self.core.msm.run_stb.eq((self.rtlink.o.address == 1) & self.rtlink.o.stb), ] self.sync.rio += [ If( write_timings & self.rtlink.o.stb, Case(self.rtlink.o.address[:3], cases), ), If( (self.rtlink.o.address == 0) & self.rtlink.o.stb, # Write config self.core.enable.eq(self.rtlink.o.data[0]), self.core.msm.standalone.eq(self.rtlink.o.data[2]), ), If( (self.rtlink.o.address == 2) & self.rtlink.o.stb, # Write cycle length self.core.msm.m_end.eq(self.rtlink.o.data[:10]), ), If( (self.rtlink.o.address == 3) & self.rtlink.o.stb, # Write herald patterns and enables *[ self.core.heralder.patterns[i].eq( self.rtlink.o.data[4 * i:4 * (i + 1)] # noqa ) for i in range(4) ], self.core.heralder.pattern_ens.eq(self.rtlink.o.data[16:20])), ] # Write is_master bit in rio_phy reset domain to not break 422ps trigger # forwarding on core.reset(). self.sync.rio_phy += If( (self.rtlink.o.address == 0) & self.rtlink.o.stb, self.core.msm.is_master.eq(self.rtlink.o.data[1]), ) read = Signal() read_timings = Signal() read_addr = Signal(3) # Input timestamps are [apd0, apd1, apd2, apd3, ref] input_timestamps = [gater.sig_ts for gater in self.core.apd_gaters] input_timestamps.append(self.core.apd_gaters[0].ref_ts) cases = {} timing_data = Signal(14) for i, ts in enumerate(input_timestamps): cases[i] = [timing_data.eq(ts)] self.comb += Case(read_addr, cases) self.sync.rio += [ If(read, read.eq(0)), If( self.rtlink.o.stb, read.eq(read_en), read_timings.eq(self.rtlink.o.address[3:5] == 0b11), read_addr.eq(self.rtlink.o.address[:3]), ), ] status = Signal(3) self.comb += status.eq( Cat(self.core.msm.ready, self.core.msm.success, self.core.msm.timeout)) reg_read = Signal(14) cases = {} cases[0] = [reg_read.eq(status)] cases[1] = [reg_read.eq(self.core.msm.cycles_completed)] cases[2] = [reg_read.eq(self.core.msm.time_remaining)] cases[3] = [reg_read.eq(self.core.triggers_received)] self.comb += Case(read_addr, cases) # Generate an input event if we have a read request RTIO Output event, or if the # core has finished. If the core is finished output the herald match, or 0x3fff # on timeout. # # Simultaneous read requests and core-done events are not currently handled, but # are easy to avoid in the client code. self.comb += [ self.rtlink.i.stb.eq(read | self.core.enable & self.core.msm.done_stb), self.rtlink.i.data.eq( Mux( self.core.enable & self.core.msm.done_stb, Mux(self.core.msm.success, self.core.heralder.matches, 0x3FFF), Mux(read_timings, timing_data, reg_read), )), ]
def __init__(self, testcase, dut_class, args=None, specials=None): self.i_go = Signal() # Unused for now. # Outputs #: Signal: up if the test process is over. self.o_over = Signal() #: Signal: up if the test result is successful. Relevant only when # `o_over` is up. self.o_success = Signal(reset=1) # Locals #: dict: association between DUT's output signals names and signals. self._test_outs = self._make_outputs_signals(testcase.io_decl) #: Signal(n): concatenation of all signals contained in # `self.test_outs`. self._cat_test_outs = Cat( [signal for _, signal in self._test_outs.items()]) # Sub-modules #: Module: device under test's module instance. self._dut = dut_class() if args is None else dut_class(*args) self.submodules += self._dut # Specials if specials is not None: self.specials += specials ### cases = {} tick_count = 0 in_q, exp_q = testcase.get_io_queues() while not in_q.empty() or not exp_q.empty(): cases[tick_count] = [] in_values = None if in_q.empty() else in_q.get() if in_values is not None: cases[tick_count] += self._make_inputs_applications(in_values) exp_values = None if exp_q.empty() else exp_q.get() if exp_values is not None: cases[tick_count] += self._make_outputs_checker(exp_values) tick_count += 1 # Counter initialization using `tick_count` counter = Counter(tick_count + 2) self.submodules += counter self.sync += Case(counter.o, cases) # `self.o_over` control self.comb += [self.o_over.eq(counter.o == tick_count + 1)] # `self.o_success` control self.sync += [ If(self.o_success == 1, self.o_success.eq(self._cat_test_outs == 0)) .Else( self.o_success.eq(0)) ]