/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22238 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26