--- trunk/src/devices/dev_le.c 2007/10/08 16:19:23 20 +++ trunk/src/devices/dev_le.c 2007/10/08 16:22:32 42 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2005 Anders Gavare. All rights reserved. + * Copyright (C) 2003-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,9 +25,9 @@ * SUCH DAMAGE. * * - * $Id: dev_le.c,v 1.46 2005/11/13 00:14:09 debug Exp $ + * $Id: dev_le.c,v 1.56 2007/06/15 19:11:15 debug Exp $ * - * LANCE ethernet, as used in DECstations. + * COMMENT: LANCE ethernet, as used in DECstations * * This is based on "PMAD-AA TURBOchannel Ethernet Module Functional * Specification". I've tried to keep symbol names in this file to what @@ -47,6 +47,9 @@ * * TODO: Error conditions (such as when there are not enough receive * buffers) are not emulated yet. + * + * (Old bug, but probably still valid: "UDP packets that are too + * large are not handled well by the Lance device.") */ #include @@ -82,7 +85,8 @@ struct le_data { - int irq_nr; + struct interrupt irq; + int irq_asserted; uint64_t buf_start; uint64_t buf_end; @@ -230,7 +234,8 @@ { int start_txp = d->txp; uint16_t tx_descr[4]; - int stp, enp, i, cur_packet_offset; + int stp, enp, cur_packet_offset; + size_t i; uint32_t bufaddr, buflen; /* TODO: This is just a guess: */ @@ -285,20 +290,11 @@ /* Start of a new packet: */ if (stp) { d->tx_packet_len = buflen; - d->tx_packet = malloc(buflen); - if (d->tx_packet == NULL) { - fprintf(stderr, "out of memory (1) in " - "le_tx()\n"); - exit(1); - } + CHECK_ALLOCATION(d->tx_packet = malloc(buflen)); } else { d->tx_packet_len += buflen; - d->tx_packet = realloc(d->tx_packet, d->tx_packet_len); - if (d->tx_packet == NULL) { - fprintf(stderr, "out of memory (2) in" - " le_tx()\n"); - exit(1); - } + CHECK_ALLOCATION(d->tx_packet = + realloc(d->tx_packet, d->tx_packet_len)); } /* Copy data from SRAM into the tx packet: */ @@ -349,7 +345,8 @@ */ static void le_rx(struct net *net, struct le_data *d) { - int i, start_rxp = d->rxp; + int start_rxp = d->rxp; + size_t i; uint16_t rx_descr[4]; uint32_t bufaddr, buflen; @@ -387,7 +384,7 @@ /* Copy data from the packet into SRAM: */ for (i=0; irx_packet_offset + i >= d->rx_packet_len) + if (d->rx_packet_offset+(ssize_t)i >= d->rx_packet_len) break; d->sram[(bufaddr + i) & (SRAM_SIZE-1)] = d->rx_packet[d->rx_packet_offset + i]; @@ -526,19 +523,21 @@ } -/* - * dev_le_tick(): - */ -void dev_le_tick(struct cpu *cpu, void *extra) +DEVICE_TICK(le) { - struct le_data *d = (struct le_data *) extra; + struct le_data *d = extra; + int new_assert; le_register_fix(cpu->machine->emul->net, d); - if (d->reg[0] & LE_INTR && d->reg[0] & LE_INEA) - cpu_interrupt(cpu, d->irq_nr); - else - cpu_interrupt_ack(cpu, d->irq_nr); + new_assert = (d->reg[0] & LE_INTR) && (d->reg[0] & LE_INEA); + + if (new_assert && !d->irq_asserted) + INTERRUPT_ASSERT(d->irq); + if (d->irq_asserted && !new_assert) + INTERRUPT_DEASSERT(d->irq); + + d->irq_asserted = new_assert; } @@ -599,15 +598,11 @@ } -/* - * dev_le_sram_access(): - */ -int dev_le_sram_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) +DEVICE_ACCESS(le_sram) { - int i, retval; struct le_data *d = extra; + size_t i; + int retval; #ifdef LE_DEBUG if (writeflag == MEM_WRITE) { @@ -648,15 +643,12 @@ } -/* - * dev_le_access(): - */ -int dev_le_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, - unsigned char *data, size_t len, int writeflag, void *extra) +DEVICE_ACCESS(le) { - uint64_t idata = 0, odata = 0; - int i, retval = 1; struct le_data *d = extra; + uint64_t idata = 0, odata = 0; + int retval = 1; + size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); @@ -672,11 +664,12 @@ /* Read from station's ROM (ethernet address): */ if (relative_addr >= 0xc0000 && relative_addr <= 0xfffff) { - i = (relative_addr & 0xff) / 4; - i = d->rom[i & (ROM_SIZE-1)]; + uint32_t a; + int j = (relative_addr & 0xff) / 4; + a = d->rom[j & (ROM_SIZE-1)]; if (writeflag == MEM_READ) { - odata = (i << 24) + (i << 16) + (i << 8) + i; + odata = (a << 24) + (a << 16) + (a << 8) + a; } else { fatal("[ le: WRITE to ethernet addr (%08lx):", (long)relative_addr); @@ -766,25 +759,18 @@ * dev_le_init(): */ void dev_le_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, - uint64_t buf_start, uint64_t buf_end, int irq_nr, int len) + uint64_t buf_start, uint64_t buf_end, char *irq_path, int len) { char *name2; size_t nlen = 55; - struct le_data *d = malloc(sizeof(struct le_data)); - - if (d == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + struct le_data *d; + CHECK_ALLOCATION(d = malloc(sizeof(struct le_data))); memset(d, 0, sizeof(struct le_data)); - d->irq_nr = irq_nr; - d->sram = malloc(SRAM_SIZE); - if (d->sram == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + INTERRUPT_CONNECT(irq_path, d->irq); + + CHECK_ALLOCATION(d->sram = malloc(SRAM_SIZE)); memset(d->sram, 0, SRAM_SIZE); /* TODO: Are these actually used yet? */ @@ -820,11 +806,7 @@ DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS, d->sram); - name2 = malloc(nlen); - if (name2 == NULL) { - fprintf(stderr, "out of memory in dev_le_init()\n"); - exit(1); - } + CHECK_ALLOCATION(name2 = malloc(nlen)); snprintf(name2, nlen, "le [%02x:%02x:%02x:%02x:%02x:%02x]", d->rom[0], d->rom[1], d->rom[2], d->rom[3], d->rom[4], d->rom[5]);