Exemplo n.º 1
0
Arquivo: ila.py Projeto: zyp/luna
    def __init__(self,
                 *,
                 signals,
                 sample_depth,
                 domain="sync",
                 sample_rate=60e6,
                 samples_pretrigger=1):
        self.domain = domain
        self.signals = signals
        self.inputs = Cat(*signals)
        self.sample_width = len(self.inputs)
        self.sample_depth = sample_depth
        self.samples_pretrigger = samples_pretrigger
        self.sample_rate = sample_rate
        self.sample_period = 1 / sample_rate

        #
        # Create a backing store for our samples.
        #
        self.mem = Memory(width=self.sample_width,
                          depth=sample_depth,
                          name="ila_buffer")

        #
        # I/O port
        #
        self.trigger = Signal()
        self.sampling = Signal()
        self.complete = Signal()

        self.captured_sample_number = Signal(range(0, self.sample_depth))
        self.captured_sample = Signal(self.sample_width)
Exemplo n.º 2
0
Arquivo: crc.py Projeto: ret/daqnet
    def elaborate(self, platform):

        m = Module()
        crc = Signal(32)

        self.crctable = Memory(32, 256, make_crc32_table())
        table_port = self.crctable.read_port()
        m.submodules += table_port

        m.d.comb += [
            self.crc_out.eq(crc ^ 0xFFFFFFFF),
            self.crc_match.eq(crc == 0xDEBB20E3),
            table_port.addr.eq(crc ^ self.data),
        ]

        with m.FSM():
            with m.State("RESET"):
                m.d.sync += crc.eq(0xFFFFFFFF)
                m.next = "IDLE"

            with m.State("IDLE"):
                with m.If(self.reset):
                    m.next = "RESET"
                with m.Elif(self.data_valid):
                    m.next = "BUSY"

            with m.State("BUSY"):
                with m.If(self.reset):
                    m.next = "RESET"
                m.d.sync += crc.eq(table_port.data ^ (crc >> 8))
                m.next = "IDLE"

        return m
Exemplo n.º 3
0
 def __init__(self):
     self.user_rx_mem = Memory(8, 32)
     self.user_tx_mem = Memory(8, 32,
                               [ord(x) for x in "Hello, World!!\r\n"])
     self.mem_r_port = self.user_tx_mem.read_port()
     self.mem_w_port = self.user_rx_mem.write_port()
     self.packet_received = Signal()
     self.transmit_ready = Signal()
     self.transmit_packet = Signal()
Exemplo n.º 4
0
 def elab(self, m):
     mem = Memory(width=self.width, depth=self.depth, simulate=self.is_sim)
     m.submodules['wp'] = wp = mem.write_port()
     m.submodules['rp'] = rp = mem.read_port(transparent=False)
     m.d.comb += [
         wp.en.eq(self.w_en),
         wp.addr.eq(self.w_addr),
         wp.data.eq(self.w_data),
         rp.en.eq(1),
         rp.addr.eq(self.r_addr),
         self.r_data.eq(rp.data),
     ]
Exemplo n.º 5
0
    def __init__(self, out_width: int, samples: int):
        M = 1 << (out_width - 1)

        amplitudes = [int(M * math.sin((math.pi / 2) * (i/samples))) for i in range(samples)]

        self.quarter_sin_mem = Memory(
            width=(out_width - 1),
            depth=samples,
            init=amplitudes,
        )

        self.addr = Signal(range(samples * 4))
        self.sin = Signal(out_width)
        self.cos = Signal(out_width)
Exemplo n.º 6
0
class SinCosLookup(Elaboratable):
    def __init__(self, out_width: int, samples: int):
        M = 1 << (out_width - 1)

        amplitudes = [int(M * math.sin((math.pi / 2) * (i/samples))) for i in range(samples)]

        self.quarter_sin_mem = Memory(
            width=(out_width - 1),
            depth=samples,
            init=amplitudes,
        )

        self.addr = Signal(range(samples * 4))
        self.sin = Signal(out_width)
        self.cos = Signal(out_width)

    def elaborate(self, platform):
        m = Module()
        m.submodules.sin_rdport = sin_rdport = self.quarter_sin_mem.read_port()
        m.submodules.cos_rdport = cos_rdport = self.quarter_sin_mem.read_port()

        def sinewave(rdport, addr):
            m.d.comb += rdport.addr.eq(Mux(addr[-2], ~addr[:-2], addr[:-2]))
            return Mux(addr[-1],
                Cat(~rdport.data, 0),
                Cat(rdport.data, 1),
            )
        m.d.comb += [
            self.sin.eq(sinewave(sin_rdport, self.addr)),
            self.cos.eq(sinewave(cos_rdport, trunc_add(self.addr, self.quarter_sin_mem.depth)))
        ]

        return m
Exemplo n.º 7
0
    def elaborate(self, platform):
        m = Module()
        m.submodules.serdes = serdes = self.serdes

        # The symbol table reads the corresponding symbols for each
        # symbol in PACKET and outputs them on tx_data
        m.submodules.symboltable = symboltable = SymbolTable(
            table=pack_mem(TABLE, width=20),
            packet=Memory(width=16,
                          depth=len(PACKET),
                          init=[int(i) for i in np.array(PACKET) * 5000 / 20]),
            samples_per_symbol=int(5e9 / 1e6),
            tx_domain="tx")
        m.d.comb += [
            symboltable.packet_length.eq(len(PACKET)),
            serdes.tx_data.eq(symboltable.tx_data)
        ]

        # Quick state machine to transmit and then wait a bit before
        # transmitting again
        counter = Signal(32)
        with m.FSM():
            with m.State("START"):
                m.d.sync += symboltable.tx_reset.eq(1)
                m.next = "WAIT_DONE"
            with m.State("WAIT_DONE"):
                m.d.sync += symboltable.tx_reset.eq(0)
                with m.If(symboltable.tx_done):
                    m.d.sync += counter.eq(0)
                    m.next = "PAUSE"
            with m.State("PAUSE"):
                m.d.sync += counter.eq(counter + 1)
                with m.If(counter >= int(1e4)):
                    m.next = "START"
        return m
Exemplo n.º 8
0
def test_symbol_table():
    st = SymbolTable(table=[i for i in range(100)],
                     packet=Memory(width=16,
                                   depth=5,
                                   init=[i * 10 for i in [1, 2, 3, 4, 5]]),
                     samples_per_symbol=10 * 20,
                     tx_domain="sync")
    st = make_callable(st,
                       inputs=[st.tx_reset, st.packet_length],
                       outputs=[st.tx_data, st.tx_done])

    # This should output an incrementing output symbol a couple cycles delayed until we get done
    print(st(1, 5))
    for i in range(100):
        out, done = st(0, 5)
        print(i, out, done)
        if done:
            break
        if i > 4:
            assert (i + 10 - 4 == out)

    # Do it again to test reset logic
    print(st(1, 5))
    for i in range(100):
        out, done = st(0, 5)
        print(i, out, done)
        if done:
            break
        if i > 4:
            assert (i + 10 - 4 == out)
Exemplo n.º 9
0
class User(Elaboratable):
    def __init__(self):
        self.user_rx_mem = Memory(width=8, depth=32)
        self.user_tx_mem = Memory(width=8,
                                  depth=32,
                                  init=[ord(x) for x in "Hello, World!!\r\n"])
        self.mem_r_port = self.user_tx_mem.read_port()
        self.mem_w_port = self.user_rx_mem.write_port()
        self.packet_received = Signal()
        self.transmit_ready = Signal()
        self.transmit_packet = Signal()

    def elaborate(self, platform):
        m = Module()
        rx_port = self.user_rx_mem.read_port()
        tx_port = self.user_tx_mem.write_port()

        m.submodules += [self.mem_r_port, self.mem_w_port, rx_port, tx_port]

        led1 = platform.request("user_led", 0)
        led2 = platform.request("user_led", 1)

        m.d.comb += [
            tx_port.addr.eq(0),
            tx_port.en.eq(0),
            tx_port.data.eq(0),
            rx_port.addr.eq(0),
        ]

        m.d.sync += [
            led1.eq(rx_port.data & 1),
            led2.eq((rx_port.data & 2) >> 1),
        ]

        with m.FSM():
            with m.State("IDLE"):
                m.d.sync += self.transmit_packet.eq(0)
                with m.If(self.packet_received):
                    m.next = "RX"
            with m.State("RX"):
                with m.If(self.transmit_ready):
                    m.d.sync += self.transmit_packet.eq(1)
                    m.next = "IDLE"

        return m
Exemplo n.º 10
0
Arquivo: mac.py Projeto: ret/daqnet
    def __init__(self,
                 clk_freq,
                 phy_addr,
                 mac_addr,
                 rmii,
                 mdio,
                 phy_rst,
                 eth_led,
                 tx_buf_size=2048,
                 rx_buf_size=2048):
        # Memory Ports
        self.rx_port = None  # Assigned below
        self.tx_port = None  # Assigned below

        # TX port
        self.tx_start = Signal()
        self.tx_len = Signal(11)
        self.tx_offset = Signal(max=tx_buf_size - 1)

        # RX port
        self.rx_ack = Signal()
        self.rx_valid = Signal()
        self.rx_len = Signal(11)
        self.rx_offset = Signal(max=rx_buf_size - 1)

        # Inputs
        self.phy_reset = Signal()

        # Outputs
        self.link_up = Signal()

        self.clk_freq = clk_freq
        self.phy_addr = phy_addr
        self.mac_addr = [int(x, 16) for x in mac_addr.split(":")]
        self.rmii = rmii
        self.mdio = mdio
        self.phy_rst = phy_rst
        self.eth_led = eth_led

        # Create packet memories and interface ports
        self.tx_mem = Memory(8, tx_buf_size)
        self.tx_port = self.tx_mem.write_port()
        self.rx_mem = Memory(8, rx_buf_size)
        self.rx_port = self.rx_mem.read_port(transparent=False)
Exemplo n.º 11
0
    def __init__(self,
                 *,
                 signals,
                 sample_depth,
                 domain="sync",
                 sample_rate=60e6,
                 samples_pretrigger=1):
        """
        Parameters:
            signals            -- An iterable of signals that should be captured by the ILA.
            sample_depth       -- The depth of the desired buffer, in samples.
            domain             -- The clock domain in which the ILA should operate.
            sample_rate        -- Cosmetic indication of the sample rate. Used to format output.
            samples_pretrigger -- The number of our samples which should be captured _before_ the trigger.
                                  This also can act like an implicit synchronizer; so asynchronous inputs
                                  are allowed if this number is >= 2. Note that the trigger strobe is read
                                  on the rising edge of the
        """

        self.domain = domain
        self.signals = signals
        self.inputs = Cat(*signals)
        self.sample_width = len(self.inputs)
        self.sample_depth = sample_depth
        self.samples_pretrigger = samples_pretrigger
        self.sample_rate = sample_rate
        self.sample_period = 1 / sample_rate

        #
        # Create a backing store for our samples.
        #
        self.mem = Memory(width=self.sample_width,
                          depth=sample_depth,
                          name="ila_buffer")

        #
        # I/O port
        #
        self.trigger = Signal()
        self.sampling = Signal()
        self.complete = Signal()

        self.captured_sample_number = Signal(range(0, self.sample_depth))
        self.captured_sample = Signal(self.sample_width)
Exemplo n.º 12
0
    def elaborate(self, platform):
        m = Module()
        m.submodules.serdes = serdes = get_serdes_implementation()()

        seq = prbs14()
        print("Peaks will be", 5000/len(seq), "MHz apart")
        pattern = Memory(width=20, depth=len(seq), init=pack_mem(seq*20, 20))
        m.submodules.pattern_rport = rport = pattern.read_port(domain="tx")

        counter = Signal(range(len(seq) + 1))
        with m.If(counter == (len(seq) - 1)):
            m.d.tx += counter.eq(0) 
        with m.Else():
            m.d.tx += counter.eq(counter + 1) 

        m.d.comb += [
            rport.addr.eq(counter),
            serdes.tx_data.eq(rport.data)
        ]
        return m
Exemplo n.º 13
0
    def elaborate(self, platform):
        m = Module()

        # Create our memory initializer from our initial value.
        initial_value = self._initialization_value(self.initial_value,
                                                   self.data_width,
                                                   self.granularity,
                                                   self.byteorder)

        # Create the the memory used to store our data.
        memory_depth = 2**self.local_addr_width
        memory = Memory(width=self.data_width,
                        depth=memory_depth,
                        init=initial_value,
                        name=self.name)

        # Grab a reference to the bits of our Wishbone bus that are relevant to us.
        local_address_bits = self.bus.adr[:self.local_addr_width]

        # Create a read port, and connect it to our Wishbone bus.
        m.submodules.rdport = read_port = memory.read_port()
        m.d.comb += [
            read_port.addr.eq(local_address_bits),
            self.bus.dat_r.eq(read_port.data)
        ]

        # If this is a read/write memory, create a write port, as well.
        if not self.read_only:
            m.submodules.wrport = write_port = memory.write_port(
                granularity=self.granularity)
            m.d.comb += [
                write_port.addr.eq(local_address_bits),
                write_port.data.eq(self.bus.dat_w)
            ]

            # Generate the write enables for each of our words.
            for i in range(self.bytes_per_word):
                m.d.comb += write_port.en[i].eq(
                    self.bus.cyc &  # Transaction is active.
                    self.bus.stb &  # Valid data is being provided.
                    self.bus.we &  # This is a write.
                    self.bus.sel[
                        i]  # The relevant setion of the datum is being targeted.
                )

        # We can handle any transaction request in a single cycle, when our RAM handles
        # the read or write. Accordingly, we'll ACK the cycle after any request.
        m.d.sync += self.bus.ack.eq(self.bus.cyc & self.bus.stb
                                    & ~self.bus.ack)

        return m
