Skip to content

Commit

Permalink
replace synthesis pseudo-comments with V2001 attributes
Browse files Browse the repository at this point in the history
sbourdeauducq committed Oct 29, 2016
1 parent 160cf5f commit a361611
Showing 11 changed files with 68 additions and 92 deletions.
7 changes: 0 additions & 7 deletions doc/fhdl.rst
Original file line number Diff line number Diff line change
@@ -219,13 +219,6 @@ Options to ``get_port`` are:

Migen generates behavioural V*HDL code that should be compatible with all simulators and, if the number of ports is <= 2, most FPGA synthesizers. If a specific code is needed, the memory handler can be overriden using the appropriate parameter of the V*HDL conversion function.

Inline synthesis directives
===========================

Inline synthesis directives (pseudo-comments such as ``// synthesis attribute keep of clock_signal_name is true``) are supported using the ``SynthesisDirective`` object. Its constructor takes as parameters a string containing the body of the directive, and optional keyword parameters that are used to replace signal names similarly to the Python string method ``format``. The above example could be represented as follows: ::

SynthesisDirective("attribute keep of {clksig} is true", clksig=clock_domain.clk)

Modules
*******

21 changes: 5 additions & 16 deletions examples/basic/psync.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
from migen import *
from migen.fhdl.specials import SynthesisDirective
from migen.build.xilinx.common import XilinxMultiReg
from migen.build.xilinx.vivado import XilinxVivadoToolchain
from migen.fhdl import verilog
from migen.genlib.cdc import *


class XilinxMultiRegImpl(MultiRegImpl):
def __init__(self, *args, **kwargs):
MultiRegImpl.__init__(self, *args, **kwargs)
self.specials += set(SynthesisDirective("attribute shreg_extract of {r} is no", r=r)
for r in self.regs)


class XilinxMultiReg:
@staticmethod
def lower(dr):
return XilinxMultiRegImpl(dr.i, dr.o, dr.odomain, dr.n)


if __name__ == "__main__":
ps = PulseSynchronizer("from", "to")
v = verilog.convert(ps, {ps.i, ps.o}, special_overrides={MultiReg: XilinxMultiReg})
v = verilog.convert(ps, {ps.i, ps.o},
special_overrides={MultiReg: XilinxMultiReg},
attr_translate=XilinxVivadoToolchain.attr_translate)
print(v)
20 changes: 5 additions & 15 deletions migen/build/xilinx/common.py
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@
from migen.fhdl.structure import *
from migen.fhdl.specials import Instance
from migen.fhdl.module import Module
from migen.fhdl.specials import SynthesisDirective
from migen.genlib.cdc import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.io import *
@@ -61,22 +60,12 @@ def settings(path, ver=None, sub=None):
raise OSError("no Xilinx tools settings file found")


class XilinxNoRetimingImpl(Module):
def __init__(self, reg):
self.specials += SynthesisDirective("attribute register_balancing of {r} is no", r=reg)


class XilinxNoRetiming:
@staticmethod
def lower(dr):
return XilinxNoRetimingImpl(dr.reg)


class XilinxMultiRegImpl(MultiRegImpl):
def __init__(self, *args, **kwargs):
MultiRegImpl.__init__(self, *args, **kwargs)
self.specials += [SynthesisDirective("attribute shreg_extract of {r} is no", r=r)
for r in self.regs]
for r in self.regs:
r.attr.add("async_reg")
r.attr.add("no_shreg_extract")


class XilinxMultiReg:
@@ -94,6 +83,8 @@ def __init__(self, cd, async_reset):
Instance("FDPE", p_INIT=1, i_D=rst1, i_PRE=async_reset,
i_CE=1, i_C=cd.clk, o_Q=cd.rst)
]
rst1.attr.add("async_reg")
cd.rst.attr.add("async_reg")


class XilinxAsyncResetSynchronizer:
@@ -140,7 +131,6 @@ def lower(dr):


