1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
3 # Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
4 # Copyright (c) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6 # Code from LambaConcept is Licensed BSD
7 # Code from Luke Kenneth Casson Leighton is Licensed LGPLv3+
9 # Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
10 # under EU Grants 871528 and 957073
14 from nmigen
import (Module
, Elaboratable
, Signal
, Repl
)
15 from nmigen
.utils
import log2_int
17 from nmigen_soc
import wishbone
18 from nmigen_soc
.memory
import MemoryMap
19 from lambdasoc
.periph
import Peripheral
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
27 class gramWishbone(Peripheral
, Elaboratable
):
28 def __init__(self
, core
, data_width
=32, granularity
=8,
29 features
=frozenset()):
31 super().__init
__(name
="wishbone")
33 self
.native_port
= core
.crossbar
.get_native_port()
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
,
44 mmap
= MemoryMap(addr_width
=addr_width_r
+self
.dsize
,
45 data_width
=granularity
)
47 self
.bus
.memory_map
= mmap
49 def elaborate(self
, platform
):
52 cmd
= self
.native_port
.cmd
53 wdata
= self
.native_port
.wdata
54 rdata
= self
.native_port
.rdata
58 comb
+= wdata
.valid
.eq(bus
.cyc
& bus
.stb
& bus
.we
)
60 ratio_bitmask
= Repl(1, log2_int(self
.ratio
))
62 # XXX? sel is zero being compensated-for as all 1s does not seem right
63 sel
= Signal
.like(bus
.sel
)
64 with m
.If(bus
.sel
== 0):
65 comb
+= sel
.eq(-1) # all 1s
67 comb
+= sel
.eq(bus
.sel
)
69 with m
.Switch(bus
.adr
& ratio_bitmask
): # XXX adr changes (WB4-pipe)
70 for i
in range(self
.ratio
):
73 we
= Repl(sel
, bus
.granularity
//8) << (self
.ratio
*i
)
74 comb
+= wdata
.we
.eq(we
)
76 data
= bus
.dat_w
<< (bus
.data_width
*i
)
77 comb
+= wdata
.data
.eq(data
)
80 comb
+= rdata
.ready
.eq(1)
82 with m
.Switch(bus
.adr
& ratio_bitmask
): # XXX adr changes (WB4-pipe)
83 for i
in range(self
.ratio
):
85 data
= rdata
.data
>> (bus
.data_width
*i
)
86 comb
+= bus
.dat_r
.eq(data
)
90 # raise a command when WB has a request
91 with m
.State("Send-Cmd"):
92 # XXX this logic is only WB 3.0 classic compatible!
94 cmd
.valid
.eq(bus
.cyc
& bus
.stb
),
96 cmd
.addr
.eq(bus
.adr
>> self
.dsize
),
99 # when cmd is accepted, move to either read or write FSM
100 with m
.If(cmd
.valid
& cmd
.ready
):
102 m
.next
= "Wait-Write"
106 # read-wait: when read valid, ack the WB bus, return idle
107 with m
.State("Wait-Read"):
108 with m
.If(rdata
.valid
):
109 comb
+= bus
.ack
.eq(1)
112 # write-wait: when write valid, ack the WB bus, return idle
113 with m
.State("Wait-Write"):
114 with m
.If(wdata
.ready
):
115 comb
+= bus
.ack
.eq(1)