New CSR API

This commit is contained in:
Sebastien Bourdeauducq 2013-03-30 17:28:41 +01:00
parent 633e5e6747
commit c4f4143591
9 changed files with 201 additions and 328 deletions

View file

@ -3,12 +3,11 @@ from migen.fhdl.module import Module
from migen.fhdl import verilog from migen.fhdl import verilog
from migen.genlib.cdc import MultiReg from migen.genlib.cdc import MultiReg
from migen.bank import description, csrgen from migen.bank import description, csrgen
from migen.bank.description import READ_ONLY, WRITE_ONLY
class Example(Module): class Example(Module):
def __init__(self, ninputs=32, noutputs=32): def __init__(self, ninputs=32, noutputs=32):
r_o = description.RegisterField(noutputs, atomic_write=True) r_o = description.CSRStorage(noutputs, atomic_write=True)
r_i = description.RegisterField(ninputs, READ_ONLY, WRITE_ONLY) r_i = description.CSRStatus(ninputs)
self.submodules.bank = csrgen.Bank([r_o, r_i]) self.submodules.bank = csrgen.Bank([r_o, r_i])
self.gpio_in = Signal(ninputs) self.gpio_in = Signal(ninputs)
@ -17,10 +16,10 @@ class Example(Module):
### ###
gpio_in_s = Signal(ninputs) 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 += [ self.comb += [
r_i.field.w.eq(gpio_in_s), self.gpio_out.eq(r_o.storage),
self.gpio_out.eq(r_o.field.r) r_i.status.eq(gpio_in_s)
] ]
example = Example() example = Example()

View file

@ -18,16 +18,16 @@ def _convert_layout(layout):
r.append((element[0], element[1])) r.append((element[0], element[1]))
return r return r
def _create_registers_assign(layout, target, atomic, prefix=""): def _create_csrs_assign(layout, target, atomic, prefix=""):
registers = [] csrs = []
assigns = [] assigns = []
for element in layout: for element in layout:
if isinstance(element[1], list): if isinstance(element[1], list):
r_registers, r_assigns = _create_registers_assign(element[1], r_csrs, r_assigns = _create_csrs_assign(element[1],
atomic, atomic,
getattr(target, element[0]), getattr(target, element[0]),
element[0] + "_") element[0] + "_")
registers += r_registers csrs += r_csrs
assigns += r_assigns assigns += r_assigns
else: else:
name = element[0] name = element[0]
@ -40,10 +40,10 @@ def _create_registers_assign(layout, target, atomic, prefix=""):
alignment = element[3] alignment = element[3]
else: else:
alignment = 0 alignment = 0
reg = RegisterField(nbits + alignment, reset=reset, atomic_write=atomic, name=prefix + name) reg = CSRStorage(nbits + alignment, reset=reset, atomic_write=atomic, name=prefix + name)
registers.append(reg) csrs.append(reg)
assigns.append(getattr(target, name).eq(reg.field.r[alignment:])) assigns.append(getattr(target, name).eq(reg.storage[alignment:]))
return registers, assigns return csrs, assigns
(MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3) (MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3)
@ -51,23 +51,23 @@ class SingleGenerator(Actor):
def __init__(self, layout, mode): def __init__(self, layout, mode):
self._mode = mode self._mode = mode
Actor.__init__(self, ("source", Source, _convert_layout(layout))) 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) self.token("source"), self._mode != MODE_SINGLE_SHOT)
if mode == MODE_EXTERNAL: if mode == MODE_EXTERNAL:
self.trigger = Signal() self.trigger = Signal()
elif mode == MODE_SINGLE_SHOT: elif mode == MODE_SINGLE_SHOT:
shoot = RegisterRaw() shoot = CSR()
self._registers.insert(0, shoot) self._csrs.insert(0, shoot)
self.trigger = shoot.re self.trigger = shoot.re
elif mode == MODE_CONTINUOUS: elif mode == MODE_CONTINUOUS:
enable = RegisterField() enable = CSRStorage()
self._registers.insert(0, enable) self._csrs.insert(0, enable)
self.trigger = enable.field.r self.trigger = enable.storage
else: else:
raise ValueError raise ValueError
def get_registers(self): def get_csrs(self):
return self._registers return self._csrs
def get_fragment(self): def get_fragment(self):
stb = self.endpoints["source"].stb stb = self.endpoints["source"].stb
@ -79,19 +79,16 @@ class SingleGenerator(Actor):
sync = [If(ack | ~stb, *stmts)] sync = [If(ack | ~stb, *stmts)]
return Fragment(comb, sync) return Fragment(comb, sync)
class Collector(Actor): class Collector(Actor, AutoCSR):
def __init__(self, layout, depth=1024): def __init__(self, layout, depth=1024):
Actor.__init__(self, ("sink", Sink, layout)) Actor.__init__(self, ("sink", Sink, layout))
self._depth = depth self._depth = depth
self._dw = sum(len(s) for s in self.token("sink").flatten()) 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_wa = CSRStorage(bits_for(self._depth-1), write_from_dev=True)
self._r_wc = RegisterField(bits_for(self._depth), READ_WRITE, READ_WRITE, atomic_write=True) self._r_wc = CSRStorage(bits_for(self._depth), write_from_dev=True, atomic_write=True)
self._r_ra = RegisterField(bits_for(self._depth-1), READ_WRITE, READ_ONLY) self._r_ra = CSRStorage(bits_for(self._depth-1))
self._r_rd = RegisterField(self._dw, READ_ONLY, WRITE_ONLY) self._r_rd = CSRStatus(self._dw)
def get_registers(self):
return [self._r_wa, self._r_wc, self._r_ra, self._r_rd]
def get_fragment(self): def get_fragment(self):
mem = Memory(self._dw, self._depth) mem = Memory(self._dw, self._depth)
@ -99,22 +96,22 @@ class Collector(Actor):
rp = mem.get_port() rp = mem.get_port()
comb = [ comb = [
If(self._r_wc.field.r != 0, If(self._r_wc.r != 0,
self.endpoints["sink"].ack.eq(1), self.endpoints["sink"].ack.eq(1),
If(self.endpoints["sink"].stb, If(self.endpoints["sink"].stb,
self._r_wa.field.we.eq(1), self._r_wa.we.eq(1),
self._r_wc.field.we.eq(1), self._r_wc.we.eq(1),
wp.we.eq(1) wp.we.eq(1)
) )
), ),
self._r_wa.field.w.eq(self._r_wa.field.r + 1), self._r_wa.dat_w.eq(self._r_wa.storage + 1),
self._r_wc.field.w.eq(self._r_wc.field.r - 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())), wp.dat_w.eq(Cat(*self.token("sink").flatten())),
rp.adr.eq(self._r_ra.field.r), rp.adr.eq(self._r_ra.storage),
self._r_rd.field.w.eq(rp.dat_r) self._r_rd.status.eq(rp.dat_r)
] ]
return Fragment(comb, specials={mem}) return Fragment(comb, specials={mem})

