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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 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 dpavlin 4 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 4 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 34 * $Id: dev_le.c,v 1.54 2006/12/31 21:35:26 debug Exp $
29 dpavlin 4 *
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 dpavlin 22 *
51     * (Old bug, but probably still valid: "UDP packets that are too
52     * large are not handled well by the Lance device.")
53 dpavlin 4 */
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 dpavlin 34 struct interrupt irq;
89     int irq_asserted;
90 dpavlin 4
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 dpavlin 12 unsigned char *sram;
101 dpavlin 4
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 dpavlin 22 int stp, enp, cur_packet_offset;
238     size_t i;
239 dpavlin 4 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 dpavlin 22 int start_rxp = d->rxp;
358     size_t i;
359 dpavlin 4 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 dpavlin 22 if (d->rx_packet_offset+(ssize_t)i >= d->rx_packet_len)
397 dpavlin 4 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 dpavlin 34 int new_assert;
542 dpavlin 4
543     le_register_fix(cpu->machine->emul->net, d);
544    
545 dpavlin 34 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 dpavlin 4 }
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 dpavlin 22 DEVICE_ACCESS(le_sram)
613 dpavlin 4 {
614 dpavlin 22 size_t i;
615     int retval;
616 dpavlin 4 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 dpavlin 22 DEVICE_ACCESS(le)
658 dpavlin 4 {
659     uint64_t idata = 0, odata = 0;
660 dpavlin 22 size_t i;
661     int retval = 1;
662 dpavlin 4 struct le_data *d = extra;
663    
664 dpavlin 18 if (writeflag == MEM_WRITE)
665     idata = memory_readmax64(cpu, data, len);
666 dpavlin 4
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 dpavlin 22 uint32_t a;
679     int j = (relative_addr & 0xff) / 4;
680     a = d->rom[j & (ROM_SIZE-1)];
681 dpavlin 4
682     if (writeflag == MEM_READ) {
683 dpavlin 22 odata = (a << 24) + (a << 16) + (a << 8) + a;
684 dpavlin 4 } 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 dpavlin 34 uint64_t buf_start, uint64_t buf_end, char *irq_path, int len)
774 dpavlin 4 {
775     char *name2;
776 dpavlin 10 size_t nlen = 55;
777 dpavlin 4 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 dpavlin 34 INTERRUPT_CONNECT(irq_path, d->irq);
787    
788 dpavlin 12 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 dpavlin 4 /* 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 dpavlin 20 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK
826     | DM_READS_HAVE_NO_SIDE_EFFECTS, d->sram);
827 dpavlin 4
828 dpavlin 10 name2 = malloc(nlen);
829 dpavlin 4 if (name2 == NULL) {
830     fprintf(stderr, "out of memory in dev_le_init()\n");
831     exit(1);
832     }
833 dpavlin 10 snprintf(name2, nlen, "le [%02x:%02x:%02x:%02x:%02x:%02x]",
834 dpavlin 4 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 dpavlin 20 len - 0x100000, dev_le_access, (void *)d, DM_DEFAULT, NULL);
838 dpavlin 4
839 dpavlin 24 machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT, 0.0);
840 dpavlin 4
841     net_add_nic(machine->emul->net, d, &d->rom[0]);
842     }
843    

  ViewVC Help
Powered by ViewVC 1.1.26