Beispiel #1
0
def top(din, init_b, cclk,
        ref_clk,
        soc_clk_p, soc_clk_n, soc_cs, soc_ras, soc_cas, soc_we, soc_ba, soc_a,
        soc_dqs, soc_dm, soc_dq,
        adc_clk_p, adc_clk_n, adc_dat_p, adc_dat_n, adc_ovr_p, adc_ovr_n,
        shifter_sck, shifter_sdo,
        bu2506_ld, adf4360_le, adc08d500_cs, lmh6518_cs, dac8532_sync,
        trig_p, trig_n, ba7406_vd, ba7406_hd, ac_trig,
        probe_comp, ext_trig_out,
        i2c_scl, i2c_sda,
        mcb3_dram_ck, mcb3_dram_ck_n,
        mcb3_dram_ras_n, mcb3_dram_cas_n, mcb3_dram_we_n,
        mcb3_dram_ba, mcb3_dram_a, mcb3_dram_odt,
        mcb3_dram_dqs, mcb3_dram_dqs_n, mcb3_dram_udqs, mcb3_dram_udqs_n, mcb3_dram_dm, mcb3_dram_udm,
        mcb3_dram_dq,
        bank2):
    insts = []

    # Clock generator using STARTUP_SPARTAN primitive
    clk_unbuf = Signal(False)
    clk_unbuf_inst = startup_spartan6('startup_inst', cfgmclk = clk_unbuf)
    insts.append(clk_unbuf_inst)

    clk_buf = Signal(False)
    clk_inst = bufg('bufg_clk', clk_unbuf, clk_buf)
    insts.append(clk_inst)

    system = System(clk_buf, None)

    mux = WbMux()

    # Rename and adapt external SPI bus signals
    slave_spi_bus = SpiInterface()
    slave_cs = Signal(False)
    slave_cs_inst = syncro(clk_buf, din, slave_spi_bus.CS)
    insts.append(slave_cs_inst)
    slave_sck_inst = syncro(clk_buf, cclk, slave_spi_bus.SCK)
    insts.append(slave_sck_inst)
    slave_sdioinst = tristate(init_b,
                              slave_spi_bus.SD_I,
                              slave_spi_bus.SD_O, slave_spi_bus.SD_OE)
    insts.append(slave_sdioinst)

    ####################################################################
    # SoC bus

    if 0:
        soc_clk = Signal(False)
        soc_clk_b = Signal(False)
        soc_clk_inst = ibufgds_diff_out('ibufgds_diff_out_soc_clk', soc_clk_p, soc_clk_n, soc_clk, soc_clk_b)
        insts.append(soc_clk_inst)

        soc_clk._name = 'soc_clk' # Must match name of timing spec in ucf file
        soc_clk_b._name = 'soc_clk_b' # Must match name of timing spec in ucf file

        soc_system = System(soc_clk, None)

        soc_bus = DdrBus(2, 12, 2)

        soc_connect_inst = ddr_connect(
            soc_bus, soc_clk, soc_clk_b, None,
            soc_cs, soc_ras, soc_cas, soc_we, soc_ba, soc_a,
            soc_dqs, soc_dm, soc_dq)
        insts.append(soc_connect_inst)

        if 1:
            soc_source0 = DdrSource(soc_system, 16, 16)
            soc_source1 = DdrSource(soc_system, 16, 16)

            soc_ddr = Ddr(soc_source0, soc_source1)
            soc_inst = soc_ddr.gen(soc_system, soc_bus)
            insts.append(soc_inst)

        if 1:
            # Trace soc bus control signals

            soc_capture = Signal(False)
            soc_ctl = RegFile('soc_ctl', "SOC control", [
                RwField(system, 'soc_capture', "Capture samples", soc_capture),
                ])
            mux.add(soc_ctl, 0x231)
            soc_capture_sync = Signal(False)
            soc_capture_sync_inst = syncro(soc_clk, soc_capture, soc_capture_sync)
            insts.append(soc_capture_sync_inst)

            soc_sdr = ConcatSignal(
                soc_a, soc_ba, soc_we, soc_cas, soc_ras, soc_cs)

            soc_sdr_sampler = Sampler(addr_depth = 0x800,
                                      sample_clk = soc_clk,
                                      sample_data = soc_sdr,
                                      sample_enable = soc_capture_sync)
            mux.add(soc_sdr_sampler, 0x2000)

            soc_reg = ConcatSignal(
                soc_bus.A, soc_bus.BA,
                soc_bus.WE_B, soc_bus.CAS_B, soc_bus.RAS_B, soc_bus.CS_B)

            soc_reg_sampler = Sampler(addr_depth = 0x800,
                                       sample_clk = soc_clk,
                                       sample_data = soc_reg,
                                       sample_enable = soc_capture_sync)
            mux.add(soc_reg_sampler, 0x2800)

            soc_ddr_0 = ConcatSignal(soc_bus.DQ1_OE, soc_bus.DQS1_O, soc_bus.DQS1_OE, soc_bus.DQ0_I, soc_bus.DM0_I, soc_bus.DQS0_I)
            soc_ddr_1 = ConcatSignal(soc_bus.DQ0_OE, soc_bus.DQS0_O, soc_bus.DQS0_OE, soc_bus.DQ1_I, soc_bus.DM1_I, soc_bus.DQS1_I)

            soc_ddr_sampler_0 = Sampler(addr_depth = 0x800,
                                        sample_clk = soc_clk,
                                        sample_data = soc_ddr_0,
                                        sample_enable = soc_capture_sync)
            mux.add(soc_ddr_sampler_0, 0x3000)

            soc_ddr_sampler_1 = Sampler(addr_depth = 0x800,
                                        sample_clk = soc_clk,
                                        sample_data = soc_ddr_1,
                                        sample_enable = soc_capture_sync)
            mux.add(soc_ddr_sampler_1, 0x3800)

    ####################################################################
    # ADC bus

    adc_clk_ibuf = Signal(False)
    adc_clk_ibuf_b = Signal(False)
    adc_clk_ibuf_inst = ibufgds_diff_out('ibufgds_diff_out_adc_clk', adc_clk_p, adc_clk_n, adc_clk_ibuf, adc_clk_ibuf_b)
    insts.append(adc_clk_ibuf_inst)

    if 0:
        adc_clk = Signal(False)
        adc_clk_buf_inst = bufg('bufg_adc_clk', adc_clk_ibuf, adc_clk)
        insts.append(adc_clk_buf_inst)

        adc_clk_b = Signal(False)
        adc_clk_b_buf_inst = bufg('bufg_adc_clk_b', adc_clk_ibuf_b, adc_clk_b)
        insts.append(adc_clk_b_buf_inst)
    else:
        adc_clk = adc_clk_ibuf
        adc_clk_b = adc_clk_ibuf_b

    adc_clk._name = 'adc_clk' # Must match name of timing spec in ucf file
    adc_clk_b._name = 'adc_clk_b' # Must match name of timing spec in ucf file

    if 0:
        # For some reason myhdl doesn't recognize these signals
        adc_dat_p._name = 'adc_dat_p'
        adc_dat_n._name = 'adc_dat_n'

    if 0:
        adc_dat_p.read = True
        adc_dat_n.read = True

    print "adc_dat_p", type(adc_dat_p), len(adc_dat_p)
    print "adc_dat_n", type(adc_dat_n), len(adc_dat_n)

    if 0:
        adc_dat_array = [ Signal(False) for _ in range(len(adc_dat_p)) ]
        for i in range(len(adc_dat_p)):
            adc_dat_inst = ibufds('ibufds_adc_dat%d' % i,
                                  adc_dat_p[i], adc_dat_n[i], adc_dat_array[i])
            insts.append(adc_dat_inst)

        print 'adc_dat_array', adc_dat_array

        adc_dat = ConcatSignal(*adc_dat_array)

        print len(adc_dat)

    else:
        adc_dat = Signal(intbv(0)[len(adc_dat_p):])
        if 0:
            adc_dat._name = 'adc_dat'
            adc_dat.read = True
        adc_dat_inst = ibufds_vec('adc_dat_ibufds', adc_dat_p, adc_dat_n, adc_dat)
        insts.append(adc_dat_inst)

    adc_dat_0 = Signal(intbv(0)[len(adc_dat):])
    adc_dat_1 = Signal(intbv(0)[len(adc_dat):])
    adc_dat_ddr_inst = iddr2('adc_dat_iddr2',
                             adc_dat, adc_dat_0, adc_dat_1,
                             c0 = adc_clk, c1 = adc_clk_b,
                             ddr_alignment = 'C0')
    insts.append(adc_dat_ddr_inst)

    adc_ovr = Signal(False)
    adc_ovr_inst = ibufds('ibufds_adc_ovr', adc_ovr_p, adc_ovr_n, adc_ovr)
    insts.append(adc_ovr_inst)

    if 1:
        adc_capture = Signal(False)
        adc_ctl = RegFile('adc_ctl', "ADC control", [
            RwField(system, 'adc_capture', "Capture samples", adc_capture),
            ])
        mux.add(adc_ctl, 0x230)

        adc_capture_sync = Signal(False)
        adc_capture_sync_inst = syncro(adc_clk, adc_capture, adc_capture_sync)
        insts.append(adc_capture_sync_inst)

        adc_sampler_0 = Sampler(addr_depth = 1024,
                                sample_clk = adc_clk,
                                sample_data = adc_dat_0,
                                sample_enable = adc_capture_sync,
                                skip_cnt = 99)
        mux.add(adc_sampler_0, 0x4000)

        adc_sampler_1 = Sampler(addr_depth = 1024,
                                sample_clk = adc_clk,
                                sample_data = adc_dat_1,
                                sample_enable = adc_capture_sync,
                                skip_cnt = 99)
        mux.add(adc_sampler_1, 0x6000)

    ####################################################################
    # Analog frontend

    if 1:
        shifter_bus = ShifterBus(6)

        @always_comb
        def shifter_comb():
            shifter_sck.next = shifter_bus.SCK
            shifter_sdo.next = shifter_bus.SDO

            bu2506_ld.next = shifter_bus.CS[0]
            adf4360_le.next = shifter_bus.CS[1]
            adc08d500_cs.next = not shifter_bus.CS[2]
            lmh6518_cs.next[0] = not shifter_bus.CS[3]
            lmh6518_cs.next[1] = not shifter_bus.CS[4]
            dac8532_sync.next = not shifter_bus.CS[5]
        insts.append(shifter_comb)

        shifter = Shifter(system, shifter_bus, divider = 100)
        addr = 0x210
        for reg in shifter.create_regs():
            mux.add(reg, addr)
            addr += 1
        insts.append(shifter.gen())

    trig = Signal(intbv(0)[len(trig_p):])
    trig_inst = ibufds_vec('ibufds_trig', trig_p, trig_n, trig)
    insts.append(trig_inst)

    ####################################################################
    # Probe compensation output and external trigger output
    # Just toggle them at 1kHz

    probe_comb_div = 25000
    probe_comp_ctr = Signal(intbv(0, 0, probe_comb_div))
    probe_comp_int = Signal(False)
    @always_seq (system.CLK.posedge, system.RST)
    def probe_comp_seq():
        if probe_comp_ctr == probe_comb_div - 1:
            probe_comp_int.next = not probe_comp_int
            probe_comp_ctr.next = 0
        else:
            probe_comp_ctr.next = probe_comp_ctr + 1
    insts.append(probe_comp_seq)
    @always_comb
    def probe_comp_comb():
        probe_comp.next = probe_comp_int
        ext_trig_out.next = probe_comp_int
    insts.append(probe_comp_comb)

    ####################################################################

    dram_rst_i = Signal(False)
    dram_clk_p = soc_clk_p
    dram_clk_n = soc_clk_n

    dram_calib_done = Signal(False)
    dram_error = Signal(False)

    dram_ctl = RegFile('dram_ctl', "DRAM control", [
        RwField(system, 'dram_rst_i', "Reset", dram_rst_i),
        RoField(system, 'dram_calib_done', "Calib flag", dram_calib_done),
        RoField(system, 'dram_error', "Error flag", dram_error),
        ])
    mux.add(dram_ctl, 0x250)

    mig_inst = mig(
        dram_rst_i, dram_clk_p, dram_clk_n,
        dram_calib_done, dram_error,

        mcb3_dram_ck, mcb3_dram_ck_n,
        mcb3_dram_ras_n, mcb3_dram_cas_n, mcb3_dram_we_n,
        mcb3_dram_ba, mcb3_dram_a, mcb3_dram_odt,
        mcb3_dram_dqs, mcb3_dram_dqs_n, mcb3_dram_udqs, mcb3_dram_udqs_n, mcb3_dram_dm, mcb3_dram_udm,
        mcb3_dram_dq)
    insts.append(mig_inst)

    ####################################################################
    # Random stuff

    if 1:
        pins = ConcatSignal(cclk,
                            i2c_sda, i2c_scl,
                            ext_trig_out, probe_comp,
                            ac_trig, ba7406_hd, ba7406_vd, trig,
                            ref_clk,
                            bank2)
        hc = HybridCounter()
        mux.add(hc, 0, pins)

    # I have a bug somewhere in my Mux, unless I add this the adc
    # sample buffer won't show up in the address range.  I should fix
    # it but I haven't managed to figure out what's wrong yet.
    if 1:
        ram3 = Ram(addr_depth = 1024, data_width = 32)
        mux.add(ram3, 0x8000)

    wb_slave = mux

    # Create the wishbone bus
    wb_bus = wb_slave.create_bus()
    wb_bus.CLK_I = clk_buf
    wb_bus.RST_I = None

    # Create the SPI slave
    spi = SpiSlave()
    spi.addr_width = 32
    spi.data_width = 32

    wb_inst = wb_slave.gen(wb_bus)
    insts.append(wb_inst)

    slave_spi_inst = spi.gen(slave_spi_bus, wb_bus)
    insts.append(slave_spi_inst)

    return insts
