| 12
 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
 |