Ethernet RX support
[fpgaboy.git] / Ethernet.v
CommitLineData
99b96879
JW
1`define ADDR_ETH_STATUS 16'hFF68
2`define ADDR_ETH 16'hFF69
3
4module Ethernet (
5 input clk,
6 input wr,
7 input rd,
8 input [15:0] addr,
9 inout [7:0] data,
10 input ethclk, rxclk,
11 input rxp, rxm,
faa9ae6f 12 output txp, txm);
99b96879 13
faa9ae6f
JW
14 wire [10:0] txhwaddr;
15 wire [7:0] txhwdata;
16 wire txbusy;
99b96879 17
faa9ae6f
JW
18 reg [10:0] txlength = 0;
19 reg [10:0] txwraddr = 0;
20 reg [1:0] txstate = 0;
21 reg txstart = 0;
99b96879
JW
22
23 reg [15:0] addrlatch;
24 reg rdlatch;
faa9ae6f
JW
25
26 wire decode = (addrlatch == `ADDR_ETH_STATUS) || (addrlatch == `ADDR_ETH);
27 reg [7:0] odata;
28 assign data = (decode && rdlatch) ? odata : 8'bzzzzzzzz;
99b96879
JW
29
30 EnetTX tx(
31 .clk20(ethclk),
32 .Ethernet_TDp(txp),
33 .Ethernet_TDm(txm),
faa9ae6f
JW
34 .busy(txbusy),
35 .length(txlength),
36 .rdaddress(txhwaddr),
37 .start(txstart),
38 .indata(txhwdata));
99b96879
JW
39
40 EthModRam txram(
41 .wdata(data),
faa9ae6f 42 .waddr(txwraddr),
99b96879 43 .wr(wr && state == 2'b10 && addr == `ADDR_ETH),
faa9ae6f
JW
44 .wrclk(clk),
45 .rdata(txhwdata),
46 .raddr(txhwaddr),
47 .rdclk(ethclk));
48
49 wire [10:0] rxphyaddr;
50 wire [7:0] rxphydata;
51 wire rxphywr;
52 wire rxpktrdy;
53 reg rxclear = 0;
54 reg [1:0] rxstate = 0;
55 wire [10:0] rxlength;
56 reg [10:0] rxcurlength;
57
58 reg [10:0] rxcoreaddr = 0;
59 wire [7:0] rxcoredata;
99b96879 60
faa9ae6f
JW
61 EnetRX rx(
62 .rxclk(rxclk),
63 .manchester_data_in(~rxp),
64 .wr(rxphywr),
65 .oaddr(rxphyaddr),
66 .odata(rxphydata),
67 .pktrdy(rxpktrdy),
68 .olength(rxlength),
69 .pktclear(rxclear));
70
71 EthModRam rxram(
72 .wdata(rxphydata),
73 .waddr(rxphyaddr),
74 .wr(rxphywr),
75 .wrclk(rxclk),
76 .rdata(rxcoredata),
77 .raddr(rxcoreaddr),
78 .rdclk(clk));
79
99b96879
JW
80 always @ (posedge clk) begin
81 addrlatch <= addr;
82 rdlatch <= rd;
faa9ae6f
JW
83
84 if (rd && addr == `ADDR_ETH_STATUS)
85 odata <= {state,4'b0,rxpktrdy,txbusy};
86 else if (wr && addr == `ADDR_ETH_STATUS) begin /* Reset the state machines. */
87 rxstate <= 2'b00;
88 txstate <= 2'b00;
89 end else if (rd && addr == `ADDR_ETH) begin
90 case (rxstate)
99b96879 91 2'b00: begin
faa9ae6f
JW
92 if (!rxpktrdy)
93 rxcurlength <= 0;
94 else
95 rxcurlength <= rxlength;
96 odata <= rxpktrdy ? {5'b0,rxlength[10:8]} : 8'b0;
97 rxstate <= 2'b01;
99b96879
JW
98 end
99 2'b01: begin
faa9ae6f
JW
100 rxstate <= (rxcurlength == 0) ? 2'b00 : 2'b10;
101 odata <= rxcurlength[7:0];
102 rxcoreaddr <= 0;
103 end
104 2'b10: begin
105 odata <= rxcoredata;
106 if (rxcoreaddr == (rxcurlength - 1)) begin
107 rxstate <= 2'b11;
108 rxclear <= 1;
109 end else
110 rxcoreaddr <= rxcoreaddr + 1;
111 end
112 endcase
113 end else if (rxstate == 2'b11 || rxclear) begin
114 rxstate <= 2'b00;
115 rxclear <= 0;
116 end else if (wr && addr == `ADDR_ETH) begin
117 case(txstate)
118 2'b00: begin
119 txlength[10:8] <= data[2:0];
120 txstate <= 2'b01;
121 end
122 2'b01: begin
123 txlength[7:0] <= data[7:0];
124 txstate <= 2'b10;
125 txwraddr <= 0;
99b96879
JW
126 end
127 2'b10:
faa9ae6f
JW
128 if(txwraddr == (txlength - 1)) begin
129 txstate <= 2'b11;
130 txstart <= 1'b1;
99b96879 131 end else
faa9ae6f 132 txwraddr <= txwraddr + 1;
99b96879 133 endcase
faa9ae6f
JW
134 end else if (txstate == 2'b11) begin
135 txstart <= 1'b0;
136 txstate <= 2'b00;
99b96879
JW
137 end
138 end
139
140endmodule
141
142module EthModRam (
143 input [7:0] wdata,
144 input [10:0] waddr,
145 input [10:0] raddr,
146 input wr,
faa9ae6f
JW
147 input wrclk,
148 input rdclk,
149 output reg [7:0] rdata);
99b96879
JW
150
151 reg [7:0] mem [1600:0];
152
faa9ae6f 153 always @(posedge wrclk) begin
99b96879
JW
154 if(wr)
155 mem[waddr] <= wdata;
156 end
157
faa9ae6f 158 always @(posedge rdclk)
99b96879
JW
159 rdata <= mem[raddr];
160endmodule
161
162module EnetTX(input clk20, output reg Ethernet_TDp, output reg Ethernet_TDm, output wire busy, input start, input [11:0] length, output wire [11:0] rdaddress, input [7:0] indata);
163 reg StartSending; always @(posedge clk20) StartSending<=start;
164 reg [11:0] curlen = 0; always @(posedge clk20) if (start) curlen <= length + 8;
165
166 reg [11:0] internaladdr;
167 assign rdaddress = internaladdr - 8;
168 wire [7:0] pkt_data = (internaladdr < 7) ? 8'h55 :
169 (internaladdr == 7) ? 8'hD5 :
170 indata;
171
172 //////////////////////////////////////////////////////////////////////
173 // and finally the 10BASE-T's magic
174 reg [3:0] ShiftCount;
175 reg SendingPacket;
176 always @(posedge clk20) if(StartSending) SendingPacket<=1; else if(ShiftCount==14 && internaladdr==(curlen + 4)) SendingPacket<=0;
177 always @(posedge clk20) ShiftCount <= SendingPacket ? ShiftCount+1 : 15;
178 wire readram = (ShiftCount==15);
179 always @(posedge clk20) if(ShiftCount==15) internaladdr <= SendingPacket ? internaladdr+1 : 0;
180 reg [7:0] ShiftData; always @(posedge clk20) if(ShiftCount[0]) ShiftData <= readram ? pkt_data : {1'b0, ShiftData[7:1]};
181
182 // generate the CRC32
183 reg [31:0] CRC;
184 reg CRCflush; always @(posedge clk20) if(CRCflush) CRCflush <= SendingPacket; else if(readram) CRCflush <= (internaladdr==curlen);
185 reg CRCinit; always @(posedge clk20) if(readram) CRCinit <= (internaladdr==7);
186 wire CRCinput = CRCflush ? 0 : (ShiftData[0] ^ CRC[31]);
187 always @(posedge clk20) if(ShiftCount[0]) CRC <= CRCinit ? ~0 : ({CRC[30:0],1'b0} ^ ({32{CRCinput}} & 32'h04C11DB7));
188
189 // generate the NLP
190 reg [17:0] LinkPulseCount; always @(posedge clk20) LinkPulseCount <= SendingPacket ? 0 : LinkPulseCount+1;
191 reg LinkPulse; always @(posedge clk20) LinkPulse <= &LinkPulseCount[17:1];
192
193 // TP_IDL, shift-register and manchester encoder
194 reg SendingPacketData; always @(posedge clk20) SendingPacketData <= SendingPacket;
195 assign busy = SendingPacketData;
196 reg [2:0] idlecount; always @(posedge clk20) if(SendingPacketData) idlecount<=0; else if(~&idlecount) idlecount<=idlecount+1;
197 wire dataout = CRCflush ? ~CRC[31] : ShiftData[0];
198 reg qo; always @(posedge clk20) qo <= SendingPacketData ? ~dataout^ShiftCount[0] : 1;
199 reg qoe; always @(posedge clk20) qoe <= SendingPacketData | LinkPulse | (idlecount<6);
200 always @(posedge clk20) Ethernet_TDp <= (qoe ? qo : 1'b0);
201 always @(posedge clk20) Ethernet_TDm <= (qoe ? ~qo : 1'b0);
202endmodule
203
204module EnetRX(
205 input rxclk,
206 input manchester_data_in,
faa9ae6f 207 output reg wr,
99b96879 208 output reg [10:0] oaddr,
faa9ae6f
JW
209 output reg [7:0] odata,
210 output reg pktrdy = 0,
211 output reg [10:0] olength = 0,
99b96879
JW
212 input pktclear);
213
214 reg [2:0] in_data;
215 always @(posedge rxclk) in_data <= {in_data[1:0], manchester_data_in};
216
217 reg [7:0] data;
218
219 reg [1:0] cnt;
220 always @(posedge rxclk) if(|cnt || (in_data[2] ^ in_data[1])) cnt<=cnt+1;
221
222 reg new_bit_avail;
223 always @(posedge rxclk) new_bit_avail <= (cnt==3);
224 always @(posedge rxclk) if(cnt==3) data<={in_data[1],data[7:1]};
225
226 /////////////////////////////////////////////////
227 reg end_of_Ethernet_frame;
228
229 reg [4:0] sync1;
230 always @(posedge rxclk)
231 if(end_of_Ethernet_frame)
232 sync1<=0;
233 else if(new_bit_avail) begin
234 if(!(data==8'h55 || data==8'hAA)) // not preamble?
235 sync1 <= 0;
236 else
237 if(~&sync1) // if all bits of this "sync1" counter are one, we decide that enough of the preamble
238 // has been received, so stop counting and wait for "sync2" to detect the SFD
239 sync1 <= sync1 + 1; // otherwise keep counting
240 end
241
242 reg [9:0] sync2;
243 always @(posedge rxclk)
faa9ae6f 244 if(end_of_Ethernet_frame || pktrdy) // i.e., if we're busy, drop it on the floor
99b96879
JW
245 sync2 <= 0;
246 else
247 if(new_bit_avail) begin
248 if(|sync2) // if the SFD has already been detected (Ethernet data is coming in)
249 sync2 <= sync2 + 1; // then count the bits coming in
250 else if(&sync1 && data==8'hD5) // otherwise, let's wait for the SFD (0xD5)
251 sync2 <= sync2 + 1;
252 end
253
254 wire new_byte_available = new_bit_avail && (sync2[2:0]==3'h0) && (sync2[9:3]!=0);
255
256 /////////////////////////////////////////////////
257 // if no clock transistion is detected for some time, that's the end of the Ethernet frame
258
259 reg [2:0] transition_timeout;
260 always @(posedge rxclk) if(in_data[2]^in_data[1]) transition_timeout<=0; else if(~&cnt) transition_timeout<=transition_timeout+1;
261 always @(posedge rxclk) end_of_Ethernet_frame <= &transition_timeout;
262
263 /////////////////////////////////////////////////
264 always @(posedge rxclk)
265 if (new_byte_available && !pktrdy) begin
266 odata <= data;
267 oaddr <= oaddr + 1;
268 wr <= 1;
faa9ae6f 269 end else if (end_of_Ethernet_frame && (oaddr > 1)) begin
99b96879
JW
270 olength <= oaddr;
271 oaddr <= 0;
272 wr <= 0;
273 pktrdy <= 1;
274 end else if (pktclear) begin
275 pktrdy <= 0;
276 wr <= 0;
faa9ae6f 277 end else
99b96879
JW
278 wr <= 0;
279
280endmodule
This page took 0.044106 seconds and 4 git commands to generate.