diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 21f06df03..8a959684e 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -4758,7 +4758,7 @@ static const scancode scancode_set82[512] = { // clang-format on }; /* Scancode set 8Ah : IBM 5556 keyboard compatible scancode set used by J-DOS */ -static scancode scancode_set8a[512] = +const scancode scancode_set8a[512] = { // clang-format off {.mk = { 0 }, .brk = { 0 } }, /* 000 */ @@ -4817,7 +4817,7 @@ static scancode scancode_set8a[512] = {.mk = { 0x0a, 0 }, .brk = { 0 } }, /* 035 */ {.mk = { 0x39, 0 }, .brk = { 0xb9, 0 } }, /* 036 RSHIFT */ {.mk = { 0x64, 0 }, .brk = { 0 } }, /* 037 * (asterisk) */ - {.mk = { 0x3A, 0 }, .brk = { 0xba, 0 } }, /* 038 0x3A LALT = Kanji */ + {.mk = { 0x3a, 0 }, .brk = { 0xba, 0 } }, /* 038 0x3A LALT = Kanji */ {.mk = { 0x34, 0 }, .brk = { 0 } }, /* 039 */ {.mk = { 0x32, 0 }, .brk = { 0xb2, 0 } }, /* 03a CAPSLOCK */ {.mk = { 0x68, 0 }, .brk = { 0 } }, /* 03b F1 */ diff --git a/src/device/postcard.c b/src/device/postcard.c index f33574452..f842cbb33 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -195,6 +195,8 @@ postcard_init(UNUSED(const device_t *info)) postcard_port = 0x190; /* ISA PS/2 machines */ else if (strstr(machines[machine].name, " IBM XT ")) postcard_port = 0x60; /* IBM XT */ + else if (strstr(machines[machine].name, " Multistation ")) + postcard_port = 0xA1; /* IBM 5550 */ else if (strstr(machines[machine].name, " IBM PCjr")) { postcard_port = 0x10; /* IBM PCjr */ postcard_ports_num = 3; /* IBM PCjr error ports 11h and 12h */ diff --git a/src/dma.c b/src/dma.c index 5dfd70ae8..e36b0b4e5 100644 --- a/src/dma.c +++ b/src/dma.c @@ -978,10 +978,15 @@ dma_page_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) addr &= 0x0f; dmaregs[2][addr] = val; - if (addr >= 8) - addr = convert[addr & 0x07] | 4; - else - addr = convert[addr & 0x07]; + if (machines[machine].init == machine_xt_ibm5550_init) { + if (addr >= 4) + addr = 8; + } else { + if (addr >= 8) + addr = convert[addr & 0x07] | 4; + else + addr = convert[addr & 0x07]; + } if (addr < 8) { dma[addr].page_l = val; diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index d6d27da3b..cfc51f2b0 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -664,6 +664,21 @@ real_drive(fdc_t *fdc, int drive) return drive; } +void +fdc_diskchange_interrupt(fdc_t *fdc, int drive) +{ + /* + For the IBM 5550 machine to detect the disk in the drive has been changed. + A hardware interrupt is caused by the FDC (NEC uPD765A) when the Ready line from the drive changes its state. + Other PCs never use the Ready line. + */ + if (fdc->flags & FDC_FLAG_5550) { + fdc->st0 = 0xc0 | (drive & 3); + fdc_int(fdc, 1); + fdd_changed[drive] = 0; + } +} + /* FDD notifies FDC when seek operation is complete */ void fdc_seek_complete_interrupt(fdc_t *fdc, int drive) @@ -822,8 +837,47 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 0: return; case 1: + if (fdc->flags & FDC_FLAG_5550) { + val = 0; + if (!(val & 0x08)) { /* Drive 2 active */ + val = 0x42; + } + if (!(val & 0x04)) { /* Drive 1 active */ + val &= 0xf0; + val |= 0x21; + } + if (!(val & 0x02)) { /* Drive 0 active */ + val &= 0xf0; + val |= 0x10; + } + /* Update the DOR because this emulation module depend on it */ + fdc->dor &= 0x0c; + fdc->dor |= val; + /* We can now simplify this since each motor now spins separately. */ + for (int i = 0; i < FDD_NUM; i++) { + drive_num = real_drive(fdc, i); + if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) + val &= ~(0x10 << drive_num); + else + fdd_set_motor_enable(i, (val & (0x10 << drive_num))); + } + drive_num = real_drive(fdc, val & 0x03); + current_drive = drive_num; + fdc->st0 = (fdc->st0 & 0xf8) | (val & 0x03) | (fdd_get_head(drive_num) ? 4 : 0); + fdc_log("val:%x, dor=%x, drv=%x\n", val, fdc->dor, drive_num); + } return; case 2: /*DOR*/ + if (fdc->flags & FDC_FLAG_5550) { /* Reset */ + fdd_stop(fdc->drive); + for (int i = 0; i < FDD_NUM; i++) + fdd_set_motor_enable(i, 0); /* Need to restart fdd timer */ + fdc->stat = 0x00; + fdc->pnum = fdc->ptot = 0; + fdc_soft_reset(fdc); + fdc->dor = 0x0c; + return; + } if (fdc->flags & FDC_FLAG_PCJR) { if ((fdc->dor & 0x40) && !(val & 0x40)) { timer_set_delay_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); @@ -903,6 +957,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } return; case 4: /* DSR */ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); if (!(fdc->flags & FDC_FLAG_NO_DSR_RESET)) { if (!(val & 0x80)) { timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); @@ -914,6 +970,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->dsr = val; return; case 5: /*Command register*/ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); if (fdc->fifointest) { /* Write FIFO buffer in the test mode (PS/55) */ fdc_log("FIFO buffer position = %X\n", ((fifo_t *) fdc->fifo_p)->end); @@ -948,7 +1006,33 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->command = val; fdc->stat |= 0x10; - fdc_log("Starting FDC command %02X\n", fdc->command); + fdc_log("Starting FDC command %02X ", fdc->command); + switch (fdc->command & 0x1f) { + case 0x06: + fdc_log("READ DATA\n"); + break; + case 0x0a: + fdc_log("READ ID\n"); + break; + case 0x07: + fdc_log("RECALIB\n"); + break; + case 0x08: + fdc_log("SENSE INTERRUPT\n"); + break; + case 0x03: + fdc_log("SPECIFY\n"); + break; + case 0x04: + fdc_log("SENSE DRIVE\n"); + break; + case 0x0f: + fdc_log("SEEK\n"); + break; + default: + fdc_log("\n"); + break; + } fdc->error = 0; if (((fdc->command & 0x1f) == 0x02) || ((fdc->command & 0x1f) == 0x05) || @@ -1106,6 +1190,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if (command_has_drivesel[fdc->command & 0x1F]) { if (fdc->flags & FDC_FLAG_PCJR) fdc->drive = 0; + else if (fdc->flags & FDC_FLAG_5550) + fdc->drive = fdc->params[0] & 3; else fdc->drive = fdc->dor & 3; fdc->rw_drive = fdc->params[0] & 3; @@ -1115,6 +1201,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } if (fdc->pnum == fdc->ptot) { fdc_log("Got all params %02X\n", fdc->command); + for (int i = 0; i < fdc->ptot; i++) + fdc_log(" [%d] %02x\n", i, fdc->params[i]); fifo_reset(fdc->fifo_p); fdc->interrupt = fdc->processed_cmd; fdc->reset_stat = 0; @@ -1451,6 +1539,8 @@ fdc_read(uint16_t addr, void *priv) ret = 0xc0; ret |= (fdc->dor & 0x01) << 5; /* Drive Select 0 */ ret |= (fdc->dor & 0x30) >> 4; /* Motor Select 1, 0 */ + } else if (fdc->flags & FDC_FLAG_5550) { + ret = 0; } else { if (is486 || !fdc->enable_3f1) ret = 0xff; @@ -1503,9 +1593,13 @@ fdc_read(uint16_t addr, void *priv) ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6); break; case 4: /*Status*/ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); ret = fdc->stat; break; case 5: /*Data*/ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); if (fdc->fifointest) { /* Read FIFO buffer in the test mode (PS/55) */ ret = fifo_read(fdc->fifo_p); @@ -1733,6 +1827,8 @@ fdc_callback(void *priv) } if (writeprot[fdc->drive]) fdc->res[10] |= 0x40; + if ((fdc->flags & FDC_FLAG_5550) && drive_empty[fdc->drive])//IBM 5550 + fdc->res[10] &= 0xdf; /* Set Not Ready */ fdc->stat = (fdc->stat & 0xf) | 0xd0; fdc->paramstogo = 1; @@ -2349,6 +2445,10 @@ fdc_set_base(fdc_t *fdc, int base) if (fdc->flags & FDC_FLAG_NSC) { io_sethandler(base + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else if (fdc->flags & FDC_FLAG_5550) { + io_sethandler(base, 0x0003, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); @@ -2383,6 +2483,10 @@ fdc_remove(fdc_t *fdc) if (fdc->flags & FDC_FLAG_NSC) { io_removehandler(fdc->base_address + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else if (fdc->flags & FDC_FLAG_5550) { + io_removehandler(fdc->base_address, 0x0003, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 4, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 5, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_removehandler(fdc->base_address + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); @@ -2534,6 +2638,8 @@ fdc_init(const device_t *info) fdc->irq = FDC_TERTIARY_IRQ; else if (fdc->flags & FDC_FLAG_QUA) fdc->irq = FDC_QUATERNARY_IRQ; + else if (fdc->flags & FDC_FLAG_5550) + fdc->irq = 4; else fdc->irq = FDC_PRIMARY_IRQ; @@ -2686,6 +2792,20 @@ const device_t fdc_xt_umc_um8398_device = { .config = NULL }; +const device_t fdc_xt_5550_device = { + .name = "IBM 5550 Floppy Drive Controller", + .internal_name = "fdc_xt_5550", + .flags = 0, + .local = FDC_FLAG_5550, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t fdc_pcjr_device = { .name = "PCjr Floppy Drive Controller", .internal_name = "fdc_pcjr", diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 89ec2e9f6..592258cee 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -777,6 +777,10 @@ fdd_poll(void *priv) if (!fdd_notfound) fdc_noidam(fdd_fdc); } + + if (fdd_changed[drive]) { + fdc_diskchange_interrupt(fdd_fdc, drive); + } } int diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index ff56aa0ef..e1a818147 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -59,6 +59,7 @@ #define FDC_FLAG_TER 0x40000 /* Is Tertiary */ #define FDC_FLAG_QUA 0x80000 /* Is Quaternary */ #define FDC_FLAG_SMC661 0x100000 /* SM(s)C FDC37C661 - different TDR enhanced mode */ +#define FDC_FLAG_5550 0x200000 /* IBM Multistation 5550 */ typedef struct fdc_t { uint8_t dor; @@ -252,6 +253,7 @@ extern void fdc_reset(void *priv); extern uint8_t fdc_get_current_drive(void); extern void fdc_seek_complete_interrupt(fdc_t *fdc, int drive); +extern void fdc_diskchange_interrupt(fdc_t *fdc, int drive); #ifdef EMU_DEVICE_H extern const device_t fdc_xt_device; @@ -262,6 +264,7 @@ extern const device_t fdc_xt_t1x00_device; extern const device_t fdc_xt_tandy_device; extern const device_t fdc_xt_amstrad_device; extern const device_t fdc_xt_umc_um8398_device; +extern const device_t fdc_xt_5550_device; extern const device_t fdc_pcjr_device; extern const device_t fdc_at_device; extern const device_t fdc_at_sec_device; diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 8b32851bb..16aec312f 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -170,6 +170,7 @@ extern void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)); extern void kbd_adddata_process_10x(uint16_t val, void (*adddata)(uint16_t val)); extern const scancode scancode_xt[512]; +extern const scancode scancode_set8a[512]; extern uint8_t keyboard_set3_flags[512]; extern uint8_t keyboard_set3_all_repeat; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 21e279da7..b7702e55b 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1512,6 +1512,10 @@ extern int machine_xt_iskra3104_init(const machine_t *); extern int machine_xt_lxt3_init(const machine_t *); extern int machine_xt_compaq_deskpro_init(const machine_t *); +/* m_xt_ibm5550.c */ + +extern int machine_xt_ibm5550_init(const machine_t *); + /* m_xt_t1000.c */ #ifdef EMU_DEVICE_H extern const device_t t1000_video_device; diff --git a/src/include/86box/pit.h b/src/include/86box/pit.h index 991be4424..bc346f549 100644 --- a/src/include/86box/pit.h +++ b/src/include/86box/pit.h @@ -90,6 +90,8 @@ typedef struct pit_intf_t { void (*write)(uint16_t addr, uint8_t val, void *priv); /* Gets a counter's count. */ uint16_t (*get_count)(void *data, int counter_id); + /* Gets a counter's out. */ + int (*get_outlevel)(void *data, int counter_id); /* Sets a counter's GATE input. */ void (*set_gate)(void *data, int counter_id, int gate); /* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */ diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 816c9d38c..30d9da51d 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -26,6 +26,7 @@ add_library(mch OBJECT m_europc.c m_elt.c m_xt_olivetti.c + m_xt_ibm5550.c m_tandy.c m_v86p.c m_at_t3100e.c diff --git a/src/machine/m_xt_ibm5550.c b/src/machine/m_xt_ibm5550.c new file mode 100644 index 000000000..e1c842ecb --- /dev/null +++ b/src/machine/m_xt_ibm5550.c @@ -0,0 +1,2132 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the IBM 5550 machine. + * + * The IBM 5550 was launched with three models: + * 5551-Axx: 12" monochrome CRT with 16x16 font + * (replaced by model D) + * 5551-Bxx: 15" monochrome CRT with 24x24 font + * (replaced by model G, J, M) + * 5551-Cxx: 14" color CRT with 16x16 font + * (replaced by model E, H, K, P) + * These first-gen models have 1-3 DSQD diskette drives. + * You need select "Type: 5.25" 720k" in the Settings dialog - Floppy & CD-ROM drives. + * + * Currently, this module only support the model B configuration without hard disk. + * + * Authors: Akamaki. + * + * Copyright 2026 Akamaki. + */ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/dma.h> +#include <86box/pic.h> +#include <86box/ppi.h> +#include <86box/nmi.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/nvr.h> +#include <86box/keyboard.h> +#include <86box/rom.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/serial.h> +#include <86box/snd_speaker.h> +#include <86box/video.h> +#include <86box/machine.h> +#include <86box/plat_unused.h> +#define EMU_DEVICE_H +#include <86box/pit.h> + +// #define EPOCH_FONTROM_SIZE (1024 * 1024) +// #define EPOCH_FONTROM_MASK 0xffff +// #define EPOCH_FONTROM_BASESBCS 0x98000 +#define EPOCH_VRAM_SBCS 0x38000 +#define EPOCH_VRAM_SBEX 0x30000 +#define EPOCH_INVALIDACCESS8 0xffu +#define EPOCH_INVALIDACCESS16 0xffffu +#define EPOCH_INVALIDACCESS32 0xffffffffu +#define EPOCH_SIZE_VRAM (256 * 1024) /* 0x40000 */ +#define EPOCH_SIZE_CRAM (4 * 1024) /* 0x1000 */ +#define EPOCH_MASK_A000 0x1ffff /* 0x1FFFF */ +#define EPOCH_MASK_CRAM 0xfff /* 0xFFF */ +#define EPOCH_MASK_VRAM 0x3ffff /* 0xFFFFF */ +// #define EPOCH_MASK_VRAMPLANE 0x1ffff /* 0x1FFFF */ +#define EPOCH_PIXELCLOCK 40000000.0 /* 40 MHz interlaced */ + +#define LC_INDEX 0x3D0 +#define LC_DATA 0x3D1 +#define LS_ENABLE 0x3D2 +#define LS_DISABLE 0x3D3 +#define LC_HORIZONTAL_TOTAL 0x00 /* -1 */ +#define LC_HORIZONTAL_DISPLAYED 0x01 +#define LC_H_SYNC_POSITION 0x02 +#define LC_SYNC_WIDTH 0x03 +#define LC_VERTICAL_TOTAL 0x04 /* -1 */ +#define LC_V_TOTAL_ADJUST 0x05 +#define LC_VERTICAL_DISPLAYED 0x06 +#define LC_V_SYNC_POSITION 0x07 +#define LC_INTERLACE_AND_SKEW 0x08 +#define LC_MAXIMUM_SCAN_LINE 0x09 /* -1 */ +#define LC_CURSOR_ROW_START 0x0A +#define LC_CURSOR_ROW_END 0x0B +#define LC_START_ADDRESS_HIGH 0x0C +#define LC_START_ADDRESS_LOW 0x0D +#define LC_CURSOR_LOC_HIGH 0x0E +#define LC_CURSOR_LOC_LOWJ 0x0F +#define LC_LIGHT_PEN_HIGH 0x10 +#define LC_LIGHT_PEN_LOW 0x11 +// #define LV_PORT 0x3E8 +// #define LV_PALETTE_0 0x00 +// #define LV_MODE_CONTROL 0x10 +// #define LV_OVERSCAN_COLOR 0x11 +// #define LV_COLOR_PLANE_ENAB 0x12 +// #define LV_PANNING 0x13 +// #define LV_VIEWPORT1_BG 0x14 +// #define LV_VIEWPORT2_BG 0x15 +// #define LV_VIEWPORT3_BG 0x16 +// #define LV_BLINK_COLOR 0x17 +// #define LV_BLINK_CODE 0x18 +// #define LV_GR_CURSOR_ROTATION 0x19 +// #define LV_GR_CURSOR_COLOR 0x1A +// #define LV_GR_CURSOR_CONTROL 0x1B +// #define LV_COMMAND 0x1C +// #define LV_VP_BORDER_LINE 0x1D +// #define LV_SYNC_POLARITY 0x1F +// #define LV_CURSOR_CODE_0 0x20 +// #define LV_GRID_COLOR_0 0x34 +// #define LV_GRID_COLOR_1 0x35 +// #define LV_GRID_COLOR_2 0x36 +// #define LV_GRID_COLOR_3 0x37 +// #define LV_ATTRIBUTE_CNTL 0x38 +// #define LV_CURSOR_COLOR 0x3A +// #define LV_CURSOR_CONTROL 0x3B +// #define LV_RAS_STATUS_VIDEO 0x3C +// #define LV_PAS_STATUS_CNTRL 0x3D +// #define LV_IDENTIFICATION 0x3E +// #define LV_OUTPUT 0x3E +// #define LV_COMPATIBILITY 0x3F + +#define TIMER_CTR_0 0 //DMA +#define TIMER_CTR_1 1 //8253 timer +#define TIMER_CTR_2 2 //Speaker + +#define EPOCH_IRQ3_BIT (1 << 3) //Keyboard +#define EPOCH_IRQ6_BIT (1 << 6) //Timer + +enum epoch_nvr_ADDR { + epoch_nvr_SECOND1, + epoch_nvr_SECOND10, + epoch_nvr_MINUTE1, + epoch_nvr_MINUTE10, + epoch_nvr_HOUR1, + epoch_nvr_HOUR10, + epoch_nvr_WEEKDAY, + epoch_nvr_DAY1, + epoch_nvr_DAY10, + epoch_nvr_MONTH1, + epoch_nvr_MONTH10, + epoch_nvr_YEAR1, + epoch_nvr_YEAR10, + epoch_nvr_UNKOWN_D, + epoch_nvr_UNKOWN_E, + epoch_nvr_UNKOWN_F, + epoch_nvr_CONTROL /* Internal data for configuration port (I/O 360h) */ +}; + +#ifndef RELEASE_BUILD +// #define ENABLE_EPOCH_LOG 1 +#endif + +#ifdef ENABLE_EPOCH_LOG +// # define ENABLE_EPOCH_DEBUGIO 1 +int epoch_do_log = ENABLE_EPOCH_LOG; + +static void +epoch_log(const char *fmt, ...) +{ + va_list ap; + + if (epoch_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define epoch_log(fmt, ...) +#endif +#ifdef ENABLE_EPOCH_DEBUGIO +# define epoch_iolog epoch_log +#else +# define epoch_iolog(fmt, ...) +#endif + +typedef struct epoch_t { + mem_mapping_t cmapping; + + uint16_t crtc[32]; + // uint16_t crtc_vpreg[128]; + // uint8_t crtc_vpsel; + uint8_t crtmode; + // uint8_t attrc[0x40]; + // int attraddr, attrff; + // int attr_palette_enable; + int outflipflop; + int inflipflop; + int iolatch; + + int crtcaddr; + + uint8_t cgastat; + + // int writemode, readplane; + // uint8_t planemask; + + uint8_t egapal[16]; + uint32_t pallook[64]; + PALETTE vgapal; + + int vtotal, dispend, vsyncstart, vblankstart; + int hdisp, htotal, hdisp_time, rowoffset; + int lowres; + int rowcount; + double clock; + uint32_t memaddr_latch, ca_adj; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + uint64_t epochconst; + + int dispon; + int hdisp_on; + + uint32_t memaddr, memaddr_backup, cursoraddr; + int vc; + int scanline; + int linepos, vslines, linecountff; + int cursorvisible, cursoron, blink; + int scrollcache; + int char_width; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + int oddeven; + + /* Attribute Buffer E0000-E0FFFh (4 KB) */ + uint8_t *cram; + /* SBCS Font Buffer D8000-DBFFFh (16 KB) */ + /* APA Buffer A0000-DFFFFh (256 KB) */ + uint8_t *vram; + mem_mapping_t cmap, vmap, paritymap; + /* Font ROM card option (?KB) */ + // struct { + // int bank; + // mem_mapping_t map; + // uint8_t *rom; + // int charset; + // int portdata; + // } fontcard; + // uint8_t *changedvram; + uint32_t vram_display_mask; + + int parityerror; + int parityenabled; + uint8_t parityerroraddr; + int lowmemorydisabled; + int crtioenabled; + + int fullchange; + + void (*render)(struct epoch_t *epoch); + + nvr_t nvr; + int nvrctrl; + int nvrdata; + +} epoch_t; + +static void epoch_recalctimings(epoch_t *epoch); +static void epoch_reset(void *priv); + +/* +[IRQ] +The IBM 5550 has different IRQ assignments like the 6580 Displaywriter System. + +| IRQ | 5550 | Displaywriter | PC/XT | +| --- | ---------- | ---------------------------------- | ---------------- | +| 0 | ? | Incoming data for printer sharing | Timer | +| 1 | Async Comm | Transfer data to commo data link | Keyboard | +| 2 | Fixed Disk | Printer and Mag Card data transfer | Reserved | +| 3 | Keyboard | Keyboard incoming data | Async Comm (Sec) | +| 4 | Diskette | Diskette interrupt | Async Comm (Pri) | +| 5 | ? | Not used | Fixed Disk | +| 6 | Timer | Software timer | Diskette | +| 7 | ? | Error on commo data link | Printer | + +[Memory map] +| Start Address | Function | +| ------------- | ----------------------------------------------------- | +| 0 | 256 KB RAM on System Board | +| 40000h | 128 KB Expansion RAM Card | +| 60000h | 128 KB Expansion RAM Card | +| 80000h | 128 KB Expansion RAM Card | +| A0000h | 256 KB Video RAM | +| E0000h | 4 KB Code/Attribute Buffer | +| E8000h | ? KB Hard Disk Control Local Memory (not implemented) | +| F0000h | Kanji Font Card (not implemented) | +| FC000h | ROM | +*/ + +static void +epoch_out(uint16_t addr, uint16_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + epoch_iolog("%04X:%04X epoch Out addr %03X val %02X\n", cs >> 4, cpu_state.pc, addr, val); + switch (addr) { + case LC_INDEX: + epoch->crtcaddr = val; + break; + case LC_DATA: + if (epoch->crtcaddr > 0x1f) + return; + if (epoch->crtioenabled == 0) + return; + if (!(epoch->crtcaddr == LC_CURSOR_LOC_HIGH || epoch->crtcaddr == LC_CURSOR_LOC_LOWJ)) + epoch_iolog("%04X:%04X epoch Out addr %03X idx %02X val %02X (%d)\n", cs >> 4, cpu_state.pc, addr, epoch->crtcaddr, val, val); + if (!(epoch->crtc[epoch->crtcaddr] ^ val)) + return; + // switch (epoch->crtcaddr) { + // // case LC_CRTC_OVERFLOW: + // // // return; + // // break; + // case LC_MAXIMUM_SCAN_LINE: + // // if (!(epoch->ioctl[LS_MODE] & 0x01)) /* 16 or 256 color graphics mode */ + // // val = 0; + // break; + // // case LC_VERTICAL_TOTALJ: /* Vertical Total */ + // // break; + // } + switch (epoch->crtcaddr) { + case LC_START_ADDRESS_HIGH: + case LC_CURSOR_LOC_HIGH: + case LC_LIGHT_PEN_HIGH: + val &= 0x3F; + break; + } + epoch->crtc[epoch->crtcaddr] = val; + switch (epoch->crtcaddr) { + case LC_HORIZONTAL_DISPLAYED: + case LC_VERTICAL_DISPLAYED: + case LC_MAXIMUM_SCAN_LINE: + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: + epoch->fullchange = changeframecount; + epoch_recalctimings(epoch); + break; + default: + break; + } + break; + case LS_ENABLE: + // mem_mapping_disable(&epoch->paritymap); + epoch->crtioenabled = 1; + mem_mapping_enable(&epoch->cmap); + mem_mapping_enable(&epoch->vmap); + break; + case LS_DISABLE: + epoch->crtioenabled = 0; + mem_mapping_disable(&epoch->cmap); + mem_mapping_disable(&epoch->vmap); + // mem_mapping_enable(&epoch->paritymap); + break; + case 0x3D8: + epoch->crtmode = val; + epoch_recalctimings(epoch); + // epoch->attrff ^= 1; + break; + // case LV_PORT: + // // epoch_iolog("epoch Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, epoch->attrff,cs >> 4, cpu_state.pc); + // if (!epoch->attrff) { + // epoch->attraddr = val & 0x3f; + // if ((val & 0x20) != (epoch->attr_palette_enable & 0x20)) { + // epoch->fullchange = 3; + // epoch->attr_palette_enable = val & 0x20; + // epoch_recalctimings(epoch); + // } + // // epoch_iolog("set attraddr: %X\n", epoch->attraddr); + // } else { + // if ((epoch->attraddr == LV_PANNING) && (epoch->attrc[LV_PANNING] != val)) + // epoch->fullchange = changeframecount; + // if (epoch->attrc[epoch->attraddr & 0x3f] != val) + // epoch_iolog("attr changed %x: %x -> %x\n", epoch->attraddr & 0x3f, epoch->attrc[epoch->attraddr & 0x3f], val); + // epoch->attrc[epoch->attraddr & 0x3f] = val; + // // epoch_iolog("set attrc %x: %x\n", epoch->attraddr & 31, val); + // if (epoch->attraddr < 16) + // epoch->fullchange = changeframecount; + // if (epoch->attraddr == LV_MODE_CONTROL || epoch->attraddr < 0x10) { + // for (uint8_t c = 0; c < 16; c++) { + // // if (epoch->attrc[LV_MODE_CONTROL] & 0x80) + // // epoch->egapal[c] = epoch->attrc[c] & 0xf; + // // else + // // epoch->egapal[c] = epoch->attrc[c] & 0x3f; + // } + // } + // switch (epoch->attraddr) { + // case LV_COLOR_PLANE_ENAB: + // if ((val & 0xff) != epoch->plane_mask) + // epoch->fullchange = changeframecount; + // epoch->plane_mask = val & 0xff; + // break; + // case LV_CURSOR_CONTROL: + // switch (val & 0x18) { + // case 0x08: /* fast blink */ + // epoch->blinkconf = 0x10; + // break; + // case 0x18: /* slow blink */ + // epoch->blinkconf = 0x20; + // break; + // default: /* no blink */ + // epoch->blinkconf = 0xff; + // break; + // } + // break; + // case LV_MODE_CONTROL: + // case LV_ATTRIBUTE_CNTL: + // case LV_COMPATIBILITY: + // epoch_recalctimings(epoch); + // break; + // default: + // break; + // } + // } + // epoch->attrff ^= 1; + // break; + // case LV_PORT+1: + // /* VZ Editor's CURSOR.COM writes data via this port */ + // epoch->attrc[epoch->attraddr & 0x3f] = val; + // break; + default: + epoch_iolog("epoch? Out addr %03X val %02X\n", addr, val); + break; + } +} + +static uint16_t +epoch_in(uint16_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + uint16_t temp = 0xff; + + switch (addr) { + case LC_INDEX: + temp = epoch->crtcaddr; + break; + case LC_DATA: + if (epoch->crtcaddr > 0x1f) + return EPOCH_INVALIDACCESS16; + if (epoch->crtioenabled == 0) + return EPOCH_INVALIDACCESS16; + temp = epoch->crtc[epoch->crtcaddr]; + break; + // case LV_PORT: + // temp = epoch->attraddr | epoch->attr_palette_enable; + // break; + // case LV_PORT + 1: + // switch (epoch->attraddr) { + // case LV_RAS_STATUS_VIDEO: /* this maybe equivalent to 3ba / 3da ISR1 */ + // if (epoch->cgastat & 0x01) + // epoch->cgastat &= ~0x30; + // else + // epoch->cgastat ^= 0x30; /* toggle */ + // if (epoch->cgastat & 0x08) + // epoch->cgastat &= ~0x08; + // else + // epoch->cgastat ^= 0x08; /* toggle */ + // temp = epoch->cgastat; + // break; + // case LV_IDENTIFICATION: + // temp = 0x28; + // break; + // default: + // temp = epoch->attrc[epoch->attraddr]; + // break; + // } + // // epoch_iolog("epoch In %04X(%02X) %04X %04X:%04X\n", addr, epoch->attraddr, temp, cs >> 4, cpu_state.pc); + // epoch->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ + // break; + case 0x3DA: + temp = 0xff; + if (!(epoch->crtmode & 0x08)) {/* The video out is active */ + if(epoch->cgastat & 8) + temp &= 0x7f; + } + temp &= 0xfe;/* equipment ? color or monochrome monitor */ + // temp |= 0x01; + break; + } + if (addr != 0x3DA) + epoch_iolog("%04X:%04X epoch In %04X %04X\n", cs >> 4, cpu_state.pc, addr, temp); + return temp; +} +/* + * Write I/O + * out b(idx), out b(data), out b(data) + * out b(idx), out w(data) + * out b(idx), out w(data), out b(data) + * out w(idx) + * Read I/O + * out b(idx), in b(data) + * out b(idx), in b, in b(data) + * out b(idx), in w(data) + */ +static void +epoch_outb(uint16_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_iolog("%04X:%04X epoch Outb addr %03X val %02X es:di=%x:%x ds:si=%x:%x\n", cs >> 4, cpu_state.pc, addr, val, ES, DI, DS, SI); + epoch->inflipflop = 0; + switch (addr) { + // case LS_DATA: + // case LF_DATA: + case LC_DATA: + if (epoch->outflipflop) { + /* out b(idx), out b(data), out b(data) */ + epoch->iolatch |= (uint16_t) val << 8; + epoch->outflipflop = 0; + } else { // + epoch->iolatch = val; + epoch->outflipflop = 1; + } + break; + // case LS_INDEX: + // case LF_INDEX: + case LC_INDEX: + default: + epoch->iolatch = val; + epoch->outflipflop = 0; + break; + } + epoch_out(addr, epoch->iolatch, epoch); +} +static void +epoch_outw(uint16_t addr, uint16_t val, void *priv) +{ + epoch_iolog("epoch Outw addr %03X val %04X\n", addr, val); + epoch_t *epoch = (epoch_t *) priv; + epoch->inflipflop = 0; + switch (addr) { + // case LS_INDEX: + // case LF_INDEX: + case LC_INDEX: + // case LG_INDEX: + epoch_out(addr, val & 0xff, epoch); + epoch->iolatch = val >> 8; + epoch_out(addr + 1, epoch->iolatch, epoch); + epoch->outflipflop = 1; + break; + // case LV_PORT: + // // epoch->attrff = 0; + // epoch_out(addr, val & 0xff, epoch); + // epoch_out(addr, val >> 8, epoch); + // epoch->outflipflop = 0; + // break; + // case LS_DATA: + // case LF_DATA: + case LC_DATA: + // case LG_DATA: + default: + epoch_out(addr, val, epoch); + epoch->outflipflop = 0; + break; + } +} +static uint8_t +epoch_inb(uint16_t addr, void *priv) +{ + uint8_t temp; + epoch_t *epoch = (epoch_t *) priv; + epoch->outflipflop = 0; + switch (addr) { + case LC_DATA: + if (epoch->inflipflop) { + /* out b(idx), in b(low data), in b(high data) */ + temp = epoch->iolatch >> 8; + epoch->inflipflop = 0; + } else { // + epoch->iolatch = epoch_in(addr, epoch); + temp = epoch->iolatch & 0xff; + epoch->inflipflop = 1; + } + break; + // case LS_INDEX: + // case LF_INDEX: + case LC_INDEX: + // case LS_DATA: + // case LF_DATA: + default: + temp = epoch_in(addr, epoch) & 0xff; + epoch->inflipflop = 0; + break; + } + // epoch_iolog("epoch Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +static uint16_t +epoch_inw(uint16_t addr, void *priv) +{ + uint16_t temp; + epoch_t *epoch = (epoch_t *) priv; + epoch->inflipflop = 0; + epoch->outflipflop = 0; + temp = epoch_in(addr, epoch); + epoch_iolog("epoch Inw addr %03X val %04X\n", addr, temp); + return temp; +} + +/* Get character line pattern from jfont rom or gaiji volatile memory */ +static uint32_t +getfont_ps55dbcs(int32_t code, int32_t line, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + uint32_t font = 0; + if (code < 1536) { + code *= 0x80; + font = epoch->vram[code + line * 4]; + font <<= 8; + font |= epoch->vram[code + line * 4 + 1]; + font <<= 8; + font |= epoch->vram[code + line * 4 + 2]; + font <<= 8; + font |= epoch->vram[code + line * 4 + 3]; + } else + font = EPOCH_INVALIDACCESS32; + return font; +} + +/* Get the foreground color from the attribute byte */ +static uint8_t +getPS55ForeColor(uint8_t attr, epoch_t *epoch) +{ + uint8_t foreground = ~attr & 0x08; /* 0000 1000 */ + foreground <<= 2; /* 0010 0000 */ + foreground |= ~attr & 0xc0; /* 1110 0000 */ + foreground >>= 4; /* 0000 1110 */ + // if (epoch->attrc[LV_PAS_STATUS_CNTRL] & 0x40) + // foreground |= 0x01; /* bright color palette */ + return foreground; +} + +static void +epoch_render_blank(epoch_t *epoch) +{ + int x, xx; + + if (epoch->firstline_draw == 2000) + epoch->firstline_draw = epoch->displine; + epoch->lastline_draw = epoch->displine; + + for (x = 0; x < epoch->hdisp + epoch->scrollcache; x++) { + for (xx = 0; xx < epoch->char_width; xx++) + ((uint32_t *) buffer32->line[epoch->displine])[(x * epoch->char_width) + xx] = 0; + } +} +/* Display Adapter Mode 8, E Drawing */ +static void +epoch_render_text(epoch_t *epoch) +{ + if (epoch->firstline_draw == 2000) + epoch->firstline_draw = epoch->displine; + epoch->lastline_draw = epoch->displine; + + if (epoch->fullchange) { + int offset = (8 - epoch->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[epoch->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + // int colormode = ((epoch->attrc[LV_PAS_STATUS_CNTRL] & 0x80) == 0x80); + int colormode = 0; + // epoch_log("displ: %x, first: %x, epochma: %x, epochsc: %x\n", + // epoch->displine , epoch->firstline_draw, epoch->memaddr, epoch->scanline); + for (x = 0; x < epoch->hdisp; x += 13) { + chr = epoch->cram[(epoch->memaddr) & EPOCH_MASK_CRAM]; + attr = epoch->cram[(epoch->memaddr + 1) & EPOCH_MASK_CRAM]; + // if(chr!=0x20) epoch_log("chr: %x, attr: %x ", chr, attr); + if (colormode) /* IO 3E8h, Index 1Dh */ + { /* --Parse attribute byte in color mode-- */ + bg = 0; /* bg color is always black (the only way to change background color is programming PAL) */ + fg = getPS55ForeColor(attr, epoch); + if (attr & 0x04) { /* reverse 0000 0100 */ + bg = fg; + fg = 0; + } + } else { /* --Parse attribute byte in monochrome mode-- */ + if (attr & 0x08) + fg = 3; /* Highlight 0000 1000 */ + else + fg = 2; + bg = 0; /* Background is always color #0 (default is black) */ + if (!(~attr & 0xCC)) /* Invisible 11xx 11xx -> 00xx 00xx */ + { + fg = bg; + attr &= 0x33; /* disable blinkking, underscore, highlight and reverse */ + } + if (attr & 0x04) { /* reverse 0000 0100 */ + bg = fg; + fg = 0; + } + /* Blinking 1000 0000 */ + fg = ((epoch->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; + // if(chr!=0x20) epoch_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, epoch->egapal[fg], epoch->pallook[epoch->egapal[fg]]); + } + /* Draw character */ + for (uint32_t n = 0; n < 13; n++) + p[n] = epoch->pallook[epoch->egapal[bg]]; /* draw blank */ + /* SBCS or DBCS left half */ + if (chr_wide == 0) { + if (attr & 0x01) + chr_wide = 1; + // chr_wide = 0; + /* Stay drawing If the char code is DBCS and not at last column. */ + if (chr_wide) { + /* Get high DBCS code from the next video address */ + chr_dbcs = epoch->cram[(epoch->memaddr + 2) & EPOCH_MASK_CRAM]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + /* Get the font pattern */ + uint32_t font = getfont_ps55dbcs(chr_dbcs, epoch->scanline, epoch); + /* Draw 13 dots */ + for (uint32_t n = 0; n < 13; n++) { + p[n] = epoch->pallook[epoch->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } else { + /* the char code is SBCS (ANK) */ + uint32_t fontbase; + if (attr & 0x02) /* second map of SBCS font */ + fontbase = EPOCH_VRAM_SBEX; + else + fontbase = EPOCH_VRAM_SBCS; + uint16_t font = epoch->vram[fontbase + chr * 0x80 + epoch->scanline * 4]; /* w13xh29 font */ + font <<= 8; + font |= epoch->vram[fontbase + chr * 0x80 + epoch->scanline * 4 + 1]; /* w13xh29 font */ + // if(chr!=0x20) epoch_log("memaddr: %x, scanline: %x, chr: %x, font: %x ", epoch->memaddr, epoch->scanline, chr, font); + /* Draw 13 dots */ + for (uint32_t n = 0; n < 13; n++) { + p[n] = epoch->pallook[epoch->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + /* right half of DBCS */ + else { + uint32_t font = getfont_ps55dbcs(chr_dbcs, epoch->scanline, epoch); + /* Draw 13 dots */ + for (uint32_t n = 0; n < 13; n++) { + p[n] = epoch->pallook[epoch->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + /* Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. */ + if (epoch->scanline == 28 && attr & 0x40 && !colormode) { /* Underscore only in monochrome mode */ + for (uint32_t n = 0; n < 13; n++) + p[n] = epoch->pallook[epoch->egapal[fg]]; /* under line (white) */ + } + /* Column 1 (Vertical Line) */ + if (attr & 0x10) { + p[0] = epoch->pallook[epoch->egapal[2]]; /* vertical line (white) */ + } + if (epoch->scanline == 0 && attr & 0x20) { /* HGrid */ + for (uint32_t n = 0; n < 13; n++) + p[n] = epoch->pallook[epoch->egapal[2]]; /* horizontal line (white) */ + } + /* Drawing text cursor */ + drawcursor = ((epoch->memaddr == epoch->cursoraddr) && epoch->cursorvisible && epoch->cursoron); + if (drawcursor && epoch->scanline >= epoch->crtc[LC_CURSOR_ROW_START] && epoch->scanline <= epoch->crtc[LC_CURSOR_ROW_END]) { + // int cursorwidth = (epoch->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); + int cursorwidth = 13; + int cursorcolor = 2; /* Choose color 2 if mode 8 */ + fg = ((attr & 0x08) ? 3 : 2); + bg = 0; + if (attr & 0x04) { /* Color 0 if reverse */ + bg = fg; + fg = 0; + } + for (uint32_t n = 0; n < cursorwidth; n++) + if (p[n] == epoch->pallook[epoch->egapal[cursorcolor]] || epoch->egapal[bg] == epoch->egapal[cursorcolor]) + p[n] = (p[n] == epoch->pallook[epoch->egapal[bg]]) ? epoch->pallook[epoch->egapal[fg]] : epoch->pallook[epoch->egapal[bg]]; + else + p[n] = (p[n] == epoch->pallook[epoch->egapal[bg]]) ? epoch->pallook[epoch->egapal[cursorcolor]] : p[n]; + } + epoch->memaddr += 2; + p += 13; + } + } +} + +static void +epoch_render_color_4bpp(epoch_t *epoch) +{ + // int changed_offset = epoch->memaddr >> 9; + // epoch_log("memaddr %x cf %x\n", epoch->memaddr, changed_offset); + // epoch->plane_mask &= 1; /*safety */ + + // if (epoch->changedvram[changed_offset] || epoch->changedvram[changed_offset + 1] || epoch->fullchange) { + int x; + int offset = (8 - epoch->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[epoch->displine])[offset]; + + if (epoch->firstline_draw == 2000) + epoch->firstline_draw = epoch->displine; + epoch->lastline_draw = epoch->displine; + // epoch_log("d %X\n", epoch->memaddr); + int readvaddr = (epoch->memaddr * 8) + (epoch->scanline * 128); + for (x = 0; x <= epoch->hdisp; x += 8) /* hdisp = 1024 */ + { + uint8_t edat[8]; + uint8_t dat; + + /* get 8 pixels from vram */ + readvaddr &= epoch->vram_display_mask; + *(uint8_t *) (&edat[0]) = *(uint8_t *) (&epoch->vram[readvaddr]); + readvaddr += 1; + + dat = ((edat[0] >> 7) & 1); + p[0] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 6) & 1); + p[1] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 5) & 1); + p[2] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 4) & 1); + p[3] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 3) & 1); + p[4] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 2) & 1); + p[5] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 1) & 1); + p[6] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 0) & 1); + p[7] = epoch->pallook[epoch->egapal[dat]]; + p += 8; + } +} + +/* + INT 10h video modes supported in DOS K3.44. + Mode Type Colors Text Base Address PELs Render + 2 A/N 3 80 x 25 E0000h 1040 x 725 text + 8 A/N/K 3 80 x 25 E0000h 1040 x 725 text + Ah APA 2 78 x 25 A0000h 1024 x 768 color_4bpp + Bh APA 16 40 x 25 A0000h 360 x 512 n/a + Ch APA 16 80 x 25 A0000h 720 x 512 n/a + Dh APA 16 78 x 25 A0000h 1024 x 768 n/a + Eh A/N/K 16 80 x 25 E0000h 1040 x 725 n/a +*/ +static void +epoch_recalctimings(epoch_t *epoch) +{ + double crtcconst; + double _dispontime, _dispofftime, disptime; + + epoch->vblankstart = epoch->crtc[LC_VERTICAL_TOTAL] & 0x7f; + epoch->dispend = epoch->crtc[LC_VERTICAL_DISPLAYED] & 0x7f; + epoch->vsyncstart = epoch->crtc[LC_V_SYNC_POSITION] & 0x7f; + epoch->vblankstart += 1; + epoch->vtotal = epoch->vblankstart + (epoch->crtc[LC_V_TOTAL_ADJUST] & 0x1f); + epoch->hdisp = epoch->crtc[LC_HORIZONTAL_DISPLAYED] & 0xff; + + // epoch->hdisp -= epoch->crtc[LC_START_H_DISPLAY_ENAB]; + // epoch->dispend -= epoch->crtc[LC_START_V_DISPLAY_ENAB]; + //epoch_log("Dispend %d\n", epoch->dispend); + // epoch->vsyncstart += 1; + //epoch->vtotal += 1; + + epoch->htotal = epoch->crtc[LC_HORIZONTAL_TOTAL] & 0xff; + epoch->htotal += 1; + + // epoch->rowoffset = epoch->crtc[LC_OFFSET]; /* number of bytes in a scanline */ + epoch->rowoffset = epoch->crtc[LC_HORIZONTAL_DISPLAYED] & 0xff; + + epoch->clock = epoch->epochconst; + + if (epoch->vtotal == 0) + epoch->vtotal = epoch->vsyncstart = epoch->vblankstart = 32; + if (epoch->htotal == 0) + epoch->htotal = epoch->dispend = epoch->hdisp = 64; + if (epoch->rowoffset == 0) + epoch->rowoffset = 64 * 2; /* To avoid causing a DBZ error */ + + epoch->memaddr_latch = ((epoch->crtc[LC_START_ADDRESS_HIGH] & 0x3f) << 8) | epoch->crtc[LC_START_ADDRESS_LOW]; + + epoch->ca_adj = 0; + epoch->rowcount = epoch->crtc[LC_MAXIMUM_SCAN_LINE] & 0x1f; + epoch->rowcount += 1; + + epoch->vtotal *= (epoch->rowcount + 1); + epoch->dispend *= (epoch->rowcount + 1); + epoch->vsyncstart *= (epoch->rowcount + 1); + epoch->vblankstart *= (epoch->rowcount + 1); + + epoch->hdisp_time = epoch->hdisp; + + /* determine display mode */ + if (epoch->crtmode & 0x02) { + epoch->hdisp *= 16; + epoch->char_width = 16; + /* PS/55 8-color */ + epoch_log("Set videomode to PS/55 4 bpp graphics.\n"); + epoch->render = epoch_render_color_4bpp; + epoch->vram_display_mask = EPOCH_MASK_A000; + } else { + /* PS/55 text(color/mono) */ + epoch_log("Set videomode to PS/55 Mode 8/E text.\n"); + epoch->render = epoch_render_text; + epoch->vram_display_mask = EPOCH_MASK_CRAM; + epoch->hdisp *= 13; + epoch->char_width = 13; + } + if (epoch->crtmode & 0x08) + epoch->render = epoch_render_blank; + + if (epoch->vblankstart < epoch->vsyncstart) + epoch->vsyncstart = epoch->vblankstart; + if (epoch->vsyncstart < epoch->dispend) + epoch->dispend = epoch->vsyncstart; + + crtcconst = epoch->clock * epoch->char_width; + + disptime = epoch->htotal; + _dispontime = epoch->hdisp_time; + + epoch_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, epoch->hdisp); + + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + epoch->dispontime = (uint64_t) _dispontime; + epoch->dispofftime = (uint64_t) _dispofftime; + if (epoch->dispontime < TIMER_USEC) + epoch->dispontime = TIMER_USEC; + if (epoch->dispofftime < TIMER_USEC) + epoch->dispofftime = TIMER_USEC; + epoch_log("epoch horiz display end %i vidclock %f htotal %i\n", epoch->hdisp, epoch->clock, epoch->htotal); + epoch_log("epoch vert display end %i max row %i vsyncstart %i vtotal %i\n",epoch->dispend,epoch->rowcount,epoch->vsyncstart,epoch->vtotal); + epoch_log("epoch dispon %lu dispoff %lu on(us) %f off(us) %f\n",epoch->dispontime, epoch->dispofftime, + (double)epoch->dispontime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0, + (double)epoch->dispofftime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0); +} + +static void +epoch_doblit(int wx, int wy, epoch_t *epoch) +{ + if (wx != xsize || wy != ysize) { + xsize = wx; + ysize = wy; + set_screen_size(xsize, ysize); + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(32, 0, xsize, ysize); + frames++; + + video_res_x = wx; + video_res_y = wy; + video_bpp = 8; +} + +static void +epoch_poll(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + int x; + + if (!epoch->linepos) { + timer_advance_u64(&epoch->timer, epoch->dispofftime); + + epoch->cgastat |= 1; + epoch->linepos = 1; + + if (epoch->dispon) { + epoch->hdisp_on = 1; + + epoch->memaddr &= epoch->vram_display_mask; + if (epoch->firstline == 2000) { + epoch->firstline = epoch->displine; + video_wait_for_buffer(); + } + + if((epoch->displine ^ !epoch->oddeven) & 1) + epoch->render(epoch); + + if (epoch->lastline < epoch->displine) + epoch->lastline = epoch->displine; + } + + // epoch_log("%03i %06X %06X\n", epoch->displine, epoch->memaddr,epoch->vram_display_mask); + epoch->displine++; + if ((epoch->cgastat & 8) && ((epoch->displine & 0xf) == (epoch->vblankstart & 0xf)) && epoch->vslines) { + // epoch_log("Vsync off at line %i\n",displine); + epoch->cgastat &= ~8; + } + epoch->vslines++; + if (epoch->displine > 2000) + epoch->displine = 0; + } else { + // epoch_log("VC %i memaddr %05X\n", epoch->vc, epoch->memaddr); + timer_advance_u64(&epoch->timer, epoch->dispontime); + + if (epoch->dispon) + epoch->cgastat &= ~1; + epoch->hdisp_on = 0; + + epoch->linepos = 0; + if (epoch->scanline == (epoch->crtc[LC_CURSOR_ROW_END] & 0x1f)) + epoch->cursorvisible = 0; + if (epoch->dispon) { + if (epoch->scanline == epoch->rowcount) { + epoch->linecountff = 0; + epoch->scanline = 0; + + epoch->memaddr_backup += (epoch->rowoffset << 1); /* interlace */ + epoch->memaddr_backup &= epoch->vram_display_mask; + epoch->memaddr = epoch->memaddr_backup; + } else { + epoch->linecountff = 0; + epoch->scanline++; + epoch->scanline &= 0x1f; + epoch->memaddr = epoch->memaddr_backup; + } + } + + epoch->vc++; + epoch->vc &= 0x7ff; + + if (epoch->vc == epoch->dispend) { + epoch->dispon = 0; + if (!(epoch->crtmode & 0x02)) { /* in text mode */ + // if (epoch->attrc[LV_CURSOR_CONTROL] & 0x01) /* cursor blinking */ + // { + // epoch->cursoron = (epoch->blink | 1) & epoch->blinkconf; + epoch->cursoron = 1; + // } else { + // epoch->cursoron = 0; + // } + if (!(epoch->blink & (0x10 - 1))) /* force redrawing for cursor and blink attribute */ + epoch->fullchange = changeframecount; + } + epoch->blink++; + + // for (x = 0; x <= (EPOCH_MASK_VRAMPLANE >> 9); x++) { + // if (epoch->changedvram[x]) + // epoch->changedvram[x]--; + // } + // memset(changedvram,0,2048); del + if (epoch->fullchange) { + epoch->fullchange--; + } + } + if (epoch->vc == epoch->vsyncstart) { + int wx, wy; + // epoch_log("VC vsync %i %i\n", epoch->firstline_draw, epoch->lastline_draw); + epoch->dispon = 0; + epoch->cgastat |= 8; + x = epoch->hdisp; + + if (!epoch->oddeven) + epoch->lastline++; + if (epoch->oddeven) + epoch->firstline--; + + wx = x; + wy = epoch->lastline - epoch->firstline; + + epoch_doblit(wx, wy, epoch); + + epoch->firstline = 2000; + epoch->lastline = 0; + + epoch->firstline_draw = 2000; + epoch->lastline_draw = 0; + + epoch->oddeven ^= 1; + + epoch->vslines = 0; + + epoch->memaddr + = epoch->memaddr_backup = epoch->memaddr_latch << 1; + epoch->cursoraddr = ((epoch->crtc[LC_CURSOR_LOC_HIGH] << 8) | epoch->crtc[LC_CURSOR_LOC_LOWJ]) + epoch->ca_adj; + epoch->cursoraddr <<= 1; + + // epoch_log("Addr %08X vson %03X vsoff %01X\n",epoch->memaddr,epoch->vsyncstart,epoch->crtc[0x11]&0xF); + } + if (epoch->vc == epoch->vtotal) { + // epoch_log("VC vtotal\n"); + // printf("Frame over at line %i %i %i %i\n",displine,vc,epoch_vsyncstart,epoch_dispend); + epoch->vc = 0; + epoch->scanline = 0; + epoch->dispon = 1; + epoch->displine = 0; + // epoch->scrollcache = epoch->attrc[LV_PANNING] & 0x07; + epoch->scrollcache = 0; + } + if (epoch->scanline == (epoch->crtc[LC_CURSOR_ROW_START] & 31)) + epoch->cursorvisible = 1; + } +} + +static void +epoch_vram_write(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~0xfff) != 0xE0000) return; + addr -= 0xA0000; + addr &= EPOCH_MASK_VRAM; + epoch->vram[addr] = val; + epoch->fullchange = changeframecount; + // if(val == 0x66) + // epoch_log("66 %04X:%04X %04X:%04X>%04X:%04X\n", cs >> 4, cpu_state.pc, DS, SI,ES,DI); +} +static void +epoch_vram_writeb(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_log("epoch_vram_writeb: Write to %x, val %x\n", addr, val); + cycles -= video_timing_write_b; + epoch_vram_write(addr, val, epoch); +} +static void +epoch_vram_writew(uint32_t addr, uint16_t val, void *priv) +{ + // epoch_log("epoch_vram_writ ew: Write to %x, val %x\n", addr, val); + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_write_w; + epoch_vram_write(addr, val & 0xff, epoch); + epoch_vram_write(addr + 1, val >> 8, epoch); +} + +static uint8_t +epoch_vram_read(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~epoch_MASK_CRAM) != 0xE0000) + // return epoch_INVALIDACCESS8; + addr -= 0xA0000; + addr &= EPOCH_MASK_VRAM; + return epoch->vram[addr]; +} +static uint8_t +epoch_vram_readb(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_b; + return epoch_vram_read(addr, epoch); +} + +static uint16_t +epoch_vram_readw(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_w; + return epoch_vram_read(addr, epoch) | (epoch_vram_read(addr + 1, epoch) << 8); +} + + +static void +epoch_cram_write(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~0xfff) != 0xE0000) return; + addr &= EPOCH_MASK_CRAM; + epoch->cram[addr] = val; + epoch->fullchange = changeframecount;; + // epoch_log("cw %04X:%04X %04X %02X\n", cs >> 4, cpu_state.pc, addr, val); +} +static void +epoch_cram_writeb(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_log("epoch_cram_writeb: Write to %x, val %x\n", addr, val); + cycles -= video_timing_write_b; + epoch_cram_write(addr, val, epoch); +} +static void +epoch_cram_writew(uint32_t addr, uint16_t val, void *priv) +{ + // epoch_log("epoch_cram_writ ew: Write to %x, val %x\n", addr, val); + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_write_w; + epoch_cram_write(addr, val & 0xff, epoch); + epoch_cram_write(addr + 1, val >> 8, epoch); +} + +static uint8_t +epoch_cram_read(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~epoch_MASK_CRAM) != 0xE0000) + // return epoch_INVALIDACCESS8; + addr &= EPOCH_MASK_CRAM; + return epoch->cram[addr]; +} +static uint8_t +epoch_cram_readb(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_b; + return epoch_cram_read(addr, epoch); +} + +static uint16_t +epoch_cram_readw(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_w; + return epoch_cram_read(addr, epoch) | (epoch_cram_read(addr + 1, epoch) << 8); +} + +static uint8_t +epoch_parity_readb(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + if ((epoch->parityerror != 0) && (epoch->parityenabled != 0)) { + epoch->parityerroraddr = (addr >> 16) & 0xFF; /* X000:0 */ + epoch_log("%04X:%04X perror at %0X\n", cs >> 4, cpu_state.pc, addr); + if (nmi_mask) + nmi_raise(); + } + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mrerror at %0X\n", cs >> 4, cpu_state.pc, addr); + return EPOCH_INVALIDACCESS8; + } + } + // return EPOCH_INVALIDACCESS8; + return mem_read_ram(addr, priv); +} + +static uint16_t +epoch_parity_readw(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + if ((epoch->parityerror != 0) && (epoch->parityenabled != 0)) { + epoch->parityerroraddr = (addr >> 16) & 0xFF; + epoch_log("%04X:%04X perror at %X\n", cs >> 4, cpu_state.pc, addr); + if (nmi_mask) + nmi_raise(); + } + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mrerror at %X\n", cs >> 4, cpu_state.pc, addr); + return EPOCH_INVALIDACCESS16; + } + } + return mem_read_ramw(addr, priv); +} + +static void +epoch_parity_writeb(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_log("%04X:%04X mw %0X\n", cs >> 4, cpu_state.pc, addr); + if (epoch->parityenabled == 0) + epoch->parityerror = 1; + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mwerror at %X\n", cs >> 4, cpu_state.pc, addr); + if (epoch->parityenabled) + epoch->parityerror = 1; + return; + } + } + // if (val == 0xcb) + // epoch_log("CB %04X:%04X %04X:%04X>%04X:%04X\n", cs >> 4, cpu_state.pc, DS, SI, ES, DI); + mem_write_ram(addr, val, priv); +} +static void +epoch_parity_writew(uint32_t addr, uint16_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + if (epoch->parityenabled == 0) + epoch->parityerror = 1; + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mwerror at %X\n", cs >> 4, cpu_state.pc, addr); + if (epoch->parityenabled) + epoch->parityerror = 1; + return; + } + } + mem_write_ramw(addr, val, priv); +} + +static uint8_t +epoch_misc_in(uint16_t port, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + uint8_t ret = 0xff; + + switch (port) { +/* +I/O A0h R: +xxxx xxx1: Memory or parity error? +0xxx xxxx: Coprocessor installed? +*/ + case 0xA0: + if(!epoch->parityenabled) + ret &= 0xfe; + else + ret = epoch->parityerror & 1; + if (fpu_type == FPU_NONE) + ret |= 0x80; + break; + case 0xA1: /* High address where memory error occured */ + ret = epoch->parityerroraddr; + break; +/* +I/O A2h R: +xxxx 0x0x: Color CRT +xxxx 1x0x: Mono 24 CRT ? +xxxx xx1x: 16 pixel CRT +xx1x xxxx: No hard drive +x1xx xxxx: No floppy drive +1xxx xxxx: No (bootable?) hard drive +*/ + case 0xA2: + ret = 0xA8;/* Mono 24 */ + // ret = 0xA8;/* Mono 16 */ + break; +/* +I/O A3h R: +xxxx x001: Main RAM 256 KB? +xxxx x011: Main RAM 384 KB? +xxxx x111: Main RAM 512 KB? +xxxx x000: Main RAM 640 KB? +xxxx 1xxx: Serial port 3f8h +xxx1 xxxx: Serial port 2f8h +*/ + case 0xA3: + ret = 0x08; + if (mem_size < 384) + ret |= 0x07; + else if (mem_size < 512) + ret |= 0x06; + else if (mem_size < 640) + ret |= 0x04; + break; + case 0xA4: + ret = 0; + break; + case 0xA5: + ret = 0x08; /* Bit 3: Keyboard connected? */ + break; + // case 0x164: + // switch (epoch->fontcard.portdata) { + // case 0x16A: + // ret = 0xFD; + // break; + // case 0x168: + // ret = 0xFE; + // break; + // } + // break; + default: + break; + } + epoch_log("%04X:%04X I/O In %02X: %02X\n", cs >> 4, cpu_state.pc, port, ret); + return ret; +} + +static void +epoch_misc_out(uint16_t port, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + pit_intf_t *pit_intf = &pit_devs[0]; + + // dev->regs[port & 0x0007] = val; + // epoch_log("%04X:%04X I/O Out %02X: %02X\n AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X\n", + // cs >> 4, cpu_state.pc, port, val, AX, BX, CX, DX, ES, DI, DS, SI); + if(port != 0x44) + epoch_log("%04X:%04X I/O Out %02X: %02X\n", cs >> 4, cpu_state.pc, port, val); + + switch (port) { + case 0x44: + for (uint8_t i = 0; i < 3; i++) { + pit_intf->set_gate(pit_intf->data, i, val & 1); + } + break; +/* +I/O A0h W: +x1xx xxxx: Enable parity update (Disable this -> Write data -> Enable this -> Read data, causes NMI) +1xxx xxxx: Enable NMI check +*/ + case 0xA0: + nmi_mask = val & 0x80; + epoch->parityenabled = val & 0x40; /* 1 = Enable read/write with parity */ + break; + case 0xA1: + /* Diagnostics LED (used by debug card module) */ + break; + case 0xA2: + /* Reset memory error bit */ + epoch->parityerror = 0; + break; + // case 0x160 ... 0x16A: + // mem_mapping_enable(&epoch->fontcard.map); + // epoch->fontcard.portdata = port; + // break; + case 0x310 ... 0x312: + epoch->lowmemorydisabled = 0; + epoch_log("Low memory enabled\n"); + break; + case 0x314 ... 0x316: + epoch->lowmemorydisabled = 1; + epoch_log("Low memory disabled\n"); + break; + } +} +typedef struct epochkbd_t { + int want_irq; + int blocked; + + uint8_t pa; + uint8_t pb; + uint8_t clock; + uint8_t key_waiting; + uint8_t reset_step; + + pc_timer_t send_delay_timer; +} epochkbd_t; + +static uint8_t key_queue[16]; +static int key_queue_start = 0; +static int key_queue_end = 0; + +static void +kbd_epoch_poll(void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + + timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC); + + if (kbd->pb & 0x04) + return; + + if (kbd->want_irq) { + kbd->want_irq = 0; + kbd->pa = kbd->key_waiting; + kbd->pb &= 0xF7; + kbd->blocked = 1; + picint(EPOCH_IRQ3_BIT); + epoch_log("epochkbd: kbd_poll(): keyboard_xt : take IRQ\n"); + } + + if ((key_queue_start != key_queue_end) && !kbd->blocked) { + kbd->key_waiting = key_queue[key_queue_start]; + epoch_log("epochkbd: reading %02X from the key queue at %i\n", + kbd->key_waiting, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0x0f; + kbd->want_irq = 1; + } +} + +static void +kbd_epoch_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) +{ + // uint8_t num_lock = 0; + // uint8_t shift_states = 0; + + if (!adddata) + return; + + // keyboard_get_states(NULL, &num_lock, NULL, NULL); + // shift_states = keyboard_get_shift() & STATE_LSHIFT; + + // /* If NumLock is on, invert the left shift state so we can always check for + // the the same way flag being set (and with NumLock on that then means it + // is actually *NOT* set). */ + // if (num_lock) + // shift_states ^= STATE_LSHIFT; + + adddata(val); +} + +static void +kbd_epoch_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + epoch_log("XTkbd: %02X added to key queue at %i\n", + val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0x0f; +} + +static void +kbd_adddata_ex(uint16_t val) +{ + if (val < 0x100) + kbd_epoch_adddata_process(val, kbd_epoch_adddata); +} + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + uint8_t new_clock; + epoch_log("%04X:%04X epochkbd: Port %04X out: %02X\n", cs >> 4, cpu_state.pc, port, val); + + switch (port) { + case 0x61: /* Keyboard Control Register (aka Port B) */ + if (val & 0x08) { + new_clock = !(val & 0x04); + if (kbd->clock && new_clock) { + key_queue_start = key_queue_end = 0; + kbd->want_irq = 0; + kbd->blocked = 0; + kbd->reset_step = 0; + /* Specific 5556 keyboards send three bytes of identification code, + but this simply sends AAh that can pass the IPL and DOS K3.4 init. */ + kbd_epoch_adddata(0xaa); + } else if (!(kbd->pb & 0x08)) { + kbd->pa = 0; + kbd->blocked = 0; + } + } + + kbd->pb = val; + if (kbd->pb & 0x08) + kbd->clock = !!(kbd->pb & 0x04); + ppi.pb = val; + + timer_process(); + + speaker_update(); + + speaker_gated = val & 2; + speaker_enable = val & 2; + + if (speaker_enable) + was_speaker_enable = 1; + pit_devs[0].set_gate(pit_devs[0].data, TIMER_CTR_2, val & 2); + + break; + + default: + break; + } +} + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: /* Keyboard Data Register (aka Port A) */ + ret = kbd->pa; + break; + + case 0x61: /* Keyboard Control Register (aka Port B) */ + /* Bit 3 and 2: Keyboard Data and Clk line ? */ + if (kbd->reset_step < 18) { + ret &= 0xf3; + if (kbd->reset_step & 1) + ret |= 0x04; + switch (kbd->reset_step) { /* AAh (1010 1010) in serial data */ + case 3: + case 7: + case 11: + case 15: + ret |= 0x00; + break; + default: + ret |= 0x08; + break; + } + kbd->reset_step += 1; + } + /* Bit 1: Timer 2 (Speaker) out state */ + if (pit_devs[0].get_outlevel(pit_devs[0].data, TIMER_CTR_2) && speaker_enable) + ret &= 0xfd;/* 1111 1101 */ + else + ret |= 0x02; + break; + + default: + break; + } + // epoch_log("%04X:%04X epochkbd: Port %04X in : %02X BX:%04x\n", cs >> 4, cpu_state.pc, port, ret, BX); + + return ret; +} + +static void +kbd_reset(void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + + kbd->want_irq = 0; + kbd->blocked = 0; + kbd->pa = 0x00; + kbd->pb = 0x00; + + keyboard_scan = 1; + + key_queue_start = 0; + key_queue_end = 0; +} + +static void * +kbd_init(const device_t *info) +{ + epochkbd_t *kbd; + + kbd = (epochkbd_t *) calloc(1, sizeof(epochkbd_t)); + + io_sethandler(0x0060, 4, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + keyboard_send = kbd_adddata_ex; + kbd_reset(kbd); + + key_queue_start = key_queue_end = 0; + + timer_add(&kbd->send_delay_timer, kbd_epoch_poll, kbd, 1); + + keyboard_set_table(scancode_set8a); + keyboard_mode = 0x8a; + + return kbd; +} + +static void +kbd_close(void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + + /* Stop the timer. */ + timer_disable(&kbd->send_delay_timer); + + /* Disable scanning. */ + keyboard_scan = 0; + + keyboard_send = NULL; + + io_removehandler(0x0060, 2, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + + free(kbd); +} + +static const device_t kbc_epoch_device = { + .name = "IBM 5550 Keyboard Controller", + .internal_name = "kbc_epoch", + .flags = 0, + .local = 0, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +static void +epoch_nvr_time_set(uint8_t *regs, struct tm *tm) +{ + regs[epoch_nvr_SECOND1] = tm->tm_sec % 10; + regs[epoch_nvr_SECOND10] = (tm->tm_sec / 10); + regs[epoch_nvr_MINUTE1] = (tm->tm_min % 10); + regs[epoch_nvr_MINUTE10] = (tm->tm_min / 10); + regs[epoch_nvr_HOUR1] = (tm->tm_hour % 10); + regs[epoch_nvr_HOUR10] = (tm->tm_hour / 10); + regs[epoch_nvr_WEEKDAY] = tm->tm_wday; + regs[epoch_nvr_DAY1] = (tm->tm_mday % 10); + regs[epoch_nvr_DAY10] = (tm->tm_mday / 10); + regs[epoch_nvr_MONTH1] = ((tm->tm_mon + 1) % 10); + regs[epoch_nvr_MONTH10] = ((tm->tm_mon + 1) / 10); + regs[epoch_nvr_YEAR1] = (tm->tm_year % 10); + regs[epoch_nvr_YEAR10] = ((tm->tm_year % 100) / 10); +} + +/* Get the chip time. */ +#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) +static void +epoch_nvr_time_get(uint8_t *regs, struct tm *tm) +{ + tm->tm_sec = nibbles(epoch_nvr_SECOND); + tm->tm_min = nibbles(epoch_nvr_MINUTE); + tm->tm_hour = nibbles(epoch_nvr_HOUR); + tm->tm_wday = regs[epoch_nvr_WEEKDAY]; + tm->tm_mday = nibbles(epoch_nvr_DAY); + tm->tm_mon = (nibbles(epoch_nvr_MONTH) - 1); + tm->tm_year = (nibbles(epoch_nvr_YEAR)); +} + +/* This is called every second through the NVR/RTC hook. */ +static void +epoch_nvr_tick(nvr_t *nvr) +{ + struct tm tm; + if (!(nvr->regs[epoch_nvr_CONTROL] & 0x40)) { + /* Get the current time from the internal clock. */ + nvr_time_get(&tm); + /* Update registers with current time. */ + epoch_nvr_time_set(nvr->regs, &tm); + } +} + +static void +epoch_nvr_start(nvr_t *nvr) +{ + struct tm tm; + /* Initialize the internal and chip times. */ + if (time_sync & TIME_SYNC_ENABLED) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + epoch_nvr_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + epoch_nvr_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } +} + +/* Write to one of the chip registers. */ +static void +epoch_nvr_write(uint16_t port, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + int addr = 0; + + switch (port) { + case 0x360: + epoch->nvrctrl = val; + addr = val & 0xf; + if (val & 0x20) { /* Write */ + if (addr >= 0x8 && (epoch->nvr.regs[addr] != val)) + nvr_dosave = 1; + epoch->nvr.regs[addr] = epoch->nvrdata; + } + break; + case 0x361: + if(epoch->nvrctrl & 0x40) /* Is the access enabled? */ + epoch->nvrdata = val; + break; + } + // epoch_log("%04X:%04X I/O Out %02X: %02X\n", cs >> 4, cpu_state.pc, port, val); +} + +/* Read from one of the chip registers. */ +static uint8_t +epoch_nvr_read(uint16_t port, void *priv) +{ + const epoch_t *epoch = (epoch_t *) priv; + + switch (port) { + case 0x360: + return epoch->nvrctrl; + break; + case 0x361: + if(epoch->nvrctrl & 0x40) /* Is the access enabled? */ + return (epoch->nvr.regs[(epoch->nvrctrl & 0xf)]); + break; + } + return EPOCH_INVALIDACCESS8; +} + +/* Reset the RTC registers to a default state. */ +static void +epoch_nvr_reset(nvr_t *nvr) +{ + /* Clear the NVRAM. */ + memset(nvr->regs, 0xff, nvr->size); + /* Reset the RTC registers. */ + memset(nvr->regs, 0x00, 0xc); + nvr->regs[epoch_nvr_CONTROL] = 0; +} + +static void +epoch_nvr_init(epoch_t *epoch, int size) +{ + nvr_t* nvr = &epoch->nvr; + /* This is machine specific. */ + nvr->size = size; + nvr->irq = -1; + /* Set up any local handlers here. */ + nvr->reset = epoch_nvr_reset; + nvr->start = epoch_nvr_start; + nvr->tick = epoch_nvr_tick; + /* Initialize the actual NVR. */ + nvr_init(nvr); + io_sethandler(0x0360, 2, + epoch_nvr_read, NULL, NULL, epoch_nvr_write, NULL, NULL, epoch); +} + +static uint8_t ibm5550_attr_mono[16] = +{ + 0,6,6,62,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +// static uint8_t ps55_attr_color[16] = /* for video mode 0eh color character */ +// { +// 0x00,0x38,0x24,0x3c,0x12,0x3a,0x36,0x3e,0x09,0x39,0x2d,0x3d,0x1b,0x3b,0x3f,0x3f +// }; + +/* 12-bit DAC color palette for IBMJ Display Adapter with color monitor */ +static uint8_t ps55_palette_color[64][3] = { + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x2A }, { 0x00, 0x2A, 0x00 }, { 0x00, 0x2A, 0x2A }, + { 0x2A, 0x00, 0x00 }, { 0x2A, 0x00, 0x2A }, { 0x2A, 0x2A, 0x00 }, { 0x2A, 0x2A, 0x2A }, + { 0x00, 0x00, 0x15 }, { 0x00, 0x00, 0x3F }, { 0x00, 0x2A, 0x15 }, { 0x00, 0x2A, 0x3F }, + { 0x2A, 0x00, 0x15 }, { 0x2A, 0x00, 0x3F }, { 0x2A, 0x2A, 0x15 }, { 0x2A, 0x2A, 0x3F }, + { 0x00, 0x15, 0x00 }, { 0x00, 0x15, 0x2A }, { 0x00, 0x3F, 0x00 }, { 0x00, 0x3F, 0x2A }, + { 0x2A, 0x15, 0x00 }, { 0x2A, 0x15, 0x2A }, { 0x2A, 0x3F, 0x00 }, { 0x2A, 0x3F, 0x2A }, + { 0x00, 0x15, 0x15 }, { 0x00, 0x15, 0x3F }, { 0x00, 0x3F, 0x15 }, { 0x00, 0x3F, 0x3F }, + { 0x2A, 0x15, 0x15 }, { 0x2A, 0x15, 0x3F }, { 0x2A, 0x3F, 0x15 }, { 0x2A, 0x3F, 0x3F }, + { 0x15, 0x00, 0x00 }, { 0x15, 0x00, 0x2A }, { 0x15, 0x2A, 0x00 }, { 0x15, 0x2A, 0x2A }, + { 0x3F, 0x00, 0x00 }, { 0x3F, 0x00, 0x2A }, { 0x3F, 0x2A, 0x00 }, { 0x3F, 0x2A, 0x2A }, + { 0x15, 0x00, 0x15 }, { 0x15, 0x00, 0x3F }, { 0x15, 0x2A, 0x15 }, { 0x15, 0x2A, 0x3F }, + { 0x3F, 0x00, 0x15 }, { 0x3F, 0x00, 0x3F }, { 0x3F, 0x2A, 0x15 }, { 0x3F, 0x2A, 0x3F }, + { 0x15, 0x15, 0x00 }, { 0x15, 0x15, 0x2A }, { 0x15, 0x3F, 0x00 }, { 0x15, 0x3F, 0x2A }, + { 0x3F, 0x15, 0x00 }, { 0x3F, 0x15, 0x2A }, { 0x3F, 0x3F, 0x00 }, { 0x3F, 0x3F, 0x2A }, + { 0x15, 0x15, 0x15 }, { 0x15, 0x15, 0x3F }, { 0x15, 0x3F, 0x15 }, { 0x15, 0x3F, 0x3F }, + { 0x3F, 0x15, 0x15 }, { 0x3F, 0x15, 0x3F }, { 0x3F, 0x3F, 0x15 }, { 0x3F, 0x3F, 0x3F } +}; + +static video_timings_t timing_epoch_vid = +{ .type = VIDEO_ISA, .write_b = 8, .write_w = 8, .write_l = 16, .read_b = 8, .read_w = 8, .read_l = 16 }; + +static void +epoch_reset(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + + epoch->parityerror = 0; + epoch->parityenabled = 1; + epoch->lowmemorydisabled = 1; + epoch->crtioenabled = 0; + // epoch->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ + epoch->crtc[LC_HORIZONTAL_TOTAL] = 103; /* Horizontal Total */ + epoch->crtc[LC_VERTICAL_TOTAL] = 26; /* Vertical Total (These two must be set before the timer starts.) */ + epoch->crtmode = 0x08; + epoch->vram_display_mask = EPOCH_MASK_CRAM; + // epoch->plane_mask = 1; + epoch->oddeven = 0; + // epoch->memaddr_latch = 0; + // epoch->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + // epoch->attr_palette_enable = 0; /* disable attribute generator */ + + // epoch->attrc[LV_PAS_STATUS_CNTRL] = 0; + // epoch->attrc[LV_PANNING] = 0; + + /* Set internal color palette registers */ + for (uint16_t i = 0; i < 16; i++) { + epoch->egapal[i] = ibm5550_attr_mono[i]; + } + /* Set color palette for video output */ + for (uint16_t i = 0; i < 64; i++) { + epoch->vgapal[i].r = ps55_palette_color[i & 0x3F][0]; + epoch->vgapal[i].g = ps55_palette_color[i & 0x3F][1]; + epoch->vgapal[i].b = ps55_palette_color[i & 0x3F][2]; + epoch->pallook[i] = makecol32((epoch->vgapal[i].r & 0x3f) * 4, (epoch->vgapal[i].g & 0x3f) * 4, (epoch->vgapal[i].b & 0x3f) * 4); + } + + // mem_mapping_disable(&epoch->fontcard.map); + + epoch_log("epoch_reset done.\n"); +} + +/* +//[Font ROM Map (DA1)] +//Bank 0 +// 0000-581Fh Pointers (Low) for each character font? +// 5820-7FFFh Pointers (High) for each character font? +// 8000- * h Font Data +*/ +// static void +// epoch_video_load_font(char *fname, epoch_t *epoch) +// { +// uint8_t buf; +// uint64_t fsize; +// if (!fname) +// return; +// if (*fname == '\0') +// return; +// FILE *mfile = rom_fopen(fname, "rb"); +// if (!mfile) { +// // da2_log("MSG: Can't open binary ROM font file: %s\n", fname); +// return; +// } +// fseek(mfile, 0, SEEK_END); +// fsize = ftell(mfile); /* get filesize */ +// fseek(mfile, 0, SEEK_SET); +// if (fsize > EPOCH_FONTROM_SIZE) { +// fsize = EPOCH_FONTROM_SIZE; /* truncate read data */ +// // da2_log("MSG: The binary ROM font is truncated: %s\n", fname); +// // fclose(mfile); +// // return 1; +// } +// uint32_t j = 0; +// while (ftell(mfile) < fsize) { +// (void) !fread(&buf, sizeof(uint8_t), 1, mfile); +// epoch->fontcard.rom[j] = buf; +// j++; +// } +// fclose(mfile); +// return; +// } + +// static void +// epoch_font_writeb(uint32_t addr, uint8_t val, void *priv) +// { +// epoch_t *epoch = (epoch_t *) priv; +// epoch->fontcard.bank = val; +// // if ((addr & ~0xfff) != 0xE0000) return; +// epoch_log("cw %04X %02X %04X %04X %04X %04X\n", addr, val, DS, SI, ES, DI); +// } +// static uint8_t +// epoch_font_readb(uint32_t addr, void *priv) +// { +// epoch_t *epoch = (epoch_t *) priv; +// uint32_t readaddr = epoch->fontcard.bank; +// addr &= EPOCH_FONTROM_MASK; +// readaddr *= 0xc000;/* xxx x000 0000 0000 0000 (8000h) */ +// readaddr += addr; +// if (readaddr >= EPOCH_FONTROM_SIZE) +// return EPOCH_INVALIDACCESS8; +// // epoch_log("cr %X %x %04X %04X %04X %04X\n", readaddr, epoch->fontcard.rom[readaddr], DS, SI, ES, DI); +// // if(epoch->vram[addr] == 0xcb) +// // epoch_log("CB %04X:%04X %04X:%04X>%04X:%04X\n", cs >> 4, cpu_state.pc, DS, SI,ES,DI); +// return epoch->fontcard.rom[readaddr]; +// } +static void * +epoch_init(UNUSED(const device_t *info)) +{ + epoch_t *epoch = calloc(1, sizeof(epoch_t)); + video_inform(VIDEO_FLAG_TYPE_NONE, &timing_epoch_vid); + video_update_timing(); + + epoch->dispontime = 1000ull << 32; + epoch->dispofftime = 1000ull << 32; + // epoch->changedvram = calloc(1, (EPOCH_MASK_VRAMPLANE + 1) >> 9); /* XX000h */ + changeframecount = 3; + + epoch->vram = calloc(1, 256* 1024); + epoch->cram = calloc(1, 4 * 1024); + // epoch->fontcard.rom = calloc(1, EPOCH_FONTROM_SIZE); + //epoch_video_load_font("roms/machines/ibm5550/GEN1FONT.BIN", epoch); + + epoch->epochconst = (uint64_t) ((cpuclock / EPOCH_PIXELCLOCK) * (double) (1ull << 32)); + + epoch_reset(epoch); + + mem_mapping_add(&epoch->cmap, 0xE0000, 0x1000, epoch_cram_readb, epoch_cram_readw, NULL, + epoch_cram_writeb, epoch_cram_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, epoch); + mem_mapping_add(&epoch->vmap, 0xA0000, 0x40000, epoch_vram_readb, epoch_vram_readw, NULL, + epoch_vram_writeb, epoch_vram_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, epoch); + // mem_mapping_add(&epoch->fontcard.map, 0xF0000, 0xC000, epoch_font_readb, NULL, NULL, + // epoch_font_writeb, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, epoch); + + mem_mapping_disable(&epoch->cmap); + mem_mapping_disable(&epoch->vmap); + // mem_mapping_disable(&epoch->fontcard.map); + mem_mapping_add(&epoch->paritymap, 0, 0xA0000, epoch_parity_readb, epoch_parity_readw, NULL, + epoch_parity_writeb, epoch_parity_writew, NULL, NULL, MEM_MAPPING_CACHE, epoch); + + io_sethandler(0x03d0, 0x0020, epoch_inb, epoch_inw, NULL, epoch_outb, epoch_outw, NULL, epoch); + + io_sethandler(0x44, 0x0001, + epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + io_sethandler(0xA0, 0x0005, + epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + io_sethandler(0x310, 0x0008, + epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + // io_sethandler(0x160, 0x0010, + // epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + + timer_add(&epoch->timer, epoch_poll, epoch, 1); + + epoch_nvr_init(epoch, 17); + + return epoch; +} + +static void +epoch_close(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + + /* dump mem for debug */ +#ifdef ENABLE_EPOCH_LOG + FILE *fp; + fp = fopen("epoch_cram.dmp", "wb"); + if (fp != NULL) { + fwrite(epoch->cram, EPOCH_SIZE_CRAM, 1, fp); + fclose(fp); + } + fp = fopen("epoch_vram.dmp", "wb"); + if (fp != NULL) { + fwrite(epoch->vram, EPOCH_SIZE_VRAM, 1, fp); + fclose(fp); + } + // fp = fopen("epoch_attrpal.dmp", "wb"); + // if (fp != NULL) { + // fwrite(epoch->attrc, 32, 1, fp); + // fclose(fp); + // } + fp = fopen("epoch_daregs.txt", "w"); + if (fp != NULL) { + // for (uint8_t i = 0; i < 0x10; i++) + // fprintf(fp, "3e1(ioctl) %02X: %4X %d\n", i, epoch->ioctl[i], epoch->ioctl[i]); + // for (uint8_t i = 0; i < 0x20; i++) + // fprintf(fp, "3e3(fctl) %02X: %4X %d\n", i, epoch->fctl[i], epoch->fctl[i]); + for (uint8_t i = 0; i < 0x20; i++) + fprintf(fp, "3e5(crtc) %02X: %4X %d\n", i, epoch->crtc[i], epoch->crtc[i]); + // for (uint8_t i = 0; i < 0x40; i++) + // fprintf(fp, "3e8(attr) %02X: %4X %d\n", i, epoch->attrc[i], epoch->attrc[i]); + // for (uint8_t i = 0; i < 0x10; i++) + // fprintf(fp, "3eb(gcr) %02X: %4X\n", i, epoch->gdcreg[i]); + // for (uint8_t i = 0; i < 0x20; i++) { + // fprintf(fp, "vp %02X: %4X %4X %4X %4X\n", i, + // epoch->crtc_vpreg[0 + i], epoch->crtc_vpreg[0x20 + i], epoch->crtc_vpreg[0x40 + i], epoch->crtc_vpreg[0x60 + i]); + // } + fclose(fp); + } + fp = fopen("ram_low.dmp", "wb"); + if (fp != NULL) { + fwrite(ram, 0x40000, 1, fp); + fclose(fp); + } + epoch_log("closed %04X:%04X AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X\n", + cs >> 4, cpu_state.pc, AX, BX, CX, DX, ES, DI, DS, SI); + epoch_log("PIC IRR=%02X ISR=%02X IMR=%02X ICW1=%02X ICW2=%02X ICW3=%02X ICW4=%02X OCW2=%02X OCW3=%02X\n", + pic.irr, pic.isr, pic.imr, pic.icw1, pic.icw2, pic.icw3, pic.icw4, pic.ocw2, pic.ocw3); +#endif + free(epoch->cram); + free(epoch->vram); + // free(epoch->fontcard.rom); + // free(epoch->changedvram); + free(epoch); +} + +static void +epoch_speed_changed(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + epoch->epochconst = (uint64_t) ((cpuclock / EPOCH_PIXELCLOCK) * (double) (1ull << 32)); + epoch_recalctimings(epoch); +} + +static void +epoch_force_redraw(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + epoch->fullchange = changeframecount; +} + +static const device_t epoch_device = { + .name = "IBM 5550 Video Controller (Epoch)", + .internal_name = "ibm5550vid", + .flags = DEVICE_ISA, + .local = 0, + .init = epoch_init, + .close = epoch_close, + .reset = epoch_reset, + .available = NULL, + .speed_changed = epoch_speed_changed, + .force_redraw = epoch_force_redraw, + .config = NULL +}; + +static void +pit_irq6_timer(int new_out, int old_out, UNUSED(void *priv)) +{ + // epoch_log("%04X:%04X IRQ6 Timer triggered.\n", cs >> 4, cpu_state.pc); + if (new_out && !old_out) + picint(EPOCH_IRQ6_BIT); + + if (!new_out) + picintc(EPOCH_IRQ6_BIT); +} + +static pit_t * +pit_ibm5550_init(void) +{ + void *pit; + + pit_intf_t *pit_intf = &pit_devs[0]; + + pit = device_add(&i8253_device); + *pit_intf = pit_classic_intf; + + pit_intf->data = pit; + + for (uint8_t i = 0; i < 3; i++) { + pit_intf->set_gate(pit_intf->data, i, 1); + pit_intf->set_using_timer(pit_intf->data, i, 1); + } + + pit_intf->set_out_func(pit_intf->data, TIMER_CTR_1, pit_irq6_timer); + pit_intf->set_out_func(pit_intf->data, TIMER_CTR_0, pit_refresh_timer_xt); + pit_intf->set_out_func(pit_intf->data, TIMER_CTR_2, pit_speaker_timer); + pit_intf->set_load_func(pit_intf->data, TIMER_CTR_2, speaker_set_count); + + pit_intf->set_gate(pit_intf->data, TIMER_CTR_2, 0); + + return pit; +} + +int +machine_xt_ibm5550_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ibm5550/ipl5550.rom", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + device_add(&fdc_xt_5550_device); + + device_add(&kbc_epoch_device); + + pic_init(); + dma_init(); + pit_ibm5550_init(); + nmi_mask = 0; + + device_add(&epoch_device); + + device_add(&lpt_port_device); + serial_t *uart = device_add(&ns8250_device); + serial_setup(uart, 0x3f8, 1);/* Use IRQ 1 */ + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 4bf04b2d6..c67a22c04 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3033,6 +3033,49 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { + .name = "[8086] IBM Multistation 5550", + .internal_name = "ibm5550", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_ibm5550_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED | MACHINE_KEYBOARD, + .ram = { + .min = 256, + .max = 640, + .step = 128 + }, + .nvrmask = 15, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = NULL, + .kbc_params = 0x00000000, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* 286 AT machines */ /* Has IBM AT KBC firmware. */ diff --git a/src/pit.c b/src/pit.c index 7c58a4b67..5a8078c97 100644 --- a/src/pit.c +++ b/src/pit.c @@ -420,6 +420,15 @@ pit_ctr_get_count(void *data, int counter_id) return (uint16_t) ctr->l; } +int +pit_ctr_get_outlevel(void *data, int counter_id) +{ + const pit_t *pit = (pit_t *) data; + const ctr_t *ctr = &pit->counters[counter_id]; + + return (int) ctr->out; +} + void pit_ctr_set_load_func(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count)) { @@ -1208,6 +1217,11 @@ pit_set_clock(uint32_t clock) CGACONST = (uint64_t) ((cpuclock / (157500000.0 / 88.0)) * (double) (1ULL << 32)); #endif } + + if (machines[machine].init == machine_xt_ibm5550_init) { + PITCONSTD = (cpuclock / 2000000.0); /* CLK input 2.0 MHz */ + PITCONST = (uint64_t) (PITCONSTD * (double) (1ULL << 32)); + } ISACONST = (1ULL << 32ULL); } @@ -1263,6 +1277,7 @@ const pit_intf_t pit_classic_intf = { .read = &pit_read, .write = &pit_write, .get_count = &pit_ctr_get_count, + .get_outlevel = &pit_ctr_get_outlevel, .set_gate = &pit_ctr_set_gate, .set_using_timer = &pit_ctr_set_using_timer, .set_out_func = &pit_ctr_set_out_func, diff --git a/src/printer/prt_cpmap.c b/src/printer/prt_cpmap.c index 370e258ce..37243f0db 100644 --- a/src/printer/prt_cpmap.c +++ b/src/printer/prt_cpmap.c @@ -1,75 +1,24 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * Various ASCII to Unicode maps, for the various codepages. + * This file is part of the 86Box distribution. * - * Authors: Michael Drüing, - * Fred N. van Kempen, + * Code page to Unicode mapping + * for a generic ESC/P 2 dot-matrix printer. * - * Based on code by Frederic Weymann (originally for DosBox.) + * Authors: Lili Kurek, * - * Copyright 2018 Michael Drüing. - * Copyright 2018 Fred N. van Kempen. + * Based on code by Frederic Weymann (originally for DOSBox.) * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Copyright 2025-2026 Lili Kurek. */ #include #include -#include -#include -#include -#include <86box/86box.h> -#include <86box/plat.h> -#include <86box/printer.h> -static const uint16_t cp437Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp437Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -88,23 +37,7 @@ static const uint16_t cp437Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp737Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp737Map[128] = { 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, @@ -123,23 +56,7 @@ static const uint16_t cp737Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp775Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp775Map[128] = { 0x0106, 0x00fc, 0x00e9, 0x0101, 0x00e4, 0x0123, 0x00e5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012b, 0x0179, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x014d, 0x00f6, 0x0122, 0x00a2, 0x015a, @@ -158,23 +75,7 @@ static const uint16_t cp775Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp850Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp850Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -193,23 +94,7 @@ static const uint16_t cp850Map[256] = { 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp852Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp852Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x016f, 0x0107, 0x00e7, 0x0142, 0x00eb, 0x0150, 0x0151, 0x00ee, 0x0179, 0x00c4, 0x0106, 0x00c9, 0x0139, 0x013a, 0x00f4, 0x00f6, 0x013d, 0x013e, 0x015a, @@ -228,23 +113,7 @@ static const uint16_t cp852Map[256] = { 0x00b0, 0x00a8, 0x02d9, 0x0171, 0x0158, 0x0159, 0x25a0, 0x00a0 }; -static const uint16_t cp855Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp855Map[128] = { 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045a, 0x040a, 0x045b, 0x040b, 0x045c, 0x040c, @@ -263,23 +132,7 @@ static const uint16_t cp855Map[256] = { 0x042d, 0x0449, 0x0429, 0x0447, 0x0427, 0x00a7, 0x25a0, 0x00a0 }; -static const uint16_t cp857Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp857Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0131, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -298,23 +151,7 @@ static const uint16_t cp857Map[256] = { 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp860Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp860Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e3, 0x00e0, 0x00c1, 0x00e7, 0x00ea, 0x00ca, 0x00e8, 0x00cd, 0x00d4, 0x00ec, 0x00c3, 0x00c2, 0x00c9, 0x00c0, 0x00c8, 0x00f4, 0x00f5, 0x00f2, 0x00da, 0x00f9, @@ -333,23 +170,7 @@ static const uint16_t cp860Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp861Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp861Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00d0, 0x00f0, 0x00de, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00fe, 0x00fb, 0x00dd, @@ -368,23 +189,7 @@ static const uint16_t cp861Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp862Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp862Map[128] = { 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, @@ -403,23 +208,7 @@ static const uint16_t cp862Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp863Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp863Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00c2, 0x00e0, 0x00b6, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x2017, 0x00c0, 0x00a7, 0x00c9, 0x00c8, 0x00ca, 0x00f4, 0x00cb, 0x00cf, 0x00fb, 0x00f9, @@ -438,23 +227,7 @@ static const uint16_t cp863Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp864Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x066a, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp864Map[128] = { 0x00b0, 0x00b7, 0x2219, 0x221a, 0x2592, 0x2500, 0x2502, 0x253c, 0x2524, 0x252c, 0x251c, 0x2534, 0x2510, 0x250c, 0x2514, 0x2518, 0x03b2, 0x221e, 0x03c6, 0x00b1, 0x00bd, 0x00bc, 0x2248, 0x00ab, @@ -473,23 +246,7 @@ static const uint16_t cp864Map[256] = { 0xfed5, 0xfef5, 0xfef6, 0xfedd, 0xfed9, 0xfef1, 0x25a0, 0x00a0 }; -static const uint16_t cp865Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp865Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -508,23 +265,7 @@ static const uint16_t cp865Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp866Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp866Map[128] = { 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, @@ -570,7 +311,7 @@ static const struct { void select_codepage(uint16_t code, uint16_t *curmap) { - uint16_t i = 0; + uint8_t i = 0; const uint16_t *map_to_use; map_to_use = maps[0].map; @@ -583,6 +324,9 @@ select_codepage(uint16_t code, uint16_t *curmap) i++; } - for (uint16_t j = 0; j < 256; j++) - curmap[j] = map_to_use[j]; + for (i = 0; i < 128; ++i) + curmap[i] = i; + + for (; i != 0; ++i) + curmap[i] = map_to_use[i - 128]; } diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index e9f6ca71e..5a507ad30 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -1,63 +1,30 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * Implementation of the Generic ESC/P 2 Dot-Matrix printer. + * This file is part of the 86Box distribution. * - * Authors: Michael Drüing, - * Fred N. van Kempen, + * Implementation of a generic ESC/P 2 dot-matrix printer. * - * Based on code by Frederic Weymann (originally for DosBox.) + * Authors: Lili Kurek, * - * Copyright 2018-2019 Michael Drüing. - * Copyright 2019 Fred N. van Kempen. + * Based on code by Frederic Weymann (originally for DOSBox.) * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Copyright 2025-2026 Lili Kurek. */ + #include +#include #include #include -#include -#include -#include #include #include #include FT_FREETYPE_H #define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/device.h> #include "cpu.h" -#include <86box/machine.h> #include <86box/timer.h> #include <86box/mem.h> #include <86box/rom.h> @@ -79,6 +46,11 @@ enum { LANG_ESCP2 }; +enum { + QUALITY_DRAFT = 0, + QUALITY_LQ +}; + enum { PAPER_LETTER = 0, PAPER_A4, @@ -88,7 +60,7 @@ enum { /* Default page values (for now.) */ #define COLOR_BLACK 7 << 5 -#define PAGE_CPI 10.0 /* standard310 cpi */ +#define PAGE_CPI 10.0 /* standard 10 cpi */ #define PAGE_LPI 6.0 /* standard 6 lpi */ /* FreeType library handles - global so they can be shared. */ @@ -106,19 +78,19 @@ enum { }; /* Font styles. */ -#define STYLE_PROP 0x0001 -#define STYLE_CONDENSED 0x0002 -#define STYLE_BOLD 0x0004 -#define STYLE_DOUBLESTRIKE 0x0008 -#define STYLE_DOUBLEWIDTH 0x0010 -#define STYLE_ITALICS 0x0020 -#define STYLE_UNDERLINE 0x0040 -#define STYLE_SUPERSCRIPT 0x0080 -#define STYLE_SUBSCRIPT 0x0100 -#define STYLE_STRIKETHROUGH 0x0200 -#define STYLE_OVERSCORE 0x0400 -#define STYLE_DOUBLEWIDTHONELINE 0x0800 -#define STYLE_DOUBLEHEIGHT 0x1000 +#define STYLE_PROP 0x0002 +#define STYLE_CONDENSED 0x0004 +#define STYLE_BOLD 0x0008 +#define STYLE_DOUBLESTRIKE 0x0010 +#define STYLE_DOUBLEWIDTH 0x0020 +#define STYLE_ITALICS 0x0040 +#define STYLE_UNDERLINE 0x0080 +#define STYLE_SUPERSCRIPT 0x0100 +#define STYLE_SUBSCRIPT 0x0200 +#define STYLE_STRIKETHROUGH 0x0400 +#define STYLE_OVERSCORE 0x0800 +#define STYLE_DOUBLEWIDTHONELINE 0x1000 +#define STYLE_DOUBLEHEIGHT 0x2000 /* Underlining styles. */ #define SCORE_NONE 0x00 @@ -127,10 +99,6 @@ enum { #define SCORE_SINGLEBROKEN 0x05 #define SCORE_DOUBLEBROKEN 0x06 -/* Print quality. */ -#define QUALITY_DRAFT 0x01 -#define QUALITY_LQ 0x02 - /* Typefaces. */ enum { TYPEFACE_ROMAN = 0, @@ -179,6 +147,8 @@ typedef struct escp_t { char page_fn[260]; uint8_t color; + bool dc1_selected; + /* page data (TODO: make configurable) */ double page_width; /* all in inches */ double page_height; @@ -213,16 +183,16 @@ typedef struct escp_t { /* handshake data */ uint8_t data; - uint8_t ack; - uint8_t select; - uint8_t busy; - uint8_t int_pending; - uint8_t error; - uint8_t autofeed; + bool ack; + bool select; + bool busy; + bool int_pending; + bool error; + bool autofeed; /* ESC command data */ - int8_t esc_seen; /* set to 1 if an ESC char was seen */ - int8_t fss_seen; + bool esc_seen; /* set if an ESC char was seen */ + bool fss_seen; uint16_t esc_pending; /* in which ESC command are we */ uint8_t esc_parms_req; uint8_t esc_parms_curr; @@ -267,7 +237,7 @@ typedef struct escp_t { PALETTE palcol; - uint8_t auto_lf; + bool auto_lf; } escp_t; /* Codepage table, needed for ESC t ( */ @@ -328,18 +298,13 @@ static const uint16_t intCharSets[15][12] = { }; #ifdef ENABLE_ESCP_LOG -int escp_do_log = ENABLE_ESCP_LOG; - static void escp_log(const char *fmt, ...) { va_list ap; - - if (escp_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } #else # define escp_log(fmt, ...) @@ -382,7 +347,7 @@ pulse_timer(void *priv) escp_t *dev = (escp_t *) priv; if (dev->ack) { - dev->ack = 0; + dev->ack = false; lpt_irq(dev->lpt, 1); } @@ -426,7 +391,7 @@ update_font(escp_t *dev) double vpoints = 10.5; /* We need the FreeType library. */ - if (ft_lib == NULL) + if (!ft_lib) return; /* Release current font if we have one. */ @@ -560,9 +525,10 @@ reset_printer(escp_t *dev) dev->bottom_margin = dev->page_height - 1.0 / 36.0; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; + dev->dc1_selected = true; dev->curr_x = dev->curr_y = 0.0; - dev->esc_seen = 0; - dev->fss_seen = 0; + dev->esc_seen = false; + dev->fss_seen = false; dev->esc_pending = 0; dev->esc_parms_req = dev->esc_parms_curr = 0; dev->lpi = PAGE_LPI; @@ -570,7 +536,7 @@ reset_printer(escp_t *dev) dev->cpi = PAGE_CPI; dev->curr_char_table = 1; dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; + dev->print_quality = device_get_config_int("quality"); dev->extra_intra_space = 0.0; dev->print_upper_control = 1; dev->bg_remaining_bytes = 0; @@ -600,7 +566,7 @@ reset_printer(escp_t *dev) dev->num_horizontal_tabs = 32; dev->num_vertical_tabs = -1; - if (dev->page != NULL) + if (dev->page) dev->page->dirty = 0; escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", @@ -611,7 +577,7 @@ reset_printer(escp_t *dev) static void reset_printer_hard(escp_t *dev) { - dev->ack = 0; + dev->ack = false; timer_disable(&dev->pulse_timer); timer_stop(&dev->timeout_timer); reset_printer(dev); @@ -803,7 +769,7 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_pending = ch; if (dev->fss_seen) dev->esc_pending |= 0x800; - dev->esc_seen = dev->fss_seen = 0; + dev->esc_seen = dev->fss_seen = false; dev->esc_parms_curr = 0; escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); @@ -1169,24 +1135,11 @@ process_char(escp_t *dev, uint8_t ch) case '!': /* master select */ dev->cpi = (dev->esc_parms[0]) & 0x01 ? 12.0 : 10.0; - /* Reset first seven bits. */ - dev->font_style &= 0xFF80; - if (dev->esc_parms[0] & 0x02) - dev->font_style |= STYLE_PROP; - if (dev->esc_parms[0] & 0x04) - dev->font_style |= STYLE_CONDENSED; - if (dev->esc_parms[0] & 0x08) - dev->font_style |= STYLE_BOLD; - if (dev->esc_parms[0] & 0x10) - dev->font_style |= STYLE_DOUBLESTRIKE; - if (dev->esc_parms[0] & 0x20) - dev->font_style |= STYLE_DOUBLEWIDTH; - if (dev->esc_parms[0] & 0x40) - dev->font_style |= STYLE_ITALICS; - if (dev->esc_parms[0] & 0x80) { + /* Reset first seven style bits (starting from two as CPI had one). */ + dev->font_style &= 0xFF01; + dev->font_style |= dev->esc_parms[0]; + if (dev->esc_parms[0] & 0x80) dev->font_score = SCORE_SINGLE; - dev->font_style |= STYLE_UNDERLINE; - } dev->hmi = -1; dev->multipoint_mode = 0; @@ -1268,6 +1221,10 @@ process_char(escp_t *dev, uint8_t ch) dev->print_upper_control = 0; break; + case '8': // disable + case '9': // enable paper-out sensor + // We don't have real paper, ignore. + case '<': /* unidirectional mode (one line) */ /* We don't have a print head, so just * ignore this. */ @@ -1409,7 +1366,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 'T': /* cancel superscript/subscript printing */ - dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + dev->font_style &= ~(STYLE_SUPERSCRIPT | STYLE_SUBSCRIPT); update_font(dev); break; @@ -1737,7 +1694,7 @@ process_char(escp_t *dev, uint8_t ch) } if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { - dev->font_style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; update_font(dev); } return 1; @@ -1784,8 +1741,8 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x11: /* select printer (DC1) */ - /* Ignore. */ - return 0; + dev->dc1_selected = true; + return 1; case 0x12: /* cancel condensed printing (DC2) */ dev->hmi = -1; @@ -1794,7 +1751,7 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x13: /* deselect printer (DC3) */ - /* Ignore. */ + dev->dc1_selected = false; return 1; case 0x14: /* cancel double-width printing (one line) (DC4) */ @@ -1807,13 +1764,13 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x1b: /* ESC */ - dev->esc_seen = 1; + dev->esc_seen = true; return 1; case 0x1c: /* FS (IBM Proprinter II) TODO: Make an IBM printer. */ if (dev->lang == LANG_ESCP2) { - dev->fss_seen = 1; + dev->fss_seen = true; return 1; } @@ -1832,7 +1789,7 @@ blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) uint8_t *dst; /* check if freetype is available */ - if (ft_lib == NULL) + if (!ft_lib) return; for (unsigned int y = 0; y < bitmap->rows; y++) { @@ -1954,16 +1911,18 @@ handle_char(escp_t *dev, uint8_t ch) uint16_t line_y; double x_advance; - if (dev->page == NULL) + if (!(dev->page)) return; /* MSB mode */ - if (dev->msb != 255) { - if (dev->msb == 0) - ch &= 0x7f; - else if (dev->msb == 1) - ch |= 0x80; - } + if (dev->msb == 0) + ch &= 0x7f; + else if (dev->msb == 1) + ch |= 0x80; + // else it's neutral at 255 + + if (!(dev->dc1_selected) && ch != 0x11) + return; if (dev->bg_remaining_bytes > 0) { print_bit_graph(dev, ch); @@ -1981,7 +1940,7 @@ handle_char(escp_t *dev, uint8_t ch) } /* We cannot print if we have no font loaded. */ - if (dev->fontface == NULL) + if (!(dev->fontface)) return; if (ch == 0x01) @@ -2066,7 +2025,7 @@ write_data(uint8_t val, void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; dev->data = val; @@ -2077,7 +2036,7 @@ strobe(uint8_t old, uint8_t val, void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; /* Data is strobed to the parallel printer on the falling edge of the @@ -2094,7 +2053,7 @@ strobe(uint8_t old, uint8_t val, void *priv) #endif } /* ACK it, will be read on next READ STATUS. */ - dev->ack = 1; + dev->ack = true; timer_set_delay_u64(&dev->pulse_timer, ISACONST); timer_on_auto(&dev->timeout_timer, 5000000.0); @@ -2106,17 +2065,17 @@ write_ctrl(uint8_t val, void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; if (val & 0x08) { /* SELECT */ /* select printer */ - dev->select = 1; + dev->select = true; } if ((val & 0x04) && !(dev->ctrl & 0x04)) { /* reset printer */ - dev->select = 0; + dev->select = false; reset_printer_hard(dev); } @@ -2135,7 +2094,7 @@ write_ctrl(uint8_t val, void *priv) #endif } /* ACK it, will be read on next READ STATUS. */ - dev->ack = 1; + dev->ack = true; timer_set_delay_u64(&dev->pulse_timer, ISACONST); timer_on_auto(&dev->timeout_timer, 5000000.0); @@ -2174,11 +2133,11 @@ escp_init(const device_t *info) escp_t *dev = NULL; /* Initialize FreeType. */ - if (ft_lib == NULL) { + if (!ft_lib) { if (FT_Init_FreeType(&ft_lib)) { pclog("ESC/P: FT_Init_FreeType failed\n"); ft_lib = NULL; - return (NULL); + return(NULL); } } @@ -2197,7 +2156,7 @@ escp_init(const device_t *info) ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_ESCP_ERROR_TITLE), plat_get_string(STRING_ESCP_ERROR_DESC)); free(dev); - return (NULL); + return(NULL); } /* Create the full path for the page images. */ @@ -2264,7 +2223,7 @@ escp_init(const device_t *info) dev->color = COLOR_BLACK; dev->fontface = 0; - dev->autofeed = 0; + dev->autofeed = false; reset_printer(dev); @@ -2282,15 +2241,15 @@ escp_close(void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; - if (dev->page != NULL) { + if (dev->page) { /* Print last page if it contains data. */ if (dev->page->dirty) dump_page(dev); - if (dev->page->pixels != NULL) + if (dev->page->pixels) free(dev->page->pixels); free(dev->page); } @@ -2337,6 +2296,21 @@ static const device_config_t lpt_prt_escp_config[] = { }, .bios = { { 0 } } }, + { + .name = "quality", + .description = "Quality", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Draft", .value = QUALITY_DRAFT }, + { .description = "(Near) Letter", .value = QUALITY_LQ }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "auto_lf", .description = "Auto LF", diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 968858dd2..c9250f44c 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -592,10 +592,10 @@ MediaMenu::cdromMount(int i, int dir, const QString &arg) if (dir > 1) filename = QString::asprintf(R"(ioctl://%s)", arg.toUtf8().data()); else if (dir == 1) - filename = QFileDialog::getExistingDirectory(parentWidget); + filename = QFileDialog::getExistingDirectory(parentWidget, QString(), getMediaOpenDirectory()); else { filename = QFileDialog::getOpenFileName(parentWidget, QString(), - QString(), + getMediaOpenDirectory(), tr("CD-ROM images") % util::DlgFilter({ "iso", "cue", "mds", "mdx" }) % tr("All files") % util::DlgFilter({ "*" }, true)); } @@ -1199,10 +1199,13 @@ MediaMenu::nicUpdateMenu(int i) QString MediaMenu::getMediaOpenDirectory() { - QString openDirectory; + static bool firstCall = true; + QString openDirectory; - if (open_dir_usr_path > 0) + if (open_dir_usr_path > 0 && firstCall) { openDirectory = QString::fromUtf8(usr_path); + firstCall = false; + } return openDirectory; }