diff --git a/src/um8669f.c b/src/um8669f.c index 8132ff0..67e2ba4 100644 --- a/src/um8669f.c +++ b/src/um8669f.c @@ -5,36 +5,21 @@ data read/write to 109 55 to 108 locks - - - -C0 -bit 3 = LPT1 enable -bit 2 = COM2 enable -bit 1 = COM1 enable -bit 0 = FDC enable - C1 -bits 7-6 = LPT1 mode : 11 = ECP/EPP, 01 = EPP, 10 = SPP -bit 3 = clear when LPT1 = 278 +bit 7 - enable PnP registers -C3 -bits 7-6 = LPT1 DMA mode : 11 = ECP/EPP DMA1, 10 = ECP/EPP DMA3, 01 = EPP/SPP, 00 = ECP -bits 5-4 = LPT1 addr : 10 = 278/IRQ5, 01 = 3BC/IRQ7, 00 = 378/IRQ7 +PnP registers : -COM1 : -3f8, IRQ4 - C1 = BF, C3 = 00 -2f8, IRQ3 - C1 = BF, C3 = 03 -3e8, IRQ4 - C1 = BD, C3 = 00 -2e8, IRQ3 - B1 = BD, C3 = 03 - -COM2 : -3f8, IRQ4 - C1 = BF, C3 = 0C -2f8, IRQ3 - C1 = BF, C3 = 00 -3e8, IRQ4 - C1 = BB, C3 = 0C -2e8, IRQ3 - C1 = BB, C3 = 00 - - */ +07 - device : + 0 = FDC + 1 = COM1 + 2 = COM2 + 3 = LPT1 + 5 = Game port +30 - enable +60/61 - addr +70 - IRQ +74 - DMA*/ #include "ibm.h" @@ -44,91 +29,178 @@ COM2 : #include "serial.h" #include "um8669f.h" -static int um8669f_locked; -static int um8669f_curreg; -static uint8_t um8669f_regs[256]; - -void um8669f_write(uint16_t port, uint8_t val, void *priv) +typedef struct um8669f_t { - int temp; -// pclog("um8669f_write : port=%04x reg %02X = %02X locked=%i\n", port, um8669f_curreg, val, um8669f_locked); - if (um8669f_locked) + int locked; + int cur_reg_108; + uint8_t regs_108[256]; + + int cur_reg; + int cur_device; + struct + { + int enable; + uint16_t addr; + int irq; + int dma; + } dev[8]; +} um8669f_t; + +static um8669f_t um8669f_global; + +#define DEV_FDC 0 +#define DEV_COM1 1 +#define DEV_COM2 2 +#define DEV_LPT1 3 +#define DEV_GAME 5 + +#define REG_DEVICE 0x07 +#define REG_ENABLE 0x30 +#define REG_ADDRHI 0x60 +#define REG_ADDRLO 0x61 +#define REG_IRQ 0x70 +#define REG_DMA 0x74 + +void um8669f_pnp_write(uint16_t port, uint8_t val, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + + if (port == 0x279) + um8669f->cur_reg = val; + else + { + if (um8669f->cur_reg == REG_DEVICE) + um8669f->cur_device = val & 7; + else + { +// pclog("Write UM8669F %02x [%02x] %02x\n", um8669f->cur_reg, um8669f->cur_device, val); + switch (um8669f->cur_reg) + { + case REG_ENABLE: + um8669f->dev[um8669f->cur_device].enable = val; + break; + case REG_ADDRLO: + um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0xff00) | val; + break; + case REG_ADDRHI: + um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0x00ff) | (val << 8); + break; + case REG_IRQ: + um8669f->dev[um8669f->cur_device].irq = val; + break; + case REG_DMA: + um8669f->dev[um8669f->cur_device].dma = val; + break; + } + + switch (um8669f->cur_device) + { + case DEV_FDC: + fdc_remove(); + if (um8669f->dev[DEV_FDC].enable & 1) + fdc_add(); + break; + case DEV_COM1: + serial1_remove(); + if (um8669f->dev[DEV_COM1].enable & 1) + serial1_set(um8669f->dev[DEV_COM1].addr, um8669f->dev[DEV_COM1].irq); + break; + case DEV_COM2: + serial2_remove(); + if (um8669f->dev[DEV_COM2].enable & 1) + serial2_set(um8669f->dev[DEV_COM2].addr, um8669f->dev[DEV_COM2].irq); + break; + case DEV_LPT1: + lpt1_remove(); + lpt2_remove(); + if (um8669f->dev[DEV_LPT1].enable & 1) + lpt1_init(um8669f->dev[DEV_LPT1].addr); + break; + } + } + } +} + +uint8_t um8669f_pnp_read(uint16_t port, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + +// pclog("Read UM8669F %02x\n", um8669f->cur_reg); + + switch (um8669f->cur_reg) + { + case REG_DEVICE: + return um8669f->cur_device; + case REG_ENABLE: + return um8669f->dev[um8669f->cur_device].enable; + case REG_ADDRLO: + return um8669f->dev[um8669f->cur_device].addr & 0xff; + case REG_ADDRHI: + return um8669f->dev[um8669f->cur_device].addr >> 8; + case REG_IRQ: + return um8669f->dev[um8669f->cur_device].irq; + case REG_DMA: + return um8669f->dev[um8669f->cur_device].dma; + } + + return 0xff; +} + +void um8669f_write(uint16_t port, uint8_t val, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + + if (um8669f->locked) { if (port == 0x108 && val == 0xaa) - um8669f_locked = 0; + um8669f->locked = 0; } else { if (port == 0x108) { if (val == 0x55) - um8669f_locked = 1; + um8669f->locked = 1; else - um8669f_curreg = val; + um8669f->cur_reg_108 = val; } else { - um8669f_regs[um8669f_curreg] = val; +// pclog("Write UM8669f register %02x %02x %04x:%04x %i\n", um8669f_curreg, val, CS,cpu_state.pc, ins); + um8669f->regs_108[um8669f->cur_reg_108] = val; - fdc_remove(); - if (um8669f_regs[0xc0] & 1) - fdc_add(); - - if (um8669f_regs[0xc0] & 2) + io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); + if (um8669f->regs_108[0xc1] & 0x80) { - temp = um8669f_regs[0xc3] & 1; /*might be & 2*/ - if (!(um8669f_regs[0xc1] & 2)) - temp |= 2; - switch (temp) - { - case 0: serial1_set(0x3f8, 4); break; - case 1: serial1_set(0x2f8, 4); break; - case 2: serial1_set(0x3e8, 4); break; - case 3: serial1_set(0x2e8, 4); break; - } - } - - if (um8669f_regs[0xc0] & 4) - { - temp = (um8669f_regs[0xc3] & 4) ? 0 : 1; /*might be & 8*/ - if (!(um8669f_regs[0xc1] & 4)) - temp |= 2; - switch (temp) - { - case 0: serial2_set(0x3f8, 3); break; - case 1: serial2_set(0x2f8, 3); break; - case 2: serial2_set(0x3e8, 3); break; - case 3: serial2_set(0x2e8, 3); break; - } - } - - lpt1_remove(); - lpt2_remove(); - temp = (um8669f_regs[0xc3] >> 4) & 3; - switch (temp) - { - case 0: lpt1_init(0x378); break; - case 1: lpt1_init(0x3bc); break; - case 2: lpt1_init(0x278); break; + io_sethandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_sethandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_sethandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); } } } } -uint8_t um8669f_read(uint16_t port, void *priv) +uint8_t um8669f_read(uint16_t port, void *p) { -// pclog("um8669f_read : port=%04x reg %02X locked=%i\n", port, um8669f_curreg, um8669f_locked); - if (um8669f_locked) - return 0xff; + um8669f_t *um8669f = (um8669f_t *)p; + +// pclog("um8669f_read : port=%04x reg %02X locked=%i %02x\n", port, um8669f_curreg, um8669f_locked, um8669f_regs[um8669f_curreg]); + if (um8669f->locked) + return 0xff; if (port == 0x108) - return um8669f_curreg; /*???*/ + return um8669f->cur_reg_108; /*???*/ else - return um8669f_regs[um8669f_curreg]; + return um8669f->regs_108[um8669f->cur_reg_108]; } void um8669f_init() { - io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL); - um8669f_locked = 1; + memset(&um8669f_global, 0, sizeof(um8669f_t)); + + um8669f_global.locked = 1; + + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, &um8669f_global); }