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