Exemplo n.º 14
0
    def __init__(self,
                 table=None,
                 packet=None,
                 samples_per_symbol=1,
                 tx_domain="tx"):
        """
            table is a list of deserialized 20-bit words that represent a symbol table
            packet is the symbol indexes to send (in a Memory, not yet multiplied by samples_per_symbol)
            samples_per_symbol is the number of bits per symbol at the TX output bit rate
            tx_domain is the name of the domain used to clock the SERDES TX
        """
        self.table = Memory(width=20, depth=len(table), init=table)
        self.samples_per_symbol = samples_per_symbol
        self.tx_domain = tx_domain
        self.packet = packet

        # Inputs
        self.packet_length = Signal(16)
        self.tx_reset = Signal()

        # Outputs
        self.tx_data = Signal(20)
        self.tx_done = Signal(reset=1)  # Goes high when transmit has completed
Exemplo n.º 15
0
Arquivo: analyzer.py Projeto: zyp/luna
    def __init__(self, *, utmi_interface, mem_depth=8192):
        """
        Parameters:
            utmi_interface -- A record or elaboratable that presents a UTMI interface.
        """

        self.utmi = utmi_interface

        # Internal storage memory.
        self.mem = Memory(width=8, depth=mem_depth, name="analysis_ringbuffer")
        self.mem_size = mem_depth

        #
        # I/O port
        #
        self.stream = StreamInterface()

        self.idle = Signal()
        self.overrun = Signal()
        self.capturing = Signal()

        # Diagnostic I/O.
        self.sampling = Signal()
Exemplo n.º 16
0
    def __init__(self, *, umti_interface, mem_depth=8192):
        """
        Parameters:
            umti_interface -- A record or elaboratable that presents a UMTI interface.
        """

        self.umti = umti_interface

        # Internal storage memory.
        self.mem = Memory(width=8, depth=mem_depth, name="analysis_ringbuffer")
        self.mem_size = mem_depth

        #
        # I/O port
        #
        self.data_available = Signal()
        self.data_out = Signal(8)
        self.next = Signal()

        self.overrun = Signal()
        self.capturing = Signal()

        # Diagnostic I/O.
        self.sampling = Signal()
Exemplo n.º 17
0
class Memtest(Elaboratable):
    def __init__(self):
        self.mem = Memory(width=MEMWIDTH, depth=Firestarter.memdepth)

    def elaborate(self, platform):
        m = Module()
        led0 = platform.request("led", 0)
        led1 = platform.request("led", 1)
        m.submodules.rdport = rdport = self.mem.read_port()
        with m.If(rdport.data == 255):
            m.d.comb += led0.eq(0)
        with m.Else():
            m.d.comb += led0.eq(1)
        timer = Signal(range(round(100E6)))
        with m.If(timer > 100):
            m.d.comb += rdport.addr.eq(100)
        with m.Else():
            m.d.comb += rdport.addr.eq(0)
        m.d.sync += timer.eq(timer + 1)
        m.d.comb += led1.o.eq(timer[-1])
        return m
Exemplo n.º 18
0
Arquivo: rmii.py Projeto: ret/daqnet
def test_rmii_tx():
    from nmigen.back import pysim
    from nmigen import Memory

    txen = Signal()
    txd0 = Signal()
    txd1 = Signal()

    txbytes = [
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x44, 0x4e, 0x30, 0x76, 0x9e,
        0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x02, 0x44,
        0x4e, 0x30, 0x76, 0x9e, 0xc0, 0xa8, 0x02, 0xc8, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0xc0, 0xa8, 0x02, 0xc8
    ]

    preamblebytes = [0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5]
    padbytes = [0x00] * (60 - len(txbytes))
    crcbytes = [0x44, 0x5E, 0xB4, 0xD2]

    txnibbles = []
    rxnibbles = []

    for txbyte in preamblebytes + txbytes + padbytes + crcbytes:
        txnibbles += [
            (txbyte & 0b11),
            ((txbyte >> 2) & 0b11),
            ((txbyte >> 4) & 0b11),
            ((txbyte >> 6) & 0b11),
        ]

    # Put the transmit bytes into memory at some offset, and fill the rest of
    # memory with all-1s (to ensure we're not relying on memory being zeroed).
    txbytes_zp = txbytes + [0xFF] * (128 - len(txbytes))
    txoffset = 120
    txbytes_mem = txbytes_zp[-txoffset:] + txbytes_zp[:-txoffset]
    mem = Memory(8, 128, txbytes_mem)
    mem_port = mem.read_port()

    rmii_tx = RMIITx(mem_port, txen, txd0, txd1)

    def testbench():
        for _ in range(10):
            yield

        yield (rmii_tx.tx_start.eq(1))
        yield (rmii_tx.tx_offset.eq(txoffset))
        yield (rmii_tx.tx_len.eq(len(txbytes)))

        yield

        yield (rmii_tx.tx_start.eq(0))
        yield (rmii_tx.tx_offset.eq(0))
        yield (rmii_tx.tx_len.eq(0))

        for _ in range((len(txbytes) + 12) * 4 + 120):
            if (yield txen):
                rxnibbles.append((yield txd0) | ((yield txd1) << 1))
            yield

        print(len(txnibbles), len(rxnibbles))
        print(txnibbles)
        print(rxnibbles)
        assert txnibbles == rxnibbles

    mod = Module()
    mod.submodules += rmii_tx, mem_port

    vcdf = open("rmii_tx.vcd", "w")
    with pysim.Simulator(mod, vcd_file=vcdf) as sim:
        sim.add_clock(1 / 50e6)
        sim.add_sync_process(testbench())
        sim.run()
Exemplo n.º 19
0
Arquivo: rmii.py Projeto: ret/daqnet
def test_rmii_rx():
    import random
    from nmigen.back import pysim
    from nmigen import Memory

    crs_dv = Signal()
    rxd0 = Signal()
    rxd1 = Signal()

    mem = Memory(8, 128)
    mem_port = mem.write_port()
    mac_addr = [random.randint(0, 255) for _ in range(6)]

    rmii_rx = RMIIRx(mac_addr, mem_port, crs_dv, rxd0, rxd1)

    def testbench():
        def tx_packet():
            yield (crs_dv.eq(1))
            # Preamble
            for _ in range(random.randint(10, 40)):
                yield (rxd0.eq(1))
                yield (rxd1.eq(0))
                yield
            # SFD
            yield (rxd0.eq(1))
            yield (rxd1.eq(1))
            yield
            # Data
            for txbyte in txbytes:
                for dibit in range(0, 8, 2):
                    yield (rxd0.eq((txbyte >> (dibit + 0)) & 1))
                    yield (rxd1.eq((txbyte >> (dibit + 1)) & 1))
                    yield
            yield (crs_dv.eq(0))

            # Finish clocking
            for _ in range(6):
                yield

        for _ in range(10):
            yield

        txbytes = [
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xDE, 0xF1, 0x38, 0x89,
            0x40, 0x08, 0x00, 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00,
            0x40, 0x01, 0xB6, 0xD0, 0xC0, 0xA8, 0x01, 0x88, 0xC0, 0xA8, 0x01,
            0x00, 0x08, 0x00, 0x0D, 0xD9, 0x12, 0x1E, 0x00, 0x07, 0x3B, 0x3E,
            0x0C, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x13, 0x03, 0x0F, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x48, 0x65,
            0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x48, 0x65,
            0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x48, 0x65,
            0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x48, 0x52,
            0x32, 0x1F, 0x9E
        ]

        # Transmit first packet
        yield from tx_packet()

        # Check packet was received
        assert (yield rmii_rx.rx_valid)
        assert (yield rmii_rx.rx_len) == 102
        assert (yield rmii_rx.rx_offset) == 0
        mem_contents = []
        for idx in range(102):
            mem_contents.append((yield mem[idx]))
        assert mem_contents == txbytes

        # Pause (inter-frame gap)
        for _ in range(20):
            yield

        assert (yield rmii_rx.rx_valid) == 0

        # Transmit a second packet
        yield from tx_packet()

        # Check packet was received
        assert (yield rmii_rx.rx_valid)
        assert (yield rmii_rx.rx_len) == 102
        assert (yield rmii_rx.rx_offset) == 102
        mem_contents = []
        for idx in range(102):
            mem_contents.append((yield mem[(102 + idx) % 128]))
        assert mem_contents == txbytes

        yield

    mod = Module()
    mod.submodules += rmii_rx, mem_port
    vcdf = open("rmii_rx.vcd", "w")
    with pysim.Simulator(mod, vcd_file=vcdf) as sim:
        sim.add_clock(1 / 50e6)
        sim.add_sync_process(testbench())
        sim.run()
Exemplo n.º 20
0
    def elaborate(self, platform):
        m = Module()
        m.submodules.lfsr = self.lfsr
        m.submodules.crc = self.crc

        if self.printer:
            payload_data = self.printer.mem
        else:
            payload_data = Memory(width=8, depth=64)

        m.submodules.payload_wport = wport = payload_data.write_port()

        header = Signal(16)
        header_idx = Signal(range(16))

        pdu = Signal(8)
        m.d.comb += pdu.eq(header[0:8])

        size = Signal(8)
        m.d.comb += size.eq(header[8:16])

        payload_read = Signal(12)  # How many bits of the payload we've read

        payload_addr = Signal(48)
        payload_addr_idx = Signal(8)

        payload_sec_header_idx = Signal(4)
        payload_sec_header = Signal(16)
        payload_sec_size = Signal(8)
        payload_sec_type = Signal(8)
        m.d.comb += [
            payload_sec_size.eq(payload_sec_header[0:8]),
            payload_sec_type.eq(payload_sec_header[8:16])
        ]
        payload_sec_read = Signal(12)

        payload_byte = Signal(8)

        dewhitened = Signal()
        m.d.comb += dewhitened.eq(self.bitstream ^ self.lfsr.output)

        crc = Signal(24)
        crc_idx = Signal(8)
        crc_matches = self.crc_matches
        m.d.comb += crc_matches.eq(
            Cat([self.crc.crc[i] == crc[24 - i - 1] for i in range(24)]).all())

        should_print = Signal()

        with m.FSM() as fsm:
            # Exposed for debugging purposes
            m.d.comb += self.state.eq(fsm.state)

            with m.State("IDLE"):
                with m.If(self.sample):
                    m.next = "READ_HEADER"
                    m.d.sync += [
                        header_idx.eq(1),
                        header.eq(Cat(dewhitened, [0] * 7)),
                        self.currentbit.eq(dewhitened),
                        self.lfsr.run_strobe.eq(1),
                        self.crc.input.eq(dewhitened),
                        self.crc.en.eq(1),
                        should_print.eq(0),
                    ]
                with m.Else():
                    # Reset goes high at the end
                    m.d.sync += [self.lfsr.reset.eq(0), self.crc.reset.eq(0)]

            with m.State("READ_HEADER"):
                with m.If(self.sample):
                    m.d.sync += [
                        header_idx.eq(header_idx + 1),
                        header.eq(header | (dewhitened << header_idx)),
                        self.currentbit.eq(dewhitened),
                        self.lfsr.run_strobe.eq(1),
                        self.crc.input.eq(dewhitened),
                        self.crc.en.eq(1),
                    ]
                    with m.If(header_idx == 15):
                        m.d.sync += [
                            payload_read.eq(0),
                            payload_addr.eq(0),
                            payload_addr_idx.eq(0)
                        ]
                        m.next = "READ_PAYLOAD_ADDR"
                with m.Else():
                    m.d.sync += [self.lfsr.run_strobe.eq(0), self.crc.en.eq(0)]

            with m.State("READ_PAYLOAD_ADDR"):
                with m.If(self.sample):
                    m.d.sync += [
                        payload_read.eq(payload_read + 1),
                        payload_addr_idx.eq(payload_addr_idx + 1),
                        payload_addr.eq(payload_addr
                                        | (dewhitened << payload_addr_idx)),
                        self.currentbit.eq(dewhitened),
                        self.lfsr.run_strobe.eq(1),
                        self.crc.input.eq(dewhitened),
                        self.crc.en.eq(1),
                    ]
                    with m.If(payload_addr_idx == (48 - 1)):
                        m.d.sync += [
                            payload_sec_header.eq(0),
                            payload_sec_header_idx.eq(0)
                        ]
                        m.next = "READ_PAYLOAD_SECTION_HEADER"
                with m.Else():
                    m.d.sync += [self.lfsr.run_strobe.eq(0), self.crc.en.eq(0)]

            with m.State("READ_PAYLOAD_SECTION_HEADER"):
                with m.If(self.sample):
                    m.d.sync += [
                        payload_read.eq(payload_read + 1),
                        payload_sec_header_idx.eq(payload_sec_header_idx + 1),
                        payload_sec_header.eq(payload_sec_header | (
                            dewhitened << payload_sec_header_idx)),
                        self.currentbit.eq(dewhitened),
                        self.lfsr.run_strobe.eq(1),
                        self.crc.input.eq(dewhitened),
                        self.crc.en.eq(1),
                    ]
                    with m.If(payload_sec_header_idx == 15):
                        m.d.sync += payload_sec_read.eq(0)
                        m.next = "READ_PAYLOAD_SECTION_CONTENT"
                with m.Else():
                    m.d.sync += [self.lfsr.run_strobe.eq(0), self.crc.en.eq(0)]

                # If we previously were in READ_PAYLOAD_SECTION_CONTENT, null terminate
                # what we read
                m.d.comb += [
                    wport.addr.eq((payload_sec_read >> 3) + 1),
                    wport.en.eq(1),
                    wport.data.eq(0)
                ]

            with m.State("READ_PAYLOAD_SECTION_CONTENT"):
                with m.If(self.sample):
                    m.d.sync += [
                        payload_read.eq(payload_read + 1),
                        payload_sec_read.eq(payload_sec_read + 1),
                        self.currentbit.eq(dewhitened),
                        self.lfsr.run_strobe.eq(1),
                        self.crc.input.eq(dewhitened),
                        self.crc.en.eq(1),
                    ]

                    # m.d.comb += self.debug.eq(payload_sec_type == 0x9)

                    with m.If((payload_sec_type == 0x9)
                              | (payload_sec_type == 0x8)
                              ):  # If this section is a complete local name
                        idx = payload_read & 0x7
                        with m.If(idx == 0):
                            m.d.sync += payload_byte.eq(dewhitened)
                        with m.Else():
                            m.d.sync += payload_byte.eq(payload_byte
                                                        | (dewhitened << idx))
                        with m.If(idx == 0b111):
                            m.d.comb += [
                                wport.addr.eq(payload_sec_read >> 3),
                                wport.en.eq(1),
                                wport.data.eq(payload_byte
                                              | (dewhitened << idx))
                            ]
                        m.d.sync += should_print.eq(should_print | 1)

                    with m.If((payload_read + 1) >= size << 3):
                        m.next = "READ_CRC"
                        m.d.sync += [crc_idx.eq(0), crc.eq(0)]

                    with m.Else():
                        with m.If((payload_sec_read +
                                   1) == (payload_sec_size - 1) << 3):
                            m.d.sync += [
                                payload_sec_header.eq(0),
                                payload_sec_header_idx.eq(0)
                            ]
                            m.next = "READ_PAYLOAD_SECTION_HEADER"

                with m.Else():
                    m.d.sync += [self.lfsr.run_strobe.eq(0), self.crc.en.eq(0)]

            with m.State("READ_CRC"):
                with m.If(self.sample):
                    m.d.sync += [
                        crc_idx.eq(crc_idx + 1),
                        crc.eq(crc | (dewhitened << crc_idx)),
                        self.currentbit.eq(dewhitened),
                        self.lfsr.run_strobe.eq(1),
                        self.crc.en.eq(0),
                    ]
                    with m.If(crc_idx == 23):
                        m.next = "CHECK_CRC"
                with m.Else():
                    m.d.sync += [self.lfsr.run_strobe.eq(0), self.crc.en.eq(0)]

            with m.State("CHECK_CRC"):
                with m.If(crc_matches & should_print):
                    m.next = "START_READOUT"
                with m.Else():
                    m.next = "IDLE"
                    m.d.comb += self.done.eq(1)
                    m.d.sync += [
                        self.lfsr.run_strobe.eq(0),
                        self.lfsr.reset.eq(1),
                        self.crc.reset.eq(1)
                    ]
            with m.State("START_READOUT"):
                # If we previously were in READ_PAYLOAD_SECTION_CONTENT, null terminate
                # what we read
                m.d.comb += [
                    wport.addr.eq((payload_sec_read >> 3) + 1),
                    wport.en.eq(1),
                    wport.data.eq(0)
                ]

                m.d.comb += self.debug.eq(1)
                if self.printer:
                    m.d.comb += self.printer.start.eq(1)
                    m.next = "WAIT_READOUT"
                else:
                    m.d.comb += self.done.eq(1)
                    m.next = "IDLE"
            with m.State("WAIT_READOUT"):
                if self.printer:
                    with m.If(self.printer.done):
                        m.next = "IDLE"
                        m.d.comb += self.done.eq(1)
                        m.d.sync += [
                            self.lfsr.run_strobe.eq(0),
                            self.lfsr.reset.eq(1),
                            self.crc.reset.eq(1)
                        ]
                else:
                    # Invalid
                    pass

        return m
