fhdl/structure: introduce Constant, autowrap for eq/ops, fix Signal as dictionary key problem

This commit is contained in:
Sebastien Bourdeauducq 2015-09-15 12:38:02 +08:00
parent 42afba2bbc
commit e940c6d9b9
7 changed files with 224 additions and 108 deletions

View file

@ -27,11 +27,7 @@ def bits_for(n, require_sign_bit=False):
def value_bits_sign(v): def value_bits_sign(v):
if isinstance(v, bool): if isinstance(v, (f.Constant, f.Signal)):
return 1, False
elif isinstance(v, int):
return bits_for(v), v < 0
elif isinstance(v, f.Signal):
return v.nbits, v.signed return v.nbits, v.signed
elif isinstance(v, (f.ClockSignal, f.ResetSignal)): elif isinstance(v, (f.ClockSignal, f.ResetSignal)):
return 1, False return 1, False

View file

@ -158,16 +158,16 @@ def _build_pnd_for_group(group_n, signals):
if _debug: if _debug:
print("namer: using basic strategy (group {0})".format(group_n)) print("namer: using basic strategy (group {0})".format(group_n))
# ...then add number suffixes by HUID # ...then add number suffixes by DUID
inv_pnd = _invert_pnd(pnd) inv_pnd = _invert_pnd(pnd)
huid_suffixed = False duid_suffixed = False
for name, signals in inv_pnd.items(): for name, signals in inv_pnd.items():
if len(signals) > 1: if len(signals) > 1:
huid_suffixed = True duid_suffixed = True
for n, signal in enumerate(sorted(signals, key=lambda x: x.huid)): for n, signal in enumerate(sorted(signals, key=lambda x: x.duid)):
pnd[signal] += str(n) pnd[signal] += str(n)
if _debug and huid_suffixed: if _debug and duid_suffixed:
print("namer: using HUID suffixes (group {0})".format(group_n)) print("namer: using DUID suffixes (group {0})".format(group_n))
return pnd return pnd

View file

@ -1,6 +1,7 @@
from operator import itemgetter from operator import itemgetter
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.structure import _DUID
from migen.fhdl.bitcontainer import bits_for, value_bits_sign from migen.fhdl.bitcontainer import bits_for, value_bits_sign
from migen.fhdl.tools import * from migen.fhdl.tools import *
from migen.fhdl.tracer import get_obj_var_name from migen.fhdl.tracer import get_obj_var_name
@ -11,7 +12,7 @@ __all__ = ["TSTriple", "Instance", "Memory",
"READ_FIRST", "WRITE_FIRST", "NO_CHANGE"] "READ_FIRST", "WRITE_FIRST", "NO_CHANGE"]
class Special(HUID): class Special(_DUID):
def iter_expressions(self): def iter_expressions(self):
for x in []: for x in []:
yield x yield x

View file

