build.plat,vendor: automatically create sync domain from default_clk.
But only if it is not defined by the programmer. Closes #57.
This commit is contained in:
parent
e0b54b417e
commit
8854ca03ae
|
@ -7,6 +7,7 @@ import jinja2
|
||||||
|
|
||||||
from .. import __version__
|
from .. import __version__
|
||||||
from ..hdl.ast import *
|
from ..hdl.ast import *
|
||||||
|
from ..hdl.cd import *
|
||||||
from ..hdl.dsl import *
|
from ..hdl.dsl import *
|
||||||
from ..hdl.ir import *
|
from ..hdl.ir import *
|
||||||
from ..back import rtlil, verilog
|
from ..back import rtlil, verilog
|
||||||
|
@ -71,11 +72,27 @@ class Platform(ResourceManager, metaclass=ABCMeta):
|
||||||
|
|
||||||
self.toolchain_program(products, name, **(program_opts or {}))
|
self.toolchain_program(products, name, **(program_opts or {}))
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def create_missing_domain(self, name):
|
||||||
|
if name == "sync" and self.default_clk is not None:
|
||||||
|
clk_i = self.request(self.default_clk).i
|
||||||
|
if self.default_rst is not None:
|
||||||
|
rst_i = self.request(self.default_rst).i
|
||||||
|
|
||||||
|
m = Module()
|
||||||
|
m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
|
||||||
|
m.d.comb += ClockSignal("sync").eq(clk_i)
|
||||||
|
if self.default_rst is not None:
|
||||||
|
m.d.comb += ResetSignal("sync").eq(rst_i)
|
||||||
|
return m
|
||||||
|
|
||||||
def prepare(self, fragment, name="top", **kwargs):
|
def prepare(self, fragment, name="top", **kwargs):
|
||||||
assert not self._prepared
|
assert not self._prepared
|
||||||
self._prepared = True
|
self._prepared = True
|
||||||
|
|
||||||
fragment = Fragment.get(fragment, self)
|
fragment = Fragment.get(fragment, self)
|
||||||
|
fragment = fragment.prepare(ports=list(self.iter_ports()),
|
||||||
|
missing_domain=self.create_missing_domain)
|
||||||
|
|
||||||
def add_pin_fragment(pin, pin_fragment):
|
def add_pin_fragment(pin, pin_fragment):
|
||||||
pin_fragment = Fragment.get(pin_fragment, self)
|
pin_fragment = Fragment.get(pin_fragment, self)
|
||||||
|
@ -226,9 +243,8 @@ class TemplatedPlatform(Platform):
|
||||||
autogenerated = "Automatically generated by nMigen {}. Do not edit.".format(__version__)
|
autogenerated = "Automatically generated by nMigen {}. Do not edit.".format(__version__)
|
||||||
|
|
||||||
def emit_design(backend):
|
def emit_design(backend):
|
||||||
return {"rtlil": rtlil, "verilog": verilog}[backend].convert(
|
return {"rtlil": rtlil, "verilog": verilog}[backend].convert(fragment, name=name,
|
||||||
fragment, name=name, platform=self, ports=list(self.iter_ports()),
|
ports=list(self.iter_ports()), missing_domain=lambda name: None)
|
||||||
missing_domain=lambda name: None)
|
|
||||||
|
|
||||||
def emit_commands(format):
|
def emit_commands(format):
|
||||||
commands = []
|
commands = []
|
||||||
|
|
4
nmigen/vendor/lattice_ecp5.py
vendored
4
nmigen/vendor/lattice_ecp5.py
vendored
|
@ -127,6 +127,10 @@ class LatticeECP5Platform(TemplatedPlatform):
|
||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def create_missing_domain(self, name):
|
||||||
|
# No additional reset logic needed.
|
||||||
|
return super().create_missing_domain(name)
|
||||||
|
|
||||||
_single_ended_io_types = [
|
_single_ended_io_types = [
|
||||||
"HSUL12", "LVCMOS12", "LVCMOS15", "LVCMOS18", "LVCMOS25", "LVCMOS33", "LVTTL33",
|
"HSUL12", "LVCMOS12", "LVCMOS15", "LVCMOS18", "LVCMOS25", "LVCMOS33", "LVTTL33",
|
||||||
"SSTL135_I", "SSTL135_II", "SSTL15_I", "SSTL15_II", "SSTL18_I", "SSTL18_II",
|
"SSTL135_I", "SSTL135_II", "SSTL15_I", "SSTL15_II", "SSTL18_I", "SSTL18_II",
|
||||||
|
|
40
nmigen/vendor/lattice_ice40.py
vendored
40
nmigen/vendor/lattice_ice40.py
vendored
|
@ -119,6 +119,46 @@ class LatticeICE40Platform(TemplatedPlatform):
|
||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def create_missing_domain(self, name):
|
||||||
|
# For unknown reasons (no errata was ever published, and no documentation mentions this
|
||||||
|
# issue), iCE40 BRAMs read as zeroes for ~3 us after configuration and release of internal
|
||||||
|
# global reset. Note that this is a *time-based* delay, generated purely by the internal
|
||||||
|
# oscillator, which may not be observed nor influenced directly. For details, see links:
|
||||||
|
# * https://github.com/cliffordwolf/icestorm/issues/76#issuecomment-289270411
|
||||||
|
# * https://github.com/cliffordwolf/icotools/issues/2#issuecomment-299734673
|
||||||
|
#
|
||||||
|
# To handle this, it is necessary to have a global reset in any iCE40 design that may
|
||||||
|
# potentially instantiate BRAMs, and assert this reset for >3 us after configuration.
|
||||||
|
# (We add a margin of 5x to allow for PVT variation.) If the board includes a dedicated
|
||||||
|
# reset line, this line is ORed with the power on reset.
|
||||||
|
#
|
||||||
|
# The power-on reset timer counts up because the vendor tools do not support initialization
|
||||||
|
# of flip-flops.
|
||||||
|
if name == "sync" and self.default_clk is not None:
|
||||||
|
clk_i = self.request(self.default_clk).i
|
||||||
|
if self.default_rst is not None:
|
||||||
|
rst_i = self.request(self.default_rst).i
|
||||||
|
|
||||||
|
m = Module()
|
||||||
|
# Power-on-reset domain
|
||||||
|
m.domains += ClockDomain("ice40_por", reset_less=True)
|
||||||
|
delay = int(15e-6 * self.default_clk_frequency)
|
||||||
|
timer = Signal(max=delay)
|
||||||
|
ready = Signal()
|
||||||
|
m.d.comb += ClockSignal("ice40_por").eq(clk_i)
|
||||||
|
with m.If(timer == delay):
|
||||||
|
m.d.ice40_por += ready.eq(1)
|
||||||
|
with m.Else():
|
||||||
|
m.d.ice40_por += timer.eq(timer + 1)
|
||||||
|
# Primary domain
|
||||||
|
m.domains += ClockDomain("sync")
|
||||||
|
m.d.comb += ClockSignal("sync").eq(clk_i)
|
||||||
|
if self.default_rst is not None:
|
||||||
|
m.d.comb += ResetSignal("sync").eq(~ready | rst_i)
|
||||||
|
else:
|
||||||
|
m.d.comb += ResetSignal("sync").eq(~ready)
|
||||||
|
return m
|
||||||
|
|
||||||
def should_skip_port_component(self, port, attrs, component):
|
def should_skip_port_component(self, port, attrs, component):
|
||||||
# On iCE40, a differential input is placed by only instantiating an SB_IO primitive for
|
# On iCE40, a differential input is placed by only instantiating an SB_IO primitive for
|
||||||
# the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs
|
# the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs
|
||||||
|
|
4
nmigen/vendor/xilinx_7series.py
vendored
4
nmigen/vendor/xilinx_7series.py
vendored
|
@ -122,6 +122,10 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
|
||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def create_missing_domain(self, name):
|
||||||
|
# No additional reset logic needed.
|
||||||
|
csuper().create_missing_domain(name)
|
||||||
|
|
||||||
def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
|
def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
|
||||||
def get_dff(clk, d, q):
|
def get_dff(clk, d, q):
|
||||||
# SDR I/O is performed by packing a flip-flop into the pad IOB.
|
# SDR I/O is performed by packing a flip-flop into the pad IOB.
|
||||||
|
|
36
nmigen/vendor/xilinx_spartan_3_6.py
vendored
36
nmigen/vendor/xilinx_spartan_3_6.py
vendored
|
@ -59,6 +59,23 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
|
||||||
package = abstractproperty()
|
package = abstractproperty()
|
||||||
speed = abstractproperty()
|
speed = abstractproperty()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def family(self):
|
||||||
|
device = self.device.upper()
|
||||||
|
if device.startswith("XC3S"):
|
||||||
|
if device.endswith("A"):
|
||||||
|
return "3A"
|
||||||
|
elif device.endswith("E"):
|
||||||
|
raise NotImplementedError("""Spartan 3E family is not supported
|
||||||
|
as a nMigen platform.""")
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("""Spartan 3 family is not supported
|
||||||
|
as a nMigen platform.""")
|
||||||
|
elif device.startswith("XC6S"):
|
||||||
|
return "6"
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
file_templates = {
|
file_templates = {
|
||||||
**TemplatedPlatform.build_script_templates,
|
**TemplatedPlatform.build_script_templates,
|
||||||
"{{name}}.v": r"""
|
"{{name}}.v": r"""
|
||||||
|
@ -142,22 +159,9 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
|
||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
def create_missing_domain(self, name):
|
||||||
def family(self):
|
# No additional reset logic needed.
|
||||||
device = self.device.upper()
|
return super().create_missing_domain(name)
|
||||||
if device.startswith("XC3S"):
|
|
||||||
if device.endswith("A"):
|
|
||||||
return "3A"
|
|
||||||
elif device.endswith("E"):
|
|
||||||
raise NotImplementedError("""Spartan 3E family is not supported
|
|
||||||
as a nMigen platform.""")
|
|
||||||
else:
|
|
||||||
raise NotImplementedError("""Spartan 3 family is not supported
|
|
||||||
as a nMigen platform.""")
|
|
||||||
elif device.startswith("XC6S"):
|
|
||||||
return "6"
|
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
|
|
||||||
def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
|
def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
|
||||||
def get_dff(clk, d, q):
|
def get_dff(clk, d, q):
|
||||||
|
|
Loading…
Reference in a new issue