Exemplo n.º 1
0
    def elaborate(self, platform):
        m = Module()
        m.submodules.demoaxi_i = Instance(
            'demoaxi',
	        p_C_S_AXI_DATA_WIDTH=self.data_w,
	        p_C_S_AXI_ADDR_WIDTH=self.addr_w,
            i_S_AXI_ACLK=ClockSignal(self.domain),
            i_S_AXI_ARESETN=~ResetSignal(self.domain),
            **get_ports_for_instance(self.axilite, prefix='S_AXI_'),
        )

        if isinstance(platform, Platform):
            for d in self.DEPENDENCIES:
                add_verilog_file(platform, d)
        return m
    def elaborate(self, platform):
        m = Module()
        import os
        dir_path = os.path.dirname(os.path.realpath(__file__))
        with open(dir_path + "/sdram_controller.v") as f:
            platform.add_file("sdram_controller.v", f.read())

        dir_dict = {
            "a": "-",
            "ba": "-",
            "cke": "-",
            "clk": "-",
            "clk_en": "-",
            "dq": "-",
            "dqm": "-",
            "cas": "-",
            "cs": "-",
            "ras": "-",
            "we": "-",
        }

        sdram = platform.request("sdram", dir=dir_dict)

        m.submodules += Instance(
            "sdram_controller",
            i_CLOCK_50=ClockSignal("compute"),
            i_CLOCK_100=ClockSignal("sdram"),
            i_CLOCK_100_del_3ns=ClockSignal("sdram_180_deg"),
            i_rst=ResetSignal("sdram"),
            i_address=self.address,
            i_req_read=self.req_read,
            i_req_write=self.req_write,
            i_data_in=self.data_in,
            o_data_out=self.data_out,
            o_data_valid=self.data_valid,
            o_write_complete=self.write_complete,
            o_DRAM_ADDR=sdram.a,
            o_DRAM_BA=sdram.ba,
            o_DRAM_CKE=sdram.clk_en,
            o_DRAM_CLK=sdram.clk,
            io_DRAM_DQ=sdram.dq,
            o_DRAM_DQM=sdram.dqm,
            o_DRAM_CAS_N=sdram.cas,
            o_DRAM_CS_N=sdram.cs,
            o_DRAM_RAS_N=sdram.ras,
            o_DRAM_WE_N=sdram.we)

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

        # Create the component parts of our ULPI interfacing hardware.
        register_window = ULPIRegisterWindow()
        rxevent_decoder = ULPIRxEventDecoder(ulpi_bus=self.ulpi)
        m.submodules.register_window = register_window
        m.submodules.rxevent_decoder = rxevent_decoder

        # Connect our ULPI control signals to each of our subcomponents.
        m.d.comb += [

            # Drive the bus whenever the target PHY isn't.
            self.ulpi.data.oe.eq(~self.ulpi.dir),

            # Generate our busy signal.
            self.busy.eq(register_window.busy),

            # Connect up our clock and reset signals.
            self.ulpi.clk.eq(ClockSignal("ulpi")),
            self.ulpi.rst.eq(ResetSignal("ulpi")),

            # Connect our data inputs to the event decoder.
            # Note that the event decoder is purely passive.
            rxevent_decoder.register_operation_in_progress.eq(
                register_window.busy),
            self.last_rx_command.eq(rxevent_decoder.last_rx_command),

            # Connect our signals to our register window.
            register_window.ulpi_data_in.eq(self.ulpi.data.i),
            register_window.ulpi_dir.eq(self.ulpi.dir),
            register_window.ulpi_next.eq(self.ulpi.nxt),
            self.ulpi.data.o.eq(register_window.ulpi_data_out),
            self.ulpi.stp.eq(register_window.ulpi_stop),
            register_window.address.eq(self.address),
            register_window.write_data.eq(self.write_data),
            register_window.read_request.eq(self.manual_read),
            register_window.write_request.eq(self.manual_write),
            self.read_data.eq(register_window.read_data)
        ]

        # Connect our RxEvent status signals from our RxEvent decoder.
        for signal_name in self.RXEVENT_STATUS_SIGNALS:
            signal = getattr(rxevent_decoder, signal_name)
            m.d.comb += self.__dict__[signal_name].eq(signal)

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

        oserdes = m.submodules.oserdes = Oserdes(data_width=self.bit_width,
                                                 tristate_width=1,
                                                 data_rate_oq="ddr",
                                                 serdes_mode="master",
                                                 data_rate_tq="buf")
        m.d.comb += oserdes.oce.eq(1)
        m.d.comb += oserdes.clk.eq(ClockSignal(self.x4_clockdomain))
        m.d.comb += oserdes.clkdiv.eq(ClockSignal())
        m.d.comb += oserdes.rst.eq(ResetSignal())
        m.d.comb += Cat(oserdes.d[i] for i in reversed(range(1, 9))).eq(
            self.value)  # reversed is needed!!1
        m.d.comb += self.pad.eq(oserdes.oq)

        return m
Exemplo n.º 5
0
    def add_ulpi_registers(self, m, platform, *, ulpi_bus, register_base):
        """ Adds a set of ULPI registers to the active design. """

        target_ulpi      = platform.request(ulpi_bus)

        ulpi_reg_window  = ULPIRegisterWindow()
        m.submodules  += ulpi_reg_window

        m.d.comb += [
            ulpi_reg_window.ulpi_data_in  .eq(target_ulpi.data.i),
            ulpi_reg_window.ulpi_dir      .eq(target_ulpi.dir),
            ulpi_reg_window.ulpi_next     .eq(target_ulpi.nxt),

            target_ulpi.clk      .eq(ClockSignal("usb")),
            target_ulpi.rst      .eq(ResetSignal("usb")),
            target_ulpi.stp      .eq(ulpi_reg_window.ulpi_stop),
            target_ulpi.data.o   .eq(ulpi_reg_window.ulpi_data_out),
            target_ulpi.data.oe  .eq(~target_ulpi.dir)
        ]

        register_address_change  = Signal()
        register_value_change    = Signal()

        # ULPI register address.
        spi_registers = m.submodules.spi_registers
        spi_registers.add_register(register_base + 0,
            write_strobe=register_address_change,
            value_signal=ulpi_reg_window.address,
            size=6
        )
        m.submodules.clocking.stretch_sync_strobe_to_usb(m,
            strobe=register_address_change,
            output=ulpi_reg_window.read_request,
        )

        # ULPI register value.
        spi_registers.add_sfr(register_base + 1,
            read=ulpi_reg_window.read_data,
            write_signal=ulpi_reg_window.write_data,
            write_strobe=register_value_change
        )
        m.submodules.clocking.stretch_sync_strobe_to_usb(m,
            strobe=register_value_change,
            output=ulpi_reg_window.write_request
        )
Exemplo n.º 6
0
    def elaborate(self, platform):
        m = Module()

        self.invert = ControlSignal(
            reset=is_signal_inverted(platform, self.pad))

        oserdes = m.submodules.oserdes = _OSerdes(data_width=self.bit_width,
                                                  tristate_width=1,
                                                  data_rate_oq="ddr",
                                                  serdes_mode="master",
                                                  data_rate_tq="buf")
        m.d.comb += oserdes.oce.eq(1)
        m.d.comb += oserdes.clk.eq(ClockSignal(self.ddr_domain))
        m.d.comb += oserdes.clkdiv.eq(ClockSignal())
        m.d.comb += oserdes.rst.eq(ResetSignal())
        m.d.comb += Cat(
            oserdes.d[i]
            for i in (range(1, 9) if self.msb_first else reversed(range(1, 9))
                      )).eq(self.value ^ self.invert)
        m.d.comb += self.pad.eq(oserdes.oq)

        return m
    def formal(cls) -> Tuple[Module, List[Signal]]:
        """Formal verification for my module."""
        m = Module()
        m.submodules.my_class = my_class = cls()

        sync_clk = ClockSignal("sync")
        sync_rst = ResetSignal("sync")

        # Make sure that the output is always the same as the input
        m.d.comb += Assert(my_class.my_input == my_class.my_output)

        # Cover the case where the output is 1.
        m.d.comb += Cover(my_class.my_output == 1)

        # Make sure the clock is clocking
        m.d.comb += Assume(sync_clk == ~Past(sync_clk))

        # Include this only if you don't want to test resets
        m.d.comb += Assume(~sync_rst)

        # Ensure sync's clock and reset signals are manipulable.
        return m, [sync_clk, sync_rst, my_class.my_input]
Exemplo n.º 8
0
    def formal(cls) -> Tuple[Module, List[Signal]]:
        """Formal verification for the Counter module."""
        m = Module()
        m.submodules.c = c = cls()

        m.d.comb += Assert((c.count >= 1) & (c.count <= 999_999_999_999))

        sync_clk = ClockSignal("sync")
        sync_rst = ResetSignal("sync")

        with m.If(Rose(sync_clk) & ~Initial()):
            with m.If(c.count == 1):
                m.d.comb += Assert(Past(c.count) == 999_999_999_999)
            with m.Else():
                m.d.comb += Assert(c.count == (Past(c.count) + 1))

        # Make sure the clock is clocking
        m.d.comb += Assume(sync_clk == ~Past(sync_clk))

        # Don't want to test what happens when we reset.
        m.d.comb += Assume(~sync_rst)

        return m, [sync_clk, sync_rst]
Exemplo n.º 9
0
    def elaborate(self, platform):
        m = Module()

        iserdes = m.submodules.iserdes = _ISerdes(
            data_width=self.bit_width,
            data_rate="ddr",
            serdes_mode="master",
            interface_type="networking",
            num_ce=1,
            iobDelay="ifd",
        )
        m.d.comb += iserdes.ddly.eq(self.pad)
        m.d.comb += iserdes.ce[1].eq(1)
        m.d.comb += iserdes.clk.eq(ClockSignal(self.ddr_domain))
        m.d.comb += iserdes.clkb.eq(~ClockSignal(self.ddr_domain))
        m.d.comb += iserdes.rst.eq(ResetSignal())
        m.d.comb += iserdes.clkdiv.eq(ClockSignal())
        m.d.comb += self.output.eq(
            Cat(iserdes.q[i]
                for i in (range(1, 9) if self.
                          msb_first else reversed(list(range(1, 9))))))
        m.d.comb += iserdes.bitslip.eq(self.bitslip)

        return m
Exemplo n.º 10
0

if __name__ == "__main__":
    parser = main_parser()
    parser.add_argument("--oper")
    args = parser.parse_args()

    oper: Optional[Operation] = None
    if args.oper is not None:
        oper = Operation[args.oper]

    m = Module()
    m.submodules.alu = alu = ALU_big(oper)

    if oper is not None:
        m.d.comb += Assume(~ResetSignal())
        m.d.comb += Assume(alu.oper == oper)
        main_runner(parser, args, m, ports=alu.ports())

    else:
        sim = Simulator(m)

        def process():
            yield
            yield alu.inputa.eq(0x12)
            yield alu.inputb.eq(0x34)
            yield alu.oper.eq(Operation.ADC)
            yield
            yield
            yield alu.inputa.eq(0x7F)
            yield alu.inputb.eq(0x7F)
Exemplo n.º 11
0
    def elaborate(self, platform):
        m = Module()

        data = Signal.like(self.input)
        m.d[self.domain] += data.eq(self.input
                                    ^ Repl(self.invert, len(self.input)))

        ce = Signal()
        m.d.comb += ce.eq(~ResetSignal(self.domain))

        shift = Signal(2)

        m.submodules += Instance(
            "OSERDESE2",
            p_DATA_WIDTH=10,
            p_TRISTATE_WIDTH=1,
            p_DATA_RATE_OQ="DDR",
            p_DATA_RATE_TQ="DDR",
            p_SERDES_MODE="MASTER",
            o_OQ=self.output,
            i_OCE=ce,
            i_TCE=0,
            i_RST=ResetSignal(self.domain),
            i_CLK=ClockSignal(self.domain_5x),
            i_CLKDIV=ClockSignal(self.domain),
            i_D1=data[0],
            i_D2=data[1],
            i_D3=data[2],
            i_D4=data[3],
            i_D5=data[4],
            i_D6=data[5],
            i_D7=data[6],
            i_D8=data[7],
            i_SHIFTIN1=shift[0],
            i_SHIFTIN2=shift[1],
        )

        m.submodules += Instance("OSERDESE2",
                                 p_DATA_WIDTH=10,
                                 p_TRISTATE_WIDTH=1,
                                 p_DATA_RATE_OQ="DDR",
                                 p_DATA_RATE_TQ="DDR",
                                 p_SERDES_MODE="SLAVE",
                                 i_OCE=ce,
                                 i_TCE=0,
                                 i_RST=ResetSignal(self.domain),
                                 i_CLK=ClockSignal(self.domain_5x),
                                 i_CLKDIV=ClockSignal(self.domain),
                                 i_D1=0,
                                 i_D2=0,
                                 i_D3=data[8],
                                 i_D4=data[9],
                                 i_D5=0,
                                 i_D6=0,
                                 i_D7=0,
                                 i_D8=0,
                                 i_SHIFTIN1=0,
                                 i_SHIFTIN2=0,
                                 o_SHIFTOUT1=shift[0],
                                 o_SHIFTOUT2=shift[1])

        return m