from nmigen_soc.wishbone.sram import SRAM
from nmigen import Memory, Signal, Module

memory = Memory(width=32, depth=16)
sram = SRAM(memory=memory,granularity=8)

# valid wishbone signals include
# sram.bus.adr
# sram.bus.dat_w
# sram.bus.dat_r
# sram.bus.sel
# sram.bus.cyc
# sram.bus.stb
# sram.bus.we
# sram.bus.ack

# setup simulation
from nmigen.back.pysim import Simulator, Delay, Settle
m = Module()
m.submodules.sram = sram
sim = Simulator(m)
sim.add_clock(1e-6)

def print_sig(sig, format=None):
    if format == None:
        print(f"{sig.__repr__()} = {(yield sig)}")
    if format == "h":
        print(f"{sig.__repr__()} = {hex((yield sig))}")

def process():
    # enable necessary signals for write
Exemplo n.º 22
0
    def elaborate(self, platform):
        m = Module()

        # Range shortcuts for internal signals.
        address_range = range(0, self.depth + 1)

        #
        # Core internal "backing store".
        #
        memory = Memory(width=self.width, depth=self.depth + 1, name=self.name)
        m.submodules.read_port  = read_port  = memory.read_port()
        m.submodules.write_port = write_port = memory.write_port()

        # Always connect up our memory's data/en ports to ours.
        m.d.comb += [
            self.read_data  .eq(read_port.data),

            write_port.data .eq(self.write_data),
            write_port.en   .eq(self.write_en & ~self.full)
        ]

        #
        # Write port.
        #

        # We'll track two pieces of data: our _committed_ write position, and our current un-committed write one.
        # This will allow us to rapidly backtrack to our pre-commit position.
        committed_write_pointer = Signal(address_range)
        current_write_pointer   = Signal(address_range)
        m.d.comb += write_port.addr.eq(current_write_pointer)


        # Compute the location for the next write, accounting for wraparound. We'll not assume a binary-sized
        # buffer; so we'll compute the wraparound manually.
        next_write_pointer      = Signal.like(current_write_pointer)
        with m.If(current_write_pointer == self.depth):
            m.d.comb += next_write_pointer.eq(0)
        with m.Else():
            m.d.comb += next_write_pointer.eq(current_write_pointer + 1)


        # If we're writing to the fifo, update our current write position.
        with m.If(self.write_en & ~self.full):
            m.d.sync += current_write_pointer.eq(next_write_pointer)

        # If we're committing a FIFO write, update our committed position.
        with m.If(self.write_commit):
            m.d.sync += committed_write_pointer.eq(current_write_pointer)

        # If we're discarding our current write, reset our current position,
        with m.If(self.write_discard):
            m.d.sync += current_write_pointer.eq(committed_write_pointer)


        #
        # Read port.
        #

        # We'll track two pieces of data: our _committed_ read position, and our current un-committed read one.
        # This will allow us to rapidly backtrack to our pre-commit position.
        committed_read_pointer = Signal(address_range)
        current_read_pointer   = Signal(address_range)


        # Compute the location for the next read, accounting for wraparound. We'll not assume a binary-sized
        # buffer; so we'll compute the wraparound manually.
        next_read_pointer      = Signal.like(current_read_pointer)
        with m.If(current_read_pointer == self.depth):
            m.d.comb += next_read_pointer.eq(0)
        with m.Else():
            m.d.comb += next_read_pointer.eq(current_read_pointer + 1)


        # Our memory always takes a single cycle to provide its read output; so we'll update its address
        # "one cycle in advance". Accordingly, if we're about to advance the FIFO, we'll use the next read
        # address as our input. If we're not, we'll use the current one.
        with m.If(self.read_en & ~self.empty):
            m.d.comb += read_port.addr.eq(next_read_pointer)
        with m.Else():
            m.d.comb += read_port.addr.eq(current_read_pointer)


        # If we're reading from our the fifo, update our current read position.
        with m.If(self.read_en & ~self.empty):
            m.d.sync += current_read_pointer.eq(next_read_pointer)

        # If we're committing a FIFO write, update our committed position.
        with m.If(self.read_commit):
            m.d.sync += committed_read_pointer.eq(current_read_pointer)

        # If we're discarding our current write, reset our current position,
        with m.If(self.read_discard):
            m.d.sync += current_read_pointer.eq(committed_read_pointer)


        #
        # FIFO status.
        #

        # Our FIFO is empty if our read and write pointers are in the same. We'll use the current
        # read position (which leads ahead) and the committed write position (which lags behind).
        m.d.comb += self.empty.eq(current_read_pointer == committed_write_pointer)

        # For our space available, we'll use the current write position (which leads ahead) and our committed
        # read position (which lags behind). This yields two cases: one where the buffer isn't wrapped around,
        # and one where it is.
        with m.If(self.full):
            m.d.comb += self.space_available.eq(0)
        with m.Elif(committed_read_pointer <= current_write_pointer):
            m.d.comb += self.space_available.eq(self.depth - (current_write_pointer - committed_read_pointer))
        with m.Else():
            m.d.comb += self.space_available.eq(committed_read_pointer - current_write_pointer - 1)

        # Our FIFO is full if we don't have any space available.
        m.d.comb += self.full.eq(next_write_pointer == committed_read_pointer)


        # If we're not supposed to be in the sync domain, rename our sync domain to the target.
        if self.domain != "sync":
            m = DomainRenamer({"sync": self.domain})(m)

        return m
Exemplo n.º 23
0
Arquivo: crc.py Projeto: ret/daqnet
class CRC32(Elaboratable):
    """
    Ethernet CRC32

    Processes one byte of data every two clock cycles.

    Inputs:
        * `reset`: Re-initialises CRC to start state while high
        * `data`: 8-bit input data
        * `data_valid`: Pulsed high when new data is ready at `data`.
                        Requires one clock to process between new data.

    Outputs:
        * `crc_out`: complement of current 32-bit CRC value
        * `crc_match`: high if crc residual is currently 0xC704DD7B

    When using for transmission, note that `crc_out` must be sent in little
    endian (i.e. if `crc_out` is 0xAABBCCDD then transmit 0xDD 0xCC 0xBB 0xAA).
    """
    def __init__(self):
        # Inputs
        self.reset = Signal()
        self.data = Signal(8)
        self.data_valid = Signal()

        # Outputs
        self.crc_out = Signal(32)
        self.crc_match = Signal()

    def elaborate(self, platform):

        m = Module()
        crc = Signal(32)

        self.crctable = Memory(32, 256, make_crc32_table())
        table_port = self.crctable.read_port()
        m.submodules += table_port

        m.d.comb += [
            self.crc_out.eq(crc ^ 0xFFFFFFFF),
            self.crc_match.eq(crc == 0xDEBB20E3),
            table_port.addr.eq(crc ^ self.data),
        ]

        with m.FSM():
            with m.State("RESET"):
                m.d.sync += crc.eq(0xFFFFFFFF)
                m.next = "IDLE"

            with m.State("IDLE"):
                with m.If(self.reset):
                    m.next = "RESET"
                with m.Elif(self.data_valid):
                    m.next = "BUSY"

            with m.State("BUSY"):
                with m.If(self.reset):
                    m.next = "RESET"
                m.d.sync += crc.eq(table_port.data ^ (crc >> 8))
                m.next = "IDLE"

        return m
