1 # Copyright (C) 2022 Raptor Engineering, LLC <support@raptorengineering.com>
3 # Based partly on code from LibreSoC
5 # Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
6 # under EU Grants 871528 and 957073, under the LGPLv3+ License
8 # this is a wrapper around the Verilog Wishbone Components wb_async_reg module
10 from nmigen
import (Elaboratable
, Cat
, Module
, Signal
, ClockSignal
, Instance
,
13 from nmigen_soc
.wishbone
.bus
import Interface
14 from nmigen_soc
.memory
import MemoryMap
15 from nmigen
.utils
import log2_int
16 from nmigen
.cli
import rtlil
, verilog
17 from nmutil
.byterev
import byte_reverse
20 __all__
= ["WBAsyncBridge"]
23 class WBAsyncBridge(Elaboratable
):
24 """Verilog Wishbone Components wb_async_reg module, nmigen wrapper.
25 remember to call WBAsyncBridge.add_verilog_source
28 def __init__(self
, master_bus
=None, slave_bus
=None, features
=None, name
=None,
29 address_width
=30, data_width
=32, granularity
=8,
30 master_clock_domain
=None, slave_clock_domain
=None):
32 # convention: give the name in the format "name_number"
33 self
.idx
= int(name
.split("_")[-1])
36 name
= "wbasyncbridge_0"
37 self
.address_width
= address_width
38 self
.data_width
= data_width
39 self
.granularity
= granularity
40 self
.dsize
= log2_int(self
.data_width
//self
.granularity
)
42 # set up the clock domains
43 if master_clock_domain
is None:
44 self
.wb_mclk
= ClockSignal()
45 self
.wb_mrst
= ResetSignal()
47 self
.wb_mclk
= ClockSignal(master_clock_domain
)
48 self
.wb_mrst
= ResetSignal(master_clock_domain
)
49 if slave_clock_domain
is None:
50 self
.wb_sclk
= ClockSignal()
51 self
.wb_srst
= ResetSignal()
53 self
.wb_sclk
= ClockSignal(slave_clock_domain
)
54 self
.wb_srst
= ResetSignal(slave_clock_domain
)
56 # set up the wishbone busses
58 features
= frozenset()
59 if master_bus
is None:
60 master_bus
= Interface(addr_width
=self
.address_width
,
61 data_width
=self
.data_width
,
63 granularity
=self
.granularity
,
64 name
=name
+"_wb_%d_master" % self
.idx
)
66 slave_bus
= Interface(addr_width
=self
.address_width
,
67 data_width
=self
.data_width
,
69 granularity
=self
.granularity
,
70 name
=name
+"_wb_%d_slave" % self
.idx
)
71 self
.master_bus
= master_bus
72 assert len(self
.master_bus
.dat_r
) == data_width
, \
73 "bus width must be %d" % data_width
74 self
.slave_bus
= slave_bus
75 assert len(self
.slave_bus
.dat_r
) == data_width
, \
76 "bus width must be %d" % data_width
79 def add_verilog_source(cls
, verilog_src_dir
, platform
):
80 # add each of the verilog sources, needed for when doing platform.build
81 for fname
in ['wb_async_reg.v']:
82 # prepend the src directory to each filename, add its contents
83 fullname
= os
.path
.join(verilog_src_dir
, fname
)
84 with
open(fullname
) as f
:
85 platform
.add_file(fullname
, f
)
87 def elaborate(self
, platform
):
90 master_bus
, slave_bus
= self
.master_bus
, self
.slave_bus
95 # create definition of external verilog bridge code here, so that
96 # nmigen understands I/O directions (defined by i_ and o_ prefixes)
98 wb_async_bridge
= Instance("wb_async_reg",
100 p_ADDR_WIDTH
=self
.address_width
,
101 p_DATA_WIDTH
=self
.data_width
,
102 p_SELECT_WIDTH
=self
.granularity
,
105 i_wbm_clk
=self
.wb_mclk
,
106 i_wbm_rst
=self
.wb_mrst
,
107 i_wbs_clk
=self
.wb_sclk
,
108 i_wbs_rst
=self
.wb_srst
,
110 # Master Wishbone bus signals
111 i_wbm_adr_i
=self
.master_bus
.adr
,
112 i_wbm_dat_i
=self
.master_bus
.dat_w
,
113 o_wbm_dat_o
=self
.master_bus
.dat_r
,
114 i_wbm_we_i
=self
.master_bus
.we
,
115 i_wbm_sel_i
=self
.master_bus
.sel
,
116 i_wbm_stb_i
=self
.master_bus
.stb
,
117 i_wbm_cyc_i
=self
.master_bus
.cyc
,
118 o_wbm_ack_o
=self
.master_bus
.ack
,
119 #o_wbm_err=self.master_bus.err,
120 #o_wbm_rty_i=self.master_bus.rty,
122 # Slave Wishbone bus signals
123 o_wbs_adr_o
=self
.slave_bus
.adr
,
124 i_wbs_dat_i
=self
.slave_bus
.dat_r
,
125 o_wbs_dat_o
=self
.slave_bus
.dat_w
,
126 o_wbs_we_o
=self
.slave_bus
.we
,
127 o_wbs_sel_o
=self
.slave_bus
.sel
,
128 o_wbs_stb_o
=self
.slave_bus
.stb
,
129 o_wbs_cyc_o
=self
.slave_bus
.cyc
,
130 i_wbs_ack_i
=slave_ack
,
131 i_wbs_err_i
=slave_err
,
132 i_wbs_rty_i
=slave_rty
135 # Synthesize STALL signal for master port
136 comb
+= self
.master_bus
.stall
.eq(self
.master_bus
.cyc
& ~self
.master_bus
.ack
)
138 # Convert incoming slave STALL signal to a format that the async bridge understands...
139 comb
+= slave_ack
.eq(self
.slave_bus
.ack
& ~self
.slave_bus
.stall
)
141 # Wire unused signals to 0
142 comb
+= slave_err
.eq(0)
143 comb
+= slave_rty
.eq(0)
145 m
.submodules
['wb_async_bridge_%d' % self
.idx
] = wb_async_bridge
150 return [self
.master_bus
.adr
, self
.master_bus
.dat_w
, self
.master_bus
.dat_r
,
151 self
.master_bus
.we
, self
.master_bus
.sel
, self
.master_bus
.stb
,
152 self
.master_bus
.cyc
, self
.master_bus
.ack
, self
.master_bus
.err
,
154 self
.slave_bus
.adr
, self
.slave_bus
.dat_w
, self
.slave_bus
.dat_r
,
155 self
.slave_bus
.we
, self
.slave_bus
.sel
, self
.slave_bus
.stb
,
156 self
.slave_bus
.cyc
, self
.slave_bus
.ack
, self
.slave_bus
.err
,
160 def create_ilang(dut
, ports
, test_name
):
161 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
162 with
open("%s.il" % test_name
, "w") as f
:
165 def create_verilog(dut
, ports
, test_name
):
166 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
167 with
open("%s.v" % test_name
, "w") as f
:
171 if __name__
== "__main__":
172 wbasyncbridge
= WBAsyncBridge(name
="wbasyncbridge_0", address_width
=30, data_width
=32, granularity
=8)
173 create_ilang(wbasyncbridge
, wbasyncbridge
.ports(), "wbasyncbridge_0")