Exemplo n.º 12
0
Arquivo: ulpi.py Projeto: jboone/luna
    def elaborate(self, platform):
        m = Module()

        # Create the component parts of our ULPI interfacing hardware.
        m.submodules.register_window = register_window = ULPIRegisterWindow()
        m.submodules.control_translator = control_translator = ULPIControlTranslator(
            register_window=register_window)
        m.submodules.rxevent_decoder = rxevent_decoder = ULPIRxEventDecoder(
            ulpi_bus=self.ulpi)
        m.submodules.transmit_translator = transmit_translator = ULPITransmitTranslator(
        )

        # If we're choosing to honor any registers defined in the platform file, apply those
        # before continuing with elaboration.
        if self.use_platform_registers and hasattr(platform,
                                                   'ulpi_extra_registers'):
            for address, value in platform.ulpi_extra_registers.items():
                self.add_extra_register(address, value)

        # Add any extra registers provided by the user to our control translator.
        for address, values in self._extra_registers.items():
            control_translator.add_composite_register(
                m, address, values['value'], reset_value=values['default'])

        # Keep track of when any of our components are busy
        any_busy = \
            register_window.busy     | \
            transmit_translator.busy | \
            control_translator.busy  | \
            self.ulpi.dir

        # If we're handling ULPI clocking, do so.
        if self.handle_clocking:

            # We can't currently handle bidirectional clock lines, as we don't know if they
            # should be used in input or output modes.
            if hasattr(self.ulpi.clk, 'oe'):
                raise TypeError(
                    "ULPI records with bidirectional clock lines require manual handling."
                )

            # Just Input (TM) and Just Output (TM) clocks are simpler: we know how to drive them.
            elif hasattr(self.ulpi.clk, 'o'):
                m.d.comb += self.ulpi.clk.eq(ClockSignal('usb'))
            elif hasattr(self.ulpi.clk, 'i'):
                m.d.comb += ClockSignal('usb').eq(self.ulpi.clk)

            # Clocks that don't seem to be I/O pins aren't what we're expecting; fail out.
            else:
                raise TypeError(f"ULPI `clk` was an unexpected type {type(self.ulpi.clk)}." \
                    " You may need to handle clocking manually.")

        # Connect our ULPI control signals to each of our subcomponents.
        m.d.comb += [

            # Drive the bus whenever the target PHY isn't.
            self.ulpi.data.oe.eq(~self.ulpi.dir),

            # Generate our busy signal.
            self.busy.eq(any_busy),

            # Connect up our clock and reset signals.
            self.ulpi.rst.eq(ResetSignal("usb")),

            # Connect our data inputs to the event decoder.
            # Note that the event decoder is purely passive.
            rxevent_decoder.register_operation_in_progress.eq(
                register_window.busy),
            self.last_rx_command.eq(rxevent_decoder.last_rx_command),

            # Connect our inputs to our transmit translator.
            transmit_translator.ulpi_nxt.eq(self.ulpi.nxt),
            transmit_translator.op_mode.eq(self.op_mode),
            transmit_translator.bus_idle.eq(~control_translator.busy
                                            & ~self.ulpi.dir),
            transmit_translator.tx_data.eq(self.tx_data),
            transmit_translator.tx_valid.eq(self.tx_valid),
            self.tx_ready.eq(transmit_translator.tx_ready),

            # Connect our inputs to our control translator / register window.
            control_translator.bus_idle.eq(~transmit_translator.busy),
            register_window.ulpi_data_in.eq(self.ulpi.data.i),
            register_window.ulpi_dir.eq(self.ulpi.dir),
            register_window.ulpi_next.eq(self.ulpi.nxt),
        ]

        # Control our the source of our ULPI data output.
        # If a transmit request is active, prioritize that over
        # any register reads/writes.
        with m.If(transmit_translator.ulpi_out_req):
            m.d.comb += [
                self.ulpi.data.o.eq(transmit_translator.ulpi_data_out),
                self.ulpi.stp.eq(transmit_translator.ulpi_stp)
            ]
        # Otherwise, yield control to the register handler.
        # This is a slight optimization: since it properly generates NOPs
        # while not in use, we can let it handle idle, as well, saving a mux.
        with m.Else():
            m.d.comb += [
                self.ulpi.data.o.eq(register_window.ulpi_data_out),
                self.ulpi.stp.eq(register_window.ulpi_stop)
            ]

        # Connect our RxEvent status signals from our RxEvent decoder.
        for signal_name, _ in self.RXEVENT_STATUS_SIGNALS:
            signal = getattr(rxevent_decoder, signal_name)
            m.d.comb += self.__dict__[signal_name].eq(signal)

        # Connect our control signals through the control translator.
        for signal_name, _ in self.CONTROL_SIGNALS:
            signal = getattr(control_translator, signal_name)
            m.d.comb += signal.eq(self.__dict__[signal_name])

        # RxActive handler:
        # A transmission starts when DIR goes high with NXT, or when an RxEvent indicates
        # a switch from RxActive = 0 to RxActive = 1. A transmission stops when DIR drops low,
        # or when the RxEvent RxActive bit drops from 1 to 0, or an error occurs.A
        dir_rising_edge = Rose(self.ulpi.dir.i, domain="usb")
        dir_based_start = dir_rising_edge & self.ulpi.nxt

        with m.If(~self.ulpi.dir | rxevent_decoder.rx_stop):
            # TODO: this should probably also trigger if RxError
            m.d.usb += self.rx_active.eq(0)
        with m.Elif(dir_based_start | rxevent_decoder.rx_start):
            m.d.usb += self.rx_active.eq(1)

        # Data-out: we'll connect this almost direct through from our ULPI
        # interface, as it's essentially the same as in the UTMI spec. We'll
        # add a one cycle processing delay so it matches the rest of our signals.

        # RxValid: equivalent to NXT whenever a Rx is active.
        m.d.usb += [
            self.rx_data.eq(self.ulpi.data.i),
            self.rx_valid.eq(self.ulpi.nxt & self.rx_active)
        ]

        return m
