/[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 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22182 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26