mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
4323 lines
100 KiB
C++
4323 lines
100 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.
|
|
*
|
|
* 2018: Replaced Fake86 and DOSBox with PCem v14.
|
|
* 2020: PCem v16.
|
|
*
|
|
*/
|
|
|
|
#define X86_DEBUG_BRIDGE 1
|
|
#define FLOPPY_IO_DEBUG 0
|
|
#define X86_DEBUG_BRIDGE_IO 0
|
|
#define X86_DEBUG_BRIDGE_IRQ 0
|
|
#define X86_IO_PORT_DEBUG 0
|
|
#define X86_DEBUG_SPECIAL_IO 0
|
|
#define FLOPPY_DEBUG 1
|
|
#define EMS_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 "pci_hw.h"
|
|
#include "devices.h"
|
|
#include "audio.h"
|
|
|
|
#include "pcem/ibm.h"
|
|
#include "pcem/pic.h"
|
|
#include "pcem/pit.h"
|
|
#include "pcem/timer.h"
|
|
#include "pcem/pcemglue.h"
|
|
#include "pcem/model.h"
|
|
#include "pcem/mem.h"
|
|
#include "pcem/codegen.h"
|
|
#include "pcem/x86.h"
|
|
#include "pcem/nvr.h"
|
|
#include "pcem/keyboard_at.h"
|
|
#include "pcem/keyboard.h"
|
|
#include "pcem/dma.h"
|
|
#include "pcem/sound_speaker.h"
|
|
#include "pcem/sound.h"
|
|
#include "pcem/sound_cms.h"
|
|
#include "pcem/mouse.h"
|
|
#include "pcem/mouse_serial.h"
|
|
#include "pcem/serial.h"
|
|
extern int cpu;
|
|
extern int nvrmask;
|
|
void keyboard_at_write(uint16_t port, uint8_t val, void *priv);
|
|
|
|
#define MAX_IO_PORT 0x400
|
|
|
|
static uint8_t(*port_inb[MAX_IO_PORT])(uint16_t addr, void *priv);
|
|
static uint16_t(*port_inw[MAX_IO_PORT])(uint16_t addr, void *priv);
|
|
static uint32_t(*port_inl[MAX_IO_PORT])(uint16_t addr, void *priv);
|
|
static void(*port_outb[MAX_IO_PORT])(uint16_t addr, uint8_t val, void *priv);
|
|
static void(*port_outw[MAX_IO_PORT])(uint16_t addr, uint16_t val, void *priv);
|
|
static void(*port_outl[MAX_IO_PORT])(uint16_t addr, uint32_t val, void *priv);
|
|
static void *port_priv[MAX_IO_PORT];
|
|
|
|
static float x86_base_event_clock;
|
|
static int x86_sndbuffer_playpos;
|
|
static int x86_sndbuffer_playindex;
|
|
static int sound_handlers_num;
|
|
static uint64_t sound_poll_latch;
|
|
static pc_timer_t sound_poll_timer;
|
|
void sound_poll(void *priv);
|
|
void sound_speed_changed(bool);
|
|
|
|
#define TYPE_SIDECAR 0
|
|
#define TYPE_2088 1
|
|
#define TYPE_2088T 2
|
|
#define TYPE_2286 3
|
|
#define TYPE_2386 4
|
|
|
|
void x86_doirq(uint8_t irqnum);
|
|
|
|
bool x86_cpu_active;
|
|
extern int cpu_multiplier;
|
|
|
|
static int x86_vga_mode;
|
|
static int x86_vga_board;
|
|
int x86_cmos_bank;
|
|
|
|
static uae_u8 *xtiderom;
|
|
static uae_u8 *rt1000rom;
|
|
|
|
int GAMEBLASTER = 1;
|
|
int sound_pos_global;
|
|
int SOUNDBUFLEN = 8192;
|
|
static int32_t outbuffer1[MAXSOUNDBUFLEN * 2];
|
|
static int32_t outbuffer2[MAXSOUNDBUFLEN * 2];
|
|
static int x86_sndbuffer_index;
|
|
static int32_t *x86_sndbuffer[2];
|
|
static bool x86_sndbuffer_filled[2];
|
|
bool ps2_mouse_supported;
|
|
|
|
struct membase
|
|
{
|
|
uae_u8 *base;
|
|
uae_u32 mask;
|
|
};
|
|
|
|
struct scamp_shadow
|
|
{
|
|
mem_mapping_t r_map;
|
|
mem_mapping_t w_map;
|
|
};
|
|
|
|
struct x86_bridge
|
|
{
|
|
uae_u8 acmemory[128];
|
|
addrbank *bank;
|
|
int configured;
|
|
int type;
|
|
uaecptr baseaddress;
|
|
uae_u8 *pc_ram;
|
|
uae_u8 *pc_rom;
|
|
uae_u8 *io_ports;
|
|
uae_u8 *amiga_io;
|
|
uae_u8 *amiga_parameter;
|
|
uae_u8 *amiga_buffer;
|
|
uae_u8 *amiga_mono;
|
|
uae_u8 *amiga_color;
|
|
int mode_register;
|
|
bool x86_reset;
|
|
bool amiga_irq;
|
|
bool amiga_forced_interrupts;
|
|
bool pc_irq3a, pc_irq3b, pc_irq7;
|
|
int delayed_interrupt;
|
|
uae_u8 pc_jumpers;
|
|
int pc_maxbaseram;
|
|
int bios_size;
|
|
int settings;
|
|
struct zfile *cmosfile;
|
|
uae_u8 cmosregs[3 * 0x40];
|
|
int a2386_default_video;
|
|
bool pc_speaker;
|
|
int cmossize;
|
|
struct romconfig *rc;
|
|
int vgaboard;
|
|
int vgaboard_vram;
|
|
const struct pci_board *ne2000_isa;
|
|
struct pci_board_state *ne2000_isa_board_state;
|
|
int ne2000_io;
|
|
int ne2000_irq;
|
|
mem_mapping_t sharedio_parameter;
|
|
struct membase sharedio_parameter_mb;
|
|
mem_mapping_t sharedio_mono;
|
|
struct membase sharedio_mono_mb;
|
|
mem_mapping_t sharedio_color;
|
|
struct membase sharedio_color_mb;
|
|
mem_mapping_t sharedio_buffer[3];
|
|
uae_u32 shared_io_addr;
|
|
struct membase sharedio_buffer_mb;
|
|
mem_mapping_t vgamem;
|
|
mem_mapping_t vgalfbmem;
|
|
int audstream;
|
|
int audeventtime;
|
|
bool sound_emu;
|
|
bool sound_initialized;
|
|
void *sb_base;
|
|
void *cms_base;
|
|
void *mouse_base;
|
|
int mouse_type;
|
|
int mouse_port;
|
|
bool video_initialized;
|
|
|
|
struct scamp_shadow shadows[16];
|
|
mem_mapping_t ems[0x24];
|
|
int shadowvals[4];
|
|
int emsvals[0x24];
|
|
int sltptr;
|
|
int scamp_idx1, scamp_idx2;
|
|
uae_u8 vlsi_regs[0x100];
|
|
uae_u16 vlsi_regs_ems[64];
|
|
bool vlsi_config;
|
|
int a2386flipper;
|
|
bool a2386_amigapcdrive;
|
|
|
|
X86_INTERRUPT_CALLBACK irq_callback;
|
|
};
|
|
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() (bridges[0]->vgaboard >= 0)
|
|
|
|
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;
|
|
};
|
|
|
|
static void reset_cpu(void)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
|
|
resetx86();
|
|
}
|
|
|
|
static void reset_x86_hardware(struct x86_bridge *xb);
|
|
static void reset_x86_cpu(struct x86_bridge *xb)
|
|
{
|
|
write_log(_T("x86 CPU reset\n"));
|
|
reset_cpu();
|
|
}
|
|
|
|
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 int get_shared_io(struct x86_bridge *xb)
|
|
{
|
|
int opt = (xb->amiga_io[IO_MODE_REGISTER] >> 5) & 3;
|
|
// disk buffer
|
|
if (xb->type >= TYPE_2286) {
|
|
switch (opt)
|
|
{
|
|
case 1:
|
|
return 0xa0000;
|
|
case 2:
|
|
default:
|
|
return 0xd0000;
|
|
}
|
|
}
|
|
else {
|
|
switch (opt)
|
|
{
|
|
case 1:
|
|
default:
|
|
return 0xa0000;
|
|
case 2:
|
|
return 0xd0000;
|
|
case 3:
|
|
return 0xe0000;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void set_configurable_shared_io(struct x86_bridge *xb)
|
|
{
|
|
if (get_shared_io(xb) == xb->shared_io_addr)
|
|
return;
|
|
xb->shared_io_addr = get_shared_io(xb);
|
|
mem_mapping_disable(&xb->sharedio_buffer[0]);
|
|
mem_mapping_disable(&xb->sharedio_buffer[1]);
|
|
mem_mapping_disable(&xb->sharedio_buffer[2]);
|
|
switch (xb->shared_io_addr)
|
|
{
|
|
case 0xa0000:
|
|
mem_mapping_enable(&xb->sharedio_buffer[0]);
|
|
break;
|
|
case 0xd0000:
|
|
mem_mapping_enable(&xb->sharedio_buffer[1]);
|
|
break;
|
|
case 0xe0000:
|
|
mem_mapping_enable(&xb->sharedio_buffer[2]);
|
|
break;
|
|
}
|
|
write_log(_T("Buffer IO = %08x\n"), xb->shared_io_addr);
|
|
}
|
|
|
|
static uae_u8 get_mode_register(struct x86_bridge *xb, uae_u8 v)
|
|
{
|
|
if (xb->type == TYPE_SIDECAR) {
|
|
// PC/XT + keyboard. Read-only.
|
|
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 (read-write)
|
|
v |= 0x80;
|
|
} else {
|
|
// AT (read-write)
|
|
v &= ~0x80;
|
|
}
|
|
set_configurable_shared_io(xb);
|
|
return v;
|
|
}
|
|
|
|
static uae_u8 x86_bridge_put_io(struct x86_bridge *xb, uaecptr addr, uae_u8 v)
|
|
{
|
|
#if X86_DEBUG_BRIDGE_IO
|
|
uae_u8 old = xb->amiga_io[addr];
|
|
write_log(_T("IO write %08x %02x -> %02x\n"), addr, old, 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 -> %02x\n"), old, 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 -> %02x\n"), old, 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;
|
|
reset_x86_hardware(xb);
|
|
}
|
|
if (!(v & 1))
|
|
v |= 2;
|
|
else if (!(v & 2))
|
|
v |= 1;
|
|
xb->a2386flipper = (v >> 5) & 3;
|
|
#if X86_DEBUG_BRIDGE_IO
|
|
write_log(_T("IO_CONTROL_REGISTER %02X -> %02x\n"), old, 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 -> %02x\n"), old, 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 -> %02x\n"), old, v);
|
|
#endif
|
|
xb->io_ports[0x60] = v;
|
|
if (xb->type >= TYPE_2286) {
|
|
keyboard_send(v);
|
|
}
|
|
}
|
|
break;
|
|
case IO_MODE_REGISTER:
|
|
v = get_mode_register(xb, v);
|
|
#if X86_DEBUG_BRIDGE_IO
|
|
write_log(_T("IO_MODE_REGISTER %02X -> %02x\n"), old, v);
|
|
#endif
|
|
break;
|
|
case IO_INTERRUPT_MASK:
|
|
#if X86_DEBUG_BRIDGE_IO
|
|
write_log(_T("IO_INTERRUPT_MASK %02X -> %02x\n"), old, v);
|
|
#endif
|
|
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"));
|
|
}
|
|
if (v == 6 || v == 7) {
|
|
xb->pc_speaker = (v & 1) != 0;
|
|
}
|
|
if (v == 10 || v == 11) {
|
|
xb->a2386_amigapcdrive = (v & 1) != 0;
|
|
write_log(_T("A2386 Flipper mode = %s\n"), xb->a2386_amigapcdrive ? _T("PC") : _T("Amiga"));
|
|
}
|
|
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;
|
|
}
|
|
|
|
#if X86_DEBUG_BRIDGE_IO > 1
|
|
write_log(_T("IO read %08x %02x\n"), addr, v);
|
|
#endif
|
|
return v;
|
|
}
|
|
|
|
static void x86_bridge_rethink(void);
|
|
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;
|
|
devices_rethink_all(x86_bridge_rethink);
|
|
}
|
|
|
|
void x86_ack_keyboard(void)
|
|
{
|
|
set_interrupt(bridges[0], 4);
|
|
}
|
|
|
|
void x86_clearirq(uint8_t irqnum)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (xb->irq_callback) {
|
|
xb->irq_callback(irqnum, false);
|
|
} else {
|
|
picintc(1 << irqnum);
|
|
}
|
|
}
|
|
|
|
void x86_doirq(uint8_t irqnum)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (xb->irq_callback) {
|
|
xb->irq_callback(irqnum, true);
|
|
} else {
|
|
picint(1 << irqnum);
|
|
}
|
|
}
|
|
|
|
struct pc_floppy
|
|
{
|
|
int seek_offset;
|
|
int phys_cyl;
|
|
int cyl;
|
|
uae_u8 sector;
|
|
uae_u8 head;
|
|
bool disk_changed;
|
|
};
|
|
|
|
static struct pc_floppy floppy_pc[4];
|
|
static uae_u8 floppy_dpc;
|
|
static uae_s8 floppy_idx;
|
|
static uae_u8 floppy_dir;
|
|
static uae_s8 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 bool floppy_specify_pio;
|
|
static uae_u8 *floppy_pio_buffer;
|
|
static int floppy_pio_len, floppy_pio_cnt, floppy_pio_active;
|
|
static uae_s8 floppy_rate;
|
|
|
|
#define PC_SEEK_DELAY 50
|
|
|
|
static void floppy_reset(void)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy reset\n"));
|
|
#endif
|
|
floppy_idx = 0;
|
|
floppy_dir = 0;
|
|
floppy_did_reset = true;
|
|
floppy_specify_pio = false;
|
|
floppy_pio_active = 0;
|
|
floppy_dpc = 0;
|
|
floppy_cmd_len = 0;
|
|
floppy_num = 0;
|
|
floppy_delay_hsync = 0;
|
|
floppy_irq = false;
|
|
floppy_pio_len = 0;
|
|
floppy_pio_cnt = 0;
|
|
floppy_rate = 0;
|
|
for (int i = 0; i < 4; i++) {
|
|
floppy_seeking[i] = 0;
|
|
floppy_seekcyl[i] = 0;
|
|
}
|
|
|
|
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)
|
|
{
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("floppy%d irq (enable=%d)\n"), floppy_num, (floppy_dpc & 8) != 0);
|
|
#endif
|
|
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[num];
|
|
|
|
disk_reserved_reset_disk_change(num);
|
|
if (!error) {
|
|
struct floppy_reserved fr = { 0 };
|
|
bool valid_floppy = disk_reserved_getinfo(num, &fr);
|
|
if (floppy_seekcyl[num] != pcf->phys_cyl) {
|
|
|
|
pcf->disk_changed = false;
|
|
|
|
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
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d seeking.. %d\n"), num, pcf->phys_cyl);
|
|
#endif
|
|
if (pcf->phys_cyl - pcf->seek_offset <= 0) {
|
|
pcf->phys_cyl = 0;
|
|
if (pcf->seek_offset) {
|
|
floppy_seekcyl[num] = 0;
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d early track zero\n"), num);
|
|
#endif
|
|
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(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:
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d seek done err=%d. pcyl=%d cyl=%d h=%d\n"), num, error, pcf->phys_cyl,pcf->cyl, pcf->head);
|
|
#endif
|
|
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 void floppy_clear_irq(void)
|
|
{
|
|
if (floppy_irq) {
|
|
x86_clearirq(6);
|
|
floppy_irq = false;
|
|
}
|
|
}
|
|
|
|
static bool floppy_valid_format(struct floppy_reserved *fr)
|
|
{
|
|
if (fr->secs == 11 || fr->secs == 22)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static bool floppy_valid_rate(struct floppy_reserved *fr)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
// A2386 BIOS sets 720k data rate for 720k, 1.2M and 1.4M drives
|
|
// probably because it thinks Amiga half-speed drive is connected?
|
|
if (xb->type == TYPE_2386 && fr->rate == 0 && (floppy_rate == 1 || floppy_rate == 2))
|
|
return true;
|
|
return fr->rate == floppy_rate || floppy_rate < 0;
|
|
}
|
|
|
|
static void floppy_format(struct x86_bridge *xb, bool real)
|
|
{
|
|
uae_u8 cmd = floppy_cmd[0];
|
|
struct pc_floppy *pcf = &floppy_pc[floppy_num];
|
|
struct floppy_reserved fr = { 0 };
|
|
bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
|
|
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d %s format MF=%d N=%d:SC=%d:GPL=%d:D=%d\n"),
|
|
floppy_num, real ? _T("real") : _T("sim"), (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"), dma[2].page | dma[2].ac, dma[2].cb);
|
|
write_log(_T("IMG: Secs=%d Heads=%d\n"), fr.secs, fr.heads);
|
|
#endif
|
|
int secs = floppy_cmd[3];
|
|
int sector = pcf->sector;
|
|
int head = pcf->head;
|
|
int cyl = pcf->cyl;
|
|
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);
|
|
uae_u8 *pioptr = floppy_pio_buffer;
|
|
for (int i = 0; i < secs && i < fr.secs && !fr.wrprot; i++) {
|
|
uae_u8 cx = 0, hx = 0, rx = 0, nx = 0;
|
|
if (floppy_specify_pio) {
|
|
if (real) {
|
|
floppy_pio_cnt += 4;
|
|
if (floppy_pio_cnt <= floppy_pio_len) {
|
|
cx = *pioptr++;
|
|
hx = *pioptr++;
|
|
rx = *pioptr++;
|
|
nx = *pioptr++;
|
|
}
|
|
} else {
|
|
floppy_pio_len += 4;
|
|
}
|
|
} else {
|
|
if (real) {
|
|
cx = dma_channel_read(2);
|
|
hx = dma_channel_read(2);
|
|
rx = dma_channel_read(2);
|
|
nx = dma_channel_read(2);
|
|
}
|
|
}
|
|
pcf->sector = rx - 1;
|
|
#if FLOPPY_DEBUG
|
|
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);
|
|
#endif
|
|
if (real) {
|
|
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++;
|
|
}
|
|
} 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];
|
|
if (real) {
|
|
floppy_delay_hsync = 10;
|
|
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
|
|
} else {
|
|
pcf->cyl = cyl;
|
|
pcf->sector = sector;
|
|
pcf->head = head;
|
|
}
|
|
}
|
|
|
|
static void floppy_write(struct x86_bridge *xb, bool real)
|
|
{
|
|
uae_u8 cmd = floppy_cmd[0];
|
|
struct pc_floppy *pcf = &floppy_pc[floppy_num];
|
|
struct floppy_reserved fr = { 0 };
|
|
bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
|
|
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d %s write MT=%d MF=%d C=%d:H=%d:R=%d:N=%d:EOT=%d:GPL=%d:DTL=%d\n"),
|
|
floppy_num, real ? _T("real") : _T("sim"), (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"), dma[2].page | dma[2].ac, dma[2].ab);
|
|
#endif
|
|
floppy_delay_hsync = 50;
|
|
int eot = floppy_cmd[6];
|
|
bool mt = (floppy_cmd[0] & 0x80) != 0;
|
|
int sector = pcf->sector;
|
|
int head = pcf->head;
|
|
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) {
|
|
int end = 0;
|
|
pcf->sector = floppy_cmd[4] - 1;
|
|
pcf->head = (floppy_cmd[1] & 4) ? 1 : 0;
|
|
uae_u8 *pioptr = floppy_pio_buffer;
|
|
while (!end && !fr.wrprot) {
|
|
int len = 128 << floppy_cmd[5];
|
|
uae_u8 buf[512] = { 0 };
|
|
if (floppy_specify_pio) {
|
|
for (int i = 0; i < 512 && i < len; i++) {
|
|
if (real) {
|
|
if (floppy_pio_cnt >= floppy_pio_len) {
|
|
end = 1;
|
|
break;
|
|
}
|
|
int v = *pioptr++;
|
|
buf[i] = v;
|
|
floppy_pio_cnt++;
|
|
} else {
|
|
floppy_pio_len++;
|
|
}
|
|
}
|
|
} else {
|
|
for (int i = 0; i < 512 && i < len; i++) {
|
|
if (real) {
|
|
int v = dma_channel_read(2);
|
|
if (v < 0) {
|
|
end = -1;
|
|
break;
|
|
}
|
|
buf[i] = v;
|
|
if (v >= 0x10000) {
|
|
end = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("LEN=%d END=%d C=%d H=%d S=%d. IMG S=%d H=%d\n"), len, end, pcf->cyl, pcf->head, pcf->sector, fr.secs, fr.heads);
|
|
#endif
|
|
if (end < 0)
|
|
break;
|
|
if (real) {
|
|
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 (pcf->sector == eot) {
|
|
if (mt) {
|
|
pcf->sector = 0;
|
|
if (pcf->head)
|
|
pcf->cyl++;
|
|
pcf->head ^= 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (pcf->sector >= fr.secs) {
|
|
pcf->sector = 0;
|
|
pcf->head ^= 1;
|
|
break;
|
|
}
|
|
}
|
|
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];
|
|
if (real) {
|
|
floppy_delay_hsync = 10;
|
|
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
|
|
} else {
|
|
pcf->cyl = cyl;
|
|
pcf->sector = sector;
|
|
pcf->head = head;
|
|
}
|
|
}
|
|
|
|
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_DEBUG
|
|
if (floppy_cmd_len > 0) {
|
|
write_log(_T("Command: "));
|
|
for (int i = 0; i < floppy_cmd_len; i++) {
|
|
write_log(_T("%02x "), floppy_cmd[i]);
|
|
}
|
|
write_log(_T("\n"));
|
|
}
|
|
#endif
|
|
|
|
if (cmd == 8) {
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d Sense Interrupt Status\n"), floppy_num);
|
|
#endif
|
|
floppy_cmd_len = 2;
|
|
#if FLOPPY_DEBUG
|
|
if (floppy_irq) {
|
|
write_log(_T("Floppy interrupt reset\n"));
|
|
}
|
|
#endif
|
|
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;
|
|
}
|
|
floppy_clear_irq();
|
|
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:
|
|
#if FLOPPY_DEBUG
|
|
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);
|
|
#endif
|
|
floppy_delay_hsync = -5;
|
|
floppy_specify_pio = (floppy_cmd[2] & 1) != 0;
|
|
if (floppy_specify_pio && !floppy_pio_buffer) {
|
|
floppy_pio_buffer = xcalloc(uae_u8, 512 * 36);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d Sense Drive Status\n"), floppy_num);
|
|
#endif
|
|
floppy_delay_hsync = 5;
|
|
floppy_result[0] = floppy_status[3];
|
|
floppy_cmd_len = 1;
|
|
break;
|
|
|
|
case 5:
|
|
{
|
|
floppy_write(xb, true);
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
{
|
|
#if FLOPPY_DEBUG
|
|
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"), dma[2].page | dma[2].ac, dma[2].cb);
|
|
write_log(_T("IMG: Secs=%d Heads=%d\n"), fr.secs, fr.heads);
|
|
#endif
|
|
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) || !floppy_valid_format(&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;
|
|
floppy_pio_len = 0;
|
|
floppy_pio_cnt = 0;
|
|
uae_u8 *pioptr = floppy_pio_buffer;
|
|
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);
|
|
if (floppy_specify_pio) {
|
|
memcpy(pioptr, buf, 512);
|
|
pioptr += 512;
|
|
floppy_pio_len += 512;
|
|
floppy_pio_active = 1;
|
|
} else {
|
|
for (int i = 0; i < 512 && i < len; i++) {
|
|
int v = dma_channel_write(2, buf[i]);
|
|
if (v < 0 || v > 65535)
|
|
end = true;
|
|
}
|
|
}
|
|
pcf->sector++;
|
|
if (pcf->sector == eot) {
|
|
if (mt) {
|
|
pcf->sector = 0;
|
|
if (pcf->head)
|
|
pcf->cyl++;
|
|
pcf->head ^= 1;
|
|
} else {
|
|
end = true;
|
|
}
|
|
}
|
|
if (pcf->sector >= fr.secs) {
|
|
pcf->sector = 0;
|
|
pcf->head ^= 1;
|
|
end = true;
|
|
}
|
|
}
|
|
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:
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d recalibrate\n"), floppy_num);
|
|
#endif
|
|
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:
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy read ID\n"));
|
|
#endif
|
|
if (!valid_floppy || !fr.img || !floppy_valid_rate(&fr) || (pcf->head && fr.heads == 1) || !floppy_valid_format(&fr)) {
|
|
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 = maxvpos * 20;
|
|
disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1);
|
|
break;
|
|
|
|
case 13:
|
|
{
|
|
floppy_format(xb, true);
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
{
|
|
int newcyl = floppy_cmd[2];
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("Floppy%d seek %d->%d (max %d)\n"), floppy_num, pcf->phys_cyl, newcyl, fr.cyls);
|
|
#endif
|
|
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;
|
|
|
|
case 16:
|
|
floppy_status[0] = 0x90;
|
|
floppy_cmd_len = 1;
|
|
break;
|
|
|
|
default:
|
|
floppy_status[0] = 0x80;
|
|
floppy_cmd_len = 1;
|
|
break;
|
|
|
|
}
|
|
|
|
end:
|
|
if (floppy_cmd_len > 0) {
|
|
floppy_idx = -1;
|
|
floppy_dir = 1;
|
|
#if FLOPPY_DEBUG
|
|
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"));
|
|
#endif
|
|
} else {
|
|
floppy_idx = 0;
|
|
floppy_dir = 0;
|
|
}
|
|
}
|
|
|
|
static int draco_force_irq;
|
|
|
|
static void outfloppy(struct x86_bridge *xb, int portnum, uae_u8 v)
|
|
{
|
|
#if FLOPPY_IO_DEBUG
|
|
write_log(_T("out floppy port %04x %02x\n"), portnum, v);
|
|
#endif
|
|
|
|
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;
|
|
if (xb->type < 0) {
|
|
floppy_dpc |= 8;
|
|
}
|
|
floppy_num = v & 3;
|
|
for (int i = 0; i < 2; i++) {
|
|
disk_reserved_setinfo(i, floppy_pc[i].cyl, floppy_pc[i].head, floppy_selected() == i);
|
|
}
|
|
break;
|
|
case 0x3f5: // data reg
|
|
if (floppy_pio_len > 0 && floppy_pio_cnt < floppy_pio_len && floppy_pio_active) {
|
|
floppy_pio_buffer[floppy_pio_cnt++] = v;
|
|
if (floppy_pio_cnt >= floppy_pio_len) {
|
|
floppy_pio_cnt = 0;
|
|
floppy_pio_active = 0;
|
|
floppy_clear_irq();
|
|
floppy_do_cmd(xb);
|
|
floppy_pio_cnt = 0;
|
|
floppy_pio_len = 0;
|
|
}
|
|
} else {
|
|
floppy_cmd[floppy_idx] = v;
|
|
if (floppy_idx == 0) {
|
|
floppy_cmd_len = -1;
|
|
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 12: // perpendiculaor mode
|
|
if (xb->type < 0) {
|
|
floppy_cmd_len = 2;
|
|
}
|
|
break;
|
|
case 13: // format track
|
|
floppy_cmd_len = 6;
|
|
break;
|
|
case 15: // seek
|
|
floppy_cmd_len = 3;
|
|
break;
|
|
case 16: // get versionm
|
|
if (xb->type < 0) {
|
|
floppy_cmd_len = 1;
|
|
}
|
|
break;
|
|
case 19: // configure
|
|
if (xb->type < 0) {
|
|
floppy_cmd_len = 4;
|
|
}
|
|
break;
|
|
}
|
|
if (floppy_cmd_len < 0) {
|
|
write_log(_T("Floppy unimplemented command %02x\n"), v);
|
|
floppy_cmd_len = 1;
|
|
}
|
|
}
|
|
floppy_idx++;
|
|
if (floppy_idx >= floppy_cmd_len) {
|
|
if (floppy_specify_pio && (floppy_cmd[0] & 31) == 5) {
|
|
floppy_write(xb, false);
|
|
floppy_pio_cnt = 0;
|
|
floppy_pio_active = 0;
|
|
if (floppy_pio_len > 0) {
|
|
floppy_delay_hsync = 10;
|
|
floppy_pio_active = 1;
|
|
} else {
|
|
floppy_write(xb, true);
|
|
}
|
|
} else if (floppy_specify_pio && (floppy_cmd[0] & 31) == 13) {
|
|
floppy_format(xb, false);
|
|
floppy_pio_cnt = 0;
|
|
floppy_pio_active = 0;
|
|
if (floppy_pio_len > 0) {
|
|
floppy_delay_hsync = 10;
|
|
floppy_pio_active = 1;
|
|
} else {
|
|
floppy_format(xb, true);
|
|
}
|
|
} else {
|
|
floppy_do_cmd(xb);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 0x3f7: // configuration control
|
|
if (xb->type >= TYPE_2286) {
|
|
#if FLOPPY_DEBUG
|
|
write_log(_T("FDC Control Register %02x\n"), v);
|
|
#endif
|
|
floppy_rate = v & 3;
|
|
} else {
|
|
floppy_rate = -1;
|
|
}
|
|
break;
|
|
default:
|
|
write_log(_T("Unknown FDC %04x write %02x\n"), portnum, v);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uae_u8 infloppy(struct x86_bridge *xb, int portnum)
|
|
{
|
|
uae_u8 v = 0;
|
|
switch (portnum)
|
|
{
|
|
case 0x3f0: // PS/2 status A (draco)
|
|
if (xb->type < 0) {
|
|
struct floppy_reserved fr = { 0 };
|
|
bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
|
|
v |= floppy_irq ? 0x80 : 0x00; // INT PENDING
|
|
v |= 0x40; // nDRV2
|
|
v |= fr.wrprot ? 0 : 2; // nWP
|
|
v |= fr.cyl == 0 ? 0 : 16; // nTRK0
|
|
}
|
|
break;
|
|
case 0x3f1: // PS/2 status B (draco)
|
|
if (xb->type < 0) {
|
|
v |= 0x80 | 0x40;
|
|
if (floppy_dpc & 1)
|
|
v |= 0x20;
|
|
if ((floppy_dpc >> 4) & 1)
|
|
v |= 0x01;
|
|
if ((floppy_dpc >> 4) & 2)
|
|
v |= 0x02;
|
|
}
|
|
break;
|
|
case 0x3f2:
|
|
v = floppy_dpc;
|
|
break;
|
|
case 0x3f4: // main status
|
|
v = 0;
|
|
if (!floppy_delay_hsync && (floppy_dpc & 4))
|
|
v |= 0x80;
|
|
if (floppy_idx || floppy_delay_hsync || floppy_pio_active) {
|
|
v |= 0x10;
|
|
if (floppy_pio_active)
|
|
v |= 0x20;
|
|
}
|
|
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_pio_len > 0 && floppy_pio_cnt < floppy_pio_len) {
|
|
v = floppy_pio_buffer[floppy_pio_cnt++];
|
|
if (floppy_pio_cnt >= floppy_pio_len) {
|
|
floppy_pio_len = 0;
|
|
floppy_pio_active = 0;
|
|
floppy_clear_irq();
|
|
floppy_delay_hsync = 50;
|
|
}
|
|
} else 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;
|
|
floppy_clear_irq();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 0x3f7: // digital input register
|
|
if (xb->type >= TYPE_2286 || xb->type < 0) {
|
|
struct pc_floppy *pcf = &floppy_pc[floppy_num];
|
|
struct floppy_reserved fr = { 0 };
|
|
bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
|
|
v = 0x00;
|
|
if (valid_floppy && fr.disk_changed && (floppy_dpc >> 4) & (1 << floppy_num)) {
|
|
pcf->disk_changed = true;
|
|
}
|
|
if (pcf->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;
|
|
}
|
|
|
|
uae_u16 floppy_get_raw_data(int *rate)
|
|
{
|
|
struct floppy_reserved fr = { 0 };
|
|
bool valid_floppy = disk_reserved_getinfo(floppy_num, &fr);
|
|
*rate = fr.rate;
|
|
if (valid_floppy) {
|
|
return DSKBYTR_fake(fr.num);
|
|
}
|
|
return 0x8000;
|
|
}
|
|
|
|
static void set_cpu_turbo(struct x86_bridge *xb)
|
|
{
|
|
cpu_multiplier = (int)currprefs.x86_speed_throttle;
|
|
cpu_set();
|
|
cpu_update_waitstates();
|
|
cpu_set_turbo(0);
|
|
cpu_set_turbo(1);
|
|
}
|
|
|
|
static void set_initial_cpu_turbo(struct x86_bridge *xb)
|
|
{
|
|
xb->video_initialized = true;
|
|
if (currprefs.x86_speed_throttle) {
|
|
write_log(_T("Video initialized, activating x86 CPU turbo.\n"));
|
|
set_cpu_turbo(xb);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
xb->delayed_interrupt |= 1 << 0;
|
|
}
|
|
}
|
|
if (addr >= 0xb8000 && addr < 0xc0000) {
|
|
// color
|
|
if (xb->amiga_io[IO_MODE_REGISTER] & 16) {
|
|
xb->delayed_interrupt |= 1 << 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 (xb->mode_register < 0 || ((mode_register & (8 | 16)) != (xb->mode_register & (8 | 16)))) {
|
|
xb->mode_register = mode_register;
|
|
if (!(mode_register & 8)) {
|
|
mem_mapping_disable(&xb->sharedio_mono);
|
|
} else {
|
|
mem_mapping_enable(&xb->sharedio_mono);
|
|
}
|
|
if (!(mode_register & 16)) {
|
|
mem_mapping_disable(&xb->sharedio_color);
|
|
} else {
|
|
mem_mapping_enable(&xb->sharedio_color);
|
|
}
|
|
}
|
|
|
|
if (write && (portnum == 0x3b1 || portnum == 0x3b3 || portnum == 0x3b5 || portnum == 0x3b7 || portnum == 0x3b8)) {
|
|
if (!xb->video_initialized) {
|
|
set_initial_cpu_turbo(xb);
|
|
}
|
|
// mono crt data register
|
|
if (mode_register & 8) {
|
|
xb->delayed_interrupt |= 1 << 2;
|
|
}
|
|
} else if (write && (portnum == 0x3d1 || portnum == 0x3d3 || portnum == 0x3d5 || portnum == 0x3d7 || portnum == 0x3d8 || portnum == 0x3d9 || portnum == 0x3dd)) {
|
|
// color crt data register
|
|
if (!xb->video_initialized) {
|
|
set_initial_cpu_turbo(xb);
|
|
}
|
|
if (mode_register & 16) {
|
|
xb->delayed_interrupt |= 1 << 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 get0x3da(struct x86_bridge *xb)
|
|
{
|
|
static int toggle;
|
|
uae_u8 v = 0;
|
|
// not really correct but easy.
|
|
if (vpos < 40) {
|
|
v |= 8 | 1;
|
|
}
|
|
if (toggle) {
|
|
// hblank or vblank active
|
|
v |= 1;
|
|
}
|
|
// just toggle to keep programs happy and fast..
|
|
toggle = !toggle;
|
|
return v;
|
|
}
|
|
|
|
|
|
#define EMS_BANK 0x4000
|
|
#define EMS_MASK 0x3fff
|
|
|
|
static uint8_t mem_read_emsb(uint32_t addr, void *priv)
|
|
{
|
|
uint8_t *p = (uint8_t*)priv;
|
|
return p[addr & EMS_MASK];
|
|
}
|
|
static uint16_t mem_read_emsw(uint32_t addr, void *priv)
|
|
{
|
|
uint8_t *p = (uint8_t*)priv;
|
|
return ((uint16_t*)&p[addr & EMS_MASK])[0];
|
|
}
|
|
static uint32_t mem_read_emsl(uint32_t addr, void *priv)
|
|
{
|
|
uint8_t *p = (uint8_t*)priv;
|
|
return ((uint32_t*)&p[addr & EMS_MASK])[0];
|
|
}
|
|
static void mem_write_emsb(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
uint8_t *p = (uint8_t*)priv;
|
|
p[addr & EMS_MASK] = val;
|
|
}
|
|
static void mem_write_emsw(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
uint8_t *p = (uint8_t*)priv;
|
|
((uint16_t*)&p[addr & EMS_MASK])[0] = val;
|
|
}
|
|
static void mem_write_emsl(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
uint8_t *p = (uint8_t*)priv;
|
|
((uint32_t*)&p[addr & EMS_MASK])[0] = val;
|
|
}
|
|
|
|
static uint8_t mem_read_shadowb(uint32_t addr, void *priv)
|
|
{
|
|
struct scamp_shadow *m = (struct scamp_shadow*)priv;
|
|
return ram[addr];
|
|
}
|
|
static uint16_t mem_read_shadoww(uint32_t addr, void *priv)
|
|
{
|
|
struct scamp_shadow *m = (struct scamp_shadow*)priv;
|
|
return ((uint16_t*)&ram[addr])[0];
|
|
}
|
|
static uint32_t mem_read_shadowl(uint32_t addr, void *priv)
|
|
{
|
|
struct scamp_shadow *m = (struct scamp_shadow*)priv;
|
|
return ((uint32_t*)&ram[addr])[0];
|
|
}
|
|
static void mem_write_shadowb(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
struct scamp_shadow *m = (struct scamp_shadow*)priv;
|
|
ram[addr] = val;
|
|
}
|
|
static void mem_write_shadoww(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
struct scamp_shadow *m = (struct scamp_shadow*)priv;
|
|
((uint16_t*)&ram[addr])[0] = val;
|
|
}
|
|
static void mem_write_shadowl(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
struct scamp_shadow *m = (struct scamp_shadow*)priv;
|
|
((uint32_t*)&ram[addr])[0] = val;
|
|
}
|
|
|
|
static const uae_u32 shadow_bases[] = { 0xa0000, 0xc0000, 0xd0000, 0xe0000 };
|
|
static const uae_u32 shadow_sizes[] = { 0x08000, 0x04000, 0x04000, 0x08000 };
|
|
|
|
static void vlsi_set_mapping(struct x86_bridge *xb)
|
|
{
|
|
int sltptr = xb->vlsi_regs[2];
|
|
if (sltptr != xb->sltptr) {
|
|
xb->sltptr = sltptr;
|
|
if (sltptr < 0x0a)
|
|
xb->vlsi_regs[0x0b] &= ~0x40; // disable ems backfill
|
|
if (sltptr >= 0x0a && sltptr <= 0x0f)
|
|
sltptr = 0x10;
|
|
uae_u32 addr = sltptr << 16;
|
|
mem_set_mem_state(addr, 640 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
|
mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
|
if (sltptr < 0x10) {
|
|
mem_set_mem_state(addr, 640 * 1024 - addr, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
|
|
} else if (sltptr < 0xfe) {
|
|
mem_set_mem_state(addr, (16384 - 128) * 1024 - addr, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void vlsi_set_ems(struct x86_bridge *xb, bool all)
|
|
{
|
|
int emsenablebits = (xb->vlsi_regs[0x0b] << 8) | (xb->vlsi_regs[0x0c]);
|
|
bool emsenable = ((xb->vlsi_regs[0x0b] >> 7) & 1) != 0;
|
|
bool emsbackfillenable = ((xb->vlsi_regs[0x0b] >> 6) & 1) != 0;
|
|
for (int i = 0; i < 0x24; i++) {
|
|
mem_mapping_t *m = &xb->ems[i];
|
|
int v = xb->vlsi_regs_ems[i];
|
|
if (!all && v == xb->emsvals[i])
|
|
return;
|
|
xb->emsvals[i] = v;
|
|
uae_u32 baseaddr;
|
|
uae_u32 emsaddr;
|
|
if (i >= 0x0c) {
|
|
baseaddr = 0x40000 + (i - 0x0c) * EMS_BANK;
|
|
} else {
|
|
bool emsmap = ((xb->vlsi_regs[0x0b] >> 4) & 1) != 0;
|
|
if (emsmap) {
|
|
if (i < 0x04)
|
|
baseaddr = 0xa0000 + (i - 0) * EMS_BANK;
|
|
else if (i < 0x08)
|
|
baseaddr = 0xd0000 + (i - 4) * EMS_BANK;
|
|
else
|
|
baseaddr = 0xb0000 + (i - 8) * EMS_BANK;
|
|
} else {
|
|
baseaddr = 0xc0000 + i * EMS_BANK;
|
|
}
|
|
}
|
|
emsaddr = xb->vlsi_regs_ems[i] << 14;
|
|
if (((i < 0x0c && (emsenablebits & (1 << i))) || (i >= 0x0c && emsbackfillenable)) && emsenable) {
|
|
uae_u8 *paddr = ram + emsaddr;
|
|
#if EMS_DEBUG
|
|
if (!m->enable || m->base != baseaddr || m->exec != paddr)
|
|
write_log(_T("EMS %06x = %08x (%p)\n"), baseaddr, emsaddr, paddr);
|
|
#endif
|
|
mem_mapping_set_p(m, paddr);
|
|
mem_mapping_set_addr(m, baseaddr, EMS_BANK);
|
|
mem_mapping_set_exec(m, paddr);
|
|
} else {
|
|
#if EMS_DEBUG
|
|
if (m->enable)
|
|
write_log(_T("EMS %06x = -\n"), baseaddr);
|
|
#endif
|
|
mem_mapping_disable(m);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void vlsi_set_shadow(struct x86_bridge *xb, int base, uae_u8 v)
|
|
{
|
|
uae_u32 shadow_start = shadow_bases[base];
|
|
uae_u32 shadow_size = shadow_sizes[base];
|
|
if (xb->shadowvals[base] == v)
|
|
return;
|
|
xb->shadowvals[base] = v;
|
|
for (int i = 0; i < 4; i++) {
|
|
int state = (v >> (i * 2)) & 3;
|
|
struct scamp_shadow *m = &xb->shadows[base * 4 + i];
|
|
switch (state)
|
|
{
|
|
case 0: // read = rom, write = rom
|
|
mem_mapping_disable(&m->r_map);
|
|
mem_mapping_disable(&m->w_map);
|
|
break;
|
|
case 1: // read = rom, write = ram
|
|
mem_mapping_disable(&m->r_map);
|
|
mem_mapping_enable(&m->w_map);
|
|
break;
|
|
case 2: // read = ram, write = rom
|
|
mem_mapping_enable(&m->r_map);
|
|
mem_mapping_disable(&m->w_map);
|
|
break;
|
|
case 3: // read = ram, write = ram
|
|
mem_mapping_enable(&m->r_map);
|
|
mem_mapping_enable(&m->w_map);
|
|
break;
|
|
}
|
|
write_log(_T("%06x - %06x : shadow status=%d\n"), shadow_start, shadow_start + shadow_size - 1, state);
|
|
shadow_start += shadow_size;
|
|
}
|
|
}
|
|
|
|
static void vlsi_init_mapping(struct x86_bridge *xb)
|
|
{
|
|
// Shadow
|
|
for (int i = 0; i < 4; i++) {
|
|
uae_u32 b = shadow_bases[i];
|
|
uae_u32 s = shadow_sizes[i];
|
|
for (int j = 0; j < 4; j++) {
|
|
struct scamp_shadow *m = &xb->shadows[i * 4 + j];
|
|
mem_mapping_add(&m->r_map, b, s,
|
|
mem_read_shadowb, mem_read_shadoww, mem_read_shadowl,
|
|
NULL, NULL, NULL,
|
|
ram + b, MEM_READ_INTERNAL, m);
|
|
mem_mapping_add(&m->w_map, b, s,
|
|
NULL, NULL, NULL,
|
|
mem_write_shadowb, mem_write_shadoww, mem_write_shadowl,
|
|
ram + b, MEM_WRITE_INTERNAL, m);
|
|
mem_mapping_disable(&m->r_map);
|
|
mem_mapping_disable(&m->w_map);
|
|
b += s;
|
|
}
|
|
xb->shadowvals[i] = -1;
|
|
}
|
|
// EMS
|
|
for (int i = 0x0; i < 0xc; i++) {
|
|
uae_u32 addr = 0xa0000 + i * EMS_BANK;
|
|
mem_mapping_add(&xb->ems[i], addr, EMS_BANK,
|
|
mem_read_emsb, mem_read_emsw, mem_read_emsl,
|
|
mem_write_emsb, mem_write_emsw, mem_write_emsl,
|
|
ram + addr, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL, NULL);
|
|
mem_mapping_disable(&xb->ems[i]);
|
|
}
|
|
// EMS backfill
|
|
for (int i = 0x0c; i < 0x24; i++) {
|
|
uae_u32 addr = 0x40000 + i * EMS_BANK;
|
|
mem_mapping_add(&xb->ems[i], addr, EMS_BANK,
|
|
mem_read_emsb, mem_read_emsw, mem_read_emsl,
|
|
mem_write_emsb, mem_write_emsw, mem_write_emsl,
|
|
ram + addr, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL, NULL);
|
|
mem_mapping_disable(&xb->ems[i]);
|
|
}
|
|
xb->vlsi_regs[2] = 0xff;
|
|
xb->sltptr = 0xff;
|
|
}
|
|
|
|
static void vlsi_reset(struct x86_bridge *xb)
|
|
{
|
|
memset(xb->vlsi_regs, 0, sizeof xb->vlsi_regs);
|
|
vlsi_set_ems(xb, true);
|
|
vlsi_set_mapping(xb);
|
|
}
|
|
|
|
|
|
static void vlsi_reg_out(struct x86_bridge *xb, int reg, uae_u8 v)
|
|
{
|
|
int shadowbase = -1;
|
|
|
|
switch(reg)
|
|
{
|
|
case 0x02: // SLTPTR
|
|
write_log(_T("SLTPTR = %02x\n"), v);
|
|
vlsi_set_ems(xb, true);
|
|
vlsi_set_mapping(xb);
|
|
break;
|
|
|
|
case 0x03: // RAMMAP
|
|
write_log(_T("RAMMAP = %02x\n"), v);
|
|
if ((v & (0x40 | 0x20 | 0x10)) != 0x20)
|
|
write_log(_T("RAMMAP unsupported configuration!\n"));
|
|
if (mem_size > 4 * 1024 * 1024)
|
|
v &= ~0x10; // REMAP384 not support if >4M RAM
|
|
vlsi_set_ems(xb, true);
|
|
vlsi_set_mapping(xb);
|
|
break;
|
|
|
|
case 0x0b: // ENSEN1
|
|
case 0x0c: // ENSEN2
|
|
#if EMS_DEBUG
|
|
write_log(_T("ENSEN%d = %02x\n"), reg == 0x0b ? 1 : 2, v);
|
|
#endif
|
|
vlsi_set_ems(xb, true);
|
|
vlsi_set_mapping(xb);
|
|
break;
|
|
|
|
case 0x0e: // ABAX
|
|
shadowbase = 0;
|
|
break;
|
|
case 0x0f: // CAXS
|
|
shadowbase = 1;
|
|
break;
|
|
case 0x10: // DAXS
|
|
shadowbase = 2;
|
|
break;
|
|
case 0x11: // FEAXS
|
|
shadowbase = 3;
|
|
break;
|
|
|
|
case 0x1d:
|
|
x86_cmos_bank = (v & 0x20) ? 1 : 0;
|
|
break;
|
|
}
|
|
if (shadowbase >= 0) {
|
|
vlsi_set_shadow(xb, shadowbase, v);
|
|
vlsi_set_mapping(xb);
|
|
}
|
|
}
|
|
|
|
static void vlsi_autoinc(struct x86_bridge *xb)
|
|
{
|
|
if (!(xb->scamp_idx1 & 0x40))
|
|
return;
|
|
int reg = xb->scamp_idx1 & 0x3f;
|
|
reg++;
|
|
xb->scamp_idx1 = (xb->scamp_idx1 & (0x80 | 0x40)) | (reg & 0x3f);
|
|
}
|
|
|
|
static void vlsi_out(struct x86_bridge *xb, int portnum, uae_u8 v)
|
|
{
|
|
#if 0
|
|
switch (portnum)
|
|
{
|
|
case 0xf9: // config disable
|
|
xb->vlsi_config = false;
|
|
break;
|
|
case 0xfb: // config enable
|
|
xb->vlsi_config = true;
|
|
break;
|
|
}
|
|
|
|
if (!xb->vlsi_config)
|
|
return;
|
|
#endif
|
|
|
|
switch (portnum)
|
|
{
|
|
case 0xe8:
|
|
xb->scamp_idx1 = v;
|
|
break;
|
|
case 0xea:
|
|
xb->vlsi_regs_ems[xb->scamp_idx1 & 0x3f] &= 0xff00;
|
|
xb->vlsi_regs_ems[xb->scamp_idx1 & 0x3f] |= v << 0;
|
|
break;
|
|
case 0xeb:
|
|
xb->vlsi_regs_ems[xb->scamp_idx1 & 0x3f] &= 0x00ff;
|
|
xb->vlsi_regs_ems[xb->scamp_idx1 & 0x3f] |= v << 8;
|
|
#if EMS_DEBUG
|
|
write_log(_T("EMS %02d = %04x\n"), xb->scamp_idx1, xb->vlsi_regs_ems[xb->scamp_idx1 & 0x3f]);
|
|
#endif
|
|
vlsi_set_ems(xb, false);
|
|
vlsi_set_mapping(xb);
|
|
vlsi_autoinc(xb);
|
|
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;
|
|
case 0xee: // fast a20 (write=disable)
|
|
mem_a20_alt = 0;
|
|
mem_a20_recalc();
|
|
break;
|
|
case 0xef: // fast reset
|
|
break;
|
|
}
|
|
write_log(_T("VLSI_OUT %02x = %02x\n"), portnum, v);
|
|
}
|
|
|
|
|
|
static uae_u8 vlsi_in(struct x86_bridge *xb, int portnum)
|
|
{
|
|
uae_u8 v = 0;
|
|
switch (portnum)
|
|
{
|
|
case 0xe8:
|
|
v = xb->scamp_idx1 | 0x80;
|
|
break;
|
|
case 0xea:
|
|
v = (uae_u8)xb->vlsi_regs_ems[xb->scamp_idx1 & 0x3f];
|
|
break;
|
|
case 0xeb:
|
|
v = xb->vlsi_regs_ems[xb->scamp_idx1 & 0x3f] >> 8;
|
|
v |= ~0x03;
|
|
vlsi_autoinc(xb);
|
|
break;
|
|
case 0xec:
|
|
v = xb->scamp_idx2;
|
|
break;
|
|
case 0xed:
|
|
v = xb->vlsi_regs[xb->scamp_idx2];
|
|
if (xb->scamp_idx2 == 0)
|
|
v = 0xd6; // version
|
|
break;
|
|
case 0xee: // fast a20 (read=enable)
|
|
mem_a20_alt = 1;
|
|
mem_a20_recalc();
|
|
break;
|
|
case 0xef: // fast reset
|
|
softresetx86();
|
|
cpu_set_edx();
|
|
break;
|
|
}
|
|
write_log(_T("VLSI_IN %02x = %02x\n"), portnum, v);
|
|
return 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 >= MAX_IO_PORT)
|
|
return;
|
|
|
|
if (!is_port_enabled(xb, portnum))
|
|
return;
|
|
|
|
set_pc_io_access(xb, portnum, true);
|
|
|
|
if (xb->ne2000_isa && portnum >= xb->ne2000_io && portnum < xb->ne2000_io + 32) {
|
|
xb->ne2000_isa->bars[0].bput(xb->ne2000_isa_board_state, portnum - xb->ne2000_io, v);
|
|
goto end;
|
|
}
|
|
|
|
switch(portnum)
|
|
{
|
|
case 0x60:
|
|
if (xb->type >= TYPE_2286) {
|
|
keyboard_at_write(portnum, v, &pit);
|
|
} else {
|
|
aio = 0x41f;
|
|
}
|
|
break;
|
|
case 0x61:
|
|
//write_log(_T("OUT Port B %02x\n"), v);
|
|
if (xb->type >= TYPE_2286) {
|
|
keyboard_at_write(portnum, v, &pit);
|
|
} else {
|
|
timer_process();
|
|
//timer_update_outstanding();
|
|
speaker_update();
|
|
speaker_gated = v & 1;
|
|
speaker_enable = v & 2;
|
|
if (speaker_enable)
|
|
was_speaker_enable = 1;
|
|
pit_set_gate(&pit, 2, v & 1);
|
|
aio = 0x5f;
|
|
}
|
|
break;
|
|
case 0x62:
|
|
#if X86_DEBUG_SPECIAL_IO
|
|
write_log(_T("AMIGA SYSINT. %02x\n"), v);
|
|
#endif
|
|
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:
|
|
#if X86_DEBUG_SPECIAL_IO
|
|
write_log(_T("OUT CONFIG %02x\n"), v);
|
|
#endif
|
|
if (xb->type > TYPE_SIDECAR) {
|
|
if (xb->io_ports[0x63] & 8) {
|
|
v |= 8;
|
|
}
|
|
if (xb->type == TYPE_2088T) {
|
|
int speed = v >> 6;
|
|
switch (speed)
|
|
{
|
|
case 0:
|
|
write_log(_T("A2088T: 4.77MHz\n"));
|
|
cpu_set_turbo(0);
|
|
break;
|
|
case 1:
|
|
write_log(_T("A2088T: 7.15MHz\n"));
|
|
cpu_set_turbo(1);
|
|
break;
|
|
case 2:
|
|
write_log(_T("A2088T: 9.54MHz\n"));
|
|
cpu_set_turbo(1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 0x64:
|
|
if (xb->type >= TYPE_2286) {
|
|
keyboard_at_write(portnum, v, &pit);
|
|
}
|
|
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(xb->vgaboard, 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(xb->vgaboard, 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(xb->vgaboard, 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(xb->vgaboard, 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(xb->vgaboard, 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(xb->vgaboard, portnum, v);
|
|
}
|
|
break;
|
|
case 0x3da:
|
|
if (cga_emu) {
|
|
aio = 0x1f;
|
|
} else if (ISVGA()) {
|
|
if (x86_vga_mode == 1)
|
|
vga_io_put(xb->vgaboard, portnum, v);
|
|
}
|
|
break;
|
|
|
|
case 0x378:
|
|
write_log(_T("BIOS DIAGNOSTICS CODE: %02x ~%02X\n"), v, v ^ 0xff);
|
|
aio = 0x19f; // ??
|
|
break;
|
|
case 0x379:
|
|
#if X86_DEBUG_SPECIAL_IO
|
|
write_log(_T("0x379: %02x\n"), v);
|
|
#endif
|
|
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 0xea:
|
|
case 0xeb:
|
|
case 0xec:
|
|
case 0xed:
|
|
case 0xee:
|
|
case 0xf0:
|
|
case 0xf1:
|
|
case 0xf4:
|
|
case 0xf5:
|
|
case 0xf9:
|
|
case 0xfb:
|
|
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;
|
|
|
|
// 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;
|
|
|
|
default:
|
|
if (port_outb[portnum]) {
|
|
port_outb[portnum](portnum, v, port_priv[portnum]);
|
|
} else {
|
|
write_log(_T("X86_OUT unknown %02x %02x\n"), portnum, v);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
end:
|
|
#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)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
|
|
if (portnum >= MAX_IO_PORT)
|
|
return;
|
|
|
|
if (xb->ne2000_isa && portnum >= xb->ne2000_io && portnum < xb->ne2000_io + 32) {
|
|
xb->ne2000_isa->bars[0].wput(xb->ne2000_isa_board_state, portnum - xb->ne2000_io, value);
|
|
return;
|
|
}
|
|
|
|
switch (portnum)
|
|
{
|
|
case 0x170:
|
|
case 0x1f0:
|
|
case 0x300:
|
|
x86_ide_hd_put(portnum, value, 1);
|
|
break;
|
|
default:
|
|
if (port_outw[portnum]) {
|
|
port_outw[portnum](portnum, value, port_priv[portnum]);
|
|
} else {
|
|
portout(portnum, (uae_u8)value);
|
|
portout(portnum + 1, value >> 8);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void portout32(uint16_t portnum, uint32_t value)
|
|
{
|
|
if (portnum >= MAX_IO_PORT)
|
|
return;
|
|
|
|
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 >= MAX_IO_PORT)
|
|
return 0;
|
|
|
|
set_pc_io_access(xb, portnum, false);
|
|
|
|
uae_u8 v = xb->io_ports[portnum];
|
|
|
|
if (xb->ne2000_isa && portnum >= xb->ne2000_io && portnum < xb->ne2000_io + 32) {
|
|
v = xb->ne2000_isa->bars[0].bget(xb->ne2000_isa_board_state, portnum - xb->ne2000_io);
|
|
goto end;
|
|
}
|
|
|
|
switch (portnum)
|
|
{
|
|
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(xb->vgaboard, 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(xb->vgaboard, 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(xb->vgaboard, 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(xb->vgaboard, 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(xb->vgaboard, portnum);
|
|
}
|
|
break;
|
|
case 0x3d8:
|
|
if (cga_emu) {
|
|
aio = 0x23f;
|
|
}
|
|
break;
|
|
case 0x3d9:
|
|
if (cga_emu) {
|
|
aio = 0x25f;
|
|
}
|
|
break;
|
|
|
|
case 0x3ba:
|
|
if (mda_emu) {
|
|
v = get0x3da(xb);
|
|
} else if (ISVGA()) {
|
|
if (x86_vga_mode == 0)
|
|
v = vga_io_get(xb->vgaboard, portnum);
|
|
}
|
|
break;
|
|
case 0x3da:
|
|
if (cga_emu) {
|
|
v = get0x3da(xb);
|
|
} else if (ISVGA()) {
|
|
if (x86_vga_mode == 1)
|
|
v = vga_io_get(xb->vgaboard, 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 0xea:
|
|
case 0xeb:
|
|
case 0xec:
|
|
case 0xed:
|
|
case 0xee:
|
|
case 0xef:
|
|
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 = keyboard_at_read(portnum, NULL);
|
|
//write_log(_T("PC read keycode %02x\n"), v);
|
|
}
|
|
break;
|
|
case 0x61:
|
|
if (xb->type >= TYPE_2286) {
|
|
// bios test hack
|
|
v = keyboard_at_read(portnum, NULL);
|
|
} 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)) {
|
|
bool timer2gate = pit.gate[2] == 0;
|
|
if (timer2gate)
|
|
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 = keyboard_at_read(portnum, NULL);
|
|
}
|
|
break;
|
|
|
|
// at ide 1
|
|
case 0x170:
|
|
case 0x171:
|
|
case 0x172:
|
|
case 0x173:
|
|
case 0x174:
|
|
case 0x175:
|
|
case 0x176:
|
|
case 0x177:
|
|
case 0x376:
|
|
v = (uae_u8)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 = (uae_u8)x86_ide_hd_get(portnum, 0);
|
|
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 = (uae_u8)x86_ide_hd_get(portnum, 0);
|
|
break;
|
|
|
|
// led debug (a2286 bios uses this)
|
|
case 0x108:
|
|
case 0x109:
|
|
case 0x10a:
|
|
case 0x10b:
|
|
case 0x10c:
|
|
case 0x10d:
|
|
case 0x10e:
|
|
case 0x10f:
|
|
break;
|
|
|
|
default:
|
|
if (port_inb[portnum]) {
|
|
v = port_inb[portnum](portnum, port_priv[portnum]);
|
|
} else {
|
|
write_log(_T("X86_IN unknown %02x\n"), portnum);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
end:
|
|
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)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
uae_u16 v = 0;
|
|
|
|
if (portnum >= MAX_IO_PORT)
|
|
return v;
|
|
|
|
if (xb->ne2000_isa && portnum >= xb->ne2000_io && portnum < xb->ne2000_io + 32) {
|
|
v = xb->ne2000_isa->bars[0].wget(xb->ne2000_isa_board_state, portnum - xb->ne2000_io);
|
|
return v;
|
|
}
|
|
switch (portnum)
|
|
{
|
|
case 0x170:
|
|
case 0x1f0:
|
|
case 0x300:
|
|
v = x86_ide_hd_get(portnum, 1);
|
|
break;
|
|
default:
|
|
if (port_inw[portnum]) {
|
|
v = port_inw[portnum](portnum, port_priv[portnum]);
|
|
} else {
|
|
v = (portin(portnum) << 0) | (portin(portnum + 1) << 8);
|
|
}
|
|
break;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
uint32_t portin32(uint16_t portnum)
|
|
{
|
|
uint32_t v = 0;
|
|
|
|
if (portnum >= MAX_IO_PORT)
|
|
return v;
|
|
|
|
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;
|
|
}
|
|
|
|
static uaecptr get_x86_address(struct x86_bridge *xb, uaecptr addr, int *mode, uae_u8 **base)
|
|
{
|
|
addr -= xb->baseaddress;
|
|
if (!xb->baseaddress || addr >= 0x80000) {
|
|
*mode = -1;
|
|
return 0;
|
|
}
|
|
*mode = addr >> 17;
|
|
addr &= 0x1ffff;
|
|
if (addr < 0x10000) {
|
|
*base = xb->amiga_buffer + addr;
|
|
return get_shared_io(xb) + addr;
|
|
}
|
|
if (addr < 0x18000) {
|
|
// color video
|
|
addr -= 0x10000;
|
|
*base = xb->amiga_color + addr;
|
|
return 0xb8000 + addr;
|
|
}
|
|
if (addr < 0x1c000) {
|
|
// parameter
|
|
addr -= 0x18000;
|
|
if (xb->type >= TYPE_2286) {
|
|
if (get_shared_io(xb) == 0xd0000) {
|
|
*base = xb->amiga_buffer + addr;
|
|
return 0xd0000 + addr;
|
|
}
|
|
*base = xb->amiga_parameter + addr;
|
|
return 0xd0000 + addr;
|
|
} else {
|
|
*base = xb->amiga_parameter + addr;
|
|
return 0xf0000 + addr;
|
|
}
|
|
}
|
|
if (addr < 0x1e000) {
|
|
// mono video
|
|
addr -= 0x1c000;
|
|
*base = xb->amiga_mono + addr;
|
|
return 0xb0000 + addr;
|
|
}
|
|
// IO
|
|
addr -= 0x1e000;
|
|
return addr;
|
|
}
|
|
|
|
static struct x86_bridge *get_x86_bridge(uaecptr addr)
|
|
{
|
|
return bridges[0];
|
|
}
|
|
|
|
static void cga_gfx_read(struct x86_bridge *xb, uaecptr a_addr, uae_u8 *addr, uae_u8 *plane0p, uae_u8 *plane1p)
|
|
{
|
|
uae_u16 w;
|
|
|
|
if (a_addr & 1)
|
|
w = (addr[-1] << 8) | addr[0];
|
|
else
|
|
w = (addr[0] << 8) | addr[1];
|
|
|
|
uae_u8 plane1 = (((w >> 14) & 1) << 7) | (((w >> 12) & 1) << 6) | (((w >> 10) & 1) << 5) | (((w >> 8) & 1) << 4);
|
|
plane1 |= (((w >> 6) & 1) << 3) | (((w >> 4) & 1) << 2) | (((w >> 2) & 1) << 1) | (((w >> 0) & 1) << 0);
|
|
|
|
uae_u8 plane0 = (((w >> 15) & 1) << 7) | (((w >> 13) & 1) << 6) | (((w >> 11) & 1) << 5) | (((w >> 9) & 1) << 4);
|
|
plane0 |= (((w >> 7) & 1) << 3) | (((w >> 5) & 1) << 2) | (((w >> 3) & 1) << 1) | (((w >> 1) & 1) << 0);
|
|
|
|
*plane0p = plane0;
|
|
*plane1p = plane1;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 x86_bridge_wget(uaecptr addr)
|
|
{
|
|
uae_u16 v = 0;
|
|
uae_u8 *base;
|
|
struct x86_bridge *xb = get_x86_bridge(addr);
|
|
if (!xb)
|
|
return v;
|
|
int mode;
|
|
uaecptr a = get_x86_address(xb, addr, &mode, &base);
|
|
|
|
switch (mode)
|
|
{
|
|
case -1:
|
|
break;
|
|
case ACCESS_MODE_WORD:
|
|
v = (base[1] << 8) | (base[0] << 0);
|
|
break;
|
|
case ACCESS_MODE_GFX:
|
|
{
|
|
uae_u8 plane0, plane1;
|
|
cga_gfx_read(xb, a, base, &plane0, &plane1);
|
|
if (a & 1)
|
|
v = (plane1 << 8) | plane0;
|
|
else
|
|
v = (plane0 << 8) | plane1;
|
|
}
|
|
break;
|
|
case ACCESS_MODE_IO:
|
|
v = x86_bridge_get_io(xb, a);
|
|
v |= x86_bridge_get_io(xb, a + 1) << 8;
|
|
break;
|
|
default:
|
|
v = (base[1] << 0) | (base[0] << 8);
|
|
break;
|
|
}
|
|
#if X86_DEBUG_BRIDGE > 1
|
|
write_log(_T("x86_bridge_wget %08x (%08x,%d)=%04x PC=%08x\n"), addr - xb->baseaddress, a, mode, v, 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)
|
|
{
|
|
uae_u8 v = 0;
|
|
uae_u8 *base;
|
|
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, &base);
|
|
switch(mode)
|
|
{
|
|
case -1:
|
|
break;
|
|
case ACCESS_MODE_WORD:
|
|
v = base[(a ^ 1) & 1];
|
|
break;
|
|
case ACCESS_MODE_IO:
|
|
v = x86_bridge_get_io(xb, a);
|
|
break;
|
|
case ACCESS_MODE_GFX:
|
|
{
|
|
uae_u8 plane0, plane1;
|
|
cga_gfx_read(xb, a, base, &plane0, &plane1);
|
|
if (a & 1)
|
|
v = plane1;
|
|
else
|
|
v = plane0;
|
|
}
|
|
break;
|
|
default:
|
|
v = base[0];
|
|
break;
|
|
}
|
|
#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)
|
|
{
|
|
struct x86_bridge *xb = get_x86_bridge(addr);
|
|
if (!xb)
|
|
return;
|
|
int mode;
|
|
uae_u8 *base;
|
|
uaecptr a = get_x86_address(xb, addr, &mode, &base);
|
|
|
|
#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;
|
|
|
|
switch (mode)
|
|
{
|
|
case -1:
|
|
break;
|
|
case ACCESS_MODE_IO:
|
|
x86_bridge_put_io(xb, a + 0, b & 0xff);
|
|
x86_bridge_put_io(xb, a + 1, (b >> 8) & 0xff);
|
|
break;
|
|
case ACCESS_MODE_WORD:
|
|
base[0] = b;
|
|
base[1] = b >> 8;
|
|
break;
|
|
case ACCESS_MODE_GFX:
|
|
// does not seem to be used
|
|
//write_log(_T("ACCESS_MODE_GFX %08x %04x\n"), addr, b & 0xffff);
|
|
break;
|
|
default:
|
|
base[1] = b;
|
|
base[0] = b >> 8;
|
|
break;
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
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_board_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;
|
|
uae_u8 *base;
|
|
uaecptr a = get_x86_address(xb, addr, &mode, &base);
|
|
|
|
if (a >= 0x100000 || mode < 0)
|
|
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
|
|
|
|
switch(mode)
|
|
{
|
|
case -1:
|
|
break;
|
|
case ACCESS_MODE_IO:
|
|
x86_bridge_put_io(xb, a, b);
|
|
break;
|
|
case ACCESS_MODE_WORD:
|
|
base[(a ^ 1) & 1] = b;
|
|
break;
|
|
case ACCESS_MODE_GFX:
|
|
// does not seem to be used
|
|
//write_log(_T("ACCESS_MODE_GFX %08x %02x\n"), addr, b & 0xff);
|
|
break;
|
|
default:
|
|
base[0] = b;
|
|
break;
|
|
}
|
|
}
|
|
|
|
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, S_READ, S_WRITE
|
|
};
|
|
|
|
static uint8_t mem_read_sharedb(uint32_t addr, void *priv)
|
|
{
|
|
struct membase *mb = (struct membase*)priv;
|
|
return mb->base[addr & mb->mask];
|
|
}
|
|
static uint16_t mem_read_sharedw(uint32_t addr, void *priv)
|
|
{
|
|
struct membase *mb = (struct membase*)priv;
|
|
return ((uae_u16*)(mb->base + (addr & mb->mask)))[0];
|
|
}
|
|
static uint32_t mem_read_sharedl(uint32_t addr, void *priv)
|
|
{
|
|
struct membase *mb = (struct membase*)priv;
|
|
uae_u8 *base = (uae_u8*)priv;
|
|
return ((uae_u32*)(mb->base + (addr & mb->mask)))[0];
|
|
}
|
|
static void mem_write_sharedb(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
struct membase *mb = (struct membase*)priv;
|
|
set_pc_address_access(bridges[0], addr);
|
|
mb->base[addr & mb->mask] = val;
|
|
}
|
|
static void mem_write_sharedw(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
struct membase *mb = (struct membase*)priv;
|
|
set_pc_address_access(bridges[0], addr);
|
|
((uae_u16*)(mb->base + (addr & mb->mask)))[0] = val;
|
|
}
|
|
static void mem_write_sharedl(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
struct membase *mb = (struct membase*)priv;
|
|
set_pc_address_access(bridges[0], addr);
|
|
((uae_u32*)(mb->base + (addr & mb->mask)))[0] = val;
|
|
}
|
|
|
|
static uint8_t vga_readb(uint32_t addr, void *priv)
|
|
{
|
|
return vga_ram_get(x86_vga_board, addr);
|
|
}
|
|
static uint16_t vga_readw(uint32_t addr, void *priv)
|
|
{
|
|
return (vga_ram_get(x86_vga_board, addr) << 0) | (vga_ram_get(x86_vga_board, addr + 1) << 8);
|
|
}
|
|
static uint32_t vga_readl(uint32_t addr, void *priv)
|
|
{
|
|
return (vga_readw(addr, priv) << 0) | (vga_readw(addr + 2, priv) << 16);
|
|
}
|
|
static void vga_writeb(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
vga_ram_put(x86_vga_board, addr, val);
|
|
}
|
|
static void vga_writew(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
vga_ram_put(x86_vga_board, addr, (uae_u8)val);
|
|
vga_ram_put(x86_vga_board, addr + 1, val >> 8);
|
|
}
|
|
static void vga_writel(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
vga_ram_put(x86_vga_board, addr, val);
|
|
vga_ram_put(x86_vga_board, addr + 1, val >> 8);
|
|
vga_ram_put(x86_vga_board, addr + 2, val >> 16);
|
|
vga_ram_put(x86_vga_board, addr + 3, val >> 24);
|
|
}
|
|
|
|
static uint8_t vgalfb_readb(uint32_t addr, void *priv)
|
|
{
|
|
return vgalfb_ram_get(x86_vga_board, addr);
|
|
}
|
|
static uint16_t vgalfb_readw(uint32_t addr, void *priv)
|
|
{
|
|
return (vgalfb_ram_get(x86_vga_board, addr) << 0) | (vgalfb_ram_get(x86_vga_board, addr + 1) << 8);
|
|
}
|
|
static uint32_t vgalfb_readl(uint32_t addr, void *priv)
|
|
{
|
|
return (vgalfb_readw(addr, priv) << 0) | (vgalfb_readw(addr + 2, priv) << 16);
|
|
}
|
|
static void vgalfb_writeb(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
vgalfb_ram_put(x86_vga_board, addr, val);
|
|
}
|
|
static void vgalfb_writew(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
vgalfb_ram_put(x86_vga_board, addr, (uae_u8)val);
|
|
vgalfb_ram_put(x86_vga_board, addr + 1, val >> 8);
|
|
}
|
|
static void vgalfb_writel(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
vgalfb_ram_put(x86_vga_board, addr, val);
|
|
vgalfb_ram_put(x86_vga_board, addr + 1, val >> 8);
|
|
vgalfb_ram_put(x86_vga_board, addr + 2, val >> 16);
|
|
vgalfb_ram_put(x86_vga_board, addr + 3, val >> 24);
|
|
}
|
|
|
|
static int to53c400reg(uint32_t addr, bool rw)
|
|
{
|
|
//write_log(_T("%c %08x\n"), rw ? 'W' : 'R', addr);
|
|
// Scratchpad RAM
|
|
if (addr >= 0x3800 && addr <= 0x387f)
|
|
return (addr & 0x3f) | 0x200;
|
|
// 53C80 registers
|
|
if (addr >= 0x3880 && addr <= 0x38ff)
|
|
return addr & 7;
|
|
// Data port
|
|
if (addr >= 0x3900 && addr <= 0x397f)
|
|
return 0x80;
|
|
// 53C400 registers
|
|
if (addr >= 0x3980 && addr <= 0x39ff) {
|
|
int reg = addr & 3;
|
|
if (reg >= 2)
|
|
return -1;
|
|
return reg | 0x100;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static uint8_t mem_read_romext3(uint32_t addr, void *priv)
|
|
{
|
|
uae_u8 v = 0xff;
|
|
addr &= 0x3fff;
|
|
if (addr < 0x2000) {
|
|
v = rt1000rom[addr];
|
|
} else if (addr >= 0x3a00) {
|
|
write_log(_T("mem_read_romext3 %08x\n"), addr);
|
|
} else if (addr >= 0x3800) {
|
|
int reg = to53c400reg(addr, false);
|
|
if (reg >= 0)
|
|
v = x86_rt1000_bget(reg);
|
|
}
|
|
return v;
|
|
}
|
|
static uint16_t mem_read_romextw3(uint32_t addr, void *priv)
|
|
{
|
|
uae_u16 v = 0xffff;
|
|
addr &= 0x3fff;
|
|
if (addr < 0x2000) {
|
|
v = *(uint16_t *)&rt1000rom[addr & 0x1fff];
|
|
} else if (addr >= 0x3a00) {
|
|
write_log(_T("mem_read_romext3 %08x\n"), addr);
|
|
} else if (addr >= 0x3800) {
|
|
int reg = to53c400reg(addr + 0, false);
|
|
v = 0;
|
|
if (reg >= 0)
|
|
v = x86_rt1000_bget(reg);
|
|
reg = to53c400reg(addr + 1, false);
|
|
if (reg >= 0)
|
|
v |= x86_rt1000_bget(reg) << 8;
|
|
}
|
|
return v;
|
|
}
|
|
static uint32_t mem_read_romextl3(uint32_t addr, void *priv)
|
|
{
|
|
return *(uint32_t *)&rt1000rom[addr & 0x3fff];
|
|
}
|
|
static void mem_write_romext3(uint32_t addr, uint8_t val, void *priv)
|
|
{
|
|
addr &= 0x3fff;
|
|
if (addr >= 0x3a00) {
|
|
write_log(_T("mem_write_romext3 %08x %02x\n"), addr, val);
|
|
} else if (addr >= 0x3800) {
|
|
int reg = to53c400reg(addr, true);
|
|
if (reg >= 0)
|
|
x86_rt1000_bput(reg, val);
|
|
}
|
|
}
|
|
static void mem_write_romextw3(uint32_t addr, uint16_t val, void *priv)
|
|
{
|
|
addr &= 0x3fff;
|
|
if (addr >= 0x3a00) {
|
|
write_log(_T("mem_write_romextw3 %08x %04x\n"), addr, val);
|
|
} else if (addr >= 0x3800) {
|
|
int reg = to53c400reg(addr + 0, true);
|
|
if (reg >= 0)
|
|
x86_rt1000_bput(reg, (uae_u8)val);
|
|
reg = to53c400reg(addr + 1, true);
|
|
if (reg >= 0)
|
|
x86_rt1000_bput(reg, val >> 8);
|
|
} else {
|
|
write_log(_T("mem_write_romextw3 %08x %04x\n"), addr, val);
|
|
}
|
|
}
|
|
static void mem_write_romextl3(uint32_t addr, uint32_t val, void *priv)
|
|
{
|
|
|
|
}
|
|
|
|
static uint8_t mem_read_romext2(uint32_t addr, void *priv)
|
|
{
|
|
return xtiderom[addr & 0x3fff];
|
|
}
|
|
static uint16_t mem_read_romextw2(uint32_t addr, void *priv)
|
|
{
|
|
return *(uint16_t *)&xtiderom[addr & 0x3fff];
|
|
}
|
|
static uint32_t mem_read_romextl2(uint32_t addr, void *priv)
|
|
{
|
|
return *(uint32_t *)&xtiderom[addr & 0x3fff];
|
|
}
|
|
|
|
static void x86_bridge_rethink(void)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb)
|
|
return;
|
|
if (!(xb->amiga_io[IO_CONTROL_REGISTER] & 1)) {
|
|
xb->amiga_io[IO_AMIGA_INTERRUPT_STATUS] |= xb->delayed_interrupt;
|
|
xb->delayed_interrupt = 0;
|
|
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)
|
|
safe_interrupt_set(IRQ_SOURCE_X86, 0, false);
|
|
}
|
|
}
|
|
|
|
static void x86_bridge_reset(int hardreset)
|
|
{
|
|
for (int i = 0; i < X86_BRIDGE_MAX; i++) {
|
|
struct x86_bridge *xb = bridges[i];
|
|
if (!xb)
|
|
continue;
|
|
if (xb->ne2000_isa) {
|
|
xb->ne2000_isa->free(xb->ne2000_isa_board_state);
|
|
xb->ne2000_isa = NULL;
|
|
xfree(xb->ne2000_isa_board_state);
|
|
xb->ne2000_isa_board_state = NULL;
|
|
}
|
|
if (xb->cmosfile) {
|
|
zfile_fseek(xb->cmosfile, 0, SEEK_SET);
|
|
zfile_fwrite(nvrram, 1, xb->cmossize, xb->cmosfile);
|
|
}
|
|
if (xb->audstream) {
|
|
audio_enable_stream(false, xb->audstream, 0, NULL, NULL);
|
|
}
|
|
zfile_fclose(xb->cmosfile);
|
|
xfree(xb->amiga_io);
|
|
xfree(xb->io_ports);
|
|
xfree(xb->pc_rom);
|
|
rom = NULL;
|
|
xfree(xtiderom);
|
|
xtiderom = NULL;
|
|
xfree(rt1000rom);
|
|
rt1000rom = NULL;
|
|
xfree(xb->mouse_base);
|
|
xfree(xb->cms_base);
|
|
xfree(xb->sb_base);
|
|
mem_free();
|
|
bridges[i] = NULL;
|
|
memset(port_inb, 0, sizeof(port_inb));
|
|
memset(port_inw, 0, sizeof(port_inw));
|
|
memset(port_inl, 0, sizeof(port_inl));
|
|
memset(port_outb, 0, sizeof(port_outb));
|
|
memset(port_outw, 0, sizeof(port_outw));
|
|
memset(port_outl, 0, sizeof(port_outl));
|
|
}
|
|
}
|
|
|
|
static void x86_bridge_free(void)
|
|
{
|
|
x86_bridge_reset(1);
|
|
x86_found = 0;
|
|
}
|
|
|
|
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 cycs)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb->x86_reset) {
|
|
|
|
// no free buffers to fill
|
|
if (x86_sndbuffer_filled[x86_sndbuffer_index])
|
|
return;
|
|
|
|
if (AT)
|
|
exec386(cycs);
|
|
else
|
|
execx86(cycs);
|
|
}
|
|
|
|
// BIOS has CPU loop delays in floppy driver...
|
|
check_floppy_delay();
|
|
}
|
|
|
|
static bool audio_state_sndboard_x86(int streamid, void *param)
|
|
{
|
|
static int smp[2] = { 0, 0 };
|
|
struct x86_bridge *xb = bridges[0];
|
|
|
|
if (streamid != xb->audstream)
|
|
return false;
|
|
|
|
if (x86_sndbuffer_filled[x86_sndbuffer_playindex]) {
|
|
int32_t *p = x86_sndbuffer[x86_sndbuffer_playindex];
|
|
int32_t l = p[x86_sndbuffer_playpos * 2 + 0];
|
|
int32_t r = p[x86_sndbuffer_playpos * 2 + 1];
|
|
if (l < -32768)
|
|
l = -32768;
|
|
if (l > 32767)
|
|
l = 32767;
|
|
if (r < -32768)
|
|
r = -32768;
|
|
if (r > 32767)
|
|
r = 32767;
|
|
x86_sndbuffer_playpos++;
|
|
if (x86_sndbuffer_playpos == SOUNDBUFLEN) {
|
|
x86_sndbuffer_filled[x86_sndbuffer_playindex] = false;
|
|
x86_sndbuffer_playindex ^= 1;
|
|
x86_sndbuffer_playpos = 0;
|
|
}
|
|
smp[0] = l;
|
|
smp[1] = r;
|
|
}
|
|
audio_state_stream_state(xb->audstream, smp, 2, xb->audeventtime);
|
|
return true;
|
|
}
|
|
|
|
void x86_bridge_sync_change(void)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb)
|
|
return;
|
|
}
|
|
|
|
static void x86_bridge_vsync(void)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb)
|
|
return;
|
|
|
|
if (xb->delayed_interrupt) {
|
|
devices_rethink_all(x86_bridge_rethink);
|
|
}
|
|
struct romconfig *rc = get_device_romconfig(&changed_prefs, ROMTYPE_X86MOUSE, 0);
|
|
if (rc) {
|
|
xb->mouse_port = (rc->device_settings & 3) + 1;
|
|
}
|
|
xb->audeventtime = (int)(x86_base_event_clock * CYCLE_UNIT / currprefs.sound_freq + 1);
|
|
}
|
|
|
|
static void x86_bridge_hsync(void)
|
|
{
|
|
static float totalcycles;
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb)
|
|
return;
|
|
|
|
if (!xb->sound_initialized) {
|
|
// x86_base_event_clock is not initialized until syncs start
|
|
xb->sound_initialized = true;
|
|
if (xb->sound_emu) {
|
|
write_log(_T("x86 sound init\n"));
|
|
xb->audeventtime = (int)(x86_base_event_clock * CYCLE_UNIT / currprefs.sound_freq + 1);
|
|
timer_add(&sound_poll_timer, sound_poll, NULL, 0);
|
|
xb->audstream = audio_enable_stream(true, -1, 2, audio_state_sndboard_x86, NULL);
|
|
sound_speed_changed(true);
|
|
}
|
|
}
|
|
|
|
check_floppy_delay();
|
|
|
|
if (xb->ne2000_isa)
|
|
xb->ne2000_isa->hsync(xb->ne2000_isa_board_state);
|
|
|
|
if (!xb->x86_reset) {
|
|
float cycles_to_run = (float)cpu_get_speed() / (vblank_hz * maxvpos);
|
|
totalcycles += cycles_to_run;
|
|
int cycs = (int)totalcycles;
|
|
x86_cpu_execute(cycs);
|
|
totalcycles -= (int)totalcycles;
|
|
}
|
|
|
|
if (currprefs.x86_speed_throttle != changed_prefs.x86_speed_throttle) {
|
|
currprefs.x86_speed_throttle = changed_prefs.x86_speed_throttle;
|
|
set_cpu_turbo(xb);
|
|
}
|
|
}
|
|
|
|
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 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;
|
|
xb->mode_register = -1;
|
|
xb->video_initialized = false;
|
|
xb->a2386flipper = 0;
|
|
xb->a2386_amigapcdrive = false;
|
|
x86_cpu_active = false;
|
|
memset(xb->amiga_io, 0, 0x50000);
|
|
memset(xb->io_ports, 0, 0x10000);
|
|
memset(xb->pc_ram, 0, xb->pc_maxbaseram);
|
|
|
|
if (xb->ne2000_isa)
|
|
xb->ne2000_isa->reset(xb->ne2000_isa_board_state);
|
|
|
|
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;
|
|
memset(xb->vlsi_regs, 0, sizeof xb->vlsi_regs);
|
|
|
|
int sel1 = (xb->settings >> 10) & 1;
|
|
int sel2 = (xb->settings >> 11) & 1;
|
|
xb->amiga_io[IO_MODE_REGISTER] |= sel1 << 5;
|
|
xb->amiga_io[IO_MODE_REGISTER] |= sel2 << 6;
|
|
|
|
x86_bridge_sync_change();
|
|
floppy_hardreset();
|
|
pcem_close();
|
|
}
|
|
|
|
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;
|
|
if (xb && xb->type < 0)
|
|
return X86_STATE_INACTIVE;
|
|
return X86_STATE_ACTIVE;
|
|
}
|
|
|
|
static void ne2000_isa_irq_callback(struct pci_board_state *pcibs, bool irq)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (irq)
|
|
x86_doirq(xb->ne2000_irq);
|
|
else
|
|
x86_clearirq(xb->ne2000_irq);
|
|
}
|
|
|
|
void x86_rt1000_bios(struct zfile *z, struct romconfig *rc)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
uae_u32 addr = 0;
|
|
if (!xb || !z)
|
|
return;
|
|
addr = (rc->device_settings & 7) * 0x4000 + 0xc8000;
|
|
rt1000rom = xcalloc(uae_u8, 0x2000 + 1);
|
|
zfile_fread(rt1000rom, 1, 0x2000, z);
|
|
mem_mapping_add(&bios_mapping[6], addr, 0x4000, mem_read_romext3, mem_read_romextw3, mem_read_romextl3, mem_write_romext3, mem_write_romextw3, mem_write_romextl3, rt1000rom, MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
}
|
|
|
|
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;
|
|
}
|
|
xtiderom = xcalloc(uae_u8, 0x4000);
|
|
zfile_fread(xtiderom, 1, 0x4000, z);
|
|
mem_mapping_add(&bios_mapping[5], addr, 0x4000, mem_read_romext2, mem_read_romextw2, mem_read_romextl2, mem_write_null, mem_write_nullw, mem_write_nulll, xtiderom, MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
}
|
|
|
|
void *sb_1_init();
|
|
void *sb_15_init();
|
|
void *sb_2_init();
|
|
void *sb_pro_v1_init();
|
|
void *sb_pro_v2_init();
|
|
void *sb_16_init();
|
|
void *cms_init();
|
|
|
|
static int x86_global_settings;
|
|
|
|
int device_get_config_int(const char *s)
|
|
{
|
|
if (!strcmp(s, "bilinear")) {
|
|
return 1;
|
|
}
|
|
if (!strcmp(s, "dithering")) {
|
|
return 1;
|
|
}
|
|
if (!strcmp(s, "dacfilter")) {
|
|
return 1;
|
|
}
|
|
if (!strcmp(s, "recompiler")) {
|
|
return 1;
|
|
}
|
|
if (!strcmp(s, "memory")) {
|
|
return pcem_getvramsize() >> 20;
|
|
}
|
|
if (!strcmp(s, "render_threads")) {
|
|
#ifdef _WIN32
|
|
SYSTEM_INFO si;
|
|
GetSystemInfo(&si);
|
|
if (si.dwNumberOfProcessors >= 8)
|
|
return 4;
|
|
if (si.dwNumberOfProcessors >= 4)
|
|
return 2;
|
|
return 1;
|
|
#else
|
|
return 4;
|
|
#endif
|
|
}
|
|
|
|
|
|
if (x86_global_settings < 0)
|
|
return 0;
|
|
if (!strcmp(s, "addr")) {
|
|
int io = 0x210 + ((x86_global_settings >> 3) & 7) * 0x10;
|
|
return io;
|
|
} else if (!strcmp(s, "irq")) {
|
|
int irq = (x86_global_settings >> 6) & 7;
|
|
if (irq == 0)
|
|
return 2;
|
|
if (irq == 1)
|
|
return 3;
|
|
if (irq == 2)
|
|
return 5;
|
|
if (irq == 3)
|
|
return 7;
|
|
if (irq == 4)
|
|
return 10;
|
|
return 5;
|
|
} else if (!strcmp(s, "dma")) {
|
|
int irq = (x86_global_settings >> 9) & 1;
|
|
return irq ? 3 : 1;
|
|
} else if (!strcmp(s, "opl_emu")) {
|
|
int opl = (x86_global_settings >> 10) & 1;
|
|
return opl ? 1 : 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void set_sb_emu(struct x86_bridge *xb)
|
|
{
|
|
if (!is_board_enabled(&currprefs, ROMTYPE_SBISA, 0))
|
|
return;
|
|
void *p = NULL, *c = NULL;
|
|
struct romconfig *rc = get_device_romconfig(&currprefs, ROMTYPE_SBISA, 0);
|
|
x86_global_settings = rc->device_settings;
|
|
int model = (x86_global_settings >> 0) & 7;
|
|
switch (model)
|
|
{
|
|
case 0:
|
|
c = cms_init();
|
|
p = sb_1_init();
|
|
break;
|
|
case 1:
|
|
c = cms_init();
|
|
p = sb_15_init();
|
|
break;
|
|
case 2:
|
|
c = cms_init();
|
|
p = sb_2_init();
|
|
break;
|
|
case 3:
|
|
p = sb_pro_v1_init();
|
|
break;
|
|
case 4:
|
|
p = sb_pro_v2_init();
|
|
break;
|
|
case 5:
|
|
p = sb_16_init();
|
|
break;
|
|
}
|
|
x86_global_settings = -1;
|
|
xb->sb_base = p;
|
|
xb->cms_base = c;
|
|
xb->sound_emu = true;
|
|
}
|
|
|
|
static void x86_ne2000(struct x86_bridge *xb)
|
|
{
|
|
if (!is_board_enabled(&currprefs, ROMTYPE_NE2KISA, 0))
|
|
return;
|
|
struct romconfig *rc = get_device_romconfig(&currprefs, ROMTYPE_NE2KISA, 0);
|
|
if (rc) {
|
|
xb->ne2000_isa = &ne2000_pci_board_x86;
|
|
xb->ne2000_isa_board_state = xcalloc(pci_board_state, 1);
|
|
xb->ne2000_isa_board_state->irq_callback = ne2000_isa_irq_callback;
|
|
switch (rc->device_settings & 7)
|
|
{
|
|
case 0:
|
|
xb->ne2000_io = 0x240;
|
|
break;
|
|
case 1:
|
|
xb->ne2000_io = 0x260;
|
|
break;
|
|
case 2:
|
|
xb->ne2000_io = 0x280;
|
|
break;
|
|
case 3:
|
|
xb->ne2000_io = 0x2a0;
|
|
break;
|
|
case 4:
|
|
default:
|
|
xb->ne2000_io = 0x300;
|
|
break;
|
|
case 5:
|
|
xb->ne2000_io = 0x320;
|
|
break;
|
|
case 6:
|
|
xb->ne2000_io = 0x340;
|
|
break;
|
|
case 7:
|
|
xb->ne2000_io = 0x360;
|
|
break;
|
|
}
|
|
switch ((rc->device_settings >> 3) & 15)
|
|
{
|
|
case 0:
|
|
xb->ne2000_irq = 3;
|
|
break;
|
|
case 1:
|
|
xb->ne2000_irq = 4;
|
|
break;
|
|
case 2:
|
|
xb->ne2000_irq = 5;
|
|
break;
|
|
case 3:
|
|
default:
|
|
xb->ne2000_irq = 7;
|
|
break;
|
|
case 4:
|
|
xb->ne2000_irq = 9;
|
|
break;
|
|
case 5:
|
|
xb->ne2000_irq = 10;
|
|
break;
|
|
case 6:
|
|
xb->ne2000_irq = 11;
|
|
break;
|
|
case 7:
|
|
xb->ne2000_irq = 12;
|
|
break;
|
|
case 8:
|
|
xb->ne2000_irq = 15;
|
|
break;
|
|
}
|
|
struct romconfig *rc = get_device_romconfig(&currprefs, ROMTYPE_NE2KISA, 0);
|
|
struct autoconfig_info aci = { 0 };
|
|
aci.rc = rc;
|
|
if (xb->ne2000_isa->init(xb->ne2000_isa_board_state, &aci)) {
|
|
write_log(_T("NE2000 ISA configured, IO=%3X, IRQ=%d\n"), xb->ne2000_io, xb->ne2000_irq);
|
|
} else {
|
|
xb->ne2000_isa = NULL;
|
|
xfree(xb->ne2000_isa_board_state);
|
|
xb->ne2000_isa_board_state = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
if (zf) {
|
|
int size = (int)zfile_fread(romext, 1, 32768, zf);
|
|
write_log(_T("X86 VGA BIOS '%s' loaded, %08x %d bytes\n"), zfile_getname(zf), 0xc0000, size);
|
|
zfile_fclose(zf);
|
|
mem_mapping_add(&bios_mapping[4], 0xc0000, 0x8000, mem_read_romext, mem_read_romextw, mem_read_romextl, mem_write_null, mem_write_nullw, mem_write_nulll, romext, MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
}
|
|
}
|
|
|
|
static void set_vga(struct x86_bridge *xb)
|
|
{
|
|
// load vga bios
|
|
xb->vgaboard = -1;
|
|
for (int i = 0; i < MAX_RTG_BOARDS; i++) {
|
|
if (currprefs.rtgboards[i].rtgmem_type == GFXBOARD_ID_VGA) {
|
|
xb->vgaboard = i;
|
|
x86_vga_board = i;
|
|
xb->vgaboard_vram = currprefs.rtgboards[i].rtgmem_size;
|
|
load_vga_bios();
|
|
mem_mapping_add(&xb->vgamem, 0xa0000, 0x20000, vga_readb, vga_readw, vga_readl, vga_writeb, vga_writew, vga_writel, NULL, MEM_MAPPING_EXTERNAL, NULL);
|
|
mem_mapping_add(&xb->vgalfbmem, 0x100000, 0x00200000, vgalfb_readb, vgalfb_readw, vgalfb_readl, vgalfb_writeb, vgalfb_writew, vgalfb_writel, NULL, MEM_MAPPING_EXTERNAL, NULL);
|
|
mem_mapping_disable(&xb->vgalfbmem);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mouse_serial_poll(int x, int y, int z, int b, void *p);
|
|
void mouse_ps2_poll(int x, int y, int z, int b, void *p);
|
|
|
|
bool x86_mouse(int port, int x, int y, int z, int b)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb || !xb->mouse_port || !xb->mouse_base || xb->mouse_port != port + 1)
|
|
return false;
|
|
switch (xb->mouse_type)
|
|
{
|
|
case 0:
|
|
default:
|
|
if (b < 0)
|
|
return true;
|
|
mouse_serial_poll(x, y, z, b, xb->mouse_base);
|
|
return true;
|
|
case 1:
|
|
case 2:
|
|
if (b < 0)
|
|
return true;
|
|
mouse_ps2_poll(x, y, z, b, xb->mouse_base);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void *mouse_serial_init();
|
|
void *mouse_ps2_init();
|
|
void *mouse_intellimouse_init();
|
|
|
|
static void set_mouse(struct x86_bridge *xb)
|
|
{
|
|
ps2_mouse_supported = false;
|
|
if (!is_board_enabled(&currprefs, ROMTYPE_X86MOUSE, 0))
|
|
return;
|
|
struct romconfig *rc = get_device_romconfig(&currprefs, ROMTYPE_X86MOUSE, 0);
|
|
if (rc) {
|
|
xb->mouse_port = (rc->device_settings & 3) + 1;
|
|
xb->mouse_type = (rc->device_settings >> 2) & 3;
|
|
switch (xb->mouse_type)
|
|
{
|
|
case 0:
|
|
default:
|
|
serial1_init(0x3f8, 4, 1);
|
|
serial_reset();
|
|
xb->mouse_base = mouse_serial_init();
|
|
break;
|
|
case 1:
|
|
ps2_mouse_supported = true;
|
|
xb->mouse_base = mouse_ps2_init();
|
|
break;
|
|
case 2:
|
|
ps2_mouse_supported = true;
|
|
xb->mouse_base = mouse_intellimouse_init();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 };
|
|
|
|
bool x86_bridge_init(struct autoconfig_info *aci, uae_u32 romtype, int type)
|
|
{
|
|
const uae_u8 *ac;
|
|
struct romconfig *rc = aci->rc;
|
|
|
|
device_add_reset(x86_bridge_reset);
|
|
if (type >= TYPE_2286) {
|
|
ac = type >= TYPE_2386 ? a2386_autoconfig : a1060_autoconfig;
|
|
}
|
|
else {
|
|
ac = a1060_autoconfig;
|
|
}
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
ew(aci->autoconfig_raw, i * 4, ac[i]);
|
|
}
|
|
if (!aci->doinit)
|
|
return true;
|
|
|
|
struct x86_bridge *xb = x86_bridge_alloc();
|
|
if (!xb) {
|
|
aci->addrbank = &expamem_null;
|
|
return true;
|
|
}
|
|
memcpy(xb->acmemory, aci->autoconfig_raw, sizeof aci->autoconfig_raw);
|
|
bridges[0] = xb;
|
|
xb->rc = rc;
|
|
x86_global_settings = -1;
|
|
|
|
xb->type = type;
|
|
|
|
xb->io_ports = xcalloc(uae_u8, 0x10000);
|
|
xb->amiga_io = xcalloc(uae_u8, 0x50000);
|
|
xb->amiga_buffer = xb->amiga_io + 0x10000;
|
|
xb->amiga_parameter = xb->amiga_io + 0x20000;
|
|
xb->amiga_mono = xb->amiga_io + 0x30000;
|
|
xb->amiga_color = xb->amiga_io + 0x40000;
|
|
|
|
xb->settings = rc->device_settings;
|
|
if (xb->type >= TYPE_2286) {
|
|
xb->settings |= 0xff;
|
|
xb->bios_size = 65536;
|
|
} else {
|
|
xb->bios_size = 32768;
|
|
}
|
|
|
|
// PC Spekaer?
|
|
xb->pc_speaker = true;
|
|
xb->sound_emu = (xb->settings >> 13) & 1;
|
|
|
|
xb->pc_rom = xcalloc(uae_u8, 0x20000);
|
|
memset(xb->pc_rom, 0xff, 0x20000);
|
|
|
|
x86_ne2000(xb);
|
|
|
|
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;
|
|
}
|
|
|
|
romset = ROM_GENXT;
|
|
enable_sync = 1;
|
|
fpu_type = 0;
|
|
|
|
switch (xb->type)
|
|
{
|
|
case TYPE_SIDECAR:
|
|
model = 0;
|
|
cpu_manufacturer = 0;
|
|
cpu = 0; // 4.77MHz
|
|
fpu_type = (xb->settings & (1 << 19)) ? FPU_8087 : FPU_NONE;
|
|
break;
|
|
case TYPE_2088:
|
|
model = 0;
|
|
cpu_manufacturer = 0;
|
|
cpu = 0; // 4.77MHz
|
|
fpu_type = (xb->settings & (1 << 19)) ? FPU_8087 : FPU_NONE;
|
|
break;
|
|
case TYPE_2088T:
|
|
model = 0;
|
|
cpu_manufacturer = 0;
|
|
cpu = 0; // 4.77MHz
|
|
fpu_type = (xb->settings & (1 << 19)) ? FPU_8087 : FPU_NONE;
|
|
break;
|
|
case TYPE_2286:
|
|
model = 1;
|
|
cpu_manufacturer = 0;
|
|
cpu = 1; // 8MHz
|
|
fpu_type = (xb->settings & (1 << 19)) ? FPU_287 : FPU_NONE;
|
|
break;
|
|
case TYPE_2386:
|
|
model = 2;
|
|
cpu_manufacturer = 0;
|
|
cpu = 2; // 25MHz
|
|
fpu_type = (xb->settings & (1 << 19)) ? FPU_387 : FPU_NONE;
|
|
break;
|
|
}
|
|
if (rc->configtext[0]) {
|
|
MODEL *m = &models[model];
|
|
int mannum = 0;
|
|
while (m->cpu[mannum].cpus) {
|
|
CPU *cpup = m->cpu[mannum].cpus;
|
|
int cpunum = 0;
|
|
while (cpup[cpunum].cpu_type >= 0) {
|
|
TCHAR *cpuname = au(cpup[cpunum].name);
|
|
if (_tcsstr(rc->configtext, cpuname)) {
|
|
int cputype = cpup[cpunum].cpu_type;
|
|
cpu_manufacturer = mannum;
|
|
cpu = cpunum;
|
|
if (cputype == CPU_i486SX) {
|
|
fpu_type = FPU_NONE;
|
|
} else if (cputype == CPU_i486DX) {
|
|
fpu_type = FPU_BUILTIN;
|
|
} else if ((cputype == CPU_386DX || cputype == CPU_386SX) && fpu_type != FPU_NONE) {
|
|
fpu_type = FPU_387;
|
|
} else if (cputype == CPU_286 && fpu_type != FPU_NONE) {
|
|
fpu_type = FPU_287;
|
|
} else if (cputype == CPU_8088 && fpu_type != FPU_NONE) {
|
|
fpu_type = FPU_8087;
|
|
}
|
|
write_log(_T("CPU override = %s\n"), cpuname);
|
|
}
|
|
xfree(cpuname);
|
|
cpunum++;
|
|
}
|
|
mannum++;
|
|
}
|
|
}
|
|
|
|
cpu_multiplier = (int)currprefs.x86_speed_throttle;
|
|
cpu_set();
|
|
if (xb->type >= TYPE_2286) {
|
|
mem_size = (1024 * 1024) << ((xb->settings >> 16) & 7);
|
|
} else {
|
|
mem_size = xb->pc_maxbaseram;
|
|
}
|
|
mem_size /= 1024;
|
|
mem_init();
|
|
mem_alloc();
|
|
xb->pc_ram = ram;
|
|
if (xb->type < TYPE_2286) {
|
|
mem_set_704kb();
|
|
}
|
|
|
|
bridge_reset(xb);
|
|
|
|
timer_reset();
|
|
|
|
// SB setup must come before DMA init
|
|
sound_reset();
|
|
speaker_init();
|
|
set_sb_emu(xb);
|
|
sound_pos_global = xb->sound_emu ? 0 : -1;
|
|
|
|
dma_init();
|
|
pit_init();
|
|
pic_init();
|
|
|
|
if (xb->type >= TYPE_2286) {
|
|
AT = 1;
|
|
nvr_device.init();
|
|
TCHAR path[MAX_DPATH];
|
|
cfgfile_resolve_path_out_load(currprefs.flashfile, path, MAX_DPATH, PATH_ROM);
|
|
xb->cmossize = xb->type == TYPE_2386 ? 192 : 64;
|
|
xb->cmosfile = zfile_fopen(path, _T("rb+"), ZFD_NORMAL);
|
|
if (!xb->cmosfile) {
|
|
xb->cmosfile = zfile_fopen(path, _T("wb"));
|
|
}
|
|
memset(nvrram, 0, sizeof nvrram);
|
|
if (xb->cmosfile) {
|
|
zfile_fread(nvrram, 1, xb->cmossize, xb->cmosfile);
|
|
}
|
|
loadnvr();
|
|
nvrmask = 127;
|
|
pit_set_out_func(&pit, 1, pit_refresh_timer_at);
|
|
keyboard_at_init();
|
|
keyboard_at_init_ps2();
|
|
dma16_init();
|
|
pic2_init();
|
|
} else {
|
|
AT = 0;
|
|
pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
|
|
}
|
|
pic_reset();
|
|
dma_reset();
|
|
cpu_set_turbo(0);
|
|
cpu_set_turbo(1);
|
|
codegen_init();
|
|
|
|
// load bios
|
|
if (!load_rom_rc(rc, romtype, xb->bios_size, 0, xb->pc_rom, xb->bios_size, LOADROM_FILL)) {
|
|
error_log(_T("Bridgeboard BIOS failed to load"));
|
|
x86_bridge_free();
|
|
aci->addrbank = &expamem_null;
|
|
return false;
|
|
}
|
|
rom = xb->pc_rom;
|
|
biosmask = xb->bios_size - 1;
|
|
if (xb->type < TYPE_2286) {
|
|
mem_mapping_add(&bios_mapping[0], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
mem_mapping_add(&bios_mapping[1], 0xfc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
} else {
|
|
mem_mapping_add(&bios_mapping[0], 0xe0000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
mem_mapping_add(&bios_mapping[1], 0xe8000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
mem_mapping_add(&bios_mapping[2], 0xf0000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
mem_mapping_add(&bios_mapping[3], 0xf8000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0);
|
|
|
|
mem_mapping_add(&bios_high_mapping[0], (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_ROM, 0);
|
|
mem_mapping_add(&bios_high_mapping[1], (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_ROM, 0);
|
|
mem_mapping_add(&bios_high_mapping[2], (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_ROM, 0);
|
|
mem_mapping_add(&bios_high_mapping[3], (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x08000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_ROM, 0);
|
|
}
|
|
|
|
set_vga(xb);
|
|
|
|
// buffer ram
|
|
xb->sharedio_buffer_mb.base = xb->amiga_buffer;
|
|
xb->sharedio_buffer_mb.mask = 0xffff;
|
|
mem_mapping_add(&xb->sharedio_buffer[0], 0xa0000, 0x10000,
|
|
mem_read_sharedb, mem_read_sharedw, mem_read_sharedl,
|
|
mem_write_sharedb, mem_write_sharedw, mem_write_sharedl,
|
|
xb->amiga_buffer, 0, &xb->sharedio_buffer_mb);
|
|
mem_mapping_add(&xb->sharedio_buffer[1], 0xd0000, 0x10000,
|
|
mem_read_sharedb, mem_read_sharedw, mem_read_sharedl,
|
|
mem_write_sharedb, mem_write_sharedw, mem_write_sharedl,
|
|
xb->amiga_buffer, 0, &xb->sharedio_buffer_mb);
|
|
mem_mapping_add(&xb->sharedio_buffer[2], 0xe0000, 0x10000,
|
|
mem_read_sharedb, mem_read_sharedw, mem_read_sharedl,
|
|
mem_write_sharedb, mem_write_sharedw, mem_write_sharedl,
|
|
xb->amiga_buffer, 0, &xb->sharedio_buffer_mb);
|
|
|
|
// mono ram
|
|
xb->sharedio_mono_mb.base = xb->amiga_mono;
|
|
xb->sharedio_mono_mb.mask = 0x1fff;
|
|
mem_mapping_add(&xb->sharedio_mono, 0xb0000, 0x2000,
|
|
mem_read_sharedb, mem_read_sharedw, mem_read_sharedl,
|
|
mem_write_sharedb, mem_write_sharedw, mem_write_sharedl,
|
|
xb->amiga_mono, 0, &xb->sharedio_mono_mb);
|
|
|
|
// color ram
|
|
xb->sharedio_color_mb.base = xb->amiga_color;
|
|
xb->sharedio_color_mb.mask = 0x7fff;
|
|
mem_mapping_add(&xb->sharedio_color, 0xb8000, 0x8000,
|
|
mem_read_sharedb, mem_read_sharedw, mem_read_sharedl,
|
|
mem_write_sharedb, mem_write_sharedw, mem_write_sharedl,
|
|
xb->amiga_color, 0, &xb->sharedio_color_mb);
|
|
|
|
// parameter ram
|
|
if (xb->type < TYPE_2286) {
|
|
xb->sharedio_parameter_mb.base = xb->amiga_parameter;
|
|
xb->sharedio_parameter_mb.mask = 0x3fff;
|
|
mem_mapping_add(&xb->sharedio_parameter, 0xf0000, 0x4000,
|
|
mem_read_sharedb, mem_read_sharedw, mem_read_sharedl,
|
|
mem_write_sharedb, mem_write_sharedw, mem_write_sharedl,
|
|
xb->amiga_parameter, 0, &xb->sharedio_parameter_mb);
|
|
}
|
|
|
|
set_configurable_shared_io(xb);
|
|
|
|
if (xb->type == TYPE_2386) {
|
|
vlsi_init_mapping(xb);
|
|
}
|
|
|
|
set_mouse(xb);
|
|
|
|
xb->bank = &x86_bridge_bank;
|
|
|
|
aci->addrbank = xb->bank;
|
|
|
|
device_add_hsync(x86_bridge_hsync);
|
|
device_add_vsync_pre(x86_bridge_vsync);
|
|
device_add_exit(x86_bridge_free, NULL);
|
|
device_add_rethink(x86_bridge_rethink);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void reset_x86_hardware(struct x86_bridge *xb)
|
|
{
|
|
x86_ide_hd_put(-1, 0, 0);
|
|
x86_rt1000_bput(-1, 0);
|
|
|
|
#if 0
|
|
if (xb->type >= TYPE_2386) {
|
|
vlsi_reset(xb);
|
|
}
|
|
#endif
|
|
if (xb->ne2000_isa) {
|
|
xb->ne2000_isa->reset(xb->ne2000_isa_board_state);
|
|
}
|
|
|
|
serial_reset();
|
|
}
|
|
|
|
|
|
void x86_map_lfb(int v)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb)
|
|
return;
|
|
uae_u32 addr = v << 20;
|
|
|
|
if (addr) {
|
|
mem_mapping_set_addr(&xb->vgalfbmem, addr, xb->vgaboard_vram);
|
|
} else {
|
|
mem_mapping_disable(&xb->vgalfbmem);
|
|
}
|
|
}
|
|
|
|
void io_sethandler(uint16_t base, int size,
|
|
uint8_t(*inb)(uint16_t addr, void *priv),
|
|
uint16_t(*inw)(uint16_t addr, void *priv),
|
|
uint32_t(*inl)(uint16_t addr, void *priv),
|
|
void(*outb)(uint16_t addr, uint8_t val, void *priv),
|
|
void(*outw)(uint16_t addr, uint16_t val, void *priv),
|
|
void(*outl)(uint16_t addr, uint32_t val, void *priv),
|
|
void *priv)
|
|
{
|
|
if (base + size > MAX_IO_PORT)
|
|
return;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
int io = base + i;
|
|
port_inb[io] = inb;
|
|
port_inw[io] = inw;
|
|
port_inl[io] = inl;
|
|
port_outb[io] = outb;
|
|
port_outw[io] = outw;
|
|
port_outl[io] = outl;
|
|
port_priv[io] = priv;
|
|
}
|
|
}
|
|
|
|
void io_removehandler(uint16_t base, int size,
|
|
uint8_t(*inb)(uint16_t addr, void *priv),
|
|
uint16_t(*inw)(uint16_t addr, void *priv),
|
|
uint32_t(*inl)(uint16_t addr, void *priv),
|
|
void(*outb)(uint16_t addr, uint8_t val, void *priv),
|
|
void(*outw)(uint16_t addr, uint16_t val, void *priv),
|
|
void(*outl)(uint16_t addr, uint32_t val, void *priv),
|
|
void *priv)
|
|
{
|
|
if (base + size > MAX_IO_PORT)
|
|
return;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
int io = base + i;
|
|
port_inb[io] = NULL;
|
|
port_inw[io] = NULL;
|
|
port_inl[io] = NULL;
|
|
port_outb[io] = NULL;
|
|
port_outw[io] = NULL;
|
|
port_outl[io] = NULL;
|
|
}
|
|
}
|
|
|
|
static struct
|
|
{
|
|
void(*get_buffer)(int32_t *buffer, int len, void *p);
|
|
void *priv;
|
|
} sound_handlers[8];
|
|
|
|
void sound_add_handler(void(*get_buffer)(int32_t *buffer, int len, void *p), void *p)
|
|
{
|
|
sound_handlers[sound_handlers_num].get_buffer = get_buffer;
|
|
sound_handlers[sound_handlers_num].priv = p;
|
|
sound_handlers_num++;
|
|
}
|
|
|
|
void sound_speed_changed(bool enable)
|
|
{
|
|
if (sound_poll_timer.enabled || enable) {
|
|
sound_poll_latch = (uae_u64)((float)TIMER_USEC * (1000000.0f / currprefs.sound_freq));
|
|
timer_set_delay_u64(&sound_poll_timer, sound_poll_latch);
|
|
}
|
|
}
|
|
|
|
void sound_poll(void *priv)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
|
|
timer_advance_u64(&sound_poll_timer, sound_poll_latch);
|
|
|
|
if (x86_sndbuffer_filled[x86_sndbuffer_index]) {
|
|
return;
|
|
}
|
|
|
|
sound_pos_global++;
|
|
if (sound_pos_global == SOUNDBUFLEN) {
|
|
int32_t *p = x86_sndbuffer[x86_sndbuffer_index];
|
|
memset(p, 0, SOUNDBUFLEN * sizeof(int32_t) * 2);
|
|
for (int c = 0; c < sound_handlers_num; c++) {
|
|
if (c > 0 || (c == 0 && xb->pc_speaker)) {
|
|
sound_handlers[c].get_buffer(p, SOUNDBUFLEN, sound_handlers[c].priv);
|
|
}
|
|
}
|
|
x86_sndbuffer_filled[x86_sndbuffer_index] = true;
|
|
x86_sndbuffer_index ^= 1;
|
|
sound_pos_global = 0;
|
|
}
|
|
}
|
|
|
|
void sound_reset()
|
|
{
|
|
sound_handlers_num = 0;
|
|
sound_pos_global = 0;
|
|
x86_sndbuffer[0] = outbuffer1;
|
|
x86_sndbuffer[1] = outbuffer2;
|
|
x86_sndbuffer_filled[0] = x86_sndbuffer_filled[1] = false;
|
|
}
|
|
|
|
void sound_set_cd_volume(unsigned int l, unsigned int r)
|
|
{
|
|
|
|
}
|
|
|
|
void x86_update_sound(float clk)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
x86_base_event_clock = clk;
|
|
if (xb) {
|
|
xb->audeventtime = (int)(x86_base_event_clock * CYCLE_UNIT / currprefs.sound_freq + 1);
|
|
sound_speed_changed(false);
|
|
}
|
|
}
|
|
|
|
bool a1060_init(struct autoconfig_info *aci)
|
|
{
|
|
return x86_bridge_init(aci, ROMTYPE_A1060, TYPE_SIDECAR);
|
|
}
|
|
bool a2088xt_init(struct autoconfig_info *aci)
|
|
{
|
|
return x86_bridge_init(aci, ROMTYPE_A2088, TYPE_2088);
|
|
}
|
|
bool a2088t_init(struct autoconfig_info *aci)
|
|
{
|
|
return x86_bridge_init(aci, ROMTYPE_A2088T, TYPE_2088T);
|
|
}
|
|
bool a2286_init(struct autoconfig_info *aci)
|
|
{
|
|
return x86_bridge_init(aci, ROMTYPE_A2286, TYPE_2286);
|
|
}
|
|
bool a2386_init(struct autoconfig_info *aci)
|
|
{
|
|
return x86_bridge_init(aci, ROMTYPE_A2386, TYPE_2386);
|
|
}
|
|
|
|
bool isa_expansion_init(struct autoconfig_info *aci)
|
|
{
|
|
static const int parent[] = { ROMTYPE_A1060, ROMTYPE_A2088, ROMTYPE_A2088T, ROMTYPE_A2286, ROMTYPE_A2386, 0 };
|
|
aci->parent_romtype = parent;
|
|
aci->zorro = 0;
|
|
return true;
|
|
}
|
|
|
|
void x86_outfloppy(int portnum, uae_u8 v)
|
|
{
|
|
struct x86_bridge *b = bridges[0];
|
|
outfloppy(b, portnum, v);
|
|
}
|
|
uae_u8 x86_infloppy(int portnum)
|
|
{
|
|
struct x86_bridge *b = bridges[0];
|
|
return infloppy(b, portnum);
|
|
}
|
|
void x86_floppy_run(void)
|
|
{
|
|
check_floppy_delay();
|
|
}
|
|
void x86_initfloppy(X86_INTERRUPT_CALLBACK irq_callback)
|
|
{
|
|
struct x86_bridge *xb = bridges[0];
|
|
if (!xb) {
|
|
xb = x86_bridge_alloc();
|
|
bridges[0] = xb;
|
|
}
|
|
xb->type = -1;
|
|
xb->irq_callback = irq_callback;
|
|
floppy_hardreset();
|
|
}
|