diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index e0aaf1410..0fec8df13 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -3,7 +3,7 @@ In order for everyone to enjoy their time contributing to 86Box or otherwise bei ## 1. No illegal activity or GitHub ToS violations - 1.1. Do not distribute malware for non-research purposes. Post samples in a clearly named encrypted archive. -- 1.2. Posting old software is allowed if at least 10 years old and out of support. +- 1.2. Disclosure of copyrighted materials is permitted only if they are demo/trial versions, shareware, freeware, or open-source software, or if they are disclosed by the copyright holder or on the copyright holder’s behalf. If such materials need to be disclosed for testing or bug-fixing purposes, any available private channels should be used. Developers undertake to remove any materials obtained for such purposes as soon as they are no longer needed. - 1.3. Do not post NSFW content (defined at the staff's discretion). - 1.4. Do not do anything forbidden by the law or the Discord or GitHub Terms of Service. diff --git a/src/86box.c b/src/86box.c index 24e8be26a..cf992df4c 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1494,6 +1494,7 @@ pc_init_modules(void) fdd_audio_init(); } + hdd_audio_load_profiles(); hdd_audio_init(); sound_init(); diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index e5f6ba259..8c781caf7 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -692,14 +692,14 @@ read_toc_raw(const cdrom_t *dev, unsigned char *b, const unsigned char start_tra int num = 0; int len = 4; - /* Bytes 2 and 3 = Number of first and last sessions */ - read_toc_identify_sessions((raw_track_info_t *) rti, num, b); - cdrom_log(dev->log, "read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR ", %02X)\n", (uintptr_t) dev, (uintptr_t) b, start_track); dev->ops->get_raw_track_info(dev->local, &num, rti); + /* Bytes 2 and 3 = Number of first and last sessions */ + read_toc_identify_sessions((raw_track_info_t *) rti, num, b); + if (num != 0) for (int i = 0; i < num; i++) if (t[i].session >= start_track) { memcpy(&(b[len]), &(t[i]), 11); @@ -1654,6 +1654,9 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int dev->cd_end = len2; dev->cd_status = CD_STATUS_PLAYING; dev->cd_buflen = 0; + + if (dev->cached_sector != dev->seek_pos) + dev->cached_sector = -1; } else { cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); cdrom_stop(dev); diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index fdde47251..20977f48b 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -2965,7 +2965,7 @@ image_close(void *local) free(img); if (temp_file[0] != 0x00) { - remove(temp_file); + remove(nvr_path(temp_file)); temp_file[0] = 0x00; } } diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 480766103..337aefb00 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -18,11 +18,17 @@ * Copyright 2017-2019 Miran Grca. * Copyright 2017-2019 GreatPsycho. */ +#ifdef ENABLE_HEADLAND_LOG +#include +#endif #include #include #include #include #include +#ifdef ENABLE_HEADLAND_LOG +#define HAVE_STDARG_H +#endif #include <86box/86box.h> #include "cpu.h" #include "x86.h" @@ -35,6 +41,24 @@ #include <86box/plat_unused.h> #include <86box/port_92.h> #include <86box/chipset.h> +#include <86box/log.h> + +#ifdef ENABLE_HEADLAND_LOG +int headland_do_log = ENABLE_HEADLAND_LOG; + +static void +headland_log(void *priv, const char *fmt, ...) +{ + if (headland_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define headland_log(fmt, ...) +#endif enum { HEADLAND_GC103 = 0x00, @@ -82,6 +106,8 @@ typedef struct headland_t { mem_mapping_t high_mapping; mem_mapping_t shadow_mapping[2]; mem_mapping_t upper_mapping[24]; + + void * log; /* New logging system */ } headland_t; /* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, @@ -117,27 +143,30 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) else if ((addr >= 0xfe0000) && (addr <= 0xffffff)) return addr & 0x0fffff; - if (dev->revision == 8) { - shift = (dev->cr[0] & 0x80) ? 21 : ((dev->cr[6] & 0x01) ? 23 : 19); - other_shift = (dev->cr[0] & 0x80) ? ((dev->cr[6] & 0x01) ? 19 : 23) : 21; + if ((dev->revision == 8) && ((dev->cr[6] & 0x01) == 0x01)) { + shift = (dev->cr[0] & 0x80) ? 21 : ((dev->cr[1] & 0x40) ? 19 : 23); + other_shift = (dev->cr[0] & 0x80) ? 23 : ((dev->cr[1] & 0x40) ? 23 : 23); } else { shift = (dev->cr[0] & 0x80) ? 21 : 19; - other_shift = (dev->cr[0] & 0x80) ? 21 : 19; + other_shift = (dev->cr[0] & 0x80) ? 19 : 21; } + headland_log(dev->log, "Headland shift values: shift = %i, other_shift = %i\n", shift, other_shift); + /* Bank size = 1 << (bank shift + 2) . */ bank_shift[0] = bank_shift[1] = shift; bank_base[0] = 0x00000000; bank_base[1] = bank_base[0] + (1 << shift); - bank_base[2] = bank_base[1] + (1 << shift); - if ((dev->revision > 0) && (dev->revision < 8) && (dev->cr[1] & 0x40)) { + if ((dev->revision > 0) && (dev->cr[1] & 0x40)) { bank_shift[2] = bank_shift[3] = other_shift; + bank_base[2] = bank_base[1] + (1 << other_shift); bank_base[3] = bank_base[2] + (1 << other_shift); /* First address after the memory is bank_base[3] + (1 << other_shift) */ } else { bank_shift[2] = bank_shift[3] = shift; + bank_base[2] = bank_base[1] + (1 << shift); bank_base[3] = bank_base[2] + (1 << shift); /* First address after the memory is bank_base[3] + (1 << shift) */ } @@ -220,9 +249,10 @@ memmap_state_default(headland_t *dev, uint8_t ht_romcs) mem_mapping_disable(&dev->mid_mapping); if (ht_romcs) - mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); + mem_set_mem_state(0x0e0000, 0x10000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); else - mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0e0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0f0000, 0x10000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); mem_mapping_disable(&dev->shadow_mapping[0]); @@ -247,15 +277,18 @@ memmap_state_update(headland_t *dev) memmap_state_default(dev, ht_romcs); + headland_log(dev->log, "Headland 384K Remap %sabled\n", ht_cr0 & 0x04 ? "Dis" : "En"); if (mem_size > 640) { if (ht_cr0 & 0x04) { mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, 0x40000); mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); mem_mapping_disable(&dev->mid_mapping); if (mem_size > 1024) { - mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } else if ((mem_size > 640) && (mem_size <=1024)) { + mem_set_mem_state(0x100000, (mem_size - 640) << 10, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } } else { /* 1 MB - 1 MB + 384k: RAM pointing to A0000-FFFFF @@ -265,14 +298,17 @@ memmap_state_update(headland_t *dev) mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); if (mem_size > 1024) { /* We have ram above 1 MB, we need to relocate that. */ - mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } else if ((mem_size > 640) && (mem_size <=1024)) { + mem_set_mem_state(0x100000, (mem_size - 640) << 10, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); } } } - switch (ht_cr0) { + headland_log(dev->log, "Headland shadow RAM val = %02X\n", ht_cr0 & 0x18); + switch (ht_cr0 & 0x18) { case 0x18: if ((mem_size << 10) > 0xe0000) { mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); @@ -330,6 +366,8 @@ hl_write(uint16_t addr, uint8_t val, void *priv) { headland_t *dev = (headland_t *) priv; + headland_log(dev->log, "[%04X:%08X] Headland: [W] addr = %04X, val = %02X\n", CS, cpu_state.pc, addr, val); + switch (addr) { case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val | 0xff00; @@ -400,6 +438,8 @@ hl_writew(uint16_t addr, uint16_t val, void *priv) { headland_t *dev = (headland_t *) priv; + headland_log(dev->log, "[%04X:%08X] Headland: [W] addr = %04X, val = %04X\n", CS, cpu_state.pc, addr, val); + switch (addr) { case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val; @@ -469,6 +509,8 @@ hl_read(uint16_t addr, void *priv) break; } + headland_log(dev->log, "[%04X:%08X] Headland [R] addr = %04X, val = %02X\n", CS, cpu_state.pc, addr, ret); + return ret; } @@ -489,6 +531,8 @@ hl_readw(uint16_t addr, void *priv) break; } + headland_log(dev->log, "[%04X:%08X] Headland [R] addr = %04X, val = %04X\n", CS, cpu_state.pc, addr, ret); + return ret; } @@ -583,6 +627,11 @@ headland_close(void *priv) { headland_t *dev = (headland_t *) priv; + if (dev->log != NULL) { + log_close(dev->log); + dev->log = NULL; + } + free(dev); } @@ -620,6 +669,8 @@ headland_init(const device_t *info) dev->ems_mr[i].headland = dev; } + dev->log = log_open("Headland"); + /* Turn off mem.c mappings. */ mem_mapping_disable(&ram_low_mapping); mem_mapping_disable(&ram_mid_mapping); diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index ed7c269b0..132754ac7 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -28,6 +28,7 @@ #include <86box/device.h> #include <86box/mem.h> #include <86box/port_92.h> +#include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> #include <86box/chipset.h> @@ -176,6 +177,9 @@ opti499_write(uint16_t addr, uint8_t val, void *priv) break; case 0x22: + mem_a20_chipset = (val & 0x02); + mem_a20_recalc(); + fallthrough; case 0x23: case 0x26: case 0x2d: diff --git a/src/config.c b/src/config.c index 52eb05dae..06049713c 100644 --- a/src/config.c +++ b/src/config.c @@ -27,6 +27,11 @@ * -DANSI_CFG for use on these systems. */ +#ifdef _WIN32 +# include +#else +# include +#endif #include #ifdef ENABLE_CONFIG_LOG #include @@ -886,6 +891,25 @@ load_network(void) } else strcpy(nc->host_dev_name, "none"); + if (nc->net_type == NET_TYPE_SLIRP) { + sprintf(temp, "net_%02i_addr", c + 1); + p = ini_section_get_string(cat, temp, ""); + if (p && *p) { + struct in_addr addr; + if (inet_pton(AF_INET, p, &addr)) { + uint8_t *bytes = (uint8_t *)&addr.s_addr; + bytes[3] = 0; + sprintf(nc->slirp_net, "%d.%d.%d.0", bytes[0], bytes[1], bytes[2]); + } else { + nc->slirp_net[0] = '\0'; + } + } else { + nc->slirp_net[0] = '\0'; + } + } else { + nc->slirp_net[0] = '\0'; + } + sprintf(temp, "net_%02i_switch_group", c + 1); nc->switch_group = ini_section_get_int(cat, temp, NET_SWITCH_GRP_MIN); if (nc->switch_group < NET_SWITCH_GRP_MIN) @@ -1458,7 +1482,7 @@ load_floppy_and_cdrom_drives(void) int c; int d; int count = cdrom_get_type_count(); - + #ifndef DISABLE_FDD_AUDIO fdd_audio_load_profiles(); #endif @@ -1532,7 +1556,7 @@ load_floppy_and_cdrom_drives(void) fdd_set_audio_profile(c, d); #else fdd_set_audio_profile(c, 0); -#endif +#endif for (int i = 0; i < MAX_PREV_IMAGES; i++) { fdd_image_history[c][i] = (char *) calloc((MAX_IMAGE_PATH_LEN + 1) << 1, sizeof(char)); @@ -2987,6 +3011,14 @@ save_network(void) else ini_section_set_int(cat, temp, nc->link_state); + if (nc->net_type == NET_TYPE_SLIRP && nc->slirp_net[0] != '\0') { + sprintf(temp, "net_%02i_addr", c + 1); + ini_section_set_string(cat, temp, nc->slirp_net); + } else { + sprintf(temp, "net_%02i_addr", c + 1); + ini_section_delete_var(cat, temp); + } + sprintf(temp, "net_%02i_switch_group", c + 1); if (nc->switch_group == NET_SWITCH_GRP_MIN) ini_section_delete_var(cat, temp); 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/mouse_serial.c b/src/device/mouse_serial.c index 45750ef09..340d3d144 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -143,8 +143,24 @@ sermouse_transmit_byte(mouse_t *dev, int do_next) if (dev->buf_pos == 0) dev->acc_time = 0.0; - if (dev->serial) + if (dev->serial) { + if ((dev->state == STATE_TRANSMIT_REPORT) && (dev->format == FORMAT_PB_5BYTE) && + (dev->buf_pos == 3)) { + /* + The last two bytes are the delta between now and when we originally + prepared the report for sending. + */ + int delta_x = 0; + int delta_y = 0; + + mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -128, 127, 1, 0); + + dev->buf[3] = delta_x; /* same as byte 1 */ + dev->buf[4] = delta_y; /* same as byte 2 */ + } + serial_write_fifo(dev->serial, dev->buf[dev->buf_pos]); + } if (do_next) { /* If we have a buffer length of 0, pretend the state is STATE_SKIP_PACKET. */ 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/disk/hdc_ide.c b/src/disk/hdc_ide.c index 56548766a..8b955c315 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -2610,8 +2610,8 @@ ide_callback(void *priv) err = ABRT_ERR; else { /* Only accept after RESET or DIAG. */ - if (ide->params_specified) { - ide->cfg_spt = ide->tf->secount; + if (!ide->params_specified) { + ide->cfg_spt = (ide->tf->secount == 0) ? 256 : ide->tf->secount; ide->cfg_hpc = ide->tf->head + 1; ide->params_specified = 1; 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 606b21b4b..f9fe268b0 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -569,6 +569,7 @@ extern int machine_at_acer100t_init(const machine_t *); /* HT18 */ extern int machine_at_ama932j_init(const machine_t *); +extern int machine_at_tandy1000rsx_init(const machine_t *); /* Intel 82335 */ extern int machine_at_adi386sx_init(const machine_t *); @@ -750,6 +751,9 @@ extern int machine_at_4gpv5_init(const machine_t *); /* Contaq 82C597 */ extern int machine_at_greenb_init(const machine_t *); +/* OPTi 499 */ +extern int machine_at_xenon_init(const machine_t *); + /* OPTi 895 */ #ifdef EMU_DEVICE_H extern const device_t j403tg_device; @@ -1211,6 +1215,9 @@ extern int machine_at_ma30d_init(const machine_t *); /* i440EX */ extern int machine_at_brio83xx_init(const machine_t *); extern int machine_at_p6i440e2_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t como_device; +#endif extern int machine_at_como_init(const machine_t *); /* i440BX */ @@ -1506,6 +1513,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/mem.h b/src/include/86box/mem.h index 9051189a6..1fc95c047 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -307,6 +307,7 @@ extern int read_type; extern int mem_a20_state; extern int mem_a20_alt; +extern int mem_a20_chipset; extern int mem_a20_key; extern uint8_t read_mem_b(uint32_t addr); diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 2c91a6d9f..f3f1b1f8a 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -99,6 +99,7 @@ typedef struct netcard_conf_t { uint32_t link_state; uint8_t switch_group; uint8_t promisc_mode; + char slirp_net[16]; char nrs_hostname[128]; } netcard_conf_t; 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/include/86box/prt_papersizes.h b/src/include/86box/prt_papersizes.h index c45c74568..f0c9e626a 100644 --- a/src/include/86box/prt_papersizes.h +++ b/src/include/86box/prt_papersizes.h @@ -28,23 +28,27 @@ #define LEDGER_PAGE_HEIGHT 17.0 /* Standard A0 */ -#define A0_PAGE_WIDTH 33.125 -#define A0_PAGE_HEIGHT 46.75 +#define A0_PAGE_WIDTH 33.110236 +#define A0_PAGE_HEIGHT 46.811023 /* Standard A1 */ -#define A1_PAGE_WIDTH 23.375 -#define A1_PAGE_HEIGHT 33.125 +#define A1_PAGE_WIDTH 23.385826 +#define A1_PAGE_HEIGHT 33.110236 /* Standard A2 */ -#define A2_PAGE_WIDTH 16.5 -#define A2_PAGE_HEIGHT 23.375 +#define A2_PAGE_WIDTH 16.535433 +#define A2_PAGE_HEIGHT 23.385826 /* Standard A3 */ -#define A3_PAGE_WIDTH 11.75 -#define A3_PAGE_HEIGHT 16.5 +#define A3_PAGE_WIDTH 11.692913 +#define A3_PAGE_HEIGHT 16.535433 /* Standard A4 */ -#define A4_PAGE_WIDTH 8.25 -#define A4_PAGE_HEIGHT 11.75 +#define A4_PAGE_WIDTH 8.267716 +#define A4_PAGE_HEIGHT 11.692913 + +/* Standard B4 */ +#define B4_PAGE_WIDTH 9.8425197 +#define B4_PAGE_HEIGHT 13.897637 #endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 252463af7..3d6bf3caf 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -352,8 +352,9 @@ extern void ati8514_out(uint16_t addr, uint8_t val, void *priv); extern uint8_t ati8514_in(uint16_t addr, void *priv); extern void ati8514_recalctimings(svga_t *svga); extern uint8_t ati8514_mca_read(int port, void *priv); -extern uint8_t ati8514_rom_readb(uint32_t addr, void *priv); -extern uint16_t ati8514_rom_readw(uint32_t addr, void *priv); +extern uint8_t ati8514_bios_rom_readb(uint32_t addr, void *priv); +extern uint16_t ati8514_bios_rom_readw(uint32_t addr, void *priv); +extern uint32_t ati8514_bios_rom_readl(uint32_t addr, void *priv); extern void ati8514_mca_write(int port, uint8_t val, void *priv); extern void ati8514_pos_write(uint16_t port, uint8_t val, void *priv); extern void ati8514_init(svga_t *svga, void *ext8514, void *dev8514); 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_at_386sx.c b/src/machine/m_at_386sx.c index 9ad29e2e8..6b5c4414c 100644 --- a/src/machine/m_at_386sx.c +++ b/src/machine/m_at_386sx.c @@ -42,6 +42,7 @@ #include <86box/vid_cga.h> #include <86box/flash.h> #include <86box/machine.h> +#include <86box/sound.h> /* ISA */ /* @@ -369,6 +370,32 @@ machine_at_ama932j_init(const machine_t *model) return ret; } +int +machine_at_tandy1000rsx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/tandy1000rsx/tandy-1000rsx-1-10.00.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&headland_ht18c_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add(&pssj_1e0_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + return ret; +} + /* Intel 82335 */ int machine_at_adi386sx_init(const machine_t *model) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index cbd0cdec5..a40fac2dd 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -544,17 +544,72 @@ machine_at_brio83xx_init(const machine_t *model) return ret; } +static const device_config_t como_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "como", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "AMIBIOS 6 (071595) - Revision 1.08 (Olivetti OEM)", + .internal_name = "como_olivetti", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/como/COMO_Olivetti_OEM.ROM", "" } + }, + { + .name = "AMIBIOS 6 (071595) - Revision 1.12 (eMachines OEM)", + .internal_name = "como", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/como/COMO.ROM", "" } + }, + { .files_no = 0 } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t como_device = { + .name = "TriGem Como", + .internal_name = "como_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = como_config +}; + int machine_at_como_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/como/COMO.ROM", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) + /* No ROMs available */ + if (!device_available(model->device)) return ret; + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000c0000, 262144, 0); + device_context_restore(); + machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1); diff --git a/src/machine/m_at_socket1.c b/src/machine/m_at_socket1.c index c4932399d..7279668f5 100644 --- a/src/machine/m_at_socket1.c +++ b/src/machine/m_at_socket1.c @@ -426,6 +426,8 @@ machine_at_tuliptc38_init(const machine_t *model) device_add(&ide_isa_device); device_add_params(&fdc37c6xx_device, (void *) (FDC37C651 | FDC37C6XX_IDE_PRI)); + video_reset(gfxcard[0]); + if (gfxcard[0] == VID_INTERNAL) { bios_load_aux_linear("roms/machines/tuliptc38/VBIOS.BIN", 0x000c0000, 32768, 0); diff --git a/src/machine/m_at_socket2.c b/src/machine/m_at_socket2.c index d8fdd79f1..5ec4039b2 100644 --- a/src/machine/m_at_socket2.c +++ b/src/machine/m_at_socket2.c @@ -311,6 +311,8 @@ machine_at_dell466np_init(const machine_t *model) machine_at_common_init(model); device_add(&sis_85c461_device); + video_reset(gfxcard[0]); + if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); else { @@ -354,6 +356,8 @@ machine_at_valuepoint433_init(const machine_t *model) // hangs without the PS/2 if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); + video_reset(gfxcard[0]); + if (gfxcard[0] != VID_INTERNAL) { for (uint16_t i = 0; i < 32768; i++) rom[i] = mem_readb_phys(0x000c0000 + i); diff --git a/src/machine/m_at_socket3.c b/src/machine/m_at_socket3.c index 008394505..7c8c801f6 100644 --- a/src/machine/m_at_socket3.c +++ b/src/machine/m_at_socket3.c @@ -166,6 +166,29 @@ machine_at_greenb_init(const machine_t *model) return ret; } +/* OPTi 499 */ +int +machine_at_xenon_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/xenon/addx-bios-7-71-i28f001.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti499_device); + device_add(&ide_vlb_device); + device_add_params(&fdc37c6xx_device, (void *) (FDC37C661 | FDC37C6XX_IDE_PRI)); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add(&intel_flash_bxt_device); + + return ret; +} + /* OPTi 895 */ static const device_config_t j403tg_config[] = { // clang-format off @@ -467,6 +490,8 @@ machine_at_tg486g_init(const machine_t *model) device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + video_reset(gfxcard[0]); + if (gfxcard[0] != VID_INTERNAL) { for (uint16_t i = 0; i < 32768; i++) rom[i] = mem_readb_phys(0x000c0000 + i); 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 335860616..d11561140 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. */ @@ -5468,6 +5511,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has unknown KBC firmware */ + { + .name = "[HT18] Tandy 1000 RSX", + .internal_name = "tandy1000rsx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_HT18, + .init = machine_at_tandy1000rsx_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386SX, + .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_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO | MACHINE_GAMEPORT, + .ram = { + .min = 1024, + .max = 9216, + .step = 512 + }, + .nvrmask = 127, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = 0x00000000, + .kbc_p1 = 0x000004f0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5402_onboard_device, + .snd_device = NULL, + .net_device = NULL + }, /* Most likely has a Phoenix MultiKey/42 keyboard controller. */ { .name = "[Intel 82335] ADI 386SX", @@ -8805,6 +8892,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[OPTi 499] ADD-X Normerel Xenon", + .internal_name = "xenon", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_OPTI_499, + .init = machine_at_xenon_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .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_PS2_VLB, + .flags = MACHINE_IDE | MACHINE_APM, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_AMI | 0x00004600, + .kbc_p1 = 0x00000cf0, + .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 + }, /* Version 1.0 has an AMIKEY-2, version 2.0 has a VIA VT82C42N KBC. */ { .name = "[OPTi 895] Jetway J-403TG", @@ -18575,11 +18706,11 @@ const machine_t machines[] = { .kbc_p1 = 0x00000cf0, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &como_device, .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = NULL, /* Onboard video not yet emulated: ATi Rage IIc AGP */ .snd_device = &cs4235_onboard_device, .net_device = NULL }, diff --git a/src/mem/mem.c b/src/mem/mem.c index 91fa277be..c456c840a 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -106,9 +106,10 @@ int cachesize = 256; uint32_t get_phys_virt; uint32_t get_phys_phys; -int mem_a20_key = 0; -int mem_a20_alt = 0; -int mem_a20_state = 0; +int mem_a20_key = 0; +int mem_a20_alt = 0; +int mem_a20_chipset = 0; +int mem_a20_state = 0; int mmuflush = 0; @@ -3109,12 +3110,12 @@ mem_a20_recalc(void) if (!is286) { rammask = 0xfffff; flushmmucache(); - mem_a20_key = mem_a20_alt = mem_a20_state = 0; + mem_a20_key = mem_a20_alt = mem_a20_state = mem_a20_chipset = 0; return; } - state = mem_a20_key | mem_a20_alt; + state = mem_a20_key | mem_a20_alt | mem_a20_chipset; if (state && !mem_a20_state) { rammask = cpu_16bitbus ? 0xffffff : 0xffffffff; if (is6117) diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index c7243baac..86c0896a7 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -43,6 +43,7 @@ #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include +# include #else # include #endif @@ -493,13 +494,30 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv slirp->pfd = calloc(1, slirp->pfd_size); #endif - /* Set the IP addresses to use. */ - struct in_addr net = { .s_addr = htonl(0x0a000000 | (slirp_card_num << 8)) }; /* 10.0.x.0 */ - struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ - struct in_addr host = { .s_addr = htonl(0x0a000002 | (slirp_card_num << 8)) }; /* 10.0.x.2 */ - struct in_addr dhcp = { .s_addr = htonl(0x0a00000f | (slirp_card_num << 8)) }; /* 10.0.x.15 */ - struct in_addr dns = { .s_addr = htonl(0x0a000003 | (slirp_card_num << 8)) }; /* 10.0.x.3 */ - struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ + struct in_addr net; + struct in_addr host; + struct in_addr dhcp; + struct in_addr dns; + + /* Set the IP addresses to use. + Use a configured address if set, otherwise 10.0.x.0 */ + const char *slirp_net = net_cards_conf[card->card_num].slirp_net; + if (slirp_net[0] != '\0') { + struct in_addr addr; + inet_pton(AF_INET, slirp_net, &addr); + net.s_addr = htonl(ntohl(addr.s_addr) & 0xffffff00); + host.s_addr = htonl(ntohl(addr.s_addr) + 2); + dhcp.s_addr = htonl(ntohl(addr.s_addr) + 15); + dns.s_addr = htonl(ntohl(addr.s_addr) + 3); + } else { + net.s_addr = htonl(0x0a000000 | (slirp_card_num << 8)); /* 10.0.x.0 */ + host.s_addr = htonl(0x0a000002 | (slirp_card_num << 8)); /* 10.0.x.2 */ + dhcp.s_addr = htonl(0x0a00000f | (slirp_card_num << 8)); /* 10.0.x.15 */ + dns.s_addr = htonl(0x0a000003 | (slirp_card_num << 8)); /* 10.0.x.3 */ + } + + struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ + struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ const SlirpConfig slirp_config = { #if SLIRP_CHECK_VERSION(4, 9, 0) 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 2a50ae54f..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> @@ -72,17 +39,27 @@ #include <86box/prt_devs.h> #include <86box/prt_papersizes.h> +enum { + LANG_EX1000 = 0, // last printer with ESC i and j + LANG_9PIN, + LANG_ESCP, // also known as 24/48-pin + LANG_ESCP2 +}; + +enum { + QUALITY_DRAFT = 0, + QUALITY_LQ +}; + +enum { + PAPER_LETTER = 0, + PAPER_A4, + PAPER_LEGAL_SIDE, + PAPER_B4_SIDE +}; + /* Default page values (for now.) */ #define COLOR_BLACK 7 << 5 -#define PAGE_WIDTH LETTER_PAGE_WIDTH -#define PAGE_HEIGHT LETTER_PAGE_HEIGHT -#if 0 -#define PAGE_LMARGIN 0.0 -#define PAGE_RMARGIN PAGE_WIDTH -#define PAGE_TMARGIN 0.0 -#define PAGE_BMARGIN PAGE_HEIGHT -#endif -#define PAGE_DPI 360 #define PAGE_CPI 10.0 /* standard 10 cpi */ #define PAGE_LPI 6.0 /* standard 6 lpi */ @@ -90,28 +67,30 @@ FT_Library ft_lib = NULL; /* The fonts. */ -#define FONT_DEFAULT 0 -#define FONT_ROMAN 1 -#define FONT_SANSSERIF 2 -#define FONT_COURIER 3 -#define FONT_SCRIPT 4 -#define FONT_OCRA 5 -#define FONT_OCRB 6 +enum { + FONT_DEFAULT = 0, + FONT_ROMAN, + FONT_SANSSERIF, + FONT_COURIER, + FONT_SCRIPT, + FONT_OCRA, + FONT_OCRB +}; /* 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 @@ -120,30 +99,28 @@ FT_Library ft_lib = NULL; #define SCORE_SINGLEBROKEN 0x05 #define SCORE_DOUBLEBROKEN 0x06 -/* Print quality. */ -#define QUALITY_DRAFT 0x01 -#define QUALITY_LQ 0x02 - /* Typefaces. */ -#define TYPEFACE_ROMAN 0 -#define TYPEFACE_SANSSERIF 1 -#define TYPEFACE_COURIER 2 -#define TYPEFACE_PRESTIGE 3 -#define TYPEFACE_SCRIPT 4 -#define TYPEFACE_OCRB 5 -#define TYPEFACE_OCRA 6 -#define TYPEFACE_ORATOR 7 -#define TYPEFACE_ORATORS 8 -#define TYPEFACE_SCRIPTC 9 -#define TYPEFACE_ROMANT 10 -#define TYPEFACE_SANSSERIFH 11 -#define TYPEFACE_SVBUSABA 30 -#define TYPEFACE_SVJITTRA 31 +enum { + TYPEFACE_ROMAN = 0, + TYPEFACE_SANSSERIF, + TYPEFACE_COURIER, + TYPEFACE_PRESTIGE, + TYPEFACE_SCRIPT, + TYPEFACE_OCRB, + TYPEFACE_OCRA, + TYPEFACE_ORATOR, + TYPEFACE_ORATORS, + TYPEFACE_SCRIPTC, + TYPEFACE_ROMANT, + TYPEFACE_SANSSERIFH, + TYPEFACE_SVBUSABA = 30, + TYPEFACE_SVJITTRA +}; /* Some helper macros. */ #define PARAM16(x) (dev->esc_parms[x + 1] * 256 + dev->esc_parms[x]) -#define PIXX ((unsigned) floor(dev->curr_x * dev->dpi + 0.5)) -#define PIXY ((unsigned) floor(dev->curr_y * dev->dpi + 0.5)) +#define PIXX ((unsigned) round(dev->curr_x * dev->dpi)) +#define PIXY ((unsigned) round(dev->curr_y * dev->dpi)) typedef struct psurface_t { int8_t dirty; /* has the page been printed on? */ @@ -164,9 +141,14 @@ typedef struct escp_t { pc_timer_t pulse_timer; pc_timer_t timeout_timer; + int lang; + int paper_size; + char page_fn[260]; uint8_t color; + bool dc1_selected; + /* page data (TODO: make configurable) */ double page_width; /* all in inches */ double page_height; @@ -192,24 +174,25 @@ typedef struct escp_t { /* bit graphics data */ uint16_t bg_h_density; /* in dpi */ uint16_t bg_v_density; /* in dpi */ - int8_t bg_adjacent; /* print adjacent pixels (ignored) */ + int8_t bg_adjacent; /* print adjacent pixels */ uint8_t bg_bytes_per_column; uint16_t bg_remaining_bytes; /* #bytes left before img is complete */ uint8_t bg_column[6]; /* #bytes of the current and last col */ + uint8_t bg_previous[6]; // for non-adjacent pixels in graphics mode uint8_t bg_bytes_read; /* #bytes read so far for current col */ /* 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; @@ -253,24 +236,9 @@ typedef struct escp_t { uint8_t ctrl; PALETTE palcol; -} escp_t; -static void -update_font(escp_t *dev); -static void -blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add); -static void -draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken); -static void -init_codepage(escp_t *dev, uint16_t num); -static void -reset_printer(escp_t *dev); -static void -setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns); -static void -print_bit_graph(escp_t *dev, uint8_t ch); -static void -new_page(escp_t *dev, int8_t save, int8_t resetx); + bool auto_lf; +} escp_t; /* Codepage table, needed for ESC t ( */ static const uint16_t codepages[15] = { @@ -330,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, ...) @@ -384,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); } @@ -405,13 +368,11 @@ timeout_timer(void *priv) static void fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, escp_t *dev) { - uint8_t colormask; + const uint8_t colormask = colorID <<= 5; - double red = (double) redmax / (double) 30.9; - double green = (double) greenmax / (double) 30.9; - double blue = (double) bluemax / (double) 30.9; - - colormask = colorID <<= 5; + const double red = (double) redmax / (double) 30.9; + const double green = (double) greenmax / (double) 30.9; + const double blue = (double) bluemax / (double) 30.9; for (uint8_t i = 0; i < 32; i++) { dev->palcol[i + colormask].r = 255 - (uint8_t) floor(red * (double) i); @@ -420,79 +381,6 @@ fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, } } -static void -reset_printer(escp_t *dev) -{ - /* TODO: these should be configurable. */ - dev->color = COLOR_BLACK; - dev->curr_x = dev->curr_y = 0.0; - dev->esc_seen = 0; - dev->fss_seen = 0; - dev->esc_pending = 0; - dev->esc_parms_req = dev->esc_parms_curr = 0; - dev->top_margin = dev->left_margin = 0.0; - dev->right_margin = dev->page_width = PAGE_WIDTH; - dev->bottom_margin = dev->page_height = PAGE_HEIGHT; - dev->lpi = PAGE_LPI; - dev->linespacing = 1.0 / dev->lpi; - dev->cpi = PAGE_CPI; - dev->curr_char_table = 1; - dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; - dev->extra_intra_space = 0.0; - dev->print_upper_control = 1; - dev->bg_remaining_bytes = 0; - dev->density_k = 0; - dev->density_l = 1; - dev->density_y = 2; - dev->density_z = 3; - dev->char_tables[0] = 0; /* italics */ - dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ - dev->defined_unit = -1.0; - dev->multipoint_mode = 0; - dev->multipoint_size = 0.0; - dev->multipoint_cpi = 0.0; - dev->hmi = -1; - dev->msb = 255; - dev->print_everything_count = 0; - dev->lq_typeface = TYPEFACE_COURIER; - - init_codepage(dev, dev->char_tables[dev->curr_char_table]); - - update_font(dev); - - new_page(dev, 0, 1); - - for (uint8_t i = 0; i < 32; i++) - dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); - dev->num_horizontal_tabs = 32; - dev->num_vertical_tabs = -1; - - if (dev->page != NULL) - dev->page->dirty = 0; - - escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", - dev->page_width, dev->page_height, (int) dev->dpi, - (int) dev->cpi, (int) dev->lpi); -} - -static void -reset_printer_hard(escp_t *dev) -{ - dev->ack = 0; - timer_disable(&dev->pulse_timer); - timer_stop(&dev->timeout_timer); - reset_printer(dev); -} - -/* Select a ASCII->Unicode mapping by CP number */ -static void -init_codepage(escp_t *dev, uint16_t num) -{ - /* Get the codepage map for this number. */ - select_codepage(num, dev->curr_cpmap); -} - static void update_font(escp_t *dev) { @@ -503,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. */ @@ -607,6 +495,260 @@ update_font(escp_t *dev) } } +/* Select a ASCII->Unicode mapping by CP number */ +static void +init_codepage(escp_t *dev, uint16_t num) +{ + /* Get the codepage map for this number. */ + select_codepage(num, dev->curr_cpmap); +} + +static void +reset_printer(escp_t *dev) +{ + dev->top_margin = dev->left_margin = 1.0 / 36.0; + dev->right_margin = dev->page_width; + switch (dev->paper_size) { + case PAPER_A4: + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + break; + case PAPER_LETTER: + default: + dev->page_height = LETTER_PAGE_HEIGHT; + } + 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 = false; + dev->fss_seen = false; + dev->esc_pending = 0; + dev->esc_parms_req = dev->esc_parms_curr = 0; + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; + dev->print_quality = device_get_config_int("quality"); + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ + dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ + dev->defined_unit = -1.0; + dev->multipoint_mode = 0; + dev->multipoint_size = 0.0; + dev->multipoint_cpi = 0.0; + dev->hmi = -1; + dev->msb = 255; + dev->print_everything_count = 0; + dev->lq_typeface = TYPEFACE_COURIER; + + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + + update_font(dev); + + new_page(dev, 0, 1); + + for (uint8_t i = 0; i < 32; i++) + dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); + dev->num_horizontal_tabs = 32; + dev->num_vertical_tabs = -1; + + if (dev->page) + dev->page->dirty = 0; + + escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", + dev->page_width, dev->page_height, (int) dev->dpi, + (int) dev->cpi, (int) dev->lpi); +} + +static void +reset_printer_hard(escp_t *dev) +{ + dev->ack = false; + timer_disable(&dev->pulse_timer); + timer_stop(&dev->timeout_timer); + reset_printer(dev); +} + +static void +setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) +{ + escp_log("Density=%d\n", density); + switch (density) { + case 0: + dev->bg_h_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 1: + dev->bg_h_density = 120; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 2: + dev->bg_h_density = 120; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 3: + dev->bg_h_density = 240; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 4: + dev->bg_h_density = 80; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 5: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 72; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 6: + dev->bg_h_density = 90; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 7: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 144; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 32: + if (dev->lang < LANG_ESCP) + break; + dev->bg_h_density = 60; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 33: + if (dev->lang < LANG_ESCP) + break; + dev->bg_h_density = 120; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 38: + if (dev->lang < LANG_ESCP) + break; + dev->bg_h_density = 90; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 39: + if (dev->lang < LANG_ESCP) + break; + dev->bg_h_density = 180; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 40: + if (dev->lang < LANG_ESCP) + break; + dev->bg_h_density = 360; + dev->bg_v_density = 180; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 3; + break; + + case 71: + if (dev->lang < LANG_ESCP) + break; + dev->bg_h_density = 180; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + case 72: + if (dev->lang < LANG_ESCP) + break; + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 6; + break; + + case 73: + if (dev->lang < LANG_ESCP2) + break; + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + case 254: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 120; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 2; + break; + + case 255: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 60; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 2; + break; + + default: + escp_log("ESC/P: Unsupported bit image density %d.\n", density); + break; + } + for (uint8_t i = 0; i < dev->bg_bytes_per_column; ++i) + dev->bg_previous[i] = 0; + + dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; + dev->bg_bytes_read = 0; +} + /* This is the actual ESC/P interpreter. */ static int process_char(escp_t *dev, uint8_t ch) @@ -627,79 +769,66 @@ 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); switch (dev->esc_pending) { case 0x02: // Undocumented - case 0x0a: // Reverse line feed - case 0x0c: // Return to top of current page case 0x0e: // Select double-width printing (one line) (ESC SO) case 0x0f: // Select condensed printing (ESC SI) - case 0x23: // Cancel MSB control (ESC #) - case 0x30: // Select 1/8-inch line spacing (ESC 0) - case 0x31: // Select 7/60-inch line spacing - case 0x32: // Select 1/6-inch line spacing (ESC 2) - case 0x34: // Select italic font (ESC 4) - case 0x35: // Cancel italic font (ESC 5) - case 0x36: // Enable printing of upper control codes (ESC 6) - case 0x37: // Enable upper control codes (ESC 7) - case 0x38: // Disable paper-out detector - case 0x39: // Enable paper-out detector - case 0x3c: // Unidirectional mode (one line) (ESC <) - case 0x3d: // Set MSB to 0 (ESC =) - case 0x3e: // Set MSB to 1 (ESC >) - case 0x40: // Initialize printer (ESC @) - case 0x45: // Select bold font (ESC E) - case 0x46: // Cancel bold font (ESC F) - case 0x47: // Select double-strike printing (ESC G) - case 0x48: // Cancel double-strike printing (ESC H) - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - case 0x54: // Cancel superscript/subscript printing (ESC T) - case 0x5e: // Enable printing of all character codes on next character - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - + case '#': // Cancel MSB control + case '0': // Select 1/8-inch line spacing + case '2': // Select 1/6-inch line spacing + case '4': // Select italic font + case '5': // Cancel italic font + case '6': // Enable printing of upper control codes + case '7': // Enable upper control codes + case '<': // Unidirectional mode (one line) + case '=': // Set MSB to 0 + case '>': // Set MSB to 1 + case '@': // Initialize printer + case 'E': // Select bold font + case 'F': // Cancel bold font + case 'G': // Select double-strike printing + case 'H': // Cancel double-strike printing + case 'M': // Select 10.5-point, 12-cpi + case 'O': // Cancel bottom margin + case 'P': // Select 10.5-point, 10-cpi + case 'T': // Cancel superscript/subscript printing + dev->esc_parms_req = 0; + break; + case 'g': // Select 10.5-point, 15-cpi + dev->esc_parms_req = 0; + if (dev->lang == LANG_EX1000) { + dev->esc_pending = 0; + return 1; + } + break; + case '1': // Select 7/72-inch line spacing + case '8': // Disable paper-out detector + case '9': // Enable paper-out detector + dev->esc_parms_req = 0; + if (dev->lang >= LANG_ESCP) { + dev->esc_pending = 0; + return 1; + } + break; + case 0x0a: // Reverse line feed (IBM's ESC LF) + case 0x0c: // Return to top of current page (IBM's ESC FF) case 0x834: // Select italic font (FS 4) (= ESC 4) case 0x835: // Cancel italic font (FS 5) (= ESC 5) case 0x846: // Select forward feed mode (FS F) case 0x852: // Select reverse feed mode (FS R) dev->esc_parms_req = 0; + if (dev->lang < LANG_ESCP2) { + dev->esc_pending = 0; + return 1; + } break; - case 0x19: // Control paper loading/ejecting (ESC EM) - case 0x20: // Set intercharacter space (ESC SP) - case 0x21: // Master select (ESC !) - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x2d: // Turn underline on/off (ESC -) - case 0x2f: // Select vertical tab channel (ESC /) - case 0x33: // Set n/180-inch line spacing (ESC 3) - case 0x41: // Set n/60-inch line spacing - case 0x43: // Set page length in lines (ESC C) - case 0x49: // Select character type and print pitch - case 0x4a: // Advance print position vertically (ESC J n) - case 0x4e: // Set bottom margin (ESC N) - case 0x51: // Set right margin (ESC Q) - case 0x52: // Select an international character set (ESC R) - case 0x53: // Select superscript/subscript printing (ESC S) - case 0x55: // Turn unidirectional mode on/off (ESC U) - case 0x57: // Turn double-width printing on/off (ESC W) - case 0x61: // Select justification (ESC a) - case 0x66: // Absolute horizontal tab in columns [conflict] - case 0x68: // Select double or quadruple size - case 0x69: // Immediate print - case 0x6a: // Reverse paper feed - case 0x6b: // Select typeface (ESC k) - case 0x6c: // Set left margin (ESC 1) - case 0x70: // Turn proportional mode on/off (ESC p) - case 0x72: // Select printing color (ESC r) - case 0x73: // Select low-speed mode (ESC s) - case 0x74: // Select character table (ESC t) - case 0x77: // Turn double-height printing on/off (ESC w) - case 0x78: // Select LQ or draft (ESC x) - case 0x7e: // Select/Deselect slash zero (ESC ~) + case 'h': // Select double or quadruple size (IBM's) + case '~': // Select/Deselect slash zero (IBM's?) case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) @@ -708,53 +837,152 @@ process_char(escp_t *dev, uint8_t ch) case 0x849: // Select character table (FS I) (= ESC t) case 0x853: // Select High Speed/High Density elite pitch (FS S) case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '+': // Set n/360-inch line spacing + if (dev->lang < LANG_ESCP) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 'w': // Turn double-height printing on/off + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 0x19: // Control paper loading/ejecting (ESC EM) + case ' ': // Set intercharacter space + case '!': // Master select + case '-': // Turn underline on/off + case '/': // Select vertical tab channel + case '3': // Set n/180-inch line spacing + case 'A': // Set n/60-inch line spacing + case 'C': // Set page length in lines + case 'I': // Select character type and print pitch + case 'J': // Advance print position vertically + case 'N': // Set bottom margin + case 'Q': // Set right margin + case 'R': // Select an international character set + case 'S': // Select superscript/subscript printing + case 'U': // Turn unidirectional mode on/off + case 'W': // Turn double-width printing on/off + case 'a': // Select justification + case 'k': // Select typeface + case 'l': // Set left margin + case 'p': // Turn proportional mode on/off + case 'r': // Select printing color + case 's': // Select low-speed mode + case 't': // Select character table + case 'x': // Select LQ or draft + dev->esc_parms_req = 1; + break; + case 'f': // Absolute horizontal tab in columns + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 1; + break; + case 'i': // Immediate print + case 'j': // Reverse paper feed + if (dev->lang != LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 1; break; - case 0x24: // Set absolute horizontal print position (ESC $) - case 0x3f: // Reassign bit-image mode (ESC ?) - case 0x4b: // Select 60-dpi graphics (ESC K) - case 0x4c: // Select 120-dpi graphics (ESC L) - case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) - case 0x5a: // Select 240-dpi graphics (ESC Z) - case 0x5c: // Set relative horizontal print position (ESC \) - case 0x63: // Set horizontal motion index (HMI) (ESC c) - case 0x65: // Set vertical tab stops every n lines (ESC e) + case 'c': // Set horizontal motion index (HMI) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '$': // Set absolute horizontal print position + case '?': // Reassign bit-image mode + case 'K': // Select 60-dpi graphics + case 'L': // Select 120-dpi graphics + case 'Y': // Select 120-dpi, double-speed graphics + case 'Z': // Select 240-dpi graphics + case '\\': // Set relative horizontal print position case 0x85a: // Print 24-bit hex-density graphics (FS Z) dev->esc_parms_req = 2; break; + case 'e': // Set vertical tab stops every n lines + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 2; + break; - case 0x2a: // Select bit image (ESC *) - case 0x58: // Select font by pitch and point (ESC X) + case 'X': // Select font by pitch and point + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '^': /* 9-pin ESC/P: Select 60/120-dpi, 9-bit graphics + IBM: Enable printing of all character codes on next character */ + if (dev->lang <= LANG_9PIN) + dev->esc_parms_req = 3; + else { + dev->esc_parms_req = 0; + if (dev->lang == LANG_ESCP) + dev->esc_pending = 0; + } + break; + case '*': // Select bit image dev->esc_parms_req = 3; break; - case 0x5b: // Select character height, width, line spacing + case '[': // Select character height, width, line spacing (IBM's) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 7; break; - case 0x62: // Set vertical tabs in VFU channels (ESC b) - case 0x42: // Set vertical tabs (ESC B) + case 'b': // Set vertical tabs in VFU channels + case 'B': // Set vertical tabs dev->num_vertical_tabs = 0; return 1; - case 0x44: // Set horizontal tabs (ESC D) + case 'D': // Set horizontal tabs dev->num_horizontal_tabs = 0; return 1; - case 0x25: // Select user-defined set (ESC %) - case 0x26: // Define user-defined characters (ESC &) - case 0x3a: // Copy ROM to RAM (ESC :) + case '%': // Select user-defined set + case '&': // Define user-defined characters + case ':': // Copy ROM to RAM escp_log("ESC/P: User-defined characters not supported (0x%02x).\n", dev->esc_pending); return 1; - case 0x28: // Two bytes sequence + case '(': // Two bytes sequence + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + } /* return and wait for second ESC byte */ return 1; - case 0x2e: - fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); - exit(-1); + case '.': + if (dev->lang >= LANG_ESCP2) { + fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); + exit(-1); + } + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; default: escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", @@ -776,50 +1004,67 @@ process_char(escp_t *dev, uint8_t ch) escp_log("Two-byte command pending=%03x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { - case 0x0242: // Bar code setup and print (ESC (B) case 0x025e: // Print data as characters (ESC (^) + if (dev->lang < LANG_ESCP2) + default: + /* ESC ( commands are always followed by a "number of parameters" word parameter */ + dev->esc_pending = 0x101; /* dummy value to be checked later */ + case 0x0242: // Bar code setup and print (ESC (B) dev->esc_parms_req = 2; break; case 0x0255: // Set unit (ESC (U) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 3; break; case 0x0243: // Set page length in defined unit (ESC (C) case 0x0256: // Set absolute vertical print position (ESC (V) case 0x0276: // Set relative vertical print position (ESC (v) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 4; break; - case 0x0228: // Assign character table (ESC (t) case 0x022d: // Select line/score (ESC (-) + if (dev->lang == LANG_9PIN) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } + case 0x0228: // Assign character table (ESC (t) dev->esc_parms_req = 5; break; case 0x0263: // Set page format (ESC (c) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 6; break; - - default: - /* ESC ( commands are always followed by a "number of parameters" word parameter */ - dev->esc_parms_req = 2; - dev->esc_pending = 0x101; /* dummy value to be checked later */ - return 1; } - /* If we need parameters, return and wait for them to appear. */ - if (dev->esc_parms_req > 0) - return 1; + // Wait for more parameters. + return 1; } /* Ignore VFU channel setting. */ - if (dev->esc_pending == 0x62) { - dev->esc_pending = 0x42; + if (dev->esc_pending == 'b') { + dev->esc_pending = 'B'; return 1; } /* Collect vertical tabs. */ - if (dev->esc_pending == 0x42) { + if (dev->esc_pending == 'B') { /* check if we're done */ if ((ch == 0) || (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double) ch * dev->linespacing)) { dev->esc_pending = 0; @@ -830,7 +1075,7 @@ process_char(escp_t *dev, uint8_t ch) } /* Collect horizontal tabs. */ - if (dev->esc_pending == 0x44) { + if (dev->esc_pending == 'D') { /* check if we're done... */ if ((ch == 0) || (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double) ch * (1.0 / dev->cpi))) { dev->esc_pending = 0; @@ -887,38 +1132,25 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x21: /* master select (ESC !) */ + 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; update_font(dev); break; - case 0x23: /* cancel MSB control (ESC #) */ + case '#': /* cancel MSB control */ dev->msb = 255; break; - case 0x24: /* set abs horizontal print position (ESC $) */ + case '$': /* set abs horizontal print position */ unit_size = dev->defined_unit; if (unit_size < 0) unit_size = 60.0; @@ -932,12 +1164,12 @@ process_char(escp_t *dev, uint8_t ch) setup_bit_image(dev, 40, PARAM16(0)); break; - case 0x2a: /* select bit image (ESC *) */ + case '*': /* select bit image */ setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); break; - case 0x2b: /* set n/360-inch line spacing (ESC +) */ case 0x833: /* Set n/360-inch line spacing (FS 3) */ + case '+': /* set n/360-inch line spacing */ dev->linespacing = (double) dev->esc_parms[0] / 360.0; break; @@ -951,58 +1183,70 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x2f: /* select vertical tab channel (ESC /) */ + case '/': /* select vertical tab channel */ /* Ignore */ break; - case 0x30: /* select 1/8-inch line spacing (ESC 0) */ + case '0': /* select 1/8-inch line spacing */ dev->linespacing = 1.0 / 8.0; break; - case 0x31: /* select 7/60-inch line spacing */ - dev->linespacing = 7.0 / 60.0; + case '1': /* select 7/72-inch line spacing */ + dev->linespacing = 7.0 / 72.0; break; - case 0x32: /* select 1/6-inch line spacing (ESC 2) */ + case '2': /* select 1/6-inch line spacing */ dev->linespacing = 1.0 / 6.0; break; - case 0x33: /* set n/180-inch line spacing (ESC 3) */ - dev->linespacing = (double) dev->esc_parms[0] / 180.0; + case '3': /* set n/180 or n/216-inch line spacing */ + dev->linespacing = (double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 180.0 : 216.0); break; - case 0x34: /* select italic font (ESC 4) */ + case '4': /* select italic font */ dev->font_style |= STYLE_ITALICS; update_font(dev); break; - case 0x35: /* cancel italic font (ESC 5) */ + case '5': /* cancel italic font */ dev->font_style &= ~STYLE_ITALICS; update_font(dev); break; - case 0x36: /* enable printing of upper control codes (ESC 6) */ + case '6': /* enable printing of upper control codes */ dev->print_upper_control = 1; break; - case 0x37: /* enable upper control codes (ESC 7) */ + case '7': /* enable upper control codes */ dev->print_upper_control = 0; break; - case 0x3c: /* unidirectional mode (one line) (ESC <) */ + 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. */ break; - case 0x3d: /* set MSB to 0 (ESC =) */ + case '=': /* set MSB to 0 */ dev->msb = 0; break; - case 0x3e: /* set MSB to 1 (ESC >) */ + case '>': /* set MSB to 1 */ dev->msb = 1; break; - case 0x3f: /* reassign bit-image mode (ESC ?) */ + case '?': /* reassign bit-image mode */ + if ((dev->esc_parms[1] == 3 || dev->esc_parms[1] == 5) && dev->lang >= LANG_ESCP) + break; + if (dev->esc_parms[1] > 7) { + if (dev->lang < LANG_ESCP) + break; + if (dev->esc_parms[1] > 40 && dev->lang < LANG_ESCP2) + break; + } if (dev->esc_parms[0] == 'K') dev->density_k = dev->esc_parms[1]; if (dev->esc_parms[0] == 'L') @@ -1013,16 +1257,16 @@ process_char(escp_t *dev, uint8_t ch) dev->density_z = dev->esc_parms[1]; break; - case 0x40: /* initialize printer (ESC @) */ + case '@': /* initialize printer */ reset_printer(dev); break; - case 0x41: /* set n/60-inch line spacing */ - case 0x841: - dev->linespacing = (double) dev->esc_parms[0] / 60.0; + case 'A': /* set n/60 or n/72-inch line spacing */ + case 0x841: // FS A + dev->linespacing = (double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 60.0 : 72.0); break; - case 0x43: /* set page length in lines (ESC C) */ + case 'C': /* set page length in lines */ if (dev->esc_parms[0] != 0) { dev->page_height = dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; } else { /* == 0 => Set page length in inches */ @@ -1033,69 +1277,67 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x45: /* select bold font (ESC E) */ + case 'E': /* select bold font */ dev->font_style |= STYLE_BOLD; update_font(dev); break; - case 0x46: /* cancel bold font (ESC F) */ + case 'F': /* cancel bold font */ dev->font_style &= ~STYLE_BOLD; update_font(dev); break; - case 0x47: /* select double-strike printing (ESC G) */ + case 'G': /* select double-strike printing */ dev->font_style |= STYLE_DOUBLESTRIKE; break; - case 0x48: /* cancel double-strike printing (ESC H) */ + case 'H': /* cancel double-strike printing */ dev->font_style &= ~STYLE_DOUBLESTRIKE; break; - case 0x4a: /* advance print pos vertically (ESC J n) */ - dev->curr_y += (double) ((double) dev->esc_parms[0] / 180.0); + case 'J': /* advance print pos vertically */ + dev->curr_y += ((double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 180.0 : 216.0)); if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); break; - case 0x4b: /* select 60-dpi graphics (ESC K) */ - /* TODO: graphics stuff */ + case 'K': /* select 60-dpi graphics */ setup_bit_image(dev, dev->density_k, PARAM16(0)); break; - case 0x4c: /* select 120-dpi graphics (ESC L) */ - /* TODO: graphics stuff */ + case 'L': /* select 120-dpi graphics */ setup_bit_image(dev, dev->density_l, PARAM16(0)); break; - case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ + case 'M': /* select 10.5-point, 12-cpi */ dev->cpi = 12.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x4e: /* set bottom margin (ESC N) */ + case 'N': /* set bottom margin */ dev->top_margin = 0.0; dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; break; - case 0x4f: /* cancel bottom (and top) margin */ + case 'O': /* cancel bottom (and top) margin */ dev->top_margin = 0.0; dev->bottom_margin = dev->page_height; break; - case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ + case 'P': /* select 10.5-point, 10-cpi */ dev->cpi = 10.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x51: /* set right margin */ + case 'Q': /* set right margin */ dev->right_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; break; - case 0x52: /* select an intl character set (ESC R) */ + case 'R': /* select an intl character set */ if ((dev->esc_parms[0] <= 13) || (dev->esc_parms[0] == 64)) { if (dev->esc_parms[0] == 64) dev->esc_parms[0] = 14; @@ -1115,7 +1357,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x53: /* select superscript/subscript printing (ESC S) */ + case 'S': /* select superscript/subscript printing */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style |= STYLE_SUBSCRIPT; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[1] == '1')) @@ -1123,16 +1365,16 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x54: /* cancel superscript/subscript printing (ESC T) */ - dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + case 'T': /* cancel superscript/subscript printing */ + dev->font_style &= ~(STYLE_SUPERSCRIPT | STYLE_SUBSCRIPT); update_font(dev); break; - case 0x55: /* turn unidirectional mode on/off (ESC U) */ + case 'U': /* turn unidirectional mode on/off */ /* We don't have a print head, so just ignore this. */ break; - case 0x57: /* turn double-width printing on/off (ESC W) */ + case 'W': /* turn double-width printing on/off */ if (!dev->multipoint_mode) { dev->hmi = -1; if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) @@ -1143,7 +1385,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x58: /* select font by pitch and point (ESC X) */ + case 'X': /* select font by pitch and point */ dev->multipoint_mode = 1; /* Copy currently non-multipoint CPI if no value was set so far. */ if (dev->multipoint_cpi == 0.0) { @@ -1165,34 +1407,37 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ - /* TODO: graphics stuff */ + case 'Y': /* select 120-dpi, double-speed graphics */ setup_bit_image(dev, dev->density_y, PARAM16(0)); break; - case 0x5a: /* select 240-dpi graphics (ESC Z) */ - /* TODO: graphics stuff */ + case 'Z': /* select 240-dpi graphics */ setup_bit_image(dev, dev->density_z, PARAM16(0)); break; - case 0x5c: /* set relative horizontal print pos (ESC \) */ + case '\\': /* set relative horizontal print pos */ rel_move = PARAM16(0); unit_size = dev->defined_unit; if (unit_size < 0) - unit_size = (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); - dev->curr_x += ((double) rel_move / unit_size); + unit_size = (dev->print_quality == QUALITY_DRAFT || dev->lang < LANG_ESCP) ? 120.0 : 180.0; + if (dev->curr_x + ((double) rel_move / unit_size) < dev->right_margin) + dev->curr_x += ((double) rel_move / unit_size); break; - case 0x61: /* select justification (ESC a) */ + case '^': // Select 60/120-dpi, 9-pin graphics) + setup_bit_image(dev, 255 - dev->esc_parms[0], PARAM16(0)); + break; + + case 'a': /* select justification */ /* Ignore. */ break; - case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + case 'c': /* set horizontal motion index (HMI) */ dev->hmi = (double) PARAM16(0) / 360.0; dev->extra_intra_space = 0.0; break; - case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ + case 'g': /* select 10.5-point, 15-cpi */ dev->cpi = 15; dev->hmi = -1; dev->multipoint_mode = 0; @@ -1204,29 +1449,28 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing *= -1; break; - case 0x6a: // Reverse paper feed (ESC j) - reverse = (double) PARAM16(0) / (double) 216.0; - reverse = dev->curr_y - reverse; + case 'j': // Reverse paper feed (ESC j) + reverse = dev->curr_y - (double) PARAM16(0) / (double) 216.0; if (reverse < dev->left_margin) dev->curr_y = dev->left_margin; else dev->curr_y = reverse; break; - case 0x6b: /* select typeface (ESC k) */ + case 'k': /* select typeface */ if ((dev->esc_parms[0] <= 11) || (dev->esc_parms[0] == 30) || (dev->esc_parms[0] == 31)) dev->lq_typeface = dev->esc_parms[0]; update_font(dev); break; - case 0x6c: /* set left margin (ESC 1) */ + case 'l': /* set left margin */ dev->left_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; if (dev->curr_x < dev->left_margin) dev->curr_x = dev->left_margin; break; - case 0x70: /* Turn proportional mode on/off (ESC p) */ + case 'p': /* Turn proportional mode on/off */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_PROP; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[0] == '1')) { @@ -1238,18 +1482,18 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x72: /* select printing color (ESC r) */ + case 'r': /* select printing color */ if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) dev->color = COLOR_BLACK; else dev->color = dev->esc_parms[0] << 5; break; - case 0x73: /* select low-speed mode (ESC s) */ + case 's': /* select low-speed mode */ /* Ignore. */ break; - case 0x74: /* select character table (ESC t) */ + case 't': /* select character table */ case 0x849: /* Select character table (FS I) */ if (dev->esc_parms[0] < 4) { dev->curr_char_table = dev->esc_parms[0]; @@ -1260,7 +1504,7 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x77: /* turn double-height printing on/off (ESC w) */ + case 'w': /* turn double-height printing on/off */ if (!dev->multipoint_mode) { if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_DOUBLEHEIGHT; @@ -1270,7 +1514,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x78: /* select LQ or draft (ESC x) */ + case 'x': /* select LQ or draft */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) { dev->print_quality = QUALITY_DRAFT; dev->font_style |= STYLE_CONDENSED; @@ -1450,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; @@ -1465,7 +1709,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x0d: /* Carriage Return (CR) */ dev->curr_x = dev->left_margin; - if (!dev->autofeed) + if (!dev->autofeed && !dev->auto_lf) return 1; fallthrough; @@ -1497,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; @@ -1507,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) */ @@ -1520,12 +1764,15 @@ 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 commands) */ - dev->fss_seen = 1; - return 1; + case 0x1c: /* FS (IBM Proprinter II) + TODO: Make an IBM printer. */ + if (dev->lang == LANG_ESCP2) { + dev->fss_seen = true; + return 1; + } default: /* This is a printable character -> print it. */ @@ -1533,6 +1780,127 @@ process_char(escp_t *dev, uint8_t ch) } } +/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ +static void +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) +{ + const FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; + uint8_t src; + uint8_t *dst; + + /* check if freetype is available */ + if (!ft_lib) + return; + + for (unsigned int y = 0; y < bitmap->rows; y++) { + for (unsigned int x = 0; x < bitmap->width; x++) { + src = *(bitmap->buffer + x + y * bitmap->pitch); + /* ignore background, and respect page size */ + if (src > 0 && (destx + x < (unsigned) dev->page->w) && (desty + y < (unsigned) dev->page->h)) { + dst = (uint8_t *) dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; + src >>= 3; + + if (add) { + if (((*dst) & 0x1f) + src > 31) + *dst |= (dev->color | 0x1f); + else { + *dst += src; + *dst |= dev->color; + } + } else + *dst = src | dev->color; + } + } + } +} + +/* Draw anti-aliased line. */ +static void +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) +{ + unsigned breakmod = dev->dpi / 15; + unsigned gapstart = (breakmod * 4) / 5; + + for (unsigned int x = from_x; x <= to_x; x++) { + /* Skip parts if broken line or going over the border. */ + if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { + if (y > 0 && (y - 1) < dev->page->h) + *((uint8_t *) dev->page->pixels + x + (y - 1) * (unsigned) dev->page->pitch) = 240; + if (y < dev->page->h) + *((uint8_t *) dev->page->pixels + x + y * (unsigned) dev->page->pitch) = !broken ? 255 : 240; + if (y + 1 < dev->page->h) + *((uint8_t *) dev->page->pixels + x + (y + 1) * (unsigned) dev->page->pitch) = 240; + } + } +} + +static void +print_bit_graph(escp_t *dev, uint8_t ch) +{ + dev->bg_column[dev->bg_bytes_read++] = ch; + dev->bg_remaining_bytes--; + + /* Only print after reading a full column. */ + if (dev->bg_bytes_read < dev->bg_bytes_per_column) + return; + + /* vertical density is how big the dot is + * (horziontal / vertical / 2) is how many middle points between two full dots are + * if horizontal < vertical, this means a column is printed multiple times + */ + uint8_t dot_size_x; + const uint8_t dot_size_y = round((double) dev->dpi / (double) dev->bg_v_density); + if (dev->bg_h_density < dev->bg_v_density) + dot_size_x = round((double) dev->dpi / (double) dev->bg_h_density); + else + dot_size_x = dot_size_y; + + const double old_y = dev->curr_y; + + for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { + /* for each byte */ + for (uint8_t j = 128; j != 0; j >>= 1) { + if (dev->bg_v_density == 72 && i == 1 && j != 128) // 9-bit mode from ESC ^ + break; + /* for each bit */ + if (dev->bg_column[i] & j) { + if (!(dev->bg_adjacent) && (dev->bg_previous[i] & j)) { + dev->bg_column[i] &= ~j; + dev->curr_y += 1.0 / (double) dev->bg_v_density; + continue; + } + /* draw a dot */ + for (uint8_t xx = 0; xx < dot_size_x; ++xx) { + if ((PIXX + xx) >= (unsigned) dev->page->w) + break; + + for (uint8_t yy = 0; yy < dot_size_y; ++yy) { + if ((PIXY + yy) >= (unsigned) dev->page->h) + break; + + *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); + } + } + } + + dev->curr_y += 1.0 / (double) dev->bg_v_density; + } + } + + memcpy(dev->bg_previous, dev->bg_column, dev->bg_bytes_per_column * sizeof(uint8_t)); + + /* Mark page dirty. */ + dev->page->dirty = 1; + + /* Restore Y-position. */ + dev->curr_y = old_y; + + dev->bg_bytes_read = 0; + + /* Advance print head. */ + dev->curr_x += 1.0 / dev->bg_h_density; +} + static void handle_char(escp_t *dev, uint8_t ch) { @@ -1543,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); @@ -1570,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) @@ -1650,233 +2020,12 @@ handle_char(escp_t *dev, uint8_t ch) } } -/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ -static void -blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) -{ - const FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; - uint8_t src; - uint8_t *dst; - - /* check if freetype is available */ - if (ft_lib == NULL) - return; - - for (unsigned int y = 0; y < bitmap->rows; y++) { - for (unsigned int x = 0; x < bitmap->width; x++) { - src = *(bitmap->buffer + x + y * bitmap->pitch); - /* ignore background, and respect page size */ - if (src > 0 && (destx + x < (unsigned) dev->page->w) && (desty + y < (unsigned) dev->page->h)) { - dst = (uint8_t *) dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; - src >>= 3; - - if (add) { - if (((*dst) & 0x1f) + src > 31) - *dst |= (dev->color | 0x1f); - else { - *dst += src; - *dst |= dev->color; - } - } else - *dst = src | dev->color; - } - } - } -} - -/* Draw anti-aliased line. */ -static void -draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) -{ - unsigned breakmod = dev->dpi / 15; - unsigned gapstart = (breakmod * 4) / 5; - - for (unsigned int x = from_x; x <= to_x; x++) { - /* Skip parts if broken line or going over the border. */ - if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { - if (y > 0 && (y - 1) < dev->page->h) - *((uint8_t *) dev->page->pixels + x + (y - 1) * (unsigned) dev->page->pitch) = 240; - if (y < dev->page->h) - *((uint8_t *) dev->page->pixels + x + y * (unsigned) dev->page->pitch) = !broken ? 255 : 240; - if (y + 1 < dev->page->h) - *((uint8_t *) dev->page->pixels + x + (y + 1) * (unsigned) dev->page->pitch) = 240; - } - } -} - -static void -setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) -{ - escp_log("Density=%d\n", density); - switch (density) { - case 0: - dev->bg_h_density = 60; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 1: - dev->bg_h_density = 120; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 2: - dev->bg_h_density = 120; - dev->bg_v_density = 60; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 1; - break; - - case 3: - dev->bg_h_density = 60; - dev->bg_v_density = 240; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 1; - break; - - case 4: - dev->bg_h_density = 80; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 6: - dev->bg_h_density = 90; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 32: - dev->bg_h_density = 60; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 33: - dev->bg_h_density = 120; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 38: - dev->bg_h_density = 90; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 39: - dev->bg_h_density = 180; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 40: - dev->bg_h_density = 360; - dev->bg_v_density = 180; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 3; - break; - - case 71: - dev->bg_h_density = 180; - dev->bg_v_density = 360; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 6; - break; - - case 72: - dev->bg_h_density = 360; - dev->bg_v_density = 360; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 6; - break; - - case 73: - dev->bg_h_density = 360; - dev->bg_v_density = 360; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 6; - break; - - default: - escp_log("ESC/P: Unsupported bit image density %d.\n", density); - break; - } - - dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; - dev->bg_bytes_read = 0; -} - -static void -print_bit_graph(escp_t *dev, uint8_t ch) -{ - uint8_t pixel_w; /* width of the "pixel" */ - uint8_t pixel_h; /* height of the "pixel" */ - double old_y; - - dev->bg_column[dev->bg_bytes_read++] = ch; - dev->bg_remaining_bytes--; - - /* Only print after reading a full column. */ - if (dev->bg_bytes_read < dev->bg_bytes_per_column) - return; - - old_y = dev->curr_y; - - pixel_w = 1; - pixel_h = 1; - - if (dev->bg_adjacent) { - /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ - pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; - pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; - } - - for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { - /* for each byte */ - for (uint8_t j = 128; j != 0; j >>= 1) { - /* for each bit */ - if (dev->bg_column[i] & j) { - /* draw a "pixel" */ - for (uint8_t xx = 0; xx < pixel_w; xx++) { - for (uint8_t yy = 0; yy < pixel_h; yy++) { - if (((PIXX + xx) < (unsigned) dev->page->w) && ((PIXY + yy) < (unsigned) dev->page->h)) - *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); - } - } - } - - dev->curr_y += 1.0 / (double) dev->bg_v_density; - } - } - - /* Mark page dirty. */ - dev->page->dirty = 1; - - /* Restore Y-position. */ - dev->curr_y = old_y; - - dev->bg_bytes_read = 0; - - /* Advance print head. */ - dev->curr_x += 1.0 / dev->bg_h_density; -} - static void write_data(uint8_t val, void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; dev->data = val; @@ -1887,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 @@ -1904,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); @@ -1916,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); } @@ -1945,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); @@ -1984,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); } } @@ -1998,6 +2147,8 @@ escp_init(const device_t *info) dev->lpt = lpt_attach(write_data, write_ctrl, strobe, read_status, read_ctrl, NULL, NULL, dev); + dev->lang = device_get_config_int("language"); + rom_get_full_path(dev->fontpath, "roms/printer/fonts/"); /* Create a full pathname for the font files. */ @@ -2005,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. */ @@ -2014,9 +2165,30 @@ escp_init(const device_t *info) plat_dir_create(dev->pagepath); path_slash(dev->pagepath); - dev->page_width = PAGE_WIDTH; - dev->page_height = PAGE_HEIGHT; - dev->dpi = PAGE_DPI; + dev->paper_size = device_get_config_int("paper_size"); + + switch (dev->paper_size) { + case PAPER_A4: + dev->page_width = A4_PAGE_WIDTH; + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + dev->page_width = LEGAL_PAGE_HEIGHT; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + dev->page_width = B4_PAGE_HEIGHT; + break; + case PAPER_LETTER: + default: + dev->page_width = LETTER_PAGE_WIDTH; + dev->page_height = LETTER_PAGE_HEIGHT; + } + + dev->auto_lf = device_get_config_int("auto_lf"); + + dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *) malloc(sizeof(psurface_t)); @@ -2027,14 +2199,13 @@ escp_init(const device_t *info) memset(dev->page->pixels, 0x00, (size_t) dev->page->pitch * dev->page->h); /* Initialize parameters. */ + /* 0 = all white needed for logic 000 */ for (uint8_t i = 0; i < 32; i++) { dev->palcol[i].r = 255; dev->palcol[i].g = 255; dev->palcol[i].b = 255; } - /* 0 = all white needed for logic 000 */ - fill_palette(0, 0, 0, 1, dev); /* 1 = magenta* 001 */ fill_palette(0, 255, 0, 1, dev); /* 2 = cyan* 010 */ @@ -2052,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); @@ -2070,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); } @@ -2088,8 +2259,26 @@ escp_close(void *priv) } // clang-format off -#if 0 static const device_config_t lpt_prt_escp_config[] = { + { + .name = "language", + .description = "Language", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = LANG_ESCP2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "EX-1000", .value = LANG_EX1000 }, +#if 0 + { .description = "9-pin", .value = LANG_9PIN }, + { .description = "ESC/P", .value = LANG_ESCP }, +#endif + { .description = "ESC/P 2", .value = LANG_ESCP2 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "paper_size", .description = "Paper Size", @@ -2099,15 +2288,42 @@ static const device_config_t lpt_prt_escp_config[] = { .file_filter = NULL, .spinner = { 0 }, .selection = { - { .description = "Letter", .value = 0 }, - { .description = "A4", .value = 1 }, + { .description = "Letter", .value = PAPER_LETTER }, + { .description = "A4", .value = PAPER_A4 }, + { .description = "Legal (sideways)", .value = PAPER_LEGAL_SIDE }, + { .description = "B4 (sideways)", .value = PAPER_B4_SIDE }, { .description = "" } }, .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", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } }; -#endif // clang-format on const device_t lpt_prt_escp_device = { @@ -2121,9 +2337,5 @@ const device_t lpt_prt_escp_device = { .available = NULL, .speed_changed = NULL, .force_redraw = NULL, -#if 0 .config = lpt_prt_escp_config -#else - .config = NULL -#endif }; diff --git a/src/qt/icons/active.ico b/src/qt/icons/active.ico index 9569a3962..ebd5bb452 100644 Binary files a/src/qt/icons/active.ico and b/src/qt/icons/active.ico differ diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 5dccc6e54..d0e649bc2 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -55,10 +55,10 @@ msgid "&Resizeable window" msgstr "G&rößenverstellbares Fenster" msgid "R&emember size && position" -msgstr "Größe && &Position merken" +msgstr "Größe und &Position merken" msgid "Remember size && position" -msgstr "Größe && Position merken" +msgstr "Größe und Position merken" msgid "Re&nderer" msgstr "Re&nderer" @@ -742,10 +742,10 @@ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video msgstr "Die Videokarte \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird auf eine verfügbare Videokarte gewechselt." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "Das Gerät \"%hs\" ist aufgrund von fehlenden ROMs nicht verfügbar. Es wird ignoriert." +msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird deaktiviert." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." -msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird deaktiviert." +msgstr "Das Gerät \"%hs\" ist aufgrund von fehlenden ROMs nicht verfügbar. Es wird ignoriert." msgid "Machine" msgstr "System" @@ -2848,10 +2848,10 @@ msgid "Hostname:" msgstr "Hostname:" msgid "ISA RAM:" -msgstr "" +msgstr "ISA RAM:" msgid "ISA ROM:" -msgstr "" +msgstr "ISA ROM:" msgid "&Wipe NVRAM" msgstr "NVRAM leeren" @@ -2869,7 +2869,7 @@ msgid "An error occurred trying to wipe the NVRAM contents of the virtual machin msgstr "Beim Leeren des NVRAMs der virtuellen Maschine ist ein Fehler aufgetreten \"%1\"" msgid "%1 VM Manager" -msgstr "" +msgstr "%1 VM Manager" msgid "%n disk(s)" msgstr "%n Festplatte(n)" diff --git a/src/qt/languages/el-GR.po b/src/qt/languages/el-GR.po index 6933075a5..1442183df 100644 --- a/src/qt/languages/el-GR.po +++ b/src/qt/languages/el-GR.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-01-26 17:57+0000\n" +"PO-Revision-Date: 2026-02-04 18:32+0000\n" "Last-Translator: DimMan88 \n" "Language-Team: Greek \n" "Language: el-GR\n" @@ -61,7 +61,7 @@ msgid "Remember size && position" msgstr "Απομνήμευση μεγέθους && θέσης" msgid "Re&nderer" -msgstr "Re&nderer" +msgstr "&Απεικονιστής" msgid "&Qt (Software)" msgstr "&Qt (Software)" @@ -397,7 +397,7 @@ msgid "Enabled (UTC)" msgstr "Ενεργό (UTC)" msgid "Dynamic Recompiler" -msgstr "Dynamic Recompiler" +msgstr "Δυναμικός Αναμεταγλωττιστής" msgid "CPU frame size" msgstr "Μέγεθος πλαισίου CPU" @@ -619,7 +619,7 @@ msgid "Image Format:" msgstr "Τύπος Εικόνας:" msgid "Block Size:" -msgstr "Block Size:" +msgstr "Μέγεθος Block:" msgid "Floppy drives:" msgstr "Οδηγοί δισκέτας:" @@ -721,10 +721,10 @@ msgid "Turbo" msgstr "Turbo" msgid "On" -msgstr "On" +msgstr "Ενεργό" msgid "Off" -msgstr "Off" +msgstr "Ανενεργό" msgid "All images" msgstr "Όλες οι εικόνες" @@ -1080,7 +1080,7 @@ msgid "Cartridge %1: %2" msgstr "Κασέτα δεδομένων %1: %2" msgid "Car&tridge %1: %2" -msgstr "Car&tridge %1: %2" +msgstr "&Κασέτα δεδομένων %1: %2" msgid "Cartridge images" msgstr "Εικόνες κασέτας δεδομένων" @@ -1460,13 +1460,13 @@ msgid "HDX image" msgstr "Εικόνα HDX" msgid "Fixed-size VHD" -msgstr "Fixed-size VHD" +msgstr "Σταθερό-μέγεθος VHD" msgid "Dynamic-size VHD" -msgstr "Dynamic-size VHD" +msgstr "Δυναμικό-μέγεθος VHD" msgid "Differencing VHD" -msgstr "Differencing VHD" +msgstr "Διαφοροποίηση VHD" msgid "(N/A)" msgstr "(Μ/Δ)" @@ -1481,19 +1481,19 @@ msgid "HDX image (.hdx)" msgstr "Εικόνα HDX (.hdx)" msgid "Fixed-size VHD (.vhd)" -msgstr "Fixed-size VHD (.vhd)" +msgstr "Σταθερό-μέγεθος VHD (.vhd)" msgid "Dynamic-size VHD (.vhd)" -msgstr "Dynamic-size VHD (.vhd)" +msgstr "Δυναμικό-μέγεθος VHD (.vhd)" msgid "Differencing VHD (.vhd)" -msgstr "Differencing VHD (.vhd)" +msgstr "Διαφοροποίηση VHD (.vhd)" msgid "Large blocks (2 MB)" -msgstr "Large blocks (2 MB)" +msgstr "Μεγάλα blocks (2 MB)" msgid "Small blocks (512 KB)" -msgstr "Small blocks (512 KB)" +msgstr "Μικρά blocks (512 KB)" msgid "VHD files" msgstr "Αρχεία VHD" @@ -2964,7 +2964,7 @@ msgid "version" msgstr "έκδοση" msgid "build" -msgstr "build" +msgstr "δομή" msgid "You are currently running version %1." msgstr "Τρέχετε την έκδοση %1." diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po index fdc71fcb1..b2dc80dd7 100644 --- a/src/qt/languages/en-GB.po +++ b/src/qt/languages/en-GB.po @@ -15,6 +15,9 @@ msgstr "&RGB Greyscale" msgid "Generic RGBI color monitor" msgstr "Generic RGBI colour monitor" +msgid "Grayscale &conversion type" +msgstr "Greyscale &conversion type" + msgid "Time synchronization" msgstr "Time synchronisation" @@ -28,7 +31,7 @@ msgid "Failed to initialize network driver" msgstr "Failed to initialise network driver" msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." -msgstr "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behaviour will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." +msgstr "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behaviour should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behaviour will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Appl&y fullscreen stretch mode when maximised" @@ -78,9 +81,18 @@ msgstr "Enhanced Colour - Enhanced Mode (5154/ECD)" msgid "Gray" msgstr "Grey" +msgid "Grayscale" +msgstr "Greyscale" + msgid "Color" msgstr "Colour" +msgid "Color Interlaced" +msgstr "Colour Interlaced" + +msgid "Color Non-Interlaced" +msgstr "Colour Non-Interlaced" + msgid "Failed to initialize Vulkan renderer." msgstr "Failed to initialise Vulkan renderer." diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 4f34c34f5..af2e1e75e 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2025-11-29 00:34+0000\n" -"Last-Translator: OBattler \n" +"PO-Revision-Date: 2026-02-06 05:57+0000\n" +"Last-Translator: Jeffrey Hope \n" "Language-Team: Spanish \n" "Language: es-ES\n" "MIME-Version: 1.0\n" @@ -1108,7 +1108,7 @@ msgid "Not running" msgstr "No en ejecución" msgid "Running" -msgstr "En ejeución" +msgstr "En ejecución" msgid "Paused" msgstr "En pausa" diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 9d55ba7ca..fd4bc5610 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -400,7 +400,8 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) ret = CallNextHookEx(NULL, nCode, wParam, lParam); if (lpKdhs->scanCode == 0x00000045) { - if ((lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000090)) { + if ((lpKdhs->flags & LLKHF_EXTENDED) && ((lpKdhs->vkCode == 0x00000090) || + (lpKdhs->vkCode == 0x00000013))) { /* NumLock. */ lpKdhs->flags &= ~LLKHF_EXTENDED; } else if (!(lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000013)) { @@ -621,7 +622,7 @@ main(int argc, char *argv[]) fprintf(stderr, "Qt: version %s, platform \"%s\"\n", qVersion(), QApplication::platformName().toUtf8().data()); ProgSettings::loadTranslators(&app); #ifdef Q_OS_WINDOWS - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); SetCurrentProcessExplicitAppUserModelID(L"86Box.86Box"); #endif diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index f6195389c..1133b26c0 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -2431,7 +2431,7 @@ MainWindow::changeEvent(QEvent *event) #ifdef Q_OS_WINDOWS if (event->type() == QEvent::LanguageChange) { auto size = this->centralWidget()->size(); - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); QApplication::processEvents(); main_window->centralWidget()->setFixedSize(size); QApplication::processEvents(); 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; } diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 62b63bbcc..9be40c1cb 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -28,6 +28,8 @@ #ifdef Q_OS_WINDOWS # include # include +# define WIN32_LEAN_AND_MEAN +# include #endif extern "C" { @@ -157,27 +159,67 @@ ProgSettings::~ProgSettings() delete ui; } +static QString sys_lang; + #ifdef Q_OS_WINDOWS -/* Return the standard font name on Windows, which is overridden per-language - to prevent CJK fonts with embedded bitmaps being chosen as a fallback. */ -QString -ProgSettings::getFontName(int langId) +/* Returns the standard UI font for Windows, which by default varies for different + languages. It can also be changed via external tools, if the user wants that. + + We use the message font here since that is what most Windows components and + other third-party programs use. */ +QFont +ProgSettings::getUIFont() { QString langCode = languageIdToCode(lang_id); - if (langCode == "ja-JP") { - /* Check for Windows 10 or later to choose the appropriate system font */ - if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) - return "Yu Gothic UI"; - else - return "Meiryo UI"; - } else if (langCode == "ko-KR") - return "Malgun Gothic"; - else if (langCode == "zh-CN") - return "Microsoft YaHei"; - else if (langCode == "zh-TW") - return "Microsoft JhengHei"; - else - return "Segoe UI"; + + if ((langCode != sys_lang) && ((langCode == "ja-JP") || (langCode == "ko-KR") || + (langCode == "zh-CN") || (langCode == "zh-TW"))) { + /* + Work around Windows' inappropriate, ugly default fonts when using an East Asian + language when it is not also the system language. + */ + if (langCode == "ja-JP") { + /* Check for Windows 10 or later to choose the appropriate system font */ + if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) + return QFont("Yu Gothic UI", 9); + else + return QFont("Meiryo UI", 9); + } else if (langCode == "ko-KR") + return QFont("Malgun Gothic", 9); + else if (langCode == "zh-CN") + return QFont("Microsoft YaHei", 9); + else if (langCode == "zh-TW") + return QFont("Microsoft JhengHei", 9); + } + + // Get the system (primary monitor) DPI. The font returned by + // SystemParametersInfo is scaled according to this and we need + // to get the font size in points to pass into QFont's constructor. + HDC hdc = GetDC(NULL); + int systemDpi = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(NULL, hdc); + + // Get the font metrics. + NONCLIENTMETRICSW ncm = {}; + ncm.cbSize = sizeof(ncm); + // This should never happen, but just to be safe, return Segoe UI if + // SPI fails. + if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) + { + return QFont("Segoe UI", 9); + } + + QString fontName = QString::fromWCharArray(ncm.lfMessageFont.lfFaceName); + // Windows' conversion from points to pixels goes as follows: + // + // -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72) + // + // (source: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfontw) + // + // Let's reverse that calculation to get the point size from the message font. + int fontSize = -MulDiv(ncm.lfMessageFont.lfHeight, 72, systemDpi); + + return QFont(fontName, fontSize); } #endif @@ -201,9 +243,42 @@ ProgSettings::languageIdToCode(int id) return languages[id].first; } +void +ProgSettings::getSysLang(QObject *parent) +{ + if (qtTranslator) { + QApplication::removeTranslator(qtTranslator); + qtTranslator = nullptr; + } + if (translator) { + QApplication::removeTranslator(translator); + translator = nullptr; + } + qtTranslator = new QTranslator(parent); + translator = new CustomTranslator(parent); + QString localetofilename = ""; + for (int i = 0; i < QLocale::system().uiLanguages().size(); i++) { + localetofilename = QLocale::system().uiLanguages()[i]; + if (translator->load(QLatin1String("86box_") + localetofilename, QLatin1String(":/"))) { + qDebug() << "Translations loaded."; + QCoreApplication::installTranslator(translator); + /* First try qtbase */ + if (!loadQtTranslations(QLatin1String("qtbase_") + localetofilename.replace('-', '_'))) + /* If that fails, try legacy qt_* translations */ + if (!loadQtTranslations(QLatin1String("qt_") + localetofilename.replace('-', '_'))) + qDebug() << "Failed to find Qt translations!"; + if (QCoreApplication::installTranslator(qtTranslator)) + qDebug() << "Qt translations loaded."; + sys_lang = localetofilename; + break; + } + } +} + void ProgSettings::loadTranslators(QObject *parent) { + getSysLang(parent); if (qtTranslator) { QApplication::removeTranslator(qtTranslator); qtTranslator = nullptr; diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index 2ada8c2bf..cebfa8177 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -15,10 +15,11 @@ public: explicit ProgSettings(QWidget *parent = nullptr); ~ProgSettings(); #ifdef Q_OS_WINDOWS - static QString getFontName(int langId); + static QFont getUIFont(); #endif static int languageCodeToId(QString langCode); static QString languageIdToCode(int id); + static void getSysLang(QObject *parent = nullptr); static void loadTranslators(QObject *parent = nullptr); static void reloadStrings(); class CustomTranslator : public QTranslator { diff --git a/src/qt/qt_settings.cpp b/src/qt/qt_settings.cpp index 312b48996..d1c25a014 100644 --- a/src/qt/qt_settings.cpp +++ b/src/qt/qt_settings.cpp @@ -44,6 +44,9 @@ extern "C" { #include #include +#include +#include + class SettingsModel : public QAbstractListModel { public: SettingsModel(QObject *parent) @@ -236,5 +239,36 @@ Settings::accept() return; } } + QDialog::accept(); } + +static int +plat_path_is_empty(char *path) +{ + int n = 0; + DIR *dir = opendir(path); + struct dirent *d; + + if (dir == NULL) + /* Not a directory or doesn't exist. */ + return 1; + + while ((d = readdir(dir)) != NULL) { + if (++n > 2) + break; + } + + closedir(dir); + + return (n <= 2); +} + +void +Settings::reject() +{ + if (plat_path_is_empty(usr_path)) + rmdir(usr_path); + + QDialog::reject(); +} diff --git a/src/qt/qt_settings.hpp b/src/qt/qt_settings.hpp index 8603c42b6..b64ea8e83 100644 --- a/src/qt/qt_settings.hpp +++ b/src/qt/qt_settings.hpp @@ -30,6 +30,7 @@ public: static Settings *settings; protected slots: void accept() override; + void reject() override; private: Ui::Settings *ui; diff --git a/src/qt/qt_vmmanager_details.cpp b/src/qt/qt_vmmanager_details.cpp index 40d0fb185..300e227e2 100644 --- a/src/qt/qt_vmmanager_details.cpp +++ b/src/qt/qt_vmmanager_details.cpp @@ -165,7 +165,7 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) connect(this, &VMManagerDetails::styleUpdated, portsSection, &VMManagerDetailSection::updateStyle); connect(this, &VMManagerDetails::styleUpdated, otherSection, &VMManagerDetailSection::updateStyle); - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); #endif sysconfig = new VMManagerSystem(); diff --git a/src/qt/qt_vmmanager_mainwindow.cpp b/src/qt/qt_vmmanager_mainwindow.cpp index 17bd898bd..a52002653 100644 --- a/src/qt/qt_vmmanager_mainwindow.cpp +++ b/src/qt/qt_vmmanager_mainwindow.cpp @@ -269,7 +269,7 @@ VMManagerMainWindow::changeEvent(QEvent *event) { #ifdef Q_OS_WINDOWS if (event->type() == QEvent::LanguageChange) { - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(QFont(ProgSettings::getUIFont())); } #endif QWidget::changeEvent(event); diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 44e328842..181d2158e 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -411,19 +411,6 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) goto readonly_i; } - /* HACK: the Windows 9x driver's "Synth" control writes to this - register with no remapping, even if internal FM is enabled. */ - if (ad1848->index == 18) { - if (val & 0x80) - ad1848->fm_vol_l = 0; - else - ad1848->fm_vol_l = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; - } else { - if (val & 0x80) - ad1848->fm_vol_r = 0; - else - ad1848->fm_vol_r = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; - } } if ((ad1848->type >= AD1848_TYPE_CS4232) && (ad1848->type <= AD1848_TYPE_CS4236)) { if (ad1848->index == 18) { diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index b9004454e..264171b1e 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -290,7 +290,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) ad1848_init(&dev->ad1848, dev->ad1848_type); ad1848_set_cd_audio_channel(&dev->ad1848, AD1848_AUX2); } - val = 0x00; + val &= 0x07; break; case 1: /* Version / Chip ID */ diff --git a/src/sound/snd_pssj.c b/src/sound/snd_pssj.c index 7de8ec824..1b10fdd8d 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -55,8 +55,10 @@ pssj_write(uint16_t port, uint8_t val, void *priv) if (!pssj->enable) timer_disable(&pssj->timer_count); sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); - if (!(val & 8)) + if (!(val & 8)) { pssj->irq = 0; + picintc(1 << 7); + } pssj_update_irq(pssj); break; case 1: @@ -78,7 +80,7 @@ pssj_write(uint16_t port, uint8_t val, void *priv) break; case 3: pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8); - pssj->amplitude = val >> 4; + pssj->amplitude = (val & 0xef) >> 4; break; default: diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 872743b72..d44d9e9d8 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -45,7 +45,7 @@ # undef CLAMP #endif -#define BIOS_MACH8_ROM_PATH "roms/video/mach8/11301113140_ROM.BIN" +#define BIOS_MACH8_ROM_PATH "roms/video/mach8/11301113140_4k.BIN" static void ibm8514_accel_outb(uint16_t port, uint8_t val, void *priv); static void ibm8514_accel_outw(uint16_t port, uint16_t val, void *priv); @@ -1197,8 +1197,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat old_mix_dat = mix_dat; - if (cmd != 0) - ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x, ssvdraw=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06, dev->accel.ssv_draw); + ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x, ssvdraw=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06, dev->accel.ssv_draw); /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on @@ -1215,41 +1214,43 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - src_dat = 0; - break; + if (ibm8514_cpu_src(svga) || !cpu_input) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; - default: - break; - } + default: + break; + } - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - if ((compare_mode == 0) || - ((compare_mode == 0x10) && (dest_dat >= compare)) || - ((compare_mode == 0x18) && (dest_dat < compare)) || - ((compare_mode == 0x20) && (dest_dat != compare)) || - ((compare_mode == 0x28) && (dest_dat == compare)) || - ((compare_mode == 0x30) && (dest_dat <= compare)) || - ((compare_mode == 0x38) && (dest_dat > compare))) { - old_dest_dat = dest_dat; - MIX(mix_dat & mix_mask, dest_dat, src_dat); - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if (dev->accel.ssv_draw) { - if ((dev->accel.cmd & 0x04) && dev->accel.ssv_len) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if (dev->accel.ssv_draw) { + if ((dev->accel.cmd & 0x04) && dev->accel.ssv_len) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } } } } @@ -1837,20 +1838,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { - mix_dat = mix_mask; /* Mix data = forced to foreground register. */ - } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { - /* Mix data = current video memory value. */ - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, mix_dat); - mix_dat = ((mix_dat & rd_mask) == rd_mask); - mix_dat = mix_dat ? mix_mask : 0; - } - - if (ibm8514_cpu_dest(svga)) { - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, src_dat); - if (pixcntl == 3) - src_dat = ((src_dat & rd_mask) == rd_mask); - } else + if (ibm8514_cpu_src(svga) || !cpu_input) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1869,21 +1857,18 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat break; } - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - if ((compare_mode == 0) || - ((compare_mode == 0x10) && (dest_dat >= compare)) || - ((compare_mode == 0x18) && (dest_dat < compare)) || - ((compare_mode == 0x20) && (dest_dat != compare)) || - ((compare_mode == 0x28) && (dest_dat == compare)) || - ((compare_mode == 0x30) && (dest_dat <= compare)) || - ((compare_mode == 0x38) && (dest_dat > compare))) { - old_dest_dat = dest_dat; - MIX(mix_dat & mix_mask, dest_dat, src_dat); - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if ((dev->accel.cmd & 0x04) && dev->accel.sy) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); } } @@ -4038,10 +4023,8 @@ ibm8514_vblank_start(void *priv) static void * ibm8514_init(const device_t *info) { - FILE *fp; - uint8_t *rom_load = NULL; - uint32_t bios_addr = 0; uint16_t bios_rom_eeprom = 0x0000; + uint32_t bios_addr; if (svga_get_pri() == NULL) return NULL; @@ -4067,37 +4050,34 @@ ibm8514_init(const device_t *info) dev->bpp = 0; dev->extensions = device_get_config_int("extensions"); - bios_addr = device_get_config_hex20("bios_addr"); + dev->bios_addr = device_get_config_hex20("bios_addr"); if (dev->type & DEVICE_MCA) - bios_addr = 0xc6800; + dev->bios_addr = 0xc6800; switch (dev->extensions) { case ATI: if (rom_present(BIOS_MACH8_ROM_PATH)) { mach_t * mach = (mach_t *) calloc(1, sizeof(mach_t)); svga->ext8514 = mach; - fp = rom_fopen(BIOS_MACH8_ROM_PATH, "rb"); - if (bios_addr & 0x800) - (void) fseek(fp, 0x000, SEEK_SET); - else - (void) fseek(fp, 0x800, SEEK_SET); + bios_addr = dev->bios_addr; - rom_load = malloc(0x2000); - (void) !fread(rom_load, 0x2000, 1, fp); - (void) fclose(fp); - memset(&dev->bios_rom, 0x00, sizeof(rom_t)); + dev->bios_rom.rom = malloc(0x2000); + memset(dev->bios_rom.rom, 0xff, 0x2000); - dev->bios_rom.rom = rom_load; + (void) rom_load_linear(BIOS_MACH8_ROM_PATH, bios_addr, 0x2000, 0x0000, dev->bios_rom.rom + (bios_addr & 0x0800)); + dev->bios_rom.sz = 0x2000; dev->bios_rom.mask = 0x1fff; - mem_mapping_add(&dev->bios_rom.mapping, bios_addr, 0x2000, - ati8514_rom_readb, ati8514_rom_readw, NULL, + + mem_mapping_add(&dev->bios_rom.mapping, bios_addr, dev->bios_rom.sz, + ati8514_bios_rom_readb, ati8514_bios_rom_readw, ati8514_bios_rom_readl, NULL, NULL, NULL, dev->bios_rom.rom, MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM_WS, dev); + ati8514_init(svga, svga->ext8514, svga->dev8514); if (dev->type & DEVICE_MCA) { - dev->accel.scratch0 = (((bios_addr >> 7) - 0x1000) >> 4); - dev->accel.scratch0 |= ((dev->accel.scratch0 + 0x01) << 8); - bios_rom_eeprom = dev->accel.scratch0; + mach->accel.scratch0 = (((dev->bios_addr >> 7) - 0x1000) >> 4); + mach->accel.scratch0 |= ((mach->accel.scratch0 + 0x01) << 8); + bios_rom_eeprom = mach->accel.scratch0; dev->pos_regs[0] = 0x88; dev->pos_regs[1] = 0x80; mach->eeprom.data[1] = bios_rom_eeprom; @@ -4105,8 +4085,9 @@ ibm8514_init(const device_t *info) ati_eeprom_load_mach8(&mach->eeprom, "ati8514_mca.nvr", 1); mem_mapping_disable(&dev->bios_rom.mapping); } else { - dev->accel.scratch0 = ((bios_addr >> 7) - 0x1000) >> 4; - dev->accel.scratch0 |= ((dev->accel.scratch0 + 0x01) << 8); + mach->accel.scratch0 = ((dev->bios_addr >> 7) - 0x1000) >> 4; + mach->accel.scratch0 |= ((mach->accel.scratch0 + 0x01) << 8); + ibm8514_log("Scratch0 init val=%04x, bios=%06x, base=%06x.\n", mach->accel.scratch0, dev->bios_addr, dev->bios_rom.mapping.base); ati_eeprom_load_mach8(&mach->eeprom, "ati8514.nvr", 0); } break; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index fff9bce3e..ab38e26f6 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -333,7 +333,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } } - mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x, cur_x = %d, cur_y = %d, cl = %d, cr = %d, ct = %d, cb = %d, accel_bpp = %d, pitch = %d, hicolbpp = %d, pattlen = %d.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config, dev->accel.cur_x, dev->accel.cur_y, clip_l, clip_r, clip_t, clip_b, dev->accel_bpp, dev->pitch, dev->bpp, mach->accel.patt_len); + if (cmd_type == 1 || cmd_type == 3 || cmd_type == 4) { + if (mach->accel.linedraw_opt & 0x04) + mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x, cur_x = %d, cur_y = %d, cl = %d, cr = %d, ct = %d, cb = %d, accel_bpp = %d, pitch = %d, hicolbpp = %d, pattlen = %d.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config, dev->accel.cur_x, dev->accel.cur_y, clip_l, clip_r, clip_t, clip_b, dev->accel_bpp, dev->pitch, dev->bpp, mach->accel.patt_len); + } switch (cmd_type) { case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ @@ -437,88 +440,84 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); if (mono_src == 3) src_dat = (src_dat & rd_mask) == rd_mask; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; - - default: - break; - } - - if (mach->accel.linedraw_opt & 0x02) { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); - poly_src = ((poly_src & rd_mask) == rd_mask); - if (poly_src) - mach->accel.poly_fill = !mach->accel.poly_fill; - } - - if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { - READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); - - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; break; case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (!compare) { - if (mach_pixel_write(mach)) { + if (mach->accel.linedraw_opt & 0x02) { + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill = !mach->accel.poly_fill; + } + + if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { + READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; + + default: + break; + } + + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - if (mach->accel.linedraw_opt & 0x04) { - if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + if (mach->accel.dp_config & 0x10) { + if (mach->accel.linedraw_opt & 0x04) { + if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } } @@ -647,89 +646,84 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) - src_dat = cpu_dat; - else { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); - if (mono_src == 3) { - src_dat = (src_dat & rd_mask) == rd_mask; - } - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; - - default: - break; - } - - if (mach->accel.linedraw_opt & 0x02) { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); - poly_src = ((poly_src & rd_mask) == rd_mask); - if (poly_src) - mach->accel.poly_fill = !mach->accel.poly_fill; - } - - if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { - READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); - - switch (compare_mode) { + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; case 1: - compare = 1; + src_dat = frgd_color; break; case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + src_dat = cpu_dat; break; case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); + if (mono_src == 3) + src_dat = (src_dat & rd_mask) == rd_mask; break; case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (!compare) { - if (mach_pixel_write(mach)) { + if (mach->accel.linedraw_opt & 0x02) { + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill = !mach->accel.poly_fill; + } + + if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { + READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; + + default: + break; + } + + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - if (mach->accel.linedraw_opt & 0x04) { - if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + if (mach->accel.dp_config & 0x10) { + if (mach->accel.linedraw_opt & 0x04) { + if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } } @@ -906,23 +900,27 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.sx_end > mach->accel.sx_start) { mach->accel.src_width = (mach->accel.sx_end - mach->accel.sx_start); mach->accel.src_stepx = 1; - mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + if (mach->accel.dp_config == 0x6011) + mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d, srcpitch = %d, dstpitch = %d, dststepx = %d, dststepy = %d, dx = %d, dy = %d.\n", mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_start, mach->accel.src_x_end, - mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1, mach->accel.src_pitch, mach->accel.dst_pitch, mach->accel.stepx, mach->accel.stepy, dev->accel.dx, dev->accel.dy); } else if (mach->accel.sx_end < mach->accel.sx_start) { mach->accel.src_width = (mach->accel.sx_start - mach->accel.sx_end); mach->accel.src_stepx = -1; if (dev->accel.cx > 0) dev->accel.cx--; - mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", - mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, - mach->accel.src_width & 1); + + if (mach->accel.dp_config == 0x6011) + mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, + mach->accel.src_width & 1); } else { mach->accel.src_stepx = 1; mach->accel.src_width = 0; - mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", - mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, - mach->accel.dp_config, mach->accel.src_width & 1); + if (mach->accel.dp_config == 0x6011) + mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, + mach->accel.dp_config, mach->accel.src_width & 1); } mach->accel.sx = 0; if (mach->accel.patt_data_idx < 0x10) @@ -1075,98 +1073,94 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - if (mach->accel.dp_config & 0x02) { - READ(dev->accel.src + dev->accel.cx, poly_src); - poly_src = ((poly_src & rd_mask) == rd_mask); - if (poly_src) - mach->accel.poly_fill ^= 1; - } + if (mach_pixel_write(mach) || !cpu_input) { + if (mach->accel.dp_config & 0x02) { + READ(dev->accel.src + dev->accel.cx, poly_src); + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill ^= 1; + } - if (mach->accel.poly_fill || !(mach->accel.dp_config & 0x02)) { - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach->accel.poly_fill || !(mach->accel.dp_config & 0x02)) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); if (mono_src == 3) src_dat = (src_dat & rd_mask) == rd_mask; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; + + default: + break; + } + + if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { + if (dev->accel.sy & 1) { + READ(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); + } else { + READ(dev->accel.dest + dev->accel.dx, dest_dat); } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; - - default: - break; - } - - if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { - if (dev->accel.sy & 1) { - READ(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); } else { READ(dev->accel.dest + dev->accel.dx, dest_dat); } - } else { - READ(dev->accel.dest + dev->accel.dx, dest_dat); - } - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { - if (dev->accel.sy & 1) { - WRITE(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); + if (mach->accel.dp_config & 0x10) { + if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { + if (dev->accel.sy & 1) { + WRITE(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); + } else { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } } else { WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } - } else { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } } } @@ -1186,15 +1180,29 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if ((mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02)) { dev->accel.cx += mach->accel.src_stepx; mach->accel.sx++; - if (mach->accel.sx >= mach->accel.src_width) { - mach->accel.sx = 0; - if (mach->accel.src_stepx == -1) - dev->accel.cx += mach->accel.src_width; - else - dev->accel.cx -= mach->accel.src_width; + if (mach->accel.dp_config == 0x6011) { + mach_log("DX=%d, DY=%d, SX=%d, SY=%d, SRCSX=%d, SRCWIDTH=%d, CX=%d, CY=%d, srcydir=%d, srcoffset=%08x.\n", dev->accel.dx, dev->accel.dy, dev->accel.sx, dev->accel.sy, mach->accel.sx - 1, mach->accel.src_width, dev->accel.cx - mach->accel.src_stepx, dev->accel.cy, mach->accel.src_y_dir, mach->accel.src_ge_offset); + if (mach->accel.sx >= mach->accel.src_width) { + mach->accel.sx = 0; + if (mach->accel.src_stepx == -1) + dev->accel.cx += mach->accel.src_width; + else + dev->accel.cx -= mach->accel.src_width; - dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); - dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); + dev->accel.cy += mach->accel.stepy; + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); + } + } else { + if (mach->accel.sx >= mach->accel.src_width) { + mach->accel.sx = 0; + if (mach->accel.src_stepx == -1) + dev->accel.cx += mach->accel.src_width; + else + dev->accel.cx -= mach->accel.src_width; + + dev->accel.cy += mach->accel.src_y_dir; + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); + } } } @@ -1211,7 +1219,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.dx += mach->accel.stepx; dev->accel.sx++; if ((dev->accel.sx >= mach->accel.width) || (dev->accel.dx >= 0x600)) { - dev->accel.sx = 0; + dev->accel.sx = 0; if (mach->accel.stepx == -1) dev->accel.dx += mach->accel.width; else @@ -1318,71 +1326,68 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else + break; + case 3: src_dat = 0; - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } } } else mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); @@ -1448,86 +1453,82 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - if (mach->accel.linedraw_opt & 0x02) { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); - if (poly_src) - mach->accel.poly_fill ^= 1; - } + if (mach_pixel_write(mach) || !cpu_input) { + if (mach->accel.linedraw_opt & 0x02) { + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); + if (poly_src) + mach->accel.poly_fill ^= 1; + } - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: src_dat = 0; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { MIX(mix, dest_dat, src_dat); } dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - if (mach->accel.linedraw_opt & 0x04) { - if (dev->accel.sx < mach->accel.width) { + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } } else @@ -1583,73 +1584,69 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: src_dat = 0; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } } } else mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); @@ -1715,78 +1712,74 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: src_dat = 0; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - if (mach->accel.linedraw_opt & 0x04) { - if (dev->accel.sx < mach->accel.width) { + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } } else @@ -2016,7 +2009,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 cx--; } - cy += (mach->accel.src_y_dir ? 1 : -1); + cy += mach->accel.src_y_dir; dev->accel.src = mach->accel.src_ge_offset + (cy * mach->accel.src_pitch); } @@ -2099,75 +2092,71 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); if (mono_src == 3) src_dat = (src_dat & rd_mask) == rd_mask; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(dev->accel.dest + dev->accel.dx, dest_dat); + READ(dev->accel.dest + dev->accel.dx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + if (mach->accel.dp_config & 0x10) { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } } } @@ -2185,7 +2174,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else dev->accel.cx -= mach->accel.src_width; - dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); + dev->accel.cy += mach->accel.src_y_dir; dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); } @@ -3942,7 +3931,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u } else dev->_8514crt = 1; - if (dev->mode != VGA_MODE) + if ((dev->mode != VGA_MODE) && ATI_MACH32) mach_set_resolution(mach, svga); else svga_recalctimings(svga); @@ -4067,9 +4056,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x52ef: mach_log("ATI 8514/A: (0x%04x) ScratchPad0 val=%04x.\n", port, val); if (len == 2) - dev->accel.scratch0 = val; + mach->accel.scratch0 = val; else { - WRITE8(port, dev->accel.scratch0, val); + WRITE8(port, mach->accel.scratch0, val); } break; @@ -4077,9 +4066,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x56ef: mach_log("ATI 8514/A: (0x%04x) ScratchPad1 val=%04x.\n", port, val); if (len == 2) - dev->accel.scratch1 = val; + mach->accel.scratch1 = val; else { - WRITE8(port, dev->accel.scratch1, val); + WRITE8(port, mach->accel.scratch1, val); } break; @@ -4360,7 +4349,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xc2ee: - mach->accel.src_y_dir = val & 1; + mach->accel.src_y_dir = (val & 1) ? 1 : -1; + mach_log("Source Y Direction=%x.\n", val); break; case 0xc6ee: @@ -5170,16 +5160,16 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 0x52ee: case 0x52ef: - READ8(port, dev->accel.scratch0); - mach_log("ScratchPad0=%x.\n", dev->accel.scratch0); - if (dev->accel.scratch0 == 0x1234) + READ8(port, mach->accel.scratch0); + mach_log("ScratchPad0=%x.\n", mach->accel.scratch0); + if (mach->accel.scratch0 == 0x1234) temp = 0x0000; break; case 0x56ee: case 0x56ef: - READ8(port, dev->accel.scratch1); - mach_log("ScratchPad1=%x.\n", dev->accel.scratch1); + READ8(port, mach->accel.scratch1); + mach_log("ScratchPad1=%x.\n", mach->accel.scratch1); break; case 0x5eee: @@ -7326,34 +7316,47 @@ mach_reset(void *priv) } uint8_t -ati8514_rom_readb(uint32_t addr, void *priv) +ati8514_bios_rom_readb(uint32_t addr, void *priv) { const ibm8514_t *dev = (ibm8514_t *) priv; const rom_t *rom = &dev->bios_rom; - uint8_t ret; + uint8_t ret = 0xff; - mach_log("ROM1RB=%05x, ", addr); + mach_log("%04X:%08X: ROM1RB=%05x, ", CS, cpu_state.pc, addr); + addr &= rom->mask; - addr &= 0x1fff; ret = rom->rom[addr]; - - mach_log("ReadBAddr1=%03x, ret=%02x.\n", addr, ret); + mach_log("BIOS: ReadBAddr1=%04x, ret=%02x.\n", addr, ret); return (ret); } uint16_t -ati8514_rom_readw(uint32_t addr, void *priv) +ati8514_bios_rom_readw(uint32_t addr, void *priv) { const ibm8514_t *dev = (ibm8514_t *) priv; const rom_t *rom = &dev->bios_rom; - uint16_t ret; + uint16_t ret = 0xffff; - mach_log("ROM1RW=%05x, ", addr); + mach_log("%04X:%08X: ROM1RW=%05x, ", CS, cpu_state.pc, addr); + addr &= rom->mask; - addr &= 0x1fff; ret = (*(uint16_t *) &(rom->rom[addr])); + mach_log("BIOS: ReadWAddr1=%04x, ret=%04x.\n", addr, ret); + return (ret); +} - mach_log("ReadWAddr1=%03x, ret=%04x.\n", addr, ret); +uint32_t +ati8514_bios_rom_readl(uint32_t addr, void *priv) +{ + const ibm8514_t *dev = (ibm8514_t *) priv; + const rom_t *rom = &dev->bios_rom; + uint32_t ret = 0xffffffff; + + mach_log("%04X:%08X: ROM1RL=%05x, ", CS, cpu_state.pc, addr); + addr &= rom->mask; + + ret = (*(uint32_t *) &(rom->rom[addr])); + mach_log("BIOS: ReadLAddr1=%04x, ret=%08x.\n", addr, ret); return (ret); } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 2409d1202..0a2866413 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -814,6 +814,7 @@ svga_recalctimings(svga_t *svga) svga->render = svga_render_2bpp_highres; } else { svga->map8 = svga->pallook; + svga_log("Map8.\n"); if (svga->lowres) { /*Low res (320)*/ svga->render = svga_render_8bpp_lowres; svga_log("8 bpp low res.\n");