View file

@ -1,91 +1,51 @@
from operator import itemgetter from operator import itemgetter
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.bus import csr from migen.bus import csr
from migen.bank.description import * from migen.bank.description import *
class Bank: class Bank(Module):
def __init__(self, description, address=0, bus=None): def __init__(self, description, address=0, bus=None):
self.description = description
self.address = address
if bus is None: if bus is None:
bus = csr.Interface() bus = csr.Interface()
self.bus = bus self.bus = bus
def get_fragment(self):
comb = []
sync = []
###
if not description:
return
# 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() sel = Signal()
comb.append(sel.eq(self.bus.adr[9:] == self.address)) self.comb += sel.eq(self.bus.adr[9:] == address)
desc_exp = expand_description(self.description, csr.data_width)
nbits = bits_for(len(desc_exp)-1)
# Bus writes # Bus writes
bwcases = {} for i, c in enumerate(simple_csrs):
for i, reg in enumerate(desc_exp): self.comb += [
if isinstance(reg, RegisterRaw): c.r.eq(self.bus.dat_w[:c.size]),
comb.append(reg.r.eq(self.bus.dat_w[:reg.size])) c.re.eq(sel & \
comb.append(reg.re.eq(sel & \
self.bus.we & \ self.bus.we & \
(self.bus.adr[:nbits] == i))) (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)))
# Bus reads # Bus reads
brcases = {} brcases = dict((i, self.bus.dat_r.eq(c.w)) for i, c in enumerate(simple_csrs))
for i, reg in enumerate(desc_exp): self.sync += [
if isinstance(reg, RegisterRaw): self.bus.dat_r.eq(0),
brcases[i] = [self.bus.dat_r.eq(reg.w)] If(sel, Case(self.bus.adr[:nbits], brcases))
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)
# address_map(name, memory) returns the CSR offset at which to map # address_map(name, memory) returns the CSR offset at which to map
# the CSR object (register bank or memory). # the CSR object (register bank or memory).
@ -93,7 +53,7 @@ class Bank:
# Otherwise, it is a memory object belonging to source.name. # Otherwise, it is a memory object belonging to source.name.
# address_map is called exactly once for each object at each call to # address_map is called exactly once for each object at each call to
# scan(), so it can have side effects. # scan(), so it can have side effects.
class BankArray: class BankArray(Module):
def __init__(self, source, address_map): def __init__(self, source, address_map):
self.source = source self.source = source
self.address_map = address_map self.address_map = address_map
@ -103,30 +63,29 @@ class BankArray:
self.banks = [] self.banks = []
self.srams = [] self.srams = []
for name, obj in sorted(self.source.__dict__.items(), key=itemgetter(0)): for name, obj in sorted(self.source.__dict__.items(), key=itemgetter(0)):
if hasattr(obj, "get_registers"): if hasattr(obj, "get_csrs"):
registers = obj.get_registers() csrs = obj.get_csrs()
else: else:
registers = [] csrs = []
if hasattr(obj, "get_memories"): if hasattr(obj, "get_memories"):
memories = obj.get_memories() memories = obj.get_memories()
for memory in memories: for memory in memories:
mapaddr = self.address_map(name, memory) mapaddr = self.address_map(name, memory)
mmap = csr.SRAM(memory, mapaddr) mmap = csr.SRAM(memory, mapaddr)
registers += mmap.get_registers() self.submodules += mmap
self.srams.append((name, memory, mmap)) csrs += mmap.get_csrs()
if registers: self.srams.append((name, memory, mapaddr, mmap))
if csrs:
mapaddr = self.address_map(name, None) mapaddr = self.address_map(name, None)
rmap = Bank(registers, mapaddr) rmap = Bank(csrs, mapaddr)
self.banks.append((name, rmap)) self.submodules += rmap
self.banks.append((name, csrs, mapaddr, rmap))
def get_rmaps(self): 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): 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): def get_buses(self):
return [i.bus for i in self.get_rmaps() + self.get_mmaps()] 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())

