From: Sebastien Bourdeauducq Date: Sat, 30 Mar 2013 16:28:41 +0000 (+0100) Subject: New CSR API X-Git-Tag: 24jan2021_ls180~2099^2~620 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c4f41435910aeec750b8d13a83dda6942ed3dc2b;p=litex.git New CSR API --- diff --git a/examples/basic/simple_gpio.py b/examples/basic/simple_gpio.py index 0576473c..cb8a3a8f 100644 --- a/examples/basic/simple_gpio.py +++ b/examples/basic/simple_gpio.py @@ -3,12 +3,11 @@ from migen.fhdl.module import Module from migen.fhdl import verilog from migen.genlib.cdc import MultiReg from migen.bank import description, csrgen -from migen.bank.description import READ_ONLY, WRITE_ONLY class Example(Module): def __init__(self, ninputs=32, noutputs=32): - r_o = description.RegisterField(noutputs, atomic_write=True) - r_i = description.RegisterField(ninputs, READ_ONLY, WRITE_ONLY) + r_o = description.CSRStorage(noutputs, atomic_write=True) + r_i = description.CSRStatus(ninputs) self.submodules.bank = csrgen.Bank([r_o, r_i]) self.gpio_in = Signal(ninputs) @@ -17,10 +16,10 @@ class Example(Module): ### gpio_in_s = Signal(ninputs) - self.specials += MultiReg(self.gpio_in, gpio_in_s, "sys") + self.specials += MultiReg(self.gpio_in, gpio_in_s) self.comb += [ - r_i.field.w.eq(gpio_in_s), - self.gpio_out.eq(r_o.field.r) + self.gpio_out.eq(r_o.storage), + r_i.status.eq(gpio_in_s) ] example = Example() diff --git a/migen/actorlib/spi.py b/migen/actorlib/spi.py index 1981b72d..b831c3ba 100644 --- a/migen/actorlib/spi.py +++ b/migen/actorlib/spi.py @@ -18,16 +18,16 @@ def _convert_layout(layout): r.append((element[0], element[1])) return r -def _create_registers_assign(layout, target, atomic, prefix=""): - registers = [] +def _create_csrs_assign(layout, target, atomic, prefix=""): + csrs = [] assigns = [] for element in layout: if isinstance(element[1], list): - r_registers, r_assigns = _create_registers_assign(element[1], + r_csrs, r_assigns = _create_csrs_assign(element[1], atomic, getattr(target, element[0]), element[0] + "_") - registers += r_registers + csrs += r_csrs assigns += r_assigns else: name = element[0] @@ -40,10 +40,10 @@ def _create_registers_assign(layout, target, atomic, prefix=""): alignment = element[3] else: alignment = 0 - reg = RegisterField(nbits + alignment, reset=reset, atomic_write=atomic, name=prefix + name) - registers.append(reg) - assigns.append(getattr(target, name).eq(reg.field.r[alignment:])) - return registers, assigns + reg = CSRStorage(nbits + alignment, reset=reset, atomic_write=atomic, name=prefix + name) + csrs.append(reg) + assigns.append(getattr(target, name).eq(reg.storage[alignment:])) + return csrs, assigns (MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3) @@ -51,23 +51,23 @@ class SingleGenerator(Actor): def __init__(self, layout, mode): self._mode = mode Actor.__init__(self, ("source", Source, _convert_layout(layout))) - self._registers, self._assigns = _create_registers_assign(layout, + self._csrs, self._assigns = _create_csrs_assign(layout, self.token("source"), self._mode != MODE_SINGLE_SHOT) if mode == MODE_EXTERNAL: self.trigger = Signal() elif mode == MODE_SINGLE_SHOT: - shoot = RegisterRaw() - self._registers.insert(0, shoot) + shoot = CSR() + self._csrs.insert(0, shoot) self.trigger = shoot.re elif mode == MODE_CONTINUOUS: - enable = RegisterField() - self._registers.insert(0, enable) - self.trigger = enable.field.r + enable = CSRStorage() + self._csrs.insert(0, enable) + self.trigger = enable.storage else: raise ValueError - def get_registers(self): - return self._registers + def get_csrs(self): + return self._csrs def get_fragment(self): stb = self.endpoints["source"].stb @@ -79,19 +79,16 @@ class SingleGenerator(Actor): sync = [If(ack | ~stb, *stmts)] return Fragment(comb, sync) -class Collector(Actor): +class Collector(Actor, AutoCSR): def __init__(self, layout, depth=1024): Actor.__init__(self, ("sink", Sink, layout)) self._depth = depth self._dw = sum(len(s) for s in self.token("sink").flatten()) - self._r_wa = RegisterField(bits_for(self._depth-1), READ_WRITE, READ_WRITE) - self._r_wc = RegisterField(bits_for(self._depth), READ_WRITE, READ_WRITE, atomic_write=True) - self._r_ra = RegisterField(bits_for(self._depth-1), READ_WRITE, READ_ONLY) - self._r_rd = RegisterField(self._dw, READ_ONLY, WRITE_ONLY) - - def get_registers(self): - return [self._r_wa, self._r_wc, self._r_ra, self._r_rd] + self._r_wa = CSRStorage(bits_for(self._depth-1), write_from_dev=True) + self._r_wc = CSRStorage(bits_for(self._depth), write_from_dev=True, atomic_write=True) + self._r_ra = CSRStorage(bits_for(self._depth-1)) + self._r_rd = CSRStatus(self._dw) def get_fragment(self): mem = Memory(self._dw, self._depth) @@ -99,22 +96,22 @@ class Collector(Actor): rp = mem.get_port() comb = [ - If(self._r_wc.field.r != 0, + If(self._r_wc.r != 0, self.endpoints["sink"].ack.eq(1), If(self.endpoints["sink"].stb, - self._r_wa.field.we.eq(1), - self._r_wc.field.we.eq(1), + self._r_wa.we.eq(1), + self._r_wc.we.eq(1), wp.we.eq(1) ) ), - self._r_wa.field.w.eq(self._r_wa.field.r + 1), - self._r_wc.field.w.eq(self._r_wc.field.r - 1), + self._r_wa.dat_w.eq(self._r_wa.storage + 1), + self._r_wc.dat_w.eq(self._r_wc.storage - 1), - wp.adr.eq(self._r_wa.field.r), + wp.adr.eq(self._r_wa.storage), wp.dat_w.eq(Cat(*self.token("sink").flatten())), - rp.adr.eq(self._r_ra.field.r), - self._r_rd.field.w.eq(rp.dat_r) + rp.adr.eq(self._r_ra.storage), + self._r_rd.status.eq(rp.dat_r) ] return Fragment(comb, specials={mem}) diff --git a/migen/bank/csrgen.py b/migen/bank/csrgen.py index 6cf26b3e..01e4bf0f 100644 --- a/migen/bank/csrgen.py +++ b/migen/bank/csrgen.py @@ -1,91 +1,51 @@ from operator import itemgetter from migen.fhdl.structure import * +from migen.fhdl.module import Module from migen.bus import csr from migen.bank.description import * -class Bank: +class Bank(Module): def __init__(self, description, address=0, bus=None): - self.description = description - self.address = address if bus is None: bus = csr.Interface() self.bus = bus - - def get_fragment(self): - comb = [] - sync = [] - sel = Signal() - comb.append(sel.eq(self.bus.adr[9:] == self.address)) + ### + + if not description: + return - desc_exp = expand_description(self.description, csr.data_width) - nbits = bits_for(len(desc_exp)-1) + # Turn description into simple CSRs and claim ownership of compound CSR modules + simple_csrs = [] + for c in description: + if isinstance(c, CSR): + simple_csrs.append(c) + else: + c.finalize(csr.data_width) + simple_csrs += c.get_simple_csrs() + self.submodules += c + nbits = bits_for(len(simple_csrs)-1) + + # Decode selection + sel = Signal() + self.comb += sel.eq(self.bus.adr[9:] == address) # Bus writes - bwcases = {} - for i, reg in enumerate(desc_exp): - if isinstance(reg, RegisterRaw): - comb.append(reg.r.eq(self.bus.dat_w[:reg.size])) - comb.append(reg.re.eq(sel & \ + for i, c in enumerate(simple_csrs): + self.comb += [ + c.r.eq(self.bus.dat_w[:c.size]), + c.re.eq(sel & \ self.bus.we & \ - (self.bus.adr[:nbits] == i))) - elif isinstance(reg, RegisterFields): - bwra = [] - offset = 0 - for field in reg.fields: - if field.access_bus == WRITE_ONLY or field.access_bus == READ_WRITE: - bwra.append(field.storage.eq(self.bus.dat_w[offset:offset+field.size])) - offset += field.size - if bwra: - bwcases[i] = 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.bus.we & self.bus.adr[:nbits] == i, *commit_instr)) - else: - raise TypeError - if bwcases: - sync.append(If(sel & self.bus.we, Case(self.bus.adr[:nbits], bwcases))) + (self.bus.adr[:nbits] == i)) + ] # Bus reads - brcases = {} - for i, reg in enumerate(desc_exp): - if isinstance(reg, RegisterRaw): - brcases[i] = [self.bus.dat_r.eq(reg.w)] - elif isinstance(reg, RegisterFields): - brs = [] - reg_readable = False - for field in reg.fields: - if field.access_bus == READ_ONLY or field.access_bus == READ_WRITE: - brs.append(field.storage) - reg_readable = True - else: - brs.append(Replicate(0, field.size)) - if reg_readable: - brcases[i] = [self.bus.dat_r.eq(Cat(*brs))] - else: - raise TypeError - if brcases: - sync.append(self.bus.dat_r.eq(0)) - sync.append(If(sel, Case(self.bus.adr[:nbits], brcases))) - else: - comb.append(self.bus.dat_r.eq(0)) - - # Device access - for reg in self.description: - if isinstance(reg, RegisterFields): - for field in reg.fields: - if field.access_bus == READ_ONLY and field.access_dev == WRITE_ONLY: - comb.append(field.storage.eq(field.w)) - else: - if field.access_dev == READ_ONLY or field.access_dev == READ_WRITE: - comb.append(field.r.eq(field.storage)) - if field.access_dev == WRITE_ONLY or field.access_dev == READ_WRITE: - sync.append(If(field.we, field.storage.eq(field.w))) - - return Fragment(comb, sync) + brcases = dict((i, self.bus.dat_r.eq(c.w)) for i, c in enumerate(simple_csrs)) + self.sync += [ + self.bus.dat_r.eq(0), + If(sel, Case(self.bus.adr[:nbits], brcases)) + ] # address_map(name, memory) returns the CSR offset at which to map # the CSR object (register bank or memory). @@ -93,7 +53,7 @@ class Bank: # Otherwise, it is a memory object belonging to source.name. # address_map is called exactly once for each object at each call to # scan(), so it can have side effects. -class BankArray: +class BankArray(Module): def __init__(self, source, address_map): self.source = source self.address_map = address_map @@ -103,30 +63,29 @@ class BankArray: self.banks = [] self.srams = [] for name, obj in sorted(self.source.__dict__.items(), key=itemgetter(0)): - if hasattr(obj, "get_registers"): - registers = obj.get_registers() + if hasattr(obj, "get_csrs"): + csrs = obj.get_csrs() else: - registers = [] + csrs = [] if hasattr(obj, "get_memories"): memories = obj.get_memories() for memory in memories: mapaddr = self.address_map(name, memory) mmap = csr.SRAM(memory, mapaddr) - registers += mmap.get_registers() - self.srams.append((name, memory, mmap)) - if registers: + self.submodules += mmap + csrs += mmap.get_csrs() + self.srams.append((name, memory, mapaddr, mmap)) + if csrs: mapaddr = self.address_map(name, None) - rmap = Bank(registers, mapaddr) - self.banks.append((name, rmap)) + rmap = Bank(csrs, mapaddr) + self.submodules += rmap + self.banks.append((name, csrs, mapaddr, rmap)) def get_rmaps(self): - return [rmap for name, rmap in self.banks] + return [rmap for name, csrs, mapaddr, rmap in self.banks] def get_mmaps(self): - return [mmap for name, memory, mmap in self.srams] + return [mmap for name, memory, mapaddr, mmap in self.srams] def get_buses(self): return [i.bus for i in self.get_rmaps() + self.get_mmaps()] - - def get_fragment(self): - return sum([i.get_fragment() for i in self.get_rmaps() + self.get_mmaps()], Fragment()) diff --git a/migen/bank/description.py b/migen/bank/description.py index 160f2fb4..1eb5c2c1 100644 --- a/migen/bank/description.py +++ b/migen/bank/description.py @@ -1,70 +1,92 @@ from migen.fhdl.structure import * from migen.fhdl.specials import Memory +from migen.fhdl.module import * from migen.fhdl.tracer import get_obj_var_name -class _Register(HUID): - def __init__(self, name): +class _CSRBase(HUID): + def __init__(self, size, 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.") + raise ValueError("Cannot extract CSR name from code, need to specify.") if len(self.name) > 2 and self.name[:2] == "r_": self.name = self.name[2:] + self.size = size -class RegisterRaw(_Register): +class CSR(_CSRBase): def __init__(self, size=1, name=None): - _Register.__init__(self, name) - self.size = size - self.re = Signal() - self.r = Signal(self.size) - self.w = Signal(self.size) + _CSRBase.__init__(self, size, name) + self.re = Signal(name=self.name + "_re") + self.r = Signal(self.size, name=self.name + "_r") + self.w = Signal(self.size, name=self.name + "_w") - def get_size(self): - return self.size +class _CompoundCSR(_CSRBase, Module): + def __init__(self, size, name): + _CSRBase.__init__(self, size, name) + self.simple_csrs = [] -(READ_ONLY, WRITE_ONLY, READ_WRITE) = range(3) + def get_simple_csrs(self): + if not self.finalized: + raise FinalizeError + return self.simple_csrs -class Field: - 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.") - self.size = size - self.access_bus = access_bus - self.access_dev = access_dev + def do_finalize(self, busword): + raise NotImplementedError + +class CSRStatus(_CompoundCSR): + def __init__(self, size=1, name=None): + _CompoundCSR.__init__(self, size, name) + self.status = Signal(self.size) + + def do_finalize(self, busword): + nwords = (self.size + busword - 1)//busword + for i in reversed(range(nwords)): + nbits = min(self.size - i*busword, busword) + sc = CSR(nbits, self.name + str(i) if nwords > 1 else self.name) + self.comb += sc.w.eq(self.status[i*busword:i*busword+nbits]) + self.simple_csrs.append(sc) + +class CSRStorage(_CompoundCSR): + def __init__(self, size=1, reset=0, atomic_write=False, write_from_dev=False, name=None): + _CompoundCSR.__init__(self, size, name) self.storage = Signal(self.size, reset=reset) 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() - -class RegisterFields(_Register): - def __init__(self, *fields, name=None): - _Register.__init__(self, name) - self.fields = fields + if write_from_dev: + self.we = Signal() + self.dat_w = Signal(self.size) + self.sync += If(self.we, self.storage.eq(self.dat_w)) - def get_size(self): - return sum(field.size for field in self.fields) + def do_finalize(self, busword): + nwords = (self.size + busword - 1)//busword + if nwords > 1 and self.atomic_write: + backstore = Signal(self.size - busword, name=self.name + "_backstore") + for i in reversed(range(nwords)): + nbits = min(self.size - i*busword, busword) + sc = CSR(nbits, self.name + str(i) if nwords else self.name) + lo = i*busword + hi = lo+nbits + # read + self.comb += sc.w.eq(self.storage[lo:hi]) + # write + if nwords > 1 and self.atomic_write: + if i: + self.sync += If(sc.re, backstore[lo-busword:hi-busword].eq(sc.r)) + else: + self.sync += If(sc.re, self.storage.eq(Cat(sc.r, backstore))) + else: + self.sync += If(sc.re, self.storage[lo:hi].eq(sc.r)) -class RegisterField(RegisterFields): - 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) + self.simple_csrs.append(sc) -def regprefix(prefix, registers): - for register in registers: - register.name = prefix + register.name +def csrprefix(prefix, csrs): + for csr in csrs: + csr.name = prefix + csr.name def memprefix(prefix, memories): for memory in memories: memory.name_override = prefix + memory.name_override -class AutoReg: +class AutoCSR: def get_memories(self): r = [] for k, v in self.__dict__.items(): @@ -76,88 +98,13 @@ class AutoReg: r += memories return sorted(r, key=lambda x: x.huid) - def get_registers(self): + def get_csrs(self): r = [] for k, v in self.__dict__.items(): - if isinstance(v, _Register): + if isinstance(v, _CSRBase): r.append(v) - elif hasattr(v, "get_registers") and callable(v.get_registers): - registers = v.get_registers() - regprefix(k + "_", registers) - r += registers + elif hasattr(v, "get_csrs") and callable(v.get_csrs): + csrs = v.get_csrs() + csrprefix(k + "_", csrs) + r += csrs return sorted(r, key=lambda x: x.huid) - -(ALIAS_NON_ATOMIC, ALIAS_ATOMIC_HOLD, ALIAS_ATOMIC_COMMIT) = range(3) - -class FieldAlias: - 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 - if mode == ALIAS_ATOMIC_HOLD: - self.storage = Signal(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): - 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 = [] - offset = 0 - totalsize = 0 - for field in reg.fields: - offset += field.size - totalsize += field.size - if offset > busword: - # add padding - padding = busword - (totalsize % busword) - if padding != busword: - totalsize += padding - offset += padding - - top = field.size - 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: - 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(*f, name=reg.name)) - alias = FieldAlias(mode, field, top - slice2, top, commit_list) - f = [alias] - if mode == ALIAS_ATOMIC_HOLD: - commit_list.append(alias) - top -= slice2 - offset -= busword - else: - f.append(field) - if f: - d.append(RegisterFields(*f, name=reg.name)) - else: - raise TypeError - return d diff --git a/migen/bank/eventmanager.py b/migen/bank/eventmanager.py index d325d0de..b8981e59 100644 --- a/migen/bank/eventmanager.py +++ b/migen/bank/eventmanager.py @@ -15,7 +15,7 @@ class EventSourcePulse(_EventSource): class EventSourceLevel(_EventSource): pass -class EventManager(Module, AutoReg): +class EventManager(Module, AutoCSR): def __init__(self): self.irq = Signal() @@ -23,9 +23,9 @@ class EventManager(Module, AutoReg): sources_u = [v for v in self.__dict__.values() if isinstance(v, _EventSource)] sources = sorted(sources_u, key=lambda x: x.huid) n = len(sources) - self.status = RegisterRaw(n) - self.pending = RegisterRaw(n) - self.enable = RegisterFields(*(Field(1, READ_WRITE, READ_ONLY, name="e" + str(i)) for i in range(n))) + self.status = CSR(n) + self.pending = CSR(n) + self.enable = CSRStorage(n) # status for i, source in enumerate(sources): @@ -55,7 +55,7 @@ class EventManager(Module, AutoReg): self.comb += self.pending.w[i].eq(source.pending) # IRQ - irqs = [self.pending.w[i] & field.r for i, field in enumerate(self.enable.fields)] + irqs = [self.pending.w[i] & self.enable.storage[i] for i in range(n)] self.comb += self.irq.eq(optree("|", irqs)) def __setattr__(self, name, value): diff --git a/migen/bus/csr.py b/migen/bus/csr.py index 82b68aed..a320ae86 100644 --- a/migen/bus/csr.py +++ b/migen/bus/csr.py @@ -3,7 +3,7 @@ from migen.fhdl.specials import Memory from migen.fhdl.module import Module from migen.bus.simple import * from migen.bus.transactions import * -from migen.bank.description import RegisterField +from migen.bank.description import CSRStorage from migen.genlib.misc import chooser data_width = 8 @@ -68,7 +68,7 @@ class SRAM: self.word_bits = 0 page_bits = _compute_page_bits(self.mem.depth + self.word_bits) if page_bits: - self._page = RegisterField(page_bits, name=self.mem.name_override + "_page") + self._page = CSRStorage(page_bits, name=self.mem.name_override + "_page") else: self._page = None if read_only is None: @@ -81,7 +81,7 @@ class SRAM: bus = Interface() self.bus = bus - def get_registers(self): + def get_csrs(self): if self._page is None: return [] else: @@ -126,7 +126,7 @@ class SRAM: if self._page is None: comb.append(port.adr.eq(self.bus.adr[self.word_bits:len(port.adr)])) else: - pv = self._page.field.r + pv = self._page.storage comb.append(port.adr.eq(Cat(self.bus.adr[self.word_bits:len(port.adr)-len(pv)], pv))) return Fragment(comb, sync, specials={self.mem}) diff --git a/migen/flow/hooks.py b/migen/flow/hooks.py index 7d2d3658..82ae60a5 100644 --- a/migen/flow/hooks.py +++ b/migen/flow/hooks.py @@ -1,3 +1,5 @@ +from collections import defaultdict + from migen.fhdl.structure import * from migen.fhdl.module import Module from migen.flow.actor import * @@ -24,23 +26,18 @@ class EndpointSimHook(Module): else: self.on_inactive() -class DFGHook: +class DFGHook(Module): def __init__(self, dfg, create): assert(not dfg.is_abstract()) - self.nodepair_to_ep = dict() - for u, v, data in dfg.edges_iter(data=True): - if (u, v) in self.nodepair_to_ep: - ep_to_hook = self.nodepair_to_ep[(u, v)] - else: - ep_to_hook = dict() - self.nodepair_to_ep[(u, v)] = ep_to_hook + self.nodepair_to_ep = defaultdict(dict) + for hookn, (u, v, data) in dfg.edges_iter(data=True): + ep_to_hook = self.nodepair_to_ep[(u, v)] ep = data["source"] - ep_to_hook[ep] = create(u, ep, v) + h = create(u, ep, v) + ep_to_hook[ep] = h + setattr(self.submodules, "hook"+str(hookn), h) def hooks_iter(self): for v1 in self.nodepair_to_ep.values(): for v2 in v1.values(): yield v2 - - def get_fragment(self): - return sum([h.get_fragment() for h in self.hooks_iter()], Fragment()) diff --git a/migen/flow/isd.py b/migen/flow/isd.py index a112070c..1b7d2ea3 100644 --- a/migen/flow/isd.py +++ b/migen/flow/isd.py @@ -1,38 +1,30 @@ from migen.fhdl.structure import * +from migen.fhdl.module import Module from migen.bank.description import * from migen.flow.hooks import DFGHook ISD_MAGIC = 0x6ab4 -class EndpointReporter: +class EndpointReporter(Module, AutoCSR): def __init__(self, endpoint, nbits): - self.endpoint = endpoint - self.nbits = nbits self.reset = Signal() self.freeze = Signal() - self._ack_count = RegisterField(self.nbits, READ_ONLY, WRITE_ONLY) - self._nack_count = RegisterField(self.nbits, READ_ONLY, WRITE_ONLY) - self._cur_stb = Field(1, READ_ONLY, WRITE_ONLY) - self._cur_ack = Field(1, READ_ONLY, WRITE_ONLY) - self._cur_status = RegisterFields(self._cur_stb, self._cur_ack) + self._ack_count = CSRStatus(nbits) + self._nack_count = CSRStatus(nbits) + self._cur_status = CSRStatus(2) - def get_registers(self): - return [self._ack_count, self._nack_count, self._cur_status] - - def get_fragment(self): + ### + stb = Signal() ack = Signal() - ack_count = Signal(self.nbits) - nack_count = Signal(self.nbits) - comb = [ - self._cur_stb.w.eq(stb), - self._cur_ack.w.eq(ack) - ] - sync = [ + self.comb += self._cur_status.status.eq(Cat(stb, ack)) + ack_count = Signal(nbits) + nack_count = Signal(nbits) + self.sync += [ # register monitored signals - stb.eq(self.endpoint.stb), - ack.eq(self.endpoint.ack), + stb.eq(endpoint.stb), + ack.eq(endpoint.ack), # count operations If(self.reset, ack_count.eq(0), @@ -47,49 +39,31 @@ class EndpointReporter: ) ), If(~self.freeze, - self._ack_count.field.w.eq(ack_count), - self._nack_count.field.w.eq(nack_count) + self._ack_count.status.eq(ack_count), + self._nack_count.status.eq(nack_count) ) ] - return Fragment(comb, sync) -class DFGReporter(DFGHook): +class DFGReporter(DFGHook, AutoCSR): def __init__(self, dfg, nbits): - self._nbits = nbits + self._r_magic = CSRStatus(16) + self._r_neps = CSRStatus(8) + self._r_nbits = CSRStatus(8) + self._r_freeze = CSRStorage() + self._r_reset = CSR() - self._r_magic = RegisterField(16, access_bus=READ_ONLY, access_dev=WRITE_ONLY) - self._r_neps = RegisterField(8, access_bus=READ_ONLY, access_dev=WRITE_ONLY) - self._r_nbits = RegisterField(8, access_bus=READ_ONLY, access_dev=WRITE_ONLY) - self._r_freeze = RegisterField() - self._r_reset = RegisterRaw() - - self.order = [] - DFGHook.__init__(self, dfg, self._create) - - def _create(self, u, ep, v): - self.order.append((u, ep, v)) - return EndpointReporter(u.actor.endpoints[ep], self._nbits) - - def print_map(self): - for n, (u, ep, v) in enumerate(self.order): - print("#" + str(n) + ": " + str(u) + ":" + ep + " -> " + str(v)) - - def get_registers(self): - registers = [self._r_magic, self._r_neps, self._r_nbits, - self._r_freeze, self._r_reset] - for u, ep, v in self.order: - registers += self.nodepair_to_ep[(u, v)][ep].get_registers() - return registers - - def get_fragment(self): - comb = [ - self._r_magic.field.w.eq(ISD_MAGIC), - self._r_neps.field.w.eq(len(self.order)), - self._r_nbits.field.w.eq(self._nbits) + ### + + DFGHook.__init__(self, dfg, + lambda u, ep, v: EndpointReporter(u.endpoints[ep], nbits)) + + self.comb += [ + self._r_magic.status.eq(ISD_MAGIC), + self._r_neps.status.eq(len(self.hooks_iter())), + self._r_nbits.status.eq(nbits) ] for h in self.hooks_iter(): - comb += [ - h.freeze.eq(self._r_freeze.field.r), + self.comb += [ + h.freeze.eq(self._r_freeze.storage), h.reset.eq(self._r_reset.re) ] - return Fragment(comb) + DFGHook.get_fragment(self) diff --git a/migen/flow/network.py b/migen/flow/network.py index df739eef..ee696294 100644 --- a/migen/flow/network.py +++ b/migen/flow/network.py @@ -211,9 +211,9 @@ class CompositeActor(Actor): self.debugger = DFGReporter(self.dfg, debugger_nbits) Actor.__init__(self) - def get_registers(self): + def get_csrs(self): if hasattr(self, "debugger"): - return self.debugger.get_registers() + return self.debugger.get_csrs() else: return []