Exemplo n.º 24
0
    def elaborate(self, platform):

        m = Module()

        # N is size of RAMs.
        N = self.M + 2
        assert _is_power_of_2(N)

        # kernel_RAM is a buffer of convolution kernel coefficents.
        # It is read-only.  The 0'th element is zero, because the kernel
        # has length N-1.
        kernel_RAM = Memory(width=COEFF_WIDTH, depth=256, init=kernel)
        # kernel_RAM = Memory(width=COEFF_WIDTH, depth=N, init=kernel)
        m.submodules.kr_port = kr_port = kernel_RAM.read_port()

        # sample_RAM is a circular buffer for incoming samples.
        # sample_RAM = Array(
        #     Signal(signed(self.sample_depth), reset_less=True, reset=0)
        #     for _ in range(N)
        # )
        sample_RAM = Memory(width=self.sample_depth, depth=N, init=[0] * N)
        m.submodules.sw_port = sw_port = sample_RAM.write_port()
        m.submodules.sr_port = sr_port = sample_RAM.read_port()

        # The rotors index through sample_RAM.  They have an extra MSB
        # so we can distinguish between buffer full and buffer empty.
        #
        #   w_rotor: write rotor.  Points to the next entry to be written.
        #   s_rotor: start rotor.  Points to the oldest valid entry.
        #   r_rotor: read rotor.  Points to the next entry to be read.
        #
        # The polyphase decimator reads each sample N / R times, so
        # `r_rotor` is **NOT** the oldest needed sample.  Instead,
        # `s_rotor` is the oldest.  `s_rotor` is incremented by `R`
        # at the start of each convolution.
        #
        # We initialize the rotors so that the RAM contains N-1 zero samples,
        # and `r_rotor` is pointing to the first sample to be used.
        # The convolution engine can start immediately and produce a zero
        # result.
        w_rotor = Signal(range(2 * N), reset=N)
        s_rotor = Signal(range(2 * N), reset=1)
        r_rotor = Signal(range(2 * N), reset=1)

        # `c_index` is the next kernel coefficient to read.
        # `c_index` == 0 indicates done, so start at 1.
        c_index = Signal(range(N), reset=1)  # kernel coefficient index

        # Useful conditions
        buf_n_used = Signal(range(N + 1))
        buf_is_empty = Signal()
        buf_is_full = Signal()
        buf_n_readable = Signal(range(N + 1))
        buf_has_readable = Signal()
        m.d.comb += [
            buf_n_used.eq(w_rotor - s_rotor),
            buf_is_empty.eq(buf_n_used == 0),
            buf_is_full.eq(buf_n_used == N),
            buf_n_readable.eq(w_rotor - r_rotor),
            buf_has_readable.eq(buf_n_readable != 0),
            # Assert(buf_n_used <= N),
            # Assert(buf_n_readable <= buf_n_used),
        ]

        # put incoming samples into sample_RAM.
        m.d.comb += [
            self.samples_in.o_ready.eq(~buf_is_full),
            sw_port.addr.eq(w_rotor[:-1]),
            sw_port.data.eq(self.samples_in.i_data),
        ]
        m.d.sync += sw_port.en.eq(self.samples_in.received())
        with m.If(self.samples_in.received()):
            m.d.sync += [
                # sample_RAM[w_rotor[:-1]].eq(self.samples_in.i_data),
                w_rotor.eq(w_rotor + 1),
            ]

        # The convolution is pipelined.
        #
        #   stage 0: fetch coefficient and sample from their RAMs.
        #   stage 1: multiply coefficient and sample.
        #   stage 2: add product to accumulator.
        #   stage 3: if complete, try to send accumulated sample.
        #
        p_valid = Signal(4)
        p_ready = Array(
            Signal(name=f'p_ready{i}', reset=True) for i in range(4))
        p_complete = Signal(4)
        m.d.sync += [
            p_valid[1:].eq(p_valid[:-1]),
            p_ready[0].eq(p_ready[1]),
            p_ready[1].eq(p_ready[2]),
            p_ready[2].eq(p_ready[3]),
        ]

        # calculation variables
        coeff = Signal(COEFF_SHAPE)
        sample = Signal(signed(self.sample_depth))
        prod = Signal(signed(COEFF_WIDTH + self.sample_depth))
        acc = Signal(signed(self.acc_width))

        # Stage 0.
        en0 = Signal()
        m.d.comb += en0.eq(buf_has_readable & p_ready[0] * (c_index != 0))

        # with m.If(en0):
        #     m.d.sync += [
        #         coeff.eq(kernel_RAM[c_index]),
        #     ]
        m.d.comb += coeff.eq(kr_port.data)
        with m.If(en0):
            m.d.sync += [
                sample.eq(sample_RAM[r_rotor[:-1]]),
            ]
        with m.If(en0):
            m.d.sync += [
                c_index.eq(c_index + 1),
                r_rotor.eq(r_rotor + 1),
                p_valid[0].eq(True),
                p_complete[0].eq(False),
                # kr_port.addr.eq(c_index + 1),
            ]
        m.d.comb += kr_port.addr.eq(c_index)
        # with m.If(buf_has_readable & p_ready[0] & (c_index != 0)):
        #     m.d.sync += [
        #         coeff.eq(kernel_RAM[c_index]),
        #         sample.eq(sample_RAM[r_rotor[:-1]]),
        #         c_index.eq(c_index + 1),
        #         r_rotor.eq(r_rotor + 1),
        #         p_valid[0].eq(True),
        #         p_complete[0].eq(False),
        #     ]
        with m.If((~buf_has_readable | ~p_ready[0]) & (c_index != 0)):
            m.d.sync += [
                p_valid[0].eq(False),
                p_complete[0].eq(False),
            ]
        # When c_index is zero, all convolution samples have been read.
        # Set up the rotors for the next sample.  (and pause the
        # pipelined calculation.)
        with m.If(c_index == 0):
            m.d.sync += [
                c_index.eq(c_index + 1),
                s_rotor.eq(s_rotor + self.R),
                r_rotor.eq(s_rotor + self.R),
                p_valid[0].eq(False),
                p_complete[0].eq(True),
            ]

        # Stage 1.
        with m.If(p_valid[1] & p_ready[1]):
            m.d.sync += [
                prod.eq(coeff * sample),
                p_complete[1].eq(p_complete[0]),
            ]

        # Stage 2.
        with m.If(p_valid[2] & p_ready[2]):
            m.d.sync += [
                acc.eq(acc + prod),
                p_complete[2].eq(p_complete[1]),
            ]

        # Stage 3.
        m.d.comb += p_ready[3].eq(~self.samples_out.full())
        m.d.sync += p_complete[3].eq(p_complete[3] | p_complete[2])
        with m.If(p_valid[3] & p_ready[3] & p_complete[2]):
            m.d.sync += [
                self.samples_out.o_valid.eq(1),
                self.samples_out.o_data.eq(acc[self.shift:]),
                acc.eq(0),
                p_complete[3].eq(False),
            ]

        with m.If(self.samples_out.sent()):
            m.d.sync += [
                self.samples_out.o_valid.eq(0),
            ]

        # # s_in_index = Signal(range(2 * N), reset=N)
        # # s_out_index = Signal(range(2 * N), reset=self.R + 1)
        # # c_index = Signal(range(N), reset=1)
        # # start_index = Signal(range(2 *  N), reset=self.R)
        # s_in_index = Signal(range(2 * N), reset=N)
        # s_out_index = Signal(range(2 * N))
        # c_index = Signal(range(N))
        # start_index = Signal(range(2 *  N))
        #
        # coeff = Signal(signed(16))
        # sample = Signal(signed(self.sample_depth))
        # prod = Signal(signed(2 * self.sample_depth))
        # acc = Signal(signed(self.acc_width))
        #
        # m = Module()
        #
        # n_full = (s_in_index - start_index - 1)[:s_in_index.shape()[0]]
        # n_avail = (s_in_index - s_out_index)[:-1]
        # print(f's_in_index shape = {s_in_index.shape()}')
        # print(f'start_index shape = {start_index.shape()}')
        # print(f'n_full shape = {n_full.shape()}')
        # print(f'n_avail shape = {n_avail.shape()}')
        # full = Signal(n_full.shape())
        # avail = Signal(n_avail.shape())
        # m.d.comb += full.eq(n_full)
        # m.d.comb += avail.eq(n_avail)
        #
        #
        # # input process stores new samples in the ring buffer.
        # # with m.If(self.samples_in.received()):
        # #     m.d.sync += [
        # #         sample_RAM[s_in_index[:-1]].eq(self.samples_in.i_data),
        # #     ]
        # with m.If(self.samples_in.received()):
        #     m.d.sync += [
        #         sample_RAM[s_in_index[:-1]].eq(self.samples_in.i_data),
        #         s_in_index.eq(s_in_index + 1),
        #     ]
        # m.d.sync += [
        #     self.samples_in.o_ready.eq(n_full < N),
        # ]
        #
        # # convolution process
        # sample_ready = Signal()
        # sample_ready = n_avail > 0
        #
        # # with m.If(c_index == 1):
        # #     with m.If(sample_ready):
        # #         m.d.sync += [
        # #             start_index.eq(start_index + self.R),
        # #             s_out_index.eq(start_index + self.R + 1),
        # #         ]
        # #     with m.Else():
        # #         with m.If(sample_ready):
        # #             m.d.sync += [
        # #                 s_out_index.eq(s_out_index + 1),
        # #          ]
        # # with m.Else():
        # #     with m.If(sample_ready):
        # #         m.d.sync += [
        # #             s_out_index.eq(s_out_index + 1),
        # #         ]
        #
        # with m.If(sample_ready):
        #     with m.If(c_index == 1):
        #         m.d.sync += [
        #             start_index.eq(start_index + self.R),
        #             s_out_index.eq(start_index + self.R + 1),
        #         ]
        #     with m.Else():
        #         m.d.sync += [
        #             s_out_index.eq(s_out_index + 1),
        #         ]
        #
        # with m.If(c_index == 2):
        #     with m.If(~self.samples_out.full()):
        #         m.d.sync += [
        #             self.samples_out.o_valid.eq(True),
        #             self.samples_out.o_data.eq(acc[self.shift:]),
        #             acc.eq(0),
        #             c_index.eq(c_index + 1),
        #         ]
        # with m.Else():
        #     with m.If(sample_ready):
        #         m.d.sync += [
        #             acc.eq(acc + prod),
        #             c_index.eq(c_index + 1),
        #         ]
        #
        # with m.If(sample_ready):
        #     m.d.sync += [
        #         prod.eq(coeff * sample),
        #     ]
        #
        # with m.If(sample_ready):
        #     m.d.sync += [
        #         coeff.eq(kernel_RAM[c_index]),
        #     ]
        #
        # with m.If(sample_ready):
        #     m.d.sync += [
        #         sample.eq(sample_RAM[s_out_index]),
        #     ]
        #
        # with m.If(self.samples_out.sent()):
        #     m.d.sync += [
        #         self.samples_out.o_valid.eq(False),
        #     ]
        # # # convolution process
        # # if c_index == 0:
        # #     if sample_ready:
        # #         start_index += R
        # #         s_out_index = start_index + R + 1
        # # else:
        # #     if sample_ready:
        # #         s_out_index += 1
        # #
        # # if c_index == 1:
        # #     if not out_full:
        # #         out_sample = acc[shift:]
        # #         out_valid = True
        # #         acc = 0
        # #         c_index += 1
        # # else
        # #     if sample_ready:
        # #         acc += prod
        # #         c_index += 1
        # #
        # # if sample_ready:
        # #     prod = coeff * sample
        # #
        # # if sample_ready:
        # #    coeff = kernel_RAM[c_index]
        # #
        # # if sample_ready:
        # #    sample = sample_RAM[s_out_index]
        #
        # # # convolution process
        # # fill = Signal(range(N + 1))
        # # m.d.comb += fill.eq(s_in_index - s_out_index)
        # # with m.FSM():
        # #
        # #     with m.State('RUN'):
        # #         # when s_out_index MSB is zero, sample is ready.
        # #         # when MSB is one, test out_idx < in_idx.
        # #         # extended_in_index = Cat(s_in_index, 1)
        # #         sample_ready = (fill > 0) & (fill <= N)
        # #         # sample_ready = s_out_index < extended_in_index
        # #         # xii = Signal.like(s_out_index)
        # #         sr = Signal()
        # #         # m.d.comb += xii.eq(extended_in_index)
        # #         m.d.comb += sr.eq(sample_ready)
        # #         with m.If(sample_ready):
        # #             m.d.sync += [
        # #                 acc.eq(acc + prod),   # sign extension is automatic
        # #                 prod.eq(coeff * sample),
        # #                 coeff.eq(kernel_RAM[c_index]),
        # #                 sample.eq(sample_RAM[s_out_index[:-1]]),
        # #                 c_index.eq(c_index + 1),
        # #                 s_out_index.eq(s_out_index + 1),
        # #             ]
        # #             with m.If(c_index == 0):
        # #                 m.next = 'DONE'
        # #         with m.If(self.samples_out.sent()):
        # #             m.d.sync += [
        # #                 self.samples_out.o_valid.eq(False),
        # #             ]
        # #
        # #     with m.State('DONE'):
        # #         with m.If(~self.samples_out.full()):
        # #             m.d.sync += [
        # #                 self.samples_out.o_valid.eq(True),
        # #                 self.samples_out.o_data.eq(acc[self.shift:]),
        # #                 c_index.eq(1),
        # #                 start_index.eq(start_index + self.R),
        # #                 # s_out_index[:-1].eq(start_index + self.R + 1),
        # #                 # s_out_index[-1].eq(0),
        # #                 s_out_index.eq(start_index + self.R + 1),
        # #                 coeff.eq(0),
        # #                 sample.eq(0),
        # #                 prod.eq(0),
        # #                 acc.eq(0),
        # #             ]
        # #             m.next = 'RUN'
        #
        #
        # # i_ready = true
        # # if received:
        # #     sample_RAM[in_index] = samples_in.i_data
        # #     in_index += 1
        # #
        # # FSM:
        # #     start:
        # #         if start_index + cv_index < in_index:  <<<<< Wrong
        # #             acc += sign_extend(prod)
        # #             prod = coeff * sample
        # #             coeff = kernel_RAM[cv_index]
        # #             sample = sample_RAM[(start_index + cv_index)[:-1]]
        # #
        # #             if cv_index + 1 == 0:
        # #                 goto done
        # #
        # #     done:
        # #         o_valid = true
        # #         o_data = acc[shift:shift + 16]
        # #         acc = 0
        # #         start_index = (start_index + R) % Mp2
        # #         cv_index = 0
        # #         prod = 0
        # #         coeff = 0
        # #         sample = 0
        # #
        # # if sent:
        # #     o_valid = false

        return m
