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
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
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
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 )
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]
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]
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
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)
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
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
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), ]
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
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
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()] )
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
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
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