View file

@ -1,70 +1,92 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.specials import Memory from migen.fhdl.specials import Memory
from migen.fhdl.module import *
from migen.fhdl.tracer import get_obj_var_name from migen.fhdl.tracer import get_obj_var_name
class _Register(HUID): class _CSRBase(HUID):
def __init__(self, name): def __init__(self, size, name):
HUID.__init__(self) HUID.__init__(self)
self.name = get_obj_var_name(name) self.name = get_obj_var_name(name)
if self.name is None: 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_": if len(self.name) > 2 and self.name[:2] == "r_":
self.name = self.name[2:] self.name = self.name[2:]
self.size = size
class RegisterRaw(_Register): class CSR(_CSRBase):
def __init__(self, size=1, name=None): def __init__(self, size=1, name=None):
_Register.__init__(self, name) _CSRBase.__init__(self, size, name)
self.size = size self.re = Signal(name=self.name + "_re")
self.re = Signal() self.r = Signal(self.size, name=self.name + "_r")
self.r = Signal(self.size) self.w = Signal(self.size, name=self.name + "_w")
self.w = Signal(self.size)
def get_size(self): class _CompoundCSR(_CSRBase, Module):
return self.size 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 do_finalize(self, busword):
def __init__(self, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False, name=None): raise NotImplementedError
self.name = get_obj_var_name(name)
if self.name is None: class CSRStatus(_CompoundCSR):
raise ValueError("Cannot extract field name from code, need to specify.") def __init__(self, size=1, name=None):
self.size = size _CompoundCSR.__init__(self, size, name)
self.access_bus = access_bus self.status = Signal(self.size)
self.access_dev = access_dev
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.storage = Signal(self.size, reset=reset)
self.atomic_write = atomic_write self.atomic_write = atomic_write
if self.access_bus == READ_ONLY and self.access_dev == WRITE_ONLY: if write_from_dev:
self.w = Signal(self.size) self.we = Signal()
else: self.dat_w = Signal(self.size)
if self.access_dev == READ_ONLY or self.access_dev == READ_WRITE: self.sync += If(self.we, self.storage.eq(self.dat_w))
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 do_finalize(self, busword):
def __init__(self, *fields, name=None): nwords = (self.size + busword - 1)//busword
_Register.__init__(self, name) if nwords > 1 and self.atomic_write:
self.fields = fields 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))
def get_size(self): self.simple_csrs.append(sc)
return sum(field.size for field in self.fields)
class RegisterField(RegisterFields): def csrprefix(prefix, csrs):
def __init__(self, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False, name=None): for csr in csrs:
self.field = Field(size, access_bus, access_dev, reset, atomic_write, name="") csr.name = prefix + csr.name
RegisterFields.__init__(self, self.field, name=name)
def regprefix(prefix, registers):
for register in registers:
register.name = prefix + register.name
def memprefix(prefix, memories): def memprefix(prefix, memories):
for memory in memories: for memory in memories:
memory.name_override = prefix + memory.name_override memory.name_override = prefix + memory.name_override
class AutoReg: class AutoCSR:
def get_memories(self): def get_memories(self):
r = [] r = []
for k, v in self.__dict__.items(): for k, v in self.__dict__.items():
@ -76,88 +98,13 @@ class AutoReg:
r += memories r += memories
return sorted(r, key=lambda x: x.huid) return sorted(r, key=lambda x: x.huid)
def get_registers(self): def get_csrs(self):
r = [] r = []
for k, v in self.__dict__.items(): for k, v in self.__dict__.items():
if isinstance(v, _Register): if isinstance(v, _CSRBase):
r.append(v) r.append(v)
elif hasattr(v, "get_registers") and callable(v.get_registers): elif hasattr(v, "get_csrs") and callable(v.get_csrs):
registers = v.get_registers() csrs = v.get_csrs()
regprefix(k + "_", registers) csrprefix(k + "_", csrs)
r += registers r += csrs
return sorted(r, key=lambda x: x.huid) 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

