blob: d830eb02244ca9a05f0bb0b55e37928cf791a73d [file] [log] [blame]
kthacker6de67752006-04-17 15:02:26 +00001/*
2 * uIP lan91c96 (smc9194) driver
3 * Based on cs8900a driver, copyrighted (c) 2001, by Adam Dunkels
4 * Copyright (c) 2003, Josef Soucek
5 * All rights reserved.
6 *
7 * Ethernet card for Commodore 64, based on lan91c96 chip
8 * is a device created by IDE64 Project team.
9 * More information: http://ide64.come.to
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
24 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 * $Id: lan91c96.c,v 1.1 2006/04/17 15:02:40 kthacker Exp $
36 *
37 */
38
39#define UIP_ETHADDR0 0x00
40#define UIP_ETHADDR1 0x0d
41#define UIP_ETHADDR2 0x60
42#define UIP_ETHADDR3 0x80
43#define UIP_ETHADDR4 0x3d
44#define UIP_ETHADDR5 0xb9
45
46#include "lan91c96.h"
47#include "uip.h"
48#include "uip_arp.h"
49
50#include <stdio.h>
51
52// #define DEBUG
53
54#define ETHBASE 0xde10
55
56#define ETHBSR ETHBASE+0x0e //Bank select register R/W (2B)
57
58/* Register bank 0 */
59
60#define ETHTCR ETHBASE //Transmition control register R/W (2B)
61#define ETHEPHSR ETHBASE+2 //EPH status register R/O (2B)
62#define ETHRCR ETHBASE+4 //Receive control register R/W (2B)
63#define ETHECR ETHBASE+6 //Counter register R/O (2B)
64#define ETHMIR (ETHBASE+8) //Memory information register R/O (2B)
65#define ETHMCR ETHBASE+0x0a //Memory Config. reg. +0 R/W +1 R/O (2B)
66
67/* Register bank 1 */
68
69#define ETHCR ETHBASE //Configuration register R/W (2B)
70#define ETHBAR ETHBASE+2 //Base address register R/W (2B)
71#define ETHIAR ETHBASE+4 //Individual address register R/W (6B)
72#define ETHGPR ETHBASE+0x0a //General address register R/W (2B)
73#define ETHCTR ETHBASE+0x0c //Control register R/W (2B)
74
75/* Register bank 2 */
76
77#define ETHMMUCR ETHBASE //MMU command register W/O (1B)
78#define ETHAUTOTX ETHBASE+1 //AUTO TX start register R/W (1B)
79#define ETHPNR ETHBASE+2 //Packet number register R/W (1B)
80#define ETHARR ETHBASE+3 //Allocation result register R/O (1B)
81#define ETHFIFO ETHBASE+4 //FIFO ports register R/O (2B)
82#define ETHPTR ETHBASE+6 //Pointer register R/W (2B)
83#define ETHDATA ETHBASE+8 //Data register R/W (4B)
84#define ETHIST (ETHBASE+0x0c) //Interrupt status register R/O (1B)
85#define ETHACK ETHBASE+0x0c //Interrupt acknowledge register W/O (1B)
86#define ETHMSK ETHBASE+0x0d //Interrupt mask register R/W (1B)
87
88/* Register bank 3 */
89
90#define ETHMT ETHBASE //Multicast table R/W (8B)
91#define ETHMGMT ETHBASE+8 //Management interface R/W (2B)
92#define ETHREV ETHBASE+0x0a //Revision register R/W (2B)
93#define ETHERCV ETHBASE+0x0c //Early RCV register R/W (2B)
94
95#define BANK(num) asm("lda #%b",num); asm("sta %w",ETHBSR);
96
97#ifdef DEBUG
98static void print_packet(u8_t *, u16_t);
99#endif
100
101static u8_t packet_status;
102static u16_t packet_length;
103
104extern u16_t uip_len;
105
106
107#pragma optimize(push, off)
108void lan91c96_init(void)
109{
110 /* Check if high byte is 0x33 */
111 asm("lda %w", ETHBSR+1);
112 asm("cmp #$33");
113 asm("beq @L1");
114
115 asm("inc $d021"); // Error
116
117 asm("@L1:");
118
119 /* Reset ETH card */
120 BANK(0);
121 asm("lda #%%10000000"); //Software reset
122 asm("sta %w", ETHRCR+1);
123
124 asm("lda #0");
125 asm("sta %w", ETHRCR);
126 asm("sta %w", ETHRCR+1);
127
128 /* delay */
129 asm("ldx #0");
130 asm("@L2:");
131 asm("cmp ($ff,x)"); //6 cycles
132 asm("cmp ($ff,x)"); //6 cycles
133 asm("dex"); //2 cycles
134 asm("bne @L2"); //3 cycles
135 //17*256=4352 => 4,4 ms
136
137 /* Enable transmit and receive */
138 asm("lda #%%10000001"); //Enable transmit TXENA, PAD_EN
139 asm("sta %w", ETHTCR);
140 asm("lda #%%00000011"); //Enable receive, strip CRC ???
141 asm("sta %w", ETHRCR+1);
142
143 BANK(1);
144 asm("lda %w", ETHCR+1);
145 asm("ora #%%00010000"); //No wait (IOCHRDY)
146 asm("sta %w", ETHCR+1);
147
148 asm("lda #%%00001001"); //Auto release
149 asm("sta %w", ETHCTR+1);
150
151 /* Set MAC address */
152 asm("lda #%b", (unsigned)UIP_ETHADDR0);
153 asm("sta %w", ETHIAR);
154 asm("lda #%b", (unsigned)UIP_ETHADDR1);
155 asm("sta %w", ETHIAR+1);
156 asm("lda #%b", (unsigned)UIP_ETHADDR2);
157 asm("sta %w", ETHIAR+2);
158 asm("lda #%b", (unsigned)UIP_ETHADDR3);
159 asm("sta %w", ETHIAR+3);
160 asm("lda #%b", (unsigned)UIP_ETHADDR4);
161 asm("sta %w", ETHIAR+4);
162 asm("lda #%b", (unsigned)UIP_ETHADDR5);
163 asm("sta %w", ETHIAR+5);
164
165 BANK(2);
166 asm("lda #%%00001111"); //RCV INT, ALLOC INT, TX INT, TX EMPTY
167 asm("sta %w", ETHMSK);
168}
169#pragma optimize(pop)
170
171
172#pragma optimize(push, off)
173#if UIP_BUFSIZE > 255
174u16_t lan91c96_poll(void)
175#else
176u8_t lan91c96_poll(void)
177#endif
178{
179 // #######
180// BANK(0);
181// printf("RAM: %d ", ((*(unsigned int *)ETHMIR) & 0xff00));
182// BANK(2);
183 // #######
184
185 asm("lda %w", ETHIST);
186 asm("and #%%00000001"); //RCV INT
187 asm("bne @L1");
188
189 /* No packet available */
190 return 0;
191
192 asm("@L1:");
193
194 #ifdef DEBUG
195 printf("RCV: IRQ\n");
196 #endif
197
198 asm("lda #0");
199 asm("sta %w", ETHPTR);
200 asm("lda #%%11100000"); //RCV,AUTO INCR.,READ
201 asm("sta %w", ETHPTR+1);
202
203 asm("lda %w", ETHDATA); //Status word
204 asm("lda %w", ETHDATA);
205 asm("sta _packet_status"); //High byte only
206
207 asm("lda %w", ETHDATA); //Total number of bytes
208 asm("sta _packet_length");
209 asm("lda %w", ETHDATA);
210 asm("sta _packet_length+1");
211
212 /* Last word contain 'last data byte' and 0x60 */
213 /* or 'fill byte' and 0x40 */
214
215 packet_length -= 6; //The packet contains 3 extra words
216
217 asm("lda _packet_status");
218 asm("and #$10");
219 asm("beq @L2");
220
221 packet_length++;
222
223 #ifdef DEBUG
224 printf("RCV: odd number of bytes\n");
225 #endif
226
227 asm("@L2:");
228
229 #ifdef DEBUG
230 printf("RCV: L:%d ST-HIGH:0x%02x ",packet_length,packet_status);
231 #endif
232
233 if (packet_length > UIP_BUFSIZE)
234 {
235 /* Remove and release RX packet from FIFO*/
236 asm("lda #%%10000000");
237 asm("sta %w", ETHMMUCR);
238
239 #ifdef DEBUG
240 printf("RCV: UIP_BUFSIZE exceeded - packet dropped!\n");
241 #endif
242
243 return 0;
244 }
245
246 asm("lda #<_uip_buf");
247 asm("sta ptr1");
248 asm("lda #>_uip_buf");
249 asm("sta ptr1+1");
250
251 asm("ldy #0");
252 asm("ldx _packet_length+1");
253 asm("beq @RE1"); //packet_length < 256
254
255 asm("@RL1:");
256 asm("lda %w", ETHDATA);
257 asm("sta (ptr1),y");
258 asm("iny");
259 asm("bne @RL1");
260 asm("inc ptr1+1");
261 asm("dex");
262 asm("bne @RL1");
263
264 asm("@RE1:");
265 asm("lda %w", ETHDATA);
266 asm("sta (ptr1),y");
267 asm("iny");
268 asm("cpy _packet_length");
269 asm("bne @RE1");
270
271 /* Remove and release RX packet from FIFO*/
272 asm("lda #%%10000000");
273 asm("sta %w", ETHMMUCR);
274
275 #ifdef DEBUG
276// print_packet(uip_buf, packet_length);
277 #endif
278
279 return packet_length;
280}
281#pragma optimize(pop)
282
283/* First 40+14 (IP nad TCP header) is send from uip_buf */
284/* than data from uip_appdata */
285
286#pragma optimize(push, off)
287void lan91c96_send(void)
288{
289 #ifdef DEBUG
290 printf("SND: send packet\n");
291 #endif
292
293 #if UIP_BUFSIZE > 255
294 asm("lda _uip_len+1");
295 #else
296 asm("lda #0");
297 #endif
298 asm("ora #%%00100000"); //Allocate memory for TX
299 asm("sta %w", ETHMMUCR);
300
301 asm("ldx #8"); //Wait...
302 asm("@L1:"); //Wait for allocation ready
303 asm("lda %w", ETHIST);
304 asm("and #%%00001000"); //ALLOC INT
305 asm("bne @X1");
306 asm("dex");
307 asm("bne @L1");
308
309 #ifdef DEBUG
310 printf("SND: ERR: memory alloc timeout\n");
311 #endif
312
313 return;
314
315 asm("@X1:");
316 #ifdef DEBUG
317 printf("SND: packet memory allocated\n");
318 #endif
319
320 asm("lda #%%00001000"); //Acknowledge int, is it necessary ???
321 asm("sta %w", ETHACK);
322
323 asm("lda %w", ETHARR);
324 asm("sta %w", ETHPNR); //Set packet address
325
326 asm("lda #0");
327 asm("sta %w", ETHPTR);
328 asm("lda #%%01000000"); //AUTO INCR.
329 asm("sta %w", ETHPTR+1);
330
331 #ifdef DEBUG
332 printf("SND: L:%d ", uip_len);
333 #endif
334
335 asm("lda #0"); //Status written by CSMA
336 asm("sta %w", ETHDATA);
337 asm("sta %w", ETHDATA);
338
339 asm("lda _uip_len");
340 asm("and #$01");
341 asm("beq @SD1");
342
343 packet_length=uip_len+5;
344 asm("jmp @LC1");
345
346 asm("@SD1:");
347
348 packet_length=uip_len+6; //+6 for status word, length and ctl byte
349
350 asm("@LC1:");
351
352// printf("SND: L:%d ", packet_length);
353
354 asm("lda _packet_length");
355 asm("sta %w", ETHDATA);
356 asm("lda _packet_length+1");
357 asm("sta %w", ETHDATA);
358
359 #ifdef DEBUG
360// print_packet(uip_buf, uip_len);
361 #endif
362
363 /* Send 40+14=54 bytes of header */
364
365 if(uip_len <= 54) {
366
367 #ifdef DEBUG
368 printf("SND: short packet sent.\n");
369 #endif
370
371 asm("ldx _uip_len");
372 asm("ldy #0");
373 asm("@WL1:");
374 asm("lda _uip_buf,y");
375 asm("sta %w", ETHDATA);
376 asm("iny");
377 asm("dex");
378 asm("bne @WL1");
379
380 } else {
381
382 asm("ldx #54");
383 asm("ldy #0");
384 asm("@WL2:");
385 asm("lda _uip_buf,y");
386 asm("sta %w", ETHDATA);
387 asm("iny");
388 asm("dex");
389 asm("bne @WL2");
390
391 uip_len -= 54;
392
393 asm("lda _uip_appdata"); //uip_appdata is pointer
394 asm("sta ptr1");
395 asm("lda _uip_appdata+1");
396 asm("sta ptr1+1");
397
398 asm("ldy #0");
399 #if UIP_BUFSIZE > 255
400 asm("ldx _uip_len+1");
401 #else
402 asm("ldx #0");
403 #endif
404 asm("beq @RE1"); //packet_length < 256
405
406 asm("@RL1:");
407 asm("lda (ptr1),y");
408 asm("sta %w", ETHDATA);
409 asm("iny");
410 asm("bne @RL1");
411 asm("inc ptr1+1");
412 asm("dex");
413 asm("bne @RL1");
414
415 asm("@RE1:");
416 asm("lda (ptr1),y");
417 asm("sta %w", ETHDATA);
418 asm("iny");
419 asm("cpy _uip_len");
420 asm("bne @RE1");
421
422 }
423
424 asm("lda _uip_len");
425 asm("and #$01");
426 asm("beq @R3");
427
428 asm("lda #%%00100000");
429 asm("sta %w", ETHDATA); //Control byte
430
431 asm("lda #%%11000000"); //ENQUEUE PACKET - transmit packet
432 asm("sta %w", ETHMMUCR);
433
434// printf("\n## %02x", *(unsigned char *)ETHIST);
435
436 return;
437
438 asm("@R3:");
439
440 asm("lda #0");
441 asm("sta %w", ETHDATA); //Fill byte
442 asm("sta %w", ETHDATA); //Control byte
443
444 asm("lda #%%11000000"); //ENQUEUE PACKET - transmit packet
445 asm("sta %w", ETHMMUCR);
446
447// printf("\n## %02x\n", *(unsigned char *)ETHIST);
448 return;
449}
450#pragma optimize(pop)
451
452#ifdef DEBUG
453static void print_packet(u8_t *buf, u16_t length)
454{
455 int i;
456 int remainder;
457 int lines;
458 u8_t a;
459 int cur;
460 int address=0;
461
462 printf("\nPacket of length %d \n", length );
463
464 lines = length / 8;
465 remainder = length % 8;
466
467 for ( i = 0; i < lines ; i ++ ) {
468 printf(":%04x ", address=i*8);
469
470 for ( cur = 0; cur < 8; cur ++ ) {
471 a = *(buf ++ );
472 printf("%02x ", a);
473 }
474 printf("\n");
475 }
476
477 printf(":%04x ", address+8);
478
479 for ( i = 0; i < remainder ; i++ ) {
480 a = *(buf ++ );
481 printf("%02x ", a);
482 }
483 printf("\n");
484}
485#endif /* DEBUG */
486