blob: 34d8efc98ea7ed9d217e5ac5b87469ba0b788a14 [file] [log] [blame]
adamdunkels7e4982c2003-03-19 16:26:18 +00001/*
2 * Copyright (c) 2001, Adam Dunkels.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
adamdunkelsfb24dff2004-09-12 14:07:30 +000013 * 3. The name of the author may not be used to endorse or promote
adamdunkels7e4982c2003-03-19 16:26:18 +000014 * products derived from this software without specific prior
15 * written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * This file is part of the C64 RealAudio server demo project.
30 *
oliverschmidtc8bfc022005-03-16 22:39:21 +000031 * $Id: cs8900a.c,v 1.13 2005/03/16 22:39:21 oliverschmidt Exp $
adamdunkels7e4982c2003-03-19 16:26:18 +000032 *
33 */
34
35/* cs8900a.c: device driver for the CS8900a chip in 8-bit mode. Mostly
36 written in 6502 assembler for speed. */
37
38#include "cs8900a.h"
39#include "uip.h"
40#include "uip_arp.h"
41
adamdunkelscd499282003-07-30 22:40:36 +000042extern u8_t *cs8900a_rxtxreg,
oliverschmidt9d2b0c22005-02-02 22:34:18 +000043 *cs8900a_txcmd,
44 *cs8900a_txlen,
45 *cs8900a_packetpp,
46 *cs8900a_ppdata;
adamdunkelscd499282003-07-30 22:40:36 +000047
adamdunkels7e4982c2003-03-19 16:26:18 +000048static u16_t len;
oliverschmidt9d2b0c22005-02-02 22:34:18 +000049static u16_t cnt;
adamdunkels7e4982c2003-03-19 16:26:18 +000050
51
52/*-----------------------------------------------------------------------------------*/
oliverschmidta8240ea2004-07-18 13:19:47 +000053#pragma optimize(push, off)
adamdunkels7e4982c2003-03-19 16:26:18 +000054void
55cs8900a_init(void)
56{
57 /* Turn on transmission and reception of frames. */
58 /* PACKETPP = 0x0112;
59 PPDATA = 0x00c0; */
60 asm("lda #$12");
adamdunkelscd499282003-07-30 22:40:36 +000061 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +000062 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +000063 asm("sta %v+1", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +000064 asm("lda #$c0");
adamdunkelscd499282003-07-30 22:40:36 +000065 asm("sta %v", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +000066 asm("lda #$00");
adamdunkelscd499282003-07-30 22:40:36 +000067 asm("sta %v+1", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +000068
69 /* Accept valid unicast+broadcast frames. */
70 /* PACKETPP = 0x0104;
71 PPDATA = 0x0d05; */
72 asm("lda #$04");
adamdunkelscd499282003-07-30 22:40:36 +000073 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +000074 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +000075 asm("sta %v+1", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +000076 asm("lda #$05");
adamdunkelscd499282003-07-30 22:40:36 +000077 asm("sta %v", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +000078 asm("lda #$0d");
adamdunkelscd499282003-07-30 22:40:36 +000079 asm("sta %v+1", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +000080
81 /* Set MAC address. */
82 /* PACKETPP = 0x0158;
83 PPDATA = (ETHADDR1 << 8) | (ETHADDR0); */
84 asm("lda #$58");
adamdunkelscd499282003-07-30 22:40:36 +000085 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +000086 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +000087 asm("sta %v+1", cs8900a_packetpp);
adamdunkels24b83292004-09-18 20:44:27 +000088 asm("lda %v", uip_ethaddr);
adamdunkelscd499282003-07-30 22:40:36 +000089 asm("sta %v", cs8900a_ppdata);
adamdunkels24b83292004-09-18 20:44:27 +000090 asm("lda %v+1", uip_ethaddr);
adamdunkelscd499282003-07-30 22:40:36 +000091 asm("sta %v+1", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +000092
93 /* PACKETPP = 0x015a;
94 PPDATA = (ETHADDR3 << 8) | (ETHADDR2); */
95 asm("lda #$5a");
adamdunkelscd499282003-07-30 22:40:36 +000096 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +000097 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +000098 asm("sta %v+1", cs8900a_packetpp);
adamdunkels24b83292004-09-18 20:44:27 +000099 asm("lda %v+2", uip_ethaddr);
adamdunkelscd499282003-07-30 22:40:36 +0000100 asm("sta %v", cs8900a_ppdata);
adamdunkels24b83292004-09-18 20:44:27 +0000101 asm("lda %v+3", uip_ethaddr);
adamdunkelscd499282003-07-30 22:40:36 +0000102 asm("sta %v+1", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000103
104 /* PACKETPP = 0x015c;
105 PPDATA = (ETHADDR5 << 8) | (ETHADDR4); */
106 asm("lda #$5c");
adamdunkelscd499282003-07-30 22:40:36 +0000107 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +0000108 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +0000109 asm("sta %v+1", cs8900a_packetpp);
adamdunkels24b83292004-09-18 20:44:27 +0000110 asm("lda %v+4", uip_ethaddr);
adamdunkelscd499282003-07-30 22:40:36 +0000111 asm("sta %v", cs8900a_ppdata);
adamdunkels24b83292004-09-18 20:44:27 +0000112 asm("lda %v+5", uip_ethaddr);
adamdunkelscd499282003-07-30 22:40:36 +0000113 asm("sta %v+1", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000114}
oliverschmidta8240ea2004-07-18 13:19:47 +0000115#pragma optimize(pop)
adamdunkels7e4982c2003-03-19 16:26:18 +0000116/*-----------------------------------------------------------------------------------*/
oliverschmidta8240ea2004-07-18 13:19:47 +0000117#pragma optimize(push, off)
adamdunkels7e4982c2003-03-19 16:26:18 +0000118void
119cs8900a_send(void)
120{
adamdunkels7e4982c2003-03-19 16:26:18 +0000121 /* Transmit command. */
122 asm("lda #$c0");
adamdunkelscd499282003-07-30 22:40:36 +0000123 asm("sta %v", cs8900a_txcmd);
adamdunkels7e4982c2003-03-19 16:26:18 +0000124 asm("lda #$00");
adamdunkelscd499282003-07-30 22:40:36 +0000125 asm("sta %v+1", cs8900a_txcmd);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000126 asm("lda %v", uip_len);
adamdunkelscd499282003-07-30 22:40:36 +0000127 asm("sta %v", cs8900a_txlen);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000128 asm("lda %v+1", uip_len);
adamdunkelscd499282003-07-30 22:40:36 +0000129 asm("sta %v+1", cs8900a_txlen);
adamdunkels7e4982c2003-03-19 16:26:18 +0000130
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000131 asm("ldy #8");
oliverschmidt815f57e2005-03-09 23:31:54 +0000132tryagain:
adamdunkels7e4982c2003-03-19 16:26:18 +0000133 /* Check for avaliable buffer space. */
134 asm("lda #$38");
adamdunkelscd499282003-07-30 22:40:36 +0000135 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +0000136 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +0000137 asm("sta %v+1", cs8900a_packetpp);
138 asm("lda %v+1", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000139 asm("and #1");
oliverschmidt815f57e2005-03-09 23:31:54 +0000140 asm("bne %g", send);
adamdunkels7e4982c2003-03-19 16:26:18 +0000141
142 /* No space avaliable, skip a received frame and try again. */
143 asm("lda #$02");
adamdunkelscd499282003-07-30 22:40:36 +0000144 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +0000145 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +0000146 asm("sta %v+1", cs8900a_packetpp);
147 asm("lda %v", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000148 asm("ora #$40");
adamdunkelscd499282003-07-30 22:40:36 +0000149 asm("sta %v", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000150
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000151 asm("dey");
oliverschmidt815f57e2005-03-09 23:31:54 +0000152 asm("bne %g", tryagain);
adamdunkels7e4982c2003-03-19 16:26:18 +0000153 return;
154
155 /* Send the frame. */
oliverschmidt815f57e2005-03-09 23:31:54 +0000156send:
adamdunkels7e4982c2003-03-19 16:26:18 +0000157
oliverschmidt4affe762005-02-23 22:43:00 +0000158 /* First, send 14+40=54 bytes of header. */
adamdunkels7e4982c2003-03-19 16:26:18 +0000159 asm("ldy #0");
oliverschmidt815f57e2005-03-09 23:31:54 +0000160sendloop1:
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000161 asm("lda %v,y", uip_buf);
adamdunkelscd499282003-07-30 22:40:36 +0000162 asm("sta %v", cs8900a_rxtxreg);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000163 asm("iny");
164 asm("lda %v,y", uip_buf);
adamdunkelscd499282003-07-30 22:40:36 +0000165 asm("sta %v+1", cs8900a_rxtxreg);
adamdunkels7e4982c2003-03-19 16:26:18 +0000166 asm("iny");
oliverschmidt4affe762005-02-23 22:43:00 +0000167 asm("cpy #%b", UIP_LLH_LEN + UIP_TCPIP_HLEN);
oliverschmidt815f57e2005-03-09 23:31:54 +0000168 asm("bne %g", sendloop1);
adamdunkels7e4982c2003-03-19 16:26:18 +0000169
oliverschmidt4affe762005-02-23 22:43:00 +0000170 if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
adamdunkels7e4982c2003-03-19 16:26:18 +0000171 return;
172 }
173
174 /* Next, send rest of the packet. */
oliverschmidtc8bfc022005-03-16 22:39:21 +0000175 cnt = uip_len - (UIP_LLH_LEN + UIP_TCPIP_HLEN);
adamdunkels7e4982c2003-03-19 16:26:18 +0000176
oliverschmidtfcdbaec2005-03-13 21:16:30 +0000177 asm("lda %v", cnt);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000178 asm("lsr");
oliverschmidt815f57e2005-03-09 23:31:54 +0000179 asm("bcc %g", noinc);
oliverschmidtfcdbaec2005-03-13 21:16:30 +0000180 asm("inc %v", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000181 asm("bne %g", noinc);
oliverschmidtfcdbaec2005-03-13 21:16:30 +0000182 asm("inc %v+1", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000183noinc:
adamdunkels7e4982c2003-03-19 16:26:18 +0000184
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000185 asm("lda %v", uip_appdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000186 asm("sta ptr1");
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000187 asm("lda %v+1", uip_appdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000188 asm("sta ptr1+1");
189
adamdunkels7e4982c2003-03-19 16:26:18 +0000190 asm("ldy #0");
oliverschmidt815f57e2005-03-09 23:31:54 +0000191sendloop2:
adamdunkels7e4982c2003-03-19 16:26:18 +0000192 asm("lda (ptr1),y");
adamdunkelscd499282003-07-30 22:40:36 +0000193 asm("sta %v", cs8900a_rxtxreg);
adamdunkels7e4982c2003-03-19 16:26:18 +0000194 asm("iny");
195 asm("lda (ptr1),y");
adamdunkelscd499282003-07-30 22:40:36 +0000196 asm("sta %v+1", cs8900a_rxtxreg);
adamdunkels7e4982c2003-03-19 16:26:18 +0000197 asm("iny");
oliverschmidt815f57e2005-03-09 23:31:54 +0000198 asm("bne %g", check);
adamdunkels7e4982c2003-03-19 16:26:18 +0000199 asm("inc ptr1+1");
oliverschmidt815f57e2005-03-09 23:31:54 +0000200check:
oliverschmidtfcdbaec2005-03-13 21:16:30 +0000201 asm("cpy %v", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000202 asm("bne %g", sendloop2);
oliverschmidtfcdbaec2005-03-13 21:16:30 +0000203 asm("dec %v+1", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000204 asm("bpl %g", sendloop2);
adamdunkels7e4982c2003-03-19 16:26:18 +0000205}
oliverschmidta8240ea2004-07-18 13:19:47 +0000206#pragma optimize(pop)
adamdunkels7e4982c2003-03-19 16:26:18 +0000207/*-----------------------------------------------------------------------------------*/
oliverschmidta8240ea2004-07-18 13:19:47 +0000208#pragma optimize(push, off)
adamdunkels7e4982c2003-03-19 16:26:18 +0000209static void
210skip_frame(void)
211{
212 /* PACKETPP = 0x0102;
213 PPDATA = PPDATA | 0x0040; */
214 asm("lda #$02");
adamdunkelscd499282003-07-30 22:40:36 +0000215 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +0000216 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +0000217 asm("sta %v+1", cs8900a_packetpp);
218 asm("lda %v", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000219 asm("ora #$40");
adamdunkelscd499282003-07-30 22:40:36 +0000220 asm("sta %v", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000221}
oliverschmidta8240ea2004-07-18 13:19:47 +0000222#pragma optimize(pop)
adamdunkels7e4982c2003-03-19 16:26:18 +0000223/*-----------------------------------------------------------------------------------*/
oliverschmidta8240ea2004-07-18 13:19:47 +0000224#pragma optimize(push, off)
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000225u16_t
adamdunkels7e4982c2003-03-19 16:26:18 +0000226cs8900a_poll(void)
227{
228 /* Check receiver event register to see if there are any valid
229 unicast frames avaliable. */
230 /* PACKETPP = 0x0124;
231 if(PPDATA & 0x000d == 0x0000) {
232 return 0;
233 }
234 */
235 asm("lda #$24");
adamdunkelscd499282003-07-30 22:40:36 +0000236 asm("sta %v", cs8900a_packetpp);
adamdunkels7e4982c2003-03-19 16:26:18 +0000237 asm("lda #$01");
adamdunkelscd499282003-07-30 22:40:36 +0000238 asm("sta %v+1", cs8900a_packetpp);
239 asm("lda %v+1", cs8900a_ppdata);
adamdunkels7e4982c2003-03-19 16:26:18 +0000240 asm("and #$0d");
241 asm("cmp #$00");
oliverschmidt815f57e2005-03-09 23:31:54 +0000242 asm("bne %g", noreturn);
adamdunkels7e4982c2003-03-19 16:26:18 +0000243 /* No frame ready. */
244 return 0;
245
oliverschmidt815f57e2005-03-09 23:31:54 +0000246noreturn:
adamdunkels7e4982c2003-03-19 16:26:18 +0000247 /* Process the incoming frame. */
adamdunkelscd499282003-07-30 22:40:36 +0000248
adamdunkels7e4982c2003-03-19 16:26:18 +0000249 /* Read receiver event and discard it. */
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000250 /* RXTXREG; */
adamdunkelscd499282003-07-30 22:40:36 +0000251 asm("lda %v+1", cs8900a_rxtxreg);
adamdunkelscd499282003-07-30 22:40:36 +0000252 asm("lda %v", cs8900a_rxtxreg);
adamdunkels7e4982c2003-03-19 16:26:18 +0000253
254 /* Read frame length. */
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000255 /* cnt = len = RXTXREG; */
adamdunkelscd499282003-07-30 22:40:36 +0000256 asm("lda %v+1", cs8900a_rxtxreg);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000257 asm("sta %v+1", len);
258 asm("sta %v+1", cnt);
adamdunkelscd499282003-07-30 22:40:36 +0000259 asm("lda %v", cs8900a_rxtxreg);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000260 asm("sta %v", len);
261 asm("sta %v", cnt);
adamdunkels7e4982c2003-03-19 16:26:18 +0000262
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000263 asm("lsr");
oliverschmidt815f57e2005-03-09 23:31:54 +0000264 asm("bcc %g", noinc);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000265 asm("inc %v", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000266 asm("bne %g", noinc);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000267 asm("inc %v+1", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000268noinc:
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000269
270 if(cnt > UIP_BUFSIZE) {
adamdunkels7e4982c2003-03-19 16:26:18 +0000271 skip_frame();
272 return 0;
273 }
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000274
adamdunkels7e4982c2003-03-19 16:26:18 +0000275 /* Read bytes into uip_buf. */
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000276 asm("lda #<%v", uip_buf);
adamdunkels7e4982c2003-03-19 16:26:18 +0000277 asm("sta ptr1");
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000278 asm("lda #>%v", uip_buf);
adamdunkels7e4982c2003-03-19 16:26:18 +0000279 asm("sta ptr1+1");
280
adamdunkels7e4982c2003-03-19 16:26:18 +0000281 asm("ldy #0");
oliverschmidt815f57e2005-03-09 23:31:54 +0000282readloop:
adamdunkelscd499282003-07-30 22:40:36 +0000283 asm("lda %v", cs8900a_rxtxreg);
adamdunkels7e4982c2003-03-19 16:26:18 +0000284 asm("sta (ptr1),y");
285 asm("iny");
adamdunkelscd499282003-07-30 22:40:36 +0000286 asm("lda %v+1", cs8900a_rxtxreg);
adamdunkels7e4982c2003-03-19 16:26:18 +0000287 asm("sta (ptr1),y");
288 asm("iny");
oliverschmidt815f57e2005-03-09 23:31:54 +0000289 asm("bne %g", check);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000290 asm("inc ptr1+1");
oliverschmidt815f57e2005-03-09 23:31:54 +0000291check:
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000292 asm("cpy %v", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000293 asm("bne %g", readloop);
oliverschmidt9d2b0c22005-02-02 22:34:18 +0000294 asm("dec %v+1", cnt);
oliverschmidt815f57e2005-03-09 23:31:54 +0000295 asm("bpl %g", readloop);
adamdunkels7e4982c2003-03-19 16:26:18 +0000296 return len;
297}
oliverschmidta8240ea2004-07-18 13:19:47 +0000298#pragma optimize(pop)