But only if it is not defined by the programmer.
Closes #57.
from .. import __version__
from ..hdl.ast import *
+from ..hdl.cd import *
from ..hdl.dsl import *
from ..hdl.ir import *
from ..back import rtlil, verilog
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):
assert not self._prepared
self._prepared = True
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):
pin_fragment = Fragment.get(pin_fragment, self)
autogenerated = "Automatically generated by nMigen {}. Do not edit.".format(__version__)
def emit_design(backend):
- return {"rtlil": rtlil, "verilog": verilog}[backend].convert(
- fragment, name=name, platform=self, ports=list(self.iter_ports()),
- missing_domain=lambda name: None)
+ return {"rtlil": rtlil, "verilog": verilog}[backend].convert(fragment, name=name,
+ ports=list(self.iter_ports()), missing_domain=lambda name: None)
def emit_commands(format):
commands = []
"""
]
+ def create_missing_domain(self, name):
+ # No additional reset logic needed.
+ return super().create_missing_domain(name)
+
_single_ended_io_types = [
"HSUL12", "LVCMOS12", "LVCMOS15", "LVCMOS18", "LVCMOS25", "LVCMOS33", "LVTTL33",
"SSTL135_I", "SSTL135_II", "SSTL15_I", "SSTL15_II", "SSTL18_I", "SSTL18_II",
"""
]
+ 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):
# 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
"""
]
+ 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_dff(clk, d, q):
# SDR I/O is performed by packing a flip-flop into the pad IOB.
package = 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 = {
**TemplatedPlatform.build_script_templates,
"{{name}}.v": r"""
"""
]
- @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
+ def create_missing_domain(self, name):
+ # No additional reset logic needed.
+ return super().create_missing_domain(name)
def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None):
def get_dff(clk, d, q):