/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 21909 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


1 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 42 * $Id: dev_le.c,v 1.56 2007/06/15 19:11:15 debug Exp $
29 dpavlin 4 *
30 dpavlin 42 * COMMENT: LANCE ethernet, as used in DECstations
31 dpavlin 4 *
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 dpavlin 42 CHECK_ALLOCATION(d->tx_packet = malloc(buflen));
294 dpavlin 4 } else {
295     d->tx_packet_len += buflen;
296 dpavlin 42 CHECK_ALLOCATION(d->tx_packet =
297     realloc(d->tx_packet, d->tx_packet_len));
298 dpavlin 4 }
299    
300     /* Copy data from SRAM into the tx packet: */
301     for (i=0; i<buflen; i++) {
302     unsigned char ch;
303     ch = d->sram[(bufaddr + i) & (SRAM_SIZE-1)];
304     d->tx_packet[cur_packet_offset + i] = ch;
305     }
306    
307     /*
308     * Is this the last buffer in a packet? Then transmit
309     * it, cause an interrupt, and free the memory used by
310     * the packet.
311     */
312     if (enp) {
313     net_ethernet_tx(net, d, d->tx_packet, d->tx_packet_len);
314    
315     free(d->tx_packet);
316     d->tx_packet = NULL;
317     d->tx_packet_len = 0;
318    
319     d->reg[0] |= LE_TINT;
320     }
321    
322     /* Clear the OWN bit: */
323     tx_descr[1] &= ~LE_OWN;
324    
325     /* Write back the descriptor to SRAM: */
326     le_write_16bit(d, d->tdra + d->txp*8 + 2, tx_descr[1]);
327     le_write_16bit(d, d->tdra + d->txp*8 + 4, tx_descr[2]);
328     le_write_16bit(d, d->tdra + d->txp*8 + 6, tx_descr[3]);
329    
330     /* Go to the next descriptor: */
331     d->txp ++;
332     if (d->txp >= d->tlen)
333     d->txp = 0;
334     } while (d->txp != start_txp);
335    
336     /* We are here if all descriptors were taken care of. */
337     fatal("[ le_tx(): all TX descriptors used up? ]\n");
338     }
339    
340    
341     /*
342     * le_rx():
343     *
344     * This routine should only be called if RXON is enabled.
345     */
346     static void le_rx(struct net *net, struct le_data *d)
347     {
348 dpavlin 22 int start_rxp = d->rxp;
349     size_t i;
350 dpavlin 4 uint16_t rx_descr[4];
351     uint32_t bufaddr, buflen;
352    
353     do {
354     if (d->rx_packet == NULL)
355     return;
356    
357     /* Load the 8 descriptor bytes: */
358     rx_descr[0] = le_read_16bit(d, d->rdra + d->rxp*8 + 0);
359     rx_descr[1] = le_read_16bit(d, d->rdra + d->rxp*8 + 2);
360     rx_descr[2] = le_read_16bit(d, d->rdra + d->rxp*8 + 4);
361     rx_descr[3] = le_read_16bit(d, d->rdra + d->rxp*8 + 6);
362    
363     bufaddr = rx_descr[0] + ((rx_descr[1] & 0xff) << 16);
364     buflen = 4096 - (rx_descr[2] & 0xfff);
365    
366     /*
367     * Check the OWN bit. If it is zero, then this buffer is
368     * not ready to receive data yet. Also check the '1111'
369     * mark, and make sure that byte-count is reasonable.
370     */
371     if (!(rx_descr[1] & LE_OWN))
372     return;
373     if ((rx_descr[2] & 0xf000) != 0xf000)
374     return;
375     if (buflen < 12 || buflen > 1900) {
376     fatal("[ le_rx(): buflen = %i ]\n", buflen);
377     return;
378     }
379    
380     debug("[ le_rx(): descr %3i DUMP: 0x%04x 0x%04x 0x%04x 0x%04x "
381     "=> addr=0x%06x, len=%i bytes ]\n", d->rxp,
382     rx_descr[0], rx_descr[1], rx_descr[2], rx_descr[3],
383     bufaddr, buflen);
384    
385     /* Copy data from the packet into SRAM: */
386     for (i=0; i<buflen; i++) {
387 dpavlin 22 if (d->rx_packet_offset+(ssize_t)i >= d->rx_packet_len)
388 dpavlin 4 break;
389     d->sram[(bufaddr + i) & (SRAM_SIZE-1)] =
390     d->rx_packet[d->rx_packet_offset + i];
391     }
392    
393     /* Here, i is the number of bytes copied. */
394     d->rx_packet_offset += i;
395    
396     /* Set the ENP bit if this was the end of a packet: */
397     if (d->rx_packet_offset >= d->rx_packet_len) {
398     rx_descr[1] |= LE_ENP;
399    
400     /*
401     * NOTE: The Lance documentation that I have read
402     * says _NOTHING_ about the length being 4 more than
403     * the length of the data. You can guess how
404     * surprised I was when I saw the following in
405     * NetBSD (dev/ic/am7990.c):
406     *
407     * lance_read(sc, LE_RBUFADDR(sc, bix),
408     * (int)rmd.rmd3 - 4);
409     */
410     rx_descr[3] &= ~0xfff;
411     rx_descr[3] |= d->rx_packet_len + 4;
412    
413     free(d->rx_packet);
414     d->rx_packet = NULL;
415     d->rx_packet_len = 0;
416     d->rx_packet_offset = 0;
417     d->rx_middle_bit = 0;
418    
419     d->reg[0] |= LE_RINT;
420     }
421    
422     /* Set the STP bit if this was the start of a packet: */
423     if (!d->rx_middle_bit) {
424     rx_descr[1] |= LE_STP;
425    
426     /* Are we continuing on this packet? */
427     if (d->rx_packet != NULL)
428     d->rx_middle_bit = 1;
429     }
430    
431     /* Clear the OWN bit: */
432     rx_descr[1] &= ~LE_OWN;
433    
434     /* Write back the descriptor to SRAM: */
435     le_write_16bit(d, d->rdra + d->rxp*8 + 2, rx_descr[1]);
436     le_write_16bit(d, d->rdra + d->rxp*8 + 4, rx_descr[2]);
437     le_write_16bit(d, d->rdra + d->rxp*8 + 6, rx_descr[3]);
438    
439     /* Go to the next descriptor: */
440     d->rxp ++;
441     if (d->rxp >= d->rlen)
442     d->rxp = 0;
443     } while (d->rxp != start_rxp);
444    
445     /* We are here if all descriptors were taken care of. */
446     fatal("[ le_rx(): all RX descriptors used up? ]\n");
447     }
448    
449    
450     /*
451     * le_register_fix():
452     */
453     static void le_register_fix(struct net *net, struct le_data *d)
454     {
455     /* Init with new Initialization block, if needed. */
456     if (d->reg[0] & LE_INIT)
457     le_chip_init(d);
458    
459     #ifdef LE_DEBUG
460     {
461     static int x = 1234;
462     if (x != d->reg[0]) {
463     debug("[ le reg[0] = 0x%04x ]\n", d->reg[0]);
464     x = d->reg[0];
465     }
466     }
467     #endif
468    
469     /*
470     * If the receiver is on:
471     * If there is a current rx_packet, try to receive it into the
472     * Lance buffers. Then try to receive any additional packets.
473     */
474     if (d->reg[0] & LE_RXON) {
475     do {
476     if (d->rx_packet != NULL)
477     /* Try to receive the packet: */
478     le_rx(net, d);
479    
480     if (d->rx_packet != NULL)
481     /* If the packet wasn't fully received,
482     then abort for now. */
483     break;
484    
485     if (d->rx_packet == NULL &&
486     net_ethernet_rx_avail(net, d))
487     net_ethernet_rx(net, d,
488     &d->rx_packet, &d->rx_packet_len);
489     } while (d->rx_packet != NULL);
490     }
491    
492     /* If the transmitter is on, check for outgoing buffers: */
493     if (d->reg[0] & LE_TXON)
494     le_tx(net, d);
495    
496     /* SERR should be the OR of BABL, CERR, MISS, and MERR: */
497     d->reg[0] &= ~LE_SERR;
498     if (d->reg[0] & (LE_BABL | LE_CERR | LE_MISS | LE_MERR))
499     d->reg[0] |= LE_SERR;
500    
501     /* INTR should be the OR of BABL, MISS, MERR, RINT, TINT, IDON: */
502     d->reg[0] &= ~LE_INTR;
503     if (d->reg[0] & (LE_BABL | LE_MISS | LE_MERR | LE_RINT |
504     LE_TINT | LE_IDON))
505     d->reg[0] |= LE_INTR;
506    
507     /* The MERR bit clears some bits: */
508     if (d->reg[0] & LE_MERR)
509     d->reg[0] &= ~(LE_RXON | LE_TXON);
510    
511     /* The STOP bit clears a lot of stuff: */
512     #if 0
513     /* According to the LANCE manual: (doesn't work with Ultrix) */
514     if (d->reg[0] & LE_STOP)
515     d->reg[0] &= ~(LE_SERR | LE_BABL | LE_CERR | LE_MISS | LE_MERR
516     | LE_RINT | LE_TINT | LE_IDON | LE_INTR | LE_INEA
517     | LE_RXON | LE_TXON | LE_TDMD);
518     #else
519     /* Works with Ultrix: */
520     if (d->reg[0] & LE_STOP)
521     d->reg[0] &= ~(LE_IDON);
522     #endif
523     }
524    
525    
526 dpavlin 42 DEVICE_TICK(le)
527 dpavlin 4 {
528 dpavlin 42 struct le_data *d = extra;
529 dpavlin 34 int new_assert;
530 dpavlin 4
531     le_register_fix(cpu->machine->emul->net, d);
532    
533 dpavlin 34 new_assert = (d->reg[0] & LE_INTR) && (d->reg[0] & LE_INEA);
534 dpavlin 42
535 dpavlin 34 if (new_assert && !d->irq_asserted)
536     INTERRUPT_ASSERT(d->irq);
537     if (d->irq_asserted && !new_assert)
538     INTERRUPT_DEASSERT(d->irq);
539    
540     d->irq_asserted = new_assert;
541 dpavlin 4 }
542    
543    
544     /*
545     * le_register_write():
546     *
547     * This function is called when the value 'x' is written to register 'r'.
548     */
549     void le_register_write(struct le_data *d, int r, uint32_t x)
550     {
551     switch (r) {
552     case 0: /* CSR0: */
553     /* Some bits are write-one-to-clear: */
554     if (x & LE_BABL)
555     d->reg[r] &= ~LE_BABL;
556     if (x & LE_CERR)
557     d->reg[r] &= ~LE_CERR;
558     if (x & LE_MISS)
559     d->reg[r] &= ~LE_MISS;
560     if (x & LE_MERR)
561     d->reg[r] &= ~LE_MERR;
562     if (x & LE_RINT)
563     d->reg[r] &= ~LE_RINT;
564     if (x & LE_TINT)
565     d->reg[r] &= ~LE_TINT;
566     if (x & LE_IDON)
567     d->reg[r] &= ~LE_IDON;
568    
569     /* Some bits are write-only settable, not clearable: */
570     if (x & LE_TDMD)
571     d->reg[r] |= LE_TDMD;
572     if (x & LE_STRT) {
573     d->reg[r] |= LE_STRT;
574     d->reg[r] &= ~LE_STOP;
575     }
576     if (x & LE_INIT) {
577     if (!(d->reg[r] & LE_STOP))
578     fatal("[ le: attempt to INIT before"
579     " STOPped! ]\n");
580     d->reg[r] |= LE_INIT;
581     d->reg[r] &= ~LE_STOP;
582     }
583     if (x & LE_STOP) {
584     d->reg[r] |= LE_STOP;
585     /* STOP takes precedence over STRT and INIT: */
586     d->reg[r] &= ~(LE_STRT | LE_INIT);
587     }
588    
589     /* Some bits get through, both settable and clearable: */
590     d->reg[r] &= ~LE_INEA;
591     d->reg[r] |= (x & LE_INEA);
592     break;
593    
594     default:
595     /* CSR1, CSR2, and CSR3: */
596     d->reg[r] = x;
597     }
598     }
599    
600    
601 dpavlin 22 DEVICE_ACCESS(le_sram)
602 dpavlin 4 {
603 dpavlin 42 struct le_data *d = extra;
604 dpavlin 22 size_t i;
605     int retval;
606 dpavlin 4
607     #ifdef LE_DEBUG
608     if (writeflag == MEM_WRITE) {
609     fatal("[ le_sram: write to addr 0x%06x: ", (int)relative_addr);
610     for (i=0; i<len; i++)
611     fatal("%02x ", data[i]);
612     fatal("]\n");
613     }
614     #endif
615    
616     /* Read/write of the SRAM: */
617     if (relative_addr < SRAM_SIZE && relative_addr + len <= SRAM_SIZE) {
618     if (writeflag == MEM_READ) {
619     memcpy(data, d->sram + relative_addr, len);
620     if (!quiet_mode) {
621     debug("[ le: read from SRAM offset 0x%05x:",
622     relative_addr);
623     for (i=0; i<len; i++)
624     debug(" %02x", data[i]);
625     debug(" ]\n");
626     }
627     retval = 9; /* 9 cycles */
628     } else {
629     memcpy(d->sram + relative_addr, data, len);
630     if (!quiet_mode) {
631     debug("[ le: write to SRAM offset 0x%05x:",
632     relative_addr);
633     for (i=0; i<len; i++)
634     debug(" %02x", data[i]);
635     debug(" ]\n");
636     }
637     retval = 6; /* 6 cycles */
638     }
639     return retval;
640     }
641    
642     return 0;
643     }
644    
645    
646 dpavlin 22 DEVICE_ACCESS(le)
647 dpavlin 4 {
648 dpavlin 42 struct le_data *d = extra;
649 dpavlin 4 uint64_t idata = 0, odata = 0;
650 dpavlin 42 int retval = 1;
651 dpavlin 22 size_t i;
652 dpavlin 4
653 dpavlin 18 if (writeflag == MEM_WRITE)
654     idata = memory_readmax64(cpu, data, len);
655 dpavlin 4
656     #ifdef LE_DEBUG
657     if (writeflag == MEM_WRITE) {
658     fatal("[ le: write to addr 0x%06x: ", (int)relative_addr);
659     for (i=0; i<len; i++)
660     fatal("%02x ", data[i]);
661     fatal("]\n");
662     }
663     #endif
664    
665     /* Read from station's ROM (ethernet address): */
666     if (relative_addr >= 0xc0000 && relative_addr <= 0xfffff) {
667 dpavlin 22 uint32_t a;
668     int j = (relative_addr & 0xff) / 4;
669     a = d->rom[j & (ROM_SIZE-1)];
670 dpavlin 4
671     if (writeflag == MEM_READ) {
672 dpavlin 22 odata = (a << 24) + (a << 16) + (a << 8) + a;
673 dpavlin 4 } else {
674     fatal("[ le: WRITE to ethernet addr (%08lx):",
675     (long)relative_addr);
676     for (i=0; i<len; i++)
677     fatal(" %02x", data[i]);
678     fatal(" ]\n");
679     }
680    
681     retval = 13; /* 13 cycles */
682     goto do_return;
683     }
684    
685    
686     switch (relative_addr) {
687    
688     /* Register read/write: */
689     case 0:
690     if (writeflag==MEM_READ) {
691     odata = d->reg[d->reg_select];
692     if (!quiet_mode)
693     debug("[ le: read from register 0x%02x: 0x"
694     "%02x ]\n", d->reg_select, (int)odata);
695     /*
696     * A read from csr1..3 should return "undefined"
697     * result if the stop bit is set. However, Ultrix
698     * seems to do just that, so let's _not_ print
699     * a warning here.
700     */
701     } else {
702     if (!quiet_mode)
703     debug("[ le: write to register 0x%02x: 0x"
704     "%02x ]\n", d->reg_select, (int)idata);
705     /*
706     * A write to from csr1..3 when the stop bit is
707     * set should be ignored. However, Ultrix writes
708     * even if the stop bit is set, so let's _not_
709     * print a warning about it.
710     */
711     le_register_write(d, d->reg_select, idata);
712     }
713     break;
714    
715     /* Register select: */
716     case 4:
717     if (writeflag==MEM_READ) {
718     odata = d->reg_select;
719     if (!quiet_mode)
720     debug("[ le: read from register select: "
721     "0x%02x ]\n", (int)odata);
722     } else {
723     if (!quiet_mode)
724     debug("[ le: write to register select: "
725     "0x%02x ]\n", (int)idata);
726     d->reg_select = idata & (N_REGISTERS - 1);
727     if (idata >= N_REGISTERS)
728     fatal("[ le: WARNING! register select %i "
729     "(max is %i) ]\n", idata, N_REGISTERS - 1);
730     }
731     break;
732    
733     default:
734     if (writeflag==MEM_READ) {
735     fatal("[ le: read from UNIMPLEMENTED addr 0x%06x ]\n",
736     (int)relative_addr);
737     } else {
738     fatal("[ le: write to UNIMPLEMENTED addr 0x%06x: "
739     "0x%08x ]\n", (int)relative_addr, (int)idata);
740     }
741     }
742    
743     do_return:
744     if (writeflag == MEM_READ) {
745     memory_writemax64(cpu, data, len, odata);
746     #ifdef LE_DEBUG
747     fatal("[ le: read from addr 0x%06x: 0x%08x ]\n",
748     relative_addr, odata);
749     #endif
750     }
751    
752     dev_le_tick(cpu, extra);
753    
754     return retval;
755     }
756    
757    
758     /*
759     * dev_le_init():
760     */
761     void dev_le_init(struct machine *machine, struct memory *mem, uint64_t baseaddr,
762 dpavlin 34 uint64_t buf_start, uint64_t buf_end, char *irq_path, int len)
763 dpavlin 4 {
764     char *name2;
765 dpavlin 10 size_t nlen = 55;
766 dpavlin 42 struct le_data *d;
767 dpavlin 4
768 dpavlin 42 CHECK_ALLOCATION(d = malloc(sizeof(struct le_data)));
769 dpavlin 4 memset(d, 0, sizeof(struct le_data));
770    
771 dpavlin 34 INTERRUPT_CONNECT(irq_path, d->irq);
772    
773 dpavlin 42 CHECK_ALLOCATION(d->sram = malloc(SRAM_SIZE));
774 dpavlin 12 memset(d->sram, 0, SRAM_SIZE);
775    
776 dpavlin 4 /* TODO: Are these actually used yet? */
777     d->len = len;
778     d->buf_start = buf_start;
779     d->buf_end = buf_end;
780    
781     /* Initial register contents: */
782     d->reg[0] = LE_STOP;
783    
784     d->tx_packet = NULL;
785     d->rx_packet = NULL;
786    
787     /* ROM (including the MAC address): */
788     net_generate_unique_mac(machine, &d->rom[0]);
789    
790     /* Copies of the MAC address and a test pattern: */
791     d->rom[10] = d->rom[21] = d->rom[5];
792     d->rom[11] = d->rom[20] = d->rom[4];
793     d->rom[12] = d->rom[19] = d->rom[3];
794     d->rom[7] = d->rom[8] = d->rom[23] =
795     d->rom[13] = d->rom[18] = d->rom[2];
796     d->rom[6] = d->rom[9] = d->rom[22] =
797     d->rom[14] = d->rom[17] = d->rom[1];
798     d->rom[15] = d->rom[16] = d->rom[0];
799     d->rom[24] = d->rom[28] = 0xff;
800     d->rom[25] = d->rom[29] = 0x00;
801     d->rom[26] = d->rom[30] = 0x55;
802     d->rom[27] = d->rom[31] = 0xaa;
803    
804     memory_device_register(mem, "le_sram", baseaddr,
805     SRAM_SIZE, dev_le_sram_access, (void *)d,
806 dpavlin 20 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK
807     | DM_READS_HAVE_NO_SIDE_EFFECTS, d->sram);
808 dpavlin 4
809 dpavlin 42 CHECK_ALLOCATION(name2 = malloc(nlen));
810 dpavlin 10 snprintf(name2, nlen, "le [%02x:%02x:%02x:%02x:%02x:%02x]",
811 dpavlin 4 d->rom[0], d->rom[1], d->rom[2], d->rom[3], d->rom[4], d->rom[5]);
812    
813     memory_device_register(mem, name2, baseaddr + 0x100000,
814 dpavlin 20 len - 0x100000, dev_le_access, (void *)d, DM_DEFAULT, NULL);
815 dpavlin 4
816 dpavlin 42 machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT);
817 dpavlin 4
818     net_add_nic(machine->emul->net, d, &d->rom[0]);
819     }
820    

  ViewVC Help
Powered by ViewVC 1.1.26