fhdl: support len() on all values

This commit is contained in:
Sebastien Bourdeauducq 2013-04-14 13:50:26 +02:00
parent 75d33a0c05
commit ea63389823
3 changed files with 83 additions and 83 deletions

View file

@ -110,6 +110,9 @@ class Value(HUID):
def eq(self, r):
return _Assign(self, r)
def __len__(self):
return value_bits_sign(self)[0]
def __hash__(self):
return HUID.__hash__(self)
@ -164,9 +167,6 @@ class Signal(Value):
self.name_override = name_override
self.backtrace = tracer.trace_back(name)
def __len__(self): # TODO: remove (use tools.value_bits_sign instead)
return self.nbits
def __repr__(self):
return "<Signal " + (self.backtrace[-1][0] or "anonymous") + " at " + hex(id(self)) + ">"
@ -299,3 +299,81 @@ class Fragment:
self.specials | other.specials,
self.clock_domains + other.clock_domains,
self.sim + other.sim)
def value_bits_sign(v):
if isinstance(v, bool):
return 1, False
elif isinstance(v, int):
return bits_for(v), v < 0
elif isinstance(v, Signal):
return v.nbits, v.signed
elif isinstance(v, (ClockSignal, ResetSignal)):
return 1, False
elif isinstance(v, _Operator):
obs = list(map(value_bits_sign, v.operands))
if v.op == "+" or v.op == "-":
if not obs[0][1] and not obs[1][1]:
# both operands unsigned
return max(obs[0][0], obs[1][0]) + 1, False
elif obs[0][1] and obs[1][1]:
# both operands signed
return max(obs[0][0], obs[1][0]) + 1, True
elif not obs[0][1] and obs[1][1]:
# first operand unsigned (add sign bit), second operand signed
return max(obs[0][0] + 1, obs[1][0]) + 1, True
else:
# first signed, second operand unsigned (add sign bit)
return max(obs[0][0], obs[1][0] + 1) + 1, True
elif v.op == "*":
if not obs[0][1] and not obs[1][1]:
# both operands unsigned
return obs[0][0] + obs[1][0]
elif obs[0][1] and obs[1][1]:
# both operands signed
return obs[0][0] + obs[1][0] - 1
else:
# one operand signed, the other unsigned (add sign bit)
return obs[0][0] + obs[1][0] + 1 - 1
elif v.op == "<<<":
if obs[1][1]:
extra = 2**(obs[1][0] - 1) - 1
else:
extra = 2**obs[1][0] - 1
return obs[0][0] + extra, obs[0][1]
elif v.op == ">>>":
if obs[1][1]:
extra = 2**(obs[1][0] - 1)
else:
extra = 0
return obs[0][0] + extra, obs[0][1]
elif v.op == "&" or v.op == "^" or v.op == "|":
if not obs[0][1] and not obs[1][1]:
# both operands unsigned
return max(obs[0][0], obs[1][0]), False
elif obs[0][1] and obs[1][1]:
# both operands signed
return max(obs[0][0], obs[1][0]), True
elif not obs[0][1] and obs[1][1]:
# first operand unsigned (add sign bit), second operand signed
return max(obs[0][0] + 1, obs[1][0]), True
else:
# first signed, second operand unsigned (add sign bit)
return max(obs[0][0], obs[1][0] + 1), True
elif v.op == "<" or v.op == "<=" or v.op == "==" or v.op == "!=" \
or v.op == ">" or v.op == ">=":
return 1, False
elif v.op == "~":
return obs[0]
else:
raise TypeError
elif isinstance(v, _Slice):
return v.stop - v.start, value_bits_sign(v.value)[1]
elif isinstance(v, Cat):
return sum(value_bits_sign(sv)[0] for sv in v.l), False
elif isinstance(v, Replicate):
return (value_bits_sign(v.v)[0])*v.n, False
elif isinstance(v, _ArrayProxy):
bsc = map(value_bits_sign, v.choices)
return max(bs[0] for bs in bsc), any(bs[1] for bs in bsc)
else:
raise TypeError

View file

