/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (hide 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 dpavlin 20 /*
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