Beispiel #2
0
def spi_slave_fifo(glbl, spibus, fifobus):
    """
    This is an SPI slave peripheral, when the master starts clocking
    any data in the TX FIFO (fifobus.write) will be sent (the next
    byte) and the received byte will be copied to RX FIFO
    (fifobus.read).  The `cso` interface can be used to configure
    how the SPI slave peripheral behaves.

    (Arguments == Ports)
    Arguments:
        glbl (Global): global clock and reset
        spibus  (SPIBus): the external SPI interface
        fifobus (FIFOBus): the fifo interface
        cso (ControlStatus): the control status signals
    """
    fifosize = 8

    # Use an async FIFO to transfer from the SPI SCK clock domain and
    # the internal clock domain.  This allows for high-speed SCK.
    clock, reset = glbl.clock, glbl.reset
    assert isinstance(spibus, SPIBus)
    assert isinstance(fifobus, FIFOBus)

    sck, csn = spibus.sck, spibus.csn
    # the FIFOs for the receive and transmit (external perspective)
    readpath = FIFOBus(width=fifobus.width)
    writepath = FIFOBus(width=fifobus.width)

    # the FIFO instances
    tx_fifo_inst = fifo_fast(glbl, writepath, size=fifosize)
    rx_fifo_inst = fifo_fast(glbl, readpath, size=fifosize)
    mp_fifo_inst = fifobus.assign_read_write_paths(readpath, writepath)

    spi_start = Signal(bool(0))
    ireg, icap, icaps = Signals(intbv(0)[8:], 3)
    oreg, ocap = Signals(intbv(0)[8:], 2)
    bitcnt, b2, b3 = Signals(intbv(0, min=0, max=10), 3)

    @always(sck.posedge, csn.negedge)
    def csn_falls():
        if sck:
            spi_start.next = False
        elif not csn:
            spi_start.next = True

    # SCK clock domain, this allows high SCK rates
    @always(sck.posedge, csn.posedge)
    def sck_capture_send():
        if csn:
            b2.next = 0
            bitcnt.next = 0
        else:
            if bitcnt == 0 or spi_start:
                spibus.miso.next = ocap[7]
                oreg.next = (ocap << 1) & 0xFF
            else:
                spibus.miso.next = oreg[7]
                oreg.next = (oreg << 1) & 0xFF

            ireg.next = concat(ireg[7:0], spibus.mosi)
            bitcnt.next = bitcnt + 1
            if bitcnt == (8 - 1):
                bitcnt.next = 0
                b2.next = 8
                icap.next = concat(ireg[7:0], spibus.mosi)
            else:
                b2.next = 0

    # synchronize the SCK domain to the clock domain
    syncro(clock, icap, icaps)
    syncro(clock, b2, b3)

    gotit = Signal(bool(0))

    @always(clock.posedge)
    def beh_io_capture():
        # default no writes
        readpath.write.next = False
        writepath.read.next = False

        if b3 == 0:
            gotit.next = False
        elif b3 == 8 and not gotit:
            readpath.write.next = True
            readpath.write_data.next = icaps
            gotit.next = True
            ocap.next = writepath.read_data
            if not writepath.empty:
                writepath.read.next = True

    return myhdl.instances()
