litex/migen/fhdl/structure.py

392 lines
8.8 KiB
Python
Raw Normal View History

import inspect
import re
from collections import defaultdict
from migen.fhdl import tracer
2012-01-16 12:09:52 -05:00
def log2_int(n, need_pow2=True):
2012-03-14 07:19:42 -04:00
l = 1
r = 0
while l < n:
l *= 2
r += 1
if need_pow2 and l != n:
2012-03-14 07:19:42 -04:00
raise ValueError("Not a power of 2")
return r
2012-03-14 07:19:42 -04:00
def bits_for(n, require_sign_bit=False):
if n > 0:
r = log2_int(n + 1, False)
else:
require_sign_bit = True
r = log2_int(-n, False)
if require_sign_bit:
r += 1
return r
class BV:
def __init__(self, width=1, signed=False):
self.width = width
self.signed = signed
2011-12-09 07:11:34 -05:00
def __repr__(self):
r = str(self.width) + "'"
if self.signed:
r += "s"
r += "d"
return r
2012-01-06 17:00:23 -05:00
def __eq__(self, other):
return self.width == other.width and self.signed == other.signed
class HUID:
__next_uid = 0
def __init__(self):
self.huid = HUID.__next_uid
HUID.__next_uid += 1
def __hash__(self):
return self.huid
class Value(HUID):
2011-12-08 15:15:44 -05:00
def __invert__(self):
2011-12-16 15:30:14 -05:00
return _Operator("~", [self])
2011-12-08 15:15:44 -05:00
def __add__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("+", [self, other])
def __radd__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("+", [other, self])
def __sub__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("-", [self, other])
def __rsub__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("-", [other, self])
def __mul__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("*", [self, other])
def __rmul__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("*", [other, self])
def __lshift__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("<<", [self, other])
def __rlshift__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("<<", [other, self])
def __rshift__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator(">>", [self, other])
def __rrshift__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator(">>", [other, self])
def __and__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("&", [self, other])
def __rand__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("&", [other, self])
def __xor__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("^", [self, other])
def __rxor__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("^", [other, self])
def __or__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("|", [self, other])
def __ror__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("|", [other, self])
def __lt__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("<", [self, other])
def __le__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("<=", [self, other])
def __eq__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("==", [self, other])
def __ne__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator("!=", [self, other])
def __gt__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator(">", [self, other])
def __ge__(self, other):
2011-12-16 15:30:14 -05:00
return _Operator(">=", [self, other])
def __getitem__(self, key):
if isinstance(key, int):
2011-12-21 16:57:07 -05:00
return _Slice(self, key, key+1)
elif isinstance(key, slice):
start = key.start or 0
2012-07-13 12:32:54 -04:00
stop = key.stop or len(self)
if stop > len(self):
stop = len(self)
if key.step != None:
raise KeyError
2011-12-21 16:57:07 -05:00
return _Slice(self, start, stop)
else:
raise KeyError
2011-12-16 15:30:14 -05:00
def eq(self, r):
2011-12-21 16:57:07 -05:00
return _Assign(self, r)
def __hash__(self):
return super().__hash__()
2011-12-16 15:30:14 -05:00
class _Operator(Value):
def __init__(self, op, operands):
super().__init__()
self.op = op
2012-11-28 17:18:43 -05:00
self.operands = operands
2011-12-21 16:57:07 -05:00
class _Slice(Value):
def __init__(self, value, start, stop):
super().__init__()
self.value = value
self.start = start
self.stop = stop
class Cat(Value):
def __init__(self, *args):
super().__init__()
2012-11-28 17:18:43 -05:00
self.l = args
2011-12-09 07:11:34 -05:00
class Replicate(Value):
def __init__(self, v, n):
super().__init__()
2012-11-28 17:18:43 -05:00
self.v = v
2011-12-09 07:11:34 -05:00
self.n = n
class Signal(Value):
2012-01-16 12:09:52 -05:00
def __init__(self, bv=BV(), name=None, variable=False, reset=0, name_override=None):
super().__init__()
2012-02-17 17:50:54 -05:00
assert(isinstance(bv, BV))
self.bv = bv
self.variable = variable
2012-11-28 17:18:43 -05:00
self.reset = reset
2012-01-16 12:09:52 -05:00
self.name_override = name_override
self.backtrace = tracer.trace_back(name)
2012-09-11 03:59:37 -04:00
2012-04-08 12:06:22 -04:00
def __len__(self):
return self.bv.width
2012-01-06 05:20:33 -05:00
def __repr__(self):
2012-09-09 13:33:55 -04:00
return "<Signal " + (self.backtrace[-1][0] or "anonymous") + " at " + hex(id(self)) + ">"
# statements
2011-12-21 16:57:07 -05:00
class _Assign:
def __init__(self, l, r):
self.l = l
2012-11-28 17:18:43 -05:00
self.r = r
2011-12-16 15:30:14 -05:00
class If:
def __init__(self, cond, *t):
self.cond = cond
2012-07-13 11:07:56 -04:00
self.t = list(t)
self.f = []
2011-12-16 15:30:14 -05:00
def Else(self, *f):
2012-07-13 11:07:56 -04:00
_insert_else(self, list(f))
2011-12-16 15:30:14 -05:00
return self
def Elif(self, cond, *t):
2012-07-13 11:07:56 -04:00
_insert_else(self, [If(cond, *t)])
2011-12-16 15:30:14 -05:00
return self
2011-12-17 14:31:42 -05:00
def _insert_else(obj, clause):
o = obj
2012-07-13 11:07:56 -04:00
while o.f:
assert(len(o.f) == 1)
assert(isinstance(o.f[0], If))
o = o.f[0]
2011-12-17 14:31:42 -05:00
o.f = clause
class Case:
2012-11-28 19:11:15 -05:00
def __init__(self, test, cases):
self.test = test
2012-11-28 19:11:15 -05:00
self.cases = cases
def makedefault(self, key=None):
if key is None:
for choice in self.cases.keys():
if key is None or choice > key:
key = choice
self.cases["default"] = self.cases[key]
del self.cases[key]
return self
# arrays
class _ArrayProxy(Value):
def __init__(self, choices, key):
self.choices = choices
self.key = key
def __getattr__(self, attr):
return _ArrayProxy([getattr(choice, attr) for choice in self.choices],
self.key)
def __getitem__(self, key):
return _ArrayProxy([choice.__getitem__(key) for choice in self.choices],
self.key)
class Array(list):
def __getitem__(self, key):
if isinstance(key, Value):
return _ArrayProxy(self, key)
else:
return super().__getitem__(key)
# extras
class Instance(HUID):
def __init__(self, of, *items, name=""):
super().__init__()
2011-12-08 10:35:32 -05:00
self.of = of
if name:
2012-01-20 16:36:17 -05:00
self.name_override = name
2011-12-08 10:35:32 -05:00
else:
2012-01-20 16:36:17 -05:00
self.name_override = of
self.items = items
class _IO:
def __init__(self, name, expr=BV(1)):
self.name = name
if isinstance(expr, BV):
self.expr = Signal(expr, name)
2011-12-08 12:56:14 -05:00
else:
self.expr = expr
class Input(_IO):
pass
class Output(_IO):
pass
class InOut(_IO):
pass
class Parameter:
def __init__(self, name, value):
self.name = name
self.value = value
class _CR:
def __init__(self, name_inst, domain="sys", invert=False):
self.name_inst = name_inst
self.domain = domain
self.invert = invert
class ClockPort(_CR):
pass
class ResetPort(_CR):
pass
def get_io(self, name):
for item in self.items:
if isinstance(item, Instance._IO) and item.name == name:
2012-09-28 12:02:03 -04:00
return item.expr
2011-12-08 10:35:32 -05:00
2012-01-27 14:22:17 -05:00
(READ_FIRST, WRITE_FIRST, NO_CHANGE) = range(3)
class _MemoryPort:
2012-01-27 14:22:17 -05:00
def __init__(self, adr, dat_r, we=None, dat_w=None,
async_read=False, re=None, we_granularity=0, mode=WRITE_FIRST,
clock_domain="sys"):
2012-01-27 10:53:34 -05:00
self.adr = adr
self.dat_r = dat_r
self.we = we
self.dat_w = dat_w
self.async_read = async_read
self.re = re
self.we_granularity = we_granularity
2012-01-27 14:22:17 -05:00
self.mode = mode
self.clock_domain = clock_domain
2012-01-27 10:53:34 -05:00
class Memory(HUID):
def __init__(self, width, depth, init=None):
super().__init__()
2012-01-27 10:53:34 -05:00
self.width = width
self.depth = depth
self.ports = []
2012-01-27 10:53:34 -05:00
self.init = init
def get_port(self, write_capable=False, async_read=False,
has_re=False, we_granularity=0, mode=WRITE_FIRST,
clock_domain="sys"):
if we_granularity >= self.width:
we_granularity = 0
adr = Signal(BV(bits_for(self.depth-1)))
dat_r = Signal(BV(self.width))
if write_capable:
2012-11-23 13:21:52 -05:00
if we_granularity:
we = Signal(BV(self.width//we_granularity))
else:
we = Signal()
dat_w = Signal(BV(self.width))
else:
we = None
dat_w = None
if has_re:
re = Signal()
else:
re = None
mp = _MemoryPort(adr, dat_r, we, dat_w,
2012-11-23 13:21:52 -05:00
async_read, re, we_granularity, mode,
clock_domain)
self.ports.append(mp)
return mp
2012-01-27 10:53:34 -05:00
#
class Fragment:
2012-04-02 13:21:43 -04:00
def __init__(self, comb=None, sync=None, instances=None, memories=None, sim=None):
if comb is None: comb = []
if sync is None: sync = dict()
if instances is None: instances = set()
if memories is None: memories = set()
if sim is None: sim = []
if isinstance(sync, list):
sync = {"sys": sync}
2012-07-13 11:07:56 -04:00
self.comb = comb
self.sync = sync
self.instances = set(instances)
self.memories = set(memories)
self.sim = sim
2011-12-05 11:43:56 -05:00
def __add__(self, other):
newsync = defaultdict(list)
for k, v in self.sync.items():
newsync[k] = v[:]
for k, v in other.sync.items():
newsync[k].extend(v)
return Fragment(self.comb + other.comb, newsync,
self.instances | other.instances,
self.memories | other.memories,
self.sim + other.sim)
def rename_clock_domain(self, old, new):
self.sync["new"] = self.sync["old"]
del self.sync["old"]
for inst in self.instances:
for cr in filter(lambda x: isinstance(x, Instance._CR), inst.items):
if cr.domain == old:
cr.domain = new
for mem in self.memories:
for port in mem.ports:
if port.clock_domain == old:
port.clock_domain = new
def get_clock_domains(self):
r = set(self.sync.keys())
r |= set(cr.domain
for inst in self.instances
for cr in filter(lambda x: isinstance(x, Instance._CR), inst.items))
r |= set(port.clock_domain
for mem in self.memories
for port in mem.ports)
return r
2012-03-06 13:29:39 -05:00
def call_sim(self, simulator):
for s in self.sim:
if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize):
s(simulator)
class ClockDomain:
def __init__(self, n1, n2=None):
if n2 is None:
n_clk = n1 + "_clk"
n_rst = n1 + "_rst"
else:
n_clk = n1
n_rst = n2
self.clk = Signal(name_override=n_clk)
self.rst = Signal(name_override=n_rst)