Fixes for the (S)VGA common DAC and some card-specific DAT's (ATi 68860, BT48x family, and the Cirrus Logic DAC), fixes Star Control II among other things.

This commit is contained in:
OBattler
2018-10-04 01:19:43 +02:00
parent 6b938d63c3
commit ed92602dad
883 changed files with 444853 additions and 88 deletions

File diff suppressed because it is too large Load Diff

111
src/machine/m_at.c$ Normal file
View File

@@ -0,0 +1,111 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../pic.h"
#include "../pit.h"
#include "../dma.h"
#include "../mem.h"
#include "../device.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../nvr.h"
#include "../game/gameport.h"
#include "../keyboard.h"
#include "../lpt.h"
#include "../disk/hdc.h"
#include "machine.h"
void
machine_at_common_init(const machine_t *model)
{
machine_common_init(model);
pit_set_out_func(&pit, 1, pit_refresh_timer_at);
pic2_init();
dma16_init();
if (lpt_enabled)
lpt2_remove();
device_add(&at_nvr_device);
if (joystick_type != 7)
device_add(&gameport_device);
}
void
machine_at_init(const machine_t *model)
{
machine_at_common_init(model);
device_add(&keyboard_at_device);
}
void
machine_at_ps2_init(const machine_t *model)
{
machine_at_common_init(model);
device_add(&keyboard_ps2_device);
}
void
machine_at_common_ide_init(const machine_t *model)
{
machine_at_common_init(model);
device_add(&ide_isa_2ch_opt_device);
}
void
machine_at_ide_init(const machine_t *model)
{
machine_at_init(model);
device_add(&ide_isa_2ch_opt_device);
}
void
machine_at_ps2_ide_init(const machine_t *model)
{
machine_at_ps2_init(model);
device_add(&ide_isa_2ch_opt_device);
}
void
machine_at_top_remap_init(const machine_t *model)
{
machine_at_init(model);
if (mem_size >= 1024)
mem_remap_top_384k();
}
void
machine_at_ide_top_remap_init(const machine_t *model)
{
machine_at_ide_init(model);
if (mem_size >= 1024)
mem_remap_top_384k();
}
void
machine_at_ibm_init(const machine_t *model)
{
machine_at_top_remap_init(model);
device_add(&fdc_at_device);
}

View File

