/[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 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 28387 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26