View file

@ -15,7 +15,7 @@ class EventSourcePulse(_EventSource):
class EventSourceLevel(_EventSource): class EventSourceLevel(_EventSource):
pass pass
class EventManager(Module, AutoReg): class EventManager(Module, AutoCSR):
def __init__(self): def __init__(self):
self.irq = Signal() 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_u = [v for v in self.__dict__.values() if isinstance(v, _EventSource)]
sources = sorted(sources_u, key=lambda x: x.huid) sources = sorted(sources_u, key=lambda x: x.huid)
n = len(sources) n = len(sources)
self.status = RegisterRaw(n) self.status = CSR(n)
self.pending = RegisterRaw(n) self.pending = CSR(n)
self.enable = RegisterFields(*(Field(1, READ_WRITE, READ_ONLY, name="e" + str(i)) for i in range(n))) self.enable = CSRStorage(n)
# status # status
for i, source in enumerate(sources): for i, source in enumerate(sources):
@ -55,7 +55,7 @@ class EventManager(Module, AutoReg):
self.comb += self.pending.w[i].eq(source.pending) self.comb += self.pending.w[i].eq(source.pending)
# IRQ # 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)) self.comb += self.irq.eq(optree("|", irqs))
def __setattr__(self, name, value): def __setattr__(self, name, value):

View file

@ -3,7 +3,7 @@ from migen.fhdl.specials import Memory
from migen.fhdl.module import Module from migen.fhdl.module import Module
from migen.bus.simple import * from migen.bus.simple import *
from migen.bus.transactions import * from migen.bus.transactions import *
from migen.bank.description import RegisterField from migen.bank.description import CSRStorage
from migen.genlib.misc import chooser from migen.genlib.misc import chooser
data_width = 8 data_width = 8
@ -68,7 +68,7 @@ class SRAM:
self.word_bits = 0 self.word_bits = 0
page_bits = _compute_page_bits(self.mem.depth + self.word_bits) page_bits = _compute_page_bits(self.mem.depth + self.word_bits)
if page_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: else:
self._page = None self._page = None
if read_only is None: if read_only is None:
@ -81,7 +81,7 @@ class SRAM:
bus = Interface() bus = Interface()
self.bus = bus self.bus = bus
def get_registers(self): def get_csrs(self):
if self._page is None: if self._page is None:
return [] return []
else: else:
@ -126,7 +126,7 @@ class SRAM:
if self._page is None: if self._page is None:
comb.append(port.adr.eq(self.bus.adr[self.word_bits:len(port.adr)])) comb.append(port.adr.eq(self.bus.adr[self.word_bits:len(port.adr)]))
else: 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))) 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}) return Fragment(comb, sync, specials={self.mem})

View file

