From d9e7f0c4fc3d9012eae29e423a36697a8803b03e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 31 Dec 2017 06:37:19 +0100 Subject: [PATCH] Renamed the Paradise WD90C11 Standalone to Paradise WD90C11-LR and made it use the correct BIOS; Added the Paradise PVGA1A (standalone) and the Paradise WD90C30-LR, both with configurable video memory; Added the Toshiba T3100e. --- src/keyboard.c | 9 +- src/keyboard.h | 3 +- src/keyboard_at.c | 108 +++++- src/machine/m_at_t3100e.c | 721 +++++++++++++++++++++++++++++++++++ src/machine/m_at_t3100e.h | 7 + src/machine/machine.h | 2 + src/machine/machine_table.c | 5 +- src/rom.c | 9 +- src/rom.h | 4 +- src/video/vid_cga.c | 10 +- src/video/vid_cga.h | 3 +- src/video/vid_compaq_cga.c | 8 +- src/video/vid_paradise.c | 215 +++++++++-- src/video/vid_paradise.h | 2 + src/video/vid_t3100e.c | 726 ++++++++++++++++++++++++++++++++++++ src/video/vid_t3100e.h | 4 + src/video/vid_table.c | 6 +- src/video/video.c | 36 +- src/video/video.h | 12 +- src/win/Makefile.mingw | 2 + 20 files changed, 1834 insertions(+), 58 deletions(-) create mode 100644 src/machine/m_at_t3100e.c create mode 100644 src/machine/m_at_t3100e.h create mode 100644 src/video/vid_t3100e.c create mode 100644 src/video/vid_t3100e.h 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 \