whitespace cleanup (80 char limit)
[soc.git] / src / soc / bus / opencores_ethmac.py
1 #!/usr/bin/env python3
2 #
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.
8 #
9 # this is a wrapper around the opencores verilog 10/100 MAC
10
11 from nmigen import (Elaboratable, Cat, Module, Signal, ClockSignal, Instance,
12 ResetSignal)
13
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
19 import os
20
21 __all__ = ["EthMAC"]
22
23
24 class EthMAC(Elaboratable):
25 """Ethernet MAC from opencores, nmigen wrapper.
26 remember to call EthMAC.add_verilog_source
27 """
28
29 def __init__(self, master_bus=None, slave_bus=None, name=None,
30 irq=None, pins=None):
31 if name is not None:
32 # convention: give the name in the format "name_number"
33 self.idx = int(name.split("_")[-1])
34 else:
35 self.idx = 0
36 name = "eth_0"
37 self.granularity = 8
38 self.data_width = 32
39 self.dsize = log2_int(self.data_width//self.granularity)
40
41 # set up the wishbone busses
42 features = frozenset()
43 if master_bus is None:
44 master_bus = Interface(addr_width=30,
45 data_width=32,
46 features=features,
47 granularity=8,
48 name=name+"_wb_%d_0" % self.idx)
49 if slave_bus is None:
50 slave_bus = Interface(addr_width=12,
51 data_width=32,
52 features=features,
53 granularity=8,
54 name=name+"_wb_%d_1" % self.idx)
55 self.master_bus = master_bus
56 self.slave_bus = slave_bus
57 if irq is None:
58 irq = IRQLine()
59 self.irq = irq
60
61 slave_mmap = MemoryMap(addr_width=12+self.dsize,
62 data_width=self.granularity)
63
64 self.slave_bus.memory_map = slave_mmap
65
66 # RMII TX signals
67 self.mtx_clk = Signal()
68 self.mtxd = Signal(4)
69 self.mtxen = Signal()
70 self.mtxerr = Signal()
71
72 # RMII RX signals
73 self.mrx_clk = Signal()
74 self.mrxd = Signal(4)
75 self.mrxdv = Signal()
76 self.mrxerr = Signal()
77
78 # RMII common signals
79 self.mcoll = Signal()
80 self.mcrs = Signal()
81
82 # RMII management interface signals
83 self.mdc = Signal()
84 self.md_in = Signal()
85 self.md_out = Signal()
86 self.md_direction = Signal()
87
88 # pins resource
89 self.pins = pins
90
91 @classmethod
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',
105 'timescale.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)
110
111 def elaborate(self, platform):
112 m = Module()
113 comb = m.d.comb
114
115 # Calculate arbiter bus address
116 spi_bus_adr = Signal(30)
117 # arbiter address is in words, ethernet master address is in bytes
118 self.comb += wb_master_bus_adr.eq(self.master_bus.adr >> 2)
119
120 # create definition of external verilog EthMAC code here, so that
121 # nmigen understands I/O directions (defined by i_ and o_ prefixes)
122 idx, bus = self.idx, self.bus
123 ethmac = Instance("ethmac",
124 # Clock/reset (use DomainRenamer if needed)
125 i_wb_clk_i=ClockSignal(),
126 i_wb_rst_i=ResetSignal(),
127
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_w,
131 o_m_wb_sel_o=self.master_bus.sel,
132 o_m_wb_dat_o=self.master_bus.dat_r,
133 i_cfg_wishbone_we_i=self.master_bus.we,
134 i_cfg_wishbone_stb_i=self.master_bus.stb,
135 o_m_wb_cyc_o=self.master_bus.cyc,
136 i_m_wb_ack_i=self.master_bus.ack,
137
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,
147
148 int_o=self.irq.stb,
149
150 # RMII TX
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,
155
156 # RMII RX
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,
161
162 # RMII common
163 i_mcoll_pad_i=self.mcoll,
164 i_mcrs_pad_i=self.mcrs,
165
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
171 );
172
173 m.submodules['ethmac_%d' % self.idx] = ethmac
174
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)
180
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)
187
188 comb += self.pins.mdc.o.eq(self.mdc)
189
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)
193 return m
194
195
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:
199 f.write(vl)
200
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:
204 f.write(vl)
205
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
222 ], "eth_0")
223