Beispiel #3
0
def top(din, init_b, cclk,
        ref_clk,
        soc_clk_p, soc_clk_n, soc_cs, soc_ras, soc_cas, soc_we, soc_ba, soc_a,
        soc_dqs, soc_dm, soc_dq,
        adc_clk_p, adc_clk_n, adc_dat_p, adc_dat_n, adc_ovr_p, adc_ovr_n,
        shifter_sck, shifter_sdo,
        bu2506_ld, adf4360_le, adc08d500_cs, lmh6518_cs, dac8532_sync,
        trig_p, trig_n, ba7406_vd, ba7406_hd, ac_trig,
        probe_comp, ext_trig_out,
        i2c_scl, i2c_sda,
        fp_rst, fp_clk, fp_din, led_green, led_white,
        mcb3_dram_ck, mcb3_dram_ck_n,
        mcb3_dram_ras_n, mcb3_dram_cas_n, mcb3_dram_we_n,
        mcb3_dram_ba, mcb3_dram_a, mcb3_dram_odt,
        mcb3_dram_dqs, mcb3_dram_dqs_n, mcb3_dram_udqs, mcb3_dram_udqs_n,
        mcb3_dram_dm, mcb3_dram_udm, mcb3_dram_dq,
        bank2):
    insts = []

    # Clock generator using STARTUP_SPARTAN primitive
    clk_unbuf = Signal(False)
    clk_unbuf_inst = startup_spartan6('startup_inst', cfgmclk = clk_unbuf)
    insts.append(clk_unbuf_inst)

    clk_buf = Signal(False)
    clk_inst = bufg('bufg_clk', clk_unbuf, clk_buf)
    insts.append(clk_inst)

    spi_system = System(clk_buf, None)

    mux = WbMux()

    # Rename and adapt external SPI bus signals
    slave_spi_bus = SpiInterface()
    slave_cs = Signal(False)
    slave_cs_inst = syncro(clk_buf, din, slave_spi_bus.CS)
    insts.append(slave_cs_inst)
    slave_sck_inst = syncro(clk_buf, cclk, slave_spi_bus.SCK)
    insts.append(slave_sck_inst)
    slave_sdioinst = tristate(init_b,
                              slave_spi_bus.SD_I,
                              slave_spi_bus.SD_O, slave_spi_bus.SD_OE)
    insts.append(slave_sdioinst)

    ####################################################################
    # A MUX and some test code for it

    soc_clk = Signal(False)
    soc_clk_b = Signal(False)

    soc_system = System(soc_clk, None)

    sm = SimpleMux(soc_system)

    if 1:
        # A read only area which returns predictable patterns
        sa = Algo(soc_system, (1<<16), 32)
        sa_inst = sa.gen()
        insts.append(sa_inst)
        sm.add(sa.bus(), 0x10000)

    ####################################################################
    # Create a MIG instance

    # The DDR memory controller uses the SoC clock pins as the input
    # to its PLL.  It also generates soc_clk which is used above

    soc_clk_ibuf = Signal(False)
    soc_clk_ibuf_inst = ibufgds('soc_clk_ibuf_inst',
                                soc_clk_p, soc_clk_n,
                                soc_clk_ibuf)
    insts.append(soc_clk_ibuf_inst)

    mig = Mig(soc_clk_ibuf)

    ####################################################################
    # MIG port 0

    mig_port = MigPort(mig, soc_system.CLK)
    mig.ports[0] = mig_port

    # MIG port 0 command register

    # I'm trying to squeeze all the MIG command bits into a 32 bit
    # register.  Since the MIG port is 32 bits wide, the low two
    # address bits are always going to be zero, so we only have to
    # keep track of the highest 24 bits of a 32 MByte address.  The
    # highest bit of the instr field is only 1 when used for refresh.
    # I won't use refresh so I can skip that bit too.

    mig_cmd_addr = Signal(intbv(0)[24:])
    mig_cmd_instr = Signal(intbv(0)[2:])

    @always_comb
    def mig_cmd_comb():
        mig_port.cmd_byte_addr.next = mig_cmd_addr << 2
        mig_port.cmd_instr.next = mig_cmd_instr
    insts.append(mig_cmd_comb)

    mig_cmd = SimpleReg(soc_system, 'mig_cmd', "MIG cmd", [
        SimpleRwField('addr', "", mig_cmd_addr),
        SimpleRwField('bl', "", mig_port.cmd_bl),
        SimpleRwField('instr', "", mig_cmd_instr),
        ])
    sm.add(mig_cmd.bus(), addr = 0x210)
    insts.append(mig_cmd.gen())

    # Strobe the cmd_en signal after the register has been written
    mig_cmd_bus = mig_cmd.bus()
    @always_seq(soc_clk.posedge, soc_system.RST)
    def mig_cmd_seq():
        mig_port.cmd_en.next = mig_cmd_bus.WR
    insts.append(mig_cmd_seq)

    mig_status_0_bus, mig_status_0_inst = mig_port.status_reg(soc_system, 0)
    sm.add(mig_status_0_bus, addr = 0x211)
    insts.append(mig_status_0_inst)

    mig_count_0_bus, mig_count_0_inst = mig_port.count_reg(soc_system, 0)
    sm.add(mig_count_0_bus, addr = 0x212)
    insts.append(mig_count_0_inst)

    # MIG port 0 read/write data.  This register must be a bit off
    # from any other regiters that might be read to avoid a read burst
    # popping off data from the fifo when not expected
    mig_data_bus = SimpleBus(1, 32)
    sm.add(mig_data_bus, addr = 0x218)

    @always_comb
    def mig_data_comb():
         mig_port.rd_en.next = mig_data_bus.RD
    insts.append(mig_data_comb)

    @always_seq (soc_system.CLK.posedge, soc_system.RST)
    def mig_data_seq():
        mig_port.wr_en.next = mig_data_bus.WR
        mig_port.wr_data.next = mig_data_bus.WR_DATA
        if mig_data_bus.RD:
            mig_data_bus.RD_DATA.next = mig_port.rd_data
        else:
            mig_data_bus.RD_DATA.next = 0
    insts.append(mig_data_seq)

    ####################################################################
    # Front panel attached to the SoC bus

    if 1:
        frontpanel = FrontPanel(soc_system, fp_rst, fp_clk, fp_din)
        frontpanel_inst = frontpanel.gen()
        insts.append(frontpanel_inst)

        # These need to be spaced a bit apart, otherwise burst will make
        # us read from the data_bus register when we only want to read the
        # ctl_bus register.
        sm.add(frontpanel.ctl_bus, addr = 0x100)
        sm.add(frontpanel.data_bus, addr = 0x104)

    ####################################################################
    # LEDs on the front panel

    if 1:
        led_green_tmp = Signal(False)
        led_white_tmp = Signal(False)

        misc_reg = SimpleReg(soc_system, 'misc', "Miscellaneous", [
            SimpleRwField('green', "Green LED", led_green_tmp),
            SimpleRwField('white', "White LED", led_white_tmp),
            ])

        sm.add(misc_reg.bus(), addr = 0x108)
        insts.append(misc_reg.gen())

        @always_comb
        def led_inst():
            led_green.next = led_green_tmp
            led_white.next = led_white_tmp
        insts.append(led_inst)

    ####################################################################
    # FIFO reading from MIG

    if 1:
        mig_fifo = SyncFifo(None, soc_clk, intbv(0)[32:], 4)
        insts.append(mig_fifo.gen())

        mig_fifo_count_bus, mig_fifo_count_inst = mig_fifo.count_reg(
            soc_system, 'mig_fifo')
        sm.add(mig_fifo_count_bus, addr = 0x132)
        insts.append(mig_fifo_count_inst)

        mig_rd_port = MigPort(mig, soc_clk)
        mig.ports[2] = mig_rd_port

        mig_status_2_bus, mig_status_2_inst = mig_rd_port.status_reg(soc_system, 2)
        sm.add(mig_status_2_bus, addr = 0x134)
        insts.append(mig_status_2_inst)

        mig_count_2_bus, mig_count_2_inst = mig_rd_port.count_reg(soc_system, 2)
        sm.add(mig_count_2_bus, addr = 0x135)
        insts.append(mig_count_2_inst)

        mig_reader_addresser = MigReaderAddresser('mig_reader', soc_system, mig_rd_port)

        insts.append(mig_reader_addresser.regs_gen())
        sm.add(mig_reader_addresser.regs_bus(), addr = 0x130)

        mig_reader_addresser_inst = mig_reader_addresser.gen(mig_rd_port)
        insts.append(mig_reader_addresser_inst)

        mig_reader = MigReader(mig_rd_port, mig_fifo)
        insts.append(mig_reader.gen())

    ####################################################################
    # Test code for FIFO RAM

    if 0:
        wr_fifo = DummyWriteFifo(None, soc_clk, intbv(0)[32:])
        insts.append(wr_fifo.gen())

        fifo_ram = FifoRam('fifo_ram', soc_system, wr_fifo, mig_fifo, 1024, 32)

        insts.append(fifo_ram.regs_gen())
        sm.add(fifo_ram.regs_bus(), addr = 0x120)

        insts.append(fifo_ram.gen())
        sm.add(fifo_ram.bus(), addr = 0x8000)

    ####################################################################
    # Test code for renderer

    if 1:
        renderer_clr_port = SimplePort(1)
        renderer_clr = Signal(False)
        renderer_clr_addr = Signal(intbv(0)[8:])

        renderer_idle = Signal(False)

        renderer0 = Renderer(system = soc_system,
                             sample_width = 8,
                             accumulator_width = 16)
        insts.append(renderer0.gen())

        renderer1 = Renderer(system = soc_system,
                             sample_width = 8,
                             accumulator_width = 16)
        insts.append(renderer1.gen())

        renderer2 = Renderer(system = soc_system,
                             sample_width = 8,
                             accumulator_width = 16)
        insts.append(renderer2.gen())

        renderer3 = Renderer(system = soc_system,
                             sample_width = 8,
                             accumulator_width = 16)
        insts.append(renderer3.gen())

        renderer_reg = SimpleReg(soc_system, 'renderer', "", [
            SimpleField('clear', "", renderer_clr_port),
            SimpleRoField('idle', "", renderer_idle),
            ])

        sm.add(renderer_reg.bus(), addr = 0x240)
        insts.append(renderer_reg.gen())

        renderer_bus = SimpleBus(addr_depth = 256, data_width = 32)

        @always_seq(soc_clk.posedge, None)
        def renderer_seq():
            renderer0.STROBE.next = 0
            renderer1.STROBE.next = 0
            renderer2.STROBE.next = 0
            renderer3.STROBE.next = 0

            # Can't feed the renderer it is read or written from the host
            mig_fifo.RD.next = 0
            if (not renderer_bus.RD and
                not renderer_bus.WR and
                not mig_fifo.RD_EMPTY):
                renderer0.SAMPLE.next = mig_fifo.RD_DATA[8:0]
                renderer0.STROBE.next = 1

                renderer1.SAMPLE.next = mig_fifo.RD_DATA[16:8]
                renderer1.STROBE.next = 1

                renderer2.SAMPLE.next = mig_fifo.RD_DATA[24:16]
                renderer2.STROBE.next = 1

                renderer3.SAMPLE.next = mig_fifo.RD_DATA[32:24]
                renderer3.STROBE.next = 1

                mig_fifo.RD.next = 1

            renderer_idle.next = 0
            if mig_fifo.RD_EMPTY and mig_reader_addresser.rd_count == 0:
                renderer_idle.next = 1
        insts.append(renderer_seq)

        @always_seq(soc_clk.posedge, None)
        def renderer_clr_seq():
            renderer_clr.next = 0
            renderer_clr_addr.next = 0
            if renderer_clr_port.WR and renderer_clr_port.WR_DATA != 0:
                renderer_clr.next = 1
                renderer_clr_addr.next = 0
            elif renderer_clr:
                if renderer_clr_addr.next != 255:
                    renderer_clr.next = 1
                    renderer_clr_addr.next = renderer_clr_addr + 1

            renderer_clr_port.RD_DATA.next = 0
            if renderer_clr_port.RD:
                renderer_clr_port.RD_DATA.next = renderer_clr
        insts.append(renderer_clr_seq)

        renderer0_bus = renderer0.bus()
        renderer1_bus = renderer1.bus()
        renderer2_bus = renderer2.bus()
        renderer3_bus = renderer3.bus()

        # Combine results from all four renderers
        @always_comb
        def renderer_bus_comb():
            renderer0_bus.WR.next = 0
            renderer1_bus.WR.next = 0
            renderer2_bus.WR.next = 0
            renderer3_bus.WR.next = 0

            renderer0_bus.ADDR.next = 0
            renderer1_bus.ADDR.next = 0
            renderer2_bus.ADDR.next = 0
            renderer3_bus.ADDR.next = 0

            renderer0_bus.WR_DATA.next = 0
            renderer1_bus.WR_DATA.next = 0
            renderer2_bus.WR_DATA.next = 0
            renderer3_bus.WR_DATA.next = 0

            renderer0_bus.RD.next = 0
            renderer1_bus.RD.next = 0
            renderer2_bus.RD.next = 0
            renderer3_bus.RD.next = 0

            if renderer_bus_RD or renderer_bus.WR:
                renderer0_bus.ADDR.next = renderer_bus.ADDR
                renderer1_bus.ADDR.next = renderer_bus.ADDR
                renderer2_bus.ADDR.next = renderer_bus.ADDR
                renderer3_bus.ADDR.next = renderer_bus.ADDR

                renderer0_bus.WR.next = renderer_bus.WR
                renderer1_bus.WR.next = renderer_bus.WR
                renderer2_bus.WR.next = renderer_bus.WR
                renderer3_bus.WR.next = renderer_bus.WR

                renderer0_bus.WR_DATA.next = renderer_bus.WR_DATA
                renderer1_bus.WR_DATA.next = renderer_bus.WR_DATA
                renderer2_bus.WR_DATA.next = renderer_bus.WR_DATA
                renderer3_bus.WR_DATA.next = renderer_bus.WR_DATA

                renderer0_bus.RD.next = renderer_bus.RD
                renderer1_bus.RD.next = renderer_bus.RD
                renderer2_bus.RD.next = renderer_bus.RD
                renderer3_bus.RD.next = renderer_bus.RD

            elif renderer_clr:
                renderer0_bus.ADDR.next = renderer_clr_addr
                renderer1_bus.ADDR.next = renderer_clr_addr
                renderer2_bus.ADDR.next = renderer_clr_addr
                renderer3_bus.ADDR.next = renderer_clr_addr

                renderer0_bus.WR.next = 1
                renderer1_bus.WR.next = 1
                renderer2_bus.WR.next = 1
                renderer3_bus.WR.next = 1

            renderer_bus.RD_DATA.next[16:0] = renderer0_bus.RD_DATA + renderer1_bus.RD_DATA
            renderer_bus.RD_DATA.next[32:16] = renderer2_bus.RD_DATA + renderer3_bus.RD_DATA
        insts.append(renderer_bus_comb)

        sm.add(renderer_bus, addr = 0x400)

    ####################################################################
    # ADC bus

    ADC_INVERT = 0x51a04418

    adc_clk = Signal(False)
    adc_clk_b = Signal(False)
    adc_clk_ibuf_inst = ibufgds_diff_out('ibufgds_diff_out_adc_clk',
                                         adc_clk_p, adc_clk_n,
                                         adc_clk, adc_clk_b)
    insts.append(adc_clk_ibuf_inst)

    adc_dat = Signal(intbv(0)[len(adc_dat_p):])
    adc_dat_ibuf_inst = ibufds_vec('adc_dat_ibufds',
                                   adc_dat_p, adc_dat_n, adc_dat)
    insts.append(adc_dat_ibuf_inst)

    adc_dat_tmp_0 = Signal(intbv(0)[len(adc_dat):])
    adc_dat_tmp_1 = Signal(intbv(0)[len(adc_dat):])
    adc_dat_ddr_inst = iddr2('adc_dat_iddr2',
                             adc_dat, adc_dat_tmp_0, adc_dat_tmp_1,
                             c0 = adc_clk, c1 = adc_clk_b,
                             ddr_alignment = 'C0')
    insts.append(adc_dat_ddr_inst)

    adc_dat_0 = Signal(intbv(0)[len(adc_dat):])
    adc_dat_1 = Signal(intbv(0)[len(adc_dat):])

    @always_comb
    def adc_dat_inv_inst():
        adc_dat_0.next = adc_dat_tmp_0 ^ ADC_INVERT
        adc_dat_1.next = adc_dat_tmp_1 ^ ADC_INVERT
    insts.append(adc_dat_inv_inst)

    adc_ovr = Signal(False)
    adc_ovr_inst = ibufds('ibufds_adc_ovr',
                          adc_ovr_p, adc_ovr_n, adc_ovr)
    insts.append(adc_ovr_inst)

    if 1:
        fifo_overflow_0 = Signal(False)
        fifo_overflow_1 = Signal(False)

        adc_capture = Signal(False)
        adc_ctl = RegFile('adc_ctl', "ADC control", [
            RwField(spi_system, 'adc_capture', "Capture samples", adc_capture),
            RoField(spi_system, 'fifo_overflow_0', "", fifo_overflow_0),
            RoField(spi_system, 'fifo_overflow_', "", fifo_overflow_1),
            ])
        mux.add(adc_ctl, 0x230)

        adc_capture_sync = Signal(False)
        adc_capture_sync_inst = syncro(adc_clk, adc_capture, adc_capture_sync)
        insts.append(adc_capture_sync_inst)

    if 0:
        adc_sampler_0 = Sampler(addr_depth = 1024,
                                sample_clk = adc_clk,
                                sample_data = adc_dat_0,
                                sample_enable = adc_capture_sync,
                                skip_cnt = 99)
        mux.add(adc_sampler_0, 0x4000)

        adc_sampler_1 = Sampler(addr_depth = 1024,
                                sample_clk = adc_clk,
                                sample_data = adc_dat_1,
                                sample_enable = adc_capture_sync,
                                skip_cnt = 99)
        mux.add(adc_sampler_1, 0x6000)

    mig_sample_synthetic = Signal(False)
    mig_sample_enable = Signal(False)

    mig_sample_enable_sync_adc = Signal(False)
    insts.append(syncro(adc_clk,
                        mig_sample_enable, mig_sample_enable_sync_adc))

    mig_sample_overflow_0 = Signal(False)
    mig_sample_overflow_1 = Signal(False)

    # Synthetic ADC data to test the FIFO
    mig_synthetic_data_0 = Signal(intbv(0)[32:])
    mig_synthetic_data_1 = Signal(intbv(0)[32:])

    @always_seq(adc_clk.posedge, None)
    def mig_synthetic_inst():
        if mig_sample_enable_sync_adc:
            mig_synthetic_data_0.next = mig_synthetic_data_0 + 2
            mig_synthetic_data_1.next = mig_synthetic_data_1 + 2
        else:
            mig_synthetic_data_0.next = 1
            mig_synthetic_data_1.next = 0
    insts.append(mig_synthetic_inst)

    mig_data_0 = Signal(intbv(0)[32:])
    mig_data_1 = Signal(intbv(0)[32:])

    @always_comb
    def mig_data_inst():
        if mig_sample_synthetic:
            mig_data_0.next = mig_synthetic_data_0
            mig_data_1.next = mig_synthetic_data_1
        else:
            mig_data_0.next = adc_dat_0
            mig_data_1.next = adc_dat_1
    insts.append(mig_data_inst)

    if 1:
        adc_mig_port_0 = MigPort(mig, soc_clk)
        mig.ports[4] = adc_mig_port_0

        mig_status_4_bus, mig_status_4_inst = adc_mig_port_0.status_reg(soc_system, 4)
        sm.add(mig_status_4_bus, addr = 0x220)
        insts.append(mig_status_4_inst)

        mig_count_4_bus, mig_count_4_inst = adc_mig_port_0.count_reg(soc_system, 4)
        sm.add(mig_count_4_bus, addr = 0x221)
        insts.append(mig_count_4_inst)

        adc_mig_port_1 = MigPort(mig, soc_clk)
        mig.ports[5] = adc_mig_port_1

        mig_status_5_bus, mig_status_5_inst = adc_mig_port_1.status_reg(soc_system, 5)
        sm.add(mig_status_5_bus, addr = 0x228)
        insts.append(mig_status_5_inst)

        mig_count_5_bus, mig_count_5_inst = adc_mig_port_1.count_reg(soc_system, 5)
        sm.add(mig_count_5_bus, addr = 0x229)
        insts.append(mig_count_5_inst)

        mig_sampler = MigSampler2(sample_clk = adc_clk,
                                  sample_data_0 = mig_data_0,
                                  sample_data_1 = mig_data_1,
                                  sample_enable = mig_sample_enable_sync_adc,

                                  mig_port_0 = adc_mig_port_0,
                                  mig_port_1 = adc_mig_port_1,

                                  overflow_0 = mig_sample_overflow_0,
                                  overflow_1 = mig_sample_overflow_1,
                                  )
        insts.append(mig_sampler.gen())

        mig_sampler_reg = SimpleReg(soc_system, 'mig_sampler', "", [
            SimpleRwField('enable', "", mig_sample_enable),
            SimpleRwField('synthetic', "", mig_sample_synthetic),
            SimpleRoField('overflow_0', "", mig_sample_overflow_0),
            SimpleRoField('overflow_1', "", mig_sample_overflow_1),
            ])

        sm.add(mig_sampler_reg.bus(), addr = 0x230)
        insts.append(mig_sampler_reg.gen())

    ####################################################################
    # Analog frontend

    if 1:
        shifter_bus = ShifterBus(6)

        @always_comb
        def shifter_comb():
            shifter_sck.next = shifter_bus.SCK
            shifter_sdo.next = shifter_bus.SDO

            bu2506_ld.next = shifter_bus.CS[0]
            adf4360_le.next = shifter_bus.CS[1]
            adc08d500_cs.next = not shifter_bus.CS[2]
            lmh6518_cs.next[0] = not shifter_bus.CS[3]
            lmh6518_cs.next[1] = not shifter_bus.CS[4]
            dac8532_sync.next = not shifter_bus.CS[5]
        insts.append(shifter_comb)

        shifter = Shifter(spi_system, shifter_bus, divider = 100)
        addr = 0x210
        for reg in shifter.create_regs():
            mux.add(reg, addr)
            addr += 1
        insts.append(shifter.gen())

    trig = Signal(intbv(0)[len(trig_p):])
    trig_inst = ibufds_vec('ibufds_trig', trig_p, trig_n, trig)
    insts.append(trig_inst)

    ####################################################################
    # Probe compensation output and external trigger output
    # Just toggle them at 1kHz

    probe_comb_div = 25000
    probe_comp_ctr = Signal(intbv(0, 0, probe_comb_div))
    probe_comp_int = Signal(False)
    @always_seq (spi_system.CLK.posedge, spi_system.RST)
    def probe_comp_seq():
        if probe_comp_ctr == probe_comb_div - 1:
            probe_comp_int.next = not probe_comp_int
            probe_comp_ctr.next = 0
        else:
            probe_comp_ctr.next = probe_comp_ctr + 1
    insts.append(probe_comp_seq)
    @always_comb
    def probe_comp_comb():
        probe_comp.next = probe_comp_int
        ext_trig_out.next = probe_comp_int
    insts.append(probe_comp_comb)

    ####################################################################
    # DDR memory using MIG

    mig_control_bus, mig_control_inst = mig.control_reg(soc_system)
    sm.add(mig_control_bus, addr = 0x200)
    insts.append(mig_control_inst)

    @always_comb
    def mig_soc_clk_inst():
        soc_clk.next = mig.soc_clk
        soc_clk_b.next = mig.soc_clk_b
    insts.append(mig_soc_clk_inst)

    mig.mcbx_dram_addr = mcb3_dram_a
    mig.mcbx_dram_ba = mcb3_dram_ba
    mig.mcbx_dram_ras_n = mcb3_dram_ras_n
    mig.mcbx_dram_cas_n = mcb3_dram_cas_n
    mig.mcbx_dram_we_n = mcb3_dram_we_n
    mig.mcbx_dram_clk = mcb3_dram_ck
    mig.mcbx_dram_clk_n = mcb3_dram_ck_n
    mig.mcbx_dram_dq = mcb3_dram_dq
    mig.mcbx_dram_dqs = mcb3_dram_dqs
    mig.mcbx_dram_dqs_n = mcb3_dram_dqs_n
    mig.mcbx_dram_udqs = mcb3_dram_udqs
    mig.mcbx_dram_udqs_n = mcb3_dram_udqs_n
    mig.mcbx_dram_udm = mcb3_dram_udm
    mig.mcbx_dram_ldm = mcb3_dram_dm

    mig_inst = mig.gen()
    insts.append(mig_inst)

    ####################################################################
    # Finalize the SoC MUX
    sm.addr_depth = 32 * 1024 * 1024
    sm_inst = sm.gen()
    insts.append(sm_inst)

    ####################################################################
    # SoC bus

    soc_bus = DdrBus(2, 12, 2)

    # Attach the MUX bus to the SoC bus
    soc_ddr = Ddr()
    soc_inst = soc_ddr.gen(soc_system, soc_bus, sm.bus())
    insts.append(soc_inst)

    soc_connect_inst = ddr_connect(
        soc_bus, soc_clk, soc_clk_b, None,
        soc_cs, soc_ras, soc_cas, soc_we, soc_ba, soc_a,
        soc_dqs, soc_dm, soc_dq)
    insts.append(soc_connect_inst)

    if 1:

        soc_capture = Signal(False)
        soc_ctl = RegFile('soc_ctl', "SOC control", [
            RwField(spi_system, 'soc_capture', "Capture samples", soc_capture),
            ])
        mux.add(soc_ctl, 0x231)
        soc_capture_sync = Signal(False)
        soc_capture_sync_inst = syncro(soc_clk, soc_capture, soc_capture_sync)
        insts.append(soc_capture_sync_inst)

        soc_sdr = ConcatSignal(
            soc_a, soc_ba, soc_we, soc_cas, soc_ras, soc_cs)

        soc_sdr_sampler = Sampler(addr_depth = 0x800,
                                  sample_clk = soc_clk,
                                  sample_data = soc_sdr,
                                  sample_enable = soc_capture_sync)
        mux.add(soc_sdr_sampler, 0x2000)

        soc_reg = ConcatSignal(
            soc_bus.A, soc_bus.BA,
            soc_bus.WE_B, soc_bus.CAS_B, soc_bus.RAS_B, soc_bus.CS_B)

        soc_reg_sampler = Sampler(addr_depth = 0x800,
                                   sample_clk = soc_clk,
                                   sample_data = soc_reg,
                                   sample_enable = soc_capture_sync)
        mux.add(soc_reg_sampler, 0x2800)

        soc_ddr_0 = ConcatSignal(soc_bus.DQ1_OE, soc_bus.DQS1_O, soc_bus.DQS1_OE, soc_bus.DQ0_I, soc_bus.DM0_I, soc_bus.DQS0_I)
        soc_ddr_1 = ConcatSignal(soc_bus.DQ0_OE, soc_bus.DQS0_O, soc_bus.DQS0_OE, soc_bus.DQ1_I, soc_bus.DM1_I, soc_bus.DQS1_I)

        soc_ddr_sampler_0 = Sampler(addr_depth = 0x800,
                                    sample_clk = soc_clk,
                                    sample_data = soc_ddr_0,
                                    sample_enable = soc_capture_sync)
        mux.add(soc_ddr_sampler_0, 0x3000)

        soc_ddr_sampler_1 = Sampler(addr_depth = 0x800,
                                    sample_clk = soc_clk,
                                    sample_data = soc_ddr_1,
                                    sample_enable = soc_capture_sync)
        mux.add(soc_ddr_sampler_1, 0x3800)

    ####################################################################
    # Random stuff

    if 1:
        pins = ConcatSignal(cclk,
                            i2c_sda, i2c_scl,
                            ext_trig_out, probe_comp,
                            ac_trig, ba7406_hd, ba7406_vd, trig,
                            ref_clk,
                            bank2)
        hc = HybridCounter()
        mux.add(hc, 0, pins)

    # I have a bug somewhere in my Mux, unless I add this the adc
    # sample buffer won't show up in the address range.  I should fix
    # it but I haven't managed to figure out what's wrong yet.
    if 1:
        ram3 = Ram(addr_depth = 1024, data_width = 32)
        mux.add(ram3, 0x8000)

    wb_slave = mux

    # Create the wishbone bus
    wb_bus = wb_slave.create_bus()
    wb_bus.CLK_I = clk_buf
    wb_bus.RST_I = None

    # Create the SPI slave
    spi = SpiSlave()
    spi.addr_width = 32
    spi.data_width = 32

    wb_inst = wb_slave.gen(wb_bus)
    insts.append(wb_inst)

    slave_spi_inst = spi.gen(slave_spi_bus, wb_bus)
    insts.append(slave_spi_inst)

    return insts
