blob: 2c3b7f33fa21b515f0512d34304096d3dfa2a05c [file] [log] [blame]
adamdunkels45c1f132004-02-16 20:59:49 +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.2 2004/02/16 21:00:05 adamdunkels Exp $
36 *
37 */
38
39#include "lan91c96.h"
40#include "uip.h"
41#include "uip_arp.h"
42
43#include <stdio.h>
44
45// #define DEBUG
46
47#define ETHBASE 0xde10
48
49#define ETHBSR ETHBASE+0x0e //Bank select register R/W (2B)
50
51/* Register bank 0 */
52
53#define ETHTCR ETHBASE //Transmition control register R/W (2B)
54#define ETHEPHSR ETHBASE+2 //EPH status register R/O (2B)
55#define ETHRCR ETHBASE+4 //Receive control register R/W (2B)
56#define ETHECR ETHBASE+6 //Counter register R/O (2B)
57#define ETHMIR (ETHBASE+8) //Memory information register R/O (2B)
58#define ETHMCR ETHBASE+0x0a //Memory Config. reg. +0 R/W +1 R/O (2B)
59
60/* Register bank 1 */
61
62#define ETHCR ETHBASE //Configuration register R/W (2B)
63#define ETHBAR ETHBASE+2 //Base address register R/W (2B)
64#define ETHIAR ETHBASE+4 //Individual address register R/W (6B)
65#define ETHGPR ETHBASE+0x0a //General address register R/W (2B)
66#define ETHCTR ETHBASE+0x0c //Control register R/W (2B)
67
68/* Register bank 2 */
69
70#define ETHMMUCR ETHBASE //MMU command register W/O (1B)
71#define ETHAUTOTX ETHBASE+1 //AUTO TX start register R/W (1B)
72#define ETHPNR ETHBASE+2 //Packet number register R/W (1B)
73#define ETHARR ETHBASE+3 //Allocation result register R/O (1B)
74#define ETHFIFO ETHBASE+4 //FIFO ports register R/O (2B)
75#define ETHPTR ETHBASE+6 //Pointer register R/W (2B)
76#define ETHDATA ETHBASE+8 //Data register R/W (4B)
77#define ETHIST (ETHBASE+0x0c) //Interrupt status register R/O (1B)
78#define ETHACK ETHBASE+0x0c //Interrupt acknowledge register W/O (1B)
79#define ETHMSK ETHBASE+0x0d //Interrupt mask register R/W (1B)
80
81/* Register bank 3 */
82
83#define ETHMT ETHBASE //Multicast table R/W (8B)
84#define ETHMGMT ETHBASE+8 //Management interface R/W (2B)
85#define ETHREV ETHBASE+0x0a //Revision register R/W (2B)
86#define ETHERCV ETHBASE+0x0c //Early RCV register R/W (2B)
87
88#define BANK(num) asm("lda #%b",num); asm("sta %w",ETHBSR);
89
90#ifdef DEBUG
91static void print_packet(u8_t *, u16_t);
92#endif
93
94static u8_t packet_status;
95static u16_t packet_length;
96
97#if UIP_BUFSIZE > 255
98extern u16_t uip_len;
99#else
100extern u8_t uip_len;
101#endif
102
103
104void lan91c96_init(void)
105{
106 /* Check if high byte is 0x33 */
107 asm("lda %w", ETHBSR+1);
108 asm("cmp #$33");
109 asm("beq @L1");
110
111 asm("inc $d021"); // Error
112
113 asm("@L1:");
114
115 /* Reset ETH card */
116 BANK(0);
117 asm("lda #%%10000000"); //Software reset
118 asm("sta %w", ETHRCR+1);
119
120 asm("lda #0");
121 asm("sta %w", ETHRCR);
122 asm("sta %w", ETHRCR+1);
123
124 /* delay */
125 asm("ldx #0");
126 asm("@L2:");
127 asm("cmp ($ff,x)"); //6 cycles
128 asm("cmp ($ff,x)"); //6 cycles
129 asm("dex"); //2 cycles
130 asm("bne @L2"); //3 cycles
131 //17*256=4352 => 4,4 ms
132
133 /* Enable transmit and receive */
134 asm("lda #%%10000001"); //Enable transmit TXENA, PAD_EN
135 asm("sta %w", ETHTCR);
136 asm("lda #%%00000011"); //Enable receive, strip CRC ???
137 asm("sta %w", ETHRCR+1);
138
139 BANK(1);
140 asm("lda %w", ETHCR+1);
141 asm("ora #%%00010000"); //No wait (IOCHRDY)
142 asm("sta %w", ETHCR+1);
143
144 asm("lda #%%00001001"); //Auto release
145 asm("sta %w", ETHCTR+1);
146
147 /* Set MAC address */
148 asm("lda #%b", (unsigned)UIP_ETHADDR0);
149 asm("sta %w", ETHIAR);
150 asm("lda #%b", (unsigned)UIP_ETHADDR1);
151 asm("sta %w", ETHIAR+1);
152 asm("lda #%b", (unsigned)UIP_ETHADDR2);
153 asm("sta %w", ETHIAR+2);
154 asm("lda #%b", (unsigned)UIP_ETHADDR3);
155 asm("sta %w", ETHIAR+3);
156 asm("lda #%b", (unsigned)UIP_ETHADDR4);
157 asm("sta %w", ETHIAR+4);
158 asm("lda #%b", (unsigned)UIP_ETHADDR5);
159 asm("sta %w", ETHIAR+5);
160
161 BANK(2);
162 asm("lda #%%00001111"); //RCV INT, ALLOC INT, TX INT, TX EMPTY
163 asm("sta %w", ETHMSK);
164}
165
166
167#if UIP_BUFSIZE > 255
168u16_t lan91c96_poll(void)
169#else
170u8_t lan91c96_poll(void)
171#endif
172{
173 // #######
174// BANK(0);
175// printf("RAM: %d ", ((*(unsigned int *)ETHMIR) & 0xff00));
176// BANK(2);
177 // #######
178
179 asm("lda %w", ETHIST);
180 asm("and #%%00000001"); //RCV INT
181 asm("bne @L1");
182
183 /* No packet available */
184 return 0;
185
186 asm("@L1:");
187
188 #ifdef DEBUG
189 printf("RCV: IRQ\n");
190 #endif
191
192 asm("lda #0");
193 asm("sta %w", ETHPTR);
194 asm("lda #%%11100000"); //RCV,AUTO INCR.,READ
195 asm("sta %w", ETHPTR+1);
196
197 asm("lda %w", ETHDATA); //Status word
198 asm("lda %w", ETHDATA);
199 asm("sta _packet_status"); //High byte only
200
201 asm("lda %w", ETHDATA); //Total number of bytes
202 asm("sta _packet_length");
203 asm("lda %w", ETHDATA);
204 asm("sta _packet_length+1");
205
206 /* Last word contain 'last data byte' and 0x60 */
207 /* or 'fill byte' and 0x40 */
208
209 packet_length -= 6; //The packet contains 3 extra words
210
211 asm("lda _packet_status");
212 asm("and #$10");
213 asm("beq @L2");
214
215 packet_length++;
216
217 #ifdef DEBUG
218 printf("RCV: odd number of bytes\n");
219 #endif
220
221 asm("@L2:");
222
223 #ifdef DEBUG
224 printf("RCV: L:%d ST-HIGH:0x%02x ",packet_length,packet_status);
225 #endif
226
227 if (packet_length > UIP_BUFSIZE)
228 {
229 /* Remove and release RX packet from FIFO*/
230 asm("lda #%%10000000");
231 asm("sta %w", ETHMMUCR);
232
233 #ifdef DEBUG
234 printf("RCV: UIP_BUFSIZE exceeded - packet dropped!\n");
235 #endif
236
237 return 0;
238 }
239
240 asm("lda #<_uip_buf");
241 asm("sta ptr1");
242 asm("lda #>_uip_buf");
243 asm("sta ptr1+1");
244
245 asm("ldy #0");
246 asm("ldx _packet_length+1");
247 asm("beq @RE1"); //packet_length < 256
248
249 asm("@RL1:");
250 asm("lda %w", ETHDATA);
251 asm("sta (ptr1),y");
252 asm("iny");
253 asm("bne @RL1");
254 asm("inc ptr1+1");
255 asm("dex");
256 asm("bne @RL1");
257
258 asm("@RE1:");
259 asm("lda %w", ETHDATA);
260 asm("sta (ptr1),y");
261 asm("iny");
262 asm("cpy _packet_length");
263 asm("bne @RE1");
264
265 /* Remove and release RX packet from FIFO*/
266 asm("lda #%%10000000");
267 asm("sta %w", ETHMMUCR);
268
269 #ifdef DEBUG
270// print_packet(uip_buf, packet_length);
271 #endif
272
273 return packet_length;
274}
275
276/* First 40+14 (IP nad TCP header) is send from uip_buf */
277/* than data from uip_appdata */
278
279void lan91c96_send(void)
280{
281 #ifdef DEBUG
282 printf("SND: send packet\n");
283 #endif
284
285 #if UIP_BUFSIZE > 255
286 asm("lda _uip_len+1");
287 #else
288 asm("lda #0");
289 #endif
290 asm("ora #%%00100000"); //Allocate memory for TX
291 asm("sta %w", ETHMMUCR);
292
293 asm("ldx #8"); //Wait...
294 asm("@L1:"); //Wait for allocation ready
295 asm("lda %w", ETHIST);
296 asm("and #%%00001000"); //ALLOC INT
297 asm("bne @X1");
298 asm("dex");
299 asm("bne @L1");
300
301 #ifdef DEBUG
302 printf("SND: ERR: memory alloc timeout\n");
303 #endif
304
305 return;
306
307 asm("@X1:");
308 #ifdef DEBUG
309 printf("SND: packet memory allocated\n");
310 #endif
311
312 asm("lda #%%00001000"); //Acknowledge int, is it necessary ???
313 asm("sta %w", ETHACK);
314
315 asm("lda %w", ETHARR);
316 asm("sta %w", ETHPNR); //Set packet address
317
318 asm("lda #0");
319 asm("sta %w", ETHPTR);
320 asm("lda #%%01000000"); //AUTO INCR.
321 asm("sta %w", ETHPTR+1);
322
323 #ifdef DEBUG
324 printf("SND: L:%d ", uip_len);
325 #endif
326
327 asm("lda #0"); //Status written by CSMA
328 asm("sta %w", ETHDATA);
329 asm("sta %w", ETHDATA);
330
331 asm("lda _uip_len");
332 asm("and #$01");
333 asm("beq @SD1");
334
335 packet_length=uip_len+5;
336 asm("jmp @LC1");
337
338 asm("@SD1:");
339
340 packet_length=uip_len+6; //+6 for status word, length and ctl byte
341
342 asm("@LC1:");
343
344// printf("SND: L:%d ", packet_length);
345
346 asm("lda _packet_length");
347 asm("sta %w", ETHDATA);
348 asm("lda _packet_length+1");
349 asm("sta %w", ETHDATA);
350
351 #ifdef DEBUG
352// print_packet(uip_buf, uip_len);
353 #endif
354
355 /* Send 40+14=54 bytes of header */
356
357 if(uip_len <= 54) {
358
359 #ifdef DEBUG
360 printf("SND: short packet sent.\n");
361 #endif
362
363 asm("ldx _uip_len");
364 asm("ldy #0");
365 asm("@WL1:");
366 asm("lda _uip_buf,y");
367 asm("sta %w", ETHDATA);
368 asm("iny");
369 asm("dex");
370 asm("bne @WL1");
371
372 } else {
373
374 asm("ldx #54");
375 asm("ldy #0");
376 asm("@WL2:");
377 asm("lda _uip_buf,y");
378 asm("sta %w", ETHDATA);
379 asm("iny");
380 asm("dex");
381 asm("bne @WL2");
382
383 uip_len -= 54;
384
385 asm("lda _uip_appdata"); //uip_appdata is pointer
386 asm("sta ptr1");
387 asm("lda _uip_appdata+1");
388 asm("sta ptr1+1");
389
390 asm("ldy #0");
391 #if UIP_BUFSIZE > 255
392 asm("ldx _uip_len+1");
393 #else
394 asm("ldx #0");
395 #endif
396 asm("beq @RE1"); //packet_length < 256
397
398 asm("@RL1:");
399 asm("lda (ptr1),y");
400 asm("sta %w", ETHDATA);
401 asm("iny");
402 asm("bne @RL1");
403 asm("inc ptr1+1");
404 asm("dex");
405 asm("bne @RL1");
406
407 asm("@RE1:");
408 asm("lda (ptr1),y");
409 asm("sta %w", ETHDATA);
410 asm("iny");
411 asm("cpy _uip_len");
412 asm("bne @RE1");
413
414 }
415
416 asm("lda _uip_len");
417 asm("and #$01");
418 asm("beq @R3");
419
420 asm("lda #%%00100000");
421 asm("sta %w", ETHDATA); //Control byte
422
423 asm("lda #%%11000000"); //ENQUEUE PACKET - transmit packet
424 asm("sta %w", ETHMMUCR);
425
426// printf("\n## %02x", *(unsigned char *)ETHIST);
427
428 return;
429
430 asm("@R3:");
431
432 asm("lda #0");
433 asm("sta %w", ETHDATA); //Fill byte
434 asm("sta %w", ETHDATA); //Control byte
435
436 asm("lda #%%11000000"); //ENQUEUE PACKET - transmit packet
437 asm("sta %w", ETHMMUCR);
438
439// printf("\n## %02x\n", *(unsigned char *)ETHIST);
440 return;
441}
442
443#ifdef DEBUG
444static void print_packet(u8_t *buf, u16_t length)
445{
446 int i;
447 int remainder;
448 int lines;
449 u8_t a;
450 int cur;
451 int address=0;
452
453 printf("\nPacket of length %d \n", length );
454
455 lines = length / 8;
456 remainder = length % 8;
457
458 for ( i = 0; i < lines ; i ++ ) {
459 printf(":%04x ", address=i*8);
460
461 for ( cur = 0; cur < 8; cur ++ ) {
462 a = *(buf ++ );
463 printf("%02x ", a);
464 }
465 printf("\n");
466 }
467
468 printf(":%04x ", address+8);
469
470 for ( i = 0; i < remainder ; i++ ) {
471 a = *(buf ++ );
472 printf("%02x ", a);
473 }
474 printf("\n");
475}
476#endif /* DEBUG */
477