Files
86Box/src/machine/m_xt_t1000.c

1108 lines
25 KiB
C
Raw Normal View History

2018-03-13 03:46:10 +01:00
/*
* 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 Toshiba T1000 and T1200 portables.
*
* The T1000 is the T3100e's little brother -- a real laptop
* with a rechargeable battery.
*
* Features: 80C88 at 4.77MHz
* - 512k system RAM
* - 640x200 monochrome LCD
* - 82-key keyboard
* - Real-time clock. Not the normal 146818, but a TC8521,
* which is a 4-bit chip.
* - A ROM drive (128k, 256k or 512k) which acts as a mini
* hard drive and contains a copy of DOS 2.11.
* - 160 bytes of non-volatile RAM for the CONFIG.SYS used
* when booting from the ROM drive. Possibly physically
* located in the keyboard controller RAM.
*
* An optional memory expansion board can be fitted. This adds
* 768k of RAM, which can be used for up to three purposes:
* > Conventional memory -- 128k between 512k and 640k
* > HardRAM -- a battery-backed RAM drive.
* > EMS
*
* This means that there are up to three different
* implementations of non-volatile RAM in the same computer
* (52 nibbles in the TC8521, 160 bytes of CONFIG.SYS, and
* up to 768k of HardRAM).
*
* The T1200 is a slightly upgraded version with a turbo mode
* (double CPU clock, 9.54MHz) and an optional hard drive.
* The interface for this is proprietary both at the physical
* and programming level.
*
* 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb]
* or 0Dh [10Mb].
*
* The hard drive is a 20MB (615/2/26) RLL 3.5" drive.
*
* The TC8521 is a 4-bit RTC, so each memory location can only
* hold a single BCD digit. Hence everything has 'ones' and
* 'tens' digits.
*
* NOTE: Still need to figure out a way to load/save ConfigSys and
* HardRAM stuff. Needs to be linked in to the NVR code.
*
* Version: @(#)m_xt_t1000.c 1.0.11 2018/09/15
2018-03-13 03:46:10 +01:00
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2018 Fred N. van Kempen.
* Copyright 2018 Miran Grca.
* Copyright 2018 Sarah Walker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
*/
#include <stdarg.h>
2018-03-13 03:46:10 +01:00
#include <stdint.h>
#include <stdio.h>
2018-03-13 03:46:10 +01:00
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <time.h>
#define HAVE_STDARG_H
2018-03-13 03:46:10 +01:00
#include "../86box.h"
#include "../cpu/cpu.h"
#include "../io.h"
#include "../pit.h"
#include "../nmi.h"
#include "../mem.h"
#include "../rom.h"
#include "../device.h"
#include "../nvr.h"
2018-03-13 03:46:10 +01:00
#include "../keyboard.h"
#include "../lpt.h"
#include "../mem.h"
2018-03-13 03:46:10 +01:00
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../game/gameport.h"
#include "../video/video.h"
#include "../plat.h"
#include "machine.h"
#include "m_xt_t1000.h"
#define T1000_ROMSIZE (512*1024UL) /* Maximum ROM drive size is 512k */
enum TC8521_ADDR {
/* Page 0 registers */
TC8521_SECOND1 = 0,
TC8521_SECOND10,
TC8521_MINUTE1,
TC8521_MINUTE10,
TC8521_HOUR1,
TC8521_HOUR10,
TC8521_WEEKDAY,
TC8521_DAY1,
TC8521_DAY10,
TC8521_MONTH1,
TC8521_MONTH10,
TC8521_YEAR1,
TC8521_YEAR10,
TC8521_PAGE, /* PAGE register */
TC8521_TEST, /* TEST register */
TC8521_RESET, /* RESET register */
/* Page 1 registers */
TC8521_24HR = 0x1A,
TC8521_LEAPYEAR = 0x1B
};
typedef struct {
/* ROM drive */
uint8_t *romdrive;
uint8_t rom_ctl;
uint32_t rom_offset;
mem_mapping_t rom_mapping;
/* CONFIG.SYS drive. */
uint8_t t1000_nvram[160];
uint8_t t1200_nvram[2048];
2018-03-13 03:46:10 +01:00
/* System control registers */
uint8_t sys_ctl[16];
uint8_t syskeys;
uint8_t turbo;
/* NVRAM control */
uint8_t nvr_c0;
uint8_t nvr_tick;
int nvr_addr;
uint8_t nvr_active;
mem_mapping_t nvr_mapping; /* T1200 NVRAM mapping */
2018-03-13 03:46:10 +01:00
/* EMS data */
uint8_t ems_reg[4];
mem_mapping_t mapping[4];
uint32_t page_exec[4];
uint8_t ems_port_index;
uint16_t ems_port;
uint8_t is_640k;
uint32_t ems_base;
int32_t ems_pages;
fdc_t *fdc;
nvr_t nvr;
int is_t1200;
2018-03-13 03:46:10 +01:00
} t1000_t;
static t1000_t t1000;
#ifdef ENABLE_T1000_LOG
int t1000_do_log = ENABLE_T1000_LOG;
#endif
static void
t1000_log(const char *fmt, ...)
{
#ifdef ENABLE_TANDY_LOG
va_list ap;
if (t1000_do_log)
{
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
#endif
}
2018-03-13 03:46:10 +01:00
/* Set the chip time. */
static void
tc8521_time_set(uint8_t *regs, struct tm *tm)
{
regs[TC8521_SECOND1] = (tm->tm_sec % 10);
regs[TC8521_SECOND10] = (tm->tm_sec / 10);
regs[TC8521_MINUTE1] = (tm->tm_min % 10);
regs[TC8521_MINUTE10] = (tm->tm_min / 10);
if (regs[TC8521_24HR] & 0x01) {
regs[TC8521_HOUR1] = (tm->tm_hour % 10);
regs[TC8521_HOUR10] = (tm->tm_hour / 10);
} else {
regs[TC8521_HOUR1] = ((tm->tm_hour % 12) % 10);
regs[TC8521_HOUR10] = (((tm->tm_hour % 12) / 10) |
((tm->tm_hour >= 12) ? 2 : 0));
}
regs[TC8521_WEEKDAY] = tm->tm_wday;
regs[TC8521_DAY1] = (tm->tm_mday % 10);
regs[TC8521_DAY10] = (tm->tm_mday / 10);
regs[TC8521_MONTH1] = ((tm->tm_mon + 1) % 10);
regs[TC8521_MONTH10] = ((tm->tm_mon + 1) / 10);
regs[TC8521_YEAR1] = ((tm->tm_year - 80) % 10);
regs[TC8521_YEAR10] = (((tm->tm_year - 80) % 100) / 10);
}
/* Get the chip time. */
#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)])
static void
tc8521_time_get(uint8_t *regs, struct tm *tm)
{
tm->tm_sec = nibbles(TC8521_SECOND);
tm->tm_min = nibbles(TC8521_MINUTE);
if (regs[TC8521_24HR] & 0x01)
tm->tm_hour = nibbles(TC8521_HOUR);
else
tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) +
(regs[TC8521_HOUR10] & 0x02) ? 12 : 0);
//FIXME: wday
tm->tm_mday = nibbles(TC8521_DAY);
tm->tm_mon = (nibbles(TC8521_MONTH) - 1);
tm->tm_year = (nibbles(TC8521_YEAR) + 1980);
}
/* This is called every second through the NVR/RTC hook. */
static void
tc8521_tick(nvr_t *nvr)
{
t1000_log("TC8521: ping\n");
2018-03-13 03:46:10 +01:00
}
static void
tc8521_start(nvr_t *nvr)
{
struct tm tm;
/* Initialize the internal and chip times. */
if (time_sync & TIME_SYNC_ENABLED) {
2018-03-13 03:46:10 +01:00
/* Use the internal clock's time. */
nvr_time_get(&tm);
tc8521_time_set(nvr->regs, &tm);
} else {
/* Set the internal clock from the chip time. */
tc8521_time_get(nvr->regs, &tm);
nvr_time_set(&tm);
}
#if 0
/* Start the RTC - BIOS will do this. */
nvr->regs[TC8521_PAGE] |= 0x80;
#endif
}
/* Write to one of the chip registers. */
static void
tc8521_write(uint16_t addr, uint8_t val, void *priv)
{
nvr_t *nvr = (nvr_t *)priv;
uint8_t page;
/* Get to the correct register page. */
addr &= 0x0f;
page = nvr->regs[0x0d] & 0x03;
if (addr < 0x0d)
addr += (16 * page);
if (addr >= 0x10 && nvr->regs[addr] != val)
nvr_dosave = 1;
/* Store the new value. */
nvr->regs[addr] = val;
}
/* Read from one of the chip registers. */
static uint8_t
tc8521_read(uint16_t addr, void *priv)
{
nvr_t *nvr = (nvr_t *)priv;
uint8_t page;
/* Get to the correct register page. */
addr &= 0x0f;
page = nvr->regs[0x0d] & 0x03;
if (addr < 0x0d)
addr += (16 * page);
/* Grab and return the desired value. */
return(nvr->regs[addr]);
}
/* Reset the 8521 to a default state. */
static void
tc8521_reset(nvr_t *nvr)
{
/* Clear the NVRAM. */
memset(nvr->regs, 0xff, nvr->size);
/* Reset the RTC registers. */
memset(nvr->regs, 0x00, 16);
nvr->regs[TC8521_WEEKDAY] = 0x01;
nvr->regs[TC8521_DAY1] = 0x01;
nvr->regs[TC8521_MONTH1] = 0x01;
}
static void
tc8521_init(nvr_t *nvr, int size)
{
/* This is machine specific. */
nvr->size = size;
nvr->irq = -1;
/* Set up any local handlers here. */
nvr->reset = tc8521_reset;
nvr->start = tc8521_start;
nvr->tick = tc8521_tick;
/* Initialize the actual NVR. */
nvr_init(nvr);
io_sethandler(0x02c0, 16,
tc8521_read,NULL,NULL, tc8521_write,NULL,NULL, nvr);
}
/* Given an EMS page ID, return its physical address in RAM. */
static uint32_t
ems_execaddr(t1000_t *sys, int pg, uint16_t val)
{
if (!(val & 0x80)) return(0); /* Bit 7 reset => not mapped */
if (!sys->ems_pages) return(0); /* No EMS available: all used by
* HardRAM or conventional RAM */
val &= 0x7f;
#if 0
t1000_log("Select EMS page: %d of %d\n", val, sys->ems_pages);
2018-03-13 03:46:10 +01:00
#endif
if (val < sys->ems_pages) {
/* EMS is any memory above 512k,
with ems_base giving the start address */
return((512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val));
}
return(0);
}
static uint8_t
ems_in(uint16_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
#if 0
t1000_log("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]);
2018-03-13 03:46:10 +01:00
#endif
return(sys->ems_reg[(addr >> 14) & 3]);
}
static void
ems_out(uint16_t addr, uint8_t val, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
int pg = (addr >> 14) & 3;
#if 0
t1000_log("ems_out(%04x, %02x) pg=%d\n", addr, val, pg);
2018-03-13 03:46:10 +01:00
#endif
sys->ems_reg[pg] = val;
sys->page_exec[pg] = ems_execaddr(sys, pg, val);
if (sys->page_exec[pg]) {
/* Page present */
mem_mapping_enable(&sys->mapping[pg]);
mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]);
} else {
mem_mapping_disable(&sys->mapping[pg]);
}
}
/* Hardram size is in 64k units */
static void
ems_set_hardram(t1000_t *sys, uint8_t val)
{
int n;
val &= 0x1f; /* Mask off pageframe address */
if (val && mem_size > 512)
sys->ems_base = val;
else
sys->ems_base = 0;
#if 0
t1000_log("EMS base set to %02x\n", val);
2018-03-13 03:46:10 +01:00
#endif
sys->ems_pages = ((mem_size - 512) / 16) - 4 * sys->ems_base;
2018-03-13 03:46:10 +01:00
if (sys->ems_pages < 0) sys->ems_pages = 0;
/* Recalculate EMS mappings */
for (n = 0; n < 4; n++)
ems_out(n << 14, sys->ems_reg[n], sys);
}
static void
ems_set_640k(t1000_t *sys, uint8_t val)
{
if (val && mem_size >= 640) {
mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024);
sys->is_640k = 1;
} else {
mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024);
sys->is_640k = 0;
}
}
static void
ems_set_port(t1000_t *sys, uint8_t val)
{
int n;
#if 0
t1000_log("ems_set_port(%d)", val & 0x0f);
#endif
2018-03-13 03:46:10 +01:00
if (sys->ems_port) {
for (n = 0; n <= 0xc000; n += 0x4000) {
io_removehandler(sys->ems_port+n, 1,
ems_in,NULL,NULL, ems_out,NULL,NULL, sys);
}
sys->ems_port = 0;
}
val &= 0x0f;
sys->ems_port_index = val;
if (val == 7) {
/* No EMS */
sys->ems_port = 0;
} else {
sys->ems_port = 0x208 | (val << 4);
for (n = 0; n <= 0xc000; n += 0x4000) {
io_sethandler(sys->ems_port+n, 1,
ems_in,NULL,NULL, ems_out,NULL,NULL, sys);
}
sys->ems_port = 0;
}
#if 0
t1000_log(" -> %04x\n", sys->ems_port);
2018-03-13 03:46:10 +01:00
#endif
}
static int
addr_to_page(uint32_t addr)
{
return((addr - 0xd0000) / 0x4000);
}
/* Read RAM in the EMS page frame. */
static uint8_t
ems_read_ram(uint32_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
int pg = addr_to_page(addr);
if (pg < 0) return(0xff);
addr = sys->page_exec[pg] + (addr & 0x3fff);
return(ram[addr]);
}
static uint16_t
ems_read_ramw(uint32_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
int pg = addr_to_page(addr);
if (pg < 0) return(0xff);
#if 0
t1000_log("ems_read_ramw addr=%05x ", addr);
2018-03-13 03:46:10 +01:00
#endif
addr = sys->page_exec[pg] + (addr & 0x3FFF);
#if 0
t1000_log("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]);
2018-03-13 03:46:10 +01:00
#endif
return(*(uint16_t *)&ram[addr]);
}
static uint32_t
ems_read_raml(uint32_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
int pg = addr_to_page(addr);
if (pg < 0) return(0xff);
addr = sys->page_exec[pg] + (addr & 0x3fff);
return(*(uint32_t *)&ram[addr]);
}
/* Write RAM in the EMS page frame. */
static void
ems_write_ram(uint32_t addr, uint8_t val, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
int pg = addr_to_page(addr);
if (pg < 0) return;
addr = sys->page_exec[pg] + (addr & 0x3fff);
if (ram[addr] != val) nvr_dosave = 1;
ram[addr] = val;
}
static void
ems_write_ramw(uint32_t addr, uint16_t val, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
int pg = addr_to_page(addr);
if (pg < 0) return;
#if 0
t1000_log("ems_write_ramw addr=%05x ", addr);
2018-03-13 03:46:10 +01:00
#endif
addr = sys->page_exec[pg] + (addr & 0x3fff);
#if 0
t1000_log("-> %06x val=%04x\n", addr, val);
2018-03-13 03:46:10 +01:00
#endif
if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1;
*(uint16_t *)&ram[addr] = val;
}
static void
ems_write_raml(uint32_t addr, uint32_t val, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
int pg = addr_to_page(addr);
if (pg < 0) return;
addr = sys->page_exec[pg] + (addr & 0x3fff);
if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1;
*(uint32_t *)&ram[addr] = val;
}
static uint8_t
read_ctl(uint16_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
uint8_t ret = 0xff;
switch (addr & 0x0f) {
case 1:
ret = sys->syskeys;
break;
case 0x0f: /* Detect EMS board */
switch (sys->sys_ctl[0x0e]) {
case 0x50:
if (mem_size > 512) break;
ret = (0x90 | sys->ems_port_index);
break;
case 0x51:
/* 0x60 is the page frame address:
(0xd000 - 0xc400) / 0x20 */
ret = (sys->ems_base | 0x60);
break;
case 0x52:
ret = (sys->is_640k ? 0x80 : 0);
break;
}
break;
default:
ret = (sys->sys_ctl[addr & 0x0f]);
}
return(ret);
}
static void
t1200_turbo_set(uint8_t value)
{
if (value == t1000.turbo) return;
t1000.turbo = value;
if (! value)
cpu_dynamic_switch(0);
else
cpu_dynamic_switch(cpu);
}
static void
write_ctl(uint16_t addr, uint8_t val, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
sys->sys_ctl[addr & 0x0f] = val;
switch (addr & 0x0f) {
case 4: /* Video control */
if (sys->sys_ctl[3] == 0x5A) {
t1000_video_options_set((val & 0x20) ? 1 : 0);
t1000_display_set((val & 0x40) ? 0 : 1);
if (sys->is_t1200)
2018-03-13 03:46:10 +01:00
t1200_turbo_set((val & 0x80) ? 1 : 0);
}
break;
/* It looks as if the T1200, like the T3100, can disable
* its builtin video chipset if it detects the presence of
* another video card. */
case 6: if (sys->is_t1200)
{
t1000_video_enable(val & 0x01 ? 0 : 1);
}
break;
2018-03-13 03:46:10 +01:00
case 0x0f: /* EMS control */
switch (sys->sys_ctl[0x0e]) {
case 0x50:
ems_set_port(sys, val);
break;
case 0x51:
ems_set_hardram(sys, val);
break;
case 0x52:
ems_set_640k(sys, val);
break;
}
break;
}
}
/* Ports 0xC0 to 0xC3 appear to have two purposes:
*
* > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS
* > Reading the floppy changeline. I don't know why the Toshiba doesn't
* use the normal port 0x3F7 for this, but it doesn't.
*
*/
static uint8_t
t1000_read_nvram(uint16_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
uint8_t tmp = 0xff;
switch (addr) {
case 0xc2: /* Read next byte from NVRAM */
if (sys->nvr_addr >= 0 && sys->nvr_addr < 160)
tmp = sys->t1000_nvram[sys->nvr_addr];
2018-03-13 03:46:10 +01:00
sys->nvr_addr++;
break;
case 0xc3: /* Read floppy changeline and NVRAM ready state */
tmp = fdc_read(0x03f7, t1000.fdc);
tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */
tmp |= (sys->nvr_active & 0xc0);/* Bits 6,7 are r/w mode */
tmp |= 0x2e; /* Bits 5,3,2,1 always 1 */
tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */
break;
}
return(tmp);
}
static void
t1000_write_nvram(uint16_t addr, uint8_t val, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
/*
* On the real T1000, port 0xC1 is only usable as the high byte
* of a 16-bit write to port 0xC0, with 0x5A in the low byte.
*/
switch (addr) {
case 0xc0:
sys->nvr_c0 = val;
break;
case 0xc1: /* Write next byte to NVRAM */
if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) {
if (sys->t1000_nvram[sys->nvr_addr] != val)
2018-03-13 03:46:10 +01:00
nvr_dosave = 1;
sys->t1000_nvram[sys->nvr_addr] = val;
2018-03-13 03:46:10 +01:00
}
sys->nvr_addr++;
break;
case 0xc2:
break;
case 0xc3:
/*
* At start of NVRAM read / write, 0x80 is written to
* port 0xC3. This seems to reset the NVRAM address
* counter. A single byte is then written (0xff for
* write, 0x00 for read) which appears to be ignored.
* Simulate that by starting the address counter off
* at -1.
*/
sys->nvr_active = val;
if (val == 0x80) sys->nvr_addr = -1;
break;
}
}
static
uint8_t read_t1200_nvram(uint32_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
return sys->t1200_nvram[addr & 0x7FF];
}
static void write_t1200_nvram(uint32_t addr, uint8_t value, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
if (sys->t1200_nvram[addr & 0x7FF] != value)
nvr_dosave = 1;
sys->t1200_nvram[addr & 0x7FF] = value;
}
2018-03-13 03:46:10 +01:00
/* Port 0xC8 controls the ROM drive */
static uint8_t
t1000_read_rom_ctl(uint16_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
return(sys->rom_ctl);
}
static void
t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
sys->rom_ctl = val;
if (sys->romdrive && (val & 0x80)) {
/* Enable */
sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE;
mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000);
mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset);
mem_mapping_enable(&sys->rom_mapping);
} else {
mem_mapping_disable(&sys->rom_mapping);
}
}
/* Read the ROM drive */
static uint8_t
t1000_read_rom(uint32_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
if (! sys->romdrive) return(0xff);
return(sys->romdrive[sys->rom_offset + (addr & 0xffff)]);
}
static uint16_t
t1000_read_romw(uint32_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
if (! sys->romdrive) return(0xffff);
return(*(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)]));
}
static uint32_t
t1000_read_roml(uint32_t addr, void *priv)
{
t1000_t *sys = (t1000_t *)priv;
if (! sys->romdrive) return(0xffffffff);
return(*(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)]));
}
const device_t *
2018-03-13 03:46:10 +01:00
t1000_get_device(void)
{
return(&t1000_video_device);
}
void
machine_xt_t1000_init(const machine_t *model)
2018-03-13 03:46:10 +01:00
{
FILE *f;
int pg;
memset(&t1000, 0x00, sizeof(t1000));
t1000.is_t1200 = 0;
2018-03-13 03:46:10 +01:00
t1000.turbo = 0xff;
t1000.ems_port_index = 7; /* EMS disabled */
/* Load the T1000 CGA Font ROM. */
loadfont(L"roms/machines/t1000/t1000font.rom", 2);
/*
* The ROM drive is optional.
*
* If the file is missing, continue to boot; the BIOS will
* complain 'No ROM drive' but boot normally from floppy.
*/
f = rom_fopen(L"roms/machines/t1000/t1000dos.rom", L"rb");
if (f != NULL) {
t1000.romdrive = malloc(T1000_ROMSIZE);
if (t1000.romdrive) {
memset(t1000.romdrive, 0xff, T1000_ROMSIZE);
fread(t1000.romdrive, T1000_ROMSIZE, 1, f);
}
fclose(f);
}
mem_mapping_add(&t1000.rom_mapping, 0xa0000, 0x10000,
t1000_read_rom,t1000_read_romw,t1000_read_roml,
NULL,NULL,NULL, NULL, MEM_MAPPING_INTERNAL, &t1000);
mem_mapping_disable(&t1000.rom_mapping);
/* Map the EMS page frame */
for (pg = 0; pg < 4; pg++) {
mem_mapping_add(&t1000.mapping[pg], 0xd0000 + (0x4000 * pg), 16384,
ems_read_ram,ems_read_ramw,ems_read_raml,
ems_write_ram,ems_write_ramw,ems_write_raml,
NULL, MEM_MAPPING_EXTERNAL, &t1000);
/* Start them all off disabled */
mem_mapping_disable(&t1000.mapping[pg]);
}
/* Non-volatile RAM for CONFIG.SYS */
io_sethandler(0xc0, 4,
t1000_read_nvram,NULL,NULL,
t1000_write_nvram,NULL,NULL, &t1000);
/* ROM drive */
io_sethandler(0xc8, 1,
t1000_read_rom_ctl,NULL,NULL,
t1000_write_rom_ctl,NULL,NULL, &t1000);
/* System control functions, and add-on memory board */
io_sethandler(0xe0, 16,
read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000);
machine_common_init(model);
pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
device_add(&keyboard_xt_device);
t1000.fdc = device_add(&fdc_xt_device);
nmi_init();
tc8521_init(&t1000.nvr, model->nvrmask + 1);
t1000_nvr_load();
nvr_set_ven_save(t1000_nvr_save);
if (gfxcard == GFX_INTERNAL)
device_add(&t1000_video_device);
2018-03-13 03:46:10 +01:00
}
const device_t *
2018-03-13 03:46:10 +01:00
t1200_get_device(void)
{
return(&t1200_video_device);
}
void
machine_xt_t1200_init(const machine_t *model)
2018-03-13 03:46:10 +01:00
{
int pg;
memset(&t1000, 0x00, sizeof(t1000));
t1000.is_t1200 = 1;
2018-03-13 03:46:10 +01:00
t1000.ems_port_index = 7; /* EMS disabled */
/* Load the T1200 CGA Font ROM. */
loadfont(L"roms/machines/t1200/t1000font.bin", 2);
/* Map the EMS page frame */
for (pg = 0; pg < 4; pg++) {
mem_mapping_add(&t1000.mapping[pg],
0xd0000 + (0x4000 * pg), 16384,
ems_read_ram,ems_read_ramw,ems_read_raml,
ems_write_ram,ems_write_ramw,ems_write_raml,
NULL, MEM_MAPPING_EXTERNAL, &t1000);
/* Start them all off disabled */
mem_mapping_disable(&t1000.mapping[pg]);
}
/* System control functions, and add-on memory board */
io_sethandler(0xe0, 16,
read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000);
machine_common_init(model);
mem_mapping_add(&t1000.nvr_mapping,
0x000f0000, 2048,
read_t1200_nvram, NULL, NULL,
write_t1200_nvram, NULL, NULL,
NULL, 0, &t1000);
2018-03-13 03:46:10 +01:00
pit_set_out_func(&pit, 1, pit_refresh_timer_xt);
device_add(&keyboard_xt_device);
t1000.fdc = device_add(&fdc_xt_device);
nmi_init();
tc8521_init(&t1000.nvr, model->nvrmask + 1);
t1200_nvr_load();
nvr_set_ven_save(t1200_nvr_save);
if (gfxcard == GFX_INTERNAL)
device_add(&t1200_video_device);
2018-03-13 03:46:10 +01:00
}
void
t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask)
{
t1000.syskeys &= ~andmask;
t1000.syskeys |= ormask;
t1000.syskeys ^= xormask;
}
static void
2018-03-13 03:46:10 +01:00
t1000_configsys_load(void)
{
FILE *f;
memset(t1000.t1000_nvram, 0x1a, sizeof(t1000.t1000_nvram));
2018-03-13 03:46:10 +01:00
f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb");
if (f != NULL) {
fread(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f);
2018-03-13 03:46:10 +01:00
fclose(f);
}
}
static void
2018-03-13 03:46:10 +01:00
t1000_configsys_save(void)
{
FILE *f;
f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb");
if (f != NULL) {
fwrite(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f);
fclose(f);
}
}
static void
t1200_state_load(void)
{
FILE *f;
memset(t1000.t1200_nvram, 0, sizeof(t1000.t1200_nvram));
f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"rb");
if (f != NULL) {
fread(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f);
fclose(f);
}
}
static void
t1200_state_save(void)
{
FILE *f;
f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"wb");
if (f != NULL) {
fwrite(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f);
2018-03-13 03:46:10 +01:00
fclose(f);
}
}
/* All RAM beyond 512k is non-volatile */
static void
2018-03-13 03:46:10 +01:00
t1000_emsboard_load(void)
{
FILE *f;
if (mem_size > 512) {
f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb");
if (f != NULL) {
fread(&ram[512 * 1024], 1024, (mem_size - 512), f);
fclose(f);
}
}
}
static void
2018-03-13 03:46:10 +01:00
t1000_emsboard_save(void)
{
FILE *f;
if (mem_size > 512) {
f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb");
if (f != NULL) {
fwrite(&ram[512 * 1024], 1024, (mem_size - 512), f);
fclose(f);
}
}
}
void
t1000_nvr_load(void)
{
t1000_emsboard_load();
t1000_configsys_load();
}
void
t1000_nvr_save(void)
{
t1000_emsboard_save();
t1000_configsys_save();
}
void
t1200_nvr_load(void)
{
t1000_emsboard_load();
t1200_state_load();
}
void
t1200_nvr_save(void)
{
t1000_emsboard_save();
t1200_state_save();
}