@ -1,24 +1,22 @@
import builtins import builtins
from collections import defaultdict from collections import defaultdict, Iterable
from migen.fhdl import tracer from migen.fhdl import tracer
from migen.util.misc import flat_iteration from migen.util.misc import flat_iteration
class HUID: class _DUID:
"""Deterministic Unique IDentifier"""
__next_uid = 0 __next_uid = 0
def __init__(self): def __init__(self):
self.huid = HUID.__next_uid self.duid = _DUID.__next_uid
HUID.__next_uid += 1 _DUID.__next_uid += 1
def __hash__(self):
return self.huid
class Value(HUID): class _Value(_DUID):
"""Base class for operands """Base class for operands
Instances of `Value` or its subclasses can be operands to Instances of `_Value` or its subclasses can be operands to
arithmetic, comparison, bitwise, and logic operators. arithmetic, comparison, bitwise, and logic operators.
They can be assigned (:meth:`eq`) or indexed/sliced (using the usual They can be assigned (:meth:`eq`) or indexed/sliced (using the usual
Python indexing and slicing notation). Python indexing and slicing notation).
@ -27,7 +25,18 @@ class Value(HUID):
represent the integer. represent the integer.
""" """
def __bool__(self): def __bool__(self):
raise NotImplementedError("For boolean operations between expressions: use '&'/'|' instead of 'and'/'or'") # Special case: Constants and Signals are part of a set or used as
# dictionary keys, and Python needs to check for equality.
if isinstance(self, _Operator) and self.op == "==":
a, b = self.operands
if isinstance(a, Constant) and isinstance(b, Constant):
return a.value == b.value
if isinstance(a, Signal) and isinstance(b, Signal):
return a is b
if (isinstance(a, Constant) and isinstance(b, Signal)
or isinstance(a, Signal) and isinstance(a, Constant)):
return False
raise TypeError("Attempted to convert Migen value to boolean")
def __invert__(self): def __invert__(self):
return _Operator("~", [self]) return _Operator("~", [self])
@ -104,7 +113,7 @@ class Value(HUID):
Parameters Parameters
---------- ----------
r : Value, in r : _Value, in
Value to be assigned. Value to be assigned.
Returns Returns
@ -116,14 +125,20 @@ class Value(HUID):
return _Assign(self, r) return _Assign(self, r)
def __hash__(self): def __hash__(self):
return HUID.__hash__(self) raise TypeError("unhashable type: '{}'".format(type(self).__name__))
class _Operator(Value): class _Operator(_Value):
def __init__(self, op, operands): def __init__(self, op, operands):
Value.__init__(self) _Value.__init__(self)
self.op = op self.op = op
self.operands = operands self.operands = []
for o in operands:
if isinstance(o, (bool, int)):
o = Constant(o)
if not isinstance(o, _Value):
raise TypeError("Operand not a Migen value")
self.operands.append(o)
def Mux(sel, val1, val0): def Mux(sel, val1, val0):
@ -131,33 +146,39 @@ def Mux(sel, val1, val0):
Parameters Parameters
---------- ----------
sel : Value(1), in sel : _Value(1), in
Selector. Selector.
val1 : Value(N), in val1 : _Value(N), in
val0 : Value(N), in val0 : _Value(N), in
Input values. Input values.
Returns Returns
------- -------
Value(N), out _Value(N), out
Output `Value`. If `sel` is asserted, the Mux returns Output `_Value`. If `sel` is asserted, the Mux returns
`val1`, else `val0`. `val1`, else `val0`.
""" """
return _Operator("m", [sel, val1, val0]) return _Operator("m", [sel, val1, val0])
class _Slice(Value): class _Slice(_Value):
def __init__(self, value, start, stop): def __init__(self, value, start, stop):
Value.__init__(self) _Value.__init__(self)
if isinstance(value, (bool, int)):
value = Constant(value)
if not isinstance(value, _Value):
raise TypeError("Sliced object is not a Migen value")
if not isinstance(start, int) or not isinstance(stop, int):
raise TypeError("Slice boundaries must be integers")
self.value = value self.value = value
self.start = start self.start = start
self.stop = stop self.stop = stop
class Cat(Value): class Cat(_Value):
"""Concatenate values """Concatenate values
Form a compound `Value` from several smaller ones by concatenation. Form a compound `_Value` from several smaller ones by concatenation.
The first argument occupies the lower bits of the result. The first argument occupies the lower bits of the result.
The return value can be used on either side of an assignment, that The return value can be used on either side of an assignment, that
is, the concatenated value can be used as an argument on the RHS or is, the concatenated value can be used as an argument on the RHS or
@ -170,20 +191,26 @@ class Cat(Value):
Parameters Parameters
---------- ----------
*args : Values or iterables of Values, inout *args : _Values or iterables of _Values, inout
`Value` s to be concatenated. `_Value` s to be concatenated.
Returns Returns
------- -------
Cat, inout Cat, inout
Resulting `Value` obtained by concatentation. Resulting `_Value` obtained by concatentation.
""" """
def __init__(self, *args): def __init__(self, *args):
Value.__init__(self) _Value.__init__(self)
self.l = list(flat_iteration(args)) self.l = []
for v in flat_iteration(args):
if isinstance(v, (bool, int)):
v = Constant(v)
if not isinstance(v, _Value):
raise TypeError("Concatenated object is not a Migen value")
self.l.append(v)
class Replicate(Value): class Replicate(_Value):
"""Replicate a value """Replicate a value
An input value is replicated (repeated) several times An input value is replicated (repeated) several times
@ -193,7 +220,7 @@ class Replicate(Value):
Parameters Parameters
---------- ----------
v : Value, in v : _Value, in
Input value to be replicated. Input value to be replicated.
n : int n : int
Number of replications. Number of replications.
@ -204,13 +231,52 @@ class Replicate(Value):
Replicated value. Replicated value.
""" """
def __init__(self, v, n): def __init__(self, v, n):
Value.__init__(self) _Value.__init__(self)
if isinstance(v, (bool, int)):
v = Constant(v)
if not isinstance(v, _Value):
raise TypeError("Replicated object is not a Migen value")
if not isinstance(n, int) or n < 0:
raise TypeError("Replication count must be a positive integer")
self.v = v self.v = v
self.n = n self.n = n
class Signal(Value): class Constant(_Value):
"""A `Value` that can change """A constant, HDL-literal integer `_Value`
Parameters
----------
value : int
bits_sign : int or tuple or None
Either an integer `bits` or a tuple `(bits, signed)`
specifying the number of bits in this `Constant` and whether it is
signed (can represent negative values). `bits_sign` defaults
to the minimum width and signedness of `value`.
"""
def __init__(self, value, bits_sign=None):
from migen.fhdl.bitcontainer import bits_for
_Value.__init__(self)
self.value = int(value)
if bits_sign is None:
bits_sign = bits_for(self.value), self.value < 0
elif isinstance(bits_sign, int):
bits_sign = bits_sign, self.value < 0
self.nbits, self.signed = bits_sign
if not isinstance(self.nbits, int) or self.nbits <= 0:
raise TypeError("Width must be a strictly positive integer")
def __hash__(self):
return self.value
C = Constant # shorthand
class Signal(_Value):
"""A `_Value` that can change
The `Signal` object represents a value that is expected to change The `Signal` object represents a value that is expected to change
in the circuit. It does exactly what Verilog's `wire` and in the circuit. It does exactly what Verilog's `wire` and
@ -219,7 +285,7 @@ class Signal(Value):
A `Signal` can be indexed to access a subset of its bits. Negative A `Signal` can be indexed to access a subset of its bits. Negative
indices (`signal[-1]`) and the extended Python slicing notation indices (`signal[-1]`) and the extended Python slicing notation
(`signal[start:stop:step]`) are supported. (`signal[start:stop:step]`) are supported.
The indeces 0 and -1 are the least and most significant bits The indices 0 and -1 are the least and most significant bits
respectively. respectively.
Parameters Parameters
@ -256,7 +322,7 @@ class Signal(Value):
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):
from migen.fhdl.bitcontainer import bits_for from migen.fhdl.bitcontainer import bits_for
Value.__init__(self) _Value.__init__(self)
# determine number of bits and signedness # determine number of bits and signedness
if bits_sign is None: if bits_sign is None:
@ -283,6 +349,12 @@ class Signal(Value):
self.backtrace = tracer.trace_back(name) self.backtrace = tracer.trace_back(name)
self.related = related self.related = related
def __setattr__(self, k, v):
if k == "reset":
if isinstance(v, (bool, int)):
v = Constant(v)
_Value.__setattr__(self, k, v)
def __repr__(self): def __repr__(self):
return "<Signal " + (self.backtrace[-1][0] or "anonymous") + " at " + hex(id(self)) + ">" return "<Signal " + (self.backtrace[-1][0] or "anonymous") + " at " + hex(id(self)) + ">"
@ -292,7 +364,7 @@ class Signal(Value):
Parameters Parameters
---------- ----------
other : Value other : _Value
Object to base this Signal on. Object to base this Signal on.
See `migen.fhdl.bitcontainer.value_bits_sign`() for details. See `migen.fhdl.bitcontainer.value_bits_sign`() for details.
@ -300,8 +372,11 @@ class Signal(Value):
from migen.fhdl.bitcontainer import value_bits_sign from migen.fhdl.bitcontainer import value_bits_sign
return cls(bits_sign=value_bits_sign(other), **kwargs) return cls(bits_sign=value_bits_sign(other), **kwargs)
def __hash__(self):
return self.duid
class ClockSignal(Value):
class ClockSignal(_Value):
"""Clock signal for a given clock domain """Clock signal for a given clock domain
`ClockSignal` s for a given clock domain can be retrieved multiple `ClockSignal` s for a given clock domain can be retrieved multiple
@ -313,11 +388,11 @@ class ClockSignal(Value):
Clock domain to obtain a clock signal for. Defaults to `"sys"`. Clock domain to obtain a clock signal for. Defaults to `"sys"`.
""" """
def __init__(self, cd="sys"): def __init__(self, cd="sys"):
Value.__init__(self) _Value.__init__(self)
self.cd = cd self.cd = cd
class ResetSignal(Value): class ResetSignal(_Value):
"""Reset signal for a given clock domain """Reset signal for a given clock domain
`ResetSignal` s for a given clock domain can be retrieved multiple `ResetSignal` s for a given clock domain can be retrieved multiple
@ -332,25 +407,43 @@ class ResetSignal(Value):
error. error.
""" """
def __init__(self, cd="sys", allow_reset_less=False): def __init__(self, cd="sys", allow_reset_less=False):
Value.__init__(self) _Value.__init__(self)
self.cd = cd self.cd = cd
self.allow_reset_less = allow_reset_less self.allow_reset_less = allow_reset_less
# statements # statements
class _Assign: class _Statement:
pass
class _Assign(_Statement):
def __init__(self, l, r): def __init__(self, l, r):
if not isinstance(l, _Value):
raise TypeError("LHS of assignment is not a Migen value")
if isinstance(r, (bool, int)):
r = Constant(r)
if not isinstance(r, _Value):
raise TypeError("RHS of assignment is not a Migen value")
self.l = l self.l = l
self.r = r self.r = r
class If: def _check_statement(s):
if isinstance(s, Iterable):
return all(_check_statement(ss) for ss in s)
else:
return isinstance(s, _Statement)
class If(_Statement):
"""Conditional execution of statements """Conditional execution of statements
Parameters Parameters
---------- ----------
cond : Value(1), in cond : _Value(1), in
Condition Condition
*t : Statements *t : Statements
Statements to execute if `cond` is asserted. Statements to execute if `cond` is asserted.
@ -370,6 +463,12 @@ class If:
... ) ... )
""" """
def __init__(self, cond, *t): def __init__(self, cond, *t):
if isinstance(cond, (bool, int)):
cond = Constant(cond)
if not isinstance(cond, _Value):
raise TypeError("Test condition is not a Migen value")
if not _check_statement(t):
raise TypeError("Not all test body objects are Migen statements")
self.cond = cond self.cond = cond
self.t = list(t) self.t = list(t)
self.f = [] self.f = []
@ -382,6 +481,8 @@ class If:
*f : Statements *f : Statements
Statements to execute if all previous conditions fail. Statements to execute if all previous conditions fail.
""" """
if not _check_statement(f):
raise TypeError("Not all test body objects are Migen statements")
_insert_else(self, list(f)) _insert_else(self, list(f))
return self return self
@ -390,7 +491,7 @@ class If:
Parameters Parameters
---------- ----------
cond : Value(1), in cond : _Value(1), in
Condition Condition
*t : Statements *t : Statements
Statements to execute if previous conditions fail and `cond` Statements to execute if previous conditions fail and `cond`
@ -409,12 +510,12 @@ def _insert_else(obj, clause):
o.f = clause o.f = clause
class Case: class Case(_Statement):
"""Case/Switch statement """Case/Switch statement
Parameters Parameters
---------- ----------
test : Value, in test : _Value, in
Selector value used to decide which block to execute Selector value used to decide which block to execute
cases : dict cases : dict
Dictionary of cases. The keys are numeric constants to compare Dictionary of cases. The keys are numeric constants to compare
@ -434,13 +535,27 @@ class Case:
... }) ... })
""" """
def __init__(self, test, cases): def __init__(self, test, cases):
if isinstance(test, (bool, int)):
test = Constant(test)
if not isinstance(test, _Value):
raise TypeError("Case test object is not a Migen value")
self.test = test self.test = test
self.cases = cases self.cases = dict()
for k, v in cases.items():
if isinstance(k, (bool, int)):
k = Constant(k)
if (not isinstance(k, Constant)
and not (isinstance(k, str) and k == "default")):
raise TypeError("Case object is not a Migen constant")
if not _check_statement(v):
raise TypeError("Not all objects for case {} "
"are Migen statements".format(k))
self.cases[k] = v
def makedefault(self, key=None): def makedefault(self, key=None):
"""Mark a key as the default case """Mark a key as the default case
Deletes/Substitutes any previously existing default case. Deletes/substitutes any previously existing default case.
Parameters Parameters
---------- ----------
@ -450,18 +565,26 @@ class Case:
""" """
if key is None: if key is None:
for choice in self.cases.keys(): for choice in self.cases.keys():
if key is None or choice > key: if key is None or choice.value > key.value:
key = choice key = choice
self.cases["default"] = self.cases[key] self.cases["default"] = self.cases[key]
del self.cases[key] del self.cases[key]
return self return self
# arrays # arrays
class _ArrayProxy(Value): class _ArrayProxy(_Value):
def __init__(self, choices, key): def __init__(self, choices, key):
self.choices = choices self.choices = []
for c in choices:
if isinstance(c, (bool, int)):
c = Constant(c)
if not isinstance(c, (_Value, Array)):
raise TypeError("Array element is not a Migen value: {}"
.format(c))
self.choices.append(c)
self.key = key self.key = key
def __getattr__(self, attr): def __getattr__(self, attr):
@ -478,7 +601,7 @@ class Array(list):
An array is created from an iterable of values and indexed using the An array is created from an iterable of values and indexed using the
usual Python simple indexing notation (no negative indices or usual Python simple indexing notation (no negative indices or
slices). It can be indexed by numeric constants, `Value` s, or slices). It can be indexed by numeric constants, `_Value` s, or
`Signal` s. `Signal` s.
The result of indexing the array is a proxy for the entry at the The result of indexing the array is a proxy for the entry at the
@ -491,7 +614,7 @@ class Array(list):
Parameters Parameters
---------- ----------
values : iterable of ints, Values, Signals values : iterable of ints, _Values, Signals
Entries of the array. Each entry can be a numeric constant, a Entries of the array. Each entry can be a numeric constant, a
`Signal` or a `Record`. `Signal` or a `Record`.
@ -503,7 +626,9 @@ class Array(list):
>>> b.eq(a[9 - c]) >>> b.eq(a[9 - c])
""" """
def __getitem__(self, key): def __getitem__(self, key):
if isinstance(key, Value): if isinstance(key, Constant):
return list.__getitem__(self, key.value)
elif isinstance(key, _Value):
return _ArrayProxy(self, key) return _ArrayProxy(self, key)
else: else:
return list.__getitem__(self, key) return list.__getitem__(self, key)
@ -569,6 +694,7 @@ class _ClockDomainList(list):
else: else:
return list.__getitem__(self, key) return list.__getitem__(self, key)
(SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3) (SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3)

