3078fa67dc0aa07c99f42af24965d45040336204
3 # SPDX-License-Identifier: LGPLv3+
4 # Copyright (C) 2020-2022 Raptor Engineering LLC <support@raptorengineering.com>
5 # Copyright (C) 2022 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
6 # Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073
7 # Part of the Libre-SOC Project.
9 # this is a wrapper around the opencores verilog 10/100 MAC
11 from nmigen
import (Elaboratable
, Cat
, Module
, Signal
, ClockSignal
, Instance
,
14 from nmigen_soc
.wishbone
.bus
import Interface
15 from nmigen_soc
.memory
import MemoryMap
16 from lambdasoc
.periph
.event
import IRQLine
17 from nmigen
.utils
import log2_int
18 from nmigen
.cli
import rtlil
, verilog
24 class EthMAC(Elaboratable
):
25 """Ethernet MAC from opencores, nmigen wrapper.
26 remember to call EthMAC.add_verilog_source
29 def __init__(self
, master_bus
=None, slave_bus
=None, name
=None,
32 # convention: give the name in the format "name_number"
33 self
.idx
= int(name
.split("_")[-1])
39 self
.dsize
= log2_int(self
.data_width
//self
.granularity
)
41 # set up the wishbone busses
42 features
= frozenset()
43 if master_bus
is None:
44 master_bus
= Interface(addr_width
=30,
48 name
=name
+"_wb_%d_0" % self
.idx
)
50 slave_bus
= Interface(addr_width
=12,
54 name
=name
+"_wb_%d_1" % self
.idx
)
55 self
.master_bus
= master_bus
56 self
.slave_bus
= slave_bus
61 slave_mmap
= MemoryMap(addr_width
=12+self
.dsize
,
62 data_width
=self
.granularity
)
64 self
.slave_bus
.memory_map
= slave_mmap
67 self
.mtx_clk
= Signal()
70 self
.mtxerr
= Signal()
73 self
.mrx_clk
= Signal()
76 self
.mrxerr
= Signal()
82 # RMII management interface signals
85 self
.md_out
= Signal()
86 self
.md_direction
= Signal()
92 def add_verilog_source(cls
, verilog_src_dir
, platform
):
93 # add each of the verilog sources, needed for when doing platform.build
94 for fname
in ['eth_clockgen.v', 'eth_cop.v', 'eth_crc.v',
95 'eth_fifo.v', 'eth_maccontrol.v', 'ethmac_defines.v',
96 'eth_macstatus.v', 'ethmac.v', 'eth_miim.v',
97 'eth_outputcontrol.v', 'eth_random.v',
98 'eth_receivecontrol.v', 'eth_registers.v',
99 'eth_register.v', 'eth_rxaddrcheck.v',
100 'eth_rxcounters.v', 'eth_rxethmac.v',
101 'eth_rxstatem.v', 'eth_shiftreg.v',
102 'eth_spram_256x32.v', 'eth_top.v',
103 'eth_transmitcontrol.v', 'eth_txcounters.v',
104 'eth_txethmac.v', 'eth_txstatem.v', 'eth_wishbone.v',
106 # prepend the src directory to each filename, add its contents
107 fullname
= os
.path
.join(verilog_src_dir
, fname
)
108 with
open(fullname
) as f
:
109 platform
.add_file(fullname
, f
)
111 def elaborate(self
, platform
):
115 # Calculate arbiter bus address
116 wb_master_bus_adr
= Signal(32)
117 # arbiter address is in words, ethernet master address is in bytes
118 comb
+= self
.master_bus
.adr
.eq(wb_master_bus_adr
>> 2)
120 # create definition of external verilog EthMAC code here, so that
121 # nmigen understands I/O directions (defined by i_ and o_ prefixes)
123 ethmac
= Instance("eth_top",
124 # Clock/reset (use DomainRenamer if needed)
125 i_wb_clk_i
=ClockSignal(),
126 i_wb_rst_i
=ResetSignal(),
128 # Master Wishbone bus signals
129 o_m_wb_adr_o
=wb_master_bus_adr
,
130 i_m_wb_dat_i
=self
.master_bus
.dat_r
,
131 o_m_wb_sel_o
=self
.master_bus
.sel
,
132 o_m_wb_dat_o
=self
.master_bus
.dat_w
,
133 o_m_wb_we_o
=self
.master_bus
.we
,
134 o_m_wb_stb_o
=self
.master_bus
.stb
,
135 o_m_wb_cyc_o
=self
.master_bus
.cyc
,
136 i_m_wb_ack_i
=self
.master_bus
.ack
,
138 # Slave Wishbone bus signals
139 i_wb_adr_i
=self
.slave_bus
.adr
,
140 i_wb_dat_i
=self
.slave_bus
.dat_w
,
141 i_wb_sel_i
=self
.slave_bus
.sel
,
142 o_wb_dat_o
=self
.slave_bus
.dat_r
,
143 i_wb_we_i
=self
.slave_bus
.we
,
144 i_wb_stb_i
=self
.slave_bus
.stb
,
145 i_wb_cyc_i
=self
.slave_bus
.cyc
,
146 o_wb_ack_o
=self
.slave_bus
.ack
,
151 i_mtx_clk_pad_i
=self
.mtx_clk
,
152 o_mtxd_pad_o
=self
.mtxd
,
153 o_mtxen_pad_o
=self
.mtxen
,
154 o_mtxerr_pad_o
=self
.mtxerr
,
157 i_mrx_clk_pad_i
=self
.mrx_clk
,
158 i_mrxd_pad_i
=self
.mrxd
,
159 i_mrxdv_pad_i
=self
.mrxdv
,
160 i_mrxerr_pad_i
=self
.mrxerr
,
163 i_mcoll_pad_i
=self
.mcoll
,
164 i_mcrs_pad_i
=self
.mcrs
,
166 # Management Interface
167 o_mdc_pad_o
=self
.mdc
,
168 i_md_pad_i
=self
.md_in
,
169 o_md_pad_o
=self
.md_out
,
170 o_md_padoe_o
=self
.md_direction
173 m
.submodules
['ethmac_%d' % self
.idx
] = ethmac
175 if self
.pins
is not None:
176 comb
+= self
.mtx_clk
.eq(self
.pins
.mtx_clk
.i
)
177 comb
+= self
.pins
.mtxd
.o
.eq(self
.mtxd
)
178 comb
+= self
.pins
.mtxen
.o
.eq(self
.mtxen
)
179 comb
+= self
.pins
.mtxerr
.o
.eq(self
.mtxerr
)
181 comb
+= self
.mrx_clk
.eq(self
.pins
.mrx_clk
.i
)
182 comb
+= self
.mrxd
.eq(self
.pins
.mrxd
.i
)
183 comb
+= self
.mrxdv
.eq(self
.pins
.mrxdv
.i
)
184 comb
+= self
.mrxerr
.eq(self
.pins
.mrxerr
.i
)
185 comb
+= self
.mcoll
.eq(self
.pins
.mcoll
.i
)
186 comb
+= self
.mcrs
.eq(self
.pins
.mcrs
.i
)
188 comb
+= self
.pins
.mdc
.o
.eq(self
.mdc
)
190 comb
+= self
.pins
.md
.o
.eq(self
.md_out
)
191 comb
+= self
.pins
.md
.oe
.eq(self
.md_direction
)
192 comb
+= self
.md_in
.eq(self
.pins
.md
.i
)
196 def create_ilang(dut
, ports
, test_name
):
197 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
198 with
open("%s.il" % test_name
, "w") as f
:
201 def create_verilog(dut
, ports
, test_name
):
202 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
203 with
open("%s.v" % test_name
, "w") as f
:
206 if __name__
== "__main__":
207 ethmac
= EthMAC(name
="eth_0")
208 create_ilang(ethmac
, [ethmac
.master_bus
.cyc
, ethmac
.master_bus
.stb
,
209 ethmac
.master_bus
.ack
, ethmac
.master_bus
.dat_r
,
210 ethmac
.master_bus
.dat_w
, ethmac
.master_bus
.adr
,
211 ethmac
.master_bus
.we
, ethmac
.master_bus
.sel
,
212 ethmac
.slave_bus
.cyc
, ethmac
.slave_bus
.stb
,
213 ethmac
.slave_bus
.ack
,
214 ethmac
.slave_bus
.dat_r
, ethmac
.slave_bus
.dat_w
,
215 ethmac
.slave_bus
.adr
,
216 ethmac
.slave_bus
.we
, ethmac
.slave_bus
.sel
,
217 ethmac
.mtx_clk
, ethmac
.mtxd
, ethmac
.mtxen
,
218 ethmac
.mtxerr
, ethmac
.mrx_clk
, ethmac
.mrxd
,
219 ethmac
.mrxdv
, ethmac
.mrxerr
, ethmac
.mcoll
,
220 ethmac
.mcrs
, ethmac
.mdc
, ethmac
.md_in
,
221 ethmac
.md_out
, ethmac
.md_direction