@@ -0,0 +1,578 @@
/* Copyright holders: Sarah Walker
see COPYING for more details
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../cpu/cpu.h"
#include "../cpu/x86.h"
#include "../io.h"
#include "../mem.h"
#include "../rom.h"
#include "../device.h"
#include "../keyboard.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "machine.h"
#include "../video/video.h"
#include "../video/vid_et4000.h"
#include "../video/vid_oak_oti.h"
static int headland_index;
static uint8_t headland_regs[256];
static uint8_t headland_port_92 = 0xFC, headland_ems_mar = 0, headland_cri = 0;
static uint8_t headland_regs_cr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static uint16_t headland_ems_mr[64];
static mem_mapping_t headland_low_mapping;
static mem_mapping_t headland_ems_mapping[64];
static mem_mapping_t headland_mid_mapping;
static mem_mapping_t headland_high_mapping;
static mem_mapping_t headland_4000_9FFF_mapping[24];
/* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet,
so memory configuration is hardcoded now. */
static int headland_mem_conf_cr0[41] = { 0x00, 0x00, 0x20, 0x40, 0x60, 0xA0, 0x40, 0xE0,
0xA0, 0xC0, 0xE0, 0xE0, 0xC0, 0xE0, 0xE0, 0xE0,
0xE0, 0x20, 0x40, 0x40, 0xA0, 0xC0, 0xE0, 0xE0,
0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0x20, 0x40, 0x60, 0x60, 0xC0, 0xE0, 0xE0, 0xE0,
0xE0 };
static int headland_mem_conf_cr1[41] = { 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
0x40 };
static uint32_t
get_headland_addr(uint32_t addr, uint16_t *mr)
{
if (mr && (headland_regs_cr[0] & 2) && (*mr & 0x200)) {
addr = (addr & 0x3fff) | ((*mr & 0x1F) << 14);
if (headland_regs_cr[1] & 0x40) {
if ((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) {
if (headland_regs_cr[0] & 0x80) {
addr |= (*mr & 0x60) << 14;
if (*mr & 0x100)
addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x80) << 15);
else
addr += (*mr & 0x80) << 14;
} else if (*mr & 0x100)
addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x20) << 15);
else
addr += (*mr & 0x80) << 12;
} else if (headland_regs_cr[0] & 0x80)
addr |= (*mr & 0x100) ? ((*mr & 0x80) + 0x400) << 12 : (*mr & 0xE0) << 14;
else
addr |= (*mr & 0x100) ? ((*mr & 0xE0) + 0x40) << 14 : (*mr & 0x80) << 12;
} else {
if ((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) {
if (headland_regs_cr[0] & 0x80) {
addr |= ((*mr & 0x60) << 14);
if (*mr & 0x180)
addr += ((*mr & 0xC00) << 13) + (((*mr & 0x180) - 0x60) << 16);
} else
addr |= ((*mr & 0x60) << 14) | ((*mr & 0x180) << 16) | ((*mr & 0xC00) << 13);
} else if (headland_regs_cr[0] & 0x80)
addr |= (*mr & 0x1E0) << 14;
else
addr |= (*mr & 0x180) << 12;
}
} else if (mr == NULL && (headland_regs_cr[0] & 4) == 0 && mem_size >= 1024 && addr >= 0x100000)
addr -= 0x60000;
return addr;
}
static void
headland_set_global_EMS_state(int state)
{
int i;
uint32_t base_addr, virt_addr;
for (i=0; i<32; i++) {
base_addr = (i + 16) << 14;
if (i >= 24)
base_addr += 0x20000;
if ((state & 2) && (headland_ems_mr[((state & 1) << 5) | i] & 0x200)) {
virt_addr = get_headland_addr(base_addr, &headland_ems_mr[((state & 1) << 5) | i]);
if (i < 24)
mem_mapping_disable(&headland_4000_9FFF_mapping[i]);
mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]);
mem_mapping_enable(&headland_ems_mapping[((state & 1) << 5) | i]);
if (virt_addr < (mem_size << 10))
mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + virt_addr);
else
mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], NULL);
} else {
mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + base_addr);
mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]);
mem_mapping_disable(&headland_ems_mapping[((state & 1) << 5) | i]);
if (i < 24)
mem_mapping_enable(&headland_4000_9FFF_mapping[i]);
}
}
flushmmucache();
}
static void
headland_memmap_state_update(void)
{
int i;
uint32_t addr;
for (i=0; i<24; i++) {
addr = get_headland_addr(0x40000 + (i << 14), NULL);
mem_mapping_set_exec(&headland_4000_9FFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL);
}
mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
if (mem_size > 640) {
if ((headland_regs_cr[0] & 4) == 0) {
mem_mapping_set_addr(&headland_mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10);
mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000);
if (mem_size > 1024) {
mem_mapping_set_addr(&headland_high_mapping, 0x160000, (mem_size - 1024) << 10);
mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000);
}
} else {
mem_mapping_set_addr(&headland_mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10);
mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000);
if (mem_size > 1024) {
mem_mapping_set_addr(&headland_high_mapping, 0x100000, (mem_size - 1024) << 10);
mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000);
}
}
}
headland_set_global_EMS_state(headland_regs_cr[0] & 3);
}
static void
headland_write(uint16_t addr, uint8_t val, void *priv)
{
uint8_t old_val, index;
uint32_t base_addr, virt_addr;
switch(addr) {
case 0x22:
headland_index = val;
break;
case 0x23:
old_val = headland_regs[headland_index];
if ((headland_index == 0xc1) && !is486)
val = 0;
headland_regs[headland_index] = val;
if (headland_index == 0x82) {
shadowbios = val & 0x10;
shadowbios_write = !(val & 0x10);
if (shadowbios)
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED);
else
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
} else if (headland_index == 0x87) {
if ((val & 1) && !(old_val & 1))
softresetx86();
}
break;
case 0x92:
if ((mem_a20_alt ^ val) & 2) {
mem_a20_alt = val & 2;
mem_a20_recalc();
}
if ((~headland_port_92 & val) & 1) {
softresetx86();
cpu_set_edx();
}
headland_port_92 = val | 0xFC;
break;
case 0x1EC:
headland_ems_mr[headland_ems_mar & 0x3F] = val | 0xFF00;
index = headland_ems_mar & 0x1F;
base_addr = (index + 16) << 14;
if (index >= 24)
base_addr += 0x20000;
if ((headland_regs_cr[0] & 2) && ((headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5))) {
virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]);
if (index < 24)
mem_mapping_disable(&headland_4000_9FFF_mapping[index]);
if (virt_addr < (mem_size << 10))
mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr);
else
mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL);
mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]);
flushmmucache();
}
if (headland_ems_mar & 0x80)
headland_ems_mar++;
break;
case 0x1ED:
headland_cri = val;
break;
case 0x1EE:
headland_ems_mar = val;
break;
case 0x1EF:
old_val = headland_regs_cr[headland_cri];
switch(headland_cri) {
case 0:
headland_regs_cr[0] = (val & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
mem_set_mem_state(0xE0000, 0x10000, (val & 8 ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED);
mem_set_mem_state(0xF0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED);
headland_memmap_state_update();
break;
case 1:
headland_regs_cr[1] = (val & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
headland_memmap_state_update();
break;
case 2:
case 3:
case 5:
headland_regs_cr[headland_cri] = val;
headland_memmap_state_update();
break;
case 4:
headland_regs_cr[4] = (headland_regs_cr[4] & 0xF0) | (val & 0x0F);
if (val & 1) {
mem_mapping_disable(&bios_mapping[0]);
mem_mapping_disable(&bios_mapping[1]);
mem_mapping_disable(&bios_mapping[2]);
mem_mapping_disable(&bios_mapping[3]);
} else {
mem_mapping_enable(&bios_mapping[0]);
mem_mapping_enable(&bios_mapping[1]);
mem_mapping_enable(&bios_mapping[2]);
mem_mapping_enable(&bios_mapping[3]);
}
break;
case 6:
if (headland_regs_cr[4] & 0x80) {
headland_regs_cr[headland_cri] = (val & 0xFE) | (mem_size > 8192 ? 1 : 0);
headland_memmap_state_update();
}
break;
default:
break;
}
break;
default:
break;
}
}
static void
headland_writew(uint16_t addr, uint16_t val, void *priv)
{
uint8_t index;
uint32_t base_addr, virt_addr;
switch(addr) {
case 0x1EC:
headland_ems_mr[headland_ems_mar & 0x3F] = val;
index = headland_ems_mar & 0x1F;
base_addr = (index + 16) << 14;
if (index >= 24)
base_addr += 0x20000;
if ((headland_regs_cr[0] & 2) && (headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5)) {
if(val & 0x200) {
virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]);
if (index < 24)
mem_mapping_disable(&headland_4000_9FFF_mapping[index]);
if (virt_addr < (mem_size << 10))
mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr);
else
mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL);
mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]);
} else {
mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + base_addr);
mem_mapping_disable(&headland_ems_mapping[headland_ems_mar & 0x3F]);
if (index < 24)
mem_mapping_enable(&headland_4000_9FFF_mapping[index]);
}
flushmmucache();
}
if (headland_ems_mar & 0x80)
headland_ems_mar++;
break;
default:
break;
}
}
static uint8_t
headland_read(uint16_t addr, void *priv)
{
uint8_t val;
switch(addr) {
case 0x22:
val = headland_index;
break;
case 0x23:
if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix)
val = 0xff; /*Don't conflict with Cyrix config registers*/
else
val = headland_regs[headland_index];
break;
case 0x92:
val = headland_port_92 | 0xFC;
break;
case 0x1EC:
val = headland_ems_mr[headland_ems_mar & 0x3F];
if (headland_ems_mar & 0x80)
headland_ems_mar++;
break;
case 0x1ED:
val = headland_cri;
break;
case 0x1EE:
val = headland_ems_mar;
break;
case 0x1EF:
switch(headland_cri) {
case 0:
val = (headland_regs_cr[0] & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
break;
case 1:
val = (headland_regs_cr[1] & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
break;
case 6:
if (headland_regs_cr[4] & 0x80)
val = (headland_regs_cr[6] & 0xFE) | (mem_size > 8192 ? 1 : 0);
else
val = 0;
break;
default:
val = headland_regs_cr[headland_cri];
break;
}
break;
default:
val = 0xFF;
break;
}
return val;
}
static uint16_t
headland_readw(uint16_t addr, void *priv)
{
uint16_t val;
switch(addr) {
case 0x1EC:
val = headland_ems_mr[headland_ems_mar & 0x3F] | ((headland_regs_cr[4] & 0x80) ? 0xF000 : 0xFC00);
if (headland_ems_mar & 0x80)
headland_ems_mar++;
break;
default:
val = 0xFFFF;
break;
}
return val;
}
static uint8_t
mem_read_headlandb(uint32_t addr, void *priv)
{
uint8_t val = 0xff;
addr = get_headland_addr(addr, priv);
if (addr < (mem_size << 10))
val = ram[addr];
return val;
}
static uint16_t
mem_read_headlandw(uint32_t addr, void *priv)
{
uint16_t val = 0xffff;
addr = get_headland_addr(addr, priv);
if (addr < (mem_size << 10))
val = *(uint16_t *)&ram[addr];
return val;
}
static uint32_t
mem_read_headlandl(uint32_t addr, void *priv)
{
uint32_t val = 0xffffffff;
addr = get_headland_addr(addr, priv);
if (addr < (mem_size << 10))
val = *(uint32_t *)&ram[addr];
return val;
}
static void
mem_write_headlandb(uint32_t addr, uint8_t val, void *priv)
{
addr = get_headland_addr(addr, priv);
if (addr < (mem_size << 10))
ram[addr] = val;
}
static void
mem_write_headlandw(uint32_t addr, uint16_t val, void *priv)
{
addr = get_headland_addr(addr, priv);
if (addr < (mem_size << 10))
*(uint16_t *)&ram[addr] = val;
}
static void
mem_write_headlandl(uint32_t addr, uint32_t val, void *priv)
{
addr = get_headland_addr(addr, priv);
if (addr < (mem_size << 10))
*(uint32_t *)&ram[addr] = val;
}
static void
headland_init(int ht386)
{
int i;
for(i=0; i<8; i++)
headland_regs_cr[i] = 0;
headland_regs_cr[0] = 4;
if (ht386) {
headland_regs_cr[4] = 0x20;
io_sethandler(0x0092, 0x0001, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL);
} else
headland_regs_cr[4] = 0;
io_sethandler(0x01EC, 0x0001, headland_read, headland_readw, NULL, headland_write, headland_writew, NULL, NULL);
io_sethandler(0x01ED, 0x0003, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL);
for(i=0; i<64; i++)
headland_ems_mr[i] = 0;
mem_mapping_disable(&ram_low_mapping);
mem_mapping_disable(&ram_mid_mapping);
mem_mapping_disable(&ram_high_mapping);
mem_mapping_add(&headland_low_mapping, 0, 0x40000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram, MEM_MAPPING_INTERNAL, NULL);
if(mem_size > 640) {
mem_mapping_add(&headland_mid_mapping, 0xA0000, 0x60000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL);
mem_mapping_enable(&headland_mid_mapping);
}
if(mem_size > 1024) {
mem_mapping_add(&headland_high_mapping, 0x100000, ((mem_size - 1024) * 1024), mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL);
mem_mapping_enable(&headland_high_mapping);
}
for (i = 0; i < 24; i++) {
mem_mapping_add(&headland_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL);
mem_mapping_enable(&headland_4000_9FFF_mapping[i]);
}
for (i = 0; i < 64; i++) {
headland_ems_mr[i] = 0;
mem_mapping_add(&headland_ems_mapping[i], ((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14), 0, &headland_ems_mr[i]);
mem_mapping_disable(&headland_ems_mapping[i]);
}
headland_memmap_state_update();
}
static void
machine_at_headland_common_init(int ht386)
{
device_add(&keyboard_at_ami_device);
device_add(&fdc_at_device);
headland_init(ht386);
}
void
machine_at_headland_init(const machine_t *model)
{
machine_at_common_ide_init(model);
machine_at_headland_common_init(1);
}
const device_t *
at_tg286m_get_device(void)
{
return &et4000k_tg286_isa_device;
}
void
machine_at_tg286m_init(const machine_t *model)
{
machine_at_common_init(model);
machine_at_headland_common_init(0);
if (gfxcard == GFX_INTERNAL)
device_add(&et4000k_tg286_isa_device);
}
const device_t *
at_ama932j_get_device(void)
{
return &oti067_ama932j_device;
}
void
machine_at_ama932j_init(const machine_t *model)
{
machine_at_common_ide_init(model);
machine_at_headland_common_init(1);
if (gfxcard == GFX_INTERNAL)
device_add(&oti067_ama932j_device);
}

View File

@@ -0,0 +1,767 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
*
* This file is part of the VARCem Project.
*
* Implementation of the Schneider EuroPC system.
*
* NOTES: BIOS info (taken from MAME, thanks guys!!)
*
* f000:e107 bios checksum test
* memory test
* f000:e145 irq vector init
* f000:e156
* f000:e169-d774 test of special registers 254/354
* f000:e16c-e817
* f000:e16f
* f000:ec08 test of special registers 800a rtc time
* or date error, rtc corrected
* f000:ef66 0xf
* f000:db3e 0x8..0xc
* f000:d7f8
* f000:db5f
* f000:e172
* f000:ecc5 801a video setup error
* f000:d6c9 copyright output
* f000:e1b7
* f000:e1be DI bits set mean output text!!! (801a)
* f000: 0x8000 output
* 1 rtc error
* 2 rtc time or date error
* 4 checksum error in setup
* 8 rtc status corrected
* 10 video setup error
* 20 video ram bad
* 40 monitor type not recogniced
* 80 mouse port enabled
* 100 joystick port enabled
* f000:e1e2-dc0c CPU speed is 4.77 mhz
* f000:e1e5-f9c0 keyboard processor error
* f000:e1eb-c617 external lpt1 at 0x3bc
* f000:e1ee-e8ee external coms at
*
* Routines:
* f000:c92d output text at bp
* f000:db3e RTC read reg cl
* f000:e8ee piep
* f000:e95e RTC write reg cl
* polls until JIM 0xa is zero,
* output cl at jim 0xa
* write ah hinibble as lownibble into jim 0xa
* write ah lownibble into jim 0xa
* f000:ef66 RTC read reg cl
* polls until jim 0xa is zero,
* output cl at jim 0xa
* read low 4 nibble at jim 0xa
* read low 4 nibble at jim 0xa
* return first nibble<<4|second nibble in ah
* f000:f046 seldom compares ret
* f000:fe87 0 -> ds
*
* Memory:
* 0000:0469 bit 0: b0000 memory available
* bit 1: b8000 memory available
* 0000:046a: 00 jim 250 01 jim 350
*
* WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK.
*
* Version: @(#)europc.c 1.0.7 2018/08/04
*
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
*
* Inspired by the "jim.c" file originally present, but a
* fully re-written module, based on the information from
* Schneider's schematics and technical manuals, and the
* input from people with real EuroPC hardware.
*
* Copyright 2017,2018 Fred N. van Kempen.
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <time.h>
#define HAVE_STDARG_H
#include "../86box.h"
#include "../io.h"
#include "../nmi.h"
#include "../mem.h"
#include "../rom.h"
#include "../device.h"
#include "../nvr.h"
#include "../keyboard.h"
#include "../mouse.h"
#include "../game/gameport.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../disk/hdc.h"
#include "../video/video.h"
#include "machine.h"
#define EUROPC_DEBUG 0 /* current debugging level */
/* M3002 RTC chip registers. */
#define MRTC_SECONDS 0x00 /* BCD, 00-59 */
#define MRTC_MINUTES 0x01 /* BCD, 00-59 */
#define MRTC_HOURS 0x02 /* BCD, 00-23 */
#define MRTC_DAYS 0x03 /* BCD, 01-31 */
#define MRTC_MONTHS 0x04 /* BCD, 01-12 */
#define MRTC_YEARS 0x05 /* BCD, 00-99 (year only) */
#define MRTC_WEEKDAY 0x06 /* BCD, 01-07 */
#define MRTC_WEEKNO 0x07 /* BCD, 01-52 */
#define MRTC_CONF_A 0x08 /* EuroPC config, binary */
#define MRTC_CONF_B 0x09 /* EuroPC config, binary */
#define MRTC_CONF_C 0x0a /* EuroPC config, binary */
#define MRTC_CONF_D 0x0b /* EuroPC config, binary */
#define MRTC_CONF_E 0x0c /* EuroPC config, binary */
#define MRTC_CHECK_LO 0x0d /* Checksum, low byte */
#define MRTC_CHECK_HI 0x0e /* Checksum, high byte */
#define MRTC_CTRLSTAT 0x0f /* RTC control/status, binary */
typedef struct {
uint16_t jim; /* JIM base address */
uint8_t regs[16]; /* JIM internal regs (8) */
nvr_t nvr; /* NVR */
uint8_t nvr_stat;
uint8_t nvr_addr;
} europc_t;
static europc_t europc;
#ifdef ENABLE_EUROPC_LOG
int europc_do_log = ENABLE_EUROPC_LOG;
#endif
static void
europc_log(const char *fmt, ...)
{
#ifdef ENABLE_EUROPC_LOG
va_list ap;
if (europc_do_log)
{
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
#endif
}
/*
* This is called every second through the NVR/RTC hook.
*
* We fake a 'running' RTC by updating its registers on
* each passing second. Not exactly accurate, but good
* enough.
*
* Note that this code looks nasty because of all the
* BCD to decimal vv going on.
*
* FIXME: should we mark NVR as dirty?
*/
static void
europc_rtc_tick(nvr_t *nvr)
{
uint8_t *regs;
int mon, yr;
/* Only if RTC is running.. */
regs = nvr->regs;
if (! (regs[MRTC_CTRLSTAT] & 0x01)) return;
regs[MRTC_SECONDS] = RTC_BCDINC(nvr->regs[MRTC_SECONDS], 1);
if (regs[MRTC_SECONDS] >= RTC_BCD(60)) {
regs[MRTC_SECONDS] = RTC_BCD(0);
regs[MRTC_MINUTES] = RTC_BCDINC(regs[MRTC_MINUTES], 1);
if (regs[MRTC_MINUTES] >= RTC_BCD(60)) {
regs[MRTC_MINUTES] = RTC_BCD(0);
regs[MRTC_HOURS] = RTC_BCDINC(regs[MRTC_HOURS], 1);
if (regs[MRTC_HOURS] >= RTC_BCD(24)) {
regs[MRTC_HOURS] = RTC_BCD(0);
regs[MRTC_DAYS] = RTC_BCDINC(regs[MRTC_DAYS], 1);
mon = RTC_DCB(regs[MRTC_MONTHS]);
yr = RTC_DCB(regs[MRTC_YEARS]) + 1900;
if (RTC_DCB(regs[MRTC_DAYS]) > nvr_get_days(mon, yr)) {
regs[MRTC_DAYS] = RTC_BCD(1);
regs[MRTC_MONTHS] = RTC_BCDINC(regs[MRTC_MONTHS], 1);
if (regs[MRTC_MONTHS] > RTC_BCD(12)) {
regs[MRTC_MONTHS] = RTC_BCD(1);
regs[MRTC_YEARS] = RTC_BCDINC(regs[MRTC_YEARS], 1) & 0xff;
}
}
}
}
}
}
/* Get the current NVR time. */
static void
rtc_time_get(uint8_t *regs, struct tm *tm)
{
/* NVR is in BCD data mode. */
tm->tm_sec = RTC_DCB(regs[MRTC_SECONDS]);
tm->tm_min = RTC_DCB(regs[MRTC_MINUTES]);
tm->tm_hour = RTC_DCB(regs[MRTC_HOURS]);
tm->tm_wday = (RTC_DCB(regs[MRTC_WEEKDAY]) - 1);
tm->tm_mday = RTC_DCB(regs[MRTC_DAYS]);
tm->tm_mon = (RTC_DCB(regs[MRTC_MONTHS]) - 1);
tm->tm_year = RTC_DCB(regs[MRTC_YEARS]);
#if USE_Y2K
tm->tm_year += (RTC_DCB(regs[MRTC_CENTURY]) * 100) - 1900;
#endif
}
/* Set the current NVR time. */
static void
rtc_time_set(uint8_t *regs, struct tm *tm)
{
/* NVR is in BCD data mode. */
regs[MRTC_SECONDS] = RTC_BCD(tm->tm_sec);
regs[MRTC_MINUTES] = RTC_BCD(tm->tm_min);
regs[MRTC_HOURS] = RTC_BCD(tm->tm_hour);
regs[MRTC_WEEKDAY] = RTC_BCD(tm->tm_wday + 1);
regs[MRTC_DAYS] = RTC_BCD(tm->tm_mday);
regs[MRTC_MONTHS] = RTC_BCD(tm->tm_mon + 1);
regs[MRTC_YEARS] = RTC_BCD(tm->tm_year % 100);
#if USE_Y2K
regs[MRTC_CENTURY] = RTC_BCD((tm->tm_year+1900) / 100);
#endif
}
static void
rtc_start(nvr_t *nvr)
{
struct tm tm;
/* Initialize the internal and chip times. */
if (time_sync & TIME_SYNC_ENABLED) {
/* Use the internal clock's time. */
nvr_time_get(&tm);
rtc_time_set(nvr->regs, &tm);
} else {
/* Set the internal clock from the chip time. */
rtc_time_get(nvr->regs, &tm);
nvr_time_set(&tm);
}
#if 0
/* Start the RTC - BIOS will do this. */
nvr->regs[MRTC_CTRLSTAT] = 0x01;
#endif
}
/* Create a valid checksum for the current NVR data. */
static uint8_t
rtc_checksum(uint8_t *ptr)
{
uint8_t sum;
int i;
/* Calculate all bytes with XOR. */
sum = 0x00;
for (i=MRTC_CONF_A; i<=MRTC_CONF_E; i++)
sum += ptr[i];
return(sum);
}
/* Reset the machine's NVR to a sane state. */
static void
rtc_reset(nvr_t *nvr)
{
/* Initialize the RTC to a known state. */
nvr->regs[MRTC_SECONDS] = RTC_BCD(0); /* seconds */
nvr->regs[MRTC_MINUTES] = RTC_BCD(0); /* minutes */
nvr->regs[MRTC_HOURS] = RTC_BCD(0); /* hours */
nvr->regs[MRTC_DAYS] = RTC_BCD(1); /* days */
nvr->regs[MRTC_MONTHS] = RTC_BCD(1); /* months */
nvr->regs[MRTC_YEARS] = RTC_BCD(80); /* years */
nvr->regs[MRTC_WEEKDAY] = RTC_BCD(1); /* weekday */
nvr->regs[MRTC_WEEKNO] = RTC_BCD(1); /* weekno */
/*
* EuroPC System Configuration:
*
* [A] unknown
*
* [B] 7 1 bootdrive extern
* 0 bootdribe intern
* 6:5 11 invalid hard disk type
* 10 hard disk installed, type 2
* 01 hard disk installed, type 1
* 00 hard disk not installed
* 4:3 11 invalid external drive type
* 10 external drive 720K
* 01 external drive 360K
* 00 external drive disabled
* 2 unknown
* 1:0 11 invalid internal drive type
* 10 internal drive 360K
* 01 internal drive 720K
* 00 internal drive disabled
*
* [C] 7:6 unknown
* 5 monitor detection OFF
* 4 unknown
* 3:2 11 illegal memory size
* 10 512K
* 01 256K
* 00 640K
* 1:0 11 illegal game port
* 10 gameport as mouse port
* 01 gameport as joysticks
* 00 gameport disabled
*
* [D] 7:6 10 9MHz CPU speed
* 01 7MHz CPU speed
* 00 4.77 MHz CPU
* 5 unknown
* 4 external: color, internal: mono
* 3 unknown
* 2 internal video ON
* 1:0 11 mono
* 10 color80
* 01 color40
* 00 special (EGA,VGA etc)
*
* [E] 7:4 unknown
* 3:0 country (00=Deutschland, 0A=ASCII)
*/
nvr->regs[MRTC_CONF_A] = 0x00; /* CONFIG A */
nvr->regs[MRTC_CONF_B] = 0x0A; /* CONFIG B */
nvr->regs[MRTC_CONF_C] = 0x28; /* CONFIG C */
nvr->regs[MRTC_CONF_D] = 0x12; /* CONFIG D */
nvr->regs[MRTC_CONF_E] = 0x0A; /* CONFIG E */
nvr->regs[MRTC_CHECK_LO] = 0x00; /* checksum (LO) */
nvr->regs[MRTC_CHECK_HI] = 0x00; /* checksum (HI) */
nvr->regs[MRTC_CTRLSTAT] = 0x01; /* status/control */
/* Generate a valid checksum. */
nvr->regs[MRTC_CHECK_LO] = rtc_checksum(nvr->regs);
}
/* Execute a JIM control command. */
static void
jim_set(europc_t *sys, uint8_t reg, uint8_t val)
{
switch(reg) {
case 0: /* MISC control (WO) */
// bit0: enable MOUSE
// bit1: enable joystick
break;
case 2: /* AGA control */
if (! (val & 0x80)) {
/* Reset AGA. */
break;
}
switch (val) {
case 0x1f: /* 0001 1111 */
case 0x0b: /* 0000 1011 */
//europc_jim.mode=AGA_MONO;
europc_log("EuroPC: AGA Monochrome mode!\n");
break;
case 0x18: /* 0001 1000 */
case 0x1a: /* 0001 1010 */
//europc_jim.mode=AGA_COLOR;
break;
case 0x0e: /* 0000 1100 */
/*80 columns? */
europc_log("EuroPC: AGA 80-column mode!\n");
break;
case 0x0d: /* 0000 1011 */
/*40 columns? */
europc_log("EuroPC: AGA 40-column mode!\n");
break;
default:
//europc_jim.mode=AGA_OFF;
break;
}
break;
case 4: /* CPU Speed control */
switch(val & 0xc0) {
case 0x00: /* 4.77 MHz */
// cpu_set_clockscale(0, 1.0/2);
break;
case 0x40: /* 7.16 MHz */
// cpu_set_clockscale(0, 3.0/4);
break;
default: /* 9.54 MHz */
// cpu_set_clockscale(0, 1);break;
break;
}
break;
default:
break;
}
sys->regs[reg] = val;
}
/* Write to one of the JIM registers. */
static void
jim_write(uint16_t addr, uint8_t val, void *priv)
{
europc_t *sys = (europc_t *)priv;
uint8_t b;
#if EUROPC_DEBUG > 1
europc_log("EuroPC: jim_wr(%04x, %02x)\n", addr, val);
#endif
switch (addr & 0x000f) {
case 0x00: /* JIM internal registers (WRONLY) */
case 0x01:
case 0x02:
case 0x03:
case 0x04: /* JIM internal registers (R/W) */
case 0x05:
case 0x06:
case 0x07:
jim_set(sys, (addr & 0x07), val);
break;
case 0x0a: /* M3002 RTC INDEX/DATA register */
switch(sys->nvr_stat) {
case 0: /* save index */
sys->nvr_addr = val & 0x0f;
sys->nvr_stat++;
break;
case 1: /* save data HI nibble */
b = sys->nvr.regs[sys->nvr_addr] & 0x0f;
b |= (val << 4);
sys->nvr.regs[sys->nvr_addr] = b;
sys->nvr_stat++;
nvr_dosave++;
break;
case 2: /* save data LO nibble */
b = sys->nvr.regs[sys->nvr_addr] & 0xf0;
b |= (val & 0x0f);
sys->nvr.regs[sys->nvr_addr] = b;
sys->nvr_stat = 0;
nvr_dosave++;
break;
}
break;
default:
europc_log("EuroPC: invalid JIM write %02x, val %02x\n", addr, val);
break;
}
}
/* Read from one of the JIM registers. */
static uint8_t
jim_read(uint16_t addr, void *priv)
{
europc_t *sys = (europc_t *)priv;
uint8_t r = 0xff;
switch (addr & 0x000f) {
case 0x00: /* JIM internal registers (WRONLY) */
case 0x01:
case 0x02:
case 0x03:
r = 0x00;
break;
case 0x04: /* JIM internal registers (R/W) */
case 0x05:
case 0x06:
case 0x07:
r = sys->regs[addr & 0x07];
break;
case 0x0a: /* M3002 RTC INDEX/DATA register */
switch(sys->nvr_stat) {
case 0:
r = 0x00;
break;
case 1: /* read data HI nibble */
r = (sys->nvr.regs[sys->nvr_addr] >> 4);
sys->nvr_stat++;
break;
case 2: /* read data LO nibble */
r = (sys->nvr.regs[sys->nvr_addr] & 0x0f);
sys->nvr_stat = 0;
break;
}
break;
default:
europc_log("EuroPC: invalid JIM read %02x\n", addr);
break;
}
#if EUROPC_DEBUG > 1
europc_log("EuroPC: jim_rd(%04x): %02x\n", addr, r);
#endif
return(r);
}
/* Initialize the mainboard 'device' of the machine. */
static void *
europc_boot(const device_t *info)
{
europc_t *sys = &europc;
uint8_t b;
#if EUROPC_DEBUG
europc_log("EuroPC: booting mainboard..\n");
#endif
europc_log("EuroPC: NVR=[ %02x %02x %02x %02x %02x ] %sVALID\n",
sys->nvr.regs[MRTC_CONF_A], sys->nvr.regs[MRTC_CONF_B],
sys->nvr.regs[MRTC_CONF_C], sys->nvr.regs[MRTC_CONF_D],
sys->nvr.regs[MRTC_CONF_E],
(sys->nvr.regs[MRTC_CHECK_LO]!=rtc_checksum(sys->nvr.regs))?"IN":"");
/*
* Now that we have initialized the NVR (either from file,
* or by setting it to defaults) we can start overriding it
* with values set by the user.
*/
b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17);
switch(gfxcard) {
case GFX_CGA: /* Color, CGA */
case GFX_COLORPLUS: /* Color, Hercules ColorPlus */
b |= 0x12; /* external video, CGA80 */
break;
case GFX_MDA: /* Monochrome, MDA */
case GFX_HERCULES: /* Monochrome, Hercules */
case GFX_INCOLOR: /* Color, ? */
b |= 0x03; /* external video, mono */
break;
default: /* EGA, VGA etc */
b |= 0x10; /* external video, special */
}
sys->nvr.regs[MRTC_CONF_D] = b;
/* Update the memory size. */
b = (sys->nvr.regs[MRTC_CONF_C] & 0xf3);
switch(mem_size) {
case 256:
b |= 0x04;
break;
case 512:
b |= 0x08;
break;
case 640:
b |= 0x00;
break;
}
sys->nvr.regs[MRTC_CONF_C] = b;
/* Update CPU speed. */
b = (sys->nvr.regs[MRTC_CONF_D] & 0x3f);
switch(cpu) {
case 0: /* 8088, 4.77 MHz */
b |= 0x00;
break;
case 1: /* 8088, 7.15 MHz */
b |= 0x40;
break;
case 2: /* 8088, 9.56 MHz */
b |= 0x80;
break;
}
sys->nvr.regs[MRTC_CONF_D] = b;
/* Set up game port. */
b = (sys->nvr.regs[MRTC_CONF_C] & 0xfc);
if (mouse_type == MOUSE_TYPE_LOGIBUS) {
b |= 0x01; /* enable port as MOUSE */
} else if (joystick_type != 7) {
b |= 0x02; /* enable port as joysticks */
device_add(&gameport_device);
}
sys->nvr.regs[MRTC_CONF_C] = b;
#if 0
/* Set up floppy types. */
sys->nvr.regs[MRTC_CONF_B] = 0x2a;
#endif
/* Validate the NVR checksum and save. */
sys->nvr.regs[MRTC_CHECK_LO] = rtc_checksum(sys->nvr.regs);
nvr_dosave++;
/*
* Allocate the system's I/O handlers.
*
* The first one is for the JIM. Note that although JIM usually
* resides at 0x0250, a special solder jumper on the mainboard
* (JS9) can be used to "move" it to 0x0350, to get it out of
* the way of other cards that need this range.
*/
io_sethandler(sys->jim, 16,
jim_read,NULL,NULL, jim_write,NULL,NULL, sys);
/* Only after JIM has been initialized. */
(void)device_add(&keyboard_xt_device);
/* Enable and set up the FDC. */
(void)device_add(&fdc_xt_device);
/*
* Set up and enable the HD20 disk controller.
*
* We only do this if we have not configured another one.
*/
if (hdc_current == 1)
(void)device_add(&xta_hd20_device);
return(sys);
}
static void
europc_close(void *priv)
{
nvr_t *nvr = &europc.nvr;
if (nvr->fn != NULL)
free(nvr->fn);
}
static const device_config_t europc_config[] = {
{
"js9", "JS9 Jumper (JIM)", CONFIG_INT, "", 0,
{
{
"Disabled (250h)", 0
},
{
"Enabled (350h)", 1
},
{
""
}
},
},
{
"", "", -1
}
};
const device_t europc_device = {
"EuroPC System Board",
0, 0,
europc_boot, europc_close, NULL,
NULL, NULL, NULL,
europc_config
};
/*
* This function sets up the Scheider EuroPC machine.
*
* Its task is to allocate a clean machine data block,
* and then simply enable the mainboard "device" which
* allows it to reset (dev init) and configured by the
* user.
*/
void
machine_europc_init(const machine_t *model)
{
machine_common_init(model);
nmi_init();
/* Clear the machine state. */
memset(&europc, 0x00, sizeof(europc_t));
europc.jim = 0x0250;
mem_add_bios();
/* This is machine specific. */
europc.nvr.size = model->nvrmask + 1;
europc.nvr.irq = -1;
/* Set up any local handlers here. */
europc.nvr.reset = rtc_reset;
europc.nvr.start = rtc_start;
europc.nvr.tick = europc_rtc_tick;
/* Initialize the actual NVR. */
nvr_init(&europc.nvr);
/* Enable and set up the mainboard device. */
device_add(&europc_device);
}

View File

@@ -0,0 +1,572 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Emulation of the IBM PS/1 models 2011, 2121 and 2133.
*
* Model 2011: The initial model, using a 10MHz 80286.
*
* Model 2121: This is similar to model 2011 but some of the functionality
* has moved to a chip at ports 0xe0 (index)/0xe1 (data). The
* only functions I have identified are enables for the first
* 512K and next 128K of RAM, in bits 0 of registers 0 and 1
* respectively.
*
* Port 0x105 has bit 7 forced high. Without this 128K of
* memory will be missed by the BIOS on cold boots.
*
* The reserved 384K is remapped to the top of extended memory.
* If this is not done then you get an error on startup.
*
* NOTES: Floppy does not seem to work. --FvK
* The "ROM DOS" shell does not seem to work. We do have the
* correct BIOS images now, and they do load, but they do not
* boot. Sometimes, they do, and then it shows an "Incorrect
* DOS" error message?? --FvK
*
* Version: @(#)m_ps1.c 1.0.11 2018/09/15
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2008-2018 Sarah Walker.
* Copyright 2016-2018 Miran Grca.
* Copyright 2017,2018 Fred N. van Kempen.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../cpu/cpu.h"
#include "../io.h"
#include "../dma.h"
#include "../pic.h"
#include "../pit.h"
#include "../mem.h"
#include "../nmi.h"
#include "../rom.h"
#include "../timer.h"
#include "../device.h"
#include "../nvr.h"
#include "../game/gameport.h"
#include "../lpt.h"
#include "../serial.h"
#include "../keyboard.h"
#include "../disk/hdc.h"
#include "../disk/hdc_ide.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../sound/sound.h"
#include "../sound/snd_sn76489.h"
#include "../video/video.h"
#include "../video/vid_vga.h"
#include "../video/vid_ti_cf62011.h"
#include "machine.h"
typedef struct {
sn76489_t sn76489;
uint8_t status, ctrl;
int64_t timer_latch, timer_count, timer_enable;
uint8_t fifo[2048];
int fifo_read_idx, fifo_write_idx;
int fifo_threshold;
uint8_t dac_val;
int16_t buffer[SOUNDBUFLEN];
int pos;
} ps1snd_t;
typedef struct {
int model;
rom_t high_rom;
uint8_t ps1_91,
ps1_92,
ps1_94,
ps1_102,
ps1_103,
ps1_104,
ps1_105,
ps1_190;
int ps1_e0_addr;
uint8_t ps1_e0_regs[256];
} ps1_t;
static void
update_irq_status(ps1snd_t *snd)
{
if (((snd->status & snd->ctrl) & 0x12) && (snd->ctrl & 0x01))
picint(1 << 7);
else
picintc(1 << 7);
}
static uint8_t
snd_read(uint16_t port, void *priv)
{
ps1snd_t *snd = (ps1snd_t *)priv;
uint8_t ret = 0xff;
switch (port & 7) {
case 0: /* ADC data */
snd->status &= ~0x10;
update_irq_status(snd);
ret = 0;
break;
case 2: /* status */
ret = snd->status;
ret |= (snd->ctrl & 0x01);
if ((snd->fifo_write_idx - snd->fifo_read_idx) >= 2048)
ret |= 0x08; /* FIFO full */
if (snd->fifo_read_idx == snd->fifo_write_idx)
ret |= 0x04; /* FIFO empty */
break;
case 3: /* FIFO timer */
/*
* The PS/1 Technical Reference says this should return
* thecurrent value, but the PS/1 BIOS and Stunt Island
* expect it not to change.
*/
ret = snd->timer_latch;
break;
case 4:
case 5:
case 6:
case 7:
ret = 0;
}
return(ret);
}
static void
snd_write(uint16_t port, uint8_t val, void *priv)
{
ps1snd_t *snd = (ps1snd_t *)priv;
switch (port & 7) {
case 0: /* DAC output */
if ((snd->fifo_write_idx - snd->fifo_read_idx) < 2048) {
snd->fifo[snd->fifo_write_idx & 2047] = val;
snd->fifo_write_idx++;
}
break;
case 2: /* control */
snd->ctrl = val;
if (! (val & 0x02))
snd->status &= ~0x02;
update_irq_status(snd);
break;
case 3: /* timer reload value */
snd->timer_latch = val;
snd->timer_count = (int64_t) ((0xff-val) * TIMER_USEC);
snd->timer_enable = (val != 0);
break;
case 4: /* almost empty */
snd->fifo_threshold = val * 4;
break;
}
}
static void
snd_update(ps1snd_t *snd)
{
for (; snd->pos < sound_pos_global; snd->pos++)
snd->buffer[snd->pos] = (int8_t)(snd->dac_val ^ 0x80) * 0x20;
}
static void
snd_callback(void *priv)
{
ps1snd_t *snd = (ps1snd_t *)priv;
snd_update(snd);
if (snd->fifo_read_idx != snd->fifo_write_idx) {
snd->dac_val = snd->fifo[snd->fifo_read_idx & 2047];
snd->fifo_read_idx++;
}
if ((snd->fifo_write_idx - snd->fifo_read_idx) == snd->fifo_threshold)
snd->status |= 0x02; /*FIFO almost empty*/
snd->status |= 0x10; /*ADC data ready*/
update_irq_status(snd);
snd->timer_count += snd->timer_latch * TIMER_USEC;
}
static void
snd_get_buffer(int32_t *buffer, int len, void *priv)
{
ps1snd_t *snd = (ps1snd_t *)priv;
int c;
snd_update(snd);
for (c = 0; c < len * 2; c++)
buffer[c] += snd->buffer[c >> 1];
snd->pos = 0;
}
static void *
snd_init(const device_t *info)
{
ps1snd_t *snd;
snd = malloc(sizeof(ps1snd_t));
memset(snd, 0x00, sizeof(ps1snd_t));
sn76489_init(&snd->sn76489, 0x0205, 0x0001, SN76496, 4000000);
io_sethandler(0x0200, 1, snd_read,NULL,NULL, snd_write,NULL,NULL, snd);
io_sethandler(0x0202, 6, snd_read,NULL,NULL, snd_write,NULL,NULL, snd);
timer_add(snd_callback, &snd->timer_count, &snd->timer_enable, snd);
sound_add_handler(snd_get_buffer, snd);
return(snd);
}
static void
snd_close(void *priv)
{
ps1snd_t *snd = (ps1snd_t *)priv;
free(snd);
}
static const device_t snd_device = {
"PS/1 Audio Card",
0, 0,
snd_init, snd_close, NULL,
NULL,
NULL,
NULL
};
static void
recalc_memory(ps1_t *ps)
{
/* Enable first 512K */
mem_set_mem_state(0x00000, 0x80000,
(ps->ps1_e0_regs[0] & 0x01) ?
(MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) :
(MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL));
/* Enable 512-640K */
mem_set_mem_state(0x80000, 0x20000,
(ps->ps1_e0_regs[1] & 0x01) ?
(MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) :
(MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL));
}
static void
ps1_write(uint16_t port, uint8_t val, void *priv)
{
ps1_t *ps = (ps1_t *)priv;
switch (port) {
case 0x0092:
if (ps->model != 2011) {
if (val & 1) {
softresetx86();
cpu_set_edx();
}
ps->ps1_92 = val & ~1;
} else {
ps->ps1_92 = val;
}
mem_a20_alt = val & 2;
mem_a20_recalc();
break;
case 0x0094:
ps->ps1_94 = val;
break;
case 0x00e0:
if (ps->model != 2011) {
ps->ps1_e0_addr = val;
}
break;
case 0x00e1:
if (ps->model != 2011) {
ps->ps1_e0_regs[ps->ps1_e0_addr] = val;
recalc_memory(ps);
}
break;
case 0x0102:
lpt1_remove();
if (val & 0x04)
serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ);
else
serial_remove(1);
if (val & 0x10) {
switch ((val >> 5) & 3) {
case 0:
lpt1_init(0x03bc);
break;
case 1:
lpt1_init(0x0378);
break;
case 2:
lpt1_init(0x0278);
break;
}
}
ps->ps1_102 = val;
break;
case 0x0103:
ps->ps1_103 = val;
break;
case 0x0104:
ps->ps1_104 = val;
break;
case 0x0105:
ps->ps1_105 = val;
break;
case 0x0190:
ps->ps1_190 = val;
break;
}
}
static uint8_t
ps1_read(uint16_t port, void *priv)
{
ps1_t *ps = (ps1_t *)priv;
uint8_t ret = 0xff;
switch (port) {
case 0x0091:
ret = ps->ps1_91;
ps->ps1_91 = 0;
break;
case 0x0092:
ret = ps->ps1_92;
break;
case 0x0094:
ret = ps->ps1_94;
break;
case 0x00e1:
if (ps->model != 2011) {
ret = ps->ps1_e0_regs[ps->ps1_e0_addr];
}
break;
case 0x0102:
if (ps->model == 2011)
ret = ps->ps1_102 | 0x08;
else
ret = ps->ps1_102;
break;
case 0x0103:
ret = ps->ps1_103;
break;
case 0x0104:
ret = ps->ps1_104;
break;
case 0x0105:
if (ps->model == 2011)
ret = ps->ps1_105;
else
ret = ps->ps1_105 | 0x80;
break;
case 0x0190:
ret = ps->ps1_190;
break;
default:
break;
}
return(ret);
}
static void
ps1_setup(int model)
{
ps1_t *ps;
void *priv;
ps = (ps1_t *)malloc(sizeof(ps1_t));
memset(ps, 0x00, sizeof(ps1_t));
ps->model = model;
io_sethandler(0x0091, 1,
ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps);
io_sethandler(0x0092, 1,
ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps);
io_sethandler(0x0094, 1,
ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps);
io_sethandler(0x0102, 4,
ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps);
io_sethandler(0x0190, 1,
ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps);
lpt1_remove();
lpt1_init(0x3bc);
if (model == 2011) {
rom_init(&ps->high_rom,
L"roms/machines/ibmps1es/f80000.bin",
0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL);
lpt2_remove();
serial_remove(1);
serial_remove(2);
/* Enable the PS/1 VGA controller. */
if (model == 2011)
device_add(&ps1vga_device);
else
device_add(&ibm_ps1_2121_device);
device_add(&snd_device);
device_add(&fdc_at_actlow_device);
/* Enable the builtin HDC. */
if (hdc_current == 1) {
priv = device_add(&ps1_hdc_device);
ps1_hdc_inform(priv, ps);
}
mem_mapping_add(&romext_mapping, 0xc8000, 0x08000,
mem_read_romext,mem_read_romextw,mem_read_romextl,
NULL,NULL, NULL, romext, 0, NULL);
}
if (model == 2121) {
io_sethandler(0x00e0, 2,
ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps);
#if 0
rom_init(&ps->high_rom,
L"roms/machines/ibmps1_2121/fc0000.bin",
0xfc0000, 0x20000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL);
#endif
/* Initialize the video controller. */
if (gfxcard == GFX_INTERNAL)
device_add(&ibm_ps1_2121_device);
device_add(&fdc_at_ps1_device);
device_add(&ide_isa_device);
device_add(&snd_device);
}
if (model == 2133) {
device_add(&fdc_at_device);
device_add(&ide_isa_device);
}
}
static void
ps1_common_init(const machine_t *model)
{
machine_common_init(model);
mem_remap_top(384);
pit_set_out_func(&pit, 1, pit_refresh_timer_at);
dma16_init();
pic2_init();
device_add(&ps_nvr_device);
device_add(&keyboard_ps2_device);
/* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */
if (joystick_type != 7)
device_add(&gameport_201_device);
}
/* Set the Card Selected Flag */
void
ps1_set_feedback(void *priv)
{
ps1_t *ps = (ps1_t *)priv;
ps->ps1_91 |= 0x01;
}
void
machine_ps1_m2011_init(const machine_t *model)
{
ps1_common_init(model);
ps1_setup(2011);
}
void
machine_ps1_m2121_init(const machine_t *model)
{
ps1_common_init(model);
ps1_setup(2121);
}
void
machine_ps1_m2133_init(const machine_t *model)
{
ps1_common_init(model);
ps1_setup(2133);
nmi_mask = 0x80;
}

File diff suppressed because it is too large Load Diff