Exemplo n.º 25
0
Arquivo: mac.py Projeto: ret/daqnet
class MAC(Elaboratable):
    """
    Ethernet RMII MAC.

    Clock domain:
        This module is clocked at the system clock frequency and generates an
        RMII clock domain internally. All its inputs and outputs are in the
        system clock domain.

    Parameters:
        * `clk_freq`: MAC's clock frequency
        * `phy_addr`: 5-bit address of the PHY
        * `mac_addr`: MAC address in standard XX:XX:XX:XX:XX:XX format

    Memory Ports:
        * `rx_port`: Read port into RX packet memory, 8 bytes by 2048 cells.
        * `tx_port`: Write port into TX packet memory, 8 bytes by 2048 cells.

    Pins:
        * `rmii`: signal group containing:
            txd0, txd1, txen, rxd0, rxd1, crs_dv, ref_clk
        * `mdio`: signal group containing: mdc, mdio
        * `phy_rst`: PHY RST pin (output, active low)
        * `eth_led`: Ethernet LED, active high, pulsed on packet traffic

    TX port:
        * `tx_start`: Pulse high to begin transmission of a packet from memory
        * `tx_len`: 11-bit length of packet to transmit
        * `tx_offset`: n-bit address offset of packet to transmit, with
                       n=log2(tx_buf_size)

    RX port:
        * `rx_valid`: Held high while `rx_len` and `rx_offset` are valid
        * `rx_len`: 11-bit length of received packet
        * `rx_offset`: n-bit address offset of received packet, with
                       n=log2(rx_buf_size)
        * `rx_ack`: Pulse high to acknowledge packet receipt

    Inputs:
        * `phy_reset`: Assert to reset the PHY, de-assert for normal operation

    Outputs:
        * `link_up`: High while link is established
    """
    def __init__(self,
                 clk_freq,
                 phy_addr,
                 mac_addr,
                 rmii,
                 mdio,
                 phy_rst,
                 eth_led,
                 tx_buf_size=2048,
                 rx_buf_size=2048):
        # Memory Ports
        self.rx_port = None  # Assigned below
        self.tx_port = None  # Assigned below

        # TX port
        self.tx_start = Signal()
        self.tx_len = Signal(11)
        self.tx_offset = Signal(max=tx_buf_size - 1)

        # RX port
        self.rx_ack = Signal()
        self.rx_valid = Signal()
        self.rx_len = Signal(11)
        self.rx_offset = Signal(max=rx_buf_size - 1)

        # Inputs
        self.phy_reset = Signal()

        # Outputs
        self.link_up = Signal()

        self.clk_freq = clk_freq
        self.phy_addr = phy_addr
        self.mac_addr = [int(x, 16) for x in mac_addr.split(":")]
        self.rmii = rmii
        self.mdio = mdio
        self.phy_rst = phy_rst
        self.eth_led = eth_led

        # Create packet memories and interface ports
        self.tx_mem = Memory(8, tx_buf_size)
        self.tx_port = self.tx_mem.write_port()
        self.rx_mem = Memory(8, rx_buf_size)
        self.rx_port = self.rx_mem.read_port(transparent=False)

    def elaborate(self, platform):
        m = Module()

        # Create RMII clock domain from RMII clock input
        cd = ClockDomain("rmii", reset_less=True)
        m.d.comb += cd.clk.eq(self.rmii.ref_clk)
        m.domains.rmii = cd

        # Create RX write and TX read ports for RMII use
        rx_port_w = self.rx_mem.write_port(domain="rmii")
        tx_port_r = self.tx_mem.read_port(domain="rmii", transparent=False)
        m.submodules += [self.rx_port, rx_port_w, self.tx_port, tx_port_r]
        m.d.comb += [self.rx_port.en.eq(1), tx_port_r.en.eq(1)]

        # Create submodules for PHY and RMII
        m.submodules.phy_manager = phy_manager = PHYManager(
            self.clk_freq, self.phy_addr, self.phy_rst, self.mdio.mdio,
            self.mdio.mdc)
        m.submodules.stretch = stretch = PulseStretch(int(1e6))

        rmii_rx = RMIIRx(self.mac_addr, rx_port_w, self.rmii.crs_dv,
                         self.rmii.rxd0, self.rmii.rxd1)
        rmii_tx = RMIITx(tx_port_r, self.rmii.txen, self.rmii.txd0,
                         self.rmii.txd1)

        # Create FIFOs to interface to RMII modules
        rx_fifo = AsyncFIFO(width=11 + self.rx_port.addr.nbits, depth=4)
        tx_fifo = AsyncFIFO(width=11 + self.tx_port.addr.nbits, depth=4)

        m.d.comb += [
            # RX FIFO
            rx_fifo.din.eq(Cat(rmii_rx.rx_offset, rmii_rx.rx_len)),
            rx_fifo.we.eq(rmii_rx.rx_valid),
            Cat(self.rx_offset, self.rx_len).eq(rx_fifo.dout),
            rx_fifo.re.eq(self.rx_ack),
            self.rx_valid.eq(rx_fifo.readable),

            # TX FIFO
            tx_fifo.din.eq(Cat(self.tx_offset, self.tx_len)),
            tx_fifo.we.eq(self.tx_start),
            Cat(rmii_tx.tx_offset, rmii_tx.tx_len).eq(tx_fifo.dout),
            tx_fifo.re.eq(rmii_tx.tx_ready),
            rmii_tx.tx_start.eq(tx_fifo.readable),

            # Other submodules
            phy_manager.phy_reset.eq(self.phy_reset),
            self.link_up.eq(phy_manager.link_up),
            stretch.trigger.eq(self.rx_valid),
            self.eth_led.eq(stretch.pulse),
        ]

        rdr = DomainRenamer({"read": "sync", "write": "rmii"})
        wdr = DomainRenamer({"write": "sync", "read": "rmii"})
        rr = DomainRenamer("rmii")
        m.submodules.rx_fifo = rdr(rx_fifo)
        m.submodules.tx_fifo = wdr(tx_fifo)
        m.submodules.rmii_rx = rr(rmii_rx)
        m.submodules.rmii_tx = rr(rmii_tx)

        return m
