2013-03-09 18:43:16 -05:00
|
|
|
from migen.fhdl.structure import *
|
|
|
|
from migen.fhdl.specials import Memory
|
2013-03-12 10:45:24 -04:00
|
|
|
from migen.fhdl.tracer import get_obj_var_name
|
2012-10-15 15:21:59 -04:00
|
|
|
|
2013-03-10 14:47:21 -04:00
|
|
|
class _Register(HUID):
|
2013-03-12 10:45:24 -04:00
|
|
|
def __init__(self, name):
|
|
|
|
HUID.__init__(self)
|
|
|
|
self.name = get_obj_var_name(name)
|
|
|
|
if self.name is None:
|
|
|
|
raise ValueError("Cannot extract register name from code, need to specify.")
|
|
|
|
if len(self.name) > 2 and self.name[:2] == "r_":
|
|
|
|
self.name = self.name[2:]
|
2013-02-25 17:14:15 -05:00
|
|
|
|
2013-03-10 14:47:21 -04:00
|
|
|
class RegisterRaw(_Register):
|
2013-03-12 10:45:24 -04:00
|
|
|
def __init__(self, size=1, name=None):
|
|
|
|
_Register.__init__(self, name)
|
2012-02-06 07:55:50 -05:00
|
|
|
self.size = size
|
|
|
|
self.re = Signal()
|
2012-11-29 15:22:38 -05:00
|
|
|
self.r = Signal(self.size)
|
|
|
|
self.w = Signal(self.size)
|
2011-12-05 11:43:56 -05:00
|
|
|
|
2013-03-25 09:43:44 -04:00
|
|
|
def get_size(self):
|
|
|
|
return self.size
|
|
|
|
|
2011-12-05 11:43:56 -05:00
|
|
|
(READ_ONLY, WRITE_ONLY, READ_WRITE) = range(3)
|
|
|
|
|
|
|
|
class Field:
|
2013-03-12 10:45:24 -04:00
|
|
|
def __init__(self, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False, name=None):
|
|
|
|
self.name = get_obj_var_name(name)
|
|
|
|
if self.name is None:
|
|
|
|
raise ValueError("Cannot extract field name from code, need to specify.")
|
2011-12-05 11:43:56 -05:00
|
|
|
self.size = size
|
|
|
|
self.access_bus = access_bus
|
|
|
|
self.access_dev = access_dev
|
2012-11-29 15:22:38 -05:00
|
|
|
self.storage = Signal(self.size, reset=reset)
|
2012-10-08 12:43:18 -04:00
|
|
|
self.atomic_write = atomic_write
|
2012-02-15 12:23:31 -05:00
|
|
|
if self.access_bus == READ_ONLY and self.access_dev == WRITE_ONLY:
|
2012-11-29 15:22:38 -05:00
|
|
|
self.w = Signal(self.size)
|
2012-02-15 12:23:31 -05:00
|
|
|
else:
|
|
|
|
if self.access_dev == READ_ONLY or self.access_dev == READ_WRITE:
|
2012-12-05 10:40:44 -05:00
|
|
|
self.r = Signal(self.size, reset=reset)
|
2012-02-15 12:23:31 -05:00
|
|
|
if self.access_dev == WRITE_ONLY or self.access_dev == READ_WRITE:
|
2012-11-29 15:22:38 -05:00
|
|
|
self.w = Signal(self.size)
|
2012-02-15 12:23:31 -05:00
|
|
|
self.we = Signal()
|
2012-02-06 07:55:50 -05:00
|
|
|
|
2013-03-10 14:47:21 -04:00
|
|
|
class RegisterFields(_Register):
|
2013-03-12 10:45:24 -04:00
|
|
|
def __init__(self, *fields, name=None):
|
|
|
|
_Register.__init__(self, name)
|
2012-02-06 07:55:50 -05:00
|
|
|
self.fields = fields
|
|
|
|
|
2013-03-25 09:43:44 -04:00
|
|
|
def get_size(self):
|
|
|
|
return sum(field.size for field in self.fields)
|
|
|
|
|
2012-02-06 07:55:50 -05:00
|
|
|
class RegisterField(RegisterFields):
|
2013-03-12 10:45:24 -04:00
|
|
|
def __init__(self, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False, name=None):
|
|
|
|
self.field = Field(size, access_bus, access_dev, reset, atomic_write, name="")
|
|
|
|
RegisterFields.__init__(self, self.field, name=name)
|
2012-02-06 10:15:27 -05:00
|
|
|
|
2013-03-09 18:43:16 -05:00
|
|
|
def regprefix(prefix, registers):
|
|
|
|
for register in registers:
|
2013-03-13 14:46:34 -04:00
|
|
|
register.name = prefix + register.name
|
2013-03-09 18:43:16 -05:00
|
|
|
|
|
|
|
def memprefix(prefix, memories):
|
|
|
|
for memory in memories:
|
2013-03-13 14:46:34 -04:00
|
|
|
memory.name_override = prefix + memory.name_override
|
2013-03-09 18:43:16 -05:00
|
|
|
|
|
|
|
class AutoReg:
|
|
|
|
def get_memories(self):
|
|
|
|
r = []
|
|
|
|
for k, v in self.__dict__.items():
|
|
|
|
if isinstance(v, Memory):
|
|
|
|
r.append(v)
|
2013-03-10 13:11:29 -04:00
|
|
|
elif hasattr(v, "get_memories") and callable(v.get_memories):
|
2013-03-13 14:46:34 -04:00
|
|
|
memories = v.get_memories()
|
|
|
|
memprefix(k + "_", memories)
|
|
|
|
r += memories
|
2013-03-09 18:43:16 -05:00
|
|
|
return sorted(r, key=lambda x: x.huid)
|
|
|
|
|
|
|
|
def get_registers(self):
|
|
|
|
r = []
|
|
|
|
for k, v in self.__dict__.items():
|
2013-03-10 14:47:21 -04:00
|
|
|
if isinstance(v, _Register):
|
2013-03-09 18:43:16 -05:00
|
|
|
r.append(v)
|
2013-03-10 13:11:29 -04:00
|
|
|
elif hasattr(v, "get_registers") and callable(v.get_registers):
|
2013-03-13 14:46:34 -04:00
|
|
|
registers = v.get_registers()
|
|
|
|
regprefix(k + "_", registers)
|
|
|
|
r += registers
|
2013-03-09 18:43:16 -05:00
|
|
|
return sorted(r, key=lambda x: x.huid)
|
|
|
|
|
2012-10-08 12:43:18 -04:00
|
|
|
(ALIAS_NON_ATOMIC, ALIAS_ATOMIC_HOLD, ALIAS_ATOMIC_COMMIT) = range(3)
|
|
|
|
|
2012-02-06 10:15:27 -05:00
|
|
|
class FieldAlias:
|
2012-10-08 12:43:18 -04:00
|
|
|
def __init__(self, mode, f, start, end, commit_list):
|
|
|
|
self.mode = mode
|
2012-02-06 10:15:27 -05:00
|
|
|
self.size = end - start
|
|
|
|
self.access_bus = f.access_bus
|
|
|
|
self.access_dev = f.access_dev
|
2012-10-08 12:43:18 -04:00
|
|
|
if mode == ALIAS_ATOMIC_HOLD:
|
2012-11-29 15:22:38 -05:00
|
|
|
self.storage = Signal(end-start, name="atomic_hold")
|
2012-10-08 12:43:18 -04:00
|
|
|
self.commit_to = f.storage[start:end]
|
|
|
|
else:
|
|
|
|
self.storage = f.storage[start:end]
|
|
|
|
if mode == ALIAS_ATOMIC_COMMIT:
|
|
|
|
self.commit_list = commit_list
|
|
|
|
else:
|
|
|
|
self.commit_list = []
|
2012-02-06 10:15:27 -05:00
|
|
|
# device access is through the original field
|
|
|
|
|
|
|
|
def expand_description(description, busword):
|
|
|
|
d = []
|
|
|
|
for reg in description:
|
|
|
|
if isinstance(reg, RegisterRaw):
|
|
|
|
if reg.size > busword:
|
|
|
|
raise ValueError("Raw register larger than a bus word")
|
|
|
|
d.append(reg)
|
|
|
|
elif isinstance(reg, RegisterFields):
|
|
|
|
f = []
|
2012-10-08 12:43:18 -04:00
|
|
|
offset = 0
|
|
|
|
totalsize = 0
|
2012-02-06 10:15:27 -05:00
|
|
|
for field in reg.fields:
|
2012-10-08 12:43:18 -04:00
|
|
|
offset += field.size
|
|
|
|
totalsize += field.size
|
|
|
|
if offset > busword:
|
2012-05-21 16:55:23 -04:00
|
|
|
# add padding
|
|
|
|
padding = busword - (totalsize % busword)
|
2012-10-08 12:43:18 -04:00
|
|
|
if padding != busword:
|
|
|
|
totalsize += padding
|
|
|
|
offset += padding
|
2012-05-21 16:55:23 -04:00
|
|
|
|
2012-02-06 10:15:27 -05:00
|
|
|
top = field.size
|
2012-10-08 12:43:18 -04:00
|
|
|
commit_list = []
|
|
|
|
while offset > busword:
|
|
|
|
if field.atomic_write:
|
|
|
|
if offset - busword > busword:
|
|
|
|
mode = ALIAS_ATOMIC_HOLD
|
|
|
|
else:
|
|
|
|
# last iteration
|
|
|
|
mode = ALIAS_ATOMIC_COMMIT
|
|
|
|
else:
|
|
|
|
mode = ALIAS_NON_ATOMIC
|
|
|
|
|
|
|
|
slice1 = busword - offset + top
|
|
|
|
slice2 = min(offset - busword, busword)
|
2012-02-06 10:15:27 -05:00
|
|
|
if slice1:
|
2012-10-08 12:43:18 -04:00
|
|
|
alias = FieldAlias(mode, field, top - slice1, top, commit_list)
|
|
|
|
f.append(alias)
|
|
|
|
if mode == ALIAS_ATOMIC_HOLD:
|
|
|
|
commit_list.append(alias)
|
2012-02-06 10:15:27 -05:00
|
|
|
top -= slice1
|
2013-03-12 10:45:24 -04:00
|
|
|
d.append(RegisterFields(*f, name=reg.name))
|
2012-10-08 12:43:18 -04:00
|
|
|
alias = FieldAlias(mode, field, top - slice2, top, commit_list)
|
|
|
|
f = [alias]
|
|
|
|
if mode == ALIAS_ATOMIC_HOLD:
|
|
|
|
commit_list.append(alias)
|
2012-02-06 10:15:27 -05:00
|
|
|
top -= slice2
|
2012-10-08 12:43:18 -04:00
|
|
|
offset -= busword
|
2012-02-06 10:15:27 -05:00
|
|
|
else:
|
|
|
|
f.append(field)
|
|
|
|
if f:
|
2013-03-12 10:45:24 -04:00
|
|
|
d.append(RegisterFields(*f, name=reg.name))
|
2012-02-06 10:15:27 -05:00
|
|
|
else:
|
|
|
|
raise TypeError
|
|
|
|
return d
|