1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_le.c,v 1.39 2005/03/14 19:14:02 debug Exp $ |
* $Id: dev_le.c,v 1.54 2006/12/31 21:35:26 debug Exp $ |
29 |
* |
* |
30 |
* LANCE ethernet, as used in DECstations. |
* LANCE ethernet, as used in DECstations. |
31 |
* |
* |
47 |
* |
* |
48 |
* TODO: Error conditions (such as when there are not enough receive |
* TODO: Error conditions (such as when there are not enough receive |
49 |
* buffers) are not emulated yet. |
* 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> |
#include <stdio.h> |
85 |
|
|
86 |
|
|
87 |
struct le_data { |
struct le_data { |
88 |
int irq_nr; |
struct interrupt irq; |
89 |
|
int irq_asserted; |
90 |
|
|
91 |
uint64_t buf_start; |
uint64_t buf_start; |
92 |
uint64_t buf_end; |
uint64_t buf_end; |
97 |
int reg_select; |
int reg_select; |
98 |
uint16_t reg[N_REGISTERS]; |
uint16_t reg[N_REGISTERS]; |
99 |
|
|
100 |
unsigned char sram[SRAM_SIZE]; |
unsigned char *sram; |
101 |
|
|
102 |
/* Initialization block: */ |
/* Initialization block: */ |
103 |
uint32_t init_block_addr; |
uint32_t init_block_addr; |
234 |
{ |
{ |
235 |
int start_txp = d->txp; |
int start_txp = d->txp; |
236 |
uint16_t tx_descr[4]; |
uint16_t tx_descr[4]; |
237 |
int stp, enp, i, cur_packet_offset; |
int stp, enp, cur_packet_offset; |
238 |
|
size_t i; |
239 |
uint32_t bufaddr, buflen; |
uint32_t bufaddr, buflen; |
240 |
|
|
241 |
/* TODO: This is just a guess: */ |
/* TODO: This is just a guess: */ |
354 |
*/ |
*/ |
355 |
static void le_rx(struct net *net, struct le_data *d) |
static void le_rx(struct net *net, struct le_data *d) |
356 |
{ |
{ |
357 |
int i, start_rxp = d->rxp; |
int start_rxp = d->rxp; |
358 |
|
size_t i; |
359 |
uint16_t rx_descr[4]; |
uint16_t rx_descr[4]; |
360 |
uint32_t bufaddr, buflen; |
uint32_t bufaddr, buflen; |
361 |
|
|
393 |
|
|
394 |
/* Copy data from the packet into SRAM: */ |
/* Copy data from the packet into SRAM: */ |
395 |
for (i=0; i<buflen; i++) { |
for (i=0; i<buflen; i++) { |
396 |
if (d->rx_packet_offset + i >= d->rx_packet_len) |
if (d->rx_packet_offset+(ssize_t)i >= d->rx_packet_len) |
397 |
break; |
break; |
398 |
d->sram[(bufaddr + i) & (SRAM_SIZE-1)] = |
d->sram[(bufaddr + i) & (SRAM_SIZE-1)] = |
399 |
d->rx_packet[d->rx_packet_offset + i]; |
d->rx_packet[d->rx_packet_offset + i]; |
538 |
void dev_le_tick(struct cpu *cpu, void *extra) |
void dev_le_tick(struct cpu *cpu, void *extra) |
539 |
{ |
{ |
540 |
struct le_data *d = (struct le_data *) extra; |
struct le_data *d = (struct le_data *) extra; |
541 |
|
int new_assert; |
542 |
|
|
543 |
le_register_fix(cpu->machine->emul->net, d); |
le_register_fix(cpu->machine->emul->net, d); |
544 |
|
|
545 |
if (d->reg[0] & LE_INTR && d->reg[0] & LE_INEA) |
new_assert = (d->reg[0] & LE_INTR) && (d->reg[0] & LE_INEA); |
546 |
cpu_interrupt(cpu, d->irq_nr); |
if (new_assert && !d->irq_asserted) |
547 |
else |
INTERRUPT_ASSERT(d->irq); |
548 |
cpu_interrupt_ack(cpu, d->irq_nr); |
if (d->irq_asserted && !new_assert) |
549 |
|
INTERRUPT_DEASSERT(d->irq); |
550 |
|
|
551 |
|
d->irq_asserted = new_assert; |
552 |
} |
} |
553 |
|
|
554 |
|
|
609 |
} |
} |
610 |
|
|
611 |
|
|
612 |
/* |
DEVICE_ACCESS(le_sram) |
|
* 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) |
|
613 |
{ |
{ |
614 |
int i, retval; |
size_t i; |
615 |
|
int retval; |
616 |
struct le_data *d = extra; |
struct le_data *d = extra; |
617 |
|
|
618 |
#ifdef LE_DEBUG |
#ifdef LE_DEBUG |
654 |
} |
} |
655 |
|
|
656 |
|
|
657 |
/* |
DEVICE_ACCESS(le) |
|
* 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) |
|
658 |
{ |
{ |
659 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
660 |
int i, retval = 1; |
size_t i; |
661 |
|
int retval = 1; |
662 |
struct le_data *d = extra; |
struct le_data *d = extra; |
663 |
|
|
664 |
idata = memory_readmax64(cpu, data, len); |
if (writeflag == MEM_WRITE) |
665 |
|
idata = memory_readmax64(cpu, data, len); |
666 |
|
|
667 |
#ifdef LE_DEBUG |
#ifdef LE_DEBUG |
668 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
675 |
|
|
676 |
/* Read from station's ROM (ethernet address): */ |
/* Read from station's ROM (ethernet address): */ |
677 |
if (relative_addr >= 0xc0000 && relative_addr <= 0xfffff) { |
if (relative_addr >= 0xc0000 && relative_addr <= 0xfffff) { |
678 |
i = (relative_addr & 0xff) / 4; |
uint32_t a; |
679 |
i = d->rom[i & (ROM_SIZE-1)]; |
int j = (relative_addr & 0xff) / 4; |
680 |
|
a = d->rom[j & (ROM_SIZE-1)]; |
681 |
|
|
682 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
683 |
odata = (i << 24) + (i << 16) + (i << 8) + i; |
odata = (a << 24) + (a << 16) + (a << 8) + a; |
684 |
} else { |
} else { |
685 |
fatal("[ le: WRITE to ethernet addr (%08lx):", |
fatal("[ le: WRITE to ethernet addr (%08lx):", |
686 |
(long)relative_addr); |
(long)relative_addr); |
770 |
* dev_le_init(): |
* dev_le_init(): |
771 |
*/ |
*/ |
772 |
void dev_le_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, |
void dev_le_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, |
773 |
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) |
774 |
{ |
{ |
775 |
char *name2; |
char *name2; |
776 |
|
size_t nlen = 55; |
777 |
struct le_data *d = malloc(sizeof(struct le_data)); |
struct le_data *d = malloc(sizeof(struct le_data)); |
778 |
|
|
779 |
if (d == NULL) { |
if (d == NULL) { |
782 |
} |
} |
783 |
|
|
784 |
memset(d, 0, sizeof(struct le_data)); |
memset(d, 0, sizeof(struct le_data)); |
785 |
d->irq_nr = irq_nr; |
|
786 |
|
INTERRUPT_CONNECT(irq_path, d->irq); |
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? */ |
/* TODO: Are these actually used yet? */ |
796 |
d->len = len; |
d->len = len; |
806 |
/* ROM (including the MAC address): */ |
/* ROM (including the MAC address): */ |
807 |
net_generate_unique_mac(machine, &d->rom[0]); |
net_generate_unique_mac(machine, &d->rom[0]); |
808 |
|
|
|
/* |
|
|
* NOTE: According to the Lance documentation, the low order bit of |
|
|
* a physical MAC address should be clear. However, NetBSD and |
|
|
* Linux drop packets if the _first_ byte's lowest bit is not zero. |
|
|
*/ |
|
|
d->rom[0] &= ~1; |
|
|
d->rom[5] &= ~1; |
|
|
|
|
809 |
/* Copies of the MAC address and a test pattern: */ |
/* Copies of the MAC address and a test pattern: */ |
810 |
d->rom[10] = d->rom[21] = d->rom[5]; |
d->rom[10] = d->rom[21] = d->rom[5]; |
811 |
d->rom[11] = d->rom[20] = d->rom[4]; |
d->rom[11] = d->rom[20] = d->rom[4]; |
822 |
|
|
823 |
memory_device_register(mem, "le_sram", baseaddr, |
memory_device_register(mem, "le_sram", baseaddr, |
824 |
SRAM_SIZE, dev_le_sram_access, (void *)d, |
SRAM_SIZE, dev_le_sram_access, (void *)d, |
825 |
MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK, d->sram); |
DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK |
826 |
|
| DM_READS_HAVE_NO_SIDE_EFFECTS, d->sram); |
827 |
|
|
828 |
name2 = malloc(50); |
name2 = malloc(nlen); |
829 |
if (name2 == NULL) { |
if (name2 == NULL) { |
830 |
fprintf(stderr, "out of memory in dev_le_init()\n"); |
fprintf(stderr, "out of memory in dev_le_init()\n"); |
831 |
exit(1); |
exit(1); |
832 |
} |
} |
833 |
sprintf(name2, "le [%02x:%02x:%02x:%02x:%02x:%02x]", |
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]); |
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, |
memory_device_register(mem, name2, baseaddr + 0x100000, |
837 |
len - 0x100000, dev_le_access, (void *)d, MEM_DEFAULT, NULL); |
len - 0x100000, dev_le_access, (void *)d, DM_DEFAULT, NULL); |
838 |
|
|
839 |
machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT); |
machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT, 0.0); |
840 |
|
|
841 |
net_add_nic(machine->emul->net, d, &d->rom[0]); |
net_add_nic(machine->emul->net, d, &d->rom[0]); |
842 |
} |
} |