mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
bank: support for atomic writes
This commit is contained in:
parent
24877f271b
commit
e410973352
3 changed files with 54 additions and 23 deletions
|
@ -6,7 +6,7 @@ from migen.bank.description import READ_ONLY, WRITE_ONLY
|
|||
ninputs = 32
|
||||
noutputs = 32
|
||||
|
||||
oreg = description.RegisterField("o", noutputs)
|
||||
oreg = description.RegisterField("o", noutputs, atomic_write=True)
|
||||
ireg = description.RegisterField("i", ninputs, READ_ONLY, WRITE_ONLY)
|
||||
|
||||
# input path
|
||||
|
|
|
@ -39,6 +39,11 @@ class Bank:
|
|||
if len(bwra) > 1:
|
||||
bwra.append(reg.re.eq(1))
|
||||
bwcases.append(bwra)
|
||||
# commit atomic writes
|
||||
for field in reg.fields:
|
||||
if isinstance(field, FieldAlias) and field.commit_list:
|
||||
commit_instr = [hf.commit_to.eq(hf.storage) for hf in field.commit_list]
|
||||
sync.append(If(sel & self.interface.we & self.interface.adr[:nbits] == i, *commit_instr))
|
||||
else:
|
||||
raise TypeError
|
||||
if bwcases:
|
||||
|
@ -59,10 +64,7 @@ class Bank:
|
|||
else:
|
||||
brs.append(Constant(0, BV(field.size)))
|
||||
if reg_readable:
|
||||
if len(brs) > 1:
|
||||
brcases.append([Constant(i, BV(nbits)), self.interface.dat_r.eq(Cat(*brs))])
|
||||
else:
|
||||
brcases.append([Constant(i, BV(nbits)), self.interface.dat_r.eq(brs[0])])
|
||||
brcases.append([Constant(i, BV(nbits)), self.interface.dat_r.eq(Cat(*brs))])
|
||||
else:
|
||||
raise TypeError
|
||||
if brcases:
|
||||
|
|
|
@ -11,12 +11,13 @@ class RegisterRaw:
|
|||
(READ_ONLY, WRITE_ONLY, READ_WRITE) = range(3)
|
||||
|
||||
class Field:
|
||||
def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0):
|
||||
def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False):
|
||||
self.name = name
|
||||
self.size = size
|
||||
self.access_bus = access_bus
|
||||
self.access_dev = access_dev
|
||||
self.storage = Signal(BV(self.size), reset=reset)
|
||||
self.atomic_write = atomic_write
|
||||
if self.access_bus == READ_ONLY and self.access_dev == WRITE_ONLY:
|
||||
self.w = Signal(BV(self.size))
|
||||
else:
|
||||
|
@ -36,16 +37,27 @@ class RegisterFields:
|
|||
self.re = re
|
||||
|
||||
class RegisterField(RegisterFields):
|
||||
def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0):
|
||||
self.field = Field(name, size, access_bus, access_dev, reset)
|
||||
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)
|
||||
super().__init__(name, [self.field])
|
||||
|
||||
(ALIAS_NON_ATOMIC, ALIAS_ATOMIC_HOLD, ALIAS_ATOMIC_COMMIT) = range(3)
|
||||
|
||||
class FieldAlias:
|
||||
def __init__(self, f, start, end):
|
||||
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
|
||||
self.storage = f.storage[start:end]
|
||||
if mode == ALIAS_ATOMIC_HOLD:
|
||||
self.storage = Signal(BV(end-start), name="atomic_hold")
|
||||
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):
|
||||
|
@ -57,28 +69,45 @@ def expand_description(description, busword):
|
|||
d.append(reg)
|
||||
elif isinstance(reg, RegisterFields):
|
||||
f = []
|
||||
size = 0
|
||||
offset = 0
|
||||
totalsize = 0
|
||||
for field in reg.fields:
|
||||
size += field.size
|
||||
if size > busword:
|
||||
offset += field.size
|
||||
totalsize += field.size
|
||||
if offset > busword:
|
||||
# add padding
|
||||
totalsize = sum([field.size for field in reg.fields])
|
||||
padding = busword - (totalsize % busword)
|
||||
if padding == busword:
|
||||
padding = 0
|
||||
size += padding
|
||||
if padding != busword:
|
||||
totalsize += padding
|
||||
offset += padding
|
||||
|
||||
top = field.size
|
||||
while size > busword:
|
||||
slice1 = busword - size + top
|
||||
slice2 = min(size - busword, busword)
|
||||
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:
|
||||
f.append(FieldAlias(field, top - slice1, top))
|
||||
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))
|
||||
f = [FieldAlias(field, top - slice2, top)]
|
||||
alias = FieldAlias(mode, field, top - slice2, top, commit_list)
|
||||
f = [alias]
|
||||
if mode == ALIAS_ATOMIC_HOLD:
|
||||
commit_list.append(alias)
|
||||
top -= slice2
|
||||
size -= busword
|
||||
offset -= busword
|
||||
else:
|
||||
f.append(field)
|
||||
if f:
|
||||
|
|
Loading…
Reference in a new issue