Ported over the VARCem NVR commit.

This commit is contained in:
OBattler
2018-03-13 03:46:10 +01:00
parent 4ca7abf6fe
commit ddcb901421
22 changed files with 4206 additions and 2397 deletions

View File

@@ -1,9 +1,155 @@
/*
* 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 T3100e.
*
* The Toshiba 3100e is a 286-based portable.
*
* To bring up the BIOS setup screen hold down the 'Fn' key
* on booting.
*
* Memory management
* ~~~~~~~~~~~~~~~~~
*
* Motherboard memory is divided into:
* - Conventional memory: Either 512k or 640k
* - Upper memory: Either 512k or 384k, depending on
* amount of conventional memory.
* Upper memory can be used as EMS or XMS.
* - High memory: 0-4Mb, depending on RAM installed.
* The BIOS setup screen allows some or
* all of this to be used as EMS; the
* remainder is XMS.
*
* Additional memory (either EMS or XMS) can also be provided
* by ISA expansion cards.
*
* Under test in PCem, the BIOS will boot with up to 65368Kb
* of memory in total (16Mb less 16k). However it will give
* an error with RAM sizes above 8Mb, if any of the high
* memory is allocated as EMS, because the builtin EMS page
* registers can only access up to 8Mb.
*
* Memory is controlled by writes to I/O port 8084h:
* Bit 7: Always 0 }
* Bit 6: Always 1 } These bits select which motherboard
* Bit 5: Always 0 } function to access.
* Bit 4: Set to treat upper RAM as XMS
* Bit 3: Enable external RAM boards?
* Bit 2: Set for 640k conventional memory, clear for 512k
* Bit 1: Enable RAM beyond 1Mb.
* Bit 0: Enable EMS.
*
* The last value written to this port is saved at 0040:0093h,
* and in CMOS memory at offset 0x37. If the top bit of the
* CMOS byte is set, then high memory is being provided by
* an add-on card rather than the mainboard; accordingly,
* the BIOS will not allow high memory to be used as EMS.
*
* EMS is controlled by 16 page registers:
*
* Page mapped at 0xD000 0xD400 0xD800 0xDC00
* ------------------------------------------------------
* Pages 0x00-0x7F 0x208 0x4208 0x8208 0xc208
* Pages 0x80-0xFF 0x218 0x4218 0x8218 0xc218
* Pages 0x100-0x17F 0x258 0x4258 0x8258 0xc258
* Pages 0x180-0x1FF 0x268 0x4268 0x8268 0xc268
*
* The value written has bit 7 set to enable EMS, reset to
* disable it.
*
* So:
* OUT 0x208, 0x80 will page in the first 16k page at 0xD0000.
* OUT 0x208, 0x00 will page out EMS, leaving nothing at 0xD0000.
* OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000.
* OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000.
* etc.
*
* To use EMS from DOS, you will need the Toshiba EMS driver
* (TOSHEMM.ZIP). This supports the above system, plus further
* ranges of ports at 0x_2A8, 0x_2B8, 0x_2C8.
*
* Features not implemented:
* > Four video fonts.
* > BIOS-controlled mapping of serial ports to IRQs.
* > Custom keyboard controller. This has a number of extra
* commands in the 0xB0-0xBC range, for such things as turbo
* on/off, and switching the keyboard between AT and PS/2
* modes. Currently I have only implemented command 0xBB,
* so that self-test completes successfully. Commands include:
*
* 0xB0: Turbo on
* 0xB1: Turbo off
* 0xB2: Internal display on?
* 0xB3: Internal display off?
* 0xB5: Get settings byte (bottom bit is color/mono setting)
* 0xB6: Set settings byte
* 0xB7: Behave as 101-key PS/2 keyboard
* 0xB8: Behave as 84-key AT keyboard
* 0xBB: Return a byte, bit 2 is Fn key state, other bits unknown.
*
* The other main I/O port needed to POST is:
* 0x8084: System control.
* Top 3 bits give command, bottom 5 bits give parameters.
* 000 => set serial port IRQ / addresses
* bit 4: IRQ5 serial port base: 1 => 0x338, 0 => 0x3E8
* bits 3, 2, 0 specify serial IRQs for COM1, COM2, COM3:
* 00 0 => 4, 3, 5
* 00 1 => 4, 5, 3
* 01 0 => 3, 4, 5
* 01 1 => 3, 5, 4
* 10 0 => 4, -, 3
* 10 1 => 3, -, 4
* 010 => set memory mappings
* bit 4 set if upper RAM is XMS
* bit 3 enable add-on memory boards beyond 5Mb?
* bit 2 set for 640k sysram, clear for 512k sysram
* bit 1 enable mainboard XMS
* bit 0 enable mainboard EMS
* 100 => set parallel mode / LCD settings
* bit 4 set for bidirectional parallel port
* bit 3 set to disable internal CGA
* bit 2 set for single-pixel LCD font
* bits 0,1 for display font
*
* Version: @(#)m_at_t3100e.c 1.0.3 2018/03/05
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../io.h"
#include "../mouse.h"
@@ -13,124 +159,18 @@
#include "../cpu/cpu.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../video/vid_t3100e.h"
#include "machine.h"
#include "m_at_t3100e.h"
/* The Toshiba 3100e is a 286-based portable.
*
* To bring up the BIOS setup screen hold down the 'Fn' key on booting
*
* Memory management
* ~~~~~~~~~~~~~~~~~
*
* Motherboard memory is divided into:
* - Conventional memory: Either 512k or 640k
* - Upper memory: Either 512k or 384k, depending on amount of
* conventional memory. Upper memory can be
* used either as EMS or XMS.
* - High memory: 0-4Mb, depending on RAM installed. The BIOS
* setup screen allows some or all of this to be
* used as EMS; the remainder is XMS.
*
* Additional memory (either EMS or XMS) can also be provided by ISA
* expansion cards.
*
* Under test in PCEM, the BIOS will boot with up to 65368Kb of memory in
* total (16Mb less 16k). However it will give an error with RAM sizes
* above 8Mb, if any of the high memory is allocated as EMS, because the
* builtin EMS page registers can only access up to 8Mb.
*
* Memory is controlled by writes to I/O port 8084h:
* Bit 7: Always 0 }
* Bit 6: Always 1 } These bits select which motherboard function to
* Bit 5: Always 0 } access.
* Bit 4: Set to treat upper RAM as XMS
* Bit 3: Enable external RAM boards?
* Bit 2: Set for 640k conventional memory, clear for 512k
* Bit 1: Enable RAM beyond 1Mb.
* Bit 0: Enable EMS.
*
* The last value written to this port is saved at 0040:0093h, and in
* CMOS memory at offset 0x37. If the top bit of the CMOS byte is set,
* then high memory is being provided by an add-on card rather than the
* mainboard; accordingly, the BIOS will not allow high memory to be
* used as EMS.
*
* EMS is controlled by 16 page registers:
*
* Page mapped at 0xD000 0xD400 0xD800 0xDC00
* ------------------------------------------------------
* Pages 0x00-0x7F 0x208 0x4208 0x8208 0xc208
* Pages 0x80-0xFF 0x218 0x4218 0x8218 0xc218
* Pages 0x100-0x17F 0x258 0x4258 0x8258 0xc258
* Pages 0x180-0x1FF 0x268 0x4268 0x8268 0xc268
*
* The value written has bit 7 set to enable EMS, reset to disable it.
*
* So: OUT 0x208, 0x80 will page in the first 16k page at 0xD0000.
* OUT 0x208, 0x00 will page out EMS, leaving nothing at 0xD0000.
* OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000.
* OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000.
*
* etc.
*
* To use EMS from DOS, you will need the Toshiba EMS driver (TOSHEMM.ZIP).
* This supports the above system, plus further ranges of ports at
* 0x_2A8, 0x_2B8, 0x_2C8.
*
*/
static const int t3100e_log = 0;
extern uint8_t *ram; /* Physical RAM */
/* Features not implemented:
* > Four video fonts.
* > BIOS-controlled mapping of serial ports to IRQs.
* > Custom keyboard controller. This has a number of extra commands in the
* 0xB0-0xBC range, for such things as turbo on/off, and switching the
* keyboard between AT and PS/2 modes. Currently I have only implemented
* command 0xBB, so that self-test completes successfully. Commands include:
*
* 0xB0: Turbo on
* 0xB1: Turbo off
* 0xB2: Internal display on?
* 0xB3: Internal display off?
* 0xB5: Get settings byte (bottom bit is colour / mono setting)
* 0xB6: Set settings byte
* 0xB7: Behave as 101-key PS/2 keyboard
* 0xB8: Behave as 84-key AT keyboard
* 0xBB: Return a byte, bit 2 is Fn key state, other bits unknown.
*
* The other main I/O port needed to POST is:
* 0x8084: System control.
* Top 3 bits give command, bottom 5 bits give parameters.
* 000 => set serial port IRQ / addresses
* bit 4: IRQ5 serial port base: 1 => 0x338, 0 => 0x3E8
* bits 3, 2, 0 specify serial IRQs for COM1, COM2, COM3:
* 00 0 => 4, 3, 5
* 00 1 => 4, 5, 3
* 01 0 => 3, 4, 5
* 01 1 => 3, 5, 4
* 10 0 => 4, -, 3
* 10 1 => 3, -, 4
* 010 => set memory mappings
* bit 4 set if upper RAM is XMS
* bit 3 enable add-on memory boards beyond 5Mb?
* bit 2 set for 640k sysram, clear for 512k sysram
* bit 1 enable mainboard XMS
* bit 0 enable mainboard EMS
* 100 => set parallel mode / LCD settings
* bit 4 set for bidirectional parallel port
* bit 3 set to disable internal CGA
* bit 2 set for single-pixel LCD font
* bits 0,1 for display font
*/
void at_init();
static const int t3100e_log = 0;
/* The T3100e motherboard can (and does) dynamically reassign RAM between
* conventional, XMS and EMS. This translates to monkeying with the mappings.
*/

