summaryrefslogtreecommitdiff
path: root/usrp2/fpga/simple_gemac/simple_gemac_wb.v
blob: ca7d4a3fc847cba0456d21ea631c1a28a2d9086b (plain)
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

module wb_reg
  #(parameter ADDR=0,
    parameter DEFAULT=0)
   (input clk, input rst, 
    input [5:0] adr, input wr_acc,
    input [31:0] dat_i, output reg [31:0] dat_o);

   always @(posedge clk)
     if(rst)
       dat_o <= DEFAULT;
     else if(wr_acc & (adr == ADDR))
       dat_o <= dat_i;
   
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_en  );

   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 [5:0] misc_settings;
   assign {pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all, pause_en} 	= misc_settings;

   wb_reg #(.ADDR(0),.DEFAULT(6'b111001))
   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))
   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))
   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))
   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))
   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))
   wb_reg_miimoder (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .dat_i(wb_dat_i), .dat_o({NoPre,Divider}) );
   
   wb_reg #(.ADDR(6),.DEFAULT(0))
   wb_reg_miiaddr (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .dat_i(wb_dat_i), .dat_o(MIIADDRESS) );
   
   wb_reg #(.ADDR(7),.DEFAULT(0))
   wb_reg_miidata (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .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 == 8'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) );

   always @(posedge wb_clk)
     case(wb_adr)
       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;
     endcase // case (wb_adr)
   
endmodule // simple_gemac_wb