litex/migen/bank/description.py

157 lines
4.2 KiB
Python
Raw Normal View History

2013-03-09 18:43:16 -05:00
from copy import copy
2011-12-05 11:43:56 -05:00
2013-03-09 18:43:16 -05:00
from migen.fhdl.structure import *
from migen.fhdl.specials import Memory
2012-10-15 15:21:59 -04:00
2013-03-09 18:43:16 -05:00
class Register(HUID):
pass
2013-02-25 17:14:15 -05:00
2013-03-09 18:43:16 -05:00
class RegisterRaw(Register):
2012-02-06 07:55:50 -05:00
def __init__(self, name, size=1):
2013-03-09 18:43:16 -05:00
Register.__init__(self)
2011-12-05 11:43:56 -05:00
self.name = name
2012-02-06 07:55:50 -05:00
self.size = size
self.re = Signal()
self.r = Signal(self.size)
self.w = Signal(self.size)
2011-12-05 11:43:56 -05:00
(READ_ONLY, WRITE_ONLY, READ_WRITE) = range(3)
class Field:
2012-10-08 12:43:18 -04:00
def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False):
2011-12-05 11:43:56 -05:00
self.name = name
self.size = size
self.access_bus = access_bus
self.access_dev = access_dev
self.storage = Signal(self.size, reset=reset)
2012-10-08 12:43:18 -04:00
self.atomic_write = atomic_write
if self.access_bus == READ_ONLY and self.access_dev == WRITE_ONLY:
self.w = Signal(self.size)
else:
if self.access_dev == READ_ONLY or self.access_dev == READ_WRITE:
self.r = Signal(self.size, reset=reset)
if self.access_dev == WRITE_ONLY or self.access_dev == READ_WRITE:
self.w = Signal(self.size)
self.we = Signal()
2012-02-06 07:55:50 -05:00
2013-03-09 18:43:16 -05:00
class RegisterFields(Register):
def __init__(self, name, fields):
2013-03-09 18:43:16 -05:00
Register.__init__(self)
2012-02-06 07:55:50 -05:00
self.name = name
self.fields = fields
class RegisterField(RegisterFields):
2012-10-08 12:43:18 -04:00
def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False):
self.field = Field(name, size, access_bus, access_dev, reset, atomic_write)
2012-12-18 08:54:33 -05:00
RegisterFields.__init__(self, name, [self.field])
2013-03-09 18:43:16 -05:00
def regprefix(prefix, registers):
r = []
for register in registers:
c = copy(register)
c.name = prefix + c.name
r.append(c)
return r
def memprefix(prefix, memories):
r = []
for memory in memories:
c = copy(memory)
c.name_override = prefix + c.name_override
r.append(c)
return memories
class AutoReg:
def get_memories(self):
r = []
for k, v in self.__dict__.items():
if isinstance(v, Memory):
r.append(v)
elif hasattr(v, "get_memories"):
r += memprefix(k + "_", v.get_memories())
return sorted(r, key=lambda x: x.huid)
def get_registers(self):
r = []
for k, v in self.__dict__.items():
if isinstance(v, Register):
r.append(v)
elif hasattr(v, "get_registers"):
r += regprefix(k + "_", v.get_registers())
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)
class FieldAlias:
2012-10-08 12:43:18 -04:00
def __init__(self, mode, f, start, end, commit_list):
self.mode = mode
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:
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 = []
# 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
for field in reg.fields:
2012-10-08 12:43:18 -04:00
offset += field.size
totalsize += field.size
if offset > busword:
# add padding
padding = busword - (totalsize % busword)
2012-10-08 12:43:18 -04:00
if padding != busword:
totalsize += padding
offset += padding
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)
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)
top -= slice1
d.append(RegisterFields(reg.name, f))
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)
top -= slice2
2012-10-08 12:43:18 -04:00
offset -= busword
else:
f.append(field)
if f:
d.append(RegisterFields(reg.name, f))
else:
raise TypeError
return d