Exemplo n.º 26
0
    def elaborate(self, platform):
        cpu = Module()
        # ----------------------------------------------------------------------
        # create the pipeline stages
        a = cpu.submodules.a = Stage(None, _af_layout)
        f = cpu.submodules.f = Stage(_af_layout, _fd_layout)
        d = cpu.submodules.d = Stage(_fd_layout, _dx_layout)
        x = cpu.submodules.x = Stage(_dx_layout, _xm_layout)
        m = cpu.submodules.m = Stage(_xm_layout, _mw_layout)
        w = cpu.submodules.w = Stage(_mw_layout, None)
        # ----------------------------------------------------------------------
        # connect the stages
        cpu.d.comb += [
            a.endpoint_b.connect(f.endpoint_a),
            f.endpoint_b.connect(d.endpoint_a),
            d.endpoint_b.connect(x.endpoint_a),
            x.endpoint_b.connect(m.endpoint_a),
            m.endpoint_b.connect(w.endpoint_a)
        ]
        # ----------------------------------------------------------------------
        # units
        adder = cpu.submodules.adder = AdderUnit()
        logic = cpu.submodules.logic = LogicUnit()
        shifter = cpu.submodules.shifter = ShifterUnit()
        compare = cpu.submodules.compare = CompareUnit()
        decoder = cpu.submodules.decoder = DecoderUnit(self.configuration)
        exception = cpu.submodules.exception = ExceptionUnit(
            self.configuration)
        data_sel = cpu.submodules.data_sel = DataFormat()
        csr = cpu.submodules.csr = CSRFile()
        if (self.configuration.getOption('icache', 'enable')):
            fetch = cpu.submodules.fetch = CachedFetchUnit(self.configuration)
        else:
            fetch = cpu.submodules.fetch = BasicFetchUnit()
        if (self.configuration.getOption('dcache', 'enable')):
            lsu = cpu.submodules.lsu = CachedLSU(self.configuration)
        else:
            lsu = cpu.submodules.lsu = BasicLSU()
        if self.configuration.getOption('isa', 'enable_rv32m'):
            multiplier = cpu.submodules.multiplier = Multiplier()
            divider = cpu.submodules.divider = Divider()
        if self.configuration.getOption('predictor', 'enable_predictor'):
            predictor = cpu.submodules.predictor = BranchPredictor(
                self.configuration)
        # ----------------------------------------------------------------------
        # register file (GPR)
        gprf = Memory(width=32, depth=32)
        gprf_rp1 = gprf.read_port()
        gprf_rp2 = gprf.read_port()
        gprf_wp = gprf.write_port()
        cpu.submodules += gprf_rp1, gprf_rp2, gprf_wp
        # ----------------------------------------------------------------------
        # CSR
        csr.add_csr_from_list(exception.csr.csr_list)
        csr_rp = csr.create_read_port()
        csr_wp = csr.create_write_port()
        # ----------------------------------------------------------------------
        # forward declaration of signals
        fwd_x_rs1 = Signal()
        fwd_m_rs1 = Signal()
        fwd_w_rs1 = Signal()
        fwd_x_rs2 = Signal()
        fwd_m_rs2 = Signal()
        fwd_w_rs2 = Signal()
        x_result = Signal(32)
        m_result = Signal(32)
        w_result = Signal(32)
        m_kill_bj = Signal()
        # ----------------------------------------------------------------------
        # Address Stage
        a_next_pc = Signal(32)
        a_next_pc_q = Signal(32)
        a_next_pc_fu = Signal(32)
        latched_pc = Signal()

        # set the reset value.
        # to (RA -4) because the value to feed the fetch unit is the next pc:
        a.endpoint_b.pc.reset = self.configuration.getOption(
            'reset', 'reset_address') - 4

        # select next pc
        with cpu.If(exception.m_exception & m.valid):
            cpu.d.comb += a_next_pc.eq(exception.csr.mtvec.read)  # exception
        with cpu.Elif(m.endpoint_a.mret & m.valid):
            cpu.d.comb += a_next_pc.eq(exception.csr.mepc.read)  # mret

        if (self.configuration.getOption('predictor', 'enable_predictor')):
            with cpu.Elif((m.endpoint_a.prediction & m.endpoint_a.branch)
                          & ~m.endpoint_a.take_jmp_branch & m.valid):
                cpu.d.comb += a_next_pc.eq(m.endpoint_a.pc +
                                           4)  # branch not taken
            with cpu.Elif(~(m.endpoint_a.prediction & m.endpoint_a.branch)
                          & m.endpoint_a.take_jmp_branch & m.valid):
                cpu.d.comb += a_next_pc.eq(
                    m.endpoint_a.jmp_branch_target)  # branck taken
            with cpu.Elif(predictor.f_prediction):
                cpu.d.comb += a_next_pc.eq(
                    predictor.f_prediction_pc)  # prediction
        else:
            with cpu.Elif(m.endpoint_a.take_jmp_branch & m.valid):
                cpu.d.comb += a_next_pc.eq(
                    m.endpoint_a.jmp_branch_target)  # jmp/branch

        with cpu.Elif(x.endpoint_a.fence_i & x.valid):
            cpu.d.comb += a_next_pc.eq(x.endpoint_a.pc + 4)  # fence_i.
        with cpu.Else():
            cpu.d.comb += a_next_pc.eq(f.endpoint_a.pc + 4)

        with cpu.If(f.stall):
            with cpu.If(f.kill & ~latched_pc):
                cpu.d.sync += [a_next_pc_q.eq(a_next_pc), latched_pc.eq(1)]
        with cpu.Else():
            cpu.d.sync += latched_pc.eq(0)

        with cpu.If(latched_pc):
            cpu.d.comb += a_next_pc_fu.eq(a_next_pc_q)
        with cpu.Else():
            cpu.d.comb += a_next_pc_fu.eq(a_next_pc)

        cpu.d.comb += [
            fetch.a_pc.eq(a_next_pc_fu),
            fetch.a_stall.eq(a.stall),
            fetch.a_valid.eq(a.valid),
        ]

        cpu.d.comb += a.valid.eq(1)  # the stage is always valid
        # ----------------------------------------------------------------------
        # Fetch Stage
        cpu.d.comb += fetch.iport.connect(
            self.iport)  # connect the wishbone port

        cpu.d.comb += [fetch.f_stall.eq(f.stall), fetch.f_valid.eq(f.valid)]

        f_kill_r = Signal()

        with cpu.If(f.stall):
            with cpu.If(f_kill_r == 0):
                cpu.d.sync += f_kill_r.eq(f.kill)
        with cpu.Else():
            cpu.d.sync += f_kill_r.eq(0)

        if (self.configuration.getOption('icache', 'enable')):
            cpu.d.comb += [
                fetch.flush.eq(x.endpoint_a.fence_i & x.valid & ~x.stall),
                fetch.f_pc.eq(f.endpoint_a.pc)
            ]

        f.add_kill_source(f_kill_r)
        f.add_stall_source(fetch.f_busy)
        f.add_kill_source(exception.m_exception & m.valid)
        f.add_kill_source(m.endpoint_a.mret & m.valid)
        f.add_kill_source(m_kill_bj)
        f.add_kill_source(x.endpoint_a.fence_i & x.valid & ~x.stall)
        # ----------------------------------------------------------------------
        # Decode Stage
        cpu.d.comb += decoder.instruction.eq(d.endpoint_a.instruction)

        with cpu.If(~d.stall):
            cpu.d.comb += [
                gprf_rp1.addr.eq(fetch.f_instruction[15:20]),
                gprf_rp2.addr.eq(fetch.f_instruction[20:25])
            ]
        with cpu.Else():
            cpu.d.comb += [
                gprf_rp1.addr.eq(decoder.gpr_rs1),
                gprf_rp2.addr.eq(decoder.gpr_rs2)
            ]

        cpu.d.comb += [
            gprf_wp.addr.eq(w.endpoint_a.gpr_rd),
            gprf_wp.data.eq(w_result),
            gprf_wp.en.eq(w.endpoint_a.gpr_we & w.valid)
        ]

        rs1_data = Signal(32)
        rs2_data = Signal(32)

        # select data for RS1
        with cpu.If(decoder.aiupc):
            cpu.d.comb += rs1_data.eq(d.endpoint_a.pc)
        with cpu.Elif((decoder.gpr_rs1 == 0) | decoder.lui):
            cpu.d.comb += rs1_data.eq(0)
        with cpu.Elif(fwd_x_rs1 & x.valid):
            cpu.d.comb += rs1_data.eq(x_result)
        with cpu.Elif(fwd_m_rs1 & m.valid):
            cpu.d.comb += rs1_data.eq(m_result)
        with cpu.Elif(fwd_w_rs1 & w.valid):
            cpu.d.comb += rs1_data.eq(w_result)
        with cpu.Else():
            cpu.d.comb += rs1_data.eq(gprf_rp1.data)

        # select data for RS2
        with cpu.If(decoder.csr):
            cpu.d.comb += rs2_data.eq(0)
        with cpu.Elif(~decoder.gpr_rs2_use):
            cpu.d.comb += rs2_data.eq(decoder.immediate)
        with cpu.Elif(decoder.gpr_rs2 == 0):
            cpu.d.comb += rs2_data.eq(0)
        with cpu.Elif(fwd_x_rs2 & x.valid):
            cpu.d.comb += rs2_data.eq(x_result)
        with cpu.Elif(fwd_m_rs2 & m.valid):
            cpu.d.comb += rs2_data.eq(m_result)
        with cpu.Elif(fwd_w_rs2 & w.valid):
            cpu.d.comb += rs2_data.eq(w_result)
        with cpu.Else():
            cpu.d.comb += rs2_data.eq(gprf_rp2.data)

        # Check if the forwarding is needed
        cpu.d.comb += [
            fwd_x_rs1.eq((decoder.gpr_rs1 == x.endpoint_a.gpr_rd)
                         & (decoder.gpr_rs1 != 0) & x.endpoint_a.gpr_we),
            fwd_m_rs1.eq((decoder.gpr_rs1 == m.endpoint_a.gpr_rd)
                         & (decoder.gpr_rs1 != 0) & m.endpoint_a.gpr_we),
            fwd_w_rs1.eq((decoder.gpr_rs1 == w.endpoint_a.gpr_rd)
                         & (decoder.gpr_rs1 != 0) & w.endpoint_a.gpr_we),
            fwd_x_rs2.eq((decoder.gpr_rs2 == x.endpoint_a.gpr_rd)
                         & (decoder.gpr_rs2 != 0) & x.endpoint_a.gpr_we),
            fwd_m_rs2.eq((decoder.gpr_rs2 == m.endpoint_a.gpr_rd)
                         & (decoder.gpr_rs2 != 0) & m.endpoint_a.gpr_we),
            fwd_w_rs2.eq((decoder.gpr_rs2 == w.endpoint_a.gpr_rd)
                         & (decoder.gpr_rs2 != 0) & w.endpoint_a.gpr_we),
        ]

        d.add_stall_source(((fwd_x_rs1 & decoder.gpr_rs1_use)
                            | (fwd_x_rs2 & decoder.gpr_rs2_use))
                           & ~x.endpoint_a.needed_in_x & x.valid)
        d.add_stall_source(((fwd_m_rs1 & decoder.gpr_rs1_use)
                            | (fwd_m_rs2 & decoder.gpr_rs2_use))
                           & ~m.endpoint_a.needed_in_m & m.valid)
        d.add_kill_source(exception.m_exception & m.valid)
        d.add_kill_source(m.endpoint_a.mret & m.valid)
        d.add_kill_source(m_kill_bj)
        d.add_kill_source(x.endpoint_a.fence_i & x.valid & ~x.stall)
        # ----------------------------------------------------------------------
        # Execute Stage
        x_branch_target = Signal(32)
        x_take_jmp_branch = Signal()

        cpu.d.comb += [
            x_branch_target.eq(x.endpoint_a.pc + x.endpoint_a.immediate),
            x_take_jmp_branch.eq(x.endpoint_a.jump
                                 | (x.endpoint_a.branch & compare.cmp_ok))
        ]

        cpu.d.comb += [
            adder.dat1.eq(x.endpoint_a.src_data1),
            adder.dat2.eq(
                Mux(x.endpoint_a.store, x.endpoint_a.immediate,
                    x.endpoint_a.src_data2)),
            adder.sub.eq((x.endpoint_a.arithmetic & x.endpoint_a.add_sub)
                         | x.endpoint_a.compare | x.endpoint_a.branch)
        ]

        cpu.d.comb += [
            logic.op.eq(x.endpoint_a.funct3),
            logic.dat1.eq(x.endpoint_a.src_data1),
            logic.dat2.eq(x.endpoint_a.src_data2)
        ]

        cpu.d.comb += [
            shifter.direction.eq(x.endpoint_a.shift_dir),
            shifter.sign_ext.eq(x.endpoint_a.shift_sign),
            shifter.dat.eq(x.endpoint_a.src_data1),
            shifter.shamt.eq(x.endpoint_a.src_data2),
            shifter.stall.eq(x.stall)
        ]

        cpu.d.comb += [
            compare.op.eq(x.endpoint_a.funct3),
            compare.zero.eq(adder.result == 0),
            compare.negative.eq(adder.result[-1]),
            compare.overflow.eq(adder.overflow),
            compare.carry.eq(adder.carry)
        ]

        # select result
        with cpu.If(x.endpoint_a.logic):
            cpu.d.comb += x_result.eq(logic.result)
        with cpu.Elif(x.endpoint_a.jump):
            cpu.d.comb += x_result.eq(x.endpoint_a.pc + 4)
        if (self.configuration.getOption('isa', 'enable_rv32m')):
            with cpu.Elif(x.endpoint_a.multiplier):
                cpu.d.comb += x_result.eq(multiplier.result)
        with cpu.Else():
            cpu.d.comb += x_result.eq(adder.result)

        # load/store unit
        cpu.d.comb += [
            data_sel.x_funct3.eq(x.endpoint_a.funct3),
            data_sel.x_offset.eq(adder.result[:2]),
            data_sel.x_store_data.eq(x.endpoint_a.src_data2),
        ]

        cpu.d.comb += [
            lsu.x_addr.eq(adder.result),
            lsu.x_data_w.eq(data_sel.x_data_w),
            lsu.x_store.eq(x.endpoint_a.store),
            lsu.x_load.eq(x.endpoint_a.load),
            lsu.x_byte_sel.eq(data_sel.x_byte_sel),
            lsu.x_valid.eq(x.valid & ~data_sel.x_misaligned),
            lsu.x_stall.eq(x.stall)
        ]
        if (self.configuration.getOption('dcache', 'enable')):
            cpu.d.comb += lsu.x_fence_i.eq(x.valid & x.endpoint_a.fence_i)
            x.add_stall_source(x.valid & x.endpoint_a.fence_i & m.valid
                               & m.endpoint_a.store)
        if (self.configuration.getOption('isa', 'enable_rv32m')):
            x.add_stall_source(x.valid & x.endpoint_a.multiplier
                               & ~multiplier.ready)
        if (self.configuration.getOption('dcache', 'enable')):
            x.add_stall_source(x.valid & lsu.x_busy)
        x.add_kill_source(exception.m_exception & m.valid)
        x.add_kill_source(m.endpoint_a.mret & m.valid)
        x.add_kill_source(m_kill_bj)
        # ----------------------------------------------------------------------
        # Memory (and CSR) Stage
        csr_wdata = Signal(32)

        # jump/branch
        if (self.configuration.getOption('predictor', 'enable_predictor')):
            cpu.d.comb += m_kill_bj.eq((
                (m.endpoint_a.prediction & m.endpoint_a.branch)
                ^ m.endpoint_a.take_jmp_branch) & m.valid)
        else:
            cpu.d.comb += m_kill_bj.eq(m.endpoint_a.take_jmp_branch & m.valid)

        cpu.d.comb += lsu.dport.connect(
            self.dport)  # connect the wishbone port

        # select result
        with cpu.If(m.endpoint_a.shifter):
            cpu.d.comb += m_result.eq(shifter.result)
        with cpu.Elif(m.endpoint_a.compare):
            cpu.d.comb += m_result.eq(m.endpoint_a.compare_result)
        if (self.configuration.getOption('isa', 'enable_rv32m')):
            with cpu.Elif(m.endpoint_a.divider):
                cpu.d.comb += m_result.eq(divider.result)
        with cpu.Else():
            cpu.d.comb += m_result.eq(m.endpoint_a.result)

        cpu.d.comb += [
            data_sel.m_data_r.eq(lsu.m_load_data),
            data_sel.m_funct3.eq(m.endpoint_a.funct3),
            data_sel.m_offset.eq(m.endpoint_a.result)
        ]

        cpu.d.comb += [lsu.m_valid.eq(m.valid), lsu.m_stall.eq(m.stall)]
        if (self.configuration.getOption('dcache', 'enable')):
            cpu.d.comb += [
                lsu.m_addr.eq(m.endpoint_a.result),
                lsu.m_load.eq(m.endpoint_a.load),
                lsu.m_store.eq(m.endpoint_a.store)
            ]

        csr_src0 = Signal(32)
        csr_src = Signal(32)

        cpu.d.comb += [
            csr_src0.eq(
                Mux(m.endpoint_a.funct3[2], m.endpoint_a.instruction[15:20],
                    m.endpoint_a.result)),
            csr_src.eq(
                Mux(m.endpoint_a.funct3[:2] == 0b11, ~csr_src0, csr_src0))
        ]

        with cpu.If(m.endpoint_a.funct3[:2] == 0b01):  # write
            cpu.d.comb += csr_wdata.eq(csr_src)
        with cpu.Elif(m.endpoint_a.funct3[:2] == 0b10):  # set
            cpu.d.comb += csr_wdata.eq(csr_rp.data | csr_src)
        with cpu.Else():  # clear
            cpu.d.comb += csr_wdata.eq(csr_rp.data & csr_src)

        # csr
        cpu.d.comb += [
            csr_rp.addr.eq(m.endpoint_a.csr_addr),
            csr_wp.addr.eq(m.endpoint_a.csr_addr),
            csr_wp.en.eq(m.endpoint_a.csr_we & m.valid),
            csr_wp.data.eq(csr_wdata)
        ]

        # exception unit
        cpu.d.comb += [
            exception.external_interrupt.eq(self.external_interrupt),
            exception.software_interrupt.eq(self.software_interrupt),
            exception.timer_interrupt.eq(self.timer_interrupt),
            exception.m_fetch_misalign.eq(m.endpoint_a.take_jmp_branch & (
                m.endpoint_a.jmp_branch_target[:2] != 0)),
            exception.m_fetch_error.eq(m.endpoint_a.fetch_error),
            exception.m_illegal.eq(m.endpoint_a.illegal
                                   | (m.endpoint_a.csr & csr.invalid)),
            exception.m_load_misalign.eq(m.endpoint_a.ls_misalign
                                         & m.endpoint_a.load),
            exception.m_load_error.eq(lsu.m_load_error),
            exception.m_store_misalign.eq(m.endpoint_a.ls_misalign
                                          & m.endpoint_a.store),
            exception.m_store_error.eq(lsu.m_store_error),
            exception.m_ecall.eq(m.endpoint_a.ecall),
            exception.m_ebreak.eq(m.endpoint_a.ebreak),
            exception.m_mret.eq(m.endpoint_a.mret),
            exception.m_pc.eq(m.endpoint_a.pc),
            exception.m_instruction.eq(m.endpoint_a.instruction),
            exception.m_fetch_badaddr.eq(m.endpoint_a.fetch_badaddr),
            exception.m_pc_misalign.eq(m.endpoint_a.jmp_branch_target),
            exception.m_ls_misalign.eq(m.endpoint_a.result),
            exception.m_load_store_badaddr.eq(lsu.m_badaddr),
            exception.m_store.eq(m.endpoint_a.store),
            exception.m_valid.eq(m.valid),
            exception.m_stall.eq(m.stall)
        ]

        m.add_stall_source(m.valid & lsu.m_busy)
        if (self.configuration.getOption('isa', 'enable_rv32m')):
            m.add_stall_source(divider.busy)
        m.add_kill_source(exception.m_exception & m.valid)
        # ----------------------------------------------------------------------
        # Write-back stage
        if self.configuration.getOption('isa', 'enable_extra_csr'):
            cpu.d.comb += exception.w_retire.eq(w.endpoint_a.is_instruction)

        with cpu.If(w.endpoint_a.load):
            cpu.d.comb += w_result.eq(w.endpoint_a.ld_result)
        with cpu.Elif(w.endpoint_a.csr):
            cpu.d.comb += w_result.eq(w.endpoint_a.csr_result)
        with cpu.Else():
            cpu.d.comb += w_result.eq(w.endpoint_a.result)

        # ----------------------------------------------------------------------
        # Optional units: Multiplier/Divider
        if (self.configuration.getOption('isa', 'enable_rv32m')):
            cpu.d.comb += [
                multiplier.op.eq(x.endpoint_a.funct3),
                multiplier.dat1.eq(x.endpoint_a.src_data1),
                multiplier.dat2.eq(x.endpoint_a.src_data2),
                multiplier.valid.eq(x.endpoint_a.multiplier & x.valid)
            ]
            cpu.d.comb += [
                divider.op.eq(x.endpoint_a.funct3),
                divider.dat1.eq(x.endpoint_a.src_data1),
                divider.dat2.eq(x.endpoint_a.src_data2),
                divider.stall.eq(x.stall),
                divider.start.eq(x.endpoint_a.divider)
            ]
        # ----------------------------------------------------------------------
        # Optional units: branch predictor
        if (self.configuration.getOption('predictor', 'enable_predictor')):
            cpu.d.comb += [
                predictor.a_pc.eq(a_next_pc_fu),
                predictor.a_stall.eq(a.stall),
                predictor.f_pc.eq(f.endpoint_a.pc),
                predictor.m_prediction_state.eq(m.endpoint_a.prediction_state),
                predictor.m_take_jmp_branch.eq(m.endpoint_a.take_jmp_branch
                                               & m.valid),
                predictor.m_pc.eq(m.endpoint_a.pc),
                predictor.m_target_pc.eq(m.endpoint_a.jmp_branch_target),
                predictor.m_update.eq(m.endpoint_a.branch & m.valid)
            ]
        # ----------------------------------------------------------------------
        # Pipeline registers

        # A -> F
        with cpu.If(~a.stall):
            cpu.d.sync += a.endpoint_b.pc.eq(a_next_pc_fu)

        # F -> D
        with cpu.If(~f.stall):
            cpu.d.sync += [
                f.endpoint_b.pc.eq(f.endpoint_a.pc),
                f.endpoint_b.instruction.eq(fetch.f_instruction),
                f.endpoint_b.fetch_error.eq(fetch.f_bus_error),
                f.endpoint_b.fetch_badaddr.eq(fetch.f_badaddr)
            ]
            if (self.configuration.getOption('predictor', 'enable_predictor')):
                cpu.d.sync += [
                    f.endpoint_b.prediction.eq(predictor.f_prediction),
                    f.endpoint_b.prediction_state.eq(
                        predictor.f_prediction_state)
                ]

        # D -> X
        with cpu.If(~d.stall):
            cpu.d.sync += [
                d.endpoint_b.pc.eq(d.endpoint_a.pc),
                d.endpoint_b.instruction.eq(d.endpoint_a.instruction),
                d.endpoint_b.gpr_rd.eq(decoder.gpr_rd),
                d.endpoint_b.gpr_we.eq(decoder.gpr_we),
                d.endpoint_b.src_data1.eq(rs1_data),
                d.endpoint_b.src_data2.eq(rs2_data),
                d.endpoint_b.immediate.eq(decoder.immediate),
                d.endpoint_b.funct3.eq(decoder.funct3),
                d.endpoint_b.gpr_rs1_use.eq(decoder.gpr_rs1_use),
                d.endpoint_b.needed_in_x.eq(decoder.needed_in_x),
                d.endpoint_b.needed_in_m.eq(decoder.needed_in_m),
                d.endpoint_b.arithmetic.eq(decoder.aritmetic),
                d.endpoint_b.logic.eq(decoder.logic),
                d.endpoint_b.shifter.eq(decoder.shift),
                d.endpoint_b.jump.eq(decoder.jump),
                d.endpoint_b.branch.eq(decoder.branch),
                d.endpoint_b.compare.eq(decoder.compare),
                d.endpoint_b.load.eq(decoder.load),
                d.endpoint_b.store.eq(decoder.store),
                d.endpoint_b.csr.eq(decoder.csr),
                d.endpoint_b.add_sub.eq(decoder.substract),
                d.endpoint_b.shift_dir.eq(decoder.shift_direction),
                d.endpoint_b.shift_sign.eq(decoder.shit_signed),
                d.endpoint_b.csr_addr.eq(decoder.immediate),
                d.endpoint_b.csr_we.eq(decoder.csr_we),
                d.endpoint_b.fetch_error.eq(d.endpoint_a.fetch_error),
                d.endpoint_b.fetch_badaddr.eq(d.endpoint_a.fetch_badaddr),
                d.endpoint_b.ecall.eq(decoder.ecall),
                d.endpoint_b.ebreak.eq(decoder.ebreak),
                d.endpoint_b.mret.eq(decoder.mret),
                d.endpoint_b.illegal.eq(decoder.illegal),
                d.endpoint_b.fence_i.eq(decoder.fence_i),
                d.endpoint_b.multiplier.eq(decoder.multiply),
                d.endpoint_b.divider.eq(decoder.divide),
                d.endpoint_b.prediction.eq(d.endpoint_a.prediction),
                d.endpoint_b.prediction_state.eq(d.endpoint_a.prediction_state)
            ]

        # X -> M
        with cpu.If(~x.stall):
            cpu.d.sync += [
                x.endpoint_b.pc.eq(x.endpoint_a.pc),
                x.endpoint_b.instruction.eq(x.endpoint_a.instruction),
                x.endpoint_b.gpr_rd.eq(x.endpoint_a.gpr_rd),
                x.endpoint_b.gpr_we.eq(x.endpoint_a.gpr_we),
                x.endpoint_b.needed_in_m.eq(x.endpoint_a.needed_in_m
                                            | x.endpoint_a.needed_in_x),
                x.endpoint_b.funct3.eq(x.endpoint_a.funct3),
                x.endpoint_b.shifter.eq(x.endpoint_a.shifter),
                x.endpoint_b.compare.eq(x.endpoint_a.compare),
                x.endpoint_b.branch.eq(x.endpoint_a.branch),
                x.endpoint_b.load.eq(x.endpoint_a.load),
                x.endpoint_b.store.eq(x.endpoint_a.store),
                x.endpoint_b.csr.eq(x.endpoint_a.csr),
                x.endpoint_b.csr_addr.eq(x.endpoint_a.csr_addr),
                x.endpoint_b.csr_we.eq(x.endpoint_a.csr_we),
                x.endpoint_b.result.eq(x_result),
                x.endpoint_b.compare_result.eq(compare.cmp_ok),
                x.endpoint_b.compare_result.eq(compare.cmp_ok),
                x.endpoint_b.jmp_branch_target.eq(
                    Mux(x.endpoint_a.jump & x.endpoint_a.gpr_rs1_use,
                        adder.result[1:] << 1, x_branch_target)),
                x.endpoint_b.take_jmp_branch.eq(x_take_jmp_branch),
                x.endpoint_b.fetch_error.eq(x.endpoint_a.fetch_error),
                x.endpoint_b.fetch_badaddr.eq(x.endpoint_a.fetch_badaddr),
                x.endpoint_b.ecall.eq(x.endpoint_a.ecall),
                x.endpoint_b.ebreak.eq(x.endpoint_a.ebreak),
                x.endpoint_b.mret.eq(x.endpoint_a.mret),
                x.endpoint_b.illegal.eq(x.endpoint_a.illegal),
                x.endpoint_b.ls_misalign.eq(data_sel.x_misaligned),
                x.endpoint_b.divider.eq(x.endpoint_a.divider),
                x.endpoint_b.prediction.eq(x.endpoint_a.prediction),
                x.endpoint_b.prediction_state.eq(
                    x.endpoint_a.prediction_state),
            ]

        # M -> W
        with cpu.If(~m.stall):
            cpu.d.sync += [
                m.endpoint_b.pc.eq(m.endpoint_a.pc),
                m.endpoint_b.gpr_rd.eq(m.endpoint_a.gpr_rd),
                m.endpoint_b.gpr_we.eq(m.endpoint_a.gpr_we),
                m.endpoint_b.result.eq(m_result),
                m.endpoint_b.ld_result.eq(data_sel.m_load_data),
                m.endpoint_b.csr_result.eq(csr_rp.data),
                m.endpoint_b.load.eq(m.endpoint_a.load),
                m.endpoint_b.csr.eq(m.endpoint_a.csr)
            ]

        return cpu
