Fixed the WD8013EBT NIC - now it works properly with the interface chip enabled;
Fixed the port aliasing on the WD8003E NIC; Fixed two bugs in pci.c reported by waltje.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
* - SMC/WD 8013EBT (ISA 16-bit);
|
||||
* - SMC/WD 8013EP/A (MCA).
|
||||
*
|
||||
* Version: @(#)net_wd8003.c 1.0.2 2018/10/17
|
||||
* Version: @(#)net_wd8003.c 1.0.3 2018/10/20
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../rom.h"
|
||||
#include "../machine/machine.h"
|
||||
#include "../mca.h"
|
||||
#include "../pci.h"
|
||||
#include "../pic.h"
|
||||
@@ -96,8 +97,10 @@ typedef struct {
|
||||
uint8_t pos_regs[8];
|
||||
|
||||
/* Memory for WD cards*/
|
||||
uint8_t reg0, reg1,
|
||||
reg4, reg5,
|
||||
uint8_t msr, /* Memory Select Register (MSR) */
|
||||
icr, /* Interface Configuration Register (ICR) */
|
||||
irr, /* Interrupt Request Register (IRR) */
|
||||
laar, /* LA Address Register (read by Windows 98!) */
|
||||
if_chip, board_chip;
|
||||
} wd_t;
|
||||
|
||||
@@ -129,7 +132,7 @@ wd_interrupt(void *priv, int set)
|
||||
{
|
||||
wd_t *dev = (wd_t *) priv;
|
||||
|
||||
if (dev->reg4 & 0x80)
|
||||
if (!(dev->irr & 0x80))
|
||||
return;
|
||||
|
||||
if (set)
|
||||
@@ -148,6 +151,9 @@ wd_reset(void *priv)
|
||||
wdlog("%s: reset\n", dev->name);
|
||||
|
||||
dp8390_reset(dev->dp8390);
|
||||
|
||||
dev->msr &= 0x3f;
|
||||
mem_mapping_disable(&dev->ram_mapping);
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +176,7 @@ wd_ram_read(uint32_t addr, unsigned len, void *priv)
|
||||
ret = dev->dp8390->mem[addr & ram_mask];
|
||||
|
||||
if (len == 2)
|
||||
ret |= dev->dp8390->mem[(addr + 1) & ram_mask] << 8;
|
||||
ret |= dev->dp8390->mem[(addr + 1) & ram_mask] << 8;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -231,30 +237,26 @@ wd_smc_read(wd_t *dev, uint32_t off)
|
||||
uint32_t retval = 0;
|
||||
uint32_t checksum = 0;
|
||||
|
||||
if (dev->board == WD8003E) {
|
||||
if ((off >= 0x01) && (off <= 0x06))
|
||||
off += 0x07; /* On the WD8003E, ports 00-06 shadow ports 08-0D. */
|
||||
else if (off == 0x07)
|
||||
off = 0x0f; /* Port 07 shadows port 0F (checksum). */
|
||||
}
|
||||
if (dev->board == WD8003E)
|
||||
off |= 0x08;
|
||||
|
||||
switch(off) {
|
||||
case 0x00:
|
||||
if (dev->board == WD8013EBT)
|
||||
retval = dev->reg0;
|
||||
retval = dev->msr;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
retval = dev->reg1;
|
||||
retval = dev->icr;
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
if (dev->board == WD8013EBT)
|
||||
retval = dev->reg4;
|
||||
retval = dev->irr;
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
retval = dev->reg5;
|
||||
retval = dev->laar;
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
@@ -263,7 +265,8 @@ wd_smc_read(wd_t *dev, uint32_t off)
|
||||
retval = 0;
|
||||
else
|
||||
retval = dev->if_chip;
|
||||
}
|
||||
} else
|
||||
retval = dev->if_chip;
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
@@ -301,7 +304,7 @@ wd_smc_read(wd_t *dev, uint32_t off)
|
||||
dev->board_chip);
|
||||
|
||||
retval = 0xff - (checksum & 0xff);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
wdlog("%s: ASIC read addr=0x%02x, value=0x%04x\n",
|
||||
@@ -312,74 +315,103 @@ wd_smc_read(wd_t *dev, uint32_t off)
|
||||
|
||||
|
||||
static void
|
||||
wd_set_irq(wd_t *dev)
|
||||
wd_set_ram(wd_t *dev)
|
||||
{
|
||||
uint8_t irq;
|
||||
uint32_t a13, a19;
|
||||
|
||||
irq = (dev->reg4 & 0x60) >> 5;
|
||||
irq |= (dev->reg1 & 0x04);
|
||||
a13 = dev->msr & 0x3f;
|
||||
a13 <<= 13;
|
||||
a19 = dev->laar & 0x1f;
|
||||
a19 <<= 19;
|
||||
|
||||
dev->base_irq = we_int_table[irq];
|
||||
dev->ram_addr = a13 | a19;
|
||||
mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size);
|
||||
|
||||
if (dev->msr & 0x40)
|
||||
mem_mapping_enable(&dev->ram_mapping);
|
||||
else
|
||||
mem_mapping_disable(&dev->ram_mapping);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
wd_smc_write(wd_t *dev, uint32_t off, uint32_t val)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
wdlog("%s: ASIC write addr=0x%02x, value=0x%04x\n",
|
||||
dev->name, (unsigned)off, (unsigned) val);
|
||||
|
||||
if (dev->board == WD8003E)
|
||||
off |= 0x08;
|
||||
|
||||
switch(off) {
|
||||
/* Bits 0-5: Bits 13-18 of memory address (writable?):
|
||||
Windows 98 requires this to be preloaded with the initial
|
||||
addresss to work correctly;
|
||||
Bit 6: Enable memory if set;
|
||||
Bit 7: Software reset if set. */
|
||||
case 0x00: /* WD Control register */
|
||||
dev->reg0 = val;
|
||||
old = dev->msr;
|
||||
|
||||
if (val & 0x80)
|
||||
if (!(old & 0x80) && (val & 0x80)) {
|
||||
wd_soft_reset(dev);
|
||||
wdlog("WD80x3: Soft reset\n");
|
||||
}
|
||||
|
||||
if (val & 0x40)
|
||||
mem_mapping_enable(&dev->ram_mapping);
|
||||
else
|
||||
mem_mapping_disable(&dev->ram_mapping);
|
||||
dev->msr = val;
|
||||
|
||||
if ((old &= 0x7f) != (val & 0x7f)) {
|
||||
wd_set_ram(dev);
|
||||
wdlog("WD80x3: Memory now %sabled (addr = %08X)\n", (val & 0x40) ? "en" : "dis", dev->ram_addr);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Bit 1: 0 = 8-bit slot, 1 = 16-bit slot;
|
||||
Bit 2: Bit 2 of encoded IRQ;
|
||||
Bit 3: 0 = 8k RAM, 1 = 32k RAM (only on revision < 2). */
|
||||
case 0x01:
|
||||
if (dev->board == WD8003E)
|
||||
break;
|
||||
|
||||
dev->reg1 &= 0x60;
|
||||
dev->reg1 |= (val & ~0x60);
|
||||
if (!dev->bit16)
|
||||
dev->reg1 &= ~0x01;
|
||||
|
||||
if (dev->board == WD8013EBT) {
|
||||
wd_set_irq(dev);
|
||||
|
||||
dev->ram_size = (dev->reg1 & 0x08) ? 0x8000 : 0x4000;
|
||||
|
||||
mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size);
|
||||
if (!(dev->reg0 & 0x40))
|
||||
mem_mapping_disable(&dev->ram_mapping);
|
||||
}
|
||||
dev->icr = val;
|
||||
break;
|
||||
|
||||
/* Bit 5: Bit 0 of encoded IRQ;
|
||||
Bit 6: Bit 1 of encoded IRQ;
|
||||
Bit 7: Enable interrupts. */
|
||||
case 0x04:
|
||||
if (dev->board != WD8013EBT)
|
||||
break;
|
||||
|
||||
dev->reg4 = val;
|
||||
wd_set_irq(dev);
|
||||
dev->irr = (dev->irr & 0xe0) | (val & 0x1f);
|
||||
break;
|
||||
|
||||
|
||||
/* Bits 0-4: Bits 19-23 of memory address (writable?):
|
||||
Windows 98 requires this to be preloaded with the initial
|
||||
addresss to work correctly;
|
||||
Bit 5: Enable software interrupt;
|
||||
Bit 6: Enable 16-bit RAM for LAN if set;
|
||||
Bit 7: Enable 16-bit RAM for host if set. */
|
||||
case 0x05:
|
||||
old = dev->laar;
|
||||
|
||||
if (dev->board == WD8003E)
|
||||
break;
|
||||
|
||||
dev->reg5 = val;
|
||||
dev->laar = val;
|
||||
|
||||
if (dev->board == WD8013EBT) {
|
||||
if ((old &= 0x1f) != (val & 0x1f)) {
|
||||
wd_set_ram(dev);
|
||||
wdlog("WD80x3: Memory now %sabled (addr = %08X)\n", (val & 0x40) ? "en" : "dis", dev->ram_addr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
break;
|
||||
|
||||
|
||||
/* Bits 0-4: Chip ID;
|
||||
Bit 5: Software configuration is supported if present;
|
||||
Bit 6: 0 = 16k RAM, 1 = 32k RAM. */
|
||||
case 0x07:
|
||||
dev->if_chip = val;
|
||||
break;
|
||||
@@ -645,11 +677,12 @@ wd_init(const device_t *info)
|
||||
dev->board_chip = WE_TYPE_WD8003E;
|
||||
dev->ram_size = 0x2000;
|
||||
dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CLEAR_IRQ | DP8390_FLAG_NO_CHIPMEM);
|
||||
dev->msr |= 0x40;
|
||||
break;
|
||||
|
||||
case WD8013EBT:
|
||||
dev->board_chip = WE_TYPE_WD8013EBT;
|
||||
dev->ram_size = 0x4000;
|
||||
dev->ram_size = device_get_config_int("ram_size");
|
||||
dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CLEAR_IRQ | DP8390_FLAG_NO_CHIPMEM);
|
||||
irq = 255;
|
||||
for (i = 0; i < 8; i++) {
|
||||
@@ -657,11 +690,23 @@ wd_init(const device_t *info)
|
||||
irq = i;
|
||||
}
|
||||
if (irq != 255) {
|
||||
dev->reg4 = (irq & 0x03) << 5;
|
||||
dev->reg1 = irq & 0x04;
|
||||
dev->irr = (irq & 0x03) << 5;
|
||||
dev->icr = irq & 0x04;
|
||||
}
|
||||
|
||||
dev->bit16 = 1;
|
||||
dev->msr |= (dev->ram_addr >> 13) & 0x3f;
|
||||
dev->laar |= (dev->ram_addr >> 19) & 0x1f;
|
||||
|
||||
if (dev->ram_size == 0x8000)
|
||||
dev->board_chip |= 0x40;
|
||||
|
||||
if (AT)
|
||||
dev->bit16 = 1;
|
||||
else {
|
||||
dev->bit16 = 0;
|
||||
if (dev->base_irq == 9)
|
||||
dev->base_irq = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case WD8013EPA:
|
||||
@@ -674,6 +719,9 @@ wd_init(const device_t *info)
|
||||
break;
|
||||
}
|
||||
|
||||
dev->irr |= 0x80;
|
||||
dev->icr |= dev->bit16;
|
||||
|
||||
if (dev->base_address)
|
||||
wd_io_set(dev, dev->base_address);
|
||||
|
||||
@@ -688,7 +736,7 @@ wd_init(const device_t *info)
|
||||
wd_reset(dev);
|
||||
|
||||
/* Map this system into the memory map. */
|
||||
if (dev->bit16) {
|
||||
if (!dev->bit16) {
|
||||
mem_mapping_add(&dev->ram_mapping, dev->ram_addr, dev->ram_size,
|
||||
wd_ram_readb, wd_ram_readw, NULL,
|
||||
wd_ram_writeb, wd_ram_writew, NULL,
|
||||
@@ -699,7 +747,10 @@ wd_init(const device_t *info)
|
||||
wd_ram_writeb, NULL, NULL,
|
||||
NULL, MEM_MAPPING_EXTERNAL, dev);
|
||||
}
|
||||
mem_mapping_disable(&dev->ram_mapping);
|
||||
if (dev->msr & 0x40)
|
||||
mem_mapping_enable(&dev->ram_mapping);
|
||||
else
|
||||
mem_mapping_disable(&dev->ram_mapping);
|
||||
|
||||
/* Attach ourselves to the network module. */
|
||||
network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx);
|
||||
@@ -766,9 +817,6 @@ static const device_config_t wd8003_config[] =
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"mac", "MAC Address", CONFIG_MAC, "", -1
|
||||
},
|
||||
{
|
||||
"ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000,
|
||||
{
|
||||
@@ -795,25 +843,48 @@ static const device_config_t wd8003_config[] =
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"mac", "MAC Address", CONFIG_MAC, "", -1
|
||||
},
|
||||
{
|
||||
"", "", -1
|
||||
}
|
||||
};
|
||||
|
||||
/* WD8013EBT configuration and defaults set according to this site:
|
||||
http://www.stack.nl/~marcolz/network/wd80x3.html#WD8013EBT */
|
||||
static const device_config_t wd8013_config[] =
|
||||
{
|
||||
{
|
||||
"base", "Address", CONFIG_HEX16, "", 0x300,
|
||||
"base", "Address", CONFIG_HEX16, "", 0x280,
|
||||
{
|
||||
{
|
||||
"0x200", 0x200
|
||||
},
|
||||
{
|
||||
"0x220", 0x220
|
||||
},
|
||||
{
|
||||
"0x240", 0x240
|
||||
},
|
||||
{
|
||||
"0x260", 0x260
|
||||
},
|
||||
{
|
||||
"0x280", 0x280
|
||||
},
|
||||
{
|
||||
"0x2A0", 0x2A0
|
||||
},
|
||||
{
|
||||
"0x2C0", 0x2C0
|
||||
},
|
||||
{
|
||||
"0x300", 0x300
|
||||
},
|
||||
{
|
||||
"0x340", 0x340
|
||||
},
|
||||
{
|
||||
"0x380", 0x380
|
||||
},
|
||||
@@ -825,6 +896,9 @@ static const device_config_t wd8013_config[] =
|
||||
{
|
||||
"irq", "IRQ", CONFIG_SELECTION, "", 3,
|
||||
{
|
||||
{
|
||||
"IRQ 2/9", 9
|
||||
},
|
||||
{
|
||||
"IRQ 3", 3
|
||||
},
|
||||
@@ -837,9 +911,6 @@ static const device_config_t wd8013_config[] =
|
||||
{
|
||||
"IRQ 7", 7
|
||||
},
|
||||
{
|
||||
"IRQ 9", 9
|
||||
},
|
||||
{
|
||||
"IRQ 10", 10
|
||||
},
|
||||
@@ -854,12 +925,15 @@ static const device_config_t wd8013_config[] =
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"mac", "MAC Address", CONFIG_MAC, "", -1
|
||||
},
|
||||
{
|
||||
"ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000,
|
||||
{
|
||||
{
|
||||
"C000", 0xC0000
|
||||
},
|
||||
{
|
||||
"C400", 0xC4000
|
||||
},
|
||||
{
|
||||
"C800", 0xC8000
|
||||
},
|
||||
@@ -883,6 +957,23 @@ static const device_config_t wd8013_config[] =
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"ram_size", "RAM size", CONFIG_SELECTION, "", 16384,
|
||||
{
|
||||
{
|
||||
"16 kB", 16384
|
||||
},
|
||||
{
|
||||
"32 kB", 32768
|
||||
},
|
||||
{
|
||||
""
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"mac", "MAC Address", CONFIG_MAC, "", -1
|
||||
},
|
||||
{
|
||||
"", "", -1
|
||||
}
|
||||
|
68
src/pci.c
68
src/pci.c
@@ -141,13 +141,9 @@ static void elcr_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
/* pci_log("ELCR%i: WRITE %02X\n", port & 1, val); */
|
||||
if (port & 1)
|
||||
{
|
||||
val &= 0xDE;
|
||||
}
|
||||
else
|
||||
{
|
||||
val &= 0xF8;
|
||||
}
|
||||
elcr[port & 1] = val;
|
||||
|
||||
pci_log("ELCR %i: %c %c %c %c %c %c %c %c\n", port & 1, (val & 1) ? 'L' : 'E', (val & 2) ? 'L' : 'E', (val & 4) ? 'L' : 'E', (val & 8) ? 'L' : 'E', (val & 0x10) ? 'L' : 'E', (val & 0x20) ? 'L' : 'E', (val & 0x40) ? 'L' : 'E', (val & 0x80) ? 'L' : 'E');
|
||||
@@ -162,9 +158,7 @@ static uint8_t elcr_read(uint16_t port, void *priv)
|
||||
static void elcr_reset(void)
|
||||
{
|
||||
pic_reset();
|
||||
/* elcr[0] = elcr[1] = 0; */
|
||||
elcr[0] = 0x98;
|
||||
elcr[1] = 0x00;
|
||||
elcr[0] = elcr[1] = 0x00;
|
||||
}
|
||||
|
||||
static void pci_type2_write(uint16_t port, uint8_t val, void *priv);
|
||||
@@ -174,33 +168,24 @@ static void pci_type2_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t slot = 0;
|
||||
|
||||
if (port == 0xcf8)
|
||||
{
|
||||
if (port == 0xcf8) {
|
||||
pci_func = (val >> 1) & 7;
|
||||
if (!pci_key && (val & 0xf0))
|
||||
io_sethandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL);
|
||||
else
|
||||
io_removehandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL);
|
||||
pci_key = val & 0xf0;
|
||||
}
|
||||
else if (port == 0xcfa)
|
||||
{
|
||||
} else if (port == 0xcfa)
|
||||
pci_bus = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
pci_card = (port >> 8) & 0xf;
|
||||
pci_index = port & 0xff;
|
||||
|
||||
if (!pci_bus)
|
||||
{
|
||||
if (!pci_bus) {
|
||||
slot = pci_card_to_slot_mapping[pci_card];
|
||||
if (slot != 0xFF)
|
||||
{
|
||||
if (slot != 0xFF) {
|
||||
if (pci_cards[slot].write)
|
||||
{
|
||||
pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,30 +196,21 @@ static uint8_t pci_type2_read(uint16_t port, void *priv)
|
||||
uint8_t slot = 0;
|
||||
|
||||
if (port == 0xcf8)
|
||||
{
|
||||
return pci_key | (pci_func << 1);
|
||||
}
|
||||
else if (port == 0xcfa)
|
||||
{
|
||||
return pci_bus;
|
||||
}
|
||||
else
|
||||
{
|
||||
pci_card = (port >> 8) & 0xf;
|
||||
pci_index = port & 0xff;
|
||||
|
||||
if (!pci_bus)
|
||||
{
|
||||
slot = pci_card_to_slot_mapping[pci_card];
|
||||
if (slot != 0xFF)
|
||||
{
|
||||
if (pci_cards[slot].read)
|
||||
{
|
||||
return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv);
|
||||
}
|
||||
}
|
||||
pci_card = (port >> 8) & 0xf;
|
||||
pci_index = port & 0xff;
|
||||
|
||||
if (!pci_bus) {
|
||||
slot = pci_card_to_slot_mapping[pci_card];
|
||||
if (slot != 0xFF) {
|
||||
if (pci_cards[slot].read)
|
||||
return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
@@ -258,31 +234,21 @@ int pci_irq_is_level(int irq)
|
||||
int real_irq = irq & 7;
|
||||
|
||||
if ((irq <= 2) || (irq == 8) || (irq == 13))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (irq > 7)
|
||||
{
|
||||
return !!(elcr[1] & (1 << real_irq));
|
||||
}
|
||||
else
|
||||
{
|
||||
return !!(elcr[0] & (1 << real_irq));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t pci_use_mirq(uint8_t mirq)
|
||||
{
|
||||
if (!PCI || !pci_mirqs[0].enabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pci_mirqs[mirq].irq_line & 0x80)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -442,8 +408,6 @@ void pci_clear_mirq(uint8_t mirq)
|
||||
uint8_t irq_line = 0;
|
||||
uint8_t level = 0;
|
||||
|
||||
mirq = 0;
|
||||
|
||||
if (mirq > 1)
|
||||
{
|
||||
pci_mirq_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq);
|
||||
|
Reference in New Issue
Block a user