]> Joshua Wise's Git repositories - fpgaboy.git/blob - Ethernet.v
2f0c668624e12a232f0158440e8d8524ec6b3067
[fpgaboy.git] / Ethernet.v
1 `define ADDR_ETH_STATUS 16'hFF68
2 `define ADDR_ETH 16'hFF69
3
4 module 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,
12         output txp, txm,
13 );
14
15         wire [10:0] outaddr;
16         wire [7:0] outdata;
17         wire busy;
18
19         reg [10:0] len = 0;
20         reg [10:0] addrcnt = 0;
21         reg [1:0] state = 0;
22         reg start = 0;
23         
24         reg [15:0] addrlatch;
25         reg rdlatch;
26
27         assign data = (addrlatch == `ADDR_ETH_STATUS && rdlatch) ? {state,5'b0,busy} : 8'bzzzzzzzz;
28
29         EnetTX tx(
30                 .clk20(ethclk),
31                 .Ethernet_TDp(txp),
32                 .Ethernet_TDm(txm),
33                 .busy(busy),
34                 .length(len),
35                 .rdaddress(outaddr),
36                 .start(start),
37                 .indata(outdata));
38         
39         EthModRam txram(
40                 .wdata(data),
41                 .waddr(addrcnt),
42                 .raddr(outaddr),
43                 .wr(wr && state == 2'b10 && addr == `ADDR_ETH),
44                 .clk(clk),
45                 .ethclk(ethclk),
46                 .rdata(outdata)
47         );      
48         
49         always @ (posedge clk) begin
50                 addrlatch <= addr;
51                 rdlatch <= rd;
52                 if(wr && addr == `ADDR_ETH) begin
53                         case(state)
54                         2'b00: begin
55                                 len[10:8] <= data[2:0];
56                                 state <= 2'b01;
57                         end
58                         2'b01: begin
59                                 len[7:0] <= data[7:0];
60                                 state <= 2'b10;
61                         end
62                         2'b10:
63                                 if(addrcnt == len) begin
64                                         state <= 2'b11;
65                                         start <= 1'b1;
66                                         addrcnt <= 0;
67                                 end else
68                                         addrcnt <= addrcnt + 1;
69                         endcase
70                 end else if (state == 2'b11) begin
71                         start <= 1'b0;
72                         state <= 2'b00;
73                 end
74         end
75
76 endmodule
77
78 module EthModRam (
79         input [7:0] wdata,
80         input [10:0] waddr,
81         input [10:0] raddr,
82         input wr,
83         input clk,
84         input ethclk,
85         output reg [7:0] rdata
86 );
87
88         reg [7:0] mem [1600:0];
89
90         always @ (posedge clk) begin
91                 if(wr)
92                         mem[waddr] <= wdata;
93         end
94
95         always @(posedge ethclk)
96                 rdata <= mem[raddr];
97 endmodule
98
99 module 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);
100         reg StartSending; always @(posedge clk20) StartSending<=start;
101         reg [11:0] curlen = 0; always @(posedge clk20) if (start) curlen <= length + 8;
102         
103         reg [11:0] internaladdr;
104         assign rdaddress = internaladdr - 8;
105         wire [7:0] pkt_data = (internaladdr < 7) ? 8'h55 :
106                                 (internaladdr == 7) ? 8'hD5 :
107                                 indata;
108
109         //////////////////////////////////////////////////////////////////////
110         // and finally the 10BASE-T's magic
111         reg [3:0] ShiftCount;
112         reg SendingPacket;
113         always @(posedge clk20) if(StartSending) SendingPacket<=1; else if(ShiftCount==14 && internaladdr==(curlen + 4)) SendingPacket<=0;
114         always @(posedge clk20) ShiftCount <= SendingPacket ? ShiftCount+1 : 15;
115         wire readram = (ShiftCount==15);
116         always @(posedge clk20) if(ShiftCount==15) internaladdr <= SendingPacket ? internaladdr+1 : 0;
117         reg [7:0] ShiftData; always @(posedge clk20) if(ShiftCount[0]) ShiftData <= readram ? pkt_data : {1'b0, ShiftData[7:1]};
118
119         // generate the CRC32
120         reg [31:0] CRC;
121         reg CRCflush; always @(posedge clk20) if(CRCflush) CRCflush <= SendingPacket; else if(readram) CRCflush <= (internaladdr==curlen);
122         reg CRCinit; always @(posedge clk20) if(readram) CRCinit <= (internaladdr==7);
123         wire CRCinput = CRCflush ? 0 : (ShiftData[0] ^ CRC[31]);
124         always @(posedge clk20) if(ShiftCount[0]) CRC <= CRCinit ? ~0 : ({CRC[30:0],1'b0} ^ ({32{CRCinput}} & 32'h04C11DB7));
125
126         // generate the NLP
127         reg [17:0] LinkPulseCount; always @(posedge clk20) LinkPulseCount <= SendingPacket ? 0 : LinkPulseCount+1;
128         reg LinkPulse; always @(posedge clk20) LinkPulse <= &LinkPulseCount[17:1];
129
130         // TP_IDL, shift-register and manchester encoder
131         reg SendingPacketData; always @(posedge clk20) SendingPacketData <= SendingPacket;
132         assign busy = SendingPacketData;
133         reg [2:0] idlecount; always @(posedge clk20) if(SendingPacketData) idlecount<=0; else if(~&idlecount) idlecount<=idlecount+1;
134         wire dataout = CRCflush ? ~CRC[31] : ShiftData[0];
135         reg qo; always @(posedge clk20) qo <= SendingPacketData ? ~dataout^ShiftCount[0] : 1;
136         reg qoe; always @(posedge clk20) qoe <= SendingPacketData | LinkPulse | (idlecount<6);
137         always @(posedge clk20) Ethernet_TDp <= (qoe ? qo : 1'b0);
138         always @(posedge clk20) Ethernet_TDm <= (qoe ? ~qo : 1'b0);
139 endmodule
140
141 module EnetRX(
142         input rxclk,
143         input manchester_data_in,
144         output wire wr,
145         output reg [10:0] oaddr,
146         output wire [7:0] odata,
147         output reg pktrdy,
148         output reg [10:0] olength,
149         input pktclear);
150         
151         reg [2:0] in_data;
152         always @(posedge rxclk) in_data <= {in_data[1:0], manchester_data_in};
153         
154         reg [7:0] data;
155         
156         reg [1:0] cnt;
157         always @(posedge rxclk) if(|cnt || (in_data[2] ^ in_data[1])) cnt<=cnt+1;
158         
159         reg new_bit_avail;
160         always @(posedge rxclk) new_bit_avail <= (cnt==3);
161         always @(posedge rxclk) if(cnt==3) data<={in_data[1],data[7:1]};
162
163         /////////////////////////////////////////////////
164         reg end_of_Ethernet_frame;
165         
166         reg [4:0] sync1;
167         always @(posedge rxclk)
168                 if(end_of_Ethernet_frame)
169                         sync1<=0; 
170                 else if(new_bit_avail) begin
171                         if(!(data==8'h55 || data==8'hAA))       // not preamble?
172                                 sync1 <= 0;
173                         else
174                                 if(~&sync1)             // if all bits of this "sync1" counter are one, we decide that enough of the preamble
175                                                         // has been received, so stop counting and wait for "sync2" to detect the SFD
176                                         sync1 <= sync1 + 1; // otherwise keep counting
177                 end
178         
179         reg [9:0] sync2;
180         always @(posedge rxclk)
181                 if(end_of_Ethernet_frame || !pktrdy)
182                         sync2 <= 0;
183                 else 
184                 if(new_bit_avail) begin
185                         if(|sync2) // if the SFD has already been detected (Ethernet data is coming in)
186                                 sync2 <= sync2 + 1; // then count the bits coming in
187                         else if(&sync1 && data==8'hD5) // otherwise, let's wait for the SFD (0xD5)
188                                 sync2 <= sync2 + 1;
189                 end
190
191         wire new_byte_available = new_bit_avail && (sync2[2:0]==3'h0) && (sync2[9:3]!=0);  
192
193         /////////////////////////////////////////////////
194         // if no clock transistion is detected for some time, that's the end of the Ethernet frame
195
196         reg [2:0] transition_timeout;
197         always @(posedge rxclk) if(in_data[2]^in_data[1]) transition_timeout<=0; else if(~&cnt) transition_timeout<=transition_timeout+1;
198         always @(posedge rxclk) end_of_Ethernet_frame <= &transition_timeout;
199         
200         /////////////////////////////////////////////////
201         always @(posedge rxclk)
202                 if (new_byte_available && !pktrdy) begin
203                         odata <= data;
204                         oaddr <= oaddr + 1;
205                         wr <= 1;
206                 end else if (end_of_Ethernet_frame) begin
207                         olength <= oaddr;
208                         oaddr <= 0;
209                         wr <= 0;
210                         pktrdy <= 1;
211                 end else if (pktclear) begin
212                         pktrdy <= 0;
213                         wr <= 0;
214                 else
215                         wr <= 0;
216         
217 endmodule
This page took 0.032279 seconds and 2 git commands to generate.