Exemplo n.º 13
0
    def create_submodules(self, m, platform):

        self._pll_lock = Signal()

        # Figure out our platform's clock frequencies -- grab the platform's
        # defaults, and then override any with our local, caller-provided copies.
        new_clock_frequencies = platform.DEFAULT_CLOCK_FREQUENCIES_MHZ.copy()
        if self.clock_frequencies:
            new_clock_frequencies.update(self.clock_frequencies)
        self.clock_frequencies = new_clock_frequencies

        # Use the provided clock name for our input; or the default clock
        # if no name was provided.
        clock_name = self.clock_name if self.clock_name else platform.default_clk

        # Create absolute-frequency copies of our PLL outputs.
        # We'll use the generate_ methods below to select which domains
        # apply to which components.
        self._clk_240MHz = Signal()
        self._clk_120MHz = Signal()
        self._clk_60MHz = Signal()
        self._clock_options = {
            60: self._clk_60MHz,
            120: self._clk_120MHz,
            240: self._clk_240MHz
        }

        # Grab our input clock
        # For debugging: if our clock name is "OSCG", allow using the internal
        # oscillator. This is mostly useful for debugging.
        if clock_name == "OSCG":
            logging.warning(
                "Using FPGA-internal oscillator for an approximately 62MHz.")
            logging.warning("USB communication won't work for f_OSC != 60MHz.")

            input_clock = Signal()
            m.submodules += Instance("OSCG",
                                     p_DIV=self.OSCG_DIV,
                                     o_OSC=input_clock)
        else:
            input_clock = platform.request(clock_name)

        # Instantiate the ECP5 PLL.
        # These constants generated by Clarity Designer; which will
        # ideally be replaced by an open-source component.
        # (see https://github.com/SymbiFlow/prjtrellis/issues/34.)
        m.submodules.pll = Instance(
            "EHXPLLL",

            # Clock in.
            i_CLKI=input_clock,

            # Generated clock outputs.
            o_CLKOP=self._clk_240MHz,
            o_CLKOS=self._clk_120MHz,
            o_CLKOS2=self._clk_60MHz,

            # Status.
            o_LOCK=self._pll_lock,

            # PLL parameters...
            p_PLLRST_ENA="DISABLED",
            p_INTFB_WAKE="DISABLED",
            p_STDBY_ENABLE="DISABLED",
            p_DPHASE_SOURCE="DISABLED",
            p_CLKOS3_FPHASE=0,
            p_CLKOS3_CPHASE=0,
            p_CLKOS2_FPHASE=0,
            p_CLKOS2_CPHASE=7,
            p_CLKOS_FPHASE=0,
            p_CLKOS_CPHASE=3,
            p_CLKOP_FPHASE=0,
            p_CLKOP_CPHASE=1,
            p_PLL_LOCK_MODE=0,
            p_CLKOS_TRIM_DELAY="0",
            p_CLKOS_TRIM_POL="FALLING",
            p_CLKOP_TRIM_DELAY="0",
            p_CLKOP_TRIM_POL="FALLING",
            p_OUTDIVIDER_MUXD="DIVD",
            p_CLKOS3_ENABLE="DISABLED",
            p_OUTDIVIDER_MUXC="DIVC",
            p_CLKOS2_ENABLE="ENABLED",
            p_OUTDIVIDER_MUXB="DIVB",
            p_CLKOS_ENABLE="ENABLED",
            p_OUTDIVIDER_MUXA="DIVA",
            p_CLKOP_ENABLE="ENABLED",
            p_CLKOS3_DIV=1,
            p_CLKOS2_DIV=8,
            p_CLKOS_DIV=4,
            p_CLKOP_DIV=2,
            p_CLKFB_DIV=4,
            p_CLKI_DIV=1,
            p_FEEDBK_PATH="CLKOP",

            # Internal feedback.
            i_CLKFB=self._clk_240MHz,

            # Control signals.
            i_RST=0,
            i_PHASESEL0=0,
            i_PHASESEL1=0,
            i_PHASEDIR=0,
            i_PHASESTEP=0,
            i_PHASELOADREG=0,
            i_STDBY=0,
            i_PLLWAKESYNC=0,

            # Output Enables.
            i_ENCLKOP=0,
            i_ENCLKOS=0,
            i_ENCLKOS2=0,
            i_ENCLKOS3=0,

            # Synthesis attributes.
            a_FREQUENCY_PIN_CLKI="60.000000",
            a_FREQUENCY_PIN_CLKOS2="60.000000",
            a_FREQUENCY_PIN_CLKOS="120.000000",
            a_FREQUENCY_PIN_CLKOP="240.000000",
            a_ICP_CURRENT="9",
            a_LPF_RESISTOR="8")

        # Set up our global resets so the system is kept fully in reset until
        # our core PLL is fully stable. This prevents us from internally clock
        # glitching ourselves before our PLL is locked. :)
        m.d.comb += [
            ResetSignal("sync").eq(~self._pll_lock),
            ResetSignal("fast").eq(~self._pll_lock),
        ]
