diff --git a/src/keyboard.c b/src/keyboard.c
index 18ad354da..f181dbf92 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -8,7 +8,7 @@
*
* General keyboard driver interface.
*
- * Version: @(#)keyboard.c 1.0.9 2017/11/03
+ * Version: @(#)keyboard.c 1.0.10 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -194,6 +194,13 @@ keyboard_input(int down, uint16_t scan)
}
+int
+keyboard_recv(uint16_t key)
+{
+ return recv_key[key];
+}
+
+
/* Do we have Control-Alt-PgDn in the keyboard buffer? */
int
keyboard_isfsexit(void)
diff --git a/src/keyboard.h b/src/keyboard.h
index 2b885f030..46b4af46b 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -8,7 +8,7 @@
*
* Definitions for the keyboard interface.
*
- * Version: @(#)keyboard.h 1.0.6 2017/11/06
+ * Version: @(#)keyboard.h 1.0.7 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -60,6 +60,7 @@ extern void keyboard_poll_host(void);
extern void keyboard_process(void);
extern uint16_t keyboard_convert(int ch);
extern void keyboard_input(int down, uint16_t scan);
+extern int keyboard_recv(uint16_t key);
extern int keyboard_isfsexit(void);
extern int keyboard_ismsexit(void);
diff --git a/src/keyboard_at.c b/src/keyboard_at.c
index 1d771052a..17c7cdc31 100644
--- a/src/keyboard_at.c
+++ b/src/keyboard_at.c
@@ -8,7 +8,7 @@
*
* Intel 8042 (AT keyboard controller) emulation.
*
- * Version: @(#)keyboard_at.c 1.0.11 2017/12/25
+ * Version: @(#)keyboard_at.c 1.0.12 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -35,6 +35,7 @@
#include "device.h"
#include "timer.h"
#include "machine/machine.h"
+#include "machine/m_at_t3100e.h"
#include "floppy/floppy.h"
#include "floppy/fdc.h"
#include "sound/sound.h"
@@ -567,6 +568,29 @@ kbd_adddata_keyboard(uint8_t val)
return;
}
+ /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */
+ if (romset == ROM_T3100E && (keyboard_recv(0xb8) || keyboard_recv(0x9d)))
+ {
+ switch (val)
+ {
+ case 0x4f: t3100e_notify_set(0x01); break; /* End */
+ case 0x50: t3100e_notify_set(0x02); break; /* Down */
+ case 0x51: t3100e_notify_set(0x03); break; /* PgDn */
+ case 0x52: t3100e_notify_set(0x04); break; /* Ins */
+ case 0x53: t3100e_notify_set(0x05); break; /* Del */
+ case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */
+ case 0x45: t3100e_notify_set(0x07); break; /* NumLock */
+ case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */
+ case 0x47: t3100e_notify_set(0x09); break; /* Home */
+ case 0x48: t3100e_notify_set(0x0A); break; /* Up */
+ case 0x49: t3100e_notify_set(0x0B); break; /* PgUp */
+ case 0x4A: t3100e_notify_set(0x0C); break; /* Keypad -*/
+ case 0x4B: t3100e_notify_set(0x0D); break; /* Left */
+ case 0x4C: t3100e_notify_set(0x0E); break; /* KP 5 */
+ case 0x4D: t3100e_notify_set(0x0F); break; /* Right */
+ }
+ }
+
key_queue[key_queue_end] = (((keyboard_mode & 0x40) && !(keyboard_mode & 0x20)) ? (nont_to_t[val] | sc_or) : val);
key_queue_end = (key_queue_end + 1) & 0xf;
@@ -656,6 +680,11 @@ write_register:
}
break;
+ case 0xb6: /* T3100e - set colour/mono switch */
+ if (romset == ROM_T3100E)
+ t3100e_mono_set(val);
+ break;
+
case 0xcb: /*AMI - set keyboard mode*/
kbdlog("AMI - set keyboard mode\n");
break;
@@ -924,6 +953,8 @@ bad_command:
case 0xaa: /*Self-test*/
kbdlog("Self-test\n");
+ if(romset == ROM_T3100E)
+ kbd->status |= STAT_IFULL;
if (! kbd->initialized) {
kbd->initialized = 1;
key_ctrl_queue_start = key_ctrl_queue_end = 0;
@@ -998,10 +1029,64 @@ bad_command:
}
break;
- case 0xb0: case 0xb1: case 0xb2: case 0xb3:
- case 0xb4: case 0xb5: case 0xb6: case 0xb7:
- case 0xb8: case 0xb9: case 0xba: case 0xbb:
- case 0xbc: case 0xbd: case 0xbe: case 0xbf:
+ case 0xb0: /* T3100e: Turbo on */
+ if (romset == ROM_T3100E) {
+ t3100e_turbo_set(1);
+ break;
+ }
+ case 0xb1: /* T3100e: Turbo off */
+ if (romset == ROM_T3100E) {
+ t3100e_turbo_set(0);
+ break;
+ }
+ case 0xb2: /* T3100e: Select external display */
+ if (romset == ROM_T3100E) {
+ t3100e_display_set(0x00);
+ break;
+ }
+ case 0xb3: /* T3100e: Select internal display */
+ if (romset == ROM_T3100E) {
+ t3100e_display_set(0x01);
+ break;
+ }
+ case 0xb4: /* T3100e: Get configuration / status */
+ if (romset == ROM_T3100E) {
+ kbd_adddata(t3100e_config_get());
+ break;
+ }
+ case 0xb5: /* T3100e: Get colour / mono byte */
+ if (romset == ROM_T3100E) {
+ kbd_adddata(t3100e_mono_get());
+ break;
+ }
+ case 0xb6: /* T3100e: Set colour / mono byte */
+ if (romset == ROM_T3100E) {
+ kbd->want60 = 1;
+ break;
+ }
+ case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */
+ case 0xb8: /* T3100e: Emulate AT keyboard - not implemented */
+ if (romset == ROM_T3100E)
+ break;
+ case 0xbb: /* T3100e: Read 'Fn' key.
+ Return it for right Ctrl and right Alt; on the real
+ T3100e, these keystrokes could only be generated
+ using 'Fn'. */
+ if (romset == ROM_T3100E)
+ {
+ if (keyboard_recv(0xb8) || /* Right Alt */
+ keyboard_recv(0x9d)) /* Right Ctrl */
+ kbd_adddata(0x04);
+ else kbd_adddata(0x00);
+ break;
+ }
+ case 0xbc: /* T3100e: Reset Fn+Key notification */
+ if (romset == ROM_T3100E) {
+ t3100e_notify_set(0x00);
+ break;
+ }
+ case 0xb9: case 0xba:
+ case 0xbd: case 0xbe: case 0xbf:
/*Set keyboard lines low (B0-B7) or high (B8-BF)*/
kbdlog("ATkbd: set keyboard lines low (B0-B7) or high (B8-BF)\n");
kbd_adddata(0x00);
@@ -1009,8 +1094,17 @@ bad_command:
case 0xc0: /*Read input port*/
kbdlog("ATkbd: read input port\n");
- kbd_adddata(kbd->input_port | 4 | fdc_ps1_525());
- kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc) | fdc_ps1_525();
+
+ /* The T3100e returns all bits set except bit 6 which
+ * is set by t3100e_mono_set() */
+ if (romset == ROM_T3100E) {
+ kbd->input_port = (t3100e_mono_get() & 1) ? 0xFF : 0xBF;
+ kbd_adddata(kbd->input_port | 4 | fdc_ps1_525());
+ kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc);
+ } else {
+ kbd_adddata(kbd->input_port | 4 | fdc_ps1_525());
+ kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc) | fdc_ps1_525();
+ }
break;
case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/
diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c
new file mode 100644
index 000000000..73ac42fe9
--- /dev/null
+++ b/src/machine/m_at_t3100e.c
@@ -0,0 +1,721 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "../86box.h"
+#include "../io.h"
+#include "../mouse.h"
+#include "../mem.h"
+#include "../device.h"
+#include "../cpu/cpu.h"
+#include "../floppy/fdd.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();
+
+/* The T3100e motherboard can (and does) dynamically reassign RAM between
+ * conventional, XMS and EMS. This translates to monkeying with the mappings.
+ */
+
+extern mem_mapping_t base_mapping;
+
+extern mem_mapping_t ram_low_mapping; /* This is to switch conventional RAM
+ * between 512k and 640k */
+
+extern mem_mapping_t ram_mid_mapping; /* This will not be used */
+
+extern mem_mapping_t ram_high_mapping; /* This is RAM beyond 1Mb if any */
+
+extern uint8_t *ram;
+
+static unsigned t3100e_ems_page_reg[] =
+{
+ 0x208, 0x4208, 0x8208, 0xc208, /* The first four map the first 2Mb */
+ /* of RAM into the page frame */
+ 0x218, 0x4218, 0x8218, 0xc218, /* The next four map the next 2Mb */
+ /* of RAM */
+ 0x258, 0x4258, 0x8258, 0xc258, /* and so on. */
+ 0x268, 0x4268, 0x8268, 0xc268,
+};
+
+struct t3100e_ems_regs
+{
+ uint8_t page[16];
+ mem_mapping_t mapping[4];
+ uint32_t page_exec[4]; /* Physical location of memory pages */
+ uint32_t upper_base; /* Start of upper RAM */
+ uint8_t upper_pages; /* Pages of EMS available from upper RAM */
+ uint8_t upper_is_ems; /* Upper RAM is EMS? */
+ mem_mapping_t upper_mapping;
+ uint8_t notify; /* Notification from keyboard controller */
+ uint8_t turbo; /* 0 for 6MHz, else full speed */
+ uint8_t mono; /* Emulates PC/AT 'mono' motherboard switch */
+ /* Bit 0 is 0 for colour, 1 for mono */
+} t3100e_ems;
+
+void t3100e_ems_out(uint16_t addr, uint8_t val, void *p);
+
+
+/* Given a memory address (which ought to be in the page frame at 0xD0000),
+ * which page does it relate to? */
+static int addr_to_page(uint32_t addr)
+{
+ if ((addr & 0xF0000) == 0xD0000)
+ {
+ return ((addr >> 14) & 3);
+ }
+ return -1;
+}
+
+/* And vice versa: Given a page slot, which memory address does it
+ * correspond to? */
+static uint32_t page_to_addr(int pg)
+{
+ return 0xD0000 + ((pg & 3) * 16384);
+}
+
+/* Given an EMS page ID, return its physical address in RAM. */
+uint32_t t3100e_ems_execaddr(struct t3100e_ems_regs *regs,
+ int pg, uint16_t val)
+{
+ uint32_t addr;
+
+ if (!(val & 0x80)) return 0; /* Bit 7 reset => not mapped */
+
+ val &= 0x7F;
+ val += (0x80 * (pg >> 2)); /* The high bits of the register bank */
+ /* are used to extend val to allow up */
+ /* to 8Mb of EMS to be accessed */
+
+ /* Is it in the upper memory range? */
+ if (regs->upper_is_ems)
+ {
+ if (val < regs->upper_pages)
+ {
+ addr = regs->upper_base + 0x4000 * val;
+ return addr;
+ }
+ val -= regs->upper_pages;
+ }
+ /* Otherwise work down from the top of high RAM (so, the more EMS,
+ * the less XMS) */
+ if ((val * 0x4000) + 0x100000 >= (mem_size * 1024))
+ {
+ return 0; /* Not enough high RAM for this page */
+ }
+ /* High RAM found */
+ addr = (mem_size * 1024) - 0x4000 * (val + 1);
+
+ return addr;
+}
+
+
+/* The registers governing the EMS ports are in rather a nonintuitive order */
+static int port_to_page(uint16_t addr)
+{
+ switch (addr)
+ {
+ case 0x208: return 0;
+ case 0x4208: return 1;
+ case 0x8208: return 2;
+ case 0xC208: return 3;
+ case 0x218: return 4;
+ case 0x4218: return 5;
+ case 0x8218: return 6;
+ case 0xC218: return 7;
+ case 0x258: return 8;
+ case 0x4258: return 9;
+ case 0x8258: return 10;
+ case 0xC258: return 11;
+ case 0x268: return 12;
+ case 0x4268: return 13;
+ case 0x8268: return 14;
+ case 0xC268: return 15;
+ }
+ return -1;
+}
+
+/* Used to dump the memory mapping table, for debugging
+void dump_mappings()
+{
+ mem_mapping_t *mm = base_mapping.next;
+
+ if (!t3100e_log) return;
+ while (mm)
+ {
+ const char *name = "";
+ uint32_t offset = (uint32_t)(mm->exec - ram);
+
+ if (mm == &ram_low_mapping ) name = "LOW ";
+ if (mm == &ram_mid_mapping ) name = "MID ";
+ if (mm == &ram_high_mapping) name = "HIGH";
+ if (mm == &t3100e_ems.upper_mapping) name = "UPPR";
+ if (mm == &t3100e_ems.mapping[0])
+ {
+ name = "EMS0";
+ offset = t3100e_ems.page_exec[0];
+ }
+ if (mm == &t3100e_ems.mapping[1])
+ {
+ name = "EMS1";
+ offset = t3100e_ems.page_exec[1];
+ }
+ if (mm == &t3100e_ems.mapping[2])
+ {
+ name = "EMS2";
+ offset = t3100e_ems.page_exec[2];
+ }
+ if (mm == &t3100e_ems.mapping[3])
+ {
+ name = "EMS3";
+ offset = t3100e_ems.page_exec[3];
+ }
+
+ pclog(" %p | base=%05x size=%05x %c @ %06x %s\n", mm,
+ mm->base, mm->size, mm->enable ? 'Y' : 'N',
+ offset, name);
+
+ mm = mm->next;
+ }
+}*/
+
+void t3100e_map_ram(uint8_t val)
+{
+ int n;
+ int32_t upper_len;
+
+ if (t3100e_log)
+ {
+ pclog("OUT 0x8084, %02x [ set memory mapping :", val | 0x40);
+ if (val & 1) pclog("ENABLE_EMS ");
+ if (val & 2) pclog("ENABLE_XMS ");
+ if (val & 4) pclog("640K ");
+ if (val & 8) pclog("X8X ");
+ if (val & 16) pclog("UPPER_IS_XMS ");
+ pclog("\n");
+ }
+ /* Bit 2 controls size of conventional memory */
+ if (val & 4)
+ {
+ t3100e_ems.upper_base = 0xA0000;
+ t3100e_ems.upper_pages = 24;
+ }
+ else
+ {
+ t3100e_ems.upper_base = 0x80000;
+ t3100e_ems.upper_pages = 32;
+ }
+ upper_len = t3100e_ems.upper_pages * 16384;
+
+ mem_mapping_set_addr(&ram_low_mapping, 0, t3100e_ems.upper_base);
+ /* Bit 0 set if upper RAM is EMS */
+ t3100e_ems.upper_is_ems = (val & 1);
+
+ /* Bit 1 set if high RAM is enabled */
+ if (val & 2)
+ {
+ mem_mapping_enable(&ram_high_mapping);
+ }
+ else
+ {
+ mem_mapping_disable(&ram_high_mapping);
+ }
+
+ /* Bit 4 set if upper RAM is mapped to high memory
+ * (and bit 1 set if XMS enabled) */
+ if ((val & 0x12) == 0x12)
+ {
+ mem_mapping_set_addr(&t3100e_ems.upper_mapping,
+ mem_size * 1024,
+ upper_len);
+ mem_mapping_enable(&t3100e_ems.upper_mapping);
+ mem_mapping_set_exec(&t3100e_ems.upper_mapping, ram + t3100e_ems.upper_base);
+ }
+ else
+ {
+ mem_mapping_disable(&t3100e_ems.upper_mapping);
+ }
+ /* Recalculate EMS mappings */
+ for (n = 0; n < 4; n++)
+ {
+ t3100e_ems_out(t3100e_ems_page_reg[n], t3100e_ems.page[n],
+ &t3100e_ems);
+ }
+
+ //dump_mappings();
+}
+
+
+void t3100e_notify_set(uint8_t value)
+{
+ t3100e_ems.notify = value;
+}
+
+void t3100e_mono_set(uint8_t value)
+{
+ t3100e_ems.mono = value;
+}
+
+uint8_t t3100e_mono_get(void)
+{
+ return t3100e_ems.mono;
+}
+
+void t3100e_turbo_set(uint8_t value)
+{
+ t3100e_ems.turbo = value;
+ if (!value)
+ {
+ int c = cpu;
+ cpu = 0; /* 286/6 */
+ cpu_set();
+ cpu = c;
+ }
+ else
+ {
+ cpu_set();
+ }
+}
+
+
+
+uint8_t t3100e_sys_in(uint16_t addr, void *p)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p;
+
+ /* The low 4 bits always seem to be 0x0C. The high 4 are a
+ * notification sent by the keyboard controller when it detects
+ * an [Fn] key combination */
+ if (t3100e_log) pclog("IN 0x8084\n");
+ return 0x0C | (regs->notify << 4);
+}
+
+
+
+/* Handle writes to the T3100e system control port at 0x8084 */
+void t3100e_sys_out(uint16_t addr, uint8_t val, void *p)
+{
+// struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p;
+
+ switch (val & 0xE0)
+ {
+ case 0x00: /* Set serial port IRQs. Not implemented */
+ if (t3100e_log) pclog("OUT 0x8084, %02x [ set serial port IRQs]\n", val);
+ break;
+ case 0x40: /* Set RAM mappings. */
+ t3100e_map_ram(val & 0x1F);
+ break;
+
+ case 0x80: /* Set video options. */
+ t3100e_video_options_set(val & 0x1F); break;
+
+ /* Other options not implemented. */
+ default: if (t3100e_log) pclog("OUT 0x8084, %02x\n", val); break;
+ }
+}
+
+
+uint8_t t3100e_config_get(void)
+{
+/* The byte returned:
+ Bit 7: Set if internal plasma display enabled
+ Bit 6: Set if running at 6MHz, clear at full speed
+ Bit 5: Always 1?
+ Bit 4: Set if the FD2MB jumper is present (internal floppy is ?tri-mode)
+ Bit 3: Clear if the FD2 jumper is present (two internal floppies)
+ Bit 2: Set if the internal drive is A:, clear if B:
+ Bit 1: Set if the parallel port is configured as a floppy connector
+ for the second drive.
+ Bit 0: Set if the F2HD jumper is present (internal floppy is 720k)
+ */
+ uint8_t value = 0x28; /* Start with bits 5 and 3 set. */
+
+ int type_a = fdd_get_type(0);
+ int type_b = fdd_get_type(1);
+ int prt_switch; /* External drive type: 0=> none, 1=>A, 2=>B */
+
+/* Get display setting */
+ if (t3100e_display_get()) value |= 0x80;
+ if (!t3100e_ems.turbo) value |= 0x40;
+
+/* Try to determine the floppy types.*/
+
+ prt_switch = (type_b ? 2 : 0);
+ switch(type_a)
+ {
+/* Since a T3100e cannot have an internal 5.25" drive, mark 5.25" A: drive as
+ * being external, and set the internal type based on type_b. */
+ case 1: /* 360k */
+ case 2: /* 1.2Mb */
+ case 3: /* 1.2Mb RPMx2*/
+ prt_switch = 1; /* External drive is A: */
+ switch (type_b)
+ {
+ case 1: /* 360k */
+ case 4: value |= 1; break; /* 720k */
+ case 6: value |= 0x10; break; /* Tri-mode */
+ /* All others will be treated as 1.4M */
+ }
+ break;
+ case 4: value |= 0x01; /* 720k */
+ if (type_a == type_b)
+ {
+ value &= (~8); /* Two internal drives */
+ prt_switch = 0; /* No external drive */
+ }
+ break;
+ case 5: /* 1.4M */
+ case 7: /* 2.8M */
+ if (type_a == type_b)
+ {
+ value &= (~8); /* Two internal drives */
+ prt_switch = 0; /* No external drive */
+ }
+ break;
+ case 6: /* 3-mode */
+ value |= 0x10;
+ if (type_a == type_b)
+ {
+ value &= (~8); /* Two internal drives */
+ prt_switch = 0; /* No external drive */
+ }
+ break;
+ } /* End switch */
+ switch (prt_switch)
+ {
+ case 0: value |= 4; break; /* No external floppy */
+ case 1: value |= 2; break; /* External floppy is A: */
+ case 2: value |= 6; break; /* External floppy is B: */
+ }
+ return value;
+}
+
+
+/* Read EMS page register */
+uint8_t t3100e_ems_in(uint16_t addr, void *p)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p;
+
+ return regs->page[port_to_page(addr)];
+
+}
+
+/* Write EMS page register */
+void t3100e_ems_out(uint16_t addr, uint8_t val, void *p)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p;
+ int pg = port_to_page(addr);
+
+ regs->page_exec[pg & 3] = t3100e_ems_execaddr(regs, pg, val);
+ if (t3100e_log) pclog("EMS: page %d %02x -> %02x [%06x]\n",
+ pg, regs->page[pg], val, regs->page_exec[pg & 3]);
+ regs->page[pg] = val;
+
+ pg &= 3;
+/* Bit 7 set if page is enabled, reset if page is disabled */
+ if (regs->page_exec[pg])
+ {
+ if (t3100e_log) pclog("Enabling EMS RAM at %05x\n",
+ page_to_addr(pg));
+ mem_mapping_enable(®s->mapping[pg]);
+ mem_mapping_set_exec(®s->mapping[pg], ram + regs->page_exec[pg]);
+ }
+ else
+ {
+ if (t3100e_log) pclog("Disabling EMS RAM at %05x\n",
+ page_to_addr(pg));
+ mem_mapping_disable(®s->mapping[pg]);
+ }
+}
+
+
+/* Read RAM in the EMS page frame */
+static uint8_t ems_read_ram(uint32_t addr, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+ int pg = addr_to_page(addr);
+
+ if (pg < 0) return 0xFF;
+ addr = regs->page_exec[pg] + (addr & 0x3FFF);
+ return ram[addr];
+}
+
+
+
+
+static uint16_t ems_read_ramw(uint32_t addr, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+ int pg = addr_to_page(addr);
+
+ if (pg < 0) return 0xFF;
+ //pclog("ems_read_ramw addr=%05x ", addr);
+ addr = regs->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 t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+ int pg = addr_to_page(addr);
+
+ if (pg < 0) return 0xFF;
+ addr = regs->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 t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+ int pg = addr_to_page(addr);
+
+ if (pg < 0) return;
+ addr = regs->page_exec[pg] + (addr & 0x3FFF);
+ ram[addr] = val;
+}
+
+
+static void ems_write_ramw(uint32_t addr, uint16_t val, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+ int pg = addr_to_page(addr);
+
+ if (pg < 0) return;
+ //pclog("ems_write_ramw addr=%05x ", addr);
+ addr = regs->page_exec[pg] + (addr & 0x3FFF);
+ //pclog("-> %06x val=%04x\n", addr, val);
+
+ *(uint16_t *)&ram[addr] = val;
+}
+
+
+static void ems_write_raml(uint32_t addr, uint32_t val, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+ int pg = addr_to_page(addr);
+
+ if (pg < 0) return;
+ addr = regs->page_exec[pg] + (addr & 0x3FFF);
+ *(uint32_t *)&ram[addr] = val;
+}
+
+
+
+/* Read RAM in the upper area. This is basically what the 'remapped'
+ * mapping in mem.c does, except that the upper area can move around */
+static uint8_t upper_read_ram(uint32_t addr, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+
+ addr = (addr - (1024 * mem_size)) + regs->upper_base;
+ return ram[addr];
+}
+
+static uint16_t upper_read_ramw(uint32_t addr, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+
+ addr = (addr - (1024 * mem_size)) + regs->upper_base;
+ return *(uint16_t *)&ram[addr];
+}
+
+static uint32_t upper_read_raml(uint32_t addr, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+
+ addr = (addr - (1024 * mem_size)) + regs->upper_base;
+ return *(uint32_t *)&ram[addr];
+}
+
+
+static void upper_write_ram(uint32_t addr, uint8_t val, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+
+ addr = (addr - (1024 * mem_size)) + regs->upper_base;
+ ram[addr] = val;
+}
+
+
+static void upper_write_ramw(uint32_t addr, uint16_t val, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+
+ addr = (addr - (1024 * mem_size)) + regs->upper_base;
+ *(uint16_t *)&ram[addr] = val;
+}
+
+
+
+static void upper_write_raml(uint32_t addr, uint32_t val, void *priv)
+{
+ struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv;
+
+ addr = (addr - (1024 * mem_size)) + regs->upper_base;
+ *(uint32_t *)&ram[addr] = val;
+}
+
+
+
+
+void machine_at_t3100e_init(machine_t *model)
+{
+ int pg;
+
+ memset(&t3100e_ems, 0, sizeof(t3100e_ems));
+
+ machine_at_ide_init(model);
+ /* Hook up system control port */
+ io_sethandler(0x8084, 0x0001,
+ t3100e_sys_in, NULL, NULL,
+ t3100e_sys_out, NULL, NULL, &t3100e_ems);
+
+ /* Start monitoring all 16 EMS registers */
+ for (pg = 0; pg < 16; pg++)
+ {
+ io_sethandler(t3100e_ems_page_reg[pg], 0x0001,
+ t3100e_ems_in, NULL, NULL,
+ t3100e_ems_out, NULL, NULL, &t3100e_ems);
+ }
+
+ /* Map the EMS page frame */
+ for (pg = 0; pg < 4; pg++)
+ {
+ if (t3100e_log) pclog("Adding memory map at %x for page %d\n", page_to_addr(pg), pg);
+ mem_mapping_add(&t3100e_ems.mapping[pg],
+ page_to_addr(pg), 16384,
+ ems_read_ram, ems_read_ramw, ems_read_raml,
+ ems_write_ram, ems_write_ramw, ems_write_raml,
+ NULL, MEM_MAPPING_EXTERNAL,
+ &t3100e_ems);
+ /* Start them all off disabled */
+ mem_mapping_disable(&t3100e_ems.mapping[pg]);
+ }
+ /* Mapping for upper RAM when in use as XMS*/
+ mem_mapping_add(&t3100e_ems.upper_mapping, mem_size * 1024, 384 * 1024,
+ upper_read_ram, upper_read_ramw, upper_read_raml,
+ upper_write_ram, upper_write_ramw, upper_write_raml,
+ NULL, MEM_MAPPING_INTERNAL, &t3100e_ems);
+ mem_mapping_disable(&t3100e_ems.upper_mapping);
+
+ device_add(&t3100e_device);
+}
diff --git a/src/machine/m_at_t3100e.h b/src/machine/m_at_t3100e.h
new file mode 100644
index 000000000..0f3ac3093
--- /dev/null
+++ b/src/machine/m_at_t3100e.h
@@ -0,0 +1,7 @@
+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);
diff --git a/src/machine/machine.h b/src/machine/machine.h
index ee3bb16c3..c01ebed55 100644
--- a/src/machine/machine.h
+++ b/src/machine/machine.h
@@ -100,6 +100,8 @@ extern void machine_at_ide_init(machine_t *);
extern void machine_at_top_remap_init(machine_t *);
extern void machine_at_ide_top_remap_init(machine_t *);
+extern void machine_at_t3100e_init(machine_t *);
+
extern void machine_at_p54tp4xe_init(machine_t *);
extern void machine_at_endeavor_init(machine_t *);
extern void machine_at_zappa_init(machine_t *);
diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c
index 2bfe91fa3..7fc5b6724 100644
--- a/src/machine/machine_table.c
+++ b/src/machine/machine_table.c
@@ -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.8 2017/12/29
+ * Version: @(#)machine_table.c 1.0.9 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -72,8 +72,9 @@ machine_t machines[] = {
{ "[286 ISA] IBM XT Model 286", ROM_IBMXT286, "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_top_remap_init, NULL, nvr_at_close },
{ "[286 ISA] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_scat_init, NULL, nvr_at_close },
#ifdef WALTJE
- { "[286 ISA] OpenAT 286", ROM_OPENAT, "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512, 4096, 128, 127, machine_at_init, NULL, nvr_at_close },
+ { "[286 ISA] OpenAT 286", ROM_OPENAT, "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512, 4096, 128, 127, machine_at_init, NULL, nvr_at_close },
#endif
+ { "[286 ISA] Toshiba 3100e", ROM_T3100E, "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL, nvr_at_close },
{ "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 16, 1, 63, machine_ps2_model_50_init, NULL, nvr_at_close },
diff --git a/src/rom.c b/src/rom.c
index 04eb41e1b..1c523e3e3 100644
--- a/src/rom.c
+++ b/src/rom.c
@@ -13,7 +13,7 @@
* - c386sx16 BIOS fails checksum
* - the loadfont() calls should be done elsewhere
*
- * Version: @(#)rom.c 1.0.22 2017/12/29
+ * Version: @(#)rom.c 1.0.23 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -819,6 +819,13 @@ rom_load_bios(int rom_id)
return(1);
#endif
+ case ROM_T3100E:
+ loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5);
+ if (rom_load_linear(
+ L"roms/machines/t3100e/t3100e.rom",
+ 0x000000, 65536, 0, rom)) return(1);
+ break;
+
default:
pclog("ROM: don't know how to handle ROM set %d !\n", rom_id);
}
diff --git a/src/rom.h b/src/rom.h
index bad57cdbf..9294b6d65 100644
--- a/src/rom.h
+++ b/src/rom.h
@@ -8,7 +8,7 @@
*
* Definitions for the ROM image handler.
*
- * Version: @(#)rom.h 1.0.8 2017/12/29
+ * Version: @(#)rom.h 1.0.9 2017/12/31
*
* Author: Fred N. van Kempen,
* Copyright 2017 Fred N. van Kempen.
@@ -140,6 +140,8 @@ enum {
ROM_OPENAT, /* PC/AT clone with Open BIOS */
#endif
+ ROM_T3100E,
+
ROM_MAX
};
diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c
index d9b197a6a..c256b7b44 100644
--- a/src/video/vid_cga.c
+++ b/src/video/vid_cga.c
@@ -8,7 +8,7 @@
*
* Emulation of the old and new IBM CGA graphics cards.
*
- * Version: @(#)vid_cga.c 1.0.11 2017/12/28
+ * Version: @(#)vid_cga.c 1.0.12 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -221,12 +221,12 @@ void cga_poll(void *p)
if (drawcursor)
{
for (c = 0; c < 8; c++)
- buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
+ buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
}
else
{
for (c = 0; c < 8; c++)
- buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
+ buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
}
cga->ma++;
}
@@ -253,12 +253,12 @@ void cga_poll(void *p)
if (drawcursor)
{
for (c = 0; c < 8; c++)
- buffer->line[cga->displine][(x << 4)+(c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
+ buffer->line[cga->displine][(x << 4)+(c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
}
else
{
for (c = 0; c < 8; c++)
- buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
+ buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
}
}
}
diff --git a/src/video/vid_cga.h b/src/video/vid_cga.h
index 2724ac0ec..93c8bac68 100644
--- a/src/video/vid_cga.h
+++ b/src/video/vid_cga.h
@@ -8,7 +8,7 @@
*
* Emulation of the old and new IBM CGA graphics cards.
*
- * Version: @(#)vid_cga.h 1.0.1 2017/12/29
+ * Version: @(#)vid_cga.h 1.0.2 2017/12/31
*
* Author: Sarah Walker,
* Miran Grca,
@@ -27,6 +27,7 @@ typedef struct cga_t
uint8_t cgamode, cgacol;
+ int fontbase;
int linepos, displine;
int sc, vc;
int cgadispon;
diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_compaq_cga.c
index 346befc20..17c0dbdef 100644
--- a/src/video/vid_compaq_cga.c
+++ b/src/video/vid_compaq_cga.c
@@ -132,12 +132,12 @@ void compaq_cga_poll(void *p)
else if (drawcursor)
{
for (c = 0; c < 8; c++)
- ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff;
+ ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff;
}
else
{
for (c = 0; c < 8; c++)
- ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0];
+ ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0];
}
self->cga.ma++;
}
@@ -187,13 +187,13 @@ void compaq_cga_poll(void *p)
{
for (c = 0; c < 8; c++)
((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] =
- ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
+ ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
}
else
{
for (c = 0; c < 8; c++)
((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 8] =
- ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0];
+ ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0];
}
}
}
diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c
index 78d69ccaf..c2d6a7f5b 100644
--- a/src/video/vid_paradise.c
+++ b/src/video/vid_paradise.c
@@ -10,7 +10,7 @@
* PC2086, PC3086 use PVGA1A
* MegaPC uses W90C11A
*
- * Version: @(#)vid_paradise.c 1.0.2 2017/11/04
+ * Version: @(#)vid_paradise.c 1.0.3 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -43,7 +43,8 @@ typedef struct paradise_t
enum
{
PVGA1A = 0,
- WD90C11
+ WD90C11,
+ WD90C30
} type;
uint32_t read_bank[4], write_bank[4];
@@ -207,37 +208,39 @@ uint8_t paradise_in(uint16_t addr, void *p)
void paradise_remap(paradise_t *paradise)
{
svga_t *svga = ¶dise->svga;
+
+ uint8_t mask = (paradise->type == WD90C11) ? 0x7f : 0xff;
if (svga->seqregs[0x11] & 0x80)
{
- paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12;
- paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
- paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12;
- paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0xa] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12;
+ paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12;
+ paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
}
else if (svga->gdcreg[0xe] & 0x08)
{
if (svga->gdcreg[0x6] & 0xc)
{
- paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12;
- paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12;
- paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
- paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & mask) << 12;
+ paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12;
+ paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
}
else
{
- paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & 0x7f) << 12;
- paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
- paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12;
- paradise->read_bank[3] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & mask) << 12;
+ paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12;
+ paradise->read_bank[3] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
}
}
else
{
- paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12;
- paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
- paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12;
- paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12;
+ paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
+ paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12;
+ paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000);
}
}
@@ -264,7 +267,7 @@ uint8_t paradise_read(uint32_t addr, void *p)
}
-void *paradise_pvga1a_init(device_t *info)
+void *paradise_pvga1a_init(device_t *info, uint32_t memsize)
{
paradise_t *paradise = malloc(sizeof(paradise_t));
svga_t *svga = ¶dise->svga;
@@ -272,7 +275,7 @@ void *paradise_pvga1a_init(device_t *info)
io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise);
- svga_init(¶dise->svga, paradise, 1 << 18, /*256kb*/
+ svga_init(¶dise->svga, paradise, memsize, /*256kb*/
NULL,
paradise_in, paradise_out,
NULL,
@@ -332,9 +335,44 @@ void *paradise_wd90c11_init(device_t *info)
return paradise;
}
+void *paradise_wd90c30_init(device_t *info, uint32_t memsize)
+{
+ paradise_t *paradise = malloc(sizeof(paradise_t));
+ svga_t *svga = ¶dise->svga;
+ memset(paradise, 0, sizeof(paradise_t));
+
+ io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise);
+
+ svga_init(¶dise->svga, paradise, memsize,
+ paradise_recalctimings,
+ paradise_in, paradise_out,
+ NULL,
+ NULL);
+
+ mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, NULL, NULL, paradise_write, NULL, NULL);
+ mem_mapping_set_p(¶dise->svga.mapping, paradise);
+
+ svga->crtc[0x31] = 'W';
+ svga->crtc[0x32] = 'D';
+ svga->crtc[0x33] = '9';
+ svga->crtc[0x34] = '0';
+ svga->crtc[0x35] = 'C';
+ svga->crtc[0x36] = '3';
+ svga->crtc[0x37] = '0';
+
+ svga->bpp = 8;
+ svga->miscout = 1;
+
+ svga->linear_base = 0;
+
+ paradise->type = WD90C11;
+
+ return paradise;
+}
+
static void *paradise_pvga1a_pc2086_init(device_t *info)
{
- paradise_t *paradise = paradise_pvga1a_init(info);
+ paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18);
if (paradise)
rom_init(¶dise->bios_rom, L"roms/machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
@@ -343,7 +381,7 @@ static void *paradise_pvga1a_pc2086_init(device_t *info)
}
static void *paradise_pvga1a_pc3086_init(device_t *info)
{
- paradise_t *paradise = paradise_pvga1a_init(info);
+ paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18);
if (paradise)
rom_init(¶dise->bios_rom, L"roms/machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
@@ -351,6 +389,27 @@ static void *paradise_pvga1a_pc3086_init(device_t *info)
return paradise;
}
+static void *paradise_pvga1a_standalone_init(device_t *info)
+{
+ paradise_t *paradise;
+ uint32_t memory = 512;
+
+ memory = device_get_config_int("memory");
+ memory <<= 10;
+
+ paradise = paradise_pvga1a_init(info, memory);
+
+ if (paradise)
+ rom_init(¶dise->bios_rom, L"roms/video/pvga1a/BIOS.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+
+ return paradise;
+}
+
+static int paradise_pvga1a_standalone_available(void)
+{
+ return rom_present(L"roms/video/pvga1a/BIOS.BIN");
+}
+
static void *paradise_wd90c11_megapc_init(device_t *info)
{
paradise_t *paradise = paradise_wd90c11_init(info);
@@ -364,9 +423,40 @@ static void *paradise_wd90c11_megapc_init(device_t *info)
return paradise;
}
+static void *paradise_wd90c11_standalone_init(device_t *info)
+{
+ paradise_t *paradise = paradise_wd90c11_init(info);
+
+ if (paradise)
+ rom_init(¶dise->bios_rom, L"roms/video/wd90c11/WD90C11.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+
+ return paradise;
+}
+
static int paradise_wd90c11_standalone_available(void)
{
- return rom_present(L"roms/machines/megapc/41651-bios lo.u18") && rom_present(L"roms/machines/megapc/211253-bios hi.u19");
+ return rom_present(L"roms/video/wd90c11/WD90C11.VBI");
+}
+
+static void *paradise_wd90c30_standalone_init(device_t *info)
+{
+ paradise_t *paradise;
+ uint32_t memory = 512;
+
+ memory = device_get_config_int("memory");
+ memory <<= 10;
+
+ paradise = paradise_wd90c30_init(info, memory);
+
+ if (paradise)
+ rom_init(¶dise->bios_rom, L"roms/video/wd90c30/90C30-LR.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+
+ return paradise;
+}
+
+static int paradise_wd90c30_standalone_available(void)
+{
+ return rom_present(L"roms/video/wd90c30/90C30-LR.VBI");
}
void paradise_close(void *p)
@@ -426,6 +516,45 @@ device_t paradise_pvga1a_pc3086_device =
paradise_force_redraw,
paradise_add_status_info
};
+
+static device_config_t paradise_pvga1a_config[] =
+{
+ {
+ "memory", "Memory size", CONFIG_SELECTION, "", 512,
+ {
+ {
+ "256 kB", 256
+ },
+ {
+ "512 kB", 512
+ },
+ {
+ "1 MB", 1024
+ },
+ {
+ ""
+ }
+ }
+ },
+ {
+ "", "", -1
+ }
+};
+
+device_t paradise_pvga1a_device =
+{
+ "Paradise PVGA1A",
+ DEVICE_ISA,
+ 0,
+ paradise_pvga1a_standalone_init,
+ paradise_close,
+ NULL,
+ paradise_pvga1a_standalone_available,
+ paradise_speed_changed,
+ paradise_force_redraw,
+ paradise_add_status_info,
+ paradise_pvga1a_config
+};
device_t paradise_wd90c11_megapc_device =
{
"Paradise WD90C11 (Amstrad MegaPC)",
@@ -441,10 +570,10 @@ device_t paradise_wd90c11_megapc_device =
};
device_t paradise_wd90c11_device =
{
- "Paradise WD90C11",
+ "Paradise WD90C11-LR",
DEVICE_ISA,
0,
- paradise_wd90c11_megapc_init,
+ paradise_wd90c11_standalone_init,
paradise_close,
NULL,
paradise_wd90c11_standalone_available,
@@ -452,3 +581,39 @@ device_t paradise_wd90c11_device =
paradise_force_redraw,
paradise_add_status_info
};
+
+static device_config_t paradise_wd90c30_config[] =
+{
+ {
+ "memory", "Memory size", CONFIG_SELECTION, "", 1024,
+ {
+ {
+ "512 kB", 512
+ },
+ {
+ "1 MB", 1024
+ },
+ {
+ ""
+ }
+ }
+ },
+ {
+ "", "", -1
+ }
+};
+
+device_t paradise_wd90c30_device =
+{
+ "Paradise WD90C30-LR",
+ DEVICE_ISA,
+ 0,
+ paradise_wd90c30_standalone_init,
+ paradise_close,
+ NULL,
+ paradise_wd90c30_standalone_available,
+ paradise_speed_changed,
+ paradise_force_redraw,
+ paradise_add_status_info,
+ paradise_wd90c30_config
+};
diff --git a/src/video/vid_paradise.h b/src/video/vid_paradise.h
index 83dd1042b..19c34b582 100644
--- a/src/video/vid_paradise.h
+++ b/src/video/vid_paradise.h
@@ -3,5 +3,7 @@
*/
extern device_t paradise_pvga1a_pc2086_device;
extern device_t paradise_pvga1a_pc3086_device;
+extern device_t paradise_pvga1a_device;
extern device_t paradise_wd90c11_megapc_device;
extern device_t paradise_wd90c11_device;
+extern device_t paradise_wd90c30_device;
diff --git a/src/video/vid_t3100e.c b/src/video/vid_t3100e.c
new file mode 100644
index 000000000..e7ce5e45b
--- /dev/null
+++ b/src/video/vid_t3100e.c
@@ -0,0 +1,726 @@
+/* Emulate the Toshiba 3100e plasma display. This display has a fixed 640x400
+ * resolution. */
+#include
+#include
+#include
+#include
+#include
+
+#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_t3100e.h"
+
+#define T3100E_XSIZE 640
+#define T3100E_YSIZE 400
+
+/* 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
+ */
+
+/* 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 uint8_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
+};
diff --git a/src/video/vid_t3100e.h b/src/video/vid_t3100e.h
new file mode 100644
index 000000000..ba0f4aa00
--- /dev/null
+++ b/src/video/vid_t3100e.h
@@ -0,0 +1,4 @@
+extern device_t t3100e_device;
+
+void t3100e_video_options_set(uint8_t options);
+void t3100e_display_set(uint8_t internal);
diff --git a/src/video/vid_table.c b/src/video/vid_table.c
index 704c9ee3f..e9b1145d7 100644
--- a/src/video/vid_table.c
+++ b/src/video/vid_table.c
@@ -8,7 +8,7 @@
*
* Define all known video cards.
*
- * Version: @(#)vid_table.c 1.0.7 2017/12/29
+ * Version: @(#)vid_table.c 1.0.8 2017/12/31
*
* Authors: Miran Grca,
* Fred N. van Kempen,
@@ -115,7 +115,9 @@ video_cards[] = {
{ "[ISA] MDSI Genius", "genius", &genius_device, GFX_GENIUS },
{ "[ISA] OAK OTI-067", "oti067", &oti067_device, GFX_OTI067 },
{ "[ISA] OAK OTI-077", "oti077", &oti077_device, GFX_OTI077 },
- { "[ISA] Paradise WD90C11", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11 },
+ { "[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device, GFX_PVGA1A },
+ { "[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11 },
+ { "[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device, GFX_WD90C30 },
{ "[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS },
{"[ISA] TI CF62011 SVGA", "ti_cf62011",
&ti_cf62011_device, GFX_TICF62011 },
diff --git a/src/video/video.c b/src/video/video.c
index 06529623e..3d13be7d7 100644
--- a/src/video/video.c
+++ b/src/video/video.c
@@ -40,7 +40,7 @@
* W = 3 bus clocks
* L = 4 bus clocks
*
- * Version: @(#)video.c 1.0.11 2017/12/15
+ * Version: @(#)video.c 1.0.12 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -76,8 +76,8 @@ enum {
bitmap_t *screen = NULL,
*buffer = NULL,
*buffer32 = NULL;
-uint8_t fontdat[256][8]; /* IBM CGA font */
-uint8_t fontdatm[256][16]; /* IBM MDA font */
+uint8_t fontdat[2048][8]; /* IBM CGA font */
+uint8_t fontdatm[2048][16]; /* IBM MDA font */
uint8_t fontdatw[512][32]; /* Wyse700 font */
uint8_t fontdat8x12[256][16]; /* MDSI Genius font */
uint32_t pal_lookup[256];
@@ -632,6 +632,36 @@ loadfont(wchar_t *s, int format)
fontdat8x12[c][d] = fgetc(f);
break;
+ case 5: /* Toshiba 3100e */
+ for (d = 0; d < 2048; d += 512) /* Four languages... */
+ {
+ for (c = d; c < d+256; c++)
+ {
+ fread(&fontdatm[c][8], 1, 8, f);
+ }
+ for (c = d+256; c < d+512; c++)
+ {
+ fread(&fontdatm[c][8], 1, 8, f);
+ }
+ for (c = d; c < d+256; c++)
+ {
+ fread(&fontdatm[c][0], 1, 8, f);
+ }
+ for (c = d+256; c < d+512; c++)
+ {
+ fread(&fontdatm[c][0], 1, 8, f);
+ }
+ fseek(f, 4096, SEEK_CUR); /* Skip blank section */
+ for (c = d; c < d+256; c++)
+ {
+ fread(&fontdat[c][0], 1, 8, f);
+ }
+ for (c = d+256; c < d+512; c++)
+ {
+ fread(&fontdat[c][0], 1, 8, f);
+ }
+ }
+ break;
}
(void)fclose(f);
diff --git a/src/video/video.h b/src/video/video.h
index 1e0a83b28..2cc8b00a5 100644
--- a/src/video/video.h
+++ b/src/video/video.h
@@ -8,7 +8,7 @@
*
* Definitions for the video controller module.
*
- * Version: @(#)video.h 1.0.6 2017/12/29
+ * Version: @(#)video.h 1.0.7 2017/12/31
*
* Authors: Sarah Walker,
* Miran Grca,
@@ -68,7 +68,7 @@ enum {
GFX_COMPAQ_VGA, /* Compaq/Paradise VGA */
GFX_CL_GD5446, /* Cirrus Logic CL-GD5446 */
GFX_VGAWONDERXL, /* Compaq ATI VGA Wonder XL (28800-5) */
- GFX_WD90C11, /* Paradise WD90C11 Standalone */
+ GFX_WD90C11, /* Paradise WD90C11-LR Standalone */
GFX_OTI077, /* Oak OTI-077 */
GFX_VGAWONDERXL24, /* Compaq ATI VGA Wonder XL24 (28800-6) */
GFX_STEALTH64_VLB, /* S3 Vision864 (Diamond Stealth 64) VLB */
@@ -94,6 +94,8 @@ enum {
GFX_TICF62011, /* TI CF62011 */
GFX_COMPAQ_CGA, /* Compaq CGA */
GFX_COMPAQ_CGA_2, /* Compaq CGA 2 */
+ GFX_PVGA1A, /* Paradise PVGA1A Standalone */
+ GFX_WD90C30, /* Paradise WD90C30-LR Standalone */
GFX_MAX
};
@@ -108,7 +110,7 @@ enum {
gfxcard!=GFX_GENIUS && gfxcard!=GFX_COMPAQ_EGA && \
gfxcard!=GFX_SUPER_EGA && gfxcard!=GFX_HERCULESPLUS) && \
(romset!=ROM_PC1640 && romset!=ROM_PC1512 && \
- romset!=ROM_TANDY && romset!=ROM_PC200))
+ romset!=ROM_TANDY && romset!=ROM_PC200 && romset!=ROM_T3100E))
enum {
FULLSCR_SCALE_FULL = 0,
@@ -151,8 +153,8 @@ extern int video_fullscreen,
video_fullscreen_scale,
video_fullscreen_first;
extern int fullchange;
-extern uint8_t fontdat[256][8];
-extern uint8_t fontdatm[256][16];
+extern uint8_t fontdat[2048][8];
+extern uint8_t fontdatm[2048][16];
extern uint32_t *video_6to8,
*video_15to32,
*video_16to32;
diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw
index f27f3d3e7..de964c399 100644
--- a/src/win/Makefile.mingw
+++ b/src/win/Makefile.mingw
@@ -355,6 +355,7 @@ MCHOBJ := machine.o machine_table.o \
m_xt.o m_xt_compaq.o m_xt_laserxt.o \
m_at.o m_at_ali1429.o m_at_commodore.o \
m_at_neat.o m_at_headland.o \
+ m_at_t3100e.o \
m_at_opti495.o m_at_scat.o \
m_at_compaq.o m_at_wd76c10.o \
m_at_sis_85c471.o m_at_sis_85c496.o \
@@ -440,6 +441,7 @@ VIDOBJ := video.o \
vid_hercules.o vid_herculesplus.o vid_incolor.o \
vid_colorplus.o \
vid_genius.o \
+ vid_t3100e.o \
vid_s3.o vid_s3_virge.o \
vid_et4000.o vid_et4000w32.o vid_icd2061.o \
vid_oti067.o \