add wishbone components
This commit is contained in:
parent
88db84cfd7
commit
70638e6d87
|
@ -1,20 +0,0 @@
|
|||
from nmigen import *
|
||||
|
||||
|
||||
class RoundRobin(Elaboratable):
|
||||
def __init__(self, n):
|
||||
self.n = n
|
||||
self.request = Signal(n)
|
||||
self.grant = Signal(max=n)
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
with m.Switch(self.grant):
|
||||
for i in range(self.n):
|
||||
with m.Case(i):
|
||||
with m.If(~self.request[i]):
|
||||
for j in reversed(range(i+1, i+self.n)):
|
||||
t = j % self.n
|
||||
with m.If(self.request[t]):
|
||||
m.d.sync += self.grant.eq(t)
|
||||
return m
|
|
@ -0,0 +1,210 @@
|
|||
from enum import Enum
|
||||
from functools import reduce
|
||||
from operator import or_
|
||||
|
||||
from nmigen import *
|
||||
from nmigen.hdl.rec import *
|
||||
|
||||
|
||||
__all__ = ["Cycle", "Interface", "Arbiter", "Decoder", "InterconnectShared"]
|
||||
|
||||
|
||||
class Cycle(Enum):
|
||||
CLASSIC = 0
|
||||
CONSTANT = 1
|
||||
INCREMENT = 2
|
||||
END = 7
|
||||
|
||||
|
||||
wishbone_layout = [
|
||||
("adr", 30, DIR_FANOUT),
|
||||
("dat_w", 32, DIR_FANOUT),
|
||||
("dat_r", 32, DIR_FANIN),
|
||||
("sel", 4, DIR_FANOUT),
|
||||
("cyc", 1, DIR_FANOUT),
|
||||
("stb", 1, DIR_FANOUT),
|
||||
("ack", 1, DIR_FANIN),
|
||||
("we", 1, DIR_FANOUT),
|
||||
("cti", 3, DIR_FANOUT),
|
||||
("bte", 2, DIR_FANOUT),
|
||||
("err", 1, DIR_FANIN)
|
||||
]
|
||||
|
||||
|
||||
class Interface(Record):
|
||||
def __init__(self):
|
||||
Record.__init__(self, wishbone_layout)
|
||||
|
||||
def _do_transaction(self):
|
||||
yield self.cyc.eq(1)
|
||||
yield self.stb.eq(1)
|
||||
yield
|
||||
while not (yield self.ack):
|
||||
yield
|
||||
yield self.cyc.eq(0)
|
||||
yield self.stb.eq(0)
|
||||
|
||||
def write(self, adr, dat, sel=None):
|
||||
if sel is None:
|
||||
sel = 2**len(self.sel) - 1
|
||||
yield self.adr.eq(adr)
|
||||
yield self.dat_w.eq(dat)
|
||||
yield self.sel.eq(sel)
|
||||
yield self.we.eq(1)
|
||||
yield from self._do_transaction()
|
||||
|
||||
def read(self, adr):
|
||||
yield self.adr.eq(adr)
|
||||
yield self.we.eq(0)
|
||||
yield from self._do_transaction()
|
||||
return (yield self.dat_r)
|
||||
|
||||
|
||||
class SRAM(Elaboratable):
|
||||
def __init__(self, mem, read_only=False, bus=None):
|
||||
self.mem = mem
|
||||
self.read_only = read_only
|
||||
if bus is None:
|
||||
bus = Interface()
|
||||
self.bus = bus
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
if self.mem.width > len(self.bus.dat_r):
|
||||
raise NotImplementedError
|
||||
|
||||
# read
|
||||
m.submodules.rdport = rdport = self.mem.read_port()
|
||||
m.d.comb += [
|
||||
rdport.addr.eq(self.bus.adr[:len(rdport.addr)]),
|
||||
self.bus.dat_r.eq(rdport.data)
|
||||
]
|
||||
|
||||
# write
|
||||
if not self.read_only:
|
||||
m.submodules.wrport = wrport = self.mem.write_port(granularity=8)
|
||||
m.d.comb += [
|
||||
wrport.addr.eq(self.bus.adr[:len(rdport.addr)]),
|
||||
wrport.data.eq(self.bus.dat_w)
|
||||
]
|
||||
for i in range(4):
|
||||
m.d.comb += wrport.en[i].eq(self.bus.cyc & self.bus.stb & self.bus.we & self.bus.sel[i])
|
||||
|
||||
# generate ack
|
||||
m.d.sync += self.bus.ack.eq(0)
|
||||
with m.If(self.bus.cyc & self.bus.stb & ~self.bus.ack):
|
||||
m.d.sync += self.bus.ack.eq(1)
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class RoundRobin(Elaboratable):
|
||||
def __init__(self, n):
|
||||
self.n = n
|
||||
self.request = Signal(n)
|
||||
self.grant = Signal(max=n)
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
with m.Switch(self.grant):
|
||||
for i in range(self.n):
|
||||
with m.Case(i):
|
||||
with m.If(~self.request[i]):
|
||||
for j in reversed(range(i+1, i+self.n)):
|
||||
t = j % self.n
|
||||
with m.If(self.request[t]):
|
||||
m.d.sync += self.grant.eq(t)
|
||||
return m
|
||||
|
||||
|
||||
class Arbiter(Elaboratable):
|
||||
def __init__(self, masters, target):
|
||||
self.masters = masters
|
||||
self.target = target
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
m.submodules.rr = rr = RoundRobin(len(self.masters))
|
||||
|
||||
# mux master->target signals
|
||||
for name, size, direction in wishbone_layout:
|
||||
if direction == DIR_FANOUT:
|
||||
choices = Array(getattr(m, name) for m in self.masters)
|
||||
m.d.comb += getattr(self.target, name).eq(choices[rr.grant])
|
||||
|
||||
# connect target->master signals
|
||||
for name, size, direction in wishbone_layout:
|
||||
if direction == DIR_FANIN:
|
||||
source = getattr(self.target, name)
|
||||
for i, master in enumerate(self.masters):
|
||||
dest = getattr(master, name)
|
||||
if name == "ack" or name == "err":
|
||||
m.d.comb += dest.eq(source & (rr.grant == i))
|
||||
else:
|
||||
m.d.comb += dest.eq(source)
|
||||
|
||||
# connect bus requests to round-robin selector
|
||||
reqs = [m.cyc & ~m.ack for m in self.masters]
|
||||
m.d.comb += rr.request.eq(Cat(*reqs))
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class Decoder(Elaboratable):
|
||||
def __init__(self, master, targets, register=False):
|
||||
self.master = master
|
||||
self.targets = targets
|
||||
self.register = register
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
nt = len(self.targets)
|
||||
target_sel = Signal(nt)
|
||||
target_sel_r = Signal(nt)
|
||||
|
||||
# decode target addresses
|
||||
for i, (fun, bus) in enumerate(self.targets):
|
||||
m.d.comb += target_sel[i].eq(fun(self.master.adr))
|
||||
if self.register:
|
||||
m.d.sync += target_sel_r.eq(target_sel)
|
||||
else:
|
||||
m.d.comb += target_sel_r.eq(target_sel)
|
||||
|
||||
# connect master->targets signals except cyc
|
||||
for target in self.targets:
|
||||
for name, size, direction in wishbone_layout:
|
||||
if direction == DIR_FANOUT and name != "cyc":
|
||||
m.d.comb += getattr(target[1], name).eq(getattr(self.master, name))
|
||||
|
||||
# combine cyc with target selection signals
|
||||
for i, target in enumerate(self.targets):
|
||||
m.d.comb += target[1].cyc.eq(self.master.cyc & target_sel[i])
|
||||
|
||||
# generate master ack (resp. err) by ORing all target acks (resp. errs)
|
||||
m.d.comb += [
|
||||
self.master.ack.eq(reduce(or_, [target[1].ack for target in self.targets])),
|
||||
self.master.err.eq(reduce(or_, [target[1].err for target in self.targets]))
|
||||
]
|
||||
|
||||
# mux (1-hot) target data return
|
||||
masked = [Repl(target_sel_r[i], len(self.master.dat_r)) & self.targets[i][1].dat_r for i in range(nt)]
|
||||
m.d.comb += self.master.dat_r.eq(reduce(or_, masked))
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class InterconnectShared(Module):
|
||||
def __init__(self, masters, targets, register=False):
|
||||
self.masters = masters
|
||||
self.targets = targets
|
||||
self.register = register
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
shared = Interface()
|
||||
m.submodules.arbiter = Arbiter(self.masters, shared)
|
||||
m.submodules.decoder = Decoder(shared, self.targets, self.register)
|
||||
return m
|
Loading…
Reference in New Issue