/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 5 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 /*
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.31 2007/06/15 18:44:19 debug Exp $
29 *
30 * COMMENT: DEC 21143 "Tulip" ethernet controller
31 *
32 * 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 * This device emulates several sub-components:
37 *
38 * 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 * TODO:
47 * 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 */
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 #include "interrupt.h"
64 #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 struct interrupt irq;
82 int irq_was_asserted;
83
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 *
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 */
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 /* Append a 4 byte CRC: */
159 d->cur_rx_buf_len += 4;
160 CHECK_ALLOCATION(d->cur_rx_buf = realloc(d->cur_rx_buf,
161 d->cur_rx_buf_len));
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;
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
376 CHECK_ALLOCATION(d->cur_tx_buf = malloc(bufsize));
377 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 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 }
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
425 /* We are done with this segment. */
426 tdes0 &= ~TDSTAT_OWN;
427 }
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 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
444 if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t)
445 * 4, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) {
446 fatal("[ dec21143_tx: memory_rw failed! ]\n");
447 return 0;
448 }
449
450 return 1;
451 }
452
453
454 DEVICE_TICK(dec21143)
455 {
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 if (asserted)
477 INTERRUPT_ASSERT(d->irq);
478 if (!asserted && d->irq_was_asserted)
479 INTERRUPT_DEASSERT(d->irq);
480
481 /* Remember assertion flag: */
482 d->irq_was_asserted = asserted;
483 }
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 * sources; it seems to work with OpenBSD, NetBSD, and Linux, though.
656 *
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 DEVICE_ACCESS(dec21143)
817 {
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 | OPMODE_PS | OPMODE_SF | OPMODE_TTM | OPMODE_FD);
923 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 DEVINIT(dec21143)
978 {
979 struct dec21143_data *d;
980 char name2[100];
981
982 CHECK_ALLOCATION(d = malloc(sizeof(struct dec21143_data)));
983 memset(d, 0, sizeof(struct dec21143_data));
984
985 INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
986 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 dev_dec21143_tick, d, DEC21143_TICK_SHIFT);
1003
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