/[gxemul]/trunk/src/devices/dev_le.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_le.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: 22348 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) 2003-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_le.c,v 1.54 2006/12/31 21:35:26 debug Exp $
29 *
30 * LANCE ethernet, as used in DECstations.
31 *
32 * This is based on "PMAD-AA TURBOchannel Ethernet Module Functional
33 * Specification". I've tried to keep symbol names in this file to what
34 * the specs use.
35 *
36 * This is what the memory layout looks like on a DECstation 5000/200:
37 *
38 * 0x000000 - 0x0fffff Ethernet SRAM buffer (should be 128KB)
39 * 0x100000 - 0x17ffff LANCE registers
40 * 0x1c0000 - 0x1fffff Ethernet Diagnostic ROM and Station
41 * Address ROM
42 *
43 * The length of the device is set to 0x1c0200, however, because Sprite
44 * tries to read TURBOchannel rom data from 0x1c03f0, and that is provided
45 * by the turbochannel device, not this device.
46 *
47 *
48 * TODO: Error conditions (such as when there are not enough receive
49 * buffers) are not emulated yet.
50 *
51 * (Old bug, but probably still valid: "UDP packets that are too
52 * large are not handled well by the Lance device.")
53 */
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58
59 #include "cpu.h"
60 #include "devices.h"
61 #include "emul.h"
62 #include "machine.h"
63 #include "memory.h"
64 #include "misc.h"
65 #include "net.h"
66
67 #include "if_lereg.h"
68
69
70 #define LE_TICK_SHIFT 14
71
72 /* #define LE_DEBUG */
73 /* #define debug fatal */
74
75 extern int quiet_mode;
76
77 #define LE_MODE_LOOP 4
78 #define LE_MODE_DTX 2
79 #define LE_MODE_DRX 1
80
81
82 #define N_REGISTERS 4
83 #define SRAM_SIZE (128*1024)
84 #define ROM_SIZE 32
85
86
87 struct le_data {
88 struct interrupt irq;
89 int irq_asserted;
90
91 uint64_t buf_start;
92 uint64_t buf_end;
93 int len;
94
95 uint8_t rom[ROM_SIZE];
96
97 int reg_select;
98 uint16_t reg[N_REGISTERS];
99
100 unsigned char *sram;
101
102 /* Initialization block: */
103 uint32_t init_block_addr;
104
105 uint16_t mode;
106 uint64_t padr; /* MAC address */
107 uint64_t ladrf;
108 uint32_t rdra; /* receive descriptor ring address */
109 int rlen; /* nr of rx descriptors */
110 uint32_t tdra; /* transmit descriptor ring address */
111 int tlen; /* nr ot tx descriptors */
112
113 /* Current rx and tx descriptor indices: */
114 int rxp;
115 int txp;
116
117 unsigned char *tx_packet;
118 int tx_packet_len;
119
120 unsigned char *rx_packet;
121 int rx_packet_len;
122 int rx_packet_offset;
123 int rx_middle_bit;
124 };
125
126
127 /*
128 * le_read_16bit():
129 *
130 * Read a 16-bit word from the SRAM.
131 */
132 static uint64_t le_read_16bit(struct le_data *d, int addr)
133 {
134 /* TODO: This is for little endian only */
135 int x = d->sram[addr & (SRAM_SIZE-1)] +
136 (d->sram[(addr+1) & (SRAM_SIZE-1)] << 8);
137 return x;
138 }
139
140
141 /*
142 * le_write_16bit():
143 *
144 * Write a 16-bit word to the SRAM.
145 */
146 static void le_write_16bit(struct le_data *d, int addr, uint16_t x)
147 {
148 /* TODO: This is for little endian only */
149 d->sram[addr & (SRAM_SIZE-1)] = x & 0xff;
150 d->sram[(addr+1) & (SRAM_SIZE-1)] = (x >> 8) & 0xff;
151 }
152
153
154 /*
155 * le_chip_init():
156 *
157 * Initialize data structures by reading an 'initialization block' from the
158 * SRAM.
159 */
160 static void le_chip_init(struct le_data *d)
161 {
162 d->init_block_addr = (d->reg[1] & 0xffff) + ((d->reg[2] & 0xff) << 16);
163 if (d->init_block_addr & 1)
164 fatal("[ le: WARNING! initialization block address "
165 "not word aligned? ]\n");
166
167 debug("[ le: d->init_block_addr = 0x%06x ]\n", d->init_block_addr);
168
169 d->mode = le_read_16bit(d, d->init_block_addr + 0);
170 d->padr = le_read_16bit(d, d->init_block_addr + 2);
171 d->padr += (le_read_16bit(d, d->init_block_addr + 4) << 16);
172 d->padr += (le_read_16bit(d, d->init_block_addr + 6) << 32);
173 d->ladrf = le_read_16bit(d, d->init_block_addr + 8);
174 d->ladrf += (le_read_16bit(d, d->init_block_addr + 10) << 16);
175 d->ladrf += (le_read_16bit(d, d->init_block_addr + 12) << 32);
176 d->ladrf += (le_read_16bit(d, d->init_block_addr + 14) << 48);
177 d->rdra = le_read_16bit(d, d->init_block_addr + 16);
178 d->rdra += ((le_read_16bit(d, d->init_block_addr + 18) & 0xff) << 16);
179 d->rlen = 1 << ((le_read_16bit(d, d->init_block_addr + 18) >> 13) & 7);
180 d->tdra = le_read_16bit(d, d->init_block_addr + 20);
181 d->tdra += ((le_read_16bit(d, d->init_block_addr + 22) & 0xff) << 16);
182 d->tlen = 1 << ((le_read_16bit(d, d->init_block_addr + 22) >> 13) & 7);
183
184 debug("[ le: DEBUG: mode %04x ]\n", d->mode);
185 debug("[ le: DEBUG: padr %016llx ]\n", (long long)d->padr);
186 debug("[ le: DEBUG: ladrf %016llx ]\n", (long long)d->ladrf);
187 debug("[ le: DEBUG: rdra %06llx ]\n", d->rdra);
188 debug("[ le: DEBUG: rlen %3i ]\n", d->rlen);
189 debug("[ le: DEBUG: tdra %06llx ]\n", d->tdra);
190 debug("[ le: DEBUG: tlen %3i ]\n", d->tlen);
191
192 /* Set TXON and RXON, unless they are disabled by 'mode': */
193 if (d->mode & LE_MODE_DTX)
194 d->reg[0] &= ~LE_TXON;
195 else
196 d->reg[0] |= LE_TXON;
197
198 if (d->mode & LE_MODE_DRX)
199 d->reg[0] &= ~LE_RXON;
200 else
201 d->reg[0] |= LE_RXON;
202
203 /* Go to the start of the descriptor rings: */
204 d->rxp = d->txp = 0;
205
206 /* Set IDON and reset the INIT bit when we are done. */
207 d->reg[0] |= LE_IDON;
208 d->reg[0] &= ~LE_INIT;
209
210 /* Free any old packets: */
211 if (d->tx_packet != NULL)
212 free(d->tx_packet);
213 d->tx_packet = NULL;
214 d->tx_packet_len = 0;
215
216 if (d->rx_packet != NULL)
217 free(d->rx_packet);
218 d->rx_packet = NULL;
219 d->rx_packet_len = 0;
220 d->rx_packet_offset = 0;
221 d->rx_middle_bit = 0;
222 }
223
224
225 /*
226 * le_tx():
227 *
228 * Check the transmitter descriptor ring for buffers that are owned by the
229 * Lance chip (that is, buffers that are to be transmitted).
230 *
231 * This routine should only be called if TXON is enabled.
232 */
233 static void le_tx(struct net *net, struct le_data *d)
234 {
235 int start_txp = d->txp;
236 uint16_t tx_descr[4];
237 int stp, enp, cur_packet_offset;
238 size_t i;
239 uint32_t bufaddr, buflen;
240
241 /* TODO: This is just a guess: */
242 d->reg[0] &= ~LE_TDMD;
243
244 do {
245 /* Load the 8 descriptor bytes: */
246 tx_descr[0] = le_read_16bit(d, d->tdra + d->txp*8 + 0);
247 tx_descr[1] = le_read_16bit(d, d->tdra + d->txp*8 + 2);
248 tx_descr[2] = le_read_16bit(d, d->tdra + d->txp*8 + 4);
249 tx_descr[3] = le_read_16bit(d, d->tdra + d->txp*8 + 6);
250
251 bufaddr = tx_descr[0] + ((tx_descr[1] & 0xff) << 16);
252 stp = tx_descr[1] & LE_STP? 1 : 0;
253 enp = tx_descr[1] & LE_ENP? 1 : 0;
254 buflen = 4096 - (tx_descr[2] & 0xfff);
255
256 /*
257 * Check the OWN bit. If it is zero, then this buffer is
258 * not ready to be transmitted yet. Also check the '1111'
259 * mark, and make sure that byte-count is reasonable.
260 */
261 if (!(tx_descr[1] & LE_OWN))
262 return;
263 if ((tx_descr[2] & 0xf000) != 0xf000)
264 return;
265 if (buflen < 12 || buflen > 1900) {
266 fatal("[ le_tx(): buflen = %i ]\n", buflen);
267 return;
268 }
269
270 debug("[ le_tx(): descr %3i DUMP: 0x%04x 0x%04x 0x%04x 0x%04x "
271 "=> addr=0x%06x, len=%i bytes, STP=%i ENP=%i ]\n", d->txp,
272 tx_descr[0], tx_descr[1], tx_descr[2], tx_descr[3],
273 bufaddr, buflen, stp, enp);
274
275 if (d->tx_packet == NULL && !stp) {
276 fatal("[ le_tx(): !stp but tx_packet == NULL ]\n");
277 return;
278 }
279
280 if (d->tx_packet != NULL && stp) {
281 fatal("[ le_tx(): stp but tx_packet != NULL ]\n");
282 free(d->tx_packet);
283 d->tx_packet = NULL;
284 d->tx_packet_len = 0;
285 }
286
287 /* Where to write to in the tx_packet: */
288 cur_packet_offset = d->tx_packet_len;
289
290 /* Start of a new packet: */
291 if (stp) {
292 d->tx_packet_len = buflen;
293 d->tx_packet = malloc(buflen);
294 if (d->tx_packet == NULL) {
295 fprintf(stderr, "out of memory (1) in "
296 "le_tx()\n");
297 exit(1);
298 }
299 } else {
300 d->tx_packet_len += buflen;
301 d->tx_packet = realloc(d->tx_packet, d->tx_packet_len);
302 if (d->tx_packet == NULL) {
303 fprintf(stderr, "out of memory (2) in"
304 " le_tx()\n");
305 exit(1);
306 }
307 }
308
309 /* Copy data from SRAM into the tx packet: */
310 for (i=0; i<buflen; i++) {
311 unsigned char ch;
312 ch = d->sram[(bufaddr + i) & (SRAM_SIZE-1)];
313 d->tx_packet[cur_packet_offset + i] = ch;
314 }
315
316 /*
317 * Is this the last buffer in a packet? Then transmit
318 * it, cause an interrupt, and free the memory used by
319 * the packet.
320 */
321 if (enp) {
322 net_ethernet_tx(net, d, d->tx_packet, d->tx_packet_len);
323
324 free(d->tx_packet);
325 d->tx_packet = NULL;
326 d->tx_packet_len = 0;
327
328 d->reg[0] |= LE_TINT;
329 }
330
331 /* Clear the OWN bit: */
332 tx_descr[1] &= ~LE_OWN;
333
334 /* Write back the descriptor to SRAM: */
335 le_write_16bit(d, d->tdra + d->txp*8 + 2, tx_descr[1]);
336 le_write_16bit(d, d->tdra + d->txp*8 + 4, tx_descr[2]);
337 le_write_16bit(d, d->tdra + d->txp*8 + 6, tx_descr[3]);
338
339 /* Go to the next descriptor: */
340 d->txp ++;
341 if (d->txp >= d->tlen)
342 d->txp = 0;
343 } while (d->txp != start_txp);
344
345 /* We are here if all descriptors were taken care of. */
346 fatal("[ le_tx(): all TX descriptors used up? ]\n");
347 }
348
349
350 /*
351 * le_rx():
352 *
353 * This routine should only be called if RXON is enabled.
354 */
355 static void le_rx(struct net *net, struct le_data *d)
356 {
357 int start_rxp = d->rxp;
358 size_t i;
359 uint16_t rx_descr[4];
360 uint32_t bufaddr, buflen;
361
362 do {
363 if (d->rx_packet == NULL)
364 return;
365
366 /* Load the 8 descriptor bytes: */
367 rx_descr[0] = le_read_16bit(d, d->rdra + d->rxp*8 + 0);
368 rx_descr[1] = le_read_16bit(d, d->rdra + d->rxp*8 + 2);
369 rx_descr[2] = le_read_16bit(d, d->rdra + d->rxp*8 + 4);
370 rx_descr[3] = le_read_16bit(d, d->rdra + d->rxp*8 + 6);
371
372 bufaddr = rx_descr[0] + ((rx_descr[1] & 0xff) << 16);
373 buflen = 4096 - (rx_descr[2] & 0xfff);
374
375 /*
376 * Check the OWN bit. If it is zero, then this buffer is
377 * not ready to receive data yet. Also check the '1111'
378 * mark, and make sure that byte-count is reasonable.
379 */
380 if (!(rx_descr[1] & LE_OWN))
381 return;
382 if ((rx_descr[2] & 0xf000) != 0xf000)
383 return;
384 if (buflen < 12 || buflen > 1900) {
385 fatal("[ le_rx(): buflen = %i ]\n", buflen);
386 return;
387 }
388
389 debug("[ le_rx(): descr %3i DUMP: 0x%04x 0x%04x 0x%04x 0x%04x "
390 "=> addr=0x%06x, len=%i bytes ]\n", d->rxp,
391 rx_descr[0], rx_descr[1], rx_descr[2], rx_descr[3],
392 bufaddr, buflen);
393
394 /* Copy data from the packet into SRAM: */
395 for (i=0; i<buflen; i++) {
396 if (d->rx_packet_offset+(ssize_t)i >= d->rx_packet_len)
397 break;
398 d->sram[(bufaddr + i) & (SRAM_SIZE-1)] =
399 d->rx_packet[d->rx_packet_offset + i];
400 }
401
402 /* Here, i is the number of bytes copied. */
403 d->rx_packet_offset += i;
404
405 /* Set the ENP bit if this was the end of a packet: */
406 if (d->rx_packet_offset >= d->rx_packet_len) {
407 rx_descr[1] |= LE_ENP;
408
409 /*
410 * NOTE: The Lance documentation that I have read
411 * says _NOTHING_ about the length being 4 more than
412 * the length of the data. You can guess how
413 * surprised I was when I saw the following in
414 * NetBSD (dev/ic/am7990.c):
415 *
416 * lance_read(sc, LE_RBUFADDR(sc, bix),
417 * (int)rmd.rmd3 - 4);
418 */
419 rx_descr[3] &= ~0xfff;
420 rx_descr[3] |= d->rx_packet_len + 4;
421
422 free(d->rx_packet);
423 d->rx_packet = NULL;
424 d->rx_packet_len = 0;
425 d->rx_packet_offset = 0;
426 d->rx_middle_bit = 0;
427
428 d->reg[0] |= LE_RINT;
429 }
430
431 /* Set the STP bit if this was the start of a packet: */
432 if (!d->rx_middle_bit) {
433 rx_descr[1] |= LE_STP;
434
435 /* Are we continuing on this packet? */
436 if (d->rx_packet != NULL)
437 d->rx_middle_bit = 1;
438 }
439
440 /* Clear the OWN bit: */
441 rx_descr[1] &= ~LE_OWN;
442
443 /* Write back the descriptor to SRAM: */
444 le_write_16bit(d, d->rdra + d->rxp*8 + 2, rx_descr[1]);
445 le_write_16bit(d, d->rdra + d->rxp*8 + 4, rx_descr[2]);
446 le_write_16bit(d, d->rdra + d->rxp*8 + 6, rx_descr[3]);
447
448 /* Go to the next descriptor: */
449 d->rxp ++;
450 if (d->rxp >= d->rlen)
451 d->rxp = 0;
452 } while (d->rxp != start_rxp);
453
454 /* We are here if all descriptors were taken care of. */
455 fatal("[ le_rx(): all RX descriptors used up? ]\n");
456 }
457
458
459 /*
460 * le_register_fix():
461 */
462 static void le_register_fix(struct net *net, struct le_data *d)
463 {
464 /* Init with new Initialization block, if needed. */
465 if (d->reg[0] & LE_INIT)
466 le_chip_init(d);
467
468 #ifdef LE_DEBUG
469 {
470 static int x = 1234;
471 if (x != d->reg[0]) {
472 debug("[ le reg[0] = 0x%04x ]\n", d->reg[0]);
473 x = d->reg[0];
474 }
475 }
476 #endif
477
478 /*
479 * If the receiver is on:
480 * If there is a current rx_packet, try to receive it into the
481 * Lance buffers. Then try to receive any additional packets.
482 */
483 if (d->reg[0] & LE_RXON) {
484 do {
485 if (d->rx_packet != NULL)
486 /* Try to receive the packet: */
487 le_rx(net, d);
488
489 if (d->rx_packet != NULL)
490 /* If the packet wasn't fully received,
491 then abort for now. */
492 break;
493
494 if (d->rx_packet == NULL &&
495 net_ethernet_rx_avail(net, d))
496 net_ethernet_rx(net, d,
497 &d->rx_packet, &d->rx_packet_len);
498 } while (d->rx_packet != NULL);
499 }
500
501 /* If the transmitter is on, check for outgoing buffers: */
502 if (d->reg[0] & LE_TXON)
503 le_tx(net, d);
504
505 /* SERR should be the OR of BABL, CERR, MISS, and MERR: */
506 d->reg[0] &= ~LE_SERR;
507 if (d->reg[0] & (LE_BABL | LE_CERR | LE_MISS | LE_MERR))
508 d->reg[0] |= LE_SERR;
509
510 /* INTR should be the OR of BABL, MISS, MERR, RINT, TINT, IDON: */
511 d->reg[0] &= ~LE_INTR;
512 if (d->reg[0] & (LE_BABL | LE_MISS | LE_MERR | LE_RINT |
513 LE_TINT | LE_IDON))
514 d->reg[0] |= LE_INTR;
515
516 /* The MERR bit clears some bits: */
517 if (d->reg[0] & LE_MERR)
518 d->reg[0] &= ~(LE_RXON | LE_TXON);
519
520 /* The STOP bit clears a lot of stuff: */
521 #if 0
522 /* According to the LANCE manual: (doesn't work with Ultrix) */
523 if (d->reg[0] & LE_STOP)
524 d->reg[0] &= ~(LE_SERR | LE_BABL | LE_CERR | LE_MISS | LE_MERR
525 | LE_RINT | LE_TINT | LE_IDON | LE_INTR | LE_INEA
526 | LE_RXON | LE_TXON | LE_TDMD);
527 #else
528 /* Works with Ultrix: */
529 if (d->reg[0] & LE_STOP)
530 d->reg[0] &= ~(LE_IDON);
531 #endif
532 }
533
534
535 /*
536 * dev_le_tick():
537 */
538 void dev_le_tick(struct cpu *cpu, void *extra)
539 {
540 struct le_data *d = (struct le_data *) extra;
541 int new_assert;
542
543 le_register_fix(cpu->machine->emul->net, d);
544
545 new_assert = (d->reg[0] & LE_INTR) && (d->reg[0] & LE_INEA);
546 if (new_assert && !d->irq_asserted)
547 INTERRUPT_ASSERT(d->irq);
548 if (d->irq_asserted && !new_assert)
549 INTERRUPT_DEASSERT(d->irq);
550
551 d->irq_asserted = new_assert;
552 }
553
554
555 /*
556 * le_register_write():
557 *
558 * This function is called when the value 'x' is written to register 'r'.
559 */
560 void le_register_write(struct le_data *d, int r, uint32_t x)
561 {
562 switch (r) {
563 case 0: /* CSR0: */
564 /* Some bits are write-one-to-clear: */
565 if (x & LE_BABL)
566 d->reg[r] &= ~LE_BABL;
567 if (x & LE_CERR)
568 d->reg[r] &= ~LE_CERR;
569 if (x & LE_MISS)
570 d->reg[r] &= ~LE_MISS;
571 if (x & LE_MERR)
572 d->reg[r] &= ~LE_MERR;
573 if (x & LE_RINT)
574 d->reg[r] &= ~LE_RINT;
575 if (x & LE_TINT)
576 d->reg[r] &= ~LE_TINT;
577 if (x & LE_IDON)
578 d->reg[r] &= ~LE_IDON;
579
580 /* Some bits are write-only settable, not clearable: */
581 if (x & LE_TDMD)
582 d->reg[r] |= LE_TDMD;
583 if (x & LE_STRT) {
584 d->reg[r] |= LE_STRT;
585 d->reg[r] &= ~LE_STOP;
586 }
587 if (x & LE_INIT) {
588 if (!(d->reg[r] & LE_STOP))
589 fatal("[ le: attempt to INIT before"
590 " STOPped! ]\n");
591 d->reg[r] |= LE_INIT;
592 d->reg[r] &= ~LE_STOP;
593 }
594 if (x & LE_STOP) {
595 d->reg[r] |= LE_STOP;
596 /* STOP takes precedence over STRT and INIT: */
597 d->reg[r] &= ~(LE_STRT | LE_INIT);
598 }
599
600 /* Some bits get through, both settable and clearable: */
601 d->reg[r] &= ~LE_INEA;
602 d->reg[r] |= (x & LE_INEA);
603 break;
604
605 default:
606 /* CSR1, CSR2, and CSR3: */
607 d->reg[r] = x;
608 }
609 }
610
611
612 DEVICE_ACCESS(le_sram)
613 {
614 size_t i;
615 int retval;
616 struct le_data *d = extra;
617
618 #ifdef LE_DEBUG
619 if (writeflag == MEM_WRITE) {
620 fatal("[ le_sram: write to addr 0x%06x: ", (int)relative_addr);
621 for (i=0; i<len; i++)
622 fatal("%02x ", data[i]);
623 fatal("]\n");
624 }
625 #endif
626
627 /* Read/write of the SRAM: */
628 if (relative_addr < SRAM_SIZE && relative_addr + len <= SRAM_SIZE) {
629 if (writeflag == MEM_READ) {
630 memcpy(data, d->sram + relative_addr, len);
631 if (!quiet_mode) {
632 debug("[ le: read from SRAM offset 0x%05x:",
633 relative_addr);
634 for (i=0; i<len; i++)
635 debug(" %02x", data[i]);
636 debug(" ]\n");
637 }
638 retval = 9; /* 9 cycles */
639 } else {
640 memcpy(d->sram + relative_addr, data, len);
641 if (!quiet_mode) {
642 debug("[ le: write to SRAM offset 0x%05x:",
643 relative_addr);
644 for (i=0; i<len; i++)
645 debug(" %02x", data[i]);
646 debug(" ]\n");
647 }
648 retval = 6; /* 6 cycles */
649 }
650 return retval;
651 }
652
653 return 0;
654 }
655
656
657 DEVICE_ACCESS(le)
658 {
659 uint64_t idata = 0, odata = 0;
660 size_t i;
661 int retval = 1;
662 struct le_data *d = extra;
663
664 if (writeflag == MEM_WRITE)
665 idata = memory_readmax64(cpu, data, len);
666
667 #ifdef LE_DEBUG
668 if (writeflag == MEM_WRITE) {
669 fatal("[ le: write to addr 0x%06x: ", (int)relative_addr);
670 for (i=0; i<len; i++)
671 fatal("%02x ", data[i]);
672 fatal("]\n");
673 }
674 #endif
675
676 /* Read from station's ROM (ethernet address): */
677 if (relative_addr >= 0xc0000 && relative_addr <= 0xfffff) {
678 uint32_t a;
679 int j = (relative_addr & 0xff) / 4;
680 a = d->rom[j & (ROM_SIZE-1)];
681
682 if (writeflag == MEM_READ) {
683 odata = (a << 24) + (a << 16) + (a << 8) + a;
684 } else {
685 fatal("[ le: WRITE to ethernet addr (%08lx):",
686 (long)relative_addr);
687 for (i=0; i<len; i++)
688 fatal(" %02x", data[i]);
689 fatal(" ]\n");
690 }
691
692 retval = 13; /* 13 cycles */
693 goto do_return;
694 }
695
696
697 switch (relative_addr) {
698
699 /* Register read/write: */
700 case 0:
701 if (writeflag==MEM_READ) {
702 odata = d->reg[d->reg_select];
703 if (!quiet_mode)
704 debug("[ le: read from register 0x%02x: 0x"
705 "%02x ]\n", d->reg_select, (int)odata);
706 /*
707 * A read from csr1..3 should return "undefined"
708 * result if the stop bit is set. However, Ultrix
709 * seems to do just that, so let's _not_ print
710 * a warning here.
711 */
712 } else {
713 if (!quiet_mode)
714 debug("[ le: write to register 0x%02x: 0x"
715 "%02x ]\n", d->reg_select, (int)idata);
716 /*
717 * A write to from csr1..3 when the stop bit is
718 * set should be ignored. However, Ultrix writes
719 * even if the stop bit is set, so let's _not_
720 * print a warning about it.
721 */
722 le_register_write(d, d->reg_select, idata);
723 }
724 break;
725
726 /* Register select: */
727 case 4:
728 if (writeflag==MEM_READ) {
729 odata = d->reg_select;
730 if (!quiet_mode)
731 debug("[ le: read from register select: "
732 "0x%02x ]\n", (int)odata);
733 } else {
734 if (!quiet_mode)
735 debug("[ le: write to register select: "
736 "0x%02x ]\n", (int)idata);
737 d->reg_select = idata & (N_REGISTERS - 1);
738 if (idata >= N_REGISTERS)
739 fatal("[ le: WARNING! register select %i "
740 "(max is %i) ]\n", idata, N_REGISTERS - 1);
741 }
742 break;
743
744 default:
745 if (writeflag==MEM_READ) {
746 fatal("[ le: read from UNIMPLEMENTED addr 0x%06x ]\n",
747 (int)relative_addr);
748 } else {
749 fatal("[ le: write to UNIMPLEMENTED addr 0x%06x: "
750 "0x%08x ]\n", (int)relative_addr, (int)idata);
751 }
752 }
753
754 do_return:
755 if (writeflag == MEM_READ) {
756 memory_writemax64(cpu, data, len, odata);
757 #ifdef LE_DEBUG
758 fatal("[ le: read from addr 0x%06x: 0x%08x ]\n",
759 relative_addr, odata);
760 #endif
761 }
762
763 dev_le_tick(cpu, extra);
764
765 return retval;
766 }
767
768
769 /*
770 * dev_le_init():
771 */
772 void dev_le_init(struct machine *machine, struct memory *mem, uint64_t baseaddr,
773 uint64_t buf_start, uint64_t buf_end, char *irq_path, int len)
774 {
775 char *name2;
776 size_t nlen = 55;
777 struct le_data *d = malloc(sizeof(struct le_data));
778
779 if (d == NULL) {
780 fprintf(stderr, "out of memory\n");
781 exit(1);
782 }
783
784 memset(d, 0, sizeof(struct le_data));
785
786 INTERRUPT_CONNECT(irq_path, d->irq);
787
788 d->sram = malloc(SRAM_SIZE);
789 if (d->sram == NULL) {
790 fprintf(stderr, "out of memory\n");
791 exit(1);
792 }
793 memset(d->sram, 0, SRAM_SIZE);
794
795 /* TODO: Are these actually used yet? */
796 d->len = len;
797 d->buf_start = buf_start;
798 d->buf_end = buf_end;
799
800 /* Initial register contents: */
801 d->reg[0] = LE_STOP;
802
803 d->tx_packet = NULL;
804 d->rx_packet = NULL;
805
806 /* ROM (including the MAC address): */
807 net_generate_unique_mac(machine, &d->rom[0]);
808
809 /* Copies of the MAC address and a test pattern: */
810 d->rom[10] = d->rom[21] = d->rom[5];
811 d->rom[11] = d->rom[20] = d->rom[4];
812 d->rom[12] = d->rom[19] = d->rom[3];
813 d->rom[7] = d->rom[8] = d->rom[23] =
814 d->rom[13] = d->rom[18] = d->rom[2];
815 d->rom[6] = d->rom[9] = d->rom[22] =
816 d->rom[14] = d->rom[17] = d->rom[1];
817 d->rom[15] = d->rom[16] = d->rom[0];
818 d->rom[24] = d->rom[28] = 0xff;
819 d->rom[25] = d->rom[29] = 0x00;
820 d->rom[26] = d->rom[30] = 0x55;
821 d->rom[27] = d->rom[31] = 0xaa;
822
823 memory_device_register(mem, "le_sram", baseaddr,
824 SRAM_SIZE, dev_le_sram_access, (void *)d,
825 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK
826 | DM_READS_HAVE_NO_SIDE_EFFECTS, d->sram);
827
828 name2 = malloc(nlen);
829 if (name2 == NULL) {
830 fprintf(stderr, "out of memory in dev_le_init()\n");
831 exit(1);
832 }
833 snprintf(name2, nlen, "le [%02x:%02x:%02x:%02x:%02x:%02x]",
834 d->rom[0], d->rom[1], d->rom[2], d->rom[3], d->rom[4], d->rom[5]);
835
836 memory_device_register(mem, name2, baseaddr + 0x100000,
837 len - 0x100000, dev_le_access, (void *)d, DM_DEFAULT, NULL);
838
839 machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT, 0.0);
840
841 net_add_nic(machine->emul->net, d, &d->rom[0]);
842 }
843

  ViewVC Help
Powered by ViewVC 1.1.26