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