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
):
51 cmd
= self
.native_port
.cmd
52 wdata
= self
.native_port
.wdata
53 rdata
= self
.native_port
.rdata
56 m
.d
.comb
+= wdata
.valid
.eq(self
.bus
.cyc
& self
.bus
.stb
& self
.bus
.we
)
58 ratio_bitmask
= Repl(1, log2_int(self
.ratio
))
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
))
64 m
.d
.comb
+= sel
.eq(self
.bus
.sel
)
66 with m
.Switch(self
.bus
.adr
& ratio_bitmask
):
67 for i
in range(self
.ratio
):
69 m
.d
.comb
+= wdata
.we
.eq(Repl(sel
, self
.bus
.granularity
//8) << (self
.ratio
*i
))
71 with m
.Switch(self
.bus
.adr
& ratio_bitmask
):
72 for i
in range(self
.ratio
):
74 m
.d
.comb
+= wdata
.data
.eq(self
.bus
.dat_w
<< (self
.bus
.data_width
*i
))
77 m
.d
.comb
+= rdata
.ready
.eq(1)
79 with m
.Switch(self
.bus
.adr
& ratio_bitmask
):
80 for i
in range(self
.ratio
):
82 m
.d
.comb
+= self
.bus
.dat_r
.eq(rdata
.data
>> (self
.bus
.data_width
*i
))
85 with m
.State("Send-Cmd"):
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
)),
92 with m
.If(cmd
.valid
& cmd
.ready
):
93 with m
.If(self
.bus
.we
):
98 with m
.State("Wait-Read"):
99 with m
.If(rdata
.valid
):
100 m
.d
.comb
+= self
.bus
.ack
.eq(1)
103 with m
.State("Wait-Write"):
104 with m
.If(wdata
.ready
):
105 m
.d
.comb
+= self
.bus
.ack
.eq(1)