Re-implemented UM8669F emulation.
This commit is contained in:
parent
b0215f309a
commit
668a0dd18d
1 changed files with 157 additions and 85 deletions
244
src/um8669f.c
244
src/um8669f.c
|
|
@ -5,36 +5,21 @@
|
||||||
data read/write to 109
|
data read/write to 109
|
||||||
55 to 108 locks
|
55 to 108 locks
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
C0
|
|
||||||
bit 3 = LPT1 enable
|
|
||||||
bit 2 = COM2 enable
|
|
||||||
bit 1 = COM1 enable
|
|
||||||
bit 0 = FDC enable
|
|
||||||
|
|
||||||
C1
|
C1
|
||||||
bits 7-6 = LPT1 mode : 11 = ECP/EPP, 01 = EPP, 10 = SPP
|
bit 7 - enable PnP registers
|
||||||
bit 3 = clear when LPT1 = 278
|
|
||||||
|
|
||||||
C3
|
PnP registers :
|
||||||
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
|
|
||||||
|
|
||||||
COM1 :
|
07 - device :
|
||||||
3f8, IRQ4 - C1 = BF, C3 = 00
|
0 = FDC
|
||||||
2f8, IRQ3 - C1 = BF, C3 = 03
|
1 = COM1
|
||||||
3e8, IRQ4 - C1 = BD, C3 = 00
|
2 = COM2
|
||||||
2e8, IRQ3 - B1 = BD, C3 = 03
|
3 = LPT1
|
||||||
|
5 = Game port
|
||||||
COM2 :
|
30 - enable
|
||||||
3f8, IRQ4 - C1 = BF, C3 = 0C
|
60/61 - addr
|
||||||
2f8, IRQ3 - C1 = BF, C3 = 00
|
70 - IRQ
|
||||||
3e8, IRQ4 - C1 = BB, C3 = 0C
|
74 - DMA*/
|
||||||
2e8, IRQ3 - C1 = BB, C3 = 00
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ibm.h"
|
#include "ibm.h"
|
||||||
|
|
||||||
|
|
@ -44,91 +29,178 @@ COM2 :
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "um8669f.h"
|
#include "um8669f.h"
|
||||||
|
|
||||||
static int um8669f_locked;
|
typedef struct um8669f_t
|
||||||
static int um8669f_curreg;
|
|
||||||
static uint8_t um8669f_regs[256];
|
|
||||||
|
|
||||||
void um8669f_write(uint16_t port, uint8_t val, void *priv)
|
|
||||||
{
|
{
|
||||||
int temp;
|
int locked;
|
||||||
// pclog("um8669f_write : port=%04x reg %02X = %02X locked=%i\n", port, um8669f_curreg, val, um8669f_locked);
|
int cur_reg_108;
|
||||||
if (um8669f_locked)
|
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)
|
if (port == 0x108 && val == 0xaa)
|
||||||
um8669f_locked = 0;
|
um8669f->locked = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (port == 0x108)
|
if (port == 0x108)
|
||||||
{
|
{
|
||||||
if (val == 0x55)
|
if (val == 0x55)
|
||||||
um8669f_locked = 1;
|
um8669f->locked = 1;
|
||||||
else
|
else
|
||||||
um8669f_curreg = val;
|
um8669f->cur_reg_108 = val;
|
||||||
}
|
}
|
||||||
else
|
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();
|
io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f);
|
||||||
if (um8669f_regs[0xc0] & 1)
|
io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f);
|
||||||
fdc_add();
|
io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f);
|
||||||
|
if (um8669f->regs_108[0xc1] & 0x80)
|
||||||
if (um8669f_regs[0xc0] & 2)
|
|
||||||
{
|
{
|
||||||
temp = um8669f_regs[0xc3] & 1; /*might be & 2*/
|
io_sethandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f);
|
||||||
if (!(um8669f_regs[0xc1] & 2))
|
io_sethandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f);
|
||||||
temp |= 2;
|
io_sethandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
um8669f_t *um8669f = (um8669f_t *)p;
|
||||||
if (um8669f_locked)
|
|
||||||
return 0xff;
|
// 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)
|
if (port == 0x108)
|
||||||
return um8669f_curreg; /*???*/
|
return um8669f->cur_reg_108; /*???*/
|
||||||
else
|
else
|
||||||
return um8669f_regs[um8669f_curreg];
|
return um8669f->regs_108[um8669f->cur_reg_108];
|
||||||
}
|
}
|
||||||
|
|
||||||
void um8669f_init()
|
void um8669f_init()
|
||||||
{
|
{
|
||||||
io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL);
|
memset(&um8669f_global, 0, sizeof(um8669f_t));
|
||||||
um8669f_locked = 1;
|
|
||||||
|
um8669f_global.locked = 1;
|
||||||
|
|
||||||
|
io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, &um8669f_global);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue