Merge branch 'master' of github.com:OBattler/86Box
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
* Implementation of the NEC uPD-765 and compatible floppy disk
|
* Implementation of the NEC uPD-765 and compatible floppy disk
|
||||||
* controller.
|
* controller.
|
||||||
*
|
*
|
||||||
* Version: @(#)fdc->c 1.0.16 2018/02/02
|
* Version: @(#)fdc->c 1.0.17 2018/03/02
|
||||||
*
|
*
|
||||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||||
* Miran Grca, <mgrca8@gmail.com>
|
* Miran Grca, <mgrca8@gmail.com>
|
||||||
@@ -1140,7 +1140,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t
|
uint8_t
|
||||||
fdc_read(uint16_t addr, void *priv)
|
fdc_read(uint16_t addr, void *priv)
|
||||||
{
|
{
|
||||||
fdc_t *fdc = (fdc_t *) priv;
|
fdc_t *fdc = (fdc_t *) priv;
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
* Implementation of the NEC uPD-765 and compatible floppy disk
|
* Implementation of the NEC uPD-765 and compatible floppy disk
|
||||||
* controller.
|
* controller.
|
||||||
*
|
*
|
||||||
* Version: @(#)fdc.h 1.0.4 2018/02/02
|
* Version: @(#)fdc.h 1.0.5 2018/03/02
|
||||||
*
|
*
|
||||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||||
* Miran Grca, <mgrca8@gmail.com>
|
* Miran Grca, <mgrca8@gmail.com>
|
||||||
@@ -150,6 +150,7 @@ extern int fdc_data(fdc_t *fdc, uint8_t data);
|
|||||||
|
|
||||||
extern void fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2);
|
extern void fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2);
|
||||||
|
|
||||||
|
extern uint8_t fdc_read(uint16_t addr, void *priv);
|
||||||
extern void fdc_reset(void *priv);
|
extern void fdc_reset(void *priv);
|
||||||
|
|
||||||
extern uint8_t fdc_ps1_525(void);
|
extern uint8_t fdc_ps1_525(void);
|
||||||
|
674
src/machine/m_xt_t1000.c
Normal file
674
src/machine/m_xt_t1000.c
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include "../86box.h"
|
||||||
|
#include "../device.h"
|
||||||
|
#include "../io.h"
|
||||||
|
#include "../keyboard.h"
|
||||||
|
#include "../lpt.h"
|
||||||
|
#include "../mem.h"
|
||||||
|
#include "../nmi.h"
|
||||||
|
#include "../nvr.h"
|
||||||
|
#include "../nvr_tc8521.h"
|
||||||
|
#include "../pit.h"
|
||||||
|
#include "../plat.h"
|
||||||
|
#include "../rom.h"
|
||||||
|
#include "../cpu/cpu.h"
|
||||||
|
#include "../floppy/fdd.h"
|
||||||
|
#include "../floppy/fdc.h"
|
||||||
|
#include "../game/gameport.h"
|
||||||
|
#include "../video/vid_t1000.h"
|
||||||
|
#include "machine.h"
|
||||||
|
|
||||||
|
/* 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].
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void common_init();
|
||||||
|
|
||||||
|
uint8_t config_sys[160];
|
||||||
|
|
||||||
|
static struct t1000_system
|
||||||
|
{
|
||||||
|
/* ROM drive */
|
||||||
|
uint8_t *romdrive;
|
||||||
|
uint8_t rom_ctl;
|
||||||
|
uint32_t rom_offset;
|
||||||
|
mem_mapping_t rom_mapping;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
} t1000;
|
||||||
|
|
||||||
|
#define T1000_ROMSIZE (512 * 1024) /* Maximum ROM drive size is 512k */
|
||||||
|
|
||||||
|
/* The CONFIG.SYS storage (160 bytes) and battery-backed EMS (all RAM
|
||||||
|
* above 512k) are implemented as NVR devices */
|
||||||
|
|
||||||
|
void t1000_configsys_loadnvr()
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
memset(config_sys, 0x1A, sizeof(config_sys));
|
||||||
|
f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fread(config_sys, sizeof(config_sys), 1, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All RAM beyond 512k is non-volatile */
|
||||||
|
void t1000_emsboard_loadnvr()
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (mem_size > 512)
|
||||||
|
{
|
||||||
|
f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fread(&ram[512 * 1024],
|
||||||
|
1024, (mem_size - 512), f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void t1000_configsys_savenvr()
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fwrite(config_sys, sizeof(config_sys), 1, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void t1000_emsboard_savenvr()
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (mem_size > 512)
|
||||||
|
{
|
||||||
|
f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fwrite(&ram[512 * 1024],
|
||||||
|
1024, (mem_size - 512), f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Given an EMS page ID, return its physical address in RAM. */
|
||||||
|
uint32_t ems_execaddr(struct t1000_system *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;
|
||||||
|
|
||||||
|
/* pclog("Select EMS page: %d of %d\n", val, sys->ems_pages); */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
|
||||||
|
/* pclog("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); */
|
||||||
|
return sys->ems_reg[(addr >> 14) & 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ems_out(uint16_t addr, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
int pg = (addr >> 14) & 3;
|
||||||
|
|
||||||
|
/* pclog("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); */
|
||||||
|
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(struct t1000_system *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;
|
||||||
|
}
|
||||||
|
/* pclog("EMS base set to %02x\n", val); */
|
||||||
|
sys->ems_pages = 48 - 4 * sys->ems_base;
|
||||||
|
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(struct t1000_system *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(struct t1000_system *sys, uint8_t val)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* pclog("ems_set_port(%d)", val & 0x0F); */
|
||||||
|
if (sys->ems_port)
|
||||||
|
{
|
||||||
|
for (n = 0; n <= 0xC000; n += 0x4000)
|
||||||
|
{
|
||||||
|
io_removehandler(sys->ems_port + n, 0x01,
|
||||||
|
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, 0x01,
|
||||||
|
ems_in, NULL, NULL, ems_out, NULL, NULL, sys);
|
||||||
|
}
|
||||||
|
sys->ems_port = 0;
|
||||||
|
}
|
||||||
|
/* pclog(" -> %04x\n", sys->ems_port); */
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
int pg = addr_to_page(addr);
|
||||||
|
|
||||||
|
if (pg < 0) return 0xFF;
|
||||||
|
/* pclog("ems_read_ramw addr=%05x ", addr); */
|
||||||
|
addr = sys->page_exec[pg] + (addr & 0x3FFF);
|
||||||
|
/* pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); */
|
||||||
|
return *(uint16_t *)&ram[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t ems_read_raml(uint32_t addr, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
int pg = addr_to_page(addr);
|
||||||
|
|
||||||
|
if (pg < 0) return;
|
||||||
|
/* pclog("ems_write_ramw addr=%05x ", addr); */
|
||||||
|
addr = sys->page_exec[pg] + (addr & 0x3FFF);
|
||||||
|
/* pclog("-> %06x val=%04x\n", addr, val); */
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask)
|
||||||
|
{
|
||||||
|
t1000.syskeys &= ~andmask;
|
||||||
|
t1000.syskeys |= ormask;
|
||||||
|
t1000.syskeys ^= xormask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t read_t1000_ctl(uint16_t addr, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
|
||||||
|
switch (addr & 0x0F)
|
||||||
|
{
|
||||||
|
case 1: return sys->syskeys;
|
||||||
|
/* Detect EMS board */
|
||||||
|
case 0x0F: switch (sys->sys_ctl[0x0E])
|
||||||
|
{
|
||||||
|
case 0x50: if (mem_size <= 512)
|
||||||
|
return 0xFF;
|
||||||
|
return 0x90 | sys->ems_port_index;
|
||||||
|
/* 0x60 is the page frame address: (0xD000 - 0xC400) / 0x20 */
|
||||||
|
case 0x51: return sys->ems_base | 0x60;
|
||||||
|
case 0x52: return sys->is_640k ? 0x80 : 0;
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
|
default: return sys->sys_ctl[addr & 0x0F];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t1200_turbo_set(uint8_t value)
|
||||||
|
{
|
||||||
|
if (value == t1000.turbo)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t1000.turbo = value;
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
int c = cpu;
|
||||||
|
cpu = 0; /* 8088/4.77MHz */
|
||||||
|
cpu_set();
|
||||||
|
cpu = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cpu_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_t1000_ctl(uint16_t addr, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
|
||||||
|
sys->sys_ctl[addr & 0x0F] = val;
|
||||||
|
switch (addr & 0x0F)
|
||||||
|
{
|
||||||
|
/* Video control */
|
||||||
|
case 4: if (sys->sys_ctl[3] == 0x5A)
|
||||||
|
{
|
||||||
|
t1000_video_options_set((val & 0x20) ? 1 : 0);
|
||||||
|
t1000_display_set((val & 0x40) ? 0 : 1);
|
||||||
|
if (romset == ROM_T1200)
|
||||||
|
{
|
||||||
|
t1200_turbo_set((val & 0x80) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* EMS control*/
|
||||||
|
case 0x0F:
|
||||||
|
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 read_t1000_nvram(uint16_t addr, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
uint8_t tmp;
|
||||||
|
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0xC2: /* Read next byte from NVRAM */
|
||||||
|
tmp = 0xFF;
|
||||||
|
if (sys->nvr_addr >= 0 && sys->nvr_addr < 160)
|
||||||
|
tmp = config_sys[sys->nvr_addr];
|
||||||
|
++sys->nvr_addr;
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
case 0xC3: /* Read floppy changeline and NVRAM ready state */
|
||||||
|
tmp = fdc_read(0x3F7, 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 */
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_t1000_nvram(uint16_t addr, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
/* 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. */
|
||||||
|
case 0xC0: sys->nvr_c0 = val;
|
||||||
|
break;
|
||||||
|
/* Write next byte to NVRAM */
|
||||||
|
case 0xC1: if (sys->nvr_addr >= 0 && sys->nvr_addr < 160)
|
||||||
|
{
|
||||||
|
if (config_sys[sys->nvr_addr] != val)
|
||||||
|
nvr_dosave = 1;
|
||||||
|
config_sys[sys->nvr_addr] = val;
|
||||||
|
}
|
||||||
|
++sys->nvr_addr;
|
||||||
|
break;
|
||||||
|
case 0xC2: break;
|
||||||
|
/* 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 */
|
||||||
|
case 0xC3: sys->nvr_active = val;
|
||||||
|
if (val == 0x80) sys->nvr_addr = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Port 0xC8 controls the ROM drive */
|
||||||
|
static uint8_t read_t1000_rom_ctl(uint16_t addr, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
|
||||||
|
return sys->rom_ctl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_t1000_rom_ctl(uint16_t addr, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)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)
|
||||||
|
{
|
||||||
|
struct t1000_system *sys = (struct t1000_system *)priv;
|
||||||
|
|
||||||
|
if (!sys->romdrive) return 0xFFFFFFFF;
|
||||||
|
return *(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xFFFF)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_t *
|
||||||
|
t1000_get_device(void)
|
||||||
|
{
|
||||||
|
return &t1000_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void machine_xt_t1000_init(machine_t *model)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int pg;
|
||||||
|
|
||||||
|
memset(&t1000, 0, sizeof(t1000));
|
||||||
|
t1000.turbo = 0xff;
|
||||||
|
t1000.ems_port_index = 7; /* EMS disabled */
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
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, read_t1000_nvram, NULL, NULL,
|
||||||
|
write_t1000_nvram, NULL, NULL, &t1000);
|
||||||
|
/* ROM drive */
|
||||||
|
io_sethandler(0xC8, 1, read_t1000_rom_ctl, NULL, NULL,
|
||||||
|
write_t1000_rom_ctl, NULL, NULL, &t1000);
|
||||||
|
/* System control functions, and add-on memory board */
|
||||||
|
io_sethandler(0xE0, 0x10, read_t1000_ctl, NULL, NULL,
|
||||||
|
write_t1000_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();
|
||||||
|
nvr_tc8521_init();
|
||||||
|
/* No gameport, and no provision to fit one device_add(&gameport_device); */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_t *
|
||||||
|
t1200_get_device(void)
|
||||||
|
{
|
||||||
|
return &t1200_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void machine_xt_t1200_init(machine_t *model)
|
||||||
|
{
|
||||||
|
int pg;
|
||||||
|
|
||||||
|
memset(&t1000, 0, sizeof(t1000));
|
||||||
|
t1000.ems_port_index = 7; /* EMS disabled */
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* System control functions, and add-on memory board */
|
||||||
|
io_sethandler(0xE0, 0x10, read_t1000_ctl, NULL, NULL,
|
||||||
|
write_t1000_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();
|
||||||
|
nvr_tc8521_init();
|
||||||
|
/* No gameport, and no provision to fit one device_add(&gameport_device); */
|
||||||
|
}
|
7
src/machine/m_xt_t1000.h
Normal file
7
src/machine/m_xt_t1000.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask);
|
||||||
|
|
||||||
|
void t1000_configsys_loadnvr();
|
||||||
|
void t1000_emsboard_loadnvr();
|
||||||
|
|
||||||
|
void t1000_configsys_savenvr();
|
||||||
|
void t1000_emsboard_savenvr();
|
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
* Handling of the emulated machines.
|
* Handling of the emulated machines.
|
||||||
*
|
*
|
||||||
* Version: @(#)machine.h 1.0.19 2018/02/09
|
* Version: @(#)machine.h 1.0.20 2018/03/02
|
||||||
*
|
*
|
||||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||||
* Miran Grca, <mgrca8@gmail.com>
|
* Miran Grca, <mgrca8@gmail.com>
|
||||||
@@ -186,12 +186,18 @@ extern void machine_xt_compaq_init(machine_t *);
|
|||||||
extern void machine_xt_laserxt_init(machine_t *);
|
extern void machine_xt_laserxt_init(machine_t *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern void machine_xt_t1000_init(machine_t *);
|
||||||
|
extern void machine_xt_t1200_init(machine_t *);
|
||||||
|
|
||||||
#ifdef EMU_DEVICE_H
|
#ifdef EMU_DEVICE_H
|
||||||
extern device_t *pcjr_get_device(void);
|
extern device_t *pcjr_get_device(void);
|
||||||
|
|
||||||
extern device_t *tandy1k_get_device(void);
|
extern device_t *tandy1k_get_device(void);
|
||||||
extern device_t *tandy1k_hx_get_device(void);
|
extern device_t *tandy1k_hx_get_device(void);
|
||||||
|
|
||||||
|
extern device_t *t1000_get_device(void);
|
||||||
|
extern device_t *t1200_get_device(void);
|
||||||
|
|
||||||
extern device_t *at_endeavor_get_device(void);
|
extern device_t *at_endeavor_get_device(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
* NOTES: OpenAT wip for 286-class machine with open BIOS.
|
* NOTES: OpenAT wip for 286-class machine with open BIOS.
|
||||||
* PS2_M80-486 wip, pending receipt of TRM's for machine.
|
* PS2_M80-486 wip, pending receipt of TRM's for machine.
|
||||||
*
|
*
|
||||||
* Version: @(#)machine_table.c 1.0.19 2018/02/18
|
* Version: @(#)machine_table.c 1.0.20 2018/03/02
|
||||||
*
|
*
|
||||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||||
* Miran Grca, <mgrca8@gmail.com>
|
* Miran Grca, <mgrca8@gmail.com>
|
||||||
@@ -47,6 +47,7 @@ machine_t machines[] = {
|
|||||||
{ "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 0, machine_europc_init, NULL, NULL },
|
{ "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 0, machine_europc_init, NULL, NULL },
|
||||||
{ "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device, NULL },
|
{ "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device, NULL },
|
||||||
{ "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device, NULL },
|
{ "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device, NULL },
|
||||||
|
{ "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 1280, 768, 0, machine_xt_t1000_init, t1000_get_device, NULL },
|
||||||
#if defined(DEV_BRANCH) && defined(USE_LASERXT)
|
#if defined(DEV_BRANCH) && defined(USE_LASERXT)
|
||||||
{ "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL },
|
{ "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL },
|
||||||
#endif
|
#endif
|
||||||
@@ -58,6 +59,7 @@ machine_t machines[] = {
|
|||||||
{ "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close },
|
{ "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close },
|
||||||
{ "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL, NULL },
|
{ "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL, NULL },
|
||||||
{ "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL, NULL },
|
{ "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL, NULL },
|
||||||
|
{ "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 1024, 2048,1024, 0, machine_xt_t1200_init, t1200_get_device, NULL },
|
||||||
#if defined(DEV_BRANCH) && defined(USE_LASERXT)
|
#if defined(DEV_BRANCH) && defined(USE_LASERXT)
|
||||||
{ "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL },
|
{ "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL },
|
||||||
#endif
|
#endif
|
||||||
|
115
src/nvr_tc8521.c
Normal file
115
src/nvr_tc8521.c
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include "86box.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "nvr.h"
|
||||||
|
#include "nvr_tc8521.h"
|
||||||
|
#include "rtc_tc8521.h"
|
||||||
|
#include "pic.h"
|
||||||
|
#include "pit.h"
|
||||||
|
#include "plat.h"
|
||||||
|
#include "rom.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "nmi.h"
|
||||||
|
#include "machine/machine.h"
|
||||||
|
|
||||||
|
int oldromset;
|
||||||
|
int nvrmask=63;
|
||||||
|
uint8_t nvrram[128];
|
||||||
|
int nvraddr;
|
||||||
|
|
||||||
|
int nvr_dosave = 0;
|
||||||
|
|
||||||
|
static int64_t nvr_onesec_time = 0, nvr_onesec_cnt = 0;
|
||||||
|
|
||||||
|
static void tc8521_onesec(void *p)
|
||||||
|
{
|
||||||
|
nvr_onesec_cnt++;
|
||||||
|
if (nvr_onesec_cnt >= 100)
|
||||||
|
{
|
||||||
|
tc8521_tick();
|
||||||
|
nvr_onesec_cnt = 0;
|
||||||
|
}
|
||||||
|
nvr_onesec_time += (int)(10000 * TIMER_USEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_tc8521(uint16_t addr, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
uint8_t page = nvrram[0x0D] & 3;
|
||||||
|
|
||||||
|
addr &= 0x0F;
|
||||||
|
if (addr < 0x0D) addr += 16 * page;
|
||||||
|
|
||||||
|
if (addr >= 0x10 && nvrram[addr] != val)
|
||||||
|
nvr_dosave = 1;
|
||||||
|
|
||||||
|
nvrram[addr] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t read_tc8521(uint16_t addr, void *priv)
|
||||||
|
{
|
||||||
|
uint8_t page = nvrram[0x0D] & 3;
|
||||||
|
|
||||||
|
addr &= 0x0F;
|
||||||
|
if (addr < 0x0D) addr += 16 * page;
|
||||||
|
|
||||||
|
return nvrram[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tc8521_loadnvr()
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
nvrmask=63;
|
||||||
|
oldromset=romset;
|
||||||
|
switch (romset)
|
||||||
|
{
|
||||||
|
case ROM_T1000: f = plat_fopen(nvr_path(L"t1000.nvr"), L"rb"); break;
|
||||||
|
case ROM_T1200: f = plat_fopen(nvr_path(L"t1200.nvr"), L"rb"); break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
memset(nvrram,0xFF,64);
|
||||||
|
nvrram[0x0E] = 0; /* Test register */
|
||||||
|
if (!enable_sync)
|
||||||
|
{
|
||||||
|
memset(nvrram, 0, 16);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fread(nvrram,64,1,f);
|
||||||
|
if (enable_sync)
|
||||||
|
tc8521_internal_sync(nvrram);
|
||||||
|
else
|
||||||
|
tc8521_internal_set_nvrram(nvrram); /* Update the internal clock state based on the NVR registers. */
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tc8521_savenvr()
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
switch (oldromset)
|
||||||
|
{
|
||||||
|
case ROM_T1000: f = plat_fopen(nvr_path(L"t1000.nvr"), L"wb"); break;
|
||||||
|
case ROM_T1200: f = plat_fopen(nvr_path(L"t1200.nvr"), L"wb"); break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
fwrite(nvrram,64,1,f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvr_tc8521_init()
|
||||||
|
{
|
||||||
|
io_sethandler(0x2C0, 0x10, read_tc8521, NULL, NULL, write_tc8521, NULL, NULL, NULL);
|
||||||
|
timer_add(tc8521_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL);
|
||||||
|
}
|
12
src/nvr_tc8521.h
Normal file
12
src/nvr_tc8521.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
void nvr_tc8521_init();
|
||||||
|
|
||||||
|
extern int enable_sync;
|
||||||
|
|
||||||
|
extern int nvr_dosave;
|
||||||
|
|
||||||
|
void tc8521_loadnvr();
|
||||||
|
void tc8521_savenvr();
|
||||||
|
|
||||||
|
void tc8521_nvr_recalc();
|
||||||
|
|
||||||
|
FILE *nvrfopen(char *fn, char *mode);
|
18
src/rom.c
18
src/rom.c
@@ -13,7 +13,7 @@
|
|||||||
* - c386sx16 BIOS fails checksum
|
* - c386sx16 BIOS fails checksum
|
||||||
* - the loadfont() calls should be done elsewhere
|
* - the loadfont() calls should be done elsewhere
|
||||||
*
|
*
|
||||||
* Version: @(#)rom.c 1.0.30 2018/03/02
|
* Version: @(#)rom.c 1.0.31 2018/03/02
|
||||||
*
|
*
|
||||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||||
* Miran Grca, <mgrca8@gmail.com>
|
* Miran Grca, <mgrca8@gmail.com>
|
||||||
@@ -828,6 +828,22 @@ rom_load_bios(int rom_id)
|
|||||||
return(1);
|
return(1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
case ROM_T1000:
|
||||||
|
loadfont(L"roms/machines/t1000/t1000font.bin", 2);
|
||||||
|
if (rom_load_linear(
|
||||||
|
L"roms/machines/t1000/t1000.rom",
|
||||||
|
0x000000, 32768, 0, rom)) return(1);
|
||||||
|
memcpy(rom + 0x8000, rom, 0x8000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROM_T1200:
|
||||||
|
loadfont(L"roms/machines/t1200/t1000font.bin", 2);
|
||||||
|
if (rom_load_linear(
|
||||||
|
L"roms/machines/t1200/t1200_019e.ic15.bin",
|
||||||
|
0x000000, 32768, 0, rom)) return(1);
|
||||||
|
memcpy(rom + 0x8000, rom, 0x8000);
|
||||||
|
break;
|
||||||
|
|
||||||
case ROM_T3100E:
|
case ROM_T3100E:
|
||||||
loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5);
|
loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5);
|
||||||
if (rom_load_linear(
|
if (rom_load_linear(
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
* Definitions for the ROM image handler.
|
* Definitions for the ROM image handler.
|
||||||
*
|
*
|
||||||
* Version: @(#)rom.h 1.0.13 2018/01/28
|
* Version: @(#)rom.h 1.0.14 2018/03/02
|
||||||
*
|
*
|
||||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||||
* Copyright 2018 Fred N. van Kempen.
|
* Copyright 2018 Fred N. van Kempen.
|
||||||
@@ -52,6 +52,9 @@ enum {
|
|||||||
ROM_LXT3,
|
ROM_LXT3,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ROM_T1000,
|
||||||
|
ROM_T1200,
|
||||||
|
|
||||||
ROM_IBMPCJR,
|
ROM_IBMPCJR,
|
||||||
ROM_TANDY,
|
ROM_TANDY,
|
||||||
ROM_TANDY1000HX,
|
ROM_TANDY1000HX,
|
||||||
@@ -63,6 +66,7 @@ enum {
|
|||||||
ROM_PC3086,
|
ROM_PC3086,
|
||||||
ROM_OLIM24,
|
ROM_OLIM24,
|
||||||
ROM_TANDY1000SL2,
|
ROM_TANDY1000SL2,
|
||||||
|
|
||||||
ROM_T3100E,
|
ROM_T3100E,
|
||||||
|
|
||||||
ROM_AMI286,
|
ROM_AMI286,
|
||||||
|
221
src/rtc_tc8521.c
Normal file
221
src/rtc_tc8521.c
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/* Emulation of:
|
||||||
|
Toshiba TC8521 Real Time Clock */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "nvr.h"
|
||||||
|
#include "rtc_tc8521.h"
|
||||||
|
|
||||||
|
#define peek2(a) (nvrram[(a##1)] + 10 * nvrram[(a##10)])
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int sec;
|
||||||
|
int min;
|
||||||
|
int hour;
|
||||||
|
int mday;
|
||||||
|
int mon;
|
||||||
|
int year;
|
||||||
|
} internal_clock;
|
||||||
|
|
||||||
|
/* Table for days in each month */
|
||||||
|
static int rtc_days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
/* Called to determine whether the year is leap or not */
|
||||||
|
static int rtc_is_leap(int org_year)
|
||||||
|
{
|
||||||
|
if (org_year % 400 == 0) return 1;
|
||||||
|
if (org_year % 100 == 0) return 0;
|
||||||
|
if (org_year % 4 == 0) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called to determine the days in the current month */
|
||||||
|
static int rtc_get_days(int org_month, int org_year)
|
||||||
|
{
|
||||||
|
if (org_month != 2)
|
||||||
|
return rtc_days_in_month[org_month];
|
||||||
|
else
|
||||||
|
return rtc_is_leap(org_year) ? 29 : 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when the internal clock gets updated */
|
||||||
|
static void tc8521_recalc()
|
||||||
|
{
|
||||||
|
if (internal_clock.sec == 60)
|
||||||
|
{
|
||||||
|
internal_clock.sec = 0;
|
||||||
|
internal_clock.min++;
|
||||||
|
}
|
||||||
|
if (internal_clock.min == 60)
|
||||||
|
{
|
||||||
|
internal_clock.min = 0;
|
||||||
|
internal_clock.hour++;
|
||||||
|
}
|
||||||
|
if (internal_clock.hour == 24)
|
||||||
|
{
|
||||||
|
internal_clock.hour = 0;
|
||||||
|
internal_clock.mday++;
|
||||||
|
}
|
||||||
|
if (internal_clock.mday == (rtc_get_days(internal_clock.mon, internal_clock.year) + 1))
|
||||||
|
{
|
||||||
|
internal_clock.mday = 1;
|
||||||
|
internal_clock.mon++;
|
||||||
|
}
|
||||||
|
if (internal_clock.mon == 13)
|
||||||
|
{
|
||||||
|
internal_clock.mon = 1;
|
||||||
|
internal_clock.year++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when ticking the second */
|
||||||
|
void tc8521_tick()
|
||||||
|
{
|
||||||
|
internal_clock.sec++;
|
||||||
|
tc8521_recalc();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when modifying the NVR registers */
|
||||||
|
void tc8521_update(uint8_t *nvrram, int reg)
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
switch(reg)
|
||||||
|
{
|
||||||
|
case TC8521_SECOND1:
|
||||||
|
case TC8521_SECOND10:
|
||||||
|
internal_clock.sec = peek2(TC8521_SECOND);
|
||||||
|
break;
|
||||||
|
case TC8521_MINUTE1:
|
||||||
|
case TC8521_MINUTE10:
|
||||||
|
internal_clock.min = peek2(TC8521_MINUTE);
|
||||||
|
break;
|
||||||
|
case TC8521_HOUR1:
|
||||||
|
case TC8521_HOUR10:
|
||||||
|
temp = peek2(TC8521_HOUR);
|
||||||
|
if (nvrram[TC8521_24HR] & 1)
|
||||||
|
internal_clock.hour = temp;
|
||||||
|
else
|
||||||
|
internal_clock.hour = ((temp & ~0x20) % 12) + ((temp & 0x20) ? 12 : 0);
|
||||||
|
break;
|
||||||
|
case TC8521_DAY1:
|
||||||
|
case TC8521_DAY10:
|
||||||
|
internal_clock.mday = peek2(TC8521_DAY);
|
||||||
|
break;
|
||||||
|
case TC8521_MONTH1:
|
||||||
|
case TC8521_MONTH10:
|
||||||
|
internal_clock.mon = peek2(TC8521_MONTH);
|
||||||
|
break;
|
||||||
|
case TC8521_YEAR1:
|
||||||
|
case TC8521_YEAR10:
|
||||||
|
internal_clock.year = 1980 + peek2(TC8521_YEAR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called to obtain the current day of the week based on the internal clock */
|
||||||
|
static int time_week_day()
|
||||||
|
{
|
||||||
|
int day_of_month = internal_clock.mday;
|
||||||
|
int month2 = internal_clock.mon;
|
||||||
|
int year2 = internal_clock.year % 100;
|
||||||
|
int century = ((internal_clock.year - year2) / 100) % 4;
|
||||||
|
int sum = day_of_month + month2 + year2 + century;
|
||||||
|
/* (Sum mod 7) gives 0 for Saturday, we need it for Sunday, so +6 for Saturday to get 6 and Sunday 0 */
|
||||||
|
int raw_wd = ((sum + 6) % 7);
|
||||||
|
return raw_wd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called to get time into the internal clock */
|
||||||
|
static void tc8521_internal_get(struct tm *time_var)
|
||||||
|
{
|
||||||
|
time_var->tm_sec = internal_clock.sec;
|
||||||
|
time_var->tm_min = internal_clock.min;
|
||||||
|
time_var->tm_hour = internal_clock.hour;
|
||||||
|
time_var->tm_wday = time_week_day();
|
||||||
|
time_var->tm_mday = internal_clock.mday;
|
||||||
|
time_var->tm_mon = internal_clock.mon - 1;
|
||||||
|
time_var->tm_year = internal_clock.year - 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tc8521_internal_set(struct tm *time_var)
|
||||||
|
{
|
||||||
|
internal_clock.sec = time_var->tm_sec;
|
||||||
|
internal_clock.min = time_var->tm_min;
|
||||||
|
internal_clock.hour = time_var->tm_hour;
|
||||||
|
internal_clock.mday = time_var->tm_mday;
|
||||||
|
internal_clock.mon = time_var->tm_mon + 1;
|
||||||
|
internal_clock.year = time_var->tm_year + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tc8521_set_nvrram(uint8_t *nvrram, struct tm *cur_time_tm)
|
||||||
|
{
|
||||||
|
nvrram[TC8521_SECOND1] = cur_time_tm->tm_sec % 10;
|
||||||
|
nvrram[TC8521_SECOND10] = cur_time_tm->tm_sec / 10;
|
||||||
|
nvrram[TC8521_MINUTE1] = cur_time_tm->tm_min % 10;
|
||||||
|
nvrram[TC8521_MINUTE10] = cur_time_tm->tm_min / 10;
|
||||||
|
if (nvrram[TC8521_24HR] & 1)
|
||||||
|
{
|
||||||
|
nvrram[TC8521_HOUR1] = cur_time_tm->tm_hour % 10;
|
||||||
|
nvrram[TC8521_HOUR10] = cur_time_tm->tm_hour / 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nvrram[TC8521_HOUR1] = (cur_time_tm->tm_hour % 12) % 10;
|
||||||
|
nvrram[TC8521_HOUR10] = ((cur_time_tm->tm_hour % 12) / 10)
|
||||||
|
| (cur_time_tm->tm_hour >= 12) ? 2 : 0;
|
||||||
|
}
|
||||||
|
nvrram[TC8521_WEEKDAY] = cur_time_tm->tm_wday;
|
||||||
|
nvrram[TC8521_DAY1] = cur_time_tm->tm_mday % 10;
|
||||||
|
nvrram[TC8521_DAY10] = cur_time_tm->tm_mday / 10;
|
||||||
|
nvrram[TC8521_MONTH1] = (cur_time_tm->tm_mon + 1) / 10;
|
||||||
|
nvrram[TC8521_MONTH10] = (cur_time_tm->tm_mon + 1) % 10;
|
||||||
|
nvrram[TC8521_YEAR1] = (cur_time_tm->tm_year - 80) % 10;
|
||||||
|
nvrram[TC8521_YEAR10] = ((cur_time_tm->tm_year - 80) % 100) / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tc8521_internal_set_nvrram(uint8_t *nvrram)
|
||||||
|
{
|
||||||
|
/* Load the entire internal clock state from the NVR. */
|
||||||
|
internal_clock.sec = peek2(TC8521_SECOND);
|
||||||
|
internal_clock.min = peek2(TC8521_MINUTE);
|
||||||
|
if (nvrram[TC8521_24HR] & 1)
|
||||||
|
{
|
||||||
|
internal_clock.hour = peek2(TC8521_HOUR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
internal_clock.hour = (peek2(TC8521_HOUR) % 12)
|
||||||
|
+ (nvrram[TC8521_HOUR10] & 2) ? 12 : 0;
|
||||||
|
}
|
||||||
|
internal_clock.mday = peek2(TC8521_DAY);
|
||||||
|
internal_clock.mon = peek2(TC8521_MONTH);
|
||||||
|
internal_clock.year = 1980 + peek2(TC8521_YEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tc8521_internal_sync(uint8_t *nvrram)
|
||||||
|
{
|
||||||
|
struct tm *cur_time_tm;
|
||||||
|
time_t cur_time;
|
||||||
|
|
||||||
|
time(&cur_time);
|
||||||
|
cur_time_tm = localtime(&cur_time);
|
||||||
|
|
||||||
|
tc8521_internal_set(cur_time_tm);
|
||||||
|
|
||||||
|
tc8521_set_nvrram(nvrram, cur_time_tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tc8521_get(uint8_t *nvrram)
|
||||||
|
{
|
||||||
|
struct tm cur_time_tm;
|
||||||
|
|
||||||
|
tc8521_internal_get(&cur_time_tm);
|
||||||
|
|
||||||
|
tc8521_set_nvrram(nvrram, &cur_time_tm);
|
||||||
|
}
|
33
src/rtc_tc8521.h
Normal file
33
src/rtc_tc8521.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
/* 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. */
|
||||||
|
enum TC8521_ADDR
|
||||||
|
{
|
||||||
|
/* Page 0 registers */
|
||||||
|
TC8521_SECOND1,
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void tc8521_tick();
|
||||||
|
void tc8521_update(uint8_t *nvrram, int reg);
|
||||||
|
void tc8521_get(uint8_t *nvrram);
|
||||||
|
void tc8521_internal_set_nvrram(uint8_t *nvrram);
|
||||||
|
void tc8521_internal_sync(uint8_t *nvrram);
|
721
src/video/vid_t1000.c
Normal file
721
src/video/vid_t1000.c
Normal file
@@ -0,0 +1,721 @@
|
|||||||
|
/* Emulate the Toshiba 1000 plasma display. This display has a fixed 640x200
|
||||||
|
* resolution. */
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include "../86box.h"
|
||||||
|
#include "../device.h"
|
||||||
|
#include "../io.h"
|
||||||
|
#include "../mem.h"
|
||||||
|
#include "../timer.h"
|
||||||
|
#include "../cpu/cpu.h"
|
||||||
|
#include "video.h"
|
||||||
|
#include "vid_cga.h"
|
||||||
|
#include "vid_t1000.h"
|
||||||
|
|
||||||
|
#define T1000_XSIZE 640
|
||||||
|
#define T1000_YSIZE 200
|
||||||
|
|
||||||
|
/* Mapping of attributes to colours */
|
||||||
|
static uint32_t blue, grey;
|
||||||
|
static uint8_t boldcols[256]; /* Which attributes use the bold font */
|
||||||
|
static uint32_t blinkcols[256][2];
|
||||||
|
static uint32_t normcols[256][2];
|
||||||
|
static uint8_t language;
|
||||||
|
|
||||||
|
/* Video options set by the motherboard; they will be picked up by the card
|
||||||
|
* on the next poll.
|
||||||
|
*
|
||||||
|
* Bit 1: Danish
|
||||||
|
* Bit 0: Thin font
|
||||||
|
*/
|
||||||
|
static uint8_t st_video_options;
|
||||||
|
static uint8_t st_display_internal = -1;
|
||||||
|
|
||||||
|
void t1000_video_options_set(uint8_t options)
|
||||||
|
{
|
||||||
|
st_video_options = options & 1;
|
||||||
|
st_video_options |= language;
|
||||||
|
}
|
||||||
|
|
||||||
|
void t1000_display_set(uint8_t internal)
|
||||||
|
{
|
||||||
|
st_display_internal = internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t t1000_display_get()
|
||||||
|
{
|
||||||
|
return st_display_internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct t1000_t
|
||||||
|
{
|
||||||
|
mem_mapping_t mapping;
|
||||||
|
|
||||||
|
cga_t cga; /* The CGA is used for the external
|
||||||
|
* display; most of its registers are
|
||||||
|
* ignored by the plasma display. */
|
||||||
|
|
||||||
|
int font; /* Current font, 0-3 */
|
||||||
|
int enabled; /* Hardware enabled, 0 or 1 */
|
||||||
|
int internal; /* Using internal display? */
|
||||||
|
uint8_t attrmap; /* Attribute mapping register */
|
||||||
|
|
||||||
|
int dispontime, dispofftime;
|
||||||
|
|
||||||
|
int linepos, displine;
|
||||||
|
int vc;
|
||||||
|
int dispon;
|
||||||
|
int vsynctime;
|
||||||
|
uint8_t video_options;
|
||||||
|
|
||||||
|
uint8_t *vram;
|
||||||
|
} t1000_t;
|
||||||
|
|
||||||
|
|
||||||
|
static void t1000_recalctimings(t1000_t *t1000);
|
||||||
|
static void t1000_write(uint32_t addr, uint8_t val, void *p);
|
||||||
|
static uint8_t t1000_read(uint32_t addr, void *p);
|
||||||
|
static void t1000_recalcattrs(t1000_t *t1000);
|
||||||
|
|
||||||
|
|
||||||
|
static void t1000_out(uint16_t addr, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = (t1000_t *)p;
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
/* Emulated CRTC, register select */
|
||||||
|
case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6:
|
||||||
|
cga_out(addr, val, &t1000->cga);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Emulated CRTC, value */
|
||||||
|
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
|
||||||
|
/* Register 0x12 controls the attribute mappings for the
|
||||||
|
* LCD screen. */
|
||||||
|
if (t1000->cga.crtcreg == 0x12)
|
||||||
|
{
|
||||||
|
t1000->attrmap = val;
|
||||||
|
t1000_recalcattrs(t1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cga_out(addr, val, &t1000->cga);
|
||||||
|
|
||||||
|
t1000_recalctimings(t1000);
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* CGA control register */
|
||||||
|
case 0x3D8:
|
||||||
|
cga_out(addr, val, &t1000->cga);
|
||||||
|
return;
|
||||||
|
/* CGA colour register */
|
||||||
|
case 0x3D9:
|
||||||
|
cga_out(addr, val, &t1000->cga);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t t1000_in(uint16_t addr, void *p)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = (t1000_t *)p;
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
|
||||||
|
if (t1000->cga.crtcreg == 0x12)
|
||||||
|
{
|
||||||
|
val = t1000->attrmap & 0x0F;
|
||||||
|
if (t1000->internal) val |= 0x20; /* LCD / CRT */
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cga_in(addr, &t1000->cga);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void t1000_write(uint32_t addr, uint8_t val, void *p)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = (t1000_t *)p;
|
||||||
|
egawrites++;
|
||||||
|
|
||||||
|
// pclog("CGA_WRITE %04X %02X\n", addr, val);
|
||||||
|
t1000->vram[addr & 0x3fff] = val;
|
||||||
|
cycles -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t t1000_read(uint32_t addr, void *p)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = (t1000_t *)p;
|
||||||
|
egareads++;
|
||||||
|
cycles -= 4;
|
||||||
|
|
||||||
|
// pclog("CGA_READ %04X\n", addr);
|
||||||
|
return t1000->vram[addr & 0x3fff];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void t1000_recalctimings(t1000_t *t1000)
|
||||||
|
{
|
||||||
|
double disptime;
|
||||||
|
double _dispontime, _dispofftime;
|
||||||
|
|
||||||
|
if (!t1000->internal)
|
||||||
|
{
|
||||||
|
cga_recalctimings(&t1000->cga);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
disptime = 651;
|
||||||
|
_dispontime = 640;
|
||||||
|
_dispofftime = disptime - _dispontime;
|
||||||
|
t1000->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
|
||||||
|
t1000->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a row of text in 80-column mode */
|
||||||
|
static void t1000_text_row80(t1000_t *t1000)
|
||||||
|
{
|
||||||
|
uint32_t cols[2];
|
||||||
|
int x, c;
|
||||||
|
uint8_t chr, attr;
|
||||||
|
int drawcursor;
|
||||||
|
int cursorline;
|
||||||
|
int bold;
|
||||||
|
int blink;
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t sc;
|
||||||
|
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||||
|
uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff;
|
||||||
|
|
||||||
|
sc = (t1000->displine) & 7;
|
||||||
|
addr = ((ma & ~1) + (t1000->displine >> 3) * 80) * 2;
|
||||||
|
ma += (t1000->displine >> 3) * 80;
|
||||||
|
|
||||||
|
if ((t1000->cga.crtc[10] & 0x60) == 0x20)
|
||||||
|
{
|
||||||
|
cursorline = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) &&
|
||||||
|
((t1000->cga.crtc[11] & 0x0F) >= sc);
|
||||||
|
}
|
||||||
|
for (x = 0; x < 80; x++)
|
||||||
|
{
|
||||||
|
chr = t1000->vram[(addr + 2 * x) & 0x3FFF];
|
||||||
|
attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF];
|
||||||
|
drawcursor = ((ma == ca) && cursorline &&
|
||||||
|
(t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16));
|
||||||
|
|
||||||
|
blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) &&
|
||||||
|
(attr & 0x80) && !drawcursor);
|
||||||
|
|
||||||
|
if (t1000->video_options & 1)
|
||||||
|
bold = boldcols[attr] ? chr : chr + 256;
|
||||||
|
else
|
||||||
|
bold = boldcols[attr] ? chr + 256 : chr;
|
||||||
|
if (t1000->video_options & 2)
|
||||||
|
bold += 512;
|
||||||
|
|
||||||
|
if (t1000->cga.cgamode & 0x20) /* Blink */
|
||||||
|
{
|
||||||
|
cols[1] = blinkcols[attr][1];
|
||||||
|
cols[0] = blinkcols[attr][0];
|
||||||
|
if (blink) cols[1] = cols[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cols[1] = normcols[attr][1];
|
||||||
|
cols[0] = normcols[attr][0];
|
||||||
|
}
|
||||||
|
if (drawcursor)
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
|
||||||
|
}
|
||||||
|
++ma;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a row of text in 40-column mode */
|
||||||
|
static void t1000_text_row40(t1000_t *t1000)
|
||||||
|
{
|
||||||
|
uint32_t cols[2];
|
||||||
|
int x, c;
|
||||||
|
uint8_t chr, attr;
|
||||||
|
int drawcursor;
|
||||||
|
int cursorline;
|
||||||
|
int bold;
|
||||||
|
int blink;
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t sc;
|
||||||
|
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||||
|
uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff;
|
||||||
|
|
||||||
|
sc = (t1000->displine) & 7;
|
||||||
|
addr = ((ma & ~1) + (t1000->displine >> 3) * 40) * 2;
|
||||||
|
ma += (t1000->displine >> 3) * 40;
|
||||||
|
|
||||||
|
if ((t1000->cga.crtc[10] & 0x60) == 0x20)
|
||||||
|
{
|
||||||
|
cursorline = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) &&
|
||||||
|
((t1000->cga.crtc[11] & 0x0F) >= sc);
|
||||||
|
}
|
||||||
|
for (x = 0; x < 40; x++)
|
||||||
|
{
|
||||||
|
chr = t1000->vram[(addr + 2 * x) & 0x3FFF];
|
||||||
|
attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF];
|
||||||
|
drawcursor = ((ma == ca) && cursorline &&
|
||||||
|
(t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16));
|
||||||
|
|
||||||
|
blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) &&
|
||||||
|
(attr & 0x80) && !drawcursor);
|
||||||
|
|
||||||
|
if (t1000->video_options & 1)
|
||||||
|
bold = boldcols[attr] ? chr : chr + 256;
|
||||||
|
else
|
||||||
|
bold = boldcols[attr] ? chr + 256 : chr;
|
||||||
|
if (t1000->video_options & 2)
|
||||||
|
bold += 512;
|
||||||
|
|
||||||
|
if (t1000->cga.cgamode & 0x20) /* Blink */
|
||||||
|
{
|
||||||
|
cols[1] = blinkcols[attr][1];
|
||||||
|
cols[0] = blinkcols[attr][0];
|
||||||
|
if (blink) cols[1] = cols[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cols[1] = normcols[attr][1];
|
||||||
|
cols[0] = normcols[attr][0];
|
||||||
|
}
|
||||||
|
if (drawcursor)
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] =
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2 + 1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] =
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2+1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++ma;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a line in CGA 640x200 mode */
|
||||||
|
static void t1000_cgaline6(t1000_t *t1000)
|
||||||
|
{
|
||||||
|
int x, c;
|
||||||
|
uint8_t dat;
|
||||||
|
uint32_t ink = 0;
|
||||||
|
uint16_t addr;
|
||||||
|
uint32_t fg = (t1000->cga.cgacol & 0x0F) ? blue : grey;
|
||||||
|
uint32_t bg = grey;
|
||||||
|
|
||||||
|
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||||
|
|
||||||
|
addr = ((t1000->displine) & 1) * 0x2000 +
|
||||||
|
(t1000->displine >> 1) * 80 +
|
||||||
|
((ma & ~1) << 1);
|
||||||
|
|
||||||
|
for (x = 0; x < 80; x++)
|
||||||
|
{
|
||||||
|
dat = t1000->vram[addr & 0x3FFF];
|
||||||
|
addr++;
|
||||||
|
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
ink = (dat & 0x80) ? fg : bg;
|
||||||
|
if (!(t1000->cga.cgamode & 8))
|
||||||
|
ink = grey;
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[x*8+c] = ink;
|
||||||
|
dat = dat << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to
|
||||||
|
* dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */
|
||||||
|
static void t1000_cgaline4(t1000_t *t1000)
|
||||||
|
{
|
||||||
|
int x, c;
|
||||||
|
uint8_t dat, pattern;
|
||||||
|
uint32_t ink0, ink1;
|
||||||
|
uint16_t addr;
|
||||||
|
|
||||||
|
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||||
|
addr = ((t1000->displine) & 1) * 0x2000 +
|
||||||
|
(t1000->displine >> 1) * 80 +
|
||||||
|
((ma & ~1) << 1);
|
||||||
|
|
||||||
|
for (x = 0; x < 80; x++)
|
||||||
|
{
|
||||||
|
dat = t1000->vram[addr & 0x3FFF];
|
||||||
|
addr++;
|
||||||
|
|
||||||
|
for (c = 0; c < 4; c++)
|
||||||
|
{
|
||||||
|
pattern = (dat & 0xC0) >> 6;
|
||||||
|
if (!(t1000->cga.cgamode & 8)) pattern = 0;
|
||||||
|
|
||||||
|
switch (pattern & 3)
|
||||||
|
{
|
||||||
|
case 0: ink0 = ink1 = grey; break;
|
||||||
|
case 1: if (t1000->displine & 1)
|
||||||
|
{
|
||||||
|
ink0 = grey; ink1 = grey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ink0 = blue; ink1 = grey;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: if (t1000->displine & 1)
|
||||||
|
{
|
||||||
|
ink0 = grey; ink1 = blue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ink0 = blue; ink1 = grey;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: ink0 = ink1 = blue; break;
|
||||||
|
|
||||||
|
}
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c] = ink0;
|
||||||
|
((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c+1] = ink1;
|
||||||
|
dat = dat << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t1000_poll(void *p)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = (t1000_t *)p;
|
||||||
|
|
||||||
|
if (t1000->video_options != st_video_options)
|
||||||
|
{
|
||||||
|
t1000->video_options = st_video_options;
|
||||||
|
|
||||||
|
/* Set the font used for the external display */
|
||||||
|
t1000->cga.fontbase = ((t1000->video_options & 3) * 256);
|
||||||
|
}
|
||||||
|
/* Switch between internal plasma and external CRT display. */
|
||||||
|
if (st_display_internal != -1 && st_display_internal != t1000->internal)
|
||||||
|
{
|
||||||
|
t1000->internal = st_display_internal;
|
||||||
|
t1000_recalctimings(t1000);
|
||||||
|
}
|
||||||
|
if (!t1000->internal)
|
||||||
|
{
|
||||||
|
cga_poll(&t1000->cga);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!t1000->linepos)
|
||||||
|
{
|
||||||
|
t1000->cga.vidtime += t1000->dispofftime;
|
||||||
|
t1000->cga.cgastat |= 1;
|
||||||
|
t1000->linepos = 1;
|
||||||
|
if (t1000->dispon)
|
||||||
|
{
|
||||||
|
if (t1000->displine == 0)
|
||||||
|
{
|
||||||
|
video_wait_for_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Graphics */
|
||||||
|
if (t1000->cga.cgamode & 0x02)
|
||||||
|
{
|
||||||
|
if (t1000->cga.cgamode & 0x10)
|
||||||
|
t1000_cgaline6(t1000);
|
||||||
|
else t1000_cgaline4(t1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (t1000->cga.cgamode & 0x01) /* High-res text */
|
||||||
|
{
|
||||||
|
t1000_text_row80(t1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t1000_text_row40(t1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t1000->displine++;
|
||||||
|
/* Hardcode a fixed refresh rate and VSYNC timing */
|
||||||
|
if (t1000->displine == 200) /* Start of VSYNC */
|
||||||
|
{
|
||||||
|
t1000->cga.cgastat |= 8;
|
||||||
|
t1000->dispon = 0;
|
||||||
|
}
|
||||||
|
if (t1000->displine == 216) /* End of VSYNC */
|
||||||
|
{
|
||||||
|
t1000->displine = 0;
|
||||||
|
t1000->cga.cgastat &= ~8;
|
||||||
|
t1000->dispon = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (t1000->dispon)
|
||||||
|
{
|
||||||
|
t1000->cga.cgastat &= ~1;
|
||||||
|
}
|
||||||
|
t1000->cga.vidtime += t1000->dispontime;
|
||||||
|
t1000->linepos = 0;
|
||||||
|
|
||||||
|
if (t1000->displine == 200)
|
||||||
|
{
|
||||||
|
/* Hardcode 640x200 window size */
|
||||||
|
if (T1000_XSIZE != xsize || T1000_YSIZE != ysize)
|
||||||
|
{
|
||||||
|
xsize = T1000_XSIZE;
|
||||||
|
ysize = T1000_YSIZE;
|
||||||
|
if (xsize < 64) xsize = 656;
|
||||||
|
if (ysize < 32) ysize = 200;
|
||||||
|
updatewindowsize(xsize, ysize);
|
||||||
|
}
|
||||||
|
video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize);
|
||||||
|
|
||||||
|
frames++;
|
||||||
|
/* Fixed 640x200 resolution */
|
||||||
|
video_res_x = T1000_XSIZE;
|
||||||
|
video_res_y = T1000_YSIZE;
|
||||||
|
|
||||||
|
if (t1000->cga.cgamode & 0x02)
|
||||||
|
{
|
||||||
|
if (t1000->cga.cgamode & 0x10)
|
||||||
|
video_bpp = 1;
|
||||||
|
else video_bpp = 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
else video_bpp = 0;
|
||||||
|
t1000->cga.cgablink++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t1000_recalcattrs(t1000_t *t1000)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* val behaves as follows:
|
||||||
|
* Bit 0: Attributes 01-06, 08-0E are inverse video
|
||||||
|
* Bit 1: Attributes 01-06, 08-0E are bold
|
||||||
|
* Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF
|
||||||
|
* are inverse video
|
||||||
|
* Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF
|
||||||
|
* are bold */
|
||||||
|
|
||||||
|
/* Set up colours */
|
||||||
|
blue = makecol(0x2D, 0x39, 0x5A);
|
||||||
|
grey = makecol(0x85, 0xa0, 0xD6);
|
||||||
|
|
||||||
|
/* Initialise the attribute mapping. Start by defaulting everything
|
||||||
|
* to grey on blue, and with bold set by bit 3 */
|
||||||
|
for (n = 0; n < 256; n++)
|
||||||
|
{
|
||||||
|
boldcols[n] = (n & 8) != 0;
|
||||||
|
blinkcols[n][0] = normcols[n][0] = blue;
|
||||||
|
blinkcols[n][1] = normcols[n][1] = grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Colours 0x11-0xFF are controlled by bits 2 and 3 of the
|
||||||
|
* passed value. Exclude x0 and x8, which are always grey on
|
||||||
|
* blue. */
|
||||||
|
for (n = 0x11; n <= 0xFF; n++)
|
||||||
|
{
|
||||||
|
if ((n & 7) == 0) continue;
|
||||||
|
if (t1000->attrmap & 4) /* Inverse */
|
||||||
|
{
|
||||||
|
blinkcols[n][0] = normcols[n][0] = blue;
|
||||||
|
blinkcols[n][1] = normcols[n][1] = grey;
|
||||||
|
}
|
||||||
|
else /* Normal */
|
||||||
|
{
|
||||||
|
blinkcols[n][0] = normcols[n][0] = grey;
|
||||||
|
blinkcols[n][1] = normcols[n][1] = blue;
|
||||||
|
}
|
||||||
|
if (t1000->attrmap & 8) boldcols[n] = 1; /* Bold */
|
||||||
|
}
|
||||||
|
/* Set up the 01-0E range, controlled by bits 0 and 1 of the
|
||||||
|
* passed value. When blinking is enabled this also affects 81-8E. */
|
||||||
|
for (n = 0x01; n <= 0x0E; n++)
|
||||||
|
{
|
||||||
|
if (n == 7) continue;
|
||||||
|
if (t1000->attrmap & 1)
|
||||||
|
{
|
||||||
|
blinkcols[n][0] = normcols[n][0] = blue;
|
||||||
|
blinkcols[n][1] = normcols[n][1] = grey;
|
||||||
|
blinkcols[n+128][0] = blue;
|
||||||
|
blinkcols[n+128][1] = grey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blinkcols[n][0] = normcols[n][0] = grey;
|
||||||
|
blinkcols[n][1] = normcols[n][1] = blue;
|
||||||
|
blinkcols[n+128][0] = grey;
|
||||||
|
blinkcols[n+128][1] = blue;
|
||||||
|
}
|
||||||
|
if (t1000->attrmap & 2) boldcols[n] = 1;
|
||||||
|
}
|
||||||
|
/* Colours 07 and 0F are always blue on grey. If blinking is
|
||||||
|
* enabled so are 87 and 8F. */
|
||||||
|
for (n = 0x07; n <= 0x0F; n += 8)
|
||||||
|
{
|
||||||
|
blinkcols[n][0] = normcols[n][0] = grey;
|
||||||
|
blinkcols[n][1] = normcols[n][1] = blue;
|
||||||
|
blinkcols[n+128][0] = grey;
|
||||||
|
blinkcols[n+128][1] = blue;
|
||||||
|
}
|
||||||
|
/* When not blinking, colours 81-8F are always blue on grey. */
|
||||||
|
for (n = 0x81; n <= 0x8F; n ++)
|
||||||
|
{
|
||||||
|
normcols[n][0] = grey;
|
||||||
|
normcols[n][1] = blue;
|
||||||
|
boldcols[n] = (n & 0x08) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Finally do the ones which are solid grey. These differ between
|
||||||
|
* the normal and blinking mappings */
|
||||||
|
for (n = 0; n <= 0xFF; n += 0x11)
|
||||||
|
{
|
||||||
|
normcols[n][0] = normcols[n][1] = grey;
|
||||||
|
}
|
||||||
|
/* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are grey */
|
||||||
|
for (n = 0; n <= 0x77; n += 0x11)
|
||||||
|
{
|
||||||
|
blinkcols[n][0] = blinkcols[n][1] = grey;
|
||||||
|
blinkcols[n+128][0] = blinkcols[n+128][1] = grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *t1000_init(device_t *info)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = malloc(sizeof(t1000_t));
|
||||||
|
memset(t1000, 0, sizeof(t1000_t));
|
||||||
|
cga_init(&t1000->cga);
|
||||||
|
|
||||||
|
t1000->internal = 1;
|
||||||
|
|
||||||
|
/* 16k video RAM */
|
||||||
|
t1000->vram = malloc(0x4000);
|
||||||
|
|
||||||
|
timer_add(t1000_poll, &t1000->cga.vidtime, TIMER_ALWAYS_ENABLED, t1000);
|
||||||
|
|
||||||
|
/* Occupy memory between 0xB8000 and 0xBFFFF */
|
||||||
|
mem_mapping_add(&t1000->mapping, 0xb8000, 0x8000, t1000_read, NULL, NULL, t1000_write, NULL, NULL, NULL, 0, t1000);
|
||||||
|
/* Respond to CGA I/O ports */
|
||||||
|
io_sethandler(0x03d0, 0x000c, t1000_in, NULL, NULL, t1000_out, NULL, NULL, t1000);
|
||||||
|
|
||||||
|
/* Default attribute mapping is 4 */
|
||||||
|
t1000->attrmap = 4;
|
||||||
|
t1000_recalcattrs(t1000);
|
||||||
|
|
||||||
|
/* Start off in 80x25 text mode */
|
||||||
|
t1000->cga.cgastat = 0xF4;
|
||||||
|
t1000->cga.vram = t1000->vram;
|
||||||
|
t1000->enabled = 1;
|
||||||
|
t1000->video_options = 0x01;
|
||||||
|
language = device_get_config_int("display_language") ? 2 : 0;
|
||||||
|
return t1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t1000_close(void *p)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = (t1000_t *)p;
|
||||||
|
|
||||||
|
free(t1000->vram);
|
||||||
|
free(t1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t1000_speed_changed(void *p)
|
||||||
|
{
|
||||||
|
t1000_t *t1000 = (t1000_t *)p;
|
||||||
|
|
||||||
|
t1000_recalctimings(t1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_config_t t1000_config[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.name = "display_language",
|
||||||
|
.description = "Language",
|
||||||
|
.type = CONFIG_SELECTION,
|
||||||
|
.selection =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.description = "USA",
|
||||||
|
.value = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.description = "Danish",
|
||||||
|
.value = 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.default_int = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = -1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
device_t t1000_device =
|
||||||
|
{
|
||||||
|
"Toshiba T1000",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
t1000_init,
|
||||||
|
t1000_close,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
t1000_speed_changed,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
t1000_config
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
device_t t1200_device =
|
||||||
|
{
|
||||||
|
"Toshiba T1200",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
t1000_init,
|
||||||
|
t1000_close,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
t1000_speed_changed,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
t1000_config
|
||||||
|
};
|
5
src/video/vid_t1000.h
Normal file
5
src/video/vid_t1000.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
extern device_t t1000_device;
|
||||||
|
extern device_t t1200_device;
|
||||||
|
|
||||||
|
void t1000_video_options_set(uint8_t options);
|
||||||
|
void t1000_display_set(uint8_t internal);
|
@@ -8,7 +8,7 @@
|
|||||||
#
|
#
|
||||||
# Makefile for Win32 (MinGW32) environment.
|
# Makefile for Win32 (MinGW32) environment.
|
||||||
#
|
#
|
||||||
# Version: @(#)Makefile.mingw 1.0.104 2018/02/19
|
# Version: @(#)Makefile.mingw 1.0.105 2018/03/02
|
||||||
#
|
#
|
||||||
# Authors: Miran Grca, <mgrca8@gmail.com>
|
# Authors: Miran Grca, <mgrca8@gmail.com>
|
||||||
# Fred N. van Kempen, <decwiz@yahoo.com>
|
# Fred N. van Kempen, <decwiz@yahoo.com>
|
||||||
@@ -220,7 +220,11 @@ else
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
AFLAGS := -msse2 -mfpmath=sse
|
ifeq ($(W5580), y)
|
||||||
|
AFLAGS := -msse2 -msse3 -mssse3 -msse4 -msse4.1 -msse4.2 -mfpmath=sse
|
||||||
|
else
|
||||||
|
AFLAGS := -msse2 -mfpmath=sse
|
||||||
|
endif
|
||||||
RFLAGS := --input-format=rc -O coff
|
RFLAGS := --input-format=rc -O coff
|
||||||
ifeq ($(RELEASE), y)
|
ifeq ($(RELEASE), y)
|
||||||
OPTS += -DRELEASE_BUILD
|
OPTS += -DRELEASE_BUILD
|
||||||
@@ -377,7 +381,8 @@ CFLAGS := $(CFLAGS)
|
|||||||
#########################################################################
|
#########################################################################
|
||||||
MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \
|
MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \
|
||||||
pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \
|
pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \
|
||||||
device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ)
|
device.o nvr.o nvr_tc8521.o rtc_tc8521.o nvr_at.o \
|
||||||
|
nvr_ps2.o $(VNCOBJ) $(RDPOBJ)
|
||||||
|
|
||||||
INTELOBJ := intel.o \
|
INTELOBJ := intel.o \
|
||||||
intel_flash.o \
|
intel_flash.o \
|
||||||
@@ -390,6 +395,7 @@ CPUOBJ := cpu.o cpu_table.o \
|
|||||||
|
|
||||||
MCHOBJ := machine.o machine_table.o \
|
MCHOBJ := machine.o machine_table.o \
|
||||||
m_xt.o m_xt_compaq.o \
|
m_xt.o m_xt_compaq.o \
|
||||||
|
m_xt_t1000.o \
|
||||||
m_pcjr.o \
|
m_pcjr.o \
|
||||||
m_amstrad.o \
|
m_amstrad.o \
|
||||||
m_europc.o m_europc_hdc.o \
|
m_europc.o m_europc_hdc.o \
|
||||||
@@ -486,7 +492,7 @@ VIDOBJ := video.o \
|
|||||||
vid_hercules.o vid_herculesplus.o vid_incolor.o \
|
vid_hercules.o vid_herculesplus.o vid_incolor.o \
|
||||||
vid_colorplus.o \
|
vid_colorplus.o \
|
||||||
vid_genius.o \
|
vid_genius.o \
|
||||||
vid_t3100e.o \
|
vid_t1000.o vid_t3100e.o \
|
||||||
vid_wy700.o \
|
vid_wy700.o \
|
||||||
vid_ega.o vid_ega_render.o \
|
vid_ega.o vid_ega_render.o \
|
||||||
vid_svga.o vid_svga_render.o \
|
vid_svga.o vid_svga_render.o \
|
||||||
|
Reference in New Issue
Block a user