Exemplo n.º 14
0
    def elaborate(self, platform):
        m = Module()

        # Create the component parts of our ULPI interfacing hardware.
        m.submodules.register_window    = register_window    = ULPIRegisterWindow()
        m.submodules.control_translator = control_translator = ULPIControlTranslator(register_window=register_window)
        m.submodules.rxevent_decoder    = rxevent_decoder    = ULPIRxEventDecoder(ulpi_bus=self.ulpi)

        # If we're choosing to honor any registers defined in the platform file, apply those
        # before continuing with elaboration.
        if self.use_platform_registers and hasattr(platform, 'ulpi_extra_registers'):
            for address, value in platform.ulpi_extra_registers.items():
                self.add_extra_register(address, value)

        # Add any extra registers provided by the user to our control translator.
        for address, values in self._extra_registers.items():
            control_translator.add_composite_register(m, address, values['value'], reset_value=values['default'])

        # Connect our ULPI control signals to each of our subcomponents.
        m.d.comb += [

            # Drive the bus whenever the target PHY isn't.
            self.ulpi.data.oe            .eq(~self.ulpi.dir),

            # Generate our busy signal.
            self.busy                    .eq(register_window.busy),

            # Connect up our clock and reset signals.
            self.ulpi.clk                .eq(ClockSignal("ulpi")),
            self.ulpi.rst                .eq(ResetSignal("ulpi")),

            # Connect our data inputs to the event decoder.
            # Note that the event decoder is purely passive.
            rxevent_decoder.register_operation_in_progress.eq(register_window.busy),
            self.last_rx_command          .eq(rxevent_decoder.last_rx_command),

            # Connect our signals to our register window.
            register_window.ulpi_data_in  .eq(self.ulpi.data.i),
            register_window.ulpi_dir      .eq(self.ulpi.dir),
            register_window.ulpi_next     .eq(self.ulpi.nxt),
            self.ulpi.data.o              .eq(register_window.ulpi_data_out),
            self.ulpi.stp                 .eq(register_window.ulpi_stop),

        ]

        # Connect our RxEvent status signals from our RxEvent decoder.
        for signal_name in self.RXEVENT_STATUS_SIGNALS:
            signal = getattr(rxevent_decoder, signal_name)
            m.d.comb += self.__dict__[signal_name].eq(signal)

        # Connect our control signals through the control translator.
        for signal_name, _ in self.CONTROL_SIGNALS:
            signal = getattr(control_translator, signal_name)
            m.d.comb += signal.eq(self.__dict__[signal_name])


        # RxActive handler:
        # A transmission starts when DIR goes high with NXT, or when an RxEvent indicates
        # a switch from RxActive = 0 to RxActive = 1. A transmission stops when DIR drops low,
        # or when the RxEvent RxActive bit drops from 1 to 0, or an error occurs.
        dir_rising_edge = Rose(self.ulpi.dir, domain='ulpi')
        dir_based_start = dir_rising_edge & self.ulpi.nxt

        with m.If(~self.ulpi.dir | rxevent_decoder.rx_stop):
            # TODO: this should probably also trigger if RxError
            m.d.ulpi += self.rx_active.eq(0)
        with m.Elif(dir_based_start | rxevent_decoder.rx_start):
            m.d.ulpi += self.rx_active.eq(1)


        # Data-out: we'll connect this almost direct through from our ULPI
        # interface, as it's essentially the same as in the UTMI spec. We'll
        # add a one cycle processing delay so it matches the rest of our signals.

        # RxValid: equivalent to NXT whenever a Rx is active.
        m.d.ulpi += [
            self.rx_data   .eq(self.ulpi.data.i),
            self.rx_valid  .eq(self.ulpi.nxt & self.rx_active)
        ]


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

        # Generate our clock domains.
        clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES)
        m.submodules.clocking = clocking

        # Create a set of registers, and expose them over SPI.
        board_spi = platform.request("debug_spi")
        spi_registers = SPIRegisterInterface(default_read_value=-1)
        m.submodules.spi_registers = spi_registers

        # Simple applet ID register.
        spi_registers.add_read_only_register(REGISTER_ID, read=0x54455354)

        # LED test register.
        led_reg = spi_registers.add_register(REGISTER_LEDS,
                                             size=5,
                                             name="leds",
                                             reset=0b1)
        led_out = Cat(
            [platform.request("led", i, dir="o") for i in range(0, 6)])
        m.d.comb += led_out[1:].eq(led_reg)

        #
        # User IO GPIO registers.
        #

        # Data direction register.
        user_io_dir = spi_registers.add_register(REGISTER_USER_IO_DIR, size=4)

        # Pin (input) state register.
        user_io_in = Signal(4)
        spi_registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in)

        # Output value register.
        user_io_out = spi_registers.add_register(REGISTER_USER_IO_OUT, size=4)

        # Grab and connect each of our user-I/O ports our GPIO registers.
        for i in range(4):
            pin = platform.request("user_io", i)
            m.d.comb += [
                pin.oe.eq(user_io_dir[i]), user_io_in[i].eq(pin.i),
                pin.o.eq(user_io_out[i])
            ]

        #
        # ULPI PHY windows
        #
        self.add_ulpi_registers(m,
                                platform,
                                ulpi_bus="host_phy",
                                register_base=REGISTER_HOST_ADDR)
        self.add_ulpi_registers(m,
                                platform,
                                ulpi_bus="sideband_phy",
                                register_base=REGISTER_SIDEBAND_ADDR)

        #
        # HyperRAM test connections.
        #
        ram_bus = platform.request('ram')
        psram = HyperRAMInterface(bus=ram_bus)
        m.submodules += psram

        psram_address_changed = Signal()
        psram_address = spi_registers.add_register(
            REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed)

        spi_registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data)

        # Hook up our PSRAM.
        m.d.comb += [
            ram_bus.reset.eq(0),
            psram.single_page.eq(0),
            psram.perform_write.eq(0),
            psram.register_space.eq(1),
            psram.final_word.eq(1),
            psram.start_transfer.eq(psram_address_changed),
            psram.address.eq(psram_address),
        ]

        #
        # SPI flash passthrough connections.
        #
        flash_sdo = Signal()

        spi_flash_bus = platform.request('spi_flash')
        spi_flash_passthrough = ECP5ConfigurationFlashInterface(
            bus=spi_flash_bus)

        m.submodules += spi_flash_passthrough
        m.d.comb += [
            spi_flash_passthrough.sck.eq(board_spi.sck),
            spi_flash_passthrough.sdi.eq(board_spi.sdi),
            flash_sdo.eq(spi_flash_passthrough.sdo),
        ]

        #
        # Synchronize each of our I/O SPI signals, where necessary.
        #
        spi = synchronize(m, board_spi)

        # Select the passthrough or gateware SPI based on our chip-select values.
        gateware_sdo = Signal()
        with m.If(spi_registers.spi.cs):
            m.d.comb += board_spi.sdo.eq(gateware_sdo)
        with m.Else():
            m.d.comb += board_spi.sdo.eq(flash_sdo)

        # Connect our register interface to our board SPI.
        m.d.comb += [
            spi_registers.spi.sck.eq(spi.sck),
            spi_registers.spi.sdi.eq(spi.sdi),
            gateware_sdo.eq(spi_registers.spi.sdo),
            spi_registers.spi.cs.eq(spi.cs)
        ]

        # Radio SPI window
        radio = platform.request("radio")
        radio_spi = RadioSPI(clk_freq=CLOCK_FREQUENCIES["sync"] * 1e6)
        m.submodules += radio_spi

        radio_address_changed = Signal()
        radio_address = spi_registers.add_register(
            REGISTER_RADIO_ADDR, write_strobe=radio_address_changed)

        radio_value_changed = Signal()
        spi_registers.add_sfr(
            REGISTER_RADIO_VALUE,
            read=radio_spi.read_value,
            write_signal=radio_spi.write_value,
            write_strobe=radio_value_changed,
        )

        # Hook up our radio.
        m.d.comb += [
            radio.rst.eq(0),

            # SPI outputs
            radio.sel.eq(radio_spi.sel),
            radio.sclk.eq(radio_spi.sclk),
            radio.mosi.eq(radio_spi.mosi),

            # SPI inputs
            radio_spi.miso.eq(radio.miso),
            radio_spi.write.eq(radio_value_changed),
            radio_spi.start.eq(radio_address_changed | radio_value_changed),
            radio_spi.address.eq(radio_address),
        ]

        # Radio LVDS loop-back

        # Set up radio clock domain from rxclk, and pass it through to txclk
        m.domains.radio = ClockDomain()
        m.d.comb += [
            ClockSignal("radio").eq(radio.rxclk),
            ResetSignal("radio").eq(ResetSignal()),
            radio.txclk.eq(ClockSignal("radio")),
        ]

        # TX a pattern
        tx = Signal(8, reset=0x2e)
        m.d.radio += [
            tx.eq(Cat(tx[7], tx[:-1])),
            radio.txd.eq(tx[7]),
        ]

        # ... and receive it back.
        rx = Signal(8)
        rx_counter = Signal(range(8))
        m.d.radio += rx.eq(Cat(radio.rxd09, rx[:-1]))
        m.d.radio += rx_counter.eq(rx_counter - 1)

        # Sync up to the pattern
        got_sync = Signal()
        with m.FSM() as fsm:
            with m.State("start"):
                with m.If(rx == 0x2e):
                    m.next = "sync"
                    m.d.radio += got_sync.eq(1)
                    m.d.radio += rx_counter.eq(7)

            with m.State("sync"):
                with m.If(rx_counter == 0):
                    with m.If(rx != 0x2e):
                        m.next = "start"
                        m.d.radio += got_sync.eq(0)

            with m.State("error"):
                pass

        got_sync_reg = Signal()
        m.submodules += FFSynchronizer(got_sync, got_sync_reg)
        spi_registers.add_read_only_register(REGISTER_RADIO_SYNC,
                                             read=got_sync_reg)
        m.d.comb += led_out[0].eq(got_sync)

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

        # Create our clock domains.
        m.domains.fast = ClockDomain()
        m.domains.sync = ClockDomain()
        m.domains.usb = ClockDomain()
        m.domains.clkref = ClockDomain()

        # Grab our clock and global reset signals.
        clk_16m384 = platform.request(platform.default_clk)
        # reset      = platform.request(platform.default_rst)

        # Generate the clocks we need for our PLL.
        feedback = Signal()
        locked = Signal()

        m.submodules.pll = Instance(
            "EHXPLLL",
            i_CLKI=clk_16m384,
            o_CLKOP=ClockSignal("fast"),
            o_CLKOS=ClockSignal("sync"),

            # Status.
            o_LOCK=locked,
            i_CLKFB=ClockSignal("fast"),

            # Control signals.
            i_RST=0,
            i_STDBY=0,
            # i_CLKINTFB         = 0,
            i_PHASESEL0=0,
            i_PHASESEL1=0,
            i_PHASEDIR=1,
            i_PHASESTEP=1,
            i_PHASELOADREG=1,
            i_PLLWAKESYNC=0,
            i_ENCLKOP=0,
            i_ENCLKOS=0,
            i_ENCLKOS2=0,
            i_ENCLKOS3=0,
            p_PLLRST_ENA="DISABLED",
            p_INTFB_WAKE="DISABLED",
            p_STDBY_ENABLE="DISABLED",
            p_DPHASE_SOURCE="DISABLED",
            p_CLKI_DIV=1,
            p_CLKOP_ENABLE="ENABLED",
            p_CLKOP_DIV=4,
            p_CLKOP_CPHASE=1,
            p_CLKOP_FPHASE=0,
            # p_CLKOP_TRIM_DELAY = 0,
            # p_CLKOP_TRIM_POL   = "FALLING",
            p_CLKOS_ENABLE="ENABLED",
            p_CLKOS_DIV=8,
            p_CLKOS_CPHASE=1,
            p_CLKOS_FPHASE=0,
            # p_CLKOS_TRIM_DELAY = 0,
            # p_CLKOS_TRIM_POL   = "FALLING",
            p_FEEDBK_PATH="CLKOP",
            p_CLKFB_DIV=12,
            p_CLKOS3_FPHASE=0,
            p_CLKOS3_CPHASE=0,
            p_CLKOS2_FPHASE=0,
            p_CLKOS2_CPHASE=0,
            p_PLL_LOCK_MODE=0,
            p_OUTDIVIDER_MUXD="DIVD",
            p_CLKOS3_ENABLE="DISABLED",
            p_OUTDIVIDER_MUXC="DIVC",
            p_CLKOS2_ENABLE="DISABLED",
            p_OUTDIVIDER_MUXB="DIVB",
            p_OUTDIVIDER_MUXA="DIVA",
            p_CLKOS3_DIV=1,
            p_CLKOS2_DIV=1,

            # Synthesis attributes.
            a_FREQUENCY_PIN_CLKI="16.384000",
            a_FREQUENCY_PIN_CLKOP="196.608000",
            a_FREQUENCY_PIN_CLKOS="98.304000",
            a_ICP_CURRENT="12",
            a_LPF_RESISTOR="8",
            a_MFG_ENABLE_FILTEROPAMP="1",
            a_MFG_GMCREF_SEL="2",
        )

        m.d.comb += [
            ClockSignal("clkref").eq(clk_16m384),
            ResetSignal("sync").eq(~locked),
            ResetSignal("fast").eq(~locked),
            # ResetSignal("framer").eq(0),
        ]

        return m