Beispiel #4
0
def spi_slave_fifo(glbl, spibus, fifobus):
    """
    This is an SPI slave peripheral, when the master starts clocking
    any data in the TX FIFO (fifobus.write) will be sent (the next
    byte) and the received byte will be copied to RX FIFO
    (fifobus.read).  The `cso` interface can be used to configure
    how the SPI slave peripheral behaves.

    (Arguments == Ports)
    Arguments:
        glbl (Global): global clock and reset
        spibus  (SPIBus): the external SPI interface
        fifobus (FIFOBus): the fifo interface
        cso (ControlStatus): the control status signals
    """
    fifosize = 8

    # Use an async FIFO to transfer from the SPI SCK clock domain and
    # the internal clock domain.  This allows for high-speed SCK.
    clock, reset = glbl.clock, glbl.reset
    assert isinstance(spibus, SPIBus)
    assert isinstance(fifobus, FIFOBus)

    sck, csn = spibus.sck, spibus.csn
    # the FIFOs for the receive and transmit (external perspective)
    readpath = FIFOBus(width=fifobus.width)
    writepath = FIFOBus(width=fifobus.width)

    # the FIFO instances
    tx_fifo_inst = fifo_fast(glbl, writepath, size=fifosize)
    rx_fifo_inst = fifo_fast(glbl, readpath, size=fifosize)
    mp_fifo_inst = fifobus.assign_read_write_paths(readpath, writepath)

    spi_start = Signal(bool(0))
    ireg, icap, icaps = Signals(intbv(0)[8:], 3)
    oreg, ocap = Signals(intbv(0)[8:], 2)
    bitcnt, b2, b3 = Signals(intbv(0, min=0, max=10), 3)

    @always(sck.posedge, csn.negedge)
    def csn_falls():
        if sck:
            spi_start.next = False
        elif not csn:
            spi_start.next = True

    # SCK clock domain, this allows high SCK rates
    @always(sck.posedge, csn.posedge)
    def sck_capture_send():
        if csn:
            b2.next = 0
            bitcnt.next = 0
        else:
            if bitcnt == 0 or spi_start:
                spibus.miso.next = ocap[7]
                oreg.next = (ocap << 1) & 0xFF
            else:
                spibus.miso.next = oreg[7]
                oreg.next = (oreg << 1) & 0xFF

            ireg.next = concat(ireg[7:0], spibus.mosi)
            bitcnt.next = bitcnt + 1
            if bitcnt == (8-1):
                bitcnt.next = 0
                b2.next = 8
                icap.next = concat(ireg[7:0], spibus.mosi)
            else:
                b2.next = 0

    # synchronize the SCK domain to the clock domain
    syncro(clock, icap, icaps)
    syncro(clock, b2, b3)

    gotit = Signal(bool(0))

    @always(clock.posedge)
    def beh_io_capture():
        # default no writes
        readpath.write.next = False
        writepath.read.next = False

        if b3 == 0:
            gotit.next = False
        elif b3 == 8 and not gotit:
            readpath.write.next = True
            readpath.write_data.next = icaps
            gotit.next = True
            ocap.next = writepath.read_data
            if not writepath.empty:
                writepath.read.next = True

    return myhdl.instances()
