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', 'eth_fifo.v', 'eth_maccontrol.v', 'ethmac_defines.v', 'eth_macstatus.v', 'ethmac.v', 'eth_miim.v', 'eth_outputcontrol.v', 'eth_random.v', 'eth_receivecontrol.v', 'eth_registers.v', 'eth_register.v', 'eth_rxaddrcheck.v', 'eth_rxcounters.v', 'eth_rxethmac.v', 'eth_rxstatem.v', 'eth_shiftreg.v', 'eth_spram_256x32.v', 'eth_top.v', 'eth_transmitcontrol.v', 'eth_txcounters.v', 'eth_txethmac.v', 'eth_txstatem.v', 'eth_wishbone.v', 'timescale.v']:
95 # prepend the src directory to each filename, add its contents
96 fullname
= os
.path
.join(verilog_src_dir
, fname
)
97 with
open(fullname
) as f
:
98 platform
.add_file(fullname
, f
)
100 def elaborate(self
, platform
):
104 # Calculate arbiter bus address
105 spi_bus_adr
= Signal(30)
106 # arbiter address is in words, ethernet master address is in bytes
107 self
.comb
+= wb_master_bus_adr
.eq(self
.master_bus
.adr
>> 2)
109 # create definition of external verilog EthMAC code here, so that
110 # nmigen understands I/O directions (defined by i_ and o_ prefixes)
111 idx
, bus
= self
.idx
, self
.bus
112 ethmac
= Instance("ethmac",
113 # Clock/reset (use DomainRenamer if needed)
114 i_wb_clk_i
=ClockSignal(),
115 i_wb_rst_i
=ResetSignal(),
117 # Master Wishbone bus signals
118 o_m_wb_adr_o
=wb_master_bus_adr
,
119 i_m_wb_dat_i
=self
.master_bus
.dat_w
,
120 o_m_wb_sel_o
=self
.master_bus
.sel
,
121 o_m_wb_dat_o
=self
.master_bus
.dat_r
,
122 i_cfg_wishbone_we_i
=self
.master_bus
.we
,
123 i_cfg_wishbone_stb_i
=self
.master_bus
.stb
,
124 o_m_wb_cyc_o
=self
.master_bus
.cyc
,
125 i_m_wb_ack_i
=self
.master_bus
.ack
,
127 # Slave Wishbone bus signals
128 i_wb_adr_i
=self
.slave_bus
.adr
,
129 i_wb_dat_i
=self
.slave_bus
.dat_w
,
130 i_wb_sel_i
=self
.slave_bus
.sel
,
131 o_wb_dat_o
=self
.slave_bus
.dat_r
,
132 i_wb_we_i
=self
.slave_bus
.we
,
133 i_wb_stb_i
=self
.slave_bus
.stb
,
134 i_wb_cyc_i
=self
.slave_bus
.cyc
,
135 o_wb_ack_o
=self
.slave_bus
.ack
,
140 i_mtx_clk_pad_i
=self
.mtx_clk
,
141 o_mtxd_pad_o
=self
.mtxd
,
142 o_mtxen_pad_o
=self
.mtxen
,
143 o_mtxerr_pad_o
=self
.mtxerr
,
146 i_mrx_clk_pad_i
=self
.mrx_clk
,
147 i_mrxd_pad_i
=self
.mrxd
,
148 i_mrxdv_pad_i
=self
.mrxdv
,
149 i_mrxerr_pad_i
=self
.mrxerr
,
152 i_mcoll_pad_i
=self
.mcoll
,
153 i_mcrs_pad_i
=self
.mcrs
,
155 # Management Interface
156 o_mdc_pad_o
=self
.mdc
,
157 i_md_pad_i
=self
.md_in
,
158 o_md_pad_o
=self
.md_out
,
159 o_md_padoe_o
=self
.md_direction
162 m
.submodules
['ethmac_%d' % self
.idx
] = ethmac
164 if self
.pins
is not None:
165 comb
+= self
.mtx_clk
.eq(self
.pins
.mtx_clk
.i
)
166 comb
+= self
.pins
.mtxd
.o
.eq(self
.mtxd
)
167 comb
+= self
.pins
.mtxen
.o
.eq(self
.mtxen
)
168 comb
+= self
.pins
.mtxerr
.o
.eq(self
.mtxerr
)
170 comb
+= self
.mrx_clk
.eq(self
.pins
.mrx_clk
.i
)
171 comb
+= self
.mrxd
.eq(self
.pins
.mrxd
.i
)
172 comb
+= self
.mrxdv
.eq(self
.pins
.mrxdv
.i
)
173 comb
+= self
.mrxerr
.eq(self
.pins
.mrxerr
.i
)
174 comb
+= self
.mcoll
.eq(self
.pins
.mcoll
.i
)
175 comb
+= self
.mcrs
.eq(self
.pins
.mcrs
.i
)
177 comb
+= self
.pins
.mdc
.o
.eq(self
.mdc
)
179 comb
+= self
.pins
.md
.o
.eq(self
.md_out
)
180 comb
+= self
.pins
.md
.oe
.eq(self
.md_direction
)
181 comb
+= self
.md_in
.eq(self
.pins
.md
.i
)
185 def create_ilang(dut
, ports
, test_name
):
186 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
187 with
open("%s.il" % test_name
, "w") as f
:
190 def create_verilog(dut
, ports
, test_name
):
191 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
192 with
open("%s.v" % test_name
, "w") as f
:
195 if __name__
== "__main__":
196 ethmac
= EthMAC(name
="eth_0")
197 create_ilang(ethmac
, [ethmac
.master_bus
.cyc
, ethmac
.master_bus
.stb
, ethmac
.master_bus
.ack
,
198 ethmac
.master_bus
.dat_r
, ethmac
.master_bus
.dat_w
, ethmac
.master_bus
.adr
,
199 ethmac
.master_bus
.we
, ethmac
.master_bus
.sel
,
200 ethmac
.slave_bus
.cyc
, ethmac
.slave_bus
.stb
,
201 ethmac
.slave_bus
.ack
,
202 ethmac
.slave_bus
.dat_r
, ethmac
.slave_bus
.dat_w
,
203 ethmac
.slave_bus
.adr
,
204 ethmac
.slave_bus
.we
, ethmac
.slave_bus
.sel
,
205 ethmac
.mtx_clk
, ethmac
.mtxd
, ethmac
.mtxen
,
206 ethmac
.mtxerr
, ethmac
.mrx_clk
, ethmac
.mrxd
,
207 ethmac
.mrxdv
, ethmac
.mrxerr
, ethmac
.mcoll
,
208 ethmac
.mcrs
, ethmac
.mdc
, ethmac
.md_in
,
209 ethmac
.md_out
, ethmac
.md_direction