View file

@ -143,7 +143,7 @@ def is_variable(node):
def generate_reset(rst, sl): def generate_reset(rst, sl):
targets = list_targets(sl) targets = list_targets(sl)
return [t.eq(t.reset) for t in sorted(targets, key=lambda x: x.huid)] return [t.eq(t.reset) for t in sorted(targets, key=lambda x: x.duid)]
def insert_reset(rst, sl): def insert_reset(rst, sl):

View file

@ -10,23 +10,24 @@ from migen.fhdl.conv_output import ConvOutput
_reserved_keywords = { _reserved_keywords = {
"always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1", "always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1",
"case", "casex", "casez", "cell", "cmos", "config", "deassign", "default", "case", "casex", "casez", "cell", "cmos", "config", "deassign", "default",
"defparam", "design", "disable", "edge", "else", "end", "endcase", "endconfig", "defparam", "design", "disable", "edge", "else", "end", "endcase",
"endfunction", "endgenerate", "endmodule", "endprimitive", "endspecify", "endconfig", "endfunction", "endgenerate", "endmodule", "endprimitive",
"endtable", "endtask", "event", "for", "force", "forever", "fork", "function", "endspecify", "endtable", "endtask", "event", "for", "force", "forever",
"generate", "genvar", "highz0", "highz1", "if", "ifnone", "incdir", "include", "fork", "function", "generate", "genvar", "highz0", "highz1", "if",
"initial", "inout", "input", "instance", "integer", "join", "large", "liblist", "ifnone", "incdir", "include", "initial", "inout", "input",
"library", "localparam", "macromodule", "medium", "module", "nand", "negedge", "instance", "integer", "join", "large", "liblist", "library", "localparam",
"nmos", "nor", "noshowcancelled", "not", "notif0", "notif1", "or", "output", "macromodule", "medium", "module", "nand", "negedge", "nmos", "nor",
"parameter", "pmos", "posedge", "primitive", "pull0", "pull1" "pulldown" "noshowcancelled", "not", "notif0", "notif1", "or", "output", "parameter",
"pullup","pulsestyle_onevent", "pulsestyle_ondetect", "remos", "real", "pmos", "posedge", "primitive", "pull0", "pull1" "pulldown",
"realtime", "reg", "release", "repeat", "rnmos", "rpmos", "rtran", "rtranif0", "pullup", "pulsestyle_onevent", "pulsestyle_ondetect", "remos", "real",
"rtranif1", "scalared", "showcancelled", "signed", "small", "specify", "realtime", "reg", "release", "repeat", "rnmos", "rpmos", "rtran",
"specparam", "strong0", "strong1", "supply0", "supply1", "table", "task", "rtranif0", "rtranif1", "scalared", "showcancelled", "signed", "small",
"time", "tran", "tranif0", "tranif1", "tri", "tri0", "tri1", "triand", "specify", "specparam", "strong0", "strong1", "supply0", "supply1",
"trior", "trireg", "unsigned", "use", "vectored", "wait", "wand", "weak0", "table", "task", "time", "tran", "tranif0", "tranif1", "tri", "tri0",
"weak1", "while", "wire", "wor","xnor","xor" "tri1", "triand", "trior", "trireg", "unsigned", "use", "vectored", "wait",
"wand", "weak0", "weak1", "while", "wire", "wor","xnor", "xor"
} }
@ -41,25 +42,17 @@ def _printsig(ns, s):
return n return n
def _printintbool(node): def _printconstant(node):
if isinstance(node, bool): if node.signed:
if node: return (str(node.nbits) + "'sd" + str(2**node.nbits + node.value),
return "1'd1", False True)
else:
return "1'd0", False
elif isinstance(node, int):
nbits = bits_for(node)
if node >= 0:
return str(nbits) + "'d" + str(node), False
else:
return str(nbits) + "'sd" + str(2**nbits + node), True
else: else:
raise TypeError return str(node.nbits) + "'d" + str(node.value), False
def _printexpr(ns, node): def _printexpr(ns, node):
if isinstance(node, (int, bool)): if isinstance(node, Constant):
return _printintbool(node) return _printconstant(node)
elif isinstance(node, Signal): elif isinstance(node, Signal):
return ns.get_name(node), node.signed return ns.get_name(node), node.signed
elif isinstance(node, _Operator): elif isinstance(node, _Operator):
@ -116,7 +109,7 @@ def _printexpr(ns, node):
elif isinstance(node, Replicate): elif isinstance(node, Replicate):
return "{" + str(node.n) + "{" + _printexpr(ns, node.v)[0] + "}}", False return "{" + str(node.n) + "{" + _printexpr(ns, node.v)[0] + "}}", False
else: else:
raise TypeError("Expression of unrecognized type: "+str(type(node))) raise TypeError("Expression of unrecognized type: '{}'".format(type(node).__name__))
(_AT_BLOCKING, _AT_NONBLOCKING, _AT_SIGNAL) = range(3) (_AT_BLOCKING, _AT_NONBLOCKING, _AT_SIGNAL) = range(3)
@ -148,7 +141,7 @@ def _printnode(ns, at, level, node):
elif isinstance(node, Case): elif isinstance(node, Case):
if node.cases: if node.cases:
r = "\t"*level + "case (" + _printexpr(ns, node.test)[0] + ")\n" r = "\t"*level + "case (" + _printexpr(ns, node.test)[0] + ")\n"
css = sorted([(k, v) for (k, v) in node.cases.items() if k != "default"], key=itemgetter(0)) css = sorted([(k, v) for (k, v) in node.cases.items() if isinstance(k, Constant)], key=itemgetter(0))
for choice, statements in css: for choice, statements in css:
r += "\t"*(level + 1) + _printexpr(ns, choice)[0] + ": begin\n" r += "\t"*(level + 1) + _printexpr(ns, choice)[0] + ": begin\n"
r += _printnode(ns, at, level + 2, statements) r += _printnode(ns, at, level + 2, statements)
@ -183,7 +176,7 @@ def _printheader(f, ios, name, ns,
wires = _list_comb_wires(f) | special_outs wires = _list_comb_wires(f) | special_outs
r = "module " + name + "(\n" r = "module " + name + "(\n"
firstp = True firstp = True
for sig in sorted(ios, key=lambda x: x.huid): for sig in sorted(ios, key=lambda x: x.duid):
if not firstp: if not firstp:
r += ",\n" r += ",\n"
firstp = False firstp = False
@ -197,7 +190,7 @@ def _printheader(f, ios, name, ns,
else: else:
r += "\tinput " + _printsig(ns, sig) r += "\tinput " + _printsig(ns, sig)
r += "\n);\n\n" r += "\n);\n\n"
for sig in sorted(sigs - ios, key=lambda x: x.huid): for sig in sorted(sigs - ios, key=lambda x: x.duid):
if sig in wires: if sig in wires:
r += "wire " + _printsig(ns, sig) + ";\n" r += "wire " + _printsig(ns, sig) + ";\n"
else: else:
@ -280,7 +273,7 @@ def _call_special_classmethod(overrides, obj, method, *args, **kwargs):
def _lower_specials_step(overrides, specials): def _lower_specials_step(overrides, specials):
f = _Fragment() f = _Fragment()
lowered_specials = set() lowered_specials = set()
for special in sorted(specials, key=lambda x: x.huid): for special in sorted(specials, key=lambda x: x.duid):
impl = _call_special_classmethod(overrides, special, "lower") impl = _call_special_classmethod(overrides, special, "lower")
if impl is not None: if impl is not None:
f += impl.get_fragment() f += impl.get_fragment()
@ -310,7 +303,7 @@ def _lower_specials(overrides, specials):
def _printspecials(overrides, specials, ns, add_data_file): def _printspecials(overrides, specials, ns, add_data_file):
r = "" r = ""
for special in sorted(specials, key=lambda x: x.huid): for special in sorted(specials, key=lambda x: x.duid):
pr = _call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file) pr = _call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file)
if pr is None: if pr is None:
raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog") raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog")

View file

@ -73,8 +73,8 @@ class Evaluator:
return r return r
def eval(self, node): def eval(self, node):
if isinstance(node, (int, bool)): if isinstance(node, Constant):
return node return node.value
elif isinstance(node, Signal): elif isinstance(node, Signal):
try: try:
return self.signal_values[node] return self.signal_values[node]