Exemplo n.º 27
0
class USBAnalyzer(Elaboratable):
    """ Core USB analyzer; backed by a small ringbuffer in FPGA block RAM.

    If you're looking to instantiate a full analyzer, you'll probably want to grab
    one of the DRAM-based ringbuffer variants (which are currently forthcoming).

    If you're looking to use this with a ULPI PHY, rather than the FPGA-convenient UMTI interface,
    grab the UMTITranslator from `luna.gateware.interface.ulpi`.

    I/O port:
        O: data_available -- indicates that new data is available in the analysis stream
        O: data_out[8]    -- the next byte in the captured stream; valid when data_available is asserted
        I: next           -- strobe that indicates when the data_out byte has been accepted; and can be
                             discarded from the local memory
    """

    # Current, we'll provide a packet header of 16 bits.
    HEADER_SIZE_BITS = 16
    HEADER_SIZE_BYTES = HEADER_SIZE_BITS // 8

    # Support a maximum payload size of 1024B, plus a 1-byte PID and a 2-byte CRC16.
    MAX_PACKET_SIZE_BYTES = 1024 + 1 + 2

    def __init__(self, *, umti_interface, mem_depth=8192):
        """
        Parameters:
            umti_interface -- A record or elaboratable that presents a UMTI interface.
        """

        self.umti = umti_interface

        # Internal storage memory.
        self.mem = Memory(width=8, depth=mem_depth, name="analysis_ringbuffer")
        self.mem_size = mem_depth

        #
        # I/O port
        #
        self.data_available = Signal()
        self.data_out = Signal(8)
        self.next = Signal()

        self.overrun = Signal()
        self.capturing = Signal()

        # Diagnostic I/O.
        self.sampling = Signal()

    def elaborate(self, platform):
        m = Module()

        # Memory read and write ports.
        m.submodules.read = mem_read_port = self.mem.read_port(domain="ulpi")
        m.submodules.write = mem_write_port = self.mem.write_port(
            domain="ulpi")

        # Store the memory address of our active packet header, which will store
        # packet metadata like the packet size.
        header_location = Signal.like(mem_write_port.addr)
        write_location = Signal.like(mem_write_port.addr)

        # Read FIFO status.
        read_location = Signal.like(mem_read_port.addr)
        fifo_count = Signal.like(mem_read_port.addr, reset=0)
        fifo_new_data = Signal()

        # Current receive status.
        packet_size = Signal(16)

        #
        # Read FIFO logic.
        #
        m.d.comb += [

            # We have data ready whenever there's not data in the FIFO.
            self.data_available.eq(fifo_count != 0),

            # Our data_out is always the output of our read port...
            self.data_out.eq(mem_read_port.data),

            # ... and our read port always reads from our read pointer.
            mem_read_port.addr.eq(read_location),
            self.sampling.eq(mem_write_port.en)
        ]

        # Once our consumer has accepted our current data, move to the next address.
        with m.If(self.next & self.data_available):
            m.d.ulpi += read_location.eq(read_location + 1)

        #
        # FIFO count handling.
        #
        fifo_full = (fifo_count == self.mem_size)

        data_pop = Signal()
        data_push = Signal()
        m.d.comb += [
            data_pop.eq(self.next & self.data_available),
            data_push.eq(fifo_new_data & ~fifo_full)
        ]

        # If we have both a read and a write, don't update the count,
        # as we've both added one and subtracted one.
        with m.If(data_push & data_pop):
            pass

        # Otherwise, add when data's added, and subtract when data's removed.
        with m.Elif(data_push):
            m.d.ulpi += fifo_count.eq(fifo_count + 1)
        with m.Elif(data_pop):
            m.d.ulpi += fifo_count.eq(fifo_count - 1)

        #
        # Core analysis FSM.
        #
        with m.FSM(domain="ulpi") as f:
            m.d.comb += [
                self.overrun.eq(f.ongoing("OVERRUN")),
                self.capturing.eq(f.ongoing("CAPTURE")),
            ]

            # IDLE: wait for an active receive.
            with m.State("IDLE"):

                # Wait until a transmission is active.
                # TODO: add triggering logic?
                with m.If(self.umti.rx_active):
                    m.next = "CAPTURE"
                    m.d.ulpi += [
                        header_location.eq(write_location),
                        write_location.eq(write_location +
                                          self.HEADER_SIZE_BYTES),
                        packet_size.eq(0),
                    ]

                    #with m.If(self.umti.rx_valid):
                    #    m.d.ulpi += [
                    #        fifo_count   .eq(fifo_count + 1),
                    #    write_location   .eq(write_location + self.HEADER_SIZE_BYTES + 1),
                    #        packet_size  .eq(1)
                    #    ]
                    #    m.d.comb += [
                    #        mem_write_port.addr  .eq(write_location + self.HEADER_SIZE_BYTES),
                    #        mem_write_port.data  .eq(self.umti.data_out),
                    #        mem_write_port.en    .eq(1)
                    #    ]

            # Capture data until the packet is complete.
            with m.State("CAPTURE"):

                # Capture data whenever RxValid is asserted.
                m.d.comb += [
                    mem_write_port.addr.eq(write_location),
                    mem_write_port.data.eq(self.umti.data_out),
                    mem_write_port.en.eq(self.umti.rx_valid
                                         & self.umti.rx_active),
                    fifo_new_data.eq(self.umti.rx_valid & self.umti.rx_active)
                ]

                # Advance the write pointer each time we receive a bit.
                with m.If(self.umti.rx_valid & self.umti.rx_active):
                    m.d.ulpi += [
                        write_location.eq(write_location + 1),
                        packet_size.eq(packet_size + 1)
                    ]

                    # If this would be filling up our data memory,
                    # move to the OVERRUN state.
                    with m.If(fifo_count == self.mem_size - 1 -
                              self.HEADER_SIZE_BYTES):
                        m.next = "OVERRUN"

                # If we've stopped receiving, move to the "finalize" state.
                with m.If(~self.umti.rx_active):

                    # Optimization: if we didn't receive any data, there's no need
                    # to create a packet. Clear our header from the FIFO and disarm.
                    with m.If(packet_size == 0):
                        m.next = "IDLE"
                        m.d.ulpi += [write_location.eq(header_location)]
                    with m.Else():
                        m.next = "EOP_1"

            # EOP: handle the end of the relevant packet.
            with m.State("EOP_1"):

                # Now that we're done, add the header to the start of our packet.
                # This will take two cycles, currently, as we're using a 2-byte header,
                # but we only have an 8-bit write port.
                m.d.comb += [
                    mem_write_port.addr.eq(header_location),
                    mem_write_port.data.eq(packet_size[7:16]),
                    #mem_write_port.data  .eq(0xAA),
                    mem_write_port.en.eq(1),
                    fifo_new_data.eq(1)
                ]
                m.next = "EOP_2"

            with m.State("EOP_2"):

                # Add the second byte of our header.
                # Note that, if this is an adjacent read, we should have
                # just captured our packet header _during_ the stop turnaround.
                m.d.comb += [
                    mem_write_port.addr.eq(header_location + 1),
                    mem_write_port.data.eq(packet_size[0:8]),
                    mem_write_port.en.eq(1),
                    fifo_new_data.eq(1)
                ]

                # Move to the next state, which will either be another capture,
                # or our idle state, depending on whether we have another rx.
                with m.If(self.umti.rx_active):
                    m.next = "CAPTURE"
                    m.d.ulpi += [
                        header_location.eq(write_location),
                        write_location.eq(write_location +
                                          self.HEADER_SIZE_BYTES),
                        packet_size.eq(0),
                    ]

                    # FIXME: capture if rx_valid

                with m.Else():
                    m.next = "IDLE"

            # BABBLE -- handles the case in which we've received a packet beyond
            # the allowable size in the USB spec
            with m.State("BABBLE"):

                # Trap here, for now.
                pass

            with m.State("OVERRUN"):
                # TODO: we should probably set an overrun flag and then emit an EOP, here?

                pass

        return m
