/[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 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22359 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26