MDIO R/W working
[mw/milkymist.git] / cores / minimac / rtl / minimac_ctlif.v
1 /*
2  * Milkymist VJ SoC
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
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 module minimac_ctlif #(
19         parameter csr_addr = 4'h0
20 ) (
21         input sys_clk,
22         input sys_rst,
23
24         input [13:0] csr_a,
25         input csr_we,
26         input [31:0] csr_di,
27         output reg [31:0] csr_do,
28
29         output reg irq_rx,
30         output reg irq_tx,
31
32         output reg speed10,
33         output reg promisc,
34         output reg [47:0] macaddr,
35
36         output rx_valid,
37         output [29:0] rx_adr,
38         input rx_incrcount,
39         input rx_endframe,
40
41         output tx_valid,
42         output reg [29:0] tx_adr,
43         output reg [1:0] tx_bytecount,
44         input tx_next,
45
46         output reg phy_mii_clk,
47         inout phy_mii_data
48 );
49
50 reg mii_data_oe;
51 reg mii_data_do;
52 assign phy_mii_data = mii_data_oe ? mii_data_do : 1'bz;
53
54 /* Be paranoid about metastability */
55 reg mii_data_di1;
56 reg mii_data_di;
57 always @(posedge sys_clk) begin
58         mii_data_di1 <= phy_mii_data;
59         mii_data_di <= mii_data_di1;
60 end
61
62 /*
63  * RX Slots
64  *
65  * State:
66  * 00 -> slot is not in use
67  * 01 -> slot has been loaded with a buffer
68  * 10 -> slot has received a packet
69  * 11 -> invalid
70  */
71 reg [1:0] slot0_state;
72 reg [29:0] slot0_adr;
73 reg [10:0] slot0_count;
74 reg [1:0] slot1_state;
75 reg [29:0] slot1_adr;
76 reg [10:0] slot1_count;
77 reg [1:0] slot2_state;
78 reg [29:0] slot2_adr;
79 reg [10:0] slot2_count;
80 reg [1:0] slot3_state;
81 reg [29:0] slot3_adr;
82 reg [10:0] slot3_count;
83
84 wire select0 = slot0_state[0];
85 wire select1 = slot1_state[0] & ~slot0_state[0];
86 wire select2 = slot2_state[0] & ~slot1_state[0] & ~slot0_state[0];
87 wire select3 = slot3_state[0] & ~slot2_state[0] & ~slot1_state[0] & ~slot0_state[0];
88
89 assign rx_valid = slot0_state[0] | slot1_state[0] | slot2_state[0] | slot3_state[0];
90 assign rx_adr =  {30{select0}} & slot0_adr
91                 |{30{select1}} & slot1_adr
92                 |{30{select2}} & slot2_adr
93                 |{30{select3}} & slot3_adr;
94
95 /*
96  * TX
97  */
98 reg [10:0] tx_remaining;
99 assign tx_valid = |tx_remaining;
100
101 wire csr_selected = csr_a[13:10] == csr_addr;
102
103 always @(posedge sys_clk) begin
104         if(sys_rst) begin
105                 csr_do <= 32'd0;
106
107                 speed10 <= 1'b0;
108                 promisc <= 1'b0;
109                 // Goldman Sachs sells hot air, not network devices.
110                 // Squatting their OUI is a safe bet.
111                 macaddr <= 48'hf871fe030405;
112
113                 mii_data_oe <= 1'b0;
114                 mii_data_do <= 1'b0;
115                 phy_mii_clk <= 1'b0;
116
117                 slot0_state <= 2'b00;
118                 slot0_adr <= 30'd0;
119                 slot0_count <= 11'd0;
120                 slot1_state <= 2'b00;
121                 slot1_adr <= 30'd0;
122                 slot1_count <= 11'd0;
123                 slot2_state <= 2'b00;
124                 slot2_adr <= 30'd0;
125                 slot2_count <= 11'd0;
126                 slot3_state <= 2'b00;
127                 slot3_adr <= 30'd0;
128                 slot3_count <= 11'd0;
129
130                 tx_remaining <= 11'd0;
131                 tx_adr <= 30'd0;
132                 tx_bytecount <= 2'd0;
133         end else begin
134                 csr_do <= 32'd0;
135                 if(csr_selected) begin
136                         if(csr_we) begin
137                                 case(csr_a[4:0])
138                                         5'd0 : begin
139                                                 promisc <= csr_di[1];
140                                                 speed10 <= csr_di[0];
141                                         end
142                                         5'd1 : macaddr[47:24] <= csr_di[23:0];
143                                         5'd2 : macaddr[23:0] <= csr_di[23:0];
144
145                                         5'd3 : begin
146                                                 phy_mii_clk <= csr_di[3];
147                                                 mii_data_oe <= csr_di[2];
148                                                 mii_data_do <= csr_di[0];
149                                         end
150
151                                         5'd4 : begin
152                                                 slot0_state <= csr_di[1:0];
153                                                 slot0_count <= 11'd0;
154                                         end
155                                         5'd5 : slot0_adr <= csr_di[31:2];
156                                         // slot0_count is read-only
157                                         5'd7 : begin
158                                                 slot1_state <= csr_di[1:0];
159                                                 slot1_count <= 11'd0;
160                                         end
161                                         5'd8 : slot1_adr <= csr_di[31:2];
162                                         // slot1_count is read-only
163                                         5'd10: begin
164                                                 slot2_state <= csr_di[1:0];
165                                                 slot2_count <= 11'd0;
166                                         end
167                                         5'd11: slot2_adr <= csr_di[31:2];
168                                         // slot2_count is read-only
169                                         5'd13: begin
170                                                 slot3_state <= csr_di[1:0];
171                                                 slot3_count <= 11'd0;
172                                         end
173                                         5'd14: slot3_adr <= csr_di[31:2];
174                                         // slot3_count is read-only
175
176                                         5'd16: csr_do <= tx_adr;
177                                         5'd17: begin
178                                                 csr_do <= tx_remaining;
179                                                 tx_bytecount <= 2'd0;
180                                         end
181                                 endcase
182                         end
183                         case(csr_a[4:0])
184                                 5'd0 : csr_do <= {promisc, speed10};
185                                 5'd1 : csr_do <= macaddr[47:24];
186                                 5'd2 : csr_do <= macaddr[23:0];
187
188                                 5'd3 : csr_do <= {phy_mii_clk, mii_data_oe, mii_data_di, mii_data_do};
189                                 
190                                 5'd4 : csr_do <= slot0_state;
191                                 5'd5 : csr_do <= slot0_adr;
192                                 5'd6 : csr_do <= slot0_count;
193                                 5'd7 : csr_do <= slot1_state;
194                                 5'd8 : csr_do <= slot1_adr;
195                                 5'd9 : csr_do <= slot1_count;
196                                 5'd10: csr_do <= slot2_state;
197                                 5'd11: csr_do <= slot2_adr;
198                                 5'd12: csr_do <= slot2_count;
199                                 5'd13: csr_do <= slot3_state;
200                                 5'd14: csr_do <= slot3_adr;
201                                 5'd15: csr_do <= slot3_count;
202
203                                 5'd16: csr_do <= tx_adr;
204                                 5'd17: csr_do <= tx_remaining;
205                         endcase
206                 end
207
208                 if(rx_incrcount) begin
209                         if(select0)
210                                 slot0_count <= slot0_count + 11'd1;
211                         if(select1)
212                                 slot1_count <= slot1_count + 11'd1;
213                         if(select2)
214                                 slot2_count <= slot2_count + 11'd1;
215                         if(select3)
216                                 slot3_count <= slot3_count + 11'd1;
217                 end
218                 if(rx_endframe) begin
219                         if(select0)
220                                 slot0_state <= 2'b10;
221                         if(select1)
222                                 slot1_state <= 2'b10;
223                         if(select2)
224                                 slot2_state <= 2'b10;
225                         if(select3)
226                                 slot3_state <= 2'b10;
227                 end
228
229                 if(tx_next) begin
230                         tx_remaining <= tx_remaining - 11'd1;
231                         tx_bytecount <= tx_bytecount + 2'd1;
232                         if(tx_bytecount == 2'd3)
233                                 tx_adr <= tx_adr + 30'd1;
234                 end
235         end
236 end
237
238 /* Interrupt logic */
239
240 reg tx_valid_r;
241
242 always @(posedge sys_clk) begin
243         if(sys_rst) begin
244                 irq_rx <= 1'b0;
245                 tx_valid_r <= 1'b0;
246                 irq_tx <= 1'b0;
247         end else begin
248                 irq_rx <= slot0_state[1] | slot1_state[1] | slot2_state[1] | slot3_state[1];
249                 tx_valid_r <= tx_valid;
250                 irq_tx <= tx_valid_r & ~tx_valid;
251         end
252 end
253
254 endmodule