/[gxemul]/trunk/src/devices/dev_dec21143.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_dec21143.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 27232 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_dec21143.c,v 1.16 2005/11/25 03:52:55 debug Exp $
29 *
30 * DEC 21143 ("Tulip") ethernet controller. Implemented from Intel document
31 * 278074-001 ("21143 PC/CardBus 10/100Mb/s Ethernet LAN Controller") and by
32 * reverse-engineering OpenBSD and NetBSD sources.
33 *
34 *
35 * TODO:
36 *
37 * o) Endianness for descriptors...
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "cpu.h"
45 #include "device.h"
46 #include "devices.h"
47 #include "emul.h"
48 #include "machine.h"
49 #include "memory.h"
50 #include "misc.h"
51 #include "net.h"
52
53 #include "mii.h"
54 #include "tulipreg.h"
55
56
57 /* #define debug fatal */
58
59 #define DEC21143_TICK_SHIFT 16
60
61 #define N_REGS 32
62 #define ROM_WIDTH 6
63
64 struct dec21143_data {
65 int irq_nr;
66 int irq_asserted;
67
68 /* PCI: */
69 int pci_little_endian;
70
71 /* Ethernet address, and a network which we are connected to: */
72 uint8_t mac[6];
73 struct net *net;
74
75 /* SROM emulation: */
76 uint8_t srom[1 << (ROM_WIDTH + 1)];
77 int srom_curbit;
78 int srom_opcode;
79 int srom_opcode_has_started;
80 int srom_addr;
81
82 /* MII PHY emulation: */
83 uint16_t mii_phy_reg[MII_NPHY * 32];
84 int mii_state;
85 int mii_bit;
86 int mii_opcode;
87 int mii_phyaddr;
88 int mii_regaddr;
89
90 /* 21143 registers: */
91 uint32_t reg[N_REGS];
92
93 /* Internal TX state: */
94 uint64_t cur_tx_addr;
95 unsigned char *cur_tx_buf;
96 int cur_tx_buf_len;
97 int tx_idling;
98 int tx_idling_threshold;
99
100 /* Internal RX state: */
101 uint64_t cur_rx_addr;
102 unsigned char *cur_rx_buf;
103 int cur_rx_buf_len;
104 int cur_rx_offset;
105 };
106
107
108 /* Internal states during MII data stream decode: */
109 #define MII_STATE_RESET 0
110 #define MII_STATE_START_WAIT 1
111 #define MII_STATE_READ_OP 2
112 #define MII_STATE_READ_PHYADDR_REGADDR 3
113 #define MII_STATE_A 4
114 #define MII_STATE_D 5
115 #define MII_STATE_IDLE 6
116
117
118 /*
119 * dec21143_rx():
120 */
121 int dec21143_rx(struct cpu *cpu, struct dec21143_data *d)
122 {
123 uint64_t addr = d->cur_rx_addr, bufaddr;
124 unsigned char descr[16];
125 uint32_t rdes0, rdes1, rdes2, rdes3;
126 int bufsize, buf1_size, buf2_size, i, writeback_len = 4, to_xfer;
127
128 /* No current packet? Then check for new ones. */
129 if (d->cur_rx_buf == NULL) {
130 /* Nothing available? Then abort. */
131 if (!net_ethernet_rx_avail(d->net, d))
132 return 0;
133
134 /* Get the next packet into our buffer: */
135 net_ethernet_rx(d->net, d, &d->cur_rx_buf,
136 &d->cur_rx_buf_len);
137
138 d->cur_rx_offset = 0;
139 }
140
141 /* fatal("{ dec21143_rx: base = 0x%08x }\n", (int)addr); */
142
143 if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t),
144 MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {
145 fatal("[ dec21143_rx: memory_rw failed! ]\n");
146 return 0;
147 }
148
149 rdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24);
150
151 /* Only use descriptors owned by the 21143: */
152 if (!(rdes0 & TDSTAT_OWN)) {
153 d->reg[CSR_STATUS/8] |= STATUS_RU;
154 return 0;
155 }
156
157 if (!cpu->memory_rw(cpu, cpu->mem, addr + sizeof(uint32_t), descr +
158 sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ, PHYSICAL |
159 NO_EXCEPTIONS)) {
160 fatal("[ dec21143_rx: memory_rw failed! ]\n");
161 return 0;
162 }
163
164 rdes1 = descr[4] + (descr[5]<<8) + (descr[6]<<16) + (descr[7]<<24);
165 rdes2 = descr[8] + (descr[9]<<8) + (descr[10]<<16) + (descr[11]<<24);
166 rdes3 = descr[12] + (descr[13]<<8) + (descr[14]<<16) + (descr[15]<<24);
167
168 buf1_size = rdes1 & TDCTL_SIZE1;
169 buf2_size = (rdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT;
170 bufaddr = buf1_size? rdes2 : rdes3;
171 bufsize = buf1_size? buf1_size : buf2_size;
172
173 d->reg[CSR_STATUS/8] &= ~STATUS_RS;
174
175 if (rdes1 & TDCTL_ER)
176 d->cur_rx_addr = d->reg[CSR_RXLIST / 8];
177 else {
178 if (rdes1 & TDCTL_CH)
179 d->cur_rx_addr = rdes3;
180 else
181 d->cur_rx_addr += 4 * sizeof(uint32_t);
182 }
183
184 /* fatal("{ RX (%llx): %08x %08x %x %x: buf %i bytes at 0x%x }\n",
185 (long long)addr, rdes0, rdes1, rdes2, rdes3, bufsize,
186 (int)bufaddr); */
187
188 /* Turn off all status bits, and give up ownership: */
189 rdes0 = 0x00000000;
190
191 to_xfer = d->cur_rx_buf_len - d->cur_rx_offset;
192 if (to_xfer > bufsize)
193 to_xfer = bufsize;
194
195 /* DMA bytes from the packet into emulated physical memory: */
196 for (i=0; i<to_xfer; i++) {
197 cpu->memory_rw(cpu, cpu->mem, bufaddr + i,
198 d->cur_rx_buf + d->cur_rx_offset + i, 1, MEM_WRITE,
199 PHYSICAL | NO_EXCEPTIONS);
200 /* fatal(" %02x", d->cur_rx_buf[d->cur_rx_offset + i]); */
201 }
202
203 /* Was this the first buffer in a frame? Then mark it as such. */
204 if (d->cur_rx_offset == 0)
205 rdes0 |= TDSTAT_Rx_FS;
206
207 d->cur_rx_offset += to_xfer;
208
209 /* Frame completed? */
210 if (d->cur_rx_offset >= d->cur_rx_buf_len) {
211 rdes0 |= TDSTAT_Rx_LS;
212
213 /* Frame len, which includes the size of a 4-byte CRC: */
214 rdes0 |= ((d->cur_rx_buf_len + 4) << 16) & TDSTAT_Rx_FL;
215
216 /* Frame too long? (1518 is max ethernet frame length) */
217 if (d->cur_rx_buf_len > 1518)
218 rdes0 |= TDSTAT_Rx_TL;
219
220 /* Cause a receiver interrupt: */
221 d->reg[CSR_STATUS/8] |= STATUS_RI;
222
223 free(d->cur_rx_buf);
224 d->cur_rx_buf = NULL;
225 d->cur_rx_buf_len = 0;
226 }
227
228 /* Descriptor writeback: */
229 descr[ 0] = rdes0; descr[ 1] = rdes0 >> 8;
230 descr[ 2] = rdes0 >> 16; descr[ 3] = rdes0 >> 24;
231 if (writeback_len > 1) {
232 descr[ 4] = rdes1; descr[ 5] = rdes1 >> 8;
233 descr[ 6] = rdes1 >> 16; descr[ 7] = rdes1 >> 24;
234 descr[ 8] = rdes2; descr[ 9] = rdes2 >> 8;
235 descr[10] = rdes2 >> 16; descr[11] = rdes2 >> 24;
236 descr[12] = rdes3; descr[13] = rdes3 >> 8;
237 descr[14] = rdes3 >> 16; descr[15] = rdes3 >> 24;
238 }
239
240 if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t)
241 * writeback_len, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) {
242 fatal("[ dec21143_rx: memory_rw failed! ]\n");
243 return 0;
244 }
245
246 return 1;
247 }
248
249
250 /*
251 * dec21143_tx():
252 */
253 int dec21143_tx(struct cpu *cpu, struct dec21143_data *d)
254 {
255 uint64_t addr = d->cur_tx_addr, bufaddr;
256 unsigned char descr[16];
257 uint32_t tdes0, tdes1, tdes2, tdes3;
258 int bufsize, buf1_size, buf2_size, i, writeback_len = 4;
259
260 /* fatal("{ dec21143_tx: base = 0x%08x }\n", (int)addr); */
261
262 if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t),
263 MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {
264 fatal("[ dec21143_tx: memory_rw failed! ]\n");
265 return 0;
266 }
267
268 tdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24);
269
270 /* Only process packets owned by the 21143: */
271 if (!(tdes0 & TDSTAT_OWN)) {
272 if (d->tx_idling > d->tx_idling_threshold) {
273 d->reg[CSR_STATUS/8] |= STATUS_TU;
274 d->tx_idling = 0;
275 } else
276 d->tx_idling ++;
277 return 0;
278 }
279
280 if (!cpu->memory_rw(cpu, cpu->mem, addr + sizeof(uint32_t), descr +
281 sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ, PHYSICAL |
282 NO_EXCEPTIONS)) {
283 fatal("[ dec21143_tx: memory_rw failed! ]\n");
284 return 0;
285 }
286
287 tdes1 = descr[4] + (descr[5]<<8) + (descr[6]<<16) + (descr[7]<<24);
288 tdes2 = descr[8] + (descr[9]<<8) + (descr[10]<<16) + (descr[11]<<24);
289 tdes3 = descr[12] + (descr[13]<<8) + (descr[14]<<16) + (descr[15]<<24);
290
291 buf1_size = tdes1 & TDCTL_SIZE1;
292 buf2_size = (tdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT;
293 bufaddr = buf1_size? tdes2 : tdes3;
294 bufsize = buf1_size? buf1_size : buf2_size;
295
296 d->reg[CSR_STATUS/8] &= ~STATUS_TS;
297
298 if (tdes1 & TDCTL_ER)
299 d->cur_tx_addr = d->reg[CSR_TXLIST / 8];
300 else {
301 if (tdes1 & TDCTL_CH)
302 d->cur_tx_addr = tdes3;
303 else
304 d->cur_tx_addr += 4 * sizeof(uint32_t);
305 }
306
307 /* fatal("{ TX (%llx): %08x %08x %x %x: buf %i bytes at 0x%x }\n",
308 (long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize,
309 (int)bufaddr); */
310
311 /* Assume no error: */
312 tdes0 &= ~ (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC
313 | TDSTAT_Tx_NC | TDSTAT_Tx_LO | TDSTAT_Tx_TO | TDSTAT_ES);
314
315 if (tdes1 & TDCTL_Tx_SET) {
316 /*
317 * Setup Packet.
318 *
319 * TODO. For now, just ignore it, and pretend it worked.
320 */
321 /* fatal("{ TX: setup packet }\n"); */
322 if (bufsize != 192)
323 fatal("[ dec21143: setup packet len = %i, should be"
324 " 192! ]\n", (int)bufsize);
325 if (tdes1 & TDCTL_Tx_IC)
326 d->reg[CSR_STATUS/8] |= STATUS_TI;
327 /* New descriptor values, according to the docs: */
328 tdes0 = 0x7fffffff; tdes1 = 0xffffffff;
329 tdes2 = 0xffffffff; tdes3 = 0xffffffff;
330 } else {
331 /*
332 * Data Packet.
333 */
334 /* fatal("{ TX: data packet: "); */
335 if (tdes1 & TDCTL_Tx_FS) {
336 /* First segment. Let's allocate a new buffer: */
337 /* fatal("new frame }\n"); */
338 d->cur_tx_buf = malloc(bufsize);
339 d->cur_tx_buf_len = 0;
340 } else {
341 /* Not first segment. Increase the length of
342 the current buffer: */
343 /* fatal("continuing last frame }\n"); */
344 d->cur_tx_buf = realloc(d->cur_tx_buf,
345 d->cur_tx_buf_len + bufsize);
346 }
347
348 if (d->cur_tx_buf == NULL) {
349 fatal("dec21143_tx(): out of memory\n");
350 exit(1);
351 }
352
353 /* "DMA" data from emulated physical memory into the buf: */
354 for (i=0; i<bufsize; i++) {
355 cpu->memory_rw(cpu, cpu->mem, bufaddr + i,
356 d->cur_tx_buf + d->cur_tx_buf_len + i, 1, MEM_READ,
357 PHYSICAL | NO_EXCEPTIONS);
358 /* fatal(" %02x", d->cur_tx_buf[
359 d->cur_tx_buf_len + i]); */
360 }
361
362 d->cur_tx_buf_len += bufsize;
363
364 /* Last segment? Then actually transmit it: */
365 if (tdes1 & TDCTL_Tx_LS) {
366 /* fatal("{ TX: data frame complete. }\n"); */
367 if (d->net != NULL) {
368 net_ethernet_tx(d->net, d, d->cur_tx_buf,
369 d->cur_tx_buf_len);
370 } else {
371 static int warn = 0;
372 if (!warn)
373 fatal("[ dec21143: WARNING! Not "
374 "connected to a network! ]\n");
375 warn = 1;
376 }
377
378 free(d->cur_tx_buf);
379 d->cur_tx_buf = NULL;
380 d->cur_tx_buf_len = 0;
381
382 /* We are done. */
383 tdes0 &= ~TDSTAT_OWN;
384 writeback_len = 1;
385
386 /* Interrupt, if Tx_IC is set: */
387 if (tdes1 & TDCTL_Tx_IC)
388 d->reg[CSR_STATUS/8] |= STATUS_TI;
389 }
390 }
391
392 /* Error summary: */
393 if (tdes0 & (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC
394 | TDSTAT_Tx_NC | TDSTAT_Tx_LO | TDSTAT_Tx_TO))
395 tdes0 |= TDSTAT_ES;
396
397 /* Descriptor writeback: */
398 descr[ 0] = tdes0; descr[ 1] = tdes0 >> 8;
399 descr[ 2] = tdes0 >> 16; descr[ 3] = tdes0 >> 24;
400 if (writeback_len > 1) {
401 descr[ 4] = tdes1; descr[ 5] = tdes1 >> 8;
402 descr[ 6] = tdes1 >> 16; descr[ 7] = tdes1 >> 24;
403 descr[ 8] = tdes2; descr[ 9] = tdes2 >> 8;
404 descr[10] = tdes2 >> 16; descr[11] = tdes2 >> 24;
405 descr[12] = tdes3; descr[13] = tdes3 >> 8;
406 descr[14] = tdes3 >> 16; descr[15] = tdes3 >> 24;
407 }
408
409 if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t)
410 * writeback_len, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) {
411 fatal("[ dec21143_tx: memory_rw failed! ]\n");
412 return 0;
413 }
414
415 return 1;
416 }
417
418
419 /*
420 * dev_dec21143_tick():
421 */
422 void dev_dec21143_tick(struct cpu *cpu, void *extra)
423 {
424 struct dec21143_data *d = extra;
425 int asserted;
426
427 if (d->reg[CSR_OPMODE / 8] & OPMODE_ST)
428 while (dec21143_tx(cpu, d))
429 ;
430
431 if (d->reg[CSR_OPMODE / 8] & OPMODE_SR)
432 while (dec21143_rx(cpu, d))
433 ;
434
435 /* Normal and Abnormal interrupt summary: */
436 d->reg[CSR_STATUS / 8] &= ~(STATUS_NIS | STATUS_AIS);
437 if (d->reg[CSR_STATUS / 8] & 0x00004845)
438 d->reg[CSR_STATUS / 8] |= STATUS_NIS;
439 if (d->reg[CSR_STATUS / 8] & 0x0c0037ba)
440 d->reg[CSR_STATUS / 8] |= STATUS_AIS;
441
442 asserted = d->reg[CSR_STATUS / 8] & d->reg[CSR_INTEN / 8] & 0x0c01ffff;
443 if (asserted) {
444 cpu_interrupt(cpu, d->irq_nr);
445 } else {
446 if (d->irq_asserted)
447 cpu_interrupt_ack(cpu, d->irq_nr);
448 }
449
450 /* Remember assertion flag: */
451 d->irq_asserted = asserted;
452 }
453
454
455 /*
456 * mii_access():
457 *
458 * This function handles accesses to the MII. Data streams seem to be of the
459 * following format:
460 *
461 * vv---- starting delimiter
462 * ... 01 xx yyyyy zzzzz a[a] dddddddddddddddd
463 * ^---- I am starting with mii_bit = 0 here
464 *
465 * where x = opcode (10 = read, 01 = write)
466 * y = PHY address
467 * z = register address
468 * a = on Reads: ACK bit (returned, should be 0)
469 * on Writes: _TWO_ dummy bits (10)
470 * d = 16 bits of data (MSB first)
471 */
472 static void mii_access(struct cpu *cpu, struct dec21143_data *d,
473 uint32_t oldreg, uint32_t idata)
474 {
475 int obit, ibit = 0;
476 uint16_t tmp;
477
478 /* Only care about data during clock cycles: */
479 if (!(idata & MIIROM_MDC))
480 return;
481
482 if (idata & MIIROM_MDC && oldreg & MIIROM_MDC)
483 return;
484
485 /* fatal("[ mii_access(): 0x%08x ]\n", (int)idata); */
486
487 if (idata & MIIROM_BR) {
488 fatal("[ mii_access(): MIIROM_BR: TODO ]\n");
489 return;
490 }
491
492 obit = idata & MIIROM_MDO? 1 : 0;
493
494 if (d->mii_state >= MII_STATE_START_WAIT &&
495 d->mii_state <= MII_STATE_READ_PHYADDR_REGADDR &&
496 idata & MIIROM_MIIDIR)
497 fatal("[ mii_access(): bad dir? ]\n");
498
499 switch (d->mii_state) {
500
501 case MII_STATE_RESET:
502 /* Wait for a starting delimiter (0 followed by 1). */
503 if (obit)
504 return;
505 if (idata & MIIROM_MIIDIR)
506 return;
507 /* fatal("[ mii_access(): got a 0 delimiter ]\n"); */
508 d->mii_state = MII_STATE_START_WAIT;
509 d->mii_opcode = 0;
510 d->mii_phyaddr = 0;
511 d->mii_regaddr = 0;
512 break;
513
514 case MII_STATE_START_WAIT:
515 /* Wait for a starting delimiter (0 followed by 1). */
516 if (!obit)
517 return;
518 if (idata & MIIROM_MIIDIR) {
519 d->mii_state = MII_STATE_RESET;
520 return;
521 }
522 /* fatal("[ mii_access(): got a 1 delimiter ]\n"); */
523 d->mii_state = MII_STATE_READ_OP;
524 d->mii_bit = 0;
525 break;
526
527 case MII_STATE_READ_OP:
528 if (d->mii_bit == 0) {
529 d->mii_opcode = obit << 1;
530 /* fatal("[ mii_access(): got first opcode bit "
531 "(%i) ]\n", obit); */
532 } else {
533 d->mii_opcode |= obit;
534 /* fatal("[ mii_access(): got opcode = %i ]\n",
535 d->mii_opcode); */
536 d->mii_state = MII_STATE_READ_PHYADDR_REGADDR;
537 }
538 d->mii_bit ++;
539 break;
540
541 case MII_STATE_READ_PHYADDR_REGADDR:
542 /* fatal("[ mii_access(): got phy/reg addr bit nr %i (%i)"
543 " ]\n", d->mii_bit - 2, obit); */
544 if (d->mii_bit <= 6)
545 d->mii_phyaddr |= obit << (6-d->mii_bit);
546 else
547 d->mii_regaddr |= obit << (11-d->mii_bit);
548 d->mii_bit ++;
549 if (d->mii_bit >= 12) {
550 /* fatal("[ mii_access(): phyaddr=0x%x regaddr=0x"
551 "%x ]\n", d->mii_phyaddr, d->mii_regaddr); */
552 d->mii_state = MII_STATE_A;
553 }
554 break;
555
556 case MII_STATE_A:
557 switch (d->mii_opcode) {
558 case MII_COMMAND_WRITE:
559 if (d->mii_bit >= 13)
560 d->mii_state = MII_STATE_D;
561 break;
562 case MII_COMMAND_READ:
563 ibit = 0;
564 d->mii_state = MII_STATE_D;
565 break;
566 default:debug("[ mii_access(): UNIMPLEMENTED MII opcode "
567 "%i (probably just a bug in GXemul's "
568 "MII data stream handling) ]\n", d->mii_opcode);
569 d->mii_state = MII_STATE_RESET;
570 }
571 d->mii_bit ++;
572 break;
573
574 case MII_STATE_D:
575 switch (d->mii_opcode) {
576 case MII_COMMAND_WRITE:
577 if (idata & MIIROM_MIIDIR)
578 fatal("[ mii_access(): write: bad dir? ]\n");
579 obit = obit? (0x8000 >> (d->mii_bit - 14)) : 0;
580 tmp = d->mii_phy_reg[(d->mii_phyaddr << 5) +
581 d->mii_regaddr] | obit;
582 if (d->mii_bit >= 29) {
583 d->mii_state = MII_STATE_IDLE;
584 debug("[ mii_access(): WRITE to phyaddr=0x%x "
585 "regaddr=0x%x: 0x%04x ]\n", d->mii_phyaddr,
586 d->mii_regaddr, tmp);
587 }
588 break;
589 case MII_COMMAND_READ:
590 if (!(idata & MIIROM_MIIDIR))
591 break;
592 tmp = d->mii_phy_reg[(d->mii_phyaddr << 5) +
593 d->mii_regaddr];
594 if (d->mii_bit == 13)
595 debug("[ mii_access(): READ phyaddr=0x%x "
596 "regaddr=0x%x: 0x%04x ]\n", d->mii_phyaddr,
597 d->mii_regaddr, tmp);
598 ibit = tmp & (0x8000 >> (d->mii_bit - 13));
599 if (d->mii_bit >= 28)
600 d->mii_state = MII_STATE_IDLE;
601 break;
602 }
603 d->mii_bit ++;
604 break;
605
606 case MII_STATE_IDLE:
607 d->mii_bit ++;
608 if (d->mii_bit >= 31)
609 d->mii_state = MII_STATE_RESET;
610 break;
611 }
612
613 d->reg[CSR_MIIROM / 8] &= ~MIIROM_MDI;
614 if (ibit)
615 d->reg[CSR_MIIROM / 8] |= MIIROM_MDI;
616 }
617
618
619 /*
620 * srom_access():
621 *
622 * This function handles reads from the Ethernet Address ROM. This is not a
623 * 100% correct implementation, as it was reverse-engineered from OpenBSD
624 * sources; it seems to work with OpenBSD, NetBSD, and Linux.
625 *
626 * Each transfer (if I understood this correctly) is of the following format:
627 *
628 * 1xx yyyyyy zzzzzzzzzzzzzzzz
629 *
630 * where 1xx = operation (6 means a Read),
631 * yyyyyy = ROM address
632 * zz...z = data
633 *
634 * y and z are _both_ read and written to at the same time; this enables the
635 * operating system to sense the number of bits in y (when reading, all y bits
636 * are 1 except the last one).
637 */
638 static void srom_access(struct cpu *cpu, struct dec21143_data *d,
639 uint32_t oldreg, uint32_t idata)
640 {
641 int obit, ibit;
642
643 /* debug("CSR9 WRITE! 0x%08x\n", (int)idata); */
644
645 /* New selection? Then reset internal state. */
646 if (idata & MIIROM_SR && !(oldreg & MIIROM_SR)) {
647 d->srom_curbit = 0;
648 d->srom_opcode = 0;
649 d->srom_opcode_has_started = 0;
650 d->srom_addr = 0;
651 }
652
653 /* Only care about data during clock cycles: */
654 if (!(idata & MIIROM_SROMSK))
655 return;
656
657 obit = 0;
658 ibit = idata & MIIROM_SROMDI? 1 : 0;
659 /* debug("CLOCK CYCLE! (bit %i): ", d->srom_curbit); */
660
661 /*
662 * Linux sends more zeroes before starting the actual opcode, than
663 * OpenBSD and NetBSD. Hopefully this is correct. (I'm just guessing
664 * that all opcodes should start with a 1, perhaps that's not really
665 * the case.)
666 */
667 if (!ibit && !d->srom_opcode_has_started)
668 return;
669
670 if (d->srom_curbit < 3) {
671 d->srom_opcode_has_started = 1;
672 d->srom_opcode <<= 1;
673 d->srom_opcode |= ibit;
674 /* debug("opcode input '%i'\n", ibit); */
675 } else {
676 switch (d->srom_opcode) {
677 case TULIP_SROM_OPC_READ:
678 if (d->srom_curbit < ROM_WIDTH + 3) {
679 obit = d->srom_curbit < ROM_WIDTH + 2;
680 d->srom_addr <<= 1;
681 d->srom_addr |= ibit;
682 } else {
683 uint16_t romword = d->srom[d->srom_addr*2]
684 + (d->srom[d->srom_addr*2+1] << 8);
685 if (d->srom_curbit == ROM_WIDTH + 3)
686 debug("[ dec21143: ROM read from offset"
687 " 0x%03x: 0x%04x ]\n",
688 d->srom_addr, romword);
689 obit = romword & (0x8000 >>
690 (d->srom_curbit - ROM_WIDTH - 3))? 1 : 0;
691 }
692 break;
693 default:fatal("[ dec21243: unimplemented SROM/EEPROM "
694 "opcode %i ]\n", d->srom_opcode);
695 }
696 d->reg[CSR_MIIROM / 8] &= ~MIIROM_SROMDO;
697 if (obit)
698 d->reg[CSR_MIIROM / 8] |= MIIROM_SROMDO;
699 /* debug("input '%i', output '%i'\n", ibit, obit); */
700 }
701
702 d->srom_curbit ++;
703
704 /*
705 * Done opcode + addr + data? Then restart. (At least NetBSD does
706 * sequential reads without turning selection off and then on.)
707 */
708 if (d->srom_curbit >= 3 + ROM_WIDTH + 16) {
709 d->srom_curbit = 0;
710 d->srom_opcode = 0;
711 d->srom_opcode_has_started = 0;
712 d->srom_addr = 0;
713 }
714 }
715
716
717 /*
718 * dec21143_reset():
719 *
720 * Set the 21143 registers, SROM, and MII data to reasonable values.
721 */
722 static void dec21143_reset(struct cpu *cpu, struct dec21143_data *d)
723 {
724 int leaf;
725
726 if (d->cur_rx_buf != NULL)
727 free(d->cur_rx_buf);
728 if (d->cur_tx_buf != NULL)
729 free(d->cur_tx_buf);
730 d->cur_rx_buf = d->cur_tx_buf = NULL;
731
732 memset(d->reg, 0, sizeof(uint32_t) * N_REGS);
733 memset(d->srom, 0, sizeof(d->srom));
734 memset(d->mii_phy_reg, 0, sizeof(d->mii_phy_reg));
735
736 /* Register values at reset, according to the manual: */
737 d->reg[CSR_BUSMODE / 8] = 0xfe000000; /* csr0 */
738 d->reg[CSR_MIIROM / 8] = 0xfff483ff; /* csr9 */
739 d->reg[CSR_SIACONN / 8] = 0xffff0000; /* csr13 */
740 d->reg[CSR_SIATXRX / 8] = 0xffffffff; /* csr14 */
741 d->reg[CSR_SIAGEN / 8] = 0x8ff00000; /* csr15 */
742
743 d->tx_idling_threshold = 10;
744 d->cur_rx_addr = d->cur_tx_addr = 0;
745
746 /* Version (= 1) and Chip count (= 1): */
747 d->srom[TULIP_ROM_SROM_FORMAT_VERION] = 1;
748 d->srom[TULIP_ROM_CHIP_COUNT] = 1;
749
750 /* Set the MAC address: */
751 memcpy(d->srom + TULIP_ROM_IEEE_NETWORK_ADDRESS, d->mac, 6);
752
753 leaf = 30;
754 d->srom[TULIP_ROM_CHIPn_DEVICE_NUMBER(0)] = 0;
755 d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)] = leaf & 255;
756 d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)+1] = leaf >> 8;
757
758 d->srom[leaf+TULIP_ROM_IL_SELECT_CONN_TYPE] = 0; /* Not used? */
759 d->srom[leaf+TULIP_ROM_IL_MEDIA_COUNT] = 2;
760 leaf += TULIP_ROM_IL_MEDIAn_BLOCK_BASE;
761
762 d->srom[leaf] = 7; /* descriptor length */
763 d->srom[leaf+1] = TULIP_ROM_MB_21142_SIA;
764 d->srom[leaf+2] = TULIP_ROM_MB_MEDIA_100TX;
765 /* here comes 4 bytes of GPIO control/data settings */
766 leaf += d->srom[leaf];
767
768 d->srom[leaf] = 15; /* descriptor length */
769 d->srom[leaf+1] = TULIP_ROM_MB_21142_MII;
770 d->srom[leaf+2] = 0; /* PHY nr */
771 d->srom[leaf+3] = 0; /* len of select sequence */
772 d->srom[leaf+4] = 0; /* len of reset sequence */
773 /* 5,6, 7,8, 9,10, 11,12, 13,14 = unused by GXemul */
774 leaf += d->srom[leaf];
775
776 /* MII PHY initial state: */
777 d->mii_state = MII_STATE_RESET;
778
779 /* PHY #0: */
780 d->mii_phy_reg[MII_BMSR] = BMSR_100TXFDX | BMSR_10TFDX |
781 BMSR_ACOMP | BMSR_ANEG | BMSR_LINK;
782 }
783
784
785 /*
786 * dev_dec21143_access():
787 */
788 int dev_dec21143_access(struct cpu *cpu, struct memory *mem,
789 uint64_t relative_addr, unsigned char *data, size_t len,
790 int writeflag, void *extra)
791 {
792 struct dec21143_data *d = extra;
793 uint64_t idata = 0, odata = 0;
794 uint32_t oldreg = 0;
795 int regnr = relative_addr >> 3;
796
797 if (writeflag == MEM_WRITE)
798 idata = memory_readmax64(cpu, data, len | d->pci_little_endian);
799
800 if ((relative_addr & 7) == 0 && regnr < N_REGS) {
801 if (writeflag == MEM_READ) {
802 odata = d->reg[regnr];
803 } else {
804 oldreg = d->reg[regnr];
805 switch (regnr) {
806 case CSR_STATUS / 8: /* Zero-on-write */
807 d->reg[regnr] &= ~(idata & 0x0c01ffff);
808 break;
809 case CSR_MISSED / 8: /* Read only */
810 break;
811 default:d->reg[regnr] = idata;
812 }
813 }
814 } else
815 fatal("[ dec21143: WARNING! unaligned access (0x%x) ]\n",
816 (int)relative_addr);
817
818 switch (relative_addr) {
819
820 case CSR_BUSMODE: /* csr0 */
821 if (writeflag == MEM_WRITE) {
822 /* Software reset takes effect immediately. */
823 if (idata & BUSMODE_SWR) {
824 dec21143_reset(cpu, d);
825 idata &= ~BUSMODE_SWR;
826 }
827 }
828 break;
829
830 case CSR_TXPOLL: /* csr1 */
831 if (writeflag == MEM_READ)
832 fatal("[ dec21143: UNIMPLEMENTED READ from "
833 "txpoll ]\n");
834 d->tx_idling = d->tx_idling_threshold;
835 dev_dec21143_tick(cpu, extra);
836 break;
837
838 case CSR_RXPOLL: /* csr2 */
839 if (writeflag == MEM_READ)
840 fatal("[ dec21143: UNIMPLEMENTED READ from "
841 "rxpoll ]\n");
842 dev_dec21143_tick(cpu, extra);
843 break;
844
845 case CSR_RXLIST: /* csr3 */
846 if (writeflag == MEM_WRITE) {
847 debug("[ dec21143: setting RXLIST to 0x%x ]\n",
848 (int)idata);
849 if (idata & 0x3)
850 fatal("[ dec21143: WARNING! RXLIST not aligned"
851 "? (0x%llx) ]\n", (long long)idata);
852 idata &= ~0x3;
853 d->cur_rx_addr = idata;
854 }
855 break;
856
857 case CSR_TXLIST: /* csr4 */
858 if (writeflag == MEM_WRITE) {
859 debug("[ dec21143: setting TXLIST to 0x%x ]\n",
860 (int)idata);
861 if (idata & 0x3)
862 fatal("[ dec21143: WARNING! TXLIST not aligned"
863 "? (0x%llx) ]\n", (long long)idata);
864 idata &= ~0x3;
865 d->cur_tx_addr = idata;
866 }
867 break;
868
869 case CSR_STATUS: /* csr5 */
870 case CSR_INTEN: /* csr7 */
871 if (writeflag == MEM_WRITE) {
872 /* Recalculate interrupt assertion. */
873 dev_dec21143_tick(cpu, extra);
874 }
875 break;
876
877 case CSR_OPMODE: /* csr6: */
878 if (writeflag == MEM_WRITE) {
879 if (idata & 0x02000000) {
880 /* A must-be-one bit. */
881 idata &= ~0x02000000;
882 }
883 if (idata & OPMODE_ST) {
884 idata &= ~OPMODE_ST;
885 } else {
886 /* Turned off TX? Then idle: */
887 d->reg[CSR_STATUS/8] |= STATUS_TPS;
888 }
889 if (idata & OPMODE_SR) {
890 idata &= ~OPMODE_SR;
891 } else {
892 /* Turned off RX? Then go to stopped state: */
893 d->reg[CSR_STATUS/8] &= ~STATUS_RS;
894 }
895 idata &= ~(OPMODE_HBD | OPMODE_SCR | OPMODE_PCS
896 | OPMODE_PS | OPMODE_SF | OPMODE_TTM);
897 if (idata & OPMODE_PNIC_IT) {
898 idata &= ~OPMODE_PNIC_IT;
899 d->tx_idling = d->tx_idling_threshold;
900 }
901 if (idata != 0) {
902 fatal("[ dec21143: UNIMPLEMENTED OPMODE bits"
903 ": 0x%08x ]\n", (int)idata);
904 }
905 dev_dec21143_tick(cpu, extra);
906 }
907 break;
908
909 case CSR_MISSED: /* csr8 */
910 break;
911
912 case CSR_MIIROM: /* csr9 */
913 if (writeflag == MEM_WRITE) {
914 if (idata & MIIROM_MDC)
915 mii_access(cpu, d, oldreg, idata);
916 else
917 srom_access(cpu, d, oldreg, idata);
918 }
919 break;
920
921 case CSR_SIASTAT: /* csr12 */
922 /* Auto-negotiation status = Good. */
923 odata = SIASTAT_ANS_FLPGOOD;
924 break;
925
926 case CSR_SIATXRX: /* csr14 */
927 /* Auto-negotiation Enabled */
928 odata = SIATXRX_ANE;
929 break;
930
931 case CSR_SIACONN: /* csr13 */
932 case CSR_SIAGEN: /* csr15 */
933 /* Don't print warnings for these, for now. */
934 break;
935
936 default:if (writeflag == MEM_READ)
937 fatal("[ dec21143: read from unimplemented 0x%02x ]\n",
938 (int)relative_addr);
939 else
940 fatal("[ dec21143: write to unimplemented 0x%02x: "
941 "0x%02x ]\n", (int)relative_addr, (int)idata);
942 }
943
944 if (writeflag == MEM_READ)
945 memory_writemax64(cpu, data, len | d->pci_little_endian, odata);
946
947 return 1;
948 }
949
950
951 /*
952 * devinit_dec21143():
953 */
954 int devinit_dec21143(struct devinit *devinit)
955 {
956 struct dec21143_data *d;
957 char name2[100];
958
959 d = malloc(sizeof(struct dec21143_data));
960 if (d == NULL) {
961 fprintf(stderr, "out of memory\n");
962 exit(1);
963 }
964 memset(d, 0, sizeof(struct dec21143_data));
965
966 d->irq_nr = devinit->irq_nr;
967 d->pci_little_endian = devinit->pci_little_endian;
968
969 net_generate_unique_mac(devinit->machine, d->mac);
970 net_add_nic(devinit->machine->emul->net, d, d->mac);
971 d->net = devinit->machine->emul->net;
972
973 dec21143_reset(devinit->machine->cpus[0], d);
974
975 snprintf(name2, sizeof(name2), "%s [%02x:%02x:%02x:%02x:%02x:%02x]",
976 devinit->name, d->mac[0], d->mac[1], d->mac[2], d->mac[3],
977 d->mac[4], d->mac[5]);
978
979 memory_device_register(devinit->machine->memory, name2,
980 devinit->addr, 0x100, dev_dec21143_access, d, DM_DEFAULT, NULL);
981
982 machine_add_tickfunction(devinit->machine,
983 dev_dec21143_tick, d, DEC21143_TICK_SHIFT);
984
985 /*
986 * NetBSD/cats uses memory accesses, OpenBSD/cats uses I/O registers.
987 * Let's make a mirror from the memory range to the I/O range:
988 */
989 dev_ram_init(devinit->machine, devinit->addr2, 0x100, DEV_RAM_MIRROR
990 | DEV_RAM_MIGHT_POINT_TO_DEVICES, devinit->addr);
991
992 return 1;
993 }
994

  ViewVC Help
Powered by ViewVC 1.1.26