From: Sebastien Bourdeauducq Date: Mon, 8 Oct 2012 16:43:18 +0000 (+0200) Subject: bank: support for atomic writes X-Git-Tag: 24jan2021_ls180~2099^2~829 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e410973352617a0b0ee0f1bd6ddc04f0172f9e63;p=litex.git bank: support for atomic writes --- diff --git a/examples/basic/simple_gpio.py b/examples/basic/simple_gpio.py index 1a738791..d469eec2 100644 --- a/examples/basic/simple_gpio.py +++ b/examples/basic/simple_gpio.py @@ -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 diff --git a/migen/bank/csrgen.py b/migen/bank/csrgen.py index ec9a4148..140e9baa 100644 --- a/migen/bank/csrgen.py +++ b/migen/bank/csrgen.py @@ -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: diff --git a/migen/bank/description.py b/migen/bank/description.py index 7f79ca6a..854e19d6 100644 --- a/migen/bank/description.py +++ b/migen/bank/description.py @@ -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: