/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 28107 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26