]>
Commit | Line | Data |
---|---|---|
99b96879 JW |
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 |