tidy up gramWishbone constructor, pass Wishbone features to bus
[gram.git] / gram / frontend / wishbone.py
1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
2 # License: BSD
3 # Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
4 # Copyright (c) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
5 #
6 # Code from LambaConcept is Licensed BSD
7 # Code from Luke Kenneth Casson Leighton is Licensed LGPLv3+
8 #
9 # Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
10 # under EU Grants 871528 and 957073
11
12 from math import log2
13
14 from nmigen import (Module, Elaboratable, Signal, Repl)
15 from nmigen.utils import log2_int
16
17 from nmigen_soc import wishbone
18 from nmigen_soc.memory import MemoryMap
19 from lambdasoc.periph import Peripheral
20
21 # XXX
22 # WARNING - THIS CODE CANNOT COPE WITH WISHBONE 4.0 PIPELINE MODE
23 # THE ADDRESS MAY CHANGE AFTER EACH STB AND THIS IS AN ASSUMPTION
24 # FROM WISHBONE 3.0 CLASSIC. USE THE COMPATIBILITY MODE stall=cyc&~ack
25 # OR USE BURST-MODE ONLY
26 # XXX
27 class gramWishbone(Peripheral, Elaboratable):
28 def __init__(self, core, data_width=32, granularity=8,
29 features=frozenset()):
30
31 super().__init__(name="wishbone")
32
33 self.native_port = core.crossbar.get_native_port()
34
35 self.ratio = self.native_port.data_width//data_width
36 addr_width = log2_int(core.size//self.ratio)
37 addr_width_r = addr_width + log2_int(self.ratio)
38 self.dsize = log2_int(data_width//granularity)
39 self.bus = wishbone.Interface(addr_width=addr_width_r,
40 data_width=data_width,
41 granularity=granularity,
42 features=features)
43
44 mmap = MemoryMap(addr_width=addr_width_r+self.dsize,
45 data_width=granularity)
46
47 self.bus.memory_map = mmap
48
49 def elaborate(self, platform):
50 m = Module()
51 cmd = self.native_port.cmd
52 wdata = self.native_port.wdata
53 rdata = self.native_port.rdata
54
55 # Write datapath
56 m.d.comb += wdata.valid.eq(self.bus.cyc & self.bus.stb & self.bus.we)
57
58 ratio_bitmask = Repl(1, log2_int(self.ratio))
59
60 sel = Signal.like(self.bus.sel)
61 with m.If(self.bus.sel == 0):
62 m.d.comb += sel.eq(Repl(1, sel.width))
63 with m.Else():
64 m.d.comb += sel.eq(self.bus.sel)
65
66 with m.Switch(self.bus.adr & ratio_bitmask):
67 for i in range(self.ratio):
68 with m.Case(i):
69 m.d.comb += wdata.we.eq(Repl(sel, self.bus.granularity//8) << (self.ratio*i))
70
71 with m.Switch(self.bus.adr & ratio_bitmask):
72 for i in range(self.ratio):
73 with m.Case(i):
74 m.d.comb += wdata.data.eq(self.bus.dat_w << (self.bus.data_width*i))
75
76 # Read datapath
77 m.d.comb += rdata.ready.eq(1)
78
79 with m.Switch(self.bus.adr & ratio_bitmask):
80 for i in range(self.ratio):
81 with m.Case(i):
82 m.d.comb += self.bus.dat_r.eq(rdata.data >> (self.bus.data_width*i))
83
84 with m.FSM():
85 with m.State("Send-Cmd"):
86 m.d.comb += [
87 cmd.valid.eq(self.bus.cyc & self.bus.stb),
88 cmd.we.eq(self.bus.we),
89 cmd.addr.eq(self.bus.adr >> log2_int(self.bus.data_width//self.bus.granularity)),
90 ]
91
92 with m.If(cmd.valid & cmd.ready):
93 with m.If(self.bus.we):
94 m.next = "Wait-Write"
95 with m.Else():
96 m.next = "Wait-Read"
97
98 with m.State("Wait-Read"):
99 with m.If(rdata.valid):
100 m.d.comb += self.bus.ack.eq(1)
101 m.next = "Send-Cmd"
102
103 with m.State("Wait-Write"):
104 with m.If(wdata.ready):
105 m.d.comb += self.bus.ack.eq(1)
106 m.next = "Send-Cmd"
107
108 return m