Beispiel #5
0
    def gen(self):
        if self.RST is not None:
            wr_rst_inst = rst_sync(self.WR_CLK, self.RST, self.WR_RST)
            rd_rst_inst = rst_sync(self.RD_CLK, self.RST, self.RD_RST)

        mem = FifoMem(self.WR_CLK, self.RD_CLK, self.depth, len(self.WR_DATA))
        mem_inst = mem.gen()

        gray_init = intbv(0, 0, 2 * self.depth)

        # Gray encoded write and read pointers
        wr_gray = Signal(gray_init)
        rd_gray = Signal(gray_init)

        ################################################################
        # Write side of the FIFO

        wr_cur = Signal(gray_init)
        wr_new = Signal(gray_init)

        # Gray encoded read pointer synchronized to the write clock domain
        wr_sync_rd_gray = Signal(gray_init)

        wr_sync_inst = syncro(self.WR_CLK, rd_gray, wr_sync_rd_gray,
                              num_sync_ff = 2)

        @always_comb
        def wr_new_comb():
            wr_new.next = wr_cur
            if self.WR:
                wr_new.next = (wr_cur + 1) & ((1<<len(wr_new))-1)

        @always_comb
        def wr_data_comb():
            mem.WR.next = 0
            mem.WR_ADDR.next = wr_cur & ((1<<len(mem.WR_ADDR))-1)
            mem.WR_DATA.next = self.WR_DATA
            if self.WR:
                mem.WR.next = 1

        @always_comb
        def wr_full_comb():
            self.WR_FULL.next = 0
            if gray_encode(wr_new ^ self.depth) == wr_sync_rd_gray:
                self.WR_FULL.next = 1

        @always_seq(self.WR_CLK.posedge, self.WR_RST)
        def wr_seq():
            wr_cur.next = wr_new
            wr_gray.next = gray_encode(wr_new)

        ################################################################
        # Read side of the FIFO

        rd_cur = Signal(gray_init)
        rd_new = Signal(gray_init)

        # Gray encoded read pointer synchronized to the write clock domain
        rd_sync_wr_gray = Signal(gray_init)

        rd_sync_inst = syncro(self.RD_CLK, wr_gray, rd_sync_wr_gray,
                              num_sync_ff = 2)

        @always_comb
        def rd_new_comb():
            rd_new.next = rd_cur
            if self.RD:
                rd_new.next = (rd_cur + 1) & ((1<<len(rd_new))-1)

        @always_comb
        def rd_data_comb():
            mem.RD.next = 1
            mem.RD_ADDR.next = rd_new & ((1<<len(mem.RD_ADDR))-1)
            self.RD_DATA.next = mem.RD_DATA

        @always_comb
        def rd_empty_comb():
            self.RD_EMPTY.next = 0
            if gray_encode(rd_new) == rd_sync_wr_gray:
                self.RD_EMPTY.next = 1

        @always_seq(self.RD_CLK.posedge, self.RD_RST)
        def rd_seq():
            rd_cur.next = rd_new
            rd_gray.next = gray_encode(rd_new)

        return instances()