Exemplo n.º 17
0
    instr: Optional[Instruction] = None
    if args.instr is not None:
        instr = getattr(modules["instruction.implemented"], args.instr.split(".")[0])
        instr = getattr(instr, args.instr.split(".")[1])
        if instr not in implemented.implemented:
            raise AttributeError()

    m = Module()
    m.submodules.core = core = Core(instr)

    if instr is not None:
        time = Signal(6, reset_less=True)
        m.d.sync += time.eq(time + 1)

        with m.If(Initial()):
            m.d.sync += Assume(ResetSignal())
        with m.Else():
            m.d.sync += Assume(~ResetSignal())

        # A time slot delayed because PC and addr need to sync
        with m.If(time == 2):
            m.d.sync += Assume(~core.snapshot.taken)
        with m.If(time == 3):
            m.d.sync += Cover(core.snapshot.taken)
            m.d.sync += Assume(core.snapshot.taken)
        m.d.sync += Cover(Fell(core.snapshot.taken))

        main_runner(
            parser, args, m, ports=core.ports() + [ClockSignal(), ResetSignal()]
        )
Exemplo n.º 18
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        m.domains.ramg = ClockDomain(async_reset=True, local=True)
        m.domains.romb0 = ClockDomain(async_reset=True, local=True)
        m.domains.romb1 = ClockDomain(async_reset=True, local=True)
        m.domains.ramb = ClockDomain(async_reset=True, local=True)

        ramg_clk = ClockSignal("ramg")
        romb0_clk = ClockSignal("romb0")
        romb1_clk = ClockSignal("romb1")
        ramb_clk = ClockSignal("ramb")

        m.d.comb += [
            ResetSignal("ramg").eq(self.cart_rst),
            ResetSignal("romb0").eq(self.cart_rst),
            ResetSignal("romb1").eq(self.cart_rst),
            ResetSignal("ramb").eq(self.cart_rst),
        ]

        ramg = Signal(8)
        romb0 = Signal(8, reset=0x01)
        romb1 = Signal(1)
        ramb = Signal(4)

        m.d.ramg += ramg.eq(self.cart_data)
        m.d.romb0 += romb0.eq(self.cart_data)
        m.d.romb1 += romb1.eq(self.cart_data)
        m.d.ramb += ramb.eq(self.cart_data)

        m.d.comb += [
            ramg_clk.eq(1),
            romb0_clk.eq(1),
            romb1_clk.eq(1),
            ramb_clk.eq(1)
        ]
        with m.If(self.cart_wr):
            with m.Switch(self.cart_addr[12:]):
                with m.Case(0b0000):
                    m.d.comb += ramg_clk.eq(0)
                with m.Case(0b0001):
                    m.d.comb += ramg_clk.eq(0)
                with m.Case(0b0010):
                    m.d.comb += romb0_clk.eq(0)
                with m.Case(0b0011):
                    m.d.comb += romb1_clk.eq(0)
                with m.Case(0b0100):
                    m.d.comb += ramb_clk.eq(0)
                with m.Case(0b0101):
                    m.d.comb += ramb_clk.eq(0)

        m.d.comb += [
            self.ram_en.eq(ramg == 0x0A),
            self.ram_bank.eq(ramb),
        ]
        with m.If(self.cart_addr[14]):
            m.d.comb += self.rom_bank.eq(Cat(romb0, romb1))
        with m.Else():
            m.d.comb += self.rom_bank.eq(0)

        return m
