1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
//
// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
module wb_reg
#(parameter ADDR=0,
parameter DEFAULT=0,
parameter WIDTH=32)
(input clk, input rst,
input [5:0] adr, input wr_acc,
input [31:0] dat_i, output reg [WIDTH-1:0] dat_o);
always @(posedge clk)
if(rst)
dat_o <= DEFAULT;
else if(wr_acc & (adr == ADDR))
dat_o <= dat_i[WIDTH-1:0];
endmodule // wb_reg
module simple_gemac_wb
(input wb_clk, input wb_rst,
input wb_cyc, input wb_stb, output reg wb_ack, input wb_we,
input [7:0] wb_adr, input [31:0] wb_dat_i, output reg [31:0] wb_dat_o,
inout mdio, output mdc,
output [47:0] ucast_addr, output [47:0] mcast_addr,
output pass_ucast, output pass_mcast, output pass_bcast,
output pass_pause, output pass_all,
output pause_respect_en, output pause_request_en,
output [15:0] pause_time, output [15:0] pause_thresh );
wire acc = wb_cyc & wb_stb;
wire wr_acc = wb_cyc & wb_stb & wb_we;
wire rd_acc = wb_cyc & wb_stb & ~wb_we;
always @(posedge wb_clk)
if(wb_rst)
wb_ack <= 0;
else
wb_ack <= acc & ~wb_ack;
wire [6:0] misc_settings;
assign {pause_request_en, pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all, pause_respect_en} = misc_settings;
wb_reg #(.ADDR(0),.DEFAULT(7'b0111011),.WIDTH(7))
wb_reg_settings (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(misc_settings) );
wb_reg #(.ADDR(1),.DEFAULT(0),.WIDTH(16))
wb_reg_ucast_h (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(ucast_addr[47:32]) );
wb_reg #(.ADDR(2),.DEFAULT(0),.WIDTH(32))
wb_reg_ucast_l (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(ucast_addr[31:0]) );
wb_reg #(.ADDR(3),.DEFAULT(0),.WIDTH(16))
wb_reg_mcast_h (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(mcast_addr[47:32]) );
wb_reg #(.ADDR(4),.DEFAULT(0),.WIDTH(32))
wb_reg_mcast_l (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(mcast_addr[31:0]) );
//MII to CPU
wire [7:0] Divider; // Divider for the host clock
wire [15:0] CtrlData; // Control Data (to be written to the PHY reg.)
wire [4:0] Rgad; // Register Address (within the PHY)
wire [4:0] Fiad; // PHY Address
wire NoPre; // No Preamble (no 32-bit preamble)
wire WCtrlData; // Write Control Data operation
wire RStat; // Read Status operation
wire ScanStat; // Scan Status operation
wire Busy; // Busy Signal
wire LinkFail; // Link Integrity Signal
wire Nvalid; // Invalid Status (qualifier for the valid scan result)
wire [15:0] Prsd; // Read Status Data (data read from the PHY)
wire WCtrlDataStart; // This signals resets the WCTRLDATA bit in the MIIM Command register
wire RStatStart; // This signal resets the RSTAT BIT in the MIIM Command register
wire UpdateMIIRX_DATAReg; // Updates MII RX_DATA register with read data
// registers for controlling the MII interface
reg [2:0] MIICOMMAND;
wire [12:0] MIIADDRESS;
reg [15:0] MIIRX_DATA;
wire [2:0] MIISTATUS;
wb_reg #(.ADDR(5),.DEFAULT(0),.WIDTH(9))
wb_reg_miimoder (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o({NoPre,Divider}) );
wb_reg #(.ADDR(6),.DEFAULT(0),.WIDTH(13))
wb_reg_miiaddr (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(MIIADDRESS) );
wb_reg #(.ADDR(7),.DEFAULT(0),.WIDTH(16))
wb_reg_miidata (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(CtrlData) );
// MIICOMMAND register - needs special treatment because of auto-resetting bits
always @ (posedge wb_clk)
if (wb_rst)
MIICOMMAND <= 0;
else
if (wr_acc & (wb_adr[7:2] == 6'd8))
MIICOMMAND <= wb_dat_i;
else
begin
if ( WCtrlDataStart )
MIICOMMAND[2] <= 0;
if ( RStatStart )
MIICOMMAND[1] <= 0;
end
// MIIRX_DATA register
always @(posedge wb_clk)
if (wb_rst)
MIIRX_DATA <= 0;
else
if (UpdateMIIRX_DATAReg )
MIIRX_DATA <= Prsd;
// MIICOMMAND
assign WCtrlData = MIICOMMAND[2];
assign RStat = MIICOMMAND[1];
assign ScanStat = MIICOMMAND[0];
// MIIADDRESS
assign Rgad = MIIADDRESS[12:8];
assign Fiad = MIIADDRESS[4:0];
// MIISTATUS
assign MIISTATUS[2:0] = { Nvalid, Busy, LinkFail };
eth_miim eth_miim
(.Clk(wb_clk), .Reset(wb_rst),
.Divider(Divider), .NoPre(NoPre), .CtrlData(CtrlData), .Rgad(Rgad), .Fiad(Fiad),
.WCtrlData(WCtrlData), .RStat(RStat), .ScanStat(ScanStat), .Mdio(mdio), .Mdc(mdc),
.Busy(Busy), .Prsd(Prsd), .LinkFail(LinkFail), .Nvalid(Nvalid),
.WCtrlDataStart(WCtrlDataStart), .RStatStart(RStatStart),
.UpdateMIIRX_DATAReg(UpdateMIIRX_DATAReg) );
wb_reg #(.ADDR(11),.DEFAULT(0),.WIDTH(16))
wb_reg_pausetime (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(pause_time) );
wb_reg #(.ADDR(12),.DEFAULT(0),.WIDTH(16))
wb_reg_pausethresh (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(pause_thresh) );
always @(posedge wb_clk)
case(wb_adr[7:2])
0 : wb_dat_o <= misc_settings;
1 : wb_dat_o <= ucast_addr[47:32];
2 : wb_dat_o <= ucast_addr[31:0];
3 : wb_dat_o <= mcast_addr[47:32];
4 : wb_dat_o <= mcast_addr[31:0];
5 : wb_dat_o <= {NoPre,Divider};
6 : wb_dat_o <= MIIADDRESS;
7 : wb_dat_o <= CtrlData;
8 : wb_dat_o <= MIICOMMAND;
9 : wb_dat_o <= MIISTATUS;
10: wb_dat_o <= MIIRX_DATA;
11: wb_dat_o <= pause_time;
12: wb_dat_o <= pause_thresh;
endcase // case (wb_adr[7:2])
endmodule // simple_gemac_wb
|