Exemplo n.º 28
0
    def elaborate(self, platform):
        m = Module()


        #
        # Core ROM.
        #

        data_length = len(self.data)

        rom = Memory(width=self.data_width, depth=data_length, init=self.data)
        m.submodules.rom_read_port = rom_read_port = rom.read_port()

        # Register that stores our current position in the stream.
        position_in_stream = Signal(range(0, data_length))

        # Track when we're on the first and last packet.
        on_first_packet = position_in_stream == 0
        on_last_packet  = \
            (position_in_stream == (data_length - 1))      | \
            (position_in_stream == (self.max_length - 1))

        m.d.comb += [
            # Always drive the stream from our current memory output...
            self.stream.payload  .eq(rom_read_port.data),

            ## ... and base First and Last based on our current position in the stream.
            self.stream.first    .eq(on_first_packet & self.stream.valid),
            self.stream.last     .eq(on_last_packet  & self.stream.valid)
        ]



        #
        # Controller.
        #
        with m.FSM(domain=self.domain) as fsm:
            m.d.comb += self.stream.valid.eq(fsm.ongoing('STREAMING'))

            # IDLE -- we're not actively transmitting.
            with m.State('IDLE'):

                # Keep ourselves at the beginning of the stream, but don't yet count.
                m.d.sync += position_in_stream.eq(0)

                # Once the user requests that we start, move to our stream being valid.
                with m.If(self.start & (self.max_length > 0)):
                    m.next = 'STREAMING'


            # STREAMING -- we're actively transmitting data
            with m.State('STREAMING'):
                m.d.comb += [
                    rom_read_port.addr  .eq(position_in_stream)
                ]

                # If the current data byte is accepted, move past it.
                with m.If(self.stream.ready):

                    should_continue = \
                        ((position_in_stream + 1) < self.max_length) & \
                        ((position_in_stream + 1) < data_length)

                    # If there's still data left to transmit, move forward.
                    with m.If(should_continue):
                        m.d.sync += position_in_stream.eq(position_in_stream + 1)
                        m.d.comb += rom_read_port.addr.eq(position_in_stream + 1)

                    # Otherwise, we've finished streaming. Return to IDLE.
                    with m.Else():
                        m.next = 'DONE'

            # DONE -- report our completion; and then return to idle
            with m.State('DONE'):
                m.d.comb += self.done.eq(1)
                m.next = 'IDLE'


        # Convert our sync domain to the domain requested by the user, if necessary.
        if self.domain != "sync":
            m = DomainRenamer({"sync": self.domain})(m)

        return m
Exemplo n.º 29
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        snoop_addr = Record(self.pc_layout)
        snoop_valid = Signal()

        # -------------------------------------------------------------------------
        # Performance counter
        # TODO: connect to CSR's performance counter
        with m.If(~self.s1_stall & self.s1_valid & self.s1_access):
            m.d.sync += self.access_cnt.eq(self.access_cnt + 1)
        with m.If(self.s2_valid & self.s2_miss & ~self.bus_valid
                  & self.s2_access):
            m.d.sync += self.miss_cnt.eq(self.miss_cnt + 1)
        # -------------------------------------------------------------------------

        way_layout = [('data', 32 * self.nwords),
                      ('tag', self.s1_address.tag.shape()), ('valid', 1),
                      ('sel_lru', 1), ('snoop_hit', 1)]
        if self.enable_write:
            way_layout.append(('sel_we', 1))

        ways = Array(
            Record(way_layout, name='way_idx{}'.format(_way))
            for _way in range(self.nways))
        fill_cnt = Signal.like(self.s1_address.offset)

        # Check hit/miss
        way_hit = m.submodules.way_hit = Encoder(self.nways)
        for idx, way in enumerate(ways):
            m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag)
                                          & way.valid)

        m.d.comb += self.s2_miss.eq(way_hit.n)
        if self.enable_write:
            # Asumiendo que hay un HIT, indicar que la vía que dió hit es en la cual se va a escribir
            m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid)

        # set the LRU
        if self.nways == 1:
            # One way: LRU is useless
            lru = Const(0)  # self.nlines
        else:
            # LRU es un vector de N bits, cada uno indicado el set a reemplazar
            # como NWAY es máximo 2, cada LRU es de un bit
            lru = Signal(self.nlines)
            _lru = lru.bit_select(self.s2_address.line, 1)
            write_ended = self.bus_valid & self.bus_ack & self.bus_last  # err ^ ack = = 1
            access_hit = ~self.s2_miss & self.s2_valid & (way_hit.o == _lru)
            with m.If(write_ended | access_hit):
                m.d.sync += _lru.eq(~_lru)

        # read data from the cache
        m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select(
            self.s2_address.offset, 32))

        # Internal Snoop
        snoop_use_cache = Signal()
        snoop_tag_match = Signal()
        snoop_line_match = Signal()
        snoop_cancel_refill = Signal()
        if not self.enable_write:
            bits_range = log2_int(self.end_addr - self.start_addr,
                                  need_pow2=False)

            m.d.comb += [
                snoop_addr.eq(self.dcache_snoop.addr),  # aux
                snoop_valid.eq(self.dcache_snoop.we & self.dcache_snoop.valid
                               & self.dcache_snoop.ack),
                snoop_use_cache.eq(snoop_addr[bits_range:] == (
                    self.start_addr >> bits_range)),
                snoop_tag_match.eq(snoop_addr.tag == self.s2_address.tag),
                snoop_line_match.eq(snoop_addr.line == self.s2_address.line),
                snoop_cancel_refill.eq(snoop_use_cache & snoop_valid
                                       & snoop_line_match & snoop_tag_match),
            ]
        else:
            m.d.comb += snoop_cancel_refill.eq(0)

        with m.FSM():
            with m.State('READ'):
                with m.If(self.s2_re & self.s2_miss & self.s2_valid):
                    m.d.sync += [
                        self.bus_addr.eq(self.s2_address),
                        self.bus_valid.eq(1),
                        fill_cnt.eq(self.s2_address.offset - 1)
                    ]
                    m.next = 'REFILL'
            with m.State('REFILL'):
                m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset)
                with m.If(self.bus_ack):
                    m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset +
                                                        1)
                with m.If(self.bus_ack & self.bus_last | self.bus_err):
                    m.d.sync += self.bus_valid.eq(0)
                with m.If(~self.bus_valid | self.s1_flush
                          | snoop_cancel_refill):
                    m.next = 'READ'
                    m.d.sync += self.bus_valid.eq(0)

        # mark the way to use (replace)
        m.d.comb += ways[lru.bit_select(self.s2_address.line,
                                        1)].sel_lru.eq(self.bus_valid)

        # generate for N ways
        for way in ways:
            # create the memory structures for valid, tag and data.
            valid = Signal(self.nlines)  # Valid bits

            tag_m = Memory(width=len(way.tag), depth=self.nlines)  # tag memory
            tag_rp = tag_m.read_port()
            snoop_rp = tag_m.read_port()
            tag_wp = tag_m.write_port()
            m.submodules += tag_rp, tag_wp, snoop_rp

            data_m = Memory(width=len(way.data),
                            depth=self.nlines)  # data memory
            data_rp = data_m.read_port()
            data_wp = data_m.write_port(
                granularity=32
            )  # implica que solo puedo escribir palabras de 32 bits.
            m.submodules += data_rp, data_wp

            # handle valid
            with m.If(self.s1_flush & self.s1_valid):  # flush
                m.d.sync += valid.eq(0)
            with m.Elif(way.sel_lru & self.bus_last
                        & self.bus_ack):  # refill ok
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1)
            with m.Elif(way.sel_lru & self.bus_err):  # refill error
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0)
            with m.Elif(self.s2_evict & self.s2_valid
                        & (way.tag == self.s2_address.tag)):  # evict
                m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0)

            # assignments
            m.d.comb += [
                tag_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                tag_wp.addr.eq(self.bus_addr.line),
                tag_wp.data.eq(self.bus_addr.tag),
                tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last),
                data_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                way.data.eq(data_rp.data),
                way.tag.eq(tag_rp.data),
                way.valid.eq(valid.bit_select(self.s2_address.line, 1))
            ]

            # update cache: CPU or Refill
            # El puerto de escritura se multiplexa debido a que la memoria solo puede tener un
            # puerto de escritura.
            if self.enable_write:
                update_addr = Signal(len(data_wp.addr))
                update_data = Signal(len(data_wp.data))
                update_we = Signal(len(data_wp.en))
                aux_wdata = Signal(32)

                with m.If(self.bus_valid):
                    m.d.comb += [
                        update_addr.eq(self.bus_addr.line),
                        update_data.eq(Repl(self.bus_data, self.nwords)),
                        update_we.bit_select(self.bus_addr.offset,
                                             1).eq(way.sel_lru & self.bus_ack),
                    ]
                with m.Else():
                    m.d.comb += [
                        update_addr.eq(self.s2_address.line),
                        update_data.eq(Repl(aux_wdata, self.nwords)),
                        update_we.bit_select(self.s2_address.offset,
                                             1).eq(way.sel_we & ~self.s2_miss)
                    ]
                m.d.comb += [
                    # Aux data: no tengo granularidad de byte en el puerto de escritura. Así que para el
                    # caso en el cual el CPU tiene que escribir, hay que construir el dato (wrord) a reemplazar
                    aux_wdata.eq(
                        Cat(
                            Mux(self.s2_sel[0],
                                self.s2_wdata.word_select(0, 8),
                                self.s2_rdata.word_select(0, 8)),
                            Mux(self.s2_sel[1],
                                self.s2_wdata.word_select(1, 8),
                                self.s2_rdata.word_select(1, 8)),
                            Mux(self.s2_sel[2],
                                self.s2_wdata.word_select(2, 8),
                                self.s2_rdata.word_select(2, 8)),
                            Mux(self.s2_sel[3],
                                self.s2_wdata.word_select(3, 8),
                                self.s2_rdata.word_select(3, 8)))),
                    #
                    data_wp.addr.eq(update_addr),
                    data_wp.data.eq(update_data),
                    data_wp.en.eq(update_we),
                ]
            else:
                m.d.comb += [
                    data_wp.addr.eq(self.bus_addr.line),
                    data_wp.data.eq(Repl(self.bus_data, self.nwords)),
                    data_wp.en.bit_select(self.bus_addr.offset,
                                          1).eq(way.sel_lru & self.bus_ack),
                ]

                # --------------------------------------------------------------
                # intenal snoop
                # for FENCE.i instruction
                _match_snoop = Signal()

                m.d.comb += [
                    snoop_rp.addr.eq(snoop_addr.line),  # read tag memory
                    _match_snoop.eq(snoop_rp.data == snoop_addr.tag),
                    way.snoop_hit.eq(snoop_use_cache & snoop_valid
                                     & _match_snoop
                                     & valid.bit_select(snoop_addr.line, 1)),
                ]
                # check is the snoop match a write from this core
                with m.If(way.snoop_hit):
                    m.d.sync += valid.bit_select(snoop_addr.line, 1).eq(0)
                # --------------------------------------------------------------

        return m
Exemplo n.º 30
0
 def __init__(self):
     self.mem = Memory(width=MEMWIDTH, depth=Firestarter.memdepth)