/[gxemul]/trunk/src/devices/dev_le.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show 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 /*
2 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_le.c,v 1.56 2007/06/15 19:11:15 debug Exp $
29 *
30 * COMMENT: LANCE ethernet, as used in DECstations
31 *
32 * This is based on "PMAD-AA TURBOchannel Ethernet Module Functional
33 * Specification". I've tried to keep symbol names in this file to what
34 * the specs use.
35 *
36 * This is what the memory layout looks like on a DECstation 5000/200:
37 *
38 * 0x000000 - 0x0fffff Ethernet SRAM buffer (should be 128KB)
39 * 0x100000 - 0x17ffff LANCE registers
40 * 0x1c0000 - 0x1fffff Ethernet Diagnostic ROM and Station
41 * Address ROM
42 *
43 * The length of the device is set to 0x1c0200, however, because Sprite
44 * tries to read TURBOchannel rom data from 0x1c03f0, and that is provided
45 * by the turbochannel device, not this device.
46 *
47 *
48 * TODO: Error conditions (such as when there are not enough receive
49 * buffers) are not emulated yet.
50 *
51 * (Old bug, but probably still valid: "UDP packets that are too
52 * large are not handled well by the Lance device.")
53 */
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58
59 #include "cpu.h"
60 #include "devices.h"
61 #include "emul.h"
62 #include "machine.h"
63 #include "memory.h"
64 #include "misc.h"
65 #include "net.h"
66
67 #include "if_lereg.h"
68
69
70 #define LE_TICK_SHIFT 14
71
72 /* #define LE_DEBUG */
73 /* #define debug fatal */
74
75 extern int quiet_mode;
76
77 #define LE_MODE_LOOP 4
78 #define LE_MODE_DTX 2
79 #define LE_MODE_DRX 1
80
81
82 #define N_REGISTERS 4
83 #define SRAM_SIZE (128*1024)
84 #define ROM_SIZE 32
85
86
87 struct le_data {
88 struct interrupt irq;
89 int irq_asserted;
90
91 uint64_t buf_start;
92 uint64_t buf_end;
93 int len;
94
95 uint8_t rom[ROM_SIZE];
96
97 int reg_select;
98 uint16_t reg[N_REGISTERS];
99
100 unsigned char *sram;
101
102 /* Initialization block: */
103 uint32_t init_block_addr;
104
105 uint16_t mode;
106 uint64_t padr; /* MAC address */
107 uint64_t ladrf;
108 uint32_t rdra; /* receive descriptor ring address */
109 int rlen; /* nr of rx descriptors */
110 uint32_t tdra; /* transmit descriptor ring address */
111 int tlen; /* nr ot tx descriptors */
112
113 /* Current rx and tx descriptor indices: */
114 int rxp;
115 int txp;
116
117 unsigned char *tx_packet;
118 int tx_packet_len;
119
120 unsigned char *rx_packet;
121 int rx_packet_len;
122 int rx_packet_offset;
123 int rx_middle_bit;
124 };
125
126
127 /*
128 * le_read_16bit():
129 *
130 * Read a 16-bit word from the SRAM.
131 */
132 static uint64_t le_read_16bit(struct le_data *d, int addr)
133 {
134 /* TODO: This is for little endian only */
135 int x = d->sram[addr & (SRAM_SIZE-1)] +
136 (d->sram[(addr+1) & (SRAM_SIZE-1)] << 8);
137 return x;
138 }
139
140
141 /*
142 * le_write_16bit():
143 *
144 * Write a 16-bit word to the SRAM.
145 */
146 static void le_write_16bit(struct le_data *d, int addr, uint16_t x)
147 {
148 /* TODO: This is for little endian only */
149 d->sram[addr & (SRAM_SIZE-1)] = x & 0xff;
150 d->sram[(addr+1) & (SRAM_SIZE-1)] = (x >> 8) & 0xff;
151 }
152
153
154 /*
155 * le_chip_init():
156 *
157 * Initialize data structures by reading an 'initialization block' from the
158 * SRAM.
159 */
160 static void le_chip_init(struct le_data *d)
161 {
162 d->init_block_addr = (d->reg[1] & 0xffff) + ((d->reg[2] & 0xff) << 16);
163 if (d->init_block_addr & 1)
164 fatal("[ le: WARNING! initialization block address "
165 "not word aligned? ]\n");
166
167 debug("[ le: d->init_block_addr = 0x%06x ]\n", d->init_block_addr);
168
169 d->mode = le_read_16bit(d, d->init_block_addr + 0);
170 d->padr = le_read_16bit(d, d->init_block_addr + 2);
171 d->padr += (le_read_16bit(d, d->init_block_addr + 4) << 16);
172 d->padr += (le_read_16bit(d, d->init_block_addr + 6) << 32);
173 d->ladrf = le_read_16bit(d, d->init_block_addr + 8);
174 d->ladrf += (le_read_16bit(d, d->init_block_addr + 10) << 16);
175 d->ladrf += (le_read_16bit(d, d->init_block_addr + 12) << 32);
176 d->ladrf += (le_read_16bit(d, d->init_block_addr + 14) << 48);
177 d->rdra = le_read_16bit(d, d->init_block_addr + 16);
178 d->rdra += ((le_read_16bit(d, d->init_block_addr + 18) & 0xff) << 16);
179 d->rlen = 1 << ((le_read_16bit(d, d->init_block_addr + 18) >> 13) & 7);
180 d->tdra = le_read_16bit(d, d->init_block_addr + 20);
181 d->tdra += ((le_read_16bit(d, d->init_block_addr + 22) & 0xff) << 16);
182 d->tlen = 1 << ((le_read_16bit(d, d->init_block_addr + 22) >> 13) & 7);
183
184 debug("[ le: DEBUG: mode %04x ]\n", d->mode);
185 debug("[ le: DEBUG: padr %016llx ]\n", (long long)d->padr);
186 debug("[ le: DEBUG: ladrf %016llx ]\n", (long long)d->ladrf);
187 debug("[ le: DEBUG: rdra %06llx ]\n", d->rdra);
188 debug("[ le: DEBUG: rlen %3i ]\n", d->rlen);
189 debug("[ le: DEBUG: tdra %06llx ]\n", d->tdra);
190 debug("[ le: DEBUG: tlen %3i ]\n", d->tlen);
191
192 /* Set TXON and RXON, unless they are disabled by 'mode': */
193 if (d->mode & LE_MODE_DTX)
194 d->reg[0] &= ~LE_TXON;
195 else
196 d->reg[0] |= LE_TXON;
197
198 if (d->mode & LE_MODE_DRX)
199 d->reg[0] &= ~LE_RXON;
200 else
201 d->reg[0] |= LE_RXON;
202
203 /* Go to the start of the descriptor rings: */
204 d->rxp = d->txp = 0;
205
206 /* Set IDON and reset the INIT bit when we are done. */
207 d->reg[0] |= LE_IDON;
208 d->reg[0] &= ~LE_INIT;
209
210 /* Free any old packets: */
211 if (d->tx_packet != NULL)
212 free(d->tx_packet);
213 d->tx_packet = NULL;
214 d->tx_packet_len = 0;
215
216 if (d->rx_packet != NULL)
217 free(d->rx_packet);
218 d->rx_packet = NULL;
219 d->rx_packet_len = 0;
220 d->rx_packet_offset = 0;
221 d->rx_middle_bit = 0;
222 }
223
224
225 /*
226 * le_tx():
227 *
228 * Check the transmitter descriptor ring for buffers that are owned by the
229 * Lance chip (that is, buffers that are to be transmitted).
230 *
231 * This routine should only be called if TXON is enabled.
232 */
233 static void le_tx(struct net *net, struct le_data *d)
234 {
235 int start_txp = d->txp;
236 uint16_t tx_descr[4];
237 int stp, enp, cur_packet_offset;
238 size_t i;
239 uint32_t bufaddr, buflen;
240
241 /* TODO: This is just a guess: */
242 d->reg[0] &= ~LE_TDMD;
243
244 do {
245 /* Load the 8 descriptor bytes: */
246 tx_descr[0] = le_read_16bit(d, d->tdra + d->txp*8 + 0);
247 tx_descr[1] = le_read_16bit(d, d->tdra + d->txp*8 + 2);
248 tx_descr[2] = le_read_16bit(d, d->tdra + d->txp*8 + 4);
249 tx_descr[3] = le_read_16bit(d, d->tdra + d->txp*8 + 6);
250
251 bufaddr = tx_descr[0] + ((tx_descr[1] & 0xff) << 16);
252 stp = tx_descr[1] & LE_STP? 1 : 0;
253 enp = tx_descr[1] & LE_ENP? 1 : 0;
254 buflen = 4096 - (tx_descr[2] & 0xfff);
255
256 /*
257 * Check the OWN bit. If it is zero, then this buffer is
258 * not ready to be transmitted yet. Also check the '1111'
259 * mark, and make sure that byte-count is reasonable.
260 */
261 if (!(tx_descr[1] & LE_OWN))
262 return;
263 if ((tx_descr[2] & 0xf000) != 0xf000)
264 return;
265 if (buflen < 12 || buflen > 1900) {
266 fatal("[ le_tx(): buflen = %i ]\n", buflen);
267 return;
268 }
269
270 debug("[ le_tx(): descr %3i DUMP: 0x%04x 0x%04x 0x%04x 0x%04x "
271 "=> addr=0x%06x, len=%i bytes, STP=%i ENP=%i ]\n", d->txp,
272 tx_descr[0], tx_descr[1], tx_descr[2], tx_descr[3],
273 bufaddr, buflen, stp, enp);
274
275 if (d->tx_packet == NULL && !stp) {
276 fatal("[ le_tx(): !stp but tx_packet == NULL ]\n");
277 return;
278 }
279
280 if (d->tx_packet != NULL && stp) {
281 fatal("[ le_tx(): stp but tx_packet != NULL ]\n");
282 free(d->tx_packet);
283 d->tx_packet = NULL;
284 d->tx_packet_len = 0;
285 }
286
287 /* Where to write to in the tx_packet: */
288 cur_packet_offset = d->tx_packet_len;
289
290 /* Start of a new packet: */
291 if (stp) {
292 d->tx_packet_len = buflen;
293 CHECK_ALLOCATION(d->tx_packet = malloc(buflen));
294 } else {
295 d->tx_packet_len += buflen;
296 CHECK_ALLOCATION(d->tx_packet =
297 realloc(d->tx_packet, d->tx_packet_len));
298 }
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 int start_rxp = d->rxp;
349 size_t i;
350 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 if (d->rx_packet_offset+(ssize_t)i >= d->rx_packet_len)
388 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 DEVICE_TICK(le)
527 {
528 struct le_data *d = extra;
529 int new_assert;
530
531 le_register_fix(cpu->machine->emul->net, d);
532
533 new_assert = (d->reg[0] & LE_INTR) && (d->reg[0] & LE_INEA);
534
535 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 }
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 DEVICE_ACCESS(le_sram)
602 {
603 struct le_data *d = extra;
604 size_t i;
605 int retval;
606
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 DEVICE_ACCESS(le)
647 {
648 struct le_data *d = extra;
649 uint64_t idata = 0, odata = 0;
650 int retval = 1;
651 size_t i;
652
653 if (writeflag == MEM_WRITE)
654 idata = memory_readmax64(cpu, data, len);
655
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 uint32_t a;
668 int j = (relative_addr & 0xff) / 4;
669 a = d->rom[j & (ROM_SIZE-1)];
670
671 if (writeflag == MEM_READ) {
672 odata = (a << 24) + (a << 16) + (a << 8) + a;
673 } 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 uint64_t buf_start, uint64_t buf_end, char *irq_path, int len)
763 {
764 char *name2;
765 size_t nlen = 55;
766 struct le_data *d;
767
768 CHECK_ALLOCATION(d = malloc(sizeof(struct le_data)));
769 memset(d, 0, sizeof(struct le_data));
770
771 INTERRUPT_CONNECT(irq_path, d->irq);
772
773 CHECK_ALLOCATION(d->sram = malloc(SRAM_SIZE));
774 memset(d->sram, 0, SRAM_SIZE);
775
776 /* 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 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK
807 | DM_READS_HAVE_NO_SIDE_EFFECTS, d->sram);
808
809 CHECK_ALLOCATION(name2 = malloc(nlen));
810 snprintf(name2, nlen, "le [%02x:%02x:%02x:%02x:%02x:%02x]",
811 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 len - 0x100000, dev_le_access, (void *)d, DM_DEFAULT, NULL);
815
816 machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT);
817
818 net_add_nic(machine->emul->net, d, &d->rom[0]);
819 }
820

  ViewVC Help
Powered by ViewVC 1.1.26