WinUAE/x86.cpp
2015-09-04 22:36:11 +02:00

3460 lines
76 KiB
C++

/*
* UAE - The Un*x Amiga Emulator
*
* X86 Bridge board emulation
* A1060, A2088, A2088T, A2286, A2386
*
* Copyright 2015 Toni Wilen
* 8088 x86 and PC support chip emulation from Fake86.
* 80286+ CPU and AT support chip emulation from DOSBox.
*
*/
#define X86_DEBUG_BRIDGE 1
#define FLOPPY_IO_DEBUG 0
#define X86_DEBUG_BRIDGE_IO 0
#define X86_IO_PORT_DEBUG 0
#define DEBUG_DMA 0
#define DEBUG_PIT 0
#define DEBUG_INT 0
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "custom.h"
#include "memory.h"
#include "debug.h"
#include "x86.h"
#include "newcpu.h"
#include "uae.h"
#include "rommgr.h"
#include "zfile.h"
#include "disk.h"
#include "driveclick.h"
#include "scsi.h"
#include "idecontrollers.h"
#include "gfxboard.h"
#include "dosbox/dosbox.h"
#include "dosbox/mem.h"
#include "dosbox/paging.h"
#include "dosbox/setup.h"
#include "dosbox/cpu.h"
#include "dosbox/pic.h"
#include "dosbox/timer.h"
typedef Bits(CPU_Decoder)(void);
extern CPU_Decoder *cpudecoder;
extern Bit32s CPU_Cycles;
#define TYPE_SIDECAR 0
#define TYPE_2088 1
#define TYPE_2088T 2
#define TYPE_2286 3
#define TYPE_2386 4
void x86_reset(void);
int x86_execute(void);
void exec86(uint32_t execloops);
void reset86(int v20);
void intcall86(uint8_t intnum);
void x86_doirq(uint8_t irqnum);
static frame_time_t last_cycles;
#define DEFAULT_X86_INSTRUCTION_COUNT 120
static int x86_instruction_count;
static bool x86_turbo_allowed;
static bool x86_turbo_enabled;
bool x86_turbo_on;
bool x86_cpu_active;
void CPU_Init(Section*, int, int);
void CPU_ShutDown(Section*);
void CPU_JMP(bool use32, Bitu selector, Bitu offset, Bitu oldeip);
void PAGING_Init(Section * sec);
void MEM_Init(Section * sec);
void MEM_ShutDown(Section * sec);
void CMOS_Init(Section* sec, int);
void CMOS_Destroy(Section* sec);
void PIC_Init(Section* sec);
void PIC_Destroy(Section* sec);
void TIMER_Destroy(Section*);
void TIMER_Init(Section* sec);
static Section_prop *dosbox_sec;
Bitu x86_in_keyboard(Bitu port);
void x86_out_keyboard(Bitu port, Bitu val);
void cmos_selreg(Bitu port, Bitu val, Bitu iolen);
void cmos_writereg(Bitu port, Bitu val, Bitu iolen);
Bitu cmos_readreg(Bitu port, Bitu iolen);
void x86_pic_write(Bitu port, Bitu val);
Bitu x86_pic_read(Bitu port);
void x86_timer_write(Bitu port, Bitu val);
Bitu x86_timer_read(Bitu port);
void PIC_ActivateIRQ(Bitu irq);
void PIC_DeActivateIRQ(Bitu irq);
void PIC_runIRQs(void);
void KEYBOARD_AddBuffer(Bit8u data);
void FPU_Init(Section*);
Bit8u *x86_cmos_regs(Bit8u *regs);
void MEM_SetVGAHandler(void);
Bit32s ticksDone;
Bit32u ticksScheduled;
HostPt mono_start, mono_end, color_start, color_end;
int x86_memsize;
int x86_biosstart;
int x86_fpu_enabled;
int x86_cmos_bank;
int x86_xrom_start[2];
int x86_xrom_end[2];
int x86_vga_mode;
struct x86_bridge
{
uae_u8 acmemory[128];
addrbank *bank;
int configured;
int type;
uaecptr baseaddress;
int pc_maxram;
uae_u8 *pc_ram;
uae_u8 *pc_rom;
uae_u8 *io_ports;
uae_u8 *amiga_io;
bool x86_reset;
bool amiga_irq;
bool amiga_forced_interrupts;
bool pc_irq3a, pc_irq3b, pc_irq7;
uae_u8 pc_jumpers;
int pc_maxbaseram;
int bios_size;
int settings;
int dosbox_cpu;
int dosbox_cpu_arch;
bool x86_reset_requested;
struct zfile *cmosfile;
uae_u8 cmosregs[3 * 0x40];
uae_u8 vlsi_regs[0x100];
int a2386_default_video;
int cmossize;
int scamp_idx1, scamp_idx2;
uae_u8 rombank[1024 * 1024 / 4096];
float dosbox_vpos_tick;
float dosbox_tick_vpos_cnt;
struct romconfig *rc;
};
static int x86_found;
#define X86_BRIDGE_A1060 0
#define X86_BRIDGE_MAX (X86_BRIDGE_A1060 + 1)
#define ACCESS_MODE_BYTE 0
#define ACCESS_MODE_WORD 1
#define ACCESS_MODE_GFX 2
#define ACCESS_MODE_IO 3
#define IO_AMIGA_INTERRUPT_STATUS 0x1ff1
#define IO_PC_INTERRUPT_STATUS 0x1ff3
#define IO_NEGATE_PC_RESET 0x1ff5
#define IO_MODE_REGISTER 0x1ff7
#define IO_INTERRUPT_MASK 0x1ff9
#define IO_PC_INTERRUPT_CONTROL 0x1ffb
#define IO_CONTROL_REGISTER 0x1ffd
#define IO_KEYBOARD_REGISTER_A1000 0x61f
#define IO_KEYBOARD_REGISTER_A2000 0x1fff
#define IO_A2386_CONFIG 0x1f9f
#define ISVGA() (currprefs.rtgmem_type == GFXBOARD_VGA)
static struct x86_bridge *bridges[X86_BRIDGE_MAX];
static struct x86_bridge *x86_bridge_alloc(void)
{
struct x86_bridge *xb = xcalloc(struct x86_bridge, 1);
return xb;
};
void x86_init_reset(void)
{
struct x86_bridge *xb = bridges[0];
xb->x86_reset_requested = true;
write_log(_T("8042 CPU reset requested\n"));
}
static void reset_dosbox_cpu(void)
{
struct x86_bridge *xb = bridges[0];
CPU_ShutDown(dosbox_sec);
CPU_Init(dosbox_sec, xb->dosbox_cpu, xb->dosbox_cpu_arch);
CPU_JMP(false, 0xffff, 0, 0);
}
static void reset_x86_cpu(struct x86_bridge *xb)
{
write_log(_T("x86 CPU reset\n"));
if (!xb->dosbox_cpu) {
reset86(xb->type == ROMTYPE_A2088T);
} else {
reset_dosbox_cpu();
}
// reset x86 hd controllers
x86_ide_hd_put(-1, 0, 0);
x86_xt_hd_bput(-1, 0);
}
uint8_t x86_get_jumpers(void)
{
struct x86_bridge *xb = bridges[0];
uint8_t v = 0;
if (xb->type >= TYPE_2286) {
if (xb->pc_maxbaseram > 512 * 1024)
v |= 0x20;
}
if (xb->type == TYPE_2386) {
// A2386 = software controlled
if (xb->a2386_default_video)
v |= 0x40;
} else {
// Others have default video jumper
if (!(xb->settings & (1 << 14))) {
// default video mde, 0 = cga, 1 = mda
v |= 0x40;
}
}
if (!(xb->settings & (1 << 15))) {
// key lock state: 0 = on, 1 = off
v |= 0x80;
}
return v;
}
static uae_u8 get_mode_register(struct x86_bridge *xb, uae_u8 v)
{
if (xb->type == TYPE_SIDECAR) {
// PC/XT + keyboard
v = 0x84;
if (!(xb->settings & (1 << 12)))
v |= 0x02;
if (!(xb->settings & (1 << 8)))
v |= 0x08;
if (!(xb->settings & (1 << 9)))
v |= 0x10;
if ((xb->settings & (1 << 10)))
v |= 0x20;
if ((xb->settings & (1 << 11)))
v |= 0x40;
} else if (xb->type < TYPE_2286) {
// PC/XT
v |= 0x80;
} else {
// AT
v &= ~0x80;
}
return v;
}
static uae_u8 x86_bridge_put_io(struct x86_bridge *xb, uaecptr addr, uae_u8 v)
{
#if X86_DEBUG_BRIDGE_IO
write_log(_T("IO write %08x %02x\n"), addr, v);
#endif
switch (addr)
{
// read-only
case IO_AMIGA_INTERRUPT_STATUS:
v = xb->amiga_io[addr];
break;
case IO_PC_INTERRUPT_STATUS:
v = xb->amiga_io[addr];
#if X86_DEBUG_BRIDGE_IRQ
write_log(_T("IO_PC_INTERRUPT_STATUS %02x\n"), v);
#endif
break;
case IO_NEGATE_PC_RESET:
v = xb->amiga_io[addr];
break;
case IO_PC_INTERRUPT_CONTROL:
if ((v & 1) || (v & (2 | 4 | 8)) != (2 | 4 | 8)) {
#if X86_DEBUG_BRIDGE_IRQ
write_log(_T("IO_PC_INTERRUPT_CONTROL %02x\n"), v);
#endif
if (xb->type < TYPE_2286 && (v & 1))
x86_doirq(1);
if (!(v & 2) || !(v & 4))
x86_doirq(3);
if (!(v & 8))
x86_doirq(7);
}
break;
case IO_CONTROL_REGISTER:
if (!(v & 0x4)) {
xb->x86_reset = true;
}
if (!(v & 1))
v |= 2;
else if (!(v & 2))
v |= 1;
#if X86_DEBUG_BRIDGE_IO
write_log(_T("IO_CONTROL_REGISTER %02x\n"), v);
#endif
break;
case IO_KEYBOARD_REGISTER_A1000:
if (xb->type == TYPE_SIDECAR) {
#if X86_DEBUG_BRIDGE_IO
write_log(_T("IO_KEYBOARD_REGISTER %02x\n"), v);
#endif
xb->io_ports[0x60] = v;
}
break;
case IO_KEYBOARD_REGISTER_A2000:
if (xb->type >= TYPE_2088) {
#if X86_DEBUG_BRIDGE_IO
write_log(_T("IO_KEYBOARD_REGISTER %02x\n"), v);
#endif
xb->io_ports[0x60] = v;
if (xb->type >= TYPE_2286) {
KEYBOARD_AddBuffer(v);
}
}
break;
case IO_MODE_REGISTER:
v = get_mode_register(xb, v);
#if X86_DEBUG_BRIDGE_IO
write_log(_T("IO_MODE_REGISTER %02x\n"), v);
#endif
break;
case IO_INTERRUPT_MASK:
break;
case IO_A2386_CONFIG:
write_log(_T("A2386 CONFIG BYTE %02x\n"), v);
if (v == 8 || v == 9) {
xb->a2386_default_video = v & 1;
write_log(_T("A2386 Default mode = %s\n"), xb->a2386_default_video ? _T("MDA") : _T("CGA"));
}
break;
default:
if (addr >= 0x400)
write_log(_T("Unknown bridge IO write %08x = %02x\n"), addr, v);
break;
}
xb->amiga_io[addr] = v;
return v;
}
static uae_u8 x86_bridge_get_io(struct x86_bridge *xb, uaecptr addr)
{
uae_u8 v = xb->amiga_io[addr];
v = xb->amiga_io[addr];
switch(addr)
{
case IO_AMIGA_INTERRUPT_STATUS:
xb->amiga_io[addr] = 0;
#if X86_DEBUG_BRIDGE_IRQ
if (v)
write_log(_T("IO_AMIGA_INTERRUPT_STATUS %02x. CLEARED.\n"), v);
#endif
break;
case IO_PC_INTERRUPT_STATUS:
v |= 0xf0;
#if X86_DEBUG_BRIDGE_IRQ
write_log(_T("IO_PC_INTERRUPT_STATUS %02x\n"), v);
#endif
break;
case IO_NEGATE_PC_RESET:
{
if (xb->x86_reset) {
reset_x86_cpu(xb);
xb->x86_reset = false;
}
// because janus.library has stupid CPU loop wait
int vp = vpos;
while (vp == vpos) {
x_do_cycles(maxhpos * CYCLE_UNIT);
}
}
break;
case IO_MODE_REGISTER:
v = get_mode_register(xb, v);
#if X86_DEBUG_BRIDGE_IO
write_log(_T("IO_MODE_REGISTER %02x\n"), v);
#endif
break;
default:
if (addr >= 0x400)
write_log(_T("Unknown bridge IO read %08x\n"), addr);
break;
}
return v;
}
static void set_interrupt(struct x86_bridge *xb, int bit)
{
if (xb->amiga_io[IO_AMIGA_INTERRUPT_STATUS] & (1 << bit))
return;
#if X86_DEBUG_BRIDGE_IRQ
write_log(_T("IO_AMIGA_INTERRUPT_STATUS set bit %d\n"), bit);
#endif
xb->amiga_io[IO_AMIGA_INTERRUPT_STATUS] |= 1 << bit;
x86_bridge_rethink();
}
/* 8237 and 8253 from fake86 with small modifications */
#define PIT_MODE_LATCHCOUNT 0
#define PIT_MODE_LOBYTE 1
#define PIT_MODE_HIBYTE 2
#define PIT_MODE_TOGGLE 3
struct i8253_s {
uint16_t chandata[3];
uint8_t accessmode[3];
uint8_t bytetoggle[3];
uint32_t effectivedata[3];
float chanfreq[3];
uint8_t active[3];
uint16_t counter[3];
};
static struct i8253_s i8253;
static uint16_t latched_val, latched;
static uint64_t hostfreq = 313 * 50 * 227;
static uint64_t tickgap, curtick, lasttick, lasti8253tick, i8253tickgap;
static void inittiming()
{
curtick = 0;
lasti8253tick = lasttick = curtick;
i8253tickgap = hostfreq / 119318;
}
static void timing(int count)
{
struct x86_bridge *xb = bridges[0];
curtick += count;
if (i8253.active[0]) { //timer interrupt channel on i8253
if (curtick >= (lasttick + tickgap)) {
lasttick = curtick;
x86_doirq(0);
}
}
if (curtick >= (lasti8253tick + i8253tickgap)) {
for (int i8253chan = 0; i8253chan<3; i8253chan++) {
bool cantrun = (i8253chan == 2 && !(xb->io_ports[0x61] & 1));
if (i8253.active[i8253chan] && !cantrun) {
if (i8253.counter[i8253chan] < 10)
i8253.counter[i8253chan] = i8253.chandata[i8253chan];
i8253.counter[i8253chan] -= 10;
}
}
lasti8253tick = curtick;
}
}
static void out8253(uint16_t portnum, uint8_t value)
{
uint8_t curbyte;
#if DEBUG_PIT
write_log("out8253(0x%X = %02x);\n", portnum, value);
#endif
portnum &= 3;
switch (portnum)
{
case 0:
case 1:
case 2: //channel data
if ((i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ((i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0)))
curbyte = 0;
else if ((i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ((i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1)))
curbyte = 1;
if (curbyte == 0) { //low byte
i8253.chandata[portnum] = (i8253.chandata[portnum] & 0xFF00) | value;
} else { //high byte
i8253.chandata[portnum] = (i8253.chandata[portnum] & 0x00FF) | ((uint16_t)value << 8);
}
if (i8253.chandata[portnum] == 0)
i8253.effectivedata[portnum] = 65536;
else
i8253.effectivedata[portnum] = i8253.chandata[portnum];
i8253.counter[portnum] = i8253.chandata[portnum];
i8253.active[portnum] = 1;
tickgap = (uint64_t)((float)hostfreq / (float)((float)1193182 / (float)i8253.effectivedata[0]));
if (i8253.accessmode[portnum] == PIT_MODE_TOGGLE)
i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1;
i8253.chanfreq[portnum] = (float)((uint32_t)(((float) 1193182.0 / (float)i8253.effectivedata[portnum]) * (float) 1000.0)) / (float) 1000.0;
//printf("[DEBUG] PIT channel %u counter changed to %u (%f Hz)\n", portnum, i8253.chandata[portnum], i8253.chanfreq[portnum]);
break;
case 3: //mode/command
i8253.accessmode[value >> 6] = (value >> 4) & 3;
if (i8253.accessmode[value >> 6] == PIT_MODE_LATCHCOUNT) {
latched_val = i8253.counter[value >> 6];
latched = 2;
} else if (i8253.accessmode[value >> 6] == PIT_MODE_TOGGLE)
i8253.bytetoggle[value >> 6] = 0;
break;
}
}
static uint8_t in8253(uint16_t portnum)
{
uint8_t curbyte;
uint8_t out = 0;
#if DEBUG_PIT
uint16_t portnum2 = portnum;
#endif
portnum &= 3;
switch (portnum)
{
case 0:
case 1:
case 2: //channel data
if (latched == 2) {
latched = 1;
out = latched_val & 0xff;
} else if (latched == 1) {
latched = 0;
out = latched_val >> 8;
} else {
if ((i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ((i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0)))
curbyte = 0;
else if ((i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ((i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1)))
curbyte = 1;
if ((i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_TOGGLE))
i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1;
if (curbyte == 0) { //low byte
out = ((uint8_t)i8253.counter[portnum]);
} else { //high byte
out = ((uint8_t)(i8253.counter[portnum] >> 8));
}
}
break;
}
#if DEBUG_PIT
write_log("in8253(0x%X = %02x);\n", portnum2, out);
#endif
return out;
}
struct dmachan_s {
uint32_t page;
uint32_t addr;
uint32_t reload;
uint32_t count;
uint8_t direction;
uint8_t autoinit;
uint8_t writemode;
uint8_t modeselect;
uint8_t masked;
uint8_t verifymode;
};
static struct dmachan_s dmachan[2 * 4];
static uae_u8 dmareg[2 * 16];
static uint8_t flipflop = 0;
static int write8237(struct x86_bridge *xb, uint8_t channel, uint8_t data)
{
if (dmachan[channel].masked)
return 0;
if (dmachan[channel].autoinit && (dmachan[channel].count > dmachan[channel].reload))
dmachan[channel].count = 0;
if (dmachan[channel].count > dmachan[channel].reload)
return 0;
//if (dmachan[channel].direction) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count];
// else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count];
if (!dmachan[channel].verifymode) {
xb->pc_ram[dmachan[channel].page + dmachan[channel].addr] = data;
if (dmachan[channel].direction == 0) {
dmachan[channel].addr++;
} else {
dmachan[channel].addr--;
}
dmachan[channel].addr &= 0xffff;
}
dmachan[channel].count++;
if (dmachan[channel].count > dmachan[channel].reload)
return -1;
return 1;
}
static uint8_t read8237(struct x86_bridge *xb, uint8_t channel, bool *end)
{
uint8_t ret = 128;
*end = false;
if (dmachan[channel].masked) {
*end = true;
return ret;
}
if (dmachan[channel].autoinit && (dmachan[channel].count > dmachan[channel].reload))
dmachan[channel].count = 0;
if (dmachan[channel].count > dmachan[channel].reload) {
*end = true;
return ret;
}
//if (dmachan[channel].direction) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count];
// else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count];
if (!dmachan[channel].verifymode) {
ret = xb->pc_ram[dmachan[channel].page + dmachan[channel].addr];
if (dmachan[channel].direction == 0) {
dmachan[channel].addr++;
} else {
dmachan[channel].addr--;
}
dmachan[channel].addr &= 0xffff;
}
dmachan[channel].count++;
if (dmachan[channel].count > dmachan[channel].reload)
*end = true;
return ret;
}
static void out8237(uint16_t addr, uint8_t value)
{
uint8_t channel;
int chipnum = 0;
int reg = -1;
#if DEBUG_DMA
write_log("out8237(0x%X, %X);\n", addr, value);
#endif
if (addr >= 0x80 && addr <= 0x8f) {
dmareg[addr & 0xf] = value;
reg = addr;
} else if (addr >= 0xc0 && addr <= 0xdf) {
reg = (addr - 0xc0) / 2;
chipnum = 4;
} else if (addr <= 0x0f) {
reg = addr;
chipnum = 0;
}
switch (reg) {
case 0x0:
case 0x2: //channel 1 address register
case 0x4:
case 0x6:
channel = reg / 2 + chipnum;
if (flipflop == 1)
dmachan[channel].addr = (dmachan[channel].addr & 0x00FF) | ((uint32_t)value << 8);
else
dmachan[channel].addr = (dmachan[channel].addr & 0xFF00) | value;
#if DEBUG_DMA
if (flipflop == 1) write_log("[NOTICE] DMA channel %d address register = %04X\n", channel, dmachan[channel].addr);
#endif
flipflop = ~flipflop & 1;
break;
case 0x1:
case 0x3: //channel 1 count register
case 0x5:
case 0x7:
channel = reg / 2 + chipnum;
if (flipflop == 1)
dmachan[channel].reload = (dmachan[channel].reload & 0x00FF) | ((uint32_t)value << 8);
else
dmachan[channel].reload = (dmachan[channel].reload & 0xFF00) | value;
if (flipflop == 1) {
if (dmachan[channel].reload == 0)
dmachan[channel].reload = 65536;
dmachan[channel].count = 0;
#if DEBUG_DMA
write_log("[NOTICE] DMA channel %d reload register = %04X\n", channel, dmachan[channel].reload);
#endif
}
flipflop = ~flipflop & 1;
break;
case 0xA: //write single mask register
channel = (value & 3) + chipnum;
dmachan[channel].masked = (value >> 2) & 1;
#if DEBUG_DMA
write_log("[NOTICE] DMA channel %u masking = %u\n", channel, dmachan[channel].masked);
#endif
break;
case 0xB: //write mode register
channel = (value & 3) + chipnum;
dmachan[channel].direction = (value >> 5) & 1;
dmachan[channel].autoinit = (value >> 4) & 1;
dmachan[channel].modeselect = (value >> 6) & 3;
dmachan[channel].writemode = (value >> 2) & 1; //not quite accurate
dmachan[channel].verifymode = ((value >> 2) & 3) == 0;
#if DEBUG_DMA
write_log("[NOTICE] DMA channel %u write mode reg: direction = %u, autoinit = %u, write mode = %u, verify mode = %u, mode select = %u\n",
channel, dmachan[channel].direction, dmachan[channel].autoinit, dmachan[channel].writemode, dmachan[channel].verifymode, dmachan[channel].modeselect);
#endif
break;
case 0xC: //clear byte pointer flip-flop
#if DEBUG_DMA
write_log("[NOTICE] DMA cleared byte pointer flip-flop\n");
#endif
flipflop = 0;
break;
case 0x89: // 6
case 0x8a: // 7
case 0x8b: // 5
case 0x81: // 2
case 0x82: // 3
case 0x83: // DMA channel 1 page register
// Original PC design. It can't get any more stupid.
if ((addr & 3) == 1)
channel = 2;
else if ((addr & 3) == 2)
channel = 3;
else
channel = 1;
if (addr >= 0x84)
channel += 4;
dmachan[channel].page = (uint32_t)value << 16;
#if DEBUG_DMA
write_log("[NOTICE] DMA channel %d page base = %05X\n", channel, dmachan[channel].page);
#endif
break;
}
}
static uint8_t in8237(uint16_t addr)
{
struct x86_bridge *xb = bridges[0];
uint8_t channel;
int reg = -1;
int chipnum = addr >= 0xc0 ? 4 : 0;
uint8_t out = 0;
if (addr >= 0xc0 && addr <= 0xdf) {
reg = (addr - 0xc0) / 2;
chipnum = 4;
} else if (addr <= 0x0f) {
reg = addr;
chipnum = 0;
}
switch (reg) {
case 0x0:
case 0x2: //channel 1 address register
case 0x4:
case 0x6:
channel = reg / 2 + chipnum;
flipflop = ~flipflop & 1;
if (flipflop == 0)
out = dmachan[channel].addr >> 8;
else
out = dmachan[channel].addr;
break;
case 0x1:
case 0x3: //channel 1 count register
case 0x5:
case 0x7:
channel = reg / 2 + chipnum;
flipflop = ~flipflop & 1;
if (flipflop == 0)
out = dmachan[channel].reload >> 8;
else
out = dmachan[channel].reload;
break;
}
if (addr >= 0x80 && addr <= 0x8f)
out = dmareg[addr & 0xf];
#if DEBUG_DMA
write_log("in8237(0x%X = %02x);\n", addr, out);
#endif
return out;
}
static int keyboardwaitack;
void x86_ack_keyboard(void)
{
if (keyboardwaitack)
set_interrupt(bridges[0], 4);
keyboardwaitack = 0;
}
struct structpic {
uint8_t imr; //mask register
uint8_t irr; //request register
uint8_t isr; //service register
uint8_t icwstep; //used during initialization to keep track of which ICW we're at
uint8_t icw[5];
uint8_t intoffset; //interrupt vector offset
uint8_t priority; //which IRQ has highest priority
uint8_t autoeoi; //automatic EOI mode
uint8_t readmode; //remember what to return on read register from OCW3
uint8_t enabled;
};
static struct structpic i8259[2];
static uint8_t in8259(uint16_t portnum)
{
struct x86_bridge *xb = bridges[0];
uint8_t out = 0;
int chipnum = (portnum & 0x80) ? 1 : 0;
if (chipnum && xb->type < TYPE_2286)
return 0;
switch (portnum & 1) {
case 0:
if (i8259[chipnum].readmode == 0)
out = (i8259[chipnum].irr);
else
out = (i8259[chipnum].isr);
break;
case 1: //read mask register
out = (i8259[chipnum].imr);
break;
}
#if DEBUG_INT
write_log("in8259(0x%X = %02x);\n", portnum, out);
#endif
return out;
}
extern uint32_t makeupticks;
void out8259(uint16_t portnum, uint8_t value)
{
struct x86_bridge *xb = bridges[0];
uint8_t i;
int chipnum = (portnum & 0x80) ? 1 : 0;
#if DEBUG_INT
write_log("out8259(0x%X = %02x);\n", portnum, value);
#endif
if (chipnum && xb->type < TYPE_2286)
return;
switch (portnum & 1) {
case 0:
if (value & 0x10) { //begin initialization sequence
i8259[chipnum].icwstep = 1;
i8259[chipnum].imr = 0; //clear interrupt mask register
i8259[chipnum].icw[i8259[chipnum].icwstep++] = value;
return;
}
if ((value & 0x98) == 8) { //it's an OCW3
if (value & 2)
i8259[chipnum].readmode = value & 2;
}
if (value & 0x20) { //EOI command
if (!chipnum) {
x86_ack_keyboard();
keyboardwaitack = 0;
}
for (i = 0; i < 8; i++)
if ((i8259[chipnum].isr >> i) & 1) {
i8259[chipnum].isr ^= (1 << i);
#if 0
if ((i == 0) && (makeupticks>0)) {
makeupticks = 0;
i8259.irr |= 1;
}
#endif
return;
}
}
break;
case 1:
if ((i8259[chipnum].icwstep == 3) && (i8259[chipnum].icw[1] & 2))
i8259[chipnum].icwstep = 4; //single mode, so don't read ICW3
if (i8259[chipnum].icwstep<5) {
i8259[chipnum].icw[i8259[chipnum].icwstep++] = value;
return;
}
//if we get to this point, this is just a new IMR value
i8259[chipnum].imr = value;
break;
}
}
static uint8_t nextintr(void)
{
uint8_t i, tmpirr;
tmpirr = i8259[0].irr & (~i8259[0].imr); //XOR request register with inverted mask register
for (i = 0; i<8; i++) {
if ((tmpirr >> i) & 1) {
i8259[0].irr ^= (1 << i);
i8259[0].isr |= (1 << i);
return(i8259[0].icw[2] + i);
}
}
return(0); //this won't be reached, but without it the compiler gives a warning
}
void x86_clearirq(uint8_t irqnum)
{
struct x86_bridge *xb = bridges[0];
if (xb->dosbox_cpu) {
PIC_DeActivateIRQ(irqnum);
}
}
void x86_doirq(uint8_t irqnum)
{
struct x86_bridge *xb = bridges[0];
if (xb->dosbox_cpu) {
PIC_ActivateIRQ(irqnum);
} else {
i8259[0].irr |= (1 << irqnum);
}
if (irqnum == 1)
keyboardwaitack = 1;
}
void x86_doirq_keyboard(void)
{
x86_doirq(1);
}
void check_x86_irq(void)
{
struct x86_bridge *xb = bridges[0];
if (xb->dosbox_cpu) {
PIC_runIRQs();
} else {
if (i8259[0].irr & (~i8259[0].imr)) {
uint8_t irq = nextintr();
intcall86(irq); /* get next interrupt from the i8259, if any */
}
}
}
struct pc_floppy
{
int seek_offset;
int phys_cyl;
int cyl;
uae_u8 sector;
uae_u8 head;
};
static struct pc_floppy floppy_pc[4];
static uae_u8 floppy_dpc;
static uae_s8 floppy_idx;
static uae_u8 floppy_dir;
static uae_u8 floppy_cmd_len;
static uae_u8 floppy_cmd[16];
static uae_u8 floppy_result[16];
static uae_u8 floppy_status[4];
static uae_u8 floppy_num;
static int floppy_seeking[4];
static uae_u8 floppy_seekcyl[4];
static int floppy_delay_hsync;
static bool floppy_did_reset;
static bool floppy_irq;
static uae_s8 floppy_rate;
#define PC_SEEK_DELAY 50
static void floppy_reset(void)
{
struct x86_bridge *xb = bridges[0];
write_log(_T("Floppy reset\n"));
floppy_idx = 0;
floppy_dir = 0;
floppy_did_reset = true;
if (xb->type == TYPE_2286) {
// apparently A2286 BIOS AT driver assumes
// floppy reset also resets IDE.
// Perhaps this is forgotten feature from
// Commodore PC model that uses same BIOS variant?
x86_ide_hd_put(-1, 0, 0);
}
}
static void floppy_hardreset(void)
{
floppy_rate = -1;
floppy_reset();
}
static void do_floppy_irq2(void)
{
write_log(_T("floppy%d irq (enable=%d)\n"), floppy_num, (floppy_dpc & 8) != 0);
if (floppy_dpc & 8) {
floppy_irq = true;
x86_doirq(6);
}
}
static void do_floppy_irq(void)
{
if (floppy_delay_hsync > 0) {
do_floppy_irq2();
}
floppy_delay_hsync = 0;
}
static void do_floppy_seek(int num, int error)
{
struct pc_floppy *pcf = &floppy_pc[floppy_num];
disk_reserved_reset_disk_change(num);
if (!error) {
struct floppy_reserved fr = { 0 };
bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
if (floppy_seekcyl[num] != pcf->phys_cyl) {
if (floppy_seekcyl[num] > pcf->phys_cyl)
pcf->phys_cyl++;
else if (pcf->phys_cyl > 0)
pcf->phys_cyl--;
#ifdef DRIVESOUND
if (valid_floppy)
driveclick_click(fr.num, pcf->phys_cyl);
#endif
write_log(_T("Floppy%d seeking.. %d\n"), floppy_num, pcf->phys_cyl);
if (pcf->phys_cyl - pcf->seek_offset <= 0) {
pcf->phys_cyl = 0;
if (pcf->seek_offset) {
floppy_seekcyl[num] = 0;
write_log(_T("Floppy%d early track zero\n"), floppy_num);
pcf->seek_offset = 0;
}
}
if (valid_floppy && fr.cyls < 80 && fr.drive_cyls >=80)
pcf->cyl = pcf->phys_cyl / 2;
else
pcf->cyl = pcf->phys_cyl;
floppy_seeking[num] = PC_SEEK_DELAY;
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
return;
}
if (valid_floppy && pcf->phys_cyl > fr.drive_cyls + 3) {
pcf->seek_offset = pcf->phys_cyl - (fr.drive_cyls + 3);
pcf->phys_cyl = fr.drive_cyls + 3;
goto done;
}
if (valid_floppy && fr.cyls < 80 && fr.drive_cyls >= 80)
pcf->cyl = pcf->phys_cyl / 2;
else
pcf->cyl = pcf->phys_cyl;
if (floppy_seekcyl[num] != pcf->phys_cyl)
return;
}
done:
write_log(_T("Floppy%d seek done err=%d. pcyl=%d cyl=%d h=%d\n"), floppy_num, error, pcf->phys_cyl,pcf->cyl, pcf->head);
floppy_status[0] = 0;
floppy_status[0] |= 0x20; // seek end
if (error) {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[0] |= 0x10; // equipment check
}
floppy_status[0] |= num;
floppy_status[0] |= pcf->head ? 4 : 0;
do_floppy_irq2();
}
static int floppy_exists(void)
{
uae_u8 sel = floppy_dpc & 3;
if (sel == 0)
return 0;
if (sel == 1)
return 1;
return -1;
}
static int floppy_selected(void)
{
uae_u8 motormask = (floppy_dpc >> 4) & 15;
uae_u8 sel = floppy_dpc & 3;
if (floppy_exists() < 0)
return -1;
if (motormask & (1 << sel))
return sel;
return -1;
}
static bool floppy_valid_rate(struct floppy_reserved *fr)
{
struct x86_bridge *xb = bridges[0];
// A2386 BIOS sets 720k data rate for both 720k and 1.4M drives
// probably because it thinks Amiga half-speed drive is connected?
if (xb->type == TYPE_2386 && fr->rate == 0 && floppy_rate == 2)
return true;
return fr->rate == floppy_rate || floppy_rate < 0;
}
static void floppy_do_cmd(struct x86_bridge *xb)
{
uae_u8 cmd = floppy_cmd[0];
struct pc_floppy *pcf = &floppy_pc[floppy_num];
struct floppy_reserved fr = { 0 };
bool valid_floppy;
valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
if (floppy_cmd_len) {
write_log(_T("Command: "));
for (int i = 0; i < floppy_cmd_len; i++) {
write_log(_T("%02x "), floppy_cmd[i]);
}
write_log(_T("\n"));
}
if (cmd == 8) {
write_log(_T("Floppy%d Sense Interrupt Status\n"), floppy_num);
floppy_cmd_len = 2;
if (floppy_irq) {
write_log(_T("Floppy interrupt reset\n"));
}
if (!floppy_irq) {
floppy_status[0] = 0x80;
floppy_cmd_len = 1;
} else if (floppy_did_reset) {
floppy_did_reset = false;
// 0xc0 status after reset.
floppy_status[0] = 0xc0;
}
x86_clearirq(6);
floppy_irq = false;
floppy_result[0] = floppy_status[0];
floppy_result[1] = pcf->phys_cyl;
floppy_status[0] = 0;
goto end;
}
memset(floppy_status, 0, sizeof floppy_status);
memset(floppy_result, 0, sizeof floppy_result);
if (floppy_exists() >= 0) {
if (pcf->head)
floppy_status[0] |= 4;
floppy_status[3] |= pcf->phys_cyl == 0 ? 0x10 : 0x00;
floppy_status[3] |= pcf->head ? 4 : 0;
floppy_status[3] |= 8; // two side
if (fr.wrprot)
floppy_status[3] |= 0x40; // write protected
floppy_status[3] |= 0x20; // ready
}
floppy_status[3] |= floppy_dpc & 3;
floppy_status[0] |= floppy_dpc & 3;
floppy_cmd_len = 0;
switch (cmd & 31)
{
case 3:
write_log(_T("Floppy%d Specify SRT=%d HUT=%d HLT=%d ND=%d\n"), floppy_num, floppy_cmd[1] >> 4, floppy_cmd[1] & 0x0f, floppy_cmd[2] >> 1, floppy_cmd[2] & 1);
floppy_delay_hsync = -5;
break;
case 4:
write_log(_T("Floppy%d Sense Drive Status\n"), floppy_num);
floppy_delay_hsync = 5;
floppy_result[0] = floppy_status[3];
floppy_cmd_len = 1;
break;
case 5:
{
write_log(_T("Floppy%d write MT=%d MF=%d C=%d:H=%d:R=%d:N=%d:EOT=%d:GPL=%d:DTL=%d\n"),
(floppy_cmd[0] & 0x80) ? 1 : 0, (floppy_cmd[0] & 0x40) ? 1 : 0,
floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5],
floppy_cmd[6], floppy_cmd[7], floppy_cmd[8]);
write_log(_T("DMA addr %08x len %04x\n"), dmachan[2].page | dmachan[2].addr, dmachan[2].reload);
floppy_delay_hsync = 50;
int eot = floppy_cmd[6];
bool mt = (floppy_cmd[0] & 0x80) != 0;
int cyl = pcf->cyl;
if (valid_floppy) {
if (fr.img && pcf->cyl != floppy_cmd[2]) {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[2] |= 0x20; // wrong cylinder
} else if (fr.img) {
bool end = false;
pcf->sector = floppy_cmd[4] - 1;
pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
while (!end) {
int len = 128 << floppy_cmd[5];
uae_u8 buf[512] = { 0 };
for (int i = 0; i < 512 && i < len; i++) {
buf[i] = read8237(xb, 2, &end);
if (end)
break;
}
zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET);
zfile_fwrite(buf, 1, 512, fr.img);
pcf->sector++;
if (!(floppy_cmd[0] & 0x80))
break;
if (pcf->sector == eot) {
pcf->sector = 0;
if (mt) {
if (pcf->head)
pcf->cyl++;
pcf->head ^= 1;
}
break;
}
if (pcf->sector >= fr.secs) {
pcf->sector = 0;
pcf->head ^= 1;
}
}
floppy_result[3] = cyl;
floppy_result[4] = pcf->head;
floppy_result[5] = pcf->sector + 1;
floppy_result[6] = floppy_cmd[5];
} else {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[0] |= 0x10; // equipment check
}
}
floppy_cmd_len = 7;
if (fr.wrprot) {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[1] |= 0x02; // not writable
}
floppy_result[0] = floppy_status[0];
floppy_result[1] = floppy_status[1];
floppy_result[2] = floppy_status[2];
floppy_delay_hsync = 10;
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
}
break;
case 6:
{
write_log(_T("Floppy%d read MT=%d MF=%d SK=%d C=%d:H=%d:R=%d:N=%d:EOT=%d:GPL=%d:DTL=%d\n"),
floppy_num, (floppy_cmd[0] & 0x80) ? 1 : 0, (floppy_cmd[0] & 0x40) ? 1 : 0, (floppy_cmd[0] & 0x20) ? 1 : 0,
floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5],
floppy_cmd[6], floppy_cmd[7], floppy_cmd[8]);
write_log(_T("DMA addr %08x len %04x\n"), dmachan[2].page | dmachan[2].addr, dmachan[2].reload);
floppy_delay_hsync = 50;
int eot = floppy_cmd[6];
bool mt = (floppy_cmd[0] & 0x80) != 0;
int cyl = pcf->cyl;
bool nodata = false;
if (valid_floppy) {
if (!floppy_valid_rate(&fr)) {
nodata = true;
} else if (pcf->head && fr.heads == 1) {
nodata = true;
} else if (fr.img && pcf->cyl != floppy_cmd[2]) {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[2] |= 0x20; // wrong cylinder
} else if (fr.img) {
bool end = false;
pcf->sector = floppy_cmd[4] - 1;
pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
while (!end) {
int len = 128 << floppy_cmd[5];
uae_u8 buf[512];
zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET);
zfile_fread(buf, 1, 512, fr.img);
for (int i = 0; i < 512 && i < len; i++) {
if (write8237(xb, 2, buf[i]) <= 0)
end = true;
}
pcf->sector++;
if (!(floppy_cmd[0] & 0x80))
break;
if (pcf->sector == eot) {
pcf->sector = 0;
if (mt) {
if (pcf->head)
pcf->cyl++;
pcf->head ^= 1;
}
break;
}
if (pcf->sector >= fr.secs) {
pcf->sector = 0;
pcf->head ^= 1;
}
}
floppy_result[3] = cyl;
floppy_result[4] = pcf->head;
floppy_result[5] = pcf->sector + 1;
floppy_result[6] = floppy_cmd[5];
} else {
nodata = true;
}
}
if (nodata) {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[1] |= 0x04; // no data
}
floppy_cmd_len = 7;
floppy_result[0] = floppy_status[0];
floppy_result[1] = floppy_status[1];
floppy_result[2] = floppy_status[2];
floppy_delay_hsync = 10;
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
}
break;
case 7:
write_log(_T("Floppy%d recalibrate\n"), floppy_num);
if (valid_floppy) {
floppy_seekcyl[floppy_num] = 0;
floppy_seeking[floppy_num] = PC_SEEK_DELAY;
} else {
floppy_seeking[floppy_num] = -PC_SEEK_DELAY;
}
break;
case 10:
write_log(_T("Floppy read ID\n"));
if (!valid_floppy || !fr.img || !floppy_valid_rate(&fr) || (pcf->head && fr.heads == 1)) {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[1] |= 0x04; // no data
}
floppy_cmd_len = 7;
floppy_result[0] = floppy_status[0];
floppy_result[1] = floppy_status[1];
floppy_result[2] = floppy_status[2];
floppy_result[3] = pcf->cyl;
floppy_result[4] = pcf->head;
floppy_result[5] = pcf->sector + 1;
floppy_result[6] = 2;
if (valid_floppy && fr.img) {
pcf->sector++;
pcf->sector %= fr.secs;
}
floppy_delay_hsync = 10;
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
break;
case 13:
{
write_log(_T("Floppy%d format MF=%d N=%d:SC=%d:GPL=%d:D=%d\n"),
floppy_num, (floppy_cmd[0] & 0x40) ? 1 : 0,
floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5]);
write_log(_T("DMA addr %08x len %04x\n"), dmachan[2].page | dmachan[2].addr, dmachan[2].reload);
int secs = floppy_cmd[3];
if (valid_floppy && fr.img) {
// TODO: CHRN values totally ignored
pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
uae_u8 buf[512];
memset(buf, floppy_cmd[5], sizeof buf);
for (int i = 0; i < secs && i < fr.secs; i++) {
bool dmaend;
uae_u8 cx = read8237(xb, 2, &dmaend);
uae_u8 hx = read8237(xb, 2, &dmaend);
uae_u8 rx = read8237(xb, 2, &dmaend);
uae_u8 nx = read8237(xb, 2, &dmaend);
pcf->sector = rx - 1;
write_log(_T("Floppy%d %d/%d: C=%d H=%d R=%d N=%d\n"), floppy_num, i, fr.secs, cx, hx, rx, nx);
zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET);
zfile_fwrite(buf, 1, 512, fr.img);
}
} else {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[0] |= 0x10; // equipment check
}
floppy_cmd_len = 7;
if (fr.wrprot) {
floppy_status[0] |= 0x40; // abnormal termination
floppy_status[1] |= 0x02; // not writable
}
floppy_result[0] = floppy_status[0];
floppy_result[1] = floppy_status[1];
floppy_result[2] = floppy_status[2];
floppy_result[3] = pcf->cyl;
floppy_result[4] = pcf->head;
floppy_result[5] = pcf->sector + 1;
floppy_result[6] = floppy_cmd[2];
floppy_delay_hsync = 10;
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
}
break;
case 15:
{
int newcyl = floppy_cmd[2];
write_log(_T("Floppy%d seek %d->%d (max %d)\n"), floppy_num, pcf->phys_cyl, newcyl, fr.cyls);
floppy_seekcyl[floppy_num] = newcyl;
floppy_seeking[floppy_num] = valid_floppy ? PC_SEEK_DELAY : -PC_SEEK_DELAY;
pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
}
break;
default:
floppy_status[0] = 0x80;
floppy_cmd_len = 1;
break;
}
end:
if (floppy_cmd_len) {
floppy_idx = -1;
floppy_dir = 1;
write_log(_T("Status return: "));
for (int i = 0; i < floppy_cmd_len; i++) {
write_log(_T("%02x "), floppy_result[i]);
}
write_log(_T("\n"));
} else {
floppy_idx = 0;
floppy_dir = 0;
}
}
static void outfloppy(struct x86_bridge *xb, int portnum, uae_u8 v)
{
if (!x86_turbo_allowed) {
x86_turbo_allowed = true;
}
switch (portnum)
{
case 0x3f2: // dpc
if ((v & 4) && !(floppy_dpc & 4)) {
floppy_reset();
floppy_delay_hsync = 20;
}
#if FLOPPY_IO_DEBUG
write_log(_T("DPC=%02x: Motormask %02x sel=%d dmaen=%d reset=%d\n"), v, (v >> 4) & 15, v & 3, (v & 8) ? 1 : 0, (v & 4) ? 0 : 1);
#endif
#ifdef DRIVESOUND
for (int i = 0; i < 2; i++) {
int mask = 0x10 << i;
if ((floppy_dpc & mask) != (v & mask)) {
struct floppy_reserved fr = { 0 };
bool valid_floppy = disk_reserved_getinfo(i, &fr);
if (valid_floppy)
driveclick_motor(fr.num, (v & mask) ? 1 : 0);
}
}
#endif
floppy_dpc = v;
floppy_num = v & 3;
for (int i = 0; i < 2; i++) {
disk_reserved_setinfo(0, floppy_pc[i].cyl, floppy_pc[i].head, floppy_selected() == i);
}
break;
case 0x3f5: // data reg
floppy_cmd[floppy_idx] = v;
if (floppy_idx == 0) {
switch(v & 31)
{
case 3: // specify
floppy_cmd_len = 3;
break;
case 4: // sense drive status
floppy_cmd_len = 2;
break;
case 5: // write data
floppy_cmd_len = 9;
break;
case 6: // read data
floppy_cmd_len = 9;
break;
case 7: // recalibrate
floppy_cmd_len = 2;
break;
case 8: // sense interrupt status
floppy_cmd_len = 1;
break;
case 10: // read id
floppy_cmd_len = 2;
break;
case 13: // format track
floppy_cmd_len = 6;
break;
case 15: // seek
floppy_cmd_len = 3;
break;
default:
write_log(_T("Floppy unimplemented command %02x\n"), v);
floppy_cmd_len = 1;
break;
}
}
floppy_idx++;
if (floppy_idx >= floppy_cmd_len) {
floppy_do_cmd(xb);
}
break;
case 0x3f7: // configuration control
if (xb->type >= TYPE_2286) {
write_log(_T("FDC Control Register %02x\n"), v);
floppy_rate = v & 3;
} else {
floppy_rate = -1;
}
break;
default:
write_log(_T("Unknown FDC %04x write %02x\n"), portnum, v);
break;
}
#if FLOPPY_IO_DEBUG
write_log(_T("out floppy port %04x %02x\n"), portnum, v);
#endif
}
static uae_u8 infloppy(struct x86_bridge *xb, int portnum)
{
uae_u8 v = 0;
switch (portnum)
{
case 0x3f4: // main status
v = 0;
if (!floppy_delay_hsync && (floppy_dpc & 4))
v |= 0x80;
if (floppy_idx || floppy_delay_hsync)
v |= 0x10;
if ((v & 0x80) && floppy_dir)
v |= 0x40;
for (int i = 0; i < 4; i++) {
if (floppy_seeking[i])
v |= 1 << i;
}
break;
case 0x3f5: // data reg
if (floppy_cmd_len && floppy_dir) {
int idx = (-floppy_idx) - 1;
if (idx < sizeof floppy_result) {
v = floppy_result[idx];
idx++;
floppy_idx--;
if (idx >= floppy_cmd_len) {
floppy_cmd_len = 0;
floppy_dir = 0;
floppy_idx = 0;
}
}
}
break;
case 0x3f7: // digital input register
if (xb->type >= TYPE_2286) {
struct floppy_reserved fr = { 0 };
bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
v = 0x00;
if (valid_floppy && fr.disk_changed)
v = 0x80;
}
break;
default:
write_log(_T("Unknown FDC %04x read\n"), portnum);
break;
}
#if FLOPPY_IO_DEBUG
write_log(_T("in floppy port %04x %02x\n"), portnum, v);
#endif
return v;
}
void bridge_mono_hit(void)
{
struct x86_bridge *xb = bridges[0];
if (xb->amiga_io[IO_MODE_REGISTER] & 8)
set_interrupt(xb, 0);
}
void bridge_color_hit(void)
{
struct x86_bridge *xb = bridges[0];
if (xb->amiga_io[IO_MODE_REGISTER] & 16)
set_interrupt(xb, 1);
}
static void set_pc_address_access(struct x86_bridge *xb, uaecptr addr)
{
if (addr >= 0xb0000 && addr < 0xb2000) {
// mono
if (xb->amiga_io[IO_MODE_REGISTER] & 8)
set_interrupt(xb, 0);
}
if (addr >= 0xb8000 && addr < 0xc0000) {
// color
if (xb->amiga_io[IO_MODE_REGISTER] & 16)
set_interrupt(xb, 1);
}
}
static void set_pc_io_access(struct x86_bridge *xb, uaecptr portnum, bool write)
{
uae_u8 mode_register = xb->amiga_io[IO_MODE_REGISTER];
if (write && portnum >= 0x3b0 && portnum < 0x3bf) {
// mono crt
if (mode_register & 8)
set_interrupt(xb, 2);
} else if (write && portnum >= 0x3d0 && portnum < 0x3df) {
// color crt
if (mode_register & 16)
set_interrupt(xb, 3);
} else if (portnum >= 0x37a && portnum < 0x37b) {
// LPT1
set_interrupt(xb, 5);
} else if (portnum >= 0x2f8 && portnum < 0x2f9) {
// COM2
set_interrupt(xb, 6);
}
}
static bool is_port_enabled(struct x86_bridge *xb, uint16_t portnum)
{
uae_u8 enables = xb->amiga_io[IO_MODE_REGISTER];
// COM2
if (portnum >= 0x2f8 && portnum < 0x300) {
if (!(enables & 1))
return false;
}
// LPT1
if (portnum >= 0x378 && portnum < 0x37f) {
if (!(enables & 2))
return false;
}
// Keyboard
// ???
return true;
}
static uae_u8 vlsi_in(struct x86_bridge *xb, int portnum)
{
uae_u8 v = 0;
switch(portnum)
{
case 0xed:
v = xb->vlsi_regs[xb->scamp_idx2];
break;
}
//write_log(_T("VLSI_IN %02x = %02x\n"), portnum, v);
return v;
}
static void vlsi_reg_out(struct x86_bridge *xb, int reg, uae_u8 v)
{
uae_u32 shadow_start = 0;
uae_u32 shadow_size = 0;
switch(reg)
{
case 0x1d:
x86_cmos_bank = (v & 0x20) ? 1 : 0;
break;
case 0x0e: // ABAX
shadow_size = 0x8000;
shadow_start = 0xa0000;
break;
case 0x0f: // CAXS
shadow_size = 0x4000;
shadow_start = 0xc0000;
break;
case 0x10: // DAXS
shadow_size = 0x4000;
shadow_start = 0xd0000;
break;
case 0x11: // FEAXS
shadow_size = 0x4000;
shadow_start = 0xe0000;
break;
}
if (shadow_size) {
for (int i = 0; i < 4; i++) {
int state = (v >> (i * 2)) & 3;
write_log(_T("%06x - %06x : shadow status=%d\n"), shadow_start, shadow_start + shadow_size - 1, state);
shadow_start += shadow_size;
}
}
}
static void vlsi_out(struct x86_bridge *xb, int portnum, uae_u8 v)
{
switch (portnum)
{
case 0xe8:
xb->scamp_idx1 = v;
break;
case 0xec:
xb->scamp_idx2 = v;
break;
case 0xed:
xb->vlsi_regs[xb->scamp_idx2] = v;
vlsi_reg_out(xb, xb->scamp_idx2, v);
break;
}
//write_log(_T("VLSI_OUT %02x = %02x\n"), portnum, v);
}
void portout(uint16_t portnum, uint8_t v)
{
struct x86_bridge *xb = bridges[0];
uae_u8 *io = xb->io_ports;
int aio = -1;
uae_u8 enables = xb->amiga_io[IO_MODE_REGISTER];
bool mda_emu = (enables & 8) != 0;
bool cga_emu = (enables & 16) != 0;
if (portnum >= 0x400)
return;
if (!is_port_enabled(xb, portnum))
return;
set_pc_io_access(xb, portnum, true);
switch(portnum)
{
case 0x20:
case 0x21:
case 0xa0:
case 0xa1:
if (xb->dosbox_cpu)
x86_pic_write(portnum, v);
else
out8259(portnum, v);
break;
case 0x40:
case 0x41:
case 0x42:
case 0x43:
if (xb->dosbox_cpu)
x86_timer_write(portnum, v);
else
out8253(portnum, v);
break;
case 0x80:
case 0x81:
case 0x82:
case 0x83:
case 0x84:
case 0x85:
case 0x86:
case 0x87:
case 0x88:
case 0x89:
case 0x8a:
case 0x8b:
case 0x8c:
case 0x8d:
case 0x8e:
case 0x8f:
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
case 0xc0:
case 0xc1:
case 0xc2:
case 0xc3:
case 0xc4:
case 0xc5:
case 0xc6:
case 0xc7:
case 0xc8:
case 0xc9:
case 0xca:
case 0xcb:
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
case 0xd0:
case 0xd1:
case 0xd2:
case 0xd3:
case 0xd4:
case 0xd5:
case 0xd6:
case 0xd7:
case 0xd8:
case 0xd9:
case 0xda:
case 0xdb:
case 0xdc:
case 0xdd:
case 0xde:
case 0xdf:
out8237(portnum, v);
break;
case 0x60:
if (xb->type >= TYPE_2286) {
x86_out_keyboard(0x60, v);
} else {
aio = 0x41f;
}
break;
case 0x61:
//write_log(_T("OUT Port B %02x\n"), v);
if (xb->type >= TYPE_2286) {
x86_out_keyboard(0x61, v);
} else {
aio = 0x5f;
}
break;
case 0x62:
//write_log(_T("AMIGA SYSINT. %02x\n"), v);
set_interrupt(xb, 7);
aio = 0x3f;
if (xb->type > TYPE_SIDECAR) {
// default video mode bits 4-5 come from jumpers.
if (!(xb->io_ports[0x63] & 8)) {
xb->pc_jumpers &= ~0xcf;
xb->pc_jumpers |= v & 0xcf;
}
}
break;
case 0x63:
write_log(_T("OUT CONFIG %02x\n"), v);
if (xb->type > TYPE_SIDECAR) {
if (xb->io_ports[0x63] & 8) {
v |= 8;
}
if (xb->type == TYPE_2088T) {
int speed = v >> 6;
if (speed == 0)
write_log(_T("A2088T: 4.77MHz\n"));
if (speed == 1)
write_log(_T("A2088T: 7.15MHz\n"));
if (speed == 2)
write_log(_T("A2088T: 9.54MHz\n"));
}
}
break;
case 0x64:
if (xb->type >= TYPE_2286) {
x86_out_keyboard(0x64, v);
}
break;
case 0x70:
if (xb->type >= TYPE_2286)
cmos_selreg(portnum, v, 1);
break;
case 0x71:
if (xb->type >= TYPE_2286)
cmos_writereg(portnum, v, 1);
break;
case 0x2f8:
if (xb->amiga_io[0x13f] & 0x80)
aio = 0x7f;
else
aio = 0x7d;
break;
case 0x2f9:
if (xb->amiga_io[0x13f] & 0x80)
aio = 0x9f;
else
aio = 0xbd;
break;
case 0x2fb:
aio = 0x11f;
break;
case 0x2fc:
aio = 0x13f;
break;
case 0x2fa:
case 0x2fd:
case 0x2fe:
case 0x2ff:
aio = 0x1f;
break;
// vga
case 0x3c2:
x86_vga_mode = v & 1;
case 0x3c0:
case 0x3c1:
case 0x3c3:
case 0x3c4:
case 0x3c5:
case 0x3c6:
case 0x3c7:
case 0x3c8:
case 0x3c9:
case 0x3ca:
case 0x3cb:
case 0x3cc:
case 0x3cd:
case 0x3ce:
case 0x3cf:
case 0x3b9:
if (ISVGA()) {
vga_io_put(portnum, v);
}
break;
// mono video
case 0x3b0:
case 0x3b2:
case 0x3b4:
case 0x3b6:
if (mda_emu) {
aio = 0x1ff;
} else if (ISVGA()) {
if (x86_vga_mode == 0)
vga_io_put(portnum, v);
}
break;
case 0x3b1:
case 0x3b3:
case 0x3b5:
case 0x3b7:
if (mda_emu) {
aio = 0x2a1 + (xb->amiga_io[0x1ff] & 15) * 2;
} else if (ISVGA()) {
if (x86_vga_mode == 0)
vga_io_put(portnum, v);
}
break;
case 0x3b8:
if (mda_emu) {
aio = 0x2ff;
}
break;
// color video
case 0x3d0:
case 0x3d2:
case 0x3d4:
case 0x3d6:
if (cga_emu) {
aio = 0x21f;
} else if (ISVGA()) {
if (x86_vga_mode == 1)
vga_io_put(portnum, v);
}
break;
case 0x3d1:
case 0x3d3:
case 0x3d5:
case 0x3d7:
if (cga_emu) {
aio = 0x2c1 + (xb->amiga_io[0x21f] & 15) * 2;
} else if (ISVGA()) {
if (x86_vga_mode == 1)
vga_io_put(portnum, v);
}
break;
case 0x3d8:
if (cga_emu) {
aio = 0x23f;
}
break;
case 0x3d9:
if (cga_emu) {
aio = 0x25f;
}
break;
case 0x3dd:
if (cga_emu) {
aio = 0x29f;
}
break;
case 0x3ba:
if (cga_emu) {
aio = 0x1f;
} else if (ISVGA()) {
if (x86_vga_mode == 0)
vga_io_put(portnum, v);
}
break;
case 0x3da:
if (cga_emu) {
aio = 0x1f;
} else if (ISVGA()) {
if (x86_vga_mode == 1)
vga_io_put(portnum, v);
}
break;
case 0x378:
write_log(_T("BIOS DIAGNOSTICS CODE: %02x ~%02X\n"), v, v ^ 0xff);
aio = 0x19f; // ??
break;
case 0x379:
if (xb->amiga_io[IO_MODE_REGISTER] & 2) {
xb->amiga_forced_interrupts = (v & 40) ? false : true;
}
aio = 0x19f; // ??
break;
case 0x37a:
aio = 0x1df;
break;
case 0x3bb:
case 0x3bc:
case 0x3bd:
case 0x3be:
case 0x3bf:
if (mda_emu) {
aio = 0x1f;
}
break;
case 0x3de:
case 0x3df:
if (cga_emu) {
aio = 0x1f;
}
break;
// A2386SX only
case 0xe8:
case 0xe9:
case 0xea:
case 0xeb:
case 0xec:
case 0xed:
case 0xee:
case 0xef:
case 0xf0:
case 0xf1:
case 0xf4:
case 0xf5:
case 0xf8:
case 0xf9:
case 0xfa:
case 0xfb:
case 0xfc:
case 0xfe:
if (xb->type >= TYPE_2386)
vlsi_out(xb, portnum, v);
break;
// floppy
case 0x3f0:
case 0x3f1:
case 0x3f2:
case 0x3f3:
case 0x3f4:
case 0x3f5:
case 0x3f7:
outfloppy(xb, portnum, v);
break;
// at ide 1
case 0x170:
case 0x171:
case 0x172:
case 0x173:
case 0x174:
case 0x175:
case 0x176:
case 0x177:
case 0x376:
x86_ide_hd_put(portnum, v, 0);
break;
// at ide 0
case 0x1f0:
case 0x1f1:
case 0x1f2:
case 0x1f3:
case 0x1f4:
case 0x1f5:
case 0x1f6:
case 0x1f7:
case 0x3f6:
x86_ide_hd_put(portnum, v, 0);
break;
// xt hd
case 0x320:
case 0x321:
case 0x322:
case 0x323:
x86_xt_hd_bput(portnum, v);
break;
// universal xt bios
case 0x300:
case 0x301:
case 0x302:
case 0x303:
case 0x304:
case 0x305:
case 0x306:
case 0x307:
case 0x308:
case 0x309:
case 0x30a:
case 0x30b:
case 0x30c:
case 0x30d:
case 0x30e:
case 0x30f:
x86_ide_hd_put(portnum, v, 0);
break;
case 0x101:
case 0x102:
// A2286 BIOS timer test fails if CPU is too fast
// so we'll run normal speed until tests are done
if (!x86_turbo_allowed) {
x86_turbo_allowed = true;
}
break;
default:
write_log(_T("X86_OUT unknown %02x %02x\n"), portnum, v);
break;
}
#if X86_IO_PORT_DEBUG
write_log(_T("X86_OUT %08x %02X\n"), portnum, v);
#endif
if (aio >= 0)
xb->amiga_io[aio] = v;
xb->io_ports[portnum] = v;
}
void portout16(uint16_t portnum, uint16_t value)
{
switch (portnum)
{
case 0x170:
case 0x1f0:
case 0x300:
x86_ide_hd_put(portnum, value, 1);
break;
default:
portout(portnum, value);
portout(portnum + 1, value >> 8);
break;
}
}
static void portout32(uint16_t portnum, uint32_t value)
{
switch (portnum)
{
case 0x170:
case 0x1f0:
case 0x300:
x86_ide_hd_put(portnum, value, 1);
x86_ide_hd_put(portnum, value >> 16, 1);
break;
default:
write_log(_T("portout32 %08x %08x\n"), portnum, value);
break;
}
}
uint8_t portin(uint16_t portnum)
{
struct x86_bridge *xb = bridges[0];
int aio = -1;
uae_u8 enables = xb->amiga_io[IO_MODE_REGISTER];
bool mda_emu = (enables & 8) != 0;
bool cga_emu = (enables & 16) != 0;
if (!is_port_enabled(xb, portnum))
return 0;
if (portnum >= 0x400)
return 0;
set_pc_io_access(xb, portnum, false);
uae_u8 v = xb->io_ports[portnum];
switch (portnum)
{
case 0x20:
case 0x21:
case 0xa0:
case 0xa1:
if (xb->dosbox_cpu)
v = x86_pic_read(portnum);
else
v = in8259(portnum);
break;
case 0x40:
case 0x41:
case 0x42:
case 0x43:
if (xb->dosbox_cpu)
v = x86_timer_read(portnum);
else
v = in8253(portnum);
break;
case 0x80:
case 0x81:
case 0x82:
case 0x83:
case 0x84:
case 0x85:
case 0x86:
case 0x87:
case 0x88:
case 0x89:
case 0x8a:
case 0x8b:
case 0x8c:
case 0x8d:
case 0x8e:
case 0x8f:
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
case 0xc0:
case 0xc1:
case 0xc2:
case 0xc3:
case 0xc4:
case 0xc5:
case 0xc6:
case 0xc7:
case 0xc8:
case 0xc9:
case 0xca:
case 0xcb:
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
case 0xd0:
case 0xd1:
case 0xd2:
case 0xd3:
case 0xd4:
case 0xd5:
case 0xd6:
case 0xd7:
case 0xd8:
case 0xd9:
case 0xda:
case 0xdb:
case 0xdc:
case 0xdd:
case 0xde:
case 0xdf:
v = in8237(portnum);
break;
case 0x71:
if (xb->type >= TYPE_2286)
v = cmos_readreg(portnum, 1);
break;
case 0x2f8:
if (xb->amiga_io[0x11f] & 0x80)
aio = 0x7f;
else
aio = 0x9d;
xb->pc_irq3b = false;
break;
case 0x2f9:
if (xb->amiga_io[0x11f] & 0x80)
aio = 0x9f;
else
aio = 0xdd;
break;
case 0x2fa:
aio = 0xff;
break;
case 0x2fd:
aio = 0x15f;
break;
case 0x2fe:
aio = 0x17f;
break;
case 0x2fb:
case 0x2fc:
case 0x2ff:
aio = 0x1f;
break;
case 0x378:
aio = 0x19f; // ?
break;
case 0x379:
xb->pc_irq7 = false;
aio = 0x1bf;
break;
case 0x37a:
aio = 0x19f; // ?
break;
// vga
case 0x3c0:
case 0x3c1:
case 0x3c2:
case 0x3c3:
case 0x3c4:
case 0x3c5:
case 0x3c6:
case 0x3c7:
case 0x3c8:
case 0x3c9:
case 0x3ca:
case 0x3cb:
case 0x3cc:
case 0x3cd:
case 0x3ce:
case 0x3cf:
case 0x3b9:
if (ISVGA()) {
v = vga_io_get(portnum);
}
break;
// mono video
case 0x3b0:
xb->pc_irq3a = false;
aio = 0x1ff;
break;
case 0x3b2:
case 0x3b4:
case 0x3b6:
if (mda_emu) {
aio = 0x1ff;
} else if (ISVGA()) {
if (x86_vga_mode == 0)
v = vga_io_get(portnum);
}
break;
case 0x3b1:
case 0x3b3:
case 0x3b5:
case 0x3b7:
if (mda_emu) {
aio = 0x2a1 + (xb->amiga_io[0x1ff] & 15) * 2;
} else if (ISVGA()) {
if (x86_vga_mode == 0)
v = vga_io_get(portnum);
}
break;
case 0x3b8:
if (mda_emu) {
aio = 0x2ff;
}
break;
// color video
case 0x3d0:
case 0x3d2:
case 0x3d4:
case 0x3d6:
if (cga_emu) {
aio = 0x21f;
} else if (ISVGA()) {
if (x86_vga_mode == 1)
v = vga_io_get(portnum);
}
break;
case 0x3d1:
case 0x3d3:
case 0x3d5:
case 0x3d7:
if (cga_emu) {
aio = 0x2c1 + (xb->amiga_io[0x21f] & 15) * 2;
} else if (ISVGA()) {
if (x86_vga_mode == 1)
v = vga_io_get(portnum);
}
break;
case 0x3d8:
if (cga_emu) {
aio = 0x23f;
}
break;
case 0x3d9:
if (cga_emu) {
aio = 0x25f;
}
break;
case 0x3ba:
if (mda_emu) {
v = 0;
// not really correct but easy.
if (vpos < 20)
v |= 8 | 1;
if (get_cycles() - last_cycles > maxhpos / 2)
v |= 1;
last_cycles = get_cycles();
} else if (ISVGA()) {
if (x86_vga_mode == 0)
v = vga_io_get(portnum);
}
break;
case 0x3da:
if (cga_emu) {
v = 0;
// not really correct but easy.
if (vpos < 20)
v |= 8 | 1;
if (get_cycles() - last_cycles > maxhpos / 2)
v |= 1;
last_cycles = get_cycles();
} else if (ISVGA()) {
if (x86_vga_mode == 1)
v = vga_io_get(portnum);
}
break;
case 0x3dd:
if (cga_emu) {
aio = 0x29f;
}
break;
case 0x3bb:
case 0x3bc:
case 0x3bd:
case 0x3be:
case 0x3bf:
if (mda_emu) {
aio = 0x1f;
}
break;
case 0x3de:
case 0x3df:
if (cga_emu) {
aio = 0x1f;
}
break;
// A2386SX only
case 0xe8:
case 0xe9:
case 0xea:
case 0xeb:
case 0xec:
case 0xed:
case 0xee:
case 0xef:
case 0xf0:
case 0xf1:
case 0xf4:
case 0xf5:
case 0xf8:
case 0xf9:
case 0xfa:
case 0xfb:
case 0xfc:
case 0xfe:
if (xb->type >= TYPE_2386)
v = vlsi_in(xb, portnum);
break;
// floppy
case 0x3f0:
case 0x3f1:
case 0x3f2:
case 0x3f3:
case 0x3f4:
case 0x3f5:
case 0x3f7:
v = infloppy(xb, portnum);
break;
case 0x60:
if (xb->type >= TYPE_2286) {
v = x86_in_keyboard(0x60);
//write_log(_T("PC read keycode %02x\n"), v);
}
break;
case 0x61:
if (xb->type >= TYPE_2286) {
// bios test hack
v = x86_in_keyboard(0x61);
} else {
v = xb->amiga_io[0x5f];
}
//write_log(_T("IN Port B %02x\n"), v);
break;
case 0x62:
{
v = xb->amiga_io[0x3f];
if (xb->type == TYPE_SIDECAR) {
// Sidecar has jumpers.
if (xb->amiga_io[0x5f] & 8) {
// bit 0-1: display (11=mono 80x25,10=01=color 80x25,00=no video)
// bit 2-3: number of drives (11=1..)
v &= 0xf0;
v |= (xb->pc_jumpers >> 4) & 0x0f;
} else {
v &= 0xf0;
// bit 0: 0=loop on POST
// bit 1: 0=8087 installed
// bit 2-3: (11=640k,10=256k,01=512k,00=128k) RAM size
v |= xb->pc_jumpers & 0xf;
}
} else {
// A2088+ are software configurable (Except default video mode)
if (!(xb->amiga_io[0x5f] & 4)) {
v &= 0xf0;
v |= (xb->pc_jumpers >> 4) & 0x0f;
} else {
v &= 0xf0;
v |= xb->pc_jumpers & 0xf;
}
}
v &= ~0x20;
if (!(xb->amiga_io[0x5f] & 1) && i8253.active[2])
v |= 0x20;
//write_log(_T("IN Port C %02x\n"), v);
}
break;
case 0x63:
//write_log(_T("IN Control %02x\n"), v);
break;
case 0x64:
if (xb->type >= TYPE_2286) {
v = x86_in_keyboard(0x64);
}
break;
// at ide 1
case 0x170:
case 0x171:
case 0x172:
case 0x173:
case 0x174:
case 0x175:
case 0x176:
case 0x177:
case 0x376:
v = x86_ide_hd_get(portnum, 0);
break;
// at ide 0
case 0x1f0:
case 0x1f1:
case 0x1f2:
case 0x1f3:
case 0x1f4:
case 0x1f5:
case 0x1f6:
case 0x1f7:
case 0x3f6:
v = x86_ide_hd_get(portnum, 0);
break;
// xt hd
case 0x320:
case 0x321:
case 0x322:
case 0x323:
v = x86_xt_hd_bget(portnum);
break;
// universal xt bios
case 0x300:
case 0x301:
case 0x302:
case 0x303:
case 0x304:
case 0x305:
case 0x306:
case 0x307:
case 0x308:
case 0x309:
case 0x30a:
case 0x30b:
case 0x30c:
case 0x30d:
case 0x30e:
case 0x30f:
v = x86_ide_hd_get(portnum, 0);
break;
default:
write_log(_T("X86_IN unknown %02x\n"), portnum);
return 0;
}
if (aio >= 0)
v = xb->amiga_io[aio];
#if X86_IO_PORT_DEBUG
write_log(_T("X86_IN %08x %02X\n"), portnum, v);
#endif
return v;
}
uint16_t portin16(uint16_t portnum)
{
uae_u16 v = 0;
switch (portnum)
{
case 0x170:
case 0x1f0:
case 0x300:
v = x86_ide_hd_get(portnum, 1);
break;
default:
write_log(_T("portin16 %08x\n"), portnum);
break;
}
return v;
}
static uint32_t portin32(uint16_t portnum)
{
uint32_t v = 0;
switch (portnum)
{
case 0x170:
case 0x1f0:
case 0x300:
v = x86_ide_hd_get(portnum, 1) << 0;
v |= x86_ide_hd_get(portnum, 1) << 16;
break;
default:
write_log(_T("portin32 %08x\n"), portnum);
break;
}
return v;
}
void write86(uint32_t addr32, uint8_t value)
{
struct x86_bridge *xb = bridges[0];
addr32 &= 0xFFFFF;
if (addr32 >= xb->pc_maxbaseram && addr32 < 0xa0000)
return;
if (addr32 >= x86_xrom_start[0] && addr32 < x86_xrom_end[0])
return;
if (addr32 >= x86_xrom_start[1] && addr32 < x86_xrom_end[1])
return;
set_pc_address_access(xb, addr32);
xb->pc_ram[addr32] = value;
}
void writew86(uint32_t addr32, uint16_t value)
{
struct x86_bridge *xb = bridges[0];
addr32 &= 0xFFFFF;
if (addr32 >= xb->pc_maxbaseram && addr32 < 0xa0000)
return;
if (addr32 >= x86_xrom_start[0] && addr32 < x86_xrom_end[0])
return;
if (addr32 >= x86_xrom_start[1] && addr32 < x86_xrom_end[1])
return;
set_pc_address_access(xb, addr32);
xb->pc_ram[addr32] = value & 0xff;
xb->pc_ram[addr32 + 1] = value >> 8;
}
uint8_t read86(uint32_t addr32)
{
struct x86_bridge *xb = bridges[0];
addr32 &= 0xFFFFF;
return xb->pc_ram[addr32];
}
uint16_t readw86(uint32_t addr32)
{
uint16_t v;
struct x86_bridge *xb = bridges[0];
addr32 &= 0xFFFFF;
v = xb->pc_ram[addr32];
v |= xb->pc_ram[addr32 + 1] << 8;
return v;
}
static uaecptr get_x86_address(struct x86_bridge *xb, uaecptr addr, int *mode)
{
addr -= xb->baseaddress;
if (!xb->baseaddress || addr >= 0x80000) {
*mode = -1;
return 0;
}
*mode = addr >> 17;
addr &= 0x1ffff;
if (addr < 0x10000) {
int opt = (xb->amiga_io[IO_MODE_REGISTER] >> 5) & 3;
// disk buffer
switch(opt)
{
case 1:
default:
return 0xa0000 + addr;
case 2:
return 0xd0000 + addr;
case 3:
return 0xe0000 + addr;
}
}
if (addr < 0x18000) {
// color video
addr -= 0x10000;
return 0xb8000 + addr;
}
if (addr < 0x1c000) {
addr -= 0x18000;
// parameter
if (xb->type >= TYPE_2286)
return 0xd0000 + addr;
else
return 0xf0000 + addr;
}
if (addr < 0x1e000) {
addr -= 0x1c000;
// mono video
return 0xb0000 + addr;
}
// IO
addr -= 0x1e000;
return addr;
}
static struct x86_bridge *get_x86_bridge(uaecptr addr)
{
return bridges[0];
}
static uae_u32 REGPARAM2 x86_bridge_wget(uaecptr addr)
{
#ifdef JIT
special_mem |= S_READ;
#endif
uae_u16 v = 0;
struct x86_bridge *xb = get_x86_bridge(addr);
if (!xb)
return v;
int mode;
uaecptr a = get_x86_address(xb, addr, &mode);
if (mode == ACCESS_MODE_WORD) {
v = (xb->pc_ram[a + 1] << 8) | (xb->pc_ram[a + 0] << 0);
} else if (mode == ACCESS_MODE_GFX) {
write_log(_T("ACCESS_MODE_GFX\n"));
} else if (mode == ACCESS_MODE_IO) {
v = x86_bridge_get_io(xb, a);
v |= x86_bridge_get_io(xb, a + 1) << 8;
} else if (mode >= 0) {
v = (xb->pc_ram[a + 1] << 0) | (xb->pc_ram[a + 0] << 8);
}
#if X86_DEBUG_BRIDGE > 1
write_log(_T("x86_bridge_wget %08x (%08x,%d) PC=%08x\n"), addr - xb->baseaddress, a, mode, M68K_GETPC);
#endif
return v;
}
static uae_u32 REGPARAM2 x86_bridge_lget(uaecptr addr)
{
uae_u32 v;
v = x86_bridge_wget(addr) << 16;
v |= x86_bridge_wget(addr + 2);
return v;
}
static uae_u32 REGPARAM2 x86_bridge_bget(uaecptr addr)
{
#ifdef JIT
special_mem |= S_READ;
#endif
uae_u8 v = 0;
struct x86_bridge *xb = get_x86_bridge(addr);
if (!xb)
return v;
if (!xb->configured) {
uaecptr offset = addr & 65535;
if (offset >= sizeof xb->acmemory)
return 0;
return xb->acmemory[offset];
}
int mode;
uaecptr a = get_x86_address(xb, addr, &mode);
if (mode == ACCESS_MODE_WORD) {
v = xb->pc_ram[a ^ 1];
} else if (mode == ACCESS_MODE_IO) {
v = x86_bridge_get_io(xb, a);
} else if (mode >= 0) {
v = xb->pc_ram[a];
}
#if X86_DEBUG_BRIDGE > 1
write_log(_T("x86_bridge_bget %08x (%08x,%d) %02x PC=%08x\n"), addr - xb->baseaddress, a, mode, v, M68K_GETPC);
#endif
return v;
}
static void REGPARAM2 x86_bridge_wput(uaecptr addr, uae_u32 b)
{
#ifdef JIT
special_mem |= S_WRITE;
#endif
struct x86_bridge *xb = get_x86_bridge(addr);
if (!xb)
return;
int mode;
uaecptr a = get_x86_address(xb, addr, &mode);
#if X86_DEBUG_BRIDGE > 1
write_log(_T("pci_bridge_wput %08x (%08x,%d) %04x PC=%08x\n"), addr - xb->baseaddress, a, mode, b & 0xffff, M68K_GETPC);
#endif
if (a >= 0x100000 || mode < 0)
return;
if (xb->rombank[a / 4096])
return;
if (mode == ACCESS_MODE_IO) {
uae_u16 v = b;
x86_bridge_put_io(xb, a, v & 0xff);
x86_bridge_put_io(xb, a + 1, v >> 8);
} else if (mode == ACCESS_MODE_WORD) {
xb->pc_ram[a + 0] = b;
xb->pc_ram[a + 1] = b >> 8;
} else if (mode == ACCESS_MODE_GFX) {
write_log(_T("ACCESS_MODE_GFX\n"));
} else {
xb->pc_ram[a + 1] = b;
xb->pc_ram[a + 0] = b >> 8;
}
}
static void REGPARAM2 x86_bridge_lput(uaecptr addr, uae_u32 b)
{
x86_bridge_wput(addr, b >> 16);
x86_bridge_wput(addr + 2, b);
}
static void REGPARAM2 x86_bridge_bput(uaecptr addr, uae_u32 b)
{
#ifdef JIT
special_mem |= S_WRITE;
#endif
struct x86_bridge *xb = get_x86_bridge(addr);
if (!xb)
return;
if (!xb->configured) {
uaecptr offset = addr & 65535;
switch (offset)
{
case 0x48:
map_banks_z2(xb->bank, b, expamem_z2_size >> 16);
xb->baseaddress = b << 16;
xb->configured = 1;
expamem_next(xb->bank, NULL);
break;
case 0x4c:
xb->configured = -1;
expamem_shutup(xb->bank);
break;
}
}
int mode;
uaecptr a = get_x86_address(xb, addr, &mode);
if (a >= 0x100000 || mode < 0)
return;
if (xb->rombank[a / 4096])
return;
#if X86_DEBUG_BRIDGE > 1
write_log(_T("x86_bridge_bput %08x (%08x,%d) %02x PC=%08x\n"), addr - xb->baseaddress, a, mode, b & 0xff, M68K_GETPC);
#endif
if (mode == ACCESS_MODE_IO) {
x86_bridge_put_io(xb, a, b);
} else if (mode == ACCESS_MODE_WORD) {
xb->pc_ram[a ^ 1] = b;
} else {
xb->pc_ram[a] = b;
}
}
addrbank x86_bridge_bank = {
x86_bridge_lget, x86_bridge_wget, x86_bridge_bget,
x86_bridge_lput, x86_bridge_wput, x86_bridge_bput,
default_xlate, default_check, NULL, NULL, _T("X86 BRIDGE"),
x86_bridge_lget, x86_bridge_wget, ABFLAG_IO | ABFLAG_SAFE
};
void x86_bridge_rethink(void)
{
struct x86_bridge *xb = bridges[0];
if (!xb)
return;
if (!(xb->amiga_io[IO_CONTROL_REGISTER] & 1)) {
uae_u8 intreq = xb->amiga_io[IO_AMIGA_INTERRUPT_STATUS];
uae_u8 intena = xb->amiga_io[IO_INTERRUPT_MASK];
uae_u8 status = intreq & ~intena;
if (status)
INTREQ_0(0x8000 | 0x0008);
}
}
void x86_bridge_free(void)
{
x86_bridge_reset();
x86_found = 0;
}
void x86_bridge_reset(void)
{
x86_xrom_start[0] = x86_xrom_end[0] = 0;
x86_xrom_start[1] = x86_xrom_end[1] = 0;
for (int i = 0; i < X86_BRIDGE_MAX; i++) {
struct x86_bridge *xb = bridges[i];
if (!xb)
continue;
if (xb->dosbox_cpu) {
if (xb->cmosfile) {
uae_u8 *regs = x86_cmos_regs(NULL);
zfile_fseek(xb->cmosfile, 0, SEEK_SET);
zfile_fwrite(regs, 1, xb->cmossize, xb->cmosfile);
}
CPU_ShutDown(dosbox_sec);
CMOS_Destroy(dosbox_sec);
TIMER_Destroy(dosbox_sec);
PIC_Destroy(dosbox_sec);
MEM_ShutDown(dosbox_sec);
delete dosbox_sec;
}
xfree(xb->amiga_io);
xfree(xb->io_ports);
xfree(xb->pc_ram);
xfree(xb->pc_rom);
zfile_fclose(xb->cmosfile);
bridges[i] = NULL;
}
}
static void check_floppy_delay(void)
{
for (int i = 0; i < 4; i++) {
if (floppy_seeking[i]) {
bool neg = floppy_seeking[i] < 0;
if (floppy_seeking[i] > 0)
floppy_seeking[i]--;
else if (neg)
floppy_seeking[i]++;
if (floppy_seeking[i] == 0)
do_floppy_seek(i, neg);
}
}
if (floppy_delay_hsync > 1 || floppy_delay_hsync < -1) {
if (floppy_delay_hsync > 0)
floppy_delay_hsync--;
else
floppy_delay_hsync++;
if (floppy_delay_hsync == 1 || floppy_delay_hsync == -1)
do_floppy_irq();
}
}
static void x86_cpu_execute(int cnt)
{
struct x86_bridge *xb = bridges[0];
if (!xb->x86_reset) {
if (xb->dosbox_cpu) {
if (xb->x86_reset_requested) {
xb->x86_reset_requested = false;
reset_x86_cpu(xb);
}
Bit32s old_cpu_cycles = CPU_Cycles;
if (CPU_Cycles > cnt)
CPU_Cycles = cnt;
if (PIC_RunQueue()) {
(*cpudecoder)();
}
CPU_Cycles = old_cpu_cycles -= cnt;
if (CPU_Cycles < 0)
CPU_Cycles = 0;
check_x86_irq();
} else {
exec86(cnt);
}
}
// BIOS has CPU loop delays in floppy driver...
check_floppy_delay();
}
void x86_bridge_execute_until(int until)
{
struct x86_bridge *xb = bridges[0];
if (!xb)
return;
if (!x86_turbo_allowed)
return;
for (;;) {
x86_cpu_execute(until ? 10 : 1);
if (until == 0)
break;
frame_time_t rpt = read_processor_time();
if ((int)until - (int)rpt <= 0)
break;
}
}
void x86_bridge_sync_change(void)
{
struct x86_bridge *xb = bridges[0];
if (!xb)
return;
xb->dosbox_vpos_tick = maxvpos * vblank_hz / 1000;
if (xb->dosbox_vpos_tick >= xb->dosbox_vpos_tick)
xb->dosbox_tick_vpos_cnt -= xb->dosbox_vpos_tick;
}
void x86_bridge_hsync(void)
{
struct x86_bridge *xb = bridges[0];
if (!xb)
return;
check_floppy_delay();
if (!xb->x86_reset) {
if (xb->dosbox_cpu) {
xb->dosbox_tick_vpos_cnt++;
if (xb->dosbox_tick_vpos_cnt >= xb->dosbox_vpos_tick) {
TIMER_AddTick();
xb->dosbox_tick_vpos_cnt -= xb->dosbox_vpos_tick;
}
x86_cpu_execute(x86_instruction_count);
} else {
for (int i = 0; i < 3; i++) {
x86_cpu_execute(x86_instruction_count / 3);
timing(maxhpos / 3);
}
}
}
if (currprefs.x86_speed_throttle != changed_prefs.x86_speed_throttle) {
currprefs.x86_speed_throttle = changed_prefs.x86_speed_throttle;
x86_instruction_count = DEFAULT_X86_INSTRUCTION_COUNT;
if (currprefs.x86_speed_throttle < 0) {
x86_turbo_enabled = true;
} else {
x86_turbo_enabled = false;
x86_instruction_count = DEFAULT_X86_INSTRUCTION_COUNT + DEFAULT_X86_INSTRUCTION_COUNT * currprefs.x86_speed_throttle / 1000;
}
}
if (x86_turbo_allowed && x86_turbo_enabled && !x86_turbo_on) {
x86_turbo_on = true;
} else if ((!x86_turbo_allowed || !x86_turbo_enabled) && x86_turbo_on) {
x86_turbo_on = false;
}
}
static void ew(uae_u8 *acmemory, int addr, uae_u8 value)
{
if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
acmemory[addr] = (value & 0xf0);
acmemory[addr + 2] = (value & 0x0f) << 4;
} else {
acmemory[addr] = ~(value & 0xf0);
acmemory[addr + 2] = ~((value & 0x0f) << 4);
}
}
static void setrombank(struct x86_bridge *xb, int start, int len)
{
while (len > 0) {
xb->rombank[start / 4096] = 1;
start += 4096;
len -= 4096;
}
}
static void bridge_reset(struct x86_bridge *xb)
{
xb->x86_reset = true;
xb->configured = 0;
xb->amiga_forced_interrupts = false;
xb->amiga_irq = false;
xb->pc_irq3a = xb->pc_irq3b = xb->pc_irq7 = false;
x86_turbo_allowed = false;
x86_cpu_active = false;
x86_instruction_count = DEFAULT_X86_INSTRUCTION_COUNT;
memset(xb->amiga_io, 0, 0x10000);
memset(xb->io_ports, 0, 0x10000);
memset(xb->pc_ram, 0, 0x100000 - xb->bios_size);
memset(xb->rombank, 0, sizeof xb->rombank);
for (int i = 0; i < 2; i++) {
if (x86_xrom_end[i] - x86_xrom_start[i] > 0) {
memcpy(xb->pc_ram + x86_xrom_start[i], xb->pc_rom + x86_xrom_start[i], x86_xrom_end[i] - x86_xrom_start[i]);
setrombank(xb, x86_xrom_start[i], x86_xrom_end[i] - x86_xrom_start[i]);
}
}
memcpy(xb->pc_ram + 0x100000 - xb->bios_size, xb->pc_rom + 0x100000 - xb->bios_size, xb->bios_size);
setrombank(xb, 0x100000 - xb->bios_size, xb->bios_size);
xb->amiga_io[IO_CONTROL_REGISTER] = 0xfe;
xb->amiga_io[IO_PC_INTERRUPT_CONTROL] = 0xff;
xb->amiga_io[IO_INTERRUPT_MASK] = 0xff;
xb->amiga_io[IO_MODE_REGISTER] = 0x00;
xb->amiga_io[IO_PC_INTERRUPT_STATUS] = 0xfe;
x86_cmos_bank = 0;
memset(xb->vlsi_regs, 0, sizeof xb->vlsi_regs);
if (xb->type >= TYPE_2286) {
int sel1 = (xb->settings >> 10) & 1;
int sel2 = (xb->settings >> 11) & 1;
// only A0000 or D0000 is valid for AT
if ((!sel1 && !sel2) || (sel1 && sel2)) {
sel1 = 0;
sel2 = 1;
}
xb->amiga_io[IO_MODE_REGISTER] |= sel1 << 5;
xb->amiga_io[IO_MODE_REGISTER] |= sel2 << 6;
}
if (xb->type == TYPE_2386)
x86_turbo_allowed = true;
x86_bridge_sync_change();
inittiming();
floppy_hardreset();
}
int is_x86_cpu(struct uae_prefs *p)
{
struct x86_bridge *xb = bridges[0];
if (!xb) {
if (x86_found > 0)
return X86_STATE_STOP;
else if (x86_found < 0)
return X86_STATE_INACTIVE;
if (is_device_rom(p, ROMTYPE_A1060, 0) < 0 &&
is_device_rom(p, ROMTYPE_A2088, 0) < 0 &&
is_device_rom(p, ROMTYPE_A2088T, 0) < 0 &&
is_device_rom(p, ROMTYPE_A2286, 0) < 0 &&
is_device_rom(p, ROMTYPE_A2386, 0) < 0) {
if (p == &currprefs)
x86_found = -1;
return X86_STATE_INACTIVE;
} else {
if (p == &currprefs)
x86_found = 1;
}
}
if (!xb || xb->x86_reset)
return X86_STATE_STOP;
return X86_STATE_ACTIVE;
}
static void load_vga_bios(void)
{
struct x86_bridge *xb = bridges[0];
if (!xb || !ISVGA())
return;
struct zfile *zf = read_device_rom(&currprefs, ROMTYPE_x86_VGA, 0, NULL);
x86_xrom_start[1] = 0xc0000;
x86_xrom_end[1] = x86_xrom_start[1];
if (zf) {
x86_xrom_end[1] += zfile_fread(xb->pc_rom + x86_xrom_start[1], 1, 65536, zf);
zfile_fclose(zf);
x86_xrom_end[1] += 4095;
x86_xrom_end[1] &= ~4095;
memcpy(xb->pc_ram + x86_xrom_start[1], xb->pc_rom + x86_xrom_start[1], x86_xrom_end[1] - x86_xrom_start[1]);
setrombank(xb, x86_xrom_start[1], x86_xrom_end[1] - x86_xrom_start[1]);
}
if (xb->dosbox_cpu) {
MEM_ShutDown(dosbox_sec);
MEM_Init(dosbox_sec);
MEM_SetVGAHandler();
}
}
void x86_xt_ide_bios(struct zfile *z, struct romconfig *rc)
{
struct x86_bridge *xb = bridges[0];
uae_u32 addr = 0;
if (!xb || !z)
return;
switch (rc->device_settings)
{
case 0:
addr = 0xcc000;
break;
case 1:
addr = 0xdc000;
break;
case 2:
default:
addr = 0xec000;
break;
}
x86_xrom_start[0] = addr;
x86_xrom_end[0] = x86_xrom_start[0] + 0x4000;
zfile_fread(xb->pc_rom + x86_xrom_start[0], 1, 32768, z);
memcpy(xb->pc_ram + x86_xrom_start[0], xb->pc_rom + x86_xrom_start[0], x86_xrom_end[0] - x86_xrom_start[0]);
setrombank(xb, x86_xrom_start[0], x86_xrom_end[0] - x86_xrom_start[0]);
if (xb->dosbox_cpu) {
MEM_ShutDown(dosbox_sec);
MEM_Init(dosbox_sec);
if (ISVGA()) {
MEM_SetVGAHandler();
}
}
}
static const uae_u8 a1060_autoconfig[16] = { 0xc4, 0x01, 0x80, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uae_u8 a2386_autoconfig[16] = { 0xc4, 0x67, 0x80, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
addrbank *x86_bridge_init(struct romconfig *rc, uae_u32 romtype, int type)
{
struct x86_bridge *xb = x86_bridge_alloc();
const uae_u8 *ac;
if (!xb)
return &expamem_null;
bridges[0] = xb;
xb->rc = rc;
xb->type = type;
xb->io_ports = xcalloc(uae_u8, 0x10000);
xb->amiga_io = xcalloc(uae_u8, 0x10000);
x86_xrom_start[0] = x86_xrom_end[0] = 0;
x86_xrom_start[1] = x86_xrom_end[1] = 0;
xb->settings = rc->device_settings;
if (xb->type >= TYPE_2286) {
xb->dosbox_cpu = ((xb->settings >> 19) & 3) + 1;
xb->dosbox_cpu_arch = (xb->settings >> 23) & 7;
xb->settings |= 0xff;
ac = xb->type >= TYPE_2386 ? a2386_autoconfig : a1060_autoconfig;
xb->pc_maxram = (1024 * 1024) << ((xb->settings >> 16) & 7);
xb->bios_size = 65536;
} else {
xb->dosbox_cpu = (xb->settings >> 19) & 7;
xb->dosbox_cpu_arch = (xb->settings >> 23) & 7;
ac = a1060_autoconfig;
xb->pc_maxram = 1 * 1024 * 1024;
xb->bios_size = 32768;
}
xb->pc_ram = xcalloc(uae_u8, xb->pc_maxram + 1 * 1024 * 1024);
xb->pc_rom = xcalloc(uae_u8, 0x100000);
x86_memsize = xb->pc_maxram;
mono_start = xb->pc_ram + 0xb0000;
mono_end = xb->pc_ram + 0xb2000;
color_start = xb->pc_ram + 0xb8000;
color_end = xb->pc_ram + 0xc0000;
x86_biosstart = 0x100000 - xb->bios_size;
MemBase = xb->pc_ram;
if (xb->dosbox_cpu) {
ticksDone = 0;
ticksScheduled = 0;
x86_fpu_enabled = (xb->settings >> 22) & 1;
dosbox_sec = new Section_prop("dummy");
MEM_Init(dosbox_sec);
PAGING_Init(dosbox_sec);
CMOS_Init(dosbox_sec, xb->type == TYPE_2386 ? 0x7f : 0x3f);
PIC_Init(dosbox_sec);
TIMER_Init(dosbox_sec);
FPU_Init(dosbox_sec);
if (xb->type >= TYPE_2286) {
xb->cmossize = xb->type == TYPE_2386 ? 192 : 64;
xb->cmosfile = zfile_fopen(currprefs.flashfile, _T("rb+"), ZFD_NORMAL);
if (!xb->cmosfile) {
xb->cmosfile = zfile_fopen(currprefs.flashfile, _T("wb"));
}
memset(xb->cmosregs, 0, sizeof xb->cmosregs);
if (xb->cmosfile) {
if (zfile_fread(xb->cmosregs, 1, xb->cmossize, xb->cmosfile) == xb->cmossize) {
x86_cmos_regs(xb->cmosregs);
}
}
}
}
if (ISVGA()) {
if (xb->dosbox_cpu) {
MEM_SetVGAHandler();
}
load_vga_bios();
}
xb->pc_jumpers = (xb->settings & 0xff) ^ ((0x80 | 0x40) | (0x20 | 0x10 | 0x01 | 0x02));
int ramsize = (xb->settings >> 2) & 3;
switch(ramsize) {
case 0:
xb->pc_maxbaseram = 128 * 1024;
break;
case 1:
xb->pc_maxbaseram = 256 * 1024;
break;
case 2:
xb->pc_maxbaseram = 512 * 1024;
break;
case 3:
xb->pc_maxbaseram = 640 * 1024;
break;
}
bridge_reset(xb);
// load bios
if (!load_rom_rc(rc, romtype, xb->bios_size, 0, xb->pc_rom + 0x100000 - xb->bios_size, xb->bios_size, LOADROM_FILL)) {
error_log(_T("Bridgeboard BIOS failed to load"));
x86_bridge_free();
return &expamem_null;
}
memcpy(xb->pc_ram + 0x100000 - xb->bios_size, xb->pc_rom + 0x100000 - xb->bios_size, xb->bios_size);
setrombank(xb, 0x100000 - xb->bios_size, xb->bios_size);
xb->bank = &x86_bridge_bank;
for (int i = 0; i < 16; i++) {
ew(xb->acmemory, i * 4, ac[i]);
}
return xb->bank;
}
addrbank *a1060_init(struct romconfig *rc)
{
return x86_bridge_init(rc, ROMTYPE_A1060, TYPE_SIDECAR);
}
addrbank *a2088xt_init(struct romconfig *rc)
{
return x86_bridge_init(rc, ROMTYPE_A2088, TYPE_2088);
}
addrbank *a2088t_init(struct romconfig *rc)
{
return x86_bridge_init(rc, ROMTYPE_A2088T, TYPE_2088T);
}
addrbank *a2286_init(struct romconfig *rc)
{
return x86_bridge_init(rc, ROMTYPE_A2286, TYPE_2286);
}
addrbank *a2386_init(struct romconfig *rc)
{
return x86_bridge_init(rc, ROMTYPE_A2386, TYPE_2386);
}
/* dosbox cpu core support stuff */
void IO_WriteB(Bitu port, Bitu val)
{
portout(port, val);
}
void IO_WriteW(Bitu port, Bitu val)
{
portout16(port, val);
}
void IO_WriteD(Bitu port, Bitu val)
{
portout32(port, val);
}
Bitu IO_ReadB(Bitu port)
{
return portin(port);
}
Bitu IO_ReadW(Bitu port)
{
return portin16(port);
}
Bitu IO_ReadD(Bitu port)
{
return portin32(port);
}
Bits CPU_Core_Prefetch_Run(void)
{
return 0;
}
bool CommandLine::FindCommand(unsigned int which, std::string & value)
{
return false;
}
unsigned int CommandLine::GetCount(void)
{
return 0;
}
CommandLine::CommandLine(int argc, char const * const argv[])
{
}
CommandLine::CommandLine(char const * const name, char const * const cmdline)
{
}
void Section::AddDestroyFunction(SectionFunction func, bool canchange)
{
}
int Section_prop::Get_int(string const&_propname) const
{
return 0;
}
const char* Section_prop::Get_string(string const& _propname) const
{
return NULL;
}
Prop_multival* Section_prop::Get_multival(string const& _propname) const
{
return NULL;
}
void Section_prop::HandleInputline(string const& gegevens)
{
}
void Section_prop::PrintData(FILE* outfile) const
{
}
Section_prop::~Section_prop()
{
}
string Section_prop::GetPropValue(string const& _property) const
{
return NO_SUCH_PROPERTY;
}
void DOSBOX_RunMachine(void)
{
}
void GFX_SetTitle(Bit32s cycles, Bits frameskip, bool paused)
{
}
void E_Exit(char *format, ...)
{
va_list parms;
va_start(parms, format);
char buffer[1000];
vsnprintf(buffer, sizeof(buffer), format, parms);
write_log("DOSBOX E_Exit: %s\n", buffer);
va_end(parms);
}
void GFX_ShowMsg(const char *format, ...)
{
va_list parms;
va_start(parms, format);
char buffer[1000];
vsnprintf(buffer, sizeof(buffer), format, parms);
write_log("DOSBOX GFX_ShowMsg: %s\n", buffer);
va_end(parms);
}