def __init__(self): self._storage = csr.CSRStorage(fields=[ csr.CSRField( "foo", size=4, offset=0, reset=0xa, description="foo"), csr.CSRField("bar", size=8, offset=16, reset=0x5a, description="bar") ]) self._status = csr.CSRStatus(fields=[ csr.CSRField("foo", size=4, offset=4, description="foo"), csr.CSRField("bar", size=8, offset=8, description="bar") ]) self.comb += [ self._status.fields.foo.eq(self._storage.fields.foo), self._status.fields.bar.eq(self._storage.fields.bar), ]
def __init__(self): self._csr = csr.CSR() self._storage = csr.CSRStorage(32, reset=0x12345678, write_from_dev=True) self._status = csr.CSRStatus(32, reset=0x12345678) # # # # When csr is written: # - set storage to 0xdeadbeef # - set status to storage value self.comb += [ If(self._csr.re, self._storage.we.eq(1), self._storage.dat_w.eq(0xdeadbeef)) ] self.sync += [ If(self._csr.re, self._status.status.eq(self._storage.storage)) ]
def __init__(self, pads, num): self._status = csr.CSRStatus(32, name='status', reset=0xadc) self._control = csr.CSRStorage(32, name='control') # just make sure these pads exist: pads.d_p pads.d_n pads.fclk_p pads.fclk_n pads.lclk_p pads.lclk_n # input delay control; doesn't seem required so not hooked up. self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() self.bitslip_do = Signal() N_CHANNELS = len(pads.d_p) self.d_preslip = Signal(N_CHANNELS * 8) self.d = Signal(N_CHANNELS * 8) self.fclk = Signal(8) self.d_clk = Signal() self.d_rst = Signal() self.d_valid = Signal() # output self.d_last = Signal() self.d_ready = Signal() # input self.fclk_preslip = Signal(8) # rx clock: # pads.lclk_p/n -> IBUFDS -> lclk_i lclk_i = Signal() lclk_i_bufio = Signal() self.clock_domains.cd_lclkdiv = ClockDomain() self.specials += MultiReg(self._control.storage[0], self.cd_lclkdiv.rst, "lclkdiv") self.specials += [ Instance("IBUFDS", i_I=pads.lclk_p, i_IB=pads.lclk_n, o_O=lclk_i ), Instance("BUFIO", i_I=lclk_i, o_O=lclk_i_bufio), Instance("BUFR", i_I=lclk_i, o_O=self.cd_lclkdiv.clk, p_BUFR_DIVIDE="4"), ] # frame clock for i in range(N_CHANNELS + 1): if i == N_CHANNELS: # fclk d_p = pads.fclk_p d_n = pads.fclk_n else: d_p = pads.d_p[i] d_n = pads.d_n[i] # pad -> IBUFDS_DIFF_OUT serdes_i_nodelay = Signal() self.specials += [ Instance("IBUFDS_DIFF_OUT", i_I=d_p, i_IB=d_n, o_O=serdes_i_nodelay ) ] serdes_i_delayed = Signal() serdes_q = Signal(8) self.specials += [ Instance("IDELAYE2", p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, i_C=self.cd_lclkdiv.clk, i_LD=self.rx_delay_rst, i_CE=self.rx_delay_inc, i_LDPIPEEN=0, i_INC=1, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed ), Instance("ISERDESE2", p_DATA_WIDTH=8, p_DATA_RATE="DDR", p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_IOBDELAY="IFD", i_DDLY=serdes_i_delayed, i_CE1=1, i_RST=self.cd_lclkdiv.rst, i_CLK=lclk_i_bufio, i_CLKB=~lclk_i_bufio, i_CLKDIV=self.cd_lclkdiv.clk, i_BITSLIP=self.bitslip_do, o_Q8=serdes_q[0], o_Q7=serdes_q[1], o_Q6=serdes_q[2], o_Q5=serdes_q[3], o_Q4=serdes_q[4], o_Q3=serdes_q[5], o_Q2=serdes_q[6], o_Q1=serdes_q[7] ) ] if i == N_CHANNELS: self.comb += self.fclk_preslip.eq(serdes_q) else: self.comb += self.d_preslip[i*8:i*8+8].eq(serdes_q) # async fifo # fclk_preslip || d_preslip (in lclkdiv clock domain) -> data clock domain self.clock_domains.cd_data = ClockDomain() self.comb += self.cd_data.clk.eq(self.d_clk) self.comb += self.cd_data.rst.eq(self.d_rst) data_fifo = AsyncFIFOBuffered((N_CHANNELS + 1) * 8, 64) self.submodules.fifo = ClockDomainsRenamer({"write": "lclkdiv", "read": "data"})(data_fifo) # data -> FIFO bitslip_delay = Signal(16) for i in range(N_CHANNELS + 1): # FIFO data layout: # low 8*N_CHANNELS bits is data, # upper 8 bits is FCLK if i == N_CHANNELS: src = self.fclk_preslip else: src = self.d_preslip[i*8:i*8+8] self.sync.lclkdiv += [ data_fifo.din[i*8:i*8+8].eq(src), ] # bitslip handling: # every once in a while (64k ticks), if the FCLK pattern doesn't match, increment bitslip. # (why only ever 64k? just to make debugging easier. could be reduced or even removed.) if i == N_CHANNELS: self.sync.lclkdiv += [ bitslip_delay.eq(bitslip_delay + 1), self.bitslip_do.eq(((src != 0x0F) & (src != 0x33) & (src != 0x55)) & (bitslip_delay == 0)), ] self.last_counter = Signal(max=16383) self.sync += [ If(self.d_valid & self.d_ready, If(self.last_counter == 16383, self.last_counter.eq(0) ).Else( self.last_counter.eq(self.last_counter + 1) ) ) ] self.comb += [ data_fifo.we.eq(1), data_fifo.re.eq(self.d_ready), self.d.eq(data_fifo.dout[:N_CHANNELS*8]), self.fclk.eq(data_fifo.dout[N_CHANNELS*8:N_CHANNELS*8+8]), self.d_valid.eq(data_fifo.readable), self.d_last.eq(self.last_counter == 16383) ] if num == 0: self.specials += [ Instance("IDELAYCTRL", i_REFCLK=ClockSignal(), i_RST=ResetSignal(), ) ]
def __init__(self): self._status = csr.CSRStatus(32, name='status', reset=0x0ffdac) self.spi = Record(SPI) self.mux = Record(MUX) self._control = csr.CSRStorage(32, name='control') # DAC PD control self._clkdiv = csr.CSRStorage(32, name='clkdiv', reset=326) # roughly matches original timing self._enable = csr.CSRStorage(32, name='enable', reset=1) self._v0 = csr.CSRStorage(32, name='v0', reset = 0x8000) # unused self._v1 = csr.CSRStorage(32, name='v1', reset = 0x8000) # unused self._v2 = csr.CSRStorage(32, name='v2', reset = 0x8000) # unused self._v3 = csr.CSRStorage(32, name='v3', reset = 0x8000) # unused self._v4 = csr.CSRStorage(32, name='v4', reset = 0x8000) # CH1 offset self._v5 = csr.CSRStorage(32, name='v5', reset = 0x8000) # CH2 offset self._v6 = csr.CSRStorage(32, name='v6', reset = 0x8000) # CH3 offset self._v7 = csr.CSRStorage(32, name='v7', reset = 0x8000) # CH4 offset # data is transferred on falling edge of SCLK while nSYNC=0 # data is MSB-first # on 24th bit, data is updated. # | 6 bits | 2 bits | 16 bits | # | XXXXXX | PD1,PD0 | data | # PD: 0 - normal # 1 - 1k to GND # 2 - 100k to GND # 3 - Hi-Z # MUX sequence: # A single DAC is used and connected to a 74HC4051 (8-channel # analog multiplexer/demultiplexer) # The DAC output is connected to the MUX "Z" pin # Z is connnected to the output selected by S if # /E is low, otherwise left unconnected. # TIMING: # /E high pulse is ~8.1us # SPI clock rate: 250kHz # repetition rate: 9.8kHz => 1/25.5 of SPI clock rate # # So DAC SPI clock is constantly running, /E is deactivated # during the DAC transition for 2 cycles # wavedrom file: """{signal: [ ["DAC", {name: 'SCLK', wave: 'n............................'}, {name: 'DIN', wave: '2.0xxxxxx2.3...............0x', data: ["Value-1", "PD", "Value"]}, {name: 'nSYNC', wave: '0.10.......................10'}, {name: 'OUT', wave: 'z.1........................z.'}, ], ["MUX", {name: 'nE', wave: '01.0......................1.0'}, {name: 'S', wave: '2.2........................3.', data: ["S-2", "S-1", "S"]}, ], ]} """ # CLK divider clkdiv = Signal(16) self.sync += [ If(clkdiv == self._clkdiv.storage[:16], clkdiv.eq(0) ).Else( clkdiv.eq(clkdiv + 1), ) ] clk = Signal() clk_falling = Signal() self.sync += [ clk_falling.eq(0), If(clkdiv == 0, clk.eq(~clk), clk_falling.eq(~clk) ), ] # FSM self.submodules.fsm = FSM(reset_state='start') dac_data = Array([self._v0.storage, self._v1.storage, self._v2.storage, self._v3.storage, self._v4.storage, self._v5.storage, self._v6.storage, self._v7.storage]) current_bit = Signal(max=24) current_channel = Signal(max=8) pd = Signal(2) pd.eq(self._control.storage[:2]) current_dac_word = Signal(24) self.comb += [ current_dac_word[0:16].eq(dac_data[current_channel][:16]), current_dac_word[16:18].eq(pd), current_dac_word[18:24].eq(0) ] self.fsm.act('start', If(clk_falling, NextValue(current_bit, 0), NextValue(self.mux.nE, 1), NextValue(self.spi.nSYNC, 1), NextValue(self.spi.DIN, 0), If(self._enable.storage[0], NextState('transfer'), ).Else( NextValue(current_channel, 0), ), ) ) self.fsm.act('transfer', If(clk_falling, NextValue(self.spi.nSYNC, 0), NextValue(self.mux.nE, 0), NextValue(self.spi.DIN, Array(current_dac_word)[23 - current_bit]), If(current_bit == 23, NextValue(self.mux.nE, 1), NextState('start'), NextValue(self.mux.S, current_channel), NextValue(current_channel, current_channel + 1) ).Else(NextValue(current_bit, current_bit + 1)) ) ) # output SPI CLK (if enabled) self.sync += self.spi.SCLK.eq(clk & self._enable.storage[0])