@ -1,3 +1,5 @@
from collections import defaultdict
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module from migen.fhdl.module import Module
from migen.flow.actor import * from migen.flow.actor import *
@ -24,23 +26,18 @@ class EndpointSimHook(Module):
else: else:
self.on_inactive() self.on_inactive()
class DFGHook: class DFGHook(Module):
def __init__(self, dfg, create): def __init__(self, dfg, create):
assert(not dfg.is_abstract()) assert(not dfg.is_abstract())
self.nodepair_to_ep = dict() self.nodepair_to_ep = defaultdict(dict)
for u, v, data in dfg.edges_iter(data=True): for hookn, (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)]
ep_to_hook = self.nodepair_to_ep[(u, v)]
else:
ep_to_hook = dict()
self.nodepair_to_ep[(u, v)] = ep_to_hook
ep = data["source"] 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): def hooks_iter(self):
for v1 in self.nodepair_to_ep.values(): for v1 in self.nodepair_to_ep.values():
for v2 in v1.values(): for v2 in v1.values():
yield v2 yield v2
def get_fragment(self):
return sum([h.get_fragment() for h in self.hooks_iter()], Fragment())

View file

@ -1,38 +1,30 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.bank.description import * from migen.bank.description import *
from migen.flow.hooks import DFGHook from migen.flow.hooks import DFGHook
ISD_MAGIC = 0x6ab4 ISD_MAGIC = 0x6ab4
class EndpointReporter: class EndpointReporter(Module, AutoCSR):
def __init__(self, endpoint, nbits): def __init__(self, endpoint, nbits):
self.endpoint = endpoint
self.nbits = nbits
self.reset = Signal() self.reset = Signal()
self.freeze = Signal() self.freeze = Signal()
self._ack_count = RegisterField(self.nbits, READ_ONLY, WRITE_ONLY) self._ack_count = CSRStatus(nbits)
self._nack_count = RegisterField(self.nbits, READ_ONLY, WRITE_ONLY) self._nack_count = CSRStatus(nbits)
self._cur_stb = Field(1, READ_ONLY, WRITE_ONLY) self._cur_status = CSRStatus(2)
self._cur_ack = Field(1, READ_ONLY, WRITE_ONLY)
self._cur_status = RegisterFields(self._cur_stb, self._cur_ack)
def get_registers(self): ###
return [self._ack_count, self._nack_count, self._cur_status]
def get_fragment(self):
stb = Signal() stb = Signal()
ack = Signal() ack = Signal()
ack_count = Signal(self.nbits) self.comb += self._cur_status.status.eq(Cat(stb, ack))
nack_count = Signal(self.nbits) ack_count = Signal(nbits)
comb = [ nack_count = Signal(nbits)
self._cur_stb.w.eq(stb), self.sync += [
self._cur_ack.w.eq(ack)
]
sync = [
# register monitored signals # register monitored signals
stb.eq(self.endpoint.stb), stb.eq(endpoint.stb),
ack.eq(self.endpoint.ack), ack.eq(endpoint.ack),
# count operations # count operations
If(self.reset, If(self.reset,
ack_count.eq(0), ack_count.eq(0),
@ -47,49 +39,31 @@ class EndpointReporter:
) )
), ),
If(~self.freeze, If(~self.freeze,
self._ack_count.field.w.eq(ack_count), self._ack_count.status.eq(ack_count),
self._nack_count.field.w.eq(nack_count) self._nack_count.status.eq(nack_count)
) )
] ]
return Fragment(comb, sync)
class DFGReporter(DFGHook): class DFGReporter(DFGHook, AutoCSR):
def __init__(self, dfg, nbits): 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) DFGHook.__init__(self, dfg,
self._r_freeze = RegisterField() lambda u, ep, v: EndpointReporter(u.endpoints[ep], nbits))
self._r_reset = RegisterRaw()
self.comb += [
self.order = [] self._r_magic.status.eq(ISD_MAGIC),
DFGHook.__init__(self, dfg, self._create) self._r_neps.status.eq(len(self.hooks_iter())),
self._r_nbits.status.eq(nbits)
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)
] ]
for h in self.hooks_iter(): for h in self.hooks_iter():
comb += [ self.comb += [
h.freeze.eq(self._r_freeze.field.r), h.freeze.eq(self._r_freeze.storage),
h.reset.eq(self._r_reset.re) h.reset.eq(self._r_reset.re)
] ]
return Fragment(comb) + DFGHook.get_fragment(self)

View file

@ -211,9 +211,9 @@ class CompositeActor(Actor):
self.debugger = DFGReporter(self.dfg, debugger_nbits) self.debugger = DFGReporter(self.dfg, debugger_nbits)
Actor.__init__(self) Actor.__init__(self)
def get_registers(self): def get_csrs(self):
if hasattr(self, "debugger"): if hasattr(self, "debugger"):
return self.debugger.get_registers() return self.debugger.get_csrs()
else: else:
return [] return []