xilinx_special_overrides = {
NoRetiming: XilinxNoRetiming,
MultiReg: XilinxMultiReg,
AsyncResetSynchronizer: XilinxAsyncResetSynchronizer,
DifferentialInput: XilinxDifferentialInput,
7 changes: 7 additions & 0 deletions migen/build/xilinx/ise.py
Original file line number Diff line number Diff line change
@@ -125,6 +125,13 @@ def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt,


class XilinxISEToolchain:
attr_translate = {
"keep": ("keep", "true"),
"no_retiming": ("register_balancing", "no"),
"async_reg": None,
"no_shreg_extract": ("shreg_extract", "no")
}

def __init__(self):
self.xst_opt = """-ifmt MIXED
-use_new_parser yes
6 changes: 2 additions & 4 deletions migen/build/xilinx/platform.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from migen.fhdl.specials import Keep
from migen.build.generic_platform import GenericPlatform
from migen.build.xilinx import common, vivado, ise

@@ -19,10 +18,9 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs):
so = dict(common.xilinx_special_overrides)
if self.device[:3] == "xc7":
so.update(common.xilinx_s7_special_overrides)
if isinstance(self.toolchain, vivado.XilinxVivadoToolchain):
so[Keep] = vivado.VivadoKeep
so.update(special_overrides)
return GenericPlatform.get_verilog(self, *args, special_overrides=so, **kwargs)
return GenericPlatform.get_verilog(self, *args,
special_overrides=so, attr_translate=self.toolchain.attr_translate, **kwargs)

def get_edif(self, fragment, **kwargs):
return GenericPlatform.get_edif(self, fragment, "UNISIMS", "Xilinx", self.device, **kwargs)
15 changes: 7 additions & 8 deletions migen/build/xilinx/vivado.py
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@
import sys

from migen.fhdl.structure import _Fragment
from migen.fhdl.specials import SynthesisDirective
from migen.build.generic_platform import *
from migen.build import tools
from migen.build.xilinx import common
@@ -71,14 +70,14 @@ def _run_vivado(build_name, vivado_path, source, ver=None):
raise OSError("Subprocess failed")


class VivadoKeep:
@staticmethod
def emit_verilog(directive, ns, add_data_file):
sig_name = ns.get_name(directive.signals["s"])
return "// synthesis attribute dont_touch of " + sig_name + " is true\n"


class XilinxVivadoToolchain:
attr_translate = {
"keep": ("dont_touch", "true"),
"no_retiming": ("dont_touch", "true"),
"async_reg": ("async_reg", "true"),
"no_shreg_extract": None
}

def __init__(self):
self.bitstream_commands = []
self.additional_commands = []
18 changes: 0 additions & 18 deletions migen/fhdl/specials.py
Original file line number Diff line number Diff line change
@@ -345,21 +345,3 @@ def gn(e):
r += "end\n\n"

return r


class SynthesisDirective(Special):
def __init__(self, template, **signals):
Special.__init__(self)
self.template = template
self.signals = signals

@staticmethod
def emit_verilog(directive, ns, add_data_file):
name_dict = dict((k, ns.get_name(sig)) for k, sig in directive.signals.items())
formatted = directive.template.format(**name_dict)
return "// synthesis " + formatted + "\n"


class Keep(SynthesisDirective):
def __init__(self, signal):
SynthesisDirective.__init__(self, "attribute keep of {s} is true", s=signal)
6 changes: 5 additions & 1 deletion migen/fhdl/structure.py
Original file line number Diff line number Diff line change
@@ -310,8 +310,9 @@ class Signal(_Value):
determined by the integer range given by `min` (inclusive,
defaults to 0) and `max` (exclusive, defaults to 2).
related : Signal or None
attr : set of synthesis attributes
"""
def __init__(self, bits_sign=None, name=None, variable=False, reset=0, name_override=None, min=None, max=None, related=None):
def __init__(self, bits_sign=None, name=None, variable=False, reset=0, name_override=None, min=None, max=None, related=None, attr=None):
from migen.fhdl.bitcontainer import bits_for

_Value.__init__(self)
@@ -334,12 +335,15 @@ def __init__(self, bits_sign=None, name=None, variable=False, reset=0, name_over
self.nbits, self.signed = bits_sign, False
if not isinstance(self.nbits, int) or self.nbits <= 0:
raise ValueError("Signal width must be a strictly positive integer")
if attr is None:
attr = set()

self.variable = variable # deprecated
self.reset = reset
self.name_override = name_override
self.backtrace = _tracer.trace_back(name)
self.related = related
self.attr = attr

def __setattr__(self, k, v):
if k == "reset":
32 changes: 30 additions & 2 deletions migen/fhdl/verilog.py
Original file line number Diff line number Diff line change
@@ -165,8 +165,29 @@ def _list_comb_wires(f):
r |= g[0]
return r

def _printattr(sig, attr_translate):
r = ""
firsta = True
for attr in sig.attr:
if isinstance(attr, tuple):
# platform-dependent attribute
attr_name, attr_value = attr
else:
# translated attribute
at = attr_translate[attr]
if at is None:
continue
attr_name, attr_value = at
if not firsta:
r += ", "
firsta = False
r += attr_name + " = \"" + attr_value + "\""
if r:
r = "(* " + r + " *)"
return r


def _printheader(f, ios, name, ns,
def _printheader(f, ios, name, ns, attr_translate,
reg_initialization):
sigs = list_signals(f) | list_special_ios(f, True, True, True)
special_outs = list_special_ios(f, False, True, True)
@@ -179,6 +200,9 @@ def _printheader(f, ios, name, ns,
if not firstp:
r += ",\n"
firstp = False
attr = _printattr(sig, attr_translate)
if attr:
r += "\t" + attr
if sig in inouts:
r += "\tinout " + _printsig(ns, sig)
elif sig in targets:
@@ -190,6 +214,9 @@ def _printheader(f, ios, name, ns,
r += "\tinput " + _printsig(ns, sig)
r += "\n);\n\n"
for sig in sorted(sigs - ios, key=lambda x: x.duid):
attr = _printattr(sig, attr_translate)
if attr:
r += attr + " "
if sig in wires:
r += "wire " + _printsig(ns, sig) + ";\n"
else:
@@ -271,6 +298,7 @@ def _printspecials(overrides, specials, ns, add_data_file):

def convert(f, ios=None, name="top",
special_overrides=dict(),
attr_translate=dict(),
create_clock_domains=True,
display_run=False, asic_syntax=False):
r = ConvOutput()
@@ -308,7 +336,7 @@ def convert(f, ios=None, name="top",
r.ns = ns

src = "/* Machine-generated using Migen */\n"
src += _printheader(f, ios, name, ns,
src += _printheader(f, ios, name, ns, attr_translate,
reg_initialization=not asic_syntax)
src += _printcomb(f, ns,
display_run=display_run,
14 changes: 2 additions & 12 deletions migen/genlib/cdc.py
Original file line number Diff line number Diff line change
@@ -10,17 +10,6 @@
from migen.genlib.resetsync import AsyncResetSynchronizer


class NoRetiming(Special):
def __init__(self, reg):
Special.__init__(self)
self.reg = reg

# do nothing
@staticmethod
def lower(dr):
return Module()


class MultiRegImpl(Module):
def __init__(self, i, o, odomain, n):
self.i = i
@@ -38,7 +27,8 @@ def __init__(self, i, o, odomain, n):
sd += reg.eq(src)
src = reg
self.comb += self.o.eq(src)
self.specials += [NoRetiming(reg) for reg in self.regs]
for reg in self.regs:
reg.attr.add("no_retiming")


class MultiReg(Special):
14 changes: 5 additions & 9 deletions migen/genlib/fifo.py
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
from migen.fhdl.specials import Memory
from migen.fhdl.bitcontainer import log2_int
from migen.fhdl.decorators import ClockDomainsRenamer
from migen.genlib.cdc import NoRetiming, MultiReg, GrayCounter
from migen.genlib.cdc import MultiReg, GrayCounter


def _inc(signal, modulo):
@@ -177,15 +177,11 @@ def __init__(self, width, depth):
]

produce_rdomain = Signal(depth_bits+1)
self.specials += [
NoRetiming(produce.q),
MultiReg(produce.q, produce_rdomain, "read")
]
produce.q.attr.add("no_retiming")
self.specials += MultiReg(produce.q, produce_rdomain, "read")
consume_wdomain = Signal(depth_bits+1)
self.specials += [
NoRetiming(consume.q),
MultiReg(consume.q, consume_wdomain, "write")
]
consume.q.attr.add("no_retiming")
self.specials += MultiReg(consume.q, consume_wdomain, "write")
if depth_bits == 1:
self.comb += self.writable.eq((produce.q[-1] == consume_wdomain[-1])
| (produce.q[-2] == consume_wdomain[-2]))

0 comments on commit a361611

Please sign in to comment.