1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * A2065 ZorroII Ethernet Card
5 *
6 * Copyright 2009 Toni Wilen
7 *
8 */
9
10 #include "sysconfig.h"
11 #include "sysdeps.h"
12
13 #ifdef A2065
14
15 #include "options.h"
16 #include "memory_uae.h"
17 #include "custom.h"
18 #include "newcpu.h"
19 #include "a2065.h"
20 #include "crc32.h"
21 #include "savestate.h"
22 #include "autoconf.h"
23 #include "uaenet.h"
24
25 #define DUMPPACKET 0
26
27 int log_a2065 = 0;
28 static int log_transmit = 1;
29 static int log_receive = 1;
30 int a2065_promiscuous = 0;
31
32 #define RAP 0x4002
33 #define RDP 0x4000
34 #define CHIP_OFFSET 0x4000
35 #define CHIP_SIZE 4
36 #define RAM_OFFSET 0x8000
37 #define RAM_SIZE 0x8000
38 #define RAM_MASK 0x7fff
39
40 static uae_u8 config[256];
41 static uae_u8 boardram[RAM_SIZE];
42 static volatile uae_u16 csr[4];
43 static int rap;
44 static int configured;
45
46 static struct netdriverdata *td;
47 static void *sysdata;
48
49 static int am_initialized;
50 static volatile int transmitnow;
51 static uae_u16 am_mode;
52 static uae_u64 am_ladrf;
53 static uae_u32 am_rdr, am_rdr_rlen, am_rdr_rdra;
54 static uae_u32 am_tdr, am_tdr_tlen, am_tdr_tdra;
55 static int tdr_offset, rdr_offset;
56 static int byteswap, prom, fakeprom;
57 static uae_u8 fakemac[6], realmac[6];
58 static uae_u8 broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
59
60 #define CSR0_ERR 0x8000
61 #define CSR0_BABL 0x4000
62 #define CSR0_CERR 0x2000
63 #define CSR0_MISS 0x1000
64 #define CSR0_MERR 0x0800
65 #define CSR0_RINT 0x0400
66 #define CSR0_TINT 0x0200
67 #define CSR0_IDON 0x0100
68 #define CSR0_INTR 0x0080
69 #define CSR0_INEA 0x0040
70 #define CSR0_RXON 0x0020
71 #define CSR0_TXON 0x0010
72 #define CSR0_TDMD 0x0008
73 #define CSR0_STOP 0x0004
74 #define CSR0_STRT 0x0002
75 #define CSR0_INIT 0x0001
76
77 #define CSR3_BSWP 0x0004
78 #define CSR3_ACON 0x0002
79 #define CSR3_BCON 0x0001
80
81 #define MODE_PROM 0x8000
82 #define MODE_EMBA 0x0080
83 #define MODE_INTL 0x0040
84 #define MODE_DRTY 0x0020
85 #define MODE_COLL 0x0010
86 #define MODE_DTCR 0x0008
87 #define MODE_LOOP 0x0004
88 #define MODE_DTX 0x0002
89 #define MODE_DRX 0x0001
90
91 #define TX_OWN 0x8000
92 #define TX_ERR 0x4000
93 #define TX_ADD_FCS 0x2000
94 #define TX_MORE 0x1000
95 #define TX_ONE 0x0800
96 #define TX_DEF 0x0400
97 #define TX_STP 0x0200
98 #define TX_ENP 0x0100
99
100 #define TX_BUFF 0x8000
101 #define TX_UFLO 0x4000
102 #define TX_LCOL 0x1000
103 #define TX_LCAR 0x0800
104 #define TX_RTRY 0x0400
105
106 #define RX_OWN 0x8000
107 #define RX_ERR 0x4000
108 #define RX_FRAM 0x2000
109 #define RX_OFLO 0x1000
110 #define RX_CRC 0x0800
111 #define RX_BUFF 0x0400
112 #define RX_STP 0x0200
113 #define RX_ENP 0x0100
114
ew(int addr,uae_u32 value)115 static void ew (int addr, uae_u32 value)
116 {
117 addr &= 0xffff;
118 if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
119 config[addr] = (value & 0xf0);
120 config[addr + 2] = (value & 0x0f) << 4;
121 } else {
122 config[addr] = ~(value & 0xf0);
123 config[addr + 2] = ~((value & 0x0f) << 4);
124 }
125 }
126
a2065_reset(void)127 void a2065_reset (void)
128 {
129 am_initialized = 0;
130 csr[0] = CSR0_STOP;
131 csr[1] = csr[2] = csr[3] = 0;
132 rap = 0;
133
134 uaenet_close (sysdata);
135 xfree (sysdata);
136 sysdata = NULL;
137 td = NULL;
138 }
139
140 #if DUMPPACKET
dumppacket(const TCHAR * n,uae_u8 * packet,int len)141 static void dumppacket (const TCHAR *n, uae_u8 *packet, int len)
142 {
143 int i;
144 TCHAR buf[10000];
145
146 for (i = 0; i < len; i++) {
147 _stprintf (buf + i * 3, _T(".%02X"), packet[i]);
148 }
149 write_log (_T("%s %d: "), n, len);
150 write_log (buf);
151 write_log (_T("\n\n"));
152 }
153 #endif
154
155 #define MAX_PACKET_SIZE 4000
156 static uae_u8 transmitbuffer[MAX_PACKET_SIZE];
157 static volatile int transmitlen;
158
dofakemac(uae_u8 * packet)159 static int dofakemac (uae_u8 *packet)
160 {
161 if (!memcmp (packet, fakemac, 6)) {
162 memcpy (packet, realmac, 6);
163 return 1;
164 }
165 if (!memcmp (packet, realmac, 6)) {
166 memcpy (packet, fakemac, 6);
167 return 1;
168 }
169 return 0;
170 }
171
172 // Replace card's MAC with real MAC and vice versa.
173 // We have to do this because drivers are hardcoded to
174 // Commodore's MAC address range.
175
mungepacket(uae_u8 * packet,int len)176 static int mungepacket (uae_u8 *packet, int len)
177 {
178 uae_u8 *data;
179 uae_u16 type;
180 int ret = 0;
181
182 if (len < 20)
183 return 0;
184 #if DUMPPACKET
185 dumppacket (_T("pre:"), packet, len);
186 #endif
187 data = packet + 14;
188 type = (packet[12] << 8) | packet[13];
189 // switch destination mac
190 ret |= dofakemac (packet);
191 // switch source mac
192 ret |= dofakemac (packet + 6);
193 if (type == 0x0806) { // ARP?
194 if (((data[0] << 8) | data[1]) == 1 && data[4] == 6) { // Ethernet and LEN=6?
195 ret |= dofakemac (data + 8); // sender
196 ret |= dofakemac (data + 8 + 6 + 4); // target
197 }
198 } else if (type == 0x0800) { // IPv4?
199 int proto = data[9];
200 int ihl = data[0] & 15;
201 uae_u8 *ipv4 = data;
202
203 data += ihl * 4;
204 if (proto == 17) { // UDP?
205 int udpcrc = 0;
206 int sp = (data[0] << 8) | data[1];
207 int dp = (data[2] << 8) | data[3];
208 int len = (data[4] << 8) | data[5];
209 if (sp == 67 || sp == 68 || dp == 67 || dp == 68)
210 udpcrc |= dofakemac (data + 36); // DHCP CHADDR
211 if (udpcrc && (data[6] || data[7])) {
212 // fix UDP checksum
213 int i;
214 uae_u32 sum;
215 data[6] = data[7] = 0;
216 data[len] = 0;
217 sum = 0;
218 for (i = 0; i < ((len + 1) & ~1); i += 2)
219 sum += (data[i] << 8) | data[i + 1];
220 sum += (ipv4[12] << 8) | ipv4[13];
221 sum += (ipv4[14] << 8) | ipv4[15];
222 sum += (ipv4[16] << 8) | ipv4[17];
223 sum += (ipv4[18] << 8) | ipv4[19];
224 sum += 17;
225 sum += len;
226 while (sum >> 16)
227 sum = (sum & 0xFFFF) + (sum >> 16);
228 sum = ~sum;
229 if (sum == 0)
230 sum = 0xffff;
231 data[6] = sum >> 8;
232 data[7] = sum >> 0;
233 ret |= 1;
234 }
235 // this all just to translate single DHCP MAC..
236 }
237 }
238 #if DUMPPACKET
239 dumppacket (_T("post:"), packet, len);
240 #endif
241 return ret;
242 }
243
mcfilter(const uae_u8 * data)244 static int mcfilter (const uae_u8 *data)
245 {
246 if (am_ladrf == 0) // multicast filter completely disabled?
247 return 0;
248 return 1; // just allow everything
249 }
250
gotfunc(struct s2devstruct * dev,const uae_u8 * databuf,int len)251 static void gotfunc (struct s2devstruct *dev, const uae_u8 *databuf, int len)
252 {
253 int i;
254 int size, insize, first;
255 uae_u32 addr;
256 uae_u8 *p, *d;
257 uae_u16 rmd0, rmd1, rmd2, rmd3;
258 uae_u32 crc32;
259 uae_u8 tmp[MAX_PACKET_SIZE], *data;
260 const uae_u8 *dstmac, *srcmac;
261
262 if (log_a2065 > 1 && log_receive) {
263 dstmac = databuf;
264 srcmac = databuf + 6;
265 write_log (_T("A2065<!DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
266 dstmac[0], dstmac[1], dstmac[2], dstmac[3], dstmac[4], dstmac[5],
267 srcmac[6], srcmac[7], srcmac[8], srcmac[9], srcmac[10], srcmac[11],
268 (databuf[12] << 8) | databuf[13], len);
269 }
270
271 if (!(csr[0] & CSR0_RXON)) // receiver off?
272 return;
273 if (len < 20) { // too short
274 if (log_a2065)
275 write_log (_T("A2065: short frame, %d bytes\n"), len);
276 return;
277 }
278
279 dstmac = databuf;
280 srcmac = databuf + 6;
281
282 if ((dstmac[0] & 0x01) && memcmp (dstmac, broadcast, sizeof broadcast) != 0) {
283 // multicast
284 if (!mcfilter (dstmac)) {
285 if (log_a2065 > 1)
286 write_log (_T("mc filtered\n"));
287 return;
288 }
289 } else {
290 // !promiscuous and dst != me and dst != broadcast
291 if (!prom && (memcmp (dstmac, realmac, sizeof realmac) != 0 && memcmp (dstmac, broadcast, sizeof broadcast) != 0)) {
292 if (log_a2065 > 1)
293 write_log (_T("not for me1\n"));
294 return;
295 }
296 }
297
298 // src and dst = me? right, better drop it.
299 if (memcmp (dstmac, realmac, sizeof realmac) == 0 && memcmp (srcmac, realmac, sizeof realmac) == 0) {
300 if (log_a2065 > 1)
301 write_log (_T("not for me2\n"));
302 return;
303 }
304 // dst = broadcast and src = me? no thanks.
305 if (memcmp (dstmac, broadcast, sizeof broadcast) == 0 && memcmp (srcmac, realmac, sizeof realmac) == 0) {
306 if (log_a2065 > 1)
307 write_log (_T("not for me3\n"));
308 return;
309 }
310
311 memcpy (tmp, databuf, len);
312 #if 0
313 FILE *f = fopen("s:\\d\\wireshark2.cap", "rb");
314 fseek (f, 474, SEEK_SET);
315 fread (tmp, 342, 1, f);
316 fclose (f);
317 realmac[0] = 0xc8;
318 realmac[1] = 0x0a;
319 realmac[2] = 0xa9;
320 realmac[3] = 0x81;
321 realmac[4] = 0xff;
322 realmac[5] = 0x2f;
323 fakemac[3] = realmac[3];
324 fakemac[4] = realmac[4];
325 fakemac[5] = realmac[5];
326 #endif
327 d = tmp;
328 dstmac = d;
329 srcmac = d + 6;
330 if (log_a2065 && log_receive) {
331 if (memcmp (dstmac, realmac, sizeof realmac) == 0) {
332 write_log (_T("A2065<-DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
333 dstmac[0], dstmac[1], dstmac[2], dstmac[3], dstmac[4], dstmac[5],
334 srcmac[6], srcmac[7], srcmac[8], srcmac[9], srcmac[10], srcmac[11],
335 (d[12] << 8) | d[13], len);
336 }
337 }
338 if (mungepacket (d, len)) {
339 if (log_a2065 && log_receive) {
340 write_log (_T("A2065<*DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
341 dstmac[0], dstmac[1], dstmac[2], dstmac[3], dstmac[4], dstmac[5],
342 srcmac[6], srcmac[7], srcmac[8], srcmac[9], srcmac[10], srcmac[11],
343 (d[12] << 8) | d[13], len);
344 }
345 }
346
347 // winpcap does not include checksum bytes
348 crc32 = get_crc32 (d, len);
349 d[len++] = crc32 >> 24;
350 d[len++] = crc32 >> 16;
351 d[len++] = crc32 >> 8;
352 d[len++] = crc32 >> 0;
353 data = tmp;
354
355 size = 0;
356 insize = 0;
357 first = 1;
358
359 for (;;) {
360 rdr_offset %= am_rdr_rlen;
361 p = boardram + ((am_rdr_rdra + rdr_offset * 8) & RAM_MASK);
362 rmd0 = (p[1] << 8) | (p[0] << 0);
363 rmd1 = (p[3] << 8) | (p[2] << 0);
364 rmd2 = (p[5] << 8) | (p[4] << 0);
365 rmd3 = (p[7] << 8) | (p[6] << 0);
366 addr = rmd0 | ((rmd1 & 0xff) << 16);
367 addr &= RAM_MASK;
368
369 if (!(rmd1 & RX_OWN)) {
370 write_log (_T("A2065: RECEIVE BUFFER ERROR\n"));
371 if (!first) {
372 rmd1 |= RX_BUFF | RX_OFLO;
373 csr[0] &= ~CSR0_RXON;
374 } else {
375 csr[0] |= CSR0_MISS;
376 }
377 p[3] = rmd1 >> 8;
378 p[2] = rmd1 >> 0;
379 rethink_a2065 ();
380 return;
381 }
382
383 rmd1 &= ~RX_OWN;
384 rdr_offset++;
385
386 if (first) {
387 rmd1 |= RX_STP;
388 first = 0;
389 }
390
391 size = 65536 - rmd2;
392 for (i = 0; i < size && insize < len; i++, insize++)
393 boardram[((addr + i) ^ byteswap) & RAM_MASK] = data[insize];
394 if (insize >= len) {
395 rmd1 |= RX_ENP;
396 rmd3 = len;
397 }
398
399 p[3] = rmd1 >> 8;
400 p[2] = rmd1 >> 0;
401 p[7] = rmd3 >> 8;
402 p[6] = rmd3 >> 0;
403
404 if (insize >= len)
405 break;
406 }
407
408 csr[0] |= CSR0_RINT;
409 rethink_a2065 ();
410 }
411
getfunc(struct s2devstruct * dev,uae_u8 * d,int * len)412 static int getfunc (struct s2devstruct *dev, uae_u8 *d, int *len)
413 {
414 if (transmitlen <= 0)
415 return 0;
416 if (transmitlen > *len) {
417 write_log (_T("A2065: too large packet transmission attempt %d > %d\n"), transmitlen, *len);
418 transmitlen = 0;
419 return 0;
420 }
421 memcpy (d, transmitbuffer, transmitlen);
422 *len = transmitlen;
423 transmitlen = 0;
424 transmitnow = 1;
425 return 1;
426 }
427
do_transmit(void)428 static void do_transmit (void)
429 {
430 int i;
431 int size, outsize;
432 int err, add_fcs;
433 uae_u32 addr, bufaddr;
434 uae_u8 *p;
435 uae_u16 tmd0, tmd1, tmd2, tmd3;
436
437 err = 0;
438 size = 0;
439 outsize = 0;
440
441 tdr_offset %= am_tdr_tlen;
442 bufaddr = am_tdr_tdra + tdr_offset * 8;
443 p = boardram + (bufaddr & RAM_MASK);
444 tmd1 = (p[3] << 8) | (p[2] << 0);
445 if (!(tmd1 & TX_OWN) || !(tmd1 & TX_STP)) {
446 tdr_offset++;
447 return;
448 }
449 if (!(tmd1 & TX_ENP) && log_a2065 > 0)
450 write_log (_T("A2065: chained transmit!?\n"));
451
452 add_fcs = tmd1 & TX_ADD_FCS;
453
454 for (;;) {
455 tdr_offset %= am_tdr_tlen;
456 p = boardram + ((am_tdr_tdra + tdr_offset * 8) & RAM_MASK);
457 tmd0 = (p[1] << 8) | (p[0] << 0);
458 tmd1 = (p[3] << 8) | (p[2] << 0);
459 tmd2 = (p[5] << 8) | (p[4] << 0);
460 tmd3 = (p[7] << 8) | (p[6] << 0);
461 addr = tmd0 | ((tmd1 & 0xff) << 16);
462 addr &= RAM_MASK;
463
464 if (!(tmd1 & TX_OWN)) {
465 tmd3 |= TX_BUFF | TX_UFLO;
466 tmd1 |= TX_ERR;
467 csr[0] &= ~CSR0_TXON;
468 write_log (_T("A2065: TRANSMIT OWN NOT SET\n"));
469 err = 1;
470 } else {
471 tmd1 &= ~TX_OWN;
472 size = 65536 - tmd2;
473 if (size > MAX_PACKET_SIZE)
474 size = MAX_PACKET_SIZE;
475 for (i = 0; i < size; i++)
476 transmitbuffer[outsize++] = boardram[((addr + i) ^ byteswap) & RAM_MASK];
477 tdr_offset++;
478 }
479 p[3] = tmd1 >> 8;
480 p[2] = tmd1 >> 0;
481 p[7] = tmd3 >> 8;
482 p[6] = tmd3 >> 0;
483 if ((tmd1 & TX_ENP) || err)
484 break;
485 }
486 if (outsize < 60) {
487 tmd3 |= TX_BUFF | TX_UFLO;
488 tmd1 |= TX_ERR;
489 csr[0] &= ~CSR0_TXON;
490 write_log (_T("A2065: TRANSMIT UNDERFLOW %d\n"), outsize);
491 err = 1;
492 p[3] = tmd1 >> 8;
493 p[2] = tmd1 >> 0;
494 p[7] = tmd3 >> 8;
495 p[6] = tmd3 >> 0;
496 }
497
498 if (!err) {
499 uae_u8 *d = transmitbuffer;
500 if ((am_mode & MODE_DTCR) && !add_fcs)
501 outsize -= 4; // do not include checksum bytes
502 if (log_a2065 && log_transmit) {
503 write_log (_T("A2065->DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d ADDR=%04X\n"),
504 d[0], d[1], d[2], d[3], d[4], d[5],
505 d[6], d[7], d[8], d[9], d[10], d[11],
506 (d[12] << 8) | d[13], outsize, bufaddr);
507 }
508 transmitlen = outsize;
509 if (mungepacket (d, transmitlen)) {
510 if (log_a2065 && log_transmit) {
511 write_log (_T("A2065*>DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
512 d[0], d[1], d[2], d[3], d[4], d[5],
513 d[6], d[7], d[8], d[9], d[10], d[11],
514 (d[12] << 8) | d[13], outsize);
515 }
516 }
517 uaenet_trigger (sysdata);
518 }
519 csr[0] |= CSR0_TINT;
520 rethink_a2065 ();
521 }
522
check_transmit(void)523 static void check_transmit (void)
524 {
525 if (transmitlen > 0)
526 return;
527 if (!(csr[0] & CSR0_TXON))
528 return;
529 transmitnow = 0;
530 do_transmit ();
531 }
532
a2065_hsync_handler(void)533 void a2065_hsync_handler (void)
534 {
535 static int cnt;
536
537 cnt--;
538 if (cnt < 0 || transmitnow) {
539 check_transmit ();
540 cnt = 15;
541 }
542 }
543
rethink_a2065(void)544 void rethink_a2065 (void)
545 {
546 uae_int_requested &= ~4;
547 if (!configured)
548 return;
549 csr[0] &= ~CSR0_INTR;
550 if (csr[0] & (CSR0_BABL | CSR0_MISS | CSR0_MERR | CSR0_RINT | CSR0_TINT | CSR0_IDON))
551 csr[0] |= CSR0_INTR;
552 if ((csr[0] & (CSR0_INTR | CSR0_INEA)) == (CSR0_INTR | CSR0_INEA))
553 uae_int_requested |= 4;
554 }
555
chip_init(void)556 static void chip_init (void)
557 {
558 uae_u32 iaddr = ((csr[2] & 0xff) << 16) | csr[1];
559 uae_u8 *p = boardram + (iaddr & RAM_MASK);
560
561 write_log (_T("A2065: Initialization block2:\n"));
562 for (int i = 0; i < 24; i++)
563 write_log (_T(".%02X"), p[i]);
564 write_log (_T("\n"));
565
566 am_mode = (p[0] << 8) | (p[1] << 0);
567 am_ladrf = ((uae_u64)p[15] << 56) | ((uae_u64)p[14] << 48) | ((uae_u64)p[13] << 40) | ((uae_u64)p[12] << 32) | (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | (p[8] << 0);
568 am_rdr = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | (p[16] << 0);
569 am_tdr = (p[23] << 24) | (p[22] << 16) | (p[21] << 8) | (p[20] << 0);
570
571 am_rdr_rlen = 1 << ((am_rdr >> 29) & 7);
572 am_tdr_tlen = 1 << ((am_tdr >> 29) & 7);
573 am_rdr_rdra = am_rdr & 0x00fffff8;
574 am_tdr_tdra = am_tdr & 0x00fffff8;
575
576 prom = (am_mode & MODE_PROM) ? 1 : 0;
577 fakeprom = a2065_promiscuous ? 1 : 0;
578
579 fakemac[0] = p[2];
580 fakemac[1] = p[3];
581 fakemac[2] = p[4];
582 fakemac[3] = p[5];
583 fakemac[4] = p[6];
584 fakemac[5] = p[7];
585
586 write_log (_T("A2065: %04X %06X %d %d %d %d %06X %06X %02X:%02X:%02X:%02X:%02X:%02X\n"),
587 am_mode, iaddr, prom, fakeprom, am_rdr_rlen, am_tdr_tlen, am_rdr_rdra, am_tdr_tdra,
588 fakemac[0], fakemac[1], fakemac[2], fakemac[3], fakemac[4], fakemac[5]);
589
590
591 am_rdr_rdra &= RAM_MASK;
592 am_tdr_tdra &= RAM_MASK;
593 tdr_offset = rdr_offset = 0;
594
595 uaenet_close (sysdata);
596 if (td != NULL) {
597 if (!sysdata)
598 sysdata = xcalloc (uae_u8, uaenet_getdatalenght());
599 if (!uaenet_open (sysdata, td, NULL, gotfunc, getfunc, prom || fakeprom)) {
600 write_log (_T("A2065: failed to initialize winpcap driver\n"));
601 }
602 }
603 }
604
chip_wget(uaecptr addr)605 static uae_u16 chip_wget (uaecptr addr)
606 {
607 if (addr == RAP) {
608 return rap;
609 } else if (addr == RDP) {
610 uae_u16 v = csr[rap];
611 if (rap == 0) {
612 if (v & (CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR))
613 v |= CSR0_ERR;
614 }
615 if (log_a2065 > 2)
616 write_log (_T("A2065_CHIPWGET: CSR%d=%04X PC=%08X\n"), rap, v, M68K_GETPC);
617 return v;
618 }
619 return 0xffff;
620 }
621
chip_wput(uaecptr addr,uae_u16 v)622 static void chip_wput (uaecptr addr, uae_u16 v)
623 {
624
625 if (addr == RAP) {
626
627 rap = v & 3;
628
629 } else if (addr == RDP) {
630
631 uae_u16 oreg = csr[rap];
632 uae_u16 t;
633
634 if (log_a2065 > 2)
635 write_log (_T("A2065_CHIPWPUT: CSR%d=%04X PC=%08X\n"), rap, v & 0xffff, M68K_GETPC);
636
637 switch (rap)
638 {
639 case 0:
640 csr[0] &= ~CSR0_INEA; csr[0] |= v & CSR0_INEA;
641 // bit = 1 -> set, bit = 0 -> nop
642 t = v & (CSR0_INIT | CSR0_STRT | CSR0_STOP | CSR0_TDMD);
643 csr[0] |= t;
644 // bit = 1 -> clear, bit = 0 -> nop
645 t = v & (CSR0_IDON | CSR0_TINT | CSR0_RINT | CSR0_MERR | CSR0_MISS | CSR0_CERR | CSR0_BABL);
646 csr[0] &= ~t;
647 csr[0] &= ~CSR0_ERR;
648
649 if ((csr[0] & CSR0_STOP) && !(oreg & CSR0_STOP)) {
650
651 csr[0] = CSR0_STOP;
652 csr[3] = 0;
653
654 } else if ((csr[0] & CSR0_STRT) && !(oreg & CSR0_STRT) && (oreg & (CSR0_STOP | CSR0_INIT))) {
655
656 csr[0] &= ~CSR0_STOP;
657 if (!(am_mode & MODE_DTX))
658 csr[0] |= CSR0_TXON;
659 if (!(am_mode & MODE_DRX))
660 csr[0] |= CSR0_RXON;
661 if ((csr[0] & CSR0_INIT) && !(oreg & CSR0_INIT)) {
662 chip_init ();
663 csr[0] |= CSR0_IDON;
664 am_initialized = 1;
665 }
666
667 } else if ((csr[0] & CSR0_INIT) && !(oreg & CSR0_INIT) && (oreg & CSR0_STOP)) {
668
669 chip_init ();
670 csr[0] |= CSR0_IDON;
671 csr[0] &= ~(CSR0_RXON | CSR0_TXON | CSR0_STOP);
672 am_initialized = 1;
673
674 }
675
676 if ((csr[0] & CSR0_STRT) && am_initialized) {
677 if (csr[0] & CSR0_TDMD)
678 check_transmit ();
679 }
680 csr[0] &= ~CSR0_TDMD;
681
682 rethink_a2065 ();
683 break;
684 case 1:
685 if (csr[0] & 4) {
686 csr[1] = v;
687 csr[1] &= ~1;
688 }
689 break;
690 case 2:
691 if (csr[0] & 4) {
692 csr[2] = v;
693 csr[2] &= 0x00ff;
694 }
695 break;
696 case 3:
697 if (csr[0] & 4) {
698 csr[3] = v;
699 csr[3] &= 7;
700 }
701 byteswap = (csr[3] & CSR3_BSWP) ? 1 : 0;
702 break;
703
704 }
705 }
706 }
707
708
a2065_bget2(uaecptr addr)709 static uae_u32 a2065_bget2 (uaecptr addr)
710 {
711 uae_u32 v = 0;
712
713 if (addr < 0x40) {
714 v = config[addr];
715 } else if (addr >= RAM_OFFSET) {
716 v = boardram[(addr & RAM_MASK) ^ 1];
717 }
718 if (log_a2065 > 2)
719 write_log (_T("A2065_BGET: %08X -> %02X PC=%08X\n"), addr, v & 0xff, M68K_GETPC);
720 return v;
721 }
722
a2065_bput2(uaecptr addr,uae_u32 v)723 static void a2065_bput2 (uaecptr addr, uae_u32 v)
724 {
725 if (addr >= RAM_OFFSET) {
726 boardram[(addr & RAM_MASK) ^ 1] = v;
727 }
728 if (log_a2065 > 2)
729 write_log (_T("A2065_BPUT: %08X <- %02X PC=%08X\n"), addr, v & 0xff, M68K_GETPC);
730 }
731
a2065_wget(uaecptr addr)732 static uae_u32 REGPARAM2 a2065_wget (uaecptr addr)
733 {
734 uae_u32 v;
735 #ifdef JIT
736 special_mem |= S_READ;
737 #endif
738 addr &= 65535;
739 if (addr == CHIP_OFFSET || addr == CHIP_OFFSET + 2) {
740 v = chip_wget (addr);
741 } else {
742 v = a2065_bget2 (addr) << 8;
743 v |= a2065_bget2 (addr + 1);
744 }
745 return v;
746 }
747
a2065_lget(uaecptr addr)748 static uae_u32 REGPARAM2 a2065_lget (uaecptr addr)
749 {
750 uae_u32 v;
751 #ifdef JIT
752 special_mem |= S_READ;
753 #endif
754 addr &= 65535;
755 v = a2065_wget (addr) << 16;
756 v |= a2065_wget (addr + 2);
757 return v;
758 }
759
a2065_bget(uaecptr addr)760 static uae_u32 REGPARAM2 a2065_bget (uaecptr addr)
761 {
762 uae_u32 v;
763 #ifdef JIT
764 special_mem |= S_READ;
765 #endif
766 addr &= 65535;
767 v = a2065_bget2 (addr);
768 if (!configured)
769 return v;
770 return v;
771 }
772
a2065_wput(uaecptr addr,uae_u32 w)773 static void REGPARAM2 a2065_wput (uaecptr addr, uae_u32 w)
774 {
775 #ifdef JIT
776 special_mem |= S_WRITE;
777 #endif
778 addr &= 65535;
779 if (addr == CHIP_OFFSET || addr == CHIP_OFFSET + 2) {
780 chip_wput (addr, w);
781 } else {
782 a2065_bput2 (addr, w >> 8);
783 a2065_bput2 (addr + 1, w);
784 }
785 }
786
a2065_lput(uaecptr addr,uae_u32 l)787 static void REGPARAM2 a2065_lput (uaecptr addr, uae_u32 l)
788 {
789 #ifdef JIT
790 special_mem |= S_WRITE;
791 #endif
792 addr &= 65535;
793 a2065_wput (addr, l >> 16);
794 a2065_wput (addr + 2, l);
795 }
796
797 extern addrbank a2065_bank;
798
a2065_bput(uaecptr addr,uae_u32 b)799 static void REGPARAM2 a2065_bput (uaecptr addr, uae_u32 b)
800 {
801 #ifdef JIT
802 special_mem |= S_WRITE;
803 #endif
804 b &= 0xff;
805 addr &= 65535;
806 if (addr == 0x48 && !configured) {
807 map_banks (&a2065_bank, b, 0x10000 >> 16, 0x10000);
808 write_log (_T("A2065 Z2 autoconfigured at %02X0000\n"), b);
809 configured = b;
810 expamem_next ();
811 return;
812 }
813 if (addr == 0x4c && !configured) {
814 write_log (_T("A2065 DMAC AUTOCONFIG SHUT-UP!\n"));
815 configured = 0xff;
816 expamem_next ();
817 return;
818 }
819 if (!configured)
820 return;
821 a2065_bput2 (addr, b);
822 }
823
a2065_wgeti(uaecptr addr)824 static uae_u32 REGPARAM2 a2065_wgeti (uaecptr addr)
825 {
826 uae_u32 v = 0xffff;
827 #ifdef JIT
828 special_mem |= S_READ;
829 #endif
830 addr &= 65535;
831 return v;
832 }
a2065_lgeti(uaecptr addr)833 static uae_u32 REGPARAM2 a2065_lgeti (uaecptr addr)
834 {
835 uae_u32 v = 0xffff;
836 #ifdef JIT
837 special_mem |= S_READ;
838 #endif
839 addr &= 65535;
840 v = (a2065_wgeti (addr) << 16) | a2065_wgeti (addr + 2);
841 return v;
842 }
843
844 addrbank a2065_bank = {
845 a2065_lget, a2065_wget, a2065_bget,
846 a2065_lput, a2065_wput, a2065_bput,
847 default_xlate, default_check, NULL, _T("A2065 Z2 Ethernet"),
848 a2065_lgeti, a2065_wgeti, ABFLAG_IO
849 };
850
a2065_config(void)851 static void a2065_config (void)
852 {
853 memset (config, 0xff, sizeof config);
854 ew (0x00, 0xc0 | 0x01);
855 // hardware id
856 ew (0x04, 0x70);
857 // manufacturer (Commodore)
858 ew (0x10, 0x02);
859 ew (0x14, 0x02);
860
861 td = NULL;
862 if ((td = uaenet_enumerate (NULL, currprefs.a2065name))) {
863 memcpy (realmac, td->mac, sizeof realmac);
864 write_log (_T("A2065: '%s' %02X:%02X:%02X:%02X:%02X:%02X\n"),
865 td->name, td->mac[0], td->mac[1], td->mac[2], td->mac[3], td->mac[4], td->mac[5]);
866 } else {
867 realmac[0] = 0x00;
868 realmac[1] = 0x80;
869 realmac[2] = 0x10;
870 realmac[3] = 4;
871 realmac[4] = 3;
872 realmac[5] = 2;
873 write_log (_T("A2065: Disconnected mode %02X:%02X:%02X:%02X:%02X:%02X\n"),
874 realmac[0], realmac[1], realmac[2], realmac[3], realmac[4], realmac[5]);
875 }
876
877 ew (0x18, realmac[2]);
878 ew (0x1c, realmac[3]);
879 ew (0x20, realmac[4]);
880 ew (0x24, realmac[5]);
881
882 fakemac[0] = 0x00;
883 fakemac[1] = 0x80;
884 fakemac[2] = 0x10;
885 fakemac[3] = realmac[3];
886 fakemac[4] = realmac[4];
887 fakemac[5] = realmac[5];
888
889 if (configured) {
890 if (configured != 0xff)
891 map_banks (&a2065_bank, configured, 0x10000 >> 16, 0x10000);
892 } else {
893 /* KS autoconfig handles the rest */
894 map_banks (&a2065_bank, 0xe80000 >> 16, 0x10000 >> 16, 0x10000);
895 }
896 }
897
save_a2065(int * len,uae_u8 * dstptr)898 uae_u8 *save_a2065 (int *len, uae_u8 *dstptr)
899 {
900 uae_u8 *dstbak,*dst;
901
902 if (currprefs.a2065name[0] == 0)
903 return NULL;
904 if (dstptr)
905 dstbak = dst = dstptr;
906 else
907 dstbak = dst = (uae_u8*)malloc (16);
908 save_u32 (0);
909 save_u8 (configured);
910 for (int i = 0; i < 6; i++)
911 save_u8 (realmac[i]);
912 *len = dst - dstbak;
913 return dstbak;
914 }
restore_a2065(uae_u8 * src)915 uae_u8 *restore_a2065 (uae_u8 *src)
916 {
917 restore_u32 ();
918 configured = restore_u8 ();
919 for (int i = 0; i < 6; i++)
920 realmac[i] = restore_u8 ();
921 return src;
922 }
923
restore_a2065_finish(void)924 void restore_a2065_finish (void)
925 {
926 if (configured)
927 a2065_config ();
928 }
929
a2065_init(void)930 void a2065_init (void)
931 {
932 configured = 0;
933 a2065_config ();
934 }
935
936 #endif //a2065
937