diff --git a/amaranth/vendor/__init__.py b/amaranth/vendor/__init__.py index 7373bb7..b35aab9 100644 --- a/amaranth/vendor/__init__.py +++ b/amaranth/vendor/__init__.py @@ -11,6 +11,7 @@ __all__ = [ "LatticeICE40Platform", "LatticeMachXO2Platform", "LatticeMachXO3LPlatform", + "LatticePlatform", "QuicklogicPlatform", "SiliconBluePlatform", "XilinxPlatform", @@ -28,12 +29,10 @@ def __getattr__(name): if name == "GowinPlatform": from ._gowin import GowinPlatform return GowinPlatform - if name == "LatticeECP5Platform": - from ._lattice_ecp5 import LatticeECP5Platform - return LatticeECP5Platform - if name in ("LatticeMachXO2Platform", "LatticeMachXO3LPlatform"): - from ._lattice_machxo_2_3l import LatticeMachXO2Or3LPlatform - return LatticeMachXO2Or3LPlatform + if name in ("LatticePlatform", "LatticeECP5Platform", "LatticeMachXO2Platform", + "LatticeMachXO3LPlatform"): + from ._lattice import LatticePlatform + return LatticePlatform if name == "QuicklogicPlatform": from ._quicklogic import QuicklogicPlatform return QuicklogicPlatform diff --git a/amaranth/vendor/_lattice_ecp5.py b/amaranth/vendor/_lattice.py similarity index 76% rename from amaranth/vendor/_lattice_ecp5.py rename to amaranth/vendor/_lattice.py index ba4c4eb..c8945e9 100644 --- a/amaranth/vendor/_lattice_ecp5.py +++ b/amaranth/vendor/_lattice.py @@ -123,7 +123,7 @@ class FFBuffer(io.FFBuffer): return m -class DDRBuffer(io.DDRBuffer): +class DDRBufferECP5(io.DDRBuffer): def elaborate(self, platform): m = Module() @@ -164,9 +164,50 @@ class DDRBuffer(io.DDRBuffer): return m -class LatticeECP5Platform(TemplatedPlatform): +class DDRBufferMachXO2(io.DDRBuffer): + def elaborate(self, platform): + m = Module() + + m.submodules.buf = buf = InnerBuffer(self.direction, self.port) + inv_mask = sum(inv << bit for bit, inv in enumerate(self.port.invert)) + + if self.direction is not io.Direction.Output: + i0_inv = Signal(len(self.port)) + i1_inv = Signal(len(self.port)) + for bit in range(len(self.port)): + m.submodules[f"i_ddr{bit}"] = Instance("IDDRXE", + i_SCLK=ClockSignal(self.i_domain), + i_RST=Const(0), + i_D=buf.i[bit], + o_Q0=i0_inv[bit], + o_Q1=i1_inv[bit], + ) + m.d.comb += self.i[0].eq(i0_inv ^ inv_mask) + m.d.comb += self.i[1].eq(i1_inv ^ inv_mask) + + if self.direction is not io.Direction.Input: + o0_inv = Signal(len(self.port)) + o1_inv = Signal(len(self.port)) + m.d.comb += [ + o0_inv.eq(self.o[0] ^ inv_mask), + o1_inv.eq(self.o[1] ^ inv_mask), + ] + for bit in range(len(self.port)): + m.submodules[f"o_ddr{bit}"] = Instance("ODDRXE", + i_SCLK=ClockSignal(self.o_domain), + i_RST=Const(0), + i_D0=o0_inv[bit], + i_D1=o1_inv[bit], + o_Q=buf.o[bit], + ) + _make_oereg(m, self.o_domain, ~self.oe, buf.t) + + return m + + +class LatticePlatform(TemplatedPlatform): """ - .. rubric:: Trellis toolchain + .. rubric:: Trellis toolchain (ECP5 only) Required tools: * ``yosys`` @@ -195,7 +236,7 @@ class LatticeECP5Platform(TemplatedPlatform): * ``{{name}}.bit``: binary bitstream. * ``{{name}}.svf``: JTAG programming vector. - .. rubric:: Diamond toolchain + .. rubric:: Diamond toolchain (ECP5, MachXO2, MachXO3) Required tools: * ``pnmainc`` @@ -217,8 +258,11 @@ class LatticeECP5Platform(TemplatedPlatform): Build products: * ``{{name}}_impl/{{name}}_impl.htm``: consolidated log. + * ``{{name}}.jed``: JEDEC fuse file (MachXO2, MachXO3 only). * ``{{name}}.bit``: binary bitstream. - * ``{{name}}.svf``: JTAG programming vector. + * ``{{name}}.svf``: JTAG programming vector (ECP5 only). + * ``{{name}}_flash.svf``: JTAG programming vector for FLASH programming (MachXO2, MachXO3 only). + * ``{{name}}_sram.svf``: JTAG programming vector for SRAM programming (MachXO2, MachXO3 only). """ toolchain = None # selected when creating platform @@ -378,6 +422,9 @@ class LatticeECP5Platform(TemplatedPlatform): prj_run Map -impl impl prj_run PAR -impl impl prj_run Export -impl impl -task Bitgen + {% if family == "machxo2" -%} + prj_run Export -impl impl -task Jedecgen + {% endif %} {{get_override("script_after_export")|default("# (script_after_export placeholder)")}} """, "{{name}}.lpf": r""" @@ -405,7 +452,7 @@ class LatticeECP5Platform(TemplatedPlatform): {{get_override("add_constraints")|default("# (add_constraints placeholder)")}} """, } - _diamond_command_templates = [ + _diamond_command_templates_ecp5 = [ # These don't have any usable command-line option overrides. r""" {{invoke_tool("pnmainc")}} @@ -422,12 +469,54 @@ class LatticeECP5Platform(TemplatedPlatform): -if {{name}}_impl/{{name}}_impl.bit -of {{name}}.svf """, ] + _diamond_command_templates_machxo2 = [ + # These don't have any usable command-line option overrides. + r""" + {{invoke_tool("pnmainc")}} + {{name}}.tcl + """, + r""" + {{invoke_tool("ddtcmd")}} + -oft -bit + -if {{name}}_impl/{{name}}_impl.bit -of {{name}}.bit + """, + r""" + {{invoke_tool("ddtcmd")}} + -oft -jed + -dev {{platform.device}}-{{platform.speed}}{{platform.package}}{{platform.grade}} + -if {{name}}_impl/{{name}}_impl.jed -of {{name}}.jed + """, + r""" + {{invoke_tool("ddtcmd")}} + -oft -svfsingle -revd -op "FLASH Erase,Program,Verify" + -if {{name}}_impl/{{name}}_impl.jed -of {{name}}_flash.svf + """, + r""" + {{invoke_tool("ddtcmd")}} + -oft -svfsingle -revd -op "SRAM Fast Program" + -if {{name}}_impl/{{name}}_impl.bit -of {{name}}_sram.svf + """, + ] # Common logic - def __init__(self, *, toolchain="Trellis"): + def __init__(self, *, toolchain=None): super().__init__() + device = self.device.lower() + if device.startswith(("lfe5", "lae5")): + self.family = "ecp5" + elif device.startswith(("lcmxo2-", "lcmxo3l", "lcmxo3d", "lamxo2-", "lamxo3l", "lamxo3d", "lfmnx-")): + self.family = "machxo2" + else: + raise ValueError(f"Device '{self.device}' is not recognized") + + if toolchain is None: + if self.family == "ecp5": + toolchain = "Trellis" + else: + toolchain = "Diamond" + assert toolchain in ("Trellis", "Diamond") self.toolchain = toolchain @@ -452,23 +541,46 @@ class LatticeECP5Platform(TemplatedPlatform): if self.toolchain == "Trellis": return self._trellis_command_templates if self.toolchain == "Diamond": - return self._diamond_command_templates + if self.family == "ecp5": + return self._diamond_command_templates_ecp5 + if self.family == "machxo2": + return self._diamond_command_templates_machxo2 assert False + # These numbers were extracted from + # "MachXO2 sysCLOCK PLL Design and Usage Guide" + _supported_osch_freqs = [ + 2.08, 2.15, 2.22, 2.29, 2.38, 2.46, 2.56, 2.66, 2.77, 2.89, + 3.02, 3.17, 3.33, 3.50, 3.69, 3.91, 4.16, 4.29, 4.43, 4.59, + 4.75, 4.93, 5.12, 5.32, 5.54, 5.78, 6.05, 6.33, 6.65, 7.00, + 7.39, 7.82, 8.31, 8.58, 8.87, 9.17, 9.50, 9.85, 10.23, 10.64, + 11.08, 11.57, 12.09, 12.67, 13.30, 14.00, 14.78, 15.65, 15.65, 16.63, + 17.73, 19.00, 20.46, 22.17, 24.18, 26.60, 29.56, 33.25, 38.00, 44.33, + 53.20, 66.50, 88.67, 133.00 + ] + @property def default_clk_constraint(self): if self.default_clk == "OSCG": + # Internal high-speed oscillator on ECP5 devices. return Clock(310e6 / self.oscg_div) + if self.default_clk == "OSCH": + # Internal high-speed oscillator on MachXO2/MachXO3L devices. + # It can have a range of frequencies. + assert self.osch_frequency in self._supported_osch_freqs + return Clock(int(self.osch_frequency * 1e6)) + # Otherwise, use the defined Clock resource. return super().default_clk_constraint def create_missing_domain(self, name): - # Lattice ECP5 devices have two global set/reset signals: PUR, which is driven at startup + # Lattice devices have two global set/reset signals: PUR, which is driven at startup # by the configuration logic and unconditionally resets every storage element, and GSR, # which is driven by user logic and each storage element may be configured as affected or # unaffected by GSR. PUR is purely asynchronous, so even though it is a low-skew global # network, its deassertion may violate a setup/hold constraint with relation to a user # clock. To avoid this, a GSR/SGSR instance should be driven synchronized to user clock. if name == "sync" and self.default_clk is not None: + using_osch = False m = Module() if self.default_clk == "OSCG": if not hasattr(self, "oscg_div"): @@ -480,6 +592,14 @@ class LatticeECP5Platform(TemplatedPlatform): .format(self.oscg_div)) clk_i = Signal() m.submodules += Instance("OSCG", p_DIV=self.oscg_div, o_OSC=clk_i) + elif self.default_clk == "OSCH": + osch_freq = self.osch_frequency + if osch_freq not in self._supported_osch_freqs: + raise ValueError("Frequency {!r} is not valid for OSCH clock. Valid frequencies are {!r}" + .format(osch_freq, self._supported_osch_freqs)) + osch_freq_param = f"{float(osch_freq):.2f}" + clk_i = Signal() + m.submodules += [ Instance("OSCH", p_NOM_FREQ=osch_freq_param, i_STDBY=Const(0), o_OSC=clk_i, o_SEDSTDBY=Signal()) ] else: clk_i = self.request(self.default_clk).i if self.default_rst is not None: @@ -489,7 +609,7 @@ class LatticeECP5Platform(TemplatedPlatform): gsr0 = Signal() gsr1 = Signal() - # There is no end-of-startup signal on ECP5, but PUR is released after IOB enable, so + # There is no end-of-startup signal on Lattice, but PUR is released after IOB enable, so # a simple reset synchronizer (with PUR as the asynchronous reset) does the job. m.submodules += [ Instance("FD1S3AX", p_GSR="DISABLED", i_CK=clk_i, i_D=~rst_i, o_Q=gsr0), @@ -512,7 +632,12 @@ class LatticeECP5Platform(TemplatedPlatform): elif isinstance(buffer, io.FFBuffer): result = FFBuffer(buffer.direction, buffer.port) elif isinstance(buffer, io.DDRBuffer): - result = DDRBuffer(buffer.direction, buffer.port) + if self.family == "ecp5": + result = DDRBufferECP5(buffer.direction, buffer.port) + elif self.family == "machxo2": + result = DDRBufferMachXO2(buffer.direction, buffer.port) + else: + raise NotImplementedError # :nocov: else: raise TypeError(f"Unsupported buffer type {buffer!r}") # :nocov: if buffer.direction is not io.Direction.Output: @@ -522,5 +647,5 @@ class LatticeECP5Platform(TemplatedPlatform): result.oe = buffer.oe return result - # CDC primitives are not currently specialized for ECP5. + # CDC primitives are not currently specialized for Lattice. # While Diamond supports false path constraints; nextpnr-ecp5 does not. diff --git a/amaranth/vendor/_lattice_machxo_2_3l.py b/amaranth/vendor/_lattice_machxo_2_3l.py deleted file mode 100644 index b36262b..0000000 --- a/amaranth/vendor/_lattice_machxo_2_3l.py +++ /dev/null @@ -1,275 +0,0 @@ -from abc import abstractmethod - -from ..hdl import * -from ..lib import io, wiring -from ..build import * - - -# MachXO[23] I/O buffers are identical to ECP5 except for DDR. - -from ._lattice_ecp5 import InnerBuffer, IOBuffer, FFBuffer, _make_oereg - - -class DDRBuffer(io.DDRBuffer): - def elaborate(self, platform): - m = Module() - - m.submodules.buf = buf = InnerBuffer(self.direction, self.port) - inv_mask = sum(inv << bit for bit, inv in enumerate(self.port.invert)) - - if self.direction is not io.Direction.Output: - i0_inv = Signal(len(self.port)) - i1_inv = Signal(len(self.port)) - for bit in range(len(self.port)): - m.submodules[f"i_ddr{bit}"] = Instance("IDDRXE", - i_SCLK=ClockSignal(self.i_domain), - i_RST=Const(0), - i_D=buf.i[bit], - o_Q0=i0_inv[bit], - o_Q1=i1_inv[bit], - ) - m.d.comb += self.i[0].eq(i0_inv ^ inv_mask) - m.d.comb += self.i[1].eq(i1_inv ^ inv_mask) - - if self.direction is not io.Direction.Input: - o0_inv = Signal(len(self.port)) - o1_inv = Signal(len(self.port)) - m.d.comb += [ - o0_inv.eq(self.o[0] ^ inv_mask), - o1_inv.eq(self.o[1] ^ inv_mask), - ] - for bit in range(len(self.port)): - m.submodules[f"o_ddr{bit}"] = Instance("ODDRXE", - i_SCLK=ClockSignal(self.o_domain), - i_RST=Const(0), - i_D0=o0_inv[bit], - i_D1=o1_inv[bit], - o_Q=buf.o[bit], - ) - _make_oereg(m, self.o_domain, ~self.oe, buf.t) - - return m - - -# MachXO2 and MachXO3L primitives are the same. Handle both using -# one class and expose user-aliases for convenience. -class LatticeMachXO2Or3LPlatform(TemplatedPlatform): - """ - Required tools: - * ``pnmainc`` - * ``ddtcmd`` - - The environment is populated by running the script specified in the environment variable - ``AMARANTH_ENV_DIAMOND``, if present. On Linux, diamond_env as provided by Diamond - itself is a good candidate. On Windows, the following script (named ``diamond_env.bat``, - for instance) is known to work:: - - @echo off - set PATH=C:\\lscc\\diamond\\%DIAMOND_VERSION%\\bin\\nt64;%PATH% - - Available overrides: - * ``script_project``: inserts commands before ``prj_project save`` in Tcl script. - * ``script_after_export``: inserts commands after ``prj_run Export`` in Tcl script. - * ``add_preferences``: inserts commands at the end of the LPF file. - * ``add_constraints``: inserts commands at the end of the XDC file. - - Build products: - * ``{{name}}_impl/{{name}}_impl.htm``: consolidated log. - * ``{{name}}.jed``: JEDEC fuse file. - * ``{{name}}.bit``: binary bitstream. - * ``{{name}}.svf``: JTAG programming vector for FLASH programming. - * ``{{name}}_flash.svf``: JTAG programming vector for FLASH programming. - * ``{{name}}_sram.svf``: JTAG programming vector for SRAM programming. - """ - - toolchain = "Diamond" - - device = property(abstractmethod(lambda: None)) - package = property(abstractmethod(lambda: None)) - speed = property(abstractmethod(lambda: None)) - grade = "C" # [C]ommercial, [I]ndustrial - - required_tools = [ - "pnmainc", - "ddtcmd" - ] - file_templates = { - **TemplatedPlatform.build_script_templates, - "build_{{name}}.sh": r""" - # {{autogenerated}} - set -e{{verbose("x")}} - if [ -z "$BASH" ] ; then exec /bin/bash "$0" "$@"; fi - if [ -n "${{platform._toolchain_env_var}}" ]; then - bindir=$(dirname "${{platform._toolchain_env_var}}") - . "${{platform._toolchain_env_var}}" - fi - {{emit_commands("sh")}} - """, - "{{name}}.v": r""" - /* {{autogenerated}} */ - {{emit_verilog()}} - """, - "{{name}}.debug.v": r""" - /* {{autogenerated}} */ - {{emit_debug_verilog()}} - """, - "{{name}}.tcl": r""" - prj_project new -name {{name}} -impl impl -impl_dir {{name}}_impl \ - -dev {{platform.device}}-{{platform.speed}}{{platform.package}}{{platform.grade}} \ - -lpf {{name}}.lpf \ - -synthesis synplify - {% for file in platform.iter_files(".v", ".sv", ".vhd", ".vhdl") -%} - prj_src add {{file|tcl_quote}} - {% endfor %} - prj_src add {{name}}.v - prj_impl option top {{name}} - prj_src add {{name}}.sdc - {{get_override("script_project")|default("# (script_project placeholder)")}} - prj_project save - prj_run Synthesis -impl impl - prj_run Translate -impl impl - prj_run Map -impl impl - prj_run PAR -impl impl - prj_run Export -impl impl -task Bitgen - prj_run Export -impl impl -task Jedecgen - {{get_override("script_after_export")|default("# (script_after_export placeholder)")}} - """, - "{{name}}.lpf": r""" - # {{autogenerated}} - BLOCK ASYNCPATHS; - BLOCK RESETPATHS; - {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%} - LOCATE COMP "{{port_name}}" SITE "{{pin_name}}"; - {% if attrs -%} - IOBUF PORT "{{port_name}}" - {%- for key, value in attrs.items() %} {{key}}={{value}}{% endfor %}; - {% endif %} - {% endfor %} - {{get_override("add_preferences")|default("# (add_preferences placeholder)")}} - """, - "{{name}}.sdc": r""" - set_hierarchy_separator {/} - {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%} - {% if port_signal is not none -%} - create_clock -name {{port_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}] - {% else -%} - create_clock -name {{net_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_quote}}] - {% endif %} - {% endfor %} - {{get_override("add_constraints")|default("# (add_constraints placeholder)")}} - """, - } - command_templates = [ - # These don't have any usable command-line option overrides. - r""" - {{invoke_tool("pnmainc")}} - {{name}}.tcl - """, - r""" - {{invoke_tool("ddtcmd")}} - -oft -bit - -if {{name}}_impl/{{name}}_impl.bit -of {{name}}.bit - """, - r""" - {{invoke_tool("ddtcmd")}} - -oft -jed - -dev {{platform.device}}-{{platform.speed}}{{platform.package}}{{platform.grade}} - -if {{name}}_impl/{{name}}_impl.jed -of {{name}}.jed - """, - r""" - {{invoke_tool("ddtcmd")}} - -oft -svfsingle -revd -op "FLASH Erase,Program,Verify" - -if {{name}}_impl/{{name}}_impl.jed -of {{name}}_flash.svf - """, - r""" - {{invoke_tool("ddtcmd")}} - -oft -svfsingle -revd -op "SRAM Fast Program" - -if {{name}}_impl/{{name}}_impl.bit -of {{name}}_sram.svf - """, - ] - # These numbers were extracted from - # "MachXO2 sysCLOCK PLL Design and Usage Guide" - _supported_osch_freqs = [ - 2.08, 2.15, 2.22, 2.29, 2.38, 2.46, 2.56, 2.66, 2.77, 2.89, - 3.02, 3.17, 3.33, 3.50, 3.69, 3.91, 4.16, 4.29, 4.43, 4.59, - 4.75, 4.93, 5.12, 5.32, 5.54, 5.78, 6.05, 6.33, 6.65, 7.00, - 7.39, 7.82, 8.31, 8.58, 8.87, 9.17, 9.50, 9.85, 10.23, 10.64, - 11.08, 11.57, 12.09, 12.67, 13.30, 14.00, 14.78, 15.65, 15.65, 16.63, - 17.73, 19.00, 20.46, 22.17, 24.18, 26.60, 29.56, 33.25, 38.00, 44.33, - 53.20, 66.50, 88.67, 133.00 - ] - - @property - def default_clk_constraint(self): - # Internal high-speed oscillator on MachXO2/MachXO3L devices. - # It can have a range of frequencies. - if self.default_clk == "OSCH": - assert self.osch_frequency in self._supported_osch_freqs - return Clock(int(self.osch_frequency * 1e6)) - # Otherwise, use the defined Clock resource. - return super().default_clk_constraint - - def create_missing_domain(self, name): - # Lattice MachXO2/MachXO3L devices have two global set/reset signals: PUR, which is driven at - # startup by the configuration logic and unconditionally resets every storage element, - # and GSR, which is driven by user logic and each storage element may be configured as - # affected or unaffected by GSR. PUR is purely asynchronous, so even though it is - # a low-skew global network, its deassertion may violate a setup/hold constraint with - # relation to a user clock. To avoid this, a GSR/SGSR instance should be driven - # synchronized to user clock. - if name == "sync" and self.default_clk is not None: - using_osch = False - if self.default_clk == "OSCH": - using_osch = True - clk_i = Signal() - else: - clk_i = self.request(self.default_clk).i - if self.default_rst is not None: - rst_i = self.request(self.default_rst).i - else: - rst_i = Const(0) - - gsr0 = Signal() - gsr1 = Signal() - m = Module() - # There is no end-of-startup signal on MachXO2/MachXO3L, but PUR is released after IOB - # enable, so a simple reset synchronizer (with PUR as the asynchronous reset) does the job. - m.submodules += [ - Instance("FD1S3AX", p_GSR="DISABLED", i_CK=clk_i, i_D=~rst_i, o_Q=gsr0), - Instance("FD1S3AX", p_GSR="DISABLED", i_CK=clk_i, i_D=gsr0, o_Q=gsr1), - # Although we already synchronize the reset input to user clock, SGSR has dedicated - # clock routing to the center of the FPGA; use that just in case it turns out to be - # more reliable. (None of this is documented.) - Instance("SGSR", i_CLK=clk_i, i_GSR=gsr1), - ] - if using_osch: - osch_freq = self.osch_frequency - if osch_freq not in self._supported_osch_freqs: - raise ValueError("Frequency {!r} is not valid for OSCH clock. Valid frequencies are {!r}" - .format(osch_freq, self._supported_osch_freqs)) - osch_freq_param = f"{float(osch_freq):.2f}" - m.submodules += [ Instance("OSCH", p_NOM_FREQ=osch_freq_param, i_STDBY=Const(0), o_OSC=clk_i, o_SEDSTDBY=Signal()) ] - # GSR implicitly connects to every appropriate storage element. As such, the sync - # domain is reset-less; domains driven by other clocks would need to have dedicated - # reset circuitry or otherwise meet setup/hold constraints on their own. - m.domains += ClockDomain("sync", reset_less=True) - m.d.comb += ClockSignal("sync").eq(clk_i) - return m - - def get_io_buffer(self, buffer): - if isinstance(buffer, io.Buffer): - result = IOBuffer(buffer.direction, buffer.port) - elif isinstance(buffer, io.FFBuffer): - result = FFBuffer(buffer.direction, buffer.port) - elif isinstance(buffer, io.DDRBuffer): - result = DDRBuffer(buffer.direction, buffer.port) - else: - raise TypeError(f"Unsupported buffer type {buffer!r}") # :nocov: - if buffer.direction is not io.Direction.Output: - result.i = buffer.i - if buffer.direction is not io.Direction.Input: - result.o = buffer.o - result.oe = buffer.oe - return result - - # CDC primitives are not currently specialized for MachXO2/MachXO3L. diff --git a/docs/platform.rst b/docs/platform.rst index 6ab4e52..8ac63ac 100644 --- a/docs/platform.rst +++ b/docs/platform.rst @@ -12,8 +12,7 @@ Platform integration platform/altera platform/gowin - platform/lattice-ecp5 - platform/lattice-ice40 - platform/lattice-machxo-2-3l + platform/lattice platform/quicklogic + platform/siliconblue platform/xilinx diff --git a/docs/platform/lattice-ecp5.rst b/docs/platform/lattice-ecp5.rst deleted file mode 100644 index 38dc10c..0000000 --- a/docs/platform/lattice-ecp5.rst +++ /dev/null @@ -1,10 +0,0 @@ -Lattice ECP5 -############ - -.. currentmodule:: amaranth.vendor - -The :class:`LatticeECP5Platform` class provides a base platform to support Lattice ECP5 devices. - -The Trellis and Diamond toolchains are supported. - -.. autoclass:: LatticeECP5Platform diff --git a/docs/platform/lattice-ice40.rst b/docs/platform/lattice-ice40.rst deleted file mode 100644 index 9c7d07f..0000000 --- a/docs/platform/lattice-ice40.rst +++ /dev/null @@ -1,10 +0,0 @@ -Lattice iCE40 -############# - -.. currentmodule:: amaranth.vendor - -The :class:`LatticeICE40Platform` class provides a base platform to support Lattice iCE40 devices. - -The IceStorm and iCECube2 toolchains are supported. - -.. autoclass:: LatticeICE40Platform diff --git a/docs/platform/lattice-machxo-2-3l.rst b/docs/platform/lattice-machxo-2-3l.rst deleted file mode 100644 index 790138d..0000000 --- a/docs/platform/lattice-machxo-2-3l.rst +++ /dev/null @@ -1,12 +0,0 @@ -Lattice MachXO2 and MachXO3L -############################ - -.. currentmodule:: amaranth.vendor - -The :class:`LatticeMachXO2Platform` and :class:`LatticeMachXO3LPlatform` classes provide base platforms to support Lattice MachXO2 and MachXO3L devices. - -The Diamond toolchain is supported. - -.. autoclass:: amaranth.vendor._lattice_machxo_2_3l.LatticeMachXO2Or3LPlatform -.. autoclass:: LatticeMachXO2Platform -.. autoclass:: LatticeMachXO3LPlatform diff --git a/docs/platform/lattice.rst b/docs/platform/lattice.rst new file mode 100644 index 0000000..8adf214 --- /dev/null +++ b/docs/platform/lattice.rst @@ -0,0 +1,10 @@ +Lattice +####### + +.. currentmodule:: amaranth.vendor + +The :class:`LatticePlatform` class provides a base platform to support Lattice toolchains (not including iCE40 devices, which are supported by :class:`SiliconBluePlatform`). Currently supported devices include ECP5, MachXO2, and MachXO3L. + +The Trellis and Diamond toolchains are supported. + +.. autoclass:: LatticePlatform diff --git a/docs/platform/siliconblue.rst b/docs/platform/siliconblue.rst new file mode 100644 index 0000000..1c6bad3 --- /dev/null +++ b/docs/platform/siliconblue.rst @@ -0,0 +1,10 @@ +SiliconBlue +########### + +.. currentmodule:: amaranth.vendor + +The :class:`SiliconBluePlatform` class provides a base platform to support Lattice (earlier SiliconBlue) iCE40 devices. + +The IceStorm and iCECube2 toolchains are supported. + +.. autoclass:: SiliconBluePlatform