From 70638e6d8794cbe95da4345a3f1b03befa227435 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 2 May 2019 12:53:08 +0800 Subject: [PATCH] add wishbone components --- heavycomps/heavycomps/roundrobin.py | 20 --- heavycomps/heavycomps/wishbone.py | 210 ++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 20 deletions(-) delete mode 100644 heavycomps/heavycomps/roundrobin.py create mode 100644 heavycomps/heavycomps/wishbone.py diff --git a/heavycomps/heavycomps/roundrobin.py b/heavycomps/heavycomps/roundrobin.py deleted file mode 100644 index 5963345..0000000 --- a/heavycomps/heavycomps/roundrobin.py +++ /dev/null @@ -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 diff --git a/heavycomps/heavycomps/wishbone.py b/heavycomps/heavycomps/wishbone.py new file mode 100644 index 0000000..fb3f875 --- /dev/null +++ b/heavycomps/heavycomps/wishbone.py @@ -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