View File

@@ -1,7 +1,58 @@
void t3100e_notify_set(uint8_t value);
void t3100e_display_set(uint8_t value);
uint8_t t3100e_display_get();
uint8_t t3100e_config_get();
void t3100e_turbo_set(uint8_t value);
uint8_t t3100e_mono_get();
void t3100e_mono_set(uint8_t value);
/*
* 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.
*
* Definitions for the Toshiba T3100e system.
*
* Version: @(#)m_at_t3100e.h 1.0.2 2018/03/05
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-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.
*/
#ifndef MACHINE_T3100E_H
# define MACHINE_T3100E_H
extern device_t t3100e_device;
extern void t3100e_notify_set(uint8_t value);
extern void t3100e_display_set(uint8_t value);
extern uint8_t t3100e_display_get(void);
extern uint8_t t3100e_config_get(void);
extern void t3100e_turbo_set(uint8_t value);
extern uint8_t t3100e_mono_get(void);
extern void t3100e_mono_set(uint8_t value);
extern void t3100e_video_options_set(uint8_t options);
extern void t3100e_display_set(uint8_t internal);
#endif /*MACHINE_T3100E_H*/

View File

@@ -0,0 +1,763 @@
/*
* 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 3100e plasma display.
* This display has a fixed 640x400 resolution.
*
* T3100e CRTC regs (from the ROM):
*
* Selecting a character height of 3 seems to be sufficient to
* convert the 640x200 graphics mode to 640x400 (and, by
* analogy, 320x200 to 320x400).
*
* Horiz-----> Vert------> I ch
* 38 28 2D 0A 1F 06 19 1C 02 07 06 07 CO40
* 71 50 5A 0A 1F 06 19 1C 02 07 06 07 CO80
* 38 28 2D 0A 7F 06 64 70 02 01 06 07 Graphics
* 61 50 52 0F 19 06 19 19 02 0D 0B 0C MONO
* 2D 28 22 0A 67 00 64 67 02 03 06 07 640x400
*
* Version: @(#)m_at_t3100e_vid.c 1.0.3 2018/03/07
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-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 <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/video.h"
#include "../video/vid_cga.h"
#include "m_at_t3100e.h"
#define T3100E_XSIZE 640
#define T3100E_YSIZE 400
/* Mapping of attributes to colours */
static uint32_t amber, black;
static uint8_t boldcols[256]; /* Which attributes use the bold font */
static uint32_t blinkcols[256][2];
static uint32_t normcols[256][2];
/* Video options set by the motherboard; they will be picked up by the card
* on the next poll.
*
* Bit 3: Disable built-in video (for add-on card)
* Bit 2: Thin font
* Bits 0,1: Font set (not currently implemented)
*/
static uint8_t st_video_options;
static int8_t st_display_internal = -1;
void t3100e_video_options_set(uint8_t options)
{
st_video_options = options;
}
void t3100e_display_set(uint8_t internal)
{
st_display_internal = internal;
}
uint8_t t3100e_display_get()
{
return st_display_internal;
}
typedef struct t3100e_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;
} t3100e_t;
void t3100e_recalctimings(t3100e_t *t3100e);
void t3100e_write(uint32_t addr, uint8_t val, void *p);
uint8_t t3100e_read(uint32_t addr, void *p);
void t3100e_recalcattrs(t3100e_t *t3100e);
void t3100e_out(uint16_t addr, uint8_t val, void *p)
{
t3100e_t *t3100e = (t3100e_t *)p;
switch (addr)
{
/* Emulated CRTC, register select */
case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6:
cga_out(addr, val, &t3100e->cga);
break;
/* Emulated CRTC, value */
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
/* Register 0x12 controls the attribute mappings for the
* plasma screen. */
if (t3100e->cga.crtcreg == 0x12)
{
t3100e->attrmap = val;
t3100e_recalcattrs(t3100e);
return;
}
cga_out(addr, val, &t3100e->cga);
t3100e_recalctimings(t3100e);
return;
/* CGA control register */
case 0x3D8:
cga_out(addr, val, &t3100e->cga);
return;
/* CGA colour register */
case 0x3D9:
cga_out(addr, val, &t3100e->cga);
return;
}
}
uint8_t t3100e_in(uint16_t addr, void *p)
{
t3100e_t *t3100e = (t3100e_t *)p;
uint8_t val;
switch (addr)
{
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
if (t3100e->cga.crtcreg == 0x12)
{
val = t3100e->attrmap & 0x0F;
if (t3100e->internal) val |= 0x30; /* Plasma / CRT */
return val;
}
}
return cga_in(addr, &t3100e->cga);
}
void t3100e_write(uint32_t addr, uint8_t val, void *p)
{
t3100e_t *t3100e = (t3100e_t *)p;
egawrites++;
// pclog("CGA_WRITE %04X %02X\n", addr, val);
t3100e->vram[addr & 0x7fff] = val;
cycles -= 4;
}
uint8_t t3100e_read(uint32_t addr, void *p)
{
t3100e_t *t3100e = (t3100e_t *)p;
egareads++;
cycles -= 4;
// pclog("CGA_READ %04X\n", addr);
return t3100e->vram[addr & 0x7fff];
}
void t3100e_recalctimings(t3100e_t *t3100e)
{
double disptime;
double _dispontime, _dispofftime;
if (!t3100e->internal)
{
cga_recalctimings(&t3100e->cga);
return;
}
disptime = 651;
_dispontime = 640;
_dispofftime = disptime - _dispontime;
t3100e->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
t3100e->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
}
/* Draw a row of text in 80-column mode */
void t3100e_text_row80(t3100e_t *t3100e)
{
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 = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff;
sc = (t3100e->displine) & 15;
addr = ((ma & ~1) + (t3100e->displine >> 4) * 80) * 2;
ma += (t3100e->displine >> 4) * 80;
if ((t3100e->cga.crtc[10] & 0x60) == 0x20)
{
cursorline = 0;
}
else
{
cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) &&
((t3100e->cga.crtc[11] & 0x0F)*2 >= sc);
}
for (x = 0; x < 80; x++)
{
chr = t3100e->vram[(addr + 2 * x) & 0x7FFF];
attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF];
drawcursor = ((ma == ca) && cursorline &&
(t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16));
blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) &&
(attr & 0x80) && !drawcursor);
if (t3100e->video_options & 4)
bold = boldcols[attr] ? chr + 256 : chr;
else
bold = boldcols[attr] ? chr : chr + 256;
bold += 512 * (t3100e->video_options & 3);
if (t3100e->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[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black);
}
}
else
{
for (c = 0; c < 8; c++)
((uint32_t *)buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
}
++ma;
}
}
/* Draw a row of text in 40-column mode */
void t3100e_text_row40(t3100e_t *t3100e)
{
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 = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff;
sc = (t3100e->displine) & 15;
addr = ((ma & ~1) + (t3100e->displine >> 4) * 40) * 2;
ma += (t3100e->displine >> 4) * 40;
if ((t3100e->cga.crtc[10] & 0x60) == 0x20)
{
cursorline = 0;
}
else
{
cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) &&
((t3100e->cga.crtc[11] & 0x0F)*2 >= sc);
}
for (x = 0; x < 40; x++)
{
chr = t3100e->vram[(addr + 2 * x) & 0x7FFF];
attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF];
drawcursor = ((ma == ca) && cursorline &&
(t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16));
blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) &&
(attr & 0x80) && !drawcursor);
if (t3100e->video_options & 4)
bold = boldcols[attr] ? chr + 256 : chr;
else bold = boldcols[attr] ? chr : chr + 256;
bold += 512 * (t3100e->video_options & 3);
if (t3100e->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[t3100e->displine])[(x << 4) + c*2] =
((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2 + 1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black);
}
}
else
{
for (c = 0; c < 8; c++)
{
((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] =
((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2+1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
}
}
++ma;
}
}
/* Draw a line in CGA 640x200 or T3100e 640x400 mode */
void t3100e_cgaline6(t3100e_t *t3100e)
{
int x, c;
uint8_t dat;
uint32_t ink = 0;
uint16_t addr;
uint32_t fg = (t3100e->cga.cgacol & 0x0F) ? amber : black;
uint32_t bg = black;
uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
if (t3100e->cga.crtc[9] == 3) /* 640*400 */
{
addr = ((t3100e->displine) & 1) * 0x2000 +
((t3100e->displine >> 1) & 1) * 0x4000 +
(t3100e->displine >> 2) * 80 +
((ma & ~1) << 1);
}
else
{
addr = ((t3100e->displine >> 1) & 1) * 0x2000 +
(t3100e->displine >> 2) * 80 +
((ma & ~1) << 1);
}
for (x = 0; x < 80; x++)
{
dat = t3100e->vram[addr & 0x7FFF];
addr++;
for (c = 0; c < 8; c++)
{
ink = (dat & 0x80) ? fg : bg;
if (!(t3100e->cga.cgamode & 8)) ink = black;
((uint32_t *)buffer32->line[t3100e->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 */
void t3100e_cgaline4(t3100e_t *t3100e)
{
int x, c;
uint8_t dat, pattern;
uint32_t ink0 = 0, ink1 = 0;
uint16_t addr;
uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
if (t3100e->cga.crtc[9] == 3) /* 320*400 undocumented */
{
addr = ((t3100e->displine) & 1) * 0x2000 +
((t3100e->displine >> 1) & 1) * 0x4000 +
(t3100e->displine >> 2) * 80 +
((ma & ~1) << 1);
}
else /* 320*200 */
{
addr = ((t3100e->displine >> 1) & 1) * 0x2000 +
(t3100e->displine >> 2) * 80 +
((ma & ~1) << 1);
}
for (x = 0; x < 80; x++)
{
dat = t3100e->vram[addr & 0x7FFF];
addr++;
for (c = 0; c < 4; c++)
{
pattern = (dat & 0xC0) >> 6;
if (!(t3100e->cga.cgamode & 8)) pattern = 0;
switch (pattern & 3)
{
case 0: ink0 = ink1 = black; break;
case 1: if (t3100e->displine & 1)
{
ink0 = black; ink1 = black;
}
else
{
ink0 = amber; ink1 = black;
}
break;
case 2: if (t3100e->displine & 1)
{
ink0 = black; ink1 = amber;
}
else
{
ink0 = amber; ink1 = black;
}
break;
case 3: ink0 = ink1 = amber; break;
}
((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c] = ink0;
((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c+1] = ink1;
dat = dat << 2;
}
}
}
void t3100e_poll(void *p)
{
t3100e_t *t3100e = (t3100e_t *)p;
if (t3100e->video_options != st_video_options)
{
t3100e->video_options = st_video_options;
if (t3100e->video_options & 8) /* Disable internal CGA */
mem_mapping_disable(&t3100e->mapping);
else mem_mapping_enable(&t3100e->mapping);
/* Set the font used for the external display */
t3100e->cga.fontbase = (512 * (t3100e->video_options & 3))
+ ((t3100e->video_options & 4) ? 256 : 0);
}
/* Switch between internal plasma and external CRT display. */
if (st_display_internal != -1 && st_display_internal != t3100e->internal)
{
t3100e->internal = st_display_internal;
t3100e_recalctimings(t3100e);
}
if (!t3100e->internal)
{
cga_poll(&t3100e->cga);
return;
}
if (!t3100e->linepos)
{
t3100e->cga.vidtime += t3100e->dispofftime;
t3100e->cga.cgastat |= 1;
t3100e->linepos = 1;
if (t3100e->dispon)
{
if (t3100e->displine == 0)
{
video_wait_for_buffer();
}
/* Graphics */
if (t3100e->cga.cgamode & 0x02)
{
if (t3100e->cga.cgamode & 0x10)
t3100e_cgaline6(t3100e);
else t3100e_cgaline4(t3100e);
}
else
if (t3100e->cga.cgamode & 0x01) /* High-res text */
{
t3100e_text_row80(t3100e);
}
else
{
t3100e_text_row40(t3100e);
}
}
t3100e->displine++;
/* Hardcode a fixed refresh rate and VSYNC timing */
if (t3100e->displine == 400) /* Start of VSYNC */
{
t3100e->cga.cgastat |= 8;
t3100e->dispon = 0;
}
if (t3100e->displine == 416) /* End of VSYNC */
{
t3100e->displine = 0;
t3100e->cga.cgastat &= ~8;
t3100e->dispon = 1;
}
}
else
{
if (t3100e->dispon)
{
t3100e->cga.cgastat &= ~1;
}
t3100e->cga.vidtime += t3100e->dispontime;
t3100e->linepos = 0;
if (t3100e->displine == 400)
{
/* Hardcode 640x400 window size */
if (T3100E_XSIZE != xsize || T3100E_YSIZE != ysize)
{
xsize = T3100E_XSIZE;
ysize = T3100E_YSIZE;
if (xsize < 64) xsize = 656;
if (ysize < 32) ysize = 200;
set_screen_size(xsize, ysize);
}
video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize);
frames++;
/* Fixed 640x400 resolution */
video_res_x = T3100E_XSIZE;
video_res_y = T3100E_YSIZE;
if (t3100e->cga.cgamode & 0x02)
{
if (t3100e->cga.cgamode & 0x10)
video_bpp = 1;
else video_bpp = 2;
}
else video_bpp = 0;
t3100e->cga.cgablink++;
}
}
}
void t3100e_recalcattrs(t3100e_t *t3100e)
{
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 */
amber = makecol(0xf7, 0x7C, 0x34);
black = makecol(0x17, 0x0C, 0x00);
/* Initialise the attribute mapping. Start by defaulting everything
* to black on amber, and with bold set by bit 3 */
for (n = 0; n < 256; n++)
{
boldcols[n] = (n & 8) != 0;
blinkcols[n][0] = normcols[n][0] = amber;
blinkcols[n][1] = normcols[n][1] = black;
}
/* Colours 0x11-0xFF are controlled by bits 2 and 3 of the
* passed value. Exclude x0 and x8, which are always black on
* amber. */
for (n = 0x11; n <= 0xFF; n++)
{
if ((n & 7) == 0) continue;
if (t3100e->attrmap & 4) /* Inverse */
{
blinkcols[n][0] = normcols[n][0] = amber;
blinkcols[n][1] = normcols[n][1] = black;
}
else /* Normal */
{
blinkcols[n][0] = normcols[n][0] = black;
blinkcols[n][1] = normcols[n][1] = amber;
}
if (t3100e->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 (t3100e->attrmap & 1)
{
blinkcols[n][0] = normcols[n][0] = amber;
blinkcols[n][1] = normcols[n][1] = black;
blinkcols[n+128][0] = amber;
blinkcols[n+128][1] = black;
}
else
{
blinkcols[n][0] = normcols[n][0] = black;
blinkcols[n][1] = normcols[n][1] = amber;
blinkcols[n+128][0] = black;
blinkcols[n+128][1] = amber;
}
if (t3100e->attrmap & 2) boldcols[n] = 1;
}
/* Colours 07 and 0F are always amber on black. If blinking is
* enabled so are 87 and 8F. */
for (n = 0x07; n <= 0x0F; n += 8)
{
blinkcols[n][0] = normcols[n][0] = black;
blinkcols[n][1] = normcols[n][1] = amber;
blinkcols[n+128][0] = black;
blinkcols[n+128][1] = amber;
}
/* When not blinking, colours 81-8F are always amber on black. */
for (n = 0x81; n <= 0x8F; n ++)
{
normcols[n][0] = black;
normcols[n][1] = amber;
boldcols[n] = (n & 0x08) != 0;
}
/* Finally do the ones which are solid black. These differ between
* the normal and blinking mappings */
for (n = 0; n <= 0xFF; n += 0x11)
{
normcols[n][0] = normcols[n][1] = black;
}
/* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are black */
for (n = 0; n <= 0x77; n += 0x11)
{
blinkcols[n][0] = blinkcols[n][1] = black;
blinkcols[n+128][0] = blinkcols[n+128][1] = black;
}
}
void *t3100e_init(device_t *info)
{
t3100e_t *t3100e = malloc(sizeof(t3100e_t));
memset(t3100e, 0, sizeof(t3100e_t));
cga_init(&t3100e->cga);
t3100e->internal = 1;
/* 32k video RAM */
t3100e->vram = malloc(0x8000);
timer_add(t3100e_poll, &t3100e->cga.vidtime, TIMER_ALWAYS_ENABLED, t3100e);
/* Occupy memory between 0xB8000 and 0xBFFFF */
mem_mapping_add(&t3100e->mapping, 0xb8000, 0x8000, t3100e_read, NULL, NULL, t3100e_write, NULL, NULL, NULL, 0, t3100e);
/* Respond to CGA I/O ports */
io_sethandler(0x03d0, 0x000c, t3100e_in, NULL, NULL, t3100e_out, NULL, NULL, t3100e);
/* Default attribute mapping is 4 */
t3100e->attrmap = 4;
t3100e_recalcattrs(t3100e);
/* Start off in 80x25 text mode */
t3100e->cga.cgastat = 0xF4;
t3100e->cga.vram = t3100e->vram;
t3100e->enabled = 1;
t3100e->video_options = 0xFF;
return t3100e;
}
void t3100e_close(void *p)
{
t3100e_t *t3100e = (t3100e_t *)p;
free(t3100e->vram);
free(t3100e);
}
void t3100e_speed_changed(void *p)
{
t3100e_t *t3100e = (t3100e_t *)p;
t3100e_recalctimings(t3100e);
}
device_t t3100e_device =
{
"Toshiba T3100e",
0,
0,
t3100e_init,
t3100e_close,
NULL,
NULL,
t3100e_speed_changed,
NULL,
NULL
};

View File

@@ -1,10 +1,10 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
* 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 86Box distribution.
* This file is part of the VARCem Project.
*
* Implementation of the Schneider EuroPC system.
*
@@ -27,8 +27,7 @@
* f000:ecc5 801a video setup error
* f000:d6c9 copyright output
* f000:e1b7
* f000:e1be DI bits set mean output text!!!,
* (801a)
* f000:e1be DI bits set mean output text!!! (801a)
* f000: 0x8000 output
* 1 rtc error
* 2 rtc time or date error
@@ -53,21 +52,23 @@
* output cl at jim 0xa
* write ah hinibble as lownibble into jim 0xa
* write ah lownibble into jim 0xa
* f000:ef66 RTC read reg cl
* f000:ef66 RTC read reg cl
* polls until jim 0xa is zero,
* output cl at jim 0xa
* read low 4 nibble at jim 0xa
* read low 4 nibble at jim 0xa
* return first nibble<<4|second nibble in ah
* f000:f046 seldom compares ret
* f000:fe87 0 -> ds
* 0000:0469 bit 0: b0000 memory available
* f000:f046 seldom compares ret
* f000:fe87 0 -> ds
*
* Memory:
* 0000:0469 bit 0: b0000 memory available
* bit 1: b8000 memory available
* 0000:046a: 00 jim 250 01 jim 350
* 0000:046a: 00 jim 250 01 jim 350
*
* WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK.
*
* Version: @(#)europc.c 1.0.6 2018/01/16
* Version: @(#)europc.c 1.0.2 2018/03/11
*
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
*
@@ -77,12 +78,43 @@
* input from people with real EuroPC hardware.
*
* Copyright 2017,2018 Fred N. van Kempen.
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <time.h>
#include "../86box.h"
#include "../io.h"
#include "../nmi.h"
@@ -90,17 +122,17 @@
#include "../rom.h"
#include "../nvr.h"
#include "../device.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../disk/hdc.h"
#include "../keyboard.h"
#include "../mouse.h"
#include "../game/gameport.h"
#include "../floppy/fdd.h"
#include "../floppy/fdc.h"
#include "../disk/hdc.h"
#include "../video/video.h"
#include "machine.h"
#define EUROPC_DEBUG 1 /* current debugging level */
#define EUROPC_DEBUG 0 /* current debugging level */
/* M3002 RTC chip registers. */
@@ -109,7 +141,7 @@
#define MRTC_HOURS 0x02 /* BCD, 00-23 */
#define MRTC_DAYS 0x03 /* BCD, 01-31 */
#define MRTC_MONTHS 0x04 /* BCD, 01-12 */
#define MRTC_YEARS 0x05 /* BCD, 00-99 (2017 is 0x17) */
#define MRTC_YEARS 0x05 /* BCD, 00-99 (year only) */
#define MRTC_WEEKDAY 0x06 /* BCD, 01-07 */
#define MRTC_WEEKNO 0x07 /* BCD, 01-52 */
#define MRTC_CONF_A 0x08 /* EuroPC config, binary */
@@ -121,127 +153,232 @@
#define MRTC_CHECK_HI 0x0e /* Checksum, high byte */
#define MRTC_CTRLSTAT 0x0f /* RTC control/status, binary */
typedef struct {
uint16_t jim; /* JIM base address */
uint8_t regs[16]; /* JIM internal regs (8) */
struct {
uint8_t dat[16];
uint8_t stat;
uint8_t addr;
} rtc;
nvr_t nvr; /* 86Box NVR */
} vm_t;
nvr_t nvr; /* NVR */
uint8_t nvr_stat;
uint8_t nvr_addr;
} europc_t;
static vm_t *vm = NULL;
static europc_t europc;
/* Load the relevant portion of the NVR to disk. */
static int8_t
load_nvr(wchar_t *fn)
{
FILE *f;
if (vm == NULL) return(0);
f = nvr_fopen(fn, L"rb");
if (f != NULL) {
(void)fread(vm->rtc.dat, 1, 16, f);
(void)fclose(f);
pclog("EuroPC: CMOS data loaded from file %ls !\n", fn);
return(1);
}
pclog("EuroPC: unable to load NVR !\n");
return(0);
}
/* Save the relevant portion of the NVR to disk. */
static int8_t
save_nvr(wchar_t *fn)
{
FILE *f;
if (vm == NULL) return(0);
f = nvr_fopen(fn, L"wb");
if (f != NULL) {
(void)fwrite(vm->rtc.dat, 1, 16, f);
(void)fclose(f);
return(1);
}
pclog("EuroPC: unable to save NVR !\n");
return(0);
}
/* This is called every second through the NVR/RTC hook. */
/*
* This is called every second through the NVR/RTC hook.
*
* We fake a 'running' RTC by updating its registers on
* each passing second. Not exactly accurate, but good
* enough.
*
* Note that this code looks nasty because of all the
* BCD to decimal vv going on.
*
* FIXME: should we mark NVR as dirty?
*/
static void
rtc_hook(nvr_t *nvr)
rtc_tick(nvr_t *nvr)
{
#if 0
int month, year;
uint8_t *regs;
int mon, yr;
sys->rtc.dat[0] = bcd_adjust(sys->rtc.dat[0]+1);
if (sys->rtc.dat[0] >= 0x60) {
sys->rtc.dat[0] = 0;
sys->rtc.dat[1] = bcd_adjust(sys->rtc.dat[1]+1);
if (sys->rtc.dat[1] >= 0x60) {
sys->rtc.dat[1] = 0;
sys->rtc.dat[2] = bcd_adjust(sys->rtc.dat[2]+1);
if (sys->rtc.dat[2] >= 0x24) {
sys->rtc.dat[2] = 0;
sys->uropc_rtc.data[3]=bcd_adjust(sys->uropc_rtc.data[3]+1);
month = bcd_2_dec(sys->rtc.dat[4]);
/* Only if RTC is running.. */
regs = nvr->regs;
if (! (regs[MRTC_CTRLSTAT] & 0x01)) return;
/* Save for julian_days_in_month_calculation. */
year = bcd_2_dec(sys->rtc.dat[5])+2000;
if (sys->rtc.dat[3] > gregorian_days_in_month(month, year)) {
sys->rtc.dat[3] = 1;
sys->rtc.dat[4] = bcd_adjust(sys->rtc.dat[4]+1);
if (sys->rtc.dat[4]>0x12) {
sys->rtc.dat[4] = 1;
sys->rtc.dat[5] = bcd_adjust(sys->rtc.dat[5]+1)&0xff;
}
regs[MRTC_SECONDS] = RTC_BCDINC(nvr->regs[MRTC_SECONDS], 1);
if (regs[MRTC_SECONDS] >= RTC_BCD(60)) {
regs[MRTC_SECONDS] = RTC_BCD(0);
regs[MRTC_MINUTES] = RTC_BCDINC(regs[MRTC_MINUTES], 1);
if (regs[MRTC_MINUTES] >= RTC_BCD(60)) {
regs[MRTC_MINUTES] = RTC_BCD(0);
regs[MRTC_HOURS] = RTC_BCDINC(regs[MRTC_HOURS], 1);
if (regs[MRTC_HOURS] >= RTC_BCD(24)) {
regs[MRTC_HOURS] = RTC_BCD(0);
regs[MRTC_DAYS] = RTC_BCDINC(regs[MRTC_DAYS], 1);
mon = RTC_DCB(regs[MRTC_MONTHS]);
yr = RTC_DCB(regs[MRTC_YEARS]) + 1900;
if (RTC_DCB(regs[MRTC_DAYS]) > nvr_get_days(mon, yr)) {
regs[MRTC_DAYS] = RTC_BCD(1);
regs[MRTC_MONTHS] = RTC_BCDINC(regs[MRTC_MONTHS], 1);
if (regs[MRTC_MONTHS] > RTC_BCD(12)) {
regs[MRTC_MONTHS] = RTC_BCD(1);
regs[MRTC_YEARS] = RTC_BCDINC(regs[MRTC_YEARS], 1) & 0xff;
}
}
}
}
}
}
/* Get the current NVR time. */
static void
rtc_time_get(uint8_t *regs, struct tm *tm)
{
/* NVR is in BCD data mode. */
tm->tm_sec = RTC_DCB(regs[MRTC_SECONDS]);
tm->tm_min = RTC_DCB(regs[MRTC_MINUTES]);
tm->tm_hour = RTC_DCB(regs[MRTC_HOURS]);
tm->tm_wday = (RTC_DCB(regs[MRTC_WEEKDAY]) - 1);
tm->tm_mday = RTC_DCB(regs[MRTC_DAYS]);
tm->tm_mon = (RTC_DCB(regs[MRTC_MONTHS]) - 1);
tm->tm_year = RTC_DCB(regs[MRTC_YEARS]);
#if USE_Y2K
tm->tm_year += (RTC_DCB(regs[MRTC_CENTURY]) * 100) - 1900;
#endif
}
/* Set the current NVR time. */
static void
rtc_time_set(uint8_t *regs, struct tm *tm)
{
/* NVR is in BCD data mode. */
regs[MRTC_SECONDS] = RTC_BCD(tm->tm_sec);
regs[MRTC_MINUTES] = RTC_BCD(tm->tm_min);
regs[MRTC_HOURS] = RTC_BCD(tm->tm_hour);
regs[MRTC_WEEKDAY] = RTC_BCD(tm->tm_wday + 1);
regs[MRTC_DAYS] = RTC_BCD(tm->tm_mday);
regs[MRTC_MONTHS] = RTC_BCD(tm->tm_mon + 1);
regs[MRTC_YEARS] = RTC_BCD(tm->tm_year % 100);
#if USE_Y2K
regs[MRTC_CENTURY] = RTC_BCD((tm->tm_year+1900) / 100);
#endif
}
static void
rtc_start(nvr_t *nvr)
{
struct tm tm;
/* Initialize the internal and chip times. */
if (enable_sync) {
/* Use the internal clock's time. */
nvr_time_get(&tm);
rtc_time_set(nvr->regs, &tm);
} else {
/* Set the internal clock from the chip time. */
rtc_time_get(nvr->regs, &tm);
nvr_time_set(&tm);
}
#if 0
void europc_rtc_init(void)
{
europc_rtc.data[0xf]=1;
europc_rtc.timer = timer_alloc(europc_rtc_timer);
timer_adjust(europc_rtc.timer, 0, 0, 1.0);
}
/* Start the RTC - BIOS will do this. */
nvr->regs[MRTC_CTRLSTAT] = 0x01;
#endif
}
/* Create a valid checksum for the current NVR data. */
static uint8_t
rtc_checksum(uint8_t *ptr)
{
uint8_t sum;
int i;
/* Calculate all bytes with XOR. */
sum = 0x00;
for (i=MRTC_CONF_A; i<=MRTC_CONF_E; i++)
sum += ptr[i];
return(sum);
}
/* Reset the machine's NVR to a sane state. */
static void
rtc_reset(nvr_t *nvr)
{
/* Initialize the RTC to a known state. */
nvr->regs[MRTC_SECONDS] = RTC_BCD(0); /* seconds */
nvr->regs[MRTC_MINUTES] = RTC_BCD(0); /* minutes */
nvr->regs[MRTC_HOURS] = RTC_BCD(0); /* hours */
nvr->regs[MRTC_DAYS] = RTC_BCD(1); /* days */
nvr->regs[MRTC_MONTHS] = RTC_BCD(1); /* months */
nvr->regs[MRTC_YEARS] = RTC_BCD(80); /* years */
nvr->regs[MRTC_WEEKDAY] = RTC_BCD(1); /* weekday */
nvr->regs[MRTC_WEEKNO] = RTC_BCD(1); /* weekno */
/*
* EuroPC System Configuration:
*
* [A] unknown
*
* [B] 7 1 bootdrive extern
* 0 bootdribe intern
* 6:5 11 invalid hard disk type
* 10 hard disk installed, type 2
* 01 hard disk installed, type 1
* 00 hard disk not installed
* 4:3 11 invalid external drive type
* 10 external drive 720K
* 01 external drive 360K
* 00 external drive disabled
* 2 unknown
* 1:0 11 invalid internal drive type
* 10 internal drive 360K
* 01 internal drive 720K
* 00 internal drive disabled
*
* [C] 7:6 unknown
* 5 monitor detection OFF
* 4 unknown
* 3:2 11 illegal memory size
* 10 512K
* 01 256K
* 00 640K
* 1:0 11 illegal game port
* 10 gameport as mouse port
* 01 gameport as joysticks
* 00 gameport disabled
*
* [D] 7:6 10 9MHz CPU speed
* 01 7MHz CPU speed
* 00 4.77 MHz CPU
* 5 unknown
* 4 external: color, internal: mono
* 3 unknown
* 2 internal video ON
* 1:0 11 mono
* 10 color80
* 01 color40
* 00 special (EGA,VGA etc)
*
* [E] 7:4 unknown
* 3:0 country (00=Deutschland, 0A=ASCII)
*/
nvr->regs[MRTC_CONF_A] = 0x00; /* CONFIG A */
nvr->regs[MRTC_CONF_B] = 0x0A; /* CONFIG B */
nvr->regs[MRTC_CONF_C] = 0x28; /* CONFIG C */
nvr->regs[MRTC_CONF_D] = 0x12; /* CONFIG D */
nvr->regs[MRTC_CONF_E] = 0x0A; /* CONFIG E */
nvr->regs[MRTC_CHECK_LO] = 0x00; /* checksum (LO) */
nvr->regs[MRTC_CHECK_HI] = 0x00; /* checksum (HI) */
nvr->regs[MRTC_CTRLSTAT] = 0x01; /* status/control */
/* Generate a valid checksum. */
nvr->regs[MRTC_CHECK_LO] = rtc_checksum(nvr->regs);
}
/* Execute a JIM control command. */
static void
jim_action(vm_t *sys, uint8_t reg, uint8_t val)
jim_set(europc_t *sys, uint8_t reg, uint8_t val)
{
switch(reg) {
case 0: /* MISC control (WO) */
//pclog("EuroPC: write MISC = %02x\n", val);
// bit0: enable MOUSE
// bit1: enable joystick
break;
case 2: /* AGA control */
//pclog("EuroPC: write AGA = %02x\n", val);
if (! (val & 0x80)) {
/* Reset AGA. */
break;
@@ -276,7 +413,6 @@ jim_action(vm_t *sys, uint8_t reg, uint8_t val)
break;
case 4: /* CPU Speed control */
//pclog("EuroPC: write CPUCLK = %02x\n", val);
switch(val & 0xc0) {
case 0x00: /* 4.77 MHz */
// cpu_set_clockscale(0, 1.0/2);
@@ -304,7 +440,7 @@ jim_action(vm_t *sys, uint8_t reg, uint8_t val)
static void
jim_write(uint16_t addr, uint8_t val, void *priv)
{
vm_t *sys = (vm_t *)priv;
europc_t *sys = (europc_t *)priv;
uint8_t b;
#if EUROPC_DEBUG > 1
@@ -320,28 +456,30 @@ jim_write(uint16_t addr, uint8_t val, void *priv)
case 0x05:
case 0x06:
case 0x07:
jim_action(sys, (addr & 0x07), val);
jim_set(sys, (addr & 0x07), val);
break;
case 0x0A: /* M3002 RTC INDEX/DATA register */
switch(sys->rtc.stat) {
case 0x0a: /* M3002 RTC INDEX/DATA register */
switch(sys->nvr_stat) {
case 0: /* save index */
sys->rtc.addr = val & 0x0f;
sys->rtc.stat++;
sys->nvr_addr = val & 0x0f;
sys->nvr_stat++;
break;
case 1: /* save data HI nibble */
b = sys->rtc.dat[sys->rtc.addr] & 0x0f;
b = sys->nvr.regs[sys->nvr_addr] & 0x0f;
b |= (val << 4);
sys->rtc.dat[sys->rtc.addr] = b;
sys->rtc.stat++;
sys->nvr.regs[sys->nvr_addr] = b;
sys->nvr_stat++;
nvr_dosave++;
break;
case 2: /* save data LO nibble */
b = sys->rtc.dat[sys->rtc.addr] & 0xf0;
b = sys->nvr.regs[sys->nvr_addr] & 0xf0;
b |= (val & 0x0f);
sys->rtc.dat[sys->rtc.addr] = b;
sys->rtc.stat = 0;
sys->nvr.regs[sys->nvr_addr] = b;
sys->nvr_stat = 0;
nvr_dosave++;
break;
}
break;
@@ -357,7 +495,7 @@ jim_write(uint16_t addr, uint8_t val, void *priv)
static uint8_t
jim_read(uint16_t addr, void *priv)
{
vm_t *sys = (vm_t *)priv;
europc_t *sys = (europc_t *)priv;
uint8_t r = 0xff;
switch (addr & 0x000f) {
@@ -375,20 +513,20 @@ jim_read(uint16_t addr, void *priv)
r = sys->regs[addr & 0x07];
break;
case 0x0A: /* M3002 RTC INDEX/DATA register */
switch(sys->rtc.stat) {
case 0x0a: /* M3002 RTC INDEX/DATA register */
switch(sys->nvr_stat) {
case 0:
r = 0x00;
break;
case 1: /* read data HI nibble */
r = (sys->rtc.dat[sys->rtc.addr] >> 4);
sys->rtc.stat++;
r = (sys->nvr.regs[sys->nvr_addr] >> 4);
sys->nvr_stat++;
break;
case 2: /* read data LO nibble */
r = (sys->rtc.dat[sys->rtc.addr] & 0x0f);
sys->rtc.stat = 0;
r = (sys->nvr.regs[sys->nvr_addr] & 0x0f);
sys->nvr_stat = 0;
break;
}
break;
@@ -406,120 +544,29 @@ jim_read(uint16_t addr, void *priv)
}
static uint8_t
rtc_checksum(uint8_t *ptr)
{
uint8_t sum;
int i;
/* Calculate all bytes with XOR. */
sum = 0x00;
for (i=MRTC_CONF_A; i<=MRTC_CONF_E; i++)
sum += ptr[i];
return(sum);
}
/*
* Initialize the mainboard 'device' of the machine.
*/
/* Initialize the mainboard 'device' of the machine. */
static void *
europc_boot(device_t *info)
{
vm_t *sys = vm;
europc_t *sys = &europc;
uint8_t b;
#if EUROPC_DEBUG
pclog("EuroPC: booting mainboard..\n");
#endif
/* Try to load the NVR from file. */
if (! nvr_load()) {
/* Load failed, reset to defaults. */
sys->rtc.dat[0x00] = 0x00; /* RTC seconds */
sys->rtc.dat[0x01] = 0x00; /* RTC minutes */
sys->rtc.dat[0x02] = 0x00; /* RTC hours */
sys->rtc.dat[0x03] = 0x01; /* RTC days */
sys->rtc.dat[0x04] = 0x01; /* RTC months */
sys->rtc.dat[0x05] = 0x17; /* RTC years */
sys->rtc.dat[0x06] = 0x01; /* RTC weekday */
sys->rtc.dat[0x07] = 0x01; /* RTC weekno */
/*
* EuroPC System Configuration:
*
* [A] unknown
*
* [B] 7 1 bootdrive extern
* 0 bootdribe intern
* 6:5 11 invalid hard disk type
* 10 hard disk installed, type 2
* 01 hard disk installed, type 1
* 00 hard disk not installed
* 4:3 11 invalid external drive type
* 10 external drive 720K
* 01 external drive 360K
* 00 external drive disabled
* 2 unknown
* 1:0 11 invalid internal drive type
* 10 internal drive 360K
* 01 internal drive 720K
* 00 internal drive disabled
*
* [C] 7:6 unknown
* 5 monitor detection OFF
* 4 unknown
* 3:2 11 illegal memory size
* 10 512K
* 01 256K
* 00 640K
* 1:0 11 illegal game port
* 10 gameport as mouse port
* 01 gameport as joysticks
* 00 gameport disabled
*
* [D] 7:6 10 9MHz CPU speed
* 01 7MHz CPU speed
* 00 4.77 MHz CPU
* 5 unknown
* 4 external: color, internal: mono
* 3 unknown
* 2 internal video ON
* 1:0 11 mono
* 10 color80
* 01 color40
* 00 special (EGA,VGA etc)
*
* [E] 7:4 unknown
* 3:0 country (00=Deutschland, 0A=ASCII)
*/
sys->rtc.dat[MRTC_CONF_A] = 0x00; /* CONFIG A */
sys->rtc.dat[MRTC_CONF_B] = 0x0A; /* CONFIG B */
sys->rtc.dat[MRTC_CONF_C] = 0x28; /* CONFIG C */
sys->rtc.dat[MRTC_CONF_D] = 0x12; /* CONFIG D */
sys->rtc.dat[MRTC_CONF_E] = 0x0A; /* CONFIG E */
sys->rtc.dat[MRTC_CHECK_LO] = 0x44; /* checksum (LO) */
sys->rtc.dat[MRTC_CHECK_HI] = 0x00; /* checksum (HI) */
sys->rtc.dat[MRTC_CTRLSTAT] = 0x01; /* status/control */
/* Provide correct checksum. */
sys->rtc.dat[MRTC_CHECK_LO] = rtc_checksum(sys->rtc.dat);
}
pclog("EuroPC: NVR=[ %02x %02x %02x %02x %02x ] %sVALID\n",
sys->rtc.dat[MRTC_CONF_A], sys->rtc.dat[MRTC_CONF_B],
sys->rtc.dat[MRTC_CONF_C], sys->rtc.dat[MRTC_CONF_D],
sys->rtc.dat[MRTC_CONF_E],
(sys->rtc.dat[MRTC_CHECK_LO]!=rtc_checksum(sys->rtc.dat))?"IN":"");
sys->nvr.regs[MRTC_CONF_A], sys->nvr.regs[MRTC_CONF_B],
sys->nvr.regs[MRTC_CONF_C], sys->nvr.regs[MRTC_CONF_D],
sys->nvr.regs[MRTC_CONF_E],
(sys->nvr.regs[MRTC_CHECK_LO]!=rtc_checksum(sys->nvr.regs))?"IN":"");
/*
* Now that we have initialized the NVR (either from file,
* or by setting it to defaults) we can start overriding it
* with values set by the 86Box user.
* with values set by the user.
*/
b = (sys->rtc.dat[MRTC_CONF_D] & ~0x17);
b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17);
switch(gfxcard) {
case GFX_CGA: /* Color, CGA */
case GFX_COLORPLUS: /* Color, Hercules ColorPlus */
@@ -536,10 +583,10 @@ europc_boot(device_t *info)
b |= 0x10; /* external video, special */
}
sys->rtc.dat[MRTC_CONF_D] = b;
sys->nvr.regs[MRTC_CONF_D] = b;
/* Update the memory size. */
b = (sys->rtc.dat[MRTC_CONF_C] & 0xf3);
b = (sys->nvr.regs[MRTC_CONF_C] & 0xf3);
switch(mem_size) {
case 256:
b |= 0x04;
@@ -553,10 +600,10 @@ europc_boot(device_t *info)
b |= 0x00;
break;
}
sys->rtc.dat[MRTC_CONF_C] = b;
sys->nvr.regs[MRTC_CONF_C] = b;
/* Update CPU speed. */
b = (sys->rtc.dat[MRTC_CONF_D] & 0x3f);
b = (sys->nvr.regs[MRTC_CONF_D] & 0x3f);
switch(cpu) {
case 0: /* 8088, 4.77 MHz */
b |= 0x00;
@@ -570,26 +617,26 @@ europc_boot(device_t *info)
b |= 0x80;
break;
}
sys->rtc.dat[MRTC_CONF_D] = b;
sys->nvr.regs[MRTC_CONF_D] = b;
/* Set up game port. */
b = (sys->rtc.dat[MRTC_CONF_C] & 0xfc);
b = (sys->nvr.regs[MRTC_CONF_C] & 0xfc);
if (mouse_type == MOUSE_TYPE_LOGIBUS) {
b |= 0x01; /* enable port as MOUSE */
} else if (joystick_type != 7) {
b |= 0x02; /* enable port as joysticks */
device_add(&gameport_device);
}
sys->rtc.dat[MRTC_CONF_C] = b;
sys->nvr.regs[MRTC_CONF_C] = b;
#if 0
/* Set up floppy types. */
sys->rtc.dat[MRTC_CONF_B] = 0x2A;
sys->nvr.regs[MRTC_CONF_B] = 0x2a;
#endif
/* Validate the NVR checksum. */
sys->rtc.dat[MRTC_CHECK_LO] = rtc_checksum(sys->rtc.dat);
nvr_save();
/* Validate the NVR checksum and save. */
sys->nvr.regs[MRTC_CHECK_LO] = rtc_checksum(sys->nvr.regs);
nvr_dosave++;
/*
* Allocate the system's I/O handlers.
@@ -600,11 +647,10 @@ europc_boot(device_t *info)
* the way of other cards that need this range.
*/
io_sethandler(sys->jim, 16,
jim_read, NULL, NULL,
jim_write, NULL, NULL, sys);
jim_read,NULL,NULL, jim_write,NULL,NULL, sys);
/* Only after JIM has been initialized. */
device_add(&keyboard_xt_device);
(void)device_add(&keyboard_xt_device);
/*
* Set up and enable the HD20 disk controller.
@@ -612,7 +658,7 @@ europc_boot(device_t *info)
* We only do this if we have not configured another one.
*/
if (hdc_current == 1)
device_add(&europc_hdc_device);
(void)device_add(&europc_hdc_device);
return(sys);
}
@@ -621,13 +667,10 @@ europc_boot(device_t *info)
static void
europc_close(void *priv)
{
nvr_t *nvr = &vm->nvr;
nvr_t *nvr = &europc.nvr;
if (nvr->fname != NULL)
free(nvr->fname);
free(vm);
vm = NULL;
if (nvr->fn != NULL)
free(nvr->fn);
}
@@ -655,9 +698,7 @@ static device_config_t europc_config[] = {
device_t europc_device = {
"EuroPC System Board",
0, 0,
europc_boot, /* init */
europc_close, /* close */
NULL,
europc_boot, europc_close, NULL,
NULL, NULL, NULL, NULL,
europc_config
};
@@ -674,36 +715,28 @@ device_t europc_device = {
void
machine_europc_init(machine_t *model)
{
vm_t *sys;
/* Allocate machine data. */
sys = (vm_t *)malloc(sizeof(vm_t));
if (sys == NULL) {
pclog("EuroPC: unable to allocate machine data!\n");
return;
}
memset(sys, 0x00, sizeof(vm_t));
sys->jim = 0x0250;
vm = sys;
/* Clear the machine state. */
memset(&europc, 0x00, sizeof(europc_t));
europc.jim = 0x0250;
machine_common_init(model);
nmi_init();
mem_add_bios();
/* This is machine specific. */
vm->nvr.mask = model->nvrmask;
vm->nvr.irq = -1;
europc.nvr.size = model->nvrmask + 1;
europc.nvr.irq = -1;
/* Set up any local handlers here. */
vm->nvr.load = load_nvr;
vm->nvr.save = save_nvr;
vm->nvr.hook = rtc_hook;
europc.nvr.reset = rtc_reset;
europc.nvr.start = rtc_start;
europc.nvr.tick = rtc_tick;
/* Initialize the actual NVR. */
nvr_init(&vm->nvr);
nvr_init(&europc.nvr);
/* Enable and set up the FDC. */
device_add(&fdc_xt_device);
(void)device_add(&fdc_xt_device);
/* Enable and set up the mainboard device. */
device_add(&europc_device);

View File

@@ -1,10 +1,10 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
* 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 86Box distribution.
* This file is part of the VARCem Project.
*
* Implementation of the EuroPC HD20 internal controller.
*
@@ -20,13 +20,45 @@
* This driver is based on the information found in the IBM-PC
* Technical Reference manual, pp 187 and on.
*
* Version: @(#)europc_hdc.c 1.0.2 2017/11/18
*
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
* Based on the original "xebec.c" from Sarah Walker.
*
* Version: @(#)m_europc_hdc.c 1.0.2 2018/03/11
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2008-2017 Sarah Walker.
* Copyright 2017 Fred N. van Kempen.
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define __USE_LARGEFILE64
#define _LARGEFILE_SOURCE
@@ -44,11 +76,12 @@
#include "../timer.h"
#include "../disk/hdc.h"
#include "../disk/hdd.h"
#include "../plat.h"
#include "../ui.h"
#include "machine.h"
#define HDC_DEBUG 1
#define HDC_DEBUG 0
#define HDC_NEWPARAMS 1 /* use NEW parameter block */
#define HDD_IOADDR 0x0320

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,59 @@
void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask);
/*
* 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.
*
* Definitions for the Toshiba T1000/T1200 machines.
*
* Version: @(#)m_xt_t1000.h 1.0.2 2018/03/10
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017,2018 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-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.
*/
#ifndef MACHINE_T1000_H
# define MACHINE_T1000_H
void t1000_configsys_loadnvr();
void t1000_emsboard_loadnvr();
void t1000_configsys_savenvr();
void t1000_emsboard_savenvr();
extern device_t t1000_video_device;
extern device_t t1200_video_device;
extern void t1000_video_options_set(uint8_t options);
extern void t1000_display_set(uint8_t internal);
extern void t1000_syskey(uint8_t amask, uint8_t omask, uint8_t xmask);
extern void t1000_configsys_load(void);
extern void t1000_configsys_save(void);
extern void t1000_emsboard_load(void);
extern void t1000_emsboard_save(void);
#endif /*MACHINE_T1000_H*/

View File

@@ -0,0 +1,753 @@
/*
* 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 plasma display, which
* has a fixed resolution of 640x200 pixels.
*
* Version: @(#)m_xt_t1000_vid.c 1.0.4 2018/03/10
*
* 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 <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/video.h"
#include "../video/vid_cga.h"
#include "m_xt_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 int8_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 = (int8_t)internal;
}
uint8_t t1000_display_get()
{
return (uint8_t)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)
{
default:
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;
set_screen_size(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_video_device = {
"Toshiba T1000 Video",
0, 0,
t1000_init, t1000_close, NULL,
NULL,
t1000_speed_changed,
NULL,
NULL,
t1000_config
};
device_t t1200_video_device = {
"Toshiba T1200 Video",
0, 0,
t1000_init, t1000_close, NULL,
NULL,
t1000_speed_changed,
NULL,
NULL,
t1000_config
};

View File

@@ -11,7 +11,7 @@
* NOTES: OpenAT wip for 286-class machine with open BIOS.
* PS2_M80-486 wip, pending receipt of TRM's for machine.
*
* Version: @(#)machine_table.c 1.0.24 2018/03/11
* Version: @(#)machine_table.c 1.0.25 2018/03/13
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -44,10 +44,10 @@ machine_t machines[] = {
{ "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL },
{ "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL },
{ "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_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] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, 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 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 | MACHINE_VIDEO, 512, 1280, 768, 0, machine_xt_t1000_init, NULL, NULL },
{ "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL, NULL },
#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 },
#endif
@@ -60,7 +60,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] 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] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 0, machine_xt_t1200_init, NULL, NULL },
{ "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL, NULL },
#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 },
#endif