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

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


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

  ViewVC Help
Powered by ViewVC 1.1.26