Exemplo n.º 19
0
    def elaborate(self, platform):
        if platform is not None:
            platform.add_file("picorv32.v", open("picorv32.v", "r"))

        if not os.path.exists("build"):
            os.makedirs("build")

        subprocess.run(
            [
                "cargo", "objcopy", "--release", "--", "-O", "binary",
                "../build/app.bin"
            ],
            cwd="app",
        ).check_returncode()

        with open("build/app.bin", "rb") as f:
            b = bytearray(f.read())
            b.extend([0] * (4 - (len(b) % 4)))
            app = np.frombuffer(b, dtype='<u4').tolist()

        # MEM_SIZE = 256 # words
        RAM_SIZE = 256  # words
        init = ([0] * RAM_SIZE) + app
        MEM_SIZE = len(init)

        mem = Memory(
            width=32,
            depth=MEM_SIZE,
            init=init,
        )

        resetn = Signal()
        mem_valid = Signal()
        mem_ready = Signal()
        mem_addr = Signal(32)
        mem_wdata = Signal(32)
        mem_wstrb = Signal(4)
        mem_rdata = Signal(32)

        m = Module()

        m.d.comb += resetn.eq(~ResetSignal())

        m.submodules.picorv32 = Instance(
            "picorv32",
            p_ENABLE_COUNTERS=0,
            p_LATCHED_MEM_RDATA=1,
            p_TWO_STAGE_SHIFT=0,
            p_TWO_CYCLE_ALU=1,
            p_CATCH_MISALIGN=0,
            p_CATCH_ILLINSN=0,
            p_COMPRESSED_ISA=1,
            p_ENABLE_MUL=1,
            p_PROGADDR_RESET=1024,
            p_PROGADDR_IRQ=1024 + 0x10,
            i_clk=ClockSignal(),
            i_resetn=resetn,
            o_mem_valid=mem_valid,
            i_mem_ready=mem_ready,
            o_mem_addr=mem_addr,
            o_mem_wdata=mem_wdata,
            o_mem_wstrb=mem_wstrb,
            i_mem_rdata=mem_rdata,
        )
        m.submodules.read_port = read_port = mem.read_port(transparent=False)
        m.submodules.write_port = write_port = mem.write_port(granularity=8)

        m.d.sync += mem_ready.eq(0)

        m.d.comb += [
            read_port.addr.eq(mem_addr >> 2),
            mem_rdata.eq(read_port.data),
            read_port.en.eq((~mem_wstrb).bool()),
            write_port.addr.eq(mem_addr >> 2),
            write_port.data.eq(mem_wdata),
            write_port.en.eq(mem_wstrb),
        ]

        with m.If(resetn & mem_valid & ~mem_ready):
            with m.If((mem_addr >> 2) < MEM_SIZE):
                m.d.sync += mem_ready.eq(1)

            for mapping in self.memory_mappings:
                if mapping.writing_enabled:
                    with m.If(mem_wstrb.bool() & (mem_addr == mapping.addr)):
                        if mapping.write is not None:
                            mapping.write(m, mem_wdata)
                        else:
                            m.d.sync += [
                                mapping.signal.eq(mem_wdata),
                                mem_ready.eq(1),
                            ]
                if mapping.read:
                    with m.If((~mem_wstrb).bool()
                              & (mem_addr == mapping.addr)):
                        m.d.comb += mem_rdata.eq(mapping.signal)
                        m.d.sync += mem_ready.eq(1)
                if not mapping.read and not (mapping.write
                                             or mapping.writing_enabled):
                    print(mapping.addr)
                    print("mapping doesn't specify read or write",
                          file=sys.stderr)

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

        # Create clock out signals
        self.clk = {cfg.cd_name: Signal() for cfg in self.clock_config}
        self._pll_lock = Signal()

        # Create our clock domains.
        for cfg in self.clock_config:
            m.domains += ClockDomain(cfg.cd_name)
            m.d.comb += ClockSignal(domain=cfg.cd_name).eq(
                self.clk[cfg.cd_name])
            m.d.comb += ResetSignal(cfg.cd_name).eq(~self._pll_lock),

        # Grab our input clock
        clock_name = self.clock_name if self.clock_name else platform.default_clk

        try:
            self.clkin_frequency = platform.lookup(
                clock_name).clock.frequency / 1e6
            input_clock_pin = platform.request(clock_name)
        except:
            input_clock_pin = ClockSignal(clock_name)
            # TODO: Make this nicer, remove clock_signal_freq
            self.clkin_frequency = self.clock_signal_freq / 1e6

        # Calculate configuration parameters
        params = self.calc_pll_params(self.clkin_frequency,
                                      self.clock_config[0].freq)
        if len(self.clock_config) > 1:
            self.generate_secondary_output(params, 0,
                                           self.clock_config[1].freq,
                                           self.clock_config[1].phase)
        if len(self.clock_config) > 2:
            self.generate_secondary_output(params, 1,
                                           self.clock_config[2].freq,
                                           self.clock_config[2].phase)
        if len(self.clock_config) > 3:
            self.generate_secondary_output(params, 2,
                                           self.clock_config[3].freq,
                                           self.clock_config[3].phase)

        for i, p in enumerate([
                params, params["secondary"][0], params["secondary"][1],
                params["secondary"][2]
        ]):
            if p["error"] > 0:
                logger.warning(
                    "ClockDomain {} has an error of {:.3f} MHz ({} instead of {})"
                    .format(self.clock_config[i].cd_name, p["error"],
                            p["freq"], p["freq_requested"]))
                if not self.skip_checks:
                    assert (p["error"] <= self.clock_config[i].error)

        m.submodules.pll = Instance(
            "EHXPLLL",
            # Clock in.
            i_CLKI=input_clock_pin,

            # Generated clock outputs.
            o_CLKOP=self.clk[self.clock_config[0].cd_name],
            o_CLKOS=self.clk[self.clock_config[1].cd_name]
            if len(self.clock_config) > 1 else Signal(),
            o_CLKOS2=self.clk[self.clock_config[2].cd_name]
            if len(self.clock_config) > 2 else Signal(),
            o_CLKOS3=self.clk[self.clock_config[3].cd_name]
            if len(self.clock_config) > 3 else Signal(),

            # Status.
            o_LOCK=self._pll_lock,

            # PLL parameters...
            p_PLLRST_ENA="DISABLED",
            p_INTFB_WAKE="DISABLED",
            p_STDBY_ENABLE="DISABLED",
            p_DPHASE_SOURCE="DISABLED",
            p_OUTDIVIDER_MUXA="DIVA",
            p_OUTDIVIDER_MUXB="DIVB",
            p_OUTDIVIDER_MUXC="DIVC",
            p_OUTDIVIDER_MUXD="DIVD",
            p_CLKI_DIV=params["refclk_div"],
            p_CLKOP_ENABLE="ENABLED",
            p_CLKOP_DIV=params["output_div"],
            p_CLKOP_CPHASE=params["primary_cphase"],
            p_CLKOP_FPHASE=0,
            p_CLKOS_ENABLE="ENABLED"
            if params["secondary"][0]["enabled"] else "DISABLED",
            p_CLKOS_FPHASE=params["secondary"][0]["fphase"],
            p_CLKOS_CPHASE=params["secondary"][0]["cphase"],
            p_CLKOS_DIV=params["secondary"][0]["div"],
            p_CLKOS2_ENABLE="ENABLED"
            if params["secondary"][1]["enabled"] else "DISABLED",
            p_CLKOS2_FPHASE=params["secondary"][1]["fphase"],
            p_CLKOS2_CPHASE=params["secondary"][1]["cphase"],
            p_CLKOS2_DIV=params["secondary"][1]["div"],
            p_CLKOS3_ENABLE="ENABLED"
            if params["secondary"][2]["enabled"] else "DISABLED",
            p_CLKOS3_FPHASE=params["secondary"][2]["fphase"],
            p_CLKOS3_CPHASE=params["secondary"][2]["cphase"],
            p_CLKOS3_DIV=params["secondary"][2]["div"],
            p_FEEDBK_PATH="CLKOP",  # TODO: external feedback
            p_CLKFB_DIV=params["feedback_div"],

            # Internal feedback.
            i_CLKFB=self.clk[self.clock_config[0].cd_name],

            # TODO: Reset
            i_RST=0,

            # TODO: Standby
            i_STDBY=0,

            # TODO: Dynamic mode
            i_PHASESEL0=0,
            i_PHASESEL1=0,
            i_PHASEDIR=0,
            i_PHASESTEP=0,
            i_PHASELOADREG=0,
            i_PLLWAKESYNC=0,

            # Output Enables.
            i_ENCLKOP=0,
            i_ENCLKOS=0,
            i_ENCLKOS2=0,
            i_ENCLKOS3=0,

            # Synthesis attributes.
            a_FREQUENCY_PIN_CLKI=str(self.clkin_frequency),
            a_FREQUENCY_PIN_CLKOP=str(self.clock_config[0].freq),
            a_FREQUENCY_PIN_CLKOS=str(self.clock_config[1].freq)
            if len(self.clock_config) > 1 else "0",
            a_FREQUENCY_PIN_CLKOS2=str(self.clock_config[2].freq)
            if len(self.clock_config) > 2 else "0",
            a_FREQUENCY_PIN_CLKOS3=str(self.clock_config[3].freq)
            if len(self.clock_config) > 3 else "0",
            a_ICP_CURRENT="12",
            a_LPF_RESISTOR="8",
            a_MFG_ENABLE_FILTEROPAMP="1",
            a_MFG_GMCREF_SEL="2",
        )
        return m