@ -1,7 +1,7 @@
import collections
from migen.fhdl.structure import *
from migen.fhdl.structure import _Operator, _Slice, _Assign, _ArrayProxy
from migen.fhdl.structure import _Slice, _Assign
from migen.fhdl.visit import NodeVisitor, NodeTransformer
def bitreverse(s):
@ -117,84 +117,6 @@ def insert_reset(rst, sl):
resetcode = [t.eq(t.reset) for t in sorted(targets, key=lambda x: x.huid)]
return [If(rst, *resetcode).Else(*sl)]
def value_bits_sign(v):
if isinstance(v, bool):
return 1, False
elif isinstance(v, int):
return bits_for(v), v < 0
elif isinstance(v, Signal):
return v.nbits, v.signed
elif isinstance(v, (ClockSignal, ResetSignal)):
return 1, False
elif isinstance(v, _Operator):
obs = list(map(value_bits_sign, v.operands))
if v.op == "+" or v.op == "-":
if not obs[0][1] and not obs[1][1]:
# both operands unsigned
return max(obs[0][0], obs[1][0]) + 1, False
elif obs[0][1] and obs[1][1]:
# both operands signed
return max(obs[0][0], obs[1][0]) + 1, True
elif not obs[0][1] and obs[1][1]:
# first operand unsigned (add sign bit), second operand signed
return max(obs[0][0] + 1, obs[1][0]) + 1, True
else:
# first signed, second operand unsigned (add sign bit)
return max(obs[0][0], obs[1][0] + 1) + 1, True
elif v.op == "*":
if not obs[0][1] and not obs[1][1]:
# both operands unsigned
return obs[0][0] + obs[1][0]
elif obs[0][1] and obs[1][1]:
# both operands signed
return obs[0][0] + obs[1][0] - 1
else:
# one operand signed, the other unsigned (add sign bit)
return obs[0][0] + obs[1][0] + 1 - 1
elif v.op == "<<<":
if obs[1][1]:
extra = 2**(obs[1][0] - 1) - 1
else:
extra = 2**obs[1][0] - 1
return obs[0][0] + extra, obs[0][1]
elif v.op == ">>>":
if obs[1][1]:
extra = 2**(obs[1][0] - 1)
else:
extra = 0
return obs[0][0] + extra, obs[0][1]
elif v.op == "&" or v.op == "^" or v.op == "|":
if not obs[0][1] and not obs[1][1]:
# both operands unsigned
return max(obs[0][0], obs[1][0]), False
elif obs[0][1] and obs[1][1]:
# both operands signed
return max(obs[0][0], obs[1][0]), True
elif not obs[0][1] and obs[1][1]:
# first operand unsigned (add sign bit), second operand signed
return max(obs[0][0] + 1, obs[1][0]), True
else:
# first signed, second operand unsigned (add sign bit)
return max(obs[0][0], obs[1][0] + 1), True
elif v.op == "<" or v.op == "<=" or v.op == "==" or v.op == "!=" \
or v.op == ">" or v.op == ">=":
return 1, False
elif v.op == "~":
return obs[0]
else:
raise TypeError
elif isinstance(v, _Slice):
return v.stop - v.start, value_bits_sign(v.value)[1]
elif isinstance(v, Cat):
return sum(value_bits_sign(sv)[0] for sv in v.l), False
elif isinstance(v, Replicate):
return (value_bits_sign(v.v)[0])*v.n, False
elif isinstance(v, _ArrayProxy):
bsc = map(value_bits_sign, v.choices)
return max(bs[0] for bs in bsc), any(bs[1] for bs in bsc)
else:
raise TypeError
# Basics are FHDL structure elements that back-ends are not required to support
# but can be expressed in terms of other elements (lowered) before conversion.
class _BasicLowerer(NodeTransformer):

View file

@ -1,6 +1,6 @@
from migen.fhdl.structure import *
from migen.fhdl.specials import Special
from migen.fhdl.tools import value_bits_sign, list_signals
from migen.fhdl.tools import list_signals
class MultiRegImpl:
def __init__(self, i, o, odomain, n):