From 74e04082017b35e284be40de36be45878baa8430 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Feb 2025 20:06:15 +0100 Subject: [PATCH 001/218] Current WIP CD-ROM changes. --- src/cdrom/cdrom.c | 692 +++++++++++++++++++------------- src/cdrom/cdrom_image.c | 2 +- src/disk/hdc_ide.c | 196 ++++++--- src/disk/hdc_ide_sff8038i.c | 2 +- src/include/86box/cdrom.h | 62 +-- src/include/86box/device.h | 29 +- src/include/86box/hdc_ide.h | 2 + src/include/86box/hdd.h | 86 ++-- src/include/86box/mo.h | 9 +- src/include/86box/scsi_cdrom.h | 16 +- src/include/86box/scsi_device.h | 28 +- src/include/86box/scsi_disk.h | 1 + src/include/86box/zip.h | 1 + src/qt/qt_winrawinputfilter.cpp | 1 + src/qt/win_cdrom_ioctl.c | 14 + src/scsi/scsi_cdrom.c | 646 ++++++++++++++++++----------- src/sound/sound.c | 150 +++---- 17 files changed, 1201 insertions(+), 736 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 2cdcc5a22..9e6c57e70 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -89,8 +89,10 @@ static char * cdrom_modes[4] = { "Mode 1", "Mode 2", "CD-I/ static uint8_t cdrom_mode_masks[14] = { 0x0f, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x05, 0x05, 0x04, 0x04, 0x0c, 0x0c }; -static uint8_t status_codes[2][8] = { { 0x13, 0x15, 0x15, 0x15, 0x12, 0x11, 0x13, 0x13 }, - { 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x00, 0x00 } }; +static uint8_t status_codes[2][16] = { { 0x13, 0x15, 0x15, 0x15, 0x12, 0x11, 0x13, 0x13, + 0x12, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15 }, + { 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; static int mult = 1; static int part = 0; static int ecc_diff = 288; @@ -122,7 +124,7 @@ static const struct { static void cdrom_generate_name(const int type, char *name, const int internal) { - char elements[3][2048] = { 0 }; + char elements[3][512] = { 0 }; memcpy(elements[0], cdrom_drive_types[type].vendor, strlen(cdrom_drive_types[type].vendor) + 1); @@ -286,32 +288,39 @@ msf_to_bcd(int *m, int *s, int *f) static int read_data(cdrom_t *dev, const uint32_t lba) { - return dev->ops->read_sector(dev->local, dev->raw_buffer, lba); + int ret = 1; + + if (dev->cached_sector != lba) { + dev->cached_sector = lba; + + ret = dev->ops->read_sector(dev->local, + dev->raw_buffer[dev->cur_buf ^ 1], lba); + + if (ret <= 0) { + memset(dev->raw_buffer[dev->cur_buf ^ 1], 0x00, 2448); + dev->cached_sector = -1; + } + + dev->cur_buf ^= 1; + } + + return ret; } static void cdrom_get_subchannel(cdrom_t *dev, const uint32_t lba, subchannel_t *subc, const int cooked) { - const uint8_t *scb; - uint32_t scb_offs = 0; uint8_t q[16] = { 0 }; + if (lba != dev->cached_sector) + dev->cached_sector = -1; - if ((lba == dev->seek_pos) && - ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED))) - scb = dev->subch_buffer; - else { - scb = (const uint8_t *) dev->raw_buffer; - scb_offs = 2352; - - memset(dev->raw_buffer, 0, 2448); - - (void) read_data(dev, lba); - } + (void) read_data(dev, lba); for (int i = 0; i < 12; i++) for (int j = 0; j < 8; j++) - q[i] |= ((scb[scb_offs + (i << 3) + j] >> 6) & 0x01) << (7 - j); + q[i] |= ((dev->raw_buffer[dev->cur_buf][RAW_SECTOR_SIZE + + (i << 3) + j] >> 6) & 0x01) << (7 - j); if (cooked) { uint8_t temp = (q[0] >> 4) | ((q[0] & 0xf) << 4); @@ -406,7 +415,7 @@ find_specific_track(const raw_track_info_t *trti, const int num, const int track static int read_toc_normal(const cdrom_t *dev, unsigned char *b, - const unsigned char start_track, const int msf, + unsigned char start_track, const int msf, const int sony) { uint8_t rti[65536] = { 0 }; @@ -417,8 +426,13 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, int len = 4; int t = -1; - cdrom_log(dev->log, "read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i)\n", + if ((dev->is_bcd || dev->is_chinon) && (start_track < 0xa0)) + start_track = bcd2bin(start_track); + + cdrom_log(dev->log, "read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); + pclog("read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", + (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); dev->ops->get_raw_track_info(dev->local, &num, rti); @@ -458,7 +472,11 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, if (!sony) b[len++] = 0; /* Reserved */ b[len++] = tprti[i].adr_ctl; /* ADR/CTL */ - b[len++] = tprti[i].point; /* Track number */ + if ((dev->is_bcd || dev->is_chinon) && (tprti[i].point >= 1) && + (tprti[i].point <= 99)) + b[len++] = bin2bcd(tprti[i].point); /* Track number */ + else + b[len++] = tprti[i].point; /* Track number */ if (!sony) b[len++] = 0; /* Reserved */ @@ -466,7 +484,7 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, b[len++] = 0; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) { + if (dev->is_bcd) { int m = tprti[i].pm; int s = tprti[i].ps; int f = tprti[i].pf; @@ -527,14 +545,18 @@ read_toc_session(const cdrom_t *dev, unsigned char *b, const int msf) if (first != NULL) { b[len++] = 0x00; b[len++] = first->adr_ctl; - b[len++] = first->point; + if ((dev->is_bcd || dev->is_chinon) && (first->point >= 1) && + (first->point <= 99)) + b[len++] = bin2bcd(first->point); + else + b[len++] = first->point; b[len++] = 0x00; if (msf) { b[len++] = 0x00; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) { + if (dev->is_bcd) { int m = first->pm; int s = first->ps; int f = first->pf; @@ -586,6 +608,16 @@ read_toc_raw(const cdrom_t *dev, unsigned char *b, const unsigned char start_tra if (num != 0) for (int i = 0; i < num; i++) if (t[i].session >= start_track) { memcpy(&(b[len]), &(t[i]), 11); + + if ((dev->is_bcd || dev->is_chinon) && (b[3] >= 1) && (b[3] <= 99)) + b[3] = bin2bcd(b[3]); + + for (int j = 0; j < 3; j++) + if (dev->is_bcd) { + b[4 + j] = bin2bcd(b[4 + j]); + b[8 + j] = bin2bcd(b[8 + j]); + } + len += 11; } @@ -642,9 +674,9 @@ track_type_is_valid(UNUSED(const cdrom_t *dev), const int type, const int flags, static int read_audio(cdrom_t *dev, const uint32_t lba, uint8_t *b) { - const int ret = dev->ops->read_sector(dev->local, dev->raw_buffer, lba); + const int ret = read_data(dev, lba); - memcpy(b, dev->raw_buffer, 2352); + memcpy(b, dev->raw_buffer[dev->cur_buf], 2352); dev->cdrom_sector_size = 2352; @@ -660,7 +692,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[Mode 1] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -668,7 +700,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[Mode 1] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -678,7 +710,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (!(cdrom_sector_flags & 0x10)) { /* No user data */ cdrom_log(dev->log, "[Mode 1] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -688,12 +720,12 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) /* User data */ cdrom_log(dev->log, "[Mode 1] User data\n"); if (mult > 1) { - memcpy(b, dev->raw_buffer + 16 + (part * dev->sector_size), - dev->sector_size); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16 + + (part * dev->sector_size), dev->sector_size); dev->cdrom_sector_size += dev->sector_size; b += dev->sector_size; } else { - memcpy(b, dev->raw_buffer + 16, 2048); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 2048); dev->cdrom_sector_size += 2048; b += 2048; } @@ -702,7 +734,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ cdrom_log(dev->log, "[Mode 1] EDC/ECC\n"); - memcpy(b, dev->raw_buffer + 2064, (288 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 2064, (288 - ecc_diff)); dev->cdrom_sector_size += (288 - ecc_diff); } } @@ -716,7 +748,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[Mode 2 Formless] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -724,7 +756,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[Mode 2 Formless] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -733,7 +765,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[Mode 2 Formless] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -741,7 +773,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x10) { /* User data */ cdrom_log(dev->log, "[Mode 2 Formless] User data\n"); - memcpy(b, dev->raw_buffer + 24, (2336 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24, (2336 - ecc_diff)); dev->cdrom_sector_size += (2336 - ecc_diff); } } @@ -755,7 +787,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -763,7 +795,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -771,7 +803,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -780,12 +812,12 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, /* User data */ cdrom_log(dev->log, "[XA Mode 2 Form 1] User data\n"); if (mult > 1) { - memcpy(b, dev->raw_buffer + 24 + (part * dev->sector_size), - dev->sector_size); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24 + + (part * dev->sector_size), dev->sector_size); dev->cdrom_sector_size += dev->sector_size; b += dev->sector_size; } else { - memcpy(b, dev->raw_buffer + 24, 2048); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24, 2048); dev->cdrom_sector_size += 2048; b += 2048; } @@ -794,7 +826,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ cdrom_log(dev->log, "[XA Mode 2 Form 1] EDC/ECC\n"); - memcpy(b, dev->raw_buffer + 2072, (280 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 2072, (280 - ecc_diff)); dev->cdrom_sector_size += (280 - ecc_diff); } } @@ -808,7 +840,7 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -816,7 +848,7 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -824,7 +856,7 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -832,14 +864,14 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x10) { /* User data */ cdrom_log(dev->log, "[XA Mode 2 Form 2] User data\n"); - memcpy(b, dev->raw_buffer + 24, (2328 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24, + (2328 - ecc_diff)); dev->cdrom_sector_size += (2328 - ecc_diff); } } static void -process_ecc_and_subch(cdrom_t *dev, const int cdrom_sector_flags, - uint8_t *b) +process_c2(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) { if ((cdrom_sector_flags & 0x06) == 0x02) { /* Add error flags. */ @@ -851,31 +883,65 @@ process_ecc_and_subch(cdrom_t *dev, const int cdrom_sector_flags, cdrom_log(dev->log, "Full error flags\n"); memcpy(b + dev->cdrom_sector_size, dev->extra_buffer, 296); dev->cdrom_sector_size += 296; - } + } +} + +static void +cdrom_deinterleave_subch(uint8_t *d, const uint8_t *s) +{ + for (int i = 0; i < 8 * 12; i++) { + int dmask = 0x80; + int smask = 1 << (7 - (i / 12)); + + (*d) = 0; + + for (int j = 0; j < 8; j++) { + (*d) |= (s[(i % 12) * 8 + j] & smask) ? dmask : 0; + dmask >>= 1; + } + + d++; + } +} + +static void +process_c2_and_subch(cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b) +{ + if (dev->c2_first) + process_c2(dev, cdrom_sector_flags, b); if ((cdrom_sector_flags & 0x700) == 0x100) { cdrom_log(dev->log, "Raw subchannel data\n"); - memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 96); + memcpy(b + dev->cdrom_sector_size, dev->raw_buffer[dev->cur_buf] + + 2352, 96); dev->cdrom_sector_size += 96; } else if ((cdrom_sector_flags & 0x700) == 0x200) { cdrom_log(dev->log, "Q subchannel data\n"); - memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 16); + memcpy(b + dev->cdrom_sector_size, dev->raw_buffer[dev->cur_buf] + + 2352, 16); dev->cdrom_sector_size += 16; } else if ((cdrom_sector_flags & 0x700) == 0x400) { cdrom_log(dev->log, "R/W subchannel data\n"); - memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 96); + cdrom_deinterleave_subch(b + dev->cdrom_sector_size, + dev->raw_buffer[dev->cur_buf] + 2352); dev->cdrom_sector_size += 96; } + + if (!dev->c2_first) + process_c2(dev, cdrom_sector_flags, b); } static void cdrom_drive_reset(cdrom_t *dev) { - dev->priv = NULL; - dev->insert = NULL; - dev->close = NULL; - dev->get_volume = NULL; - dev->get_channel = NULL; + dev->priv = NULL; + dev->insert = NULL; + dev->close = NULL; + dev->get_volume = NULL; + dev->get_channel = NULL; + + dev->cached_sector = -1; if (cdrom_drive_types[dev->type].speed == -1) dev->real_speed = dev->speed; @@ -890,7 +956,8 @@ cdrom_unload(cdrom_t *dev) cdrom_log(dev->log, "CDROM: cdrom_unload(%s)\n", dev->image_path); } - dev->cd_status = CD_STATUS_EMPTY; + dev->cd_status = CD_STATUS_EMPTY; + dev->cached_sector = -1; if (dev->local != NULL) { dev->ops->close(dev->local); @@ -900,6 +967,39 @@ cdrom_unload(cdrom_t *dev) dev->ops = NULL; } +#ifdef ENABLE_CDROM_LOG +static void +cdrom_toc_dump(cdrom_t *dev) +{ + uint8_t b[65536] = { 0 }; + int len = cdrom_read_toc(dev, b, CD_TOC_RAW, 0, 0, 65536); + const char *fn2 = "d:\\86boxnew\\toc_cue.dmp"; + FILE * f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + cdrom_log(dev->log, "Written TOC of %i bytes to %s\n", len, fn2); + + memset(b, 0x00, 65536); + len = cdrom_read_toc(dev, b, CD_TOC_NORMAL, 0, 0, 65536); + fn2 = "d:\\86boxnew\\toc_cue_cooked.dmp"; + f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + cdrom_log(dev->log, "Written cooked TOC of %i bytes to %s\n", len, fn2); + + memset(b, 0x00, 65536); + len = cdrom_read_toc(dev, b, CD_TOC_SESSION, 0, 0, 65536); + fn2 = "d:\\86boxnew\\toc_cue_session.dmp"; + f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + cdrom_log(dev->log, "Written session TOC of %i bytes to %s\n", len, fn2); +} +#endif + /* Reset the CD-ROM Interface, whichever one that is. */ void cdrom_interface_reset(void) @@ -1001,24 +1101,6 @@ cdrom_is_generic(const int type) return (cdrom_drive_types[type].speed == -1); } -int -cdrom_has_date(const int type) -{ - /* This will do for now. */ - return !strcmp(cdrom_drive_types[type].vendor, "PIONEER"); -} - -int -cdrom_is_sony(const int type) -{ - /* This will do for now. */ - return (cdrom_drive_types[type].bus_type == BUS_TYPE_SCSI) && - (!strcmp(cdrom_drive_types[type].vendor, "DEC") || - !strcmp(cdrom_drive_types[type].vendor, "ShinaKen") || - !strcmp(cdrom_drive_types[type].vendor, "SONY") || - !strcmp(cdrom_drive_types[type].vendor, "TEXEL")); -} - int cdrom_is_caddy(const int type) { @@ -1067,7 +1149,7 @@ cdrom_get_type_count(void) void cdrom_get_identify_model(const int type, char *name, const int id) { - char elements[2][2048] = { 0 }; + char elements[2][512] = { 0 }; memcpy(elements[0], cdrom_drive_types[type].vendor, strlen(cdrom_drive_types[type].vendor) + 1); @@ -1197,6 +1279,24 @@ cdrom_lba_to_msf_accurate(const int lba) return ((m << 16) | (s << 8) | f); } +void +cdrom_interleave_subch(uint8_t *d, const uint8_t *s) +{ + memset(d, 0x00, 96); + + for (int i = 0; i < 8 * 12; i++) { + int smask = 0x80; + int dmask = 1 << (7 - (i / 12)); + + for (int j = 0; j < 8; j++) { + d[(i % 12) * 8 + j] |= ((*s) & smask) ? dmask : 0; + smask >>= 1; + } + + s++; + } +} + double cdrom_seek_time(const cdrom_t *dev) { @@ -1261,40 +1361,58 @@ cdrom_is_pre(const cdrom_t *dev, const uint32_t lba) return 0; } +#include <86box/filters.h> + +static void +cdrom_audio_deemphasize(int16_t *buffer) +{ + for (int i = 0; i < 588; i++) + for (int j = 0; j < 2; j++) + buffer[(i * 2) + j] = deemph_iir(j, buffer[(i * 2) + j]); +} + int cdrom_audio_callback(cdrom_t *dev, int16_t *output, const int len) { int ret = 1; - if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING) || dev->audio_muted_soft) { - // cdrom_log(dev->log, "Audio callback while not playing\n"); - if (dev->cd_status == CD_STATUS_PLAYING) - dev->seek_pos += (len >> 11); - memset(output, 0, len * 2); - return 0; - } - while (dev->cd_buflen < len) { if (dev->seek_pos < dev->cd_end) { - if (dev->ops->read_sector(dev->local, - (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), dev->seek_pos)) { + ret = dev->ops->read_sector(dev->local, + dev->raw_buffer[dev->cur_buf ^ 1], + dev->seek_pos); + if (!dev->sound_on) + memset(dev->raw_buffer[dev->cur_buf ^ 1], 0x00, 2352); + dev->cur_buf ^= 1; + if (ret) { cdrom_log(dev->log, "Read LBA %08X successful\n", dev->seek_pos); - memcpy(dev->subch_buffer, - ((uint8_t *) &(dev->cd_buffer[dev->cd_buflen])) + 2352, 96); + dev->cached_sector = dev->seek_pos; + /* Q subchannel data in bit 6: 4-5-6-7-0-1-2-3. */ + if ((dev->raw_buffer[dev->cur_buf][2353] >> 6) & 0x01) + /* Data sector, copy silence into buffer. */ + memset((uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), + 0x00, RAW_SECTOR_SIZE); + else { + memcpy((uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), + dev->raw_buffer[dev->cur_buf], RAW_SECTOR_SIZE); + if ((dev->raw_buffer[dev->cur_buf][2355] >> 6) & 0x01) + /* De-emphasize pre-emphasized audio. */ + cdrom_audio_deemphasize(&(dev->cd_buffer[dev->cd_buflen])); + } dev->seek_pos++; dev->cd_buflen += (RAW_SECTOR_SIZE / 2); ret = 1; } else { cdrom_log(dev->log, "Read LBA %08X failed\n", dev->seek_pos); memset(&(dev->cd_buffer[dev->cd_buflen]), 0x00, - (BUF_SIZE - dev->cd_buflen) * 2); + (CD_BUF_SIZE - dev->cd_buflen) * 2); dev->cd_status = CD_STATUS_STOPPED; dev->cd_buflen = len; ret = 0; } } else { cdrom_log(dev->log, "Playing completed\n"); - memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (BUF_SIZE - dev->cd_buflen) * 2); + memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (CD_BUF_SIZE - dev->cd_buflen) * 2); dev->cd_status = CD_STATUS_PLAYING_COMPLETED; dev->cd_buflen = len; ret = 0; @@ -1302,9 +1420,12 @@ cdrom_audio_callback(cdrom_t *dev, int16_t *output, const int len) } memcpy(output, dev->cd_buffer, len * 2); - memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); + memmove(dev->cd_buffer, &dev->cd_buffer[len], (CD_BUF_SIZE - len) * 2); dev->cd_buflen -= len; + if (!dev->sound_on) + ret = 0; + cdrom_log(dev->log, "Audio callback returning %i\n", ret); return ret; } @@ -1313,15 +1434,18 @@ uint8_t cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int ismsf) { track_info_t ti; - uint32_t pos2 = pos; - uint32_t len2 = len; - int ret = 0; + uint32_t pos2 = pos; + uint32_t len2 = len; + int ret = 0; if (dev->cd_status & CD_STATUS_HAS_AUDIO) { cdrom_log(dev->log, "Play audio - %08X %08X %i\n", pos2, len, ismsf); if (ismsf & 0x100) { /* Track-relative audio play. */ + pos2 = ismsf & 0xff; + if ((dev->is_bcd || dev->is_chinon) && (pos2 < 0xa0)) + pos2 = bcd2bin(pos2); ret = dev->ops->get_track_info(dev->local, ismsf & 0xff, 0, &ti); if (ret) pos2 += MSFtoLBA(ti.m, ti.s, ti.f) - 150; @@ -1331,13 +1455,17 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int cdrom_stop(dev); } } else if ((ismsf == 2) || (ismsf == 3)) { + if ((dev->is_bcd || dev->is_chinon) && (pos2 < 0xa0)) + pos2 = bcd2bin(pos2); ret = dev->ops->get_track_info(dev->local, pos2, 0, &ti); if (ret) { pos2 = MSFtoLBA(ti.m, ti.s, ti.f) - 150; if (ismsf == 2) { /* We have to end at the *end* of the specified track, not at the beginning. */ - ret = dev->ops->get_track_info(dev->local, len, 1, &ti); + if ((dev->is_bcd || dev->is_chinon) && (len2 < 0xa0)) + len2 = bcd2bin(len2); + ret = dev->ops->get_track_info(dev->local, len2, 1, &ti); if (ret) len2 = MSFtoLBA(ti.m, ti.s, ti.f) - 150; else { @@ -1357,7 +1485,7 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int int f = pos & 0xff; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) + if (dev->is_bcd) msf_from_bcd(&m, &s, &f); if (pos == 0xffffff) { @@ -1371,7 +1499,7 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int f = len & 0xff; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) + if (dev->is_bcd) msf_from_bcd(&m, &s, &f); len2 = MSFtoLBA(m, s, f) - 150; @@ -1391,8 +1519,6 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int } if (ret) { - dev->audio_muted_soft = 0; - /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. @@ -1400,10 +1526,11 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int ret = (dev->ops->get_track_type(dev->local, pos2) == CD_TRACK_AUDIO); if (ret) { - dev->seek_pos = pos2; - dev->cd_end = len2; - dev->cd_status = CD_STATUS_PLAYING; - dev->cd_buflen = 0; + dev->seek_diff = ABS(dev->seek_pos - pos2); + dev->seek_pos = pos2; + dev->cd_end = len2; + dev->cd_status = CD_STATUS_PLAYING; + dev->cd_buflen = 0; } else { cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); cdrom_stop(dev); @@ -1424,6 +1551,8 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, cdrom_log(dev->log, "Audio Track Search: MSF = %06x, type = %02x, " "playbit = %02x\n", pos, type, playbit); + ret = 1; + switch (type) { case 0x00: if (pos == 0xffffffff) { @@ -1445,39 +1574,37 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, dev->seek_pos = pos2; break; } case 0x80: - if (pos == 0xffffffff) { - cdrom_log(dev->log, "(Type 2) Search from current position\n"); - pos2 = dev->seek_pos; + track_info_t ti; + + pos2 = (pos2 >> 24) & 0xff; + if (pos2 < 0xa0) + pos2 = bcd2bin(pos2); + ret = dev->ops->get_track_info(dev->local, pos2, 1, &ti); + if (ret) + dev->seek_pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + else { + cdrom_log(dev->log, "Unable to get the starting position for " + "track %08X\n", ismsf & 0xff); + cdrom_stop(dev); } - dev->seek_pos = (pos2 >> 24) & 0xff; break; default: break; } - if (pos2 != 0x00000000) - pos2--; + if (ret) { + if (pos2 != 0x00000000) + pos2--; - /* - Do this at this point, since it's at this point that we know the - actual LBA position to start playing from. - */ - if (dev->ops->get_track_type(dev->local, pos2) & CD_TRACK_AUDIO) - dev->audio_muted_soft = 0; - else { - cdrom_log(dev->log, "Track Search: LBA %08X not on an audio track\n", pos); - dev->audio_muted_soft = 1; - if (dev->ops->get_track_type(dev->local, pos) & CD_TRACK_AUDIO) - dev->audio_muted_soft = 0; + cdrom_log(dev->log, "Track Search Toshiba: LBA=%08X.\n", pos); + + dev->cd_end = dev->cdrom_capacity; + dev->cd_buflen = 0; + + dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_HOLD; + + ret = 1; } - - cdrom_log(dev->log, "Track Search Toshiba: Muted?=%d, LBA=%08X.\n", - dev->audio_muted_soft, pos); - dev->cd_buflen = 0; - - dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; - - ret = 1; } return ret; @@ -1501,15 +1628,15 @@ cdrom_audio_track_search_pioneer(cdrom_t *dev, const uint32_t pos, const uint8_t dev->seek_pos = pos2; - dev->audio_muted_soft = 0; - /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (dev->ops->get_track_type(dev->local, pos2) & CD_TRACK_AUDIO) { + dev->cd_end = dev->cdrom_capacity; dev->cd_buflen = 0; - dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; + + dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_HOLD; ret = 1; } else { @@ -1533,7 +1660,6 @@ cdrom_audio_play_pioneer(cdrom_t *dev, const uint32_t pos) uint32_t pos2 = MSFtoLBA(m, s, f) - 150; dev->cd_end = pos2; - dev->audio_muted_soft = 0; dev->cd_buflen = 0; dev->cd_status = CD_STATUS_PLAYING; @@ -1552,6 +1678,8 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) if (dev->cd_status & CD_STATUS_HAS_AUDIO) { /* Preliminary support, revert if too incomplete. */ + ret = 1; + switch (type) { case 0x00: dev->cd_end = pos2; @@ -1564,7 +1692,19 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) dev->cd_end = pos2; break; } case 0x80: - dev->cd_end = (pos2 >> 24) & 0xff; + track_info_t ti; + + pos2 = (pos2 >> 24) & 0xff; + if (pos2 < 0xa0) + pos2 = bcd2bin(pos2); + ret = dev->ops->get_track_info(dev->local, pos2, 1, &ti); + if (ret) + dev->cd_end = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + else { + cdrom_log(dev->log, "Unable to get the starting position for " + "track %08X\n", ismsf & 0xff); + cdrom_stop(dev); + } break; case 0xc0: if (pos == 0xffffffff) { @@ -1577,55 +1717,32 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) break; } - cdrom_log(dev->log, "Toshiba Play Audio: Muted?=%d, LBA=%08X.\n", - dev->audio_muted_soft, pos2); - dev->cd_buflen = 0; + if (ret) { + cdrom_log(dev->log, "Toshiba Play Audio: LBA=%08X.\n", pos2); - dev->cd_status = CD_STATUS_PLAYING; - - ret = 1; + dev->cd_status = CD_STATUS_PLAYING; + dev->cd_buflen = 0; + } } return ret; } uint8_t -cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type) +cdrom_audio_scan(cdrom_t *dev, const uint32_t pos) { - uint32_t pos2 = pos; - uint8_t ret = 0; + uint32_t pos2 = pos; + uint8_t ret = 0; if (dev->cd_status & CD_STATUS_HAS_AUDIO) { cdrom_log(dev->log, "Audio Scan: MSF = %06x, type = %02x\n", pos, type); - switch (type) { - case 0x00: - if (pos == 0xffffffff) { - cdrom_log(dev->log, "(Type 0) Search from current position\n"); - pos2 = dev->seek_pos; - } - dev->seek_pos = pos2; - break; - case 0x40: { - const int m = bcd2bin((pos >> 24) & 0xff); - const int s = bcd2bin((pos >> 16) & 0xff); - const int f = bcd2bin((pos >> 8) & 0xff); - if (pos == 0xffffffff) { - cdrom_log(dev->log, "(Type 1) Search from current position\n"); - pos2 = dev->seek_pos; - } else - pos2 = MSFtoLBA(m, s, f) - 150; - - dev->seek_pos = pos2; - break; - } case 0x80: - dev->seek_pos = (pos >> 24) & 0xff; - break; - default: - break; + if (pos == 0xffffffff) { + cdrom_log(dev->log, "(Type 0) Search from current position\n"); + pos2 = dev->seek_pos; } + dev->seek_pos = pos2; - dev->audio_muted_soft = 0; /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (dev->ops->get_track_type(dev->local, pos) & CD_TRACK_AUDIO) { @@ -1650,8 +1767,8 @@ cdrom_audio_pause_resume(cdrom_t *dev, const uint8_t resume) uint8_t cdrom_get_current_status(const cdrom_t *dev) { - const uint8_t is_chinon = !strcmp(cdrom_drive_types[dev->type].vendor, "CHINON"); - const uint8_t ret = status_codes[is_chinon][dev->cd_status & CD_STATUS_MASK]; + const uint8_t ret = status_codes[dev->is_chinon] + [dev->cd_status & CD_STATUS_MASK]; return ret; } @@ -1659,9 +1776,14 @@ cdrom_get_current_status(const cdrom_t *dev) void cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) { - subchannel_t subc; + subchannel_t subc; + int base = 0; + int diff = 4; - cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); + if (dev->cached_sector == -1) + cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); + else + cdrom_get_subchannel(dev, dev->cached_sector, &subc, 1); cdrom_log(dev->log, "Returned subchannel absolute at %02i:%02i.%02i, " "relative at %02i:%02i.%02i, seek pos = %08x, cd_end = %08x.\n", @@ -1674,17 +1796,29 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) Mode 0 = Q subchannel mode, first 16 bytes are indentical to mode 1 (current position), the rest are stuff like ISRC etc., which can be all zeroes. */ + case 0x00: + if (dev->bus_type == CDROM_BUS_ATAPI) { + // pclog("Format 0 on ATAPI\n"); + break; + } + // pclog("Format 0 on SCSI\n"); + diff = 0; + fallthrough; case 0x01: /* Current position. */ b[1] = subc.attr; - b[2] = subc.track; + if ((dev->is_bcd || dev->is_chinon) && + (subc.track >= 1) && (subc.track <= 99)) + b[2] = bin2bcd(subc.track); + else + b[2] = subc.track; b[3] = subc.index; if (msf) { b[4] = b[8] = 0x00; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) { + if (dev->is_bcd) { b[5] = bin2bcd(subc.abs_m); b[6] = bin2bcd(subc.abs_s); b[7] = bin2bcd(subc.abs_f); @@ -1714,26 +1848,37 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) b[10] = (dat >> 8) & 0xff; b[11] = dat & 0xff; } - break; + pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], + b[ 8], b[ 9], b[10], b[11]); + if (b[0] != 0x00) + break; + base += 12; + fallthrough; case 0x02: /* UPC - TODO: Finding and reporting the actual UPC data. */ - memset(&(b[1]), 0x00, 19); - memset(&(b[5]), 0x30, 13); + memset(&(b[base]), 0x00, 20 - diff); + base += diff; + memset(&(b[base + 1]), 0x30, 13); /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) - b[19] = bin2bcd(subc.abs_f); + if (dev->is_bcd) + b[base + 15] = bin2bcd(subc.abs_f); else - b[19] = subc.abs_f; - break; + b[base + 15] = subc.abs_f; + if (b[0] != 0x00) + break; + base += 16; + fallthrough; case 0x03: /* ISRC - TODO: Finding and reporting the actual ISRC data. */ - memset(&(b[1]), 0x00, 19); - memset(&(b[5]), 0x30, 12); + memset(&(b[base]), 0x00, 20 - diff); + base += diff; + memset(&(b[base]), 0x30, 12); /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) - b[18] = bin2bcd(subc.abs_f); + if (dev->is_bcd) + b[base + 14] = bin2bcd(subc.abs_f); else - b[18] = subc.abs_f; + b[base + 14] = subc.abs_f; break; default: cdrom_log(dev->log, "b[0] = %02X\n", b[0]); @@ -1842,7 +1987,7 @@ cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b) cdrom_get_subchannel(dev, dev->seek_pos, &subc, 0); - b[0] = subc.attr; + b[0] = (subc.attr >> 4) | ((subc.attr & 0xf) << 4); b[1] = subc.track; b[2] = subc.index; b[3] = subc.rel_m; @@ -1851,6 +1996,10 @@ cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b) b[6] = subc.abs_m; b[7] = subc.abs_s; b[8] = subc.abs_f; + + cdrom_log(dev->log, "SubCodeQ: %02X %02X %02X %02X %02X %02X %02X %02X " + "%02X\n", + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8]); } uint8_t @@ -1860,20 +2009,25 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) cdrom_get_current_subcodeq(dev, b); - if ((dev->cd_status == CD_STATUS_DATA_ONLY) || - (dev->cd_status == CD_STATUS_DVD) || - (dev->cd_status == CD_STATUS_PLAYING_COMPLETED) || - (dev->cd_status == CD_STATUS_STOPPED)) - ret = 0x03; - else - ret = (dev->cd_status == CD_STATUS_PLAYING) ? 0x00 : dev->audio_op; + switch (dev->cd_status) { + default: case CD_STATUS_EMPTY: + case CD_STATUS_DATA_ONLY: case CD_STATUS_DVD: + case CD_STATUS_STOPPED: case CD_STATUS_PLAYING_COMPLETED: + ret = 0x03; + break; + case CD_STATUS_HOLD: + ret = 0x02; + break; + case CD_STATUS_PAUSED: + ret = 0x01; + break; + case CD_STATUS_PLAYING: + ret = 0x00; + break; + } - /*If a valid audio track is detected with audio on, unmute it.*/ - if (dev->ops->get_track_type(dev->local, dev->seek_pos) & CD_TRACK_AUDIO) - dev->audio_muted_soft = 0; - - cdrom_log(dev->log, "SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x, mute=%d.\n", - dev->seek_pos, dev->cd_end, dev->audio_muted_soft); + cdrom_log(dev->log, "SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x.\n", + dev->seek_pos, dev->cd_end); return ret; } @@ -2041,14 +2195,11 @@ cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, switch (type) { case 0: if (num > 0) { - first = find_track(trti, num, 1); - const int last = find_track(trti, num, 0); - - if ((first == -1) || (last == -1)) + if (num < 4) ret = 0; else { - b[0] = bin2bcd(first); - b[1] = bin2bcd(last); + b[0] = bin2bcd(trti[0].pm); + b[1] = bin2bcd(trti[1].pm); b[2] = 0x00; b[3] = 0x00; @@ -2108,7 +2259,7 @@ cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, b[0x12] = temp; } } else { - b[0] = 0x00; /* Audio or CDROM disc. */ + b[0] = trti[0].ps; /* Disc type. */ if (num > 0) first = find_track(trti, num, 1); @@ -2195,7 +2346,6 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int if (dm != CD_TRACK_NORMAL) mode2 = 1; - memset(dev->raw_buffer, 0, 2448); memset(dev->extra_buffer, 0, 296); if ((cdrom_sector_flags & 0xf8) == 0x08) { @@ -2228,28 +2378,29 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int if (ret > 0) { int form = 0; - if ((dev->raw_buffer[0x000f] == 0x00) || - (dev->raw_buffer[0x000f] > 0x02)) { + if ((dev->raw_buffer[dev->cur_buf][0x000f] == 0x00) || + (dev->raw_buffer[dev->cur_buf][0x000f] > 0x02)) { cdrom_log(dev->log, "[%s] Unknown mode: %02X\n", cdrom_req_modes[cdrom_sector_type], - dev->raw_buffer[0x000f]); + dev->raw_buffer[dev->cur_buf][0x000f]); ret = 0; } else if (mode2) { - if (dev->raw_buffer[0x000f] == 0x01) + if (dev->raw_buffer[dev->cur_buf][0x000f] == 0x01) /* Use Mode 1, since evidently specification-violating discs exist. */ mode2 = 0; - else if (dev->raw_buffer[0x0012] != - dev->raw_buffer[0x0016]) { + else if (dev->raw_buffer[dev->cur_buf][0x0012] != + dev->raw_buffer[dev->cur_buf][0x0016]) { cdrom_log(dev->log, "[%s] XA Mode 2 sector with " "malformed sub-header\n", cdrom_req_modes[cdrom_sector_type]); ret = 0; } else - form = ((dev->raw_buffer[0x0012] & 0x20) >> 5) + 1; - } else if (dev->raw_buffer[0x000f] == 0x02) + form = ((dev->raw_buffer[dev->cur_buf][0x0012] & + 0x20) >> 5) + 1; + } else if (dev->raw_buffer[dev->cur_buf][0x000f] == 0x02) mode2 = 1; if (ret > 0) { @@ -2281,7 +2432,7 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int } if (ret > 0) { - process_ecc_and_subch(dev, cdrom_sector_flags, b); + process_c2_and_subch(dev, cdrom_sector_flags, b); *len = dev->cdrom_sector_size; } } @@ -2617,7 +2768,7 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) if (track->adr_ctl & 0x04) { ret = read_data(dev, start); - mode = dev->raw_buffer[3]; + mode = dev->raw_buffer[dev->cur_buf][3]; } } else if (track->point != 0xa2) start = 0x00000000; @@ -2641,57 +2792,22 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) return ret; } -int -cdrom_is_empty(const uint8_t id) +uint8_t +cdrom_get_current_mode(cdrom_t *dev) { - const cdrom_t *dev = &cdrom[id]; - int ret = 0; + if (dev->cached_sector == -1) + (void) read_data(dev, dev->seek_pos); + else + (void) read_data(dev, dev->cached_sector); - /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ - if (strlen(dev->image_path) == 0) - /* Switch from empty to empty. Do nothing. */ - ret = 1; - - return ret; + return dev->raw_buffer[dev->cur_buf][3]; } -#ifdef ENABLE_CDROM_LOG -static void -cdrom_toc_dump(cdrom_t *dev) -{ - uint8_t b[65536] = { 0 }; - int len = cdrom_read_toc(dev, b, CD_TOC_RAW, 0, 0, 65536); - const char *fn2 = "d:\\86boxnew\\toc_cue.dmp"; - FILE * f = fopen(fn2, "wb"); - fwrite(b, 1, len, f); - fflush(f); - fclose(f); - cdrom_log(dev->log, "Written TOC of %i bytes to %s\n", len, fn2); - - memset(b, 0x00, 65536); - len = cdrom_read_toc(dev, b, CD_TOC_NORMAL, 0, 0, 65536); - fn2 = "d:\\86boxnew\\toc_cue_cooked.dmp"; - f = fopen(fn2, "wb"); - fwrite(b, 1, len, f); - fflush(f); - fclose(f); - cdrom_log(dev->log, "Written cooked TOC of %i bytes to %s\n", len, fn2); - - memset(b, 0x00, 65536); - len = cdrom_read_toc(dev, b, CD_TOC_SESSION, 0, 0, 65536); - fn2 = "d:\\86boxnew\\toc_cue_session.dmp"; - f = fopen(fn2, "wb"); - fwrite(b, 1, len, f); - fflush(f); - fclose(f); - cdrom_log(dev->log, "Written session TOC of %i bytes to %s\n", len, fn2); -} -#endif - void cdrom_set_empty(cdrom_t *dev) { dev->cd_status = CD_STATUS_EMPTY; + dev->cached_sector = -1; } void @@ -2714,6 +2830,7 @@ cdrom_update_status(cdrom_t *dev) dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : CD_STATUS_DATA_ONLY; + dev->cached_sector = -1; dev->cdrom_capacity = dev->ops->get_last_block(dev->local); if (dev->cd_status != CD_STATUS_EMPTY) { @@ -2744,6 +2861,8 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) else dev->local = image_open(dev, dev->image_path); + dev->cached_sector = -1; + if (dev->local == NULL) { dev->ops = NULL; dev->image_path[0] = 0; @@ -2790,6 +2909,9 @@ cdrom_global_init(void) { /* Clear the global data. */ memset(cdrom, 0x00, sizeof(cdrom)); + + for (uint8_t i = 0; i < CDROM_NUM; i++) + cdrom[i].cached_sector = -1; } void @@ -2799,11 +2921,26 @@ cdrom_hard_reset(void) cdrom_t *dev = &cdrom[i]; if (dev->bus_type) { - dev->id = i; + dev->id = i; - dev->is_early = cdrom_is_early(dev->type); - dev->is_nec = (dev->bus_type == CDROM_BUS_SCSI) && - !strcmp(cdrom_drive_types[dev->type].vendor, "NEC"); + const char *vendor = cdrom_drive_types[dev->type].vendor; + + dev->is_early = cdrom_is_early(dev->type); + dev->is_bcd = !strcmp(vendor, "NEC"); + dev->is_nec = (dev->bus_type == CDROM_BUS_SCSI) && + !strcmp(vendor, "NEC"); + dev->is_chinon = !strcmp(vendor, "CHINON"); + dev->is_pioneer = !strcmp(vendor, "PIONEER"); + dev->is_plextor = !strcmp(vendor, "PLEXTOR"); + dev->is_sony = (dev->bus_type == CDROM_BUS_SCSI) && + (!strcmp(vendor, "DEC") || + !strcmp(vendor, "ShinaKen") || + !strcmp(vendor, "SONY") || + !strcmp(vendor, "TEXEL")); + dev->is_toshiba = !strcmp(vendor, "TOSHIBA"); + + dev->c2_first = !strcmp(vendor, "NEC") || + !strcmp(vendor, "PLEXTOR"); cdrom_drive_reset(dev); @@ -2824,7 +2961,8 @@ cdrom_hard_reset(void) break; } - dev->cd_status = CD_STATUS_EMPTY; + dev->cd_status = CD_STATUS_EMPTY; + dev->cached_sector = -1; if (strlen(dev->image_path) > 0) { #ifdef _WIN32 @@ -2889,6 +3027,8 @@ cdrom_exit(const uint8_t id) strcpy(dev->prev_image_path, dev->image_path); + dev->cached_sector = -1; + if (dev->ops) { cdrom_unload(dev); @@ -2901,6 +3041,20 @@ cdrom_exit(const uint8_t id) cdrom_insert(id); } +int +cdrom_is_empty(const uint8_t id) +{ + const cdrom_t *dev = &cdrom[id]; + int ret = 0; + + /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ + if (strlen(dev->image_path) == 0) + /* Switch from empty to empty. Do nothing. */ + ret = 1; + + return ret; +} + /* The mechanics of ejecting a CD-ROM from a drive. */ void cdrom_eject(const uint8_t id) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index 271a290cb..519afaa4c 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -409,7 +409,7 @@ image_get_track_and_index(const cd_image_t *img, const uint32_t sector, for (int i = 0; i < img->tracks_num; i++) { track_t *ct = &(img->tracks[i]); - for (int j = 0; j < 3; j++) { + if ((ct->point >= 1) && (ct->point <= 99)) for (int j = 0; j < 3; j++) { track_index_t *ci = &(ct->idx[j]); if ((ci->type >= INDEX_ZERO) && (ci->length != 0ULL) && ((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 3683c8671..e367f73b0 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,6 +241,7 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); +#define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -1028,9 +1029,8 @@ ide_atapi_command_bus(ide_t *ide) static void ide_atapi_callback(ide_t *ide) { - int out; - int ret = 0; - ide_bm_t *bm = ide_boards[ide->board]->bm; + static int ret = 0; + ide_bm_t *bm = ide_boards[ide->board]->bm; #ifdef ENABLE_IDE_LOG char *phases[7] = { "Idle", "Command", "Data in", "Data out", "Data in DMA", "Data out DMA", "Complete" }; @@ -1056,14 +1056,17 @@ ide_atapi_callback(ide_t *ide) switch (ide->sc->packet_status) { default: + ret = 0; break; case PHASE_IDLE: + ret = 0; ide->tf->pos = 0; ide->tf->phase = 1; ide->tf->atastat = READY_STAT | DRQ_STAT | (ide->tf->atastat & ERR_STAT); break; case PHASE_COMMAND: + ret = 1; ide->tf->atastat = BUSY_STAT | (ide->tf->atastat & ERR_STAT); if (ide->packet_command) { ide->packet_command(ide->sc, ide->sc->atapi_cdb); @@ -1073,6 +1076,7 @@ ide_atapi_callback(ide_t *ide) break; case PHASE_COMPLETE: case PHASE_ERROR: + ret = 0; ide->tf->atastat = READY_STAT; if (ide->sc->packet_status == PHASE_ERROR) ide->tf->atastat |= ERR_STAT; @@ -1082,19 +1086,30 @@ ide_atapi_callback(ide_t *ide) break; case PHASE_DATA_IN: case PHASE_DATA_OUT: + ret = 0; ide->tf->atastat = READY_STAT | DRQ_STAT | (ide->tf->atastat & ERR_STAT); ide->tf->phase = !(ide->sc->packet_status & 0x01) << 1; ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - case PHASE_DATA_OUT_DMA: - out = (ide->sc->packet_status & 0x01); - if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { - ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, out, bm->priv); - } - /* Else, DMA command without a bus master, ret = 0 (default). */ + if (ide->sc->block_len == 0) + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, bm->priv); + else { + ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos - + ide->sc->block_len, ide->sc->block_len, + 0, bm->priv); + + if (ret == 1) { + if (ide->sc->sector_len == 0) + ret = 3; + else if (ide->read != NULL) + ide->read(ide->sc); + } + } + } else + ret = 0; switch (ret) { default: @@ -1103,18 +1118,69 @@ ide_atapi_callback(ide_t *ide) if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; - case 1: - if (out && ide->phase_data_out) - (void) ide->phase_data_out(ide->sc); - else if (!out && ide->command_stop) - ide->command_stop(ide->sc); + case 2: + ide_atapi_command_bus(ide); + break; + case 3: + /* Reached EOT - terminate the command as there's nothing + more to transfer. */ + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; - if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + if (ide->command_stop != NULL) + ide->command_stop(ide->sc); + fallthrough; + case 1: + if ((ide->sc->packet_status == PHASE_COMPLETE) && + (ide->sc->callback == 0.0)) ide_atapi_callback(ide); break; + } + break; + case PHASE_DATA_OUT_DMA: + if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && + (bm != NULL) && bm->dma) { + if (ide->sc->block_len == 0) + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 1, bm->priv); + else { + ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos, + ide->sc->block_len, 1, bm->priv); + + if (ret & 1) { + if (ide->write != NULL) + ide->write(ide->sc); + + if ((ret == 1) && (ide->sc->sector_len == 0)) + ret = 3; + } + } + } else + ret = 0; + + switch (ret) { + default: + break; + case 0: + if (ide->bus_master_error) + ide->bus_master_error(ide->sc); + break; case 2: ide_atapi_command_bus(ide); break; + case 3: + /* Reached EOT - terminate the command as there's nothing + more to transfer. */ + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + if (ide->phase_data_out != NULL) + (void) ide->phase_data_out(ide->sc); + fallthrough; + case 1: + if ((ide->sc->packet_status == PHASE_COMPLETE) && + (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + break; } break; } @@ -1134,22 +1200,37 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_log("%i bytes %s, command done\n", ide->tf->pos, out ? "written" : "read"); ide->tf->pos = dev->request_pos = 0; - if (out && ide->phase_data_out) - ide->phase_data_out(dev); - else if (!out && ide->command_stop) - ide->command_stop(dev); - if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) - ide_atapi_callback(ide); + if (dev->block_len != 0) { + if (out && (ide->write != NULL)) + ide->write(dev); + else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) + ide->read(dev); + } + + if ((dev->block_len == 0) || (dev->sector_len == 0)) { + if (out && (ide->phase_data_out != NULL)) + ide->phase_data_out(dev); + else if (!out && (ide->command_stop != NULL)) + ide->command_stop(dev); + + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + } } else { ide_log("%i bytes %s, %i bytes are still left\n", ide->tf->pos, out ? "written" : "read", dev->packet_len - ide->tf->pos); - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ + /* + If less than (packet length) bytes are remaining, update packet length + accordingly. + */ if ((dev->packet_len - ide->tf->pos) < (dev->max_transfer_len)) { dev->max_transfer_len = dev->packet_len - ide->tf->pos; - /* Also update the request length so the host knows how many bytes to transfer. */ + /* + Also update the request length so the host knows how many bytes to + transfer. + */ ide->tf->request_length = dev->max_transfer_len; } ide_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, @@ -1157,10 +1238,20 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) dev->packet_status = PHASE_DATA_IN | out; + if (dev->block_len != 0) { + if (out && (ide->write != NULL)) + ide->write(dev); + else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) + ide->read(dev); + } + ide->tf->atastat = BSY_STAT; ide->tf->phase = 1; - ide_atapi_callback(ide); - ide_set_callback(ide, 0.0); + + if ((dev->block_len == 0) || (dev->sector_len == 0)) { + ide_atapi_callback(ide); + ide_set_callback(ide, 0.0); + } dev->request_pos = 0; } @@ -1179,19 +1270,26 @@ ide_atapi_packet_read(ide_t *ide) bufferw = (uint16_t *) dev->temp_buffer; - /* Make sure we return a 0 and don't attempt to read from the buffer if + /* + Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 2048 bytes). */ + (which is 1 sector = 2048 bytes). + */ ret = (ide->tf->pos < dev->packet_len) ? bufferw[ide->tf->pos >> 1] : 0; ide->tf->pos += 2; dev->request_pos += 2; - if ((dev->request_pos >= dev->max_transfer_len) || (ide->tf->pos >= dev->packet_len)) { + if ((dev->request_pos >= dev->max_transfer_len) || + (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 0); - } + } else if ((dev->block_len != 0) && + (dev->sector_len != 0) && + ((dev->request_pos % dev->block_len) == 0) && + (ide->read != NULL)) + ide->read(dev); } return ret; @@ -1221,10 +1319,14 @@ ide_atapi_packet_write(ide_t *ide, const uint16_t val) dev->request_pos += 2; if (dev->packet_status == PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (ide->tf->pos >= dev->packet_len)) { + if ((dev->request_pos >= dev->max_transfer_len) || + (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 1); - } + } else if ((dev->block_len != 0) && + ((dev->request_pos % dev->block_len) == 0) && + (ide->write != NULL)) + ide->write(dev); } else if (dev->packet_status == PHASE_IDLE) { if (ide->tf->pos >= 12) { ide->tf->pos = 0; @@ -1287,7 +1389,7 @@ ide_writew(uint16_t addr, uint16_t val, void *priv) ide = ide_drives[ch]; #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_writew(%04X, %04X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_writew(%04X, %04X, %08X)\n", CS, cpu_state.pc, addr, val, priv); #endif addr &= 0x7; @@ -1321,7 +1423,7 @@ ide_writel(uint16_t addr, uint32_t val, void *priv) ide = ide_drives[ch]; #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_writel(%04X, %08X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_writel(%04X, %08X, %08X)\n", CS, cpu_state.pc, addr, val, priv); #endif addr &= 0x7; @@ -1371,9 +1473,9 @@ ide_write_devctl(UNUSED(uint16_t addr), uint8_t val, void *priv) ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_log("ide_write_devctl(%04X, %02X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_write_devctl(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv); - if ((ide->type == IDE_NONE) && (ide_other->type == IDE_NONE)) + if ((addr & 0x0001) || ((ide->type == IDE_NONE) && (ide_other->type == IDE_NONE))) return; dev->diag = 0; @@ -1481,7 +1583,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_log("ide_writeb(%04X, %02X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_writeb(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv); addr &= 0x7; @@ -1831,7 +1933,7 @@ ide_read_data(ide_t *ide) const uint16_t *idebufferw = ide->buffer; uint16_t ret = 0x0000; -#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) +#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 3) ide_log("ide_read_data(): ch = %i, board = %i, type = %i\n", ide->channel, ide->board, ide->type); #endif @@ -2010,7 +2112,7 @@ ide_readb(uint16_t addr, void *priv) break; } - ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_readb(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); return ret; } @@ -2022,12 +2124,14 @@ ide_read_alt_status(UNUSED(const uint16_t addr), void *priv) const int ch = dev->cur_dev; ide_t * ide = ide_drives[ch]; + uint8_t ret = 0xff; /* Per the Seagate ATA-3 specification: Reading the alternate status does *NOT* clear the IRQ. */ - const uint8_t ret = ide_status(ide, ide_drives[ch ^ 1], ch); + if (!(addr & 0x0001)) + ret = ide_status(ide, ide_drives[ch ^ 1], ch); - ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_read_alt_status(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); return ret; } @@ -2053,7 +2157,7 @@ ide_readw(uint16_t addr, void *priv) } #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_readw(%04X, %08X) = %04X\n", CS, cpu_state.pc, addr, priv, ret); #endif return ret; } @@ -2084,7 +2188,7 @@ ide_readl(uint16_t addr, void *priv) } #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_readl(%04X, %08X) = %04X\n", CS, cpu_state.pc, addr, priv, ret); #endif return ret; } @@ -2270,7 +2374,7 @@ ide_callback(void *priv) ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_set_callback(ide, 6.0 * IDE_TIME); return; - } else if (ret == 1) { + } else if (ret & 1) { /* DMA successful */ ide_log("IDE %i: DMA read successful\n", ide->channel); @@ -2379,7 +2483,7 @@ ide_callback(void *priv) ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_set_callback(ide, 6.0 * IDE_TIME); return; - } else if (ret == 1) { + } else if (ret & 1) { /* DMA successful */ ret = hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); @@ -2637,7 +2741,7 @@ ide_handlers(uint8_t board, int set) } if (ide_boards[board]->base[1]) { - io_handler(set, ide_boards[board]->base[1], 1, + io_handler(set, ide_boards[board]->base[1], 2, ide_read_alt_status, NULL, NULL, ide_write_devctl, NULL, NULL, ide_boards[board]); diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 73dc5f36b..2cc1fe72e 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -375,7 +375,7 @@ sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv) } else if (dev->eot) { sff_log("Regular EOT\n"); dev->status &= ~3; - return 1; /* We have regularly reached EOT - clear status and break. */ + return 3; /* We have regularly reached EOT - clear status and break. */ } else { /* We have more to transfer and there are blocks left, get next block. */ sff_bus_master_next_addr(dev); diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 7c028d7d6..c6347fc3e 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -28,8 +28,9 @@ #define CD_STATUS_PLAYING 5 #define CD_STATUS_STOPPED 6 #define CD_STATUS_PLAYING_COMPLETED 7 -#define CD_STATUS_HAS_AUDIO 4 -#define CD_STATUS_MASK 7 +#define CD_STATUS_HOLD 8 +#define CD_STATUS_HAS_AUDIO 0xc +#define CD_STATUS_MASK 0xf /* Medium changed flag. */ #define CD_STATUS_TRANSITION 0x40 @@ -50,8 +51,6 @@ #define CD_IMAGE_HISTORY 10 -#define BUF_SIZE 32768 - #define CDROM_IMAGE 200 /* This is so that if/when this is changed to something else, @@ -63,6 +62,8 @@ #define RAW_SECTOR_SIZE 2352 #define COOKED_SECTOR_SIZE 2048 +#define CD_BUF_SIZE (16 * RAW_SECTOR_SIZE) + #define DATA_TRACK 0x14 #define AUDIO_TRACK 0x10 @@ -105,9 +106,9 @@ enum { #define CDV EMU_VERSION_EX static const struct cdrom_drive_types_s { - const char vendor[9]; - const char model[17]; - const char revision[5]; + const char * vendor; + const char * model; + const char * revision; const char * internal_name; const int bus_type; /* SCSI standard for SCSI (or both) devices, early for IDE. */ @@ -298,9 +299,7 @@ typedef struct cdrom { void * priv; char image_path[1024]; - char prev_image_path[1024]; - - char * image_history[CD_IMAGE_HISTORY]; + char prev_image_path[1280]; uint32_t sound_on; uint32_t cdrom_capacity; @@ -310,18 +309,21 @@ typedef struct cdrom { uint32_t type; uint32_t sector_size; - int cd_buflen; - int audio_op; - int audio_muted_soft; - int sony_msf; - int real_speed; - int is_early; - int is_nec; - uint32_t inv_field; + int32_t cached_sector; + int32_t cd_buflen; + int32_t sony_msf; + int32_t real_speed; + int32_t is_early; + int32_t is_nec; + int32_t is_bcd; + + int32_t cdrom_sector_size; const cdrom_ops_t *ops; + char * image_history[CD_IMAGE_HISTORY]; + void * local; void * log; @@ -330,22 +332,26 @@ typedef struct cdrom { uint32_t (*get_volume)(void *p, int channel); uint32_t (*get_channel)(void *p, int channel); - int16_t cd_buffer[BUF_SIZE]; + int16_t cd_buffer[CD_BUF_SIZE]; uint8_t subch_buffer[96]; - int cdrom_sector_size; - /* Needs some extra breathing space in case of overflows. */ - uint8_t raw_buffer[4096]; + uint8_t raw_buffer[2][4096]; uint8_t extra_buffer[296]; + + int32_t is_chinon; + int32_t is_pioneer; + int32_t is_plextor; + int32_t is_sony; + int32_t is_toshiba; + + int32_t c2_first; + int32_t cur_buf; } cdrom_t; extern cdrom_t cdrom[CDROM_NUM]; -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ #define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) static __inline int @@ -366,8 +372,6 @@ extern char *cdrom_get_revision(const int type); extern int cdrom_get_scsi_std(const int type); extern int cdrom_is_early(const int type); extern int cdrom_is_generic(const int type); -extern int cdrom_has_date(const int type); -extern int cdrom_is_sony(const int type); extern int cdrom_is_caddy(const int type); extern int cdrom_get_speed(const int type); extern int cdrom_get_inquiry_len(const int type); @@ -384,6 +388,7 @@ extern void cdrom_set_type(const int model, const int type); extern int cdrom_get_type(const int model); extern int cdrom_lba_to_msf_accurate(const int lba); +extern void cdrom_interleave_subch(uint8_t *d, const uint8_t *s); extern double cdrom_seek_time(const cdrom_t *dev); extern void cdrom_stop(cdrom_t *dev); extern void cdrom_seek(cdrom_t *dev, const uint32_t pos, const uint8_t vendor_type); @@ -396,7 +401,7 @@ extern uint8_t cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos extern uint8_t cdrom_audio_track_search_pioneer(cdrom_t *dev, const uint32_t pos, const uint8_t playbit); extern uint8_t cdrom_audio_play_pioneer(cdrom_t *dev, const uint32_t pos); extern uint8_t cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type); -extern uint8_t cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type); +extern uint8_t cdrom_audio_scan(cdrom_t *dev, const uint32_t pos); extern void cdrom_audio_pause_resume(cdrom_t *dev, const uint8_t resume); extern uint8_t cdrom_get_current_status(const cdrom_t *dev); @@ -424,6 +429,7 @@ extern int cdrom_read_dvd_structure(const cdrom_t *dev, const uint8_ uint8_t *buffer, uint32_t *info); extern void cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer); extern int cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer); +extern uint8_t cdrom_get_current_mode(cdrom_t *dev); extern void cdrom_set_empty(cdrom_t *dev); extern void cdrom_update_status(cdrom_t *dev); extern int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert); diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 1c2ec5203..6902ffdfd 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -118,16 +118,6 @@ enum { #define BIOS_INTERLEAVED_INVERT 8 #define BIOS_HIGH_BIT_INVERT 16 -#define device_common_config_t \ - const char *name; \ - const char *description; \ - int type; \ - const char *default_string; \ - int default_int; \ - const char *file_filter; \ - const device_config_spinner_t spinner; \ - const device_config_selection_t selection[32] - typedef struct device_config_selection_t { const char *description; int value; @@ -139,10 +129,6 @@ typedef struct device_config_spinner_t { int16_t step; } device_config_spinner_t; -typedef struct _device_dep_config_ { - device_common_config_t; -} device_dep_config_t; - typedef struct device_config_bios_t { const char *name; const char *internal_name; @@ -153,15 +139,18 @@ typedef struct device_config_bios_t { void *dev1; void *dev2; const char *files[9]; - /* Configuration options that depend on the device variant. - To prevent excessive nesting, there is no CONFIG_BIOS - option a dep_config struct */ - const device_dep_config_t *dep_config; } device_config_bios_t; typedef struct _device_config_ { - device_common_config_t; - const device_config_bios_t bios[32]; + const char *name; + const char *description; + int type; + const char *default_string; + int default_int; + const char *file_filter; + const device_config_spinner_t spinner; + const device_config_selection_t selection[32]; + const device_config_bios_t bios[32]; } device_config_t; typedef struct _device_ { diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 6af4d92e6..4e4ea4e5b 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -133,6 +133,8 @@ typedef struct ide_s { uint8_t (*phase_data_out)(scsi_common_t *sc); void (*command_stop)(scsi_common_t *sc); void (*bus_master_error)(scsi_common_t *sc); + void (*read)(scsi_common_t *sc); + void (*write)(scsi_common_t *sc); #else void * get_max; void * get_timings; diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index b80c21c13..eda4396ef 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -138,55 +138,63 @@ typedef struct hdd_zone_t { /* Define the virtual Hard Disk. */ typedef struct hard_disk_t { - uint8_t id; + uint8_t id; + union { - uint8_t channel; /* Needed for Settings to reduce the number of if's */ + /* Needed for Settings to reduce the number of if's */ + uint8_t channel; - uint8_t mfm_channel; /* Should rename and/or unionize */ - uint8_t esdi_channel; - uint8_t xta_channel; - uint8_t ide_channel; - uint8_t scsi_id; + uint8_t mfm_channel; + uint8_t esdi_channel; + uint8_t xta_channel; + uint8_t ide_channel; + uint8_t scsi_id; }; - uint8_t bus_type; - uint8_t bus_mode; /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ - uint8_t wp; /* Disk has been mounted READ-ONLY */ - uint8_t pad; - uint8_t pad0; - void *priv; + uint8_t bus_type; + uint8_t bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + uint8_t wp; /* Disk has been mounted + READ-ONLY */ + uint8_t pad; + uint8_t pad0; - char fn[1024]; /* Name of current image file */ - char vhd_parent[1041]; /* Differential VHD parent file */ + void * priv; - uint32_t seek_pos; - uint32_t seek_len; - uint32_t base; - uint32_t spt; - uint32_t hpc; /* Physical geometry parameters */ - uint32_t tracks; - const char *model; + char fn[1024]; /* Name of current image file */ + /* Differential VHD parent file */ + char vhd_parent[1280]; - hdd_zone_t zones[HDD_MAX_ZONES]; - uint32_t num_zones; - hdd_cache_t cache; - uint32_t phy_cyl; - uint32_t phy_heads; - uint32_t rpm; - uint8_t max_multiple_block; + uint32_t seek_pos; + uint32_t seek_len; + uint32_t base; + uint32_t spt; /* Physical geometry parameters */ + uint32_t hpc; + uint32_t tracks; + uint32_t speed_preset; - uint32_t cur_cylinder; - uint32_t cur_track; - uint32_t cur_addr; + uint32_t num_zones; + uint32_t phy_cyl; + uint32_t phy_heads; + uint32_t rpm; + uint32_t cur_cylinder; + uint32_t cur_track; + uint32_t cur_addr; + uint32_t vhd_blocksize; - uint32_t speed_preset; - uint32_t vhd_blocksize; + uint8_t max_multiple_block; + uint8_t pad1[3]; - double avg_rotation_lat_usec; - double full_stroke_usec; - double head_switch_usec; - double cyl_switch_usec; + const char * model; + + hdd_zone_t zones[HDD_MAX_ZONES]; + + hdd_cache_t cache; + + double avg_rotation_lat_usec; + double full_stroke_usec; + double head_switch_usec; + double cyl_switch_usec; } hard_disk_t; extern hard_disk_t hdd[HDD_NUM]; diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 1df16c3fe..e09515b10 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -51,10 +51,10 @@ static const mo_type_t mo_types[KNOWN_MO_TYPES] = { }; typedef struct mo_drive_type_t { - const char vendor[9]; - const char model[16]; - const char revision[5]; - int8_t supported_media[KNOWN_MO_TYPES]; + const char *vendor; + const char *model; + const char *revision; + int8_t supported_media[KNOWN_MO_TYPES]; } mo_drive_type_t; #define KNOWN_MO_DRIVE_TYPES 22 @@ -161,6 +161,7 @@ typedef struct mo_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index bc2d4c8bd..7bb39d9db 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -54,18 +54,24 @@ typedef struct scsi_cdrom_t { int do_page_save; int unit_attention; int request_pos; - int old_len; - int media_status; + int wait; + int buffer_pos; uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; - int is_sony; - int use_cdb_9; + uint8_t (*ven_cmd)(void *sc, const uint8_t *cdb, int32_t *BufLen); + int use_cdb_9; + int was_cached; + int toc_cached; + int media_access; + + uint8_t vendor_type; uint8_t ven_cmd_is_data[256]; mode_sense_pages_t ms_drive_status_pages_saved; @@ -74,8 +80,6 @@ typedef struct scsi_cdrom_t { mode_sense_pages_t ms_pages_default; mode_sense_pages_t ms_pages_changeable; - - uint8_t (*ven_cmd)(void *sc, const uint8_t *cdb, int32_t *BufLen); } scsi_cdrom_t; #endif diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index ffe042481..62da8b7dc 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -110,39 +110,40 @@ #define GPCMD_MECHANISM_STATUS 0xbd #define GPCMD_READ_CD 0xbe #define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to 86Box. */ -#define GPCMD_EJECT_CHINON 0xc0 /* Chinon Vendor Unique command */ #define GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA 0xc0 /* Toshiba Vendor Unique command */ -#define GPCMD_SET_ADDRESS_FORMAT_SONY 0xc0 /* Sony Vendor Unique command */ +#define GPCMD_EJECT_CHINON 0xc0 /* Chinon Vendor Unique command */ #define GPCMD_MAGAZINE_EJECT_PIONEER 0xc0 /* Pioneer Vendor Unique command */ +#define GPCMD_SET_ADDRESS_FORMAT_SONY 0xc0 /* Sony Vendor Unique command */ #define GPCMD_PLAY_AUDIO_TOSHIBA 0xc1 /* Toshiba Vendor Unique command */ -#define GPCMD_READ_TOC_SONY 0xc1 /* Sony Vendor Unique command */ #define GPCMD_READ_TOC_PIONEER 0xc1 /* Pioneer Vendor Unique command */ +#define GPCMD_READ_TOC_SONY 0xc1 /* Sony Vendor Unique command */ #define GPCMD_PAUSE_RESUME_ALT 0xc2 #define GPCMD_READ_SUBCHANNEL_MATSUSHITA 0xc2 /* Matsushita Vendor Unique command */ +#define GPCMD_READ_SUBCODEQ_PIONEER 0xc2 /* Pioneer Vendor Unique command */ #define GPCMD_READ_SUBCHANNEL_SONY 0xc2 /* Sony Vendor Unique command */ #define GPCMD_STILL_TOSHIBA 0xc2 /* Toshiba Vendor Unique command */ -#define GPCMD_READ_SUBCODEQ_PIONEER 0xc2 /* Pioneer Vendor Unique command */ #define GPCMD_READ_TOC_MATSUSHITA 0xc3 /* Matsushita Vendor Unique command */ #define GPCMD_READ_HEADER_SONY 0xc3 /* Sony Vendor Unique command */ #define GPCMD_SET_STOP_TIME_TOSHIBA 0xc3 /* Toshiba Vendor Unique command */ -#define GPCMD_READ_HEADER_MATSUSHITA 0xc4 /* Matsushita Vendor Unique command */ -#define GPCMD_PLAYBACK_STATUS_SONY 0xc4 /* Sony Vendor Unique command */ #define GPCMD_CADDY_EJECT_TOSHIBA 0xc4 /* Toshiba Vendor Unique command */ +#define GPCMD_PLAYBACK_STATUS_SONY 0xc4 /* Sony Vendor Unique command */ +#define GPCMD_READ_HEADER_MATSUSHITA 0xc4 /* Matsushita Vendor Unique command */ #define GPCMD_PAUSE_SONY 0xc5 /* Sony Vendor Unique command */ #define GPCMD_PLAY_AUDIO_MATSUSHITA 0xc5 /* Matsushita Vendor Unique command */ #define GPCMD_UNKNOWN_SCSI2_NEC 0xc5 /* NEC Vendor Unique Command */ -#define GPCMD_STOP_CHINON 0xc6 /* Chinon Vendor Unique command */ #define GPCMD_PLAY_TRACK_SONY 0xc6 /* Sony Vendor Unique command */ #define GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA 0xc6 /* Toshiba Vendor Unique command */ +#define GPCMD_STOP_CHINON 0xc6 /* Chinon Vendor Unique command */ #define GPCMD_PLAY_AUDIO_MSF_MATSUSHITA 0xc7 /* Matsushita Vendor Unique command*/ #define GPCMD_PLAY_MSF_SONY 0xc7 /* Sony Vendor Unique command*/ #define GPCMD_READ_DISC_INFORMATION_TOSHIBA 0xc7 /* Toshiba Vendor Unique command */ -#define GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA 0xc8 /* Matsushita Vendor Unique command */ -#define GPCMD_PLAY_AUDIO_SONY 0xc8 /* Sony Vendor Unique command */ #define GPCMD_AUDIO_TRACK_SEARCH_PIONEER 0xc8 /* Pioneer Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_SONY 0xc8 /* Sony Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA 0xc8 /* Matsushita Vendor Unique command */ +#define GPCMD_READ_CDROM_MODE_TOSHIBA 0xc8 /* Toshiba Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_PIONEER 0xc9 /* Pioneer Vendor Unique command */ #define GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10_MATSUSHITA 0xc9 /* Matsushita Vendor Unique command */ #define GPCMD_PLAYBACK_CONTROL_SONY 0xc9 /* Sony Vendor Unique command */ -#define GPCMD_PLAY_AUDIO_PIONEER 0xc9 /* Pioneer Vendor Unique command */ #define GPCMD_PAUSE_PIONEER 0xca /* Pioneer Vendor Unique command */ #define GPCMD_PAUSE_RESUME_MATSUSHITA 0xcb /* Matsushita Vendor Unique command */ #define GPCMD_STOP_PIONEER 0xcb /* Pioneer Vendor Unique command */ @@ -151,8 +152,8 @@ #define GPCMD_READ_CD_MSF_OLD 0xd5 /* Should be equivalent to 0xb9 */ #define GPCMD_AUDIO_TRACK_SEARCH_NEC 0xd8 /* NEC Vendor Unique command */ #define GPCMD_PLAY_AUDIO_NEC 0xd9 /* NEC Vendor Unique command */ -#define GPCMD_STILL_NEC 0xda /* NEC Vendor Unique command */ #define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ +#define GPCMD_STILL_NEC 0xda /* NEC Vendor Unique command */ #define GPCMD_SET_STOP_TIME_NEC 0xdb /* NEC Vendor Unique command */ #define GPCMD_CADDY_EJECT_NEC 0xdc /* NEC Vendor Unique command */ #define GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC 0xdd /* NEC Vendor Unique command */ @@ -409,12 +410,13 @@ typedef struct scsi_common_s { int do_page_save; int unit_attention; int request_pos; - int old_len; - int media_status; + int wait; + int buffer_pos; uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/include/86box/scsi_disk.h b/src/include/86box/scsi_disk.h index 7099b836a..293cc35e6 100644 --- a/src/include/86box/scsi_disk.h +++ b/src/include/86box/scsi_disk.h @@ -53,6 +53,7 @@ typedef struct scsi_disk_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/include/86box/zip.h b/src/include/86box/zip.h index 06c6e8485..443ab1327 100644 --- a/src/include/86box/zip.h +++ b/src/include/86box/zip.h @@ -108,6 +108,7 @@ typedef struct zip_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 13e0ec9a7..272b389c5 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -65,6 +65,7 @@ extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1); #include "ui_qt_mainwindow.h" bool windows_is_light_theme() { + return 0; // based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application // The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 621cf0b76..3d9ecefd5 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -91,6 +91,20 @@ ioctl_open_handle(ioctl_t *ioctl) ioctl_log(ioctl->log, "handle=%p, error=%x\n", ioctl->handle, (unsigned int) GetLastError()); + if (ioctl->handle != INVALID_HANDLE_VALUE) { + CDROM_SET_SPEED set_speed = { 0 }; + + set_speed.RequestType = CdromSetSpeed; + set_speed.ReadSpeed = 0xffff; + set_speed.WriteSpeed = 0xffff; + set_speed.RotationControl = CdromDefaultRotation; + + (void) DeviceIoControl(ioctl->handle, IOCTL_CDROM_SET_SPEED, + &set_speed, sizeof(set_speed), + NULL, 0, + 0, NULL); + } + return (ioctl->handle != INVALID_HANDLE_VALUE); } diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 04c6532df..07590d5ae 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,6 +15,7 @@ */ #include #include +#define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -110,6 +111,7 @@ uint8_t scsi_cdrom_command_flags[0x100] = { [0xbd] = IMPLEMENTED, [0xbe ... 0xbf] = IMPLEMENTED | CHECK_READY, [0xc0 ... 0xcd] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xd5] = IMPLEMENTED | CHECK_READY, [0xd8 ... 0xde] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, [0xe0 ... 0xe1] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, [0xe3 ... 0xe9] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, @@ -303,15 +305,14 @@ scsi_cdrom_init(scsi_cdrom_t *dev) dev->tf->status = 0; dev->tf->pos = 0; dev->packet_status = PHASE_NONE; - scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + scsi_cdrom_sense_key = scsi_cdrom_asc = + scsi_cdrom_ascq = dev->unit_attention = 0; scsi_cdrom_info = 0x00000000; dev->drv->cd_status &= ~CD_STATUS_TRANSITION; dev->drv->cur_speed = dev->drv->real_speed; scsi_cdrom_mode_sense_load(dev); - const char *vendor = cdrom_get_vendor(dev->drv->type); - - if ((dev->drv->bus_type == CDROM_BUS_SCSI) && !strcmp(vendor, "PIONEER")) + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && dev->drv->is_pioneer) scsi_cdrom_drive_status_load(dev); } } @@ -339,7 +340,7 @@ scsi_cdrom_get_channel(void *priv, const int channel) uint32_t ret = channel + 1; if (dev != NULL) - ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; + ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8] & 0x0f; return ret; } @@ -530,7 +531,8 @@ scsi_cdrom_mode_sense(const scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, buf[pos++] = ((dev->drv->cur_speed * 176) & 0xff); else buf[pos++] = ((dev->drv->cur_speed * 176) >> 8); - } else if (dev->is_sony && (i == GPMODE_CDROM_AUDIO_PAGE_SONY) && + } else if (dev->drv->is_sony && + (i == GPMODE_CDROM_AUDIO_PAGE_SONY) && (j >= 6) && (j <= 13)) buf[pos++] = scsi_cdrom_mode_sense_read(dev, pgctl, GPMODE_CDROM_AUDIO_PAGE, 2 + j); @@ -559,13 +561,21 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len matches the block length. */ switch (dev->current_cdb[0]) { + case 0xbc: + if (!dev->drv->is_early) { + dev->packet_len = len; + break; + } + fallthrough; case 0x08: case 0x28: case 0xa8: + case 0xb8: case 0xb9: case 0xbe: + case 0xd5: /* Round it to the nearest (block length) bytes. */ - if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { + if (dev->current_cdb[0] >= 0xb8) { /* READ CD MSF and READ CD: Round the request length to the sector size - the device must ensure that a media access comand does not DRQ in the middle @@ -601,10 +611,11 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len break; } } + dev->requested_blocks = 1; fallthrough; default: - dev->packet_len = len; + dev->packet_len = len; break; } /* @@ -649,16 +660,10 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) } static void -scsi_cdrom_command_common(scsi_cdrom_t *dev) +scsi_cdrom_set_period(scsi_cdrom_t *dev) { const uint8_t cmd = dev->current_cdb[0]; - /* MAP: BUSY_STAT, no DRQ, phase 1. */ - dev->tf->status = BUSY_STAT; - dev->tf->phase = 1; - dev->tf->pos = 0; - dev->callback = 0; - scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); if (dev->packet_status == PHASE_COMPLETE) @@ -667,91 +672,38 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) double bytes_per_second; double period; - switch (cmd) { - case GPCMD_REZERO_UNIT: - case 0x0b: - case 0x2b: - /* Seek time is in us. */ - period = cdrom_seek_time(dev->drv); - scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", - (uint64_t) period); - dev->callback += period; + if (dev->was_cached != -1) { + if (dev->was_cached) { + dev->callback += 512.0; scsi_cdrom_set_callback(dev); return; - case 0x43: - dev->drv->seek_diff = dev->drv->seek_pos + 150; - dev->drv->seek_pos = 0; - fallthrough; - case 0x08: - case 0x28: - case 0x42: case 0x44: - case 0xa8: - /* Seek time is in us. */ - period = cdrom_seek_time(dev->drv); - scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", - (uint64_t) period); - scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us, speed: %" - PRIu64 " bytes per second, should be: %" - PRIu64 " bytes per second\n", - (uint64_t) period, (uint64_t) (1000000.0 / period), - (uint64_t) (176400.0 * (double) dev->drv->cur_speed)); - dev->callback += period; - fallthrough; - case 0x25: - // case 0x42 ... 0x44: - case 0x51 ... 0x52: - case 0xad: - case 0xb8 ... 0xb9: - case 0xbe: - if (dev->current_cdb[0] == 0x42) - dev->callback += 40.0; - /* Account for seek time. */ - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - /* - TODO: This is a bit of a lie - the actual period is closer to - 75 * 2448 bytes per second, because the subchannel data - has to be read as well. - */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - case 0xc0 ... 0xc3: - case 0xc6 ... 0xc7: - case 0xdd ... 0xde: - if (dev->ven_cmd_is_data[cmd]) { - if (dev->current_cdb[0] == 0xc2) - dev->callback += 40.0; - /* Account for seek time. */ - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - } - fallthrough; - default: - bytes_per_second = scsi_cdrom_bus_speed(dev); - if (bytes_per_second == 0.0) { - dev->callback = -1; /* Speed depends on SCSI controller */ - return; - } - break; + } + + /* Seek time is in us. */ + period = cdrom_seek_time(dev->drv); + scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", + (uint64_t) period); + dev->callback += period; + + /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ + bytes_per_second = 176400.0; + bytes_per_second *= (double) dev->drv->cur_speed; + } else { + bytes_per_second = scsi_cdrom_bus_speed(dev); + if (bytes_per_second == 0.0) { + dev->callback = -1; /* Speed depends on SCSI controller */ + return; + } } period = 1000000.0 / bytes_per_second; scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); - switch (cmd) { - default: - period = period * (double) (dev->packet_len); - break; - case 0x42: case 0x44: - /* READ SUBCHANNEL or READ HEADER - period of 1 entire sector. */ - period = period * 2352.0; - break; - case 0x43: - /* READ TOC - period of 175 entire frames. */ - period = period * 150.0 * 2352.0; - break; + if (dev->was_cached == -1) + period *= (double) dev->packet_len; + else { + period *= ((double) dev->requested_blocks) * 2352.0; + pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, dev->requested_blocks); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); @@ -760,6 +712,18 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) scsi_cdrom_set_callback(dev); } +static void +scsi_cdrom_command_common(scsi_cdrom_t *dev) +{ + /* MAP: BUSY_STAT, no DRQ, phase 1. */ + dev->tf->status = BUSY_STAT; + dev->tf->phase = 1; + dev->tf->pos = 0; + dev->callback = 0; + + scsi_cdrom_set_period(dev); +} + static void scsi_cdrom_command_complete(scsi_cdrom_t *dev) { @@ -977,7 +941,7 @@ scsi_cdrom_invalid_lun(scsi_cdrom_t *dev, const uint8_t lun) static void scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev, const uint8_t opcode) { - scsi_cdrom_log(dev->log, "Illegal opcode\n"); + scsi_cdrom_log(dev->log, "Illegal opcode: %02X\n", opcode); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_ILLEGAL_OPCODE; scsi_cdrom_ascq = 0; @@ -988,7 +952,7 @@ scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev, const uint8_t opcode) static void scsi_cdrom_lba_out_of_range(scsi_cdrom_t *dev) { - scsi_cdrom_log(dev->log, "LBA out of range\n"); + scsi_cdrom_log(dev->log, "LBA out of range: %08X\n", dev->sector_pos); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_LBA_OUT_OF_RANGE; scsi_cdrom_ascq = 0; @@ -1073,7 +1037,7 @@ scsi_cdrom_illegal_mode(scsi_cdrom_t *dev) static int scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int flags, - int32_t *len, const int vendor_type) + const int vendor_type) { int temp_len = 0; int ret = 0; @@ -1081,69 +1045,60 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); else { - const uint32_t cdsize = dev->drv->cdrom_capacity; - - if (dev->sector_pos >= cdsize) { - scsi_cdrom_log(dev->log, "Trying to read from beyond the end of " - "disc (%i >= %i)\n", dev->sector_pos, cdsize); + if (dev->sector_pos > dev->drv->cdrom_capacity) { scsi_cdrom_lba_out_of_range(dev); ret = -1; } else { - int data_pos = 0; + ret = cdrom_readsector_raw(dev->drv, dev->buffer + dev->buffer_pos, + dev->sector_pos, msf, type, + flags, &temp_len, vendor_type); - dev->old_len = 0; - *len = 0; + if (ret < 0) + scsi_cdrom_circ_error(dev); + else if (ret == 0) + scsi_cdrom_illegal_mode(dev); + else { + if (dev->block_len == 0xffffffff) + dev->block_len = temp_len; - ret = 1; + dev->sector_pos++; + dev->drv->seek_pos = dev->sector_pos; - for (int i = 0; i < dev->requested_blocks; i++) { - ret = cdrom_readsector_raw(dev->drv, dev->buffer + data_pos, - dev->sector_pos + i, msf, type, - flags, &temp_len, vendor_type); + dev->sector_len--; - data_pos += temp_len; - dev->old_len += temp_len; - - *len += temp_len; - - if (ret == 0) { - scsi_cdrom_illegal_mode(dev); - break; - } - - if (ret < 0) { - scsi_cdrom_circ_error(dev); - break; - } + pclog("Sector read to buffer position %08X\n", dev->buffer_pos); + dev->buffer_pos += temp_len; } } } + if ((ret < 1) || (dev->sector_len == 0)) + dev->wait = 0; + return ret; } static int -scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, const int vendor_type) +scsi_cdrom_read_blocks(scsi_cdrom_t *dev) { int ret = 1; int msf = 0; int type = dev->sector_type; int flags = dev->sector_flags; - /* Any of these commands stop the audio playing. */ - cdrom_stop(dev->drv); - switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: case GPCMD_READ_CD_MSF: msf = 1; fallthrough; + case GPCMD_PLAY_CD: case GPCMD_READ_CD_OLD: case GPCMD_READ_CD: type = (dev->current_cdb[1] >> 2) & 7; flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); break; case GPCMD_READ_HEADER: + case GPCMD_READ_HEADER_SONY: type = 0x00; flags = 0x20; break; @@ -1164,16 +1119,10 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, const int vendor_type) scsi_cdrom_log(dev->log, "Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - ret = scsi_cdrom_read_data(dev, msf, type, flags, len, vendor_type); + ret = scsi_cdrom_read_data(dev, msf, type, flags, dev->vendor_type); - scsi_cdrom_log(dev->log, "Read %i bytes of blocks (ret = %i)...\n", *len, ret); - } - - if ((ret > 0) && (dev->current_cdb[0] != GPCMD_READ_HEADER)) { - dev->sector_pos += dev->requested_blocks; - dev->drv->seek_pos = dev->sector_pos; - - dev->sector_len -= dev->requested_blocks; + scsi_cdrom_log(dev->log, "Read %i bytes of blocks (ret = %i)...\n", + dev->block_len, ret); } return ret; @@ -1214,7 +1163,7 @@ scsi_command_check_ready(const scsi_cdrom_t *dev, const uint8_t *cdb) check for ready status but they do on Y vendor. Quite confusing I know. */ - if (!dev->is_sony || (cdb[0] != 0xc0)) + if (!dev->drv->is_sony || (cdb[0] != 0xc0)) ret = 1; } else if ((cdb[0] == GPCMD_READ_DVD_STRUCTURE) && (cdb[7] < 0xc0)) ret = 1; @@ -1317,12 +1266,6 @@ skip_ready_check: if (cdb[0] != GPCMD_REQUEST_SENSE) scsi_cdrom_sense_clear(dev, cdb[0]); - /* Next it's time for NOT READY. */ - if (ready) - dev->media_status = dev->unit_attention ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - else - dev->media_status = MEC_MEDIA_REMOVAL; - if (!ready && scsi_command_check_ready(dev, cdb)) { scsi_cdrom_log(dev->log, "Not ready (%02X)\n", cdb[0]); scsi_cdrom_not_ready(dev); @@ -1336,6 +1279,7 @@ skip_ready_check: static void scsi_cdrom_rezero(scsi_cdrom_t *dev) { + dev->drv->seek_diff = ABS(dev->sector_pos); dev->sector_pos = dev->sector_len = 0; cdrom_seek(dev->drv, 0, 0); } @@ -1388,6 +1332,10 @@ scsi_cdrom_update_sector_flags(scsi_cdrom_t *dev) dev->sector_type = 0x00; dev->sector_flags = 0x02f8; break; + case 2646: + dev->sector_type = 0x00; + dev->sector_flags = 0x00fa; + break; } return ret; @@ -1412,9 +1360,11 @@ scsi_cdrom_reset(scsi_common_t *sc) dev->drv->sector_size = 2048; (void) scsi_cdrom_update_sector_flags(dev); - scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; - scsi_cdrom_info = 0x00000000; - dev->drv->cd_status &= ~CD_STATUS_TRANSITION; + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + scsi_cdrom_info = 0x00000000; + dev->drv->cd_status &= ~CD_STATUS_TRANSITION; + dev->drv->cached_sector = -1; + dev->toc_cached = 0; } } @@ -1498,6 +1448,8 @@ scsi_cdrom_stop(const scsi_common_t *sc) const scsi_cdrom_t *dev = (const scsi_cdrom_t *) sc; cdrom_stop(dev->drv); + + ui_sb_update_icon(SB_CDROM | dev->id, 0); } static void @@ -1536,6 +1488,7 @@ scsi_cdrom_command_chinon(void *sc, const uint8_t *cdb, UNUSED(int32_t *BufLen)) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; @@ -1551,16 +1504,66 @@ scsi_cdrom_command_chinon(void *sc, const uint8_t *cdb, UNUSED(int32_t *BufLen)) return cmd_stat; } +static void +scsi_cdrom_cache_toc(scsi_cdrom_t *dev) +{ + if (!dev->toc_cached) { + dev->toc_cached = 1; + dev->drv->seek_diff = dev->drv->seek_pos + 150; + dev->sector_pos = -150; + dev->drv->seek_pos = -150; + dev->requested_blocks = 150; + dev->drv->cached_sector = -1; + } +} + +static void +scsi_cdrom_one_sector_seek(scsi_cdrom_t *dev) +{ + if (!dev->was_cached) { + dev->drv->seek_diff = 0; + dev->requested_blocks = 1; + } +} + +static void +scsi_cdrom_media_access_complete(scsi_cdrom_t *dev, const int ret) +{ + ui_sb_update_icon(SB_CDROM | dev->id, 0); + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); +} + +static void +scsi_cdrom_read(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + const int ret = scsi_cdrom_read_blocks(dev); + + dev->drv->seek_diff = 0; + + if (ret > 0) { + if (dev->packet_status != PHASE_COMPLETE) { + ui_sb_update_icon(SB_CDROM | dev->id, 1); + + scsi_cdrom_set_period(dev); + } else + ui_sb_update_icon(SB_CDROM | dev->id, 0); + } else + scsi_cdrom_media_access_complete(dev, ret); +} + static uint8_t scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int msf; + int ret = 1; uint8_t cmd_stat = 0x00; + int msf; int len; int max_len; - int alloc_length; - int real_pos; switch (cdb[0]) { default: @@ -1575,7 +1578,9 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_TOC_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - msf = dev->drv->sony_msf; + dev->was_cached = dev->toc_cached; + + msf = dev->drv->sony_msf; max_len = cdb[7]; max_len <<= 8; @@ -1592,6 +1597,8 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) /* If the returned length is -1, this means cdrom_read_toc_sony() has encountered an error. */ scsi_cdrom_invalid_field(dev, dev->drv->inv_field); else { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } @@ -1601,6 +1608,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_SUBCHANNEL_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); max_len = cdb[7]; max_len <<= 8; @@ -1615,6 +1623,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, 9); len = 9; cdrom_get_current_subchannel_sony(dev->drv, dev->buffer, msf); + scsi_cdrom_one_sector_seek(dev); len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -1631,23 +1640,54 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_HEADER_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = ((cdb[7] << 8) | cdb[8]); - scsi_cdrom_buf_alloc(dev, 4); + len = (cdb[7] << 8) | cdb[8]; + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + dev->was_cached = (dev->drv->cached_sector == dev->sector_pos); + scsi_cdrom_log(dev->log, "READ HEADER SONY: Length: %i, LBA: %i\n", + dev->sector_len, dev->sector_pos); - dev->sector_len = 1; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); - dev->buffer[0] = ((real_pos >> 16) & 0xff); - dev->buffer[1] = ((real_pos >> 8) & 0xff); - dev->buffer[2] = real_pos & 0xff; - dev->buffer[3] = 1; /*2048 bytes user data*/ + if (len > 0) { + max_len = 1; + dev->requested_blocks = 1; - len = 4; - len = MIN(len, alloc_length); + dev->packet_len = len; + scsi_cdrom_buf_alloc(dev, 2352); - scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_one_sector_seek(dev); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); + /* Any of these commands stop the audio playing. */ + cdrom_stop(dev->drv); + + dev->vendor_type = 0x00; + + dev->buffer_pos = 0x00000000; + + ret = scsi_cdrom_read_blocks(dev); + + if (ret > 0) { + len = MIN(4, len); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, + len, 0); + + ui_sb_update_icon(SB_CDROM | dev->id, 0); + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_cdrom_log(dev->log, "All done - callback set\n"); */ + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } cmd_stat = 0x01; break; @@ -1702,7 +1742,11 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_illegal_mode(dev); else { /* In this case, len is unused so just pass a fixed value of 1 intead. */ - const int ret = cdrom_audio_play(dev->drv, pos, 1, msf); + const int ret = cdrom_audio_play(dev->drv, pos, 1, msf); + dev->requested_blocks = 0; + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -1746,6 +1790,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 1); } + cmd_stat = 0x01; break; } @@ -1874,12 +1919,16 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) scsi_cdrom_illegal_mode(dev); else { - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -1909,7 +1958,6 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_STILL_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, 0x00); - dev->drv->audio_op = 0x01; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; @@ -1924,12 +1972,14 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; case GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector == -1); alloc_length = cdb[1] & 0x1f; len = 10; @@ -1958,6 +2008,8 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_DISC_INFORMATION_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; + /* NEC manual claims 4 bytes but the Linux kernel (namely sr_vendor.c) actually states otherwise. @@ -1967,6 +2019,8 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); len = 22; if (ret) { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else @@ -1998,12 +2052,15 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; case GPCMD_READ_TOC_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; + scsi_cdrom_buf_alloc(dev, 4); if (dev->drv->ops == NULL) @@ -2013,6 +2070,8 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) len = 4; if (ret) { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else @@ -2023,6 +2082,7 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_SUBCODEQ_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); alloc_length = cdb[1] & 0x1f; len = 9; @@ -2041,6 +2101,7 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); cdrom_get_current_subcodeq(dev->drv, &dev->buffer[1]); + scsi_cdrom_one_sector_seek(dev); scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[0]); scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); @@ -2051,15 +2112,18 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) ret = 0; else { pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; ret = cdrom_audio_track_search_pioneer(dev->drv, pos, cdb[1] & 1); - - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; } + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; + if (ret) scsi_cdrom_command_complete(dev); else @@ -2178,13 +2242,17 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) { scsi_cdrom_illegal_mode(dev); break; } - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -2213,7 +2281,6 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_STILL_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, 0x00); - dev->drv->audio_op = 0x01; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; @@ -2228,12 +2295,14 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; case GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); alloc_length = cdb[1] & 0x1f; len = 10; @@ -2252,6 +2321,7 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); dev->buffer[0] = cdrom_get_current_subcodeq_playstatus(dev->drv, &dev->buffer[1]); + scsi_cdrom_one_sector_seek(dev); scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[0]); scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); @@ -2262,6 +2332,8 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_DISC_INFORMATION_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; + scsi_cdrom_buf_alloc(dev, 4); if (dev->drv->ops == NULL) @@ -2270,6 +2342,8 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); len = 4; if (ret) { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else @@ -2277,6 +2351,25 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) } cmd_stat = 0x01; break; + + case GPCMD_READ_CDROM_MODE_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); + + scsi_cdrom_buf_alloc(dev, 1); + + alloc_length = 1; + + len = alloc_length; + dev->buffer[0] = cdrom_get_current_mode(dev->drv); + + scsi_cdrom_one_sector_seek(dev); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + + cmd_stat = 0x01; + break; } return cmd_stat; @@ -2306,6 +2399,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) int toc_format; int32_t *BufLen; + dev->was_cached = -1; + if (dev->drv->bus_type == CDROM_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; dev->tf->status &= ~ERR_STAT; @@ -2317,6 +2412,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; + dev->block_len = 0; + memcpy(dev->current_cdb, cdb, 12); #if ENABLE_SCSI_CDROM_LOG == 2 @@ -2331,8 +2428,9 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) cdb[8], cdb[9], cdb[10], cdb[11]); #endif - msf = cdb[1] & 2; - dev->sector_len = 0; + msf = cdb[1] & 2; + dev->sector_len = 0; + dev->requested_blocks = 0; scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); @@ -2348,17 +2446,22 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_sense_clear(dev, cdb[0]); } - if ((dev->ven_cmd == NULL) || (dev->ven_cmd(sc, cdb, BufLen) == 0x00)) switch (dev->current_cdb[0]) { + if ((dev->ven_cmd == NULL) || + (dev->ven_cmd(sc, cdb, BufLen) == 0x00)) switch (dev->current_cdb[0]) { case GPCMD_TEST_UNIT_READY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); break; case GPCMD_REZERO_UNIT: + pclog("Rezero unit\n"); + dev->was_cached = 0; scsi_cdrom_stop(sc); - dev->sector_pos = dev->sector_len = 0; + dev->requested_blocks = 0; dev->drv->seek_diff = dev->drv->seek_pos; cdrom_seek(dev->drv, 0, 0); + dev->sector_pos = dev->drv->seek_pos; + dev->drv->cached_sector = -1; scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); break; @@ -2386,7 +2489,9 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_SCAN_PIONEER: case GPCMD_AUDIO_SCAN: + pclog("Audio scan\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) { @@ -2395,7 +2500,10 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) } pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - ret = cdrom_audio_scan(dev->drv, pos, 0); + ret = cdrom_audio_scan(dev->drv, pos); + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -2419,6 +2527,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_TOC_PMA_ATIP: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; max_len = cdb[7]; max_len <<= 8; @@ -2427,6 +2536,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); toc_format = cdb[2] & 0xf; + pclog("READ TOC format %1X\n", toc_format); if (toc_format == 0) toc_format = (cdb[9] >> 6) & 3; @@ -2439,6 +2549,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) if (len == -1) scsi_cdrom_invalid_field(dev, dev->drv->inv_field); else { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } @@ -2446,6 +2558,16 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_invalid_field(dev, toc_format); break; + case GPCMD_PLAY_CD: + /* + According to the ATAPI specification, this was actually READ CD + on early drives. + */ + if (!dev->drv->is_early) { + scsi_cdrom_illegal_opcode(dev, dev->current_cdb[0]); + break; + } + fallthrough; case GPCMD_READ_6: case GPCMD_READ_10: case GPCMD_READ_12: @@ -2454,9 +2576,11 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_CD: case GPCMD_READ_CD_MSF: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = dev->drv->sector_size; + dev->was_cached = 0; - switch (cdb[0]) { + alloc_length = dev->drv->sector_size; + + switch (dev->current_cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; /* @@ -2491,6 +2615,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_CD_MSF: msf = 1; fallthrough; + case GPCMD_PLAY_CD: case GPCMD_READ_CD_OLD: case GPCMD_READ_CD: alloc_length = 2856; @@ -2535,22 +2660,30 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); dev->drv->seek_pos = dev->sector_pos; - if (dev->use_cdb_9 && ((cdb[0] == GPCMD_READ_10) || - (cdb[0] == GPCMD_READ_12))) - ret = scsi_cdrom_read_blocks(dev, &alloc_length, - cdb[9] & 0xc0); + /* Any of these commands stop the audio playing. */ + cdrom_stop(dev->drv); + + if (dev->use_cdb_9 && + ((dev->current_cdb[0] == GPCMD_READ_10) || + (dev->current_cdb[0] == GPCMD_READ_12))) + dev->vendor_type = cdb[9] & 0xc0; else - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 0); + dev->vendor_type = 0x00; + + dev->block_len = 0xffffffff; + dev->buffer_pos = 0x00000000; + + ret = scsi_cdrom_read_blocks(dev); + alloc_length = dev->requested_blocks * dev->block_len; if (ret > 0) { - dev->requested_blocks = max_len; dev->packet_len = alloc_length; scsi_cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); scsi_cdrom_data_command_finish(dev, alloc_length, - alloc_length / dev->requested_blocks, + dev->block_len, alloc_length, 0); if (dev->packet_status != PHASE_COMPLETE) @@ -2575,11 +2708,14 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_HEADER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = 2352; - len = (cdb[7] << 8) | cdb[8]; - dev->sector_len = 1; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + alloc_length = 2352; + + len = (cdb[7] << 8) | cdb[8]; + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + dev->was_cached = (dev->drv->cached_sector == dev->sector_pos); scsi_cdrom_log(dev->log, "READ HEADER: Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); @@ -2590,10 +2726,15 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->packet_len = len; scsi_cdrom_buf_alloc(dev, 2352); - dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); - dev->drv->seek_pos = dev->sector_pos; + scsi_cdrom_one_sector_seek(dev); - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 0); + /* Any of these commands stop the audio playing. */ + cdrom_stop(dev->drv); + + dev->vendor_type = 0x00; + + dev->buffer_pos = 0x00000000; + ret = scsi_cdrom_read_blocks(dev); if (ret > 0) { uint8_t header[4] = { 0 }; @@ -2650,7 +2791,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) else block_desc = !((cdb[1] >> 3) & 1); - if (cdb[0] == GPCMD_MODE_SENSE_6) { + if (dev->current_cdb[0] == GPCMD_MODE_SENSE_6) { len = cdb[4]; scsi_cdrom_buf_alloc(dev, 256); } else { @@ -2681,7 +2822,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) else max_len = 3; /* Audio or mixed-mode CD. */ - if (cdb[0] == GPCMD_MODE_SENSE_6) { + if (dev->current_cdb[0] == GPCMD_MODE_SENSE_6) { len = scsi_cdrom_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); len = MIN(len, alloc_length); dev->buffer[0] = len - 1; @@ -2714,7 +2855,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_MODE_SELECT_10: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); - if (cdb[0] == GPCMD_MODE_SELECT_6) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { len = cdb[4]; scsi_cdrom_buf_alloc(dev, 256); } else { @@ -2919,7 +3060,10 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) gesn_event_header->notification_class |= GESN_MEDIA; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status. */ - dev->buffer[4] = dev->media_status; + if (dev->drv->cd_status == CD_STATUS_EMPTY) + dev->buffer[4] = MEC_MEDIA_REMOVAL; + else + dev->buffer[4] = dev->unit_attention ? MEC_NEW_MEDIA : MEC_NO_CHANGE; /* Power Status (1 = Active). */ dev->buffer[5] = 1; dev->buffer[6] = 0; @@ -2947,6 +3091,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_DISC_INFORMATION: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; max_len = cdb[7]; max_len <<= 8; @@ -2958,6 +3103,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = MIN(34, max_len); + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -2965,6 +3112,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_TRACK_INFORMATION: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; max_len = cdb[7]; max_len <<= 8; @@ -2983,6 +3131,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->buffer[1] = (max_len - 2) & 0xff; } + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); } else @@ -2999,21 +3149,25 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = 0; - switch (cdb[0]) { + switch (dev->current_cdb[0]) { case GPCMD_PLAY_AUDIO_10: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; + pclog("Play audio (10)\n"); break; case GPCMD_PLAY_AUDIO_12: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + pclog("Play audio (12)\n"); break; case GPCMD_PLAY_AUDIO_MSF: msf = 1; pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", + cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); break; case GPCMD_PLAY_AUDIO_TRACK_INDEX: msf = 2; @@ -3022,16 +3176,19 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = cdb[7]; } else ret = 0; + pclog("Play audio track index\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: msf = 0x100 | cdb[6]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; + pclog("Play audio track relative (10)\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: msf = 0x100 | cdb[10]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + pclog("Play audio track relative (12)\n"); break; default: @@ -3039,9 +3196,11 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) } if (ret && (dev->drv->image_path[0] != 0x00) && - (dev->drv->cd_status > CD_STATUS_DVD)) - ret = cdrom_audio_play(dev->drv, pos, len, msf); - else + (dev->drv->cd_status > CD_STATUS_DVD)) { + ret = cdrom_audio_play(dev->drv, pos, len, msf); + + dev->sector_pos = dev->drv->seek_pos; + } else ret = 0; if (ret) @@ -3052,13 +3211,14 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_SUBCHANNEL: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; msf = (cdb[1] >> 1) & 1; - scsi_cdrom_buf_alloc(dev, 32); + scsi_cdrom_buf_alloc(dev, 128); scsi_cdrom_log(dev->log, "Getting page %i (%s)\n", cdb[3], msf ? "MSF" : "LBA"); @@ -3090,23 +3250,23 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = alloc_length; - memset(dev->buffer, 0, 24); - pos = 0x00; - dev->buffer[pos++] = 0x00; - dev->buffer[pos++] = 0x00; /* Audio status */ - dev->buffer[pos++] = 0x00; - dev->buffer[pos++] = 0x00; /* Subchannel length */ - dev->buffer[pos++] = cdb[3]; /* Format code */ + memset(dev->buffer, 0x00, 128); - if (alloc_length != 4) { + if (alloc_length > 4) { + dev->buffer[4] = cdb[3]; /* Format code */ cdrom_get_current_subchannel(dev->drv, &dev->buffer[4], msf); - dev->buffer[2] = alloc_length - 4; + alloc_length = MIN(max_len, alloc_length); + + dev->buffer[3] = (alloc_length - 4) & 0xff; + dev->buffer[4] = cdb[3]; /* Format code */ } dev->buffer[1] = cdrom_get_current_status(dev->drv); - scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[1]); + scsi_cdrom_log(dev->log, "Audio status: %02X\n", dev->buffer[1]); + + scsi_cdrom_one_sector_seek(dev); len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -3119,7 +3279,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - scsi_cdrom_buf_alloc(dev, alloc_length); if ((cdb[7] < 0xc0) && (dev->drv->cd_status != CD_STATUS_DVD)) @@ -3168,10 +3327,13 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) This makes no sense under emulation as this would do absolutely nothing, so just break. */ + dev->toc_cached = 0; + scsi_cdrom_cache_toc(dev); break; case 2: /* Eject the disc if possible. */ scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; break; case 3: /* Load the disc (close tray). */ cdrom_reload(dev->id); @@ -3267,7 +3429,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) if (dev->drv->bus_type == CDROM_BUS_SCSI) { dev->buffer[3] = cdrom_get_scsi_std(dev->drv->type); - if (!strcmp(cdrom_get_vendor(dev->drv->type), "TOSHIBA")) + if (dev->drv->is_toshiba) /* Linked Command and Relative Addressing supported */ dev->buffer[7] = 0x88; } else { @@ -3287,7 +3449,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) ide_padstr8(dev->buffer + 32, 4, cdrom_get_revision(dev->drv->type)); /* Revision */ - if (cdrom_has_date(dev->drv->type)) { + if (dev->drv->is_pioneer) { dev->buffer[36] = 0x20; ide_padstr8(dev->buffer + 37, 10, "1991/01/01"); /* Date */ } @@ -3321,15 +3483,16 @@ atapi_out: case GPCMD_PAUSE_RESUME: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, cdb[8] & 0x01); - dev->drv->audio_op = (cdb[8] & 0x01) ? 0x03 : 0x01; scsi_cdrom_command_complete(dev); break; case GPCMD_SEEK_6: case GPCMD_SEEK_10: + pclog("Seek\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; - switch (cdb[0]) { + switch (dev->current_cdb[0]) { case GPCMD_SEEK_6: pos = (cdb[2] << 8) | cdb[3]; break; @@ -3346,16 +3509,20 @@ atapi_out: /* Stop the audio playing. */ cdrom_stop(dev->drv); - if (dev->use_cdb_9 && (cdb[0] == GPCMD_SEEK_10)) + if (dev->use_cdb_9 && (dev->current_cdb[0] == GPCMD_SEEK_10)) cdrom_seek(dev->drv, pos, cdb[9] & 0xc0); else cdrom_seek(dev->drv, pos, 0); + dev->sector_pos = dev->drv->seek_pos; + dev->drv->cached_sector = -1; + scsi_cdrom_command_complete(dev); break; case GPCMD_READ_CDROM_CAPACITY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; scsi_cdrom_buf_alloc(dev, 8); @@ -3370,6 +3537,8 @@ atapi_out: scsi_cdrom_log(dev->log, "CD-ROM Capacity: %08X\n", dev->drv->cdrom_capacity - 1); + + scsi_cdrom_cache_toc(dev); scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -3388,7 +3557,7 @@ atapi_out: break; default: - scsi_cdrom_illegal_opcode(dev, cdb[0]); + scsi_cdrom_illegal_opcode(dev, dev->current_cdb[0]); break; } @@ -3486,7 +3655,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += 2; - if (dev->is_sony && (page == 0x08) && (page_len == 0x02)) + if (dev->drv->is_sony && (page == 0x08) && (page_len == 0x02)) dev->drv->sony_msf = dev->buffer[pos] & 0x01; if (!(dev->ms_page_flags & (1LL << ((uint64_t) page)))) { @@ -3496,7 +3665,9 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) for (i = 0; i < page_len; i++) { uint8_t pg = page; - if (dev->is_sony && (page == GPMODE_CDROM_AUDIO_PAGE_SONY) && (i >= 6) && (i <= 13)) + if (dev->drv->is_sony && + (page == GPMODE_CDROM_AUDIO_PAGE_SONY) && + (i >= 6) && (i <= 13)) pg = GPMODE_CDROM_AUDIO_PAGE; ch = dev->ms_pages_changeable.pages[pg][i + 2]; @@ -3532,7 +3703,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) } break; case 0xc9: - if (dev->is_sony) { + if (dev->drv->is_sony) { for (i = 0; i < 18; i++) { if ((i >= 8) && (i <= 15)) dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][i] = @@ -3687,12 +3858,15 @@ scsi_cdrom_drive_reset(const int c) dev->id = c; dev->drv = drv; - dev->cur_lun = SCSI_LUN_USE_CDB; + dev->cur_lun = SCSI_LUN_USE_CDB; - drv->insert = scsi_cdrom_insert; - drv->get_volume = scsi_cdrom_get_volume; - drv->get_channel = scsi_cdrom_get_channel; - drv->close = scsi_cdrom_close; + dev->toc_cached = 0; + drv->cached_sector = -1; + + drv->insert = scsi_cdrom_insert; + drv->get_volume = scsi_cdrom_get_volume; + drv->get_channel = scsi_cdrom_get_channel; + drv->close = scsi_cdrom_close; drv->sector_size = 2048; (void) scsi_cdrom_update_sector_flags(dev); @@ -3702,22 +3876,19 @@ scsi_cdrom_drive_reset(const int c) dev->ven_cmd = NULL; memset(dev->ven_cmd_is_data, 0x00, sizeof(dev->ven_cmd_is_data)); - dev->is_sony = 0; dev->use_cdb_9 = 0; dev->ms_page_flags = scsi_cdrom_ms_page_flags_scsi; dev->ms_pages_default = scsi_cdrom_ms_pages_default_scsi; dev->ms_pages_changeable = scsi_cdrom_ms_pages_changeable_scsi; - if (!strcmp(vendor, "CHINON")) + if (dev->drv->is_chinon) dev->ven_cmd = scsi_cdrom_command_chinon; - else if (!strcmp(vendor, "DEC") || !strcmp(vendor, "ShinaKen") || - !strcmp(vendor, "SONY") || !strcmp(vendor, "TEXEL")) { + else if (dev->drv->is_sony) { dev->ven_cmd = scsi_cdrom_command_dec_sony_texel; dev->ven_cmd_is_data[0xc0] = 1; dev->ven_cmd_is_data[0xc1] = 1; dev->ven_cmd_is_data[0xc2] = 1; dev->ven_cmd_is_data[0xc3] = 1; - dev->is_sony = 1; dev->ms_page_flags = scsi_cdrom_ms_page_flags_sony_scsi; dev->ms_pages_default = scsi_cdrom_ms_pages_default_sony_scsi; dev->ms_pages_changeable = scsi_cdrom_ms_pages_changeable_sony_scsi; @@ -3727,12 +3898,12 @@ scsi_cdrom_drive_reset(const int c) dev->ven_cmd = scsi_cdrom_command_nec; dev->ven_cmd_is_data[0xdd] = 1; dev->ven_cmd_is_data[0xde] = 1; - } else if (!strcmp(vendor, "PIONEER")) { + } else if (dev->drv->is_pioneer) { dev->ven_cmd = scsi_cdrom_command_pioneer; dev->ven_cmd_is_data[0xc1] = 1; dev->ven_cmd_is_data[0xc2] = 1; dev->ven_cmd_is_data[0xc3] = 1; - } else if (!strcmp(vendor, "TOSHIBA")) { + } else if (dev->drv->is_toshiba) { dev->ven_cmd = scsi_cdrom_command_toshiba; dev->ven_cmd_is_data[0xc6] = 1; dev->ven_cmd_is_data[0xc7] = 1; @@ -3768,7 +3939,6 @@ scsi_cdrom_drive_reset(const int c) if (id) { dev->ven_cmd = NULL; memset(dev->ven_cmd_is_data, 0x00, sizeof(dev->ven_cmd_is_data)); - dev->is_sony = 0; dev->use_cdb_9 = 0; dev->ms_page_flags = scsi_cdrom_ms_page_flags; dev->ms_pages_default = scsi_cdrom_ms_pages_default; @@ -3786,6 +3956,8 @@ scsi_cdrom_drive_reset(const int c) id->phase_data_out = scsi_cdrom_phase_data_out; id->command_stop = scsi_cdrom_command_stop; id->bus_master_error = scsi_cdrom_bus_master_error; + id->read = scsi_cdrom_read; + id->write = NULL; id->interrupt_drq = dev->drv->is_early; valid = 1; diff --git a/src/sound/sound.c b/src/sound/sound.c index 28cb96629..0c8dffe12 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -274,83 +274,89 @@ sound_cd_thread(UNUSED(void *param)) temp_buffer[0] = temp_buffer[1] = 0; for (uint8_t i = 0; i < CDROM_NUM; i++) { - if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || (cdrom[i].cd_status == CD_STATUS_EMPTY)) + /* Just in case the thread is in a loop when it gets terminated. */ + if (!cdaudioon) + break; + + if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || + (cdrom[i].cd_status != CD_STATUS_PLAYING)) continue; - const uint32_t lba = cdrom[i].seek_pos; - const int r = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], CD_BUFLEN * 2); - if (!cdrom[i].sound_on || !r) - continue; - const int pre = cdrom_is_pre(&(cdrom[i]), lba); + const int ret = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], + CD_BUFLEN * 2); - - if (cdrom[i].get_volume) { - audio_vol_l = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 0)]; - audio_vol_r = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 1)]; - } else { - audio_vol_l = cd_audio_volume_lut[255]; - audio_vol_r = cd_audio_volume_lut[255]; - } - - if (cdrom[i].get_channel) { - channel_select[0] = (int) cdrom[i].get_channel(cdrom[i].priv, 0); - channel_select[1] = (int) cdrom[i].get_channel(cdrom[i].priv, 1); - } else { - channel_select[0] = 1; - channel_select[1] = 2; - } - - for (int c = 0; c < CD_BUFLEN * 2; c += 2) { - /*Apply ATAPI channel select*/ - cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; - - if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { - if (channel_select[0] & 1) - cd_buffer_temp[0] += ((double) cd_buffer[i][c]); /* Channel 0 => Port 0 */ - if (channel_select[0] & 2) - cd_buffer_temp[0] += ((double) cd_buffer[i][c + 1]); /* Channel 1 => Port 0 */ - - cd_buffer_temp[0] *= audio_vol_l; /* Multiply Port 0 by Port 0 volume */ - - if (pre) - cd_buffer_temp[0] = deemph_iir(0, cd_buffer_temp[0]); /* De-emphasize if necessary */ - } - - if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { - if (channel_select[1] & 1) - cd_buffer_temp[1] += ((double) cd_buffer[i][c]); /* Channel 0 => Port 1 */ - if (channel_select[1] & 2) - cd_buffer_temp[1] += ((double) cd_buffer[i][c + 1]); /* Channel 1 => Port 1 */ - - cd_buffer_temp[1] *= audio_vol_r; /* Multiply Port 1 by Port 1 volume */ - - if (pre) - cd_buffer_temp[1] = deemph_iir(1, cd_buffer_temp[1]); /* De-emphasize if necessary */ - } - - /* Apply sound card CD volume and filters */ - if (filter_cd_audio != NULL) { - filter_cd_audio(0, &(cd_buffer_temp[0]), filter_cd_audio_p); - filter_cd_audio(1, &(cd_buffer_temp[1]), filter_cd_audio_p); - } - - if (sound_is_float) { - cd_out_buffer[c] += (float) (cd_buffer_temp[0] / 32768.0); - cd_out_buffer[c + 1] += (float) (cd_buffer_temp[1] / 32768.0); + if (ret) { + if (cdrom[i].get_volume) { + audio_vol_l = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 0)]; + audio_vol_r = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 1)]; } else { - temp_buffer[0] += (int) trunc(cd_buffer_temp[0]); - temp_buffer[1] += (int) trunc(cd_buffer_temp[1]); + audio_vol_l = cd_audio_volume_lut[255]; + audio_vol_r = cd_audio_volume_lut[255]; + } - if (temp_buffer[0] > 32767) - temp_buffer[0] = 32767; - if (temp_buffer[0] < -32768) - temp_buffer[0] = -32768; - if (temp_buffer[1] > 32767) - temp_buffer[1] = 32767; - if (temp_buffer[1] < -32768) - temp_buffer[1] = -32768; + if (cdrom[i].get_channel) { + channel_select[0] = (int) cdrom[i].get_channel(cdrom[i].priv, 0); + channel_select[1] = (int) cdrom[i].get_channel(cdrom[i].priv, 1); + } else { + channel_select[0] = 1; + channel_select[1] = 2; + } - cd_out_buffer_int16[c] = (int16_t) temp_buffer[0]; - cd_out_buffer_int16[c + 1] = (int16_t) temp_buffer[1]; + // uint16_t *cddab = (uint16_t *) cdrom[i].raw_buffer; + for (int c = 0; c < CD_BUFLEN * 2; c += 2) { + /* Apply ATAPI channel select */ + cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; + + if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { + if (channel_select[0] & 1) + /* Channel 0 => Port 0 */ + cd_buffer_temp[0] += ((double) cd_buffer[i][c]); + if (channel_select[0] & 2) + /* Channel 1 => Port 0 */ + cd_buffer_temp[0] += ((double) cd_buffer[i][c + 1]); + + /* Multiply Port 0 by Port 0 volume */ + cd_buffer_temp[0] *= audio_vol_l; + } + + if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { + if (channel_select[1] & 1) + /* Channel 0 => Port 1 */ + cd_buffer_temp[1] += ((double) cd_buffer[i][c]); + if (channel_select[1] & 2) + /* Channel 1 => Port 1 */ + cd_buffer_temp[1] += ((double) cd_buffer[i][c + 1]); + + /* Multiply Port 1 by Port 1 volume */ + cd_buffer_temp[1] *= audio_vol_r; + } + + /* Apply sound card CD volume and filters */ + if (filter_cd_audio != NULL) { + filter_cd_audio(0, &(cd_buffer_temp[0]), + filter_cd_audio_p); + filter_cd_audio(1, &(cd_buffer_temp[1]), + filter_cd_audio_p); + } + + if (sound_is_float) { + cd_out_buffer[c] += (float) (cd_buffer_temp[0] / 32768.0); + cd_out_buffer[c + 1] += (float) (cd_buffer_temp[1] / 32768.0); + } else { + temp_buffer[0] = (int) trunc(cd_buffer_temp[0]); + temp_buffer[1] = (int) trunc(cd_buffer_temp[1]); + + if (temp_buffer[0] > 32767) + temp_buffer[0] = 32767; + if (temp_buffer[0] < -32768) + temp_buffer[0] = -32768; + if (temp_buffer[1] > 32767) + temp_buffer[1] = 32767; + if (temp_buffer[1] < -32768) + temp_buffer[1] = -32768; + + cd_out_buffer_int16[c] += (int16_t) temp_buffer[0]; + cd_out_buffer_int16[c + 1] += (int16_t) temp_buffer[1]; + } } } } From ae597c2e46c3097d5f13631d408c4761022e0f90 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Feb 2025 05:31:29 +0100 Subject: [PATCH 002/218] Reverted the dark mode forcing and reveted CD-ROM to old behavior if bus is SCSI, because it turns out the changes are not even needed on SCSI. --- src/qt/qt_winrawinputfilter.cpp | 1 - src/scsi/scsi_cdrom.c | 15 +++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 272b389c5..13e0ec9a7 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -65,7 +65,6 @@ extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1); #include "ui_qt_mainwindow.h" bool windows_is_light_theme() { - return 0; // based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application // The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 07590d5ae..8a39edb39 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -611,7 +611,9 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len break; } } - dev->requested_blocks = 1; + + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->requested_blocks = 1; fallthrough; default: @@ -1044,11 +1046,12 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); - else { - if (dev->sector_pos > dev->drv->cdrom_capacity) { - scsi_cdrom_lba_out_of_range(dev); - ret = -1; - } else { + else if (dev->sector_pos > dev->drv->cdrom_capacity) { + scsi_cdrom_lba_out_of_range(dev); + ret = -1; + } else { + ret = 1; + for (int i = 0; (i < dev->requested_blocks) && (ret > 0); i++) { ret = cdrom_readsector_raw(dev->drv, dev->buffer + dev->buffer_pos, dev->sector_pos, msf, type, flags, &temp_len, vendor_type); From 9a1ae5997fe3d63941aed2ecbb9cc771fc95604c Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 01:44:10 +0100 Subject: [PATCH 003/218] Fixed ATAPI transfer split by sectors and improved the performance of IOCTL by making it no longer constantly open and close the handle. --- src/cdrom/cdrom.c | 6 ++---- src/disk/hdc_ide.c | 1 - src/qt/win_cdrom_ioctl.c | 17 ----------------- src/scsi/scsi_cdrom.c | 16 ++++++++++------ 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 9f3b6e079..aab6cf67c 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2822,9 +2822,7 @@ cdrom_update_status(cdrom_t *dev) dev->seek_pos = 0; dev->cd_buflen = 0; - if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) - dev->cd_status = CD_STATUS_EMPTY; - else if (dev->ops->is_dvd(dev->local)) + if (dev->ops->is_dvd(dev->local)) dev->cd_status = CD_STATUS_DVD; else dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : @@ -3048,7 +3046,7 @@ cdrom_is_empty(const uint8_t id) int ret = 0; /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ - if (strlen(dev->image_path) == 0) + if ((strlen(dev->image_path) == 0) || (dev->cd_status == CD_STATUS_EMPTY)) /* Switch from empty to empty. Do nothing. */ ret = 1; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index e367f73b0..d42a595df 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,7 +241,6 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); -#define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 3d9ecefd5..8da62a49d 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -124,12 +124,10 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) ioctl->cur_read_toc_ex.Msf = 1; ioctl->cur_read_toc_ex.SessionTrack = 1; - ioctl_open_handle(ioctl); const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, &ioctl->cur_read_toc_ex, 65535, cur_full_toc, 65535, (LPDWORD) &size, NULL); - ioctl_close_handle(ioctl); ioctl_log(ioctl->log, "temp = %i\n", temp); if (temp != 0) { @@ -178,12 +176,10 @@ ioctl_read_raw_toc(ioctl_t *ioctl) ioctl->cur_read_toc_ex.Msf = 1; ioctl->cur_read_toc_ex.SessionTrack = 1; - ioctl_open_handle(ioctl); const int status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, &ioctl->cur_read_toc_ex, 65535, cur_full_toc, 65535, (LPDWORD) &size, NULL); - ioctl_close_handle(ioctl); ioctl_log(ioctl->log, "status = %i\n", status); if ((status == 0) && (ioctl->tracks_num >= 1)) { @@ -384,8 +380,6 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) int ret; SCSI_PASS_THROUGH_DIRECT_BUF req; - ioctl_open_handle((ioctl_t *) ioctl); - if (ioctl->is_dvd) { int track; @@ -517,8 +511,6 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) for (int j = 7; j >= 0; j--) buffer[2352 + (i * 8) + j] = ((buffer[sc_offs + i] >> (7 - j)) & 0x01) << 6; - ioctl_close_handle((ioctl_t *) ioctl); - return ret; } @@ -587,8 +579,6 @@ ioctl_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t f const int len = 2052; SCSI_PASS_THROUGH_DIRECT_BUF req; - ioctl_open_handle((ioctl_t *) ioctl); - memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); req.spt.PathId = 0; @@ -650,8 +640,6 @@ ioctl_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t f } else ret = ret ? (req.spt.DataTransferLength >= len) : 0; - ioctl_close_handle((ioctl_t *) ioctl); - return ret; } @@ -684,8 +672,6 @@ ioctl_is_empty(const void *local) unsigned long int unused = 0; SCSI_PASS_THROUGH_DIRECT_BUF req; - ioctl_open_handle((ioctl_t *) ioctl); - memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); req.spt.PathId = 0; @@ -745,8 +731,6 @@ ioctl_is_empty(const void *local) } else ret = 0; - ioctl_close_handle((ioctl_t *) ioctl); - return ret; } @@ -774,7 +758,6 @@ ioctl_load(const void *local) DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, (LPDWORD) &size, NULL); - ioctl_close_handle((ioctl_t *) ioctl); ioctl_read_toc((ioctl_t *) ioctl); } diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 8a39edb39..53a079d6a 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,7 +15,6 @@ */ #include #include -#define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -704,8 +703,11 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) if (dev->was_cached == -1) period *= (double) dev->packet_len; else { - period *= ((double) dev->requested_blocks) * 2352.0; - pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, dev->requested_blocks); + const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + dev->requested_blocks : 1; + + period *= ((double) num) * 2352.0; + pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); @@ -1041,8 +1043,10 @@ static int scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int flags, const int vendor_type) { - int temp_len = 0; - int ret = 0; + int temp_len = 0; + int ret = 0; + const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + dev->requested_blocks : 1; if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); @@ -1051,7 +1055,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int ret = -1; } else { ret = 1; - for (int i = 0; (i < dev->requested_blocks) && (ret > 0); i++) { + for (int i = 0; (i < num) && (ret > 0); i++) { ret = cdrom_readsector_raw(dev->drv, dev->buffer + dev->buffer_pos, dev->sector_pos, msf, type, flags, &temp_len, vendor_type); From 8a66dbef372b1f06f107f8514fc41105380f52cb Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:28:05 +0100 Subject: [PATCH 004/218] Fixed ATAPI PIO operation and ATAPI DMA timings. --- src/disk/hdc_ide.c | 116 ++++++++++++++++++++++++++++++++---------- src/scsi/scsi_cdrom.c | 62 ++++++++++++---------- 2 files changed, 125 insertions(+), 53 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index d42a595df..8559d7a63 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,6 +241,7 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); +// #define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -1091,6 +1092,7 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: + pclog("Reading block %i... ", ide->sc->sector_len + 1); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) @@ -1114,13 +1116,16 @@ ide_atapi_callback(ide_t *ide) default: break; case 0: + pclog("ERROR\n"); if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; case 2: + pclog("WAIT\n"); ide_atapi_command_bus(ide); break; case 3: + pclog("DONE\n"); /* Reached EOT - terminate the command as there's nothing more to transfer. */ ide->sc->packet_status = PHASE_COMPLETE; @@ -1130,6 +1135,7 @@ ide_atapi_callback(ide_t *ide) ide->command_stop(ide->sc); fallthrough; case 1: + pclog("NEXT\n"); if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); @@ -1193,21 +1199,15 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_irq_lower(ide); - ide->tf->atastat = BSY_STAT; + ide->tf->atastat = BSY_STAT; if (ide->tf->pos >= dev->packet_len) { ide_log("%i bytes %s, command done\n", ide->tf->pos, out ? "written" : "read"); ide->tf->pos = dev->request_pos = 0; - if (dev->block_len != 0) { - if (out && (ide->write != NULL)) - ide->write(dev); - else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) - ide->read(dev); - } - - if ((dev->block_len == 0) || (dev->sector_len == 0)) { + if (dev->block_len == 0) { + // pclog("ide_atapi_pio_request(): Processing instant command...\n"); if (out && (ide->phase_data_out != NULL)) ide->phase_data_out(dev); else if (!out && (ide->command_stop != NULL)) @@ -1237,22 +1237,62 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) dev->packet_status = PHASE_DATA_IN | out; - if (dev->block_len != 0) { - if (out && (ide->write != NULL)) - ide->write(dev); - else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) - ide->read(dev); - } - - ide->tf->atastat = BSY_STAT; - ide->tf->phase = 1; - - if ((dev->block_len == 0) || (dev->sector_len == 0)) { + if (dev->block_len == 0) { ide_atapi_callback(ide); ide_set_callback(ide, 0.0); } - dev->request_pos = 0; + dev->request_pos = 0; + } + + if (dev->block_len != 0) { + if (out) { + if (ide->write != NULL) { +#if 0 + pclog("ide_atapi_pio_request(): Continuing write command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + ide->write(dev); + } + + if (dev->sector_len == 0) { +#if 0 + pclog("ide_atapi_pio_request(): Ending write command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + if (ide->phase_data_out != NULL) + (void) ide->phase_data_out(dev); + + ide_atapi_callback(ide); + } + } else { + if (dev->sector_len == 0) { +#if 0 + pclog("ide_atapi_pio_request(): Ending read command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + if (ide->command_stop != NULL) + ide->command_stop(dev); + + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + ide_atapi_callback(ide); + } else if (ide->read != NULL) { +#if 0 + pclog("ide_atapi_pio_request(): Continuing read command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + ide->read(dev); + } + } } } @@ -1284,11 +1324,27 @@ ide_atapi_packet_read(ide_t *ide) (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 0); - } else if ((dev->block_len != 0) && + } +#if 0 + else if ((dev->block_len != 0) && (dev->sector_len != 0) && - ((dev->request_pos % dev->block_len) == 0) && - (ide->read != NULL)) - ide->read(dev); + ((dev->request_pos % dev->block_len) == 0)) { + if (dev->sector_len == 0) { + // pclog("ide_atapi_packet_read(): Ending read command (dev->sector_len = %i)...\n", dev->sector_len); + + if (ide->command_stop != NULL) + ide->command_stop(ide->sc); + + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + ide_atapi_callback(ide); + } else if (ide->read != NULL) { + // pclog("ide_atapi_packet_read(): Continuing read command (dev->sector_len = %i)...\n", dev->sector_len); + ide->read(dev); + } + } +#endif } return ret; @@ -1322,10 +1378,16 @@ ide_atapi_packet_write(ide_t *ide, const uint16_t val) (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 1); - } else if ((dev->block_len != 0) && + } +#if 0 + else if ((dev->block_len != 0) && ((dev->request_pos % dev->block_len) == 0) && - (ide->write != NULL)) + (ide->write != NULL)) { + // pclog("ide_atapi_packet_write(): Continuing write command (dev->sector_len = %i)...\n", dev->sector_len); + ide->write(dev); + } +#endif } else if (dev->packet_status == PHASE_IDLE) { if (ide->tf->pos >= 12) { ide->tf->pos = 0; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 53a079d6a..21ea9ce16 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,6 +15,7 @@ */ #include #include +// #define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -611,8 +612,8 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len } } - if (dev->drv->bus_type != CDROM_BUS_SCSI) - dev->requested_blocks = 1; + if ((dev->drv->bus_type != CDROM_BUS_SCSI) && (dev->block_len != 0)) + dev->requested_blocks = (dev->packet_len / dev->block_len); fallthrough; default: @@ -667,9 +668,9 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); - if (dev->packet_status == PHASE_COMPLETE) - dev->callback = 0; - else { + dev->callback = 0; + + if (dev->packet_status != PHASE_COMPLETE) { double bytes_per_second; double period; @@ -689,6 +690,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; + // pclog("Current speed: %ix\n", dev->drv->cur_speed); } else { bytes_per_second = scsi_cdrom_bus_speed(dev); if (bytes_per_second == 0.0) { @@ -703,8 +705,11 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) if (dev->was_cached == -1) period *= (double) dev->packet_len; else { - const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? - dev->requested_blocks : 1; + const int num = ((dev->drv->bus_type == CDROM_BUS_SCSI) || + (dev->block_len == 0)) ? + dev->requested_blocks : + ((scsi_cdrom_current_mode(dev) == 2) ? 1 : + (dev->packet_len / dev->block_len)); period *= ((double) num) * 2352.0; pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); @@ -1045,7 +1050,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int { int temp_len = 0; int ret = 0; - const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? dev->requested_blocks : 1; if (dev->drv->cd_status == CD_STATUS_EMPTY) @@ -1065,15 +1070,20 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int else if (ret == 0) scsi_cdrom_illegal_mode(dev); else { - if (dev->block_len == 0xffffffff) + if (dev->block_len == 0xffffffff) { dev->block_len = temp_len; + if ((dev->drv->bus_type != CDROM_BUS_SCSI) && + (scsi_cdrom_current_mode(dev) != 2)) + num = (dev->packet_len / dev->block_len); + } + dev->sector_pos++; dev->drv->seek_pos = dev->sector_pos; dev->sector_len--; - pclog("Sector read to buffer position %08X\n", dev->buffer_pos); + // pclog("Sector read to buffer position %08X\n", dev->buffer_pos); dev->buffer_pos += temp_len; } } @@ -1547,17 +1557,17 @@ static void scsi_cdrom_read(scsi_common_t *sc) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + const int osl = dev->sector_len; const int ret = scsi_cdrom_read_blocks(dev); dev->drv->seek_diff = 0; if (ret > 0) { - if (dev->packet_status != PHASE_COMPLETE) { - ui_sb_update_icon(SB_CDROM | dev->id, 1); - + if (osl > 0) scsi_cdrom_set_period(dev); - } else - ui_sb_update_icon(SB_CDROM | dev->id, 0); + + ui_sb_update_icon(SB_CDROM | dev->id, + (dev->packet_status != PHASE_COMPLETE)); } else scsi_cdrom_media_access_complete(dev, ret); } @@ -2461,7 +2471,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) break; case GPCMD_REZERO_UNIT: - pclog("Rezero unit\n"); + // pclog("Rezero unit\n"); dev->was_cached = 0; scsi_cdrom_stop(sc); dev->requested_blocks = 0; @@ -2496,7 +2506,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_SCAN_PIONEER: case GPCMD_AUDIO_SCAN: - pclog("Audio scan\n"); + // pclog("Audio scan\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; @@ -2543,7 +2553,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); toc_format = cdb[2] & 0xf; - pclog("READ TOC format %1X\n", toc_format); + // pclog("READ TOC format %1X\n", toc_format); if (toc_format == 0) toc_format = (cdb[9] >> 6) & 3; @@ -3161,20 +3171,20 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - pclog("Play audio (10)\n"); + // pclog("Play audio (10)\n"); break; case GPCMD_PLAY_AUDIO_12: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - pclog("Play audio (12)\n"); + // pclog("Play audio (12)\n"); break; case GPCMD_PLAY_AUDIO_MSF: msf = 1; pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", - cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); + // pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", + // cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); break; case GPCMD_PLAY_AUDIO_TRACK_INDEX: msf = 2; @@ -3183,19 +3193,19 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = cdb[7]; } else ret = 0; - pclog("Play audio track index\n"); + // pclog("Play audio track index\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: msf = 0x100 | cdb[6]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - pclog("Play audio track relative (10)\n"); + // pclog("Play audio track relative (10)\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: msf = 0x100 | cdb[10]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - pclog("Play audio track relative (12)\n"); + // pclog("Play audio track relative (12)\n"); break; default: @@ -3495,7 +3505,7 @@ atapi_out: case GPCMD_SEEK_6: case GPCMD_SEEK_10: - pclog("Seek\n"); + // pclog("Seek\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; From 4221b7205997d1dab8c1f3513036a9f25443c009 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:28:52 +0100 Subject: [PATCH 005/218] Commented out some logging stuff. --- src/scsi/scsi_cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 21ea9ce16..8c24c4623 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -712,7 +712,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) (dev->packet_len / dev->block_len)); period *= ((double) num) * 2352.0; - pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); + // pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); From 1a87aea37aa05742402825ee11618628431edfe5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:32:59 +0100 Subject: [PATCH 006/218] And some more. --- src/disk/hdc_ide.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 8559d7a63..d4dcea625 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1092,7 +1092,7 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - pclog("Reading block %i... ", ide->sc->sector_len + 1); + // pclog("Reading block %i... ", ide->sc->sector_len + 1); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) @@ -1116,16 +1116,16 @@ ide_atapi_callback(ide_t *ide) default: break; case 0: - pclog("ERROR\n"); + // pclog("ERROR\n"); if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; case 2: - pclog("WAIT\n"); + // pclog("WAIT\n"); ide_atapi_command_bus(ide); break; case 3: - pclog("DONE\n"); + // pclog("DONE\n"); /* Reached EOT - terminate the command as there's nothing more to transfer. */ ide->sc->packet_status = PHASE_COMPLETE; @@ -1135,7 +1135,7 @@ ide_atapi_callback(ide_t *ide) ide->command_stop(ide->sc); fallthrough; case 1: - pclog("NEXT\n"); + // pclog("NEXT\n"); if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); From 5262693624f540eaba572ee05c63665998501bed Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:53:51 +0100 Subject: [PATCH 007/218] IOCTL: The host non-raw TOC is no longer always read and is also only used to reconstruct the raw toc for DVD's, should reduce the slowness on host drive mounting. --- src/qt/win_cdrom_ioctl.c | 104 +++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 8da62a49d..96b75db38 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -44,8 +44,6 @@ typedef struct ioctl_t { int is_dvd; int has_audio; int32_t tracks_num; - uint8_t cur_toc[65536]; - CDROM_READ_TOC_EX cur_read_toc_ex; int blocks_num; uint8_t cur_rti[65536]; HANDLE handle; @@ -111,22 +109,23 @@ ioctl_open_handle(ioctl_t *ioctl) static int ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) { - long size = 0; - PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + long size = 0; + PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + CDROM_READ_TOC_EX cur_read_toc_ex = { 0 }; ioctl->tracks_num = 0; memset(toc_buf, 0x00, 65536); cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); - ioctl->cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_TOC; - ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); - ioctl->cur_read_toc_ex.Msf = 1; - ioctl->cur_read_toc_ex.SessionTrack = 1; + cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_TOC; + ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", cur_read_toc_ex.Format); + cur_read_toc_ex.Msf = 1; + cur_read_toc_ex.SessionTrack = 1; const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &ioctl->cur_read_toc_ex, 65535, - cur_full_toc, 65535, + &cur_read_toc_ex, 65535, + cur_full_toc, 65535, (LPDWORD) &size, NULL); ioctl_log(ioctl->log, "temp = %i\n", temp); @@ -157,10 +156,12 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) static void ioctl_read_raw_toc(ioctl_t *ioctl) { - PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; - long size = 0; - raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; - uint8_t *buffer = (uint8_t *) calloc (1, 2052); + PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + long size = 0; + raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; + uint8_t *buffer = (uint8_t *) calloc (1, 2052); + int status = 0; + CDROM_READ_TOC_EX cur_read_toc_ex = { 0 }; ioctl->is_dvd = (ioctl_read_dvd_structure(ioctl, 0, 0, buffer, NULL) > 0); free(buffer); @@ -171,16 +172,18 @@ ioctl_read_raw_toc(ioctl_t *ioctl) cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); - ioctl->cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_FULL_TOC; - ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); - ioctl->cur_read_toc_ex.Msf = 1; - ioctl->cur_read_toc_ex.SessionTrack = 1; + cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_FULL_TOC; + ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", cur_read_toc_ex.Format); + cur_read_toc_ex.Msf = 1; + cur_read_toc_ex.SessionTrack = 1; - const int status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &ioctl->cur_read_toc_ex, 65535, - cur_full_toc, 65535, - (LPDWORD) &size, NULL); - ioctl_log(ioctl->log, "status = %i\n", status); + if (!ioctl->is_dvd) { + status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, + &cur_read_toc_ex, 65535, + cur_full_toc, 65535, + (LPDWORD) &size, NULL); + ioctl_log(ioctl->log, "status = %i\n", status); + } if ((status == 0) && (ioctl->tracks_num >= 1)) { /* @@ -189,8 +192,12 @@ ioctl_read_raw_toc(ioctl_t *ioctl) reading the cooked TOC does not, so we have to construct the raw TOC from the cooked TOC. */ - const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; - const TRACK_DATA *ct = &(toc->TrackData[ioctl->tracks_num - 1]); + uint8_t cur_toc[65536] = { 0 }; + + const CDROM_TOC * toc = (const CDROM_TOC *) cur_toc; + const TRACK_DATA *ct = &(toc->TrackData[ioctl->tracks_num - 1]); + + ioctl_read_normal_toc(ioctl, cur_toc); rti[0].adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); rti[0].point = 0xa0; @@ -257,7 +264,6 @@ ioctl_read_raw_toc(ioctl_t *ioctl) static void ioctl_read_toc(ioctl_t *ioctl) { - (void) ioctl_read_normal_toc(ioctl, ioctl->cur_toc); ioctl_read_raw_toc(ioctl); } @@ -306,23 +312,28 @@ static int ioctl_get_track_info(const void *local, const uint32_t track, int end, track_info_t *ti) { - const ioctl_t * ioctl = (const ioctl_t *) local; - const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; - int ret = 1; + const ioctl_t * ioctl = (const ioctl_t *) local; + const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; + int ret = 1; + int trk = -1; - if ((track < 1) || (track == 0xaa) || (track > (toc->LastTrack + 1))) { + if ((track >= 1) && (track < 99)) + for (int i = 0; i < ioctl->blocks_num; i++) + if (rti[i].point == track) { + trk = i; + break; + } + + if ((track == 0xaa) || (trk == -1)) { ioctl_log(ioctl->log, "ioctl_get_track_info(%02i)\n", track); ret = 0; } else { - const TRACK_DATA * td = &toc->TrackData[track - 1]; + ti->m = rti[trk].pm; + ti->s = rti[trk].ps; + ti->f = rti[trk].pf; - ti->m = td->Address[1]; - ti->s = td->Address[2]; - ti->f = td->Address[3]; - - ti->number = td->TrackNumber; - ti->attr = td->Control; - ti->attr |= ((td->Adr << 4) & 0xf0); + ti->number = rti[trk].point; + ti->attr = rti[trk].adr_ctl; ioctl_log(ioctl->log, "ioctl_get_track_info(%02i): %02i:%02i:%02i, %02i, %02X\n", track, ti->m, ti->s, ti->f, ti->number, ti->attr); @@ -546,18 +557,15 @@ ioctl_get_track_type(const void *local, const uint32_t sector) static uint32_t ioctl_get_last_block(const void *local) { - const ioctl_t *ioctl = (const ioctl_t *) local; - const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; + const ioctl_t * ioctl = (const ioctl_t *) local; + raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; uint32_t lb = 0; - for (int c = 0; c <= toc->LastTrack; c++) { - const TRACK_DATA *td = &toc->TrackData[c]; - const uint32_t address = MSFtoLBA(td->Address[1], td->Address[2], - td->Address[3]) - 150; - - if (address > lb) - lb = address; - } + for (int i = (ioctl->blocks_num - 1); i >= 0; i--) + if (rti[i].point == 0xa2) { + lb = MSFtoLBA(rti[i].pm, rti[i].ps, rti[i].pf) - 151; + break; + } ioctl_log(ioctl->log, "LBCapacity=%d\n", lb); From 44c6daad1c3e8189222d4aa1a1a06a3656228acf Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 08:36:36 +0100 Subject: [PATCH 008/218] Fixed IOCTL failing to read raw TOC after hard reset. --- src/cdrom/cdrom.c | 2 +- src/qt/win_cdrom_ioctl.c | 22 ++++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index aab6cf67c..b34b01fff 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2873,7 +2873,7 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) dev->cd_status = CD_STATUS_EMPTY; - if (dev->ops->is_dvd(dev->local)) + else if (dev->ops->is_dvd(dev->local)) dev->cd_status = CD_STATUS_DVD; else dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 96b75db38..40addd591 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -124,7 +124,7 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) cur_read_toc_ex.SessionTrack = 1; const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &cur_read_toc_ex, 65535, + &cur_read_toc_ex, sizeof(CDROM_READ_TOC_EX), cur_full_toc, 65535, (LPDWORD) &size, NULL); ioctl_log(ioctl->log, "temp = %i\n", temp); @@ -179,7 +179,7 @@ ioctl_read_raw_toc(ioctl_t *ioctl) if (!ioctl->is_dvd) { status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &cur_read_toc_ex, 65535, + &cur_read_toc_ex, sizeof(CDROM_READ_TOC_EX), cur_full_toc, 65535, (LPDWORD) &size, NULL); ioctl_log(ioctl->log, "status = %i\n", status); @@ -261,12 +261,6 @@ ioctl_read_raw_toc(ioctl_t *ioctl) free(cur_full_toc); } -static void -ioctl_read_toc(ioctl_t *ioctl) -{ - ioctl_read_raw_toc(ioctl); -} - static int ioctl_get_track(const ioctl_t *ioctl, const uint32_t sector) { raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; @@ -761,13 +755,13 @@ ioctl_load(const void *local) { const ioctl_t *ioctl = (const ioctl_t *) local; - if (ioctl_open_handle((ioctl_t *) ioctl)) { - long size; - DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, - NULL, 0, NULL, 0, - (LPDWORD) &size, NULL); + if ((ioctl->handle != NULL) || ioctl_open_handle((ioctl_t *) ioctl)) { + long size = 0; + (void) DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, + NULL, 0, NULL, 0, + (LPDWORD) &size, NULL); - ioctl_read_toc((ioctl_t *) ioctl); + ioctl_read_raw_toc((ioctl_t *) ioctl); } } From 48f42af74575144d19a1cb7d005dad25a6cfe332 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 10:31:12 +0100 Subject: [PATCH 009/218] Moved some files to the utils folder, that's where the CRC code is soon going to reside as well. --- src/CMakeLists.txt | 10 +++------- src/utils/CMakeLists.txt | 25 +++++++++++++++++++++++++ src/{ => utils}/cJSON.c | 0 src/{ => utils}/fifo.c | 0 src/{ => utils}/fifo8.c | 0 src/{ => utils}/ini.c | 0 src/{ => utils}/log.c | 0 src/{ => utils}/random.c | 0 8 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 src/utils/CMakeLists.txt rename src/{ => utils}/cJSON.c (100%) rename src/{ => utils}/fifo.c (100%) rename src/{ => utils}/fifo8.c (100%) rename src/{ => utils}/ini.c (100%) rename src/{ => utils}/log.c (100%) rename src/{ => utils}/random.c (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d6daff9c..3ae7c297e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,8 +23,6 @@ endif() add_executable(86Box 86box.c config.c - log.c - random.c timer.c io.c acpi.c @@ -41,15 +39,11 @@ add_executable(86Box pci.c mca.c usb.c - fifo.c - fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c machine_status.c - ini.c - cJSON.c ) if(CMAKE_SYSTEM_NAME MATCHES "Linux") @@ -106,7 +100,7 @@ if(INSTRUMENT) endif() target_link_libraries(86Box cpu chipset mch dev mem fdd game cdrom zip mo hdd - net print scsi sio snd vid voodoo plat ui) + net print scsi sio snd utils vid voodoo plat ui) if(WIN32 AND ARCH STREQUAL "i386") if(MINGW) @@ -253,7 +247,9 @@ add_subdirectory(printer) add_subdirectory(sio) add_subdirectory(scsi) add_subdirectory(sound) +add_subdirectory(utils) add_subdirectory(video) + if (APPLE) add_subdirectory(mac) endif() diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt new file mode 100644 index 000000000..1d4b1f73e --- /dev/null +++ b/src/utils/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# Jasmine Iwanek, +# +# Copyright 2020-2021 David Hrdlička. +# Copyright 2024 Jasmine Iwanek. +# + +add_library(utils OBJECT + cJSON.c + fifo.c + fifo8.c + ini.c + log.c + random.c +) diff --git a/src/cJSON.c b/src/utils/cJSON.c similarity index 100% rename from src/cJSON.c rename to src/utils/cJSON.c diff --git a/src/fifo.c b/src/utils/fifo.c similarity index 100% rename from src/fifo.c rename to src/utils/fifo.c diff --git a/src/fifo8.c b/src/utils/fifo8.c similarity index 100% rename from src/fifo8.c rename to src/utils/fifo8.c diff --git a/src/ini.c b/src/utils/ini.c similarity index 100% rename from src/ini.c rename to src/utils/ini.c diff --git a/src/log.c b/src/utils/log.c similarity index 100% rename from src/log.c rename to src/utils/log.c diff --git a/src/random.c b/src/utils/random.c similarity index 100% rename from src/random.c rename to src/utils/random.c From 1a33a2bd099763d577d0178d25240374184494c1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 19:47:21 +0100 Subject: [PATCH 010/218] CD-ROM: Ignore zero-length pages on MODE SELECT, and also stop properly on error. TODO: Apply to SCSI Disk, ZIP, and MO as well. --- src/scsi/scsi_cdrom.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 8c24c4623..5d9a6e2f2 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -3672,12 +3672,17 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += 2; + /* Ignore any page codes with zero length. */ + if (page_len == 0) + continue; + if (dev->drv->is_sony && (page == 0x08) && (page_len == 0x02)) dev->drv->sony_msf = dev->buffer[pos] & 0x01; if (!(dev->ms_page_flags & (1LL << ((uint64_t) page)))) { scsi_cdrom_log(dev->log, "Unimplemented page %02X\n", page); error |= 1; + break; } else { for (i = 0; i < page_len; i++) { uint8_t pg = page; @@ -3698,9 +3703,13 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) "%02X on page %02X\n", i + 2, page); scsi_cdrom_invalid_field_pl(dev, val); error |= 1; + break; } } } + + if (error) + break; } pos += page_len; @@ -3716,6 +3725,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) if (error) { scsi_cdrom_buf_free(dev); + scsi_cdrom_command_stop((scsi_common_t *) dev); return 0; } break; From da360ab9da6a5ca4e8a38f912e564529efa5dc6c Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 23:37:27 +0100 Subject: [PATCH 011/218] IOCTL: Fix detection of whether or not the disc has audio, fixes audio playing. --- src/cdrom/cdrom.c | 12 +++---- src/qt/win_cdrom_ioctl.c | 69 +++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index b34b01fff..8d6326f8b 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -431,8 +431,6 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, cdrom_log(dev->log, "read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); - pclog("read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", - (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); dev->ops->get_raw_track_info(dev->local, &num, rti); @@ -1848,9 +1846,9 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) b[10] = (dat >> 8) & 0xff; b[11] = dat & 0xff; } - pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], - b[ 8], b[ 9], b[10], b[11]); + // pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + // b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], + // b[ 8], b[ 9], b[10], b[11]); if (b[0] != 0x00) break; base += 12; @@ -3074,7 +3072,9 @@ cdrom_reload(const uint8_t id) { cdrom_t *dev = &cdrom[id]; - if ((strcmp(dev->image_path, dev->prev_image_path) == 0) || (strlen(dev->prev_image_path) == 0) || (strlen(dev->image_path) > 0)) { + if ((strcmp(dev->image_path, dev->prev_image_path) == 0) || + (strlen(dev->prev_image_path) == 0) || + (strlen(dev->image_path) > 0)) { /* Switch from empty to empty. Do nothing. */ return; } diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 40addd591..9af59190b 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -43,7 +43,6 @@ typedef struct ioctl_t { void *log; int is_dvd; int has_audio; - int32_t tracks_num; int blocks_num; uint8_t cur_rti[65536]; HANDLE handle; @@ -107,13 +106,13 @@ ioctl_open_handle(ioctl_t *ioctl) } static int -ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) +ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf, int32_t *tracks_num) { long size = 0; PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; CDROM_READ_TOC_EX cur_read_toc_ex = { 0 }; - ioctl->tracks_num = 0; + *tracks_num = 0; memset(toc_buf, 0x00, 65536); cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); @@ -132,7 +131,7 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) if (temp != 0) { const int length = ((cur_full_toc->Length[0] << 8) | cur_full_toc->Length[1]) + 2; memcpy(toc_buf, cur_full_toc, length); - ioctl->tracks_num = (length - 4) / 8; + *tracks_num = (length - 4) / 8; } free(cur_full_toc); @@ -141,9 +140,9 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) PCDROM_TOC toc = (PCDROM_TOC) toc_buf; ioctl_log(ioctl->log, "%i tracks: %02X %02X %02X %02X\n", - ioctl->tracks_num, toc_buf[0], toc_buf[1], toc_buf[2], toc_buf[3]); + *tracks_num, toc_buf[0], toc_buf[1], toc_buf[2], toc_buf[3]); - for (int i = 0; i < ioctl->tracks_num; i++) { + for (int i = 0; i < *tracks_num; i++) { const uint8_t *t = (const uint8_t *) &toc->TrackData[i]; ioctl_log(ioctl->log, "Track %03i: %02X %02X %02X %02X %02X %02X %02X %02X\n", i, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]); @@ -185,7 +184,7 @@ ioctl_read_raw_toc(ioctl_t *ioctl) ioctl_log(ioctl->log, "status = %i\n", status); } - if ((status == 0) && (ioctl->tracks_num >= 1)) { + if (status == 0) { /* This is needed because in some circumstances (eg. a DVD .MDS mounted in Daemon Tools), reading the raw TOC fails but @@ -193,48 +192,54 @@ ioctl_read_raw_toc(ioctl_t *ioctl) raw TOC from the cooked TOC. */ uint8_t cur_toc[65536] = { 0 }; + int32_t tracks_num = 0; const CDROM_TOC * toc = (const CDROM_TOC *) cur_toc; - const TRACK_DATA *ct = &(toc->TrackData[ioctl->tracks_num - 1]); - ioctl_read_normal_toc(ioctl, cur_toc); + status = ioctl_read_normal_toc(ioctl, cur_toc, &tracks_num); - rti[0].adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); - rti[0].point = 0xa0; - rti[0].pm = toc->FirstTrack; + const TRACK_DATA *ct = &(toc->TrackData[tracks_num - 1]); - rti[1].adr_ctl = rti[0].adr_ctl; - rti[1].point = 0xa1; - rti[1].pm = toc->LastTrack; + if ((status > 0) && (tracks_num >= 1)) { + rti[0].adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); + rti[0].point = 0xa0; + rti[0].pm = toc->FirstTrack; - rti[2].adr_ctl = rti[0].adr_ctl; - rti[2].point = 0xa2; - rti[2].pm = ct->Address[1]; - rti[2].ps = ct->Address[2]; - rti[2].pf = ct->Address[3]; + rti[1].adr_ctl = rti[0].adr_ctl; + rti[1].point = 0xa1; + rti[1].pm = toc->LastTrack; - ioctl->blocks_num = 3; + rti[2].adr_ctl = rti[0].adr_ctl; + rti[2].point = 0xa2; + rti[2].pm = ct->Address[1]; + rti[2].ps = ct->Address[2]; + rti[2].pf = ct->Address[3]; - for (int i = 0; i < (ioctl->tracks_num - 1); i++) { - raw_track_info_t *crt = &(rti[ioctl->blocks_num]); + ioctl->blocks_num = 3; - ct = &(toc->TrackData[i]); + for (int i = 0; i < (tracks_num - 1); i++) { + raw_track_info_t *crt = &(rti[ioctl->blocks_num]); - crt->adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); - crt->point = ct->TrackNumber; - crt->pm = ct->Address[1]; - crt->ps = ct->Address[2]; - crt->pf = ct->Address[3]; + ct = &(toc->TrackData[i]); - ioctl->blocks_num++; - } + crt->adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); + crt->point = ct->TrackNumber; + crt->pm = ct->Address[1]; + crt->ps = ct->Address[2]; + crt->pf = ct->Address[3]; + + ioctl->blocks_num++; + } + } else if (status > 0) + /* Announce that we've had a failure. */ + status = 0; } else if (status != 0) { ioctl->blocks_num = (((cur_full_toc->Length[0] << 8) | cur_full_toc->Length[1]) - 2) / 11; memcpy(ioctl->cur_rti, cur_full_toc->Descriptors, ioctl->blocks_num * 11); } - if (ioctl->blocks_num) for (int i = 0; i < ioctl->tracks_num; i++) { + if (ioctl->blocks_num) for (int i = 0; i < ioctl->blocks_num; i++) { const raw_track_info_t *crt = &(rti[i]); if ((crt->point >= 1) && (crt->point <= 99) && !(crt->adr_ctl & 0x04)) { From ee2b523653afd6c0f4237d231004c58cead4c433 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 01:02:13 +0100 Subject: [PATCH 012/218] Fixed two warnings. --- src/scsi/scsi_cdrom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 5d9a6e2f2..840bec6a0 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -91,7 +91,7 @@ uint8_t scsi_cdrom_command_flags[0x100] = { eventually becomes ready, make the condition go away. */ [0x43 ... 0x45] = IMPLEMENTED | CHECK_READY, - [0x46] IMPLEMENTED | ALLOW_UA, + [0x46] = IMPLEMENTED | ALLOW_UA, [0x47 ... 0x49] = IMPLEMENTED | CHECK_READY, [0x4a] = IMPLEMENTED | ALLOW_UA, [0x4b] = IMPLEMENTED | CHECK_READY, @@ -664,7 +664,7 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) static void scsi_cdrom_set_period(scsi_cdrom_t *dev) { - const uint8_t cmd = dev->current_cdb[0]; + // const uint8_t cmd = dev->current_cdb[0]; scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); From 1a0cefc3b395c0f0122cfb5626b7001cb1fb6185 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 03:29:35 +0100 Subject: [PATCH 013/218] And some more. --- src/cdrom/cdrom.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 8d6326f8b..9349223db 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -1239,7 +1239,7 @@ cdrom_get_from_name(const char *s) wchar_t tempmsg[2048]; sprintf(n, "WARNING: CD-ROM \"%s\" not found - contact 86Box support\n", s); swprintf(tempmsg, sizeof_w(tempmsg), L"%hs", n); - pclog(n); + pclog("%s", n); ui_msgbox_header(MBX_INFO, plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), tempmsg); @@ -1571,7 +1571,7 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, dev->seek_pos = pos2; break; - } case 0x80: + } case 0x80: { track_info_t ti; pos2 = (pos2 >> 24) & 0xff; @@ -1586,7 +1586,7 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, cdrom_stop(dev); } break; - default: + } default: break; } @@ -1689,7 +1689,7 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) pos2 = MSFtoLBA(m, s, f) - 150; dev->cd_end = pos2; break; - } case 0x80: + } case 0x80: { track_info_t ti; pos2 = (pos2 >> 24) & 0xff; @@ -1704,7 +1704,7 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) cdrom_stop(dev); } break; - case 0xc0: + } case 0xc0: if (pos == 0xffffffff) { cdrom_log(dev->log, "Playing from current position\n"); pos2 = dev->cd_end; From 51185745648813c1e07feaf178b325ce691af9b0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:06:20 +0100 Subject: [PATCH 014/218] Attempt to resolve again. --- src/video/vid_svga.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 7c674e00a..86173adef 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1543,8 +1543,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); - /* The chances of ever seeing a C-BUS (S)VGA card are approximately zero, but you never know. */ - } else if ((info->flags & DEVICE_CBUS) || (info->flags & DEVICE_ISA16)) { + } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_ISA16)) { svga->read = svga_read; svga->readw = svga_readw; svga->readl = NULL; From 7b1326236c0f967049664d8cc4bfa6b420d15bc4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:06:58 +0100 Subject: [PATCH 015/218] Tabs. --- src/video/vid_svga.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 86173adef..ffca0037f 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1543,6 +1543,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); + /* The chances of ever seeing a C-BUS (S)VGA card are approximately zero, but you never know. */ } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_ISA16)) { svga->read = svga_read; svga->readw = svga_readw; From 4e1926f954fb5a6dd033dffa209405b181de1d58 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:11:49 +0100 Subject: [PATCH 016/218] The last time. --- src/video/vid_svga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index ffca0037f..7c674e00a 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1544,7 +1544,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); /* The chances of ever seeing a C-BUS (S)VGA card are approximately zero, but you never know. */ - } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_ISA16)) { + } else if ((info->flags & DEVICE_CBUS) || (info->flags & DEVICE_ISA16)) { svga->read = svga_read; svga->readw = svga_readw; svga->readl = NULL; From c6dfd688f4dd8516e611b388fc5c53740deddefd Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 15 Feb 2025 07:09:14 +0100 Subject: [PATCH 017/218] Split off the CRC code to its own module. --- src/floppy/fdd_86f.c | 73 +++++++++++++++---------------------- src/include/86box/crc.h | 34 ++++++++++++++++++ src/include/86box/fdd.h | 15 ++------ src/utils/CMakeLists.txt | 1 + src/utils/crc.c | 77 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 57 deletions(-) create mode 100644 src/include/86box/crc.h create mode 100644 src/utils/crc.c diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 140e87899..f5626e35b 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -28,6 +28,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/timer.h> +#include <86box/crc.h> #include <86box/dma.h> #include <86box/nvr.h> #include <86box/random.h> @@ -223,6 +224,7 @@ typedef struct d86f_t { uint8_t *filebuf; uint8_t *outbuf; sector_t *last_side_sector[2]; + uint16_t crc_table[256]; } d86f_t; static const uint8_t encoded_fm[64] = { @@ -247,7 +249,6 @@ static const uint8_t encoded_mfm[64] = { }; static d86f_t *d86f[FDD_NUM]; -static uint16_t CRCTable[256]; static fdc_t *d86f_fdc; uint64_t poly = 0x42F0E1EBA9EA3693LL; /* ECMA normal */ @@ -276,28 +277,6 @@ d86f_log(const char *fmt, ...) # define d86f_log(fmt, ...) #endif -static void -setup_crc(uint16_t poly) -{ - int c = 256; - int bc; - uint16_t temp; - - while (c--) { - temp = c << 8; - bc = 8; - - while (bc--) { - if (temp & 0x8000) - temp = (temp << 1) ^ poly; - else - temp <<= 1; - - CRCTable[c] = temp; - } - } -} - void d86f_destroy_linked_lists(int drive, int side) { @@ -1237,16 +1216,10 @@ decodefm(UNUSED(int drive), uint16_t dat) return temp; } -void -fdd_calccrc(uint8_t byte, crc_t *crc_var) -{ - crc_var->word = (crc_var->word << 8) ^ CRCTable[(crc_var->word >> 8) ^ byte]; -} - static void d86f_calccrc(d86f_t *dev, uint8_t byte) { - fdd_calccrc(byte, &(dev->calc_crc)); + crc16_calc(dev->crc_table, byte, &(dev->calc_crc)); } int @@ -1274,7 +1247,9 @@ d86f_word_is_aligned(int drive, int side, uint32_t base_pos) /* State 1: Find sector ID */ void -d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) +d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, + uint16_t other_am, uint16_t wrong_am, + uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1282,7 +1257,8 @@ d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, ui if (dev->last_word[side] == req_am) { dev->calc_crc.word = 0xFFFF; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; @@ -1302,7 +1278,8 @@ d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, ui if ((ignore_other_am & 2) && (dev->last_word[side] == other_am)) { dev->calc_crc.word = 0xFFFF; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; if (ignore_other_am & 1) { @@ -1378,7 +1355,8 @@ d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, u if ((dev->last_word[side] == req_am) && (find->sync_marks >= 3)) { if (d86f_word_is_aligned(drive, side, find->sync_pos)) { dev->calc_crc.word = 0xCDB4; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; dev->preceding_bit[side] = dev->last_word[side] & 1; @@ -1390,7 +1368,8 @@ d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, u if ((ignore_other_am & 2) && (dev->last_word[side] == other_am) && (find->sync_marks >= 3)) { if (d86f_word_is_aligned(drive, side, find->sync_pos)) { dev->calc_crc.word = 0xCDB4; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; if (ignore_other_am & 1) { @@ -1464,8 +1443,11 @@ d86f_read_sector_id(int drive, int side, int match) if (dev->id_find.bytes_obtained < 4) { dev->last_sector.byte_array[dev->id_find.bytes_obtained] = decodefm(drive, dev->last_word[side]); - fdd_calccrc(dev->last_sector.byte_array[dev->id_find.bytes_obtained], &(dev->calc_crc)); - } else if ((dev->id_find.bytes_obtained >= 4) && (dev->id_find.bytes_obtained < 6)) { + crc16_calc(dev->crc_table, + dev->last_sector.byte_array[dev->id_find.bytes_obtained], + &(dev->calc_crc)); + } else if ((dev->id_find.bytes_obtained >= 4) && + (dev->id_find.bytes_obtained < 6)) { dev->track_crc.bytes[(dev->id_find.bytes_obtained & 1) ^ 1] = decodefm(drive, dev->last_word[side]); } @@ -1643,7 +1625,7 @@ d86f_read_sector_data(int drive, int side) } } } - fdd_calccrc(data, &(dev->calc_crc)); + crc16_calc(dev->crc_table, data, &(dev->calc_crc)); } else if (dev->data_find.bytes_obtained < crc_pos) dev->track_crc.bytes[(dev->data_find.bytes_obtained - sector_len) ^ 1] = decodefm(drive, dev->last_word[side]); @@ -1730,11 +1712,12 @@ d86f_write_sector_data(int drive, int side, int mfm, uint16_t am) if (dev->data_find.bytes_obtained < sector_len) { /* This is a data byte, so CRC it. */ - if (!dev->data_find.bytes_obtained) { - fdd_calccrc(decodefm(drive, am), &(dev->calc_crc)); - } else { - fdd_calccrc(dev->current_byte[side], &(dev->calc_crc)); - } + if (!dev->data_find.bytes_obtained) + crc16_calc(dev->crc_table, decodefm(drive, am), + &(dev->calc_crc)); + else + crc16_calc(dev->crc_table, dev->current_byte[side], + &(dev->calc_crc)); } } } else { @@ -3861,8 +3844,6 @@ d86f_load(int drive, char *fn) void d86f_init(void) { - setup_crc(0x1021); - for (uint8_t i = 0; i < FDD_NUM; i++) d86f[i] = NULL; } @@ -3926,6 +3907,8 @@ d86f_setup(int drive) dev->last_side_sector[0] = NULL; dev->last_side_sector[1] = NULL; + crc16_setup(dev->crc_table, 0x1021); + /* Set the drive as active. */ d86f[drive] = dev; } diff --git a/src/include/86box/crc.h b/src/include/86box/crc.h new file mode 100644 index 000000000..1a6e76dab --- /dev/null +++ b/src/include/86box/crc.h @@ -0,0 +1,34 @@ +/* + * 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. + * + * Definitions for the CRC code. + * + * Authors: Miran Grca, + * + * Copyright 2016-2025 Miran Grca. + */ +#ifndef EMU_CRC_H +#define EMU_CRC_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + uint16_t word; + uint8_t bytes[2]; +} crc_t; + +extern void crc16_setup(uint16_t *crc_table, uint16_t poly); +extern void crc16_calc(uint16_t *crc_table, uint8_t byte, crc_t *crc_var); + +#ifdef __cplusplus +} +#endif + +#endif /*EMU_CRC_H*/ diff --git a/src/include/86box/fdd.h b/src/include/86box/fdd.h index ff9315f1d..d6ade3bc6 100644 --- a/src/include/86box/fdd.h +++ b/src/include/86box/fdd.h @@ -8,15 +8,13 @@ * * Definitions for the floppy drive emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2025 Sarah Walker. + * Copyright 2016-2025 Miran Grca. + * Copyright 2018-2025 Fred N. van Kempen. */ #ifndef EMU_FDD_H #define EMU_FDD_H @@ -129,13 +127,6 @@ extern int drive_empty[FDD_NUM]; #define SECTOR_FIRST -2 #define SECTOR_NEXT -1 -typedef union { - uint16_t word; - uint8_t bytes[2]; -} crc_t; - -void fdd_calccrc(uint8_t byte, crc_t *crc_var); - typedef struct d86f_handler_t { uint16_t (*disk_flags)(int drive); uint16_t (*side_flags)(int drive); diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 1d4b1f73e..2ffe41f7b 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(utils OBJECT cJSON.c + crc.c fifo.c fifo8.c ini.c diff --git a/src/utils/crc.c b/src/utils/crc.c new file mode 100644 index 000000000..096a94c72 --- /dev/null +++ b/src/utils/crc.c @@ -0,0 +1,77 @@ +/* + * 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. + * + * CRC implementation. + * + * Authors: Miran Grca, + * + * Copyright 2016-2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/dma.h> +#include <86box/nvr.h> +#include <86box/random.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/crc.h> + +#ifdef ENABLE_CRC_LOG +int d86f_do_log = ENABLE_CRC_LOG; + +static void +crc_log(const char *fmt, ...) +{ + va_list ap; + + if (crc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define crc_log(fmt, ...) +#endif + +void +crc16_setup(uint16_t *crc_table, uint16_t poly) +{ + int c = 256; + int bc; + uint16_t temp; + + while (c--) { + temp = c << 8; + bc = 8; + + while (bc--) { + if (temp & 0x8000) + temp = (temp << 1) ^ poly; + else + temp <<= 1; + + crc_table[c] = temp; + } + } +} + +void +crc16_calc(uint16_t *crc_table, uint8_t byte, crc_t *crc_var) +{ + crc_var->word = (crc_var->word << 8) ^ + crc_table[(crc_var->word >> 8) ^ byte]; +} From a62a6594e6d437b88bcc46bfc65c2688497dce64 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 5 Mar 2025 23:48:47 +0100 Subject: [PATCH 018/218] SCSI CD-ROM: Fixed SCSI standard reporting in INQUIRY. --- src/scsi/scsi_cdrom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 840bec6a0..0626fbee9 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -3444,7 +3444,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->buffer[1] = 0x80; /* Removable */ if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->buffer[3] = cdrom_get_scsi_std(dev->drv->type); + dev->buffer[2] = (dev->ven_cmd == scsi_cdrom_command_nec) ? + 0x00 : cdrom_get_scsi_std(dev->drv->type); if (dev->drv->is_toshiba) /* Linked Command and Relative Addressing supported */ From 4be691afe76181f3a885a3626bc814219a805424 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 6 Mar 2025 01:44:02 +0100 Subject: [PATCH 019/218] IDE: Correctly terminate ATAPI command on DMA underrun, fixes Windows 9x freezes. --- src/disk/hdc_ide.c | 19 +++++++++++++------ src/scsi/scsi_cdrom.c | 1 - 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index afc466644..eb160c41b 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,7 +241,6 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); -// #define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -1092,12 +1091,16 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - // pclog("Reading block %i... ", ide->sc->sector_len + 1); + // pclog("Reading block %i (%i, %i)... ", ide->sc->sector_len + 1, ide->sc->block_len, ide->sc->packet_len); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { - if (ide->sc->block_len == 0) + if (ide->sc->block_len == 0) { ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, bm->priv); - else { + + /* Underrun. */ + if (ret == 1) + ret = 3; + } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos - ide->sc->block_len, ide->sc->block_len, 0, bm->priv); @@ -1145,9 +1148,13 @@ ide_atapi_callback(ide_t *ide) case PHASE_DATA_OUT_DMA: if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { - if (ide->sc->block_len == 0) + if (ide->sc->block_len == 0) { ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 1, bm->priv); - else { + + /* Underrun. */ + if (ret == 1) + ret = 3; + } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos, ide->sc->block_len, 1, bm->priv); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 0626fbee9..c505d9f53 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,7 +15,6 @@ */ #include #include -// #define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif From 265152db754b7b60cc3eeafd2b6b596ef0c4da0b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 7 Mar 2025 19:58:36 +0100 Subject: [PATCH 020/218] NCR 53c400: slightly more accurate speed. See above. --- src/scsi/scsi_ncr53c400.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index c83e75442..fc62a1cab 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -425,8 +425,8 @@ ncr53c400_callback(void *priv) if (scsi_bus->tx_mode != PIO_TX_BUS) { if (ncr400->type == ROM_T130B) { - ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 200.0); - timer_on_auto(&ncr400->timer, scsi_bus->period / 200.0); + ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 225.0); + timer_on_auto(&ncr400->timer, scsi_bus->period / 225.0); } else timer_on_auto(&ncr400->timer, 1.0); } From 86343327be6d2cd41424d1deeaa659b493bc31f2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 8 Mar 2025 02:13:14 +0600 Subject: [PATCH 021/218] Initial PCem OpenGL 3.x renderer port --- src/86box.c | 2 + src/device/kbc_at_dev.c | 3 + src/include/86box/86box.h | 2 + src/include/86box/ini.h | 28 + src/include/86box/keyboard.h | 27 +- src/include/86box/qt-glsl.h | 158 +++ src/include/86box/qt-glslp-parser.h | 56 + src/ini.c | 22 + src/qt/CMakeLists.txt | 3 + src/qt/qt.c | 5 + src/qt/qt_glsl_parser.cpp | 308 +++++ src/qt/qt_main.cpp | 1 + src/qt/qt_mainwindow.cpp | 3 + src/qt/qt_openglrenderer_pcem.cpp | 1679 +++++++++++++++++++++++++++ src/qt/qt_openglrenderer_pcem.hpp | 127 ++ src/qt/qt_rendererstack.cpp | 33 +- src/qt/qt_rendererstack.hpp | 1 + 17 files changed, 2442 insertions(+), 16 deletions(-) create mode 100644 src/include/86box/qt-glsl.h create mode 100644 src/include/86box/qt-glslp-parser.h create mode 100644 src/qt/qt_glsl_parser.cpp create mode 100644 src/qt/qt_openglrenderer_pcem.cpp create mode 100644 src/qt/qt_openglrenderer_pcem.hpp diff --git a/src/86box.c b/src/86box.c index aa3afb085..13167b1bd 100644 --- a/src/86box.c +++ b/src/86box.c @@ -252,6 +252,8 @@ int unscaled_size_y = SCREEN_RES_Y; /* current unscaled size Y */ int efscrnsz_y = SCREEN_RES_Y; #endif +__thread int is_cpu_thread = 0; + static wchar_t mouse_msg[3][200]; static volatile atomic_int do_pause_ack = 0; diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index c1041e6e1..82ce31bfd 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -88,6 +88,9 @@ kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main) { if (main) { kbc_at_dev_log("%s: dev->queue[%02X] = %02X;\n", dev->name, dev->queue_end, val); + if (!is_cpu_thread && kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) { + while (kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) {} + } dev->queue[dev->queue_end] = val; dev->queue_end = (dev->queue_end + 1) & dev->fifo_mask; } else { diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 79bb84009..30905741c 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -188,6 +188,8 @@ extern FILE *stdlog; /* file to log output to */ #endif extern int config_changed; /* config has changed */ +extern __thread int is_cpu_thread; /* Is this the CPU thread? */ + /* Function prototypes. */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list ap); diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index d52620f69..2a73a18b0 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -58,6 +58,7 @@ extern void ini_section_set_hex20(ini_section_t section, const char *name, i extern void ini_section_set_mac(ini_section_t section, const char *name, int val); extern void ini_section_set_string(ini_section_t section, const char *name, const char *val); extern void ini_section_set_wstring(ini_section_t section, const char *name, wchar_t *val); +extern int ini_has_entry(ini_section_t self, const char *name); #define ini_delete_var(ini, head, name) ini_section_delete_var(ini_find_section(ini, head), name) @@ -90,6 +91,33 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); +static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); }; +static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); + if (size == 0) + return res; + strncpy(dst, str, size); + return res; +} +static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = ini_get_int((ini_t)config, "", name, defVal); + return res; +} +static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = (float)ini_get_double((ini_t)config, "", name, defVal); + return res; +} +static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = !!ini_get_int((ini_t)config, "", name, defVal); + return res; +} +static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); } +static inline void wx_config_free(void *config) { ini_close(config); }; + #ifdef __cplusplus } #endif diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 110e4f760..b7f301a58 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -22,6 +22,13 @@ #ifndef EMU_KEYBOARD_H #define EMU_KEYBOARD_H +#ifdef __cplusplus +# include +using atomic_uint = std::atomic_uint; +#else +# include +#endif + enum { DEV_KBD = 0, DEV_AUX = 1 @@ -54,16 +61,16 @@ typedef struct kbc_at_port_t { typedef struct atkbc_dev_t { const char *name; /* name of this device */ - uint8_t type; - uint8_t command; - uint8_t last_scan_code; - uint8_t state; - uint8_t resolution; - uint8_t rate; - uint8_t cmd_queue_start; - uint8_t cmd_queue_end; - uint8_t queue_start; - uint8_t queue_end; + uint8_t type; + uint8_t command; + uint8_t last_scan_code; + uint8_t state; + uint8_t resolution; + uint8_t rate; + uint8_t cmd_queue_start; + uint8_t cmd_queue_end; + atomic_uint queue_start; + atomic_uint queue_end; uint16_t flags; diff --git a/src/include/86box/qt-glsl.h b/src/include/86box/qt-glsl.h new file mode 100644 index 000000000..0cd8e27cd --- /dev/null +++ b/src/include/86box/qt-glsl.h @@ -0,0 +1,158 @@ +#ifndef SRC_WX_GLSL_H_ +#define SRC_WX_GLSL_H_ + +#define MAX_PREV 7 + +#define MAX_SHADERS 20 +#define MAX_TEXTURES 20 +#define MAX_PARAMETERS 100 + +#define MAX_USER_SHADERS 20 +//#define SDL2_SHADER_DEBUG + +struct shader_scale { + int mode[2]; + float value[2]; +}; + +struct shader_state { + float input_size[2]; + float input_texture_size[2]; + float output_texture_size[2]; + float output_size[2]; + float tex_coords[8]; +}; + +struct shader_vbo { + int vertex_coord; + int tex_coord; + int color; +}; + +struct shader_texture { + int id; + int width; + int height; + int type; + int internal_format; + int format; + int min_filter; + int mag_filter; + int wrap_mode; + void *data; + int mipmap; +}; + +struct shader_lut_texture { + char name[50]; + struct shader_texture texture; +}; + +struct shader_fbo { + int id; + struct shader_texture texture; + int srgb; + int mipmap_input; +}; + +struct shader_prev { + struct shader_fbo fbo; + struct shader_vbo vbo; +}; + +struct shader_input { + int texture; + int input_size; + int texture_size; + int tex_coord; +}; + +struct shader_uniforms { + int mvp_matrix; + int vertex_coord; + int tex_coord; + int color; + + int texture; + int input_size; + int texture_size; + int output_size; + + int frame_count; + int frame_direction; + + struct shader_input orig; + struct shader_input pass[MAX_SHADERS]; + struct shader_input prev_pass[MAX_SHADERS]; + struct shader_input prev[MAX_PREV]; + + int parameters[MAX_PARAMETERS]; + int lut_textures[MAX_TEXTURES]; +}; + +struct shader_program { + int vertex_shader; + int fragment_shader; + int id; +}; + +struct shader_parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct shader_pass { + int active; + char alias[64]; + int vertex_array; + int frame_count_mod; + struct shader_program program; + struct shader_uniforms uniforms; + struct shader_fbo fbo; + struct shader_vbo vbo; + struct shader_state state; + struct shader_scale scale; +}; + +struct glsl_shader { + int active; + char name[64]; + + int num_passes; + struct shader_pass passes[MAX_SHADERS]; + + int num_lut_textures; + struct shader_lut_texture lut_textures[MAX_TEXTURES]; + + int num_parameters; + struct shader_parameter parameters[MAX_PARAMETERS]; + + struct shader_pass prev_scene; + struct shader_prev prev[MAX_PREV + 1]; + + int last_prev_update; + int has_prev; + + float shader_refresh_rate; + + int input_filter_linear; +}; + +typedef struct glsl_t { + int num_shaders; + struct glsl_shader shaders[MAX_USER_SHADERS]; + struct shader_pass scene; + struct shader_pass final_pass; + struct shader_pass fs_color; +#ifdef SDL2_SHADER_DEBUG + struct shader_pass debug; +#endif + int srgb; +} glsl_t; + +#endif \ No newline at end of file diff --git a/src/include/86box/qt-glslp-parser.h b/src/include/86box/qt-glslp-parser.h new file mode 100644 index 000000000..cf2ac464a --- /dev/null +++ b/src/include/86box/qt-glslp-parser.h @@ -0,0 +1,56 @@ +#ifndef SRC_WX_GLSLP_PARSER_H_ +#define SRC_WX_GLSLP_PARSER_H_ + +#include "qt-glsl.h" + +struct parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct texture { + char path[256]; + char name[50]; + int linear; + int mipmap; + char wrap_mode[50]; +}; + +struct shader { + char shader_fn[1024]; + char *shader_program; + char alias[64]; + int filter_linear; + int float_framebuffer; + int srgb_framebuffer; + int mipmap_input; + int frame_count_mod; + char wrap_mode[50]; + char scale_type_x[9], scale_type_y[9]; + float scale_x, scale_y; +}; + +typedef struct glslp_t { + char name[64]; + int num_shaders; + struct shader shaders[MAX_SHADERS]; + + int num_textures; + struct texture textures[MAX_TEXTURES]; + + int num_parameters; + struct parameter parameters[MAX_PARAMETERS]; + + int input_filter_linear; +} glslp_t; + +void get_glslp_name(const char *f, char *s, int size); +glslp_t *glslp_parse(const char *f); +void glslp_free(glslp_t *p); + +#endif /* SRC_WX_GLSLP_PARSER_H_ */ \ No newline at end of file diff --git a/src/ini.c b/src/ini.c index 78c873758..4ea6f6381 100644 --- a/src/ini.c +++ b/src/ini.c @@ -157,6 +157,23 @@ find_entry(section_t *section, const char *name) return (NULL); } +int +ini_has_entry(ini_section_t self, const char *name) +{ + section_t *section = (section_t *) self; + const entry_t *entry; + int value = 0; + + if (section == NULL) + return 0; + + entry = find_entry(section, name); + if (entry == NULL) + return 0; + + return 1; +} + static int entries_num(section_t *section) { @@ -593,6 +610,11 @@ ini_section_get_int(ini_section_t self, const char *name, int def) if (entry == NULL) return def; + if (stricmp(entry->data, "true") == 0) + return 1; + if (stricmp(entry->data, "false") == 0) + return 0; + sscanf(entry->data, "%i", &value); return value; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index c08a03016..fd82b9053 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -89,6 +89,9 @@ add_library(ui STATIC qt_hardwarerenderer.hpp qt_openglrenderer.cpp qt_openglrenderer.hpp + qt_openglrenderer_pcem.cpp + qt_openglrenderer_pcem.hpp + qt_glsl_parser.cpp qt_opengloptions.cpp qt_opengloptions.hpp qt_opengloptionsdialog.cpp diff --git a/src/qt/qt.c b/src/qt/qt.c index a9a6460eb..13ddbf498 100644 --- a/src/qt/qt.c +++ b/src/qt/qt.c @@ -54,6 +54,8 @@ plat_vidapi(const char *api) return 4; } else if (!strcasecmp(api, "vnc")) { return 5; + } else if (!strcasecmp(api, "qt_opengl3_pcem")) { + return 6; } return 0; @@ -83,6 +85,9 @@ plat_vidapi_name(int api) case 5: name = "vnc"; break; + case 6: + name = "qt_opengl3_pcem"; + break; default: fatal("Unknown renderer: %i\n", api); break; diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp new file mode 100644 index 000000000..7cf032a52 --- /dev/null +++ b/src/qt/qt_glsl_parser.cpp @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +extern "C" +{ +#include <86box/86box.h> +#include <86box/ini.h> +#include <86box/qt-glslp-parser.h> +#include <86box/path.h> +} + +#define safe_strncpy(a, b, n) \ + do { \ + strncpy((a), (b), (n)-1); \ + (a)[(n)-1] = 0; \ + } while (0) + +static int endswith(const char *str, const char *ext) { + int i; + const char *p; + int elen = strlen(ext); + int slen = strlen(str); + if (slen >= elen) { + p = &str[slen - elen]; + for (i = 0; i < elen; ++i) { + if (tolower(p[i]) != tolower(ext[i])) + return 0; + } + return 1; + } + return 0; +} + +static char *load_file(const char *fn) { + FILE *f = fopen(fn, "rb"); + if (!f) + return 0; + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + char *data = (char*)malloc(fsize + 1); + + fread(data, fsize, 1, f); + fclose(f); + + data[fsize] = 0; + + return data; +} + +static void strip_lines(const char *program, const char *starts_with) { + /* strip parameters */ + char *ptr = strstr(program, starts_with); + while (ptr) { + while (*ptr != '\n' && *ptr != '\0') + *ptr++ = ' '; + ptr = strstr(program, starts_with); + } +} + +static void strip_parameters(const char *program) { + /* strip parameters */ + strip_lines(program, "#pragma parameter"); +} + +static void strip_defines(const char *program) { + /* strip texture define */ + strip_lines(program, "#define texture"); +} + +static int has_parameter(glslp_t *glsl, char *id) { + int i; + for (i = 0; i < glsl->num_parameters; ++i) + if (!strcmp(glsl->parameters[i].id, id)) + return 1; + return 0; +} + +static int get_parameters(glslp_t *glsl) { + int i; + struct parameter p; + for (i = 0; i < glsl->num_shaders; ++i) { + struct shader *shader = &glsl->shaders[i]; + FILE *f = fopen(shader->shader_fn, "rb"); + if (!f) + return 0; + + char line[1024]; + while (fgets(line, sizeof(line) - 1, f) && glsl->num_parameters < MAX_PARAMETERS) { + int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, + &p.default_value, &p.min, &p.max, &p.step); + if (num < 5) + continue; + p.id[63] = 0; + p.description[63] = 0; + + if (num == 5) + p.step = 0.1f * (p.max - p.min); + + p.value = p.default_value; + + if (!has_parameter(glsl, p.id)) { + memcpy(&glsl->parameters[glsl->num_parameters++], &p, sizeof(struct parameter)); + pclog("Read parameter: %s (%s) %f, %f -> %f (%f)\n", p.id, p.description, p.default_value, p.min, + p.max, p.step); + } + } + + fclose(f); + } + + return 1; +} + +static struct parameter *get_parameter(glslp_t *glslp, const char *id) { + int i; + for (i = 0; i < glslp->num_parameters; ++i) { + if (!strcmp(glslp->parameters[i].id, id)) { + return &glslp->parameters[i]; + } + } + return 0; +} + +static glslp_t *glsl_parse(const char *f) { + glslp_t *glslp = (glslp_t*)malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + glslp->num_shaders = 1; + struct shader *shader = &glslp->shaders[0]; + strcpy(shader->shader_fn, f); + shader->shader_program = load_file(f); + if (!shader->shader_program) { + //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + shader->scale_x = shader->scale_y = 1.0f; + strcpy(shader->scale_type_x, "source"); + strcpy(shader->scale_type_y, "source"); + get_parameters(glslp); + return glslp; +} + +extern "C" { + +void get_glslp_name(const char *f, char *s, int size) { safe_strncpy(s, path_get_filename((char *)f), size); } + +glslp_t *glslp_parse(const char *f) { + int i, j, len, sublen; + char s[513], t[513], z[540]; + + memset(s, 0, sizeof(s)); + if (endswith(f, ".glsl")) + return glsl_parse(f); + + void *cfg = wx_config_load(f); + + if (!cfg) { + fprintf(stderr, "GLSLP Error: Could not load GLSLP-file %s\n", f); + return 0; + } + + glslp_t *glslp = (glslp_t*)malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + + get_glslp_name(f, glslp->name, sizeof(glslp->name)); + + wx_config_get_int(cfg, "shaders", &glslp->num_shaders, 0); + + wx_config_get_bool(cfg, "filter_linear0", &glslp->input_filter_linear, -1); + + for (i = 0; i < glslp->num_shaders; ++i) { + struct shader *shader = &glslp->shaders[i]; + + snprintf(s, sizeof(s) - 1, "shader%d", i); + if (!wx_config_get_string(cfg, s, t, sizeof(t), 0)) { + /* shader doesn't exist, lets break here */ + glslp->num_shaders = i; + break; + } + strcpy(s, f); + *path_get_filename(s) = 0; + snprintf(shader->shader_fn, sizeof(shader->shader_fn) - 1, "%s%s", s, t); + shader->shader_program = load_file(shader->shader_fn); + if (!shader->shader_program) { + fprintf(stderr, "GLSLP Error: Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + + snprintf(s, sizeof(s) - 1, "alias%d", i); + wx_config_get_string(cfg, s, shader->alias, sizeof(shader->alias), 0); + + snprintf(s, sizeof(s) - 1, "filter_linear%d", i + 1); + wx_config_get_bool(cfg, s, &shader->filter_linear, 0); + + snprintf(s, sizeof(s) - 1, "wrap_mode%d", i); + wx_config_get_string(cfg, s, shader->wrap_mode, sizeof(shader->wrap_mode), 0); + + snprintf(s, sizeof(s) - 1, "float_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->float_framebuffer, 0); + snprintf(s, sizeof(s) - 1, "srgb_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->srgb_framebuffer, 0); + + snprintf(s, sizeof(s) - 1, "mipmap_input%d", i); + wx_config_get_bool(cfg, s, &shader->mipmap_input, 0); + + strcpy(shader->scale_type_x, "source"); + snprintf(s, sizeof(s) - 1, "scale_type_x%d", i); + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + strcpy(shader->scale_type_y, "source"); + snprintf(s, sizeof(s) - 1, "scale_type_y%d", i); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + snprintf(s, sizeof(s) - 1, "scale_type%d", i); + if (wx_config_has_entry(cfg, s)) { + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + } + + snprintf(s, sizeof(s) - 1, "scale_x%d", i); + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + snprintf(s, sizeof(s) - 1, "scale_y%d", i); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + snprintf(s, sizeof(s) - 1, "scale%d", i); + if (wx_config_has_entry(cfg, s)) { + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + } + + snprintf(s, sizeof(s) - 1, "frame_count_mod%d", i); + wx_config_get_int(cfg, s, &shader->frame_count_mod, 0); + } + + /* textures */ + glslp->num_textures = 0; + wx_config_get_string(cfg, "textures", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) { + if (t[i] == ';' || i == len - 1) { + sublen = (i - j) + ((i == len - 1) ? 1 : 0) + 1; + safe_strncpy(s, t + j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + struct texture *tex = &glslp->textures[glslp->num_textures++]; + + strcpy(tex->name, s); + wx_config_get_string(cfg, s, tex->path, sizeof(tex->path), 0); + + snprintf(z, sizeof(z) - 1, "%s_linear", s); + wx_config_get_bool(cfg, z, &tex->linear, 0); + + snprintf(z, sizeof(z) - 1, "%s_mipmap", s); + wx_config_get_bool(cfg, z, &tex->mipmap, 0); + + snprintf(z, sizeof(z) - 1, "%s_wrap_mode", s); + wx_config_get_string(cfg, z, tex->wrap_mode, sizeof(tex->wrap_mode), 0); + + j = i + 1; + } + } + + /* parameters */ + get_parameters(glslp); + + wx_config_get_string(cfg, "parameters", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) { + if (t[i] == ';' || i == len - 1) { + sublen = (i - j) + ((i == len - 1) ? 1 : 0) + 1; + safe_strncpy(s, t + j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + struct parameter *p = get_parameter(glslp, s); + + if (p) + wx_config_get_float(cfg, s, &p->default_value, 0); + + j = i + 1; + } + } + + wx_config_free(cfg); + + return glslp; +} + +void glslp_free(glslp_t *p) { + int i; + for (i = 0; i < p->num_shaders; ++i) + if (p->shaders[i].shader_program) + free(p->shaders[i].shader_program); + free(p); +} + +} \ No newline at end of file diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 719208c18..9d965be31 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -389,6 +389,7 @@ main_thread_fn() // title_update = 1; uint64_t old_time = elapsed_timer.elapsed(); int drawits = frames = 0; + is_cpu_thread = 1; while (!is_quit && cpu_thread_run) { /* See if it is time to run a frame of code. */ const uint64_t new_time = elapsed_timer.elapsed(); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 1cc6c33c9..4c1738e63 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -452,6 +452,9 @@ MainWindow::MainWindow(QWidget *parent) endblit(); } #endif + case 6: + newVidApi = RendererStack::Renderer::OpenGL3PCem; + break; } ui->stackedWidget->switchRenderer(newVidApi); if (!show_second_monitors) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp new file mode 100644 index 000000000..4ab66105c --- /dev/null +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -0,0 +1,1679 @@ +#include "qt_renderercommon.hpp" +#include "qt_mainwindow.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "qt_openglrenderer_pcem.hpp" + +extern "C" { +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/video.h> +#include <86box/path.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/qt-glslp-parser.h> +} + +#define SCALE_SOURCE 0 +#define SCALE_VIEWPORT 1 +#define SCALE_ABSOLUTE 2 + +float gl3_shader_refresh_rate = 0; +float gl3_input_scale = 1.0f; +int gl3_input_stretch = FULLSCR_SCALE_FULL; +char gl3_shader_file[MAX_USER_SHADERS][512]; + +static int max_texture_size = 65536; + +static struct shader_texture scene_texture; + +static glsl_t *active_shader; + +static QOpenGLExtraFunctions glw; + +static GLfloat matrix[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + +extern int video_filter_method; +extern int video_vsync; +extern int video_focus_dim; +extern int video_refresh_rate; + +static int glsl_version[2]; + +const char *vertex_shader_default_tex_src = "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec2 TexCoord;\n" + "\n" + "out vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " texCoord = TexCoord;\n" + "}\n"; + +const char *fragment_shader_default_tex_src = "#version 130\n" + "\n" + "in vec2 texCoord;\n" + "uniform sampler2D Texture;\n" + "\n" + "out vec4 color;" + "\n" + "void main()\n" + "{\n" + " color = texture(Texture, texCoord);\n" + "}\n"; + +const char *vertex_shader_default_color_src = "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec4 Color;\n" + "\n" + "out vec4 color;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " color = Color;\n" + "}\n"; + +const char *fragment_shader_default_color_src = "#version 130\n" + "\n" + "in vec4 color;\n" + "\n" + "out vec4 outColor;" + "\n" + "void main()\n" + "{\n" + " outColor = color;\n" + "}\n"; + +static int +next_pow2(unsigned int n) +{ + n--; + n |= n >> 1; // Divide by 2^k for consecutive doublings of k up to 32, + n |= n >> 2; // and then or the results. + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + + return n; +} + +static int +create_program(struct shader_program *program) +{ + GLint status; + program->id = glw.glCreateProgram(); + glw.glAttachShader(program->id, program->vertex_shader); + glw.glAttachShader(program->id, program->fragment_shader); + + glw.glLinkProgram(program->id); + + glw.glDeleteShader(program->vertex_shader); + glw.glDeleteShader(program->fragment_shader); + + program->vertex_shader = program->fragment_shader = 0; + + glw.glGetProgramiv(program->id, GL_LINK_STATUS, &status); + + if (!status) { + int maxLength; + int length; + glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); + char *log = (char *) malloc(maxLength); + glw.glGetProgramInfoLog(program->id, maxLength, &length, log); + // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); + free(log); + return 0; + } + + return 1; +} + +static int +compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) +{ + const char *source[3]; + char version[50]; + int ver = 0; + char *version_loc = strstr(program, "#version"); + if (version_loc) + ver = (int) strtol(version_loc + 8, (char **) &program, 10); + else { + ver = glsl_version[0] * 100 + glsl_version[1] * 10; + if (ver == 300) + ver = 130; + else if (ver == 310) + ver = 140; + else if (ver == 320) + ver = 150; + } + sprintf(version, "#version %d\n", ver); + source[0] = version; + source[1] = prepend ? prepend : ""; + source[2] = program; + + pclog("GLSL version %d\n", ver); + + GLuint shader = glw.glCreateShader(shader_type); + glw.glShaderSource(shader, 3, source, NULL); + glw.glCompileShader(shader); + + GLint status = 0; + glw.glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) { + GLint length; + glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + char *log = (char *) malloc(length); + glw.glGetShaderInfoLog(shader, length, &length, log); + // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); + + pclog("Could not compile shader: %s\n", log); + // pclog("Shader: %s\n", program); + + free(log); + return 0; + } + + *dst = shader; + + return 1; +} + +static GLuint +get_uniform(GLuint program, const char *name) +{ + return glw.glGetUniformLocation(program, name); +} + +static GLuint +get_attrib(GLuint program, const char *name) +{ + return glw.glGetAttribLocation(program, name); +} + +static void +find_uniforms(struct glsl_shader *glsl, int num_pass) +{ + int i; + char s[50]; + struct shader_pass *pass = &glsl->passes[num_pass]; + int p = pass->program.id; + glw.glUseProgram(p); + + struct shader_uniforms *u = &pass->uniforms; + + u->mvp_matrix = get_uniform(p, "MVPMatrix"); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->color = get_attrib(p, "Color"); + + u->frame_count = get_uniform(p, "FrameCount"); + u->frame_direction = get_uniform(p, "FrameDirection"); + + u->texture = get_uniform(p, "Texture"); + u->input_size = get_uniform(p, "InputSize"); + u->texture_size = get_uniform(p, "TextureSize"); + u->output_size = get_uniform(p, "OutputSize"); + + u->orig.texture = get_uniform(p, "OrigTexture"); + u->orig.input_size = get_uniform(p, "OrigInputSize"); + u->orig.texture_size = get_uniform(p, "OrigTextureSize"); + + for (i = 0; i < glsl->num_passes; ++i) { + sprintf(s, "Pass%dTexture", (i + 1)); + u->pass[i].texture = get_uniform(p, s); + sprintf(s, "Pass%dInputSize", (i + 1)); + u->pass[i].input_size = get_uniform(p, s); + sprintf(s, "Pass%dTextureSize", (i + 1)); + u->pass[i].texture_size = get_uniform(p, s); + + sprintf(s, "PassPrev%dTexture", num_pass - i); + u->prev_pass[i].texture = get_uniform(p, s); + sprintf(s, "PassPrev%dInputSize", num_pass - i); + u->prev_pass[i].input_size = get_uniform(p, s); + sprintf(s, "PassPrev%dTextureSize", num_pass - i); + u->prev_pass[i].texture_size = get_uniform(p, s); + } + + u->prev[0].texture = get_uniform(p, "PrevTexture"); + u->prev[0].tex_coord = get_attrib(p, "PrevTexCoord"); + for (i = 1; i < MAX_PREV; ++i) { + sprintf(s, "Prev%dTexture", i); + u->prev[i].texture = get_uniform(p, s); + sprintf(s, "Prev%dTexCoord", i); + u->prev[i].tex_coord = get_attrib(p, s); + } + for (i = 0; i < MAX_PREV; ++i) + if (u->prev[i].texture >= 0) + glsl->has_prev = 1; + + for (i = 0; i < glsl->num_lut_textures; ++i) + u->lut_textures[i] = get_uniform(p, glsl->lut_textures[i].name); + + for (i = 0; i < glsl->num_parameters; ++i) + u->parameters[i] = get_uniform(p, glsl->parameters[i].id); + + glw.glUseProgram(0); +} + +static void +set_scale_mode(char *scale, int *dst) +{ + if (!strcmp(scale, "viewport")) + *dst = SCALE_VIEWPORT; + else if (!strcmp(scale, "absolute")) + *dst = SCALE_ABSOLUTE; + else + *dst = SCALE_SOURCE; +} + +static void +setup_scale(struct shader *shader, struct shader_pass *pass) +{ + set_scale_mode(shader->scale_type_x, &pass->scale.mode[0]); + set_scale_mode(shader->scale_type_y, &pass->scale.mode[1]); + pass->scale.value[0] = shader->scale_x; + pass->scale.value[1] = shader->scale_y; +} + +static void +create_texture(struct shader_texture *tex) +{ + if (tex->width > max_texture_size) + tex->width = max_texture_size; + if (tex->height > max_texture_size) + tex->height = max_texture_size; + pclog("Create texture with size %dx%d\n", tex->width, tex->height); + glw.glGenTextures(1, (GLuint *) &tex->id); + glw.glBindTexture(GL_TEXTURE_2D, tex->id); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex->wrap_mode); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex->wrap_mode); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex->min_filter); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex->mag_filter); + glw.glTexImage2D(GL_TEXTURE_2D, 0, tex->internal_format, tex->width, tex->height, 0, tex->format, tex->type, tex->data); + if (tex->mipmap) + glw.glGenerateMipmap(GL_TEXTURE_2D); + glw.glBindTexture(GL_TEXTURE_2D, 0); +} + +static void +delete_texture(struct shader_texture *tex) +{ + if (tex->id > 0) + glw.glDeleteTextures(1, (GLuint *) &tex->id); + tex->id = 0; +} + +static void +delete_fbo(struct shader_fbo *fbo) +{ + if (fbo->id >= 0) { + glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); + delete_texture(&fbo->texture); + } +} + +static void +delete_program(struct shader_program *program) +{ + if (program->vertex_shader) + glw.glDeleteShader(program->vertex_shader); + if (program->fragment_shader) + glw.glDeleteShader(program->fragment_shader); + glw.glDeleteProgram(program->id); +} + +static void +delete_vbo(struct shader_vbo *vbo) +{ + if (vbo->color >= 0) + glw.glDeleteBuffers(1, (GLuint *) &vbo->color); + glw.glDeleteBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glDeleteBuffers(1, (GLuint *) &vbo->tex_coord); +} + +static void +delete_pass(struct shader_pass *pass) +{ + delete_fbo(&pass->fbo); + delete_vbo(&pass->vbo); + delete_program(&pass->program); + glw.glDeleteVertexArrays(1, (GLuint *) &pass->vertex_array); +} + +static void +delete_prev(struct shader_prev *prev) +{ + delete_fbo(&prev->fbo); + delete_vbo(&prev->vbo); +} + +static void +delete_shader(struct glsl_shader *glsl) +{ + int i; + for (i = 0; i < glsl->num_passes; ++i) + delete_pass(&glsl->passes[i]); + if (glsl->has_prev) { + delete_pass(&glsl->prev_scene); + for (i = 0; i < MAX_PREV; ++i) + delete_prev(&glsl->prev[i]); + } + for (i = 0; i < glsl->num_lut_textures; ++i) + delete_texture(&glsl->lut_textures[i].texture); +} + +static void +delete_glsl(glsl_t *glsl) +{ + int i; + for (i = 0; i < glsl->num_shaders; ++i) + delete_shader(&glsl->shaders[i]); + delete_pass(&glsl->scene); + delete_pass(&glsl->fs_color); + delete_pass(&glsl->final_pass); +#ifdef SDL2_SHADER_DEBUG + delete_pass(&glsl->debug); +#endif +} + +static void +create_fbo(struct shader_fbo *fbo) +{ + create_texture(&fbo->texture); + + glw.glGenFramebuffers(1, (GLuint *) &fbo->id); + glw.glBindFramebuffer(GL_FRAMEBUFFER, fbo->id); + glw.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->texture.id, 0); + + if (glw.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + pclog("Could not create framebuffer!\n"); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +static void +setup_fbo(struct shader *shader, struct shader_fbo *fbo) +{ + fbo->texture.internal_format = GL_RGBA8; + fbo->texture.format = GL_RGBA; + fbo->texture.min_filter = fbo->texture.mag_filter = shader->filter_linear ? GL_LINEAR : GL_NEAREST; + fbo->texture.width = 1024; + fbo->texture.height = 1024; + fbo->texture.type = GL_UNSIGNED_BYTE; + if (!strcmp(shader->wrap_mode, "repeat")) + fbo->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(shader->wrap_mode, "mirrored_repeat")) + fbo->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(shader->wrap_mode, "clamp_to_edge")) + fbo->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + fbo->texture.wrap_mode = GL_CLAMP_TO_BORDER; + fbo->srgb = 0; + if (shader->srgb_framebuffer) { + fbo->texture.internal_format = GL_SRGB8_ALPHA8; + fbo->srgb = 1; + } else if (shader->float_framebuffer) { + fbo->texture.internal_format = GL_RGBA32F; + fbo->texture.type = GL_FLOAT; + } + + if (fbo->texture.mipmap) + fbo->texture.min_filter = shader->filter_linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_fbo(fbo); +} + +static void +recreate_fbo(struct shader_fbo *fbo, int width, int height) +{ + if (width != fbo->texture.width || height != fbo->texture.height) { + glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); + glw.glDeleteTextures(1, (GLuint *) &fbo->texture.id); + fbo->texture.width = width; + fbo->texture.height = height; + create_fbo(fbo); + } +} + +static int +create_default_shader_tex(struct shader_pass *pass) +{ + if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) + return 0; + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + + struct shader_uniforms *u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->texture = get_uniform(p, "Texture"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +static int +create_default_shader_color(struct shader_pass *pass) +{ + if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) + return 0; + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + + struct shader_uniforms *u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->color = get_attrib(p, "Color"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +/* create the default scene shader */ +static void +create_scene_shader() +{ + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_tex(&active_shader->scene); + scene_shader_conf.filter_linear = video_filter_method; + if (active_shader->num_shaders > 0 && active_shader->shaders[0].input_filter_linear >= 0) + scene_shader_conf.filter_linear = active_shader->shaders[0].input_filter_linear; + setup_fbo(&scene_shader_conf, &active_shader->scene.fbo); + + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_color(&active_shader->fs_color); + setup_fbo(&scene_shader_conf, &active_shader->fs_color.fbo); +} + +static int +load_texture(const char *f, struct shader_texture *tex) +{ + QImage img; + if (!img.load(f)) + return 0; + int width, height; + width = img.size().width(); + height = img.size().height(); + + if (width != next_pow2(width) || height != next_pow2(height)) + img = img.scaled(next_pow2(width), next_pow2(height)); + + width = img.size().width(); + height = img.size().height(); + + img.convertTo(QImage::Format_RGBA8888); + + const GLubyte *rgb = img.constBits(); + + int bpp = 4; + + GLubyte *data = (GLubyte *) malloc(width * height * bpp); + + int x, y, Y; + for (y = 0; y < height; ++y) { + Y = height - y - 1; + for (x = 0; x < width; x++) { + data[(y * width + x) * bpp + 0] = rgb[(Y * width + x) * 3 + 0]; + data[(y * width + x) * bpp + 1] = rgb[(Y * width + x) * 3 + 1]; + data[(y * width + x) * bpp + 2] = rgb[(Y * width + x) * 3 + 2]; + data[(y * width + x) * bpp + 3] = rgb[(Y * width + x) * 3 + 3]; + } + } + + tex->width = width; + tex->height = height; + tex->internal_format = GL_RGBA8; + tex->format = GL_RGBA; + tex->type = GL_UNSIGNED_BYTE; + tex->data = data; + return 1; +} + +static glsl_t * +load_glslp(glsl_t *glsl, int num_shader, const char *f) +{ + int i, j; + glslp_t *p = glslp_parse(f); + + if (p) { + char path[512]; + char file[1024]; + int failed = 0; + strcpy(path, f); + char *filename = path_get_filename(path); + + struct glsl_shader *gshader = &glsl->shaders[num_shader]; + + strcpy(gshader->name, p->name); + *filename = 0; + + gshader->num_lut_textures = p->num_textures; + + for (i = 0; i < p->num_textures; ++i) { + struct texture *texture = &p->textures[i]; + + sprintf(file, "%s%s", path, texture->path); + + struct shader_lut_texture *tex = &gshader->lut_textures[i]; + strcpy(tex->name, texture->name); + + pclog("Load texture %s...\n", file); + + if (!load_texture(file, &tex->texture)) { + // wx_simple_messagebox("GLSL Error", "Could not load texture: %s", file); + pclog("Could not load texture %s!\n", file); + failed = 1; + break; + } + + if (!strcmp(texture->wrap_mode, "repeat")) + tex->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(texture->wrap_mode, "mirrored_repeat")) + tex->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(texture->wrap_mode, "clamp_to_edge")) + tex->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + tex->texture.wrap_mode = GL_CLAMP_TO_BORDER; + + tex->texture.mipmap = texture->mipmap; + + tex->texture.min_filter = tex->texture.mag_filter = texture->linear ? GL_LINEAR : GL_NEAREST; + if (tex->texture.mipmap) + tex->texture.min_filter = texture->linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_texture(&tex->texture); + free(tex->texture.data); + tex->texture.data = 0; + } + + if (!failed) { + gshader->input_filter_linear = p->input_filter_linear; + + gshader->num_parameters = p->num_parameters; + for (j = 0; j < gshader->num_parameters; ++j) + memcpy(&gshader->parameters[j], &p->parameters[j], sizeof(struct shader_parameter)); + + gshader->num_passes = p->num_shaders; + + for (i = 0; i < p->num_shaders; ++i) { + struct shader *shader = &p->shaders[i]; + struct shader_pass *pass = &gshader->passes[i]; + + strcpy(pass->alias, shader->alias); + if (!strlen(pass->alias)) + sprintf(pass->alias, "Pass %u", (i + 1)); + + pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); + pclog("Loading shader %s...\n", shader->shader_fn); + if (!shader->shader_program) { + // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); + pclog("Could not load shader %s\n", shader->shader_fn); + failed = 1; + break; + } else + pclog("Shader %s loaded\n", shader->shader_fn); + failed = !compile_shader(GL_VERTEX_SHADER, "#define VERTEX\n#define PARAMETER_UNIFORM\n", + shader->shader_program, &pass->program.vertex_shader) + || !compile_shader(GL_FRAGMENT_SHADER, "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", + shader->shader_program, &pass->program.fragment_shader); + if (failed) + break; + + if (!create_program(&pass->program)) { + failed = 1; + break; + } + pass->frame_count_mod = shader->frame_count_mod; + pass->fbo.mipmap_input = shader->mipmap_input; + + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + find_uniforms(gshader, i); + setup_scale(shader, pass); + if (i == p->num_shaders - 1) /* last pass may or may not be an fbo depending on scale */ + { + if (num_shader == glsl->num_shaders - 1) { + pass->fbo.id = -1; + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] != SCALE_SOURCE || pass->scale.value[j] != 1) { + setup_fbo(shader, &pass->fbo); + break; + } + } + } else { + /* check if next shaders' first pass wants the input mipmapped (will this ever + * happen?) */ + pass->fbo.texture.mipmap = glsl->shaders[num_shader + 1].num_passes > 0 && glsl->shaders[num_shader + 1].passes[0].fbo.mipmap_input; + /* check if next shader wants the output of this pass to be filtered */ + if (glsl->shaders[num_shader + 1].num_passes > 0 && glsl->shaders[num_shader + 1].input_filter_linear >= 0) + shader->filter_linear = glsl->shaders[num_shader + 1].input_filter_linear; + setup_fbo(shader, &pass->fbo); + } + } else { + /* check if next pass wants the input mipmapped, if so we need to generate mipmaps of this + * pass */ + pass->fbo.texture.mipmap = (i + 1) < p->num_shaders && p->shaders[i + 1].mipmap_input; + setup_fbo(shader, &pass->fbo); + } + if (pass->fbo.srgb) + glsl->srgb = 1; + pass->active = 1; + } + if (!failed) { + if (gshader->has_prev) { + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + for (i = 0; i < MAX_PREV; ++i) { + setup_fbo(&scene_shader_conf, &gshader->prev[i].fbo); + } + } + } + } + + glslp_free(p); + + return glsl; + } + return 0; +} + +static glsl_t * +load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +{ + int i; + glsl_t *glsl; + + glsl = (glsl_t *) malloc(sizeof(glsl_t)); + memset(glsl, 0, sizeof(glsl_t)); + + glsl->num_shaders = num; + int failed = 0; + for (i = num - 1; i >= 0; --i) { + const char *f = shaders[i]; + if (f && strlen(f)) { + if (!load_glslp(glsl, i, f)) { + failed = 1; + break; + } + } + } + if (failed) { + delete_glsl(glsl); + memset(glsl, 0, sizeof(glsl_t)); + } + return glsl; +} + +static void +read_shader_config() +{ + char s[512]; + int i, j; + for (i = 0; i < active_shader->num_shaders; ++i) { + struct glsl_shader *shader = &active_shader->shaders[i]; + char *name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + // shader->shader_refresh_rate = config_get_float(CFG_MACHINE, s, "shader_refresh_rate", -1); + for (j = 0; j < shader->num_parameters; ++j) { + struct shader_parameter *param = &shader->parameters[j]; + param->value = config_get_double(s, param->id, param->default_value); + } + } +} + +OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) + : QWindow(parent->windowHandle()) + , renderTimer(new QTimer(this)) + , options(nullptr) +{ + connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } ); + imagebufs[0] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + imagebufs[1] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + + buf_usage = std::vector(2); + buf_usage[0].clear(); + buf_usage[1].clear(); + + QSurfaceFormat format; + + setSurfaceType(QWindow::OpenGLSurface); + +#ifdef Q_OS_MACOS + format.setVersion(4, 1); +#else + format.setVersion(3, 2); +#endif + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) + format.setRenderableType(QSurfaceFormat::OpenGLES); + + setFormat(format); + + parentWidget = parent; + + source.setRect(0, 0, 2048, 2048); + isInitialized = false; + isFinalized = false; +} + +OpenGLRendererPCem::~OpenGLRendererPCem() { finalize(); } + +void +OpenGLRendererPCem::initialize() +{ + try { + context = new QOpenGLContext(this); + + context->setFormat(format()); + + if (!context->create()) + throw opengl_init_error_pcem(tr("Couldn't create OpenGL context.")); + + if (!context->makeCurrent(this)) + throw opengl_init_error_pcem(tr("Couldn't switch to OpenGL context.")); + + auto version = context->format().version(); + + if (version.first < 3) + throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); + + glw.initializeOpenGLFunctions(); + + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + + logger->initialize(); // initializes in the current context, i.e. ctx + connect(logger, QOpenGLDebugLogger::messageLogged, [this] (const QOpenGLDebugMessage &message) { + qDebug() << message; + //fprintf(stderr, "OpenGL DBG: %s\n", message.message().toUtf8()); + }); + logger->enableMessages(); + logger->startLogging(); + + glw.glEnable(GL_TEXTURE_2D); + + renderTimer->start(75); + + scene_texture.data = NULL; + scene_texture.width = 2048; + scene_texture.height = 2048; + scene_texture.internal_format = GL_RGBA8; + scene_texture.format = GL_BGRA; + scene_texture.type = GL_UNSIGNED_INT_8_8_8_8_REV; + scene_texture.wrap_mode = GL_CLAMP_TO_BORDER; + scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + scene_texture.mipmap = 0; + + create_texture(&scene_texture); + + /* load shader */ + // const char* shaders[1]; + // shaders[0] = gl3_shader_file; + // + // active_shader = load_shaders(1, shaders); + + // const char* shaders[3]; + // shaders[0] = "/home/phantasy/git/glsl-shaders/ntsc/ntsc-320px.glslp"; + // shaders[1] = "/home/phantasy/git/glsl-shaders/motionblur/motionblur-simple.glslp"; + // shaders[2] = "/home/phantasy/git/glsl-shaders/crt/crt-lottes-multipass.glslp"; + // + // active_shader = load_shaders(3, shaders); + int num_shaders = 0; + for (int i = 0; i < MAX_USER_SHADERS; ++i) { + if (strlen(gl3_shader_file[i])) + ++num_shaders; + else + break; + } + active_shader = load_shaders(num_shaders, gl3_shader_file); + + create_scene_shader(); + + /* read config */ + read_shader_config(); + + /* buffers */ + + GLfloat vertex[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; + + GLfloat inv_vertex[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f }; + + GLfloat tex_coords[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }; + + GLfloat colors[] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + + /* set the scene shader buffers */ + { + glw.glBindVertexArray(active_shader->scene.vertex_array); + + struct shader_vbo *vbo = &active_shader->scene.vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(inv_vertex), inv_vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(active_shader->scene.uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(active_shader->scene.uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + } + + /* set buffers for all passes */ + for (int j = 0; j < active_shader->num_shaders; ++j) { + struct glsl_shader *shader = &active_shader->shaders[j]; + for (int i = 0; i < shader->num_passes; ++i) { + struct shader_uniforms *u = &shader->passes[i].uniforms; + + glw.glBindVertexArray(shader->passes[i].vertex_array); + + struct shader_vbo *vbo = &shader->passes[i].vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw.glVertexAttribPointer(u->vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(u->tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + if (u->color) { + glw.glGenBuffers(1, (GLuint *) &vbo->color); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); + glw.glVertexAttribPointer(u->color, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid *) 0); + } + } + } + + for (int i = 0; i < active_shader->num_shaders; ++i) { + struct glsl_shader *shader = &active_shader->shaders[i]; + if (shader->has_prev) { + struct shader_pass *prev_pass = &shader->prev_scene; + create_default_shader_tex(prev_pass); + + struct shader_vbo *vbo = &prev_pass->vbo; + + glw.glBindVertexArray(prev_pass->vertex_array); + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(prev_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(prev_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + for (int j = 0; j < MAX_PREV; ++j) { + struct shader_prev *prev = &shader->prev[j]; + struct shader_vbo *prev_vbo = &prev->vbo; + + glw.glGenBuffers(1, (GLuint *) &prev_vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw.glGenBuffers(1, (GLuint *) &prev_vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + } + } + } + + /* create final pass */ + if (active_shader->num_shaders == 0 || active_shader->shaders[active_shader->num_shaders - 1].passes[active_shader->shaders[active_shader->num_shaders - 1].num_passes - 1].fbo.id >= 0) { + struct shader_pass *final_pass = &active_shader->final_pass; + create_default_shader_tex(final_pass); + + glw.glBindVertexArray(final_pass->vertex_array); + + struct shader_vbo *vbo = &final_pass->vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(final_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(final_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + } + + { + struct shader_pass *color_pass = &active_shader->fs_color; + create_default_shader_color(color_pass); + + glw.glBindVertexArray(color_pass->vertex_array); + + struct shader_vbo *vbo = &color_pass->vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(color_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->color); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(color_pass->uniforms.color, 4, GL_FLOAT, GL_TRUE, 4 * sizeof(GLfloat), (GLvoid *) 0); + } +#ifdef SDL2_SHADER_DEBUG + struct shader_pass *debug_pass = &active_shader->debug; + create_default_shader(debug_pass); + + glw.glBindVertexArray(debug_pass->vertex_array); + + struct shader_vbo *vbo = &debug_pass->vbo; + + glw.glGenBuffers(1, &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(debug_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + glw.glGenBuffers(1, &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(debug_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), (GLvoid *) 0); +#endif + + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + glw.glBindVertexArray(0); + + isInitialized = true; + isFinalized = false; + + emit initialized(); + + glw.glClearColor(0, 0, 0, 1); + + glw.glClear(GL_COLOR_BUFFER_BIT); + + context->swapBuffers(this); + } catch (const opengl_init_error_pcem &e) { + /* Mark all buffers as in use */ + for (auto &flag : buf_usage) + flag.test_and_set(); + + QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); + + context->doneCurrent(); + isFinalized = true; + isInitialized = true; + + emit errorInitializing(); + } +} + +void +OpenGLRendererPCem::finalize() +{ + if (isFinalized) + return; + + context->makeCurrent(this); + + delete_texture(&scene_texture); + + if (active_shader) { + delete_glsl(active_shader); + free(active_shader); + } + active_shader = NULL; + + context->doneCurrent(); + + context = nullptr; + + isFinalized = true; +} + +void +OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) +{ + if (notReady()) + return; + + context->makeCurrent(this); + +#ifdef Q_OS_MACOS + glViewport( + destination.x() * devicePixelRatio(), + destination.y() * devicePixelRatio(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +#endif + source.setRect(x, y, w, h); + + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 2048); + glw.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, (const void *) ((uintptr_t) imagebufs[buf_idx].get() + (uintptr_t) (2048 * 4 * y + x * 4))); + glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glw.glBindTexture(GL_TEXTURE_2D, 0); + + buf_usage[buf_idx].clear(); + source.setRect(x, y, w, h); + onResize(this->width(), this->height()); + + render(); +} + +std::vector> +OpenGLRendererPCem::getBuffers() +{ + std::vector> buffers; + + buffers.push_back(std::make_tuple(imagebufs[0].get(), &buf_usage[0])); + buffers.push_back(std::make_tuple(imagebufs[1].get(), &buf_usage[1])); + + return buffers; +} + +void +OpenGLRendererPCem::exposeEvent(QExposeEvent *event) +{ + Q_UNUSED(event); + + if (!isInitialized) + initialize(); + + onResize(size().width(), size().height()); +} + +void +OpenGLRendererPCem::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + + onResize(event->size().width(), event->size().height()); + + if (notReady()) + return; + + context->makeCurrent(this); + + glw.glViewport( + destination.x() * devicePixelRatio(), + destination.y() * devicePixelRatio(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +} + +struct render_data { + int pass; + struct glsl_shader *shader; + struct shader_pass *shader_pass; + GLfloat *output_size; + struct shader_pass *orig_pass; + GLint texture; + int frame_count; +}; + +static void +render_pass(struct render_data *data) +{ + int i; + GLuint texture_unit = 0; + + // pclog("pass %d: %gx%g, %gx%g -> %gx%g, %gx%g, %gx%g\n", num_pass, pass->state.input_size[0], + // pass->state.input_size[1], pass->state.input_texture_size[0], pass->state.input_texture_size[1], + // pass->state.output_size[0], pass->state.output_size[1], pass->state.output_texture_size[0], + // pass->state.output_texture_size[1], output_size[0], output_size[1]); + + glw.glBindVertexArray(data->shader_pass->vertex_array); + + GLint p = data->shader_pass->program.id; + struct shader_uniforms *u = &data->shader_pass->uniforms; + + glw.glUseProgram(p); + + if (data->texture) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->texture); + glw.glUniform1i(u->texture, texture_unit); + texture_unit++; + } + + if (u->color >= 0) + glw.glEnableVertexAttribArray(u->color); + + if (u->mvp_matrix >= 0) + glw.glUniformMatrix4fv(u->mvp_matrix, 1, 0, matrix); + if (u->frame_direction >= 0) + glw.glUniform1i(u->frame_direction, 1); + + int framecnt = data->frame_count; + if (data->shader_pass->frame_count_mod > 0) + framecnt = framecnt % data->shader_pass->frame_count_mod; + if (u->frame_count >= 0) + glw.glUniform1i(u->frame_count, framecnt); + + if (u->input_size >= 0) + glw.glUniform2fv(u->input_size, 1, data->shader_pass->state.input_size); + if (u->texture_size >= 0) + glw.glUniform2fv(u->texture_size, 1, data->shader_pass->state.input_texture_size); + if (u->output_size >= 0) + glw.glUniform2fv(u->output_size, 1, data->output_size); + + if (data->shader) { + /* parameters */ + for (i = 0; i < data->shader->num_parameters; ++i) + if (u->parameters[i] >= 0) + glw.glUniform1f(u->parameters[i], data->shader->parameters[i].value); + + if (data->pass > 0) { + struct shader_pass *passes = data->shader->passes; + struct shader_pass *orig = data->orig_pass; + if (u->orig.texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, orig->fbo.texture.id); + glw.glUniform1i(u->orig.texture, texture_unit); + texture_unit++; + } + if (u->orig.input_size >= 0) + glw.glUniform2fv(u->orig.input_size, 1, orig->state.input_size); + if (u->orig.texture_size >= 0) + glw.glUniform2fv(u->orig.texture_size, 1, orig->state.input_texture_size); + + for (i = 0; i < data->pass; ++i) { + if (u->pass[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw.glUniform1i(u->pass[i].texture, texture_unit); + texture_unit++; + } + if (u->pass[i].texture_size >= 0) + glw.glUniform2fv(u->pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->pass[i].input_size >= 0) + glw.glUniform2fv(u->pass[i].input_size, 1, passes[i].state.input_size); + + if (u->prev_pass[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw.glUniform1i(u->prev_pass[i].texture, texture_unit); + texture_unit++; + } + if (u->prev_pass[i].texture_size >= 0) + glw.glUniform2fv(u->prev_pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->prev_pass[i].input_size >= 0) + glw.glUniform2fv(u->prev_pass[i].input_size, 1, passes[i].state.input_size); + } + } + + if (data->shader->has_prev) { + /* loop through each previous frame */ + for (i = 0; i < MAX_PREV; ++i) { + if (u->prev[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->shader->prev[i].fbo.texture.id); + glw.glUniform1i(u->prev[i].texture, texture_unit); + texture_unit++; + } + if (u->prev[i].tex_coord >= 0) { + glw.glBindBuffer(GL_ARRAY_BUFFER, data->shader->prev[i].vbo.tex_coord); + glw.glVertexAttribPointer(u->prev[i].tex_coord, 2, GL_FLOAT, GL_TRUE, + 2 * sizeof(GLfloat), (GLvoid *) 0); + glw.glEnableVertexAttribArray(u->prev[i].tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + } + } + } + + for (i = 0; i < data->shader->num_lut_textures; ++i) { + if (u->lut_textures[i] >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->shader->lut_textures[i].texture.id); + glw.glUniform1i(u->lut_textures[i], texture_unit); + texture_unit++; + } + } + } + + glw.glEnableVertexAttribArray(u->vertex_coord); + glw.glEnableVertexAttribArray(u->tex_coord); + + glw.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glw.glActiveTexture(GL_TEXTURE0); + glw.glBindTexture(GL_TEXTURE_2D, 0); + + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.vertex_coord); + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.tex_coord); + if (data->shader_pass->uniforms.color >= 0) + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.color); + + if (data->shader && data->shader->has_prev) { + for (i = 0; i < MAX_PREV; ++i) { + if (u->prev[i].tex_coord >= 0) + glw.glDisableVertexAttribArray(u->prev[i].tex_coord); + } + } + + glw.glBindVertexArray(0); + + glw.glUseProgram(0); +} + +bool +OpenGLRendererPCem::event(QEvent *event) +{ + Q_UNUSED(event); + + bool res = false; + if (!eventDelegate(event, res)) + return QWindow::event(event); + return res; +} + +void +OpenGLRendererPCem::render() +{ + if (!context) + return; + + int s, i, j; + + struct { + uint32_t x, y, w, h; + } window_rect; + + window_rect.w = this->size().width() * devicePixelRatio(); + window_rect.h = this->size().height() * devicePixelRatio(); + + GLfloat orig_output_size[] = { (GLfloat)window_rect.w, (GLfloat)window_rect.h }; + + if (active_shader->srgb) + glw.glEnable(GL_FRAMEBUFFER_SRGB); + + struct render_data data; + + /* render scene to texture */ + { + struct shader_pass *pass = &active_shader->scene; + + struct { + uint32_t x, y, w, h; + } rect, video_rect; + rect.x = destination.x(); + rect.y = destination.y(); + rect.w = destination.width(); + rect.h = destination.height(); + + video_rect.x = source.x(); + video_rect.y = source.y(); + video_rect.w = source.width(); + video_rect.h = source.height(); + + pass->state.input_size[0] = pass->state.output_size[0] = rect.w; + pass->state.input_size[1] = pass->state.output_size[1] = rect.h; + + pass->state.input_texture_size[0] = pass->state.output_texture_size[0] = next_pow2(pass->state.output_size[0]); + pass->state.input_texture_size[1] = pass->state.output_texture_size[1] = next_pow2(pass->state.output_size[1]); + + recreate_fbo(&active_shader->scene.fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, active_shader->scene.fbo.id); + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + // create input tex coords + minx = video_rect.x / 2048.f; + miny = video_rect.y / 2048.f; + maxx = (video_rect.x + video_rect.w) / (float) 2048.f; + maxy = (video_rect.y + video_rect.h) / (float) 2048.f; + + GLfloat tex_coords[] = { minx, miny, minx, maxy, maxx, miny, maxx, maxy }; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -1; + data.shader_pass = &active_shader->scene; + data.texture = scene_texture.id; + data.output_size = orig_output_size; + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + struct shader_pass *orig = &active_shader->scene; + struct shader_pass *input = &active_shader->scene; + + for (s = 0; s < active_shader->num_shaders; ++s) { + struct glsl_shader *shader = &active_shader->shaders[s]; + + // float refresh_rate = shader->shader_refresh_rate; + // if (refresh_rate < 0) + // refresh_rate = gl3_shader_refresh_rate; + float refresh_rate = gl3_shader_refresh_rate; + if (refresh_rate == 0) + refresh_rate = video_refresh_rate; + int frame_count = frameCounter; + + /* loop through each pass */ + for (i = 0; i < shader->num_passes; ++i) { + struct shader_pass *pass = &shader->passes[i]; + + memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2 * sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j] * pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j] * pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + if (pass->fbo.id >= 0) { + recreate_fbo(&pass->fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, pass->fbo.id); + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + } else + glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), input->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = i; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + data.frame_count = frame_count; + + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (pass->fbo.texture.mipmap) { + glw.glActiveTexture(GL_TEXTURE0); + glw.glBindTexture(GL_TEXTURE_2D, pass->fbo.texture.id); + glw.glGenerateMipmap(GL_TEXTURE_2D); + glw.glBindTexture(GL_TEXTURE_2D, 0); + } + + input = pass; + } + + if (shader->has_prev) { + /* shift array */ + memmove(&shader->prev[1], &shader->prev[0], MAX_PREV * sizeof(struct shader_prev)); + memcpy(&shader->prev[0], &shader->prev[MAX_PREV], sizeof(struct shader_prev)); + + struct shader_pass *pass = orig; + struct shader_pass *prev_pass = &shader->prev_scene; + struct shader_prev *prev = &shader->prev[0]; + + memcpy(&prev_pass->state, &pass->state, sizeof(struct shader_state)); + + recreate_fbo(&prev->fbo, prev_pass->state.output_texture_size[0], + prev_pass->state.output_texture_size[1]); + + memcpy(&prev_pass->fbo, &prev->fbo, sizeof(struct shader_fbo)); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, prev->fbo.id); + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + glw.glBindVertexArray(prev_pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, prev->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), pass->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), pass->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = -10; + data.shader_pass = prev_pass; + data.texture = pass->fbo.texture.id; + data.output_size = orig_output_size; + + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + orig = input; + } + + if (active_shader->final_pass.active) { + struct shader_pass *pass = &active_shader->final_pass; + + memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2 * sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j] * pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j] * pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), input->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -2; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + + render_pass(&data); + } + + if (1) { + // if (video_focus_dim && !(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)) { +#if 0 + if (0) { + struct shader_pass *pass = &active_shader->fs_color; + GLfloat r = 0; + GLfloat g = 0; + GLfloat b = 0; + GLfloat a = 0x80 / (float) 0xff; + + GLfloat colors[] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } + + if (flash.enabled) { + struct shader_pass *pass = &active_shader->fs_color; + GLfloat r = (flash.color[0] & 0xff) / (float)0xff; + GLfloat g = (flash.color[1] & 0xff) / (float)0xff; + GLfloat b = (flash.color[2] & 0xff) / (float)0xff; + GLfloat a = (flash.color[3] & 0xff) / (float)0xff; + + GLfloat colors[] = {r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a}; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } +#endif + } else { +#if 0 + take_screenshot = 0; + + int width = window_rect.w; + int height = window_rect.h; + + SDL_GetWindowSize(window, &width, &height); + + unsigned char *rgba = (unsigned char *)malloc(width * height * 4); + + glFinish(); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + + int x, y; + unsigned char *rgb = (unsigned char *)malloc(width * height * 3); + + for (x = 0; x < width; ++x) { + for (y = 0; y < height; ++y) { + rgb[(y * width + x) * 3 + 0] = rgba[((height - y - 1) * width + x) * 4 + 0]; + rgb[(y * width + x) * 3 + 1] = rgba[((height - y - 1) * width + x) * 4 + 1]; + rgb[(y * width + x) * 3 + 2] = rgba[((height - y - 1) * width + x) * 4 + 2]; + } + } + + screenshot_taken(rgb, width, height); + + free(rgb); + free(rgba); +#endif + } + + glw.glDisable(GL_FRAMEBUFFER_SRGB); + + context->swapBuffers(this); +} \ No newline at end of file diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp new file mode 100644 index 000000000..0e3069536 --- /dev/null +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -0,0 +1,127 @@ +/* + * 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. + * + * Header file for OpenGL renderer + * + * + * + * Authors: Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#ifndef QT_OpenGLRendererPCem_HPP +#define QT_OpenGLRendererPCem_HPP + +#if defined Q_OS_MACOS || __arm__ +# define NO_BUFFER_STORAGE +#endif + +#include +#include +#include +#include +#include +#include +#if !defined NO_BUFFER_STORAGE && !(QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +# include +#endif + +#include +#include +#include +#include + +#include "qt_opengloptions.hpp" +#include "qt_renderercommon.hpp" + +typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); + +class OpenGLRendererPCem : public QWindow, public RendererCommon { + Q_OBJECT + +public: + QOpenGLContext *context; + + OpenGLRendererPCem(QWidget *parent = nullptr); + ~OpenGLRendererPCem(); + + std::vector> getBuffers() override; + + void finalize() override final; + //bool hasOptions() const override { return true; } + //QDialog *getOptions(QWidget *parent) override; + //void reloadOptions() override; + +signals: + void initialized(); + void errorInitializing(); + +public slots: + void onBlit(int buf_idx, int x, int y, int w, int h); + +protected: + void exposeEvent(QExposeEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + bool event(QEvent *event) override; + +private: + static constexpr int INIT_WIDTH = 640; + static constexpr int INIT_HEIGHT = 400; + static constexpr int ROW_LENGTH = 2048; + static constexpr int BUFFERPIXELS = 4194304; + static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ + static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ + + std::array, 2> imagebufs; + + QTimer *renderTimer; + OpenGLOptions *options; + + QString glslVersion; + + bool isInitialized = false; + bool isFinalized = false; + + GLuint unpackBufferID = 0; + GLuint vertexArrayID = 0; + GLuint vertexBufferID = 0; + GLuint textureID = 0; + int frameCounter = 0; + + OpenGLOptions::FilterType currentFilter; + + void *unpackBuffer = nullptr; + + void initialize(); + void initializeExtensions(); + void initializeBuffers(); + void applyOptions(); + void applyShader(const OpenGLShaderPass &shader); + bool notReady() const { return !isInitialized || isFinalized; } + + /* GL_ARB_buffer_storage */ + bool hasBufferStorage = false; +#ifndef NO_BUFFER_STORAGE + PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr; +#endif + +private slots: + void render(); + //void updateOptions(OpenGLOptions *newOptions); +}; + +class opengl_init_error_pcem : public std::runtime_error { +public: + opengl_init_error_pcem(const QString &what) + : std::runtime_error(what.toStdString()) + { + } +}; + +#endif diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 8c31da2b2..63d35e719 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -23,6 +23,7 @@ #include "qt_hardwarerenderer.hpp" #include "qt_openglrenderer.hpp" +#include "qt_openglrenderer_pcem.hpp" #include "qt_softwarerenderer.hpp" #include "qt_vulkanwindowrenderer.hpp" @@ -337,19 +338,39 @@ RendererStack::createRenderer(Renderer renderer) current.reset(this->createWindowContainer(hw, this)); break; } - case Renderer::OpenGL3: + case Renderer::OpenGL3PCem: { this->createWinId(); - auto hw = new OpenGLRenderer(this); + auto hw = new OpenGLRendererPCem(this); rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRenderer::initialized, [=]() { + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRendererPCem::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); }); - connect(hw, &OpenGLRenderer::errorInitializing, [=]() { + connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { + /* Renderer not could initialize, fallback to software. */ + imagebufs = {}; + QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); + }); + current.reset(this->createWindowContainer(hw, this)); + break; + } + case Renderer::OpenGL3: + { + this->createWinId(); + auto hw = new OpenGLRendererPCem(this); + rendererWindow = hw; + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRendererPCem::initialized, [=]() { + /* Buffers are available only after initialization. */ + imagebufs = rendererWindow->getBuffers(); + endblit(); + emit rendererChanged(); + }); + connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { /* Renderer not could initialize, fallback to software. */ imagebufs = {}; QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); @@ -406,7 +427,7 @@ RendererStack::createRenderer(Renderer renderer) currentBuf = 0; - if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) { + if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::OpenGL3PCem) { imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 5a08b351c..8059d59c5 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -59,6 +59,7 @@ public: OpenGLES, OpenGL3, Vulkan, + OpenGL3PCem = 6, None = -1 }; void switchRenderer(Renderer renderer); From 05f6940844f9fed4bc6d68cd6819ae7fb76cad8e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Mar 2025 05:47:44 +0100 Subject: [PATCH 022/218] Fixed ROM BASIC loading on XT 1982, fixes #5243. --- src/machine/m_xt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 9f232ac95..78d2daa13 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -366,7 +366,11 @@ machine_xt_init(const machine_t *model) fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); (void) bios_load_aux_linear(fn, 0x000f8000, 24576, 0); fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 1); - (void) bios_load_aux_linear(fn, 0x000f0000, 32768, 0); + /* On the real machine, the BASIC is repeated. */ + (void) bios_load_aux_linear(fn, 0x000f0000, 8192, 0); + (void) bios_load_aux_linear(fn, 0x000f2000, 8192, 0); + (void) bios_load_aux_linear(fn, 0x000f4000, 8192, 0); + (void) bios_load_aux_linear(fn, 0x000f6000, 8192, 0); } device_context_restore(); From 16d7bc26dcddf666f67ba0f5d12d6c8ec237a3ab Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 8 Mar 2025 10:14:58 +0500 Subject: [PATCH 023/218] Fix the LPT device list duplicating on every machine change --- src/qt/qt_settingsports.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index 630c843b9..cb1ab794a 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -74,22 +74,26 @@ SettingsPorts::onCurrentMachineChanged(int machineId) this->machineId = machineId; for (int i = 0; i < PARALLEL_MAX; i++) { - auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); - auto *model = cbox->model(); - int c = 0; - int selectedRow = 0; + auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); + auto *model = cbox->model(); + const auto removeRows = model->rowCount(); + int c = 0; + int selectedRow = 0; while (true) { const char *lptName = lpt_device_get_name(c); if (lptName == nullptr) { break; } - Models::AddEntry(model, tr(lptName), c); + int row = Models::AddEntry(model, tr(lptName), c); if (c == lpt_ports[i].device) { - selectedRow = c; + selectedRow = row - removeRows; } c++; } + model->removeRows(0, removeRows); + cbox->setEnabled(model->rowCount() > 0); + cbox->setCurrentIndex(-1); cbox->setCurrentIndex(selectedRow); auto *checkBox = findChild(QString("checkBoxParallel%1").arg(i + 1)); From 63c5b6003f7c9fed9d12212cde9a58808bdcc1f0 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 14:29:13 +0100 Subject: [PATCH 024/218] Spock/Tribble changes of the day (March 8th, 2025) 1. Make IRQ's more correct and per manual. 2. Only an adapter reset command should reset the SCSI devices connected to it. 3. Differentiate the two controllers by the connector bit (pos3 bit 12) in the CMD GET POS INFO SCB command. 4. Actually emulate bit 7 of pos4 in the pos writes so that selection between 16KB and 32KB rom loading is done properly. 5. Some cleanups. --- src/scsi/scsi_spock.c | 144 +++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 65 deletions(-) diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index 567879a12..c500abfbc 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -206,7 +206,6 @@ typedef struct { #define IRQ_TYPE_COMMAND_FAIL 0xc #define IRQ_TYPE_COMMAND_ERROR 0xe #define IRQ_TYPE_SW_SEQ_ERROR 0xf -#define IRQ_TYPE_RESET_COMPLETE 0x10 #ifdef ENABLE_SPOCK_LOG int spock_do_log = ENABLE_SPOCK_LOG; @@ -226,7 +225,9 @@ spock_log(const char *fmt, ...) # define spock_log(fmt, ...) #endif -static void +static void spock_reset(void *priv); + +static __inline void spock_rethink_irqs(spock_t *scsi) { int irq_pending = 0; @@ -236,7 +237,7 @@ spock_rethink_irqs(spock_t *scsi) if (scsi->irq_requests[c] != IRQ_TYPE_NONE) { /* Found IRQ */ scsi->irq_status = c | (scsi->irq_requests[c] << 4); - spock_log("Found IRQ: status = %02x\n", scsi->irq_status); + spock_log("Found IRQ: status=%02x.\n", scsi->irq_status); scsi->status |= STATUS_IRQ; irq_pending = 1; break; @@ -245,38 +246,37 @@ spock_rethink_irqs(spock_t *scsi) } else irq_pending = 1; + spock_log("spock_rethink_irqs: irqstat=%02x, ctrl=%02x, irqpend=%d.\n", scsi->irq_status, scsi->basic_ctrl, irq_pending); if (scsi->basic_ctrl & CTRL_IRQ_ENA) { if (irq_pending) { spock_log("IRQ issued\n"); - scsi->irq_inactive = 0; + scsi->status |= STATUS_IRQ; picint(1 << scsi->irq); } else { /* No IRQs pending, clear IRQ state */ spock_log("IRQ cleared\n"); - scsi->irq_status = 0; - scsi->irq_inactive = 1; - scsi->status &= ~STATUS_IRQ; picintc(1 << scsi->irq); } } else { - spock_log("IRQ disabled\n"); - picintc(1 << scsi->irq); + spock_log("IRQ disabled, pending=%d.\n", irq_pending); + if (irq_pending) + scsi->status |= STATUS_IRQ; } } -static __inline void +static void spock_set_irq(spock_t *scsi, int id, int type) { - spock_log("spock_set_irq id=%i type=%x %02x\n", id, type, scsi->irq_status); + spock_log("spock_set_irq: id=%i, type=%x, irqstat=%02x\n", id, type, scsi->irq_status); scsi->irq_requests[id] = type; if (!scsi->irq_status) /* Don't change IRQ status if one is currently being processed */ spock_rethink_irqs(scsi); } -static __inline void +static void spock_clear_irq(spock_t *scsi, int id) { - spock_log("spock_clear_irq id=%i\n", id); + spock_log("spock_clear_irq: id=%i.\n", id); scsi->irq_requests[id] = IRQ_TYPE_NONE; spock_rethink_irqs(scsi); } @@ -292,7 +292,7 @@ spock_write(uint16_t port, uint8_t val, void *priv) { spock_t *scsi = (spock_t *) priv; - spock_log("spock_writeb: port=%04x, val=%02x, %04x:%04x.\n", port & 7, val, CS, cpu_state.pc); + spock_log("%04X:%08X: spock_writeb: port=%04x, val=%02x.\n", CS, cpu_state.pc, port & 7, val); switch (port & 7) { case 0: @@ -308,16 +308,14 @@ spock_write(uint16_t port, uint8_t val, void *priv) case 4: /*Attention Register*/ scsi->attention_pending = val; - scsi->attention_wait = 2; + scsi->attention_wait = 2; scsi->status |= STATUS_BUSY; break; case 5: /*Basic Control Register*/ - if ((scsi->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) { + if (!(scsi->basic_ctrl & CTRL_RESET) && (val & CTRL_RESET)) { spock_log("Spock: SCSI reset and busy\n"); - scsi->in_reset = 1; - scsi->cmd_timer = SPOCK_TIME * 2; - scsi->status |= STATUS_BUSY; + spock_reset(scsi); } scsi->basic_ctrl = val; spock_rethink_irqs(scsi); @@ -333,7 +331,7 @@ spock_writew(uint16_t port, uint16_t val, void *priv) { spock_t *scsi = (spock_t *) priv; - spock_log("spock_writew: port=%04x, val=%04x, %04x:%04x.\n", port & 7, val, CS, cpu_state.pc); + spock_log("%04X:%08X: spock_writew: port=%04x, val=%04x.\n", CS, cpu_state.pc, port & 7, val); switch (port & 7) { case 0: /*Command Interface Register*/ @@ -391,7 +389,7 @@ spock_read(uint16_t port, void *priv) break; } - spock_log("spock_readb: port=%04x, val=%02x, %04x:%04x.\n", port & 7, temp, CS, cpu_state.pc); + spock_log("%04X:%08X: spock_readb: port=%04x, temp=%02x.\n", CS, cpu_state.pc, port & 7, temp); return temp; } @@ -442,9 +440,8 @@ spock_get_len(spock_t *scsi, scb_t *scb) DataToTransfer += scb->sge.sys_buf_byte_count; } return DataToTransfer; - } else { - return (scsi->data_len); } + return (scsi->data_len); } static void @@ -494,15 +491,14 @@ spock_process_imm_cmd(spock_t *scsi) spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; case CMD_INVALID_412: - spock_log("Invalid 412\n"); + spock_log("Invalid 412.\n"); spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; case CMD_RESET: - spock_log("Reset Command, attention = %d.\n", scsi->attention & 0x0f); + spock_log("Reset command, attention=%02x.\n", scsi->attention & 0x0f); if ((scsi->attention & 0x0f) == 0x0f) { /*Adapter reset*/ - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) scsi_device_reset(&scsi_devices[scsi->bus][i]); - } for (i = 6; i > -1; i--) { if (scsi_device_present(&scsi_devices[scsi->bus][i])) { @@ -514,10 +510,21 @@ spock_process_imm_cmd(spock_t *scsi) spock_log("Adapter Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); } } + } else if ((scsi->attention & 0x0f) < 7) { /*Device reset*/ + scsi_device_reset(&scsi_devices[scsi->bus][scsi->attention & 0x0f]); - scsi->scb_state = 0; + for (i = 6; i > -1; i--) { + if (scsi_device_present(&scsi_devices[scsi->bus][i])) { + spock_log("Device Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); + scsi->present[j] = i; + j++; + } else { + scsi->present[j] = 0xff; + spock_log("Device Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); + } + } } - + scsi->scb_state = 0; spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; @@ -535,18 +542,10 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) int old_scb_state; if (scsi->in_reset) { - spock_log("Reset type=%d\n", scsi->in_reset); - scsi->status &= ~STATUS_BUSY; - scsi->irq_status = 0; - for (c = 0; c < SCSI_ID_MAX; c++) - spock_clear_irq(scsi, c); - - if (scsi->in_reset == 1) - scsi->basic_ctrl |= CTRL_IRQ_ENA; - - spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); + scsi->irq_status = 0x0f; + spock_rethink_irqs(scsi); /*Reset device mappings*/ for (c = 0; c < 7; c++) { @@ -558,7 +557,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->in_reset = 0; - for (c = 6; c > -1; c--) { + for (c = 6; c >= 0; c--) { if (scsi_device_present(&scsi_devices[scsi->bus][c])) { spock_log("Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[c].phys_id, scsi_devices[scsi->bus][c].type); scsi->present[j] = c; @@ -678,7 +677,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) get_pos_info->pos = scsi->spock_16bit ? 0x8efe : 0x8eff; get_pos_info->pos1 = scsi->pos_regs[3] | (scsi->pos_regs[2] << 8); get_pos_info->pos2 = scsi->irq | (scsi->pos_regs[4] << 8); - get_pos_info->pos3 = 1 << 12; + get_pos_info->pos3 = scsi->spock_16bit ? (1 << 12) : (0 << 12); get_pos_info->pos4 = (7 << 8) | 8; get_pos_info->pos5 = (16 << 8) | scsi->pacing; get_pos_info->pos6 = (30 << 8) | 1; @@ -965,6 +964,8 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) else sd->buffer_length = spock_get_len(scsi, scb); + scsi_device_identify(sd, scsi->temp_cdb[1] >> 5); + scsi_device_command_phase0(sd, scsi->temp_cdb); spock_log("SCSI ID %i: Current CDB[0]=%02x, LUN=%i, buffer len=%i, max len=%i, phase val=%02x, data len=%d, enable bit 10=%03x\n", scsi->cdb_id, scsi->temp_cdb[0], scsi->temp_cdb[1] >> 5, sd->buffer_length, spock_get_len(scsi, scb), sd->phase, scsi->data_len, scb->enable & 0x400); @@ -1018,8 +1019,12 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) break; case SCSI_STATE_END_PHASE: + sd = &scsi_devices[scsi->bus][scsi->cdb_id]; scsi->scsi_state = SCSI_STATE_IDLE; + if (sd->type != SCSI_NONE) + scsi_device_identify(sd, SCSI_LUN_USE_CDB); + spock_log("State to idle, cmd timer %d\n", scsi->cmd_timer); if (!scsi->cmd_timer) scsi->cmd_timer = 1; @@ -1045,7 +1050,7 @@ spock_callback(void *priv) spock_execute_cmd(scsi, scb); } - if (scsi->attention_wait && ((scsi->scb_state == 0) || (scsi->attention_pending & 0xf0) == 0xe0)) { + if (scsi->attention_wait) { scsi->attention_wait--; if (!scsi->attention_wait) { scsi->attention = scsi->attention_pending; @@ -1094,6 +1099,7 @@ spock_callback(void *priv) case 0x0e: /*EOI*/ scsi->irq_status = 0; + scsi->status &= ~STATUS_IRQ; spock_clear_irq(scsi, scsi->attention & 0x0f); break; @@ -1118,23 +1124,30 @@ spock_mca_write(int port, uint8_t val, void *priv) if (port < 0x102) return; - io_removehandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); + io_removehandler((((scsi->pos_regs[2] >> 1) & 7) << 3) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); mem_mapping_disable(&scsi->bios_rom.mapping); scsi->pos_regs[port & 7] = val; scsi->adapter_id = (scsi->pos_regs[3] & 0xe0) >> 5; - if (scsi->pos_regs[2] & 1) { - io_sethandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); - if (scsi->pos_regs[4] & 2) { - if (((scsi->pos_regs[2] >> 4) & 0x0f) != 0x0f) { - mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x8000); - mem_mapping_enable(&scsi->bios_rom.mapping); + if (scsi->pos_regs[2] & 0x01) { + io_sethandler((((scsi->pos_regs[2] >> 1) & 7) << 3) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); + if (scsi->pos_regs[4] & 0x02) { + if (scsi->pos_regs[4] & 0x80) { + if (((scsi->pos_regs[2] >> 4) & 0x0f) != 0x0f) { + mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x8000); + mem_mapping_enable(&scsi->bios_rom.mapping); + } + } else { + if (((scsi->pos_regs[2] >> 4) & 0x0f) != 0x0f) { + mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x4000); + mem_mapping_enable(&scsi->bios_rom.mapping); + } } } } - spock_log("[%04X:%08X]: POS Write Port = %x, val = %02x, rom addr = %05x\n", CS, cpu_state.pc, port & 7, val, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000); + spock_log("%04X:%08X: POS Write Port=%x, val=%02x.\n", CS, cpu_state.pc, port & 7, val); } static uint8_t @@ -1142,7 +1155,7 @@ spock_mca_read(int port, void *priv) { const spock_t *scsi = (spock_t *) priv; - spock_log("[%04X:%08X]: POS Read Port = %x, val = %02x\n", CS, cpu_state.pc, + spock_log("%04X:%08X: POS Read Port=%x, temp=%02x.\n", CS, cpu_state.pc, port & 7, scsi->pos_regs[port & 7]); return scsi->pos_regs[port & 7]; } @@ -1155,12 +1168,13 @@ spock_mca_feedb(void *priv) return (scsi->pos_regs[2] & 0x01); } + static void -spock_mca_reset(void *priv) +spock_reset(void *priv) { spock_t *scsi = (spock_t *) priv; - scsi->in_reset = 2; + scsi->in_reset = 1; scsi->cmd_timer = SPOCK_TIME * 50; scsi->status = STATUS_BUSY; scsi->scsi_state = SCSI_STATE_IDLE; @@ -1169,13 +1183,15 @@ spock_mca_reset(void *priv) scsi->attention_wait = 0; scsi->basic_ctrl = 0; - /* Reset all devices on controller reset. */ - for (uint8_t i = 0; i < 8; i++) { - scsi_device_reset(&scsi_devices[scsi->bus][i]); - scsi->present[i] = 0xff; - } + spock_log("Actual Reset.\n"); +} - spock_log("Reset.\n"); +static void +spock_mca_reset(void *priv) +{ + spock_t *scsi = (spock_t *) priv; + + spock_reset(scsi); mem_mapping_disable(&scsi->bios_rom.mapping); scsi->pos_regs[4] = 0x02; spock_mca_write(0x102, 0, scsi); @@ -1213,10 +1229,6 @@ spock_init(const device_t *info) scsi->pos_regs[4] = 0x02; mca_add(spock_mca_read, spock_mca_write, spock_mca_feedb, spock_mca_reset, scsi); - scsi->in_reset = 2; - scsi->cmd_timer = SPOCK_TIME * 50; - scsi->status = STATUS_BUSY; - for (uint8_t c = 0; c < (SCSI_ID_MAX - 1); c++) scsi->dev_id[c].phys_id = -1; @@ -1230,6 +1242,8 @@ spock_init(const device_t *info) scsi_bus_set_speed(scsi->bus, 5000000.0); + spock_reset(scsi); + return scsi; } @@ -1278,7 +1292,7 @@ const device_t spock_device = { .local = 0, .init = spock_init, .close = spock_close, - .reset = NULL, + .reset = spock_reset, .available = spock_available, .speed_changed = NULL, .force_redraw = NULL, @@ -1292,7 +1306,7 @@ const device_t tribble_device = { .local = 1, .init = spock_init, .close = spock_close, - .reset = NULL, + .reset = spock_reset, .available = spock_available, .speed_changed = NULL, .force_redraw = NULL, From a2534c1f4f655c6675f1b324344aa7233900ec0b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 14:41:59 +0100 Subject: [PATCH 025/218] Trantor T128/MediaVision SCSI changes of the day (March 8th, 2025) 1. Made as best as possible implementation of the status bits 1-2 of the Trantor 128 so to make a more accurate speed for SCSI devices (CD-ROM and HDD) without stalls. 2. Slightly reorganized the timer of the T128. --- src/scsi/scsi_t128.c | 292 +++++++++++++++++++++---------------------- 1 file changed, 142 insertions(+), 150 deletions(-) diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 5ac3b5d67..6b73ae131 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -77,11 +77,8 @@ t128_write(uint32_t addr, uint8_t val, void *priv) if ((addr >= 0x1800) && (addr < 0x1880)) t128->ext_ram[addr & 0x7f] = val; else if ((addr >= 0x1c00) && (addr < 0x1c20)) { - if ((val & 0x02) && !(t128->ctrl & 0x02)) - t128->status |= 0x02; - + t128_log("T128 ctrl write=%02x, mode=%02x.\n", val, ncr->mode & MODE_DMA); t128->ctrl = val; - t128_log("T128 ctrl write=%02x\n", val); } else if ((addr >= 0x1d00) && (addr < 0x1e00)) ncr5380_write((addr - 0x1d00) >> 5, val, ncr); else if ((addr >= 0x1e00) && (addr < 0x2000)) { @@ -90,13 +87,15 @@ t128_write(uint32_t addr, uint8_t val, void *priv) t128->buffer[t128->host_pos] = val; t128->host_pos++; - t128_log("T128 Write transfer, addr = %i, pos = %i, val = %02x\n", - addr & 0x1ff, t128->host_pos, val); + t128_log("T128 Write transfer: pos=%i, addr=%x.\n", + t128->host_pos, addr & 0x1ff); if (t128->host_pos == MIN(512, dev->buffer_length)) { + t128_log("T128 Transfer busy write, status=%02x, period=%lf, enabled=%d, loaded=%d.\n", + t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), t128->block_loaded); + t128->status &= ~0x04; - t128_log("Transfer busy write, status = %02x\n", t128->status); - timer_on_auto(&t128->timer, 0.02); + timer_on_auto(&t128->timer, 1.0); } } } @@ -119,31 +118,45 @@ t128_read(uint32_t addr, void *priv) ret = t128->ext_ram[addr & 0x7f]; else if ((addr >= 0x1c00) && (addr < 0x1c20)) { ret = t128->ctrl; - t128_log("T128 ctrl read=%02x, dma=%02x\n", ret, ncr->mode & MODE_DMA); + t128_log("T128 ctrl read=%02x, dma=%02x, load=%d, cnt=%d.\n", ret, ncr->mode & MODE_DMA, t128->block_loaded, t128->block_count); } else if ((addr >= 0x1c20) && (addr < 0x1c40)) { ret = t128->status; - t128_log("T128 status read=%02x, dma=%02x\n", ret, ncr->mode & MODE_DMA); + t128_log("T128 status read=%02x, dma=%02x, blockload=%d, timer=%d.\n", ret, ncr->mode & MODE_DMA, t128->block_loaded, timer_is_enabled(&t128->timer)); } else if ((addr >= 0x1d00) && (addr < 0x1e00)) ret = ncr5380_read((addr - 0x1d00) >> 5, ncr); else if (addr >= 0x1e00 && addr < 0x2000) { - if ((t128->host_pos >= MIN(512, dev->buffer_length)) || - (scsi_bus->tx_mode != DMA_IN_TX_BUS)) - ret = 0xff; - else { + if ((scsi_bus->tx_mode == DMA_IN_TX_BUS) && + (t128->host_pos < MIN(512, dev->buffer_length))) { ret = t128->buffer[t128->host_pos++]; - t128_log("T128 Read transfer, addr = %i, pos = %i\n", addr & 0x1ff, - t128->host_pos); + t128_log("T128 Read transfer: pos=%i, addr=%x.\n", + t128->host_pos, addr & 0x1ff); if (t128->host_pos == MIN(512, dev->buffer_length)) { - t128->status &= ~0x04; - t128_log("T128 Transfer busy read, status = %02x, period = %lf\n", - t128->status, scsi_bus->period); - if ((scsi_bus->period == 0.2) || (scsi_bus->period == 0.02)) - timer_on_auto(&t128->timer, 40.2); - } else if ((t128->host_pos < MIN(512, dev->buffer_length)) && - (scsi_device_get_callback(dev) > 100.0)) - cycles += 100; /*Needed to avoid timer de-syncing with transfers.*/ + t128_log("T128 Transfer busy read, status=%02x, period=%lf, enabled=%d.\n", + t128->status, scsi_bus->period, timer_is_enabled(&t128->timer)); + + if (!t128->block_loaded) { + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + t128_log("T128 read irq\n"); + ncr5380_irq(ncr, 1); + } + t128->status &= ~0x04; + scsi_bus->bus_out |= BUS_CD; + scsi_bus->tx_mode = PIO_TX_BUS; + timer_stop(&t128->timer); + } else if (!timer_is_enabled(&t128->timer)) + timer_on_auto(&t128->timer, 1.0); + else + t128->status &= ~0x04; + } + } else { + /*According to the WinNT DDK sources, just get the status timeout bit from here.*/ + if (!(t128->status & 0x02)) + t128->status |= 0x02; + + t128_log("Read not allowed.\n"); } } @@ -151,24 +164,20 @@ t128_read(uint32_t addr, void *priv) } static void -t128_dma_mode_ext(void *priv, void *ext_priv, UNUSED(uint8_t val)) +t128_dma_mode_ext(void *priv, void *ext_priv, uint8_t val) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; scsi_bus_t *scsi_bus = &ncr->scsibus; - /*Don't stop the timer until it finishes the transfer*/ - if (t128->block_loaded && (ncr->mode & MODE_DMA)) { - t128_log("Continuing DMA mode\n"); - timer_on_auto(&t128->timer, scsi_bus->period + 1.0); - } - /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - if (!t128->block_loaded && !(ncr->mode & MODE_DMA)) { - t128_log("No DMA mode\n"); - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - scsi_bus->tx_mode = PIO_TX_BUS; + if (!t128->block_loaded) { + if (!(val & MODE_DMA)) { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + scsi_bus->tx_mode = PIO_TX_BUS; + t128_log("End of DMA.\n"); + } } } @@ -180,9 +189,9 @@ t128_dma_send_ext(void *priv, void *ext_priv) scsi_bus_t *scsi_bus = &ncr->scsibus; scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; - if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { + if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { + t128_log("T128 DMA OUT, len=%d.\n", dev->buffer_length); memset(t128->buffer, 0, MIN(512, dev->buffer_length)); - t128->status |= 0x04; t128->host_pos = 0; t128->block_count = dev->buffer_length >> 9; @@ -190,6 +199,7 @@ t128_dma_send_ext(void *priv, void *ext_priv) t128->block_count = 1; t128->block_loaded = 1; + t128->status |= 0x04; } return 1; } @@ -202,9 +212,9 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) scsi_bus_t *scsi_bus = &ncr->scsibus; scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; - if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { + if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { + t128_log("T128 DMA IN, len=%d.\n", dev->buffer_length); memset(t128->buffer, 0, MIN(512, dev->buffer_length)); - t128->status |= 0x04; t128->host_pos = MIN(512, dev->buffer_length); t128->block_count = dev->buffer_length >> 9; @@ -212,7 +222,8 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) t128->block_count = 1; t128->block_loaded = 1; - timer_on_auto(&t128->timer, 0.02); + t128->status &= ~0x04; + timer_on_auto(&t128->timer, 1.0); } return 1; } @@ -222,16 +233,16 @@ t128_timer_on_auto(void *ext_priv, double period) { t128_t *t128 = (t128_t *) ext_priv; - if (period == 0.0) + if (period <= 0.0) timer_stop(&t128->timer); - else + else if ((period > 0.0) && !timer_is_enabled(&t128->timer)) timer_on_auto(&t128->timer, period); } void t128_callback(void *priv) { - t128_t *t128 = (void *) priv; + t128_t *t128 = (t128_t *) priv; ncr_t *ncr = &t128->ncr; scsi_bus_t *scsi_bus = &ncr->scsibus; scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; @@ -240,128 +251,110 @@ t128_callback(void *priv) uint8_t temp; uint8_t status; - if ((scsi_bus->tx_mode != PIO_TX_BUS) && (ncr->mode & MODE_DMA) && t128->block_loaded) { - if ((t128->host_pos == MIN(512, dev->buffer_length)) && t128->block_count) - t128->status |= 0x04; - - timer_on_auto(&t128->timer, scsi_bus->period / 55.0); - } + if (scsi_bus->tx_mode != PIO_TX_BUS) + timer_on_auto(&t128->timer, scsi_bus->period / 65.0); if (scsi_bus->data_wait & 1) { scsi_bus->clear_req = 3; scsi_bus->data_wait &= ~1; - if (scsi_bus->tx_mode == PIO_TX_BUS) - return; + } + + if (scsi_bus->tx_mode == PIO_TX_BUS) { + t128_log("Timer CMD=%02x.\n", scsi_bus->command[0]); + return; } switch (scsi_bus->tx_mode) { case DMA_OUT_TX_BUS: - if (!(t128->status & 0x04)) { - t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); - break; - } - - if (!t128->block_loaded) { - t128_log("Write block not loaded\n"); - break; - } - if (t128->host_pos < MIN(512, dev->buffer_length)) break; -write_again: - for (c = 0; c < 10; c++) { - status = scsi_bus_read(scsi_bus); - if (status & BUS_REQ) - break; - } - - /* Data ready. */ - temp = t128->buffer[t128->pos]; - - bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; - bus |= BUS_SETDATA(temp); - - scsi_bus_update(scsi_bus, bus | BUS_ACK); - scsi_bus_update(scsi_bus, bus & ~BUS_ACK); - - t128->pos++; - t128_log("T128 Buffer pos for writing = %d\n", t128->pos); - - if (t128->pos == MIN(512, dev->buffer_length)) { - t128->pos = 0; - t128->host_pos = 0; - t128->status &= ~0x02; - t128->block_count = (t128->block_count - 1) & 0xff; - t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); - if (!t128->block_count) { - t128->block_loaded = 0; - t128_log("IO End of write transfer\n"); - ncr->tcr |= TCR_LAST_BYTE_SENT; - ncr->isr |= STATUS_END_OF_DMA; - timer_stop(&t128->timer); - if (ncr->mode & MODE_ENA_EOP_INT) { - t128_log("T128 write irq\n"); - ncr5380_irq(ncr, 1); - } - } + if (!t128->block_loaded) break; - } else - goto write_again; + + while (1) { + for (c = 0; c < 10; c++) { + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) + break; + } + + /* Data ready. */ + temp = t128->buffer[t128->pos]; + + bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(temp); + + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); + + t128->pos++; + t128_log("T128 Buffer pos for writing = %d\n", t128->pos); + + if (t128->pos == MIN(512, dev->buffer_length)) { + t128->status |= 0x04; + t128->status &= ~0x02; + t128->pos = 0; + t128->host_pos = 0; + t128->block_count = (t128->block_count - 1) & 0xff; + t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); + if (!t128->block_count) { + t128->block_loaded = 0; + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + t128_log("T128 write irq\n"); + ncr5380_irq(ncr, 1); + } + scsi_bus->tx_mode = PIO_TX_BUS; + timer_stop(&t128->timer); + t128_log("IO End of write transfer\n"); + } + break; + } + } break; case DMA_IN_TX_BUS: - if (!(t128->status & 0x04)) { - t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); - break; - } - - if (!t128->block_loaded) { - t128_log("Read block not loaded\n"); - break; - } - if (t128->host_pos < MIN(512, dev->buffer_length)) break; -read_again: - for (c = 0; c < 10; c++) { - status = scsi_bus_read(scsi_bus); - if (status & BUS_REQ) - break; - } - - /* Data ready. */ - bus = scsi_bus_read(scsi_bus); - temp = BUS_GETDATA(bus); - - bus = ncr5380_get_bus_host(ncr); - - scsi_bus_update(scsi_bus, bus | BUS_ACK); - scsi_bus_update(scsi_bus, bus & ~BUS_ACK); - - t128->buffer[t128->pos++] = temp; - t128_log("T128 Buffer pos for reading=%d, temp=%02x, len=%d.\n", t128->pos, temp, dev->buffer_length); - - if (t128->pos == MIN(512, dev->buffer_length)) { - t128->pos = 0; - t128->host_pos = 0; - t128->status &= ~0x02; - t128->block_count = (t128->block_count - 1) & 0xff; - t128_log("T128 Remaining blocks to be read=%d, status=%02x, len=%i, cdb[0] = %02x\n", t128->block_count, t128->status, dev->buffer_length, ncr->command[0]); - if (!t128->block_count) { - t128->block_loaded = 0; - t128_log("IO End of read transfer\n"); - ncr->isr |= STATUS_END_OF_DMA; - timer_stop(&t128->timer); - if (ncr->mode & MODE_ENA_EOP_INT) { - t128_log("NCR read irq\n"); - ncr5380_irq(ncr, 1); - } - } + if (!t128->block_loaded) break; - } else - goto read_again; + + while (1) { + for (c = 0; c < 10; c++) { + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) + break; + } + /* Data ready. */ + bus = scsi_bus_read(scsi_bus); + temp = BUS_GETDATA(bus); + + bus = ncr5380_get_bus_host(ncr); + + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); + + t128->buffer[t128->pos++] = temp; + t128_log("T128 Buffer pos for reading = %d\n", t128->pos); + + if (t128->pos == MIN(512, dev->buffer_length)) { + t128->status |= 0x04; + t128->status &= ~0x02; + t128->pos = 0; + t128->host_pos = 0; + t128->block_count = (t128->block_count - 1) & 0xff; + t128_log("T128 Remaining blocks to be read=%d\n", t128->block_count); + if (!t128->block_count) { + t128->block_loaded = 0; + scsi_bus->bus_out |= BUS_REQ; + t128_log("IO End of read transfer\n"); + } + break; + } + } break; default: @@ -374,7 +367,7 @@ read_again: t128_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; scsi_bus->tx_mode = PIO_TX_BUS; - timer_on_auto(&t128->timer, 10.0); + t128->block_loaded = 0; } } @@ -513,7 +506,7 @@ t128_init(const device_t *info) scsi_bus->bus_device = ncr->bus; scsi_bus->timer = ncr->timer; scsi_bus->priv = ncr->priv; - t128->status = 0x00 /*0x04*/; + t128->status = 0x00; t128->host_pos = 512; if (!t128->bios_enabled && !(info->flags & DEVICE_MCA)) t128->status |= 0x80; @@ -528,7 +521,6 @@ t128_init(const device_t *info) scsi_bus->speed = 0.2; scsi_bus->divider = 1.0; scsi_bus->multi = 1.0; - return t128; } From 5f833a0963a1e868b107157d75a09e7ccec77bd7 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 14:45:41 +0100 Subject: [PATCH 026/218] Mach32 LFB changes of the day (March 8th, 2025) Do not subtract from the linear base when it's not in the range, should fix NT 3.x graphics bugs using the LFB. --- src/video/vid_ati_mach8.c | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 6e2798295..0c8fb6691 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -5223,11 +5223,11 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); } else { @@ -5238,9 +5238,9 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_write_common(addr - mach->linear_base, val, 1, mach, svga); + mach32_write_common(addr, val, 1, mach, svga); else - svga_write_linear(addr - mach->linear_base, val, svga); + svga_write_linear(addr, val, svga); } } @@ -5250,11 +5250,11 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { mach_log("Port WORDW Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outw(0x02ee + (port_dword << 8), val, mach); } else { @@ -5265,9 +5265,9 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_writew_linear(addr - mach->linear_base, val, mach); + mach32_writew_linear(addr, val, mach); else - svga_writew_linear(addr - mach->linear_base, val, svga); + svga_writew_linear(addr, val, svga); } } @@ -5277,11 +5277,11 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { mach_log("Port WORDL Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outw(0x02ee + (port_dword << 8), val & 0xffff, mach); mach_accel_outw(0x02ee + (port_dword << 8) + 4, val >> 16, mach); @@ -5294,9 +5294,9 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_writel_linear(addr - mach->linear_base, val, mach); + mach32_writel_linear(addr, val, mach); else - svga_writel_linear(addr - mach->linear_base, val, svga); + svga_writel_linear(addr, val, svga); } } @@ -5307,19 +5307,19 @@ mach32_ap_readb(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t temp; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) + if (addr & 0x100) temp = mach_accel_inb(0x02ee + (addr & 1) + (port_dword << 8), mach); else temp = mach_accel_inb(0x02e8 + (addr & 1) + (port_dword << 8), mach); } else { if (dev->on) - temp = mach32_read_common(addr - mach->linear_base, 1, mach, svga); + temp = mach32_read_common(addr, 1, mach, svga); else - temp = svga_read_linear(addr - mach->linear_base, svga); + temp = svga_read_linear(addr, svga); mach_log("Linear WORDB Read=%08x, ret=%02x, fast=%d.\n", addr, temp, svga->fast); } @@ -5338,15 +5338,15 @@ mach32_ap_readw(uint32_t addr, void *priv) if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) + if (addr & 0x100) temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); else temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); } else { if (dev->on) - temp = mach32_readw_linear(addr - mach->linear_base, mach); + temp = mach32_readw_linear(addr, mach); else - temp = svga_readw_linear(addr - mach->linear_base, svga); + temp = svga_readw_linear(addr, svga); mach_log("Linear WORDW Read=%08x, ret=%04x.\n", addr, temp); } @@ -5361,11 +5361,11 @@ mach32_ap_readl(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint32_t temp; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); temp |= (mach_accel_inw(0x02ee + (port_dword << 8) + 4, mach) << 8); } else { @@ -5374,9 +5374,9 @@ mach32_ap_readl(uint32_t addr, void *priv) } } else { if (dev->on) - temp = mach32_readl_linear(addr - mach->linear_base, mach); + temp = mach32_readl_linear(addr, mach); else - temp = svga_readl_linear(addr - mach->linear_base, svga); + temp = svga_readl_linear(addr, svga); mach_log("Linear WORDL Read=%08x, ret=%08x, ON%d.\n", addr, temp, dev->on); } From a4a521b3453ed28a3c19c38a2c57f53b5a836bbd Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 8 Mar 2025 20:18:27 +0600 Subject: [PATCH 027/218] Instantiate the renderer properly --- src/qt/qt_openglrenderer_pcem.cpp | 169 ++++++++++++++---------------- src/qt/qt_openglrenderer_pcem.hpp | 71 +++++++++---- 2 files changed, 127 insertions(+), 113 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 4ab66105c..8b2a25663 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -29,25 +29,14 @@ extern "C" { #include <86box/ini.h> #include <86box/config.h> #include <86box/qt-glslp-parser.h> + +char gl3_shader_file[MAX_USER_SHADERS][512]; } #define SCALE_SOURCE 0 #define SCALE_VIEWPORT 1 #define SCALE_ABSOLUTE 2 -float gl3_shader_refresh_rate = 0; -float gl3_input_scale = 1.0f; -int gl3_input_stretch = FULLSCR_SCALE_FULL; -char gl3_shader_file[MAX_USER_SHADERS][512]; - -static int max_texture_size = 65536; - -static struct shader_texture scene_texture; - -static glsl_t *active_shader; - -static QOpenGLExtraFunctions glw; - static GLfloat matrix[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; extern int video_filter_method; @@ -55,8 +44,6 @@ extern int video_vsync; extern int video_focus_dim; extern int video_refresh_rate; -static int glsl_version[2]; - const char *vertex_shader_default_tex_src = "#version 130\n" "\n" "in vec4 VertexCoord;\n" @@ -106,7 +93,7 @@ const char *fragment_shader_default_color_src = "#version 130\n" " outColor = color;\n" "}\n"; -static int +static inline int next_pow2(unsigned int n) { n--; @@ -120,8 +107,8 @@ next_pow2(unsigned int n) return n; } -static int -create_program(struct shader_program *program) +int +OpenGLRendererPCem::create_program(struct shader_program *program) { GLint status; program->id = glw.glCreateProgram(); @@ -151,8 +138,8 @@ create_program(struct shader_program *program) return 1; } -static int -compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) +int +OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) { const char *source[3]; char version[50]; @@ -201,20 +188,20 @@ compile_shader(GLenum shader_type, const char *prepend, const char *program, int return 1; } -static GLuint -get_uniform(GLuint program, const char *name) +GLuint +OpenGLRendererPCem::get_uniform(GLuint program, const char *name) { return glw.glGetUniformLocation(program, name); } -static GLuint -get_attrib(GLuint program, const char *name) +GLuint +OpenGLRendererPCem::get_attrib(GLuint program, const char *name) { return glw.glGetAttribLocation(program, name); } -static void -find_uniforms(struct glsl_shader *glsl, int num_pass) +void +OpenGLRendererPCem::find_uniforms(struct glsl_shader *glsl, int num_pass) { int i; char s[50]; @@ -298,8 +285,8 @@ setup_scale(struct shader *shader, struct shader_pass *pass) pass->scale.value[1] = shader->scale_y; } -static void -create_texture(struct shader_texture *tex) +void +OpenGLRendererPCem::create_texture(struct shader_texture *tex) { if (tex->width > max_texture_size) tex->width = max_texture_size; @@ -318,16 +305,16 @@ create_texture(struct shader_texture *tex) glw.glBindTexture(GL_TEXTURE_2D, 0); } -static void -delete_texture(struct shader_texture *tex) +void +OpenGLRendererPCem::delete_texture(struct shader_texture *tex) { if (tex->id > 0) glw.glDeleteTextures(1, (GLuint *) &tex->id); tex->id = 0; } -static void -delete_fbo(struct shader_fbo *fbo) +void +OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo) { if (fbo->id >= 0) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -335,8 +322,8 @@ delete_fbo(struct shader_fbo *fbo) } } -static void -delete_program(struct shader_program *program) +void +OpenGLRendererPCem::delete_program(struct shader_program *program) { if (program->vertex_shader) glw.glDeleteShader(program->vertex_shader); @@ -345,8 +332,8 @@ delete_program(struct shader_program *program) glw.glDeleteProgram(program->id); } -static void -delete_vbo(struct shader_vbo *vbo) +void +OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo) { if (vbo->color >= 0) glw.glDeleteBuffers(1, (GLuint *) &vbo->color); @@ -354,8 +341,8 @@ delete_vbo(struct shader_vbo *vbo) glw.glDeleteBuffers(1, (GLuint *) &vbo->tex_coord); } -static void -delete_pass(struct shader_pass *pass) +void +OpenGLRendererPCem::delete_pass(struct shader_pass *pass) { delete_fbo(&pass->fbo); delete_vbo(&pass->vbo); @@ -363,15 +350,15 @@ delete_pass(struct shader_pass *pass) glw.glDeleteVertexArrays(1, (GLuint *) &pass->vertex_array); } -static void -delete_prev(struct shader_prev *prev) +void +OpenGLRendererPCem::delete_prev(struct shader_prev *prev) { delete_fbo(&prev->fbo); delete_vbo(&prev->vbo); } -static void -delete_shader(struct glsl_shader *glsl) +void +OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl) { int i; for (i = 0; i < glsl->num_passes; ++i) @@ -385,8 +372,8 @@ delete_shader(struct glsl_shader *glsl) delete_texture(&glsl->lut_textures[i].texture); } -static void -delete_glsl(glsl_t *glsl) +void +OpenGLRendererPCem::delete_glsl(glsl_t *glsl) { int i; for (i = 0; i < glsl->num_shaders; ++i) @@ -399,8 +386,8 @@ delete_glsl(glsl_t *glsl) #endif } -static void -create_fbo(struct shader_fbo *fbo) +void +OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo) { create_texture(&fbo->texture); @@ -414,14 +401,14 @@ create_fbo(struct shader_fbo *fbo) glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); } -static void -setup_fbo(struct shader *shader, struct shader_fbo *fbo) +void +OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo) { fbo->texture.internal_format = GL_RGBA8; fbo->texture.format = GL_RGBA; fbo->texture.min_filter = fbo->texture.mag_filter = shader->filter_linear ? GL_LINEAR : GL_NEAREST; - fbo->texture.width = 1024; - fbo->texture.height = 1024; + fbo->texture.width = 2048; + fbo->texture.height = 2048; fbo->texture.type = GL_UNSIGNED_BYTE; if (!strcmp(shader->wrap_mode, "repeat")) fbo->texture.wrap_mode = GL_REPEAT; @@ -446,8 +433,8 @@ setup_fbo(struct shader *shader, struct shader_fbo *fbo) create_fbo(fbo); } -static void -recreate_fbo(struct shader_fbo *fbo, int width, int height) +void +OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height) { if (width != fbo->texture.width || height != fbo->texture.height) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -458,8 +445,8 @@ recreate_fbo(struct shader_fbo *fbo, int width, int height) } } -static int -create_default_shader_tex(struct shader_pass *pass) +int +OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -478,8 +465,8 @@ create_default_shader_tex(struct shader_pass *pass) return 1; } -static int -create_default_shader_color(struct shader_pass *pass) +int +OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -498,8 +485,8 @@ create_default_shader_color(struct shader_pass *pass) } /* create the default scene shader */ -static void -create_scene_shader() +void +OpenGLRendererPCem::create_scene_shader() { struct shader scene_shader_conf; memset(&scene_shader_conf, 0, sizeof(struct shader)); @@ -558,8 +545,8 @@ load_texture(const char *f, struct shader_texture *tex) return 1; } -static glsl_t * -load_glslp(glsl_t *glsl, int num_shader, const char *f) +glsl_t * +OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) { int i, j; glslp_t *p = glslp_parse(f); @@ -706,8 +693,8 @@ load_glslp(glsl_t *glsl, int num_shader, const char *f) return 0; } -static glsl_t * -load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +glsl_t * +OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) { int i; glsl_t *glsl; @@ -733,8 +720,8 @@ load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) return glsl; } -static void -read_shader_config() +void +OpenGLRendererPCem::read_shader_config() { char s[512]; int i, j; @@ -810,19 +797,22 @@ OpenGLRendererPCem::initialize() glw.initializeOpenGLFunctions(); - QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + pclog("OpenGL information: [%s] %s (%s)\n", glw.glGetString(GL_VENDOR), glw.glGetString(GL_RENDERER), glw.glGetString(GL_VERSION)); + glsl_version[0] = glsl_version[1] = -1; + glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); + glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); + if (glsl_version[0] < 3) { + throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); + } + pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); + pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); - logger->initialize(); // initializes in the current context, i.e. ctx - connect(logger, QOpenGLDebugLogger::messageLogged, [this] (const QOpenGLDebugMessage &message) { - qDebug() << message; - //fprintf(stderr, "OpenGL DBG: %s\n", message.message().toUtf8()); - }); - logger->enableMessages(); - logger->startLogging(); + glw.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + pclog("Max texture size: %dx%d\n", max_texture_size, max_texture_size); glw.glEnable(GL_TEXTURE_2D); - renderTimer->start(75); + //renderTimer->start(75); scene_texture.data = NULL; scene_texture.width = 2048; @@ -1140,18 +1130,8 @@ OpenGLRendererPCem::resizeEvent(QResizeEvent *event) destination.height() * devicePixelRatio()); } -struct render_data { - int pass; - struct glsl_shader *shader; - struct shader_pass *shader_pass; - GLfloat *output_size; - struct shader_pass *orig_pass; - GLint texture; - int frame_count; -}; - -static void -render_pass(struct render_data *data) +void +OpenGLRendererPCem::render_pass(struct render_data *data) { int i; GLuint texture_unit = 0; @@ -1318,8 +1298,16 @@ OpenGLRendererPCem::render() uint32_t x, y, w, h; } window_rect; - window_rect.w = this->size().width() * devicePixelRatio(); - window_rect.h = this->size().height() * devicePixelRatio(); + window_rect.x = destination.x() * devicePixelRatio(); + window_rect.y = destination.y() * devicePixelRatio(); + window_rect.w = destination.width() * devicePixelRatio(); + window_rect.h = destination.height() * devicePixelRatio(); + + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glBindTexture(GL_TEXTURE_2D, 0); GLfloat orig_output_size[] = { (GLfloat)window_rect.w, (GLfloat)window_rect.h }; @@ -1403,12 +1391,6 @@ OpenGLRendererPCem::render() for (s = 0; s < active_shader->num_shaders; ++s) { struct glsl_shader *shader = &active_shader->shaders[s]; - // float refresh_rate = shader->shader_refresh_rate; - // if (refresh_rate < 0) - // refresh_rate = gl3_shader_refresh_rate; - float refresh_rate = gl3_shader_refresh_rate; - if (refresh_rate == 0) - refresh_rate = video_refresh_rate; int frame_count = frameCounter; /* loop through each pass */ @@ -1675,5 +1657,6 @@ OpenGLRendererPCem::render() glw.glDisable(GL_FRAMEBUFFER_SRGB); + frameCounter++; context->swapBuffers(this); } \ No newline at end of file diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp index 0e3069536..88844bb02 100644 --- a/src/qt/qt_openglrenderer_pcem.hpp +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -40,7 +40,20 @@ #include "qt_opengloptions.hpp" #include "qt_renderercommon.hpp" -typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +extern "C" +{ +#include <86box/qt-glslp-parser.h> +} + +struct render_data { + int pass; + struct glsl_shader *shader; + struct shader_pass *shader_pass; + GLfloat *output_size; + struct shader_pass *orig_pass; + GLint texture; + int frame_count; +}; class OpenGLRendererPCem : public QWindow, public RendererCommon { Q_OBJECT @@ -71,45 +84,63 @@ protected: bool event(QEvent *event) override; private: - static constexpr int INIT_WIDTH = 640; - static constexpr int INIT_HEIGHT = 400; - static constexpr int ROW_LENGTH = 2048; - static constexpr int BUFFERPIXELS = 4194304; - static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ - static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ std::array, 2> imagebufs; QTimer *renderTimer; OpenGLOptions *options; - QString glslVersion; + QString glslVersion = ""; bool isInitialized = false; bool isFinalized = false; - GLuint unpackBufferID = 0; - GLuint vertexArrayID = 0; - GLuint vertexBufferID = 0; - GLuint textureID = 0; - int frameCounter = 0; + int max_texture_size = 65536; + int frameCounter = 0; OpenGLOptions::FilterType currentFilter; + QOpenGLExtraFunctions glw; + struct shader_texture scene_texture; + glsl_t *active_shader; void *unpackBuffer = nullptr; + int glsl_version[2] = { 0, 0 }; + void initialize(); void initializeExtensions(); void initializeBuffers(); void applyOptions(); - void applyShader(const OpenGLShaderPass &shader); - bool notReady() const { return !isInitialized || isFinalized; } + + void create_scene_shader(); + void create_texture(struct shader_texture *tex); + void create_fbo(struct shader_fbo *fbo); + void recreate_fbo(struct shader_fbo *fbo, int width, int height); + void setup_fbo(struct shader *shader, struct shader_fbo *fbo); - /* GL_ARB_buffer_storage */ - bool hasBufferStorage = false; -#ifndef NO_BUFFER_STORAGE - PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr; -#endif + bool notReady() const { return !isInitialized || isFinalized; } + glsl_t* load_glslp(glsl_t *glsl, int num_shader, const char *f); + glsl_t* load_shaders(int num, char shaders[MAX_USER_SHADERS][512]); + int compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst); + int create_default_shader_tex(struct shader_pass *pass); + int create_default_shader_color(struct shader_pass *pass); + int create_program(struct shader_program *program); + + GLuint get_uniform(GLuint program, const char *name); + GLuint get_attrib(GLuint program, const char *name); + + void find_uniforms(struct glsl_shader *glsl, int num_pass); + void delete_texture(struct shader_texture *tex); + void delete_fbo(struct shader_fbo *fbo); + void delete_program(struct shader_program *program); + void delete_vbo(struct shader_vbo *vbo); + void delete_pass(struct shader_pass *pass); + void delete_prev(struct shader_prev *prev); + void delete_shader(struct glsl_shader *glsl); + void delete_glsl(glsl_t *glsl); + void read_shader_config(); + + void render_pass(struct render_data *data); private slots: void render(); From 2e46cc479c446b43ddf76ddf2d6f801c5b5ca964 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 8 Mar 2025 23:19:37 +0600 Subject: [PATCH 028/218] Fix Preferences dialog crash --- src/qt/qt_mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 1cc6c33c9..9864584d3 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1267,6 +1267,7 @@ void MainWindow::refreshMediaMenu() { mm->refresh(ui->menuMedia); + status->setSoundGainAction(ui->actionSound_gain); status->refresh(ui->statusbar); ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); From 5db4de199bfc97a55b6f7c7fc9a9a05b0968f8cc Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 19:26:33 +0100 Subject: [PATCH 029/218] PAS16 SCSI change of the day (March 8th, 2025) Signal DRQ once the transfers are complete for real. --- src/sound/snd_pas16.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 353f9a3d5..675582367 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -789,6 +789,10 @@ pas16_in(uint16_t port, void *priv) scsi_bus = &pas16->scsi->ncr.scsibus; /* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */ ret = (((scsi_bus->tx_mode != PIO_TX_BUS) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; + if ((scsi_bus->tx_mode == PIO_TX_BUS) && !(ret & 0x80)) + ret |= 0x80; + + pas16_log("5C01 read ret=%02x, status=%02x, txmode=%x.\n", ret, pas16->scsi->status & 0x06, scsi_bus->tx_mode); } break; case 0x5c03: @@ -1190,6 +1194,7 @@ pas16_scsi_callback(void *priv) t128_callback(pas16->scsi); + pas16_log("TimeOutStatus=%02x, t128stat=%02x.\n", pas16->timeout_status, dev->status); if ((scsi_bus->tx_mode != PIO_TX_BUS) && (dev->status & 0x04)) { timer_stop(&pas16->scsi_timer); pas16->timeout_status &= 0x7f; From a39bef1ab881bac586532a498b5ca7cb748202d5 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 19:39:55 +0100 Subject: [PATCH 030/218] ESS/SB changes of the day (March 8th, 2025) 1. Correct ChipChat mixer port length as well as making mixer reg 0x3a read back its value. 2. Swap the sb port addresses back so that they match the Piper adf. This fixes SoundPiper 16/32 detection. 3. Log cleanups and additions for better debugging. --- src/sound/snd_sb.c | 100 ++++++++++++++++++++--------------------- src/sound/snd_sb_dsp.c | 15 +++++-- 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 689d0b91e..5f660509a 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1335,7 +1335,7 @@ sb_ct1745_mixer_read(uint16_t addr, void *priv) break; case 0x82: - ; /* Empty statement to make compilers happy about the following variable declaration. */ + /* Empty statement to make compilers happy about the following variable declaration. */ /* The Interrupt status register, addressed as register 82h on the Mixer register map, is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, in which case it should chain to the previous routine. */ @@ -1727,6 +1727,7 @@ ess_mixer_read(uint16_t addr, void *priv) case 0x32: case 0x36: case 0x38: + case 0x3a: case 0x3e: ret = mixer->regs[mixer->index]; break; @@ -2593,10 +2594,10 @@ ess_soundpiper_mca_write(const int port, const uint8_t val, void *priv) ess->dsp.sb_addr = 0x0000; break; case 0x08: - ess->dsp.sb_addr = 0x0240; + ess->dsp.sb_addr = 0x0220; break; case 0x0c: - ess->dsp.sb_addr = 0x0220; + ess->dsp.sb_addr = 0x0240; break; } @@ -2750,64 +2751,59 @@ ess_chipchat_mca_write(int port, uint8_t val, void *priv) ess->pos_regs[port & 7] = val; - if (ess->pos_regs[2] & 1) { - ess->dsp.sb_addr = (ess->pos_regs[2] == 0x51) ? 0x0220 : 0x0000; + if (ess->pos_regs[2] & 0x01) { + ess->dsp.sb_addr = 0x0220; - if (ess->dsp.sb_addr != 0x0000) { - io_sethandler(ess->dsp.sb_addr, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(ess->dsp.sb_addr + 8, 0x0002, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + io_sethandler(ess->dsp.sb_addr, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(0x0388, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 4, 0x0002, + ess_mixer_read, NULL, NULL, + ess_mixer_write, NULL, NULL, + ess); + + io_sethandler(ess->dsp.sb_addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + + if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { + mpu401_change_addr(ess->mpu, 0x0330); + + io_sethandler(0x0330, 0x0002, ess_fm_midi_read, NULL, NULL, ess_fm_midi_write, NULL, NULL, ess); - io_sethandler(0x0388, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, ess->opl.priv); - io_sethandler(0x0388, 0x0004, - ess_fm_midi_read, NULL, NULL, - ess_fm_midi_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 4, 0x0004, - ess_mixer_read, NULL, NULL, - ess_mixer_write, NULL, NULL, - ess); - - io_sethandler(ess->dsp.sb_addr + 2, 0x0004, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 6, 0x0001, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - - if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { - mpu401_change_addr(ess->mpu, (ess->pos_regs[2] == 0x51) ? 0x0330 : 0); - - if (ess->pos_regs[2] == 0x51) - io_sethandler(0x0330, 0x0002, - ess_fm_midi_read, NULL, NULL, - ess_fm_midi_write, NULL, NULL, - ess); - } } /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&ess->dsp, ess->dsp.sb_addr); - gameport_remap(ess->gameport, (ess->pos_regs[2] == 0x51) ? 0x200 : 0); - } + gameport_remap(ess->gameport, 0x0200); - if (ess->pos_regs[2] == 0x51) { sb_dsp_setirq(&ess->dsp, 7); mpu401_setirq(ess->mpu, 7); diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 9ce0b9fb7..10e5601f4 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -388,6 +388,7 @@ sb_update_status(sb_dsp_t *dsp, int bit, int set) { int masked = 0; + sb_dsp_log("SBIRQ8=%d, irqnum=%d, bit=%x, set=%x.\n", dsp->sb_irq8, dsp->sb_irqnum, bit, set); if (dsp->sb_irq8 || dsp->sb_irq16) return; @@ -423,6 +424,7 @@ sb_update_status(sb_dsp_t *dsp, int bit, int set) } } + sb_dsp_log("Masked=%02x.\n", masked); if (set && !masked) dsp->irq_update(dsp->irq_priv, 1); else if (!set) @@ -1039,6 +1041,8 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) { uint8_t chg; + sb_dsp_log("ESS Write reg=%02x, val=%02x.\n", reg, data); + switch (reg) { case 0xA1: /* Extended Mode Sample Rate Generator */ { @@ -1110,6 +1114,7 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) dsp->sb_irqnum = 10; break; } + sb_dsp_log("Legacy Audio IRQ control=%d.\n", dsp->sb_irqnum); sb_ess_update_irq_drq_readback_regs(dsp, false); break; case 0xB2: /* DRQ Control */ @@ -1131,6 +1136,7 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) dsp->sb_8_dmanum = 3; break; } + sb_dsp_log("Legacy Audio DRQ control=%d, chg=%02x.\n", dsp->sb_8_dmanum, chg); sb_ess_update_irq_drq_readback_regs(dsp, false); if (chg & 0x40) sb_ess_update_dma_status(dsp); @@ -1876,12 +1882,12 @@ sb_write(uint16_t addr, uint8_t val, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *) priv; - sb_dsp_log("[%04X:%08X] DSP: [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); - /* Sound Blasters prior to Sound Blaster 16 alias the I/O ports. */ if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xE))) addr &= 0xfffe; + sb_dsp_log("[%04X:%08X] DSP: [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); + switch (addr & 0xF) { case 6: /* Reset */ sb_do_reset(dsp, val); @@ -1962,7 +1968,7 @@ sb_read(uint16_t addr, void *priv) uint8_t ret = 0x00; /* Sound Blasters prior to Sound Blaster 16 alias the I/O ports. */ - if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xF))) + if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xE))) /* Exception: ESS AudioDrive does not alias port base+0xf */ addr &= 0xfffe; @@ -2085,7 +2091,7 @@ sb_read(uint16_t addr, void *priv) break; } - sb_dsp_log("[%04X:%08X] DSP: [R] %04X = %02X\n", CS, cpu_state.pc, a, ret); + sb_dsp_log("[%04X:%08X] DSP: [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); return ret; } @@ -2319,6 +2325,7 @@ pollsb(void *priv) if (dsp->sb_8_enable && dsp->sb_pausetime < 0 && dsp->sb_8_output) { sb_dsp_update(dsp); + sb_dsp_log("8-bit format=%02x, pause=%x, length=%d.\n", dsp->sb_8_format, dsp->sb_8_pause, dsp->sb_8_length); switch (dsp->sb_8_format) { case 0x00: /* Mono unsigned */ if (!dsp->sb_8_pause) { From e0603b28769a3c25f26f61e41e3f63d528b84159 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Mar 2025 14:35:59 -0500 Subject: [PATCH 031/218] Fix compile error --- src/sound/snd_sb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 5f660509a..e89946486 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1335,7 +1335,7 @@ sb_ct1745_mixer_read(uint16_t addr, void *priv) break; case 0x82: - /* Empty statement to make compilers happy about the following variable declaration. */ + ; /* Empty statement to make compilers happy about the following variable declaration. */ /* The Interrupt status register, addressed as register 82h on the Mixer register map, is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, in which case it should chain to the previous routine. */ From 757246998838dd1ccd84e1f3a30b53f060098b52 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 01:39:07 +0600 Subject: [PATCH 032/218] Current OpenGL port status --- src/config.c | 58 +++++++++ src/include/86box/ini.h | 7 +- src/include/86box/qt-glslp-parser.h | 5 +- src/qt/CMakeLists.txt | 4 + src/qt/qt_glsl_parser.cpp | 31 ++++- src/qt/qt_mainwindow.cpp | 11 +- src/qt/qt_openglrenderer_pcem.cpp | 9 +- src/qt/qt_openglrenderer_pcem.hpp | 6 +- src/qt/qt_openglshadermanagerdialog.cpp | 159 ++++++++++++++++++++++++ src/qt/qt_openglshadermanagerdialog.hpp | 40 ++++++ src/qt/qt_openglshadermanagerdialog.ui | 148 ++++++++++++++++++++++ src/qt/qt_renderercommon.hpp | 2 + src/qt/qt_rendererstack.hpp | 2 + 13 files changed, 473 insertions(+), 9 deletions(-) create mode 100644 src/qt/qt_openglshadermanagerdialog.cpp create mode 100644 src/qt/qt_openglshadermanagerdialog.hpp create mode 100644 src/qt/qt_openglshadermanagerdialog.ui diff --git a/src/config.c b/src/config.c index 07e770822..3ff802952 100644 --- a/src/config.c +++ b/src/config.c @@ -77,6 +77,10 @@ #include <86box/snd_opl.h> #include <86box/version.h> +/* Deliberate to not make the 86box.h header kitchen-sink. */ +#include <86box/qt-glsl.h> +extern char gl3_shader_file[MAX_USER_SHADERS][512]; + static int cx; static int cy; static int cw; @@ -1714,6 +1718,30 @@ load_other_peripherals(void) ini_section_delete_var(cat, temp); } +/* Load OpenGL 3.0 renderer options. */ +static void +load_gl3_shaders(void) +{ + ini_section_t cat = ini_find_section(config, "GL3 Shaders"); + char *p; + char temp[512]; + int i = 0; + memset(temp, 0, sizeof(temp)); + memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); + + for (int i = 0; i < MAX_USER_SHADERS; i++) { + temp[0] = 0; + snprintf(temp, 512, "shader%d", i); + p = ini_section_get_string(cat, temp, ""); + if (p[0]) { + strncpy(gl3_shader_file[i], p, 512); + } else { + gl3_shader_file[i][0] = 0; + break; + } + } +} + /* Load the specified or a default configuration file. */ void config_load(void) @@ -1810,6 +1838,7 @@ config_load(void) load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ load_other_removable_devices(); /* Other removable devices */ load_other_peripherals(); /* Other peripherals */ + load_gl3_shaders(); /* GL3 Shaders */ /* Migrate renamed device configurations. */ c = ini_find_section(config, "MDA"); @@ -2632,6 +2661,34 @@ save_other_peripherals(void) ini_delete_section_if_empty(config, cat); } +/* Save "GL3 Shaders" section. */ +static void +save_gl3_shaders(void) +{ + ini_section_t cat = ini_find_or_create_section(config, "GL3 Shaders"); + char temp[512]; + int shaders = 0, i = 0; + + for (i = 0; i < MAX_USER_SHADERS; i++) { + if (gl3_shader_file[i][0] == 0) + break; + shaders++; + } + + ini_section_set_int(cat, "shaders", shaders); + if (shaders == 0) { + ini_section_delete_var(cat, "shaders"); + } else { + for (i = 0; i < shaders; i++) { + temp[0] = 0; + snprintf(temp, 512, "shader%d"); + ini_section_set_string(cat, temp, gl3_shader_file[i]); + } + } + + ini_delete_section_if_empty(config, cat); +} + /* Save "Hard Disks" section. */ static void save_hard_disks(void) @@ -2987,6 +3044,7 @@ config_save(void) save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ save_other_removable_devices(); /* Other removable devices */ save_other_peripherals(); /* Other peripherals */ + save_gl3_shaders(); /* GL3 Shaders */ ini_write(config, cfg_path); } diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index 2a73a18b0..2ce89f788 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -91,13 +91,16 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); -static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); }; +static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); } static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); if (size == 0) return res; - strncpy(dst, str, size); + if (str != NULL) + strncpy(dst, str, size - 1); + else + dst[0] = 0; return res; } static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { diff --git a/src/include/86box/qt-glslp-parser.h b/src/include/86box/qt-glslp-parser.h index cf2ac464a..853e50e66 100644 --- a/src/include/86box/qt-glslp-parser.h +++ b/src/include/86box/qt-glslp-parser.h @@ -53,4 +53,7 @@ void get_glslp_name(const char *f, char *s, int size); glslp_t *glslp_parse(const char *f); void glslp_free(glslp_t *p); -#endif /* SRC_WX_GLSLP_PARSER_H_ */ \ No newline at end of file +void glslp_read_shader_config(glslp_t *shader); +void glslp_write_shader_config(glslp_t *shader); + +#endif /* SRC_WX_GLSLP_PARSER_H_ */ diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index fd82b9053..8a06cbe5a 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -193,6 +193,10 @@ add_library(ui STATIC ../qt_resources.qrc ./qdarkstyle/dark/darkstyle.qrc + + qt_openglshadermanagerdialog.hpp + qt_openglshadermanagerdialog.cpp + qt_openglshadermanagerdialog.ui ) if(RTMIDI) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index 7cf032a52..b1a96a312 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -7,8 +7,12 @@ extern "C" { #include <86box/86box.h> #include <86box/ini.h> +#include <86box/config.h> #include <86box/qt-glslp-parser.h> #include <86box/path.h> + +extern void startblit(); +extern void endblit(); } #define safe_strncpy(a, b, n) \ @@ -305,4 +309,29 @@ void glslp_free(glslp_t *p) { free(p); } -} \ No newline at end of file +void glslp_read_shader_config(glslp_t *shader) { + char s[512]; + int i; + char *name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) { + struct parameter *param = &shader->parameters[i]; + param->value = config_get_double(s, param->id, param->default_value); + } +} + +void glslp_write_shader_config(glslp_t *shader) { + char s[512]; + int i; + char *name = shader->name; + + startblit(); + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) { + struct parameter *param = &shader->parameters[i]; + config_set_double(s, param->id, param->value); + } + endblit(); +} + +} diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 4c1738e63..60e0494fc 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1987,7 +1987,16 @@ MainWindow::on_actionRenderer_options_triggered() { if (const auto dlg = ui->stackedWidget->getOptions(this)) { if (dlg->exec() == QDialog::Accepted) { - for (int i = 1; i < MONITORS_NUM; i++) { + if (ui->stackedWidget->reloadRendererOption()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (show_second_monitors) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + } + } + } + } else for (int i = 1; i < MONITORS_NUM; i++) { if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions(); } diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 8b2a25663..17f4299d7 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -20,6 +20,7 @@ #include #include "qt_openglrenderer_pcem.hpp" +#include "qt_openglshadermanagerdialog.hpp" extern "C" { #include <86box/86box.h> @@ -1286,6 +1287,12 @@ OpenGLRendererPCem::event(QEvent *event) return res; } +QDialog* +OpenGLRendererPCem::getOptions(QWidget *parent) +{ + return new OpenGLShaderManagerDialog(parent); +} + void OpenGLRendererPCem::render() { @@ -1659,4 +1666,4 @@ OpenGLRendererPCem::render() frameCounter++; context->swapBuffers(this); -} \ No newline at end of file +} diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp index 88844bb02..706a744fa 100644 --- a/src/qt/qt_openglrenderer_pcem.hpp +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -67,9 +67,9 @@ public: std::vector> getBuffers() override; void finalize() override final; - //bool hasOptions() const override { return true; } - //QDialog *getOptions(QWidget *parent) override; - //void reloadOptions() override; + bool hasOptions() const override { return true; } + QDialog *getOptions(QWidget *parent) override; + bool reloadRendererOption() { return true; } signals: void initialized(); diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp new file mode 100644 index 000000000..26f206a0e --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -0,0 +1,159 @@ +#include "qt_openglshadermanagerdialog.hpp" +#include "ui_qt_openglshadermanagerdialog.h" + +#include +#include +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/video.h> +#include <86box/path.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/qt-glslp-parser.h> + +extern char gl3_shader_file[MAX_USER_SHADERS][512]; +} + +OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::OpenGLShaderManagerDialog) +{ + ui->setupUi(this); + + for (int i = 0; i < MAX_USER_SHADERS; i++) { + if (gl3_shader_file[i][0] != 0) { + char* filename = path_get_filename(gl3_shader_file[i]); + if (filename[0] != 0) { + glslp_t* shaderfile = glslp_parse(gl3_shader_file[i]); + if (shaderfile) { + QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); + item->setText(filename); + item->setData(Qt::UserRole + 1, QString(gl3_shader_file[i])); + item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + } + } + } + } + if (ui->shaderListWidget->count()) { + ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + } else { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + } +} + +OpenGLShaderManagerDialog::~OpenGLShaderManagerDialog() +{ + for (int i = 0; i < ui->shaderListWidget->count(); i++) { + if (ui->shaderListWidget->item(i) && ui->shaderListWidget->item(i)->data(Qt::UserRole + 2).toULongLong()) { + glslp_free((glslp_t*)ui->shaderListWidget->item(i)->data(Qt::UserRole + 2).toULongLong()); + } + } + delete ui; +} + +void OpenGLShaderManagerDialog::on_buttonBox_clicked(QAbstractButton *button) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) { + accept(); + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) { + reject(); + } +} + + +void OpenGLShaderManagerDialog::on_buttonMoveUp_clicked() +{ + if (ui->shaderListWidget->currentRow() == 0) + return; + + int row = ui->shaderListWidget->currentRow(); + auto item = ui->shaderListWidget->takeItem(row); + ui->shaderListWidget->insertItem(row - 1, item); + ui->shaderListWidget->setCurrentItem(item); +} + + +void OpenGLShaderManagerDialog::on_shaderListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + if (current == nullptr) { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + return; + } else { + ui->buttonRemove->setDisabled(false); + } + ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); + ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); +} + + +void OpenGLShaderManagerDialog::on_shaderListWidget_currentRowChanged(int currentRow) +{ + ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); + ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); +} + + +void OpenGLShaderManagerDialog::on_buttonMoveDown_clicked() +{ + if (ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)) + return; + + int row = ui->shaderListWidget->currentRow(); + auto item = ui->shaderListWidget->takeItem(row); + ui->shaderListWidget->insertItem(row + 1, item); + ui->shaderListWidget->setCurrentItem(item); +} + + +void OpenGLShaderManagerDialog::on_buttonAdd_clicked() +{ + auto res = QFileDialog::getOpenFileName(this, QString(), QString(), "GLSL Shaders (*.glslp *.glsl);;All files (*.*)"); + if (!res.isEmpty()) { + auto glslp_file = res.toUtf8(); + glslp_t* shaderfile = glslp_parse(glslp_file.data()); + if (shaderfile) { + auto filename = path_get_filename(glslp_file.data()); + QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); + item->setText(filename); + item->setData(Qt::UserRole + 1, res); + item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + if (ui->shaderListWidget->count()) { + ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + } + } else { + QMessageBox::critical(this, tr("GLSL error"), tr("Could not load filename %1").arg(res)); + } + } +} + + +void OpenGLShaderManagerDialog::on_buttonRemove_clicked() +{ + if (ui->shaderListWidget->currentItem()) { + auto item = ui->shaderListWidget->takeItem(ui->shaderListWidget->currentRow()); + + if (item->data(Qt::UserRole + 2).toULongLong()) { + glslp_free((glslp_t*)item->data(Qt::UserRole + 2).toULongLong()); + } + delete item; + } +} + +void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() +{ + memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); + for (int i = 0; i < ui->shaderListWidget->count(); i++) { + strncpy(gl3_shader_file[i], ui->shaderListWidget->item(i)->data(Qt::UserRole + 1).toString().toUtf8(), 512); + } + startblit(); + config_save(); + endblit(); +} + diff --git a/src/qt/qt_openglshadermanagerdialog.hpp b/src/qt/qt_openglshadermanagerdialog.hpp new file mode 100644 index 000000000..bac0205cf --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.hpp @@ -0,0 +1,40 @@ +#ifndef QT_OPENGLSHADERMANAGERDIALOG_H +#define QT_OPENGLSHADERMANAGERDIALOG_H + +#include +#include +#include + +namespace Ui { +class OpenGLShaderManagerDialog; +} + +class OpenGLShaderManagerDialog : public QDialog { + Q_OBJECT + +public: + explicit OpenGLShaderManagerDialog(QWidget *parent = nullptr); + ~OpenGLShaderManagerDialog(); + +private slots: + void on_buttonBox_clicked(QAbstractButton *button); + + void on_buttonMoveUp_clicked(); + + void on_shaderListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + + void on_shaderListWidget_currentRowChanged(int currentRow); + + void on_buttonMoveDown_clicked(); + + void on_buttonAdd_clicked(); + + void on_buttonRemove_clicked(); + + void on_OpenGLShaderManagerDialog_accepted(); + +private: + Ui::OpenGLShaderManagerDialog *ui; +}; + +#endif // QT_OPENGLSHADERMANAGERDIALOG_H diff --git a/src/qt/qt_openglshadermanagerdialog.ui b/src/qt/qt_openglshadermanagerdialog.ui new file mode 100644 index 000000000..2888e106f --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.ui @@ -0,0 +1,148 @@ + + + OpenGLShaderManagerDialog + + + + 0 + 0 + 400 + 465 + + + + Dialog + + + + QLayout::SizeConstraint::SetFixedSize + + + + + QAbstractItemView::DragDropMode::InternalMove + + + QAbstractItemView::SelectionBehavior::SelectItems + + + + + + + + + Add + + + + + + + Remove + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + false + + + Configure + + + + + + + Move up + + + + + + + Move down + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + Qt::Orientation::Vertical + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + false + + + + + + + + + + + buttonBox + accepted() + OpenGLShaderManagerDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OpenGLShaderManagerDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index af72474c7..f3f5d2223 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -34,6 +34,8 @@ public: virtual QDialog *getOptions(QWidget *parent) { return nullptr; } /* Reloads options of renderer */ virtual void reloadOptions() { } + /* Make the renderer reload itself */ + virtual bool reloadRendererOption() { return false; } int r_monitor_index = 0; diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 8059d59c5..32ed5f7ca 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -70,6 +70,8 @@ public: void reloadOptions() const { return rendererWindow->reloadOptions(); } /* Returns options dialog for current renderer */ QDialog *getOptions(QWidget *parent) { return rendererWindow ? rendererWindow->getOptions(parent) : nullptr; } + /* Reload the renderer itself */ + bool reloadRendererOption() { return rendererWindow ? rendererWindow->reloadRendererOption() : false; } void setFocusRenderer(); void onResize(int width, int height); From f8517d05ef7f885a2d91629aec21fbf13a70d366 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 20:49:28 +0100 Subject: [PATCH 033/218] XGA/VGA changes of the evening (March 8th, 2025) Workaround xga/vga toggle bug in the inmos card so that it switches from xga to vga and viceversa on ami bioses. --- src/video/vid_svga.c | 5 +++-- src/video/vid_xga.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index caa20e196..1fd2460bd 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -782,7 +782,8 @@ svga_recalctimings(svga_t *svga) if (xga_active && (svga->xga != NULL)) { if (xga->on) { - if ((svga->mapping.base == 0xb8000) && (xga->aperture_cntl == 1)) /*Some operating systems reset themselves with ctrl-alt-del by going into text mode.*/ + svga_log("XGA on=%d, base=%05x, ap=%x.\n", xga->on, svga->mapping.base, xga->aperture_cntl); + if ((svga->mapping.base == 0xb8000) && (xga->aperture_cntl >= 1)) /*Some operating systems reset themselves with ctrl-alt-del by going into text mode.*/ xga->on = 0; } } @@ -1541,7 +1542,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32; svga->translate_address = NULL; - + svga->cable_connected = 1; svga->ksc5601_english_font_type = 0; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 2cc20044a..4c08b7b71 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -2738,7 +2738,7 @@ xga_write_test(uint32_t addr, uint8_t val, void *priv) xga_t *xga = (xga_t *) svga->xga; if (xga_active && xga) { - if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl) { + if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl && (svga->mapping.base == 0xb8000)) { xga_log("WriteAddr=%05x.\n", addr); if (val == 0xa5) { /*Memory size test of XGA*/ xga->test = val; @@ -2843,7 +2843,7 @@ xga_read_test(uint32_t addr, void *priv) uint8_t ret = 0x00; if (xga_active && xga) { - if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl) { + if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl && (svga->mapping.base == 0xb8000)) { if (xga->test == 0xa5) { /*Memory size test of XGA*/ if (addr == 0xa0001) { ret = xga->test; From 2f2a14e0e768dab93c78f8ee02ccac38642b6305 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 01:58:47 +0600 Subject: [PATCH 034/218] Fix not saving shader section properly --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index 3ff802952..46f935f7e 100644 --- a/src/config.c +++ b/src/config.c @@ -2681,7 +2681,7 @@ save_gl3_shaders(void) } else { for (i = 0; i < shaders; i++) { temp[0] = 0; - snprintf(temp, 512, "shader%d"); + snprintf(temp, 512, "shader%d", i); ini_section_set_string(cat, temp, gl3_shader_file[i]); } } From dad0a37ab3e7c66abecf54515f5679e39a708314 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 20:58:49 +0100 Subject: [PATCH 035/218] Mach32 LFB changes (March 8th, 2025) The Byte Write access of the LFB of the Mach32 was not correctly taking account of the subtraction of the address, this fixes possible graphics bugs using the LFB (Linear Aperture). --- src/video/vid_ati_mach8.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 0c8fb6691..d35257ea7 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -5226,7 +5226,7 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); @@ -5279,6 +5279,9 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t port_dword = addr & 0xfc; + mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { @@ -5291,8 +5294,6 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach); } } else { - mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) mach32_writel_linear(addr, val, mach); else From 9da53a611d8bfbd0100cd3caa6e88ca0d799f0fa Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Mar 2025 01:58:48 +0100 Subject: [PATCH 036/218] VIA PIPC: Fix SCI IRQ readout. --- src/chipset/via_pipc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index dcfe41811..19355431e 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -413,7 +413,9 @@ pipc_reset_hard(void *priv) dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; - dev->power_regs[0x42] = 0x50; + dev->power_regs[0x42] = 0x00; + acpi_set_irq_line(dev->acpi, 0x00); + dev->power_regs[0x48] = 0x01; if (dev->local == VIA_PIPC_686B) { @@ -1593,6 +1595,9 @@ pipc_reset(void *priv) pipc_write(pm_func, 0x48, 0x01, priv); pipc_write(pm_func, 0x49, 0x00, priv); + dev->power_regs[0x42] = 0x00; + acpi_set_irq_line(dev->acpi, 0x00); + pipc_write(1, 0x04, 0x80, priv); pipc_write(1, 0x09, 0x85, priv); pipc_write(1, 0x10, 0xf1, priv); From 0c7c85e66314fdbb7e8bad7a6392e43e1a3a0526 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Mar 2025 02:18:18 +0100 Subject: [PATCH 037/218] ACPI: Do not raise or lower IRQ if IRQ line is set to IRQ 0. --- src/acpi.c | 10 ++++++++-- src/chipset/via_pipc.c | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index b33653663..ccd51ebca 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -211,7 +211,10 @@ acpi_update_irq(acpi_t *dev) if ((dev->regs.pmcntrl & 0x01) && sci_level) switch (dev->irq_mode) { default: - picintlevel(1 << dev->irq_line, &dev->irq_state); + if (dev->irq_line != 0) + picintlevel(1 << dev->irq_line, &dev->irq_state); + else + dev->irq_state = 1; break; case 1: pci_set_irq(dev->slot, dev->irq_pin, &dev->irq_state); @@ -223,7 +226,10 @@ acpi_update_irq(acpi_t *dev) break; } else switch (dev->irq_mode) { default: - picintclevel(1 << dev->irq_line, &dev->irq_state); + if (dev->irq_line != 0) + picintclevel(1 << dev->irq_line, &dev->irq_state); + else + dev->irq_state = 0; break; case 1: pci_clear_irq(dev->slot, dev->irq_pin, &dev->irq_state); diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 19355431e..11a192450 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -1699,6 +1699,8 @@ pipc_init(const device_t *info) acpi_set_nvr(dev->acpi, dev->nvr); acpi_init_gporeg(dev->acpi, 0xff, 0xbf, 0xff, 0x7f); + + acpi_set_irq_mode(dev->acpi, 0); } return dev; From 7a4d5ee75e971fe4ddca1e72a2f8630cb2f8356e Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 13:06:58 +0600 Subject: [PATCH 038/218] Some optimizations --- src/qt/qt_openglrenderer_pcem.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 17f4299d7..e53b8b77b 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -770,7 +770,7 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) parentWidget = parent; - source.setRect(0, 0, 2048, 2048); + source.setRect(0, 0, 100, 100); isInitialized = false; isFinalized = false; } @@ -1075,11 +1075,18 @@ OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) destination.width() * devicePixelRatio(), destination.height() * devicePixelRatio()); #endif + + if (source.width() != w || source.height() != h) { + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + glw.glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, w, h, 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); + glw.glBindTexture(GL_TEXTURE_2D, 0); + } + source.setRect(x, y, w, h); glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 2048); - glw.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, (const void *) ((uintptr_t) imagebufs[buf_idx].get() + (uintptr_t) (2048 * 4 * y + x * 4))); + glw.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, (const void *) ((uintptr_t) imagebufs[buf_idx].get() + (uintptr_t) (2048 * 4 * y + x * 4))); glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glw.glBindTexture(GL_TEXTURE_2D, 0); @@ -1369,10 +1376,10 @@ OpenGLRendererPCem::render() pass->state.tex_coords[7] = maxy; // create input tex coords - minx = video_rect.x / 2048.f; - miny = video_rect.y / 2048.f; - maxx = (video_rect.x + video_rect.w) / (float) 2048.f; - maxy = (video_rect.y + video_rect.h) / (float) 2048.f; + minx = 0; + miny = 0; + maxx = 1; + maxy = 1; GLfloat tex_coords[] = { minx, miny, minx, maxy, maxx, miny, maxx, maxy }; From 7e61d2d58692c10566b891c6f387920486fa54f5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 23:58:54 +0600 Subject: [PATCH 039/218] OpenGL Shader configuration UI --- src/config.c | 14 +++- src/include/86box/ini.h | 3 +- src/ini.c | 52 +++++++++++--- src/qt/CMakeLists.txt | 1 + src/qt/qt_glsl_parser.cpp | 2 + src/qt/qt_mainwindow.cpp | 16 +++++ src/qt/qt_mainwindow.hpp | 4 ++ src/qt/qt_openglshaderconfig.cpp | 85 +++++++++++++++++++++++ src/qt/qt_openglshaderconfig.hpp | 40 +++++++++++ src/qt/qt_openglshaderconfig.ui | 92 +++++++++++++++++++++++++ src/qt/qt_openglshadermanagerdialog.cpp | 50 ++++++++++++++ src/qt/qt_openglshadermanagerdialog.hpp | 2 + src/qt/qt_openglshadermanagerdialog.ui | 4 +- 13 files changed, 349 insertions(+), 16 deletions(-) create mode 100644 src/qt/qt_openglshaderconfig.cpp create mode 100644 src/qt/qt_openglshaderconfig.hpp create mode 100644 src/qt/qt_openglshaderconfig.ui diff --git a/src/config.c b/src/config.c index 46f935f7e..20981885a 100644 --- a/src/config.c +++ b/src/config.c @@ -1725,11 +1725,15 @@ load_gl3_shaders(void) ini_section_t cat = ini_find_section(config, "GL3 Shaders"); char *p; char temp[512]; - int i = 0; + int i = 0, shaders = 0; memset(temp, 0, sizeof(temp)); memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); - for (int i = 0; i < MAX_USER_SHADERS; i++) { + shaders = ini_section_get_int(cat, "shaders", 0); + if (shaders > MAX_USER_SHADERS) + shaders = MAX_USER_SHADERS; + + for (int i = 0; i < shaders; i++) { temp[0] = 0; snprintf(temp, 512, "shader%d", i); p = ini_section_get_string(cat, temp, ""); @@ -2670,8 +2674,12 @@ save_gl3_shaders(void) int shaders = 0, i = 0; for (i = 0; i < MAX_USER_SHADERS; i++) { - if (gl3_shader_file[i][0] == 0) + if (gl3_shader_file[i][0] == 0) { + temp[0] = 0; + snprintf(temp, 512, "shader%d", i); + ini_section_delete_var(cat, temp); break; + } shaders++; } diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index 2ce89f788..3139f410e 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -31,6 +31,7 @@ typedef void *ini_section_t; extern ini_t ini_new(void); extern ini_t ini_read(const char *fn); +extern void ini_strip_quotes(ini_t ini); extern void ini_write(ini_t ini, const char *fn); extern void ini_dump(ini_t ini); extern void ini_close(ini_t ini); @@ -91,7 +92,7 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); -static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); } +static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; } static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); diff --git a/src/ini.c b/src/ini.c index 4ea6f6381..b4c905489 100644 --- a/src/ini.c +++ b/src/ini.c @@ -254,9 +254,8 @@ ini_delete_section_if_empty(ini_t ini, ini_section_t section) static section_t * create_section(list_t *head, const char *name) { - section_t *ns = malloc(sizeof(section_t)); + section_t *ns = calloc(1, sizeof(section_t)); - memset(ns, 0x00, sizeof(section_t)); memcpy(ns->name, name, strlen(name) + 1); list_add(&ns->list, head); @@ -279,9 +278,8 @@ ini_find_or_create_section(ini_t ini, const char *name) static entry_t * create_entry(section_t *section, const char *name) { - entry_t *ne = malloc(sizeof(entry_t)); + entry_t *ne = calloc(1, sizeof(entry_t)); - memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, name, strlen(name) + 1); list_add(&ne->list, §ion->entry_head); @@ -390,11 +388,8 @@ ini_read(const char *fn) if (fp == NULL) return NULL; - head = malloc(sizeof(list_t)); - memset(head, 0x00, sizeof(list_t)); - - sec = malloc(sizeof(section_t)); - memset(sec, 0x00, sizeof(section_t)); + head = calloc(1, sizeof(list_t)); + sec = calloc(1, sizeof(section_t)); list_add(&sec->list, head); if (bom) @@ -475,7 +470,7 @@ ini_read(const char *fn) d = c; /* Allocate a new variable entry.. */ - ne = malloc(sizeof(entry_t)); + ne = calloc(1, sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, ename, 128); wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata) - 1); @@ -551,6 +546,43 @@ ini_write(ini_t ini, const char *fn) (void) fclose(fp); } +void +ini_strip_quotes(ini_t ini) +{ + list_t *list = (list_t *) ini; + section_t *sec; + + sec = (section_t *) list->next; + + while (sec != NULL) { + entry_t *ent; + + ent = (entry_t *) sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + int i = 0; + if (ent->wdata[0] == L'\"') { + memmove(ent->wdata, &ent->wdata[1], sizeof(ent->wdata) - sizeof(wchar_t)); + } + if (ent->wdata[wcslen(ent->wdata) - 1] == L'\"') { + ent->wdata[wcslen(ent->wdata) - 1] = 0; + } + + if (ent->data[0] == '\"') { + memmove(ent->data, &ent->data[1], sizeof(ent->data) - sizeof(char)); + } + if (ent->data[strlen(ent->data) - 1] == '\"') { + ent->data[strlen(ent->data) - 1] = 0; + } + } + + ent = (entry_t *) ent->list.next; + } + + sec = (section_t *) sec->list.next; + } +} + ini_t ini_new(void) { diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 8a06cbe5a..574aae7b7 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -197,6 +197,7 @@ add_library(ui STATIC qt_openglshadermanagerdialog.hpp qt_openglshadermanagerdialog.cpp qt_openglshadermanagerdialog.ui + qt_openglshaderconfig.hpp qt_openglshaderconfig.cpp qt_openglshaderconfig.ui ) if(RTMIDI) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index b1a96a312..f43897506 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -255,6 +255,8 @@ glslp_t *glslp_parse(const char *f) { safe_strncpy(s, t + j, sublen); s[511 < sublen ? 511 : sublen] = 0; + if (s[strlen(s) - 1] == ';') s[strlen(s) - 1] = 0; + struct texture *tex = &glslp->textures[glslp->num_textures++]; strcpy(tex->name, s); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 60e0494fc..7e0cecdeb 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1982,6 +1982,12 @@ MainWindow::changeEvent(QEvent *event) } } +void +MainWindow::reloadAllRenderers() +{ + reload_renderers = true; +} + void MainWindow::on_actionRenderer_options_triggered() { @@ -2000,6 +2006,16 @@ MainWindow::on_actionRenderer_options_triggered() if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions(); } + } else if (reload_renderers && ui->stackedWidget->reloadRendererOption()) { + reload_renderers = false; + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (show_second_monitors) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + } + } + } } } } diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 25e33d77c..dced698bb 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -32,6 +32,7 @@ public: QSize getRenderWidgetSize(); void setSendKeyboardInput(bool enabled); void checkFullscreenHotkey(); + void reloadAllRenderers(); std::array, 8> renderers; signals: @@ -173,6 +174,9 @@ private: bool fs_on_signal = false; bool fs_off_signal = false; + /* Reload the renderers after closing renderer options dialog. */ + bool reload_renderers = false; + friend class SpecifyDimensions; friend class ProgSettings; friend class RendererCommon; diff --git a/src/qt/qt_openglshaderconfig.cpp b/src/qt/qt_openglshaderconfig.cpp new file mode 100644 index 000000000..25f9d38a8 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.cpp @@ -0,0 +1,85 @@ +#include "qt_openglshaderconfig.hpp" +#include "ui_qt_openglshaderconfig.h" + +#include "qt_mainwindow.hpp" + +extern MainWindow* main_window; + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/config.h> +} + +OpenGLShaderConfig::OpenGLShaderConfig(QWidget *parent, glslp_t* shader) + : QDialog(parent) + , ui(new Ui::OpenGLShaderConfig) +{ + ui->setupUi(this); + + currentShader = shader; + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + glslp_read_shader_config(currentShader); + + for (int i = 0; i < currentShader->num_parameters; i++) { + auto spinBox = new QDoubleSpinBox; + spinBox->setObjectName(currentShader->parameters[i].id); + spinBox->setRange(currentShader->parameters[i].min, currentShader->parameters[i].max); + spinBox->setValue(currentShader->parameters[i].value); + spinBox->setSingleStep(currentShader->parameters[i].step); + QFormLayout* layout = (QFormLayout*)ui->scrollAreaWidgetContents->layout(); + layout->addRow(currentShader->parameters[i].description, spinBox); + } +} + +OpenGLShaderConfig::~OpenGLShaderConfig() +{ + delete ui; +} + +void OpenGLShaderConfig::on_buttonBox_clicked(QAbstractButton *button) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) { + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + box->setValue(currentShader->parameters[i].default_value); + } + } + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole) { + startblit(); + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + float val = (float)box->value(); + currentShader->parameters[i].value = val; + } + } + glslp_write_shader_config(currentShader); + config_save(); + endblit(); + main_window->reloadAllRenderers(); + } +} + + +void OpenGLShaderConfig::on_OpenGLShaderConfig_accepted() +{ + startblit(); + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = (QDoubleSpinBox*)this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + float val = (float)box->value(); + currentShader->parameters[i].value = val; + } + } + glslp_write_shader_config(currentShader); + config_save(); + endblit(); + main_window->reloadAllRenderers(); +} + diff --git a/src/qt/qt_openglshaderconfig.hpp b/src/qt/qt_openglshaderconfig.hpp new file mode 100644 index 000000000..f71299d38 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.hpp @@ -0,0 +1,40 @@ +#ifndef QT_OPENGLSHADERCONFIG_HPP +#define QT_OPENGLSHADERCONFIG_HPP + +#include +#include +#include +#include + +#include +#include + +extern "C" +{ +#include <86box/qt-glslp-parser.h> +} + +namespace Ui { +class OpenGLShaderConfig; +} + +class OpenGLShaderConfig : public QDialog { + Q_OBJECT + +public: + explicit OpenGLShaderConfig(QWidget *parent = nullptr, glslp_t* shader = nullptr); + ~OpenGLShaderConfig(); + +private slots: + void on_buttonBox_clicked(QAbstractButton *button); + + void on_OpenGLShaderConfig_accepted(); + +private: + Ui::OpenGLShaderConfig *ui; + glslp_t* currentShader; + + std::map defaultValues; +}; + +#endif // QT_OPENGLSHADERCONFIG_HPP diff --git a/src/qt/qt_openglshaderconfig.ui b/src/qt/qt_openglshaderconfig.ui new file mode 100644 index 000000000..1aebdb6f6 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.ui @@ -0,0 +1,92 @@ + + + OpenGLShaderConfig + + + + 0 + 0 + 400 + 300 + + + + Shader Configuration + + + + QLayout::SizeConstraint::SetMinAndMaxSize + + + + + true + + + + + 0 + 0 + 380 + 250 + + + + + QLayout::SizeConstraint::SetMaximumSize + + + QFormLayout::FieldGrowthPolicy::AllNonFixedFieldsGrow + + + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok|QDialogButtonBox::StandardButton::Reset + + + + + + + + + buttonBox + accepted() + OpenGLShaderConfig + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OpenGLShaderConfig + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 26f206a0e..08cf94fd7 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -1,6 +1,8 @@ #include "qt_openglshadermanagerdialog.hpp" #include "ui_qt_openglshadermanagerdialog.h" +#include "qt_openglshaderconfig.hpp" + #include #include #include @@ -39,10 +41,21 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) } if (ui->shaderListWidget->count()) { ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + auto current = ui->shaderListWidget->currentItem(); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + else + ui->buttonConfigure->setEnabled(false); + } else { + ui->buttonConfigure->setEnabled(false); + } } else { ui->buttonRemove->setDisabled(true); ui->buttonMoveUp->setDisabled(true); ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); } } @@ -84,9 +97,16 @@ void OpenGLShaderManagerDialog::on_shaderListWidget_currentItemChanged(QListWidg ui->buttonRemove->setDisabled(true); ui->buttonMoveUp->setDisabled(true); ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); return; } else { ui->buttonRemove->setDisabled(false); + ui->buttonConfigure->setDisabled(true); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + } } ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); @@ -95,6 +115,22 @@ void OpenGLShaderManagerDialog::on_shaderListWidget_currentItemChanged(QListWidg void OpenGLShaderManagerDialog::on_shaderListWidget_currentRowChanged(int currentRow) { + auto current = ui->shaderListWidget->currentItem(); + if (current == nullptr) { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); + return; + } else { + ui->buttonRemove->setDisabled(false); + ui->buttonConfigure->setDisabled(true); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + } + } ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); } @@ -143,6 +179,8 @@ void OpenGLShaderManagerDialog::on_buttonRemove_clicked() glslp_free((glslp_t*)item->data(Qt::UserRole + 2).toULongLong()); } delete item; + + on_shaderListWidget_currentRowChanged(ui->shaderListWidget->currentRow()); } } @@ -157,3 +195,15 @@ void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() endblit(); } + +void OpenGLShaderManagerDialog::on_buttonConfigure_clicked() +{ + auto item = ui->shaderListWidget->currentItem(); + if (item) { + glslp_t* shader = (glslp_t*)item->data(Qt::UserRole + 2).toULongLong(); + + auto configDialog = new OpenGLShaderConfig(this, shader); + configDialog->exec(); + } +} + diff --git a/src/qt/qt_openglshadermanagerdialog.hpp b/src/qt/qt_openglshadermanagerdialog.hpp index bac0205cf..b8885e3a3 100644 --- a/src/qt/qt_openglshadermanagerdialog.hpp +++ b/src/qt/qt_openglshadermanagerdialog.hpp @@ -33,6 +33,8 @@ private slots: void on_OpenGLShaderManagerDialog_accepted(); + void on_buttonConfigure_clicked(); + private: Ui::OpenGLShaderManagerDialog *ui; }; diff --git a/src/qt/qt_openglshadermanagerdialog.ui b/src/qt/qt_openglshadermanagerdialog.ui index 2888e106f..f68827436 100644 --- a/src/qt/qt_openglshadermanagerdialog.ui +++ b/src/qt/qt_openglshadermanagerdialog.ui @@ -11,7 +11,7 @@ - Dialog + Shader Manager @@ -59,7 +59,7 @@ - false + true Configure From f4479d34854a75777a7717287ac34cff42fd87c1 Mon Sep 17 00:00:00 2001 From: barnacl437 Date: Mon, 10 Mar 2025 01:05:37 +0700 Subject: [PATCH 040/218] some translation fixes for vi-VN lang --- src/qt/languages/vi-VN.po | 122 +++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 15802fc2d..abb17351b 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -682,13 +682,13 @@ msgid "Surface images" msgstr "Ảnh bề mặt" msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." -msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/machines. Hãy chọn mẫu máy khác." +msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/machines. Hãy chọn mẫu máy khác." msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Hãy chọn card đồ họa khác." +msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Hãy chọn card đồ họa khác." +msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." msgid "Machine" msgstr "Mẫu máy" @@ -1216,7 +1216,7 @@ msgid "Development of the WinBox manager stopped in 2022 due to a lack of mainta msgstr "Trình quản lý phiên WinBox đã bị dừng phát triển năm 2022 do thiếu nhân sự duy trì. Vì những quyết định để cho 86Box trở nên tốt hơn, chúng tôi đã không còn hỗ trợ trình quản lý WinBox.\n\n Sẽ không có bản cập nhật mới cho WinBox nữa, và nếu bạn tiếp tục sử dụng với các bản 86Box mới hơn có thể gặp lỗi. Bất kì các bản bug report liên quan đến lỗi của WinBox sẽ bị coi là không hợp lệ và bị đóng.\n\nTruy cập 86Box.net để tìm qua các trình quản lý phiên/manager khác cho phù hợp." msgid "Generate" -msgstr "Phát ra" +msgstr "Tạo" msgid "Joystick configuration" msgstr "Cấu hình cần điều khiển" @@ -1237,7 +1237,7 @@ msgid "List of MCA devices:" msgstr "Danh sách các thiết bị MCA:" msgid "Tablet tool" -msgstr "Công cụ máy tính bảng" +msgstr "Công cụ bảng nhập liệu" msgid "Qt (OpenGL &ES)" msgstr "QT (OpenGL &ES)" @@ -1261,19 +1261,19 @@ msgid "Cursor/Puck" msgstr "Con trỏ/puck" msgid "Pen" -msgstr "Cái bút" +msgstr "Bút" msgid "Host CD/DVD Drive (%1:)" msgstr "Máy chủ CD/DVD ổ đĩa (%1 :)" msgid "&Connected" -msgstr "& Kết nối" +msgstr "&Đã kết nối" msgid "Clear image history" msgstr "Xóa lịch sử ảnh đĩa" msgid "Create..." -msgstr "Tạo nên..." +msgstr "Tạo..." msgid "previous image" msgstr "đĩa trước đó" @@ -1306,7 +1306,7 @@ msgid "OpenGL 3.0 renderer options" msgstr "Tùy chọn kết xuất OpenGL 3.0" msgid "Render behavior" -msgstr "Hiện ra hành vi" +msgstr "Hành vi kết xuất" msgid "Use target framerate:" msgstr "Dùng số khung hình mục tiêu:" @@ -1318,16 +1318,16 @@ msgid "VSync" msgstr "Vsync" msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Kết xuất mỗi khung ngay lập tức, đồng bộ với màn hình mô phỏng.</p><p><span style=" font-style:italic;">Đây là tùy chọn được đề xuất nếu các shader đang sử dụng không sử dụng hình chữ nhật cho các hiệu ứng hoạt hình.</span></p></body></html>" +msgstr "<html><head/><body><p>Kết xuất mỗi khung ngay lập tức, đồng bộ với màn hình mô phỏng.</p><p><span style=" font-style:italic;">Đây là tùy chọn được đề xuất nếu các shader đang sử dụng không tối ưu frametime cho các hiệu ứng động.</span></p></body></html>" msgid "Synchronize with video" -msgstr "Đồng bộ hóa với video" +msgstr "Đồng bộ với video" msgid "Shaders" msgstr "Shaders" msgid "Remove" -msgstr "Di dời" +msgstr "Loại bỏ" msgid "No shader selected" msgstr "Không có shader được chọn" @@ -1360,19 +1360,19 @@ msgid "Error initializing OpenGL" msgstr "Lỗi khởi tạo OpenGL" msgid "Falling back to software rendering.\n" -msgstr "Rơi trở lại kết xuất phần mềm.\n" +msgstr "Quay trở lại kết xuất phần mềm.\n" msgid "Allocating memory for unpack buffer failed.\n" msgstr "Phân bổ bộ nhớ cho bộ đệm giải nén không thành công.\n" msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, FLOPPY, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" +msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, ổ mềm, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" msgid "This machine might have been moved or copied." -msgstr "Máy này có thể đã được di chuyển hoặc sao chép." +msgstr "Cấu hình máy này có thể đã được di chuyển hoặc sao chép." msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." -msgstr "Để đảm bảo chức năng kết nối mạng thích hợp, 86box cần biết liệu máy này có được di chuyển hay sao chép không.\n\nNếu bạn không chắc chắn, chọn \"Tôi đã sao chép nó\"." +msgstr "Để đảm bảo chức năng kết nối mạng thích hợp, 86Box cần biết liệu máy này có được di chuyển hay sao chép không.\n\nNếu bạn không chắc chắn, chọn \"Tôi đã sao chép nó\"." msgid "I Moved It" msgstr "Tôi đã di chuyển nó" @@ -1387,7 +1387,7 @@ msgid "No MCA devices." msgstr "Không có thiết bị MCA." msgid "MiB" -msgstr "Mib" +msgstr "MiB" msgid "Network Card #1" msgstr "Thẻ mạng 1" @@ -1402,7 +1402,7 @@ msgid "Network Card #4" msgstr "Thẻ mạng 4" msgid "Mode" -msgstr "Cách thức" +msgstr "Chế độ" msgid "Interface" msgstr "Giao diện" @@ -1414,7 +1414,7 @@ msgid "VDE Socket" msgstr "Ổ cắm VDE" msgid "86Box Unit Tester" -msgstr "Người kiểm tra đơn vị 86box" +msgstr "Trình kiểm tra đơn vị 86box" msgid "Novell NetWare 2.x Key Card" msgstr "Thẻ khóa Novell Netware 2.x" @@ -1432,7 +1432,7 @@ msgid "Serial port passthrough 4" msgstr "Thông qua cổng serial 4" msgid "Vision Systems LBA Enhancer" -msgstr "Hệ thống tầm nhìn LBA Enhancer" +msgstr "Vision Systems LBA Enhancer" msgid "Renderer options..." msgstr "Tùy chọn kết xuất ..." @@ -1474,7 +1474,7 @@ msgid "Roland CM-32LN Emulation" msgstr "Mô phỏng Roland CM-32LN" msgid "OPL4-ML Daughterboard" -msgstr "Con gái OPL4-ML" +msgstr "Bo mạch con OPL4-ML" msgid "System MIDI" msgstr "MIDI của hệ thống" @@ -1486,7 +1486,7 @@ msgid "BIOS Address" msgstr "Địa chỉ BIOS" msgid "Enable BIOS extension ROM Writes" -msgstr "Bật ROM mở rộng BIOS" +msgstr "Kích hoạt ghi ROM mở rộng BIOS" msgid "Address" msgstr "Địa chỉ" @@ -1513,22 +1513,22 @@ msgid "BIOS size" msgstr "Kích thước BIOS" msgid "Map C0000-C7FFF as UMB" -msgstr "Bản đồ C0000-C7FFF dưới dạng UMB" +msgstr "Map C0000-C7FFF dưới dạng UMB" msgid "Map C8000-CFFFF as UMB" -msgstr "Bản đồ C8000-CFFFF dưới dạng UMB" +msgstr "Map C8000-CFFFF dưới dạng UMB" msgid "Map D0000-D7FFF as UMB" -msgstr "Bản đồ D0000-D7FFF dưới dạng UMB" +msgstr "Map D0000-D7FFF dưới dạng UMB" msgid "Map D8000-DFFFF as UMB" -msgstr "Bản đồ D8000-Dffff dưới dạng UMB" +msgstr "Map D8000-Dffff dưới dạng UMB" msgid "Map E0000-E7FFF as UMB" -msgstr "Bản đồ E0000-E7FFF dưới dạng UMB" +msgstr "Map E0000-E7FFF dưới dạng UMB" msgid "Map E8000-EFFFF as UMB" -msgstr "Bản đồ e8000-effff dưới dạng umb" +msgstr "Map e8000-effff dưới dạng umb" msgid "JS9 Jumper (JIM)" msgstr "JS9 Jumper (Jim)" @@ -1543,13 +1543,13 @@ msgid "MIDI Thru" msgstr "Thông qua đầu vào MIDI" msgid "MIDI Clockout" -msgstr "MIDI đồng hồ" +msgstr "MIDI Clockout" msgid "SoundFont" -msgstr "Soundfont" +msgstr "Font âm thanh" msgid "Output Gain" -msgstr "Đầu ra tăng" +msgstr "Tăng đầu ra" msgid "Chorus" msgstr "Điệp khúc" @@ -1588,7 +1588,7 @@ msgid "Interpolation Method" msgstr "Phương pháp nội suy" msgid "Reverb Output Gain" -msgstr "Gợi ý đầu ra hồi âm" +msgstr "Tăng đầu ra hồi âm" msgid "Reversed stereo" msgstr "Đảo ngược âm thanh nổi" @@ -1609,10 +1609,10 @@ msgid "RTS toggle" msgstr "RT chuyển đổi" msgid "Revision" -msgstr "Ôn tập" +msgstr "Bản sửa đổi" msgid "Controller" -msgstr "Người điều khiển" +msgstr "Bộ điều khiển" msgid "Show Crosshair" msgstr "Hiển thị hình chữ thập" @@ -1624,7 +1624,7 @@ msgid "MAC Address" msgstr "Địa chỉ MAC" msgid "MAC Address OUI" -msgstr " OUI địa chỉ MAC" +msgstr "OUI địa chỉ MAC" msgid "Enable BIOS" msgstr "Bật BIOS" @@ -1696,7 +1696,7 @@ msgid "Enable OPL" msgstr "Bật OPL" msgid "Receive MIDI input (MPU-401)" -msgstr "Nhận nhập MIDI (MPU-401)" +msgstr "Nhận đầu vào MIDI (MPU-401)" msgid "SB low DMA" msgstr "SB DMA thấp" @@ -1708,7 +1708,7 @@ msgid "Enable CMS" msgstr "Bật CMS" msgid "Mixer" -msgstr "Máy trộn" +msgstr "Bộ trộn" msgid "High DMA" msgstr "DMA cao" @@ -1744,13 +1744,13 @@ msgid "RGB type" msgstr "Loại RGB" msgid "Line doubling type" -msgstr "Dòng nhân đôi" +msgstr "Loại dòng kép" msgid "Snow emulation" -msgstr "Đun tuyết" +msgstr "Giả lập hiệu ứng tuyết" msgid "Monitor type" -msgstr "Loại giám sát" +msgstr "Loại màn hình" msgid "Character set" msgstr "Bộ ký tự" @@ -1759,13 +1759,13 @@ msgid "XGA type" msgstr "Loại XGA" msgid "Instance" -msgstr "Ví dụ" +msgstr "Bản chạy" msgid "MMIO Address" msgstr "Địa chỉ MMIO" msgid "RAMDAC type" -msgstr "Loại Ramdac" +msgstr "Loại RAMDAC" msgid "Blend" msgstr "Trộn" @@ -1789,13 +1789,13 @@ msgid "Texture memory size" msgstr "Kích thước bộ nhớ kết cấu" msgid "Dither subtraction" -msgstr "Phân biệt trừ" +msgstr "Giảm ngân tán" msgid "Screen Filter" msgstr "Bộ lọc màn hình" msgid "Render threads" -msgstr "Kết xuất chủ đề" +msgstr "Luồng kết xuất" msgid "SLI" msgstr "SLI" @@ -1810,13 +1810,13 @@ msgid "I/O Width" msgstr "Chiều rộng I/O" msgid "Transfer Speed" -msgstr "Tốc độ chuyển" +msgstr "Tốc độ truyền tải" msgid "EMS mode" msgstr "Chế độ EMS" msgid "Address for > 2 MB" -msgstr "Địa chỉ cho> 2 MB" +msgstr "Địa chỉ cho > 2 MB" msgid "Frame Address" msgstr "Địa chỉ khung" @@ -1831,7 +1831,7 @@ msgid "Always at selected speed" msgstr "Luôn ở tốc độ đã chọn" msgid "BIOS setting + Hotkeys (off during POST)" -msgstr "Cài đặt BIOS + phím nóng (TẮT trong bài đăng)" +msgstr "Cài đặt BIOS + phím nóng (TẮT trong POST)" msgid "64 kB starting from F0000" msgstr "64 kb bắt đầu từ f0000" @@ -1858,7 +1858,7 @@ msgid "Non-timed (original)" msgstr "Không đúng lúc (bản gốc)" msgid "45 Hz (JMP2 not populated)" -msgstr "45 Hz (JMP2 không dân cư)" +msgstr "45 Hz (JMP2 không phổ cập)" msgid "Two" msgstr "Hai" @@ -1867,10 +1867,10 @@ msgid "Three" msgstr "Ba" msgid "Wheel" -msgstr "Bánh xe" +msgstr "Con lăn" msgid "Five + Wheel" -msgstr "Năm + bánh xe" +msgstr "Năm + con lăn" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serial / SMT3(R)V" @@ -2005,7 +2005,7 @@ msgid "Color" msgstr "Màu sắc" msgid "U.S. English" -msgstr "Tiếng Anh Hoa Kỳ" +msgstr "Tiếng Anh Mỹ" msgid "Scandinavian" msgstr "Scandinavia" @@ -2017,13 +2017,13 @@ msgid "Bochs latest" msgstr "Bochs mới nhất" msgid "Mono Non-Interlaced" -msgstr "Đơn sắc không được xen kẽ" +msgstr "Đơn sắc không xen kẽ" msgid "Color Interlaced" msgstr "Màu sắc xen kẽ" msgid "Color Non-Interlaced" -msgstr "Màu sắc không được xen kẽ" +msgstr "Màu sắc không xen kẽ" msgid "3Dfx Voodoo Graphics" msgstr "Đồ họa 3Dfx Voodoo" @@ -2071,7 +2071,7 @@ msgid "Parallel Line Internet Protocol" msgstr "Parallel Line Internet Protocol" msgid "Protection Dongle for Savage Quest" -msgstr "Bảo vệ dongle cho Savage Quest" +msgstr "Dongle bảo vệ cho Savage Quest" msgid "Serial Passthrough Device" msgstr "Thiết bị thông qua cổng serial" @@ -2083,7 +2083,7 @@ msgid "Host Serial Device" msgstr "Thiết bị serial máy chủ" msgid "Name of pipe" -msgstr "Tên của đường ống" +msgstr "Tên đường ống" msgid "Data bits" msgstr "Bit dữ liệu" @@ -2092,10 +2092,10 @@ msgid "Stop bits" msgstr "Dừng bit" msgid "Baud Rate of Passthrough" -msgstr "Tốc độ baud của qua đường" +msgstr "Tốc độ baud của đường thông" msgid "Named Pipe (Server)" -msgstr "Đường ống được đặt tên (máy chủ)" +msgstr "Đường ống có tên (máy chủ)" msgid "Host Serial Passthrough" msgstr "Thông qua cổng serial của máy chủ" @@ -2104,19 +2104,19 @@ msgid "Eject %s" msgstr "Đẩy đĩa ra %s" msgid "&Unmute" -msgstr "&Không quay được" +msgstr "&Mở tiếng" msgid "Softfloat FPU" msgstr "Softfloat FPU" msgid "High performance impact" -msgstr "Tác động cao đến hiệu suất" +msgstr "Ảnh hưởng lớn đến hiệu suất" msgid "RAM Disk (max. speed)" -msgstr "Đĩa RAM (Tối đa. Tốc độ)" +msgstr "Đĩa RAM (tốc độ tối đa)" msgid "IBM 8514/A clone (ISA)" -msgstr "IBM 8514/A dòng vô tính (ISA)" +msgstr "IBM 8514/A bản nhái (ISA)" msgid "Vendor" msgstr "Nhà sản xuất" From ff8b96aaede62c0c4b0dbf39ca3b0341ee3be9b3 Mon Sep 17 00:00:00 2001 From: Barnacl437 Date: Mon, 10 Mar 2025 01:20:25 +0700 Subject: [PATCH 041/218] fixing master branch conflict (vi-VN qt translation) --- src/qt/languages/vi-VN.po | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index abb17351b..6a2203de2 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -687,8 +687,11 @@ msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tươ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Sẽ vô hiệu hóa card đồ họa thứ hai." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Thiết bị \"%hs\" không giả lập được do thiếu file ROM. Thiết bị sẽ bị bỏ qua." msgid "Machine" msgstr "Mẫu máy" From 34023692e15d8075127f16e14ae831f01b038fa0 Mon Sep 17 00:00:00 2001 From: Barnacl437 Date: Mon, 10 Mar 2025 01:24:41 +0700 Subject: [PATCH 042/218] conflict solving attempt #2 --- src/qt/languages/vi-VN.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 6a2203de2..93b800471 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -688,10 +688,10 @@ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Sẽ vô hiệu hóa card đồ họa thứ hai." +msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Vô hiệu hóa card đồ họa thứ hai." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." -msgstr "Thiết bị \"%hs\" không giả lập được do thiếu file ROM. Thiết bị sẽ bị bỏ qua." +msgstr "Thiết bị \"%hs\" không giả lập được do thiếu file ROM. Bỏ qua thiết bị." msgid "Machine" msgstr "Mẫu máy" From e854c5b4318b55898443c706d50b223fe29ef20d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 00:32:57 +0600 Subject: [PATCH 043/218] Some final fixes --- src/qt/qt_glsl_parser.cpp | 8 ++++++++ src/qt/qt_openglrenderer_pcem.cpp | 14 +++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index f43897506..a39e6d7bc 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -1,3 +1,10 @@ +#include "qt_mainwindow.hpp" +#include +#include +#include + +extern MainWindow* main_window; + #include #include #include @@ -137,6 +144,7 @@ static glslp_t *glsl_parse(const char *f) { strcpy(shader->shader_fn, f); shader->shader_program = load_file(f); if (!shader->shader_program) { + QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %s").arg(shader->shader_fn)); //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); glslp_free(glslp); return 0; diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index e53b8b77b..4644dc7be 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -1,6 +1,7 @@ #include "qt_renderercommon.hpp" #include "qt_mainwindow.hpp" +#include #include #include #include @@ -131,6 +132,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -175,6 +177,7 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); pclog("Could not compile shader: %s\n", log); @@ -577,7 +580,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - // wx_simple_messagebox("GLSL Error", "Could not load texture: %s", file); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -623,6 +626,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; @@ -1337,10 +1341,10 @@ OpenGLRendererPCem::render() struct { uint32_t x, y, w, h; } rect, video_rect; - rect.x = destination.x(); - rect.y = destination.y(); - rect.w = destination.width(); - rect.h = destination.height(); + rect.x = 0; + rect.y = 0; + rect.w = source.width(); + rect.h = source.height(); video_rect.x = source.x(); video_rect.y = source.y(); From 1ca2aabf2f5f7e2d4c6e1a466e84b3b959585775 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 00:37:20 +0600 Subject: [PATCH 044/218] Remove some things that shouldn't be there --- src/device/kbc_at_dev.c | 3 --- src/include/86box/keyboard.h | 11 ++--------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index 82ce31bfd..c1041e6e1 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -88,9 +88,6 @@ kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main) { if (main) { kbc_at_dev_log("%s: dev->queue[%02X] = %02X;\n", dev->name, dev->queue_end, val); - if (!is_cpu_thread && kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) { - while (kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) {} - } dev->queue[dev->queue_end] = val; dev->queue_end = (dev->queue_end + 1) & dev->fifo_mask; } else { diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index b7f301a58..3a7260c72 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -22,13 +22,6 @@ #ifndef EMU_KEYBOARD_H #define EMU_KEYBOARD_H -#ifdef __cplusplus -# include -using atomic_uint = std::atomic_uint; -#else -# include -#endif - enum { DEV_KBD = 0, DEV_AUX = 1 @@ -69,8 +62,8 @@ typedef struct atkbc_dev_t { uint8_t rate; uint8_t cmd_queue_start; uint8_t cmd_queue_end; - atomic_uint queue_start; - atomic_uint queue_end; + uint8_t queue_start; + uint8_t queue_end; uint16_t flags; From 4d5907eac6d1955c1b7f7f6da09354f6a81fba3d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 9 Mar 2025 20:32:44 +0100 Subject: [PATCH 045/218] T128 changes of the evening (March 9th, 2025) 1. More accurate speed without stalls. 2. Added more IRQ's for AT compatibles. --- src/scsi/scsi_t128.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 6b73ae131..eada27246 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -95,7 +95,7 @@ t128_write(uint32_t addr, uint8_t val, void *priv) t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), t128->block_loaded); t128->status &= ~0x04; - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); } } } @@ -147,7 +147,7 @@ t128_read(uint32_t addr, void *priv) scsi_bus->tx_mode = PIO_TX_BUS; timer_stop(&t128->timer); } else if (!timer_is_enabled(&t128->timer)) - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); else t128->status &= ~0x04; } @@ -223,7 +223,7 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) t128->block_loaded = 1; t128->status &= ~0x04; - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); } return 1; } @@ -252,7 +252,7 @@ t128_callback(void *priv) uint8_t status; if (scsi_bus->tx_mode != PIO_TX_BUS) - timer_on_auto(&t128->timer, scsi_bus->period / 65.0); + timer_on_auto(&t128->timer, scsi_bus->period / 60.0); if (scsi_bus->data_wait & 1) { scsi_bus->clear_req = 3; @@ -350,6 +350,7 @@ t128_callback(void *priv) if (!t128->block_count) { t128->block_loaded = 0; scsi_bus->bus_out |= BUS_REQ; + timer_on_auto(&t128->timer, 10.0); t128_log("IO End of read transfer\n"); } break; @@ -576,6 +577,10 @@ static const device_config_t t128_config[] = { { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 14", .value = 14 }, + { .description = "IRQ 15", .value = 15 }, { .description = "" } }, .bios = { { 0 } } From 144558e60ec806aa9643645c6774876f19a30430 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 01:33:18 +0600 Subject: [PATCH 046/218] Fix another string mistake --- src/qt/qt_glsl_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index a39e6d7bc..2a4c4ddd1 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -144,7 +144,7 @@ static glslp_t *glsl_parse(const char *f) { strcpy(shader->shader_fn, f); shader->shader_program = load_file(f); if (!shader->shader_program) { - QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %s").arg(shader->shader_fn)); + QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %1").arg(shader->shader_fn)); //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); glslp_free(glslp); return 0; From 9756fa04062c7f4306939860fe49622c22998f98 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 02:00:24 +0600 Subject: [PATCH 047/218] Fix the parser for trailing hash comments --- src/ini.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ini.c b/src/ini.c index b4c905489..8dca54754 100644 --- a/src/ini.c +++ b/src/ini.c @@ -561,6 +561,10 @@ ini_strip_quotes(ini_t ini) while (ent != NULL) { if (ent->name[0] != '\0') { int i = 0; + int trailing_hash = strcspn(ent->data, "#"); + int trailing_quote; + ent->wdata[trailing_hash] = 0; + ent->data[trailing_hash] = 0; if (ent->wdata[0] == L'\"') { memmove(ent->wdata, &ent->wdata[1], sizeof(ent->wdata) - sizeof(wchar_t)); } @@ -574,6 +578,12 @@ ini_strip_quotes(ini_t ini) if (ent->data[strlen(ent->data) - 1] == '\"') { ent->data[strlen(ent->data) - 1] = 0; } + + trailing_quote = strcspn(ent->data, "\""); + ent->wdata[trailing_quote] = 0; + ent->data[trailing_quote] = 0; + + pclog("Section %s, entry %s, value %ls\n", sec->name, ent->name, ent->wdata); } ent = (entry_t *) ent->list.next; From cfe630e5239cd46207649028f2873223ae6224d2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 02:09:40 +0600 Subject: [PATCH 048/218] Temp changes --- src/qt/qt_openglrenderer_pcem.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 4644dc7be..8ee4dff39 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -132,7 +132,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); + throw opengl_init_error_pcem(tr("Program not linked:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -177,10 +177,9 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); - // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); - pclog("Could not compile shader: %s\n", log); + throw opengl_init_error_pcem(tr("Could not compile shader:\n%1").arg(log)); + // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); // pclog("Shader: %s\n", program); free(log); @@ -580,7 +579,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + throw opengl_init_error_pcem(tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -626,7 +625,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); + throw opengl_init_error_pcem(tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; From 29b6cd484cfdd5e2477b33cfc0fe40f3e710aef1 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 6 Jan 2025 21:48:38 -0500 Subject: [PATCH 049/218] Fix a few potential segfaults found in device.c --- src/device.c | 143 ++++++++++++++++++++++++++++----------------------- 1 file changed, 79 insertions(+), 64 deletions(-) diff --git a/src/device.c b/src/device.c index 434bd3776..604f7e2f6 100644 --- a/src/device.c +++ b/src/device.c @@ -660,13 +660,15 @@ device_get_config_string(const char *str) int device_get_config_int(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -675,13 +677,15 @@ device_get_config_int(const char *str) int device_get_config_int_ex(const char *str, int def) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) device_current.name, (char *) str, def)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, def)); - cfg++; + cfg++; + } } return def; @@ -690,13 +694,15 @@ device_get_config_int_ex(const char *str, int def) int device_get_config_hex16(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_hex16((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_hex16((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -705,13 +711,15 @@ device_get_config_hex16(const char *str) int device_get_config_hex20(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_hex20((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_hex20((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -720,13 +728,15 @@ device_get_config_hex20(const char *str) int device_get_config_mac(const char *str, int def) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_mac((char *) device_current.name, (char *) str, def)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_mac((char *) device_current.name, (char *) str, def)); - cfg++; + cfg++; + } } return def; @@ -735,60 +745,68 @@ device_get_config_mac(const char *str, int def) void device_set_config_int(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_int((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_int((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } void device_set_config_hex16(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_hex16((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_hex16((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } void device_set_config_hex20(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_hex20((char *) device_current.name, (char *) str, val); - break; - } + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_hex20((char *) device_current.name, (char *) str, val); + break; + } cfg++; + } } } void device_set_config_mac(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_mac((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_mac((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } @@ -806,20 +824,18 @@ device_is_valid(const device_t *device, int mch) int machine_get_config_int(char *str) { - const device_t *dev = machine_get_device(machine); - const device_config_t *cfg; + const device_t *dev = machine_get_device(machine); - if (dev == NULL) - return 0; + if (dev != NULL) { + const device_config_t *cfg = dev->config; - cfg = dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) dev->name, str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) dev->name, str, cfg->default_int)); - cfg++; + cfg++; + } } - return 0; } @@ -830,9 +846,8 @@ machine_get_config_string(char *str) const char *ret = ""; if (dev != NULL) { - const device_config_t *cfg; + const device_config_t *cfg = dev->config; - cfg = dev->config; while ((cfg != NULL) && (cfg->type != CONFIG_END)) { if (!strcmp(str, cfg->name)) { const char *s = config_get_string((char *) dev->name, str, From a7d8f4a4e1e0808fae91ecc28149d443fc6b54d4 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 6 Jan 2025 23:30:51 -0500 Subject: [PATCH 050/218] Extra CONFIG_BIOS Helpers --- src/device.c | 107 +++++++++++++++++++++++++++++++++++++ src/include/86box/device.h | 9 +++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/device.c b/src/device.c index 604f7e2f6..814320c29 100644 --- a/src/device.c +++ b/src/device.c @@ -429,6 +429,113 @@ device_available(const device_t *dev) return 0; } +uint8_t +device_get_bios_type(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + while (bios->files_no != 0) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->bios_type; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint8_t +device_get_bios_num_files(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + while (bios->files_no != 0) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->files_no; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint32_t +device_get_bios_local(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + while (bios->files_no != 0) { + printf("Internal name was: %s", internal_name); + if (!strcmp(internal_name, bios->internal_name)) + return bios->local; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint32_t +device_get_bios_file_size(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + + /* Go through the ROM's in the device configuration. */ + while (bios->files_no != 0) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->size; + bios++; + } + } + config++; + } + } + } + + return 0; +} + const char * device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) { diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 4cc283a25..c75cbfdcc 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -137,8 +137,8 @@ typedef struct device_config_spinner_t { typedef struct device_config_bios_t { const char *name; const char *internal_name; - int bios_type; - int files_no; + uint8_t bios_type; + uint8_t files_no; uint32_t local; uint32_t size; void *dev1; @@ -211,6 +211,11 @@ extern void device_speed_changed(void); extern void device_force_redraw(void); extern void device_get_name(const device_t *dev, int bus, char *name); extern int device_has_config(const device_t *dev); + +extern uint8_t device_get_bios_type(const device_t *dev, const char *internal_name); +extern uint8_t device_get_bios_num_files(const device_t *dev, const char *internal_name); +extern uint32_t device_get_bios_local(const device_t *dev, const char *internal_name); +extern uint32_t device_get_bios_file_size(const device_t *dev, const char *internal_name); extern const char *device_get_bios_file(const device_t *dev, const char *internal_name, int file_no); extern int device_is_valid(const device_t *, int mch); From 6740b62d23e8443d7a44ebaf2e88bbdf9e3c2f1b Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Mar 2025 01:29:55 -0500 Subject: [PATCH 051/218] Improve empty bios file entry support --- src/device.c | 73 +++++++++++++++++++------------------- src/qt/qt_deviceconfig.cpp | 8 +++-- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/device.c b/src/device.c index 814320c29..e1af3c5f3 100644 --- a/src/device.c +++ b/src/device.c @@ -390,22 +390,21 @@ device_get_priv(const device_t *dev) int device_available(const device_t *dev) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { int roms_present = 0; - - bios = (const device_config_bios_t *) config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { int i = 0; - for (int bf = 0; bf < bios->files_no; bf++) + for (uint8_t bf = 0; bf < bios->files_no; bf++) i += !!rom_present(bios->files[bf]); if (i == bios->files_no) roms_present++; @@ -432,16 +431,16 @@ device_available(const device_t *dev) uint8_t device_get_bios_type(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; - while (bios->files_no != 0) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) return bios->bios_type; bios++; @@ -458,16 +457,16 @@ device_get_bios_type(const device_t *dev, const char *internal_name) uint8_t device_get_bios_num_files(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; - while (bios->files_no != 0) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) return bios->files_no; bios++; @@ -484,16 +483,16 @@ device_get_bios_num_files(const device_t *dev, const char *internal_name) uint32_t device_get_bios_local(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; - while (bios->files_no != 0) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { printf("Internal name was: %s", internal_name); if (!strcmp(internal_name, bios->internal_name)) return bios->local; @@ -511,18 +510,18 @@ device_get_bios_local(const device_t *dev, const char *internal_name) uint32_t device_get_bios_file_size(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) return bios->size; bios++; @@ -539,18 +538,20 @@ device_get_bios_file_size(const device_t *dev, const char *internal_name) const char * device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) { - const device_config_t *config = NULL; const device_config_bios_t *bios = NULL; if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) { if (file_no < bios->files_no) return bios->files[file_no]; diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index e2d6759ad..fff085194 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -242,8 +242,12 @@ DeviceConfig::ProcessConfig(void *dc, const void *c, const bool is_dep) int currentIndex = -1; q = 0; - for (auto *bios = config->bios; (bios != nullptr) && (bios->name != nullptr) && - (strlen(bios->name) > 0); ++bios) { + for (auto *bios = config->bios; (bios != nullptr) && + (bios->name != nullptr) && + (bios->internal_name != nullptr) && + (strlen(bios->name) > 0) && + (strlen(bios->internal_name) > 0) && + (bios->files_no > 0); ++bios) { p = 0; for (int d = 0; d < bios->files_no; d++) p += !!rom_present(const_cast(bios->files[d])); From 4504348fffc8fb3885347c124228fa25d19f6c86 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Mar 2025 01:49:22 -0500 Subject: [PATCH 052/218] Make config_bios_t dev's into an array --- src/include/86box/device.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/include/86box/device.h b/src/include/86box/device.h index c75cbfdcc..fb86d2adc 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -141,8 +141,7 @@ typedef struct device_config_bios_t { uint8_t files_no; uint32_t local; uint32_t size; - void *dev1; - void *dev2; + void *dev[2]; const char *files[9]; } device_config_bios_t; From 097ea4abf2d6220b2951be2996e72e9c528d2d34 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Mar 2025 04:54:42 -0400 Subject: [PATCH 053/218] Two missing CONFIG_END's in qt_deviceconfig.cpp --- src/qt/qt_deviceconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index fff085194..cda52e722 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -123,7 +123,7 @@ DeviceConfig::ProcessConfig(void *dc, const void *c, const bool is_dep) if (config == NULL) return; - while (config->type != -1) { + while (config->type != CONFIG_END) { const int config_type = config->type & CONFIG_TYPE_MASK; /* Ignore options of the wrong class. */ @@ -376,7 +376,7 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se return; config = device->config; - while (config->type != -1) { + while (config->type != CONFIG_END) { switch (config->type) { default: break; From e84bbcac0f9e72613bd9d2d10dbf387e4d91de95 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 7 Mar 2025 21:24:55 +0500 Subject: [PATCH 054/218] Handle libslirp 4.9.0's deprecations --- src/network/net_slirp.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 203428b83..e86ea45fd 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -155,14 +155,22 @@ net_slirp_timer_mod(void *timer, int64_t expire_timer, UNUSED(void *opaque)) } static void +#if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_register_poll_socket(slirp_os_socket fd, void *opaque) +#else net_slirp_register_poll_fd(int fd, void *opaque) +#endif { (void) fd; (void) opaque; } static void +#if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_unregister_poll_socket(slirp_os_socket fd, void *opaque) +#else net_slirp_unregister_poll_fd(int fd, void *opaque) +#endif { (void) fd; (void) opaque; @@ -198,7 +206,11 @@ net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque) #ifdef _WIN32 static int +# if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_add_poll(slirp_os_socket fd, int events, void *opaque) +# else net_slirp_add_poll(int fd, int events, void *opaque) +# endif { net_slirp_t *slirp = (net_slirp_t *) opaque; long bitmask = 0; @@ -216,7 +228,11 @@ net_slirp_add_poll(int fd, int events, void *opaque) } #else static int +# if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_add_poll(slirp_os_socket fd, int events, void *opaque) +# else net_slirp_add_poll(int fd, int events, void *opaque) +# endif { net_slirp_t *slirp = (net_slirp_t *) opaque; @@ -307,8 +323,13 @@ static const SlirpCb slirp_cb = { .timer_new = net_slirp_timer_new, .timer_free = net_slirp_timer_free, .timer_mod = net_slirp_timer_mod, +#if SLIRP_CHECK_VERSION(4, 9, 0) + .register_poll_socket = net_slirp_register_poll_socket, + .unregister_poll_socket = net_slirp_unregister_poll_socket, +#else .register_poll_fd = net_slirp_register_poll_fd, .unregister_poll_fd = net_slirp_unregister_poll_fd, +#endif .notify = net_slirp_notify }; @@ -362,7 +383,11 @@ net_slirp_thread(void *priv) bool run = true; while (run) { uint32_t timeout = -1; +# if SLIRP_CHECK_VERSION(4, 9, 0) + slirp_pollfds_fill_socket(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# else slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# endif if (timeout < 0) timeout = INFINITE; @@ -409,7 +434,11 @@ net_slirp_thread(void *priv) net_slirp_add_poll(net_event_get_fd(&slirp->stop_event), SLIRP_POLL_IN, slirp); net_slirp_add_poll(net_event_get_fd(&slirp->tx_event), SLIRP_POLL_IN, slirp); +# if SLIRP_CHECK_VERSION(4, 9, 0) + slirp_pollfds_fill_socket(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# else slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# endif int ret = poll(slirp->pfd, slirp->pfd_len, timeout); From a29613a88015a5d3648e17ee6b31a92f9af11801 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 7 Mar 2025 22:20:46 +0500 Subject: [PATCH 055/218] Switch to slirp_new --- src/network/net_slirp.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index e86ea45fd..92c4c4ddf 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -489,10 +489,47 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv 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 in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */ + + const SlirpConfig slirp_config = { +#if SLIRP_CHECK_VERSION(4, 9, 0) + .version = 6, +#else + .version = 1, +#endif + .restricted = 0, + .in_enabled = 1, + .vnetwork = net, + .vnetmask = mask, + .vhost = host, + .in6_enabled = 0, + .vprefix_addr6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, /* fec0:: - unused */ + .vprefix_len = 64, + .vhost6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02 } }, /* fec0::2 - unused */ + .vhostname = "86Box", + .tftp_server_name = NULL, + .tftp_path = NULL, + .bootfile = NULL, + .vdhcp_start = dhcp, + .vnameserver = dns, + .vnameserver6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03 } }, /* fec0::3 - unused */ + .vdnssearch = NULL, + .vdomainname = NULL, + .if_mtu = 0, + .if_mru = 0, + .disable_host_loopback = 0, + .enable_emu = 0, +#if SLIRP_CHECK_VERSION(4, 9, 0) + .outbound_addr = NULL, + .outbound_addr6 = NULL, + .disable_dns = 0, + .disable_dhcp = 0, + .mfr_id = 0, + .oob_eth_addr = { 0, 0, 0, 0, 0, 0 } +#endif + }; /* Initialize SLiRP. */ - slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, slirp); + slirp->slirp = slirp_new(&slirp_config, &slirp_cb, slirp); if (!slirp->slirp) { slirp_log("SLiRP: initialization failed\n"); snprintf(netdrv_errbuf, NET_DRV_ERRBUF_SIZE, "SLiRP initialization failed"); From 1005bdddd46125298461e1325dafa054fe7eeac1 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Mar 2025 02:27:02 -0400 Subject: [PATCH 056/218] Fix warning in device.c --- src/device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/device.c b/src/device.c index e1af3c5f3..25f0b55de 100644 --- a/src/device.c +++ b/src/device.c @@ -538,8 +538,6 @@ device_get_bios_file_size(const device_t *dev, const char *internal_name) const char * device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) { - const device_config_bios_t *bios = NULL; - if (dev != NULL) { const device_config_t *config = dev->config; if (config != NULL) { From ba519fa6729fd1721308a77c1a0232c3f876bfb1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 12:37:50 +0600 Subject: [PATCH 057/218] Strip all whitespaces as well --- src/ini.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/ini.c b/src/ini.c index 8dca54754..7a54d5396 100644 --- a/src/ini.c +++ b/src/ini.c @@ -546,6 +546,55 @@ ini_write(ini_t ini, const char *fn) (void) fclose(fp); } +wchar_t * +trim_w(wchar_t *str) +{ + size_t len = 0; + wchar_t *frontp = str; + wchar_t *endp = NULL; + + if (str == NULL) { + return NULL; + } + if (str[0] == L'\0') { + return str; + } + + len = wcslen(str); + endp = str + len; + + /* Move the front and back pointers to address the first non-whitespace + * characters from each end. + */ + while (iswspace((wint_t) *frontp)) { + ++frontp; + } + if (endp != frontp) { + while (iswspace((wint_t) *(--endp)) && endp != frontp) { } + } + + if (frontp != str && endp == frontp) + *str = L'\0'; + else if ((str + len - 1) != endp) + *(endp + 1) = L'\0'; + + /* Shift the string so that it starts at str so that if it's dynamically + * allocated, we can still free it on the returned pointer. Note the reuse + * of endp to mean the front of the string buffer now. + */ + endp = str; + if (frontp != str) { + while (*frontp) { + *endp++ = *frontp++; + } + *endp = L'\0'; + } + + return str; +} + +extern char* trim(char* str); + void ini_strip_quotes(ini_t ini) { @@ -582,8 +631,9 @@ ini_strip_quotes(ini_t ini) trailing_quote = strcspn(ent->data, "\""); ent->wdata[trailing_quote] = 0; ent->data[trailing_quote] = 0; - - pclog("Section %s, entry %s, value %ls\n", sec->name, ent->name, ent->wdata); + + trim_w(ent->wdata); + trim(ent->data); } ent = (entry_t *) ent->list.next; From 1626ee8760ac985680be80feecaa8aada416f81f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 12:38:21 +0600 Subject: [PATCH 058/218] Revert "Temp changes" This reverts commit cfe630e5239cd46207649028f2873223ae6224d2. --- src/qt/qt_openglrenderer_pcem.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 8ee4dff39..4644dc7be 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -132,7 +132,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - throw opengl_init_error_pcem(tr("Program not linked:\n%1").arg(log)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -177,9 +177,10 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - pclog("Could not compile shader: %s\n", log); - throw opengl_init_error_pcem(tr("Could not compile shader:\n%1").arg(log)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); + + pclog("Could not compile shader: %s\n", log); // pclog("Shader: %s\n", program); free(log); @@ -579,7 +580,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - throw opengl_init_error_pcem(tr("Could not load texture: %s").arg(file)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -625,7 +626,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { - throw opengl_init_error_pcem(tr("Could not load shader: %1").arg(shader->shader_fn)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; From dceb13f859d41185597a1e87be24d4b48bf5c283 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 13:27:29 +0600 Subject: [PATCH 059/218] OpenGL error messages are now reported properly --- src/qt/qt_main.cpp | 4 ++++ src/qt/qt_mainwindow.cpp | 12 ++++++++++-- src/qt/qt_mainwindow.hpp | 3 +++ src/qt/qt_openglrenderer_pcem.cpp | 18 +++++++++++------- src/qt/qt_platform.cpp | 5 +++++ 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 9d965be31..b48d272c5 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -90,6 +90,8 @@ extern "C" { #include <86box/timer.h> #include <86box/nvr.h> extern int qt_nvr_save(void); + +bool cpu_thread_running = false; } void qt_set_sequence_auto_mnemonic(bool b); @@ -444,6 +446,7 @@ main_thread_fn() } } + cpu_thread_running = false; is_quit = 1; for (uint8_t i = 1; i < GFXCARD_MAX; i ++) { if (gfxcard[i]) { @@ -736,6 +739,7 @@ main(int argc, char *argv[]) #endif plat_pause(0); + cpu_thread_running = true; main_thread = new std::thread(main_thread_fn); }); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 7e0cecdeb..85bc0de55 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -62,6 +62,8 @@ extern int qt_nvr_save(void); #ifdef MTR_ENABLED # include #endif + +extern bool cpu_thread_running; }; #include @@ -1256,7 +1258,7 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) static auto curdopause = dopause; if (event->type() == QEvent::WindowBlocked) { curdopause = dopause; - plat_pause(1); + plat_pause(isShowMessage ? 2 : 1); emit setMouseCapture(false); } else if (event->type() == QEvent::WindowUnblocked) { plat_pause(curdopause); @@ -1279,7 +1281,11 @@ void MainWindow::showMessage(int flags, const QString &header, const QString &message) { if (QThread::currentThread() == this->thread()) { - showMessage_(flags, header, message); + if (!cpu_thread_running) { + showMessageForNonQtThread(flags, header, message, nullptr); + } + else + showMessage_(flags, header, message); } else { std::atomic_bool done = false; emit showMessageForNonQtThread(flags, header, message, &done); @@ -1295,6 +1301,7 @@ MainWindow::showMessage_(int flags, const QString &header, const QString &messag if (done) { *done = false; } + isShowMessage = true; QMessageBox box(QMessageBox::Warning, header, message, QMessageBox::NoButton, this); if (flags & (MBX_FATAL)) { box.setIcon(QMessageBox::Critical); @@ -1306,6 +1313,7 @@ MainWindow::showMessage_(int flags, const QString &header, const QString &messag if (done) { *done = true; } + isShowMessage = false; if (cpu_thread_run == 0) QApplication::exit(-1); } diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index dced698bb..479ed38a4 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -182,6 +182,9 @@ private: friend class RendererCommon; friend class RendererStack; // For UI variable access by non-primary renderer windows. friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. + + + bool isShowMessage = false; }; #endif // QT_MAINWINDOW_HPP diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 4644dc7be..c8f3d3eb9 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -1,6 +1,8 @@ #include "qt_renderercommon.hpp" #include "qt_mainwindow.hpp" +extern MainWindow* main_window; + #include #include #include @@ -26,6 +28,7 @@ extern "C" { #include <86box/86box.h> #include <86box/plat.h> +#include <86box/ui.h> #include <86box/video.h> #include <86box/path.h> #include <86box/ini.h> @@ -33,6 +36,7 @@ extern "C" { #include <86box/qt-glslp-parser.h> char gl3_shader_file[MAX_USER_SHADERS][512]; +extern bool cpu_thread_running; } #define SCALE_SOURCE 0 @@ -132,7 +136,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -177,7 +181,7 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); pclog("Could not compile shader: %s\n", log); @@ -580,7 +584,8 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + //QMessageBox::critical(main_window, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -626,7 +631,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; @@ -764,8 +769,7 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) #else format.setVersion(3, 2); #endif - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - format.setOption(QSurfaceFormat::DebugContext); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) format.setRenderableType(QSurfaceFormat::OpenGLES); @@ -1031,7 +1035,7 @@ OpenGLRendererPCem::initialize() for (auto &flag : buf_usage) flag.test_and_set(); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); context->doneCurrent(); isFinalized = true; diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 561c94d8a..35dbc0081 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -385,6 +385,7 @@ plat_munmap(void *ptr, size_t size) #endif } +extern bool cpu_thread_running; void plat_pause(int p) { @@ -392,6 +393,10 @@ plat_pause(int p) wchar_t title[1024]; wchar_t paused_msg[512]; + if (!cpu_thread_running && p == 1) { + p = 2; + } + if ((!!p) == dopause) { #ifdef Q_OS_WINDOWS if (source_hwnd) From acf52f702793e610508b2e978c198a7db3f430e0 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 25 Aug 2024 17:55:41 -0400 Subject: [PATCH 060/218] XTIDE Changes --- src/disk/hdc_xtide.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index c18a24c4e..74abc1c4d 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -46,6 +46,7 @@ #include <86box/hdc_ide.h> #include <86box/plat_unused.h> +#define ROM_PATH_TINY "roms/hdd/xtide/ide_tiny.bin" #define ROM_PATH_XT "roms/hdd/xtide/ide_xt.bin" #define ROM_PATH_XTP "roms/hdd/xtide/ide_xtp.bin" #define ROM_PATH_AT "roms/hdd/xtide/ide_at.bin" From e257569e6763a6ba91763e089cd9c8fa64440042 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Feb 2025 23:40:56 -0500 Subject: [PATCH 061/218] Single Channel XTIDE support --- src/disk/hdc.c | 2 ++ src/disk/hdc_xtide.c | 44 ++++++++++++++++++++++++++++++++++++----- src/include/86box/hdc.h | 10 ++++++---- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/disk/hdc.c b/src/disk/hdc.c index f09a9a430..582c33428 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -72,7 +72,9 @@ static const struct { { &ide_isa_device }, { &ide_isa_2ch_device }, { &xtide_at_device }, + { &xtide_at_2ch_device }, { &xtide_at_ps2_device }, + { &xtide_at_ps2_2ch_device }, { &xta_wdxt150_device }, { &xtide_acculogic_device }, { &xtide_device }, diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 74abc1c4d..09e41b9ea 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -157,7 +157,10 @@ xtide_at_init(const device_t *info) device_get_bios_file(info, device_get_config_bios("bios"), 0), 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); - device_add(&ide_isa_2ch_device); + if (info->local == 1) + device_add(&ide_isa_2ch_device); + else + device_add(&ide_isa_device); return xtide; } @@ -203,7 +206,10 @@ xtide_at_ps2_init(UNUSED(const device_t *info)) rom_init(&xtide->bios_rom, ROM_PATH_PS2AT, 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); - device_add(&ide_isa_2ch_device); + if (info->local == 1) + device_add(&ide_isa_2ch_device); + else + device_add(&ide_isa_device); return xtide; } @@ -311,10 +317,24 @@ const device_t xtide_device = { }; const device_t xtide_at_device = { + .name = "PC/AT XTIDE (Primary Only)", + .internal_name = "xtide_at_1ch", + .flags = DEVICE_ISA16, + .local = 0, + .init = xtide_at_init, + .close = xtide_at_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = xtide_at_config +}; + +const device_t xtide_at_2ch_device = { .name = "PC/AT XTIDE", .internal_name = "xtide_at", .flags = DEVICE_ISA16, - .local = 0, + .local = 1, .init = xtide_at_init, .close = xtide_at_close, .reset = NULL, @@ -339,8 +359,8 @@ const device_t xtide_acculogic_device = { }; const device_t xtide_at_ps2_device = { - .name = "PS/2 AT XTIDE (1.1.5)", - .internal_name = "xtide_at_ps2", + .name = "PS/2 AT XTIDE (1.1.5) (Primary Only)", + .internal_name = "xtide_at_ps2_1ch", .flags = DEVICE_ISA16, .local = 0, .init = xtide_at_ps2_init, @@ -351,3 +371,17 @@ const device_t xtide_at_ps2_device = { .force_redraw = NULL, .config = NULL }; + +const device_t xtide_at_ps2_2ch_device = { + .name = "PS/2 AT XTIDE (1.1.5)", + .internal_name = "xtide_at_ps2", + .flags = DEVICE_ISA16, + .local = 1, + .init = xtide_at_ps2_init, + .close = xtide_at_close, + .reset = NULL, + .available = xtide_at_ps2_available, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 7f91fd61b..71f83e5e6 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -99,10 +99,12 @@ extern const device_t mcide_device; extern const device_t xta_wdxt150_device; /* xta_wdxt150 */ extern const device_t xta_hd20_device; /* EuroPC internal */ -extern const device_t xtide_device; /* xtide_xt */ -extern const device_t xtide_at_device; /* xtide_at */ -extern const device_t xtide_acculogic_device; /* xtide_ps2 */ -extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ +extern const device_t xtide_device; /* xtide_xt */ +extern const device_t xtide_at_device; /* xtide_at */ +extern const device_t xtide_at_2ch_device; /* xtide_at_2ch */ +extern const device_t xtide_acculogic_device; /* xtide_ps2 */ +extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ +extern const device_t xtide_at_ps2_2ch_device; /* xtide_at_ps2_2ch */ /* Miscellaneous */ extern const device_t lba_enhancer_device; From b1d68b83e7af9a271440c45826790ed767848ff3 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Feb 2025 01:51:36 -0500 Subject: [PATCH 062/218] Allow Configuration of XTIDE base and bios addr --- src/disk/hdc_xtide.c | 95 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 09e41b9ea..fc18d79db 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -137,11 +137,11 @@ xtide_init(const device_t *info) rom_init(&xtide->bios_rom, device_get_bios_file(info, device_get_config_bios("bios"), 0), - 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + device_get_config_hex20("bios_addr"), 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); xtide->ide_board = ide_xtide_init(); - io_sethandler(0x0300, 16, + io_sethandler(device_get_config_hex16("base"), 16, xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); @@ -228,8 +228,93 @@ xtide_at_close(void *priv) free(xtide); } +// clang-format off static const device_config_t xtide_config[] = { - // clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "200H", .value = 0x200 }, + { .description = "210H", .value = 0x210 }, + { .description = "220H", .value = 0x220 }, + { .description = "230H", .value = 0x230 }, + { .description = "240H", .value = 0x240 }, + { .description = "250H", .value = 0x250 }, + { .description = "260H", .value = 0x260 }, + { .description = "270H", .value = 0x270 }, + { .description = "280H", .value = 0x280 }, + { .description = "290H", .value = 0x290 }, + { .description = "2A0H", .value = 0x2a0 }, + { .description = "2B0H", .value = 0x2b0 }, + { .description = "2C0H", .value = 0x2c0 }, + { .description = "2D0H", .value = 0x2d0 }, + { .description = "2E0H", .value = 0x2e0 }, + { .description = "2F0H", .value = 0x2f0 }, + { .description = "300H", .value = 0x300 }, + { .description = "310H", .value = 0x310 }, + { .description = "320H", .value = 0x320 }, + { .description = "330H", .value = 0x330 }, + { .description = "340H", .value = 0x340 }, + { .description = "350H", .value = 0x350 }, + { .description = "360H", .value = 0x360 }, + { .description = "370H", .value = 0x370 }, + { .description = "380H", .value = 0x380 }, + { .description = "390H", .value = 0x390 }, + { .description = "3A0H", .value = 0x3a0 }, + { .description = "3B0H", .value = 0x3b0 }, + { .description = "3C0H", .value = 0x3c0 }, + { .description = "3D0H", .value = 0x3d0 }, + { .description = "3E0H", .value = 0x3e0 }, + { .description = "3F0H", .value = 0x3f0 }, + { NULL } + }, + .bios = { { 0 } } + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xd0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, +#if 0 + // Supported on XT IDE Deluxe By Monotech + { .description = "C000H", .value = 0xc0000 }, + { .description = "C200H", .value = 0xc2000 }, + { .description = "C400H", .value = 0xc4000 }, + { .description = "C600H", .value = 0xc6000 }, +#endif + { .description = "C800H", .value = 0xc8000 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "CE00H", .value = 0xce000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D200H", .value = 0xd2000 }, + { .description = "D400H", .value = 0xd4000 }, + { .description = "D600H", .value = 0xd6000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DA00H", .value = 0xda000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "DE00H", .value = 0xde000 }, +#if 0 + // Supported on VCFed rev 2 + { .description = "E000H", .value = 0xe0000 }, + { .description = "E400H", .value = 0xe4000 }, + { .description = "E800H", .value = 0xe8000 }, + { .description = "EC00H", .value = 0xec000 }, +#endif + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "bios", .description = "BIOS Revision", @@ -262,11 +347,9 @@ static const device_config_t xtide_config[] = { }, }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on }; static const device_config_t xtide_at_config[] = { - // clang-format off { .name = "bios", .description = "BIOS Revision", @@ -299,8 +382,8 @@ static const device_config_t xtide_at_config[] = { }, }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on }; +// clang-format on const device_t xtide_device = { .name = "PC/XT XTIDE", From 9e95e1e4752dcb3c01335f02d596c9592ffd6af5 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Feb 2025 02:42:19 -0500 Subject: [PATCH 063/218] Move ROM write functions to rom.c --- src/floppy/fdc_monster.c | 51 ---------------------------------------- src/include/86box/rom.h | 5 ++++ src/mem/rom.c | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index 1b0e2fbac..b91d4db66 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -47,57 +47,6 @@ typedef struct monster_fdc_t { char nvr_path[64]; } monster_fdc_t; -static void -rom_write(uint32_t addr, uint8_t val, void *priv) -{ - const rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read byte from BIOS at %06lX\n", addr); -#endif - - if (addr < rom->mapping.base) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - -static void -rom_writew(uint32_t addr, uint16_t val, void *priv) -{ - rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read word from BIOS at %06lX\n", addr); -#endif - - if (addr < (rom->mapping.base - 1)) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - *(uint16_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - -static void -rom_writel(uint32_t addr, uint32_t val, void *priv) -{ - rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read long from BIOS at %06lX\n", addr); -#endif - - if (addr < (rom->mapping.base - 3)) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - *(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - static void monster_fdc_close(void *priv) { diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index 83fd7cf90..331d78526 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -52,7 +52,12 @@ extern uint8_t rom_read(uint32_t addr, void *priv); extern uint16_t rom_readw(uint32_t addr, void *priv); extern uint32_t rom_readl(uint32_t addr, void *priv); +extern void rom_write(uint32_t addr, uint8_t val, void *priv); +extern void rom_writew(uint32_t addr, uint16_t val, void *priv); +extern void rom_writel(uint32_t addr, uint32_t val, void *priv); + extern void rom_get_full_path(char *dest, const char *fn); + extern FILE *rom_fopen(const char *fn, char *mode); extern int rom_getfile(char *fn, char *s, int size); extern int rom_present(const char *fn); diff --git a/src/mem/rom.c b/src/mem/rom.c index 8b2308402..666652d53 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -244,6 +244,57 @@ rom_readl(uint32_t addr, void *priv) return (*(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask]); } +void +rom_write(uint32_t addr, uint8_t val, void *priv) +{ + const rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write byte from BIOS at %06lX\n", addr); +#endif + + if (addr < rom->mapping.base) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + +void +rom_writew(uint32_t addr, uint16_t val, void *priv) +{ + rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write word from BIOS at %06lX\n", addr); +#endif + + if (addr < (rom->mapping.base - 1)) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + *(uint16_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + +void +rom_writel(uint32_t addr, uint32_t val, void *priv) +{ + rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write long from BIOS at %06lX\n", addr); +#endif + + if (addr < (rom->mapping.base - 3)) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + *(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + int rom_load_linear_oddeven(const char *fn, uint32_t addr, int sz, int off, uint8_t *ptr) { From f41f26a6e08d026429fd4c59f324a31557db2426 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Feb 2025 02:43:32 -0500 Subject: [PATCH 064/218] The xtide (XT) ROM is now optionally writable --- src/disk/hdc_xtide.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index fc18d79db..154a28cec 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -41,6 +41,7 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/timer.h> +#include <86box/nvr.h> #include <86box/device.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> @@ -58,6 +59,7 @@ typedef struct xtide_t { void *ide_board; uint8_t data_high; rom_t bios_rom; + char nvr_path[64]; } xtide_t; static void @@ -145,6 +147,18 @@ xtide_init(const device_t *info) xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); + uint8_t rom_writes_enabled = device_get_config_int("rom_writes_enabled"); + + if (rom_writes_enabled) { + mem_mapping_set_write_handler(&xtide->bios_rom.mapping, rom_write, rom_writew, rom_writel); + sprintf(xtide->nvr_path, "xtide_%i.nvr", device_get_instance()); + FILE *fp = nvr_fopen(xtide->nvr_path, "rb"); + if (fp != NULL) { + fread(xtide->bios_rom.rom, 1, 0x2000, fp); + fclose(fp); + } + } + return xtide; } @@ -193,6 +207,14 @@ xtide_close(void *priv) { xtide_t *xtide = (xtide_t *) priv; + if (xtide->nvr_path[0] != 0x00) { + FILE *fp = nvr_fopen(xtide->nvr_path, "wb"); + if (fp != NULL) { + fwrite(xtide->bios_rom.rom, 1, 0x2000, fp); + fclose(fp); + } + } + free(xtide); ide_xtide_close(); @@ -275,6 +297,17 @@ static const device_config_t xtide_config[] = { }, .bios = { { 0 } } }, + { + .name = "rom_writes_enabled", + .description = "Enable BIOS extension ROM Writes", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, { .name = "bios_addr", .description = "BIOS Address", From 837c0d369e4f6ea1613e3ad127b4e1271581cd32 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 21 Feb 2025 13:43:07 -0500 Subject: [PATCH 065/218] A few cleanups in qt_settingssound.cpp --- src/qt/qt_settingssound.cpp | 88 +++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/src/qt/qt_settingssound.cpp b/src/qt/qt_settingssound.cpp index e0572c3d8..cca903076 100644 --- a/src/qt/qt_settingssound.cpp +++ b/src/qt/qt_settingssound.cpp @@ -50,13 +50,15 @@ void SettingsSound::save() { for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); - sound_card_current[i] = cbox->currentData().toInt(); + QComboBox *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); + sound_card_current[i] = cbox->currentData().toInt(); } midi_output_device_current = ui->comboBoxMidiOut->currentData().toInt(); - midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt(); - mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0; + + midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt(); + + mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0; sound_is_float = ui->checkBoxFloat32->isChecked() ? 1 : 0; @@ -74,12 +76,13 @@ SettingsSound::onCurrentMachineChanged(const int machineId) int c; int selectedRow; + // Sound Card for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { - auto * cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); - auto * model = cbox->model(); - const auto removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + QComboBox *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); + c = 0; + auto model = cbox->model(); + auto removeRows = model->rowCount(); + selectedRow = 0; while (true) { /* Skip "internal" if machine doesn't have it or this is not the primary card. */ @@ -88,17 +91,21 @@ SettingsSound::onCurrentMachineChanged(const int machineId) continue; } - auto name = DeviceConfig::DeviceName(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); + const QString name = DeviceConfig::DeviceName(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); if (name.isEmpty()) { break; } - if (sound_card_available(c) && device_is_valid(sound_card_getdevice(c), machineId)) { - int row = Models::AddEntry(model, name, c); - if (c == sound_card_current[i]) { - selectedRow = row - removeRows; + if (sound_card_available(c)) { + const device_t *sound_dev = sound_card_getdevice(c); + if (device_is_valid(sound_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == sound_card_current[i]) { + selectedRow = row - removeRows; + } } } + c++; } @@ -108,12 +115,14 @@ SettingsSound::onCurrentMachineChanged(const int machineId) cbox->setCurrentIndex(selectedRow); } - auto model = ui->comboBoxMidiOut->model(); - auto removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + // Midi Out + c = 0; + auto model = ui->comboBoxMidiOut->model(); + auto removeRows = model->rowCount(); + selectedRow = 0; + while (true) { - QString name = DeviceConfig::DeviceName(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); + const QString name = DeviceConfig::DeviceName(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); if (name.isEmpty()) { break; } @@ -124,19 +133,23 @@ SettingsSound::onCurrentMachineChanged(const int machineId) selectedRow = row - removeRows; } } + c++; } + model->removeRows(0, removeRows); ui->comboBoxMidiOut->setEnabled(model->rowCount() > 0); ui->comboBoxMidiOut->setCurrentIndex(-1); ui->comboBoxMidiOut->setCurrentIndex(selectedRow); + // Midi In + c = 0; model = ui->comboBoxMidiIn->model(); removeRows = model->rowCount(); - c = 0; selectedRow = 0; + while (true) { - QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); + const QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); if (name.isEmpty()) { break; } @@ -150,14 +163,19 @@ SettingsSound::onCurrentMachineChanged(const int machineId) c++; } + model->removeRows(0, removeRows); ui->comboBoxMidiIn->setEnabled(model->rowCount() > 0); ui->comboBoxMidiIn->setCurrentIndex(-1); ui->comboBoxMidiIn->setCurrentIndex(selectedRow); + // Standalone MPU401 ui->checkBoxMPU401->setChecked(mpu401_standalone_enable > 0); + + // Float32 Sound ui->checkBoxFloat32->setChecked(sound_is_float > 0); + // FM Driver switch (fm_driver) { case FM_DRV_YMFM: ui->radioButtonYMFM->setChecked(true); @@ -193,6 +211,7 @@ SettingsSound::on_comboBoxSoundCard1_currentIndexChanged(int index) return; } int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); + if (sndCard == SOUND_INTERNAL) ui->pushButtonConfigureSoundCard1->setEnabled(machine_has_flags(machineId, MACHINE_SOUND) && device_has_config(machine_get_snd_device(machineId))); @@ -203,8 +222,9 @@ SettingsSound::on_comboBoxSoundCard1_currentIndexChanged(int index) void SettingsSound::on_pushButtonConfigureSoundCard1_clicked() { - int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); + auto *device = sound_card_getdevice(sndCard); + if (sndCard == SOUND_INTERNAL) device = machine_get_snd_device(machineId); DeviceConfig::ConfigureDevice(device, 1, qobject_cast(Settings::settings)); @@ -216,15 +236,17 @@ SettingsSound::on_comboBoxSoundCard2_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); + ui->pushButtonConfigureSoundCard2->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard2_clicked() { - int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); DeviceConfig::ConfigureDevice(device, 2, qobject_cast(Settings::settings)); } @@ -234,15 +256,18 @@ SettingsSound::on_comboBoxSoundCard3_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); + ui->pushButtonConfigureSoundCard3->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard3_clicked() { - int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); + DeviceConfig::ConfigureDevice(device, 3, qobject_cast(Settings::settings)); } @@ -252,15 +277,18 @@ SettingsSound::on_comboBoxSoundCard4_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); + ui->pushButtonConfigureSoundCard4->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard4_clicked() { - int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); + DeviceConfig::ConfigureDevice(device, 4, qobject_cast(Settings::settings)); } @@ -270,6 +298,7 @@ SettingsSound::on_comboBoxMidiOut_currentIndexChanged(int index) if (index < 0) { return; } + ui->pushButtonConfigureMidiOut->setEnabled(midi_out_device_has_config(ui->comboBoxMidiOut->currentData().toInt())); ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); @@ -288,6 +317,7 @@ SettingsSound::on_comboBoxMidiIn_currentIndexChanged(int index) if (index < 0) { return; } + ui->pushButtonConfigureMidiIn->setEnabled(midi_in_device_has_config(ui->comboBoxMidiIn->currentData().toInt())); ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); From 727bfc0745d599ad32f04cb055070a929771cd27 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 21 Feb 2025 19:25:03 -0500 Subject: [PATCH 066/218] A few cleanups in qt_settingsstoragecontrollers.cpp --- src/qt/qt_settingsstoragecontrollers.cpp | 47 +++++++++++++----------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index a86362909..4adfe1546 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -52,8 +52,8 @@ void SettingsStorageControllers::save() { /* Storage devices category */ - for (int i = 0; i < SCSI_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + QComboBox *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); scsi_card_current[i] = cbox->currentData().toInt(); } hdc_current[0] = ui->comboBoxHD->currentData().toInt(); @@ -71,10 +71,11 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) this->machineId = machineId; /*HD controller config*/ + int c = 0; auto *model = ui->comboBoxHD->model(); auto removeRows = model->rowCount(); - int c = 0; int selectedRow = 0; + while (true) { /* Skip "internal" if machine doesn't have it. */ if ((c == 1) && (machine_has_flags(machineId, MACHINE_HDC) == 0)) { @@ -88,7 +89,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (hdc_available(c)) { - auto *hdc_dev = hdc_get_device(c); + const device_t *hdc_dev = hdc_get_device(c); if (device_is_valid(hdc_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -124,7 +125,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (fdc_card_available(c)) { - auto *fdc_dev = fdc_card_getdevice(c); + const device_t *fdc_dev = fdc_card_getdevice(c); if (device_is_valid(fdc_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -141,10 +142,11 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxFD->setCurrentIndex(selectedRow); /*CD interface controller config*/ - model = ui->comboBoxCDInterface->model(); - removeRows = model->rowCount(); - c = 0; + c = 0; + model = ui->comboBoxCDInterface->model(); + removeRows = model->rowCount(); selectedRow = 0; + while (true) { /* Skip "internal" if machine doesn't have it. */ QString name = DeviceConfig::DeviceName(cdrom_interface_get_device(c), cdrom_interface_get_internal_name(c), 1); @@ -153,7 +155,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (cdrom_interface_available(c)) { - auto *cdrom_interface_dev = cdrom_interface_get_device(c); + const device_t *cdrom_interface_dev = cdrom_interface_get_device(c); if (device_is_valid(cdrom_interface_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -169,21 +171,21 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxCDInterface->setCurrentIndex(-1); ui->comboBoxCDInterface->setCurrentIndex(selectedRow); - for (int i = 0; i < SCSI_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); - model = cbox->model(); - removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + QComboBox *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); + c = 0; + model = cbox->model(); + removeRows = model->rowCount(); + selectedRow = 0; while (true) { - auto name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); + QString name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); if (name.isEmpty()) { break; } if (scsi_card_available(c)) { - auto *scsi_dev = scsi_card_getdevice(c); + const device_t *scsi_dev = scsi_card_getdevice(c); if (device_is_valid(scsi_dev, machineId)) { int row = Models::AddEntry(model, name, c); if (c == scsi_card_current[i]) { @@ -236,7 +238,8 @@ SettingsStorageControllers::on_comboBoxFD_currentIndexChanged(int index) ui->pushButtonFD->setEnabled(hdc_has_config(ui->comboBoxFD->currentData().toInt()) > 0); } -void SettingsStorageControllers::on_comboBoxCDInterface_currentIndexChanged(int index) +void +SettingsStorageControllers::on_comboBoxCDInterface_currentIndexChanged(int index) { if (index < 0) { return; @@ -346,14 +349,14 @@ SettingsStorageControllers::on_pushButtonSCSI4_clicked() DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI4->currentData().toInt()), 4, qobject_cast(Settings::settings)); } -void SettingsStorageControllers::on_checkBoxLbaEnhancer_stateChanged(int arg1) +void +SettingsStorageControllers::on_checkBoxLbaEnhancer_stateChanged(int arg1) { ui->pushButtonConfigureLbaEnhancer->setEnabled(arg1 != 0); } - -void SettingsStorageControllers::on_pushButtonConfigureLbaEnhancer_clicked() +void +SettingsStorageControllers::on_pushButtonConfigureLbaEnhancer_clicked() { DeviceConfig::ConfigureDevice(&lba_enhancer_device); } - From fc639750ac91c48873219d167934f923bcd90b83 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 21 Feb 2025 20:02:28 -0500 Subject: [PATCH 067/218] Fix three warnings --- src/cdrom/cdrom.c | 2 +- src/scsi/scsi_cdrom.c | 2 +- src/video/vid_ps55da2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 8ebcfea1f..aea1afb94 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -1159,7 +1159,7 @@ cdrom_get_from_name(const char *s) wchar_t tempmsg[2048]; sprintf(n, "WARNING: CD-ROM \"%s\" not found - contact 86Box support\n", s); swprintf(tempmsg, sizeof_w(tempmsg), L"%hs", n); - pclog(n); + pclog("%s", n); ui_msgbox_header(MBX_INFO, plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), tempmsg); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 04c6532df..cc9cc40c1 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -373,7 +373,7 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) if (fp) { if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, fp) != 0x10) log_fatal(dev->log, "scsi_cdrom_mode_sense_load(): Error reading data\n"); - (void) fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, + (void) !fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, fp); fclose(fp); } diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 823ef4d2f..db2035717 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -3101,7 +3101,7 @@ da2_loadfont(char *fname, void *p) } uint32_t j = 0; while (ftell(mfile) < fsize) { - fread(&buf, sizeof(uint8_t), 1, mfile); + (void) !fread(&buf, sizeof(uint8_t), 1, mfile); da2->mmio.font[j] = buf; j++; } From 6b6e7b404b4b6400c3e1fef523a2c8a21e45dfc2 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 5 Jul 2024 19:15:49 -0400 Subject: [PATCH 068/218] Less magic numbers in via_vt82c49x.c --- src/chipset/via_vt82c49x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index 3aaef55a6..f8a5bb593 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -275,8 +275,8 @@ vt82c49x_write(uint16_t addr, uint8_t val, void *priv) case 0x71: if (dev->has_ide) { ide_pri_disable(); - ide_set_base(0, (val & 0x40) ? 0x170 : 0x1f0); - ide_set_side(0, (val & 0x40) ? 0x376 : 0x3f6); + ide_set_base(0, (val & 0x40) ? HDC_SECONDARY_BASE : HDC_PRIMARY_BASE); + ide_set_side(0, (val & 0x40) ? HDC_SECONDARY_SIDE : HDC_PRIMARY_SIDE); if (val & 0x01) ide_pri_enable(); vt82c49x_log("VT82C496 IDE now %sabled as %sary\n", (val & 0x01) ? "en" : "dis", From bb155ea9ef9c575e90f4708c43c9ad0c09005029 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 29 Dec 2023 23:00:13 -0500 Subject: [PATCH 069/218] Cleanups in vid_s3_virge.c --- src/video/vid_s3_virge.c | 1595 +++++++++++++++++++------------------- 1 file changed, 813 insertions(+), 782 deletions(-) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 904d4a4cf..cc0985c02 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -53,10 +53,10 @@ static uint64_t virge_time = 0; static int dither[4][4] = { - {0, 4, 1, 5}, - {6, 2, 7, 3}, - {1, 5, 0, 4}, - {7, 3, 6, 2} + { 0, 4, 1, 5 }, + { 6, 2, 7, 3 }, + { 1, 5, 0, 4 }, + { 7, 3, 6, 2 } }; #define ROM_VIRGE_325 "roms/video/s3virge/86c325.bin" @@ -112,80 +112,80 @@ enum { }; enum { - FIFO_INVALID = (0x00 << 24), - FIFO_WRITE_BYTE = (0x01 << 24), - FIFO_WRITE_WORD = (0x02 << 24), + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), FIFO_WRITE_DWORD = (0x03 << 24) }; typedef struct { - uint32_t addr_type; - uint32_t val; + uint32_t addr_type; + uint32_t val; } fifo_entry_t; typedef struct s3d_t { - uint32_t cmd_set; - int clip_l; - int clip_r; - int clip_t; - int clip_b; + uint32_t cmd_set; + int clip_l; + int clip_r; + int clip_t; + int clip_b; - uint32_t dest_base; - uint32_t dest_str; + uint32_t dest_base; + uint32_t dest_str; - uint32_t z_base; - uint32_t z_str; + uint32_t z_base; + uint32_t z_str; - uint32_t tex_base; - uint32_t tex_bdr_clr; - uint32_t tbv; - uint32_t tbu; - int32_t TdVdX; - int32_t TdUdX; - int32_t TdVdY; - int32_t TdUdY; - uint32_t tus; - uint32_t tvs; + uint32_t tex_base; + uint32_t tex_bdr_clr; + uint32_t tbv; + uint32_t tbu; + int32_t TdVdX; + int32_t TdUdX; + int32_t TdVdY; + int32_t TdUdY; + uint32_t tus; + uint32_t tvs; - int32_t TdZdX; - int32_t TdZdY; - uint32_t tzs; + int32_t TdZdX; + int32_t TdZdY; + uint32_t tzs; - int32_t TdWdX; - int32_t TdWdY; - uint32_t tws; + int32_t TdWdX; + int32_t TdWdY; + uint32_t tws; - int32_t TdDdX; - int32_t TdDdY; - uint32_t tds; + int32_t TdDdX; + int32_t TdDdY; + uint32_t tds; - int16_t TdGdX; - int16_t TdBdX; - int16_t TdRdX; - int16_t TdAdX; - int16_t TdGdY; - int16_t TdBdY; - int16_t TdRdY; - int16_t TdAdY; - uint32_t tgs; - uint32_t tbs; - uint32_t trs; - uint32_t tas; + int16_t TdGdX; + int16_t TdBdX; + int16_t TdRdX; + int16_t TdAdX; + int16_t TdGdY; + int16_t TdBdY; + int16_t TdRdY; + int16_t TdAdY; + uint32_t tgs; + uint32_t tbs; + uint32_t trs; + uint32_t tas; - uint32_t TdXdY12; - uint32_t txend12; - uint32_t TdXdY01; - uint32_t txend01; - uint32_t TdXdY02; - uint32_t txs; - uint32_t tys; - int ty01; - int ty12; - int tlr; + uint32_t TdXdY12; + uint32_t txend12; + uint32_t TdXdY01; + uint32_t txend01; + uint32_t TdXdY02; + uint32_t txs; + uint32_t tys; + int ty01; + int ty12; + int tlr; - uint8_t fog_r; - uint8_t fog_g; - uint8_t fog_b; + uint8_t fog_r; + uint8_t fog_g; + uint8_t fog_b; } s3d_t; typedef struct virge_t { @@ -193,41 +193,41 @@ typedef struct virge_t { mem_mapping_t mmio_mapping; mem_mapping_t new_mmio_mapping; - rom_t bios_rom; + rom_t bios_rom; - svga_t svga; + svga_t svga; - uint8_t bank; - uint8_t ma_ext; + uint8_t bank; + uint8_t ma_ext; - uint8_t virge_id; - uint8_t virge_id_high; - uint8_t virge_id_low; - uint8_t virge_rev; + uint8_t virge_id; + uint8_t virge_id_high; + uint8_t virge_id_low; + uint8_t virge_rev; - uint32_t linear_base; - uint32_t linear_size; + uint32_t linear_base; + uint32_t linear_size; - uint8_t pci_regs[256]; - uint8_t pci_slot; + uint8_t pci_regs[256]; + uint8_t pci_slot; - int chip; + int chip; - int bilinear_enabled; - int dithering_enabled; - int memory_size; + int bilinear_enabled; + int dithering_enabled; + int memory_size; - int pixel_count; - int tri_count; + int pixel_count; + int tri_count; - thread_t * render_thread; - event_t * wake_render_thread; - event_t * wake_main_thread; - event_t * not_full_event; + thread_t *render_thread; + event_t *wake_render_thread; + event_t *wake_main_thread; + event_t *not_full_event; - uint32_t hwc_fg_col; - uint32_t hwc_bg_col; - int hwc_col_stack_pos; + uint32_t hwc_fg_col; + uint32_t hwc_bg_col; + int hwc_col_stack_pos; struct { uint32_t src_base; @@ -260,13 +260,13 @@ typedef struct virge_t { int lycnt; int line_dir; - int src_x; - int src_y; - int dest_x; - int dest_y; - int w; - int h; - uint8_t rop; + int src_x; + int src_y; + int dest_x; + int dest_y; + int w; + int h; + uint8_t rop; int data_left_count; uint32_t data_left; @@ -282,15 +282,16 @@ typedef struct virge_t { uint32_t plxstart; uint32_t pystart; uint32_t pycnt; - uint32_t dest_l, dest_r; + uint32_t dest_l; + uint32_t dest_r; } s3d; - s3d_t s3d_tri; + s3d_t s3d_tri; - s3d_t s3d_buffer[RB_SIZE]; - atomic_int s3d_read_idx; - atomic_int s3d_write_idx; - atomic_int s3d_busy; + s3d_t s3d_buffer[RB_SIZE]; + atomic_int s3d_read_idx; + atomic_int s3d_write_idx; + atomic_int s3d_busy; struct { uint32_t pri_ctrl; @@ -317,88 +318,89 @@ typedef struct virge_t { uint32_t sec_start; uint32_t sec_size; - int sdif; + int sdif; - int pri_x; - int pri_y; - int pri_w; - int pri_h; - int sec_x; - int sec_y; - int sec_w; - int sec_h; + int pri_x; + int pri_y; + int pri_w; + int pri_h; + int sec_x; + int sec_y; + int sec_w; + int sec_h; } streams; fifo_entry_t fifo[FIFO_SIZE]; atomic_int fifo_read_idx, fifo_write_idx; atomic_int fifo_thread_run, render_thread_run; - thread_t * fifo_thread; - event_t *wake_fifo_thread; - event_t * fifo_not_full_event; + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; - atomic_int virge_busy; - atomic_uint irq_pending; + atomic_int virge_busy; + atomic_uint irq_pending; - uint8_t subsys_stat; - uint8_t subsys_cntl; + uint8_t subsys_stat; + uint8_t subsys_cntl; - int local; + int local; - uint8_t serialport; + uint8_t serialport; - uint8_t irq_state; - uint8_t advfunc_cntl; + uint8_t irq_state; + uint8_t advfunc_cntl; - void *i2c, *ddc; + void *i2c, *ddc; - int onboard; - int fifo_slots_num; + int onboard; + int fifo_slots_num; - uint32_t vram_mask; + uint32_t vram_mask; - uint8_t reg6b; - uint8_t lfb_bios; - uint8_t int_line; - uint8_t cmd_dma; + uint8_t reg6b; + uint8_t lfb_bios; + uint8_t int_line; + uint8_t cmd_dma; - uint32_t cmd_dma_base; - uint32_t cmd_dma_buf_size; - uint32_t cmd_dma_buf_size_mask; - uint32_t cmd_base_addr; - uint32_t cmd_dma_write_ptr_reg; - uint32_t cmd_dma_write_ptr_update; - uint32_t cmd_dma_read_ptr_reg; - uint32_t dma_val; - uint32_t dma_dbl_words; - uint32_t dma_mmio_addr; - uint32_t dma_data_type; + uint32_t cmd_dma_base; + uint32_t cmd_dma_buf_size; + uint32_t cmd_dma_buf_size_mask; + uint32_t cmd_base_addr; + uint32_t cmd_dma_write_ptr_reg; + uint32_t cmd_dma_write_ptr_update; + uint32_t cmd_dma_read_ptr_reg; + uint32_t dma_val; + uint32_t dma_dbl_words; + uint32_t dma_mmio_addr; + uint32_t dma_data_type; - int pci; - int is_agp; + int pci; + int is_agp; - pc_timer_t irq_timer; + pc_timer_t irq_timer; } virge_t; static __inline void -wake_fifo_thread(virge_t *virge) { +wake_fifo_thread(virge_t *virge) +{ /* Wake up FIFO thread if moving from idle */ thread_set_event(virge->wake_fifo_thread); } -static virge_t *reset_state = NULL; +static virge_t *reset_state = NULL; static video_timings_t timing_diamond_stealth3d_2000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; static video_timings_t timing_diamond_stealth3d_3000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 4, .read_b = 26, .read_w = 26, .read_l = 42 }; static video_timings_t timing_virge_dx_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; static video_timings_t timing_virge_agp = { .type = VIDEO_AGP, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; -static void queue_triangle(virge_t *virge); +static void queue_triangle(virge_t *virge); -static void s3_virge_recalctimings(svga_t *svga); -static void s3_virge_updatemapping(virge_t *virge); +static void s3_virge_recalctimings(svga_t *svga); +static void s3_virge_updatemapping(virge_t *virge); -static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); static uint8_t s3_virge_mmio_read(uint32_t addr, void *priv); static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *priv); @@ -407,33 +409,33 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv); static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv); static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv); -static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type); +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type); enum { - CMD_SET_AE = 1, - CMD_SET_HC = (1 << 1), + CMD_SET_AE = 1, + CMD_SET_HC = (1 << 1), - CMD_SET_FORMAT_MASK = (7 << 2), - CMD_SET_FORMAT_8 = (0 << 2), - CMD_SET_FORMAT_16 = (1 << 2), - CMD_SET_FORMAT_24 = (2 << 2), + CMD_SET_FORMAT_MASK = (7 << 2), + CMD_SET_FORMAT_8 = (0 << 2), + CMD_SET_FORMAT_16 = (1 << 2), + CMD_SET_FORMAT_24 = (2 << 2), - CMD_SET_MS = (1 << 6), - CMD_SET_IDS = (1 << 7), - CMD_SET_MP = (1 << 8), - CMD_SET_TP = (1 << 9), + CMD_SET_MS = (1 << 6), + CMD_SET_IDS = (1 << 7), + CMD_SET_MP = (1 << 8), + CMD_SET_TP = (1 << 9), - CMD_SET_ITA_MASK = (3 << 10), - CMD_SET_ITA_BYTE = (0 << 10), - CMD_SET_ITA_WORD = (1 << 10), - CMD_SET_ITA_DWORD = (2 << 10), + CMD_SET_ITA_MASK = (3 << 10), + CMD_SET_ITA_BYTE = (0 << 10), + CMD_SET_ITA_WORD = (1 << 10), + CMD_SET_ITA_DWORD = (2 << 10), - CMD_SET_ZUP = (1 << 23), + CMD_SET_ZUP = (1 << 23), - CMD_SET_ZB_MODE = (3 << 24), + CMD_SET_ZB_MODE = (3 << 24), - CMD_SET_XP = (1 << 25), - CMD_SET_YP = (1 << 26), + CMD_SET_XP = (1 << 25), + CMD_SET_YP = (1 << 26), CMD_SET_COMMAND_MASK = (15 << 27) }; @@ -444,11 +446,11 @@ enum { #define CMD_SET_TWE (1 << 26) enum { - CMD_SET_COMMAND_BITBLT = (0 << 27), - CMD_SET_COMMAND_RECTFILL = (2 << 27), - CMD_SET_COMMAND_LINE = (3 << 27), - CMD_SET_COMMAND_POLY = (5 << 27), - CMD_SET_COMMAND_NOP = (15 << 27) + CMD_SET_COMMAND_BITBLT = (0 << 27), + CMD_SET_COMMAND_RECTFILL = (2 << 27), + CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), + CMD_SET_COMMAND_NOP = (15 << 27) }; #define INT_VSY (1 << 0) @@ -475,7 +477,7 @@ s3_virge_update_irqs(virge_t *virge) } static void -s3_virge_update_irq_timer(void* priv) +s3_virge_update_irq_timer(void *priv) { virge_t *virge = (virge_t *) priv; @@ -491,7 +493,7 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *priv) { virge_t *virge = (virge_t *) priv; - svga_t * svga = &virge->svga; + svga_t *svga = &virge->svga; uint8_t old; uint32_t cursoraddr; @@ -538,7 +540,7 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) return; - old = svga->crtc[svga->crtcreg]; + old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; switch (svga->crtcreg) { @@ -622,7 +624,7 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) switch (virge->hwc_col_stack_pos) { case 0: virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val; - break; + break; case 1: virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); break; @@ -705,9 +707,10 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) } static uint8_t -s3_virge_in(uint16_t addr, void *priv) { +s3_virge_in(uint16_t addr, void *priv) +{ virge_t *virge = (virge_t *) priv; - svga_t * svga = &virge->svga; + svga_t *svga = &virge->svga; uint8_t ret; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) @@ -758,7 +761,7 @@ s3_virge_in(uint16_t addr, void *priv) { break; case 0x45: virge->hwc_col_stack_pos = 0; - ret = svga->crtc[0x45]; + ret = svga->crtc[0x45]; break; case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); @@ -812,8 +815,10 @@ s3_virge_in(uint16_t addr, void *priv) { static void s3_virge_recalctimings(svga_t *svga) { - int n, r, m; - double freq; + int n; + int r; + int m; + double freq; virge_t *virge = (virge_t *) svga->priv; svga->hdisp = svga->hdisp_old; @@ -857,7 +862,7 @@ s3_virge_recalctimings(svga_t *svga) else r = (svga->seqregs[0x12] >> 5) & 0x03; - m = svga->seqregs[0x13] & 0x7f; + m = svga->seqregs[0x13] & 0x7f; freq = (((double) m + 2) / (((double) n + 2) * (double) (1 << r))) * 14318184.0; svga->clock = (cpuclock * (float) (1ULL << 32)) / freq; @@ -876,7 +881,7 @@ s3_virge_recalctimings(svga_t *svga) svga->vblankstart = svga->dispend; video_force_resize_set_monitor(1, svga->monitor_index); } else { - svga->hblankstart = (((svga->crtc[0x5d] & 0x04) >> 2) << 8) + svga->crtc[2]; + svga->hblankstart = (((svga->crtc[0x5d] & 0x04) >> 2) << 8) + svga->crtc[2]; svga->hblank_end_val = (svga->crtc[3] & 0x1f) | (((svga->crtc[5] & 0x80) >> 7) << 5) | (((svga->crtc[0x5d] & 0x08) >> 3) << 6); @@ -894,39 +899,39 @@ s3_virge_recalctimings(svga_t *svga) svga->rowoffset = 256; svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); - if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) switch (svga->bpp) { - case 8: - svga->render = svga_render_8bpp_highres; - break; - case 15: - svga->render = svga_render_15bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; - } - break; - case 16: - svga->render = svga_render_16bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; - } - break; - case 24: - svga->render = svga_render_24bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) - svga->rowoffset = (svga->rowoffset * 3) >> 2; /*Hack*/ - break; - case 32: - svga->render = svga_render_32bpp_highres; - break; + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } + break; + case 16: + svga->render = svga_render_16bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } + break; + case 24: + svga->render = svga_render_24bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) + svga->rowoffset = (svga->rowoffset * 3) >> 2; /*Hack*/ + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; - default: - break; - } + default: + break; + } - svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && - (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; + svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; } else { /*Streams mode*/ if (virge->chip < S3_VIRGEGX2) { if (virge->streams.buffer_ctrl & 1) @@ -960,7 +965,7 @@ s3_virge_recalctimings(svga_t *svga) else svga->overlay.addr = virge->streams.sec_fb0; - svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.ena = (svga->overlay.x >= 0); svga->overlay.h_acc = virge->streams.dda_horiz_accumulator; svga->overlay.v_acc = virge->streams.dda_vert_accumulator; @@ -968,8 +973,7 @@ s3_virge_recalctimings(svga_t *svga) svga->rowoffset = virge->streams.pri_stride >> 3; if (virge->chip <= S3_VIRGEDX && svga->overlay.ena) { - svga->overlay.ena = (((virge->streams.blend_ctrl >> 24) & 7) == 0b000) || - (((virge->streams.blend_ctrl >> 24) & 7) == 0b101); + svga->overlay.ena = (((virge->streams.blend_ctrl >> 24) & 7) == 0b000) || (((virge->streams.blend_ctrl >> 24) & 7) == 0b101); } else if (virge->chip >= S3_VIRGEGX2 && svga->overlay.ena) { /* 0x20 = Secondary Stream enabled */ /* 0x2000 = Primary Stream enabled */ @@ -1028,7 +1032,8 @@ s3_virge_recalctimings(svga_t *svga) } static void -s3_virge_updatemapping(virge_t *virge) { +s3_virge_updatemapping(virge_t *virge) +{ svga_t *svga = &virge->svga; if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { @@ -1040,7 +1045,7 @@ s3_virge_updatemapping(virge_t *virge) { } switch (svga->gdcreg[6] & 0xc) { /*Banked framebuffer*/ - case 0x0: /*128k at A0000*/ + case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; break; @@ -1114,7 +1119,8 @@ s3_virge_updatemapping(virge_t *virge) { } static void -s3_virge_vblank_start(svga_t *svga) { +s3_virge_vblank_start(svga_t *svga) +{ virge_t *virge = (virge_t *) svga->priv; if (virge->irq_pending) @@ -1124,7 +1130,8 @@ s3_virge_vblank_start(svga_t *svga) { } static void -s3_virge_wait_fifo_idle(virge_t *virge) { +s3_virge_wait_fifo_idle(virge_t *virge) +{ while (!FIFO_EMPTY) { wake_fifo_thread(virge); thread_wait_event(virge->fifo_not_full_event, 1); @@ -1135,7 +1142,7 @@ static uint8_t s3_virge_mmio_read(uint32_t addr, void *priv) { virge_t *virge = (virge_t *) priv; - uint8_t ret; + uint8_t ret; switch (addr & 0xffff) { case 0x8504: @@ -1216,9 +1223,10 @@ s3_virge_mmio_read_w(uint32_t addr, void *priv) } static uint32_t -s3_virge_mmio_read_l(uint32_t addr, void *priv) { +s3_virge_mmio_read_l(uint32_t addr, void *priv) +{ virge_t *virge = (virge_t *) priv; - uint32_t ret = 0xffffffff; + uint32_t ret = 0xffffffff; switch (addr & 0xfffc) { case 0x8180: @@ -1447,7 +1455,7 @@ s3_virge_mmio_read_l(uint32_t addr, void *priv) { break; } - //pclog("MMIO ReadL=%04x, ret=%08x.\n", addr & 0xfffc, ret); + // pclog("MMIO ReadL=%04x, ret=%08x.\n", addr & 0xfffc, ret); return ret; } @@ -1461,15 +1469,15 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) int y = (addr >> 3) & 7; int color; int byte; - uint32_t newaddr = addr; - virge->s3d.pattern_8[y * 8 + x] = val & 0xff; + uint32_t newaddr = addr; + virge->s3d.pattern_8[y * 8 + x] = val & 0xff; virge->s3d.pattern_8[y * 8 + x + 1] = val >> 8; virge->s3d.pattern_8[y * 8 + x + 2] = val >> 16; virge->s3d.pattern_8[y * 8 + x + 3] = val >> 24; - x = (addr >> 1) & 6; - y = (addr >> 4) & 7; - virge->s3d.pattern_16[y * 8 + x] = val & 0xffff; + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y * 8 + x] = val & 0xffff; virge->s3d.pattern_16[y * 8 + x + 1] = val >> 16; newaddr &= 0x00ff; @@ -1482,22 +1490,21 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.pattern_24[y * 8 + x] |= ((val >> byte) & 0xff) << color; } - x = (addr >> 2) & 7; - y = (addr >> 5) & 7; + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; virge->s3d.pattern_32[y * 8 + x] = val & 0xffffff; - } break; + } + break; case 0xa4d4: case 0xa8d4: case 0xacd4: - virge->s3d.src_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d.src_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xa4d8: case 0xa8d8: case 0xacd8: - virge->s3d.dest_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d.dest_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xa4dc: case 0xa8dc: @@ -1515,7 +1522,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xa8e4: case 0xace4: virge->s3d.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; + virge->s3d.src_str = val & 0xff8; break; case 0xa4e8: case 0xace8: @@ -1548,7 +1555,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) s3_virge_bitblt(virge, -1, 0); break; case 0xa504: - virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_width = (val >> 16) & 0x7ff; virge->s3d.r_height = val & 0x7ff; break; case 0xa508: @@ -1566,7 +1573,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.lxend1 = val & 0x7ff; break; case 0xa970: - virge->s3d.ldx = (int32_t)val; + virge->s3d.ldx = (int32_t) val; break; case 0xa974: virge->s3d.lxstart = val; @@ -1575,7 +1582,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.lystart = val & 0x7ff; break; case 0xa97c: - virge->s3d.lycnt = val & 0x7ff; + virge->s3d.lycnt = val & 0x7ff; virge->s3d.line_dir = val >> 31; if (virge->s3d.cmd_set & CMD_SET_AE) s3_virge_bitblt(virge, -1, 0); @@ -1604,13 +1611,11 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb0d4: case 0xb4d4: - virge->s3d_tri.z_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.z_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb0d8: case 0xb4d8: - virge->s3d_tri.dest_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.dest_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb0dc: case 0xb4dc: @@ -1625,15 +1630,14 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb0e4: case 0xb4e4: virge->s3d_tri.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; + virge->s3d.src_str = val & 0xff8; break; case 0xb0e8: case 0xb4e8: virge->s3d_tri.z_str = val & 0xff8; break; case 0xb4ec: - virge->s3d_tri.tex_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.tex_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb4f0: virge->s3d_tri.tex_bdr_clr = val & 0xffffff; @@ -1750,17 +1754,17 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb57c: virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; virge->s3d_tri.ty12 = val & 0x7ff; - virge->s3d_tri.tlr = val >> 31; + virge->s3d_tri.tlr = val >> 31; if (virge->s3d_tri.cmd_set & CMD_SET_AE) queue_triangle(virge); - break; + break; } } static void fifo_thread(void *param) { - virge_t *virge = (virge_t *)param; + virge_t *virge = (virge_t *) param; while (virge->fifo_thread_run) { thread_set_event(virge->fifo_not_full_event); @@ -1768,10 +1772,10 @@ fifo_thread(void *param) thread_reset_event(virge->wake_fifo_thread); virge->virge_busy = 1; while (!FIFO_EMPTY) { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; + uint64_t start_time = plat_timer_read(); + uint64_t end_time; fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; + uint32_t val = fifo->val; switch (fifo->addr_type & FIFO_TYPE) { case FIFO_WRITE_BYTE: @@ -1811,7 +1815,7 @@ fifo_thread(void *param) virge->virge_busy = 0; virge->subsys_stat |= (INT_FIFO_EMP | INT_3DF_EMP); if (virge->cmd_dma) - virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); + virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); virge->irq_pending++; } @@ -1820,8 +1824,8 @@ fifo_thread(void *param) static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) { - fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; - int limit = 0; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + int limit = 0; if (type == FIFO_WRITE_DWORD) { switch (addr & 0xfffc) { @@ -1848,7 +1852,7 @@ s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) } } - fifo->val = val; + fifo->val = val; fifo->addr_type = (addr & FIFO_ADDR) | type; virge->fifo_write_idx++; @@ -1924,7 +1928,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.chroma_ctrl = val; break; case 0x8190: - virge->streams.sec_ctrl = val; + virge->streams.sec_ctrl = val; virge->streams.dda_horiz_accumulator = val & 0xfff; if (val & 0x1000) virge->streams.dda_horiz_accumulator |= ~0xfff; @@ -1935,7 +1939,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.chroma_upper_bound = val; break; case 0x8198: - virge->streams.sec_filter = val; + virge->streams.sec_filter = val; virge->streams.k1_horiz_scale = val & 0x7ff; if (val & 0x800) virge->streams.k1_horiz_scale |= ~0x7ff; @@ -2015,29 +2019,29 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x81f0: virge->streams.pri_start = val; - virge->streams.pri_x = (val >> 16) & 0x7ff; - virge->streams.pri_y = val & 0x7ff; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81f4: virge->streams.pri_size = val; - virge->streams.pri_w = (val >> 16) & 0x7ff; - virge->streams.pri_h = val & 0x7ff; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81f8: virge->streams.sec_start = val; - virge->streams.sec_x = (val >> 16) & 0x7ff; - virge->streams.sec_y = val & 0x7ff; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81fc: virge->streams.sec_size = val; - virge->streams.sec_w = (val >> 16) & 0x7ff; - virge->streams.sec_h = val & 0x7ff; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; @@ -2054,23 +2058,23 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x8590: - virge->cmd_dma_base = val; - virge->cmd_dma_buf_size = (val & 2) ? 0x10000 : 0x1000; + virge->cmd_dma_base = val; + virge->cmd_dma_buf_size = (val & 2) ? 0x10000 : 0x1000; virge->cmd_dma_buf_size_mask = virge->cmd_dma_buf_size - 1; - virge->cmd_base_addr = (val & 2) ? (val & 0xffff0000) : (val & 0xfffff000); + virge->cmd_base_addr = (val & 2) ? (val & 0xffff0000) : (val & 0xfffff000); break; case 0x8594: virge->cmd_dma_write_ptr_update = val & (1 << 16); if (virge->cmd_dma_write_ptr_update) { virge->cmd_dma_write_ptr_reg = (virge->cmd_dma_buf_size == 0x10000) ? (val & 0xffff) : (val & 0xfff); - virge->dma_dbl_words = 0; - virge->dma_data_type = 0; - virge->dma_val = 0; + virge->dma_dbl_words = 0; + virge->dma_data_type = 0; + virge->dma_val = 0; if (virge->cmd_dma) { while (virge->cmd_dma_read_ptr_reg != virge->cmd_dma_write_ptr_reg) { virge->cmd_dma_write_ptr_update = 0; - dma_bm_read(virge->cmd_base_addr + virge->cmd_dma_read_ptr_reg, (uint8_t *)&virge->dma_val, 4, 4); + dma_bm_read(virge->cmd_base_addr + virge->cmd_dma_read_ptr_reg, (uint8_t *) &virge->dma_val, 4, 4); if (!virge->dma_dbl_words) { virge->dma_dbl_words = (virge->dma_val & 0xffff); virge->dma_data_type = !!(virge->dma_val & (1 << 31)); @@ -2094,9 +2098,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x859c: - virge->cmd_dma = val & 1; + virge->cmd_dma = val & 1; virge->cmd_dma_write_ptr_reg = 0; - virge->cmd_dma_read_ptr_reg = 0; + virge->cmd_dma_read_ptr_reg = 0; break; case 0xff20: @@ -2106,26 +2110,26 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } } -#define READ(addr, val) \ - do { \ - switch (bpp) { \ - case 0: /*8 bpp*/ \ - val = vram[addr & virge->vram_mask]; \ - break; \ - case 1: /*16 bpp*/ \ - val = *(uint16_t *)&vram[addr & virge->vram_mask]; \ - break; \ - case 2: /*24 bpp*/ \ - val = (*(uint32_t *)&vram[addr & virge->vram_mask]) & 0xffffff; \ - break; \ - } \ +#define READ(addr, val) \ + do { \ + switch (bpp) { \ + case 0: /*8 bpp*/ \ + val = vram[addr & virge->vram_mask]; \ + break; \ + case 1: /*16 bpp*/ \ + val = *(uint16_t *) &vram[addr & virge->vram_mask]; \ + break; \ + case 2: /*24 bpp*/ \ + val = (*(uint32_t *) &vram[addr & virge->vram_mask]) & 0xffffff; \ + break; \ + } \ } while (0) -#define Z_READ(addr) *(uint16_t *)&vram[addr & virge->vram_mask] +#define Z_READ(addr) *(uint16_t *) &vram[addr & virge->vram_mask] -#define Z_WRITE(addr, val) \ - if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ - *(uint16_t *)&vram[addr & virge->vram_mask] = val +#define Z_WRITE(addr, val) \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + *(uint16_t *) &vram[addr & virge->vram_mask] = val #define CLIP(x, y) \ do { \ @@ -2174,12 +2178,12 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) else \ Zzb = Zs; \ break; \ - case 5: \ + case 5: \ if (Zs == Zzb) \ update = 0; \ else \ Zzb = Zs; \ - break; \ + break; \ case 6: \ if (Zs > Zzb) \ update = 0; \ @@ -2188,10 +2192,10 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; \ case 7: \ update = 1; \ - Zzb = Zs; \ + Zzb = Zs; \ break; \ } \ - } while (0) + } while (0) #define ROPMIX(R, D, P, S, out) \ { \ @@ -2967,7 +2971,11 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } \ } -#define MIX() do { ROPMIX(virge->s3d.rop & 0xFF, dest, pattern, source, out); out &= 0xFFFFFF; } while (0) +#define MIX() \ + do { \ + ROPMIX(virge->s3d.rop & 0xFF, dest, pattern, source, out); \ + out &= 0xFFFFFF; \ + } while (0) #define WRITE(addr, val) \ do { \ @@ -2994,7 +3002,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) { - uint8_t *vram = virge->svga.vram; + uint8_t *vram = virge->svga.vram; uint32_t mono_pattern[64]; int count_mask; int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1; @@ -3008,33 +3016,33 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) { case CMD_SET_FORMAT_8: - bpp = 0; - x_mul = 1; + bpp = 0; + x_mul = 1; cpu_dat_shift = 8; - pattern_data = virge->s3d.pattern_8; - src_fg_clr = virge->s3d.src_fg_clr & 0xff; - src_bg_clr = virge->s3d.src_bg_clr & 0xff; + pattern_data = virge->s3d.pattern_8; + src_fg_clr = virge->s3d.src_fg_clr & 0xff; + src_bg_clr = virge->s3d.src_bg_clr & 0xff; break; case CMD_SET_FORMAT_16: - bpp = 1; - x_mul = 2; + bpp = 1; + x_mul = 2; cpu_dat_shift = 16; - pattern_data = virge->s3d.pattern_16; - src_fg_clr = virge->s3d.src_fg_clr & 0xffff; - src_bg_clr = virge->s3d.src_bg_clr & 0xffff; + pattern_data = virge->s3d.pattern_16; + src_fg_clr = virge->s3d.src_fg_clr & 0xffff; + src_bg_clr = virge->s3d.src_bg_clr & 0xffff; break; case CMD_SET_FORMAT_24: default: - bpp = 2; - x_mul = 3; + bpp = 2; + x_mul = 3; cpu_dat_shift = 24; - pattern_data = virge->s3d.pattern_24; - src_fg_clr = virge->s3d.src_fg_clr; - src_bg_clr = virge->s3d.src_bg_clr; + pattern_data = virge->s3d.pattern_24; + src_fg_clr = virge->s3d.src_fg_clr; + src_bg_clr = virge->s3d.src_bg_clr; break; - } - if (virge->s3d.cmd_set & CMD_SET_MP) - pattern_data = mono_pattern; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + pattern_data = mono_pattern; switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) { case CMD_SET_ITA_BYTE: @@ -3052,16 +3060,16 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) int x; int y; for (y = 0; y < 4; y++) { - for (x = 0; x < 8; x++) { - if (virge->s3d.mono_pat_0 & (1 << (x + y * 8))) - mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_fg_clr; - else - mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_bg_clr; - if (virge->s3d.mono_pat_1 & (1 << (x + y * 8))) - mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_fg_clr; - else - mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_bg_clr; - } + for (x = 0; x < 8; x++) { + if (virge->s3d.mono_pat_0 & (1 << (x + y * 8))) + mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_fg_clr; + else + mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_bg_clr; + if (virge->s3d.mono_pat_1 & (1 << (x + y * 8))) + mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_fg_clr; + else + mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_bg_clr; + } } } switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) { @@ -3070,13 +3078,13 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) case CMD_SET_COMMAND_BITBLT: if (count == -1) { - virge->s3d.src_x = virge->s3d.rsrc_x; - virge->s3d.src_y = virge->s3d.rsrc_y; - virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.dest_y = virge->s3d.rdest_y; - virge->s3d.w = virge->s3d.r_width; - virge->s3d.h = virge->s3d.r_height; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; virge->s3d.data_left_count = 0; if (virge->s3d.cmd_set & CMD_SET_IDS) @@ -3092,8 +3100,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t source = 0; uint32_t dest = 0; uint32_t pattern; - uint32_t out = 0; - int update = 1; + uint32_t out = 0; + int update = 1; switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) { case 0: @@ -3111,18 +3119,18 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) count -= (cpu_dat_shift - virge->s3d.data_left_count); virge->s3d.data_left_count = 0; if (count < cpu_dat_shift) { - virge->s3d.data_left = cpu_dat; + virge->s3d.data_left = cpu_dat; virge->s3d.data_left_count = count; - count = 0; + count = 0; } } else { source = cpu_dat; cpu_dat >>= cpu_dat_shift; count -= cpu_dat_shift; if (count < cpu_dat_shift) { - virge->s3d.data_left = cpu_dat; + virge->s3d.data_left = cpu_dat; virge->s3d.data_left_count = count; - count = 0; + count = 0; } } if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) @@ -3152,9 +3160,9 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.dest_x += x_inc; virge->s3d.dest_x &= 0x7ff; if (!virge->s3d.w) { - virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_x = virge->s3d.rsrc_x; virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.w = virge->s3d.r_width; + virge->s3d.w = virge->s3d.r_width; virge->s3d.src_y += y_inc; virge->s3d.dest_y += y_inc; @@ -3182,23 +3190,22 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) case CMD_SET_COMMAND_RECTFILL: /*No source, pattern = pat_fg_clr*/ if (count == -1) { - virge->s3d.src_x = virge->s3d.rsrc_x; - virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; virge->s3d.dest_x = virge->s3d.rdest_x; virge->s3d.dest_y = virge->s3d.rdest_y; - virge->s3d.w = virge->s3d.r_width; - virge->s3d.h = virge->s3d.r_height; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; } while (count && virge->s3d.h) { - uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + - (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); uint32_t source = 0; uint32_t dest = 0; uint32_t pattern = virge->s3d.pat_fg_clr; uint32_t out = 0; - int update = 1; + int update = 1; CLIP(virge->s3d.dest_x, virge->s3d.dest_y); @@ -3215,9 +3222,9 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.dest_x += x_inc; virge->s3d.dest_x &= 0x7ff; if (!virge->s3d.w) { - virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_x = virge->s3d.rsrc_x; virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.w = virge->s3d.r_width; + virge->s3d.w = virge->s3d.r_width; virge->s3d.src_y += y_inc; virge->s3d.dest_y += y_inc; @@ -3225,7 +3232,7 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) if (!virge->s3d.h) return; } else - virge->s3d.w--; + virge->s3d.w--; count--; } break; @@ -3234,8 +3241,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) if (count == -1) { virge->s3d.dest_x = virge->s3d.lxstart; virge->s3d.dest_y = virge->s3d.lystart; - virge->s3d.h = virge->s3d.lycnt; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.h = virge->s3d.lycnt; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; } while (virge->s3d.h) { int x; @@ -3262,8 +3269,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t source = 0; uint32_t dest = 0; uint32_t pattern; - uint32_t out = 0; - int update = 1; + uint32_t out = 0; + int update = 1; if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && ((virge->s3d.line_dir && x < virge->s3d.lxend0) || @@ -3306,39 +3313,39 @@ skip_line: virge->s3d.dest_r = virge->s3d.prxstart; if (virge->s3d.pycnt & (1 << 29)) virge->s3d.dest_l = virge->s3d.plxstart; - virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; while (virge->s3d.h) { - int x = virge->s3d.dest_l >> 20; - int xend = virge->s3d.dest_r >> 20; - int y = virge->s3d.pystart & 0x7ff; - int xdir = (x < xend) ? 1 : -1; - do { - uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); - uint32_t source = 0; - uint32_t dest = 0; - uint32_t pattern; - uint32_t out = 0; - int update = 1; + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + do { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0; + uint32_t dest = 0; + uint32_t pattern; + uint32_t out = 0; + int update = 1; - CLIP(x, y); + CLIP(x, y); - if (update) { - READ(dest_addr, dest); - pattern = pattern_data[(y & 7) * 8 + (x & 7)]; + if (update) { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7) * 8 + (x & 7)]; - MIX(); + MIX(); - WRITE(dest_addr, out); - } + WRITE(dest_addr, out); + } - x = (x + xdir) & 0x7ff; - } while (x != (xend + xdir)); + x = (x + xdir) & 0x7ff; + } while (x != (xend + xdir)); - virge->s3d.dest_l += virge->s3d.pldx; - virge->s3d.dest_r += virge->s3d.prdx; - virge->s3d.h--; - virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; } break; @@ -3375,54 +3382,57 @@ skip_line: #define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) typedef struct rgba_t { - int r, g, b, a; + int r; + int g; + int b; + int a; } rgba_t; typedef struct s3d_state_t { - int32_t r; - int32_t g; - int32_t b; - int32_t a; - int32_t u; - int32_t v; - int32_t d; - int32_t w; + int32_t r; + int32_t g; + int32_t b; + int32_t a; + int32_t u; + int32_t v; + int32_t d; + int32_t w; - int32_t base_r; - int32_t base_g; - int32_t base_b; - int32_t base_a; - int32_t base_u; - int32_t base_v; - int32_t base_d; - int32_t base_w; + int32_t base_r; + int32_t base_g; + int32_t base_b; + int32_t base_a; + int32_t base_u; + int32_t base_v; + int32_t base_d; + int32_t base_w; - uint32_t base_z; + uint32_t base_z; - uint32_t tbu; - uint32_t tbv; + uint32_t tbu; + uint32_t tbv; - uint32_t cmd_set; - int max_d; + uint32_t cmd_set; + int max_d; uint16_t *texture[10]; - uint32_t tex_bdr_clr; + uint32_t tex_bdr_clr; - int32_t x1; - int32_t x2; + int32_t x1; + int32_t x2; - int y; + int y; - rgba_t dest_rgba; + rgba_t dest_rgba; } s3d_state_t; typedef struct s3d_texture_state_t { - int level; - int texture_shift; + int level; + int texture_shift; - int32_t u; - int32_t v; + int32_t u; + int32_t v; } s3d_texture_state_t; static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out); @@ -3436,7 +3446,8 @@ static int _x; static int _y; static void -tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3448,7 +3459,8 @@ tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3463,7 +3475,8 @@ tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3475,7 +3488,8 @@ tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3490,7 +3504,8 @@ tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; @@ -3502,7 +3517,8 @@ tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; @@ -3517,19 +3533,21 @@ tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_sample_normal(s3d_state_t *state) { +tex_sample_normal(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = state->u + state->tbu; - texture_state.v = state->v + state->tbv; + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_normal_filter(s3d_state_t *state) { +tex_sample_normal_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; int tex_offset; rgba_t tex_samples[4]; @@ -3537,9 +3555,9 @@ tex_sample_normal_filter(s3d_state_t *state) { int dv; int d[4]; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = state->u + state->tbu; texture_state.v = state->v + state->tbv; @@ -3575,21 +3593,23 @@ tex_sample_normal_filter(s3d_state_t *state) { } static void -tex_sample_mipmap(s3d_state_t *state) { +tex_sample_mipmap(s3d_state_t *state) +{ s3d_texture_state_t texture_state; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = state->u + state->tbu; - texture_state.v = state->v + state->tbv; + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_mipmap_filter(s3d_state_t *state) { +tex_sample_mipmap_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; int tex_offset; rgba_t tex_samples[4]; @@ -3601,7 +3621,7 @@ tex_sample_mipmap_filter(s3d_state_t *state) { if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = state->u + state->tbu; texture_state.v = state->v + state->tbv; @@ -3637,25 +3657,27 @@ tex_sample_mipmap_filter(s3d_state_t *state) { } static void -tex_sample_persp_normal(s3d_state_t *state) { +tex_sample_persp_normal(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_normal_filter(s3d_state_t *state) { +tex_sample_persp_normal_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3665,14 +3687,14 @@ tex_sample_persp_normal_filter(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3708,25 +3730,27 @@ tex_sample_persp_normal_filter(s3d_state_t *state) { } static void -tex_sample_persp_normal_375(s3d_state_t *state) { +tex_sample_persp_normal_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_normal_filter_375(s3d_state_t *state) { +tex_sample_persp_normal_filter_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3736,14 +3760,14 @@ tex_sample_persp_normal_filter_375(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3779,27 +3803,29 @@ tex_sample_persp_normal_filter_375(s3d_state_t *state) { } static void -tex_sample_persp_mipmap(s3d_state_t *state) { +tex_sample_persp_mipmap(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_mipmap_filter(s3d_state_t *state) { +tex_sample_persp_mipmap_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3809,16 +3835,16 @@ tex_sample_persp_mipmap_filter(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3854,27 +3880,29 @@ tex_sample_persp_mipmap_filter(s3d_state_t *state) { } static void -tex_sample_persp_mipmap_375(s3d_state_t *state) { +tex_sample_persp_mipmap_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { +tex_sample_persp_mipmap_filter_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3884,16 +3912,16 @@ tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3928,40 +3956,41 @@ tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; } -#define CLAMP(x) \ - do { \ - if ((x) & ~0xff) \ - x = ((x) < 0) ? 0 : 0xff; \ +#define CLAMP(x) \ + do { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ } while (0) -#define CLAMP_RGBA(r, g, b, a) \ - if ((r) & ~0xff) \ - r = ((r) < 0) ? 0 : 0xff; \ - if ((g) & ~0xff) \ - g = ((g) < 0) ? 0 : 0xff; \ - if ((b) & ~0xff) \ - b = ((b) < 0) ? 0 : 0xff; \ - if ((a) & ~0xff) \ - a = ((a) < 0) ? 0 : 0xff; +#define CLAMP_RGBA(r, g, b, a) \ + if ((r) & ~0xff) \ + r = ((r) < 0) ? 0 : 0xff; \ + if ((g) & ~0xff) \ + g = ((g) < 0) ? 0 : 0xff; \ + if ((b) & ~0xff) \ + b = ((b) < 0) ? 0 : 0xff; \ + if ((a) & ~0xff) \ + a = ((a) < 0) ? 0 : 0xff; -#define CLAMP_RGB(r, g, b) \ - do { \ - if ((r) < 0) \ - r = 0; \ - if ((r) > 0xff) \ - r = 0xff; \ - if ((g) < 0) \ - g = 0; \ - if ((g) > 0xff) \ - g = 0xff; \ - if ((b) < 0) \ - b = 0; \ - if ((b) > 0xff) \ - b = 0xff; \ +#define CLAMP_RGB(r, g, b) \ + do { \ + if ((r) < 0) \ + r = 0; \ + if ((r) > 0xff) \ + r = 0xff; \ + if ((g) < 0) \ + g = 0; \ + if ((g) > 0xff) \ + g = 0xff; \ + if ((b) < 0) \ + b = 0; \ + if ((b) > 0xff) \ + b = 0xff; \ } while (0) static void -dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) { +dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) +{ state->dest_rgba.r = state->r >> 7; CLAMP(state->dest_rgba.r); @@ -3976,7 +4005,8 @@ dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) { } static void -dest_pixel_unlit_texture_triangle(s3d_state_t *state) { +dest_pixel_unlit_texture_triangle(s3d_state_t *state) +{ tex_sample(state); if (state->cmd_set & CMD_SET_ABC_SRC) @@ -3984,7 +4014,8 @@ dest_pixel_unlit_texture_triangle(s3d_state_t *state) { } static void -dest_pixel_lit_texture_decal(s3d_state_t *state) { +dest_pixel_lit_texture_decal(s3d_state_t *state) +{ tex_sample(state); if (state->cmd_set & CMD_SET_ABC_SRC) @@ -3992,7 +4023,8 @@ dest_pixel_lit_texture_decal(s3d_state_t *state) { } static void -dest_pixel_lit_texture_reflection(s3d_state_t *state) { +dest_pixel_lit_texture_reflection(s3d_state_t *state) +{ tex_sample(state); state->dest_rgba.r += (state->r >> 7); @@ -4005,7 +4037,8 @@ dest_pixel_lit_texture_reflection(s3d_state_t *state) { } static void -dest_pixel_lit_texture_modulate(s3d_state_t *state) { +dest_pixel_lit_texture_modulate(s3d_state_t *state) +{ int r = state->r >> 7; int g = state->g >> 7; int b = state->b >> 7; @@ -4024,17 +4057,18 @@ dest_pixel_lit_texture_modulate(s3d_state_t *state) { } static void -tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) { - uint8_t *vram = virge->svga.vram; - int x_dir = s3d_tri->tlr ? 1 : -1; - int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); - int y_count = yc; - int bpp = (s3d_tri->cmd_set >> 2) & 7; - uint32_t dest_offset; - uint32_t z_offset; +tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) +{ + uint8_t *vram = virge->svga.vram; + int x_dir = s3d_tri->tlr ? 1 : -1; + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); + int y_count = yc; + int bpp = (s3d_tri->cmd_set >> 2) & 7; + uint32_t dest_offset; + uint32_t z_offset; dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); - z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); + z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); if (s3d_tri->cmd_set & CMD_SET_HC) { if (state->y < s3d_tri->clip_t) @@ -4054,195 +4088,190 @@ tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int state->base_a += (s3d_tri->TdAdY * diff_y); state->base_d += (s3d_tri->TdDdY * diff_y); state->base_w += (s3d_tri->TdWdY * diff_y); - state->x1 += (dx1 * diff_y); - state->x2 += (dx2 * diff_y); - state->y -= diff_y; - dest_offset -= s3d_tri->dest_str; - z_offset -= s3d_tri->z_str; - y_count -= diff_y; + state->x1 += (dx1 * diff_y); + state->x2 += (dx2 * diff_y); + state->y -= diff_y; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + y_count -= diff_y; } if ((state->y - y_count) < s3d_tri->clip_t) y_count = (state->y - s3d_tri->clip_t) + 1; } for (; y_count > 0; y_count--) { - int x = (state->x1 + ((1 << 20) - 1)) >> 20; - int xe = (state->x2 + ((1 << 20) - 1)) >> 20; - uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; + int x = (state->x1 + ((1 << 20) - 1)) >> 20; + int xe = (state->x2 + ((1 << 20) - 1)) >> 20; + uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; - if (x_dir < 0) { - x--; - xe--; - } + if (x_dir < 0) { + x--; + xe--; + } - if (x != xe && ((x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))) { - uint32_t dest_addr; - uint32_t z_addr; - int dx = (x_dir > 0) ? ((31 - ((state->x1 - 1) >> 15)) & 0x1f) : - (((state->x1 - 1) >> 15) & 0x1f); - int x_offset = x_dir * (bpp + 1); - int xz_offset = x_dir << 1; + if (x != xe && ((x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))) { + uint32_t dest_addr; + uint32_t z_addr; + int dx = (x_dir > 0) ? ((31 - ((state->x1 - 1) >> 15)) & 0x1f) : (((state->x1 - 1) >> 15) & 0x1f); + int x_offset = x_dir * (bpp + 1); + int xz_offset = x_dir << 1; - if (x_dir > 0) - dx += 1; + if (x_dir > 0) + dx += 1; - state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); - state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); - state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); - state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); - state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); - state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); - state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); - state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); - z += ((s3d_tri->TdZdX * dx) >> 5); + state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); + state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); + state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); + state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); + state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); + state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); + state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); + state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); + z += ((s3d_tri->TdZdX * dx) >> 5); - if (s3d_tri->cmd_set & CMD_SET_HC) { - if (x_dir > 0) { - if (x > s3d_tri->clip_r) - goto tri_skip_line; - if (xe < s3d_tri->clip_l) - goto tri_skip_line; - if (xe > s3d_tri->clip_r) - xe = s3d_tri->clip_r + 1; - if (x < s3d_tri->clip_l) { - int diff_x = s3d_tri->clip_l - x; + if (s3d_tri->cmd_set & CMD_SET_HC) { + if (x_dir > 0) { + if (x > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + xe = s3d_tri->clip_r + 1; + if (x < s3d_tri->clip_l) { + int diff_x = s3d_tri->clip_l - x; - z += (s3d_tri->TdZdX * diff_x); - state->u += (s3d_tri->TdUdX * diff_x); - state->v += (s3d_tri->TdVdX * diff_x); - state->r += (s3d_tri->TdRdX * diff_x); - state->g += (s3d_tri->TdGdX * diff_x); - state->b += (s3d_tri->TdBdX * diff_x); - state->a += (s3d_tri->TdAdX * diff_x); - state->d += (s3d_tri->TdDdX * diff_x); - state->w += (s3d_tri->TdWdX * diff_x); + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); - x = s3d_tri->clip_l; - } - } else { - if (x < s3d_tri->clip_l) - goto tri_skip_line; - if (xe > s3d_tri->clip_r) - goto tri_skip_line; - if (xe < s3d_tri->clip_l) - xe = s3d_tri->clip_l - 1; - if (x > s3d_tri->clip_r) { - int diff_x = x - s3d_tri->clip_r; + x = s3d_tri->clip_l; + } + } else { + if (x < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + xe = s3d_tri->clip_l - 1; + if (x > s3d_tri->clip_r) { + int diff_x = x - s3d_tri->clip_r; - z += (s3d_tri->TdZdX * diff_x); - state->u += (s3d_tri->TdUdX * diff_x); - state->v += (s3d_tri->TdVdX * diff_x); - state->r += (s3d_tri->TdRdX * diff_x); - state->g += (s3d_tri->TdGdX * diff_x); - state->b += (s3d_tri->TdBdX * diff_x); - state->a += (s3d_tri->TdAdX * diff_x); - state->d += (s3d_tri->TdDdX * diff_x); - state->w += (s3d_tri->TdWdX * diff_x); + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); - x = s3d_tri->clip_r; - } - } - } + x = s3d_tri->clip_r; + } + } + } - virge->svga.changedvram[(dest_offset & virge->vram_mask) >> 12] = changeframecount; + virge->svga.changedvram[(dest_offset & virge->vram_mask) >> 12] = changeframecount; - dest_addr = dest_offset + (x * (bpp + 1)); - z_addr = z_offset + (x << 1); + dest_addr = dest_offset + (x * (bpp + 1)); + z_addr = z_offset + (x << 1); - x &= 0xfff; - xe &= 0xfff; + x &= 0xfff; + xe &= 0xfff; - for (; x != xe; x = (x + x_dir) & 0xfff) { - int update = 1; - uint16_t src_z = 0; + for (; x != xe; x = (x + x_dir) & 0xfff) { + int update = 1; + uint16_t src_z = 0; - _x = x; - _y = state->y; + _x = x; + _y = state->y; - if (use_z) { - src_z = Z_READ(z_addr); - Z_CLIP(src_z, z >> 16); - } + if (use_z) { + src_z = Z_READ(z_addr); + Z_CLIP(src_z, z >> 16); + } - if (update) { - uint32_t dest_col; + if (update) { + uint32_t dest_col; - dest_pixel(state); + dest_pixel(state); - if (s3d_tri->cmd_set & CMD_SET_FE) { - int a = state->a >> 7; - state->dest_rgba.r = ((state->dest_rgba.r * a) + (s3d_tri->fog_r * (255 - a))) / 255; - state->dest_rgba.g = ((state->dest_rgba.g * a) + (s3d_tri->fog_g * (255 - a))) / 255; - state->dest_rgba.b = ((state->dest_rgba.b * a) + (s3d_tri->fog_b * (255 - a))) / 255; - } + if (s3d_tri->cmd_set & CMD_SET_FE) { + int a = state->a >> 7; + state->dest_rgba.r = ((state->dest_rgba.r * a) + (s3d_tri->fog_r * (255 - a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * a) + (s3d_tri->fog_g * (255 - a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * a) + (s3d_tri->fog_b * (255 - a))) / 255; + } - if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) { - uint32_t src_col; - int src_r = 0; - uint32_t src_g = 0; - uint32_t src_b = 0; + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) { + uint32_t src_col; + int src_r = 0; + uint32_t src_g = 0; + uint32_t src_b = 0; + switch (bpp) { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *) &vram[dest_addr & virge->vram_mask]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *) &vram[dest_addr & virge->vram_mask]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } - switch (bpp) { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - src_col = *(uint16_t *)&vram[dest_addr & virge->vram_mask]; - RGB15_TO_24(src_col, src_r, src_g, src_b); - break; - case 2: /*24 bpp*/ - src_col = (*(uint32_t *)&vram[dest_addr & virge->vram_mask]) & 0xffffff; - RGB24_TO_24(src_col, src_r, src_g, src_b); - break; - } + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } - state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + - (src_r * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + - (src_g * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + - (src_b * (255 - state->dest_rgba.a))) / 255; - } + switch (bpp) { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *) &vram[dest_addr] = dest_col; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *) &vram[dest_addr] = dest_col & 0xff; + *(uint8_t *) &vram[dest_addr + 1] = (dest_col >> 8) & 0xff; + *(uint8_t *) &vram[dest_addr + 2] = (dest_col >> 16) & 0xff; + break; + } - switch (bpp) { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); - *(uint16_t *)&vram[dest_addr] = dest_col; - break; - case 2: /*24 bpp*/ - dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); - *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; - *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; - *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; - break; - } + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) + Z_WRITE(z_addr, src_z); + } - if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) - Z_WRITE(z_addr, src_z); - } - - z += s3d_tri->TdZdX; - state->u += s3d_tri->TdUdX; - state->v += s3d_tri->TdVdX; - state->r += s3d_tri->TdRdX; - state->g += s3d_tri->TdGdX; - state->b += s3d_tri->TdBdX; - state->a += s3d_tri->TdAdX; - state->d += s3d_tri->TdDdX; - state->w += s3d_tri->TdWdX; - dest_addr += x_offset; - z_addr += xz_offset; - virge->pixel_count++; - } + z += s3d_tri->TdZdX; + state->u += s3d_tri->TdUdX; + state->v += s3d_tri->TdVdX; + state->r += s3d_tri->TdRdX; + state->g += s3d_tri->TdGdX; + state->b += s3d_tri->TdBdX; + state->a += s3d_tri->TdAdX; + state->d += s3d_tri->TdDdX; + state->w += s3d_tri->TdWdX; + dest_addr += x_offset; + z_addr += xz_offset; + virge->pixel_count++; + } } tri_skip_line: - state->x1 += dx1; - state->x2 += dx2; + state->x1 += dx1; + state->x2 += dx2; state->base_u += s3d_tri->TdUdY; state->base_v += s3d_tri->TdVdY; state->base_z += s3d_tri->TdZdY; @@ -4253,22 +4282,23 @@ tri_skip_line: state->base_d += s3d_tri->TdDdY; state->base_w += s3d_tri->TdWdY; state->y--; - dest_offset -= s3d_tri->dest_str; - z_offset -= s3d_tri->z_str; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; } } -static int tex_size[8] = {4 * 2, 2 * 2, 2 * 2, 1 * 2, 2 / 1, 2 / 1, 1 * 2, 1 * 2}; +static int tex_size[8] = { 4 * 2, 2 * 2, 2 * 2, 1 * 2, 2 / 1, 2 / 1, 1 * 2, 1 * 2 }; static void -s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { +s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) +{ s3d_state_t state; - uint32_t tex_base; - int c; + uint32_t tex_base; + int c; - uint64_t start_time = plat_timer_read(); - uint64_t end_time; + uint64_t start_time = plat_timer_read(); + uint64_t end_time; state.tbu = s3d_tri->tbu << 11; state.tbv = s3d_tri->tbv << 11; @@ -4282,18 +4312,18 @@ s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { state.base_u = s3d_tri->tus; state.base_v = s3d_tri->tvs; state.base_z = s3d_tri->tzs; - state.base_r = (int32_t)s3d_tri->trs; - state.base_g = (int32_t)s3d_tri->tgs; - state.base_b = (int32_t)s3d_tri->tbs; - state.base_a = (int32_t)s3d_tri->tas; + state.base_r = (int32_t) s3d_tri->trs; + state.base_g = (int32_t) s3d_tri->tgs; + state.base_b = (int32_t) s3d_tri->tbs; + state.base_a = (int32_t) s3d_tri->tas; state.base_d = s3d_tri->tds; state.base_w = s3d_tri->tws; tex_base = s3d_tri->tex_base; for (c = 9; c >= 0; c--) { - state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base]; - if (c <= state.max_d) - tex_base += ((1 << (c * 2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; + state.texture[c] = (uint16_t *) &virge->svga.vram[tex_base]; + if (c <= state.max_d) + tex_base += ((1 << (c * 2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; } switch ((s3d_tri->cmd_set >> 27) & 0xf) { @@ -4407,7 +4437,7 @@ s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { static void render_thread(void *param) { - virge_t *virge = (virge_t *)param; + virge_t *virge = (virge_t *) param; while (virge->render_thread_run) { thread_wait_event(virge->wake_render_thread, -1); @@ -4443,14 +4473,14 @@ queue_triangle(virge_t *virge) static void s3_virge_hwcursor_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *) svga->priv; - int x; - uint16_t dat[2] = { 0, 0 }; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - uint32_t fg; - uint32_t bg; - uint32_t vram_mask = virge->vram_mask; + virge_t *virge = (virge_t *) svga->priv; + int x; + uint16_t dat[2] = { 0, 0 }; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t fg; + uint32_t bg; + uint32_t vram_mask = virge->vram_mask; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; @@ -4568,22 +4598,22 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) CLAMP(b[x_write + 1]); \ \ x_write = (x_write + 2) & 7; \ - } \ + } \ } while (0) /*Both YUV formats are untested*/ #define DECODE_YUV211() \ do { \ uint8_t y1, y2, y3, y4; \ - int8_t U, V; \ - int dR; \ - int dG; \ - int dB; \ + int8_t U, V; \ + int dR; \ + int dG; \ + int dB; \ \ - U = src[0] - 0x80; \ + U = src[0] - 0x80; \ y1 = (298 * (src[1] - 16)) >> 8; \ y2 = (298 * (src[2] - 16)) >> 8; \ - V = src[3] - 0x80; \ + V = src[3] - 0x80; \ y3 = (298 * (src[4] - 16)) >> 8; \ y4 = (298 * (src[5] - 16)) >> 8; \ src += 6; \ @@ -4634,9 +4664,9 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) int dG; \ int dB; \ \ - U = src[0] - 0x80; \ + U = src[0] - 0x80; \ y1 = (298 * (src[1] - 16)) >> 8; \ - V = src[2] - 0x80; \ + V = src[2] - 0x80; \ y2 = (298 * (src[3] - 16)) >> 8; \ src += 4; \ \ @@ -4757,13 +4787,13 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) static void s3_virge_overlay_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *) svga->priv; + virge_t *virge = (virge_t *) svga->priv; int offset; int r[8]; int g[8]; int b[8]; int x_size; - int x_read = 4; + int x_read = 4; int x_write = 4; int x; uint32_t *p; @@ -4774,7 +4804,7 @@ s3_virge_overlay_draw(svga_t *svga, int displine) else offset = virge->streams.sec_x + 1; - p = &((uint32_t *)buffer32->line[displine])[offset + svga->x_add]; + p = &((uint32_t *) buffer32->line[displine])[offset + svga->x_add]; if (virge->chip < S3_VIRGEGX2) { if ((offset + virge->streams.sec_w) > virge->streams.pri_w) @@ -5078,9 +5108,9 @@ s3_virge_disable_handlers(virge_t *dev) reset_state->svga.mapping = dev->svga.mapping; reset_state->bios_rom.mapping = dev->bios_rom.mapping; - reset_state->svga.timer = dev->svga.timer; - reset_state->svga.timer8514 = dev->svga.timer8514; - reset_state->irq_timer = dev->irq_timer; + reset_state->svga.timer = dev->svga.timer; + reset_state->svga.timer8514 = dev->svga.timer8514; + reset_state->irq_timer = dev->irq_timer; } static void @@ -5090,12 +5120,12 @@ s3_virge_reset(void *priv) if (reset_state != NULL) { s3_virge_disable_handlers(dev); - dev->virge_busy = 0; - dev->fifo_write_idx = 0; - dev->fifo_read_idx = 0; - dev->s3d_busy = 0; - dev->s3d_write_idx = 0; - dev->s3d_read_idx = 0; + dev->virge_busy = 0; + dev->fifo_write_idx = 0; + dev->fifo_read_idx = 0; + dev->s3d_busy = 0; + dev->s3d_write_idx = 0; + dev->s3d_read_idx = 0; reset_state->pci_slot = dev->pci_slot; *dev = *reset_state; @@ -5106,8 +5136,8 @@ static void * s3_virge_init(const device_t *info) { const char *bios_fn = NULL; - virge_t *virge = (virge_t *) calloc(1, sizeof(virge_t)); - reset_state = calloc(1, sizeof(virge_t)); + virge_t *virge = (virge_t *) calloc(1, sizeof(virge_t)); + reset_state = calloc(1, sizeof(virge_t)); virge->bilinear_enabled = device_get_config_int("bilinear"); virge->dithering_enabled = device_get_config_int("dithering"); @@ -5118,44 +5148,45 @@ s3_virge_init(const device_t *info) virge->onboard = !!(info->local & 0x100); - if (!virge->onboard) switch (info->local) { - case S3_VIRGE_325: - bios_fn = ROM_VIRGE_325; - break; - case S3_DIAMOND_STEALTH3D_2000: - bios_fn = ROM_DIAMOND_STEALTH3D_2000; - break; - case S3_MIROCRYSTAL_3D: - bios_fn = ROM_MIROCRYSTAL_3D; - break; - case S3_DIAMOND_STEALTH3D_3000: - bios_fn = ROM_DIAMOND_STEALTH3D_3000; - break; - case S3_STB_VELOCITY_3D: - bios_fn = ROM_STB_VELOCITY_3D; - break; - case S3_VIRGE_DX: - bios_fn = ROM_VIRGE_DX; - break; - case S3_DIAMOND_STEALTH3D_2000PRO: - bios_fn = ROM_DIAMOND_STEALTH3D_2000PRO; - break; - case S3_VIRGE_GX: - bios_fn = ROM_VIRGE_GX; - break; - case S3_VIRGE_GX2: - bios_fn = ROM_VIRGE_GX2; - break; - case S3_DIAMOND_STEALTH3D_4000: - bios_fn = ROM_DIAMOND_STEALTH3D_4000; - break; - case S3_TRIO_3D2X: - bios_fn = ROM_TRIO3D2X; - break; - default: - free(virge); - return NULL; - } + if (!virge->onboard) + switch (info->local) { + case S3_VIRGE_325: + bios_fn = ROM_VIRGE_325; + break; + case S3_DIAMOND_STEALTH3D_2000: + bios_fn = ROM_DIAMOND_STEALTH3D_2000; + break; + case S3_MIROCRYSTAL_3D: + bios_fn = ROM_MIROCRYSTAL_3D; + break; + case S3_DIAMOND_STEALTH3D_3000: + bios_fn = ROM_DIAMOND_STEALTH3D_3000; + break; + case S3_STB_VELOCITY_3D: + bios_fn = ROM_STB_VELOCITY_3D; + break; + case S3_VIRGE_DX: + bios_fn = ROM_VIRGE_DX; + break; + case S3_DIAMOND_STEALTH3D_2000PRO: + bios_fn = ROM_DIAMOND_STEALTH3D_2000PRO; + break; + case S3_VIRGE_GX: + bios_fn = ROM_VIRGE_GX; + break; + case S3_VIRGE_GX2: + bios_fn = ROM_VIRGE_GX2; + break; + case S3_DIAMOND_STEALTH3D_4000: + bios_fn = ROM_DIAMOND_STEALTH3D_4000; + break; + case S3_TRIO_3D2X: + bios_fn = ROM_TRIO3D2X; + break; + default: + free(virge); + return NULL; + } svga_init(info, &virge->svga, virge, virge->memory_size << 20, s3_virge_recalctimings, @@ -5223,7 +5254,7 @@ s3_virge_init(const device_t *info) case S3_VIRGE_325: case S3_DIAMOND_STEALTH3D_2000: case S3_MIROCRYSTAL_3D: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x56; virge->virge_id_low = 0x31; @@ -5233,7 +5264,7 @@ s3_virge_init(const device_t *info) break; case S3_DIAMOND_STEALTH3D_3000: case S3_STB_VELOCITY_3D: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (8 << 20) - 1; virge->virge_id_high = 0x88; virge->virge_id_low = 0x3d; @@ -5243,7 +5274,7 @@ s3_virge_init(const device_t *info) break; case S3_VIRGE_GX2: case S3_DIAMOND_STEALTH3D_4000: - virge->fifo_slots_num = 16; + virge->fifo_slots_num = 16; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x10; @@ -5255,7 +5286,7 @@ s3_virge_init(const device_t *info) break; case S3_TRIO_3D2X: - virge->fifo_slots_num = 16; + virge->fifo_slots_num = 16; virge->svga.decode_mask = (8 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x13; @@ -5272,7 +5303,7 @@ s3_virge_init(const device_t *info) fallthrough; default: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x01; @@ -5341,16 +5372,16 @@ s3_virge_init(const device_t *info) virge->svga.force_old_addr = 1; - virge->render_thread_run = 1; + virge->render_thread_run = 1; virge->wake_render_thread = thread_create_event(); - virge->wake_main_thread = thread_create_event(); - virge->not_full_event = thread_create_event(); - virge->render_thread = thread_create(render_thread, virge); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); - virge->fifo_thread_run = 1; - virge->wake_fifo_thread = thread_create_event(); + virge->fifo_thread_run = 1; + virge->wake_fifo_thread = thread_create_event(); virge->fifo_not_full_event = thread_create_event(); - virge->fifo_thread = thread_create(fifo_thread, virge); + virge->fifo_thread = thread_create(fifo_thread, virge); timer_add(&virge->irq_timer, s3_virge_update_irq_timer, virge, 1); @@ -5473,7 +5504,7 @@ s3_virge_force_redraw(void *priv) } static const device_config_t s3_virge_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5509,11 +5540,11 @@ static const device_config_t s3_virge_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_virge_stb_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5550,11 +5581,11 @@ static const device_config_t s3_virge_stb_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_virge_357_config[] = { - // clang-format off + // clang-format off { .name = "bilinear", .description = "Bilinear filtering", @@ -5576,11 +5607,11 @@ static const device_config_t s3_virge_357_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_trio3d2x_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5619,7 +5650,7 @@ static const device_config_t s3_trio3d2x_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; const device_t s3_virge_325_pci_device = { From 6c32f3ec0c1cd5997bd1c2ed717403750ea29bff Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 19:06:05 +0600 Subject: [PATCH 070/218] Properly process line endings --- src/qt/qt_openglrenderer_pcem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index c8f3d3eb9..50583bf51 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -136,7 +136,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log).replace("\n", "
")); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -181,7 +181,7 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log).replace("\n", "
")); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); pclog("Could not compile shader: %s\n", log); From 1ed579a0fceaa86d5b4dc00cc76bd751040042cf Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 19:52:59 +0600 Subject: [PATCH 071/218] Reimplement other missing options from current OpenGL renderer --- src/qt/qt_openglrenderer_pcem.cpp | 11 +- src/qt/qt_openglshadermanagerdialog.cpp | 51 ++++ src/qt/qt_openglshadermanagerdialog.hpp | 8 + src/qt/qt_openglshadermanagerdialog.ui | 300 ++++++++++++++---------- 4 files changed, 247 insertions(+), 123 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 50583bf51..79960323f 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -774,6 +774,8 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setSwapInterval(video_vsync ? 1 : 0); + setFormat(format); parentWidget = parent; @@ -822,6 +824,9 @@ OpenGLRendererPCem::initialize() glw.glEnable(GL_TEXTURE_2D); //renderTimer->start(75); + if (video_framerate != -1) { + renderTimer->start(ceilf(1000.f / (float)video_framerate)); + } scene_texture.data = NULL; scene_texture.width = 2048; @@ -1102,7 +1107,8 @@ OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) source.setRect(x, y, w, h); onResize(this->width(), this->height()); - render(); + if (video_framerate == -1) + render(); } std::vector> @@ -1314,6 +1320,9 @@ OpenGLRendererPCem::render() if (!context) return; + if (notReady()) + return; + int s, i, j; struct { diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 08cf94fd7..0bf083252 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -1,6 +1,9 @@ #include "qt_openglshadermanagerdialog.hpp" #include "ui_qt_openglshadermanagerdialog.h" +#include "qt_mainwindow.hpp" +extern MainWindow* main_window; + #include "qt_openglshaderconfig.hpp" #include @@ -25,6 +28,15 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) { ui->setupUi(this); + ui->checkBoxVSync->setChecked(!!video_vsync); + ui->radioButtonVideoSync->setChecked(video_framerate == -1); + ui->radioButtonTargetFramerate->setChecked(video_framerate != -1); + if (video_framerate != -1) { + ui->targetFrameRate->setValue(video_framerate); + } else { + ui->targetFrameRate->setDisabled(true); + } + for (int i = 0; i < MAX_USER_SHADERS; i++) { if (gl3_shader_file[i][0] != 0) { char* filename = path_get_filename(gl3_shader_file[i]); @@ -75,6 +87,9 @@ void OpenGLShaderManagerDialog::on_buttonBox_clicked(QAbstractButton *button) accept(); } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) { reject(); + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole) { + on_OpenGLShaderManagerDialog_accepted(); + main_window->reloadAllRenderers(); } } @@ -191,6 +206,12 @@ void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() strncpy(gl3_shader_file[i], ui->shaderListWidget->item(i)->data(Qt::UserRole + 1).toString().toUtf8(), 512); } startblit(); + video_vsync = ui->checkBoxVSync->isChecked(); + if (ui->radioButtonTargetFramerate->isChecked()) { + video_framerate = ui->horizontalSliderFramerate->value(); + } else { + video_framerate = -1; + } config_save(); endblit(); } @@ -207,3 +228,33 @@ void OpenGLShaderManagerDialog::on_buttonConfigure_clicked() } } + +void OpenGLShaderManagerDialog::on_radioButtonVideoSync_clicked() +{ + ui->targetFrameRate->setDisabled(true); +} + + +void OpenGLShaderManagerDialog::on_radioButtonTargetFramerate_clicked() +{ + ui->targetFrameRate->setDisabled(false); +} + + +void OpenGLShaderManagerDialog::on_horizontalSliderFramerate_sliderMoved(int position) +{ + (void)position; + + if (ui->horizontalSliderFramerate->value() != ui->targetFrameRate->value()) + ui->targetFrameRate->setValue(ui->horizontalSliderFramerate->value()); +} + + +void OpenGLShaderManagerDialog::on_targetFrameRate_valueChanged(int arg1) +{ + (void)arg1; + + if (ui->horizontalSliderFramerate->value() != ui->targetFrameRate->value()) + ui->horizontalSliderFramerate->setValue(ui->targetFrameRate->value()); +} + diff --git a/src/qt/qt_openglshadermanagerdialog.hpp b/src/qt/qt_openglshadermanagerdialog.hpp index b8885e3a3..a9f7ad3a9 100644 --- a/src/qt/qt_openglshadermanagerdialog.hpp +++ b/src/qt/qt_openglshadermanagerdialog.hpp @@ -35,6 +35,14 @@ private slots: void on_buttonConfigure_clicked(); + void on_radioButtonVideoSync_clicked(); + + void on_radioButtonTargetFramerate_clicked(); + + void on_horizontalSliderFramerate_sliderMoved(int position); + + void on_targetFrameRate_valueChanged(int arg1); + private: Ui::OpenGLShaderManagerDialog *ui; }; diff --git a/src/qt/qt_openglshadermanagerdialog.ui b/src/qt/qt_openglshadermanagerdialog.ui index f68827436..2a72c69ed 100644 --- a/src/qt/qt_openglshadermanagerdialog.ui +++ b/src/qt/qt_openglshadermanagerdialog.ui @@ -13,136 +13,192 @@ Shader Manager - + QLayout::SizeConstraint::SetFixedSize - - - - QAbstractItemView::DragDropMode::InternalMove - - - QAbstractItemView::SelectionBehavior::SelectItems + + + + Shaders + + + QLayout::SizeConstraint::SetFixedSize + + + + + QAbstractItemView::DragDropMode::InternalMove + + + QAbstractItemView::SelectionBehavior::SelectItems + + + + + + + QLayout::SizeConstraint::SetFixedSize + + + + + Add + + + + + + + Remove + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + true + + + Configure + + + + + + + Move up + + + + + + + Move down + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + Qt::Orientation::Vertical + + + QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + false + + + + + + - - - - - - Add - - - - - - - Remove - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - true - - - Configure - - - - - - - Move up - - - - - - - Move down - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - Qt::Orientation::Vertical - - - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok - - - false - - - - + + + + Render behavior + + + + QLayout::SizeConstraint::SetDefaultConstraint + + + + + Use target framerate: + + + + + + + 15 + + + 240 + + + 60 + + + Qt::Orientation::Horizontal + + + false + + + false + + + + + + + Synchronize with video + + + true + + + + + + + VSync + + + + + + + fps + + + 15 + + + 240 + + + 60 + + + + +
- - - buttonBox - accepted() - OpenGLShaderManagerDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - OpenGLShaderManagerDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - + From 81461f677df712457f3c98214ca2390c4f135d14 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 20:54:25 +0600 Subject: [PATCH 072/218] Cleanups, copyright headers and name changing for PRing --- src/86box.c | 1 - src/config.c | 19 +- src/include/86box/86box.h | 1 - src/include/86box/ini.h | 30 -- src/ini.c | 3 +- src/qt/CMakeLists.txt | 12 +- src/qt/qt_glsl_parser.cpp | 37 +++ src/qt/qt_opengloptions.cpp | 196 ------------- src/qt/qt_opengloptions.hpp | 102 ------- src/qt/qt_opengloptionsdialog.cpp | 116 -------- src/qt/qt_opengloptionsdialog.hpp | 51 ---- src/qt/qt_opengloptionsdialog.ui | 280 ------------------ src/qt/qt_openglrenderer.cpp | 468 ------------------------------ src/qt/qt_openglrenderer.hpp | 125 -------- src/qt/qt_openglrenderer_pcem.cpp | 111 ++++--- src/qt/qt_openglrenderer_pcem.hpp | 20 +- src/qt/qt_rendererstack.cpp | 17 +- 17 files changed, 136 insertions(+), 1453 deletions(-) delete mode 100644 src/qt/qt_opengloptions.cpp delete mode 100644 src/qt/qt_opengloptions.hpp delete mode 100644 src/qt/qt_opengloptionsdialog.cpp delete mode 100644 src/qt/qt_opengloptionsdialog.hpp delete mode 100644 src/qt/qt_opengloptionsdialog.ui delete mode 100644 src/qt/qt_openglrenderer.cpp delete mode 100644 src/qt/qt_openglrenderer.hpp diff --git a/src/86box.c b/src/86box.c index 13167b1bd..24f6f0deb 100644 --- a/src/86box.c +++ b/src/86box.c @@ -172,7 +172,6 @@ int force_43 = 0; /* (C) video * int video_filter_method = 1; /* (C) video */ int video_vsync = 0; /* (C) video */ int video_framerate = -1; /* (C) video */ -char video_shader[512] = { '\0' }; /* (C) video */ bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of pass-through for serial ports */ int bugger_enabled = 0; /* (C) enable ISAbugger */ diff --git a/src/config.c b/src/config.c index 20981885a..5ad804df6 100644 --- a/src/config.c +++ b/src/config.c @@ -200,7 +200,6 @@ load_general(void) video_framerate = ini_section_get_int(cat, "video_gl_framerate", -1); video_vsync = ini_section_get_int(cat, "video_gl_vsync", 0); - strncpy(video_shader, ini_section_get_string(cat, "video_gl_shader", ""), sizeof(video_shader) - 1); window_remember = ini_section_get_int(cat, "window_remember", 0); if (window_remember) { @@ -1733,7 +1732,19 @@ load_gl3_shaders(void) if (shaders > MAX_USER_SHADERS) shaders = MAX_USER_SHADERS; - for (int i = 0; i < shaders; i++) { + if (shaders == 0) { + ini_section_t general = ini_find_section(config, "General"); + if (general) { + p = ini_section_get_string(general, "video_gl_shader", NULL); + if (p) { + strncpy(gl3_shader_file[0], p, 512); + ini_delete_var(config, general, "video_gl_shader"); + return; + } + } + } + + for (i = 0; i < shaders; i++) { temp[0] = 0; snprintf(temp, 512, "shader%d", i); p = ini_section_get_string(cat, temp, ""); @@ -2035,10 +2046,6 @@ save_general(void) ini_section_set_int(cat, "video_gl_vsync", video_vsync); else ini_section_delete_var(cat, "video_gl_vsync"); - if (strlen(video_shader) > 0) - ini_section_set_string(cat, "video_gl_shader", video_shader); - else - ini_section_delete_var(cat, "video_gl_shader"); if (do_auto_pause) ini_section_set_int(cat, "do_auto_pause", do_auto_pause); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 30905741c..768ca6267 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -126,7 +126,6 @@ extern int video_filter_method; /* (C) video */ extern int video_vsync; /* (C) video */ extern int video_framerate; /* (C) video */ extern int gfxcard[GFXCARD_MAX]; /* (C) graphics/video card */ -extern char video_shader[512]; /* (C) video */ extern int bugger_enabled; /* (C) enable ISAbugger */ extern int novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */ extern int postcard_enabled; /* (C) enable POST card */ diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index 3139f410e..bb250e697 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -92,36 +92,6 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); -static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; } -static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); - if (size == 0) - return res; - if (str != NULL) - strncpy(dst, str, size - 1); - else - dst[0] = 0; - return res; -} -static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - *dst = ini_get_int((ini_t)config, "", name, defVal); - return res; -} -static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - *dst = (float)ini_get_double((ini_t)config, "", name, defVal); - return res; -} -static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - *dst = !!ini_get_int((ini_t)config, "", name, defVal); - return res; -} -static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); } -static inline void wx_config_free(void *config) { ini_close(config); }; - #ifdef __cplusplus } #endif diff --git a/src/ini.c b/src/ini.c index 7a54d5396..503b17ae3 100644 --- a/src/ini.c +++ b/src/ini.c @@ -162,7 +162,6 @@ ini_has_entry(ini_section_t self, const char *name) { section_t *section = (section_t *) self; const entry_t *entry; - int value = 0; if (section == NULL) return 0; @@ -546,6 +545,7 @@ ini_write(ini_t ini, const char *fn) (void) fclose(fp); } +/* Wide-character version of "trim" */ wchar_t * trim_w(wchar_t *str) { @@ -609,7 +609,6 @@ ini_strip_quotes(ini_t ini) ent = (entry_t *) sec->entry_head.next; while (ent != NULL) { if (ent->name[0] != '\0') { - int i = 0; int trailing_hash = strcspn(ent->data, "#"); int trailing_quote; ent->wdata[trailing_hash] = 0; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 574aae7b7..8137be98e 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -87,16 +87,9 @@ add_library(ui STATIC qt_softwarerenderer.hpp qt_hardwarerenderer.cpp qt_hardwarerenderer.hpp - qt_openglrenderer.cpp - qt_openglrenderer.hpp qt_openglrenderer_pcem.cpp qt_openglrenderer_pcem.hpp qt_glsl_parser.cpp - qt_opengloptions.cpp - qt_opengloptions.hpp - qt_opengloptionsdialog.cpp - qt_opengloptionsdialog.hpp - qt_opengloptionsdialog.ui qt_settings.cpp qt_settings.hpp @@ -197,7 +190,10 @@ add_library(ui STATIC qt_openglshadermanagerdialog.hpp qt_openglshadermanagerdialog.cpp qt_openglshadermanagerdialog.ui - qt_openglshaderconfig.hpp qt_openglshaderconfig.cpp qt_openglshaderconfig.ui + + qt_openglshaderconfig.hpp + qt_openglshaderconfig.cpp + qt_openglshaderconfig.ui ) if(RTMIDI) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index 2a4c4ddd1..bf02014db 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -28,6 +28,43 @@ extern void endblit(); (a)[(n)-1] = 0; \ } while (0) + + +static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; } + +static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); + if (size == 0) + return res; + if (str != NULL) + strncpy(dst, str, size - 1); + else + dst[0] = 0; + return res; +} + +static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = ini_get_int((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = (float)ini_get_double((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = !!ini_get_int((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); } +static inline void wx_config_free(void *config) { ini_close(config); }; + static int endswith(const char *str, const char *ext) { int i; const char *p; diff --git a/src/qt/qt_opengloptions.cpp b/src/qt/qt_opengloptions.cpp deleted file mode 100644 index 58030b467..000000000 --- a/src/qt/qt_opengloptions.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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. - * - * OpenGL renderer options for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include -#include - -#include - -#include "qt_opengloptions.hpp" - -extern "C" { -#include <86box/86box.h> -} - -/* Default vertex shader. */ -static const GLchar *vertex_shader = "\ -in vec2 VertexCoord;\n\ -in vec2 TexCoord;\n\ -out vec2 tex;\n\ -void main(){\n\ - gl_Position = vec4(VertexCoord, 0.0, 1.0);\n\ - tex = TexCoord;\n\ -}\n"; - -/* Default fragment shader. */ -static const GLchar *fragment_shader = "\ -in vec2 tex;\n\ -uniform sampler2D texsampler;\n\ -out vec4 color;\n\ -void main() {\n\ - color = texture(texsampler, tex);\n\ -}\n"; - -OpenGLOptions::OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion) - : QObject(parent) - , m_glslVersion(glslVersion) -{ - m_filter = video_filter_method == 0 - ? FilterType::Nearest - : FilterType::Linear; - - if (!loadConfig) - return; - - /* Initialize with config. */ - m_vsync = video_vsync != 0; - m_framerate = video_framerate; - - m_renderBehavior = video_framerate == -1 - ? RenderBehaviorType::SyncWithVideo - : RenderBehaviorType::TargetFramerate; - - QString shaderPath(video_shader); - - if (shaderPath.isEmpty()) { - addDefaultShader(); - } else { - try { - addShader(shaderPath); - } catch (const std::runtime_error &) { - /* Fallback to default shader */ - addDefaultShader(); - } - } -} - -void -OpenGLOptions::save() const -{ - video_vsync = m_vsync ? 1 : 0; - video_framerate = m_renderBehavior == RenderBehaviorType::SyncWithVideo ? -1 : m_framerate; - video_filter_method = m_filter == FilterType::Nearest ? 0 : 1; - - /* TODO: multiple shaders */ - auto path = m_shaders.first().path().toLocal8Bit(); - - if (!path.isEmpty()) - qstrncpy(video_shader, path.constData(), sizeof(video_shader)); - else - video_shader[0] = '\0'; -} - -OpenGLOptions::FilterType -OpenGLOptions::filter() const -{ - /* Filter method is controlled externally */ - return video_filter_method == 0 - ? FilterType::Nearest - : FilterType::Linear; -} - -void -OpenGLOptions::setRenderBehavior(RenderBehaviorType value) -{ - m_renderBehavior = value; -} - -void -OpenGLOptions::setFrameRate(int value) -{ - m_framerate = value; -} - -void -OpenGLOptions::setVSync(bool value) -{ - m_vsync = value; -} - -void -OpenGLOptions::setFilter(FilterType value) -{ - m_filter = value; -} - -void -OpenGLOptions::addShader(const QString &path) -{ - QFile shader_file(path); - - if (!shader_file.open(QIODevice::ReadOnly | QIODevice::Text)) { - throw std::runtime_error( - QString(tr("Error opening \"%1\": %2")) - .arg(path) - .arg(shader_file.errorString()) - .toStdString()); - } - - auto shader_text = QString(shader_file.readAll()); - - shader_file.close(); - - /* Remove parameter lines */ - shader_text.remove(QRegularExpression("^\\s*#pragma parameter.*?\\n", QRegularExpression::MultilineOption)); - - QRegularExpression version("^\\s*(#version\\s+\\w+)", QRegularExpression::MultilineOption); - - auto match = version.match(shader_text); - - QString version_line(m_glslVersion); - - if (match.hasMatch()) { - /* Extract existing version and remove it. */ - version_line = match.captured(1); - shader_text.remove(version); - } - - auto shader = new QOpenGLShaderProgram(this); - - auto throw_shader_error = [path, shader](const QString &what) { - throw std::runtime_error( - QString(what % ":\n\n %2") - .arg(path) - .arg(shader->log()) - .toStdString()); - }; - - static const char *extension = "\n#extension GL_ARB_shading_language_420pack : enable\n"; - - if (!shader->addShaderFromSourceCode(QOpenGLShader::Vertex, version_line % extension % "\n#define VERTEX\n#line 1\n" % shader_text)) - throw_shader_error(tr("Error compiling vertex shader in file \"%1\"")); - - if (!shader->addShaderFromSourceCode(QOpenGLShader::Fragment, version_line % extension % "\n#define FRAGMENT\n#line 1\n" % shader_text)) - throw_shader_error(tr("Error compiling fragment shader in file \"%1\"")); - - if (!shader->link()) - throw_shader_error(tr("Error linking shader program in file \"%1\"")); - - m_shaders << OpenGLShaderPass(shader, path); -} - -void -OpenGLOptions::addDefaultShader() -{ - auto shader = new QOpenGLShaderProgram(this); - shader->addShaderFromSourceCode(QOpenGLShader::Vertex, m_glslVersion % "\n" % vertex_shader); - shader->addShaderFromSourceCode(QOpenGLShader::Fragment, m_glslVersion % "\n" % fragment_shader); - shader->link(); - m_shaders << OpenGLShaderPass(shader, QString()); -} diff --git a/src/qt/qt_opengloptions.hpp b/src/qt/qt_opengloptions.hpp deleted file mode 100644 index 64f761670..000000000 --- a/src/qt/qt_opengloptions.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - * - * Header for OpenGL renderer options - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLOPTIONS_HPP -#define QT_OPENGLOPTIONS_HPP - -#include -#include -#include -#include - -class OpenGLShaderPass { -public: - OpenGLShaderPass(QOpenGLShaderProgram *shader, const QString &path) - : m_shader(shader) - , m_path(path) - , m_vertex_coord(shader->attributeLocation("VertexCoord")) - , m_tex_coord(shader->attributeLocation("TexCoord")) - , m_color(shader->attributeLocation("Color")) - , m_mvp_matrix(shader->uniformLocation("MVPMatrix")) - , m_input_size(shader->uniformLocation("InputSize")) - , m_output_size(shader->uniformLocation("OutputSize")) - , m_texture_size(shader->uniformLocation("TextureSize")) - , m_frame_count(shader->uniformLocation("FrameCount")) - { - } - - bool bind() const { return m_shader->bind(); } - const QString &path() const { return m_path; } - const GLint &vertex_coord() const { return m_vertex_coord; } - const GLint &tex_coord() const { return m_tex_coord; } - const GLint &color() const { return m_color; } - const GLint &mvp_matrix() const { return m_mvp_matrix; } - const GLint &input_size() const { return m_input_size; } - const GLint &output_size() const { return m_output_size; } - const GLint &texture_size() const { return m_texture_size; } - const GLint &frame_count() const { return m_frame_count; } - -private: - QOpenGLShaderProgram *m_shader; - QString m_path; - GLint m_vertex_coord; - GLint m_tex_coord; - GLint m_color; - GLint m_mvp_matrix; - GLint m_input_size; - GLint m_output_size; - GLint m_texture_size; - GLint m_frame_count; -}; - -class OpenGLOptions : public QObject { - Q_OBJECT - -public: - enum RenderBehaviorType { SyncWithVideo, - TargetFramerate }; - - enum FilterType { Nearest, - Linear }; - - OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion); - - RenderBehaviorType renderBehavior() const { return m_renderBehavior; } - int framerate() const { return m_framerate; } - bool vSync() const { return m_vsync; } - FilterType filter() const; - - const QList &shaders() const { return m_shaders; } - - void setRenderBehavior(RenderBehaviorType value); - void setFrameRate(int value); - void setVSync(bool value); - void setFilter(FilterType value); - void addShader(const QString &path); - void addDefaultShader(); - void save() const; - -private: - RenderBehaviorType m_renderBehavior = SyncWithVideo; - int m_framerate = -1; - bool m_vsync = false; - FilterType m_filter = Nearest; - QList m_shaders; - QString m_glslVersion; -}; - -#endif diff --git a/src/qt/qt_opengloptionsdialog.cpp b/src/qt/qt_opengloptionsdialog.cpp deleted file mode 100644 index acb2ce9f2..000000000 --- a/src/qt/qt_opengloptionsdialog.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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. - * - * OpenGL renderer options dialog for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include - -#include - -#include "qt_opengloptionsdialog.hpp" -#include "qt_util.hpp" -#include "ui_qt_opengloptionsdialog.h" - -OpenGLOptionsDialog::OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory) - : QDialog(parent) - , ui(new Ui::OpenGLOptionsDialog) - , createOptions(optionsFactory) -{ - ui->setupUi(this); - - if (options.renderBehavior() == OpenGLOptions::SyncWithVideo) - ui->syncWithVideo->setChecked(true); - else { - ui->syncToFramerate->setChecked(true); - ui->targetFps->setValue(options.framerate()); - } - - ui->vsync->setChecked(options.vSync()); - - if (!options.shaders().isEmpty()) { - auto path = options.shaders().first().path(); - if (!path.isEmpty()) - ui->shader->setPlainText(path); - } -} - -OpenGLOptionsDialog::~OpenGLOptionsDialog() -{ - delete ui; -} - -void -OpenGLOptionsDialog::accept() -{ - auto options = createOptions(); - - options->setRenderBehavior( - ui->syncWithVideo->isChecked() - ? OpenGLOptions::SyncWithVideo - : OpenGLOptions::TargetFramerate); - - options->setFrameRate(ui->targetFps->value()); - - options->setVSync(ui->vsync->isChecked()); - - auto shader = ui->shader->toPlainText(); - - try { - - if (!shader.isEmpty()) - options->addShader(shader); - else - options->addDefaultShader(); - - } catch (const std::runtime_error &e) { - delete options; - - QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Shader error")); - msgBox.setText(tr("Could not load shaders.")); - msgBox.setInformativeText(tr("More information in details.")); - msgBox.setDetailedText(e.what()); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Close); - msgBox.setDefaultButton(QMessageBox::Close); - msgBox.setStyleSheet("QTextEdit { min-width: 45em; }"); - msgBox.exec(); - - return; - } - - options->save(); - - emit optionsChanged(options); - - QDialog::accept(); -} - -void -OpenGLOptionsDialog::on_addShader_clicked() -{ - auto shader = QFileDialog::getOpenFileName( - this, - QString(), - QString(), - tr("OpenGL Shaders") % util::DlgFilter({ "glsl" }, true)); - - if (shader.isNull()) - return; - - ui->shader->setPlainText(shader); -} diff --git a/src/qt/qt_opengloptionsdialog.hpp b/src/qt/qt_opengloptionsdialog.hpp deleted file mode 100644 index f34d74d75..000000000 --- a/src/qt/qt_opengloptionsdialog.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - * - * Header for OpenGL renderer options dialog - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLOPTIONSDIALOG_H -#define QT_OPENGLOPTIONSDIALOG_H - -#include - -#include - -#include "qt_opengloptions.hpp" - -namespace Ui { -class OpenGLOptionsDialog; -} - -class OpenGLOptionsDialog : public QDialog { - Q_OBJECT - -public: - explicit OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory); - ~OpenGLOptionsDialog(); - -signals: - void optionsChanged(OpenGLOptions *options); - -public slots: - void accept() override; - -private: - Ui::OpenGLOptionsDialog *ui; - - std::function createOptions; - -private slots: - void on_addShader_clicked(); -}; - -#endif // QT_OPENGLOPTIONSDIALOG_H diff --git a/src/qt/qt_opengloptionsdialog.ui b/src/qt/qt_opengloptionsdialog.ui deleted file mode 100644 index a6f86b6c2..000000000 --- a/src/qt/qt_opengloptionsdialog.ui +++ /dev/null @@ -1,280 +0,0 @@ - - - OpenGLOptionsDialog - - - - 0 - 0 - 400 - 320 - - - - OpenGL 3.0 renderer options - - - - - - Render behavior - - - - - - Use target framerate: - - - - - - - false - - - fps - - - 15 - - - 240 - - - 60 - - - - - - - VSync - - - - - - - <html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html> - - - Synchronize with video - - - true - - - - - - - false - - - 15 - - - 240 - - - 60 - - - Qt::Horizontal - - - false - - - QSlider::NoTicks - - - - - - - - - - Shaders - - - - - - Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - true - - - No shader selected - - - - - - - Browse... - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - syncWithVideo - syncToFramerate - fpsSlider - targetFps - vsync - shader - addShader - removeShader - - - - - buttonBox - accepted() - OpenGLOptionsDialog - accept() - - - 257 - 310 - - - 157 - 274 - - - - - buttonBox - rejected() - OpenGLOptionsDialog - reject() - - - 325 - 310 - - - 286 - 274 - - - - - syncToFramerate - toggled(bool) - targetFps - setEnabled(bool) - - - 140 - 71 - - - 380 - 98 - - - - - syncToFramerate - toggled(bool) - fpsSlider - setEnabled(bool) - - - 158 - 66 - - - 168 - 87 - - - - - fpsSlider - valueChanged(int) - targetFps - setValue(int) - - - 252 - 90 - - - 308 - 89 - - - - - targetFps - valueChanged(int) - fpsSlider - setValue(int) - - - 364 - 93 - - - 134 - 93 - - - - - removeShader - clicked() - shader - clear() - - - 333 - 201 - - - 235 - 208 - - - - - diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp deleted file mode 100644 index 60aa998a9..000000000 --- a/src/qt/qt_openglrenderer.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * 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. - * - * OpenGL renderer for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "qt_opengloptionsdialog.hpp" -#include "qt_openglrenderer.hpp" - -#ifndef GL_MAP_PERSISTENT_BIT -# define GL_MAP_PERSISTENT_BIT 0x0040 -#endif - -#ifndef GL_MAP_COHERENT_BIT -# define GL_MAP_COHERENT_BIT 0x0080 -#endif - -OpenGLRenderer::OpenGLRenderer(QWidget *parent) - : QWindow(parent->windowHandle()) - , renderTimer(new QTimer(this)) - , options(nullptr) -{ - renderTimer->setTimerType(Qt::PreciseTimer); - /* TODO: need's more accuracy, maybe target 1ms earlier and spin yield */ - connect(renderTimer, &QTimer::timeout, this, &OpenGLRenderer::render); - - buf_usage = std::vector(BUFFERCOUNT); - for (auto &flag : buf_usage) - flag.clear(); - - setSurfaceType(QWindow::OpenGLSurface); - - QSurfaceFormat format; - -#ifdef Q_OS_MACOS - format.setVersion(4, 1); -#else - format.setVersion(3, 2); -#endif - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) - format.setRenderableType(QSurfaceFormat::OpenGLES); - - setFormat(format); - - parentWidget = parent; - - source.setRect(0, 0, INIT_WIDTH, INIT_HEIGHT); -} - -OpenGLRenderer::~OpenGLRenderer() -{ - finalize(); -} - -void -OpenGLRenderer::exposeEvent(QExposeEvent *event) -{ - Q_UNUSED(event); - - if (!isInitialized) - initialize(); - - onResize(size().width(), size().height()); -} - -void -OpenGLRenderer::resizeEvent(QResizeEvent *event) -{ - Q_UNUSED(event); - - onResize(event->size().width(), event->size().height()); - - if (notReady()) - return; - - context->makeCurrent(this); - - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); -} - -bool -OpenGLRenderer::event(QEvent *event) -{ - Q_UNUSED(event); - - bool res = false; - if (!eventDelegate(event, res)) - return QWindow::event(event); - return res; -} - -void -OpenGLRenderer::initialize() -{ - try { - context = new QOpenGLContext(this); - - context->setFormat(format()); - - if (!context->create()) - throw opengl_init_error(tr("Couldn't create OpenGL context.")); - - if (!context->makeCurrent(this)) - throw opengl_init_error(tr("Couldn't switch to OpenGL context.")); - - auto version = context->format().version(); - - if (version.first < 3) - throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); - - initializeOpenGLFunctions(); - - /* Prepare the shader version string */ - glslVersion = reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); - glslVersion.truncate(4); - glslVersion.remove('.'); - glslVersion.prepend("#version "); - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) - glslVersion.append(" es"); - else if (context->format().profile() == QSurfaceFormat::CoreProfile) - glslVersion.append(" core"); - - initializeExtensions(); - - initializeBuffers(); - - /* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */ - const GLfloat surface[] = { - -1.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, - 1.f, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f, - -1.f, -1.f, 0.f, 1.f, 1.f, 1.f, 1.f, 1.f, - 1.f, -1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f - }; - - glGenVertexArrays(1, &vertexArrayID); - - glBindVertexArray(vertexArrayID); - - glGenBuffers(1, &vertexBufferID); - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); - glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW); - - glGenTextures(1, &textureID); - glBindTexture(GL_TEXTURE_2D, textureID); - - const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f }; - - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - glTexImage2D(GL_TEXTURE_2D, 0, QOpenGLTexture::RGBA8_UNorm, INIT_WIDTH, INIT_HEIGHT, 0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - - reloadOptions(); - - glClearColor(0.f, 0.f, 0.f, 1.f); - - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); - - GLenum error = glGetError(); - if (error != GL_NO_ERROR) - throw opengl_init_error(tr("OpenGL initialization failed. Error %1.").arg(error)); - - isInitialized = true; - - emit initialized(); - - glClear(GL_COLOR_BUFFER_BIT); - - context->swapBuffers(this); - } catch (const opengl_init_error &e) { - /* Mark all buffers as in use */ - for (auto &flag : buf_usage) - flag.test_and_set(); - - QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() % tr("\nFalling back to software rendering.")); - - context->doneCurrent(); - isFinalized = true; - isInitialized = true; - - emit errorInitializing(); - } -} - -void -OpenGLRenderer::finalize() -{ - if (isFinalized) - return; - - renderTimer->stop(); - - context->makeCurrent(this); - - if (hasBufferStorage) - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - - glDeleteBuffers(1, &unpackBufferID); - glDeleteTextures(1, &textureID); - glDeleteBuffers(1, &vertexBufferID); - glDeleteVertexArrays(1, &vertexArrayID); - - if (!hasBufferStorage && unpackBuffer) - free(unpackBuffer); - - context->doneCurrent(); - - isFinalized = true; -} - -QDialog * -OpenGLRenderer::getOptions(QWidget *parent) -{ - auto dialog = new OpenGLOptionsDialog(parent, *options, [this]() { return new OpenGLOptions(this, false, glslVersion); }); - - connect(dialog, &OpenGLOptionsDialog::optionsChanged, this, &OpenGLRenderer::updateOptions); - - return dialog; -} - -void -OpenGLRenderer::initializeExtensions() -{ -#ifndef NO_BUFFER_STORAGE - if (context->hasExtension("GL_ARB_buffer_storage") || context->hasExtension("GL_EXT_buffer_storage")) { - hasBufferStorage = true; - - glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress(context->hasExtension("GL_EXT_buffer_storage") ? "glBufferStorageEXT" : "glBufferStorage"); - if (!glBufferStorage) - glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress("glBufferStorage"); - } -#endif -} - -void -OpenGLRenderer::initializeBuffers() -{ - glGenBuffers(1, &unpackBufferID); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); - - if (hasBufferStorage) { -#ifndef NO_BUFFER_STORAGE - /* Create persistent buffer for pixel transfer. */ - glBufferStorage(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); - - unpackBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, BUFFERBYTES * BUFFERCOUNT, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); -#endif - } else { - /* Fallback; create our own buffer. */ - unpackBuffer = malloc(BUFFERBYTES * BUFFERCOUNT); - - if (unpackBuffer == nullptr) - throw opengl_init_error(tr("Allocating memory for unpack buffer failed.")); - - glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW); - } -} - -void -OpenGLRenderer::applyOptions() -{ - /* TODO: change detection in options */ - - if (options->framerate() > 0) { - int interval = (int) ceilf(1000.f / (float) options->framerate()); - renderTimer->setInterval(std::chrono::milliseconds(interval)); - } - - if (options->renderBehavior() == OpenGLOptions::TargetFramerate) - renderTimer->start(); - else - renderTimer->stop(); - - auto format = this->format(); - int interval = options->vSync() ? 1 : 0; - - if (format.swapInterval() != interval) { - format.setSwapInterval(interval); - setFormat(format); - context->setFormat(format); - } - - GLint filter = options->filter() == OpenGLOptions::Linear ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - - currentFilter = options->filter(); -} - -void -OpenGLRenderer::reloadOptions() -{ - if (options) { - delete options; - options = nullptr; - } - options = new OpenGLOptions(this, true, glslVersion); - - applyOptions(); -} - -void -OpenGLRenderer::applyShader(const OpenGLShaderPass &shader) -{ - if (!shader.bind()) - return; - - if (shader.vertex_coord() != -1) { - glEnableVertexAttribArray(shader.vertex_coord()); - glVertexAttribPointer(shader.vertex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0); - } - - if (shader.tex_coord() != -1) { - glEnableVertexAttribArray(shader.tex_coord()); - glVertexAttribPointer(shader.tex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (2 * sizeof(GLfloat))); - } - - if (shader.color() != -1) { - glEnableVertexAttribArray(shader.color()); - glVertexAttribPointer(shader.color(), 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (4 * sizeof(GLfloat))); - } - - if (shader.mvp_matrix() != -1) { - static const GLfloat mvp[] = { - 1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f - }; - glUniformMatrix4fv(shader.mvp_matrix(), 1, GL_FALSE, mvp); - } - - if (shader.output_size() != -1) - glUniform2f(shader.output_size(), destination.width(), destination.height()); - - if (shader.input_size() != -1) - glUniform2f(shader.input_size(), source.width(), source.height()); - - if (shader.texture_size() != -1) - glUniform2f(shader.texture_size(), source.width(), source.height()); - - if (shader.frame_count() != -1) - glUniform1i(shader.frame_count(), frameCounter); -} - -void -OpenGLRenderer::render() -{ - context->makeCurrent(this); - - if (options->filter() != currentFilter) - applyOptions(); - - /* TODO: multiple shader passes */ - applyShader(options->shaders().first()); - - glClear(GL_COLOR_BUFFER_BIT); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - context->swapBuffers(this); - - frameCounter = (frameCounter + 1) & 1023; -} - -void -OpenGLRenderer::updateOptions(OpenGLOptions *newOptions) -{ - context->makeCurrent(this); - - glUseProgram(0); - - delete options; - - options = newOptions; - - options->setParent(this); - - applyOptions(); -} - -std::vector> -OpenGLRenderer::getBuffers() -{ - std::vector> buffers; - - if (notReady() || !unpackBuffer) - return buffers; - - /* Split the buffer area */ - for (int i = 0; i < BUFFERCOUNT; i++) { - buffers.push_back(std::make_tuple((uint8_t *) unpackBuffer + BUFFERBYTES * i, &buf_usage[i])); - } - - return buffers; -} - -void -OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) -{ - if (notReady()) - return; - - context->makeCurrent(this); - -#ifdef Q_OS_MACOS - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); -#endif - - if (source.width() != w || source.height() != h) { - source.setRect(0, 0, w, h); - - /* Resize the texture */ - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, source.width(), source.height(), 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); - } - - if (!hasBufferStorage) - glBufferSubData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * buf_idx, h * ROW_LENGTH * sizeof(uint32_t) + (y * ROW_LENGTH * sizeof(uint32_t)), (uint8_t *) unpackBuffer + BUFFERBYTES * buf_idx); - - glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * buf_idx + y * ROW_LENGTH + x); - glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - - /* TODO: check if fence sync is implementable here and still has any benefit. */ - glFinish(); - - buf_usage[buf_idx].clear(); - - if (options->renderBehavior() == OpenGLOptions::SyncWithVideo) - render(); -} diff --git a/src/qt/qt_openglrenderer.hpp b/src/qt/qt_openglrenderer.hpp deleted file mode 100644 index 27822600c..000000000 --- a/src/qt/qt_openglrenderer.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - * - * Header file for OpenGL renderer - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLRENDERER_HPP -#define QT_OPENGLRENDERER_HPP - -#if defined Q_OS_MACOS || __arm__ -# define NO_BUFFER_STORAGE -#endif - -#include -#include -#include -#include -#include -#include -#if !defined NO_BUFFER_STORAGE && !(QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) -# include -#endif - -#include -#include -#include -#include - -#include "qt_opengloptions.hpp" -#include "qt_renderercommon.hpp" - -typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); - -class OpenGLRenderer : public QWindow, protected QOpenGLExtraFunctions, public RendererCommon { - Q_OBJECT - -public: - QOpenGLContext *context; - - OpenGLRenderer(QWidget *parent = nullptr); - ~OpenGLRenderer(); - - std::vector> getBuffers() override; - - void finalize() override final; - bool hasOptions() const override { return true; } - QDialog *getOptions(QWidget *parent) override; - void reloadOptions() override; - -signals: - void initialized(); - void errorInitializing(); - -public slots: - void onBlit(int buf_idx, int x, int y, int w, int h); - -protected: - void exposeEvent(QExposeEvent *event) override; - void resizeEvent(QResizeEvent *event) override; - bool event(QEvent *event) override; - -private: - static constexpr int INIT_WIDTH = 640; - static constexpr int INIT_HEIGHT = 400; - static constexpr int ROW_LENGTH = 2048; - static constexpr int BUFFERPIXELS = 4194304; - static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ - static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ - - QTimer *renderTimer; - OpenGLOptions *options; - - QString glslVersion; - - bool isInitialized = false; - bool isFinalized = false; - - GLuint unpackBufferID = 0; - GLuint vertexArrayID = 0; - GLuint vertexBufferID = 0; - GLuint textureID = 0; - int frameCounter = 0; - - OpenGLOptions::FilterType currentFilter; - - void *unpackBuffer = nullptr; - - void initialize(); - void initializeExtensions(); - void initializeBuffers(); - void applyOptions(); - void applyShader(const OpenGLShaderPass &shader); - bool notReady() const { return !isInitialized || isFinalized; } - - /* GL_ARB_buffer_storage */ - bool hasBufferStorage = false; -#ifndef NO_BUFFER_STORAGE - PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr; -#endif - -private slots: - void render(); - void updateOptions(OpenGLOptions *newOptions); -}; - -class opengl_init_error : public std::runtime_error { -public: - opengl_init_error(const QString &what) - : std::runtime_error(what.toStdString()) - { - } -}; - -#endif diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 79960323f..5b1c8518d 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -1,3 +1,26 @@ +/* + * 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. + * + * OpenGL renderer for Qt, mostly ported over from PCem. + * + * + * + * Authors: Teemu Korhonen + * Cacodemon345 + * bit + * Sarah Walker + * + * Copyright 2022 Teemu Korhonen + * Copyright 2025 Cacodemon345 + * Copyright 2017 Bit + * Copyright 2017-2020 Sarah Walker + */ + #include "qt_renderercommon.hpp" #include "qt_mainwindow.hpp" @@ -114,7 +137,7 @@ next_pow2(unsigned int n) } int -OpenGLRendererPCem::create_program(struct shader_program *program) +OpenGLRenderer::create_program(struct shader_program *program) { GLint status; program->id = glw.glCreateProgram(); @@ -146,7 +169,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) } int -OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) +OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) { const char *source[3]; char version[50]; @@ -197,19 +220,19 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons } GLuint -OpenGLRendererPCem::get_uniform(GLuint program, const char *name) +OpenGLRenderer::get_uniform(GLuint program, const char *name) { return glw.glGetUniformLocation(program, name); } GLuint -OpenGLRendererPCem::get_attrib(GLuint program, const char *name) +OpenGLRenderer::get_attrib(GLuint program, const char *name) { return glw.glGetAttribLocation(program, name); } void -OpenGLRendererPCem::find_uniforms(struct glsl_shader *glsl, int num_pass) +OpenGLRenderer::find_uniforms(struct glsl_shader *glsl, int num_pass) { int i; char s[50]; @@ -294,7 +317,7 @@ setup_scale(struct shader *shader, struct shader_pass *pass) } void -OpenGLRendererPCem::create_texture(struct shader_texture *tex) +OpenGLRenderer::create_texture(struct shader_texture *tex) { if (tex->width > max_texture_size) tex->width = max_texture_size; @@ -314,7 +337,7 @@ OpenGLRendererPCem::create_texture(struct shader_texture *tex) } void -OpenGLRendererPCem::delete_texture(struct shader_texture *tex) +OpenGLRenderer::delete_texture(struct shader_texture *tex) { if (tex->id > 0) glw.glDeleteTextures(1, (GLuint *) &tex->id); @@ -322,7 +345,7 @@ OpenGLRendererPCem::delete_texture(struct shader_texture *tex) } void -OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo) +OpenGLRenderer::delete_fbo(struct shader_fbo *fbo) { if (fbo->id >= 0) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -331,7 +354,7 @@ OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo) } void -OpenGLRendererPCem::delete_program(struct shader_program *program) +OpenGLRenderer::delete_program(struct shader_program *program) { if (program->vertex_shader) glw.glDeleteShader(program->vertex_shader); @@ -341,7 +364,7 @@ OpenGLRendererPCem::delete_program(struct shader_program *program) } void -OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo) +OpenGLRenderer::delete_vbo(struct shader_vbo *vbo) { if (vbo->color >= 0) glw.glDeleteBuffers(1, (GLuint *) &vbo->color); @@ -350,7 +373,7 @@ OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo) } void -OpenGLRendererPCem::delete_pass(struct shader_pass *pass) +OpenGLRenderer::delete_pass(struct shader_pass *pass) { delete_fbo(&pass->fbo); delete_vbo(&pass->vbo); @@ -359,14 +382,14 @@ OpenGLRendererPCem::delete_pass(struct shader_pass *pass) } void -OpenGLRendererPCem::delete_prev(struct shader_prev *prev) +OpenGLRenderer::delete_prev(struct shader_prev *prev) { delete_fbo(&prev->fbo); delete_vbo(&prev->vbo); } void -OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl) +OpenGLRenderer::delete_shader(struct glsl_shader *glsl) { int i; for (i = 0; i < glsl->num_passes; ++i) @@ -381,7 +404,7 @@ OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl) } void -OpenGLRendererPCem::delete_glsl(glsl_t *glsl) +OpenGLRenderer::delete_glsl(glsl_t *glsl) { int i; for (i = 0; i < glsl->num_shaders; ++i) @@ -395,7 +418,7 @@ OpenGLRendererPCem::delete_glsl(glsl_t *glsl) } void -OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo) +OpenGLRenderer::create_fbo(struct shader_fbo *fbo) { create_texture(&fbo->texture); @@ -410,7 +433,7 @@ OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo) } void -OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo) +OpenGLRenderer::setup_fbo(struct shader *shader, struct shader_fbo *fbo) { fbo->texture.internal_format = GL_RGBA8; fbo->texture.format = GL_RGBA; @@ -442,7 +465,7 @@ OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo) } void -OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height) +OpenGLRenderer::recreate_fbo(struct shader_fbo *fbo, int width, int height) { if (width != fbo->texture.width || height != fbo->texture.height) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -454,7 +477,7 @@ OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height) } int -OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass) +OpenGLRenderer::create_default_shader_tex(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -474,7 +497,7 @@ OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass) } int -OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass) +OpenGLRenderer::create_default_shader_color(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -494,7 +517,7 @@ OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass) /* create the default scene shader */ void -OpenGLRendererPCem::create_scene_shader() +OpenGLRenderer::create_scene_shader() { struct shader scene_shader_conf; memset(&scene_shader_conf, 0, sizeof(struct shader)); @@ -554,7 +577,7 @@ load_texture(const char *f, struct shader_texture *tex) } glsl_t * -OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) +OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) { int i, j; glslp_t *p = glslp_parse(f); @@ -704,7 +727,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) } glsl_t * -OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +OpenGLRenderer::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) { int i; glsl_t *glsl; @@ -731,7 +754,7 @@ OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) } void -OpenGLRendererPCem::read_shader_config() +OpenGLRenderer::read_shader_config() { char s[512]; int i, j; @@ -747,10 +770,9 @@ OpenGLRendererPCem::read_shader_config() } } -OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) +OpenGLRenderer::OpenGLRenderer(QWidget *parent) : QWindow(parent->windowHandle()) , renderTimer(new QTimer(this)) - , options(nullptr) { connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } ); imagebufs[0] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); @@ -785,10 +807,10 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) isFinalized = false; } -OpenGLRendererPCem::~OpenGLRendererPCem() { finalize(); } +OpenGLRenderer::~OpenGLRenderer() { finalize(); } void -OpenGLRendererPCem::initialize() +OpenGLRenderer::initialize() { try { context = new QOpenGLContext(this); @@ -796,15 +818,15 @@ OpenGLRendererPCem::initialize() context->setFormat(format()); if (!context->create()) - throw opengl_init_error_pcem(tr("Couldn't create OpenGL context.")); + throw opengl_init_error(tr("Couldn't create OpenGL context.")); if (!context->makeCurrent(this)) - throw opengl_init_error_pcem(tr("Couldn't switch to OpenGL context.")); + throw opengl_init_error(tr("Couldn't switch to OpenGL context.")); auto version = context->format().version(); if (version.first < 3) - throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); + throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); glw.initializeOpenGLFunctions(); @@ -813,7 +835,7 @@ OpenGLRendererPCem::initialize() glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); if (glsl_version[0] < 3) { - throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); + throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); } pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); @@ -1035,7 +1057,7 @@ OpenGLRendererPCem::initialize() glw.glClear(GL_COLOR_BUFFER_BIT); context->swapBuffers(this); - } catch (const opengl_init_error_pcem &e) { + } catch (const opengl_init_error &e) { /* Mark all buffers as in use */ for (auto &flag : buf_usage) flag.test_and_set(); @@ -1051,7 +1073,7 @@ OpenGLRendererPCem::initialize() } void -OpenGLRendererPCem::finalize() +OpenGLRenderer::finalize() { if (isFinalized) return; @@ -1074,7 +1096,7 @@ OpenGLRendererPCem::finalize() } void -OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) +OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) { if (notReady()) return; @@ -1112,7 +1134,7 @@ OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) } std::vector> -OpenGLRendererPCem::getBuffers() +OpenGLRenderer::getBuffers() { std::vector> buffers; @@ -1123,7 +1145,7 @@ OpenGLRendererPCem::getBuffers() } void -OpenGLRendererPCem::exposeEvent(QExposeEvent *event) +OpenGLRenderer::exposeEvent(QExposeEvent *event) { Q_UNUSED(event); @@ -1134,7 +1156,7 @@ OpenGLRendererPCem::exposeEvent(QExposeEvent *event) } void -OpenGLRendererPCem::resizeEvent(QResizeEvent *event) +OpenGLRenderer::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); @@ -1153,7 +1175,7 @@ OpenGLRendererPCem::resizeEvent(QResizeEvent *event) } void -OpenGLRendererPCem::render_pass(struct render_data *data) +OpenGLRenderer::render_pass(struct render_data *data) { int i; GLuint texture_unit = 0; @@ -1298,7 +1320,7 @@ OpenGLRendererPCem::render_pass(struct render_data *data) } bool -OpenGLRendererPCem::event(QEvent *event) +OpenGLRenderer::event(QEvent *event) { Q_UNUSED(event); @@ -1309,13 +1331,13 @@ OpenGLRendererPCem::event(QEvent *event) } QDialog* -OpenGLRendererPCem::getOptions(QWidget *parent) +OpenGLRenderer::getOptions(QWidget *parent) { return new OpenGLShaderManagerDialog(parent); } void -OpenGLRendererPCem::render() +OpenGLRenderer::render() { if (!context) return; @@ -1353,17 +1375,12 @@ OpenGLRendererPCem::render() struct { uint32_t x, y, w, h; - } rect, video_rect; + } rect; rect.x = 0; rect.y = 0; rect.w = source.width(); rect.h = source.height(); - video_rect.x = source.x(); - video_rect.y = source.y(); - video_rect.w = source.width(); - video_rect.h = source.height(); - pass->state.input_size[0] = pass->state.output_size[0] = rect.w; pass->state.input_size[1] = pass->state.output_size[1] = rect.h; diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp index 706a744fa..9db1e7307 100644 --- a/src/qt/qt_openglrenderer_pcem.hpp +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -11,12 +11,14 @@ * * * Authors: Teemu Korhonen + * Cacodemon345 * * Copyright 2022 Teemu Korhonen + * Copyright 2025 Cacodemon345 */ -#ifndef QT_OpenGLRendererPCem_HPP -#define QT_OpenGLRendererPCem_HPP +#ifndef QT_OpenGLRenderer_HPP +#define QT_OpenGLRenderer_HPP #if defined Q_OS_MACOS || __arm__ # define NO_BUFFER_STORAGE @@ -37,7 +39,6 @@ #include #include -#include "qt_opengloptions.hpp" #include "qt_renderercommon.hpp" extern "C" @@ -55,14 +56,14 @@ struct render_data { int frame_count; }; -class OpenGLRendererPCem : public QWindow, public RendererCommon { +class OpenGLRenderer : public QWindow, public RendererCommon { Q_OBJECT public: QOpenGLContext *context; - OpenGLRendererPCem(QWidget *parent = nullptr); - ~OpenGLRendererPCem(); + OpenGLRenderer(QWidget *parent = nullptr); + ~OpenGLRenderer(); std::vector> getBuffers() override; @@ -88,7 +89,6 @@ private: std::array, 2> imagebufs; QTimer *renderTimer; - OpenGLOptions *options; QString glslVersion = ""; @@ -98,7 +98,6 @@ private: int max_texture_size = 65536; int frameCounter = 0; - OpenGLOptions::FilterType currentFilter; QOpenGLExtraFunctions glw; struct shader_texture scene_texture; glsl_t *active_shader; @@ -144,12 +143,11 @@ private: private slots: void render(); - //void updateOptions(OpenGLOptions *newOptions); }; -class opengl_init_error_pcem : public std::runtime_error { +class opengl_init_error : public std::runtime_error { public: - opengl_init_error_pcem(const QString &what) + opengl_init_error(const QString &what) : std::runtime_error(what.toStdString()) { } diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 63d35e719..26ea2271f 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -22,7 +22,6 @@ #include "ui_qt_rendererstack.h" #include "qt_hardwarerenderer.hpp" -#include "qt_openglrenderer.hpp" #include "qt_openglrenderer_pcem.hpp" #include "qt_softwarerenderer.hpp" #include "qt_vulkanwindowrenderer.hpp" @@ -341,16 +340,16 @@ RendererStack::createRenderer(Renderer renderer) case Renderer::OpenGL3PCem: { this->createWinId(); - auto hw = new OpenGLRendererPCem(this); + auto hw = new OpenGLRenderer(this); rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRendererPCem::initialized, [=]() { + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRenderer::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); }); - connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { + connect(hw, &OpenGLRenderer::errorInitializing, [=]() { /* Renderer not could initialize, fallback to software. */ imagebufs = {}; QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); @@ -361,16 +360,16 @@ RendererStack::createRenderer(Renderer renderer) case Renderer::OpenGL3: { this->createWinId(); - auto hw = new OpenGLRendererPCem(this); + auto hw = new OpenGLRenderer(this); rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRendererPCem::initialized, [=]() { + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRenderer::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); }); - connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { + connect(hw, &OpenGLRenderer::errorInitializing, [=]() { /* Renderer not could initialize, fallback to software. */ imagebufs = {}; QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); From 3cad9024c843575792f3d062d73c350396183c1a Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 21:14:10 +0600 Subject: [PATCH 073/218] Rename the files as well --- src/qt/CMakeLists.txt | 4 ++-- src/qt/{qt_openglrenderer_pcem.cpp => qt_openglrenderer.cpp} | 2 +- src/qt/{qt_openglrenderer_pcem.hpp => qt_openglrenderer.hpp} | 0 src/qt/qt_rendererstack.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/qt/{qt_openglrenderer_pcem.cpp => qt_openglrenderer.cpp} (99%) rename src/qt/{qt_openglrenderer_pcem.hpp => qt_openglrenderer.hpp} (100%) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 8137be98e..90ea218af 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -87,8 +87,8 @@ add_library(ui STATIC qt_softwarerenderer.hpp qt_hardwarerenderer.cpp qt_hardwarerenderer.hpp - qt_openglrenderer_pcem.cpp - qt_openglrenderer_pcem.hpp + qt_openglrenderer.cpp + qt_openglrenderer.hpp qt_glsl_parser.cpp qt_settings.cpp diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer.cpp similarity index 99% rename from src/qt/qt_openglrenderer_pcem.cpp rename to src/qt/qt_openglrenderer.cpp index 5b1c8518d..97a782f57 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -45,7 +45,7 @@ extern MainWindow* main_window; #include -#include "qt_openglrenderer_pcem.hpp" +#include "qt_openglrenderer.hpp" #include "qt_openglshadermanagerdialog.hpp" extern "C" { diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer.hpp similarity index 100% rename from src/qt/qt_openglrenderer_pcem.hpp rename to src/qt/qt_openglrenderer.hpp diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 26ea2271f..ca16b680e 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -22,7 +22,7 @@ #include "ui_qt_rendererstack.h" #include "qt_hardwarerenderer.hpp" -#include "qt_openglrenderer_pcem.hpp" +#include "qt_openglrenderer.hpp" #include "qt_softwarerenderer.hpp" #include "qt_vulkanwindowrenderer.hpp" From 1ac02618b0fa9d6acc8f3f9f1d053706884dc313 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 21:22:52 +0600 Subject: [PATCH 074/218] Clean up secondary monitors properly on close --- src/qt/qt_mainwindow.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 85bc0de55..3af9c6f70 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -784,6 +784,14 @@ MainWindow::closeEvent(QCloseEvent *event) ui->stackedWidget->mouse_exit_func(); ui->stackedWidget->switchRenderer(RendererStack::Renderer::Software); + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->isHidden()) { + renderers[i]->show(); + QApplication::processEvents(); + renderers[i]->switchRenderer(RendererStack::Renderer::Software); + QApplication::processEvents(); + } + } qt_nvr_save(); config_save(); From c832729ee565fdd54eadec896f2f9bb72b1cc99b Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 16:31:52 +0100 Subject: [PATCH 075/218] Config: Ignore the GL3 stuff on SDL builds. --- src/config.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/config.c b/src/config.c index 5ad804df6..e5fbe59b4 100644 --- a/src/config.c +++ b/src/config.c @@ -77,9 +77,11 @@ #include <86box/snd_opl.h> #include <86box/version.h> +#ifndef USE_SDL_UI /* Deliberate to not make the 86box.h header kitchen-sink. */ #include <86box/qt-glsl.h> extern char gl3_shader_file[MAX_USER_SHADERS][512]; +#endif static int cx; static int cy; @@ -1717,6 +1719,7 @@ load_other_peripherals(void) ini_section_delete_var(cat, temp); } +#ifndef USE_SDL_UI /* Load OpenGL 3.0 renderer options. */ static void load_gl3_shaders(void) @@ -1756,6 +1759,7 @@ load_gl3_shaders(void) } } } +#endif /* Load the specified or a default configuration file. */ void @@ -1853,7 +1857,9 @@ config_load(void) load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ load_other_removable_devices(); /* Other removable devices */ load_other_peripherals(); /* Other peripherals */ +#ifndef USE_SDL_UI load_gl3_shaders(); /* GL3 Shaders */ +#endif /* Migrate renamed device configurations. */ c = ini_find_section(config, "MDA"); @@ -2672,6 +2678,7 @@ save_other_peripherals(void) ini_delete_section_if_empty(config, cat); } +#ifndef USE_SDL_UI /* Save "GL3 Shaders" section. */ static void save_gl3_shaders(void) @@ -2703,6 +2710,7 @@ save_gl3_shaders(void) ini_delete_section_if_empty(config, cat); } +#endif /* Save "Hard Disks" section. */ static void @@ -3059,7 +3067,9 @@ config_save(void) save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ save_other_removable_devices(); /* Other removable devices */ save_other_peripherals(); /* Other peripherals */ +#ifndef USE_SDL_UI save_gl3_shaders(); /* GL3 Shaders */ +#endif ini_write(config, cfg_path); } From 48a5f3280fed8def764c6d8406a252155964eea1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:26:44 +0100 Subject: [PATCH 076/218] device_t: Increase the selection array to 64 elements. --- src/include/86box/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/86box/device.h b/src/include/86box/device.h index fb86d2adc..91ff2daa6 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -153,7 +153,7 @@ typedef struct _device_config_ { int default_int; const char *file_filter; const device_config_spinner_t spinner; - const device_config_selection_t selection[32]; + const device_config_selection_t selection[64]; const device_config_bios_t bios[32]; } device_config_t; From 8a2d841322c2af189acad170a678cad70cd11c24 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:29:42 +0100 Subject: [PATCH 077/218] OpenGL Renderer: Mark reloadRendererOption() as override, fixes compile on Mac. --- src/qt/qt_openglrenderer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.hpp b/src/qt/qt_openglrenderer.hpp index 9db1e7307..4d1f68acb 100644 --- a/src/qt/qt_openglrenderer.hpp +++ b/src/qt/qt_openglrenderer.hpp @@ -70,7 +70,7 @@ public: void finalize() override final; bool hasOptions() const override { return true; } QDialog *getOptions(QWidget *parent) override; - bool reloadRendererOption() { return true; } + bool reloadRendererOption() override { return true; } signals: void initialized(); From c763c6db169c2b4f2ed9d1f8177d36d67166edfa Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:31:18 +0100 Subject: [PATCH 078/218] INI: Include so iswspace() is also found in Linux. --- src/ini.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ini.c b/src/ini.c index 503b17ae3..f5dfdef46 100644 --- a/src/ini.c +++ b/src/ini.c @@ -33,6 +33,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/ini.h> From 6fa39b3a67a0818f3d6a2535e5074d5901558cc1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:32:46 +0100 Subject: [PATCH 079/218] OpenGL Renderer: Explicitly cast const char * to char *. --- src/qt/qt_openglrenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 97a782f57..860b5d303 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -174,7 +174,7 @@ OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const ch const char *source[3]; char version[50]; int ver = 0; - char *version_loc = strstr(program, "#version"); + char *version_loc = (char *) strstr(program, "#version"); if (version_loc) ver = (int) strtol(version_loc + 8, (char **) &program, 10); else { From df85868e00cd3d8e71300f8d89323d8fd0be5631 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:34:33 +0100 Subject: [PATCH 080/218] Config: Brought the strncpy() in load_gl3_shaders() in line with the other stncpy()'s. --- src/config.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index e5fbe59b4..f68b23c37 100644 --- a/src/config.c +++ b/src/config.c @@ -1740,7 +1740,10 @@ load_gl3_shaders(void) if (general) { p = ini_section_get_string(general, "video_gl_shader", NULL); if (p) { - strncpy(gl3_shader_file[0], p, 512); + if (strlen(p) > 511) + fatal("Configuration: Length of video_gl_shadr is more than 511\n"); + else + strncpy(gl3_shader_file[0], p, 511); ini_delete_var(config, general, "video_gl_shader"); return; } From daf6e242efa3f244d05aa3f5ba6cf4b50b3c66a5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 18:00:28 +0100 Subject: [PATCH 081/218] QT GLSL Parser: More explicit const char * to char * casts. --- src/qt/qt_glsl_parser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index bf02014db..9a0a0fc03 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -101,11 +101,11 @@ static char *load_file(const char *fn) { static void strip_lines(const char *program, const char *starts_with) { /* strip parameters */ - char *ptr = strstr(program, starts_with); - while (ptr) { + char *ptr = (char *) strstr(program, starts_with); + while (ptr != nullptr) { while (*ptr != '\n' && *ptr != '\0') *ptr++ = ' '; - ptr = strstr(program, starts_with); + ptr = (char *) strstr(program, starts_with); } } From df1f739b90f53c1532492f6fa50c7585f0e95718 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 23:02:18 +0600 Subject: [PATCH 082/218] OpenGL 3.x screenshots are now processed --- src/qt/qt_openglrenderer.cpp | 114 +++++++++-------------------------- src/qt/qt_renderercommon.hpp | 2 + src/qt/qt_rendererstack.cpp | 7 ++- src/qt/qt_rendererstack.hpp | 4 ++ 4 files changed, 39 insertions(+), 88 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 860b5d303..37afd4810 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1612,95 +1612,35 @@ OpenGLRenderer::render() render_pass(&data); } - if (1) { - // if (video_focus_dim && !(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)) { -#if 0 - if (0) { - struct shader_pass *pass = &active_shader->fs_color; - GLfloat r = 0; - GLfloat g = 0; - GLfloat b = 0; - GLfloat a = 0x80 / (float) 0xff; + if (monitors[r_monitor_index].mon_screenshots) { + int width = destination.width() * devicePixelRatio(), height = destination.height() * devicePixelRatio(); + char path[1024]; + char fn[256]; + + memset(fn, 0, sizeof(fn)); + memset(path, 0, sizeof(path)); + + path_append_filename(path, usr_path, SCREENSHOT_PATH); + + if (!plat_dir_check(path)) + plat_dir_create(path); + + path_slash(path); + strcat(path, "Monitor_"); + snprintf(&path[strlen(path)], 42, "%d_", r_monitor_index + 1); + + plat_tempfile(fn, NULL, (char*)".png"); + strcat(path, fn); - GLfloat colors[] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; + unsigned char *rgba = (unsigned char *)calloc(1, width * height * 4); + + glw.glFinish(); + glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); - glw.glBindVertexArray(pass->vertex_array); - - glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); - glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); - glw.glBindBuffer(GL_ARRAY_BUFFER, 0); - - memset(&data, 0, sizeof(struct render_data)); - data.pass = -3; - data.shader_pass = pass; - data.texture = 0; - data.output_size = orig_output_size; - data.orig_pass = orig; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - render_pass(&data); - glDisable(GL_BLEND); - } - - if (flash.enabled) { - struct shader_pass *pass = &active_shader->fs_color; - GLfloat r = (flash.color[0] & 0xff) / (float)0xff; - GLfloat g = (flash.color[1] & 0xff) / (float)0xff; - GLfloat b = (flash.color[2] & 0xff) / (float)0xff; - GLfloat a = (flash.color[3] & 0xff) / (float)0xff; - - GLfloat colors[] = {r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a}; - - glw.glBindVertexArray(pass->vertex_array); - - glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); - glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); - glw.glBindBuffer(GL_ARRAY_BUFFER, 0); - - memset(&data, 0, sizeof(struct render_data)); - data.pass = -3; - data.shader_pass = pass; - data.texture = 0; - data.output_size = orig_output_size; - data.orig_pass = orig; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - render_pass(&data); - glDisable(GL_BLEND); - } -#endif - } else { -#if 0 - take_screenshot = 0; - - int width = window_rect.w; - int height = window_rect.h; - - SDL_GetWindowSize(window, &width, &height); - - unsigned char *rgba = (unsigned char *)malloc(width * height * 4); - - glFinish(); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); - - int x, y; - unsigned char *rgb = (unsigned char *)malloc(width * height * 3); - - for (x = 0; x < width; ++x) { - for (y = 0; y < height; ++y) { - rgb[(y * width + x) * 3 + 0] = rgba[((height - y - 1) * width + x) * 4 + 0]; - rgb[(y * width + x) * 3 + 1] = rgba[((height - y - 1) * width + x) * 4 + 1]; - rgb[(y * width + x) * 3 + 2] = rgba[((height - y - 1) * width + x) * 4 + 2]; - } - } - - screenshot_taken(rgb, width, height); - - free(rgb); - free(rgba); -#endif + QImage image(rgba, width, height, QImage::Format_RGBA8888); + image.mirrored(false, true).save(path, "png"); + monitors[r_monitor_index].mon_screenshots--; + free(rgba); } glw.glDisable(GL_FRAMEBUFFER_SRGB); diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index f3f5d2223..bbda9516b 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -36,6 +36,8 @@ public: virtual void reloadOptions() { } /* Make the renderer reload itself */ virtual bool reloadRendererOption() { return false; } + /* Should the renderer take screenshots itself? */ + virtual bool rendererTakeScreenshot() { return false; } int r_monitor_index = 0; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index ca16b680e..38f087622 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -63,6 +63,7 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) : QStackedWidget(parent) , ui(new Ui::RendererStack) { + rendererTakesScreenshots = false; #ifdef Q_OS_WINDOWS int raw = 1; #else @@ -305,6 +306,7 @@ RendererStack::switchRenderer(Renderer renderer) void RendererStack::createRenderer(Renderer renderer) { + rendererTakesScreenshots = false; switch (renderer) { default: case Renderer::Software: @@ -360,6 +362,7 @@ RendererStack::createRenderer(Renderer renderer) case Renderer::OpenGL3: { this->createWinId(); + this->rendererTakesScreenshots = true; auto hw = new OpenGLRenderer(this); rendererWindow = hw; connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); @@ -424,6 +427,8 @@ RendererStack::createRenderer(Renderer renderer) this->setStyleSheet("background-color: black"); + rendererWindow->r_monitor_index = m_monitor_index; + currentBuf = 0; if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::OpenGL3PCem) { @@ -454,7 +459,7 @@ RendererStack::blit(int x, int y, int w, int h) video_copy(scanline, &(monitors[m_monitor_index].target_buffer->line[y1][x]), w * 4); } - if (monitors[m_monitor_index].mon_screenshots) { + if (monitors[m_monitor_index].mon_screenshots && !rendererTakesScreenshots) { video_screenshot_monitor((uint32_t *) imagebits, x, y, 2048, m_monitor_index); } video_blit_complete_monitor(m_monitor_index); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 32ed5f7ca..a84773c72 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -15,6 +15,8 @@ #include "qt_renderercommon.hpp" +#include + namespace Ui { class RendererStack; } @@ -110,6 +112,8 @@ private: RendererCommon *rendererWindow { nullptr }; std::unique_ptr current; + + std::atomic_bool rendererTakesScreenshots; }; #endif // QT_RENDERERCONTAINER_HPP From c2eb7730296d53c39bcf230b0d8334499324e782 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 23:27:19 +0600 Subject: [PATCH 083/218] Qt: Fix more compile errors --- src/qt/qt_openglshadermanagerdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 0bf083252..7f8a19414 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -46,7 +46,7 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); item->setText(filename); item->setData(Qt::UserRole + 1, QString(gl3_shader_file[i])); - item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + item->setData(Qt::UserRole + 2, (qulonglong)(uintptr_t)shaderfile); } } } @@ -174,7 +174,7 @@ void OpenGLShaderManagerDialog::on_buttonAdd_clicked() QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); item->setText(filename); item->setData(Qt::UserRole + 1, res); - item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + item->setData(Qt::UserRole + 2, (qulonglong)(uintptr_t)shaderfile); if (ui->shaderListWidget->count()) { ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); } From 2e77b47f89ec960416bb362dc75551afedd77800 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 11 Mar 2025 00:13:51 +0600 Subject: [PATCH 084/218] Call `glViewport` with correct function pointer --- src/qt/qt_openglrenderer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 37afd4810..6f024f36f 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1103,14 +1103,6 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) context->makeCurrent(this); -#ifdef Q_OS_MACOS - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); -#endif - if (source.width() != w || source.height() != h) { glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); glw.glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, w, h, 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); @@ -1129,6 +1121,14 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) source.setRect(x, y, w, h); onResize(this->width(), this->height()); +#ifdef Q_OS_MACOS + glw.glViewport( + destination.x() * devicePixelRatio(), + destination.y() * devicePixelRatio(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +#endif + if (video_framerate == -1) render(); } From f1720fdee481a226e4cc4269296a49be03269553 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 11 Mar 2025 01:20:00 +0600 Subject: [PATCH 085/218] Attempt fixing crash on NetBSD --- src/qt/qt_platform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 35dbc0081..a1deb4137 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -368,6 +368,8 @@ plat_mmap(size_t size, uint8_t executable) void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE | (executable ? MAP_JIT : 0), -1, 0); # elif defined(PROT_MPROTECT) void *ret = mmap(0, size, PROT_MPROTECT(PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0)), MAP_ANON | MAP_PRIVATE, -1, 0); + if (ret) + mprotect(ret, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0)); # else void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE, -1, 0); # endif From df5cc9b03876ac34f296a8ad900e116182fee47f Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 21:31:29 +0100 Subject: [PATCH 086/218] VIA PIPC: Restore old readout on the VT82C596/B southbridges, where it was correct, fixes the P6BAT. --- src/chipset/via_pipc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 11a192450..f7f5bf208 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -61,6 +61,7 @@ #define VIA_PIPC_586B 0x05864700 #define VIA_PIPC_596A 0x05960900 #define VIA_PIPC_596B 0x05962300 +#define VIA_PIPC_596 0x0596 #define VIA_PIPC_686A 0x06861400 #define VIA_PIPC_686B 0x06864000 #define VIA_PIPC_8231 0x82311000 @@ -413,7 +414,7 @@ pipc_reset_hard(void *priv) dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; - dev->power_regs[0x42] = 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; acpi_set_irq_line(dev->acpi, 0x00); dev->power_regs[0x48] = 0x01; @@ -1595,7 +1596,7 @@ pipc_reset(void *priv) pipc_write(pm_func, 0x48, 0x01, priv); pipc_write(pm_func, 0x49, 0x00, priv); - dev->power_regs[0x42] = 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; acpi_set_irq_line(dev->acpi, 0x00); pipc_write(1, 0x04, 0x80, priv); From 9e5697126b08ffb6329a40151da6f9caf1ea7b67 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 11 Mar 2025 10:40:40 +0100 Subject: [PATCH 087/218] QT: Fix two strings. --- src/qt/qt_main.cpp | 2 +- src/qt/qt_platform.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index b48d272c5..f6ddddd32 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -665,7 +665,7 @@ main(int argc, char *argv[]) /* Force raw input if a debugger is present. */ if (IsDebuggerPresent()) { - pclog("WARNING: Debugged detected, forcing raw input\n"); + pclog("WARNING: Debugger detected, forcing raw input\n"); hook_enabled = 0; } diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index a1deb4137..ee8d8842a 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -647,7 +647,7 @@ ProgSettings::reloadStrings() translatedstrings[STRING_NET_ERROR] = QCoreApplication::translate("", "Failed to initialize network driver").toStdWString(); translatedstrings[STRING_NET_ERROR_DESC] = QCoreApplication::translate("", "The network configuration will be switched to the null driver").toStdWString(); translatedstrings[STRING_ESCP_ERROR_TITLE] = QCoreApplication::translate("", "Unable to find Dot-Matrix fonts").toStdWString(); - translatedstrings[STRING_ESCP_ERROR_DESC] = QCoreApplication::translate("", "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulatio of the Generic ESC/P Dot-Matrix Printer.").toStdWString(); + translatedstrings[STRING_ESCP_ERROR_DESC] = QCoreApplication::translate("", "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer.").toStdWString(); } wchar_t * From 4d5adeae36d47085da9bcdd0014dbe1b2e12b391 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 11 Mar 2025 20:35:05 +0600 Subject: [PATCH 088/218] Restore older GLSL version code --- src/qt/qt_openglrenderer.cpp | 47 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 6f024f36f..b451c2245 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -34,6 +34,7 @@ extern MainWindow* main_window; #include #include #include +#include #include #include @@ -171,30 +172,33 @@ OpenGLRenderer::create_program(struct shader_program *program) int OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) { - const char *source[3]; + QRegularExpression versionRegex("^\\s*(#version\\s+\\w+)", QRegularExpression::MultilineOption); + QString progSource = QString(program); + QByteArray finalSource = nullptr; + const char *source[5]; char version[50]; int ver = 0; char *version_loc = (char *) strstr(program, "#version"); - if (version_loc) - ver = (int) strtol(version_loc + 8, (char **) &program, 10); - else { - ver = glsl_version[0] * 100 + glsl_version[1] * 10; - if (ver == 300) - ver = 130; - else if (ver == 310) - ver = 140; - else if (ver == 320) - ver = 150; + if (version_loc) { + snprintf(version, 49, "%s\n", versionRegex.match(progSource).captured(1).toLatin1().data()); + progSource.remove(versionRegex); + } else { + snprintf(version, 49, "%s\n", this->glslVersion.toLatin1().data()); } - sprintf(version, "#version %d\n", ver); - source[0] = version; - source[1] = prepend ? prepend : ""; - source[2] = program; + + /* Remove parameter lines. */ + progSource.remove(QRegularExpression("^\\s*#pragma parameter.*?\\n", QRegularExpression::MultilineOption)); - pclog("GLSL version %d\n", ver); + finalSource = progSource.toLatin1(); + + source[0] = version; + source[1] = "\n#extension GL_ARB_shading_language_420pack : enable\n"; + source[2] = prepend ? prepend : ""; + source[3] = "\n#line 1\n"; + source[4] = finalSource.data(); GLuint shader = glw.glCreateShader(shader_type); - glw.glShaderSource(shader, 3, source, NULL); + glw.glShaderSource(shader, 5, source, NULL); glw.glCompileShader(shader); GLint status = 0; @@ -840,6 +844,15 @@ OpenGLRenderer::initialize() pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); + glslVersion = reinterpret_cast(glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); + glslVersion.truncate(4); + glslVersion.remove('.'); + glslVersion.prepend("#version "); + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) + glslVersion.append(" es"); + else if (context->format().profile() == QSurfaceFormat::CoreProfile) + glslVersion.append(" core"); + glw.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); pclog("Max texture size: %dx%d\n", max_texture_size, max_texture_size); From e2aa66a523d6b465b277c86a23e6a0e8cc9f8eb6 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 12 Mar 2025 19:55:09 +0600 Subject: [PATCH 089/218] Qt: Make tooltip displays consistent --- src/qt/qdarkstyle/dark/darkstyle.qss | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index 6e1ec4b06..134d6708e 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -130,16 +130,6 @@ QStatusBar::item { border: none; } -QStatusBar QToolTip { - background-color: #666666; - border: 1px solid #272727; - color: #272727; - /* Remove padding, for fix combo box tooltip */ - padding: 0px; - /* Reducing transparency to read better */ - opacity: 230; -} - QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; From 1c54261a1b1a3e813d5cb2940e959b493b55f26f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 12 Mar 2025 21:16:53 +0600 Subject: [PATCH 090/218] Fix shader manager dialog crash when using multi-monitors --- src/qt/qt_openglrenderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index b451c2245..ef0332500 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -809,6 +809,7 @@ OpenGLRenderer::OpenGLRenderer(QWidget *parent) source.setRect(0, 0, 100, 100); isInitialized = false; isFinalized = false; + context = nullptr; } OpenGLRenderer::~OpenGLRenderer() { finalize(); } @@ -1088,7 +1089,7 @@ OpenGLRenderer::initialize() void OpenGLRenderer::finalize() { - if (isFinalized) + if (isFinalized || !context) return; context->makeCurrent(this); From 7261a0d74b11842370b2a326a96589f602f8133a Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Mar 2025 17:53:58 +0100 Subject: [PATCH 091/218] Hook input: Fix Pause scan code. --- src/qt/qt_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index f6ddddd32..10900da0d 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -359,7 +359,7 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) } else if (!(lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000013)) { /* Pause - send E1 1D. */ win_keyboard_handle(0xe1, 0, 0, 0); - win_keyboard_handle(0x1d, LLKHF_UP, 0, 0); + win_keyboard_handle(0x1d, lpKdhs->flags & LLKHF_UP, 0, 0); } } else if (!last && (lpKdhs->scanCode == 0x00000036)) /* Non-fake right shift. */ From c73c7212f8baab1b25503a4f962d90e8c7a2330c Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Mar 2025 18:02:01 +0100 Subject: [PATCH 092/218] QT OpenGL Renderer: Remove the unused variable "ver". --- src/qt/qt_openglrenderer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index ef0332500..f654747eb 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -177,7 +177,6 @@ OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const ch QByteArray finalSource = nullptr; const char *source[5]; char version[50]; - int ver = 0; char *version_loc = (char *) strstr(program, "#version"); if (version_loc) { snprintf(version, 49, "%s\n", versionRegex.match(progSource).captured(1).toLatin1().data()); From f9572be8a5651437efe328e04516bd1666207caf Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 12 Mar 2025 23:54:57 +0600 Subject: [PATCH 093/218] Alter `#version` statements for macOS --- src/qt/qt_openglrenderer.cpp | 110 +++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index f654747eb..70c70527a 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -74,54 +74,74 @@ extern int video_vsync; extern int video_focus_dim; extern int video_refresh_rate; -const char *vertex_shader_default_tex_src = "#version 130\n" - "\n" - "in vec4 VertexCoord;\n" - "in vec2 TexCoord;\n" - "\n" - "out vec2 texCoord;\n" - "\n" - "void main()\n" - "{\n" - " gl_Position = VertexCoord;\n" - " texCoord = TexCoord;\n" - "}\n"; +const char* vertex_shader_default_tex_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec4 VertexCoord;\n" + "in vec2 TexCoord;\n" + "\n" + "out vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " texCoord = TexCoord;\n" + "}\n"; -const char *fragment_shader_default_tex_src = "#version 130\n" - "\n" - "in vec2 texCoord;\n" - "uniform sampler2D Texture;\n" - "\n" - "out vec4 color;" - "\n" - "void main()\n" - "{\n" - " color = texture(Texture, texCoord);\n" - "}\n"; +const char* fragment_shader_default_tex_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec2 texCoord;\n" + "uniform sampler2D Texture;\n" + "\n" + "out vec4 color;" + "\n" + "void main()\n" + "{\n" + " color = texture(Texture, texCoord);\n" + "}\n"; -const char *vertex_shader_default_color_src = "#version 130\n" - "\n" - "in vec4 VertexCoord;\n" - "in vec4 Color;\n" - "\n" - "out vec4 color;\n" - "\n" - "void main()\n" - "{\n" - " gl_Position = VertexCoord;\n" - " color = Color;\n" - "}\n"; +const char* vertex_shader_default_color_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec4 VertexCoord;\n" + "in vec4 Color;\n" + "\n" + "out vec4 color;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " color = Color;\n" + "}\n"; -const char *fragment_shader_default_color_src = "#version 130\n" - "\n" - "in vec4 color;\n" - "\n" - "out vec4 outColor;" - "\n" - "void main()\n" - "{\n" - " outColor = color;\n" - "}\n"; +const char* fragment_shader_default_color_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec4 color;\n" + "\n" + "out vec4 outColor;" + "\n" + "void main()\n" + "{\n" + " outColor = color;\n" + "}\n"; static inline int next_pow2(unsigned int n) From 0d22e736767975d9f77da1295d404bc277a90bb1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 13 Mar 2025 00:50:16 +0600 Subject: [PATCH 094/218] Microtouch: Properly restore system cursor if "Show Crosshair" is enabled --- src/qt/qt_rendererstack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 38f087622..43e696085 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -270,7 +270,7 @@ RendererStack::leaveEvent(QEvent *event) { mousedata.mouse_tablet_in_proximity = 0; - if (mouse_input_mode == 1 && QApplication::overrideCursor()) { + if (mouse_input_mode >= 1 && QApplication::overrideCursor()) { while (QApplication::overrideCursor()) QApplication::restoreOverrideCursor(); } From 6779a3c1bdef77a49832a03663fab16b7e96d99f Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Mar 2025 23:16:16 +0100 Subject: [PATCH 095/218] Hook Keyboard Input: Ignore the extended flag for scan codes F1 and F2, fixes the passing of the Hanja and Han/Eng keys to the guest. --- src/qt/qt_main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 10900da0d..627455948 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -370,7 +370,11 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) else if (last && (lpKdhs->scanCode == 0x00000036)) last = 0; - win_keyboard_handle(lpKdhs->scanCode, lpKdhs->flags & LLKHF_UP, lpKdhs->flags & LLKHF_EXTENDED, 0); + if ((lpKdhs->scanCode == 0xf1) || (lpKdhs->scanCode == 0xf2)) + /* Hanja and Han/Eng keys, suppress the extended flag. */ + win_keyboard_handle(lpKdhs->scanCode, lpKdhs->flags & LLKHF_UP, 0, 0); + else + win_keyboard_handle(lpKdhs->scanCode, lpKdhs->flags & LLKHF_UP, lpKdhs->flags & LLKHF_EXTENDED, 0); return ret; } From 7c4df701cb37bb67b5decf625bcac81d64b9f967 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 13 Mar 2025 19:55:46 +0600 Subject: [PATCH 096/218] Add option to inhibit multimedia keys from host on Windows --- src/86box.c | 1 + src/config.c | 6 + src/include/86box/86box.h | 1 + src/qt/languages/86box.pot | 3 + src/qt/qt_main.cpp | 46 +++++++- src/qt/qt_progsettings.cpp | 9 +- src/qt/qt_progsettings.ui | 229 +++++++++++++++++++------------------ 7 files changed, 181 insertions(+), 114 deletions(-) diff --git a/src/86box.c b/src/86box.c index 24f6f0deb..5bf8177e8 100644 --- a/src/86box.c +++ b/src/86box.c @@ -213,6 +213,7 @@ int hook_enabled = 1; /* (C) Keyboar int test_mode = 0; /* (C) Test mode */ char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */ int sound_muted = 0; /* (C) Is sound muted? */ +int inhibit_multimedia_keys; /* (C) Inhibit multimedia keys on Windows. */ int other_ide_present = 0; /* IDE controllers from non-IDE cards are present */ diff --git a/src/config.c b/src/config.c index f68b23c37..3bb9fb59a 100644 --- a/src/config.c +++ b/src/config.c @@ -131,6 +131,8 @@ load_general(void) video_filter_method = ini_section_get_int(cat, "video_filter_method", 1); + inhibit_multimedia_keys = ini_section_get_int(cat, "inhibit_multimedia_keys", 0); + force_43 = !!ini_section_get_int(cat, "force_43", 0); scale = ini_section_get_int(cat, "scale", 1); if (scale > 9) @@ -1900,6 +1902,10 @@ save_general(void) const char *va_name; + ini_section_set_int(cat, "inhibit_multimedia_keys", inhibit_multimedia_keys); + if (inhibit_multimedia_keys == 0) + ini_section_delete_var(cat, "inhibit_multimedia_keys"); + ini_section_set_int(cat, "sound_muted", sound_muted); if (sound_muted == 0) ini_section_delete_var(cat, "sound_muted"); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 768ca6267..40e1f7927 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -107,6 +107,7 @@ extern uint64_t instru_run_ms; #define window_y monitor_settings[0].mon_window_y #define window_w monitor_settings[0].mon_window_w #define window_h monitor_settings[0].mon_window_h +extern int inhibit_multimedia_keys; /* (C) Inhibit multimedia keys on Windows. */ extern int window_remember; extern int vid_resize; /* (C) allow resizing */ extern int invert_display; /* (C) invert the display */ diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 65cc32f85..93a47a1cb 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2141,3 +2141,6 @@ msgstr "" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "" + +msgid "Inhibit multimedia keys on Windows" +msgstr "" diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 627455948..2e0ce33e0 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -226,7 +226,30 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) detection; rest can't be reliably detected. */ DWORD vkCode = lpKdhs->vkCode; bool up = !!(lpKdhs->flags & LLKHF_UP); - ret = CallNextHookEx(NULL, nCode, wParam, lParam);; + + if (inhibit_multimedia_keys + && (lpKdhs->vkCode == VK_MEDIA_PLAY_PAUSE + || lpKdhs->vkCode == VK_MEDIA_NEXT_TRACK + || lpKdhs->vkCode == VK_MEDIA_PREV_TRACK + || lpKdhs->vkCode == VK_VOLUME_DOWN + || lpKdhs->vkCode == VK_VOLUME_UP + || lpKdhs->vkCode == VK_VOLUME_MUTE + || lpKdhs->vkCode == VK_MEDIA_STOP + || lpKdhs->vkCode == VK_LAUNCH_MEDIA_SELECT + || lpKdhs->vkCode == VK_LAUNCH_MAIL + || lpKdhs->vkCode == VK_LAUNCH_APP1 + || lpKdhs->vkCode == VK_LAUNCH_APP2 + || lpKdhs->vkCode == VK_HELP + || lpKdhs->vkCode == VK_BROWSER_BACK + || lpKdhs->vkCode == VK_BROWSER_FORWARD + || lpKdhs->vkCode == VK_BROWSER_FAVORITES + || lpKdhs->vkCode == VK_BROWSER_HOME + || lpKdhs->vkCode == VK_BROWSER_REFRESH + || lpKdhs->vkCode == VK_BROWSER_SEARCH + || lpKdhs->vkCode == VK_BROWSER_STOP)) + ret = TRUE; + else + ret = CallNextHookEx(NULL, nCode, wParam, lParam); switch (vkCode) { @@ -349,6 +372,27 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) ret = TRUE; else if ((lpKdhs->scanCode >= 0x5b) && (lpKdhs->scanCode <= 0x5d) && (lpKdhs->flags & LLKHF_EXTENDED)) ret = TRUE; + else if (inhibit_multimedia_keys + && (lpKdhs->vkCode == VK_MEDIA_PLAY_PAUSE + || lpKdhs->vkCode == VK_MEDIA_NEXT_TRACK + || lpKdhs->vkCode == VK_MEDIA_PREV_TRACK + || lpKdhs->vkCode == VK_VOLUME_DOWN + || lpKdhs->vkCode == VK_VOLUME_UP + || lpKdhs->vkCode == VK_VOLUME_MUTE + || lpKdhs->vkCode == VK_MEDIA_STOP + || lpKdhs->vkCode == VK_LAUNCH_MEDIA_SELECT + || lpKdhs->vkCode == VK_LAUNCH_MAIL + || lpKdhs->vkCode == VK_LAUNCH_APP1 + || lpKdhs->vkCode == VK_LAUNCH_APP2 + || lpKdhs->vkCode == VK_HELP + || lpKdhs->vkCode == VK_BROWSER_BACK + || lpKdhs->vkCode == VK_BROWSER_FORWARD + || lpKdhs->vkCode == VK_BROWSER_FAVORITES + || lpKdhs->vkCode == VK_BROWSER_HOME + || lpKdhs->vkCode == VK_BROWSER_REFRESH + || lpKdhs->vkCode == VK_BROWSER_SEARCH + || lpKdhs->vkCode == VK_BROWSER_STOP)) + ret = TRUE; else ret = CallNextHookEx(NULL, nCode, wParam, lParam); diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 9e1f8c168..6ec76a290 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -115,14 +115,19 @@ ProgSettings::ProgSettings(QWidget *parent) mouseSensitivity = mouse_sensitivity; ui->horizontalSlider->setValue(mouseSensitivity * 100.); ui->openDirUsrPath->setChecked(open_dir_usr_path > 0); + ui->checkBoxMultimediaKeys->setChecked(inhibit_multimedia_keys); +#ifndef Q_OS_WINDOWS + ui->checkBoxMultimediaKeys->setHidden(true); +#endif } void ProgSettings::accept() { strcpy(icon_set, ui->comboBox->currentData().toString().toUtf8().data()); - lang_id = ui->comboBoxLanguage->currentData().toUInt(); - open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; + lang_id = ui->comboBoxLanguage->currentData().toUInt(); + open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; + inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked(); loadTranslators(QCoreApplication::instance()); reloadStrings(); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index ac4327341..dc5674425 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -27,8 +27,122 @@
- QLayout::SetFixedSize + QLayout::SizeConstraint::SetFixedSize + + + + <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + + + Select media images from program working directory + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + 30 + + + + (System Default) + + + + + + + + Default + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + Icon set: + + + + + + + Language: + + + + + + + 10 + + + 200 + + + 10 + + + 20 + + + 100 + + + Qt::Orientation::Horizontal + + + @@ -51,13 +165,6 @@ - - - - Icon set: - - - @@ -65,77 +172,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - 10 - - - 200 - - - 10 - - - 20 - - - 100 - - - Qt::Horizontal - - - - - - - 30 - - - - (System Default) - - - - - - - - Language: - - - - - - - Default - - - @@ -143,39 +179,10 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> - + + - Select media images from program working directory + Inhibit multimedia keys on Windows From b1a02a6d137be594542741bde9f6c6b4571cd43b Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Mar 2025 20:59:59 +0100 Subject: [PATCH 097/218] Windows CD-ROM disc change notification: verify the correct bit of the unit mask. --- src/qt/qt_winrawinputfilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 13e0ec9a7..cff9950b2 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -160,7 +160,7 @@ notify_drives(ULONG unitmask, int empty) char p[1024] = { 0 }; for (int i = 0; i < 26; ++i) { - if (unitmask & 0x1) { + if (unitmask & (1 << i)) { cdrom_t *dev = NULL; sprintf(p, "ioctl://\\\\.\\%c:", 'A' + i); From 8722fe0080d312c469e2750f60644fa67753facd Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Mar 2025 21:17:25 +0100 Subject: [PATCH 098/218] CD-ROM: Optimize Windows IOCTL disc change checking. --- src/cdrom/cdrom.c | 4 ++++ src/include/86box/cdrom.h | 4 ++++ src/qt/qt_winrawinputfilter.cpp | 27 ++++++++------------------- src/qt/win_cdrom_ioctl.c | 16 ++++++++++++---- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index aea1afb94..c20e18db8 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -46,6 +46,7 @@ cdrom_t cdrom[CDROM_NUM] = { 0 }; int cdrom_interface_current; +int cdrom_assigned_letters = 0; #ifdef ENABLE_CDROM_LOG int cdrom_do_log = ENABLE_CDROM_LOG; @@ -2795,6 +2796,8 @@ cdrom_global_init(void) void cdrom_hard_reset(void) { + cdrom_assigned_letters = 0; + for (uint8_t i = 0; i < CDROM_NUM; i++) { cdrom_t *dev = &cdrom[i]; @@ -2825,6 +2828,7 @@ cdrom_hard_reset(void) } dev->cd_status = CD_STATUS_EMPTY; + dev->host_letter = 0xff; if (strlen(dev->image_path) > 0) { #ifdef _WIN32 diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 7c028d7d6..805f08b10 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -335,6 +335,8 @@ typedef struct cdrom { uint8_t subch_buffer[96]; int cdrom_sector_size; + /* Only used on Windows hosts for disc change notifications. */ + uint8_t host_letter; /* Needs some extra breathing space in case of overflows. */ uint8_t raw_buffer[4096]; @@ -437,6 +439,8 @@ extern int cdrom_is_empty(const uint8_t id); extern void cdrom_eject(const uint8_t id); extern void cdrom_reload(const uint8_t id); +extern int cdrom_assigned_letters; + #ifdef __cplusplus } #endif diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index cff9950b2..8a2841f97 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -157,27 +157,16 @@ WindowsRawInputFilter::~WindowsRawInputFilter() static void notify_drives(ULONG unitmask, int empty) { - char p[1024] = { 0 }; + if (unitmask & cdrom_assigned_letters) for (int i = 0; i < CDROM_NUM; i++) { + cdrom_t *dev = &(cdrom[i]); - for (int i = 0; i < 26; ++i) { - if (unitmask & (1 << i)) { - cdrom_t *dev = NULL; - - sprintf(p, "ioctl://\\\\.\\%c:", 'A' + i); - - for (int i = 0; i < CDROM_NUM; i++) - if (!stricmp(cdrom[i].image_path, p)) { - dev = &(cdrom[i]); - if (empty) - cdrom_set_empty(dev); - else - cdrom_update_status(dev); - // pclog("CD-ROM %i : Drive notified of media %s\n", - // dev->id, empty ? "removal" : "change"); - } + if ((dev->host_letter != 0xff) && + (unitmask & (1 << dev->host_letter))) { + if (empty) + cdrom_set_empty(dev); + else + cdrom_update_status(dev); } - - unitmask = unitmask >> 1; } } diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 621cf0b76..309f861e0 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -748,6 +748,11 @@ ioctl_close(void *local) log_close(ioctl->log); ioctl->log = NULL; + + cdrom_assigned_letters &= ~(1 << ioctl->dev->host_letter); + ioctl->dev->host_letter = 0xff; + + free(ioctl); } static void @@ -788,19 +793,22 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_t *ioctl = (ioctl_t *) calloc(1, sizeof(ioctl_t)); if (ioctl != NULL) { - char n[1024] = { 0 }; + char n[1024] = { 0 }; sprintf(n, "CD-ROM %i IOCtl", dev->id + 1); - ioctl->log = log_open(n); + ioctl->log = log_open(n); memset(ioctl->path, 0x00, sizeof(ioctl->path)); wsprintf(ioctl->path, L"%S", &(drv[8])); ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); - ioctl->dev = dev; + ioctl->dev = dev; - dev->ops = &ioctl_ops; + dev->ops = &ioctl_ops; + + dev->host_letter = (drv[12] & 0xdf) - 0x41; + cdrom_assigned_letters |= (1 << dev->host_letter); ioctl_load(ioctl); } From c23114ab8d7dc062d2acf39f0d6123857f9eb300 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 14 Mar 2025 04:18:07 +0600 Subject: [PATCH 099/218] Attempt fixing OpenGL 3.x screenshot --- src/qt/qt_openglrenderer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 70c70527a..88fefa0c3 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1667,6 +1667,9 @@ OpenGLRenderer::render() unsigned char *rgba = (unsigned char *)calloc(1, width * height * 4); + glw.glFinish(); + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + glw.glReadBuffer(GL_BACK); glw.glFinish(); glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); From c166abbbc1242184dc0113b4e1a15ce93c7658f2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 14 Mar 2025 14:07:33 +0600 Subject: [PATCH 100/218] Always use an alpha value of 1.0 for drawing scene to texture Fixes invisible screenshots and blank screens on certain systems --- src/qt/qt_openglrenderer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 88fefa0c3..3b2ec58e0 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -107,6 +107,7 @@ const char* fragment_shader_default_tex_src = "void main()\n" "{\n" " color = texture(Texture, texCoord);\n" + " color.a = 1.0;\n" "}\n"; const char* vertex_shader_default_color_src = @@ -141,6 +142,7 @@ const char* fragment_shader_default_color_src = "void main()\n" "{\n" " outColor = color;\n" + " outColor.a = 1.0;\n" "}\n"; static inline int @@ -1667,9 +1669,6 @@ OpenGLRenderer::render() unsigned char *rgba = (unsigned char *)calloc(1, width * height * 4); - glw.glFinish(); - glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); - glw.glReadBuffer(GL_BACK); glw.glFinish(); glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); From 84112960c3f31df8455ea3c4b3d000f840cb5542 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Mar 2025 15:06:06 +0100 Subject: [PATCH 101/218] VIA PIPC: Also return 0x50 on power management register 0x42 for every other non-VT82c586-family southbridge, fixes CUV4X-LS. --- src/chipset/via_pipc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index f7f5bf208..6b855f5aa 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -59,6 +59,7 @@ listings on forums, as VIA's datasheets are not very helpful regarding those. */ #define VIA_PIPC_586A 0x05862500 #define VIA_PIPC_586B 0x05864700 +#define VIA_PIPC_586 0x0586 #define VIA_PIPC_596A 0x05960900 #define VIA_PIPC_596B 0x05962300 #define VIA_PIPC_596 0x0596 @@ -414,7 +415,7 @@ pipc_reset_hard(void *priv) dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; - dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_586) ? 0x00 : 0x50; acpi_set_irq_line(dev->acpi, 0x00); dev->power_regs[0x48] = 0x01; @@ -1596,7 +1597,7 @@ pipc_reset(void *priv) pipc_write(pm_func, 0x48, 0x01, priv); pipc_write(pm_func, 0x49, 0x00, priv); - dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_586) ? 0x00 : 0x50; acpi_set_irq_line(dev->acpi, 0x00); pipc_write(1, 0x04, 0x80, priv); From aef06552fb383320707d17a51fea174ddba94ff0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Mar 2025 15:34:37 +0100 Subject: [PATCH 102/218] Some missing breaks in the Cyrix register writes. --- src/cpu/cpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index e6a22394a..c4d084947 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -3948,12 +3948,15 @@ pentium_invalid_wrmsr: /* Test Data */ case 0x03: msr.tr3 = EAX; + break; /* Test Address */ case 0x04: msr.tr4 = EAX; + break; /* Test Command/Status */ case 0x05: msr.tr5 = EAX & 0x008f0f3b; + break; /* Time Stamp Counter */ case 0x10: timer_set_new_tsc(EAX | ((uint64_t) EDX << 32)); From 0686045d2a7f3a2f7fc3ed4402874ca1e3406460 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 14 Mar 2025 21:24:36 +0600 Subject: [PATCH 103/218] Fix building on Haiku OS --- src/CMakeLists.txt | 4 ++++ src/qt/qt_platform.cpp | 7 +++++++ src/unix/unix.c | 11 +++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb3bf9f50..94dc6a61a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -108,6 +108,10 @@ endif() target_link_libraries(86Box cpu chipset mch dev mem fdd game cdrom zip mo hdd net print scsi sio snd vid voodoo plat ui) +if(HAIKU) + target_link_libraries(86Box be) +endif() + if(WIN32 AND ARCH STREQUAL "i386") if(MINGW) target_link_options(86Box PRIVATE "LINKER:--large-address-aware") diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index ee8d8842a..ebd6dc30c 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -18,6 +18,11 @@ * Copyright 2021-2022 Cacodemon345 * Copyright 2021-2022 Teemu Korhonen */ + +#ifdef __HAIKU__ +#include +#endif + #include #include @@ -828,6 +833,8 @@ plat_set_thread_name(void *thread, const char *name) pthread_setname_np(truncated); # elif defined(Q_OS_NETBSD) pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, "%s"); +# elif defined(__HAIKU__) + rename_thread(find_thread(NULL), truncated); # elif defined(Q_OS_OPENBSD) pthread_set_name_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated); # else diff --git a/src/unix/unix.c b/src/unix/unix.c index 33b78ddb1..81312d25d 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -2,6 +2,9 @@ # define _FILE_OFFSET_BITS 64 # define _LARGEFILE64_SOURCE 1 #endif +#ifdef __HAIKU__ +#include +#endif #include #include #include @@ -1398,16 +1401,20 @@ plat_set_thread_name(void *thread, const char *name) if (thread) /* Apple pthread can only set self's name */ return; char truncated[64]; -#elif defined(Q_OS_NETBSD) +#elif defined(__NetBSD__) char truncated[64]; +#elif defined(__HAIKU__) + char truncated[32]; #else char truncated[16]; #endif strncpy(truncated, name, sizeof(truncated) - 1); #ifdef __APPLE__ pthread_setname_np(truncated); -#elif defined(Q_OS_NETBSD) +#elif defined(__NetBSD__) pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, "%s"); +#elif defined(__HAIKU__) + rename_thread(find_thread(NULL), truncated); #else pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated); #endif From a1996e79553ee41df49c30551403f5fd19bbd534 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sat, 15 Mar 2025 01:09:41 +0700 Subject: [PATCH 104/218] Readd XT and AT floppy controllers They got removed during the addition of CompatiCard --- src/floppy/fdc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 5de1a8ef4..51c3aa24a 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -105,6 +105,8 @@ static fdc_cards_t fdc_cards[] = { // clang-format off { &device_none }, { &device_internal }, + { &fdc_xt_device }, + { &fdc_at_device }, { &fdc_b215_device }, { &fdc_pii151b_device }, { &fdc_pii158b_device }, From a340f250f2f27f229d3aff30272d62a0b676d859 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 00:34:36 +0600 Subject: [PATCH 105/218] Attempt detecting BOM before parsing parameters --- src/qt/qt_glsl_parser.cpp | 36 ++++++++++++++++++++++--- src/qt/qt_openglshadermanagerdialog.cpp | 3 +++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index 9a0a0fc03..e5c7b77f2 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -17,6 +17,7 @@ extern "C" #include <86box/config.h> #include <86box/qt-glslp-parser.h> #include <86box/path.h> +#include <86box/plat.h> extern void startblit(); extern void endblit(); @@ -81,14 +82,38 @@ static int endswith(const char *str, const char *ext) { return 0; } +static int +glsl_detect_bom(const char *fn) +{ + FILE *fp; + unsigned char bom[4] = { 0, 0, 0, 0 }; + + fp = plat_fopen(fn, "rb"); + if (fp == NULL) + return 0; + (void) !fread(bom, 1, 3, fp); + if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) { + fclose(fp); + return 1; + } + fclose(fp); + return 0; +} + static char *load_file(const char *fn) { - FILE *f = fopen(fn, "rb"); + int bom = glsl_detect_bom(fn); + FILE *f = plat_fopen(fn, "rb"); if (!f) return 0; fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); + if (bom) { + fsize -= 3; + fseek(f, 3, SEEK_SET); + } + char *data = (char*)malloc(fsize + 1); fread(data, fsize, 1, f); @@ -131,12 +156,15 @@ static int get_parameters(glslp_t *glsl) { int i; struct parameter p; for (i = 0; i < glsl->num_shaders; ++i) { + char line[1024]; struct shader *shader = &glsl->shaders[i]; - FILE *f = fopen(shader->shader_fn, "rb"); + int bom = glsl_detect_bom(shader->shader_fn); + FILE *f = plat_fopen(shader->shader_fn, "rb"); if (!f) return 0; - - char line[1024]; + if (bom) { + fseek(f, 3, SEEK_SET); + } while (fgets(line, sizeof(line) - 1, f) && glsl->num_parameters < MAX_PARAMETERS) { int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, &p.default_value, &p.min, &p.max, &p.step); diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 7f8a19414..72f58f9cb 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -63,6 +63,7 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) } else { ui->buttonConfigure->setEnabled(false); } + ui->buttonAdd->setDisabled(ui->shaderListWidget->count() >= MAX_USER_SHADERS); } else { ui->buttonRemove->setDisabled(true); ui->buttonMoveUp->setDisabled(true); @@ -177,6 +178,7 @@ void OpenGLShaderManagerDialog::on_buttonAdd_clicked() item->setData(Qt::UserRole + 2, (qulonglong)(uintptr_t)shaderfile); if (ui->shaderListWidget->count()) { ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + ui->buttonAdd->setDisabled(ui->shaderListWidget->count() >= MAX_USER_SHADERS); } } else { QMessageBox::critical(this, tr("GLSL error"), tr("Could not load filename %1").arg(res)); @@ -197,6 +199,7 @@ void OpenGLShaderManagerDialog::on_buttonRemove_clicked() on_shaderListWidget_currentRowChanged(ui->shaderListWidget->currentRow()); } + ui->buttonAdd->setDisabled(ui->shaderListWidget->count() >= MAX_USER_SHADERS); } void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() From b5c158ec98a02df1ea1ec559712601bd8ac4681a Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Mar 2025 20:11:55 +0100 Subject: [PATCH 106/218] SCSI CD-ROM: Revert the performance-reducing changes to scsi_cdrom_command_common() introduced in build 6541. --- src/scsi/scsi_cdrom.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index cc9cc40c1..e16b16e7c 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -678,13 +678,8 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; scsi_cdrom_set_callback(dev); return; - case 0x43: - dev->drv->seek_diff = dev->drv->seek_pos + 150; - dev->drv->seek_pos = 0; - fallthrough; case 0x08: case 0x28: - case 0x42: case 0x44: case 0xa8: /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); @@ -698,7 +693,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; fallthrough; case 0x25: - // case 0x42 ... 0x44: + case 0x42 ... 0x44: case 0x51 ... 0x52: case 0xad: case 0xb8 ... 0xb9: @@ -707,11 +702,6 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += 40.0; /* Account for seek time. */ /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - /* - TODO: This is a bit of a lie - the actual period is closer to - 75 * 2448 bytes per second, because the subchannel data - has to be read as well. - */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; break; @@ -740,19 +730,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) period = 1000000.0 / bytes_per_second; scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); - switch (cmd) { - default: - period = period * (double) (dev->packet_len); - break; - case 0x42: case 0x44: - /* READ SUBCHANNEL or READ HEADER - period of 1 entire sector. */ - period = period * 2352.0; - break; - case 0x43: - /* READ TOC - period of 175 entire frames. */ - period = period * 150.0 * 2352.0; - break; - } + period = period * (double) (dev->packet_len); scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); dev->callback += period; From 9af19f850ea0374f3cbd07e0b23b0857aba581e0 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 13:17:14 +0600 Subject: [PATCH 107/218] Parse shader parameter lines with an alternate method --- src/qt/qt_glsl_parser.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index e5c7b77f2..fa45267a7 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -21,6 +21,8 @@ extern "C" extern void startblit(); extern void endblit(); +extern ssize_t local_getline(char **buf, size_t *bufsiz, FILE *fp); +extern char* trim(char* str); } #define safe_strncpy(a, b, n) \ @@ -156,7 +158,8 @@ static int get_parameters(glslp_t *glsl) { int i; struct parameter p; for (i = 0; i < glsl->num_shaders; ++i) { - char line[1024]; + size_t size = 0; + char* line = NULL; struct shader *shader = &glsl->shaders[i]; int bom = glsl_detect_bom(shader->shader_fn); FILE *f = plat_fopen(shader->shader_fn, "rb"); @@ -165,7 +168,9 @@ static int get_parameters(glslp_t *glsl) { if (bom) { fseek(f, 3, SEEK_SET); } - while (fgets(line, sizeof(line) - 1, f) && glsl->num_parameters < MAX_PARAMETERS) { + while (local_getline(&line, &size, f) != -1 && glsl->num_parameters < MAX_PARAMETERS) { + line[strcspn(line, "\r\n")] = '\0'; + trim(line); int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, &p.default_value, &p.min, &p.max, &p.step); if (num < 5) From 4a9b0e0df8a94287bef72644111df5caa7a38397 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 13:17:41 +0600 Subject: [PATCH 108/218] Apply filter changes to the scene FBO texture as well --- src/qt/qt_openglrenderer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 3b2ec58e0..b465bfddd 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1393,6 +1393,10 @@ OpenGLRenderer::render() glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + active_shader->scene.fbo.texture.min_filter = active_shader->scene.fbo.texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glBindTexture(GL_TEXTURE_2D, active_shader->scene.fbo.texture.id); glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); glw.glBindTexture(GL_TEXTURE_2D, 0); From b8894fc9dfb403e0e723091c71aa21482321d52f Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:13:02 +0200 Subject: [PATCH 109/218] Add files via upload Fixes broken translation of "About 86Box" --- src/qt/qt_mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index cdb46cb29..41654ab25 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1754,7 +1754,7 @@ MainWindow::on_actionAbout_86Box_triggered() versioninfo.append(QString(" [%1, %2]").arg(QSysInfo::buildCpuArchitecture(), tr(DYNAREC_STR))); msgBox.setText(QString("%3%1%2").arg(EMU_VERSION_FULL, versioninfo, tr("86Box v"))); msgBox.setInformativeText(tr("An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information.")); - msgBox.setWindowTitle("About 86Box"); + msgBox.setWindowTitle(tr("About 86Box")); const auto closeButton = msgBox.addButton("OK", QMessageBox::ButtonRole::AcceptRole); msgBox.setEscapeButton(closeButton); const auto webSiteButton = msgBox.addButton(EMU_SITE, QMessageBox::ButtonRole::HelpRole); From dcce23a7d3c53ea1b544d58dab02065200ffb3e5 Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:13:55 +0200 Subject: [PATCH 110/218] Add files via upload Fixes broken translation of "Receive MIDI Input" for Ensoniq AudioPCI (ES1370) --- src/sound/snd_audiopci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 8d1de442b..1ca547650 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -2742,7 +2742,7 @@ static const device_config_t es1370_config[] = { // clang-format off { .name = "receive_input", - .description = "Receive input (MIDI)", + .description = "Receive MIDI input", .type = CONFIG_BINARY, .default_string = NULL, .default_int = 1, From 26e1852b5a22ff23e079f13619f8f8fd33b4f25f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 23:47:10 +0600 Subject: [PATCH 111/218] Make renderer options item enabled/disabled instead Also a missed French translation --- src/qt/languages/fr-FR.po | 2 +- src/qt/qt.c | 5 ----- src/qt/qt_mainwindow.cpp | 5 +---- src/qt/qt_rendererstack.cpp | 22 +--------------------- src/qt/qt_rendererstack.hpp | 1 - 5 files changed, 3 insertions(+), 32 deletions(-) diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 3b283b3dd..590674a29 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -37,7 +37,7 @@ msgid "&Hide status bar" msgstr "&Masquer la barre de status" msgid "Hide &toolbar" -msgstr "Hide &toolbar" +msgstr "Masquer la &barre d'outils" msgid "&Resizeable window" msgstr "Fenètre &Retaillable" diff --git a/src/qt/qt.c b/src/qt/qt.c index 13ddbf498..a9a6460eb 100644 --- a/src/qt/qt.c +++ b/src/qt/qt.c @@ -54,8 +54,6 @@ plat_vidapi(const char *api) return 4; } else if (!strcasecmp(api, "vnc")) { return 5; - } else if (!strcasecmp(api, "qt_opengl3_pcem")) { - return 6; } return 0; @@ -85,9 +83,6 @@ plat_vidapi_name(int api) case 5: name = "vnc"; break; - case 6: - name = "qt_opengl3_pcem"; - break; default: fatal("Unknown renderer: %i\n", api); break; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index cdb46cb29..d2c4667cd 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -454,9 +454,6 @@ MainWindow::MainWindow(QWidget *parent) endblit(); } #endif - case 6: - newVidApi = RendererStack::Renderer::OpenGL3PCem; - break; } ui->stackedWidget->switchRenderer(newVidApi); if (!show_second_monitors) @@ -468,7 +465,7 @@ MainWindow::MainWindow(QWidget *parent) }); connect(ui->stackedWidget, &RendererStack::rendererChanged, [this]() { - ui->actionRenderer_options->setVisible(ui->stackedWidget->hasOptions()); + ui->actionRenderer_options->setEnabled(ui->stackedWidget->hasOptions()); }); /* Trigger initial renderer switch */ diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 43e696085..bd1fd2609 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -339,26 +339,6 @@ RendererStack::createRenderer(Renderer renderer) current.reset(this->createWindowContainer(hw, this)); break; } - case Renderer::OpenGL3PCem: - { - this->createWinId(); - auto hw = new OpenGLRenderer(this); - rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRenderer::initialized, [=]() { - /* Buffers are available only after initialization. */ - imagebufs = rendererWindow->getBuffers(); - endblit(); - emit rendererChanged(); - }); - connect(hw, &OpenGLRenderer::errorInitializing, [=]() { - /* Renderer not could initialize, fallback to software. */ - imagebufs = {}; - QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); - }); - current.reset(this->createWindowContainer(hw, this)); - break; - } case Renderer::OpenGL3: { this->createWinId(); @@ -431,7 +411,7 @@ RendererStack::createRenderer(Renderer renderer) currentBuf = 0; - if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::OpenGL3PCem) { + if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) { imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index a84773c72..309cae7f5 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -61,7 +61,6 @@ public: OpenGLES, OpenGL3, Vulkan, - OpenGL3PCem = 6, None = -1 }; void switchRenderer(Renderer renderer); From 000af483f3e0561fbb4c214496d20d0be358359b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 16 Mar 2025 01:46:34 +0600 Subject: [PATCH 112/218] C&T 69000: All ROPs now implemented, also fixed transparency bitblts Several optimizations also implemented --- src/video/vid_chips_69000.c | 1342 ++++++++++++++++++++++------------- 1 file changed, 833 insertions(+), 509 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index a387e99fa..b0e8db35a 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -251,486 +251,797 @@ chips_69000_bitblt_interrupt(chips_69000_t* chips) chips_69000_interrupt(chips); } -void -chips_69000_do_rop_8bpp(uint8_t *dst, uint8_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFF; - break; +#define ROPMIX(R, D, P, S, out) \ + { \ + switch (R) { \ + case 0x00: \ + out = 0; \ + break; \ + case 0x01: \ + out = ~(D | (P | S)); \ + break; \ + case 0x02: \ + out = D & ~(P | S); \ + break; \ + case 0x03: \ + out = ~(P | S); \ + break; \ + case 0x04: \ + out = S & ~(D | P); \ + break; \ + case 0x05: \ + out = ~(D | P); \ + break; \ + case 0x06: \ + out = ~(P | ~(D ^ S)); \ + break; \ + case 0x07: \ + out = ~(P | (D & S)); \ + break; \ + case 0x08: \ + out = S & (D & ~P); \ + break; \ + case 0x09: \ + out = ~(P | (D ^ S)); \ + break; \ + case 0x0a: \ + out = D & ~P; \ + break; \ + case 0x0b: \ + out = ~(P | (S & ~D)); \ + break; \ + case 0x0c: \ + out = S & ~P; \ + break; \ + case 0x0d: \ + out = ~(P | (D & ~S)); \ + break; \ + case 0x0e: \ + out = ~(P | ~(D | S)); \ + break; \ + case 0x0f: \ + out = ~P; \ + break; \ + case 0x10: \ + out = P & ~(D | S); \ + break; \ + case 0x11: \ + out = ~(D | S); \ + break; \ + case 0x12: \ + out = ~(S | ~(D ^ P)); \ + break; \ + case 0x13: \ + out = ~(S | (D & P)); \ + break; \ + case 0x14: \ + out = ~(D | ~(P ^ S)); \ + break; \ + case 0x15: \ + out = ~(D | (P & S)); \ + break; \ + case 0x16: \ + out = P ^ (S ^ (D & ~(P & S))); \ + break; \ + case 0x17: \ + out = ~(S ^ ((S ^ P) & (D ^ S))); \ + break; \ + case 0x18: \ + out = (S ^ P) & (P ^ D); \ + break; \ + case 0x19: \ + out = ~(S ^ (D & ~(P & S))); \ + break; \ + case 0x1a: \ + out = P ^ (D | (S & P)); \ + break; \ + case 0x1b: \ + out = ~(S ^ (D & (P ^ S))); \ + break; \ + case 0x1c: \ + out = P ^ (S | (D & P)); \ + break; \ + case 0x1d: \ + out = ~(D ^ (S & (P ^ D))); \ + break; \ + case 0x1e: \ + out = P ^ (D | S); \ + break; \ + case 0x1f: \ + out = ~(P & (D | S)); \ + break; \ + case 0x20: \ + out = D & (P & ~S); \ + break; \ + case 0x21: \ + out = ~(S | (D ^ P)); \ + break; \ + case 0x22: \ + out = D & ~S; \ + break; \ + case 0x23: \ + out = ~(S | (P & ~D)); \ + break; \ + case 0x24: \ + out = (S ^ P) & (D ^ S); \ + break; \ + case 0x25: \ + out = ~(P ^ (D & ~(S & P))); \ + break; \ + case 0x26: \ + out = S ^ (D | (P & S)); \ + break; \ + case 0x27: \ + out = S ^ (D | ~(P ^ S)); \ + break; \ + case 0x28: \ + out = D & (P ^ S); \ + break; \ + case 0x29: \ + out = ~(P ^ (S ^ (D | (P & S)))); \ + break; \ + case 0x2a: \ + out = D & ~(P & S); \ + break; \ + case 0x2b: \ + out = ~(S ^ ((S ^ P) & (P ^ D))); \ + break; \ + case 0x2c: \ + out = S ^ (P & (D | S)); \ + break; \ + case 0x2d: \ + out = P ^ (S | ~D); \ + break; \ + case 0x2e: \ + out = P ^ (S | (D ^ P)); \ + break; \ + case 0x2f: \ + out = ~(P & (S | ~D)); \ + break; \ + case 0x30: \ + out = P & ~S; \ + break; \ + case 0x31: \ + out = ~(S | (D & ~P)); \ + break; \ + case 0x32: \ + out = S ^ (D | (P | S)); \ + break; \ + case 0x33: \ + out = ~S; \ + break; \ + case 0x34: \ + out = S ^ (P | (D & S)); \ + break; \ + case 0x35: \ + out = S ^ (P | ~(D ^ S)); \ + break; \ + case 0x36: \ + out = S ^ (D | P); \ + break; \ + case 0x37: \ + out = ~(S & (D | P)); \ + break; \ + case 0x38: \ + out = P ^ (S & (D | P)); \ + break; \ + case 0x39: \ + out = S ^ (P | ~D); \ + break; \ + case 0x3a: \ + out = S ^ (P | (D ^ S)); \ + break; \ + case 0x3b: \ + out = ~(S & (P | ~D)); \ + break; \ + case 0x3c: \ + out = P ^ S; \ + break; \ + case 0x3d: \ + out = S ^ (P | ~(D | S)); \ + break; \ + case 0x3e: \ + out = S ^ (P | (D & ~S)); \ + break; \ + case 0x3f: \ + out = ~(P & S); \ + break; \ + case 0x40: \ + out = P & (S & ~D); \ + break; \ + case 0x41: \ + out = ~(D | (P ^ S)); \ + break; \ + case 0x42: \ + out = (S ^ D) & (P ^ D); \ + break; \ + case 0x43: \ + out = ~(S ^ (P & ~(D & S))); \ + break; \ + case 0x44: \ + out = S & ~D; \ + break; \ + case 0x45: \ + out = ~(D | (P & ~S)); \ + break; \ + case 0x46: \ + out = D ^ (S | (P & D)); \ + break; \ + case 0x47: \ + out = ~(P ^ (S & (D ^ P))); \ + break; \ + case 0x48: \ + out = S & (D ^ P); \ + break; \ + case 0x49: \ + out = ~(P ^ (D ^ (S | (P & D)))); \ + break; \ + case 0x4a: \ + out = D ^ (P & (S | D)); \ + break; \ + case 0x4b: \ + out = P ^ (D | ~S); \ + break; \ + case 0x4c: \ + out = S & ~(D & P); \ + break; \ + case 0x4d: \ + out = ~(S ^ ((S ^ P) | (D ^ S))); \ + break; \ + case 0x4e: \ + out = P ^ (D | (S ^ P)); \ + break; \ + case 0x4f: \ + out = ~(P & (D | ~S)); \ + break; \ + case 0x50: \ + out = P & ~D; \ + break; \ + case 0x51: \ + out = ~(D | (S & ~P)); \ + break; \ + case 0x52: \ + out = D ^ (P | (S & D)); \ + break; \ + case 0x53: \ + out = ~(S ^ (P & (D ^ S))); \ + break; \ + case 0x54: \ + out = ~(D | ~(P | S)); \ + break; \ + case 0x55: \ + out = ~D; \ + break; \ + case 0x56: \ + out = D ^ (P | S); \ + break; \ + case 0x57: \ + out = ~(D & (P | S)); \ + break; \ + case 0x58: \ + out = P ^ (D & (S | P)); \ + break; \ + case 0x59: \ + out = D ^ (P | ~S); \ + break; \ + case 0x5a: \ + out = D ^ P; \ + break; \ + case 0x5b: \ + out = D ^ (P | ~(S | D)); \ + break; \ + case 0x5c: \ + out = D ^ (P | (S ^ D)); \ + break; \ + case 0x5d: \ + out = ~(D & (P | ~S)); \ + break; \ + case 0x5e: \ + out = D ^ (P | (S & ~D)); \ + break; \ + case 0x5f: \ + out = ~(D & P); \ + break; \ + case 0x60: \ + out = P & (D ^ S); \ + break; \ + case 0x61: \ + out = ~(D ^ (S ^ (P | (D & S)))); \ + break; \ + case 0x62: \ + out = D ^ (S & (P | D)); \ + break; \ + case 0x63: \ + out = S ^ (D | ~P); \ + break; \ + case 0x64: \ + out = S ^ (D & (P | S)); \ + break; \ + case 0x65: \ + out = D ^ (S | ~P); \ + break; \ + case 0x66: \ + out = D ^ S; \ + break; \ + case 0x67: \ + out = S ^ (D | ~(P | S)); \ + break; \ + case 0x68: \ + out = ~(D ^ (S ^ (P | ~(D | S)))); \ + break; \ + case 0x69: \ + out = ~(P ^ (D ^ S)); \ + break; \ + case 0x6a: \ + out = D ^ (P & S); \ + break; \ + case 0x6b: \ + out = ~(P ^ (S ^ (D & (P | S)))); \ + break; \ + case 0x6c: \ + out = S ^ (D & P); \ + break; \ + case 0x6d: \ + out = ~(P ^ (D ^ (S & (P | D)))); \ + break; \ + case 0x6e: \ + out = S ^ (D & (P | ~S)); \ + break; \ + case 0x6f: \ + out = ~(P & ~(D ^ S)); \ + break; \ + case 0x70: \ + out = P & ~(D & S); \ + break; \ + case 0x71: \ + out = ~(S ^ ((S ^ D) & (P ^ D))); \ + break; \ + case 0x72: \ + out = S ^ (D | (P ^ S)); \ + break; \ + case 0x73: \ + out = ~(S & (D | ~P)); \ + break; \ + case 0x74: \ + out = D ^ (S | (P ^ D)); \ + break; \ + case 0x75: \ + out = ~(D & (S | ~P)); \ + break; \ + case 0x76: \ + out = S ^ (D | (P & ~S)); \ + break; \ + case 0x77: \ + out = ~(D & S); \ + break; \ + case 0x78: \ + out = P ^ (D & S); \ + break; \ + case 0x79: \ + out = ~(D ^ (S ^ (P & (D | S)))); \ + break; \ + case 0x7a: \ + out = D ^ (P & (S | ~D)); \ + break; \ + case 0x7b: \ + out = ~(S & ~(D ^ P)); \ + break; \ + case 0x7c: \ + out = S ^ (P & (D | ~S)); \ + break; \ + case 0x7d: \ + out = ~(D & ~(P ^ S)); \ + break; \ + case 0x7e: \ + out = (S ^ P) | (D ^ S); \ + break; \ + case 0x7f: \ + out = ~(D & (P & S)); \ + break; \ + case 0x80: \ + out = D & (P & S); \ + break; \ + case 0x81: \ + out = ~((S ^ P) | (D ^ S)); \ + break; \ + case 0x82: \ + out = D & ~(P ^ S); \ + break; \ + case 0x83: \ + out = ~(S ^ (P & (D | ~S))); \ + break; \ + case 0x84: \ + out = S & ~(D ^ P); \ + break; \ + case 0x85: \ + out = ~(P ^ (D & (S | ~P))); \ + break; \ + case 0x86: \ + out = D ^ (S ^ (P & (D | S))); \ + break; \ + case 0x87: \ + out = ~(P ^ (D & S)); \ + break; \ + case 0x88: \ + out = D & S; \ + break; \ + case 0x89: \ + out = ~(S ^ (D | (P & ~S))); \ + break; \ + case 0x8a: \ + out = D & (S | ~P); \ + break; \ + case 0x8b: \ + out = ~(D ^ (S | (P ^ D))); \ + break; \ + case 0x8c: \ + out = S & (D | ~P); \ + break; \ + case 0x8d: \ + out = ~(S ^ (D | (P ^ S))); \ + break; \ + case 0x8e: \ + out = S ^ ((S ^ D) & (P ^ D)); \ + break; \ + case 0x8f: \ + out = ~(P & ~(D & S)); \ + break; \ + case 0x90: \ + out = P & ~(D ^ S); \ + break; \ + case 0x91: \ + out = ~(S ^ (D & (P | ~S))); \ + break; \ + case 0x92: \ + out = D ^ (P ^ (S & (D | P))); \ + break; \ + case 0x93: \ + out = ~(S ^ (P & D)); \ + break; \ + case 0x94: \ + out = P ^ (S ^ (D & (P | S))); \ + break; \ + case 0x95: \ + out = ~(D ^ (P & S)); \ + break; \ + case 0x96: \ + out = D ^ (P ^ S); \ + break; \ + case 0x97: \ + out = P ^ (S ^ (D | ~(P | S))); \ + break; \ + case 0x98: \ + out = ~(S ^ (D | ~(P | S))); \ + break; \ + case 0x99: \ + out = ~(D ^ S); \ + break; \ + case 0x9a: \ + out = D ^ (P & ~S); \ + break; \ + case 0x9b: \ + out = ~(S ^ (D & (P | S))); \ + break; \ + case 0x9c: \ + out = S ^ (P & ~D); \ + break; \ + case 0x9d: \ + out = ~(D ^ (S & (P | D))); \ + break; \ + case 0x9e: \ + out = D ^ (S ^ (P | (D & S))); \ + break; \ + case 0x9f: \ + out = ~(P & (D ^ S)); \ + break; \ + case 0xa0: \ + out = D & P; \ + break; \ + case 0xa1: \ + out = ~(P ^ (D | (S & ~P))); \ + break; \ + case 0xa2: \ + out = D & (P | ~S); \ + break; \ + case 0xa3: \ + out = ~(D ^ (P | (S ^ D))); \ + break; \ + case 0xa4: \ + out = ~(P ^ (D | ~(S | P))); \ + break; \ + case 0xa5: \ + out = ~(P ^ D); \ + break; \ + case 0xa6: \ + out = D ^ (S & ~P); \ + break; \ + case 0xa7: \ + out = ~(P ^ (D & (S | P))); \ + break; \ + case 0xa8: \ + out = D & (P | S); \ + break; \ + case 0xa9: \ + out = ~(D ^ (P | S)); \ + break; \ + case 0xaa: \ + out = D; \ + break; \ + case 0xab: \ + out = D | ~(P | S); \ + break; \ + case 0xac: \ + out = S ^ (P & (D ^ S)); \ + break; \ + case 0xad: \ + out = ~(D ^ (P | (S & D))); \ + break; \ + case 0xae: \ + out = D | (S & ~P); \ + break; \ + case 0xaf: \ + out = D | ~P; \ + break; \ + case 0xb0: \ + out = P & (D | ~S); \ + break; \ + case 0xb1: \ + out = ~(P ^ (D | (S ^ P))); \ + break; \ + case 0xb2: \ + out = S ^ ((S ^ P) | (D ^ S)); \ + break; \ + case 0xb3: \ + out = ~(S & ~(D & P)); \ + break; \ + case 0xb4: \ + out = P ^ (S & ~D); \ + break; \ + case 0xb5: \ + out = ~(D ^ (P & (S | D))); \ + break; \ + case 0xb6: \ + out = D ^ (P ^ (S | (D & P))); \ + break; \ + case 0xb7: \ + out = ~(S & (D ^ P)); \ + break; \ + case 0xb8: \ + out = P ^ (S & (D ^ P)); \ + break; \ + case 0xb9: \ + out = ~(D ^ (S | (P & D))); \ + break; \ + case 0xba: \ + out = D | (P & ~S); \ + break; \ + case 0xbb: \ + out = D | ~S; \ + break; \ + case 0xbc: \ + out = S ^ (P & ~(D & S)); \ + break; \ + case 0xbd: \ + out = ~((S ^ D) & (P ^ D)); \ + break; \ + case 0xbe: \ + out = D | (P ^ S); \ + break; \ + case 0xbf: \ + out = D | ~(P & S); \ + break; \ + case 0xc0: \ + out = P & S; \ + break; \ + case 0xc1: \ + out = ~(S ^ (P | (D & ~S))); \ + break; \ + case 0xc2: \ + out = ~(S ^ (P | ~(D | S))); \ + break; \ + case 0xc3: \ + out = ~(P ^ S); \ + break; \ + case 0xc4: \ + out = S & (P | ~D); \ + break; \ + case 0xc5: \ + out = ~(S ^ (P | (D ^ S))); \ + break; \ + case 0xc6: \ + out = S ^ (D & ~P); \ + break; \ + case 0xc7: \ + out = ~(P ^ (S & (D | P))); \ + break; \ + case 0xc8: \ + out = S & (D | P); \ + break; \ + case 0xc9: \ + out = ~(S ^ (P | D)); \ + break; \ + case 0xca: \ + out = D ^ (P & (S ^ D)); \ + break; \ + case 0xcb: \ + out = ~(S ^ (P | (D & S))); \ + break; \ + case 0xcc: \ + out = S; \ + break; \ + case 0xcd: \ + out = S | ~(D | P); \ + break; \ + case 0xce: \ + out = S | (D & ~P); \ + break; \ + case 0xcf: \ + out = S | ~P; \ + break; \ + case 0xd0: \ + out = P & (S | ~D); \ + break; \ + case 0xd1: \ + out = ~(P ^ (S | (D ^ P))); \ + break; \ + case 0xd2: \ + out = P ^ (D & ~S); \ + break; \ + case 0xd3: \ + out = ~(S ^ (P & (D | S))); \ + break; \ + case 0xd4: \ + out = S ^ ((S ^ P) & (P ^ D)); \ + break; \ + case 0xd5: \ + out = ~(D & ~(P & S)); \ + break; \ + case 0xd6: \ + out = P ^ (S ^ (D | (P & S))); \ + break; \ + case 0xd7: \ + out = ~(D & (P ^ S)); \ + break; \ + case 0xd8: \ + out = P ^ (D & (S ^ P)); \ + break; \ + case 0xd9: \ + out = ~(S ^ (D | (P & S))); \ + break; \ + case 0xda: \ + out = D ^ (P & ~(S & D)); \ + break; \ + case 0xdb: \ + out = ~((S ^ P) & (D ^ S)); \ + break; \ + case 0xdc: \ + out = S | (P & ~D); \ + break; \ + case 0xdd: \ + out = S | ~D; \ + break; \ + case 0xde: \ + out = S | (D ^ P); \ + break; \ + case 0xdf: \ + out = S | ~(D & P); \ + break; \ + case 0xe0: \ + out = P & (D | S); \ + break; \ + case 0xe1: \ + out = ~(P ^ (D | S)); \ + break; \ + case 0xe2: \ + out = D ^ (S & (P ^ D)); \ + break; \ + case 0xe3: \ + out = ~(P ^ (S | (D & P))); \ + break; \ + case 0xe4: \ + out = S ^ (D & (P ^ S)); \ + break; \ + case 0xe5: \ + out = ~(P ^ (D | (S & P))); \ + break; \ + case 0xe6: \ + out = S ^ (D & ~(P & S)); \ + break; \ + case 0xe7: \ + out = ~((S ^ P) & (P ^ D)); \ + break; \ + case 0xe8: \ + out = S ^ ((S ^ P) & (D ^ S)); \ + break; \ + case 0xe9: \ + out = ~(D ^ (S ^ (P & ~(D & S)))); \ + break; \ + case 0xea: \ + out = D | (P & S); \ + break; \ + case 0xeb: \ + out = D | ~(P ^ S); \ + break; \ + case 0xec: \ + out = S | (D & P); \ + break; \ + case 0xed: \ + out = S | ~(D ^ P); \ + break; \ + case 0xee: \ + out = D | S; \ + break; \ + case 0xef: \ + out = S | (D | ~P); \ + break; \ + case 0xf0: \ + out = P; \ + break; \ + case 0xf1: \ + out = P | ~(D | S); \ + break; \ + case 0xf2: \ + out = P | (D & ~S); \ + break; \ + case 0xf3: \ + out = P | ~S; \ + break; \ + case 0xf4: \ + out = P | (S & ~D); \ + break; \ + case 0xf5: \ + out = P | ~D; \ + break; \ + case 0xf6: \ + out = P | (D ^ S); \ + break; \ + case 0xf7: \ + out = P | ~(D & S); \ + break; \ + case 0xf8: \ + out = P | (D & S); \ + break; \ + case 0xf9: \ + out = P | ~(D ^ S); \ + break; \ + case 0xfa: \ + out = D | P; \ + break; \ + case 0xfb: \ + out = D | (P | ~S); \ + break; \ + case 0xfc: \ + out = P | S; \ + break; \ + case 0xfd: \ + out = P | (S | ~D); \ + break; \ + case 0xfe: \ + out = D | (P | S); \ + break; \ + case 0xff: \ + out = ~0; \ + break; \ + } \ } -} - -void -chips_69000_do_rop_16bpp(uint16_t *dst, uint16_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFF; - break; - } -} - -void -chips_69000_do_rop_24bpp(uint32_t *dst, uint32_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFFFF; - break; - } -} void chips_69000_do_rop_8bpp_patterned(uint8_t *dst, uint8_t pattern, uint8_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_8bpp(dst, src, rop); - } - - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void chips_69000_do_rop_16bpp_patterned(uint16_t *dst, uint16_t pattern, uint16_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_16bpp(dst, src, rop); - } - - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void chips_69000_do_rop_24bpp_patterned(uint32_t *dst, uint32_t pattern, uint32_t src, uint8_t rop) { uint32_t orig_dst = *dst & 0xFF000000; - - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_24bpp(dst, src, rop); - } - - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); *dst &= 0xFFFFFF; *dst |= orig_dst; } @@ -895,20 +1206,22 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - dest_pixel = chips_69000_readb_linear(dest_addr, chips); + //dest_pixel = chips_69000_readb_linear(dest_addr, chips); + dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; break; } case 2: /* 16 bits-per-pixel. */ { - dest_pixel = chips_69000_readb_linear(dest_addr, chips); - dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; + //dest_pixel = *(uint16_t*)&chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; break; } case 3: /* 24 bits-per-pixel. */ { - dest_pixel = chips_69000_readb_linear(dest_addr, chips); - dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; - dest_pixel |= chips_69000_readb_linear(dest_addr + 2, chips) << 16; + dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; + dest_pixel |= chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] << 16; break; } } @@ -921,7 +1234,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) if (chips->bitblt_running.bitblt.bitblt_control & (1 << 19)) pattern_data = 0; else - pattern_data = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); + pattern_data = chips->svga.vram[(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7)) & chips->svga.vram_mask]; //chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); is_true = !!(pattern_data & (1 << (7 - ((chips->bitblt_running.bitblt.destination_addr + chips->bitblt_running.x) & 7)))); @@ -937,32 +1250,30 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) pattern_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; } else { + uint32_t pattern_pixel_addr = 0; if (chips->bitblt_running.bytes_per_pixel == 1) { - pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) - + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7), chips); + pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr + + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) + + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7); + + pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; } if (chips->bitblt_running.bytes_per_pixel == 2) { - pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); + pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr + + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); - pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; + pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; + pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; } if (chips->bitblt_running.bytes_per_pixel == 3) { - pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); + pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); - pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; - - pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 2, chips) << 16; + pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; + pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; + pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 2) & chips->svga.vram_mask] << 16; } } if (chips->bitblt_running.bytes_per_pixel == 2) { @@ -980,7 +1291,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) : chips->bitblt_running.bitblt.pattern_source_key_bg; color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1018,7 +1329,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; dest_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1030,20 +1341,21 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; + //chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); break; } case 2: /* 16 bits-per-pixel. */ { - chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); - chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); + chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; + chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; break; } case 3: /* 24 bits-per-pixel. */ { - chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); - chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); - chips_69000_writeb_linear(dest_addr + 2, (dest_pixel >> 16) & 0xFF, chips); + chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; + chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; + chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] = (dest_pixel >> 16) & 0xFF; break; } } @@ -1211,7 +1523,8 @@ chips_69000_setup_bitblt(chips_69000_t* chips) uint32_t orig_source_addr = chips->bitblt_running.bitblt.source_addr; while (orig_count_y == chips->bitblt_running.count_y) { int i = 0; - uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); + //uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); + uint8_t data = chips->svga.vram[orig_source_addr & chips->svga.vram_mask]; orig_source_addr++; for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(data & (1 << (7 - i)))); @@ -1230,14 +1543,15 @@ chips_69000_setup_bitblt(chips_69000_t* chips) case 1: /* Bit-aligned */ case 2: /* Byte-aligned */ { - uint32_t data = chips_69000_readb_linear(source_addr, chips); + //uint32_t data = chips_69000_readb_linear(source_addr, chips); + uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask]; chips_69000_bitblt_write(chips, data & 0xFF); source_addr += 1; break; } case 3: /* Word-aligned*/ { - uint32_t data = chips_69000_readw_linear(source_addr, chips); + uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); source_addr += 2; @@ -1245,7 +1559,8 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 4: /* Doubleword-aligned*/ { - uint32_t data = chips_69000_readl_linear(source_addr, chips); + uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) + | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1255,7 +1570,15 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 5: /* Quadword-aligned*/ { - uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); + uint64_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] + | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) + | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) + | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24) + | ((uint64_t)chips->svga.vram[(source_addr + 4) & chips->svga.vram_mask] << 32ULL) + | ((uint64_t)chips->svga.vram[(source_addr + 5) & chips->svga.vram_mask] << 40ULL) + | ((uint64_t)chips->svga.vram[(source_addr + 6) & chips->svga.vram_mask] << 48ULL) + | ((uint64_t)chips->svga.vram[(source_addr + 7) & chips->svga.vram_mask] << 56ULL); + //uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1280,20 +1603,21 @@ chips_69000_setup_bitblt(chips_69000_t* chips) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - pixel = chips_69000_readb_linear(source_addr, chips); + //pixel = chips_69000_readb_linear(source_addr, chips); + pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; break; } case 2: /* 16 bits-per-pixel. */ { - pixel = chips_69000_readb_linear(source_addr, chips); - pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; + pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; + pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; break; } case 3: /* 24 bits-per-pixel. */ { - pixel = chips_69000_readb_linear(source_addr, chips); - pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; - pixel |= chips_69000_readb_linear(source_addr + 2, chips) << 16; + pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; + pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; + pixel |= chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16; break; } } From 35125e70205ab59ed731059f67827dc472987eb5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 16 Mar 2025 15:24:24 +0600 Subject: [PATCH 113/218] Don't use starblit/endblit for renderer switches --- src/qt/qt_mainwindow.cpp | 4 ++-- src/qt/qt_rendererstack.cpp | 11 ++++++----- src/qt/qt_rendererstack.hpp | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 497b791ca..fb265f34d 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -2025,8 +2025,8 @@ MainWindow::on_actionRenderer_options_triggered() ui->stackedWidget->switchRenderer(static_cast(vid_api)); if (show_second_monitors) { for (int i = 1; i < MONITORS_NUM; i++) { - if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { - ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (renderers[i]) { + renderers[i]->switchRenderer(static_cast(vid_api)); } } } diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index bd1fd2609..2b1cfdf26 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -288,7 +288,8 @@ RendererStack::leaveEvent(QEvent *event) void RendererStack::switchRenderer(Renderer renderer) { - startblit(); + //startblit(); + switchInProgress = true; if (current) { rendererWindow->finalize(); removeWidget(current.get()); @@ -349,7 +350,7 @@ RendererStack::createRenderer(Renderer renderer) connect(hw, &OpenGLRenderer::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); - endblit(); + switchInProgress = false; emit rendererChanged(); }); connect(hw, &OpenGLRenderer::errorInitializing, [=]() { @@ -381,7 +382,7 @@ RendererStack::createRenderer(Renderer renderer) connect(hw, &VulkanWindowRenderer::rendererInitialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); - endblit(); + switchInProgress = false; emit rendererChanged(); }); connect(hw, &VulkanWindowRenderer::errorInitializing, [=]() { @@ -413,7 +414,7 @@ RendererStack::createRenderer(Renderer renderer) if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) { imagebufs = rendererWindow->getBuffers(); - endblit(); + switchInProgress = false; emit rendererChanged(); } } @@ -423,7 +424,7 @@ void RendererStack::blit(int x, int y, int w, int h) { if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || - (w > 2048) || (h > 2048) || + (w > 2048) || (h > 2048) || (switchInProgress) || (monitors[m_monitor_index].target_buffer == NULL) || imagebufs.empty() || std::get(imagebufs[currentBuf])->test_and_set()) { video_blit_complete_monitor(m_monitor_index); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 309cae7f5..54ea49bb9 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -113,6 +113,7 @@ private: std::unique_ptr current; std::atomic_bool rendererTakesScreenshots; + std::atomic_bool switchInProgress{false}; }; #endif // QT_RENDERERCONTAINER_HPP From c77cef6d80cdfc4c6b824ebcade534eee1bce2b7 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sun, 16 Mar 2025 16:55:29 +0500 Subject: [PATCH 114/218] Fix Qt menu roles for certain menu items --- src/qt/qt_mainwindow.cpp | 1 + src/qt/qt_mainwindow.ui | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 497b791ca..cfd6e08aa 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -181,6 +181,7 @@ MainWindow::MainWindow(QWidget *parent) main_window = this; ui->setupUi(this); status->setSoundGainAction(ui->actionSound_gain); + ui->menuEGA_S_VGA_settings->menuAction()->setMenuRole(QAction::NoRole); ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); #ifdef Q_OS_WINDOWS diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui index b1dc0ecf1..ef3cf16c6 100644 --- a/src/qt/qt_mainwindow.ui +++ b/src/qt/qt_mainwindow.ui @@ -353,6 +353,9 @@ Exit + + QAction::QuitRole + @@ -815,6 +818,9 @@ Renderer options... + + QAction::NoRole + From 271a125301342b588456dd026ea90ae809105029 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 16 Mar 2025 23:33:40 +0600 Subject: [PATCH 115/218] Use `fpclassify` for FXAM instead of manual comparison NaN detection for interpreter floating point compare on ARM64 --- src/cpu/x87_ops.h | 14 ++++++++++++-- src/cpu/x87_ops_misc.h | 22 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 97f5415b9..6a51a2c7f 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -420,11 +420,19 @@ x87_compare(double a, double b) * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; double ea = a, eb = b; + const uint64_t ia = 0x3fec1a6ff866a936ULL; + const uint64_t ib = 0x3fec1a6ff866a938ULL; + + /* Hack to make CHKCOP happy. */ + if (!memcmp(&ea, &ia, 8) && !memcmp(&eb, &ib, 8)) + return FPU_SW_C3; if ((fpu_type < FPU_287XL) && !(cpu_state.npxc & 0x1000) && ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) eb = ea; - if (ea == eb) + if ((isnan(a) || isnan(b))) + result |= FPU_SW_C3 | FPU_SW_C2 | FPU_SW_C0; + else if (ea == eb) result |= FPU_SW_C3; else if (ea < eb) result |= FPU_SW_C0; @@ -473,7 +481,9 @@ x87_ucompare(double a, double b) * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; - if (a == b) + if ((isnan(a) || isnan(b))) + result |= FPU_SW_C3 | FPU_SW_C2 | FPU_SW_C0; + else if (a == b) result |= FPU_SW_C3; else if (a < b) result |= FPU_SW_C0; diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 5821a5cd5..4009eadd6 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -585,10 +585,24 @@ opFXAM(UNUSED(uint32_t fetchdat)) if (cpu_state.tag[cpu_state.TOP & 7] == 3) cpu_state.npxs |= (FPU_SW_C0 | FPU_SW_C3); #endif - else if (ST(0) == 0.0) - cpu_state.npxs |= FPU_SW_C3; - else - cpu_state.npxs |= FPU_SW_C2; + else switch (fpclassify(ST(0))) + { + case FP_SUBNORMAL: + cpu_state.npxs |= FPU_SW_C2 | FPU_SW_C3; + break; + case FP_NAN: + cpu_state.npxs |= FPU_SW_C0; + break; + case FP_INFINITE: + cpu_state.npxs |= FPU_SW_C0 | FPU_SW_C2; + break; + case FP_ZERO: + cpu_state.npxs |= FPU_SW_C3; + break; + case FP_NORMAL: + cpu_state.npxs |= FPU_SW_C2; + break; + } if (ST(0) < 0.0) cpu_state.npxs |= FPU_SW_C1; CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fxam) : (x87_timings.fxam * cpu_multi)); From 1c5d432d3cf4332066ec48c0e572e11e95636ddb Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Mar 2025 18:37:32 +0100 Subject: [PATCH 116/218] Disable special segment selector pushing behavior on Pentium onwards, fixes MSVC builds of ReactOS. --- src/cpu/cpu.c | 79 +++++++++++++++++++++++++----------------------- src/cpu/cpu.h | 1 + src/cpu/x86seg.c | 23 +++++++++----- 3 files changed, 57 insertions(+), 46 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index c4d084947..b821bc657 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -209,6 +209,7 @@ int is286; int is386; int is6117; int is486 = 1; +int is586 = 0; int cpu_isintel; int cpu_iscyrix; int hascache; @@ -552,6 +553,8 @@ cpu_set(void) cpu_16bitbus = (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || (cpu_s->cpu_type == CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) || (cpu_s->cpu_type == CPU_IBM486SLC); cpu_64bitbus = (cpu_s->cpu_type >= CPU_WINCHIP); + is586 = cpu_64bitbus || (cpu_s->cpu_type == CPU_P24T); + if (cpu_s->multi) cpu_busspeed = cpu_s->rspeed / cpu_s->multi; else @@ -4303,47 +4306,47 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) static uint8_t cpu_read(uint16_t addr, UNUSED(void *priv)) { + uint8_t ret = 0xff; + if (addr == 0xf007) - return 0x7f; + ret = 0x7f; + else if ((addr < 0xf0) && (addr & 1)) switch (cyrix_addr) { + case 0xc0: + ret = ccr0; + break; + case 0xc1: + ret = ccr1; + break; + case 0xc2: + ret = ccr2; + break; + case 0xc3: + ret = ccr3; + break; + case 0xe8: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + break; + case 0xe9: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + break; + case 0xea: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + break; + case 0xeb: + ret = ccr7; + break; + case 0xfe: + ret = cpu_s->cyrix_id & 0xff; + break; + case 0xff: + ret = cpu_s->cyrix_id >> 8; + break; - if (addr >= 0xf0) - return 0xff; /* FPU stuff */ - - if (addr & 1) { - switch (cyrix_addr) { - case 0xc0: - return ccr0; - case 0xc1: - return ccr1; - case 0xc2: - return ccr2; - case 0xc3: - return ccr3; - case 0xe8: - return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; - case 0xe9: - return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; - case 0xea: - return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; - case 0xeb: - return ccr7; - case 0xfe: - return cpu_s->cyrix_id & 0xff; - case 0xff: - return cpu_s->cyrix_id >> 8; - - default: - break; - } - - if ((cyrix_addr & 0xf0) == 0xc0) - return 0xff; - - if (cyrix_addr == 0x20 && (cpu_s->cpu_type == CPU_Cx5x86)) - return 0xff; + default: + break; } - - return 0xff; + + return ret; } void diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 8324c543e..d58da6998 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -513,6 +513,7 @@ extern int is286; extern int is386; extern int is6117; extern int is486; +extern int is586; extern int is_am486; extern int is_am486dxl; extern int is_pentium; diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index 61c0edd9f..cd393812d 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -1113,7 +1113,7 @@ loadcscall(uint16_t seg) x86seg_log("Type %04X\n", type); if (type == 0x0c00) { - PUSHL_SEL(oldss); + is586 ? PUSHL(oldss) : PUSHL_SEL(oldss); PUSHL(oldsp2); if (cpu_state.abrt) { SS = oldss; @@ -1678,10 +1678,17 @@ pmodeint(int num, int soft) cpl_override = 1; if (type >= 0x0800) { if (cpu_state.eflags & VM_FLAG) { - PUSHL_SEL(GS); - PUSHL_SEL(FS); - PUSHL_SEL(DS); - PUSHL_SEL(ES); + if (is586) { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); + } else { + PUSHL_SEL(GS); + PUSHL_SEL(FS); + PUSHL_SEL(DS); + PUSHL_SEL(ES); + } if (cpu_state.abrt) return; op_loadseg(0, &cpu_state.seg_ds); @@ -1689,10 +1696,10 @@ pmodeint(int num, int soft) op_loadseg(0, &cpu_state.seg_fs); op_loadseg(0, &cpu_state.seg_gs); } - PUSHL_SEL(oldss); + is586 ? PUSHL(oldss) : PUSHL_SEL(oldss); PUSHL(oldsp); PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL_SEL(CS); + is586 ? PUSHL(CS) : PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; @@ -1728,7 +1735,7 @@ pmodeint(int num, int soft) } if (type > 0x0800) { PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL_SEL(CS); + is586 ? PUSHL(CS) : PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; From 9f200fe2e83c99c0e4b8076afe451bf0c3da8f98 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Mar 2025 21:20:15 +0100 Subject: [PATCH 117/218] 386 Interpreter: Check for debug breakpoint before segment limit and presence checking. --- src/cpu/386.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index caa5f84a2..c9a62fa6e 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -264,11 +264,7 @@ exec386_2386(int32_t cycs) ol = opcode_length[fetchdat & 0xff]; if ((ol == 3) && opcode_has_modrm[fetchdat & 0xff] && (((fetchdat >> 14) & 0x03) == 0x03)) ol = 2; - if (cpu_16bitbus) { - CHECK_READ_CS(MIN(ol, 2)); - } else { - CHECK_READ_CS(MIN(ol, 4)); - } + if (is386) ins_fetch_fault = cpu_386_check_instruction_fault(); @@ -276,6 +272,10 @@ exec386_2386(int32_t cycs) if (ins_fetch_fault) { ins_fetch_fault = 0; cpu_state.abrt = 1; + } else if (cpu_16bitbus) { + CHECK_READ_CS(MIN(ol, 2)); + } else { + CHECK_READ_CS(MIN(ol, 4)); } if (!cpu_state.abrt) { From 52a16529dcfd554c6e7e7a2c5c921388ee9bb9a4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Mar 2025 23:54:55 +0100 Subject: [PATCH 118/218] 386 Interpreter: Fix execute breakpoints. --- src/cpu/386.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index c9a62fa6e..6abb7da18 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -269,9 +269,11 @@ exec386_2386(int32_t cycs) ins_fetch_fault = cpu_386_check_instruction_fault(); /* Breakpoint fault has priority over other faults. */ - if (ins_fetch_fault) { + if ((cpu_state.abrt == 0) & ins_fetch_fault) { + x86gen(); ins_fetch_fault = 0; - cpu_state.abrt = 1; + /* No instructions executed at this point. */ + goto block_ended; } else if (cpu_16bitbus) { CHECK_READ_CS(MIN(ol, 2)); } else { @@ -288,7 +290,6 @@ exec386_2386(int32_t cycs) trap |= !!(cpu_state.flags & T_FLAG); cpu_state.pc++; - cpu_state.eflags &= ~(RF_FLAG); if (opcode == 0xf0) in_lock = 1; x86_2386_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); @@ -316,6 +317,7 @@ exec386_2386(int32_t cycs) if (cpu_end_block_after_ins) cpu_end_block_after_ins--; +block_ended: if (cpu_state.abrt) { flags_rebuild(); tempi = cpu_state.abrt & ABRT_MASK; @@ -338,6 +340,9 @@ exec386_2386(int32_t cycs) #endif } } + + if (!x86_was_reset && ins_fetch_fault) + x86gen(); } else if (new_ne) { flags_rebuild(); new_ne = 0; From dd4e493f646e316162c732b70ad86a3b81cc3b0f Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 00:07:41 +0100 Subject: [PATCH 119/218] Applied the fix to the optional 486 implementation as well. --- src/cpu/386.c | 2 +- src/cpu/386_dynarec.c | 45 ++++++++++++++++++------------------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index 6abb7da18..ed4b40ab2 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -341,7 +341,7 @@ block_ended: } } - if (!x86_was_reset && ins_fetch_fault) + if (is386 && !x86_was_reset && ins_fetch_fault) x86gen(); } else if (new_ne) { flags_rebuild(); diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 5f41c416a..fd6285057 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -276,11 +276,7 @@ exec386_dynarec_int(void) cpu_block_end = 0; x86_was_reset = 0; -# ifdef USE_DEBUG_REGS_486 - if (trap & 2) { -# else if (trap == 2) { -# endif /* Handle the T bit in the new TSS first. */ CPU_BLOCK_END(); goto block_ended; @@ -297,13 +293,6 @@ exec386_dynarec_int(void) cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; -# ifdef USE_DEBUG_REGS_486 - if (UNLIKELY(cpu_386_check_instruction_fault())) { - x86gen(); - goto block_ended; - } -# endif - fetchdat = fastreadl_fetch(cs + cpu_state.pc); # ifdef ENABLE_386_DYNAREC_LOG if (in_smm) @@ -370,13 +359,7 @@ exec386_dynarec_int(void) block_ended: if (!cpu_state.abrt && !new_ne && trap) { -# ifdef USE_DEBUG_REGS_486 - //pclog("Debug trap 0x%X\n", trap); - if (trap & 2) dr[6] |= 0x8000; - if (trap & 1) dr[6] |= 0x4000; -# else dr[6] |= (trap == 2) ? 0x8000 : 0x4000; -# endif trap = 0; # ifndef USE_NEW_DYNAREC @@ -902,6 +885,9 @@ exec386(int32_t cycs) cycdiff = 0; oldcyc = cycles; while (cycdiff < cycle_period) { +#ifdef USE_DEBUG_REGS_486 + int ins_fetch_fault = 0; +#endif ins_cycles = cycles; #ifndef USE_NEW_DYNAREC @@ -919,8 +905,14 @@ exec386(int32_t cycs) cpu_state.ssegs = 0; #ifdef USE_DEBUG_REGS_486 - if (UNLIKELY(cpu_386_check_instruction_fault())) { + if (is386) + ins_fetch_fault = cpu_386_check_instruction_fault(); + + /* Breakpoint fault has priority over other faults. */ + if ((cpu_state.abrt == 0) & ins_fetch_fault) { x86gen(); + ins_fetch_fault = 0; + /* No instructions executed at this point. */ goto block_ended; } #endif @@ -972,11 +964,13 @@ exec386(int32_t cycs) block_ended: #endif if (cpu_state.abrt) { + uint8_t oop = opcode; flags_rebuild(); tempi = cpu_state.abrt & ABRT_MASK; cpu_state.abrt = 0; x86_doabrt(tempi); if (cpu_state.abrt) { + pclog("Double fault - %02X\n", oop); cpu_state.abrt = 0; #ifndef USE_NEW_DYNAREC CS = oldcs; @@ -993,6 +987,11 @@ block_ended: #endif } } + +#ifdef USE_DEBUG_REGS_486 + if (is386 && !x86_was_reset && ins_fetch_fault) + x86gen(); +#endif } else if (new_ne) { flags_rebuild(); @@ -1005,20 +1004,14 @@ block_ended: } else if (trap) { flags_rebuild(); #ifdef USE_DEBUG_REGS_486 - if (trap & 1) - dr[6] |= 0x4000; - if (trap & 2) - dr[6] |= 0x8000; + if (trap & 2) dr[6] |= 0x8000; + if (trap & 1) dr[6] |= 0x4000; #endif - trap = 0; #ifndef USE_NEW_DYNAREC oldcs = CS; #endif cpu_state.oldpc = cpu_state.pc; -#ifndef USE_DEBUG_REGS_486 - dr[6] |= 0x4000; -#endif x86_int(1); } From bb1b6660103b9b61cf1d7621a0aa75cae09c0721 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 00:43:18 +0100 Subject: [PATCH 120/218] Removed some commented out stuff. --- src/cdrom/cdrom.c | 8 +----- src/disk/hdc_ide.c | 61 ++----------------------------------------- src/scsi/scsi_cdrom.c | 16 ------------ 3 files changed, 3 insertions(+), 82 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 6805d42c6..b30d93812 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -1796,11 +1796,8 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) position), the rest are stuff like ISRC etc., which can be all zeroes. */ case 0x00: - if (dev->bus_type == CDROM_BUS_ATAPI) { - // pclog("Format 0 on ATAPI\n"); + if (dev->bus_type == CDROM_BUS_ATAPI) break; - } - // pclog("Format 0 on SCSI\n"); diff = 0; fallthrough; case 0x01: @@ -1847,9 +1844,6 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) b[10] = (dat >> 8) & 0xff; b[11] = dat & 0xff; } - // pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - // b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], - // b[ 8], b[ 9], b[10], b[11]); if (b[0] != 0x00) break; base += 12; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index eb160c41b..61211228a 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1091,7 +1091,6 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - // pclog("Reading block %i (%i, %i)... ", ide->sc->sector_len + 1, ide->sc->block_len, ide->sc->packet_len); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) { @@ -1119,16 +1118,13 @@ ide_atapi_callback(ide_t *ide) default: break; case 0: - // pclog("ERROR\n"); if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; case 2: - // pclog("WAIT\n"); ide_atapi_command_bus(ide); break; case 3: - // pclog("DONE\n"); /* Reached EOT - terminate the command as there's nothing more to transfer. */ ide->sc->packet_status = PHASE_COMPLETE; @@ -1138,7 +1134,6 @@ ide_atapi_callback(ide_t *ide) ide->command_stop(ide->sc); fallthrough; case 1: - // pclog("NEXT\n"); if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); @@ -1214,7 +1209,6 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide->tf->pos = dev->request_pos = 0; if (dev->block_len == 0) { - // pclog("ide_atapi_pio_request(): Processing instant command...\n"); if (out && (ide->phase_data_out != NULL)) ide->phase_data_out(dev); else if (!out && (ide->command_stop != NULL)) @@ -1254,21 +1248,10 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) if (dev->block_len != 0) { if (out) { - if (ide->write != NULL) { -#if 0 - pclog("ide_atapi_pio_request(): Continuing write command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - + if (ide->write != NULL) ide->write(dev); - } if (dev->sector_len == 0) { -#if 0 - pclog("ide_atapi_pio_request(): Ending write command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - ide->sc->packet_status = PHASE_COMPLETE; ide->sc->callback = 0.0; @@ -1279,11 +1262,6 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) } } else { if (dev->sector_len == 0) { -#if 0 - pclog("ide_atapi_pio_request(): Ending read command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - if (ide->command_stop != NULL) ide->command_stop(dev); @@ -1291,14 +1269,8 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide->sc->callback = 0.0; ide_atapi_callback(ide); - } else if (ide->read != NULL) { -#if 0 - pclog("ide_atapi_pio_request(): Continuing read command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - + } else if (ide->read != NULL) ide->read(dev); - } } } } @@ -1332,26 +1304,6 @@ ide_atapi_packet_read(ide_t *ide) /* Time for a DRQ. */ ide_atapi_pio_request(ide, 0); } -#if 0 - else if ((dev->block_len != 0) && - (dev->sector_len != 0) && - ((dev->request_pos % dev->block_len) == 0)) { - if (dev->sector_len == 0) { - // pclog("ide_atapi_packet_read(): Ending read command (dev->sector_len = %i)...\n", dev->sector_len); - - if (ide->command_stop != NULL) - ide->command_stop(ide->sc); - - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; - - ide_atapi_callback(ide); - } else if (ide->read != NULL) { - // pclog("ide_atapi_packet_read(): Continuing read command (dev->sector_len = %i)...\n", dev->sector_len); - ide->read(dev); - } - } -#endif } return ret; @@ -1386,15 +1338,6 @@ ide_atapi_packet_write(ide_t *ide, const uint16_t val) /* Time for a DRQ. */ ide_atapi_pio_request(ide, 1); } -#if 0 - else if ((dev->block_len != 0) && - ((dev->request_pos % dev->block_len) == 0) && - (ide->write != NULL)) { - // pclog("ide_atapi_packet_write(): Continuing write command (dev->sector_len = %i)...\n", dev->sector_len); - - ide->write(dev); - } -#endif } else if (dev->packet_status == PHASE_IDLE) { if (ide->tf->pos >= 12) { ide->tf->pos = 0; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index eed57c63b..292c54127 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -663,8 +663,6 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) static void scsi_cdrom_set_period(scsi_cdrom_t *dev) { - // const uint8_t cmd = dev->current_cdb[0]; - scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); dev->callback = 0; @@ -689,7 +687,6 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; - // pclog("Current speed: %ix\n", dev->drv->cur_speed); } else { bytes_per_second = scsi_cdrom_bus_speed(dev); if (bytes_per_second == 0.0) { @@ -711,7 +708,6 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) (dev->packet_len / dev->block_len)); period *= ((double) num) * 2352.0; - // pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); @@ -1082,7 +1078,6 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int dev->sector_len--; - // pclog("Sector read to buffer position %08X\n", dev->buffer_pos); dev->buffer_pos += temp_len; } } @@ -2470,7 +2465,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) break; case GPCMD_REZERO_UNIT: - // pclog("Rezero unit\n"); dev->was_cached = 0; scsi_cdrom_stop(sc); dev->requested_blocks = 0; @@ -2505,7 +2499,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_SCAN_PIONEER: case GPCMD_AUDIO_SCAN: - // pclog("Audio scan\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; @@ -2552,7 +2545,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); toc_format = cdb[2] & 0xf; - // pclog("READ TOC format %1X\n", toc_format); if (toc_format == 0) toc_format = (cdb[9] >> 6) & 3; @@ -3170,20 +3162,16 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - // pclog("Play audio (10)\n"); break; case GPCMD_PLAY_AUDIO_12: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - // pclog("Play audio (12)\n"); break; case GPCMD_PLAY_AUDIO_MSF: msf = 1; pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - // pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", - // cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); break; case GPCMD_PLAY_AUDIO_TRACK_INDEX: msf = 2; @@ -3192,19 +3180,16 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = cdb[7]; } else ret = 0; - // pclog("Play audio track index\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: msf = 0x100 | cdb[6]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - // pclog("Play audio track relative (10)\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: msf = 0x100 | cdb[10]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - // pclog("Play audio track relative (12)\n"); break; default: @@ -3505,7 +3490,6 @@ atapi_out: case GPCMD_SEEK_6: case GPCMD_SEEK_10: - // pclog("Seek\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; From 79134f3b21648d280f56303a2c43d92821565eb5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 03:40:52 +0100 Subject: [PATCH 121/218] Assorted Cyrix (and Codegen opcode Mod R/M passing table) fixes - fixes Windows 98 SE on Cyrix 6x86's with power management enabled. --- src/codegen/codegen_x86-64.c | 8 +++--- src/codegen/codegen_x86.c | 8 +++--- src/codegen_new/codegen.c | 8 +++--- src/cpu/386_common.c | 50 +++++++++++++++++++++++++++++++++++- src/cpu/x86.h | 6 +++++ src/cpu/x86_ops_cyrix.h | 11 ++++++-- src/cpu/x86_ops_rep.h | 2 ++ src/cpu/x86_ops_rep_2386.h | 2 ++ src/cpu/x86_ops_rep_dyn.h | 2 ++ src/cpu/x86seg.c | 10 +++----- src/io.c | 16 ++++++++++++ 11 files changed, 102 insertions(+), 21 deletions(-) diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index 04c2136ff..00db630a3 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -499,14 +499,14 @@ static int opcode_modrm[256] = { int opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index df0ed3bfd..935e2bab6 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -1643,14 +1643,14 @@ static int opcode_modrm[256] = { int opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index 39ab69b3d..82f6cd037 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -359,14 +359,14 @@ static uint8_t opcode_modrm[256] = { static uint8_t opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 8a2bb4ab8..5b0e1a5c4 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -107,6 +107,12 @@ uint32_t backupregs[16]; x86seg _oldds; +uint8_t rep_op = 0x00; +uint8_t is_smint = 0; + +uint16_t io_port = 0x0000; +uint32_t io_val = 0x00000000; + int opcode_has_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ @@ -1215,7 +1221,7 @@ smram_restore_state_amd_k(uint32_t *saved_state) } static void -smram_save_state_cyrix(uint32_t *saved_state, UNUSED(int in_hlt)) +smram_save_state_cyrix(uint32_t *saved_state, int in_hlt) { saved_state[0] = dr[7]; saved_state[1] = cpu_state.flags | (cpu_state.eflags << 16); @@ -1224,6 +1230,35 @@ smram_save_state_cyrix(uint32_t *saved_state, UNUSED(int in_hlt)) saved_state[4] = cpu_state.pc; saved_state[5] = CS | (CPL << 21); saved_state[6] = 0x00000000; + saved_state[7] = 0x00010000; + + if (((opcode >= 0x6e) && (opcode <= 0x6f)) || ((opcode >= 0xe6) && (opcode <= 0xe7)) || + ((opcode >= 0xee) && (opcode <= 0xef))) { + saved_state[6] |= 0x00000002; + saved_state[7] = (opcode & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } else if (((opcode == 0xf2) || (opcode == 0xf3)) && (rep_op >= 0x6e) && (rep_op <= 0x6f)) { + saved_state[6] |= 0x00000006; + saved_state[7] = (rep_op & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } else if (((opcode == 0xf2) || (opcode == 0xf3)) && (rep_op >= 0x6e) && (rep_op <= 0x6f)) { + saved_state[6] |= 0x00000004; + saved_state[7] = (rep_op & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } + + if (is_smint) { + saved_state[6] |= 0x00000008; + is_smint = 0; + } + + if (in_hlt) + saved_state[6] |= 0x00000010; + + saved_state[7] |= io_port; + saved_state[8] = io_val; + + if (saved_state[6] & 0x00000002) + saved_state[9] = ESI; + else + saved_state[9] = EDI; } static void @@ -1234,6 +1269,13 @@ smram_restore_state_cyrix(uint32_t *saved_state) cpu_state.eflags = saved_state[1] >> 16; cr0 = saved_state[2]; cpu_state.pc = saved_state[4]; + /* Restore CPL. */ + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x9f) | (((saved_state[5] >> 21) & 0x03) << 5); + + if (saved_state[6] & 0x00000002) + ESI = saved_state[9]; + else + EDI = saved_state[9]; } void @@ -1368,6 +1410,9 @@ enter_smm(int in_hlt) writememl(0, smram_state - 0x14, saved_state[4]); writememl(0, smram_state - 0x18, saved_state[5]); writememl(0, smram_state - 0x24, saved_state[6]); + writememl(0, smram_state - 0x28, saved_state[7]); + writememl(0, smram_state - 0x2c, saved_state[8]); + writememl(0, smram_state - 0x30, saved_state[9]); } else { for (uint8_t n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { smram_state -= 4; @@ -1452,6 +1497,9 @@ leave_smm(void) else cyrix_load_seg_descriptor_2386(smram_state - 0x20, &cpu_state.seg_cs); saved_state[6] = readmeml(0, smram_state - 0x24); + saved_state[7] = readmeml(0, smram_state - 0x28); + saved_state[8] = readmeml(0, smram_state - 0x2c); + saved_state[9] = readmeml(0, smram_state - 0x30); } else { for (uint8_t n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { smram_state -= 4; diff --git a/src/cpu/x86.h b/src/cpu/x86.h index 327af8964..ccfeadea0 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -103,4 +103,10 @@ extern int fpu_cycles; extern void x86illegal(void); +extern uint8_t rep_op; +extern uint8_t is_smint; + +extern uint16_t io_port; +extern uint32_t io_val; + #endif /*EMU_X86_H*/ diff --git a/src/cpu/x86_ops_cyrix.h b/src/cpu/x86_ops_cyrix.h index 8c3d6e155..ac864cd20 100644 --- a/src/cpu/x86_ops_cyrix.h +++ b/src/cpu/x86_ops_cyrix.h @@ -63,18 +63,23 @@ opRSDC_common(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*ES*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_es); + ES = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x18: /*DS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_ds); + DS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x10: /*SS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_ss); + SS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x20: /*FS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_fs); + FS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x28: /*GS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_gs); + GS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; default: x86illegal(); @@ -216,8 +221,10 @@ opSMINT(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opSMINT\n"); - else - x86illegal(); + else { + is_smint = 1; + enter_smm(0); + } return 1; } diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index c75684d31..6449912e9 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -855,6 +855,7 @@ opREPNE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -869,6 +870,7 @@ opREPE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86_ops_rep_2386.h b/src/cpu/x86_ops_rep_2386.h index aa1984f81..3b96d54e3 100644 --- a/src/cpu/x86_ops_rep_2386.h +++ b/src/cpu/x86_ops_rep_2386.h @@ -843,6 +843,7 @@ opREPNE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -857,6 +858,7 @@ opREPE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86_ops_rep_dyn.h b/src/cpu/x86_ops_rep_dyn.h index bdb721ab0..1220c0da3 100644 --- a/src/cpu/x86_ops_rep_dyn.h +++ b/src/cpu/x86_ops_rep_dyn.h @@ -761,6 +761,7 @@ opREPNE(uint32_t fetchdat) cpu_state.pc++; CLOCK_CYCLES(2); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -774,6 +775,7 @@ opREPE(uint32_t fetchdat) cpu_state.pc++; CLOCK_CYCLES(2); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index cd393812d..2a0601661 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -2581,19 +2581,17 @@ cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg) cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else cpu_cur_status |= CPU_STATUS_NOTFLATDS; -#ifdef USE_DYNAREC - codegen_flat_ds = 0; -#endif } + + if (seg == &cpu_state.seg_cs) + set_use32(segdat[3] & 0x40); + if (seg == &cpu_state.seg_ss) { if (seg->base == 0 && seg->limit_low == 0 && seg->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; else cpu_cur_status |= CPU_STATUS_NOTFLATSS; set_stack32((segdat[3] & 0x40) ? 1 : 0); -#ifdef USE_DYNAREC - codegen_flat_ss = 0; -#endif } } } diff --git a/src/io.c b/src/io.c index 27f8503b0..9554c971d 100644 --- a/src/io.c +++ b/src/io.c @@ -28,6 +28,7 @@ #include <86box/io.h> #include <86box/timer.h> #include "cpu.h" +#include "x86.h" #include <86box/m_amstrad.h> #include <86box/pci.h> @@ -344,6 +345,8 @@ inb(uint16_t port) int qfound = 0; #endif + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -408,6 +411,9 @@ outb(uint16_t port, uint8_t val) int qfound = 0; #endif + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -464,6 +470,8 @@ inw(uint16_t port) #endif uint8_t ret8[2]; + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -540,6 +548,9 @@ outw(uint16_t port, uint16_t val) int qfound = 0; #endif + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -612,6 +623,8 @@ inl(uint16_t port) int qfound = 0; #endif + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -720,6 +733,9 @@ outl(uint16_t port, uint32_t val) #endif int i = 0; + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif From 49463607c1b5825d7805fdc5abcdec9bb1ed4027 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 04:29:58 +0100 Subject: [PATCH 122/218] C&T 69000: Rewrite the PCI register handling and intialize the registers to sane default, fixes the card's detection by the Windows 98 driver installer. --- src/video/vid_chips_69000.c | 248 +++++++++++++++++++++--------------- 1 file changed, 144 insertions(+), 104 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index b0e8db35a..c17fe2004 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -107,6 +107,7 @@ typedef struct chips_69000_t { uint8_t mm_regs[256], mm_index; uint8_t flat_panel_regs[256], flat_panel_index; uint8_t ext_regs[256], ext_index; + uint8_t pci_regs[256]; union { uint32_t mem_regs[4]; @@ -2156,57 +2157,74 @@ static uint8_t chips_69000_pci_read(UNUSED(int func), int addr, void *priv) { chips_69000_t *chips = (chips_69000_t *) priv; + uint8_t ret = 0x00; - { - switch (addr) { - case 0x00: - return 0x2C; - case 0x01: - return 0x10; - case 0x02: - return 0xC0; - case 0x03: - return 0x00; - case 0x04: - return (chips->pci_conf_status & 0b11100011) | 0x80; - case 0x06: - return 0x80; - case 0x07: - return 0x02; - case 0x08: - case 0x09: - case 0x0a: - return 0x00; - case 0x0b: - return 0x03; - case 0x13: - return chips->linear_mapping.base >> 24; - case 0x30: - return chips->pci_rom_enable & 0x1; - case 0x31: - return 0x0; - case 0x32: - return chips->rom_addr & 0xFF; - case 0x33: - return (chips->rom_addr & 0xFF00) >> 8; - case 0x3c: - return chips->pci_line_interrupt; - case 0x3d: - return 0x01; - case 0x2C: - case 0x2D: - case 0x6C: - case 0x6D: - return (chips->subsys_vid >> ((addr & 1) * 8)) & 0xFF; - case 0x2E: - case 0x2F: - case 0x6E: - case 0x6F: - return (chips->subsys_pid >> ((addr & 1) * 8)) & 0xFF; - default: - return 0x00; - } + switch (addr) { + case 0x00: + ret = 0x2c; + break; + case 0x01: + ret = 0x10; + break; + case 0x02: + ret = 0xc0; + break; + case 0x03: + ret = 0x00; + break; + + case 0x04: + ret = (chips->pci_conf_status & 0x73) | 0x80; + break; + case 0x05: + ret = chips->pci_regs[addr] & 0x01; + break; + case 0x06: + ret = 0x80; + break; + case 0x07: + ret = chips->pci_regs[addr] | 0x02; + break; + + case 0x0b: + ret = 0x03; + break; + + case 0x13: + ret = chips->linear_mapping.base >> 24; + break; + + case 0x2c ... 0x2d: + case 0x6c ... 0x6d: + ret = chips->subsys_vid_b[addr & 1]; + break; + case 0x2e ... 0x2f: + case 0x6e ... 0x6f: + ret = chips->subsys_pid_b[addr & 1]; + break; + + case 0x30: + ret = chips->pci_rom_enable & 0x1; + break; + case 0x32: + ret = chips->rom_addr & 0xff; + break; + case 0x33: + ret = (chips->rom_addr & 0xff00) >> 8; + break; + + case 0x3c: + ret = chips->pci_line_interrupt; + break; + case 0x3d: + ret = 0x01; + break; + + default: + break; } + + return ret; } static void @@ -2214,67 +2232,77 @@ chips_69000_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) { chips_69000_t *chips = (chips_69000_t *) priv; - { - switch (addr) { - case 0x04: - { - chips->pci_conf_status = val; - io_removehandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); - mem_mapping_disable(&chips->linear_mapping); - mem_mapping_disable(&chips->svga.mapping); - if (chips->pci_conf_status & PCI_COMMAND_IO) { - io_sethandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); - } - if (chips->pci_conf_status & PCI_COMMAND_MEM) { - mem_mapping_enable(&chips->svga.mapping); - if (chips->linear_mapping.base) - mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); - } - break; - } - case 0x13: - { - chips->linear_mapping.base = val << 24; - if (chips->linear_mapping.base) - mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); - break; - } - case 0x3c: - chips->pci_line_interrupt = val; - break; - case 0x30: - if (chips->on_board) break; + switch (addr) { + case 0x04: + chips->pci_conf_status = val; + io_removehandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); + mem_mapping_disable(&chips->linear_mapping); + mem_mapping_disable(&chips->svga.mapping); + if (!chips->on_board) + mem_mapping_disable(&chips->bios_rom.mapping); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); + if (val & PCI_COMMAND_MEM) { + if (!chips->on_board && (chips->pci_rom_enable & 1)) + mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); + mem_mapping_enable(&chips->svga.mapping); + if (chips->linear_mapping.base > 0x00000000) + mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); + } + break; + case 0x05: + chips->pci_regs[addr] = val & 0x01; + break; + case 0x07: + chips->pci_regs[addr] &= ~(val & 0xc8); + break; + + case 0x13: + chips->linear_mapping.base = val << 24; + mem_mapping_disable(&chips->linear_mapping); + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->linear_mapping.base > 0x00000000)) + mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); + break; + + case 0x30: + if (!chips->on_board) { chips->pci_rom_enable = val & 0x1; mem_mapping_disable(&chips->bios_rom.mapping); - if (chips->pci_rom_enable & 1) { + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->pci_rom_enable & 1)) mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); - } - break; - case 0x32: - if (chips->on_board) break; - chips->rom_addr &= ~0xFF; - chips->rom_addr |= val & 0xFC; - if (chips->pci_rom_enable & 1) { + } + break; + case 0x32: + if (!chips->on_board) { + chips->rom_addr &= ~0xff; + chips->rom_addr |= val & 0xfc; + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->pci_rom_enable & 1)) mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); - } - break; - case 0x33: - if (chips->on_board) break; - chips->rom_addr &= ~0xFF00; + } + break; + case 0x33: + if (!chips->on_board) { + chips->rom_addr &= ~0xff00; chips->rom_addr |= (val << 8); - if (chips->pci_rom_enable & 1) { + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->pci_rom_enable & 1)) mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); - } - break; - case 0x6C: - case 0x6D: - chips->subsys_vid_b[addr & 1] = val; - break; - case 0x6E: - case 0x6F: - chips->subsys_pid_b[addr & 1] = val; - break; - } + } + break; + + case 0x3c: + chips->pci_line_interrupt = val; + break; + + case 0x6c ... 0x6d: + chips->subsys_vid_b[addr & 1] = val; + break; + case 0x6e ... 0x6f: + chips->subsys_pid_b[addr & 1] = val; + break; } } @@ -2839,6 +2867,18 @@ chips_69000_init(const device_t *info) chips->flat_panel_regs[0x01] = 1; + chips->pci_conf_status = 0x00; + chips->pci_rom_enable = 0x00; + chips->rom_addr = 0x0000; + chips->subsys_vid = 0x102c; + chips->subsys_pid = 0x00c0; + + io_removehandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); + mem_mapping_disable(&chips->linear_mapping); + mem_mapping_disable(&chips->svga.mapping); + if (!chips->on_board) + mem_mapping_disable(&chips->bios_rom.mapping); + *reset_state = *chips; return chips; From b1a77195abe7b513583010b383a7f9ae317a16d2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 21:23:32 +0600 Subject: [PATCH 123/218] C&T 69000: Fix bad refresh rate --- src/video/vid_chips_69000.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index c17fe2004..f7ed7ef14 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -1428,7 +1428,6 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.bytes_skip = 0; chips->bitblt_running.mono_bytes_pitch = 0; chips->bitblt_running.mono_bits_skip_left = 0; - int orig_cycles = cycles; if (chips->bitblt.bitblt_control & (1 << 23)) { chips->bitblt_running.bytes_per_pixel = 1 + ((chips->bitblt.bitblt_control >> 24) & 3); @@ -1632,7 +1631,6 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.count_x = 0; chips->bitblt_running.x = 0; } while ((++chips->bitblt_running.count_y) < chips->bitblt_running.actual_destination_height); - cycles = orig_cycles; chips_69000_bitblt_interrupt(chips); } @@ -1644,7 +1642,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } if (chips->bitblt_running.bitblt.bitblt_control & (1 << 12)) { - int orig_cycles = cycles; chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bitblt.monochrome_source_alignment == 1) { uint8_t val = chips->bitblt_running.bytes_port[0]; @@ -1662,7 +1659,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(chips->bitblt_running.bytes_port[j] & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } @@ -1678,7 +1674,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y && chips->bitblt_running.bitblt.monochrome_source_alignment != 1) { - cycles = orig_cycles; return; } } @@ -1692,7 +1687,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 16; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (15 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } @@ -1706,7 +1700,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 32; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (31 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } @@ -1729,12 +1722,10 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 64; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (63 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } } - cycles = orig_cycles; return; } @@ -1744,7 +1735,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bytes_written == chips->bitblt_running.bytes_per_pixel) { - int orig_cycles = cycles; uint32_t source_pixel = chips->bitblt_running.bytes_port[0]; chips->bitblt_running.bytes_written = 0; if (chips->bitblt_running.bytes_per_pixel >= 2) @@ -1755,7 +1745,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { chips->bitblt_running.bytes_in_line_written += chips->bitblt_running.bytes_per_pixel; chips_69000_process_pixel(chips, source_pixel); - cycles = orig_cycles; chips->bitblt_running.x += chips->bitblt_running.x_dir; if (chips->bitblt_running.bytes_in_line_written >= chips->bitblt_running.bitblt.destination_width) { @@ -2746,7 +2735,7 @@ chips_69000_getclock(int clock, void *priv) int pl = ((chips->ext_regs[0xcb] >> 4) & 7); float fvco = 14318181.0 * ((float)(m + 2) / (float)(n + 2)); - if (chips->ext_regs[0xcb] & 4) + if (!(chips->ext_regs[0xcb] & 4)) fvco *= 4.0; float fo = fvco / (float)(1 << pl); @@ -2846,7 +2835,7 @@ chips_69000_init(const device_t *info) chips->svga.bpp = 8; chips->svga.miscout = 1; - chips->svga.vblank_start = chips_69000_vblank_start; + chips->svga.vsync_callback = chips_69000_vblank_start; chips->svga.getclock = chips_69000_getclock; chips->svga.conv_16to32 = chips_69000_conv_16to32; chips->svga.line_compare = chips_69000_line_compare; From 1bf78aebfdc599d65c67e6ff28ebbb9382a79f68 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 21:45:50 +0600 Subject: [PATCH 124/218] C&T 69000: Adjust interrupt conditions --- src/video/vid_chips_69000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index f7ed7ef14..29521d1ae 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -240,7 +240,7 @@ chips_69000_write_flat_panel(chips_69000_t* chips, uint8_t val) void chips_69000_interrupt(chips_69000_t* chips) { - pci_irq(chips->slot, PCI_INTA, 0, !!((chips->mem_regs[0] & chips->mem_regs[1]) & 0x80004040), &chips->irq_state); + pci_irq(chips->slot, PCI_INTA, 0, !!(chips->mem_regs[0] & chips->mem_regs[1] & 0x80004040), &chips->irq_state); } void @@ -2416,7 +2416,7 @@ chips_69000_writeb_mmio(uint32_t addr, uint8_t val, chips_69000_t* chips) { chips->mem_regs_b[addr & 0xF] = val; chips->mem_regs[(addr >> 2) & 0x3] &= 0x80004040; - if (addr == 0x605 || addr == 0x607) + if (addr == 0x601 || addr == 0x603) chips_69000_interrupt(chips); break; } From 277273c05da8153dfe59a9ec0a8656d36b1d5939 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 16:54:41 +0100 Subject: [PATCH 125/218] ATAPI PIO: Do not prematurely terminate the command if bytes are left to be transferred but all sectors have already been read into the buffer, fixes FreeBSD CD-ROM boot on some machines. --- src/disk/hdc_ide.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 61211228a..bf0d4d286 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1197,7 +1197,8 @@ ide_atapi_callback(ide_t *ide) static void ide_atapi_pio_request(ide_t *ide, uint8_t out) { - scsi_common_t *dev = ide->sc; + scsi_common_t *dev = ide->sc; + int left = 0; ide_irq_lower(ide); @@ -1221,6 +1222,8 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_log("%i bytes %s, %i bytes are still left\n", ide->tf->pos, out ? "written" : "read", dev->packet_len - ide->tf->pos); + left = 1; + /* If less than (packet length) bytes are remaining, update packet length accordingly. @@ -1252,23 +1255,33 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide->write(dev); if (dev->sector_len == 0) { - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; + if (left) { + ide_atapi_callback(ide); + ide_set_callback(ide, 0.0); + } else { + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; - if (ide->phase_data_out != NULL) - (void) ide->phase_data_out(dev); + if (ide->phase_data_out != NULL) + (void) ide->phase_data_out(dev); - ide_atapi_callback(ide); + ide_atapi_callback(ide); + } } } else { if (dev->sector_len == 0) { - if (ide->command_stop != NULL) - ide->command_stop(dev); + if (left) { + ide_atapi_callback(ide); + ide_set_callback(ide, 0.0); + } else { + if (ide->command_stop != NULL) + ide->command_stop(dev); - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; - ide_atapi_callback(ide); + ide_atapi_callback(ide); + } } else if (ide->read != NULL) ide->read(dev); } From 2019af174f9949bdc1017e95e02d206fb6ed0621 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 22:53:00 +0600 Subject: [PATCH 126/218] Revert "C&T 69000: Fix bad refresh rate" This reverts commit b1a77195abe7b513583010b383a7f9ae317a16d2. --- src/video/vid_chips_69000.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 29521d1ae..8963cb94b 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -1428,6 +1428,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.bytes_skip = 0; chips->bitblt_running.mono_bytes_pitch = 0; chips->bitblt_running.mono_bits_skip_left = 0; + int orig_cycles = cycles; if (chips->bitblt.bitblt_control & (1 << 23)) { chips->bitblt_running.bytes_per_pixel = 1 + ((chips->bitblt.bitblt_control >> 24) & 3); @@ -1631,6 +1632,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.count_x = 0; chips->bitblt_running.x = 0; } while ((++chips->bitblt_running.count_y) < chips->bitblt_running.actual_destination_height); + cycles = orig_cycles; chips_69000_bitblt_interrupt(chips); } @@ -1642,6 +1644,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } if (chips->bitblt_running.bitblt.bitblt_control & (1 << 12)) { + int orig_cycles = cycles; chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bitblt.monochrome_source_alignment == 1) { uint8_t val = chips->bitblt_running.bytes_port[0]; @@ -1659,6 +1662,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(chips->bitblt_running.bytes_port[j] & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } @@ -1674,6 +1678,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y && chips->bitblt_running.bitblt.monochrome_source_alignment != 1) { + cycles = orig_cycles; return; } } @@ -1687,6 +1692,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 16; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (15 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } @@ -1700,6 +1706,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 32; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (31 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } @@ -1722,10 +1729,12 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 64; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (63 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } } + cycles = orig_cycles; return; } @@ -1735,6 +1744,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bytes_written == chips->bitblt_running.bytes_per_pixel) { + int orig_cycles = cycles; uint32_t source_pixel = chips->bitblt_running.bytes_port[0]; chips->bitblt_running.bytes_written = 0; if (chips->bitblt_running.bytes_per_pixel >= 2) @@ -1745,6 +1755,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { chips->bitblt_running.bytes_in_line_written += chips->bitblt_running.bytes_per_pixel; chips_69000_process_pixel(chips, source_pixel); + cycles = orig_cycles; chips->bitblt_running.x += chips->bitblt_running.x_dir; if (chips->bitblt_running.bytes_in_line_written >= chips->bitblt_running.bitblt.destination_width) { @@ -2735,7 +2746,7 @@ chips_69000_getclock(int clock, void *priv) int pl = ((chips->ext_regs[0xcb] >> 4) & 7); float fvco = 14318181.0 * ((float)(m + 2) / (float)(n + 2)); - if (!(chips->ext_regs[0xcb] & 4)) + if (chips->ext_regs[0xcb] & 4) fvco *= 4.0; float fo = fvco / (float)(1 << pl); @@ -2835,7 +2846,7 @@ chips_69000_init(const device_t *info) chips->svga.bpp = 8; chips->svga.miscout = 1; - chips->svga.vsync_callback = chips_69000_vblank_start; + chips->svga.vblank_start = chips_69000_vblank_start; chips->svga.getclock = chips_69000_getclock; chips->svga.conv_16to32 = chips_69000_conv_16to32; chips->svga.line_compare = chips_69000_line_compare; From 65020a80c88801581d1400f23dfe515fa85b7195 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 22:53:36 +0600 Subject: [PATCH 127/218] Revert "C&T 69000: All ROPs now implemented, also fixed transparency bitblts" This reverts commit 000af483f3e0561fbb4c214496d20d0be358359b. --- src/video/vid_chips_69000.c | 1342 +++++++++++++---------------------- 1 file changed, 509 insertions(+), 833 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 8963cb94b..0347435fa 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -252,797 +252,486 @@ chips_69000_bitblt_interrupt(chips_69000_t* chips) chips_69000_interrupt(chips); } -#define ROPMIX(R, D, P, S, out) \ - { \ - switch (R) { \ - case 0x00: \ - out = 0; \ - break; \ - case 0x01: \ - out = ~(D | (P | S)); \ - break; \ - case 0x02: \ - out = D & ~(P | S); \ - break; \ - case 0x03: \ - out = ~(P | S); \ - break; \ - case 0x04: \ - out = S & ~(D | P); \ - break; \ - case 0x05: \ - out = ~(D | P); \ - break; \ - case 0x06: \ - out = ~(P | ~(D ^ S)); \ - break; \ - case 0x07: \ - out = ~(P | (D & S)); \ - break; \ - case 0x08: \ - out = S & (D & ~P); \ - break; \ - case 0x09: \ - out = ~(P | (D ^ S)); \ - break; \ - case 0x0a: \ - out = D & ~P; \ - break; \ - case 0x0b: \ - out = ~(P | (S & ~D)); \ - break; \ - case 0x0c: \ - out = S & ~P; \ - break; \ - case 0x0d: \ - out = ~(P | (D & ~S)); \ - break; \ - case 0x0e: \ - out = ~(P | ~(D | S)); \ - break; \ - case 0x0f: \ - out = ~P; \ - break; \ - case 0x10: \ - out = P & ~(D | S); \ - break; \ - case 0x11: \ - out = ~(D | S); \ - break; \ - case 0x12: \ - out = ~(S | ~(D ^ P)); \ - break; \ - case 0x13: \ - out = ~(S | (D & P)); \ - break; \ - case 0x14: \ - out = ~(D | ~(P ^ S)); \ - break; \ - case 0x15: \ - out = ~(D | (P & S)); \ - break; \ - case 0x16: \ - out = P ^ (S ^ (D & ~(P & S))); \ - break; \ - case 0x17: \ - out = ~(S ^ ((S ^ P) & (D ^ S))); \ - break; \ - case 0x18: \ - out = (S ^ P) & (P ^ D); \ - break; \ - case 0x19: \ - out = ~(S ^ (D & ~(P & S))); \ - break; \ - case 0x1a: \ - out = P ^ (D | (S & P)); \ - break; \ - case 0x1b: \ - out = ~(S ^ (D & (P ^ S))); \ - break; \ - case 0x1c: \ - out = P ^ (S | (D & P)); \ - break; \ - case 0x1d: \ - out = ~(D ^ (S & (P ^ D))); \ - break; \ - case 0x1e: \ - out = P ^ (D | S); \ - break; \ - case 0x1f: \ - out = ~(P & (D | S)); \ - break; \ - case 0x20: \ - out = D & (P & ~S); \ - break; \ - case 0x21: \ - out = ~(S | (D ^ P)); \ - break; \ - case 0x22: \ - out = D & ~S; \ - break; \ - case 0x23: \ - out = ~(S | (P & ~D)); \ - break; \ - case 0x24: \ - out = (S ^ P) & (D ^ S); \ - break; \ - case 0x25: \ - out = ~(P ^ (D & ~(S & P))); \ - break; \ - case 0x26: \ - out = S ^ (D | (P & S)); \ - break; \ - case 0x27: \ - out = S ^ (D | ~(P ^ S)); \ - break; \ - case 0x28: \ - out = D & (P ^ S); \ - break; \ - case 0x29: \ - out = ~(P ^ (S ^ (D | (P & S)))); \ - break; \ - case 0x2a: \ - out = D & ~(P & S); \ - break; \ - case 0x2b: \ - out = ~(S ^ ((S ^ P) & (P ^ D))); \ - break; \ - case 0x2c: \ - out = S ^ (P & (D | S)); \ - break; \ - case 0x2d: \ - out = P ^ (S | ~D); \ - break; \ - case 0x2e: \ - out = P ^ (S | (D ^ P)); \ - break; \ - case 0x2f: \ - out = ~(P & (S | ~D)); \ - break; \ - case 0x30: \ - out = P & ~S; \ - break; \ - case 0x31: \ - out = ~(S | (D & ~P)); \ - break; \ - case 0x32: \ - out = S ^ (D | (P | S)); \ - break; \ - case 0x33: \ - out = ~S; \ - break; \ - case 0x34: \ - out = S ^ (P | (D & S)); \ - break; \ - case 0x35: \ - out = S ^ (P | ~(D ^ S)); \ - break; \ - case 0x36: \ - out = S ^ (D | P); \ - break; \ - case 0x37: \ - out = ~(S & (D | P)); \ - break; \ - case 0x38: \ - out = P ^ (S & (D | P)); \ - break; \ - case 0x39: \ - out = S ^ (P | ~D); \ - break; \ - case 0x3a: \ - out = S ^ (P | (D ^ S)); \ - break; \ - case 0x3b: \ - out = ~(S & (P | ~D)); \ - break; \ - case 0x3c: \ - out = P ^ S; \ - break; \ - case 0x3d: \ - out = S ^ (P | ~(D | S)); \ - break; \ - case 0x3e: \ - out = S ^ (P | (D & ~S)); \ - break; \ - case 0x3f: \ - out = ~(P & S); \ - break; \ - case 0x40: \ - out = P & (S & ~D); \ - break; \ - case 0x41: \ - out = ~(D | (P ^ S)); \ - break; \ - case 0x42: \ - out = (S ^ D) & (P ^ D); \ - break; \ - case 0x43: \ - out = ~(S ^ (P & ~(D & S))); \ - break; \ - case 0x44: \ - out = S & ~D; \ - break; \ - case 0x45: \ - out = ~(D | (P & ~S)); \ - break; \ - case 0x46: \ - out = D ^ (S | (P & D)); \ - break; \ - case 0x47: \ - out = ~(P ^ (S & (D ^ P))); \ - break; \ - case 0x48: \ - out = S & (D ^ P); \ - break; \ - case 0x49: \ - out = ~(P ^ (D ^ (S | (P & D)))); \ - break; \ - case 0x4a: \ - out = D ^ (P & (S | D)); \ - break; \ - case 0x4b: \ - out = P ^ (D | ~S); \ - break; \ - case 0x4c: \ - out = S & ~(D & P); \ - break; \ - case 0x4d: \ - out = ~(S ^ ((S ^ P) | (D ^ S))); \ - break; \ - case 0x4e: \ - out = P ^ (D | (S ^ P)); \ - break; \ - case 0x4f: \ - out = ~(P & (D | ~S)); \ - break; \ - case 0x50: \ - out = P & ~D; \ - break; \ - case 0x51: \ - out = ~(D | (S & ~P)); \ - break; \ - case 0x52: \ - out = D ^ (P | (S & D)); \ - break; \ - case 0x53: \ - out = ~(S ^ (P & (D ^ S))); \ - break; \ - case 0x54: \ - out = ~(D | ~(P | S)); \ - break; \ - case 0x55: \ - out = ~D; \ - break; \ - case 0x56: \ - out = D ^ (P | S); \ - break; \ - case 0x57: \ - out = ~(D & (P | S)); \ - break; \ - case 0x58: \ - out = P ^ (D & (S | P)); \ - break; \ - case 0x59: \ - out = D ^ (P | ~S); \ - break; \ - case 0x5a: \ - out = D ^ P; \ - break; \ - case 0x5b: \ - out = D ^ (P | ~(S | D)); \ - break; \ - case 0x5c: \ - out = D ^ (P | (S ^ D)); \ - break; \ - case 0x5d: \ - out = ~(D & (P | ~S)); \ - break; \ - case 0x5e: \ - out = D ^ (P | (S & ~D)); \ - break; \ - case 0x5f: \ - out = ~(D & P); \ - break; \ - case 0x60: \ - out = P & (D ^ S); \ - break; \ - case 0x61: \ - out = ~(D ^ (S ^ (P | (D & S)))); \ - break; \ - case 0x62: \ - out = D ^ (S & (P | D)); \ - break; \ - case 0x63: \ - out = S ^ (D | ~P); \ - break; \ - case 0x64: \ - out = S ^ (D & (P | S)); \ - break; \ - case 0x65: \ - out = D ^ (S | ~P); \ - break; \ - case 0x66: \ - out = D ^ S; \ - break; \ - case 0x67: \ - out = S ^ (D | ~(P | S)); \ - break; \ - case 0x68: \ - out = ~(D ^ (S ^ (P | ~(D | S)))); \ - break; \ - case 0x69: \ - out = ~(P ^ (D ^ S)); \ - break; \ - case 0x6a: \ - out = D ^ (P & S); \ - break; \ - case 0x6b: \ - out = ~(P ^ (S ^ (D & (P | S)))); \ - break; \ - case 0x6c: \ - out = S ^ (D & P); \ - break; \ - case 0x6d: \ - out = ~(P ^ (D ^ (S & (P | D)))); \ - break; \ - case 0x6e: \ - out = S ^ (D & (P | ~S)); \ - break; \ - case 0x6f: \ - out = ~(P & ~(D ^ S)); \ - break; \ - case 0x70: \ - out = P & ~(D & S); \ - break; \ - case 0x71: \ - out = ~(S ^ ((S ^ D) & (P ^ D))); \ - break; \ - case 0x72: \ - out = S ^ (D | (P ^ S)); \ - break; \ - case 0x73: \ - out = ~(S & (D | ~P)); \ - break; \ - case 0x74: \ - out = D ^ (S | (P ^ D)); \ - break; \ - case 0x75: \ - out = ~(D & (S | ~P)); \ - break; \ - case 0x76: \ - out = S ^ (D | (P & ~S)); \ - break; \ - case 0x77: \ - out = ~(D & S); \ - break; \ - case 0x78: \ - out = P ^ (D & S); \ - break; \ - case 0x79: \ - out = ~(D ^ (S ^ (P & (D | S)))); \ - break; \ - case 0x7a: \ - out = D ^ (P & (S | ~D)); \ - break; \ - case 0x7b: \ - out = ~(S & ~(D ^ P)); \ - break; \ - case 0x7c: \ - out = S ^ (P & (D | ~S)); \ - break; \ - case 0x7d: \ - out = ~(D & ~(P ^ S)); \ - break; \ - case 0x7e: \ - out = (S ^ P) | (D ^ S); \ - break; \ - case 0x7f: \ - out = ~(D & (P & S)); \ - break; \ - case 0x80: \ - out = D & (P & S); \ - break; \ - case 0x81: \ - out = ~((S ^ P) | (D ^ S)); \ - break; \ - case 0x82: \ - out = D & ~(P ^ S); \ - break; \ - case 0x83: \ - out = ~(S ^ (P & (D | ~S))); \ - break; \ - case 0x84: \ - out = S & ~(D ^ P); \ - break; \ - case 0x85: \ - out = ~(P ^ (D & (S | ~P))); \ - break; \ - case 0x86: \ - out = D ^ (S ^ (P & (D | S))); \ - break; \ - case 0x87: \ - out = ~(P ^ (D & S)); \ - break; \ - case 0x88: \ - out = D & S; \ - break; \ - case 0x89: \ - out = ~(S ^ (D | (P & ~S))); \ - break; \ - case 0x8a: \ - out = D & (S | ~P); \ - break; \ - case 0x8b: \ - out = ~(D ^ (S | (P ^ D))); \ - break; \ - case 0x8c: \ - out = S & (D | ~P); \ - break; \ - case 0x8d: \ - out = ~(S ^ (D | (P ^ S))); \ - break; \ - case 0x8e: \ - out = S ^ ((S ^ D) & (P ^ D)); \ - break; \ - case 0x8f: \ - out = ~(P & ~(D & S)); \ - break; \ - case 0x90: \ - out = P & ~(D ^ S); \ - break; \ - case 0x91: \ - out = ~(S ^ (D & (P | ~S))); \ - break; \ - case 0x92: \ - out = D ^ (P ^ (S & (D | P))); \ - break; \ - case 0x93: \ - out = ~(S ^ (P & D)); \ - break; \ - case 0x94: \ - out = P ^ (S ^ (D & (P | S))); \ - break; \ - case 0x95: \ - out = ~(D ^ (P & S)); \ - break; \ - case 0x96: \ - out = D ^ (P ^ S); \ - break; \ - case 0x97: \ - out = P ^ (S ^ (D | ~(P | S))); \ - break; \ - case 0x98: \ - out = ~(S ^ (D | ~(P | S))); \ - break; \ - case 0x99: \ - out = ~(D ^ S); \ - break; \ - case 0x9a: \ - out = D ^ (P & ~S); \ - break; \ - case 0x9b: \ - out = ~(S ^ (D & (P | S))); \ - break; \ - case 0x9c: \ - out = S ^ (P & ~D); \ - break; \ - case 0x9d: \ - out = ~(D ^ (S & (P | D))); \ - break; \ - case 0x9e: \ - out = D ^ (S ^ (P | (D & S))); \ - break; \ - case 0x9f: \ - out = ~(P & (D ^ S)); \ - break; \ - case 0xa0: \ - out = D & P; \ - break; \ - case 0xa1: \ - out = ~(P ^ (D | (S & ~P))); \ - break; \ - case 0xa2: \ - out = D & (P | ~S); \ - break; \ - case 0xa3: \ - out = ~(D ^ (P | (S ^ D))); \ - break; \ - case 0xa4: \ - out = ~(P ^ (D | ~(S | P))); \ - break; \ - case 0xa5: \ - out = ~(P ^ D); \ - break; \ - case 0xa6: \ - out = D ^ (S & ~P); \ - break; \ - case 0xa7: \ - out = ~(P ^ (D & (S | P))); \ - break; \ - case 0xa8: \ - out = D & (P | S); \ - break; \ - case 0xa9: \ - out = ~(D ^ (P | S)); \ - break; \ - case 0xaa: \ - out = D; \ - break; \ - case 0xab: \ - out = D | ~(P | S); \ - break; \ - case 0xac: \ - out = S ^ (P & (D ^ S)); \ - break; \ - case 0xad: \ - out = ~(D ^ (P | (S & D))); \ - break; \ - case 0xae: \ - out = D | (S & ~P); \ - break; \ - case 0xaf: \ - out = D | ~P; \ - break; \ - case 0xb0: \ - out = P & (D | ~S); \ - break; \ - case 0xb1: \ - out = ~(P ^ (D | (S ^ P))); \ - break; \ - case 0xb2: \ - out = S ^ ((S ^ P) | (D ^ S)); \ - break; \ - case 0xb3: \ - out = ~(S & ~(D & P)); \ - break; \ - case 0xb4: \ - out = P ^ (S & ~D); \ - break; \ - case 0xb5: \ - out = ~(D ^ (P & (S | D))); \ - break; \ - case 0xb6: \ - out = D ^ (P ^ (S | (D & P))); \ - break; \ - case 0xb7: \ - out = ~(S & (D ^ P)); \ - break; \ - case 0xb8: \ - out = P ^ (S & (D ^ P)); \ - break; \ - case 0xb9: \ - out = ~(D ^ (S | (P & D))); \ - break; \ - case 0xba: \ - out = D | (P & ~S); \ - break; \ - case 0xbb: \ - out = D | ~S; \ - break; \ - case 0xbc: \ - out = S ^ (P & ~(D & S)); \ - break; \ - case 0xbd: \ - out = ~((S ^ D) & (P ^ D)); \ - break; \ - case 0xbe: \ - out = D | (P ^ S); \ - break; \ - case 0xbf: \ - out = D | ~(P & S); \ - break; \ - case 0xc0: \ - out = P & S; \ - break; \ - case 0xc1: \ - out = ~(S ^ (P | (D & ~S))); \ - break; \ - case 0xc2: \ - out = ~(S ^ (P | ~(D | S))); \ - break; \ - case 0xc3: \ - out = ~(P ^ S); \ - break; \ - case 0xc4: \ - out = S & (P | ~D); \ - break; \ - case 0xc5: \ - out = ~(S ^ (P | (D ^ S))); \ - break; \ - case 0xc6: \ - out = S ^ (D & ~P); \ - break; \ - case 0xc7: \ - out = ~(P ^ (S & (D | P))); \ - break; \ - case 0xc8: \ - out = S & (D | P); \ - break; \ - case 0xc9: \ - out = ~(S ^ (P | D)); \ - break; \ - case 0xca: \ - out = D ^ (P & (S ^ D)); \ - break; \ - case 0xcb: \ - out = ~(S ^ (P | (D & S))); \ - break; \ - case 0xcc: \ - out = S; \ - break; \ - case 0xcd: \ - out = S | ~(D | P); \ - break; \ - case 0xce: \ - out = S | (D & ~P); \ - break; \ - case 0xcf: \ - out = S | ~P; \ - break; \ - case 0xd0: \ - out = P & (S | ~D); \ - break; \ - case 0xd1: \ - out = ~(P ^ (S | (D ^ P))); \ - break; \ - case 0xd2: \ - out = P ^ (D & ~S); \ - break; \ - case 0xd3: \ - out = ~(S ^ (P & (D | S))); \ - break; \ - case 0xd4: \ - out = S ^ ((S ^ P) & (P ^ D)); \ - break; \ - case 0xd5: \ - out = ~(D & ~(P & S)); \ - break; \ - case 0xd6: \ - out = P ^ (S ^ (D | (P & S))); \ - break; \ - case 0xd7: \ - out = ~(D & (P ^ S)); \ - break; \ - case 0xd8: \ - out = P ^ (D & (S ^ P)); \ - break; \ - case 0xd9: \ - out = ~(S ^ (D | (P & S))); \ - break; \ - case 0xda: \ - out = D ^ (P & ~(S & D)); \ - break; \ - case 0xdb: \ - out = ~((S ^ P) & (D ^ S)); \ - break; \ - case 0xdc: \ - out = S | (P & ~D); \ - break; \ - case 0xdd: \ - out = S | ~D; \ - break; \ - case 0xde: \ - out = S | (D ^ P); \ - break; \ - case 0xdf: \ - out = S | ~(D & P); \ - break; \ - case 0xe0: \ - out = P & (D | S); \ - break; \ - case 0xe1: \ - out = ~(P ^ (D | S)); \ - break; \ - case 0xe2: \ - out = D ^ (S & (P ^ D)); \ - break; \ - case 0xe3: \ - out = ~(P ^ (S | (D & P))); \ - break; \ - case 0xe4: \ - out = S ^ (D & (P ^ S)); \ - break; \ - case 0xe5: \ - out = ~(P ^ (D | (S & P))); \ - break; \ - case 0xe6: \ - out = S ^ (D & ~(P & S)); \ - break; \ - case 0xe7: \ - out = ~((S ^ P) & (P ^ D)); \ - break; \ - case 0xe8: \ - out = S ^ ((S ^ P) & (D ^ S)); \ - break; \ - case 0xe9: \ - out = ~(D ^ (S ^ (P & ~(D & S)))); \ - break; \ - case 0xea: \ - out = D | (P & S); \ - break; \ - case 0xeb: \ - out = D | ~(P ^ S); \ - break; \ - case 0xec: \ - out = S | (D & P); \ - break; \ - case 0xed: \ - out = S | ~(D ^ P); \ - break; \ - case 0xee: \ - out = D | S; \ - break; \ - case 0xef: \ - out = S | (D | ~P); \ - break; \ - case 0xf0: \ - out = P; \ - break; \ - case 0xf1: \ - out = P | ~(D | S); \ - break; \ - case 0xf2: \ - out = P | (D & ~S); \ - break; \ - case 0xf3: \ - out = P | ~S; \ - break; \ - case 0xf4: \ - out = P | (S & ~D); \ - break; \ - case 0xf5: \ - out = P | ~D; \ - break; \ - case 0xf6: \ - out = P | (D ^ S); \ - break; \ - case 0xf7: \ - out = P | ~(D & S); \ - break; \ - case 0xf8: \ - out = P | (D & S); \ - break; \ - case 0xf9: \ - out = P | ~(D ^ S); \ - break; \ - case 0xfa: \ - out = D | P; \ - break; \ - case 0xfb: \ - out = D | (P | ~S); \ - break; \ - case 0xfc: \ - out = P | S; \ - break; \ - case 0xfd: \ - out = P | (S | ~D); \ - break; \ - case 0xfe: \ - out = D | (P | S); \ - break; \ - case 0xff: \ - out = ~0; \ - break; \ - } \ +void +chips_69000_do_rop_8bpp(uint8_t *dst, uint8_t src, uint8_t rop) +{ + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x11: + *dst = ~(*dst) & ~src; + break; + case 0x22: + *dst &= ~src; + break; + case 0x33: + *dst = ~src; + break; + case 0x44: + *dst = src & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x66: + *dst ^= src; + break; + case 0x77: + *dst = ~src | ~(*dst); + break; + case 0x88: + *dst &= src; + break; + case 0x99: + *dst ^= ~src; + break; + case 0xAA: + break; /* No-op. */ + case 0xBB: + *dst |= ~src; + break; + case 0xCC: + *dst = src; + break; + case 0xDD: + *dst = src | ~(*dst); + break; + case 0xEE: + *dst |= src; + break; + case 0xFF: + *dst = 0xFF; + break; } +} + +void +chips_69000_do_rop_16bpp(uint16_t *dst, uint16_t src, uint8_t rop) +{ + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x11: + *dst = ~(*dst) & ~src; + break; + case 0x22: + *dst &= ~src; + break; + case 0x33: + *dst = ~src; + break; + case 0x44: + *dst = src & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x66: + *dst ^= src; + break; + case 0x77: + *dst = ~src | ~(*dst); + break; + case 0x88: + *dst &= src; + break; + case 0x99: + *dst ^= ~src; + break; + case 0xAA: + break; /* No-op. */ + case 0xBB: + *dst |= ~src; + break; + case 0xCC: + *dst = src; + break; + case 0xDD: + *dst = src | ~(*dst); + break; + case 0xEE: + *dst |= src; + break; + case 0xFF: + *dst = 0xFFFF; + break; + } +} + +void +chips_69000_do_rop_24bpp(uint32_t *dst, uint32_t src, uint8_t rop) +{ + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x11: + *dst = ~(*dst) & ~src; + break; + case 0x22: + *dst &= ~src; + break; + case 0x33: + *dst = ~src; + break; + case 0x44: + *dst = src & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x66: + *dst ^= src; + break; + case 0x77: + *dst = ~src | ~(*dst); + break; + case 0x88: + *dst &= src; + break; + case 0x99: + *dst ^= ~src; + break; + case 0xAA: + break; /* No-op. */ + case 0xBB: + *dst |= ~src; + break; + case 0xCC: + *dst = src; + break; + case 0xDD: + *dst = src | ~(*dst); + break; + case 0xEE: + *dst |= src; + break; + case 0xFF: + *dst = 0xFFFFFF; + break; + } +} void chips_69000_do_rop_8bpp_patterned(uint8_t *dst, uint8_t pattern, uint8_t src, uint8_t rop) { - ROPMIX(rop, *dst, pattern, src, *dst); + if ((rop & 0xF) == ((rop >> 4) & 0xF)) { + return chips_69000_do_rop_8bpp(dst, src, rop); + } + + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x05: + *dst = ~(*dst) & ~pattern; + break; + case 0x0A: + *dst &= ~pattern; + break; + case 0x0F: + *dst = ~pattern; + break; + case 0x1A: + *dst = pattern ^ (*dst | (pattern & src)); + break; + case 0x2A: + *dst = *dst & (~(src & pattern)); + break; + case 0x3A: + *dst = src ^ (pattern | (*dst ^ src)); + break; + case 0x4A: + *dst = *dst ^ (pattern & (src | *dst)); + break; + case 0x50: + *dst = pattern & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x5A: + *dst ^= pattern; + break; + case 0x5F: + *dst = ~pattern | ~(*dst); + break; + case 0x6A: + *dst = *dst ^ (pattern & src); + break; + case 0x7A: + *dst = *dst ^ (pattern & (src | (~*dst))); + break; + case 0x8A: + *dst = *dst & (src | (~pattern)); + break; + case 0x9A: + *dst = *dst ^ (pattern & (~src)); + break; + case 0xB8: + *dst = (((pattern ^ *dst) & src) ^ pattern); + break; + case 0xA0: + *dst &= pattern; + break; + case 0xA5: + *dst ^= ~pattern; + break; + case 0xAA: + break; /* No-op. */ + case 0xAC: + *dst = src ^ (pattern & (*dst ^ src)); + break; + case 0xAF: + *dst |= ~pattern; + break; + case 0xBA: + *dst |= (pattern & ~src); + break; + case 0xCA: + *dst ^= (pattern & (src ^ *dst)); + break; + case 0xE2: + *dst ^= (src & (pattern ^ *dst)); + break; + case 0xDA: + *dst ^= pattern & (~(src & *dst)); + break; + case 0xEA: + *dst |= pattern & src; + break; + case 0xF0: + *dst = pattern; + break; + case 0xF5: + *dst = pattern | ~(*dst); + break; + case 0xFA: + *dst |= pattern; + break; + case 0xFF: + *dst = 0xFF; + break; + default: + pclog("Unknown ROP 0x%X\n", rop); + break; + } } void chips_69000_do_rop_16bpp_patterned(uint16_t *dst, uint16_t pattern, uint16_t src, uint8_t rop) { - ROPMIX(rop, *dst, pattern, src, *dst); + if ((rop & 0xF) == ((rop >> 4) & 0xF)) { + return chips_69000_do_rop_16bpp(dst, src, rop); + } + + switch (rop) { + default: + pclog("Unknown ROP 0x%X\n", rop); + break; + case 0x00: + *dst = 0; + break; + case 0x05: + *dst = ~(*dst) & ~pattern; + break; + case 0x0A: + *dst &= ~pattern; + break; + case 0x0F: + *dst = ~pattern; + break; + case 0x1A: + *dst = pattern ^ (*dst | (pattern & src)); + break; + case 0x2A: + *dst = *dst & (~(src & pattern)); + break; + case 0x3A: + *dst = src ^ (pattern | (*dst ^ src)); + break; + case 0x4A: + *dst = *dst ^ (pattern & (src | *dst)); + break; + case 0x50: + *dst = pattern & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x5A: + *dst ^= pattern; + break; + case 0x5F: + *dst = ~pattern | ~(*dst); + break; + case 0x6A: + *dst = *dst ^ (pattern & src); + break; + case 0x7A: + *dst = *dst ^ (pattern & (src | (~*dst))); + break; + case 0x8A: + *dst = *dst & (src | (~pattern)); + break; + case 0x9A: + *dst = *dst ^ (pattern & (~src)); + break; + case 0xB8: + *dst = (((pattern ^ *dst) & src) ^ pattern); + break; + case 0xA0: + *dst &= pattern; + break; + case 0xA5: + *dst ^= ~pattern; + break; + case 0xAA: + break; /* No-op. */ + case 0xAC: + *dst = src ^ (pattern & (*dst ^ src)); + break; + case 0xAF: + *dst |= ~pattern; + break; + case 0xBA: + *dst |= (pattern & ~src); + break; + case 0xCA: + *dst ^= (pattern & (src ^ *dst)); + break; + case 0xE2: + *dst ^= (src & (pattern ^ *dst)); + break; + case 0xDA: + *dst ^= pattern & (~(src & *dst)); + break; + case 0xEA: + *dst |= pattern & src; + break; + case 0xF0: + *dst = pattern; + break; + case 0xF5: + *dst = pattern | ~(*dst); + break; + case 0xFA: + *dst |= pattern; + break; + case 0xFF: + *dst = 0xFF; + break; + } } void chips_69000_do_rop_24bpp_patterned(uint32_t *dst, uint32_t pattern, uint32_t src, uint8_t rop) { uint32_t orig_dst = *dst & 0xFF000000; - ROPMIX(rop, *dst, pattern, src, *dst); + + if ((rop & 0xF) == ((rop >> 4) & 0xF)) { + return chips_69000_do_rop_24bpp(dst, src, rop); + } + + switch (rop) { + default: + pclog("Unknown ROP 0x%X\n", rop); + break; + case 0x00: + *dst = 0; + break; + case 0x05: + *dst = ~(*dst) & ~pattern; + break; + case 0x0A: + *dst &= ~pattern; + break; + case 0x0F: + *dst = ~pattern; + break; + case 0x1A: + *dst = pattern ^ (*dst | (pattern & src)); + break; + case 0x2A: + *dst = *dst & (~(src & pattern)); + break; + case 0x3A: + *dst = src ^ (pattern | (*dst ^ src)); + break; + case 0x4A: + *dst = *dst ^ (pattern & (src | *dst)); + break; + case 0x50: + *dst = pattern & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x5A: + *dst ^= pattern; + break; + case 0x5F: + *dst = ~pattern | ~(*dst); + break; + case 0x6A: + *dst = *dst ^ (pattern & src); + break; + case 0x7A: + *dst = *dst ^ (pattern & (src | (~*dst))); + break; + case 0x8A: + *dst = *dst & (src | (~pattern)); + break; + case 0x9A: + *dst = *dst ^ (pattern & (~src)); + break; + case 0xB8: + *dst = (((pattern ^ *dst) & src) ^ pattern); + break; + case 0xA0: + *dst &= pattern; + break; + case 0xA5: + *dst ^= ~pattern; + break; + case 0xAA: + break; /* No-op. */ + case 0xAC: + *dst = src ^ (pattern & (*dst ^ src)); + break; + case 0xAF: + *dst |= ~pattern; + break; + case 0xBA: + *dst |= (pattern & ~src); + break; + case 0xCA: + *dst ^= (pattern & (src ^ *dst)); + break; + case 0xDA: + *dst ^= pattern & (~(src & *dst)); + break; + case 0xE2: + *dst ^= (src & (pattern ^ *dst)); + break; + case 0xEA: + *dst |= pattern & src; + break; + case 0xF0: + *dst = pattern; + break; + case 0xF5: + *dst = pattern | ~(*dst); + break; + case 0xFA: + *dst |= pattern; + break; + case 0xFF: + *dst = 0xFF; + break; + } *dst &= 0xFFFFFF; *dst |= orig_dst; } @@ -1207,22 +896,20 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - //dest_pixel = chips_69000_readb_linear(dest_addr, chips); - dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel = chips_69000_readb_linear(dest_addr, chips); break; } case 2: /* 16 bits-per-pixel. */ { - //dest_pixel = *(uint16_t*)&chips->svga.vram[dest_addr & chips->svga.vram_mask]; - dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; - dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; + dest_pixel = chips_69000_readb_linear(dest_addr, chips); + dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; break; } case 3: /* 24 bits-per-pixel. */ { - dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; - dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; - dest_pixel |= chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] << 16; + dest_pixel = chips_69000_readb_linear(dest_addr, chips); + dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; + dest_pixel |= chips_69000_readb_linear(dest_addr + 2, chips) << 16; break; } } @@ -1235,7 +922,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) if (chips->bitblt_running.bitblt.bitblt_control & (1 << 19)) pattern_data = 0; else - pattern_data = chips->svga.vram[(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7)) & chips->svga.vram_mask]; //chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); + pattern_data = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); is_true = !!(pattern_data & (1 << (7 - ((chips->bitblt_running.bitblt.destination_addr + chips->bitblt_running.x) & 7)))); @@ -1251,30 +938,32 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) pattern_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; } else { - uint32_t pattern_pixel_addr = 0; if (chips->bitblt_running.bytes_per_pixel == 1) { - pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr - + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) - + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7); - - pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; + pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) + + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7), chips); } if (chips->bitblt_running.bytes_per_pixel == 2) { - pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr - + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); + pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); - pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; - pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; + pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; } if (chips->bitblt_running.bytes_per_pixel == 3) { - pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); + pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); - pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; - pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; - pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 2) & chips->svga.vram_mask] << 16; + pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; + + pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 2, chips) << 16; } } if (chips->bitblt_running.bytes_per_pixel == 2) { @@ -1292,7 +981,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) : chips->bitblt_running.bitblt.pattern_source_key_bg; color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1330,7 +1019,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; dest_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1342,21 +1031,20 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; - //chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); break; } case 2: /* 16 bits-per-pixel. */ { - chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; - chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; + chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); break; } case 3: /* 24 bits-per-pixel. */ { - chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; - chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; - chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] = (dest_pixel >> 16) & 0xFF; + chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); + chips_69000_writeb_linear(dest_addr + 2, (dest_pixel >> 16) & 0xFF, chips); break; } } @@ -1524,8 +1212,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) uint32_t orig_source_addr = chips->bitblt_running.bitblt.source_addr; while (orig_count_y == chips->bitblt_running.count_y) { int i = 0; - //uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); - uint8_t data = chips->svga.vram[orig_source_addr & chips->svga.vram_mask]; + uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); orig_source_addr++; for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(data & (1 << (7 - i)))); @@ -1544,15 +1231,14 @@ chips_69000_setup_bitblt(chips_69000_t* chips) case 1: /* Bit-aligned */ case 2: /* Byte-aligned */ { - //uint32_t data = chips_69000_readb_linear(source_addr, chips); - uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask]; + uint32_t data = chips_69000_readb_linear(source_addr, chips); chips_69000_bitblt_write(chips, data & 0xFF); source_addr += 1; break; } case 3: /* Word-aligned*/ { - uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8); + uint32_t data = chips_69000_readw_linear(source_addr, chips); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); source_addr += 2; @@ -1560,8 +1246,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 4: /* Doubleword-aligned*/ { - uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) - | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24); + uint32_t data = chips_69000_readl_linear(source_addr, chips); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1571,15 +1256,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 5: /* Quadword-aligned*/ { - uint64_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] - | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) - | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) - | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24) - | ((uint64_t)chips->svga.vram[(source_addr + 4) & chips->svga.vram_mask] << 32ULL) - | ((uint64_t)chips->svga.vram[(source_addr + 5) & chips->svga.vram_mask] << 40ULL) - | ((uint64_t)chips->svga.vram[(source_addr + 6) & chips->svga.vram_mask] << 48ULL) - | ((uint64_t)chips->svga.vram[(source_addr + 7) & chips->svga.vram_mask] << 56ULL); - //uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); + uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1604,21 +1281,20 @@ chips_69000_setup_bitblt(chips_69000_t* chips) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - //pixel = chips_69000_readb_linear(source_addr, chips); - pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; + pixel = chips_69000_readb_linear(source_addr, chips); break; } case 2: /* 16 bits-per-pixel. */ { - pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; - pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; + pixel = chips_69000_readb_linear(source_addr, chips); + pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; break; } case 3: /* 24 bits-per-pixel. */ { - pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; - pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; - pixel |= chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16; + pixel = chips_69000_readb_linear(source_addr, chips); + pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; + pixel |= chips_69000_readb_linear(source_addr + 2, chips) << 16; break; } } From 9182deaa2bf59c8d71b55a9a95ad551f557d9dc5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 23:04:23 +0600 Subject: [PATCH 128/218] C&T B69000: Revert optimizations that made GUI acceleration slow --- src/video/vid_chips_69000.c | 1245 ++++++++++++++++++++++------------- 1 file changed, 779 insertions(+), 466 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 0347435fa..d06ab0484 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -252,378 +252,790 @@ chips_69000_bitblt_interrupt(chips_69000_t* chips) chips_69000_interrupt(chips); } -void -chips_69000_do_rop_8bpp(uint8_t *dst, uint8_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFF; - break; +#define ROPMIX(R, D, P, S, out) \ + { \ + switch (R) { \ + case 0x00: \ + out = 0; \ + break; \ + case 0x01: \ + out = ~(D | (P | S)); \ + break; \ + case 0x02: \ + out = D & ~(P | S); \ + break; \ + case 0x03: \ + out = ~(P | S); \ + break; \ + case 0x04: \ + out = S & ~(D | P); \ + break; \ + case 0x05: \ + out = ~(D | P); \ + break; \ + case 0x06: \ + out = ~(P | ~(D ^ S)); \ + break; \ + case 0x07: \ + out = ~(P | (D & S)); \ + break; \ + case 0x08: \ + out = S & (D & ~P); \ + break; \ + case 0x09: \ + out = ~(P | (D ^ S)); \ + break; \ + case 0x0a: \ + out = D & ~P; \ + break; \ + case 0x0b: \ + out = ~(P | (S & ~D)); \ + break; \ + case 0x0c: \ + out = S & ~P; \ + break; \ + case 0x0d: \ + out = ~(P | (D & ~S)); \ + break; \ + case 0x0e: \ + out = ~(P | ~(D | S)); \ + break; \ + case 0x0f: \ + out = ~P; \ + break; \ + case 0x10: \ + out = P & ~(D | S); \ + break; \ + case 0x11: \ + out = ~(D | S); \ + break; \ + case 0x12: \ + out = ~(S | ~(D ^ P)); \ + break; \ + case 0x13: \ + out = ~(S | (D & P)); \ + break; \ + case 0x14: \ + out = ~(D | ~(P ^ S)); \ + break; \ + case 0x15: \ + out = ~(D | (P & S)); \ + break; \ + case 0x16: \ + out = P ^ (S ^ (D & ~(P & S))); \ + break; \ + case 0x17: \ + out = ~(S ^ ((S ^ P) & (D ^ S))); \ + break; \ + case 0x18: \ + out = (S ^ P) & (P ^ D); \ + break; \ + case 0x19: \ + out = ~(S ^ (D & ~(P & S))); \ + break; \ + case 0x1a: \ + out = P ^ (D | (S & P)); \ + break; \ + case 0x1b: \ + out = ~(S ^ (D & (P ^ S))); \ + break; \ + case 0x1c: \ + out = P ^ (S | (D & P)); \ + break; \ + case 0x1d: \ + out = ~(D ^ (S & (P ^ D))); \ + break; \ + case 0x1e: \ + out = P ^ (D | S); \ + break; \ + case 0x1f: \ + out = ~(P & (D | S)); \ + break; \ + case 0x20: \ + out = D & (P & ~S); \ + break; \ + case 0x21: \ + out = ~(S | (D ^ P)); \ + break; \ + case 0x22: \ + out = D & ~S; \ + break; \ + case 0x23: \ + out = ~(S | (P & ~D)); \ + break; \ + case 0x24: \ + out = (S ^ P) & (D ^ S); \ + break; \ + case 0x25: \ + out = ~(P ^ (D & ~(S & P))); \ + break; \ + case 0x26: \ + out = S ^ (D | (P & S)); \ + break; \ + case 0x27: \ + out = S ^ (D | ~(P ^ S)); \ + break; \ + case 0x28: \ + out = D & (P ^ S); \ + break; \ + case 0x29: \ + out = ~(P ^ (S ^ (D | (P & S)))); \ + break; \ + case 0x2a: \ + out = D & ~(P & S); \ + break; \ + case 0x2b: \ + out = ~(S ^ ((S ^ P) & (P ^ D))); \ + break; \ + case 0x2c: \ + out = S ^ (P & (D | S)); \ + break; \ + case 0x2d: \ + out = P ^ (S | ~D); \ + break; \ + case 0x2e: \ + out = P ^ (S | (D ^ P)); \ + break; \ + case 0x2f: \ + out = ~(P & (S | ~D)); \ + break; \ + case 0x30: \ + out = P & ~S; \ + break; \ + case 0x31: \ + out = ~(S | (D & ~P)); \ + break; \ + case 0x32: \ + out = S ^ (D | (P | S)); \ + break; \ + case 0x33: \ + out = ~S; \ + break; \ + case 0x34: \ + out = S ^ (P | (D & S)); \ + break; \ + case 0x35: \ + out = S ^ (P | ~(D ^ S)); \ + break; \ + case 0x36: \ + out = S ^ (D | P); \ + break; \ + case 0x37: \ + out = ~(S & (D | P)); \ + break; \ + case 0x38: \ + out = P ^ (S & (D | P)); \ + break; \ + case 0x39: \ + out = S ^ (P | ~D); \ + break; \ + case 0x3a: \ + out = S ^ (P | (D ^ S)); \ + break; \ + case 0x3b: \ + out = ~(S & (P | ~D)); \ + break; \ + case 0x3c: \ + out = P ^ S; \ + break; \ + case 0x3d: \ + out = S ^ (P | ~(D | S)); \ + break; \ + case 0x3e: \ + out = S ^ (P | (D & ~S)); \ + break; \ + case 0x3f: \ + out = ~(P & S); \ + break; \ + case 0x40: \ + out = P & (S & ~D); \ + break; \ + case 0x41: \ + out = ~(D | (P ^ S)); \ + break; \ + case 0x42: \ + out = (S ^ D) & (P ^ D); \ + break; \ + case 0x43: \ + out = ~(S ^ (P & ~(D & S))); \ + break; \ + case 0x44: \ + out = S & ~D; \ + break; \ + case 0x45: \ + out = ~(D | (P & ~S)); \ + break; \ + case 0x46: \ + out = D ^ (S | (P & D)); \ + break; \ + case 0x47: \ + out = ~(P ^ (S & (D ^ P))); \ + break; \ + case 0x48: \ + out = S & (D ^ P); \ + break; \ + case 0x49: \ + out = ~(P ^ (D ^ (S | (P & D)))); \ + break; \ + case 0x4a: \ + out = D ^ (P & (S | D)); \ + break; \ + case 0x4b: \ + out = P ^ (D | ~S); \ + break; \ + case 0x4c: \ + out = S & ~(D & P); \ + break; \ + case 0x4d: \ + out = ~(S ^ ((S ^ P) | (D ^ S))); \ + break; \ + case 0x4e: \ + out = P ^ (D | (S ^ P)); \ + break; \ + case 0x4f: \ + out = ~(P & (D | ~S)); \ + break; \ + case 0x50: \ + out = P & ~D; \ + break; \ + case 0x51: \ + out = ~(D | (S & ~P)); \ + break; \ + case 0x52: \ + out = D ^ (P | (S & D)); \ + break; \ + case 0x53: \ + out = ~(S ^ (P & (D ^ S))); \ + break; \ + case 0x54: \ + out = ~(D | ~(P | S)); \ + break; \ + case 0x55: \ + out = ~D; \ + break; \ + case 0x56: \ + out = D ^ (P | S); \ + break; \ + case 0x57: \ + out = ~(D & (P | S)); \ + break; \ + case 0x58: \ + out = P ^ (D & (S | P)); \ + break; \ + case 0x59: \ + out = D ^ (P | ~S); \ + break; \ + case 0x5a: \ + out = D ^ P; \ + break; \ + case 0x5b: \ + out = D ^ (P | ~(S | D)); \ + break; \ + case 0x5c: \ + out = D ^ (P | (S ^ D)); \ + break; \ + case 0x5d: \ + out = ~(D & (P | ~S)); \ + break; \ + case 0x5e: \ + out = D ^ (P | (S & ~D)); \ + break; \ + case 0x5f: \ + out = ~(D & P); \ + break; \ + case 0x60: \ + out = P & (D ^ S); \ + break; \ + case 0x61: \ + out = ~(D ^ (S ^ (P | (D & S)))); \ + break; \ + case 0x62: \ + out = D ^ (S & (P | D)); \ + break; \ + case 0x63: \ + out = S ^ (D | ~P); \ + break; \ + case 0x64: \ + out = S ^ (D & (P | S)); \ + break; \ + case 0x65: \ + out = D ^ (S | ~P); \ + break; \ + case 0x66: \ + out = D ^ S; \ + break; \ + case 0x67: \ + out = S ^ (D | ~(P | S)); \ + break; \ + case 0x68: \ + out = ~(D ^ (S ^ (P | ~(D | S)))); \ + break; \ + case 0x69: \ + out = ~(P ^ (D ^ S)); \ + break; \ + case 0x6a: \ + out = D ^ (P & S); \ + break; \ + case 0x6b: \ + out = ~(P ^ (S ^ (D & (P | S)))); \ + break; \ + case 0x6c: \ + out = S ^ (D & P); \ + break; \ + case 0x6d: \ + out = ~(P ^ (D ^ (S & (P | D)))); \ + break; \ + case 0x6e: \ + out = S ^ (D & (P | ~S)); \ + break; \ + case 0x6f: \ + out = ~(P & ~(D ^ S)); \ + break; \ + case 0x70: \ + out = P & ~(D & S); \ + break; \ + case 0x71: \ + out = ~(S ^ ((S ^ D) & (P ^ D))); \ + break; \ + case 0x72: \ + out = S ^ (D | (P ^ S)); \ + break; \ + case 0x73: \ + out = ~(S & (D | ~P)); \ + break; \ + case 0x74: \ + out = D ^ (S | (P ^ D)); \ + break; \ + case 0x75: \ + out = ~(D & (S | ~P)); \ + break; \ + case 0x76: \ + out = S ^ (D | (P & ~S)); \ + break; \ + case 0x77: \ + out = ~(D & S); \ + break; \ + case 0x78: \ + out = P ^ (D & S); \ + break; \ + case 0x79: \ + out = ~(D ^ (S ^ (P & (D | S)))); \ + break; \ + case 0x7a: \ + out = D ^ (P & (S | ~D)); \ + break; \ + case 0x7b: \ + out = ~(S & ~(D ^ P)); \ + break; \ + case 0x7c: \ + out = S ^ (P & (D | ~S)); \ + break; \ + case 0x7d: \ + out = ~(D & ~(P ^ S)); \ + break; \ + case 0x7e: \ + out = (S ^ P) | (D ^ S); \ + break; \ + case 0x7f: \ + out = ~(D & (P & S)); \ + break; \ + case 0x80: \ + out = D & (P & S); \ + break; \ + case 0x81: \ + out = ~((S ^ P) | (D ^ S)); \ + break; \ + case 0x82: \ + out = D & ~(P ^ S); \ + break; \ + case 0x83: \ + out = ~(S ^ (P & (D | ~S))); \ + break; \ + case 0x84: \ + out = S & ~(D ^ P); \ + break; \ + case 0x85: \ + out = ~(P ^ (D & (S | ~P))); \ + break; \ + case 0x86: \ + out = D ^ (S ^ (P & (D | S))); \ + break; \ + case 0x87: \ + out = ~(P ^ (D & S)); \ + break; \ + case 0x88: \ + out = D & S; \ + break; \ + case 0x89: \ + out = ~(S ^ (D | (P & ~S))); \ + break; \ + case 0x8a: \ + out = D & (S | ~P); \ + break; \ + case 0x8b: \ + out = ~(D ^ (S | (P ^ D))); \ + break; \ + case 0x8c: \ + out = S & (D | ~P); \ + break; \ + case 0x8d: \ + out = ~(S ^ (D | (P ^ S))); \ + break; \ + case 0x8e: \ + out = S ^ ((S ^ D) & (P ^ D)); \ + break; \ + case 0x8f: \ + out = ~(P & ~(D & S)); \ + break; \ + case 0x90: \ + out = P & ~(D ^ S); \ + break; \ + case 0x91: \ + out = ~(S ^ (D & (P | ~S))); \ + break; \ + case 0x92: \ + out = D ^ (P ^ (S & (D | P))); \ + break; \ + case 0x93: \ + out = ~(S ^ (P & D)); \ + break; \ + case 0x94: \ + out = P ^ (S ^ (D & (P | S))); \ + break; \ + case 0x95: \ + out = ~(D ^ (P & S)); \ + break; \ + case 0x96: \ + out = D ^ (P ^ S); \ + break; \ + case 0x97: \ + out = P ^ (S ^ (D | ~(P | S))); \ + break; \ + case 0x98: \ + out = ~(S ^ (D | ~(P | S))); \ + break; \ + case 0x99: \ + out = ~(D ^ S); \ + break; \ + case 0x9a: \ + out = D ^ (P & ~S); \ + break; \ + case 0x9b: \ + out = ~(S ^ (D & (P | S))); \ + break; \ + case 0x9c: \ + out = S ^ (P & ~D); \ + break; \ + case 0x9d: \ + out = ~(D ^ (S & (P | D))); \ + break; \ + case 0x9e: \ + out = D ^ (S ^ (P | (D & S))); \ + break; \ + case 0x9f: \ + out = ~(P & (D ^ S)); \ + break; \ + case 0xa0: \ + out = D & P; \ + break; \ + case 0xa1: \ + out = ~(P ^ (D | (S & ~P))); \ + break; \ + case 0xa2: \ + out = D & (P | ~S); \ + break; \ + case 0xa3: \ + out = ~(D ^ (P | (S ^ D))); \ + break; \ + case 0xa4: \ + out = ~(P ^ (D | ~(S | P))); \ + break; \ + case 0xa5: \ + out = ~(P ^ D); \ + break; \ + case 0xa6: \ + out = D ^ (S & ~P); \ + break; \ + case 0xa7: \ + out = ~(P ^ (D & (S | P))); \ + break; \ + case 0xa8: \ + out = D & (P | S); \ + break; \ + case 0xa9: \ + out = ~(D ^ (P | S)); \ + break; \ + case 0xaa: \ + out = D; \ + break; \ + case 0xab: \ + out = D | ~(P | S); \ + break; \ + case 0xac: \ + out = S ^ (P & (D ^ S)); \ + break; \ + case 0xad: \ + out = ~(D ^ (P | (S & D))); \ + break; \ + case 0xae: \ + out = D | (S & ~P); \ + break; \ + case 0xaf: \ + out = D | ~P; \ + break; \ + case 0xb0: \ + out = P & (D | ~S); \ + break; \ + case 0xb1: \ + out = ~(P ^ (D | (S ^ P))); \ + break; \ + case 0xb2: \ + out = S ^ ((S ^ P) | (D ^ S)); \ + break; \ + case 0xb3: \ + out = ~(S & ~(D & P)); \ + break; \ + case 0xb4: \ + out = P ^ (S & ~D); \ + break; \ + case 0xb5: \ + out = ~(D ^ (P & (S | D))); \ + break; \ + case 0xb6: \ + out = D ^ (P ^ (S | (D & P))); \ + break; \ + case 0xb7: \ + out = ~(S & (D ^ P)); \ + break; \ + case 0xb8: \ + out = P ^ (S & (D ^ P)); \ + break; \ + case 0xb9: \ + out = ~(D ^ (S | (P & D))); \ + break; \ + case 0xba: \ + out = D | (P & ~S); \ + break; \ + case 0xbb: \ + out = D | ~S; \ + break; \ + case 0xbc: \ + out = S ^ (P & ~(D & S)); \ + break; \ + case 0xbd: \ + out = ~((S ^ D) & (P ^ D)); \ + break; \ + case 0xbe: \ + out = D | (P ^ S); \ + break; \ + case 0xbf: \ + out = D | ~(P & S); \ + break; \ + case 0xc0: \ + out = P & S; \ + break; \ + case 0xc1: \ + out = ~(S ^ (P | (D & ~S))); \ + break; \ + case 0xc2: \ + out = ~(S ^ (P | ~(D | S))); \ + break; \ + case 0xc3: \ + out = ~(P ^ S); \ + break; \ + case 0xc4: \ + out = S & (P | ~D); \ + break; \ + case 0xc5: \ + out = ~(S ^ (P | (D ^ S))); \ + break; \ + case 0xc6: \ + out = S ^ (D & ~P); \ + break; \ + case 0xc7: \ + out = ~(P ^ (S & (D | P))); \ + break; \ + case 0xc8: \ + out = S & (D | P); \ + break; \ + case 0xc9: \ + out = ~(S ^ (P | D)); \ + break; \ + case 0xca: \ + out = D ^ (P & (S ^ D)); \ + break; \ + case 0xcb: \ + out = ~(S ^ (P | (D & S))); \ + break; \ + case 0xcc: \ + out = S; \ + break; \ + case 0xcd: \ + out = S | ~(D | P); \ + break; \ + case 0xce: \ + out = S | (D & ~P); \ + break; \ + case 0xcf: \ + out = S | ~P; \ + break; \ + case 0xd0: \ + out = P & (S | ~D); \ + break; \ + case 0xd1: \ + out = ~(P ^ (S | (D ^ P))); \ + break; \ + case 0xd2: \ + out = P ^ (D & ~S); \ + break; \ + case 0xd3: \ + out = ~(S ^ (P & (D | S))); \ + break; \ + case 0xd4: \ + out = S ^ ((S ^ P) & (P ^ D)); \ + break; \ + case 0xd5: \ + out = ~(D & ~(P & S)); \ + break; \ + case 0xd6: \ + out = P ^ (S ^ (D | (P & S))); \ + break; \ + case 0xd7: \ + out = ~(D & (P ^ S)); \ + break; \ + case 0xd8: \ + out = P ^ (D & (S ^ P)); \ + break; \ + case 0xd9: \ + out = ~(S ^ (D | (P & S))); \ + break; \ + case 0xda: \ + out = D ^ (P & ~(S & D)); \ + break; \ + case 0xdb: \ + out = ~((S ^ P) & (D ^ S)); \ + break; \ + case 0xdc: \ + out = S | (P & ~D); \ + break; \ + case 0xdd: \ + out = S | ~D; \ + break; \ + case 0xde: \ + out = S | (D ^ P); \ + break; \ + case 0xdf: \ + out = S | ~(D & P); \ + break; \ + case 0xe0: \ + out = P & (D | S); \ + break; \ + case 0xe1: \ + out = ~(P ^ (D | S)); \ + break; \ + case 0xe2: \ + out = D ^ (S & (P ^ D)); \ + break; \ + case 0xe3: \ + out = ~(P ^ (S | (D & P))); \ + break; \ + case 0xe4: \ + out = S ^ (D & (P ^ S)); \ + break; \ + case 0xe5: \ + out = ~(P ^ (D | (S & P))); \ + break; \ + case 0xe6: \ + out = S ^ (D & ~(P & S)); \ + break; \ + case 0xe7: \ + out = ~((S ^ P) & (P ^ D)); \ + break; \ + case 0xe8: \ + out = S ^ ((S ^ P) & (D ^ S)); \ + break; \ + case 0xe9: \ + out = ~(D ^ (S ^ (P & ~(D & S)))); \ + break; \ + case 0xea: \ + out = D | (P & S); \ + break; \ + case 0xeb: \ + out = D | ~(P ^ S); \ + break; \ + case 0xec: \ + out = S | (D & P); \ + break; \ + case 0xed: \ + out = S | ~(D ^ P); \ + break; \ + case 0xee: \ + out = D | S; \ + break; \ + case 0xef: \ + out = S | (D | ~P); \ + break; \ + case 0xf0: \ + out = P; \ + break; \ + case 0xf1: \ + out = P | ~(D | S); \ + break; \ + case 0xf2: \ + out = P | (D & ~S); \ + break; \ + case 0xf3: \ + out = P | ~S; \ + break; \ + case 0xf4: \ + out = P | (S & ~D); \ + break; \ + case 0xf5: \ + out = P | ~D; \ + break; \ + case 0xf6: \ + out = P | (D ^ S); \ + break; \ + case 0xf7: \ + out = P | ~(D & S); \ + break; \ + case 0xf8: \ + out = P | (D & S); \ + break; \ + case 0xf9: \ + out = P | ~(D ^ S); \ + break; \ + case 0xfa: \ + out = D | P; \ + break; \ + case 0xfb: \ + out = D | (P | ~S); \ + break; \ + case 0xfc: \ + out = P | S; \ + break; \ + case 0xfd: \ + out = P | (S | ~D); \ + break; \ + case 0xfe: \ + out = D | (P | S); \ + break; \ + case 0xff: \ + out = ~0; \ + break; \ + } \ } -} - -void -chips_69000_do_rop_16bpp(uint16_t *dst, uint16_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFF; - break; - } -} - -void -chips_69000_do_rop_24bpp(uint32_t *dst, uint32_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFFFF; - break; - } -} void chips_69000_do_rop_8bpp_patterned(uint8_t *dst, uint8_t pattern, uint8_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_8bpp(dst, src, rop); - } - - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void chips_69000_do_rop_16bpp_patterned(uint16_t *dst, uint16_t pattern, uint16_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_16bpp(dst, src, rop); - } - - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void @@ -631,107 +1043,8 @@ chips_69000_do_rop_24bpp_patterned(uint32_t *dst, uint32_t pattern, uint32_t src { uint32_t orig_dst = *dst & 0xFF000000; - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_24bpp(dst, src, rop); - } + ROPMIX(rop, *dst, pattern, src, *dst); - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } *dst &= 0xFFFFFF; *dst |= orig_dst; } @@ -981,7 +1294,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) : chips->bitblt_running.bitblt.pattern_source_key_bg; color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1019,7 +1332,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; dest_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -2422,7 +2735,7 @@ chips_69000_getclock(int clock, void *priv) int pl = ((chips->ext_regs[0xcb] >> 4) & 7); float fvco = 14318181.0 * ((float)(m + 2) / (float)(n + 2)); - if (chips->ext_regs[0xcb] & 4) + if (!(chips->ext_regs[0xcb] & 4)) fvco *= 4.0; float fo = fvco / (float)(1 << pl); @@ -2522,7 +2835,7 @@ chips_69000_init(const device_t *info) chips->svga.bpp = 8; chips->svga.miscout = 1; - chips->svga.vblank_start = chips_69000_vblank_start; + chips->svga.vsync_callback = chips_69000_vblank_start; chips->svga.getclock = chips_69000_getclock; chips->svga.conv_16to32 = chips_69000_conv_16to32; chips->svga.line_compare = chips_69000_line_compare; From 556c74c1599e2c279a29cade4d7ef233dd48e0aa Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 20:58:15 +0100 Subject: [PATCH 129/218] IDE DMA: Properly handle partial transfers, fixes ATAPI DMA in Windows 98 SE. --- src/disk/hdc_ide.c | 17 ++++++++++------- src/disk/hdc_ide_cmd646.c | 8 ++++---- src/disk/hdc_ide_sff8038i.c | 16 +++++++++++----- src/include/86box/hdc_ide.h | 2 +- src/include/86box/hdc_ide_sff8038i.h | 2 +- src/scsi/scsi_cdrom.c | 4 +++- 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index bf0d4d286..01690cd70 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -117,7 +117,7 @@ #define ROM_PATH_MCIDE "roms/hdd/xtide/ide_ps2 R1.1.bin" typedef struct ide_bm_t { - int (*dma)(uint8_t *data, int transfer_length, int out, void *priv); + int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv); void (*set_irq)(uint8_t status, void *priv); void *priv; } ide_bm_t; @@ -1094,7 +1094,7 @@ ide_atapi_callback(ide_t *ide) if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) { - ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, bm->priv); + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, 0, bm->priv); /* Underrun. */ if (ret == 1) @@ -1102,6 +1102,7 @@ ide_atapi_callback(ide_t *ide) } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos - ide->sc->block_len, ide->sc->block_len, + ide->sc->sector_len * ide->sc->block_len, 0, bm->priv); if (ret == 1) { @@ -1144,14 +1145,16 @@ ide_atapi_callback(ide_t *ide) if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) { - ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 1, bm->priv); + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, 1, bm->priv); /* Underrun. */ if (ret == 1) ret = 3; } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos, - ide->sc->block_len, 1, bm->priv); + ide->sc->block_len, + ide->sc->sector_len * ide->sc->block_len, + 1, bm->priv); if (ret & 1) { if (ide->write != NULL) @@ -2392,7 +2395,7 @@ ide_callback(void *priv) err = UNC_ERR; } else if (!ide_boards[ide->board]->force_ata3 && bm->dma) { /* We should not abort - we should simply wait for the host to start DMA. */ - ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, bm->priv); + ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, 0, bm->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; @@ -2500,7 +2503,7 @@ ide_callback(void *priv) else ide->sector_pos = 256; - ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 1, bm->priv); + ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, 1, bm->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ @@ -3127,7 +3130,7 @@ ide_xtide_close(void) void ide_set_bus_master(int board, - int (*dma)(uint8_t *data, int transfer_length, int out, void *priv), + int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv), void (*set_irq)(uint8_t status, void *priv), void *priv) { ide_bm_t *bm; diff --git a/src/disk/hdc_ide_cmd646.c b/src/disk/hdc_ide_cmd646.c index b548390fd..a60962ba8 100644 --- a/src/disk/hdc_ide_cmd646.c +++ b/src/disk/hdc_ide_cmd646.c @@ -95,19 +95,19 @@ cmd646_set_irq_1(uint8_t status, void *priv) } static int -cmd646_bus_master_dma_0(uint8_t *data, int transfer_length, int out, void *priv) +cmd646_bus_master_dma_0(uint8_t *data, int transfer_length, int total_length, int out, void *priv) { const cmd646_t *dev = (cmd646_t *) priv; - return sff_bus_master_dma(data, transfer_length, out, dev->bm[0]); + return sff_bus_master_dma(data, transfer_length, total_length, out, dev->bm[0]); } static int -cmd646_bus_master_dma_1(uint8_t *data, int transfer_length, int out, void *priv) +cmd646_bus_master_dma_1(uint8_t *data, int transfer_length, int total_length, int out, void *priv) { const cmd646_t *dev = (cmd646_t *) priv; - return sff_bus_master_dma(data, transfer_length, out, dev->bm[1]); + return sff_bus_master_dma(data, transfer_length, total_length, out, dev->bm[1]); } static void diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 2cc1fe72e..7ded4372f 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -316,14 +316,14 @@ sff_bus_master_readl(uint16_t port, void *priv) } int -sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv) +sff_bus_master_dma(uint8_t *data, int transfer_length, int total_length, int out, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; #ifdef ENABLE_SFF_LOG char *sop; #endif - int force_end = 0; + int force_end = 0; int buffer_pos = 0; #ifdef ENABLE_SFF_LOG @@ -365,9 +365,15 @@ sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv) return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ } else { if (!transfer_length && !dev->eot) { - sff_log("Total transfer length smaller than sum of all blocks, full block\n"); - dev->status &= ~2; - return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + if (total_length) { + sff_log("Total transfer length smaller than sum of all blocks, partial transfer\n"); + sff_bus_master_next_addr(dev); + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else { + sff_log("Total transfer length smaller than sum of all blocks, full block\n"); + dev->status &= ~2; + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } } else if (transfer_length && dev->eot) { sff_log("Total transfer length greater than sum of all blocks\n"); dev->status |= 2; diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 4e4ea4e5b..41fb7703e 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -201,7 +201,7 @@ extern uint8_t ide_read_alt_status(uint16_t addr, void *priv); extern uint16_t ide_readw(uint16_t addr, void *priv); extern void ide_set_bus_master(int board, - int (*dma)(uint8_t *data, int transfer_length, int out, void *priv), + int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv), void (*set_irq)(uint8_t status, void *priv), void *priv); extern void win_cdrom_eject(uint8_t id); diff --git a/src/include/86box/hdc_ide_sff8038i.h b/src/include/86box/hdc_ide_sff8038i.h index 3a69fdfac..79075b8b2 100644 --- a/src/include/86box/hdc_ide_sff8038i.h +++ b/src/include/86box/hdc_ide_sff8038i.h @@ -63,7 +63,7 @@ extern const device_t sff8038i_device; extern void sff_bus_master_handler(sff8038i_t *dev, int enabled, uint16_t base); extern void sff_bus_master_set_irq(uint8_t status, void *priv); -extern int sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv); +extern int sff_bus_master_dma(uint8_t *data, int transfer_length, int total_length, int out, void *priv); extern void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); extern uint8_t sff_bus_master_read(uint16_t port, void *priv); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 292c54127..a8bb1513b 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -1096,6 +1096,8 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) int msf = 0; int type = dev->sector_type; int flags = dev->sector_flags; + int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + dev->requested_blocks : 1; switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: @@ -1128,7 +1130,7 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) } scsi_cdrom_log(dev->log, "Reading %i blocks starting from %i...\n", - dev->requested_blocks, dev->sector_pos); + num, dev->sector_pos); ret = scsi_cdrom_read_data(dev, msf, type, flags, dev->vendor_type); From 48c294a13bdd59abadd7f3271e49601c5a2ce39a Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 20:59:18 +0100 Subject: [PATCH 130/218] SCSI CD-ROM: Fix a warning. --- src/scsi/scsi_cdrom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index a8bb1513b..b35662eeb 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -1096,8 +1096,10 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) int msf = 0; int type = dev->sector_type; int flags = dev->sector_flags; +#ifdef ENABLE_SCSI_CDROM_LOG int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? dev->requested_blocks : 1; +#endif switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: From be2a435e0510e939056a4334dfe5293d336f3cae Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 00:43:49 +0100 Subject: [PATCH 131/218] MO and ZIP: Fix reading, writing, and formatting, also fix > 2 GB MO images. --- src/disk/mo.c | 34 +++++++++++++++++++--------------- src/disk/zip.c | 17 +++++++++-------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index 7808e524e..b470b7761 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -63,7 +63,7 @@ const uint8_t mo_command_flags[0x100] = { [0x0a] = IMPLEMENTED | CHECK_READY, [0x0b] = IMPLEMENTED | CHECK_READY, [0x12] = IMPLEMENTED | ALLOW_UA, - [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x13] = IMPLEMENTED | CHECK_READY, [0x15] = IMPLEMENTED, [0x16] = IMPLEMENTED | SCSI_ONLY, [0x17] = IMPLEMENTED | SCSI_ONLY, @@ -74,8 +74,7 @@ const uint8_t mo_command_flags[0x100] = { [0x25] = IMPLEMENTED | CHECK_READY, [0x28] = IMPLEMENTED | CHECK_READY, [0x2a ... 0x2c] = IMPLEMENTED | CHECK_READY, - [0x2e] = IMPLEMENTED | CHECK_READY, - [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x2e ... 0x2f] = IMPLEMENTED | CHECK_READY, [0x41] = IMPLEMENTED | CHECK_READY, [0x55] = IMPLEMENTED, [0x5a] = IMPLEMENTED, @@ -172,9 +171,9 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) } if (ret) { - fseek(dev->drv->fp, 0, SEEK_END); + fseeko64(dev->drv->fp, 0, SEEK_END); - uint32_t size = (uint32_t) ftell(dev->drv->fp); + uint64_t size = (uint64_t) ftello64(dev->drv->fp); unsigned int found = 0; if (is_mdi) { @@ -185,7 +184,7 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) dev->drv->base = 0; for (uint8_t i = 0; i < KNOWN_MO_TYPES; i++) { - if (size == (mo_types[i].sectors * mo_types[i].bytes_per_sector)) { + if (size == ((uint64_t) mo_types[i].sectors * mo_types[i].bytes_per_sector)) { found = 1; dev->drv->medium_size = mo_types[i].sectors; dev->drv->sector_size = mo_types[i].bytes_per_sector; @@ -194,7 +193,7 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) } if (found) { - if (fseek(dev->drv->fp, dev->drv->base, SEEK_SET) == -1) + if (fseeko64(dev->drv->fp, (uint64_t) dev->drv->base, SEEK_SET) == -1) log_fatal(dev->log, "mo_load(): Error seeking to the beginning of " "the file\n"); @@ -799,21 +798,21 @@ mo_blocks(mo_t *dev, int32_t *len, int out) *len = 0; - if (!dev->sector_len) - mo_command_complete(dev); - else { + if (dev->sector_len == 0) { mo_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); if (dev->sector_pos >= dev->drv->medium_size) { mo_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); mo_lba_out_of_range(dev); + ret = 0; } else { *len = dev->requested_blocks * dev->drv->sector_size; ret = 1; for (int i = 0; i < dev->requested_blocks; i++) { - if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size) + (i * dev->drv->sector_size), SEEK_SET) == -1) { + if (fseeko64(dev->drv->fp, dev->drv->base + + ((uint64_t) dev->sector_pos * dev->drv->sector_size), SEEK_SET) == -1) { if (out) mo_write_error(dev); else @@ -854,6 +853,9 @@ mo_blocks(mo_t *dev, int32_t *len, int out) dev->sector_len -= dev->requested_blocks; } } + } else { + mo_command_complete(dev); + ret = 0; } return ret; @@ -888,7 +890,7 @@ mo_format(mo_t *dev) mo_log(dev->log, "Formatting media...\n"); - fseek(dev->drv->fp, 0, SEEK_END); + fseeko64(dev->drv->fp, 0, SEEK_END); long size = ftell(dev->drv->fp); #ifdef _WIN32 @@ -962,8 +964,9 @@ mo_erase(mo_t *dev) mo_buf_alloc(dev, dev->drv->sector_size); memset(dev->buffer, 0, dev->drv->sector_size); - fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size), - SEEK_SET); + fseeko64(dev->drv->fp, dev->drv->base + + ((uint64_t) dev->sector_pos * dev->drv->sector_size), + SEEK_SET); for (i = 0; i < dev->requested_blocks; i++) { if (feof(dev->drv->fp)) @@ -1878,7 +1881,8 @@ mo_phase_data_out(scsi_common_t *sc) dev->buffer[6] = (s >> 8) & 0xff; dev->buffer[7] = s & 0xff; } - if (fseek(dev->drv->fp, (i * dev->drv->sector_size), SEEK_SET) == -1) + if (fseeko64(dev->drv->fp, + ((uint64_t) i * dev->drv->sector_size), SEEK_SET) == -1) mo_write_error(dev); if (feof(dev->drv->fp)) break; diff --git a/src/disk/zip.c b/src/disk/zip.c index f579f23ec..ae3319b40 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -53,7 +53,7 @@ const uint8_t zip_command_flags[0x100] = { [0x0c] = IMPLEMENTED, [0x0d] = IMPLEMENTED | ATAPI_ONLY, [0x12] = IMPLEMENTED | ALLOW_UA, - [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x13] = IMPLEMENTED | CHECK_READY, [0x15] = IMPLEMENTED, [0x16 ... 0x17] = IMPLEMENTED | SCSI_ONLY, [0x1a] = IMPLEMENTED, @@ -64,8 +64,7 @@ const uint8_t zip_command_flags[0x100] = { [0x25] = IMPLEMENTED | CHECK_READY, [0x28] = IMPLEMENTED | CHECK_READY, [0x2a ... 0x2b] = IMPLEMENTED | CHECK_READY, - [0x2e] = IMPLEMENTED | CHECK_READY, - [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x2e ... 0x2f] = IMPLEMENTED | CHECK_READY, [0x41] = IMPLEMENTED | CHECK_READY, [0x55] = IMPLEMENTED, [0x5a] = IMPLEMENTED, @@ -898,9 +897,7 @@ zip_blocks(zip_t *dev, int32_t *len, const int out) int ret = 1; *len = 0; - if (!dev->sector_len) - zip_command_complete(dev); - else { + if (dev->sector_len > 0) { zip_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); @@ -908,12 +905,13 @@ zip_blocks(zip_t *dev, int32_t *len, const int out) zip_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); zip_lba_out_of_range(dev); + ret = 0; } else { *len = dev->requested_blocks << 9; for (int i = 0; i < dev->requested_blocks; i++) { - if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos << 9) + - (i << 9), SEEK_SET) == -1) { + if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos << 9), + SEEK_SET) == -1) { if (out) zip_write_error(dev); else @@ -952,6 +950,9 @@ zip_blocks(zip_t *dev, int32_t *len, const int out) dev->sector_len -= dev->requested_blocks; } } + } else { + zip_command_complete(dev); + ret = 0; } return ret; From 6f8594f2b22504027d4471e146d296d7a32944f2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 01:38:59 +0100 Subject: [PATCH 132/218] MO: A few bug fixes. --- src/disk/mo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index b470b7761..3165a805e 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -798,7 +798,7 @@ mo_blocks(mo_t *dev, int32_t *len, int out) *len = 0; - if (dev->sector_len == 0) { + if (dev->sector_len > 0) { mo_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); @@ -891,7 +891,7 @@ mo_format(mo_t *dev) mo_log(dev->log, "Formatting media...\n"); fseeko64(dev->drv->fp, 0, SEEK_END); - long size = ftell(dev->drv->fp); + int64_t size = ftello64(dev->drv->fp); #ifdef _WIN32 LARGE_INTEGER liSize; From 1a6f84d455287b56232c3b7a0366616f531a3648 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 03:00:56 +0100 Subject: [PATCH 133/218] MO: More bug fixes. --- src/disk/mo.c | 56 +++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index 3165a805e..e2db4bda3 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -17,6 +17,7 @@ * Copyright 2020-2025 Miran Grca. * Copyright 2020-2025 Fred N. van Kempen */ +#define _GNU_SOURCE #ifdef ENABLE_MO_LOG #include #endif @@ -432,7 +433,8 @@ mo_update_request_length(mo_t *dev, int len, int block_len) case 0xa8: case 0xaa: /* Round it to the nearest 2048 bytes. */ - dev->max_transfer_len = (dev->max_transfer_len >> 9) << 9; + dev->max_transfer_len = (dev->max_transfer_len / dev->drv->sector_size) * + dev->drv->sector_size; /* Make sure total length is not bigger than sum of the lengths of @@ -792,10 +794,9 @@ mo_invalid_field_pl(mo_t *dev, const uint32_t field) } static int -mo_blocks(mo_t *dev, int32_t *len, int out) +mo_blocks(mo_t *dev, int32_t *len, const int out) { - int ret = 0; - + int ret = 1; *len = 0; if (dev->sector_len > 0) { @@ -803,41 +804,39 @@ mo_blocks(mo_t *dev, int32_t *len, int out) dev->requested_blocks, dev->sector_pos); if (dev->sector_pos >= dev->drv->medium_size) { - mo_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); + mo_log(dev->log, "Trying to %s beyond the end of disk\n", + out ? "write" : "read"); mo_lba_out_of_range(dev); - ret = 0; + ret = 0; } else { - *len = dev->requested_blocks * dev->drv->sector_size; - ret = 1; + *len = dev->requested_blocks * dev->drv->sector_size; for (int i = 0; i < dev->requested_blocks; i++) { - if (fseeko64(dev->drv->fp, dev->drv->base + - ((uint64_t) dev->sector_pos * dev->drv->sector_size), SEEK_SET) == -1) { + if (fseeko64(dev->drv->fp, (uint64_t) dev->drv->base + + (uint64_t) (dev->sector_pos * dev->drv->sector_size), + SEEK_SET) == -1) { if (out) mo_write_error(dev); else mo_read_error(dev); - ret = -1; } else { - if (!feof(dev->drv->fp)) + if (feof(dev->drv->fp)) break; if (out) { if (fwrite(dev->buffer + (i * dev->drv->sector_size), 1, - dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { + dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { mo_log(dev->log, "mo_blocks(): Error writing data\n"); mo_write_error(dev); ret = -1; } else fflush(dev->drv->fp); - } else { - if (fread(dev->buffer + (i * dev->drv->sector_size), 1, - dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { - mo_log(dev->log, "mo_blocks(): Error reading data\n"); - mo_read_error(dev); - ret = -1; - } + } else if (fread(dev->buffer + (i * dev->drv->sector_size), 1, + dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { + mo_log(dev->log, "mo_blocks(): Error reading data\n"); + mo_read_error(dev); + ret = -1; } } @@ -848,7 +847,8 @@ mo_blocks(mo_t *dev, int32_t *len, int out) } if (ret == 1) { - mo_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + mo_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" : + "Read", *len); dev->sector_len -= dev->requested_blocks; } @@ -1394,7 +1394,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: mo_set_phase(dev, SCSI_PHASE_DATA_OUT); - alloc_length = 512; + alloc_length = dev->drv->sector_size; switch (cdb[0]) { case GPCMD_VERIFY_6: @@ -1444,11 +1444,11 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_buf_alloc(dev, dev->packet_len); dev->requested_blocks = max_len; - dev->packet_len = max_len << 9; + dev->packet_len = max_len * dev->drv->sector_size; mo_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - mo_data_command_finish(dev, dev->packet_len, 512, + mo_data_command_finish(dev, dev->packet_len, dev->drv->sector_size, dev->packet_len, 1); ui_sb_update_icon(SB_MO | dev->id, @@ -1465,7 +1465,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_WRITE_SAME_10: mo_set_phase(dev, SCSI_PHASE_DATA_OUT); - alloc_length = 512; + alloc_length = dev->drv->sector_size; if ((cdb[1] & 6) == 6) mo_invalid_field(dev, cdb[1]); @@ -1484,7 +1484,8 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_set_phase(dev, SCSI_PHASE_DATA_OUT); - mo_data_command_finish(dev, 512, 512, + mo_data_command_finish(dev, dev->drv->sector_size, + dev->drv->sector_size, alloc_length, 1); ui_sb_update_icon(SB_MO | dev->id, @@ -1916,6 +1917,9 @@ mo_phase_data_out(scsi_common_t *sc) block_desc_len = 0; pos = hdr_len + block_desc_len; + mo_log(dev->log, "Block descriptor: %08X %08X %08X %08X %08X %08X %08X %08X\n", + dev->buffer[hdr_len], dev->buffer[hdr_len + 1], dev->buffer[hdr_len + 2], dev->buffer[hdr_len + 3], + dev->buffer[hdr_len + 4], dev->buffer[hdr_len + 5], dev->buffer[hdr_len + 6], dev->buffer[hdr_len + 7]); while (1) { if (pos >= param_list_len) { From 39f65003dc999c2716bc9cfddde3b760b8d42ae6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 03:32:47 +0100 Subject: [PATCH 134/218] Acer 100T: Do not add a separate internal FDC because one is already provided by the Super I/O chip, fixes #5250. --- src/machine/m_at_286_386sx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 9086f7c8a..fd9cc3bcd 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -750,9 +750,6 @@ machine_at_acer100t_init(const machine_t *model) machine_at_ps2_ide_init(model); - if (fdc_current[0] == FDC_INTERNAL) - device_add(&fdc_at_device); - device_add(&ali1409_device); if (gfxcard[0] == VID_INTERNAL) device_add(&oti077_acer100t_device); From 8eb084d397aa8033494e69f4fcf18605fd64ae2f Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 03:34:49 +0100 Subject: [PATCH 135/218] XT KBC: Fix switches for 192k RAM, fixes #5262. --- src/device/keyboard_xt.c | 64 ++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index ddbcae61b..3c616a2ab 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -84,6 +84,7 @@ typedef struct xtkbd_t { uint8_t key_waiting; uint8_t type; uint8_t pravetz_flags; + uint8_t cpu_speed; pc_timer_t send_delay_timer; } xtkbd_t; @@ -799,6 +800,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbd_adddata(0xaa); } } + kbd->pb = val; if (!(kbd->pb & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI)) kbd->clock = !!(kbd->pb & 0x40); @@ -846,6 +848,14 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } break; + case 0x1f0: + kbd_log("XTkbd: Port %04X out: %02X\n", port, val); + if (kbd->type == KBD_TYPE_VTECH) { + kbd->cpu_speed = val; + cpu_dynamic_switch(kbd->cpu_speed >> 7); + } + break; + default: break; } @@ -863,12 +873,14 @@ kbd_read(uint16_t port, void *priv) (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || - (kbd->type == KBD_TYPE_ZENITH) || (kbd->type == KBD_TYPE_HYUNDAI))) { + (kbd->type == KBD_TYPE_ZENITH) || (kbd->type == KBD_TYPE_HYUNDAI) || + (kbd->type == KBD_TYPE_VTECH))) { if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_HYUNDAI)) ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00); - else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86)) + else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || + (kbd->type == KBD_TYPE_VTECH)) /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ ret = 0xff; @@ -926,16 +938,8 @@ kbd_read(uint16_t port, void *priv) } else { if (kbd->pb & 0x08) /* PB3 */ ret = kbd->pd >> 4; - else { - /* LaserXT = Always 512k RAM; - LaserXT/3 = Bit 0: set = 512k, clear = 256k. */ -#ifdef USE_LASERXT - if (kbd->type == KBD_TYPE_VTECH) - ret = ((mem_size == 512) ? 0x0d : 0x0c) | (hasfpu ? 0x02 : 0x00); - else -#endif /* USE_LASERXT */ - ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00); - } + else + ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00); } ret |= (ppispeakon ? 0x20 : 0); @@ -956,7 +960,8 @@ kbd_read(uint16_t port, void *priv) case 0x63: /* Keyboard Configuration Register (aka Port D) */ if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || - (kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_HYUNDAI)) + (kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_HYUNDAI) || + (kbd->type == KBD_TYPE_VTECH)) ret = kbd->pd; break; @@ -966,6 +971,12 @@ kbd_read(uint16_t port, void *priv) kbd_log("XTkbd: Port %02X in : %02X\n", port, ret); break; + case 0x1f0: + if (kbd->type == KBD_TYPE_VTECH) + ret = kbd->cpu_speed; + kbd_log("XTkbd: Port %04X in : %02X\n", port, ret); + break; + default: break; } @@ -984,7 +995,7 @@ kbd_reset(void *priv) kbd->pb = 0x00; kbd->pravetz_flags = 0x00; - keyboard_scan = 1; + keyboard_scan = 1; key_queue_start = 0; key_queue_end = 0; @@ -1006,12 +1017,16 @@ kbd_init(const device_t *info) io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); keyboard_send = kbd_adddata_ex; - kbd_reset(kbd); kbd->type = info->local; - if (kbd->type == KBD_TYPE_PRAVETZ) { + if (kbd->type == KBD_TYPE_VTECH) + kbd->cpu_speed = (!!cpu) << 2; + kbd_reset(kbd); + if (kbd->type == KBD_TYPE_PRAVETZ) io_sethandler(0x00c0, 16, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); - } + if (kbd->type == KBD_TYPE_VTECH) + io_sethandler(0x01f0, 1, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); key_queue_start = key_queue_end = 0; @@ -1021,7 +1036,8 @@ kbd_init(const device_t *info) (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) || (kbd->type <= KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_TOSHIBA) || - (kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI)) { + (kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI) || + (kbd->type == KBD_TYPE_VTECH)) { /* DIP switch readout: bit set = OFF, clear = ON. */ if (kbd->type == KBD_TYPE_OLIVETTI) /* Olivetti M19 @@ -1035,7 +1051,7 @@ kbd_init(const device_t *info) /* Switches 7, 8 - floppy drives. */ kbd->pd = get_fdd_switch_settings(); - /* Siitches 5, 6 - video card type */ + /* Switches 5, 6 - video card type */ kbd->pd |= get_videomode_switch_settings(); /* Switches 3, 4 - memory size. */ @@ -1057,7 +1073,7 @@ kbd_init(const device_t *info) kbd->pd |= 0x0c; break; } - } else if (kbd->type == KBD_TYPE_XT82) { + } else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_VTECH)) { switch (mem_size) { case 64: /* 1x64k */ kbd->pd |= 0x00; @@ -1075,9 +1091,13 @@ kbd_init(const device_t *info) } } else if (kbd->type == KBD_TYPE_PC82) { switch (mem_size) { +#ifdef PC82_192K_3BANK case 192: /* 3x64k, not supported by stock BIOS due to bugs */ kbd->pd |= 0x08; break; +#else + case 192: /* 2x64k + 2x32k */ +#endif case 64: /* 4x16k */ case 96: /* 2x32k + 2x16k */ case 128: /* 4x32k */ @@ -1294,8 +1314,8 @@ const device_t keyboard_xt_t1x00_device = { #ifdef USE_LASERXT const device_t keyboard_xt_lxt3_device = { - .name = "VTech Laser XT3 Keyboard", - .internal_name = "keyboard_xt_lxt3", + .name = "VTech Laser Turbo XT Keyboard", + .internal_name = "keyboard_xt_lxt", .flags = 0, .local = KBD_TYPE_VTECH, .init = kbd_init, From 25bcd434a0936f96875126758f510c84bc53a541 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 18 Mar 2025 13:06:14 +0600 Subject: [PATCH 136/218] Qt: Add special handling for real touchscreen devices --- src/qt/qt_renderercommon.cpp | 4 +++ src/qt/qt_rendererstack.cpp | 65 ++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_renderercommon.cpp b/src/qt/qt_renderercommon.cpp index 178134c9d..2a20ff63c 100644 --- a/src/qt/qt_renderercommon.cpp +++ b/src/qt/qt_renderercommon.cpp @@ -144,6 +144,10 @@ RendererCommon::eventDelegate(QEvent *event, bool &result) case QEvent::MouseButtonPress: case QEvent::MouseMove: case QEvent::MouseButtonRelease: + case QEvent::TouchBegin: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + case QEvent::TouchUpdate: case QEvent::Wheel: case QEvent::Enter: case QEvent::Leave: diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 2b1cfdf26..8c0792be4 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -38,6 +38,7 @@ #include #include +#include #ifdef __APPLE__ # include @@ -63,6 +64,7 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) : QStackedWidget(parent) , ui(new Ui::RendererStack) { + setAttribute(Qt::WA_AcceptTouchEvents, true); rendererTakesScreenshots = false; #ifdef Q_OS_WINDOWS int raw = 1; @@ -477,8 +479,8 @@ RendererStack::event(QEvent* event) if (m_monitor_index >= 1) { if (mouse_input_mode >= 1) { - mouse_x_abs = (mouse_event->localPos().x()) / (long double)width(); - mouse_y_abs = (mouse_event->localPos().y()) / (long double)height(); + mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); + mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); if (!mouse_tablet_in_proximity) mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; } @@ -487,15 +489,66 @@ RendererStack::event(QEvent* event) #ifdef Q_OS_WINDOWS if (mouse_input_mode == 0) { - mouse_x_abs = (mouse_event->localPos().x()) / (long double)width(); - mouse_y_abs = (mouse_event->localPos().y()) / (long double)height(); + mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); + mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); return QStackedWidget::event(event); } #endif - mouse_x_abs = (mouse_event->localPos().x()) / (long double)width(); - mouse_y_abs = (mouse_event->localPos().y()) / (long double)height(); + mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); + mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; + } else switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->touchPoints().count()) { + mouse_x_abs = (touchevent->touchPoints()[0].pos().x()) / (double)width(); + mouse_y_abs = (touchevent->touchPoints()[0].pos().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() | 1); + touchevent->accept(); + return true; +#else + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->pointCount()) { + mouse_x_abs = (touchevent->point(0).position().x()) / (double)width(); + mouse_y_abs = (touchevent->point(0).position().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() | 1); + touchevent->accept(); + return true; +#endif + } + case QEvent::TouchEnd: + case QEvent::TouchCancel: + { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->touchPoints().count()) { + mouse_x_abs = (touchevent->touchPoints()[0].pos().x()) / (double)width(); + mouse_y_abs = (touchevent->touchPoints()[0].pos().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() & ~1); + touchevent->accept(); + return true; +#else + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->pointCount()) { + mouse_x_abs = (touchevent->point(0).position().x()) / (double)width(); + mouse_y_abs = (touchevent->point(0).position().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() & ~1); + touchevent->accept(); + return true; +#endif + } } return QStackedWidget::event(event); From 96644d137f785cec857b9a1c217dae65d563d50b Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Tue, 18 Mar 2025 19:57:14 +0300 Subject: [PATCH 137/218] Add the Soyo SY-7SBB (SiS 600, Socket 370) --- src/include/86box/machine.h | 1 + src/machine/m_at_socket370.c | 28 ++++++++++++++++++++++++ src/machine/machine_table.c | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index b2e4c01f2..d1257d94c 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -855,6 +855,7 @@ extern int machine_at_s1857_init(const machine_t *); extern int machine_at_p6bap_init(const machine_t *); extern int machine_at_p6bat_init(const machine_t *); extern int machine_at_prosignias31x_bx_init(const machine_t *); +extern int machine_at_7sbb_init(const machine_t *); /* m_at_misc.c */ extern int machine_at_vpc2007_init(const machine_t *); diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index 9be2d45b8..b2e311166 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -541,3 +541,31 @@ machine_at_6via90ap_init(const machine_t *model) return ret; } + +int +machine_at_7sbb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/7sbb/sbb12aa2.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1 | FLAG_TRC_CONTROLS_CPURST); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x02, PCI_CARD_AGPBRIDGE, 0, 0, 0, 0); + device_add(&sis_5600_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&it8661f_device); + device_add(&sst_flash_29ee020_device); /* assumed */ + + return ret; +} \ No newline at end of file diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3706126a3..bae9de29f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -16227,6 +16227,48 @@ const machine_t machines[] = { .snd_device = &cmi8738_onboard_device, .net_device = NULL }, + /* SiS (5)600 */ + /* Has the SiS 600 chipset, which is a re-brand of the 5600, with + on-chip KBC. */ + { + .name = "[SiS 600] Soyo SY-7SBB", + .internal_name = "7sbb", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_SIS_5600, + .init = machine_at_7sbb_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK(CPU_CYRIX3S), + .min_bus = 60000000, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .ram = { + .min = 8192, + .max = 1572864, + .step = 1024 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Miscellaneous/Fake/Hypervisor machines */ /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC From aaaa96f785ca2ecdfa9b76561e074b6ea4815323 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 18:20:49 +0100 Subject: [PATCH 138/218] QT render stack: add a missing default entry. Also committing the missing MO image creation fixes. --- src/qt/qt_newfloppydialog.cpp | 18 +++++++++--------- src/qt/qt_rendererstack.cpp | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/qt/qt_newfloppydialog.cpp b/src/qt/qt_newfloppydialog.cpp index 48be09777..58a7a3df2 100644 --- a/src/qt/qt_newfloppydialog.cpp +++ b/src/qt/qt_newfloppydialog.cpp @@ -367,7 +367,7 @@ NewFloppyDialog::create86f(const QString &filename, const disk_size_t &disk_size bool NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t &disk_size, FileType type) { - uint32_t total_size = 0; + uint64_t total_size = 0; uint32_t total_sectors = 0; uint32_t sector_bytes = 0; uint32_t root_dir_bytes = 0; @@ -388,7 +388,7 @@ NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t &d total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; if (total_sectors > ZIP_SECTORS) total_sectors = ZIP_250_SECTORS; - total_size = total_sectors * sector_bytes; + total_size = (uint64_t) total_sectors * sector_bytes; root_dir_bytes = (disk_size.root_dir_entries << 5); fat_size = (disk_size.spfat * sector_bytes); fat1_offs = sector_bytes; @@ -465,11 +465,11 @@ NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t &d bool NewFloppyDialog::createZipSectorImage(const QString &filename, const disk_size_t &disk_size, FileType type, QProgressDialog &pbar) { - uint32_t total_size = 0; + uint64_t total_size = 0; uint32_t total_sectors = 0; uint32_t sector_bytes = 0; uint16_t base = 0x1000; - uint32_t pbar_max = 0; + uint64_t pbar_max = 0; QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { @@ -482,7 +482,7 @@ NewFloppyDialog::createZipSectorImage(const QString &filename, const disk_size_t total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; if (total_sectors > ZIP_SECTORS) total_sectors = ZIP_250_SECTORS; - total_size = total_sectors * sector_bytes; + total_size = (uint64_t) total_sectors * sector_bytes; pbar_max = total_size; if (type == FileType::Zdi) { @@ -649,12 +649,12 @@ bool NewFloppyDialog::createMoSectorImage(const QString &filename, int8_t disk_size, FileType type, QProgressDialog &pbar) { const mo_type_t *dp = &mo_types[disk_size]; - uint32_t total_size = 0; - uint32_t total_size2; + uint64_t total_size = 0; + uint64_t total_size2; uint32_t total_sectors = 0; uint32_t sector_bytes = 0; uint16_t base = 0x1000; - uint32_t pbar_max = 0; + uint64_t pbar_max = 0; uint32_t blocks_num; QFile file(filename); @@ -666,7 +666,7 @@ NewFloppyDialog::createMoSectorImage(const QString &filename, int8_t disk_size, sector_bytes = dp->bytes_per_sector; total_sectors = dp->sectors; - total_size = total_sectors * sector_bytes; + total_size = (uint64_t) total_sectors * sector_bytes; total_size2 = (total_size >> 20) << 20; total_size2 = total_size - total_size2; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 8c0792be4..3e81a52c2 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -549,6 +549,9 @@ RendererStack::event(QEvent* event) return true; #endif } + + default: + return QStackedWidget::event(event); } return QStackedWidget::event(event); From 70dcdee72bbedc8fe138edaf4321e7145c22f2f1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 19:21:00 +0100 Subject: [PATCH 139/218] Some Cyrix MII table/ID fixes and added some Cyrix CPU blocking for the NuPRO 592 and the P5MMS98. --- src/cpu/cpu.c | 8 ++++ src/cpu/cpu_table.c | 89 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index b821bc657..0c621bf68 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -384,6 +384,14 @@ cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) if (cpu_override) return 1; + /* Cyrix 6x86MX on the NuPRO 592. */ + if (((cpu_s->cyrix_id & 0xff00) == 0x0400) && (strstr(machine_s->internal_name, "nupro") != NULL)) + return 0; + + /* Cyrix 6x86MX or MII on the P5MMS98. */ + if ((cpu_s->cpu_type == CPU_Cx6x86MX) && (strstr(machine_s->internal_name, "p5mms98") != NULL)) + return 0; + /* Check CPU blocklist. */ if (machine_s->cpu.block) { i = 0; diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 5a156853e..e5c91b1a8 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -6366,6 +6366,74 @@ const cpu_family_t cpu_families[] = { .name = "MII", .internal_name = "mii", .cpus = (const CPU[]) { + { + .name = "IBM 133 (PR166)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 133333333, + .multi = 2.0, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0851, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 12, + .mem_write_cycles = 12, + .cache_read_cycles = 6, + .cache_write_cycles = 6, + .atclk_div = 16 + }, + { + .name = "166 (PR200)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 166666666, + .multi = 2.5, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0852, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 15, + .mem_write_cycles = 15, + .cache_read_cycles = 7, + .cache_write_cycles = 7, + .atclk_div = 20 + }, + { + .name = "187.5 (PR233)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 187500000, + .multi = 2.5, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0852, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 15, + .mem_write_cycles = 15, + .cache_read_cycles = 7, + .cache_write_cycles = 7, + .atclk_div = 45/2 + }, + { + .name = "208.3 (PR266)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 208333333, + .multi = 2.5, + .voltage = 2700, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0852, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 17, + .mem_write_cycles = 17, + .cache_read_cycles = 7, + .cache_write_cycles = 7, + .atclk_div = 25 + }, { .name = "233 (PR300)", .cpu_type = CPU_Cx6x86MX, @@ -6375,7 +6443,7 @@ const cpu_family_t cpu_families[] = { .voltage = 2900, .edx_reset = 0x601, .cpuid_model = 0x601, - .cyrix_id = 0x0852, + .cyrix_id = 0x0854, .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, .mem_read_cycles = 21, .mem_write_cycles = 21, @@ -6409,7 +6477,7 @@ const cpu_family_t cpu_families[] = { .voltage = 2900, .edx_reset = 0x601, .cpuid_model = 0x601, - .cyrix_id = 0x0853, + .cyrix_id = 0x0852, .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, .mem_read_cycles = 23, .mem_write_cycles = 23, @@ -6417,6 +6485,23 @@ const cpu_family_t cpu_families[] = { .cache_write_cycles = 7, .atclk_div = 30 }, + { + .name = "270 (PR350)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 270000000, + .multi = 3.0, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0853, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 25, + .mem_write_cycles = 25, + .cache_read_cycles = 8, + .cache_write_cycles = 8, + .atclk_div = 32 + }, { .name = "285 (PR400)", .cpu_type = CPU_Cx6x86MX, From 66b99cc2ff27dd9a9d962d4dc7ae1ad9a95efe09 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 22:49:03 +0100 Subject: [PATCH 140/218] QT render stack: ignore the wheel event on Windows and Apple. --- src/qt/qt_rendererstack.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 3e81a52c2..5b464f6a5 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -203,6 +203,9 @@ RendererStack::mousePressEvent(QMouseEvent *event) void RendererStack::wheelEvent(QWheelEvent *event) { +#if defined(Q_OS_WINDOWS) || defined(__APPLE__) + event->ignore(); +#else if (!mouse_capture) { event->ignore(); return; @@ -212,6 +215,7 @@ RendererStack::wheelEvent(QWheelEvent *event) mouse_set_z((int) numSteps); event->accept(); +#endif } void From 9bce2496be920bb3d2b260b53e17044d79205e0c Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 22:51:19 +0100 Subject: [PATCH 141/218] Corrected the behavior of that. --- src/qt/qt_rendererstack.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 5b464f6a5..5dc61e03b 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -203,19 +203,17 @@ RendererStack::mousePressEvent(QMouseEvent *event) void RendererStack::wheelEvent(QWheelEvent *event) { -#if defined(Q_OS_WINDOWS) || defined(__APPLE__) - event->ignore(); -#else if (!mouse_capture) { event->ignore(); return; } +#if !defined(Q_OS_WINDOWS) && !defined(__APPLE__) double numSteps = (double) event->angleDelta().y() / 120.0; mouse_set_z((int) numSteps); - event->accept(); #endif + event->accept(); } void From 67f0e9574098eab70590cae94059bdf40878f3e0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 00:24:13 +0100 Subject: [PATCH 142/218] Fixed an off by 1 error in the new recompiler. --- src/codegen_new/codegen_backend_x86-64_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index 39173505b..c70112c86 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -533,7 +533,7 @@ host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ codegen_addword(block, imm_data); } else if (offset < (1ULL << 32)) { - codegen_alloc_bytes(block, 8); + codegen_alloc_bytes(block, 9); codegen_addbyte3(block, 0x66, 0xc7, 0x85); /*MOV offset[RBP], imm_data*/ codegen_addlong(block, offset); codegen_addword(block, imm_data); From f05e2f34b615d879e7a60216ab8d24961087a023 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Mar 2025 08:51:52 +0900 Subject: [PATCH 143/218] added JEGA video emulation --- src/include/86box/vid_ega.h | 21 ++ src/video/CMakeLists.txt | 1 + src/video/vid_ega.c | 26 +- src/video/vid_jega.c | 724 ++++++++++++++++++++++++++++++++++++ src/video/vid_table.c | 1 + 5 files changed, 757 insertions(+), 16 deletions(-) create mode 100644 src/video/vid_jega.c diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 0bccd607e..082cb120a 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -140,6 +140,11 @@ typedef struct ega_t { uint32_t (*remap_func)(struct ega_t *ega, uint32_t in_addr); void (*render)(struct ega_t *svga); + + /*If set then another device is driving the monitor output and the EGA + card should not attempt to display anything */ + void (*render_override)(void *priv); + void *priv_parent; } ega_t; #endif @@ -150,6 +155,7 @@ extern const device_t sega_device; extern const device_t atiega800p_device; extern const device_t iskra_ega_device; extern const device_t et2000_device; +extern const device_t jega_device; #endif extern int update_overscan; @@ -199,4 +205,19 @@ void ega_render_text(ega_t *ega); void ega_render_graphics(ega_t *ega); #endif +enum { + EGA_IBM = 0, + EGA_COMPAQ, + EGA_SUPEREGA, + EGA_ATI800P, + EGA_ISKRA, + EGA_TSENG +}; + +enum { + EGA_TYPE_IBM = 0, + EGA_TYPE_OTHER = 1, + EGA_TYPE_COMPAQ = 2 +}; + #endif /*VIDEO_EGA_H*/ diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index fdd94f6c6..062fc272a 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -78,6 +78,7 @@ add_library(vid OBJECT vid_xga.c vid_bochs_vbe.c vid_ps55da2.c + vid_jega.c nv/nv_rivatimer.c ) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 10df85c79..781e9a9dd 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -45,21 +45,6 @@ void ega_doblit(int wx, int wy, ega_t *ega); #define BIOS_ISKRA_PATH "roms/video/ega/143-02.bin", "roms/video/ega/143-03.bin" #define BIOS_TSENG_PATH "roms/video/ega/EGA ET2000.BIN" -enum { - EGA_IBM = 0, - EGA_COMPAQ, - EGA_SUPEREGA, - EGA_ATI800P, - EGA_ISKRA, - EGA_TSENG -}; - -enum { - EGA_TYPE_IBM = 0, - EGA_TYPE_OTHER = 1, - EGA_TYPE_COMPAQ = 2 -}; - static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; static uint8_t ega_rotate[8][256]; static int active = 0; @@ -107,6 +92,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) case 0x3c0: case 0x3c1: + if (ega->actual_type == EGA_SUPEREGA) + val &= 0x7f; /* Bit 7 indicates the flipflop status (read only) */ if (!ega->attrff) { ega->attraddr = val & 31; if ((val & 0x20) != ega->attr_palette_enable) { @@ -325,6 +312,8 @@ ega_in(uint16_t addr, void *priv) case 0x3c0: if (ega_type == EGA_TYPE_OTHER) ret = ega->attraddr | ega->attr_palette_enable; + if (ega->actual_type == EGA_SUPEREGA && ega->attrff) + ret |= 0x80; /* Bit 7 indicates the flipflop status (read only) */ break; case 0x3c1: if (ega_type == EGA_TYPE_OTHER) @@ -754,7 +743,10 @@ ega_poll(void *priv) ega->y_add *= ega->vres + 1; for (y = 0; y <= ega->vres; y++) { /* Render scanline */ - ega->render(ega); + if(ega->render_override) + ega->render_override(ega->priv_parent); + else + ega->render(ega); /* Render overscan */ ega->x_add = (overscan_x >> 1); @@ -1429,6 +1421,8 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) ega->crtc[0] = 63; ega->crtc[6] = 255; + ega->render_override = NULL; + timer_add(&ega->timer, ega_poll, ega, 1); if (ega_type == EGA_TYPE_COMPAQ) timer_add(&ega->dot_timer, ega_dot_poll, ega, 1); diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c new file mode 100644 index 000000000..ad312faff --- /dev/null +++ b/src/video/vid_jega.c @@ -0,0 +1,724 @@ +/* + * 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 JEGA (Japanese EGA), a part of the AX architecture. + * + * It's an extension of the SuperEGA. Superimposing text (AX-2) is not available. + * + * Authors: Akamaki + * + * Copyright 2025 Akamaki + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/vid_ega.h> + +/* JEGA internal registers */ +#define RPESL 0x09 /* End Scan Line */ +#define RCCSL 0x0A /* Cursor Start Line */ +#define RCCEL 0x0B /* Cursor End Line */ +#define RCCLH 0x0E /* Cursor Location High */ +#define RCCLL 0x0F /* Cursor Location Low */ +#define RPULP 0x14 /* Under Line Position */ +/* + 0xB8 - 0x20 */ +#define RMOD1 0x21 /* Display out, EGA through, Superimpose, Sync with EGA, Master EGA, Slave EGA, n/a, Test */ +#define RMOD2 0x22 /* 1st Attr, 2nd Attr, Blink/Int, n/a, Font access mode (b3-2), Font map sel (b1-0)*/ +#define RDAGS 0x23 /* ANK Group Select */ +#define RDFFB 0x24 /* Font Access First Byte */ +#define RDFSB 0x25 /* Font Access Second Byte */ +#define RDFAP 0x26 /* Font Access Pattern */ +#define RSTAT 0x27 /* Font Status Register */ +/* + 0xD0 - 0x20 */ +#define RPSSU 0x29 /* Start Scan Upper */ +#define RPSSL 0x2A /* Start Scan Lower */ +#define RPSSC 0x2B /* Start Scan Count */ +#define RPPAJ 0x2C /* Phase Adjust Count */ +#define RCMOD 0x2D /* Cursor Mode */ +#define RCSKW 0x2E /* Cursor Skew Control */ +#define ROMSL 0x2F /* ? */ +#define RINVALID_INDEX 0x30 + +#define JEGA_PATH_BIOS "roms/video/jega/OKI_IF386AX_VBIOS.bin" +#define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" +#define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ +#define DBCS16_CHARS 0x2c10 +#define DBCS16_FILESIZE (DBCS16_CHARS * 16 * 2) + +#define INVALIDACCESS8 0xffu +#define INVALIDACCESS16 0xffffu +#define INVALIDACCESS32 0xffffffffu + +#ifndef RELEASE_BUILD +// # define ENABLE_JEGA_LOG 1 +#endif + +#ifdef ENABLE_JEGA_LOG +int jega_do_log = ENABLE_JEGA_LOG; + +static void +jega_log(const char *fmt, ...) +{ + va_list ap; + + if (jega_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define jega_log(fmt, ...) +#endif + +static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; + +typedef struct jega_t { + rom_t bios_rom; + ega_t ega; + uint8_t regs_index; /* 3D4/3D5 index B9-BF, D9-DF */ + uint8_t regs[0x31]; + uint8_t egapal[16]; + uint8_t attrregs[32]; + uint8_t attraddr; + uint8_t attrff; + uint8_t attr_palette_enable; + uint32_t *pallook; + int con; + int cursoron; + int cursorblink_disable; + int ca; + int font_index; + int sbcsbank_inv; + int attr3_sbcsbank; + int start_scan_lower; + int start_scan_upper; + int start_scan_count; + uint8_t *vram; + uint8_t jfont_sbcs_19[SBCS19_FILESIZE]; /* 8 x 19 font */ + uint8_t jfont_dbcs_16[DBCS16_FILESIZE]; /* 16 x 16 font. Use dbcs_read/write to access it. */ +} jega_t; + +static void jega_recalctimings(void *priv); + +#define FONTX_LEN_ID 6 +#define FONTX_LEN_FN 8 + +typedef struct { + char id[FONTX_LEN_ID]; + char name[FONTX_LEN_FN]; + unsigned char width; + unsigned char height; + unsigned char type; +} fontx_h; + +typedef struct { + uint16_t start; + uint16_t end; +} fontx_tbl; + +static uint32_t pallook64[256]; +static bool is_SJIS_1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } +static bool is_SJIS_2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } + +static uint16_t +SJIS_to_SEQ(uint16_t sjis) +{ + uint32_t chr1 = (sjis >> 8) & 0xff; + uint32_t chr2 = sjis & 0xff; + if (!is_SJIS_1(chr1) || !is_SJIS_2(chr2)) return INVALIDACCESS16; + chr1 -= 0x81; + if (chr1 > 0x5E) chr1 -= 0x40; + chr2 -= 0x40; + if (chr2 > 0x3F) chr2--; + chr1 *= 0xBC; + return (chr1 + chr2); +} + +static uint8_t +dbcs_read(uint16_t sjis, int index, void *priv) { + jega_t *jega = (jega_t *) priv; + int seq = SJIS_to_SEQ(sjis); + if (seq >= DBCS16_CHARS || index >= 32) + return INVALIDACCESS8; + return jega->jfont_dbcs_16[seq * 32 + index]; +} + +static void +dbcs_write(uint16_t sjis, int index, uint8_t val, void *priv) { + jega_t *jega = (jega_t *) priv; + int seq = SJIS_to_SEQ(sjis); + if (seq >= DBCS16_CHARS || index >= 32) + return; + jega->jfont_dbcs_16[seq * 32 + index] = val; +} + +/* Display Adapter Mode 3 Drawing */ +void +jega_render_text(void *priv) +{ + jega_t *jega = (jega_t *) priv; + if (jega->ega.firstline_draw == 2000) + jega->ega.firstline_draw = jega->ega.displine; + jega->ega.lastline_draw = jega->ega.displine; + + if (jega->ega.fullchange) { + // const bool doublewidth = ((jega->ega.seqregs[1] & 8) != 0); + const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */ + // const bool attrlinechars = (jega->ega.attrregs[0x10] & 4); + const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || (jega->regs[RMOD1] & 0x80 == 0); + const int charwidth = 8; + const bool blinked = jega->ega.blink & 0x10; + uint32_t *p = &buffer32->line[jega->ega.displine + jega->ega.y_add][jega->ega.x_add]; + bool chr_wide = false; + int sc_wide = jega->ega.sc - jega->start_scan_count; + const bool cursoron = (blinked || jega->cursorblink_disable) + && (jega->ega.sc >= jega->regs[RCCSL]) && (jega->ega.sc <= jega->regs[RCCEL]); + uint32_t chr_first; + uint32_t attr_basic; + int fg; + int bg; + + for (int x = 0; x < (jega->ega.hdisp + jega->ega.scrollcache); x += charwidth) { + uint32_t addr = jega->ega.remap_func(&jega->ega, jega->ega.ma) & jega->ega.vrammask; + + int drawcursor = ((jega->ega.ma == jega->ca) && cursoron); + + uint32_t chr; + uint32_t attr; + if (!crtcreset) { + chr = jega->ega.vram[addr]; + attr = jega->ega.vram[addr + 1]; + } else + chr = attr = 0; + if (chr_wide) { + uint8_t attr_ext = 0; + /* the code may be in DBCS */ + if (jega->regs[RMOD2] & 0x40) { + /* Parse JEGA extended attribute */ + /* Bold | 2x width | 2x height | U/L select | R/L select | - | - | - */ + attr_ext = attr; + if ((attr_ext & 0x30) == 0x30) + sc_wide = jega->ega.sc - jega->start_scan_lower; /* Set top padding of lower 2x character */ + else if ((attr_ext & 0x30) == 0x20) + sc_wide = jega->ega.sc - jega->start_scan_upper; /* Set top padding of upper 2x character */ + else + sc_wide = jega->ega.sc - jega->start_scan_count; + } + if (is_SJIS_2(chr) && sc_wide >= 0 && sc_wide < 16 && jega->ega.sc <= jega->regs[RPESL]) { + chr_first <<= 8; + chr |= chr_first; + /* Vertical wide font (Extended Attribute) */ + if (attr_ext & 0x20) { + if (attr_ext & 0x10) + sc_wide = (sc_wide >> 1) + 8; + else + sc_wide = sc_wide >> 1; + } + /* Horizontal wide font (Extended Attribute) */ + if (attr_ext & 0x40) { + uint32_t dat = dbcs_read(chr, sc_wide, jega); + if (!(attr_ext & 0x08)) { /* right half of character */ + dat = dbcs_read(chr, sc_wide + 16, jega); + } + for (int xx = 0; xx < charwidth; xx++) { + p[xx * 2] = (dat & (0x80 >> xx)) ? fg : bg; + p[xx * 2 + 1] = (dat & (0x80 >> xx)) ? fg : bg; + } + } else { + uint32_t dat = dbcs_read(chr, sc_wide, jega); + dat <<= 8; + dat |= dbcs_read(chr, sc_wide + 16, jega); + /* Bold (Extended Attribute) */ + if (attr_ext &= 0x80) { + uint32_t dat2 = dat; + dat2 >>= 1; + dat |= dat2; + } + for (int xx = 0; xx < charwidth * 2; xx++) + p[xx] = (dat & (0x8000 >> xx)) ? fg : bg; + } + } else { + /* invalid DBCS code or line space then put blank */ + for (int xx = 0; xx < charwidth * 2; xx++) + p[xx] = bg; + } + if (attr_basic & 0x20) { /* vertical line */ + p[0] = fg; + } + if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ + for (int xx = 0; xx < charwidth * 2; xx++) + p[xx] = fg; + } + chr_wide = false; + p += (charwidth * 2); + } else { + /* SBCS or invalid second byte of DBCS */ + if (jega->regs[RMOD2] & 0x80) { + /* Parse attribute as JEGA */ + /* Blink | Reverse | V line | U line | (Bit 3-0 is the same as EGA) */ + /* The background color is always black (transparent in AX-2) */ + if (drawcursor || attr & 0x40) { + bg = jega->pallook[jega->egapal[attr & 0x0f]]; + fg = 0; + } else { + fg = jega->pallook[jega->egapal[attr & 0x0f]]; + bg = 0; + if (attr & 0x80) { + bg = 0; + if (blinked) + fg = bg; + } + } + attr_basic = attr; + } else { + /* Parse attribute as EGA */ + /* BInt/Blink | BR | BG | BB | Int/Group | R | G | B */ + if (drawcursor) { + bg = jega->pallook[jega->egapal[attr & 0x0f]]; + fg = jega->pallook[jega->egapal[attr >> 4]]; + } else { + fg = jega->pallook[jega->egapal[attr & 0x0f]]; + bg = jega->pallook[jega->egapal[attr >> 4]]; + if ((attr & 0x80) && attrblink) { + bg = jega->pallook[jega->egapal[(attr >> 4) & 7]]; + if (blinked) + fg = bg; + } + } + attr_basic = 0; + } + + if (is_SJIS_1(chr)) { + /* the char code maybe in DBCS */ + chr_first = chr; + chr_wide = true; + } else { + /* the char code is in SBCS */ + uint32_t charaddr = chr; + // if (jega->attr3_sbcsbank && (attr & 8)) + // charaddr |= 0x100; + // if (jega->sbcsbank_inv) + // charaddr ^= 0x100; + charaddr *= 19; + + uint32_t dat = jega->jfont_sbcs_19[charaddr + jega->ega.sc]; + for (int xx = 0; xx < charwidth; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + + if (attr_basic & 0x20) { /* vertical line */ + p[0] = fg; + } + if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ + for (int xx = 0; xx < charwidth; xx++) + p[xx] = fg; + } + p += charwidth; + } + } + jega->ega.ma += 4; + } + jega->ega.ma &= 0x3ffff; + } +} + +static void +jega_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t o; + jega_t *jega = (jega_t *) priv; + // jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc); + switch (addr) { + case 0x3c0: + case 0x3c1: + jega_log("Palette %02X %02X(%d) %04X:%04X\n", jega->attraddr, val, val, cs >> 4, cpu_state.pc); + /* Palette (write only) */ + if (!jega->attrff) { + jega->attraddr = val & 31; + if ((val & 0x20) != jega->attr_palette_enable) { + jega->ega.fullchange = 3; + jega->attr_palette_enable = val & 0x20; + jega_recalctimings(jega); + } + } else { + o = jega->attrregs[jega->attraddr & 31]; + jega->attrregs[jega->attraddr & 31] = val; + if (jega->attraddr < 0x10) { + for (uint8_t c = 0; c < 16; c++) { + jega->egapal[c] = jega->attrregs[c] & 0x3f; + } + jega->ega.fullchange = changeframecount; + } + } + jega->attrff ^= 1; + break; + case 0x3b4: + case 0x3d4: + /* Index 0x00-0x1F (write only), 0xB8-0xDF (write and read) */ + if (val >= 0xB8 && val <= 0xBF) + jega->regs_index = val - 0xB8 + 0x20; + else if (val >= 0xD8 && val <= 0xDF) + jega->regs_index = val - 0xD0 + 0x20; + else if (val <= 0x1F) + jega->regs_index = val; + else + jega->regs_index = RINVALID_INDEX; + break; + case 0x3b5: + case 0x3d5: + /* Data */ + if (jega->regs_index != RINVALID_INDEX) { + jega->regs[jega->regs_index] = val; + jega_log("JEGA Out %04X(%02X) %02Xh(%d) %04X:%04X\n", addr, jega->regs_index, val, val, cs >> 4, cpu_state.pc); + switch (jega->regs_index) { + case RMOD1: + /* if the value is changed */ + // if (jega->regs[jega->regs_index] != val) { + if (val & 0x40) + jega->ega.render_override = NULL; + else + jega->ega.render_override = jega_render_text; + // } + break; + case RDAGS: + switch (val & 0x03) { + case 0x00: + jega->attr3_sbcsbank = false; + jega->sbcsbank_inv = false; + break; + case 0x01: + jega->attr3_sbcsbank = true; + jega->sbcsbank_inv = false; + break; + case 0x02: + jega->attr3_sbcsbank = true; + jega->sbcsbank_inv = true; + break; + case 0x03: + jega->attr3_sbcsbank = false; + jega->sbcsbank_inv = true; + break; + } + break; + case RCCLH: + case RCCLL: + jega->ca = jega->regs[RCCLH] << 10 | jega->regs[RCCLL] << 2; + break; + case RCMOD: + jega->cursoron = (val & 0x80); + jega->cursorblink_disable = (~val & 0x20); + break; + case RDFFB: + case RDFSB: + /* reset the line number */ + jega->font_index = 0; + break; + case RPSSC: + if (val <= 17) + jega->start_scan_count = val + 1; + else + jega->start_scan_count = (val - 32) + 1; + break; + case RPSSL: + jega->start_scan_lower = val - 15; + break; + case RPSSU: + if (val <= 33) + jega->start_scan_upper = val + 4; + else + jega->start_scan_upper = (val - 64) + 4; + break; + case RDFAP: + uint16_t chr = jega->regs[RDFFB]; + if (is_SJIS_1(chr) && chr >= 0xf0 && chr <= 0xf3) { + chr <<= 8; + chr |= jega->regs[RDFSB]; + if (jega->font_index < 32) + dbcs_write(chr, jega->font_index, val, jega); + } else { + if (jega->font_index <19) + jega->jfont_sbcs_19[chr * 19 + jega->font_index] = val; + } + jega_log("JEGA Font W %X %d %02Xh(%d) %04X:%04X\n", chr, jega->font_index, val, val, cs >> 4, cpu_state.pc); + jega->font_index++; + break; + } + } + break; + default: + break; + } + if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */ + ega_out(addr, val, &jega->ega); +} + +static uint8_t +jega_in(uint16_t addr, void *priv) +{ + jega_t *jega = (jega_t *) priv; + uint8_t ret = INVALIDACCESS8; + switch (addr) { + case 0x3b5: + case 0x3d5: + if (jega->regs_index >= 0x20 && jega->regs_index <= 0x2F) { + switch (jega->regs_index) { + case RDFAP: + uint16_t chr = jega->regs[RDFFB]; + /* DBCS or SBCS */ + if (is_SJIS_1(chr)) { + chr <<= 8; + chr |= jega->regs[RDFSB]; + if (jega->font_index < 32) + ret = dbcs_read(chr, jega->font_index, jega); + } else { + if (jega->font_index < 19) + ret = jega->jfont_sbcs_19[chr * 19 + jega->font_index]; + } + jega_log("JEGA Font R %X %d %02Xh(%d) %04X:%04X\n", chr, jega->font_index, ret, ret, cs >> 4, cpu_state.pc); + jega->font_index++; + break; + case RSTAT: + ret = 0x03; + break; + default: + ret = jega->regs[jega->regs_index]; + break; + } + jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc); + } else if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */ + ret = ega_in(addr, &jega->ega); + break; + case 0x3ba: + case 0x3da: + jega->attrff = 0; + default: + if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave is redirected to Master in AX-1. */ + ret = ega_in(addr, &jega->ega); + break; + } + // jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc); + return ret; +} + +static int +getfontx2header(FILE *fp, fontx_h *header) +{ + fread(header->id, FONTX_LEN_ID, 1, fp); + if (strncmp(header->id, "FONTX2", FONTX_LEN_ID) != 0) { + return 1; + } + fread(header->name, FONTX_LEN_FN, 1, fp); + header->width = (uint8_t) getc(fp); + header->height = (uint8_t) getc(fp); + header->type = (uint8_t) getc(fp); + return 0; +} + +static uint16_t +chrtosht(FILE *fp) +{ + uint16_t i, j; + i = (uint16_t) getc(fp); + j = (uint16_t) getc(fp) << 8; + return (i | j); +} + +static void +readfontxtbl(fontx_tbl *table, int size, FILE *fp) +{ + while (size > 0) { + table->start = chrtosht(fp); + table->end = chrtosht(fp); + ++table; + --size; + } +} + +static int +LoadFontxFile(const char *fn, void *priv) +{ + fontx_h fhead; + fontx_tbl *ftbl; + uint16_t code; + uint16_t scode; + uint8_t size; + uint8_t buf; + int line; + jega_t *jega = (jega_t *) priv; + FILE *fp = rom_fopen(fn, "rb"); + jega_log("JEGA: Loading font\n"); + if (fp == NULL) { + jega_log("JEGA: font file '%s' not found.\n", fn); + return 0; + } + if (getfontx2header(fp, &fhead) != 0) { + fclose(fp); + jega_log("JEGA: FONTX2 header is incorrect.\n"); + return 1; + } + /* DBCS or SBCS */ + if (fhead.type == 1) { + if (fhead.width == 16 && fhead.height == 16) { + size = getc(fp); + ftbl = (fontx_tbl *) calloc(size, sizeof(fontx_tbl)); + readfontxtbl(ftbl, size, fp); + for (int i = 0; i < size; i++) { + for (code = ftbl[i].start; code <= ftbl[i].end; code++) { + scode = SJIS_to_SEQ(code); + if (scode != INVALIDACCESS16) { + for (line = 0; line < 16; line++) { + fread(&buf, sizeof(uint8_t), 1, fp); + jega->jfont_dbcs_16[(int) (scode * 32) + line] = buf; + fread(&buf, sizeof(uint8_t), 1, fp); + jega->jfont_dbcs_16[(int) (scode * 32) + line + 16] = buf; + } + } else { + fseek(fp, 32, SEEK_CUR); + } + } + } + } else { + fclose(fp); + jega_log("JEGA: Width or height of DBCS font doesn't match.\n"); + return 1; + } + } else { + if (fhead.width == 8 && fhead.height == 19) { + fread(jega->jfont_sbcs_19, sizeof(uint8_t), SBCS19_FILESIZE, fp); + } else { + fclose(fp); + jega_log("JEGA: Width or height of SBCS font doesn't match.\n"); + return 1; + } + } + fclose(fp); + return 0; +} + +static void * +jega_init(const device_t *info) +{ + jega_t *jega = calloc(1, sizeof(jega_t)); + + rom_init(&jega->bios_rom, JEGA_PATH_BIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); + memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); + LoadFontxFile(JEGA_PATH_FONTDBCS, jega); + + for (int c = 0; c < 256; c++) { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + } + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); + jega->pallook = pallook64; + ega_init(&jega->ega, 9, 0); + jega->ega.actual_type = EGA_SUPEREGA; + jega->ega.priv_parent = jega; + mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); + + io_sethandler(0x03b0, 0x0030, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); + + jega->regs[RMOD1] = 0x48; +} + +static void +jega_close(void *priv) +{ + jega_t *jega = (jega_t *) priv; +#ifdef ENABLE_JEGA_LOG + FILE *f; + // f = fopen("jega_font16.dmp", "wb"); + // if (f != NULL) { + // fwrite(jega->jfont_dbcs_16, DBCS16_FILESIZE, 1, f); + // fclose(f); + // } + // f = fopen("jega_font19.dmp", "wb"); + // if (f != NULL) { + // fwrite(jega->jfont_sbcs_19, SBCS19_FILESIZE, 1, f); + // fclose(f); + // } + f = fopen("jega_regs.txt", "wb"); + if (f != NULL) { + for (int i = 0; i < 49; i++) + fprintf(f, "Regs %02X: %4X\n", i, jega->regs[i]); + for (int i = 0; i < 32; i++) + fprintf(f, "Attr %02X: %4X\n", i, jega->attrregs[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "JEGAPal %02X: %4X\n", i, jega->egapal[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "EGAPal %02X: %4X\n", i, jega->ega.egapal[i]); + for (int i = 0; i < 64; i++) + fprintf(f, "RealPal %02X: %4X\n", i, jega->pallook[i]); + fclose(f); + } + // f = fopen("ega_vram.dmp", "wb"); + // if (f != NULL) { + // fwrite(jega->ega.vram, 256 * 1024, 1, f); + // fclose(f); + // } + f = fopen("ram_bda.dmp", "wb"); + if (f != NULL) { + fwrite(&ram[0x0], 0x500, 1, f); + fclose(f); + } + // jega_log("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); +#endif + if (jega->ega.eeprom) + free(jega->ega.eeprom); + free(jega->ega.vram); + free(jega); +} + +static void +jega_recalctimings(void *priv) +{ + jega_t *jega = (jega_t *) priv; + ega_recalctimings(&jega->ega); +} +static void +jega_speed_changed(void *priv) +{ + jega_t *jega = (jega_t *) priv; + + jega_recalctimings(jega); +} + +static int +jega_available(void) +{ + return (rom_present(JEGA_PATH_BIOS) && rom_present(JEGA_PATH_FONTDBCS)); +} + +const device_t jega_device = { + .name = "JEGA", + .internal_name = "jega", + .flags = DEVICE_ISA, + .local = 0, + .init = jega_init, + .close = jega_close, + .reset = NULL, + .available = jega_available, + .speed_changed = jega_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index d1df2ba20..be26d9e18 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -68,6 +68,7 @@ video_cards[] = { { .device = &ati18800_wonder_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &cga_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &sega_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &jega_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5401_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5402_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5420_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, From 4d3e2a3be35606bce7d70275053ef18730c10e42 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Mar 2025 10:38:17 +0900 Subject: [PATCH 144/218] changed rom filename --- src/video/vid_jega.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index ad312faff..b6695893c 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -59,7 +59,7 @@ #define ROMSL 0x2F /* ? */ #define RINVALID_INDEX 0x30 -#define JEGA_PATH_BIOS "roms/video/jega/OKI_IF386AX_VBIOS.bin" +#define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN" #define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" #define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ #define DBCS16_CHARS 0x2c10 From 395f23cf57d608b561f6cdde77d2976e602328b0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 03:12:36 +0100 Subject: [PATCH 145/218] More Cyrix fixes. --- src/cpu/386_common.c | 60 +++++++--- src/cpu/cpu.c | 236 ++++++++++++++++++++++++++-------------- src/cpu/cpu.h | 7 ++ src/cpu/x86_ops_cyrix.h | 208 ++++++++++++++++++++++++++++++----- 4 files changed, 383 insertions(+), 128 deletions(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 5b0e1a5c4..2853e3c9a 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1449,26 +1449,44 @@ enter_smm(int in_hlt) void enter_smm_check(int in_hlt) { - if ((in_smm == 0) && smi_line) { -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SMI while not in SMM\n"); -#endif - enter_smm(in_hlt); - } else if ((in_smm == 1) && smi_line) { - /* Mark this so that we don't latch more than one SMI. */ -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SMI while in unlatched SMM\n"); -#endif - smi_latched = 1; - } else if ((in_smm == 2) && smi_line) { - /* Mark this so that we don't latch more than one SMI. */ -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SMI while in latched SMM\n"); -#endif - } + uint8_t ccr1_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && (cyrix.arr[3].size > 0); + + if (smi_line) { + if (!is_cxsmm || ccr1_check) switch (in_smm) { + default: +#ifdef ENABLE_386_COMMON_LOG + fatal("SMI while in_smm = %i\n", in_smm); + break; +#endif + case 0: +#ifdef ENABLE_386_COMMON_LOG + x386_common_log("SMI while not in SMM\n"); +#endif + enter_smm(in_hlt); + break; + case 1: + /* Mark this so that we don't latch more than one SMI. */ +#ifdef ENABLE_386_COMMON_LOG + x386_common_log("SMI while in unlatched SMM\n"); +#endif + smi_latched = 1; + break; + case 2: +#ifdef ENABLE_386_COMMON_LOG + x386_common_log("SMI while in latched SMM\n"); +#endif + break; + } +#ifdef ENABLE_386_COMMON_LOG + else { + x386_common_log("SMI while in Cyrix disabled mode\n"); + x386_common_log("lol\n"); + } +#endif - if (smi_line) smi_line = 0; + } } void @@ -2186,6 +2204,12 @@ cpu_fast_off_reset(void) void smi_raise(void) { + uint8_t ccr1_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && (cyrix.arr[3].size > 0); + + if (is_cxsmm && !ccr1_check) + return; + if (is486 && (cpu_fast_off_flags & 0x80000000)) cpu_fast_off_advance(); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 0c621bf68..41ca6932d 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -40,6 +40,7 @@ #include <86box/nmi.h> #include <86box/pic.h> #include <86box/pci.h> +#include <86box/smram.h> #include <86box/timer.h> #include <86box/gdbstub.h> #include <86box/plat_fallthrough.h> @@ -50,13 +51,6 @@ #endif /* USE_DYNAREC */ #include "x87_timings.h" -#define CCR1_USE_SMI (1 << 1) -#define CCR1_SMAC (1 << 2) -#define CCR1_SM3 (1 << 7) - -#define CCR3_SMI_LOCK (1 << 0) -#define CCR3_NMI_EN (1 << 1) - enum { CPUID_FPU = (1 << 0), /* On-chip Floating Point Unit */ CPUID_VME = (1 << 1), /* Virtual 8086 mode extensions */ @@ -289,6 +283,10 @@ uint8_t ccr5; uint8_t ccr6; uint8_t ccr7; +uint8_t reg_30 = 0x00; +uint8_t arr[24] = { 0 }; +uint8_t rcr[8] = { 0 }; + static int cyrix_addr; static void cpu_write(uint16_t addr, uint8_t val, void *priv); @@ -2627,6 +2625,23 @@ cpu_ven_reset(void) msr.amd_efer = (cpu_s->cpu_type >= CPU_K6_2C) ? 2ULL : 0ULL; break; + case CPU_Cx6x86MX: + ccr0 = 0x00; + ccr1 = 0x00; + ccr2 = 0x00; + ccr3 = 0x00; + ccr4 = 0x80; + ccr5 = 0x00; + ccr6 = 0x00; + memset(arr, 0x00, 24); + memset(rcr, 0x00, 3); + cyrix.arr[3].base = 0x00; + cyrix.arr[3].size = 0; /* Disabled */ + cyrix.smhr &= ~SMHR_VALID; + CPUID = cpu_s->cpuid_model; + reg_30 = 0xff; + break; + case CPU_PENTIUMPRO: case CPU_PENTIUM2: case CPU_PENTIUM2D: @@ -4237,78 +4252,105 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) picintc(1 << 13); else nmi = 0; - return; - } else if (addr >= 0xf1) - return; /* FPU stuff */ - - if (!(addr & 1)) + } else if ((addr < 0xf1) && !(addr & 1)) cyrix_addr = val; - else - switch (cyrix_addr) { - case 0xc0: /* CCR0 */ - ccr0 = val; - break; - case 0xc1: /* CCR1 */ - if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) - val = (val & ~(CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) | (ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)); - ccr1 = val; - break; - case 0xc2: /* CCR2 */ - ccr2 = val; - break; - case 0xc3: /* CCR3 */ - if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) - val = (val & ~(CCR3_NMI_EN)) | (ccr3 & CCR3_NMI_EN) | CCR3_SMI_LOCK; - ccr3 = val; - break; - case 0xcd: - if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { - cyrix.arr[3].base = (cyrix.arr[3].base & ~0xff000000) | (val << 24); - cyrix.smhr &= ~SMHR_VALID; - } - break; - case 0xce: - if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { - cyrix.arr[3].base = (cyrix.arr[3].base & ~0x00ff0000) | (val << 16); - cyrix.smhr &= ~SMHR_VALID; - } - break; - case 0xcf: - if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { - cyrix.arr[3].base = (cyrix.arr[3].base & ~0x0000f000) | ((val & 0xf0) << 8); - if ((val & 0xf) == 0xf) - cyrix.arr[3].size = 1ULL << 32; /* 4 GB */ - else if (val & 0xf) - cyrix.arr[3].size = 2048 << (val & 0xf); - else - cyrix.arr[3].size = 0; /* Disabled */ - cyrix.smhr &= ~SMHR_VALID; - } - break; + else if (addr < 0xf1) switch (cyrix_addr) { + default: + if (cyrix_addr >= 0xc0) + fatal("Writing unimplemented Cyrix register %02X\n", cyrix_addr); + break; - case 0xe8: /* CCR4 */ - if ((ccr3 & 0xf0) == 0x10) { - ccr4 = val; - if (cpu_s->cpu_type >= CPU_Cx6x86) { - if (val & 0x80) - CPUID = cpu_s->cpuid_model; - else - CPUID = 0; - } + case 0x30: /* ???? */ + reg_30 = val; + break; + + case 0xc0: /* CCR0 */ + ccr0 = val; + break; + case 0xc1: { /* CCR1 */ + uint8_t old = ccr1; + if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) + val = (val & ~(CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) | (ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)); + ccr1 = val; + if ((old ^ ccr1) & (CCR1_SMAC)) { + if (ccr1 & CCR1_SMAC) + smram_backup_all(); + smram_recalc_all(!(ccr1 & CCR1_SMAC)); + } + break; + } case 0xc2: /* CCR2 */ + ccr2 = val; + break; + case 0xc3: /* CCR3 */ + if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) + val = (val & ~(CCR3_NMI_EN)) | (ccr3 & CCR3_NMI_EN) | CCR3_SMI_LOCK; + ccr3 = val; + break; + + case 0xc4 ... 0xcc: + if (ccr5 & 0x20) + arr[cyrix_addr - 0xc4] = val; + break; + case 0xcd: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) { + arr[cyrix_addr - 0xc4] = val; + cyrix.arr[3].base = (cyrix.arr[3].base & ~0xff000000) | (val << 24); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xce: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) { + arr[cyrix_addr - 0xc4] = val; + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x00ff0000) | (val << 16); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xcf: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) { + arr[cyrix_addr - 0xc4] = val; + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x0000f000) | ((val & 0xf0) << 8); + if ((val & 0xf) == 0xf) + cyrix.arr[3].size = 1ULL << 32; /* 4 GB */ + else if (val & 0xf) + cyrix.arr[3].size = 2048 << (val & 0xf); + else + cyrix.arr[3].size = 0; /* Disabled */ + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xd0 ... 0xdb: + if (((ccr3 & 0xf0) == 0x10) && (ccr5 & 0x20)) + arr[cyrix_addr - 0xc4] = val; + break; + + case 0xdc ... 0xe3: + if ((ccr3 & 0xf0) == 0x10) + rcr[cyrix_addr - 0xdc] = val; + break; + + case 0xe8: /* CCR4 */ + if ((ccr3 & 0xf0) == 0x10) { + ccr4 = val; + if (cpu_s->cpu_type >= CPU_Cx6x86) { + if (val & 0x80) + CPUID = cpu_s->cpuid_model; + else + CPUID = 0; } - break; - case 0xe9: /* CCR5 */ - if ((ccr3 & 0xf0) == 0x10) - ccr5 = val; - break; - case 0xea: /* CCR6 */ - if ((ccr3 & 0xf0) == 0x10) - ccr6 = val; - break; - case 0xeb: /* CCR7 */ - ccr7 = val & 5; - break; - } + } + break; + case 0xe9: /* CCR5 */ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /* CCR6 */ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + case 0xeb: /* CCR7 */ + ccr7 = val & 5; + break; + } } static uint8_t @@ -4319,6 +4361,15 @@ cpu_read(uint16_t addr, UNUSED(void *priv)) if (addr == 0xf007) ret = 0x7f; else if ((addr < 0xf0) && (addr & 1)) switch (cyrix_addr) { + default: + if (cyrix_addr >= 0xc0) + fatal("Reading unimplemented Cyrix register %02X\n", cyrix_addr); + break; + + case 0x30: /* ???? */ + ret = reg_30; + break; + case 0xc0: ret = ccr0; break; @@ -4331,14 +4382,36 @@ cpu_read(uint16_t addr, UNUSED(void *priv)) case 0xc3: ret = ccr3; break; + + case 0xc4 ... 0xcc: + if (ccr5 & 0x20) + ret = arr[cyrix_addr - 0xc4]; + break; + case 0xcd ... 0xcf: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) + ret = arr[cyrix_addr - 0xc4]; + break; + case 0xd0 ... 0xdb: + if (((ccr3 & 0xf0) == 0x10) && (ccr5 & 0x20)) + ret = arr[cyrix_addr - 0xc4]; + break; + + case 0xdc ... 0xe3: + if ((ccr3 & 0xf0) == 0x10) + ret = rcr[cyrix_addr - 0xdc]; + break; + case 0xe8: - ret = ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + if ((ccr3 & 0xf0) == 0x10) + ret = ccr4; break; case 0xe9: - ret = ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + if ((ccr3 & 0xf0) == 0x10) + ret = ccr5; break; case 0xea: - ret = ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + if ((ccr3 & 0xf0) == 0x10) + ret = ccr6; break; case 0xeb: ret = ccr7; @@ -4349,11 +4422,8 @@ cpu_read(uint16_t addr, UNUSED(void *priv)) case 0xff: ret = cpu_s->cyrix_id >> 8; break; - - default: - break; } - + return ret; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index d58da6998..80097294d 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -120,6 +120,13 @@ enum { #define CPU_ALTERNATE_XTAL 4 #define CPU_FIXED_MULTIPLIER 8 +#define CCR1_USE_SMI (1 << 1) +#define CCR1_SMAC (1 << 2) +#define CCR1_SM3 (1 << 7) + +#define CCR3_SMI_LOCK (1 << 0) +#define CCR3_NMI_EN (1 << 1) + #if (defined __amd64__ || defined _M_X64) # define LOOKUP_INV -1LL #else diff --git a/src/cpu/x86_ops_cyrix.h b/src/cpu/x86_ops_cyrix.h index ac864cd20..c95d4b038 100644 --- a/src/cpu/x86_ops_cyrix.h +++ b/src/cpu/x86_ops_cyrix.h @@ -35,7 +35,13 @@ opSVDC_common(uint32_t fetchdat) static int opSVDC_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); opSVDC_common(fetchdat); @@ -47,7 +53,13 @@ opSVDC_a16(uint32_t fetchdat) static int opSVDC_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); opSVDC_common(fetchdat); @@ -88,7 +100,13 @@ opRSDC_common(uint32_t fetchdat) static int opRSDC_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); opRSDC_common(fetchdat); @@ -100,7 +118,13 @@ opRSDC_a16(uint32_t fetchdat) static int opRSDC_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); opRSDC_common(fetchdat); @@ -113,7 +137,13 @@ opRSDC_a32(uint32_t fetchdat) static int opSVLDT_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -126,7 +156,13 @@ opSVLDT_a16(uint32_t fetchdat) static int opSVLDT_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -140,7 +176,13 @@ opSVLDT_a32(uint32_t fetchdat) static int opRSLDT_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -152,7 +194,13 @@ opRSLDT_a16(uint32_t fetchdat) static int opRSLDT_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -165,7 +213,13 @@ opRSLDT_a32(uint32_t fetchdat) static int opSVTS_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -178,7 +232,13 @@ opSVTS_a16(uint32_t fetchdat) static int opSVTS_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -192,7 +252,13 @@ opSVTS_a32(uint32_t fetchdat) static int opRSTS_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -205,7 +271,13 @@ opRSTS_a16(uint32_t fetchdat) static int opRSTS_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -219,9 +291,13 @@ opRSTS_a32(uint32_t fetchdat) static int opSMINT(UNUSED(uint32_t fetchdat)) { + uint8_t ccr1_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) && + (cyrix.arr[3].size > 0); + if (in_smm) fatal("opSMINT\n"); - else { + else if (ccr1_check) { is_smint = 1; enter_smm(0); } @@ -232,9 +308,26 @@ opSMINT(UNUSED(uint32_t fetchdat)) static int opRDSHR_a16(UNUSED(uint32_t fetchdat)) { - if (in_smm) - fatal("opRDSHR_a16\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_16(fetchdat); + if (cpu_mod == 3) { + cpu_state.regs[cpu_rm].l = cyrix.smhr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 0); + } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(cyrix.smhr); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0, 0, 0, 1, 0); + } + return cpu_state.abrt; + } else x86illegal(); return 1; @@ -242,30 +335,91 @@ opRDSHR_a16(UNUSED(uint32_t fetchdat)) static int opRDSHR_a32(UNUSED(uint32_t fetchdat)) { - if (in_smm) - fatal("opRDSHR_a32\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_32(fetchdat); + if (cpu_mod == 3) { + cpu_state.regs[cpu_rm].l = cyrix.smhr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 1); + } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(cyrix.smhr); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0, 0, 0, 1, 1); + } + return cpu_state.abrt; + } else x86illegal(); return 1; } static int -opWRSHR_a16(UNUSED(uint32_t fetchdat)) +opWRSHR_a16(uint32_t fetchdat) { - if (in_smm) - fatal("opWRSHR_a16\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_16(fetchdat); + if (cpu_mod == 3) { + cyrix.smhr = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 0); + } else { + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + temp = geteal(); + if (cpu_state.abrt) + return 1; + cyrix.smhr = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0, 1, 0, 0, 0); + } + return 0; + } else x86illegal(); return 1; } static int -opWRSHR_a32(UNUSED(uint32_t fetchdat)) +opWRSHR_a32(uint32_t fetchdat) { - if (in_smm) - fatal("opWRSHR_a32\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_32(fetchdat); + if (cpu_mod == 3) { + cyrix.smhr = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 1); + } else { + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + temp = geteal(); + if (cpu_state.abrt) + return 1; + cyrix.smhr = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0, 1, 0, 0, 1); + } + return 0; + } else x86illegal(); return 1; From 0fd97c8427a252e4994476663846a8eb30a05640 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 04:35:47 +0100 Subject: [PATCH 146/218] MO: Fix medium size in various conditions and fix handling of unsupported media. --- src/disk/mo.c | 30 +++++++++++++++++++++++++----- src/include/86box/mo.h | 2 ++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index e2db4bda3..e5cbd9140 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -18,6 +18,7 @@ * Copyright 2020-2025 Fred N. van Kempen */ #define _GNU_SOURCE +#include #ifdef ENABLE_MO_LOG #include #endif @@ -184,11 +185,14 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) } else dev->drv->base = 0; + dev->drv->supported = 0; + for (uint8_t i = 0; i < KNOWN_MO_TYPES; i++) { if (size == ((uint64_t) mo_types[i].sectors * mo_types[i].bytes_per_sector)) { found = 1; dev->drv->medium_size = mo_types[i].sectors; dev->drv->sector_size = mo_types[i].bytes_per_sector; + dev->drv->supported = mo_drive_types[dev->drv->type].supported_media[i]; break; } } @@ -803,7 +807,12 @@ mo_blocks(mo_t *dev, int32_t *len, const int out) mo_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); - if (dev->sector_pos >= dev->drv->medium_size) { + if (!dev->drv->supported) { + mo_log(dev->log, "Trying to %s an unsupported medium\n", + out ? "write" : "read"); + out ? mo_write_error(dev) : mo_read_error(dev); + ret = 0; + } else if (dev->sector_pos >= dev->drv->medium_size) { mo_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); mo_lba_out_of_range(dev); @@ -955,7 +964,11 @@ mo_erase(mo_t *dev) mo_log(dev->log, "Erasing %i blocks starting from %i...\n", dev->sector_len, dev->sector_pos); - if (dev->sector_pos >= dev->drv->medium_size) { + if (!dev->drv->supported) { + mo_log(dev->log, "Trying to erase an unsupported medium\n"); + mo_write_error(dev); + return 0; + } else if (dev->sector_pos >= dev->drv->medium_size) { mo_log(dev->log, "Trying to erase beyond the end of disk\n"); mo_lba_out_of_range(dev); return 0; @@ -1386,6 +1399,9 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_set_phase(dev, SCSI_PHASE_STATUS); mo_command_complete(dev); break; + } else if (!dev->drv->supported) { + mo_read_error(dev); + break; } fallthrough; case GPCMD_WRITE_6: @@ -1433,7 +1449,9 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) break; } - if (dev->sector_pos > (mo_types[dev->drv->type].sectors - 1)) + if (!dev->drv->supported) + mo_write_error(dev); + else if (dev->sector_pos >= dev->drv->medium_size) mo_lba_out_of_range(dev); else { if (dev->sector_len) { @@ -1473,7 +1491,9 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if (dev->sector_pos > (mo_types[dev->drv->type].sectors - 1)) + if (!dev->drv->supported) + mo_write_error(dev); + else if (dev->sector_pos >= dev->drv->medium_size) mo_lba_out_of_range(dev); else if (dev->sector_len) { mo_buf_alloc(dev, alloc_length); @@ -1834,7 +1854,7 @@ static uint8_t mo_phase_data_out(scsi_common_t *sc) { mo_t * dev = (mo_t *) sc; - const uint32_t last_sector = mo_types[dev->drv->type].sectors - 1; + const uint32_t last_sector = dev->drv->medium_size - 1; int len = 0; uint8_t error = 0; uint32_t last_to_write; diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index e09515b10..f4e7e9809 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -122,6 +122,8 @@ typedef struct mo_drive_t { uint32_t medium_size; uint32_t base; uint16_t sector_size; + + int supported; } mo_drive_t; typedef struct mo_t { From 2cd99f0c705c9a40cbc4a11866c05c03b6704734 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 07:54:54 +0100 Subject: [PATCH 147/218] X86 segmentation: apparently, the CPU can execute a data segment in some cases, used by LINK and CodeView, fixes #5283. --- src/cpu/x86seg.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index 2a0601661..145752237 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -1334,6 +1334,12 @@ pmoderetf(int is32, uint16_t off) if (CPL == (seg & 0x0003)) { x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); switch (segdat[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS LINK for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: @@ -1384,6 +1390,12 @@ pmoderetf(int is32, uint16_t off) cycles -= timing_retf_pm; } else { switch (segdat[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS LINK for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: @@ -1605,6 +1617,12 @@ pmodeint(int num, int soft) return; } switch (segdat2[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS CodeView for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: @@ -1983,6 +2001,12 @@ pmodeiret(int is32) } switch (segdat[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS CodeView for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: From 21bafa37a5aae28aeb63f0e2f2ad4c5a0720d2b1 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:44:03 +0900 Subject: [PATCH 148/218] correct a compile error --- src/video/vid_jega.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index b6695893c..3ff13e85d 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -347,6 +347,7 @@ jega_out(uint16_t addr, uint8_t val, void *priv) { uint8_t o; jega_t *jega = (jega_t *) priv; + uint16_t chr; // jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc); switch (addr) { case 0x3c0: @@ -449,7 +450,7 @@ jega_out(uint16_t addr, uint8_t val, void *priv) jega->start_scan_upper = (val - 64) + 4; break; case RDFAP: - uint16_t chr = jega->regs[RDFFB]; + chr = jega->regs[RDFFB]; if (is_SJIS_1(chr) && chr >= 0xf0 && chr <= 0xf3) { chr <<= 8; chr |= jega->regs[RDFSB]; @@ -477,13 +478,14 @@ jega_in(uint16_t addr, void *priv) { jega_t *jega = (jega_t *) priv; uint8_t ret = INVALIDACCESS8; + uint16_t chr; switch (addr) { case 0x3b5: case 0x3d5: if (jega->regs_index >= 0x20 && jega->regs_index <= 0x2F) { switch (jega->regs_index) { case RDFAP: - uint16_t chr = jega->regs[RDFFB]; + chr = jega->regs[RDFFB]; /* DBCS or SBCS */ if (is_SJIS_1(chr)) { chr <<= 8; From e932bc940df7fcd0c0555f051f486d334e790aed Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 17:48:08 +0100 Subject: [PATCH 149/218] JEGA: Fix warnings. --- src/video/vid_jega.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 3ff13e85d..c410a15da 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -186,7 +186,7 @@ jega_render_text(void *priv) // const bool doublewidth = ((jega->ega.seqregs[1] & 8) != 0); const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */ // const bool attrlinechars = (jega->ega.attrregs[0x10] & 4); - const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || (jega->regs[RMOD1] & 0x80 == 0); + const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || ((jega->regs[RMOD1] & 0x80) == 0); const int charwidth = 8; const bool blinked = jega->ega.blink & 0x10; uint32_t *p = &buffer32->line[jega->ega.displine + jega->ega.y_add][jega->ega.x_add]; @@ -345,7 +345,6 @@ jega_render_text(void *priv) static void jega_out(uint16_t addr, uint8_t val, void *priv) { - uint8_t o; jega_t *jega = (jega_t *) priv; uint16_t chr; // jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc); @@ -362,7 +361,6 @@ jega_out(uint16_t addr, uint8_t val, void *priv) jega_recalctimings(jega); } } else { - o = jega->attrregs[jega->attraddr & 31]; jega->attrregs[jega->attraddr & 31] = val; if (jega->attraddr < 0x10) { for (uint8_t c = 0; c < 16; c++) { @@ -641,6 +639,8 @@ jega_init(const device_t *info) io_sethandler(0x03b0, 0x0030, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); jega->regs[RMOD1] = 0x48; + + return jega; } static void From 00c97dac1ccdd362a6781eedf8ba657ae5634019 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 20 Mar 2025 00:56:13 +0600 Subject: [PATCH 150/218] Add "Five + 2 Wheels" option for horizontal wheel reporting --- src/device/mouse.c | 45 +++++++++++++++++++++++- src/device/mouse_ps2.c | 61 ++++++++++++++++++++++++--------- src/include/86box/mouse.h | 3 ++ src/qt/macos_event_filter.mm | 1 + src/qt/qt_rendererstack.cpp | 2 ++ src/qt/qt_winrawinputfilter.cpp | 7 ++++ 6 files changed, 102 insertions(+), 17 deletions(-) diff --git a/src/device/mouse.c b/src/device/mouse.c index f0446d781..f7d8c9861 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -106,6 +106,7 @@ static mouse_t mouse_devices[] = { static _Atomic double mouse_x; static _Atomic double mouse_y; static atomic_int mouse_z; +static atomic_int mouse_w; static atomic_int mouse_buttons; static int mouse_delta_b; @@ -156,6 +157,7 @@ mouse_clear_coords(void) mouse_clear_y(); mouse_z = 0; + mouse_w = 0; } void @@ -355,6 +357,14 @@ mouse_wheel_moved(void) return ret; } +int +mouse_hwheel_moved(void) +{ + int ret = !!(atomic_load(&mouse_w)); + + return ret; +} + int mouse_moved(void) { @@ -373,13 +383,14 @@ mouse_state_changed(void) int b; int b_mask = (1 << mouse_nbut) - 1; int wheel = (mouse_nbut >= 4); + int hwheel = (mouse_nbut >= 6); int ret; b = atomic_load(&mouse_buttons); mouse_delta_b = (b ^ mouse_old_b); mouse_old_b = b; - ret = mouse_moved() || ((atomic_load(&mouse_z) != 0) && wheel) || (mouse_delta_b & b_mask); + ret = mouse_moved() || ((atomic_load(&mouse_z) != 0) && wheel) || ((atomic_load(&mouse_w) != 0) && hwheel) || (mouse_delta_b & b_mask); return ret; } @@ -475,6 +486,18 @@ mouse_clear_z(void) atomic_store(&mouse_z, 0); } +void +mouse_set_w(int w) +{ + atomic_fetch_add(&mouse_w, w); +} + +void +mouse_clear_w(void) +{ + atomic_store(&mouse_w, 0); +} + void mouse_subtract_z(int *delta_z, int min, int max, int invert) { @@ -495,6 +518,26 @@ mouse_subtract_z(int *delta_z, int min, int max, int invert) atomic_store(&mouse_z, invert ? -real_z : real_z); } +void +mouse_subtract_w(int *delta_w, int min, int max, int invert) +{ + int w = atomic_load(&mouse_w); + int real_w = invert ? -w : w; + + if (real_w > max) { + *delta_w = max; + real_w -= max; + } else if (real_w < min) { + *delta_w = min; + real_w += ABS(min); + } else { + *delta_w = real_w; + real_w = 0; + } + + atomic_store(&mouse_w, invert ? -real_w : real_w); +} + void mouse_set_buttons_ex(int b) { diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 79d7afc96..0d34235fe 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -34,13 +34,15 @@ enum { MODE_ECHO }; -#define FLAG_EXPLORER 0x200 /* Has 5 buttons */ -#define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */ -#define FLAG_INTELLI 0x80 /* device is IntelliMouse */ -#define FLAG_INTMODE 0x40 /* using Intellimouse mode */ -#define FLAG_SCALED 0x20 /* enable delta scaling */ -#define FLAG_ENABLED 0x10 /* dev is enabled for use */ -#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */ +#define FLAG_HWHL 0x800 /* Report horizontal wheel movements. */ +#define FLAG_EXPLORER_HWHL 0x400 /* Has tilt-wheel/horizontal scroll wheel */ +#define FLAG_EXPLORER 0x200 /* Has 5 buttons */ +#define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */ +#define FLAG_INTELLI 0x80 /* device is IntelliMouse */ +#define FLAG_INTMODE 0x40 /* using Intellimouse mode */ +#define FLAG_SCALED 0x20 /* enable delta scaling */ +#define FLAG_ENABLED 0x10 /* dev is enabled for use */ +#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */ #define FIFO_SIZE 16 @@ -82,10 +84,16 @@ ps2_report_coordinates(atkbc_dev_t *dev, int main) int overflow_y; int b = mouse_get_buttons_ex(); int delta_z; + int delta_w; mouse_subtract_coords(&delta_x, &delta_y, &overflow_x, &overflow_y, -256, 255, 1, 0); - mouse_subtract_z(&delta_z, -8, 7, 1); + + if (dev->flags & FLAG_5BTN) + mouse_subtract_z(&delta_z, -32, 31, 1); + else + mouse_subtract_z(&delta_z, -8, 7, 1); + mouse_subtract_w(&delta_w, -1, 1, 0); buff[0] |= (overflow_y << 7) | (overflow_x << 6) | ((delta_y & 0x0100) >> 3) | ((delta_x & 0x0100) >> 4) | @@ -97,10 +105,21 @@ ps2_report_coordinates(atkbc_dev_t *dev, int main) kbc_at_dev_queue_add(dev, buff[1], main); kbc_at_dev_queue_add(dev, buff[2], main); if (dev->flags & FLAG_INTMODE) { - delta_z &= 0x0f; + delta_z &= (dev->flags & FLAG_HWHL) ? 0x3f : 0x0f; if (dev->flags & FLAG_5BTN) { - if (b & 8) + if ((dev->flags & FLAG_HWHL) && (delta_z || delta_w)) + { + if (delta_w) { + delta_z = delta_w; + delta_z &= 0x3f; + delta_z |= 0x40; + } else { + delta_z &= 0x3f; + delta_z |= 0x80; + } + } + else if (b & 8) delta_z |= 0x10; if (b & 16) delta_z |= 0x20; @@ -120,7 +139,7 @@ ps2_set_defaults(atkbc_dev_t *dev) dev->rate = 100; mouse_set_sample_rate(100.0); dev->resolution = 2; - dev->flags &= 0x188; + dev->flags &= 0x688; mouse_scan = 0; } @@ -298,6 +317,13 @@ ps2_write(void *priv) (last_data[2] == 0xf3) && (last_data[3] == 0xc8) && (last_data[4] == 0xf3) && (last_data[5] == 0x50)) dev->flags |= FLAG_5BTN; + + if ((dev->flags & FLAG_5BTN) && (dev->flags & FLAG_EXPLORER_HWHL) && + (last_data[0] == 0xf3) && (last_data[1] == 0xc8) && + (last_data[2] == 0xf3) && (last_data[3] == 0x50) && + (last_data[4] == 0xf3) && (last_data[5] == 0x28)) + dev->flags |= FLAG_HWHL; + } } @@ -336,6 +362,8 @@ mouse_ps2_init(const device_t *info) dev->flags |= FLAG_INTELLI; if (i > 4) dev->flags |= FLAG_EXPLORER; + if (i > 5) + dev->flags |= FLAG_EXPLORER_HWHL; mouse_ps2_log("%s: buttons=%d\n", dev->name, i); @@ -377,11 +405,12 @@ static const device_config_t ps2_config[] = { .file_filter = NULL, .spinner = { 0 }, .selection = { - { .description = "Two", .value = 2 }, - { .description = "Three", .value = 3 }, - { .description = "Wheel", .value = 4 }, - { .description = "Five + Wheel", .value = 5 }, - { .description = "" } + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "Wheel", .value = 4 }, + { .description = "Five + Wheel", .value = 5 }, + { .description = "Five + 2 Wheels", .value = 6 }, + { .description = "" } }, .bios = { { 0 } } }, diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index bbe78413b..333849846 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -100,6 +100,9 @@ extern void mouse_scale_axis(int axis, int val); extern void mouse_set_z(int z); extern void mouse_clear_z(void); extern void mouse_subtract_z(int *delta_z, int min, int max, int invert); +extern void mouse_set_w(int w); +extern void mouse_clear_w(void); +extern void mouse_subtract_w(int *delta_w, int min, int max, int invert); extern void mouse_set_buttons_ex(int b); extern int mouse_get_buttons_ex(void); extern void mouse_set_sample_rate(double new_rate); diff --git a/src/qt/macos_event_filter.mm b/src/qt/macos_event_filter.mm index ff4e7c4d2..45c8ecbe3 100644 --- a/src/qt/macos_event_filter.mm +++ b/src/qt/macos_event_filter.mm @@ -37,6 +37,7 @@ CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, return true; } if ([event type] == NSEventTypeScrollWheel) { + mouse_set_w(-[event deltaX]); mouse_set_z([event deltaY]); return true; } diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 5dc61e03b..aed932e92 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -210,8 +210,10 @@ RendererStack::wheelEvent(QWheelEvent *event) #if !defined(Q_OS_WINDOWS) && !defined(__APPLE__) double numSteps = (double) event->angleDelta().y() / 120.0; + double numStepsW = (double) event->angleDelta().x() / 120.0; mouse_set_z((int) numSteps); + mouse_set_w((int) numStepsW); #endif event->accept(); } diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 8a2841f97..306da575f 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -330,6 +330,7 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) static int x, delta_x; static int y, delta_y; static int b, delta_z; + static int delta_w; b = mouse_get_buttons_ex(); @@ -367,6 +368,12 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) } else delta_z = 0; + if (state.usButtonFlags & RI_MOUSE_HWHEEL) { + delta_w = (SHORT) state.usButtonData / 120; + mouse_set_w(delta_w); + } else + delta_w = 0; + if (state.usFlags & MOUSE_MOVE_ABSOLUTE) { /* absolute mouse, i.e. RDP or VNC * seems to work fine for RDP on Windows 10 From 46f7c7c46f14217f41572b5e77e9b8e328e8b922 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:20:22 +0100 Subject: [PATCH 151/218] MO and ZIP: Fix return length of READ 6/10/12 and actually save the image history into the configuration file. --- src/config.c | 26 ++++++++++++++++++++++++++ src/disk/mo.c | 1 + src/disk/zip.c | 6 ++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/config.c b/src/config.c index 3bb9fb59a..2e6a5460f 100644 --- a/src/config.c +++ b/src/config.c @@ -3011,6 +3011,19 @@ save_other_removable_devices(void) else ini_section_set_string(cat, temp, zip_drives[c].image_path); } + + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + sprintf(temp, "zip_%02i_image_history_%02i", c + 1, i + 1); + if ((zip_drives[c].image_history[i] == 0) || strlen(zip_drives[c].image_history[i]) == 0) + ini_section_delete_var(cat, temp); + else { + path_normalize(zip_drives[c].image_history[i]); + if (!strnicmp(zip_drives[c].image_history[i], usr_path, strlen(usr_path))) + ini_section_set_string(cat, temp, &zip_drives[c].image_history[i][strlen(usr_path)]); + else + ini_section_set_string(cat, temp, zip_drives[c].image_history[i]); + } + } } for (c = 0; c < MO_NUM; c++) { @@ -3054,6 +3067,19 @@ save_other_removable_devices(void) else ini_section_set_string(cat, temp, mo_drives[c].image_path); } + + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + sprintf(temp, "mo_%02i_image_history_%02i", c + 1, i + 1); + if ((mo_drives[c].image_history[i] == 0) || strlen(mo_drives[c].image_history[i]) == 0) + ini_section_delete_var(cat, temp); + else { + path_normalize(mo_drives[c].image_history[i]); + if (!strnicmp(mo_drives[c].image_history[i], usr_path, strlen(usr_path))) + ini_section_set_string(cat, temp, &mo_drives[c].image_history[i][strlen(usr_path)]); + else + ini_section_set_string(cat, temp, mo_drives[c].image_history[i]); + } + } } ini_delete_section_if_empty(config, cat); diff --git a/src/disk/mo.c b/src/disk/mo.c index e5cbd9140..d59343833 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -1363,6 +1363,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_buf_alloc(dev, dev->packet_len); const int ret = mo_blocks(dev, &alloc_length, 0); + alloc_length = dev->requested_blocks * 512; if (ret > 0) { dev->requested_blocks = max_len; diff --git a/src/disk/zip.c b/src/disk/zip.c index ae3319b40..ed59154b0 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -1386,10 +1386,8 @@ zip_command(scsi_common_t *sc, const uint8_t *cdb) dev->packet_len = max_len * alloc_length; zip_buf_alloc(dev, dev->packet_len); - int ret = 0; - - if (dev->sector_len > 0) - ret = zip_blocks(dev, &alloc_length, 0); + const int ret = zip_blocks(dev, &alloc_length, 0); + alloc_length = dev->requested_blocks * 512; if (ret > 0) { dev->requested_blocks = max_len; From a886d8a9f0146907a2689795e2828023ab620300 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:20:55 +0100 Subject: [PATCH 152/218] Forgotten Cyrix-related fixes in mem.c. --- src/mem/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index d1c6de49d..d85b20581 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2370,7 +2370,7 @@ mem_mapping_recalc(uint64_t base, uint64_t size) for (i_c = i_s; i_c <= i_e; i_c += i_a) { for (c = (start + i_c); c < (end + i_c); c += MEM_GRANULARITY_SIZE) { /* CPU */ - n = !!in_smm; + n = (!!in_smm) || (is_cxsmm && (ccr1 & CCR1_SMAC)); wp = _mem_wp[c >> MEM_GRANULARITY_BITS]; if (map->exec && mem_mapping_access_allowed(map->flags, From f74db2660f2a7c2a7eeb1e08e1bf1284c38936b1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:25:49 +0100 Subject: [PATCH 153/218] Fix the exact same READ 10/12/16 bug in scsi_disk.c as well. --- src/scsi/scsi_disk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 878259094..a1afca2e2 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -1095,7 +1095,9 @@ scsi_disk_command(scsi_common_t *sc, const uint8_t *cdb) dev->drv->seek_pos = dev->sector_pos; dev->drv->seek_len = dev->sector_len; - ret = scsi_disk_blocks(dev, &alloc_length, 1, 0); + ret = scsi_disk_blocks(dev, &alloc_length, 1, 0); + alloc_length = dev->requested_blocks * 512; + if (ret > 0) { dev->requested_blocks = max_len; dev->packet_len = alloc_length; From 7575bdc562268f1660cd8bbc35e8aeae383cc167 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:30:58 +0100 Subject: [PATCH 154/218] Fixed the MO part of the fix - do NOT hardcode to 512! --- src/disk/mo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index d59343833..c039695b5 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -1363,7 +1363,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_buf_alloc(dev, dev->packet_len); const int ret = mo_blocks(dev, &alloc_length, 0); - alloc_length = dev->requested_blocks * 512; + alloc_length = dev->requested_blocks * dev->drv->sector_size; if (ret > 0) { dev->requested_blocks = max_len; From a9c97abfb6ac90aff1c0d9ea7cf594a519ff374b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 20 Mar 2025 21:52:48 +0600 Subject: [PATCH 155/218] Pre-calculate `pow` table for FXTRACT instruction --- src/86box.c | 8 ++++++++ src/cpu/cpu.c | 3 +++ src/cpu/x87_ops.h | 2 ++ src/cpu/x87_ops_misc.h | 2 +- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/86box.c b/src/86box.c index 5bf8177e8..310d0b5d3 100644 --- a/src/86box.c +++ b/src/86box.c @@ -32,6 +32,7 @@ #include #include #include +#include #ifndef _WIN32 # include @@ -233,6 +234,8 @@ extern int CPUID; extern int output; int atfullspeed; +extern double exp_pow_table[0x800]; + char exe_path[2048]; /* path (dir) of executable */ char usr_path[1024]; /* path (dir) of user data */ char cfg_path[1024]; /* full path of config file */ @@ -1086,6 +1089,11 @@ pc_init_modules(void) machine_status_init(); + for (c = 0; c <= 0x7ff; c++) { + int64_t exp = c - 1023; /* 1023 = BIAS64 */ + exp_pow_table[c] = pow(2.0, (double) exp); + } + if (do_nothing) { do_nothing = 0; exit(-1); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 41ca6932d..910d40765 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -287,6 +287,9 @@ uint8_t reg_30 = 0x00; uint8_t arr[24] = { 0 }; uint8_t rcr[8] = { 0 }; +/* Table for FXTRACT. */ +double exp_pow_table[0x800]; + static int cyrix_addr; static void cpu_write(uint16_t addr, uint8_t val, void *priv); diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 6a51a2c7f..0bd8209e1 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -36,6 +36,8 @@ extern void fpu_log(const char *fmt, ...); # endif #endif +extern double exp_pow_table[0x800]; + static int rounding_modes[4] = { FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO }; #define ST(x) cpu_state.ST[((cpu_state.TOP + (x)) & 7)] diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 4009eadd6..9a01f7496 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -46,7 +46,7 @@ opFXTRACT(UNUSED(uint32_t fetchdat)) test.eind.d = ST(0); exp80 = test.eind.ll & 0x7ff0000000000000LL; exp80final = (exp80 >> 52) - BIAS64; - mant = test.eind.d / (pow(2.0, (double) exp80final)); + mant = test.eind.d / exp_pow_table[exp80 >> 52]; ST(0) = (double) exp80final; FP_TAG_VALID; x87_push(mant); From 0ebadfb942a3233622a75e85ae3ea34e05053911 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 21 Mar 2025 03:29:46 +0100 Subject: [PATCH 156/218] CD-ROM, ATAPI HDD, MO, and ZIP: correct bus speed arithmetic, makes especially MO and ZIP much faster. --- src/disk/mo.c | 37 +++++++++++++------------------------ src/disk/zip.c | 37 +++++++++++++------------------------ src/scsi/scsi_cdrom.c | 7 ++++--- src/scsi/scsi_disk.c | 7 ++++++- 4 files changed, 36 insertions(+), 52 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index c039695b5..f1cd3b983 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -486,19 +486,16 @@ mo_bus_speed(mo_t *dev) { double ret = -1.0; - if (dev && dev->drv && (dev->drv->bus_type == MO_BUS_SCSI)) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return 0.0; - } else { - if (dev && dev->drv) - ret = ide_atapi_get_period(dev->drv->ide_channel); - if (ret == -1.0) { - if (dev) - dev->callback = -1.0; - return 0.0; - } else - return ret * 1000000.0; + if (dev && dev->drv) + ret = ide_atapi_get_period(dev->drv->ide_channel); + + if (ret == -1.0) { + if (dev) + dev->callback = -1.0; + ret = 0.0; } + + return ret; } static void @@ -509,18 +506,10 @@ mo_command_common(mo_t *dev) dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; - else { - double bytes_per_second; - - if (dev->drv->bus_type == MO_BUS_SCSI) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return; - } else - bytes_per_second = mo_bus_speed(dev); - - const double period = 1000000.0 / bytes_per_second; - dev->callback = period * (double) (dev->packet_len); - } + else if (dev->drv->bus_type == MO_BUS_SCSI) + dev->callback = -1.0; /* Speed depends on SCSI controller */ + else + dev->callback = mo_bus_speed(dev) * (double) (dev->packet_len); mo_set_callback(dev); } diff --git a/src/disk/zip.c b/src/disk/zip.c index ed59154b0..eecafb802 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -567,19 +567,16 @@ zip_bus_speed(zip_t *dev) { double ret = -1.0; - if (dev && dev->drv && (dev->drv->bus_type == ZIP_BUS_SCSI)) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return 0.0; - } else { - if (dev && dev->drv) - ret = ide_atapi_get_period(dev->drv->ide_channel); - if (ret == -1.0) { - if (dev) - dev->callback = -1.0; - return 0.0; - } else - return ret * 1000000.0; + if (dev && dev->drv) + ret = ide_atapi_get_period(dev->drv->ide_channel); + + if (ret == -1.0) { + if (dev) + dev->callback = -1.0; + ret = 0.0; } + + return ret; } static void @@ -590,18 +587,10 @@ zip_command_common(zip_t *dev) dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; - else { - double bytes_per_second; - - if (dev->drv->bus_type == ZIP_BUS_SCSI) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return; - } else - bytes_per_second = zip_bus_speed(dev); - - double period = 1000000.0 / bytes_per_second; - dev->callback = period * (double) (dev->packet_len); - } + else if (dev->drv->bus_type == ZIP_BUS_SCSI) + dev->callback = -1.0; /* Speed depends on SCSI controller */ + else + dev->callback = zip_bus_speed(dev) * (double) (dev->packet_len); zip_set_callback(dev); } diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index b35662eeb..9ae65be74 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -656,7 +656,7 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) dev->callback = -1.0; return 0.0; } else - return ret * 1000000.0; + return 1000000.0 / ret; } } @@ -1069,8 +1069,9 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int dev->block_len = temp_len; if ((dev->drv->bus_type != CDROM_BUS_SCSI) && - (scsi_cdrom_current_mode(dev) != 2)) + (scsi_cdrom_current_mode(dev) != 2)) { num = (dev->packet_len / dev->block_len); + } } dev->sector_pos++; @@ -1126,7 +1127,7 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) } if (ret) { - if (!dev->sector_len) { + if (dev->sector_len == 0) { scsi_cdrom_command_complete(dev); return -1; } diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index a1afca2e2..8528db1fb 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -400,7 +400,8 @@ scsi_disk_bus_speed(scsi_disk_t *dev) dev->callback = -1.0; return 0.0; } else - return ret * 1000000.0; + /* We get bytes per µs, so divide 1000000.0 by it. */ + return 1000000.0 / ret; } } @@ -484,6 +485,10 @@ scsi_disk_command_common(scsi_disk_t *dev) break; } + /* + For ATAPI, this will be 1000000.0 / µs_per_byte, and this will + convert it back to µs_per_byte. + */ period = 1000000.0 / bytes_per_second; scsi_disk_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); From 63f106a0fd888d994dfae60244e36ae718a01551 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 00:49:20 +0100 Subject: [PATCH 157/218] Added plat_break() for raising breakpoints and warning() and log_warning() to raise visible non-fatal warnings to the user. --- src/86box.c | 69 +++++++++++++++++++++++++++++++++++++++ src/include/86box/86box.h | 7 ++-- src/include/86box/log.h | 1 + src/include/86box/plat.h | 1 + src/qt/qt_platform.cpp | 10 ++++++ src/utils/log.c | 25 ++++++++++++++ 6 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/86box.c b/src/86box.c index 310d0b5d3..dbf58a70e 100644 --- a/src/86box.c +++ b/src/86box.c @@ -440,6 +440,75 @@ fatal_ex(const char *fmt, va_list ap) fflush(stdlog); } +/* Log a warning error, and display a UI message without exiting. */ +void +warning(const char *fmt, ...) +{ + char temp[1024]; + va_list ap; + char *sp; + + va_start(ap, fmt); + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + va_end(ap); + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) + *sp = '\0'; + + do_pause(2); + + ui_msgbox(MBX_ERROR | MBX_ANSI, temp); + + fflush(stdlog); + + do_pause(0); +} + +void +warning_ex(const char *fmt, va_list ap) +{ + char temp[1024]; + char *sp; + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) + *sp = '\0'; + + do_pause(2); + + ui_msgbox(MBX_ERROR | MBX_ANSI, temp); + + fflush(stdlog); + + do_pause(0); +} + #ifdef ENABLE_PC_LOG int pc_do_log = ENABLE_PC_LOG; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 40e1f7927..174685c34 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -194,15 +194,12 @@ extern __thread int is_cpu_thread; /* Is this the CPU thread? */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list ap); extern void fatal_ex(const char *fmt, va_list ap); +extern void warning_ex(const char *fmt, va_list ap); #endif extern void pclog_toggle_suppr(void); -#ifdef _MSC_VER -extern void pclog(const char *fmt, ...); -extern void fatal(const char *fmt, ...); -#else extern void pclog(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void fatal(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -#endif +extern void warning(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void set_screen_size(int x, int y); extern void set_screen_size_monitor(int x, int y, int monitor_index); extern void reset_screen_size(void); diff --git a/src/include/86box/log.h b/src/include/86box/log.h index a37bdec4f..e247ef9c5 100644 --- a/src/include/86box/log.h +++ b/src/include/86box/log.h @@ -36,6 +36,7 @@ extern void log_out(void *priv, const char *fmt, va_list); extern void log_out_cyclic(void* priv, const char *fmt, va_list); #endif /*RELEASE_BUILD*/ extern void log_fatal(void *priv, const char *fmt, ...); +extern void log_warning(void *priv, const char *fmt, ...); extern void *log_open(const char *dev_name); extern void *log_open_cyclic(const char *dev_name); extern void log_close(void *priv); diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 81874685e..7ed6e80d4 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -164,6 +164,7 @@ extern uint32_t plat_language_code(char *langcode); extern void plat_language_code_r(uint32_t lcid, char *outbuf, int len); extern void plat_get_cpu_string(char *outbuf, uint8_t len); extern void plat_set_thread_name(void *thread, const char *name); +extern void plat_break(void); /* Resource management. */ extern wchar_t *plat_get_string(int id); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index ebd6dc30c..1364750b1 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -842,3 +842,13 @@ plat_set_thread_name(void *thread, const char *name) # endif #endif } + +void +plat_break(void) +{ +#ifdef Q_OS_WINDOWS + DebugBreak(); +#else + raise(SIGTRAP); +#endif +} diff --git a/src/utils/log.c b/src/utils/log.c index c8dddf62e..257029b51 100644 --- a/src/utils/log.c +++ b/src/utils/log.c @@ -294,6 +294,31 @@ log_fatal(void *priv, const char *fmt, ...) exit(-1); } +void +log_warning(void *priv, const char *fmt, ...) +{ + log_t *log = (log_t *) priv; + char temp[1024]; + char fmt2[1024]; + va_list ap; + + if (log == NULL) + return; + + if (log->cyclic_buff != NULL) { + for (int i = 0; i < LOG_SIZE_BUFFER_CYCLIC_LINES; i++) + if (log->cyclic_buff[i] != NULL) + free(log->cyclic_buff[i]); + free(log->cyclic_buff); + } + + va_start(ap, fmt); + log_copy(log, fmt2, fmt, 1024); + vsprintf(temp, fmt2, ap); + warning_ex(fmt2, ap); + va_end(ap); +} + static void * log_open_common(const char *dev_name, const int cyclic) { From 81141c574ceb25b20faf221ba0877d2becb24530 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 02:14:31 +0100 Subject: [PATCH 158/218] #include on non-Windows platforms. --- src/qt/qt_platform.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 1364750b1..0df64c4dc 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -54,6 +54,10 @@ #include "qt_progsettings.hpp" #include "qt_util.hpp" +#ifndef Q_OS_WINDOWS +# include +#endif + #ifdef Q_OS_UNIX # include # include From 50e77917d5309ea69a606a3c8af03be15a9447c8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 23 Mar 2025 00:42:51 +0900 Subject: [PATCH 159/218] Fix for NetBSD --- src/CMakeLists.txt | 4 ++++ src/include/86box/86box.h | 5 +++++ src/include/86box/bswap.h | 6 ++---- src/include/86box/log.h | 5 +++++ src/qt/qt_platform.cpp | 2 +- src/unix/unix_serial_passthrough.c | 4 ++++ 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aac413aae..8cf67043f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -263,3 +263,7 @@ else() add_compile_definitions(USE_SDL_UI) add_subdirectory(unix) endif() + +if(CMAKE_SYSTEM_NAME MATCHES "NetBSD") + add_custom_command(TARGET 86Box POST_BUILD COMMAND paxctl ARGS +m $ COMMENT "Disable PaX MPROTECT") +endif() diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 174685c34..e8c5fbac9 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -20,6 +20,11 @@ #ifndef EMU_86BOX_H #define EMU_86BOX_H +#ifdef __NetBSD__ +/* Doesn't compile on NetBSD without this include */ +#include +#endif + /* Configuration values. */ #define GFXCARD_MAX 2 #define SERIAL_MAX 7 diff --git a/src/include/86box/bswap.h b/src/include/86box/bswap.h index 37c846d59..61a6a46a2 100644 --- a/src/include/86box/bswap.h +++ b/src/include/86box/bswap.h @@ -35,13 +35,12 @@ * USA. */ -#ifndef __NetBSD__ - #ifndef BSWAP_H #define BSWAP_H #include +#ifndef __NetBSD__ #define bswap_16(x) \ ((uint16_t)((((x) & 0x00ffu) << 8) | \ (((x) & 0xff00u) >> 8))) @@ -91,6 +90,7 @@ bswap64(uint64_t x) return bswap_16(x); #endif } +#endif static __inline void bswap16s(uint16_t *s) @@ -241,5 +241,3 @@ cpu_to_be32wu(uint32_t *p, uint32_t v) #undef be_bswaps #endif /*BSWAP_H*/ - -#endif diff --git a/src/include/86box/log.h b/src/include/86box/log.h index e247ef9c5..80ed6d108 100644 --- a/src/include/86box/log.h +++ b/src/include/86box/log.h @@ -24,6 +24,11 @@ extern "C" { # endif +#ifdef __NetBSD__ +/* Doesn't compile on NetBSD without this include */ +#include +#endif + #define LOG_SIZE_BUFFER 1024 /* Log size buffer */ #define LOG_SIZE_BUFFER_CYCLIC_LINES 32 /* Cyclic log size buffer (number of lines that should be cehcked) */ #define LOG_MINIMUM_REPEAT_ORDER 4 /* Minimum repeat size */ diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 0df64c4dc..e8a02fc3b 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -836,7 +836,7 @@ plat_set_thread_name(void *thread, const char *name) # if defined(Q_OS_DARWIN) pthread_setname_np(truncated); # elif defined(Q_OS_NETBSD) - pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, "%s"); + pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, (void*)"%s"); # elif defined(__HAIKU__) rename_thread(find_thread(NULL), truncated); # elif defined(Q_OS_OPENBSD) diff --git a/src/unix/unix_serial_passthrough.c b/src/unix/unix_serial_passthrough.c index a12346013..9929f3298 100644 --- a/src/unix/unix_serial_passthrough.c +++ b/src/unix/unix_serial_passthrough.c @@ -26,6 +26,7 @@ #endif #ifdef __NetBSD__ # define _NETBSD_VISIBLE 1 +# define _NETBSD_SOURCE 1 #endif #include #include @@ -149,8 +150,11 @@ plat_serpt_set_params(void *priv) BAUDRATE_RANGE(dev->baudrate, 9600, 19200, B9600); BAUDRATE_RANGE(dev->baudrate, 19200, 38400, B19200); BAUDRATE_RANGE(dev->baudrate, 38400, 57600, B38400); +#ifndef __NetBSD__ + /* nonexistent on NetBSD */ BAUDRATE_RANGE(dev->baudrate, 57600, 115200, B57600); BAUDRATE_RANGE(dev->baudrate, 115200, 0xFFFFFFFF, B115200); +#endif term_attr.c_cflag &= ~CSIZE; switch (dev->data_bits) { From a19c99eb64c85a455ad81a693fc46e5919ff5db8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 23 Mar 2025 01:19:57 +0900 Subject: [PATCH 160/218] Fix JP translation --- src/qt/languages/ja-JP.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 9c6fa66e7..6132a8db1 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -868,7 +868,7 @@ msgid "Hardware not available" msgstr "ハードウェアが利用できません" msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." -msgstr "がインストールされてるか、%1に対応したネットワークに接続されてるか確認してください。" +msgstr "%1がインストールされていてかつ、%1に対応したネットワークに接続されてるか確認してください。" msgid "Invalid configuration" msgstr "不正な設定です" @@ -910,10 +910,10 @@ msgid "OpenGL options" msgstr "OpenGL設定" msgid "You are loading an unsupported configuration" -msgstr "読み込んでいる設定がサポートされません" +msgstr "サポートされていないコンフィグを読み込んでいます" msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." -msgstr "選択したマシンに基づくCPUタイプのフィルター機能は、使用中のマシンでは無効になっています。\n\nこれにより、選択したマシンと互換性のないCPUが選択できます。しかし、マシンのBIOSや他のソフトウェアと互換性がない場合があります。\n\nこの設定を有効にすることは公式にはサポートされておらず、バグレポートは無効として中止される可能性があります。" +msgstr "選択したマシンに基づくCPUタイプのフィルター機能は、使用中のマシンでは無効になっています。\n\nこれにより、選択したマシンと互換性のないCPUが選択できます。しかし、マシンのBIOSや他のソフトウェアと互換性がない場合があります。\n\nこの設定を有効にすることは公式にはサポートされておらず、バグレポートは無効としてクローズされる可能性があります。" msgid "Continue" msgstr "続行" @@ -1015,7 +1015,7 @@ msgid "The selected file will be overwritten. Are you sure you want to use it?" msgstr "選択したファイルは上書きされます。よろしいですか?" msgid "Unsupported disk image" -msgstr "非対応のディスクイメージジ" +msgstr "非対応のディスクイメージ" msgid "Overwrite" msgstr "上書き" @@ -1285,7 +1285,7 @@ msgid "Host CD/DVD Drive (%1)" msgstr "ホスト CD/DVD ドライブ (%1)" msgid "Unknown Bus" -msgstr "不明バス" +msgstr "不明なバス" msgid "Null Driver" msgstr "ヌル・ドライバー" @@ -1294,7 +1294,7 @@ msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" msgid "Error opening \"%1\": %2" -msgstr "エラー・オープニング\"%1\": %2" +msgstr "\"%1\"を開く際にエラーが発生しました: %2" msgid "Error compiling vertex shader in file \"%1\"" msgstr "ファイル\"%1\"の頂点シェーダのコンパイルエラー。" From c3d15ef36d183cb54df75466de5bb26fd38ce8d8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 19:45:32 +0100 Subject: [PATCH 161/218] EGA and JEGA: Implement some missing SuperEGA stuff and make the JEGA properly set the EGA type to SuperEGA, fixes #5370. --- src/include/86box/vid_ega.h | 1 + src/video/vid_ega.c | 69 +++++++++++++++++++++++++++++++++---- src/video/vid_jega.c | 2 +- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 082cb120a..5ff7d3871 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -178,6 +178,7 @@ extern uint8_t ega_in(uint16_t addr, void *priv); extern void ega_poll(void *priv); extern void ega_write(uint32_t addr, uint8_t val, void *priv); extern uint8_t ega_read(uint32_t addr, void *priv); +extern void ega_set_type(void *priv, uint32_t local); extern int firstline_draw; extern int lastline_draw; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 781e9a9dd..18a53a127 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -67,6 +67,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega_t *ega = (ega_t *) priv; uint8_t o; uint8_t old; + uint8_t gdcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x0f; + uint8_t crtcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x1f; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -200,8 +202,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->gdcaddr = val; break; case 0x3cf: - ega->gdcreg[ega->gdcaddr & 15] = val; - switch (ega->gdcaddr & 15) { + ega->gdcreg[ega->gdcaddr & gdcmask] = val; + switch (ega->gdcaddr & gdcmask) { case 2: ega->colourcompare = val; break; @@ -238,6 +240,19 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->colournocare = val; break; + case 0xf8: + ega->la = val; + break; + case 0xf9: + ega->lb = val; + break; + case 0xfa: + ega->lc = val; + break; + case 0xfb: + ega->ld = val; + break; + default: break; } @@ -247,7 +262,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) if (ega->chipset) ega->crtcreg = val & 0x3f; else - ega->crtcreg = val & 0x1f; + ega->crtcreg = val & crtcmask; return; case 0x3d1: case 0x3d5: @@ -286,7 +301,8 @@ uint8_t ega_in(uint16_t addr, void *priv) { ega_t *ega = (ega_t *) priv; - uint8_t ret = 0xff; + uint8_t gdcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x0f; + uint8_t ret = 0xff; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -347,8 +363,25 @@ ega_in(uint16_t addr, void *priv) ret = ega->gdcaddr; break; case 0x3cf: - if (ega_type == EGA_TYPE_OTHER) - ret = ega->gdcreg[ega->gdcaddr & 0xf]; + if (ega_type == EGA_TYPE_OTHER) { + switch (ega->gdcaddr & gdcmask) { + default: + ret = ega->gdcreg[ega->gdcaddr & gdcmask]; + break; + case 0xf8: + ret = ega->la; + break; + case 0xf9: + ret = ega->lb; + break; + case 0xfa: + ret = ega->lc; + break; + case 0xfb: + ret = ega->ld; + break; + } + } break; case 0x3d0: case 0x3d4: @@ -1428,6 +1461,30 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) timer_add(&ega->dot_timer, ega_dot_poll, ega, 1); } +void +ega_set_type(void *priv, uint32_t local) +{ + ega_t *ega = (ega_t *) priv; + + if ((local == EGA_IBM) || (local == EGA_ISKRA) || (local == EGA_TSENG)) + ega_type = EGA_TYPE_IBM; + else if (local == EGA_COMPAQ) + ega_type = EGA_TYPE_COMPAQ; + else + ega_type = EGA_TYPE_OTHER; + + ega->actual_type = local; + ega->chipset = 0; + + switch (local) { + default: + break; + case EGA_ATI800P: + ega->chipset = 1; + break; + } +} + static void * ega_standalone_init(const device_t *info) { diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index c410a15da..145579cf5 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -632,7 +632,7 @@ jega_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); jega->pallook = pallook64; ega_init(&jega->ega, 9, 0); - jega->ega.actual_type = EGA_SUPEREGA; + ega_set_type(&jega->ega, EGA_SUPEREGA); jega->ega.priv_parent = jega; mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); From 5fe9cc76da31fdef1bf598967d7db565ed12d480 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 20:44:56 +0100 Subject: [PATCH 162/218] SuperEGA: Increase the GDC and CRTC register arrays to 256 elements to prevent overflows and correctly ignore the upper 3 bits of CRTC register 07h in ega_recalctimings(), fixes #4905. --- src/video/vid_ega.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 18a53a127..17fea7b81 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -486,19 +486,19 @@ ega_recalctimings(ega_t *ega) if (ega->crtc[7] & 1) ega->vtotal |= 0x100; - if (ega->crtc[7] & 32) + if ((ega->actual_type != EGA_SUPEREGA) && (ega->crtc[7] & 32)) ega->vtotal |= 0x200; ega->vtotal += 2; if (ega->crtc[7] & 2) ega->dispend |= 0x100; - if (ega->crtc[7] & 64) + if ((ega->actual_type != EGA_SUPEREGA) && (ega->crtc[7] & 64)) ega->dispend |= 0x200; ega->dispend++; if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; - if (ega->crtc[7] & 128) + if ((ega->actual_type != EGA_SUPEREGA) && (ega->crtc[7] & 128)) ega->vsyncstart |= 0x200; ega->vsyncstart++; From fb0704de993e36efce50ec731df13386a696c4d6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 21:23:07 +0100 Subject: [PATCH 163/218] Forgot vid_ega.h. --- src/include/86box/vid_ega.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 5ff7d3871..79375a2ae 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -47,8 +47,8 @@ typedef struct ega_t { uint8_t ctl_mode; uint8_t color_mux; uint8_t dot; - uint8_t crtc[32]; - uint8_t gdcreg[16]; + uint8_t crtc[256]; + uint8_t gdcreg[256]; uint8_t attrregs[32]; uint8_t seqregs[64]; uint8_t egapal[16]; From 2151a6064feaa9293889a5c014534ff1925b9e58 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 23:57:05 +0100 Subject: [PATCH 164/218] SuperEGA: Implement row and vertical divide modes. --- src/include/86box/vid_ega.h | 1 + src/video/vid_ega.c | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 79375a2ae..4b7d32ea0 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -73,6 +73,7 @@ typedef struct ega_t { int oddeven_page; int oddeven_chain; int vc; + int real_vc; int sc; int dispon; int hdisp_on; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 17fea7b81..c7345cd00 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -620,11 +620,15 @@ ega_recalctimings(ega_t *ega) ega->y_add >>= 1; if (ega->seqregs[1] & 8) { - disptime = (double) ((ega->crtc[0] + 2) << 1); - _dispontime = (double) ((ega->crtc[1] + 1) << 1); + disptime = (double) ((ega->crtc[0] + 2) << 1); + _dispontime = (double) ((ega->crtc[1] + 1) << 1); } else { - disptime = (double) (ega->crtc[0] + 2); - _dispontime = (double) (ega->crtc[1] + 1); + disptime = (double) (ega->crtc[0] + 2); + _dispontime = (double) (ega->crtc[1] + 1); + } + if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0xf9] & 0x01)) { + disptime *= 2.0; + _dispontime *= 2.0; } _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; @@ -852,7 +856,10 @@ ega_poll(void *priv) ega->cca = ega->maback; } } - ega->vc++; + ega->real_vc++; + if ((ega->actual_type != EGA_SUPEREGA) || !(ega->crtc[0xf9] & 0x02) || + !(ega->real_vc & 1)) + ega->vc++; if (ega->chipset) { if (ega->hdisp > 640) ega->vc &= 1023; @@ -905,9 +912,13 @@ ega_poll(void *priv) if (ega->vres) { wy = (ega->lastline - ega->firstline) << 1; + if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0xf9] & 0x02)) + wy >>= 1; ega_doblit(wx, wy, ega); } else { wy = ega->lastline - ega->firstline; + if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0xf9] & 0x02)) + wy >>= 1; ega_doblit(wx, wy, ega); } From 646e25f1bc524f21fc6a74045986142652c1cb21 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 02:22:10 +0100 Subject: [PATCH 165/218] EGA: Implement monochrome attributes for text mode. --- src/video/vid_ega.c | 20 ++++++++++++++++++++ src/video/vid_ega_render.c | 12 ++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index c7345cd00..438d5c98d 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -1447,6 +1447,26 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) ega->pallook = pallook16; + for (uint16_t c = 0; c < 256; c++) { + ega->mdacols[c][0][0] = ega->mdacols[c][1][0] = ega->mdacols[c][1][1] = 16; + if (c & 8) + ega->mdacols[c][0][1] = 15 + 16; + else + ega->mdacols[c][0][1] = 7 + 16; + } + ega->mdacols[0x70][0][1] = 16; + ega->mdacols[0x70][0][0] = ega->mdacols[0x70][1][0] = ega->mdacols[0x70][1][1] = 16 + 15; + ega->mdacols[0xF0][0][1] = 16; + ega->mdacols[0xF0][0][0] = ega->mdacols[0xF0][1][0] = ega->mdacols[0xF0][1][1] = 16 + 15; + ega->mdacols[0x78][0][1] = 16 + 7; + ega->mdacols[0x78][0][0] = ega->mdacols[0x78][1][0] = ega->mdacols[0x78][1][1] = 16 + 15; + ega->mdacols[0xF8][0][1] = 16 + 7; + ega->mdacols[0xF8][0][0] = ega->mdacols[0xF8][1][0] = ega->mdacols[0xF8][1][1] = 16 + 15; + ega->mdacols[0x00][0][1] = ega->mdacols[0x00][1][1] = 16; + ega->mdacols[0x08][0][1] = ega->mdacols[0x08][1][1] = 16; + ega->mdacols[0x80][0][1] = ega->mdacols[0x80][1][1] = 16; + ega->mdacols[0x88][0][1] = ega->mdacols[0x88][1][1] = 16; + egaswitches = monitor_type & 0xf; ega->vram_limit = 256 * 1024; diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index fe2632574..d499154e6 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -118,6 +118,7 @@ ega_render_text(ega_t *ega) const bool doublewidth = ((ega->seqregs[1] & 8) != 0); const bool attrblink = ((ega->attrregs[0x10] & 8) != 0); const bool attrlinechars = (ega->attrregs[0x10] & 4); + const bool monoattrs = (ega->attrregs[0x10] & 2); const bool crtcreset = ((ega->crtc[0x17] & 0x80) == 0); const bool seq9dot = ((ega->seqregs[1] & 1) == 0); const int dwshift = doublewidth ? 1 : 0; @@ -174,8 +175,15 @@ ega_render_text(ega_t *ega) if ((chr & ~0x1F) == 0xC0 && attrlinechars) dat |= (dat >> 1) & 1; - for (int xx = 0; xx < charwidth; xx++) - p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg; + for (int xx = 0; xx < charwidth; xx++) { + if (monoattrs) { + if ((ega->sc == (ega->crtc[0x14] + 1)) && ((attr & 7) == 1)) + p[xx] = ega->mdacols[attr][attrblink][1]; + else + p[xx] = ega->mdacols[attr][attrblink][dat & (0x100 >> (xx >> dwshift))]; + } else + p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg; + } ega->ma += 4; p += charwidth; From ae60590133a28a873ef5d974ff6d52db34bdf0ea Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 02:26:03 +0100 Subject: [PATCH 166/218] EGA: Fix underline position. --- src/video/vid_ega_render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index d499154e6..af2402414 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -177,7 +177,7 @@ ega_render_text(ega_t *ega) for (int xx = 0; xx < charwidth; xx++) { if (monoattrs) { - if ((ega->sc == (ega->crtc[0x14] + 1)) && ((attr & 7) == 1)) + if ((ega->sc == ega->crtc[0x14]) && ((attr & 7) == 1)) p[xx] = ega->mdacols[attr][attrblink][1]; else p[xx] = ega->mdacols[attr][attrblink][dat & (0x100 >> (xx >> dwshift))]; From 47aa4a1e1881bbe669f477399f3f2bc6d9d83c3b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 02:29:41 +0100 Subject: [PATCH 167/218] EGA: Process the results of the monochrome attributes into 32-bit RGB values. --- src/video/vid_ega_render.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index af2402414..dd393e4b6 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -189,6 +189,9 @@ ega_render_text(ega_t *ega) p += charwidth; } ega->ma &= 0x3ffff; + + if (monoattrs) + video_process_8(ega->hdisp + ega->scrollcache, ega->displine); } } From 2ff31188c2ae62475e5c04f1886c7b9c131ec5ab Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 06:57:40 +0100 Subject: [PATCH 168/218] CGA: Fix rounding in the interpolation calculation. --- src/video/vid_cga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index f439cb1d8..a24162019 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -442,7 +442,7 @@ cga_interpolate_linear(uint8_t co1, uint8_t co2, double fraction) r2 = pow((r1 >= 0.0) ? r1 : -r1, 1.0 / 2.19921875); if (r1 <= 0.0) r2 = -r2; - ret = (uint8_t) (r2 * 255.0); + ret = (uint8_t) round(r2 * 255.0); return ret; } From c5efce619f49b58a67ed45123c970bb43d4dd275 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 07:14:52 +0100 Subject: [PATCH 169/218] And the forgotten vid_ega.h. --- src/include/86box/vid_ega.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 4b7d32ea0..5ac5c24e3 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -53,7 +53,6 @@ typedef struct ega_t { uint8_t seqregs[64]; uint8_t egapal[16]; uint8_t regs[256]; - uint8_t *vram; uint16_t light_pen; @@ -114,6 +113,9 @@ typedef struct ega_t { int remap_required; int actual_type; int chipset; + int mono_display; + + int mdacols[256][2][2]; uint32_t charseta; uint32_t charsetb; From c65b7bda6621b4ba98cbf4bc24f3d4d477dcb3de Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Sun, 23 Mar 2025 14:26:07 +0100 Subject: [PATCH 170/218] IBM PS/2 Model 30-286 fixes the real machine supports 512 KB RAM configurations and ISA video cards --- src/machine/machine_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bae9de29f..c253bc029 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2756,11 +2756,11 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PS2, - .flags = MACHINE_XTA | MACHINE_VIDEO_FIXED, + .flags = MACHINE_XTA | MACHINE_VIDEO, .ram = { - .min = 1024, + .min = 512, .max = 16384, - .step = 1024 + .step = 512 }, .nvrmask = 127, .kbc_device = NULL, From 609f34cc492ad670bcba59f11c3092a156b3d628 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 15:36:05 +0100 Subject: [PATCH 171/218] Only flush write MMU cache on WP flag toggle as read and execute MMU cache is not affected by the flag. --- src/cpu/x86_ops_mov_ctrl.h | 10 ++++++---- src/cpu/x86_ops_mov_ctrl_2386.h | 10 ++++++---- src/include/86box/mem.h | 1 + src/mem/mem.c | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index b4f0c498a..253dc059e 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -184,7 +184,7 @@ opMOV_CRx_r_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { if (is_p6 || cpu_use_dynarec) @@ -193,7 +193,8 @@ opMOV_CRx_r_a16(uint32_t fetchdat) flushmmucache_nopc(); cpu_flush_pending = 1; } - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; @@ -249,7 +250,7 @@ opMOV_CRx_r_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { if (is_p6 || cpu_use_dynarec) @@ -258,7 +259,8 @@ opMOV_CRx_r_a32(uint32_t fetchdat) flushmmucache_nopc(); cpu_flush_pending = 1; } - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; diff --git a/src/cpu/x86_ops_mov_ctrl_2386.h b/src/cpu/x86_ops_mov_ctrl_2386.h index 13e08a145..8827d29b2 100644 --- a/src/cpu/x86_ops_mov_ctrl_2386.h +++ b/src/cpu/x86_ops_mov_ctrl_2386.h @@ -180,12 +180,13 @@ opMOV_CRx_r_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { flushmmucache_nopc(); cpu_flush_pending = 1; - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; @@ -241,12 +242,13 @@ opMOV_CRx_r_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { flushmmucache_nopc(); cpu_flush_pending = 1; - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 19a331925..81b46b2fa 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -448,6 +448,7 @@ extern void mem_flush_write_page(uint32_t addr, uint32_t virt); extern void mem_reset_page_blocks(void); extern void flushmmucache(void); +extern void flushmmucache_write(void); extern void flushmmucache_pc(void); extern void flushmmucache_nopc(void); diff --git a/src/mem/mem.c b/src/mem/mem.c index d85b20581..94c4ab788 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -225,6 +225,21 @@ flushmmucache(void) #endif } +void +flushmmucache_write(void) +{ + for (uint16_t c = 0; c < 256; c++) { + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + page_lookupp[writelookup[c]] = 4; + writelookup2[writelookup[c]] = LOOKUP_INV; + writelookupp[writelookup[c]] = 4; + writelookup[c] = 0xffffffff; + } + } + mmuflush++; +} + void flushmmucache_pc(void) { From 8cc81683f7da568a4d7bad14889eb0370d887797 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Sun, 23 Mar 2025 15:48:47 +0100 Subject: [PATCH 172/218] Change back to fixed video, apparently 86Box had it set to fixed due to bugs in 86Box itself --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index c253bc029..b38e42310 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2756,7 +2756,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PS2, - .flags = MACHINE_XTA | MACHINE_VIDEO, + .flags = MACHINE_XTA | MACHINE_VIDEO_FIXED, .ram = { .min = 512, .max = 16384, From 97707a9831d1b435b32d36a6cd24251dfefb4c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 23 Mar 2025 16:18:48 +0100 Subject: [PATCH 173/218] net_modem: fix response to unrecognized will/wont telnet commands --- src/network/net_modem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/network/net_modem.c b/src/network/net_modem.c index a8eab4290..af97a16db 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -1177,9 +1177,15 @@ modem_process_telnet(modem_t *modem, uint8_t *data, uint32_t size) uint8_t c = data[i]; if (modem->telClient.inIAC) { if (modem->telClient.recCommand) { + modem_log("modem_process_telnet: received command %i, option %i\n", modem->telClient.command, c); + if ((c != 0) && (c != 1) && (c != 3)) { - if (modem->telClient.command > 250) { - /* Reject anything we don't recognize */ + /* Reject anything we don't recognize */ + if (modem->telClient.command == 251 || modem->telClient.command == 252) { + modem_data_mode_process_byte(modem, 0xff); + modem_data_mode_process_byte(modem, 254); + modem_data_mode_process_byte(modem, c); /* Don't do crap! */ + } else if (modem->telClient.command == 253 || modem->telClient.command == 254) { modem_data_mode_process_byte(modem, 0xff); modem_data_mode_process_byte(modem, 252); modem_data_mode_process_byte(modem, c); /* We won't do crap! */ From 512c04c9f4443f7a1c3b7147d13acb18819de04f Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Mar 2025 00:56:34 +0900 Subject: [PATCH 174/218] Add OKI if386AX emulation (#7) * add a machine oki if386ax * if386AX: still in debug * Revert "if386AX: still in debug" This reverts commit ade401beb0c72cee6fd1ec4728097a87e75bc09b. * if386ax: added I/O 6xh * if386ax: remove comment * formatting, sorting, change filename * change mono color palette --- src/include/86box/machine.h | 1 + src/include/86box/video.h | 3 + src/machine/m_at_286_386sx.c | 25 +++++ src/machine/machine_table.c | 38 ++++++++ src/video/vid_ega.c | 6 +- src/video/vid_jega.c | 171 ++++++++++++++++++++++++++++++----- 6 files changed, 216 insertions(+), 28 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index d1257d94c..21e4a89e2 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -483,6 +483,7 @@ extern int machine_at_adi386sx_init(const machine_t *); extern int machine_at_cmdsl386sx16_init(const machine_t *); extern int machine_at_cmdsl386sx25_init(const machine_t *); extern int machine_at_dataexpert386sx_init(const machine_t *); +extern int machine_at_if386sx_init(const machine_t *); extern int machine_at_spc6033p_init(const machine_t *); extern int machine_at_wd76c10_init(const machine_t *); extern int machine_at_arb1374_init(const machine_t *); diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 2985559e1..6cf9c8d59 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -456,6 +456,9 @@ extern const device_t millennium_ii_device; extern const device_t productiva_g100_device; #endif /* USE_G100 */ +/* JEGA */ +extern const device_t if386jega_device; + /* Oak OTI-0x7 */ extern const device_t oti037c_device; extern const device_t oti067_device; diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index fd9cc3bcd..2f35427be 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -641,6 +641,31 @@ machine_at_cmdsl386sx16_init(const machine_t *model) return ret; } +int +machine_at_if386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/if386sx/OKI_IF386SX_odd.bin", + "roms/machines/if386sx/OKI_IF386SX_even.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&keyboard_at_device); + + device_add(&neat_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(&if386jega_device); + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + static void machine_at_scamp_common_init(const machine_t *model, int is_ps2) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bae9de29f..ce95b5fc8 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4746,6 +4746,44 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { .name = "[NEAT] OKI if386AX30L", + .internal_name = "if386sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_NEAT, + .init = machine_at_if386sx_init, + .p1_handler = NULL, + .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_AT, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 4096, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has IBM AT KBC firmware. */ { .name = "[OPTi 291] DTK PPM-3333P", diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 438d5c98d..16a3552ad 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -47,9 +47,9 @@ void ega_doblit(int wx, int wy, ega_t *ega); static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; static uint8_t ega_rotate[8][256]; -static int active = 0; -static uint32_t pallook16[256]; -static uint32_t pallook64[256]; +static int active = 0; +uint32_t pallook16[256]; +uint32_t pallook64[256]; static int ega_type = EGA_TYPE_IBM; static int old_overscan_color = 0; diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 145579cf5..edf7358a6 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -60,6 +60,7 @@ #define RINVALID_INDEX 0x30 #define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN" +#define IF386_PATH_VBIOS "roms/video/jega/OKI_IF386SX_VBIOS.bin" #define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" #define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ #define DBCS16_CHARS 0x2c10 @@ -137,7 +138,8 @@ typedef struct { uint16_t end; } fontx_tbl; -static uint32_t pallook64[256]; +extern uint32_t pallook16[256]; +extern uint32_t pallook64[256]; static bool is_SJIS_1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } static bool is_SJIS_2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } @@ -615,8 +617,27 @@ LoadFontxFile(const char *fn, void *priv) return 0; } +static void +jega_commoninit(void *priv) +{ + jega_t *jega = (jega_t *) priv; + for (int c = 0; c < 256; c++) { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + } + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); + jega->pallook = pallook64; + ega_init(&jega->ega, 9, 0); + ega_set_type(&jega->ega, EGA_SUPEREGA); + jega->ega.priv_parent = jega; + mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); + /* I/O 3DD and 3DE are used by Oki if386 */ + io_sethandler(0x03b0, 0x002c, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); + jega->regs[RMOD1] = 0x48; +} + static void * -jega_init(const device_t *info) +jega_standalone_init(const device_t *info) { jega_t *jega = calloc(1, sizeof(jega_t)); @@ -624,21 +645,7 @@ jega_init(const device_t *info) memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); LoadFontxFile(JEGA_PATH_FONTDBCS, jega); - for (int c = 0; c < 256; c++) { - pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); - pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); - } - - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); - jega->pallook = pallook64; - ega_init(&jega->ega, 9, 0); - ega_set_type(&jega->ega, EGA_SUPEREGA); - jega->ega.priv_parent = jega; - mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); - - io_sethandler(0x03b0, 0x0030, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); - - jega->regs[RMOD1] = 0x48; + jega_commoninit(jega); return jega; } @@ -665,10 +672,10 @@ jega_close(void *priv) fprintf(f, "Regs %02X: %4X\n", i, jega->regs[i]); for (int i = 0; i < 32; i++) fprintf(f, "Attr %02X: %4X\n", i, jega->attrregs[i]); - for (int i = 0; i < 16; i++) - fprintf(f, "JEGAPal %02X: %4X\n", i, jega->egapal[i]); - for (int i = 0; i < 16; i++) - fprintf(f, "EGAPal %02X: %4X\n", i, jega->ega.egapal[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "JEGAPal %02X: %4X\n", i, jega->egapal[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "EGAPal %02X: %4X\n", i, jega->ega.egapal[i]); for (int i = 0; i < 64; i++) fprintf(f, "RealPal %02X: %4X\n", i, jega->pallook[i]); fclose(f); @@ -683,7 +690,7 @@ jega_close(void *priv) fwrite(&ram[0x0], 0x500, 1, f); fclose(f); } - // jega_log("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); + pclog("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); #endif if (jega->ega.eeprom) free(jega->ega.eeprom); @@ -706,7 +713,7 @@ jega_speed_changed(void *priv) } static int -jega_available(void) +jega_standalone_available(void) { return (rom_present(JEGA_PATH_BIOS) && rom_present(JEGA_PATH_FONTDBCS)); } @@ -716,10 +723,124 @@ const device_t jega_device = { .internal_name = "jega", .flags = DEVICE_ISA, .local = 0, - .init = jega_init, + .init = jega_standalone_init, .close = jega_close, .reset = NULL, - .available = jega_available, + .available = jega_standalone_available, + .speed_changed = jega_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +static uint8_t p65idx = 0; +static uint8_t p3de_idx = 0; +static uint8_t p65[6]; +static uint8_t p3de[0x30]; + + +static uint8_t +if386_p6x_read(uint16_t port, void *priv) +{ + uint8_t ret = INVALIDACCESS8; + if (port == 0x63) { + ret = p65idx; + } else if (port == 0x65) { + ret = p65[p65idx]; + } + // pclog("p%x_r: [%04x:%04x] [%02x]%02x\n", port, cs >> 4, cpu_state.pc , p65idx, ret); + return ret; +} + +/* + OKi if386AX/SX Power management and Miscellaneous + I/O 63h: Index 0-5, I/O 65h: Data + Index 2: + Bit 3: Caps Lock enabled + Bit 2: Num Lock enabled + Bit 1: Scrl Lock enabled + Bit 0: Kana Lock enabled + Index 3 + Bit 2: External monitor output enabled + Bit 1: Floppy drive 1 active + Bit 0: Floppy drive 0 active + Index 5 + Bit 8: ? (1=Disabled, 0=Enabled) + Bit 7: Screen Off? (enabled by Ctrl + Alt + [1] and disabled by any key) + Bit 4: Shutdown? (caused by POST rebooting and POWER OFF command in DOS 3.21) + Bit 3: ? +*/ +static void +if386_p6x_write(uint16_t port, uint8_t val, void *priv) +{ + jega_t *jega = (jega_t *) priv; + // pclog("p%x_w: [%04x:%04x] val=%02x\n", port, cs >> 4, cpu_state.pc, val); + if (port == 0x63 && val < 6) + p65idx = val; + if (port == 0x65) { + // pclog("p65_w: [%04x:%04x] idx=%02x, val=%02x\n", cs >> 4, cpu_state.pc, p65idx, val); + p65[p65idx] = val; + if (p65idx == 0x03) { + if (val & 0x04) { /* Color monitor */ + for (int c = 0; c < 256; c++) { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + if ((c & 0x17) == 6) + pallook16[c] = makecol32(0xaa, 0x55, 0); + } + } else { /* Monochrome LCD */ + for (int c = 0; c < 256; c++) { + int cval = 0; + if (c & 0x0f) + cval = ((c & 0x0e) * 0x10) + 0x1f; + pallook64[c] = makecol32(cval, cval, cval); + pallook16[c] = makecol32(cval, cval, cval); + } + } + jega_recalctimings(jega); + } else if (p65idx == 0x05) { + if (val & 0x10) { /* Power off (instead this call hardware reset here) */ + resetx86(); + } + } + } + return; +} + +static void * +if386jega_init(const device_t *info) +{ + jega_t *jega = calloc(1, sizeof(jega_t)); + + rom_init(&jega->bios_rom, IF386_PATH_VBIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); + memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); + LoadFontxFile(JEGA_PATH_FONTDBCS, jega); + + jega_commoninit(jega); + + io_sethandler(0x0063, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); + io_sethandler(0x0065, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); + // io_sethandler(0x03dd, 2, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); + + return jega; +} + +static int +if386jega_available(void) +{ + return (rom_present(IF386_PATH_VBIOS) && rom_present(JEGA_PATH_FONTDBCS)); +} + +const device_t if386jega_device = { + .name = "JEGA (if386AX)", + .internal_name = "if386jega", + .flags = DEVICE_ISA, + .local = 0, + .init = if386jega_init, + .close = jega_close, + .reset = NULL, + .available = if386jega_available, .speed_changed = jega_speed_changed, .force_redraw = NULL, .config = NULL From fe0c246bd2e1bd97dce427e873b896cc8fbc6227 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:33:58 +0900 Subject: [PATCH 175/218] if386sx: change rom file path --- src/video/vid_jega.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index edf7358a6..f9bcb6918 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -60,8 +60,8 @@ #define RINVALID_INDEX 0x30 #define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN" -#define IF386_PATH_VBIOS "roms/video/jega/OKI_IF386SX_VBIOS.bin" #define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" +#define IF386_PATH_VBIOS "roms/machines/if386sx/OKI_IF386SX_VBIOS.bin" #define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ #define DBCS16_CHARS 0x2c10 #define DBCS16_FILESIZE (DBCS16_CHARS * 16 * 2) From 861d942657dc5f8484f5ed2fad331c1687737346 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 11:03:04 +0900 Subject: [PATCH 176/218] Adding skeleton that at least compiles for audio4.c --- CMakeLists.txt | 4 ++++ src/sound/CMakeLists.txt | 5 +++- src/sound/audio4.c | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/sound/audio4.c diff --git a/CMakeLists.txt b/CMakeLists.txt index fb71553e2..55cbec8b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,10 @@ else() option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) endif() +if((CMAKE_SYSTEM_NAME STREQUAL "NetBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")) + set(AUDIO4 ON) +endif() + if(WIN32) set(QT ON) option(CPPTHREADS "C++11 threads" OFF) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index a381051ba..955e96f5a 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -53,7 +53,10 @@ add_library(snd OBJECT snd_opl_esfm.c ) -if(OPENAL) +# TODO: Should platform-specific audio driver be here? +if(AUDIO4) + target_sources(snd PRIVATE audio4.c) +elseif(OPENAL) if(VCPKG_TOOLCHAIN) find_package(OpenAL CONFIG REQUIRED) elseif(MINGW) diff --git a/src/sound/audio4.c b/src/sound/audio4.c new file mode 100644 index 000000000..3b3d4a429 --- /dev/null +++ b/src/sound/audio4.c @@ -0,0 +1,51 @@ +/* + * 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. + * + * Interface to audio(4). + * + * + * + * Authors: Nishi + * + * Copyright 2025 Nishi. + */ +#include + +#include <86box/sound.h> + +#define FREQ SOUND_FREQ +#define BUFLEN SOUNDBUFLEN + +static int midi_freq = 44100; +static int midi_buf_size = 4410; + +void closeal(void){ +} + +void inital(void){ +} + +void givealbuffer(const void *buf){ +} + +void givealbuffer_music(const void *buf){ +} + +void givealbuffer_wt(const void *buf){ +} + +void givealbuffer_cd(const void *buf){ +} + +void givealbuffer_midi(const void *buf, const uint32_t size){ +} + +void al_set_midi(const int freq, const int buf_size){ + midi_freq = freq; + midi_buf_size = buf_size; +} From 56d0cbb09336f3f426b5c72c945b39cf0fd4c393 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 06:32:02 +0100 Subject: [PATCH 177/218] Different CPU's for the two V-Tech machines. --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bae9de29f..99f6e26a2 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -1760,7 +1760,7 @@ const machine_t machines[] = { .available_flag = MACHINE_AVAILABLE, .gpio_acpi_handler = NULL, .cpu = { - .package = CPU_PKG_8088, + .package = CPU_PKG_8088_VTECH, .block = CPU_BLOCK_NONE, .min_bus = 0, .max_bus = 0, @@ -2623,7 +2623,7 @@ const machine_t machines[] = { .available_flag = MACHINE_AVAILABLE, .gpio_acpi_handler = NULL, .cpu = { - .package = CPU_PKG_8086, + .package = CPU_PKG_8086_VTECH, .block = CPU_BLOCK_NONE, .min_bus = 0, .max_bus = 0, From 7056c83bbb7c444fbdb55ea4a51382f77d7faa36 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 17:41:04 +0900 Subject: [PATCH 178/218] Add working NetBSD sound support --- src/sound/audio4.c | 104 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 3b3d4a429..e7b7dcf33 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -6,8 +6,8 @@ * * This file is part of the 86Box distribution. * - * Interface to audio(4). - * + * Interface to audio(4) for NetBSD/OpenBSD. + * TODO: Test on OpenBSD * * * Authors: Nishi @@ -15,37 +15,121 @@ * Copyright 2025 Nishi. */ #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <86box/86box.h> #include <86box/sound.h> +#include <86box/plat_unused.h> -#define FREQ SOUND_FREQ -#define BUFLEN SOUNDBUFLEN +#define I_NORMAL 0 +#define I_MUSIC 1 +#define I_WT 2 +#define I_CD 3 +#define I_MIDI 4 -static int midi_freq = 44100; -static int midi_buf_size = 4410; +static int audio[5] = {-1, -1, -1, -1, -1}; +static audio_offset_t offset[5]; +static audio_info_t info[5]; +static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0}; void closeal(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + if(audio[i] != -1){ + close(audio[i]); + } + audio[i] = -1; + } } void inital(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + audio[i] = open("/dev/audio", O_WRONLY); + if(audio[i] != -1){ + AUDIO_INITINFO(&info[i]); +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) + ioctl(audio[i], AUDIO_GETFORMAT, &info[i]); +#else + ioctl(audio[i], AUDIO_GETINFO, &info[i]); +#endif + info[i].play.channels = 2; + info[i].play.precision = 16; + info[i].play.encoding = AUDIO_ENCODING_SLINEAR; + info[i].hiwat = 5; + info[i].lowat = 3; + ioctl(audio[i], AUDIO_SETINFO, &info[i]); + } + } +} + +void givealbuffer_common(const void *buf, const uint8_t src, const int size){ + const int freq = freqs[src]; + int16_t* output; + int output_size; + int16_t* conv; + int conv_size; + int i; + double gain; + if(audio[src] == -1) return; + + gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); + + if(sound_is_float){ + float* input = (float*)buf; + conv_size = sizeof(int16_t) * size; + conv = malloc(conv_size); + for(i = 0; i < conv_size / sizeof(int16_t); i++){ + conv[i] = 32767 * input[i]; + } + }else{ + conv_size = size * sizeof(int16_t); + conv = malloc(conv_size); + memcpy(conv, buf, conv_size); + } + + output_size = (double)conv_size * info[src].play.sample_rate / freq; + output = malloc(output_size); + + for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ + int ind = i * freq / info[src].play.sample_rate * 2; + output[i * 2 + 0] = conv[ind + 0] * gain; + output[i * 2 + 1] = conv[ind + 1] * gain; + } + + write(audio[src], output, output_size); + + free(conv); + free(output); } void givealbuffer(const void *buf){ + givealbuffer_common(buf, I_NORMAL, SOUNDBUFLEN << 1); } void givealbuffer_music(const void *buf){ + givealbuffer_common(buf, I_MUSIC, MUSICBUFLEN << 1); } void givealbuffer_wt(const void *buf){ + givealbuffer_common(buf, I_WT, WTBUFLEN << 1); } void givealbuffer_cd(const void *buf){ + givealbuffer_common(buf, I_CD, CD_BUFLEN << 1); } - void givealbuffer_midi(const void *buf, const uint32_t size){ + givealbuffer_common(buf, I_MIDI, (int) size); } -void al_set_midi(const int freq, const int buf_size){ - midi_freq = freq; - midi_buf_size = buf_size; +void al_set_midi(const int freq, UNUSED(const int buf_size)){ + freqs[I_MIDI] = freq; } From f287ee4fd0f96945c85feb0dd5085ef6129a223e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 18:20:05 +0900 Subject: [PATCH 179/218] Check OpenBSD version and use newer API if needed --- src/sound/audio4.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index e7b7dcf33..ebea8a08f 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -29,6 +29,10 @@ #include <86box/sound.h> #include <86box/plat_unused.h> +#if defined(OpenBSD) && OpenBSD >= 201709 +#define USE_NEW_API +#endif + #define I_NORMAL 0 #define I_MUSIC 1 #define I_WT 2 @@ -36,8 +40,11 @@ #define I_MIDI 4 static int audio[5] = {-1, -1, -1, -1, -1}; -static audio_offset_t offset[5]; +#ifdef USE_NEW_API +static struct audio_swpar info[5]; +#else static audio_info_t info[5]; +#endif static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0}; void closeal(void){ @@ -55,6 +62,14 @@ void inital(void){ for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = open("/dev/audio", O_WRONLY); if(audio[i] != -1){ +#ifdef USE_NEW_API + AUDIO_INITPAR(&info[i]); + ioctl(audio[i], AUDIO_GETPAR, &info[i]); + info[i].pchan = 2; + info[i].bits = 16; + info[i].bps = 2; + ioctl(audio[i], AUDIO_SETPAR, &info[i]); +#else AUDIO_INITINFO(&info[i]); #if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) ioctl(audio[i], AUDIO_GETFORMAT, &info[i]); @@ -67,6 +82,7 @@ void inital(void){ info[i].hiwat = 5; info[i].lowat = 3; ioctl(audio[i], AUDIO_SETINFO, &info[i]); +#endif } } } From ad655ab40c3b3d7115ae719cb985fa9333831341 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 18:55:37 +0900 Subject: [PATCH 180/218] Forgot to add newer API support in conversion part --- src/sound/audio4.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index ebea8a08f..18606f9ce 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -112,11 +112,19 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ memcpy(conv, buf, conv_size); } +#ifdef USE_NEW_API + output_size = (double)conv_size * info[src].rate / freq; +#else output_size = (double)conv_size * info[src].play.sample_rate / freq; +#endif output = malloc(output_size); for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ +#ifdef USE_NEW_API + int ind = i * freq / info[src].rate * 2; +#else int ind = i * freq / info[src].play.sample_rate * 2; +#endif output[i * 2 + 0] = conv[ind + 0] * gain; output[i * 2 + 1] = conv[ind + 1] * gain; } From 090b9d988a3efa0fa256a0c3b0bcb378dc9457f3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 18:57:36 +0900 Subject: [PATCH 181/218] Include string.h for memory operations --- src/sound/audio4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 18606f9ce..fe1b8192d 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 8daed4c70c4c8274d1bb06231443c2c23a994a2a Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:03:36 +0900 Subject: [PATCH 182/218] OpenBSD needs stdarg.h --- src/include/86box/86box.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index e8c5fbac9..c58d595c5 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -20,8 +20,8 @@ #ifndef EMU_86BOX_H #define EMU_86BOX_H -#ifdef __NetBSD__ -/* Doesn't compile on NetBSD without this include */ +#if defined(__NetBSD__) || defined(__OpenBSD__) +/* Doesn't compile on NetBSD/OpenBSD without this include */ #include #endif From ef194e003e921edc2879317bbb22ecc662d0b3fc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:29:37 +0900 Subject: [PATCH 183/218] Check /dev/audio0 too --- src/sound/audio4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index fe1b8192d..2458f78c6 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -62,6 +62,7 @@ void inital(void){ int i; for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = open("/dev/audio", O_WRONLY); + if(audio[i] != -1) audio[i] = open("/dev/audio0", O_WRONLY); if(audio[i] != -1){ #ifdef USE_NEW_API AUDIO_INITPAR(&info[i]); From e023a046bb597f292ab761df2191802474160182 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:37:15 +0900 Subject: [PATCH 184/218] Wrong comparison --- src/sound/audio4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 2458f78c6..fb98594e6 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -62,7 +62,7 @@ void inital(void){ int i; for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = open("/dev/audio", O_WRONLY); - if(audio[i] != -1) audio[i] = open("/dev/audio0", O_WRONLY); + if(audio[i] == -1) audio[i] = open("/dev/audio0", O_WRONLY); if(audio[i] != -1){ #ifdef USE_NEW_API AUDIO_INITPAR(&info[i]); From e4fb39d9441a127ae5fdcbdf571dcb31a06e91bc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:38:49 +0900 Subject: [PATCH 185/218] Remove TODO message --- src/sound/audio4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index fb98594e6..8428b3c93 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -7,7 +7,6 @@ * This file is part of the 86Box distribution. * * Interface to audio(4) for NetBSD/OpenBSD. - * TODO: Test on OpenBSD * * * Authors: Nishi From c135dddfa998c66cb71d6fff004b0f6730e94921 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:51:45 +0900 Subject: [PATCH 186/218] Use option instead of set in CMake --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55cbec8b0..aafa46b1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,7 +145,9 @@ else() endif() if((CMAKE_SYSTEM_NAME STREQUAL "NetBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")) - set(AUDIO4 ON) + option(AUDIO4 "Use audio(4) as sound backend" ON) +else() + set(AUDIO4 OFF) endif() if(WIN32) From 16a6ab3f95b187ca829dd21ffb17d698eaece1dc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 20:35:41 +0900 Subject: [PATCH 187/218] Fix music frequency conversion bug --- src/sound/audio4.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 8428b3c93..ad8b3ce82 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -96,6 +96,7 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ int conv_size; int i; double gain; + int target_rate; if(audio[src] == -1) return; gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); @@ -114,18 +115,18 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ } #ifdef USE_NEW_API - output_size = (double)conv_size * info[src].rate / freq; + target_rate = info[src].rate; #else - output_size = (double)conv_size * info[src].play.sample_rate / freq; + target_rate = info[src].play.sample_rate; #endif + + output_size = (double)conv_size * target_rate / freq; + output_size -= output_size % 2; output = malloc(output_size); for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ -#ifdef USE_NEW_API - int ind = i * freq / info[src].rate * 2; -#else - int ind = i * freq / info[src].play.sample_rate * 2; -#endif + int ind = i * freq / target_rate * 2; + ind -= ind % 2; output[i * 2 + 0] = conv[ind + 0] * gain; output[i * 2 + 1] = conv[ind + 1] * gain; } From fefcd530ab86dbb2143e01b8d0ae1117bccf6794 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 20:37:46 +0900 Subject: [PATCH 188/218] Remove the part that was not required --- src/sound/audio4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index ad8b3ce82..2bad30144 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -126,7 +126,6 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ int ind = i * freq / target_rate * 2; - ind -= ind % 2; output[i * 2 + 0] = conv[ind + 0] * gain; output[i * 2 + 1] = conv[ind + 1] * gain; } From c92d56261a38aed2e95c1445192763e540a7e244 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 20:44:29 +0900 Subject: [PATCH 189/218] Do mod4 instead of mod2, so it can keep the output channel correct --- src/sound/audio4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 2bad30144..32989eecf 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -121,7 +121,7 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ #endif output_size = (double)conv_size * target_rate / freq; - output_size -= output_size % 2; + output_size -= output_size % 4; output = malloc(output_size); for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ From b4fdb6dcdc1e4bfea8e91411112a869ced350ce6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 14:17:59 +0100 Subject: [PATCH 190/218] Vulkan renderer: Take the dpi_scale option into account when setting up the videwport, fixes #5374. --- src/qt/qt_vulkanrenderer.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_vulkanrenderer.cpp b/src/qt/qt_vulkanrenderer.cpp index 13728b82e..39830569c 100644 --- a/src/qt/qt_vulkanrenderer.cpp +++ b/src/qt/qt_vulkanrenderer.cpp @@ -970,10 +970,17 @@ VulkanRenderer2::startNextFrame() m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_buf, &vbOffset); VkViewport viewport; - viewport.x = destination.x() * m_window->devicePixelRatio(); - viewport.y = destination.y() * m_window->devicePixelRatio(); - viewport.width = destination.width() * m_window->devicePixelRatio(); - viewport.height = destination.height() * m_window->devicePixelRatio(); + if (dpi_scale) { + viewport.x = destination.x() * m_window->devicePixelRatio(); + viewport.y = destination.y() * m_window->devicePixelRatio(); + viewport.width = destination.width() * m_window->devicePixelRatio(); + viewport.height = destination.height() * m_window->devicePixelRatio(); + } else { + viewport.x = destination.x(); + viewport.y = destination.y(); + viewport.width = destination.width(); + viewport.height = destination.height(); + } viewport.minDepth = 0; viewport.maxDepth = 1; m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport); From d361befe757f6dafd2408b0d1c47c6a57c06df0f Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 14:23:38 +0100 Subject: [PATCH 191/218] JEGA: Commented out the two 3de arrays which are currently unused. --- src/video/vid_jega.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index f9bcb6918..4d411c39c 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -733,9 +733,9 @@ const device_t jega_device = { }; static uint8_t p65idx = 0; -static uint8_t p3de_idx = 0; +// static uint8_t p3de_idx = 0; static uint8_t p65[6]; -static uint8_t p3de[0x30]; +// static uint8_t p3de[0x30]; static uint8_t From 9fed70679300260260440492c7f9ae5c92a3551a Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:37:39 +0900 Subject: [PATCH 192/218] Add sndio.c that might compile --- CMakeLists.txt | 8 ++- src/sound/CMakeLists.txt | 2 + src/sound/sndio.c | 132 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/sound/sndio.c diff --git a/CMakeLists.txt b/CMakeLists.txt index aafa46b1c..a94321038 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,12 +144,18 @@ else() option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) endif() -if((CMAKE_SYSTEM_NAME STREQUAL "NetBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")) +if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") option(AUDIO4 "Use audio(4) as sound backend" ON) else() set(AUDIO4 OFF) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + option(SNDIO "Use sndio as sound backend" ON) +else() + set(SNDIO OFF) +endif() + if(WIN32) set(QT ON) option(CPPTHREADS "C++11 threads" OFF) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 955e96f5a..0f96aa9a6 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -56,6 +56,8 @@ add_library(snd OBJECT # TODO: Should platform-specific audio driver be here? if(AUDIO4) target_sources(snd PRIVATE audio4.c) +elseif(SNDIO) + target_sources(snd PRIVATE sndio.c) elseif(OPENAL) if(VCPKG_TOOLCHAIN) find_package(OpenAL CONFIG REQUIRED) diff --git a/src/sound/sndio.c b/src/sound/sndio.c new file mode 100644 index 000000000..bb483d9fe --- /dev/null +++ b/src/sound/sndio.c @@ -0,0 +1,132 @@ +/* + * 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. + * + * Interface to audio(4) for NetBSD/OpenBSD. + * + * + * Authors: Nishi + * + * Copyright 2025 Nishi. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include <86box/86box.h> +#include <86box/sound.h> +#include <86box/plat_unused.h> + +#define I_NORMAL 0 +#define I_MUSIC 1 +#define I_WT 2 +#define I_CD 3 +#define I_MIDI 4 + +static struct sio_hdl* audio[5] = {NULL, NULL, NULL, NULL, NULL}; +static struct sio_par info[5]; +static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0}; + +void closeal(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + if(audio[i] != NULL){ + sio_close(audio[i]); + } + audio[i] = NULL; + } +} + +void inital(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + audio[i] = sio_open(SIO_DEVANY, SIO_PLAY, 0); + if(audio[i] != NULL){ + sio_initpar(&info[i]); + sio_getpar(audio[i], &info[i]); + info[i].sig = 1; + info[i].bits = 16; + info[i].pchan = 2; + sio_setpar(audio[i], &info[i]); + sio_start(audio[i]); + } + } +} + +void givealbuffer_common(const void *buf, const uint8_t src, const int size){ + const int freq = freqs[src]; + int16_t* output; + int output_size; + int16_t* conv; + int conv_size; + int i; + double gain; + int target_rate; + if(audio[src] == -1) return; + + gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); + + if(sound_is_float){ + float* input = (float*)buf; + conv_size = sizeof(int16_t) * size; + conv = malloc(conv_size); + for(i = 0; i < conv_size / sizeof(int16_t); i++){ + conv[i] = 32767 * input[i]; + } + }else{ + conv_size = size * sizeof(int16_t); + conv = malloc(conv_size); + memcpy(conv, buf, conv_size); + } + + target_rate = info[src].rate; + + output_size = (double)conv_size * target_rate / freq; + output_size -= output_size % 4; + output = malloc(output_size); + + for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ + int ind = i * freq / target_rate * 2; + output[i * 2 + 0] = conv[ind + 0] * gain; + output[i * 2 + 1] = conv[ind + 1] * gain; + } + + sio_write(audio[src], output, output_size); + + free(conv); + free(output); +} + +void givealbuffer(const void *buf){ + givealbuffer_common(buf, I_NORMAL, SOUNDBUFLEN << 1); +} + +void givealbuffer_music(const void *buf){ + givealbuffer_common(buf, I_MUSIC, MUSICBUFLEN << 1); +} + +void givealbuffer_wt(const void *buf){ + givealbuffer_common(buf, I_WT, WTBUFLEN << 1); +} + +void givealbuffer_cd(const void *buf){ + givealbuffer_common(buf, I_CD, CD_BUFLEN << 1); +} +void givealbuffer_midi(const void *buf, const uint32_t size){ + givealbuffer_common(buf, I_MIDI, (int) size); +} + +void al_set_midi(const int freq, UNUSED(const int buf_size)){ + freqs[I_MIDI] = freq; +} From 277b422940fa953246cd28c054da73fce40cc596 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:41:43 +0900 Subject: [PATCH 193/218] Forgot to add linking/including stuff to CMake --- src/sound/CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 0f96aa9a6..b2cbb57f0 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -58,6 +58,20 @@ if(AUDIO4) target_sources(snd PRIVATE audio4.c) elseif(SNDIO) target_sources(snd PRIVATE sndio.c) + find_package(PkgConfig REQUIRED) + + # Use FAudio, a reimplementation of XAudio2 + pkg_check_modules(SNDIO IMPORTED_TARGET sndio) + if(SNDIO_FOUND) + target_link_libraries(86Box PkgConfig::SNDIO) + else() + find_path(SNDIO_INCLUDE_DIR NAMES "sndio.h") + find_library(SNDIO_LIBRARY sndio) + + target_link_libraries(86Box ${SNDIO_LIBRARY}) + endif() + + include_directories(${SNDIO_INCLUDE_DIRS}) elseif(OPENAL) if(VCPKG_TOOLCHAIN) find_package(OpenAL CONFIG REQUIRED) From 251dcacaa162099027b7684d3ab57faaa598c9fc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:44:28 +0900 Subject: [PATCH 194/218] fix include --- src/sound/sndio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sound/sndio.c b/src/sound/sndio.c index bb483d9fe..2a454f5fc 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Interface to audio(4) for NetBSD/OpenBSD. + * Interface to sndio * * * Authors: Nishi @@ -14,15 +14,13 @@ * Copyright 2025 Nishi. */ #include -#include #include -#include #include #include #include #include -#include +#include #include <86box/86box.h> #include <86box/sound.h> From 5de2d6b86dcba49db57039f4ce2d10f68f4004e2 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:45:11 +0900 Subject: [PATCH 195/218] Should be NULL not -1 --- src/sound/sndio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 2a454f5fc..56f8ec8cf 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -71,7 +71,7 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ int i; double gain; int target_rate; - if(audio[src] == -1) return; + if(audio[src] == NULL) return; gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); From 6e83a7fc96ea44acf9dea93d2f4752043c4cadba Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 23:30:13 +0900 Subject: [PATCH 196/218] Get sio_par for safety --- src/sound/audio4.c | 3 ++- src/sound/sndio.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 32989eecf..4e74d2c0c 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -66,8 +66,9 @@ void inital(void){ #ifdef USE_NEW_API AUDIO_INITPAR(&info[i]); ioctl(audio[i], AUDIO_GETPAR, &info[i]); - info[i].pchan = 2; + info[i].sig = 1; info[i].bits = 16; + info[i].pchan = 2; info[i].bps = 2; ioctl(audio[i], AUDIO_SETPAR, &info[i]); #else diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 56f8ec8cf..5c3adad49 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -57,6 +57,7 @@ void inital(void){ info[i].bits = 16; info[i].pchan = 2; sio_setpar(audio[i], &info[i]); + sio_getpar(audio[i], &info[i]); sio_start(audio[i]); } } From 1ef20bea361494e14960f3cb934c3b2e3f90b46b Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 25 Mar 2025 00:01:15 +0900 Subject: [PATCH 197/218] Had to assign some values --- src/sound/sndio.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 5c3adad49..2fe1434df 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -51,14 +51,23 @@ void inital(void){ for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = sio_open(SIO_DEVANY, SIO_PLAY, 0); if(audio[i] != NULL){ - sio_initpar(&info[i]); + int rate; + int max_frames; sio_getpar(audio[i], &info[i]); + rate = info[i].rate; + max_frames = info[i].bufsz; + sio_initpar(&info[i]); info[i].sig = 1; info[i].bits = 16; info[i].pchan = 2; + info[i].rate = rate; + info[i].appbufsz = max_frames; sio_setpar(audio[i], &info[i]); sio_getpar(audio[i], &info[i]); - sio_start(audio[i]); + if(!sio_start(audio[i])){ + sio_close(audio[i]); + audio[i] = NULL; + } } } } From d68a56a3c92c40c279c89bcdc69c0e1ce00c2538 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 25 Mar 2025 00:52:27 +0900 Subject: [PATCH 198/218] Forgot to remove the comment --- src/sound/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index b2cbb57f0..0a04b0ff1 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -60,7 +60,6 @@ elseif(SNDIO) target_sources(snd PRIVATE sndio.c) find_package(PkgConfig REQUIRED) - # Use FAudio, a reimplementation of XAudio2 pkg_check_modules(SNDIO IMPORTED_TARGET sndio) if(SNDIO_FOUND) target_link_libraries(86Box PkgConfig::SNDIO) From c7b5aa8f0421f3d064b23b1b3d2c924a1a3747c7 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 24 Mar 2025 18:51:28 +0100 Subject: [PATCH 199/218] DEC 21x4 changes of the day (March 24th, 2025) 1. Change the block type of the extended format of the 21143 to 3 and do not issue an IRQ abuse. --- src/network/net_tulip.c | 50 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index 7d988368c..685873c93 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -971,7 +971,8 @@ tulip_write(uint32_t addr, uint32_t data, void *opaque) case CSR(7): s->csr[7] = data; - tulip_update_int(s); + if (s->device_info->local) + tulip_update_int(s); break; case CSR(8): @@ -1006,7 +1007,7 @@ tulip_write(uint32_t addr, uint32_t data, void *opaque) case CSR(13): s->csr[13] = data; - if (s->device_info->local == 3 && (data & 0x4)) { + if ((s->device_info->local == 3) && (data & 0x4)) { s->csr[13] = 0x8f01; s->csr[14] = 0xfffd; s->csr[15] = 0; @@ -1407,7 +1408,7 @@ nic_init(const device_t *info) if (!s) return NULL; - if (info->local && info->local != 3) { + if (info->local && (info->local != 3)) { s->bios_addr = 0xD0000; s->has_bios = device_get_config_int("bios"); } else { @@ -1434,7 +1435,7 @@ nic_init(const device_t *info) s->eeprom_data[2] = 0x14; s->eeprom_data[3] = 0x21; } else { - /*Subsystem Vendor ID*/ + /*Subsystem Vendor ID*/ s->eeprom_data[0] = info->local ? 0x25 : 0x11; s->eeprom_data[1] = 0x10; @@ -1549,23 +1550,40 @@ nic_init(const device_t *info) /*Block Count*/ s->eeprom_data[32] = 0x01; - /*Extended Format - Block Type 2 for 21142/21143*/ + /*Extended Format - Block Type 3 for 21142/21143*/ /*Length (0:6) and Format Indicator (7)*/ - s->eeprom_data[33] = 0x86; + s->eeprom_data[33] = 0x8d; /*Block Type*/ - s->eeprom_data[34] = 0x02; + s->eeprom_data[34] = 0x03; - /*Media Code (0:5), EXT (6), Reserved (7)*/ - s->eeprom_data[35] = 0x01; + /*PHY Number*/ + s->eeprom_data[35] = 0x00; - /*General Purpose Control*/ - s->eeprom_data[36] = 0xff; - s->eeprom_data[37] = 0xff; + /*GPR Length*/ + s->eeprom_data[36] = 0x00; - /*General Purpose Data*/ + /*Reset Length*/ + s->eeprom_data[37] = 0x00; + + /*Media Capabilities*/ s->eeprom_data[38] = 0x00; - s->eeprom_data[39] = 0x00; + s->eeprom_data[39] = 0x78; + + /*Nway Advertisement*/ + s->eeprom_data[40] = 0xe0; + s->eeprom_data[41] = 0x01; + + /*FDX Bit Map*/ + s->eeprom_data[42] = 0x00; + s->eeprom_data[43] = 0x50; + + /*TTM Bit Map*/ + s->eeprom_data[44] = 0x00; + s->eeprom_data[45] = 0x18; + + /*MII PHY Insertion/removal Indication*/ + s->eeprom_data[46] = 0x00; } s->eeprom_data[126] = tulip_srom_crc(s->eeprom_data) & 0xff; @@ -1608,7 +1626,7 @@ nic_init(const device_t *info) checksum *= 2; if (checksum > 65535) checksum = checksum % 65535; - + /* 3rd pair. */ checksum += (s->eeprom_data[4] * 256) | s->eeprom_data[5]; if (checksum > 65535) @@ -1616,7 +1634,7 @@ nic_init(const device_t *info) if (checksum >= 65535) checksum = 0; - + s->eeprom_data[6] = (checksum >> 8) & 0xFF; s->eeprom_data[7] = checksum & 0xFF; } From d91cc459bf52fbc07fe864f67d234ed059ae45be Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 19:02:46 +0100 Subject: [PATCH 200/218] OKI IF386AX: Implement the NEATsx chipset and give it the AT Phoenix keyboard controller. --- src/chipset/neat.c | 144 ++++++++++++++++++++++++----------- src/device/kbc_at.c | 40 ++++++++-- src/include/86box/chipset.h | 1 + src/include/86box/keyboard.h | 1 + src/include/86box/machine.h | 2 + src/machine/m_at_286_386sx.c | 4 +- src/machine/machine_table.c | 12 +-- 7 files changed, 146 insertions(+), 58 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index d4eb3ec7f..f6a7fafb2 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -53,6 +53,7 @@ #define REG_RA1 0x61 /* Command Delay */ #define RA1_MASK 0xff /* 1111 1111 */ +#define RA1_MASK_SX 0xbf /* 1X11 1111 */ #define RA1_BUSDLY 0x03 /* AT BUS command delay */ #define RA1_BUSDLY_SH 0 #define RA1_BUS8DLY 0x0c /* AT BUS 8bit command delay */ @@ -81,6 +82,7 @@ #define ATWS_3 1 /* 3 wait states */ #define ATWS_4 2 /* 4 wait states */ #define ATWS_5 4 /* 5 wait states */ +#define RA2_387SX 0x80 /* CS8221 82C212 controller registers. */ #define REG_RB0 0x64 /* Version ID */ @@ -103,6 +105,9 @@ #define REG_RB2 0x66 /* Memory Enable 1 */ #define RB2_MASK 0x80 /* 1XXX XXXX */ +#define RB2_MASK_SX 0xe0 /* 111X XXXX */ +#define RB2_BOT256 0x20 /* bottom 256K is on sysboard (1) */ +#define RB2_MID256 0x40 /* middle 256K is on sysboard (1) */ #define RB2_TOP128 0x80 /* top 128K is on sysboard (1) */ #define REG_RB3 0x67 /* Memory Enable 2 */ @@ -198,6 +203,7 @@ #define REG_RB12 0x6f /* Miscellaneous */ #define RB12_MASK 0xe6 /* 111R R11R */ +#define RB12_MASK_SX 0xf6 /* 1111 R11R */ #define RB12_GA20 0x02 /* gate for A20 */ #define RB12_RASTMO 0x04 /* enable RAS timeout counter */ #define RB12_EMSLEN 0xe0 /* EMS memory chunk size */ @@ -221,11 +227,10 @@ typedef struct ram_page_t { } ram_page_t; typedef struct neat_t { - uint8_t mem_flags[32]; + uint8_t mem_flags[64]; uint8_t regs[128]; /* all the CS8221 registers */ uint8_t indx; /* programmed index into registers */ - - char pad; + uint8_t sx; uint16_t ems_base; /* configured base address */ uint32_t ems_frame; /* configured frame address */ @@ -238,8 +243,19 @@ typedef struct neat_t { ram_page_t shadow[32]; /* Shadow RAM pages */ } neat_t; -static uint8_t defaults[16] = { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 }; +static uint8_t defaults[2][16] = { { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x43, 0x10, 0x00, 0x00, 0x12 }, + { 0x0a, 0x45, 0x7c, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x43, 0x00, 0x00, 0x00, 0x08 } }; + +static uint8_t reg_masks[2][16] = { { RA0_MASK, RA1_MASK, RA2_MASK, 0x00, + RB0_MASK, RB1_MASK, RB2_MASK, RB3_MASK, + RB4_MASK, RB4_MASK, RB4_MASK, RB4_MASK, + RB8_MASK, RB9_MASK, RB10_MASK, RB12_MASK }, + { RA0_MASK, RA1_MASK_SX, RA2_MASK, 0x00, + RB0_MASK, RB1_MASK, RB2_MASK_SX, RB3_MASK, + RB4_MASK, RB4_MASK, RB4_MASK, RB4_MASK, + RB8_MASK, RB9_MASK, RB10_MASK, RB12_MASK_SX } }; static uint8_t masks[4] = { RB10_P0EXT, RB10_P1EXT, RB10_P2EXT, RB10_P3EXT }; static uint8_t shifts[4] = { RB10_P0EXT_SH, RB10_P1EXT_SH, RB10_P2EXT_SH, RB10_P3EXT_SH }; @@ -405,12 +421,12 @@ ems_writew(uint32_t addr, uint16_t val, void *priv) static void neat_mem_update_state(neat_t *dev, uint32_t addr, uint32_t size, uint8_t new_flags, uint8_t mask) { - if ((addr >= 0x00080000) && (addr < 0x00100000) && - ((new_flags ^ dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE]) & mask)) { - dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE] &= ~mask; - dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE] |= new_flags; + if ((addr < 0x00100000) && + ((new_flags ^ dev->mem_flags[addr / EMS_PGSIZE]) & mask)) { + dev->mem_flags[addr / EMS_PGSIZE] &= ~mask; + dev->mem_flags[addr / EMS_PGSIZE] |= new_flags; - new_flags = dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE]; + new_flags = dev->mem_flags[addr / EMS_PGSIZE]; if (new_flags & MEM_FLAG_ROMCS) { neat_log("neat_mem_update_state(): %08X-%08X: %02X (ROMCS)\n", addr, addr + size - 1, new_flags); @@ -691,6 +707,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) uint8_t xval; uint8_t j; uint8_t *reg; + uint8_t mask; int i; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) @@ -705,10 +722,11 @@ neat_write(uint16_t port, uint8_t val, void *priv) case 0x23: reg = &dev->regs[dev->indx]; xval = *reg ^ val; + mask = reg_masks[dev->sx][dev->indx & REG_MASK]; switch (dev->indx) { case REG_RA0: - val &= RA0_MASK; - *reg = (*reg & ~RA0_MASK) | val | (RA0_REV_ID << RA0_REV_SH); + val &= mask; + *reg = (*reg & ~mask) | val | (RA0_REV_ID << RA0_REV_SH); if ((xval & 0x20) && (val & 0x20)) outb(0x64, 0xfe); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) @@ -717,32 +735,32 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RA1: - val &= RA1_MASK; - *reg = (*reg & ~RA1_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RA1=%02x(%02x)\n", val, *reg); #endif break; case REG_RA2: - val &= RA2_MASK; - *reg = (*reg & ~RA2_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RA2=%02x(%02x)\n", val, *reg); #endif break; case REG_RB0: - val &= RB0_MASK; - *reg = (*reg & ~RB0_MASK) | val | (RB0_REV_ID << RB0_REV_SH); + val &= mask; + *reg = (*reg & ~mask) | val | (RB0_REV_ID << RB0_REV_SH); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB0=%02x(%02x)\n", val, *reg); #endif break; case REG_RB1: - val &= RB1_MASK; - *reg = (*reg & ~RB1_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB1=%02x(%02x)\n", val, *reg); @@ -750,20 +768,37 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB2: - val &= RB2_MASK; - *reg = (*reg & ~RB2_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; + if (dev->sx) { + if (val & RB2_BOT256) + neat_mem_update_state(dev, 0x00000000, 0x00040000, + MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); + else + neat_mem_update_state(dev, 0x00000000, 0x00040000, + 0x00, MEM_FMASK_SHADOW); + + if (val & RB2_MID256) + neat_mem_update_state(dev, 0x00040000, 0x00040000, + MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); + else + neat_mem_update_state(dev, 0x00040000, 0x00040000, + 0x00, MEM_FMASK_SHADOW); + } if (val & RB2_TOP128) - neat_mem_update_state(dev, 0x00080000, 0x00020000, MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); + neat_mem_update_state(dev, 0x00080000, 0x00020000, + MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); else - neat_mem_update_state(dev, 0x00080000, 0x00020000, 0x00, MEM_FMASK_SHADOW); + neat_mem_update_state(dev, 0x00080000, 0x00020000, + 0x00, MEM_FMASK_SHADOW); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg); #endif break; case REG_RB3: - val &= RB3_MASK; - *reg = (*reg & ~RB3_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB3=%02x(%02x)\n", val, *reg); @@ -771,8 +806,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB4: - val &= RB4_MASK; - *reg = (*reg & ~RB4_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB4=%02x(%02x)\n", val, *reg); @@ -780,8 +815,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB5: - val &= RB5_MASK; - *reg = (*reg & ~RB5_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB5=%02x(%02x)\n", val, *reg); @@ -789,20 +824,20 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB6: - val &= RB6_MASK; - *reg = (*reg & ~RB6_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB6=%02x(%02x)\n", val, *reg); #endif break; case REG_RB7: - val &= RB7_MASK; + val &= mask; if (xval & (RB7_EMSEN | RB7_UMAREL)) remap_update(dev, val); - dev->regs[REG_RB7] = val; + *reg = (*reg & ~mask) | val; if (xval & RB7_EMSEN) ems_remove_handlers(dev); @@ -816,16 +851,16 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB8: - val &= RB8_MASK; - *reg = (*reg & ~RB8_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB8=%02x(%02x)\n", val, *reg); #endif break; case REG_RB9: - val &= RB9_MASK; - *reg = (*reg & ~RB9_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg); #endif @@ -847,8 +882,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB10: - val &= RB10_MASK; - *reg = (*reg & ~RB10_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg); #endif @@ -882,8 +917,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB12: - val &= RB12_MASK; - *reg = (*reg & ~RB12_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB12=%02x(%02x)\n", val, *reg); #endif @@ -976,6 +1011,8 @@ neat_init(UNUSED(const device_t *info)) /* Create an instance. */ dev = (neat_t *) calloc(1, sizeof(neat_t)); + dev->sx = info->local; + if (mem_size > 1024) { mem_mapping_set_handler(&ram_high_mapping, neat_read_ram, neat_read_ramw, NULL, neat_write_ram, neat_write_ramw, NULL); @@ -1002,7 +1039,7 @@ neat_init(UNUSED(const device_t *info)) neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_SHADOW); else { /* This is needed to actually trigger an update. */ - dev->mem_flags[i + 8] = MEM_FLAG_ROMCS; + dev->mem_flags[i + 40] = MEM_FLAG_ROMCS; neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, 0x00, MEM_FMASK_SHADOW); } } @@ -1045,7 +1082,10 @@ neat_init(UNUSED(const device_t *info)) /* Initialize some of the registers to specific defaults. */ for (uint8_t i = REG_RA0; i <= REG_RB12; i++) { dev->indx = i; - neat_write(0x0023, defaults[i & REG_MASK], dev); + uint8_t def = defaults[dev->sx][i & REG_MASK]; + if ((i == REG_RA2) && (fpu_type == FPU_387)) + def |= RA2_387SX; + neat_write(0x0023, def, dev); } /* @@ -1190,7 +1230,7 @@ neat_init(UNUSED(const device_t *info)) } const device_t neat_device = { - .name = "C&T CS8121 (NEAT)", + .name = "C&T CS8221 (NEAT)", .internal_name = "neat", .flags = 0, .local = 0, @@ -1202,3 +1242,17 @@ const device_t neat_device = { .force_redraw = NULL, .config = NULL }; + +const device_t neat_sx_device = { + .name = "C&T CS8281 (NEATsx)", + .internal_name = "neat_sx", + .flags = 0, + .local = 1, + .init = neat_init, + .close = neat_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 09855a387..abb10d108 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1577,21 +1577,35 @@ write64_phoenix(void *priv, uint8_t val) revision level and proper CPU bits. */ case 0xd5: /* Read MultiKey code revision level */ kbc_at_log("ATkbc: Phoenix - Read MultiKey code revision level\n"); - kbc_at_queue_add(dev, 0x04); - kbc_at_queue_add(dev, 0x16); + if (dev->misc_flags & FLAG_PS2) { + kbc_at_queue_add(dev, 0x04); + kbc_at_queue_add(dev, 0x16); + } else { + kbc_at_queue_add(dev, 0x01); + kbc_at_queue_add(dev, 0x29); + } return 0; case 0xd6: /* Read Version Information */ kbc_at_log("ATkbc: Phoenix - Read Version Information\n"); kbc_at_queue_add(dev, 0x81); - kbc_at_queue_add(dev, 0xac); + if (dev->misc_flags & FLAG_PS2) + kbc_at_queue_add(dev, 0xac); + else + kbc_at_queue_add(dev, 0xaa); return 0; case 0xd7: /* Read MultiKey model numbers */ kbc_at_log("ATkbc: Phoenix - Read MultiKey model numbers\n"); - kbc_at_queue_add(dev, 0x02); - kbc_at_queue_add(dev, 0x87); - kbc_at_queue_add(dev, 0x02); + if (dev->misc_flags & FLAG_PS2) { + kbc_at_queue_add(dev, 0x02); + kbc_at_queue_add(dev, 0x87); + kbc_at_queue_add(dev, 0x02); + } else { + kbc_at_queue_add(dev, 0x90); + kbc_at_queue_add(dev, 0x88); + kbc_at_queue_add(dev, 0xd0); + } return 0; default: @@ -2510,6 +2524,20 @@ const device_t keyboard_at_compaq_device = { .config = NULL }; +const device_t keyboard_at_phoenix_device = { + .name = "PC/AT Keyboard (Phoenix)", + .internal_name = "keyboard_at_phoenix", + .flags = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_PHOENIX, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_ps2_device = { .name = "PS/2 Keyboard", .internal_name = "keyboard_ps2", diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index e47bb489f..3a65bbce9 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -48,6 +48,7 @@ extern const device_t contaq_82c597_device; /* C&T */ extern const device_t ct_82c100_device; extern const device_t neat_device; +extern const device_t neat_sx_device; extern const device_t scat_device; extern const device_t scat_4_device; extern const device_t scat_sx_device; diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 3a7260c72..9142fbfe1 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -234,6 +234,7 @@ extern const device_t keyboard_xtclone_device; extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; extern const device_t keyboard_at_compaq_device; +extern const device_t keyboard_at_phoenix_device; extern const device_t keyboard_at_ncr_device; extern const device_t keyboard_at_olivetti_device; extern const device_t keyboard_at_siemens_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 21e4a89e2..16ccb2720 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -208,7 +208,9 @@ enum { MACHINE_CHIPSET_ALI_ALADDIN_V, MACHINE_CHIPSET_ALI_ALADDIN_PRO_II, MACHINE_CHIPSET_SCAT, + MACHINE_CHIPSET_SCAT_SX, MACHINE_CHIPSET_NEAT, + MACHINE_CHIPSET_NEAT_SX, MACHINE_CHIPSET_CT_386, MACHINE_CHIPSET_CT_CS4031, MACHINE_CHIPSET_CONTAQ_82C596, diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 2f35427be..136922a5c 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -654,9 +654,9 @@ machine_at_if386sx_init(const machine_t *model) return ret; machine_at_common_init(model); - device_add(&keyboard_at_device); + device_add(&keyboard_at_phoenix_device); - device_add(&neat_device); + device_add(&neat_sx_device); if (gfxcard[0] == VID_INTERNAL) device_add(&if386jega_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b78c11ec8..f3d39833e 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -115,7 +115,9 @@ const machine_filter_t machine_chipsets[] = { { "ALi ALADDiN V", MACHINE_CHIPSET_ALI_ALADDIN_V }, { "ALi ALADDiN-PRO II", MACHINE_CHIPSET_ALI_ALADDIN_PRO_II }, { "C&T 82C235 SCAT", MACHINE_CHIPSET_SCAT }, - { "C&T CS8121 NEAT", MACHINE_CHIPSET_NEAT }, + { "C&T 82C236 SCATsx", MACHINE_CHIPSET_SCAT_SX }, + { "C&T CS8221 NEAT", MACHINE_CHIPSET_NEAT }, + { "C&T CS8281 NEATsx", MACHINE_CHIPSET_NEAT_SX }, { "C&T 386", MACHINE_CHIPSET_CT_386 }, { "C&T CS4031", MACHINE_CHIPSET_CT_CS4031 }, { "Contaq 82C596", MACHINE_CHIPSET_CONTAQ_82C596 }, @@ -4746,10 +4748,10 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - { .name = "[NEAT] OKI if386AX30L", + { .name = "[NEATsx] OKI if386AX30L", .internal_name = "if386sx", .type = MACHINE_TYPE_386SX, - .chipset = MACHINE_CHIPSET_NEAT, + .chipset = MACHINE_CHIPSET_NEAT_SX, .init = machine_at_if386sx_init, .p1_handler = NULL, .gpio_handler = NULL, @@ -4951,10 +4953,10 @@ const machine_t machines[] = { /* Has an unknown AMI KBC firmware, I'm going to assume 'F' until a photo or real hardware BIOS string is found. */ { - .name = "[SCAT] Kaimei KMX-C-02", + .name = "[SCATsx] Kaimei KMX-C-02", .internal_name = "kmxc02", .type = MACHINE_TYPE_386SX, - .chipset = MACHINE_CHIPSET_SCAT, + .chipset = MACHINE_CHIPSET_SCAT_SX, .init = machine_at_kmxc02_init, .p1_handler = NULL, .gpio_handler = NULL, From db6e74a3b9a94083fd47cada3b8a3325ad48dd06 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 01:47:34 +0100 Subject: [PATCH 201/218] NEAT/NEATsx: Fix the EMS enabled condition in the RAM remapping function, fixes 386 enhanced mode operations on the OKI IF386AX. --- src/chipset/neat.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index f6a7fafb2..ffc25d6d9 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -686,9 +686,10 @@ remap_update(neat_t *dev, uint8_t val) mem_mapping_set_addr(&ram_low_mapping, 0x00000000, dev->remap_base << 10); if (dev->remap_base > 1024) { - mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (dev->remap_base << 10) - 0x00100000); - mem_mapping_set_exec(&ram_high_mapping, &(ram[(val & RB7_EMSEN) ? 0x00100000 : - (0x00100000 + (dev->ems_size << 10))])); + uint32_t base = (val & RB7_EMSEN) ? (0x00100000 + (dev->ems_size << 10)) : 0x00100000; + + mem_mapping_set_addr(&ram_high_mapping, base, (dev->remap_base << 10) - 0x00100000); + mem_mapping_set_exec(&ram_high_mapping, &(ram[base])); } else mem_mapping_disable(&ram_high_mapping); From 3f6593f314f47607771395064e23b8bd3f4c3ed5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 02:02:00 +0100 Subject: [PATCH 202/218] IF386AX: Set video card to fixed and make the power off function actually power off. --- src/machine/m_at_286_386sx.c | 4 ++-- src/machine/machine_table.c | 2 +- src/video/vid_jega.c | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 136922a5c..033233955 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -658,8 +658,8 @@ machine_at_if386sx_init(const machine_t *model) device_add(&neat_sx_device); - if (gfxcard[0] == VID_INTERNAL) - device_add(&if386jega_device); + device_add(&if386jega_device); + if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f3d39833e..9f2d0ce47 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4768,7 +4768,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_AT, - .flags = MACHINE_VIDEO, + .flags = MACHINE_VIDEO_FIXED, .ram = { .min = 1024, .max = 4096, diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 4d411c39c..4730b5142 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -28,6 +28,7 @@ #include <86box/timer.h> #include <86box/pic.h> #include <86box/pit.h> +#include <86box/plat.h> #include <86box/mem.h> #include <86box/rom.h> #include <86box/device.h> @@ -800,9 +801,11 @@ if386_p6x_write(uint16_t port, uint8_t val, void *priv) } jega_recalctimings(jega); } else if (p65idx == 0x05) { - if (val & 0x10) { /* Power off (instead this call hardware reset here) */ - resetx86(); - } + if (val & 0x10) + /* Power off (instead this call hardware reset here) */ + // resetx86(); + /* Actually, power off - we have a function for that! */ + plat_power_off(); } } return; From 260f91313a574a0d1f1254cb6252b4d6d3c76daf Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 02:08:35 +0100 Subject: [PATCH 203/218] JEGA: Bring back the reset for time being, the BIOS needs it to reboot. --- src/video/vid_jega.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 4730b5142..36cf04077 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -803,9 +803,9 @@ if386_p6x_write(uint16_t port, uint8_t val, void *priv) } else if (p65idx == 0x05) { if (val & 0x10) /* Power off (instead this call hardware reset here) */ - // resetx86(); + resetx86(); /* Actually, power off - we have a function for that! */ - plat_power_off(); + // plat_power_off(); } } return; From e71c30ce8457fae5dd3910780e64cca56d8225b6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 04:03:21 +0100 Subject: [PATCH 204/218] MMU: Fix behavior of 64-bit memory reads (used by FPU and MMX), should no longer waste host cycles on extra unnecessary MMU translations and should also no longer MMU translate already translated addresses which was causing unpredictable results. --- src/mem/mem.c | 24 +++++++++++++++++++++--- src/mem/mmu_2386.c | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index 94c4ab788..074b44bda 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -1533,10 +1533,28 @@ readmemql(uint32_t addr) addr = addr64a[0] & rammask; map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - if (map && map->read_l) - return map->read_l(addr, map->priv) | ((uint64_t) map->read_l(addr + 4, map->priv) << 32); - return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32); + if (map && map->read_l) + return map->read_l(addr, map->priv) | + ((uint64_t) map->read_l(addr + 4, map->priv) << 32); + + if (map && map->read_w) + return map->read_w(addr, map->priv) | + ((uint64_t) map->read_w(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_w(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_w(addr + 6, map->priv) << 48); + + if (map && map->read_b) + return map->read_b(addr, map->priv) | + ((uint64_t) map->read_b(addr + 1, map->priv) << 8) | + ((uint64_t) map->read_b(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_b(addr + 3, map->priv) << 24) | + ((uint64_t) map->read_b(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_b(addr + 5, map->priv) << 40) | + ((uint64_t) map->read_b(addr + 6, map->priv) << 48) | + ((uint64_t) map->read_b(addr + 7, map->priv) << 56); + + return 0xffffffffffffffffULL; } void diff --git a/src/mem/mmu_2386.c b/src/mem/mmu_2386.c index 7418a88d8..1a2782237 100644 --- a/src/mem/mmu_2386.c +++ b/src/mem/mmu_2386.c @@ -102,8 +102,8 @@ mem_readw_map(uint32_t addr) if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->read_w)) ret = map->read_w(addr, map->priv); else { - ret = mem_readb_phys(addr + 1) << 8; - ret |= mem_readb_phys(addr); + ret = mem_readb_map(addr); + ret |= ((uint16_t) mem_readb_map(addr + 1)) << 8; } return ret; @@ -120,8 +120,8 @@ mem_readl_map(uint32_t addr) if (!cpu_16bitbus && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->read_l)) ret = map->read_l(addr, map->priv); else { - ret = mem_readw_phys(addr + 2) << 16; - ret |= mem_readw_phys(addr); + ret = mem_readw_map(addr); + ret |= ((uint32_t) mem_readw_map(addr + 2)) << 16; } return ret; @@ -148,8 +148,8 @@ mem_writew_map(uint32_t addr, uint16_t val) if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->write_w)) map->write_w(addr, val, map->priv); else { - mem_writeb_phys(addr, val & 0xff); - mem_writeb_phys(addr + 1, val >> 8); + mem_writeb_map(addr, val & 0xff); + mem_writeb_map(addr + 1, val >> 8); } } @@ -161,10 +161,10 @@ mem_writel_map(uint32_t addr, uint32_t val) mem_logical_addr = 0xffffffff; if (!cpu_16bitbus && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->write_l)) - map->write_l(addr, val, map->priv); + map->write_l(addr, val, map->priv); else { - mem_writew_phys(addr, val & 0xffff); - mem_writew_phys(addr + 2, val >> 16); + mem_writew_map(addr, val & 0xffff); + mem_writew_map(addr + 2, val >> 16); } } @@ -649,7 +649,7 @@ readmemll_2386(uint32_t addr) /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass their result as a parameter to be used if needed. */ return readmemwl_no_mmut_2386(addr, addr64a) | - (((uint32_t) readmemwl_no_mmut(addr + 2, &(addr64a[2]))) << 16); + (((uint32_t) readmemwl_no_mmut_2386(addr + 2, &(addr64a[2]))) << 16); } } @@ -925,10 +925,28 @@ readmemql_2386(uint32_t addr) addr = addr64a[0] & rammask; map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - if (map && map->read_l) - return map->read_l(addr, map->priv) | ((uint64_t) map->read_l(addr + 4, map->priv) << 32); - return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32); + if (map && map->read_l) + return map->read_l(addr, map->priv) | + ((uint64_t) map->read_l(addr + 4, map->priv) << 32); + + if (map && map->read_w) + return map->read_w(addr, map->priv) | + ((uint64_t) map->read_w(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_w(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_w(addr + 6, map->priv) << 48); + + if (map && map->read_b) + return map->read_b(addr, map->priv) | + ((uint64_t) map->read_b(addr + 1, map->priv) << 8) | + ((uint64_t) map->read_b(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_b(addr + 3, map->priv) << 24) | + ((uint64_t) map->read_b(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_b(addr + 5, map->priv) << 40) | + ((uint64_t) map->read_b(addr + 6, map->priv) << 48) | + ((uint64_t) map->read_b(addr + 7, map->priv) << 56); + + return 0xffffffffffffffffULL; } void From 8da843bb0acc529bb3791aa41fcde385f5e21ae6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 06:29:11 +0100 Subject: [PATCH 205/218] DMA: Fix a long-standing nasty bug in bus master transfers that was potentially causing memory corruption. --- src/dma.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dma.c b/src/dma.c index 4edeb39f8..a730f1a1c 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1877,15 +1877,15 @@ dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int Tra n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n) { - for (uint32_t i = 0; i < n; i += TransferSize) + if (n2) { + for (uint32_t i = 0; i < n2; i += TransferSize) mem_read_phys((void *) &(DataRead[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n2) { - mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); - memcpy((void *) &(DataRead[n]), bytes, n2); + if (n) { + mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); + memcpy((void *) &(DataRead[n2]), bytes, n); } } @@ -1900,16 +1900,16 @@ dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n) { - for (uint32_t i = 0; i < n; i += TransferSize) + if (n2) { + for (uint32_t i = 0; i < n2; i += TransferSize) mem_write_phys((void *) &(DataWrite[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n2) { - mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); - memcpy(bytes, (void *) &(DataWrite[n]), n2); - mem_write_phys((void *) bytes, PhysAddress + n, TransferSize); + if (n) { + mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); + memcpy(bytes, (void *) &(DataWrite[n2]), n); + mem_write_phys((void *) bytes, PhysAddress + n2, TransferSize); } if (dma_at) From d7529d4f5eb2ae4c8cbdbb1280ed2e4942b43da7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 06:32:12 +0100 Subject: [PATCH 206/218] Reverted the fix because it turned out I had actually misread the code. --- src/dma.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dma.c b/src/dma.c index a730f1a1c..4edeb39f8 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1877,15 +1877,15 @@ dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int Tra n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n2) { - for (uint32_t i = 0; i < n2; i += TransferSize) + if (n) { + for (uint32_t i = 0; i < n; i += TransferSize) mem_read_phys((void *) &(DataRead[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n) { - mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); - memcpy((void *) &(DataRead[n2]), bytes, n); + if (n2) { + mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); + memcpy((void *) &(DataRead[n]), bytes, n2); } } @@ -1900,16 +1900,16 @@ dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n2) { - for (uint32_t i = 0; i < n2; i += TransferSize) + if (n) { + for (uint32_t i = 0; i < n; i += TransferSize) mem_write_phys((void *) &(DataWrite[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n) { - mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); - memcpy(bytes, (void *) &(DataWrite[n2]), n); - mem_write_phys((void *) bytes, PhysAddress + n2, TransferSize); + if (n2) { + mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); + memcpy(bytes, (void *) &(DataWrite[n]), n2); + mem_write_phys((void *) bytes, PhysAddress + n, TransferSize); } if (dma_at) From 556aca0b4edbc24412b3a6ae0cca5243f4673389 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 07:13:50 +0100 Subject: [PATCH 207/218] NEAT/NEATsx: Fix the base of extended memory when EMS is enabled. --- src/chipset/neat.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index ffc25d6d9..1146ecbff 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -688,7 +688,7 @@ remap_update(neat_t *dev, uint8_t val) if (dev->remap_base > 1024) { uint32_t base = (val & RB7_EMSEN) ? (0x00100000 + (dev->ems_size << 10)) : 0x00100000; - mem_mapping_set_addr(&ram_high_mapping, base, (dev->remap_base << 10) - 0x00100000); + mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (dev->remap_base << 10) - 0x00100000); mem_mapping_set_exec(&ram_high_mapping, &(ram[base])); } else mem_mapping_disable(&ram_high_mapping); @@ -942,6 +942,13 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; } + if (mem_size < 1024) + /* No RAM left for EMS at all. */ + dev->ems_size = 0; + else if (mem_size < (dev->ems_size + 1024)) + /* Limit EMS size to the entirety of the remaining extended memory. */ + dev->ems_size = mem_size - 1024; + if (dev->regs[REG_RB7] & RB7_EMSEN) { remap_update(dev, dev->regs[REG_RB7]); From ce820df1d1df691780bd13e745322a127a670865 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 02:08:12 +0600 Subject: [PATCH 208/218] Always make sure emulator is not off-screen when resizing --- src/qt/qt_mainwindow.cpp | 24 ++++++++++++++++++++++++ src/qt/qt_mainwindow.hpp | 1 + src/qt/qt_rendererstack.hpp | 23 +++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index ccaf6964f..b3d0d9fa9 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -798,6 +798,30 @@ MainWindow::closeEvent(QCloseEvent *event) event->accept(); } +void +MainWindow::resizeEvent(QResizeEvent *event) +{ + //qDebug() << pos().x() + event->size().width(); + //qDebug() << pos().y() + event->size().height(); + if (vid_resize == 1) + return; + + int newX = pos().x(); + int newY = pos().y(); + + if (((frameGeometry().x() + event->size().width() + 1) > util::screenOfWidget(this)->availableGeometry().right())) { + //move(util::screenOfWidget(this)->availableGeometry().right() - size().width() - 1, pos().y()); + newX = util::screenOfWidget(this)->availableGeometry().right() - frameGeometry().width() - 1; + if (newX < 1) newX = 1; + } + + if (((frameGeometry().y() + event->size().height() + 1) > util::screenOfWidget(this)->availableGeometry().bottom())) { + newY = util::screenOfWidget(this)->availableGeometry().bottom() - frameGeometry().height() - 1; + if (newY < 1) newY = 1; + } + move(newX, newY); +} + void MainWindow::initRendererMonitorSlot(int monitor_index) { diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 479ed38a4..f1c6cadf6 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -137,6 +137,7 @@ protected: void showEvent(QShowEvent *event) override; void closeEvent(QCloseEvent *event) override; void changeEvent(QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; private slots: void on_actionPen_triggered(); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 54ea49bb9..172dc2fe6 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,7 @@ #include #include "qt_renderercommon.hpp" +#include "qt_util.hpp" #include @@ -21,6 +23,11 @@ namespace Ui { class RendererStack; } +extern "C" +{ + extern int vid_resize; +} + class RendererCommon; class RendererStack : public QStackedWidget { Q_OBJECT @@ -43,6 +50,22 @@ public: void changeEvent(QEvent *event) override; void resizeEvent(QResizeEvent *event) override { + if (this->m_monitor_index != 0 && vid_resize != 1) { + int newX = pos().x(); + int newY = pos().y(); + + if (((frameGeometry().x() + event->size().width() + 1) > util::screenOfWidget(this)->availableGeometry().right())) { + //move(util::screenOfWidget(this)->availableGeometry().right() - size().width() - 1, pos().y()); + newX = util::screenOfWidget(this)->availableGeometry().right() - frameGeometry().width() - 1; + if (newX < 1) newX = 1; + } + + if (((frameGeometry().y() + event->size().height() + 1) > util::screenOfWidget(this)->availableGeometry().bottom())) { + newY = util::screenOfWidget(this)->availableGeometry().bottom() - frameGeometry().height() - 1; + if (newY < 1) newY = 1; + } + move(newX, newY); + } onResize(event->size().width(), event->size().height()); } void keyPressEvent(QKeyEvent *event) override From 3380783876290bcb148f7e7573dabe428acd6697 Mon Sep 17 00:00:00 2001 From: flama12333 <143599905+flama12333@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:42:01 -0500 Subject: [PATCH 209/218] Replace MACHINE_PCI with MACHINE_PS2_PCI for pl4600c machine_table.c this will be solved the ps2 mouse not appear on the setting --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9f2d0ce47..62a0e1374 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8902,7 +8902,7 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_PCI, + .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND | MACHINE_APM, .ram = { .min = 1024, From bd8bade3fbe7d48208d717768abca7536522f9c2 Mon Sep 17 00:00:00 2001 From: flama12333 <143599905+flama12333@users.noreply.github.com> Date: Wed, 26 Mar 2025 01:32:24 -0500 Subject: [PATCH 210/218] update machine_table.c --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 62a0e1374..aa9bae305 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -9358,7 +9358,7 @@ const machine_t machines[] = { .min_multi = MACHINE_MULTIPLIER_FIXED, .max_multi = MACHINE_MULTIPLIER_FIXED }, - .bus_flags = MACHINE_PCI, + .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE | MACHINE_APM, .ram = { .min = 2048, From e5aed7f9e6e13302203e2ac88fd5ff5234392c88 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 16:37:59 +0600 Subject: [PATCH 211/218] Add confirmation dialog checkboxes in Preferences --- src/qt/qt_progsettings.cpp | 4 + src/qt/qt_progsettings.ui | 194 ++++++++++++++++++++----------------- 2 files changed, 108 insertions(+), 90 deletions(-) diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 6ec76a290..059005ca4 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -116,6 +116,8 @@ ProgSettings::ProgSettings(QWidget *parent) ui->horizontalSlider->setValue(mouseSensitivity * 100.); ui->openDirUsrPath->setChecked(open_dir_usr_path > 0); ui->checkBoxMultimediaKeys->setChecked(inhibit_multimedia_keys); + ui->checkBoxConfirmExit->setChecked(confirm_exit); + ui->checkBoxConfirmSave->setChecked(confirm_save); #ifndef Q_OS_WINDOWS ui->checkBoxMultimediaKeys->setHidden(true); #endif @@ -127,6 +129,8 @@ ProgSettings::accept() strcpy(icon_set, ui->comboBox->currentData().toString().toUtf8().data()); lang_id = ui->comboBoxLanguage->currentData().toUInt(); open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; + confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0; + confirm_save = ui->checkBoxConfirmSave->isChecked() ? 1 : 0; inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked(); loadTranslators(QCoreApplication::instance()); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index dc5674425..2dbaa739d 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -29,56 +29,25 @@ QLayout::SizeConstraint::SetFixedSize - - - - <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + + + + Qt::Orientation::Horizontal + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + - Select media images from program working directory + Default - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - 30 - - - - (System Default) - - - - - - + + Default @@ -97,13 +66,20 @@ - - - - Qt::Orientation::Horizontal + + + + Default - - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + + + Select media images from program working directory @@ -121,6 +97,80 @@ + + + + Ask for confirmation before saving settings + + + + + + + 30 + + + + (System Default) + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Inhibit multimedia keys on Windows + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + false + + + 30 + + + + (Default) + + + + + + + + Mouse sensitivity: + + + @@ -143,46 +193,10 @@ - - - - false - - - 30 - - - - (Default) - - - - - - + + - Mouse sensitivity: - - - - - - - Default - - - - - - - Default - - - - - - - Inhibit multimedia keys on Windows + Ask for confirmation before quitting From 38de9b7a1b52a04f300b285bf0a7530d30a67d7d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 16:52:35 +0600 Subject: [PATCH 212/218] Add the other two confirmation dialog checkboxes in Preferences --- src/qt/qt_progsettings.cpp | 5 + src/qt/qt_progsettings.ui | 204 ++++++++++++++++++++----------------- 2 files changed, 114 insertions(+), 95 deletions(-) diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 059005ca4..ce6c21dd6 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -118,6 +118,9 @@ ProgSettings::ProgSettings(QWidget *parent) ui->checkBoxMultimediaKeys->setChecked(inhibit_multimedia_keys); ui->checkBoxConfirmExit->setChecked(confirm_exit); ui->checkBoxConfirmSave->setChecked(confirm_save); + ui->checkBoxConfirmHardReset->setChecked(confirm_reset); + ui->checkBoxFullscreenFirst->setChecked(video_fullscreen_first); + #ifndef Q_OS_WINDOWS ui->checkBoxMultimediaKeys->setHidden(true); #endif @@ -131,6 +134,8 @@ ProgSettings::accept() open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0; confirm_save = ui->checkBoxConfirmSave->isChecked() ? 1 : 0; + confirm_reset = ui->checkBoxConfirmHardReset->isChecked() ? 1 : 0; + video_fullscreen_first = ui->checkBoxFullscreenFirst->isChecked() ? 1 : 0; inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked(); loadTranslators(QCoreApplication::instance()); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index 2dbaa739d..f7b32ce84 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -7,7 +7,7 @@ 0 0 458 - 374 + 391 @@ -29,43 +29,6 @@ QLayout::SizeConstraint::SetFixedSize - - - - Qt::Orientation::Horizontal - - - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok - - - - - - - Default - - - - - - - Default - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - @@ -73,16 +36,6 @@ - - - - <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> - - - Select media images from program working directory - - - @@ -90,32 +43,6 @@ - - - - Language: - - - - - - - Ask for confirmation before saving settings - - - - - - - 30 - - - - (System Default) - - - - @@ -129,10 +56,32 @@ - - + + + + 30 + + + + (System Default) + + + + + + + + <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + - Inhibit multimedia keys on Windows + Select media images from program working directory + + + + + + + Default @@ -149,25 +98,10 @@ - - - - false - - - 30 - - - - (Default) - - - - - - + + - Mouse sensitivity: + Default @@ -193,6 +127,79 @@ + + + + Language: + + + + + + + Ask for confirmation before saving settings + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + Inhibit multimedia keys on Windows + + + + + + + false + + + 30 + + + + (Default) + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Mouse sensitivity: + + + + + + + Ask for confirmation before hard resetting + + + @@ -200,6 +207,13 @@ + + + + Display hotkey message when entering full-screen mode + + + From 0a5fa0da39c12d3f438ea7197943bdf0e2df38e0 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 18 Jan 2025 15:47:41 +0500 Subject: [PATCH 213/218] Add variants of the CH Flightstick Pro and Thrustmaster FCS with rudder pedals (CH Pedals and Thrustmaster RCS respectively) attached --- src/game/gameport.c | 26 +++++++------- src/game/joystick_ch_flightstick_pro.c | 38 ++++++++++++++++++++ src/game/joystick_tm_fcs.c | 48 ++++++++++++++++++++++++++ src/include/86box/gameport.h | 2 ++ 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 90986a655..8ae1c7d25 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -88,18 +88,20 @@ static const joystick_if_t joystick_none = { static const struct { const joystick_if_t *joystick; } joysticks[] = { - { &joystick_none }, - { &joystick_2axis_2button }, - { &joystick_2axis_4button }, - { &joystick_2axis_6button }, - { &joystick_2axis_8button }, - { &joystick_3axis_2button }, - { &joystick_3axis_4button }, - { &joystick_4axis_4button }, - { &joystick_ch_flightstick_pro }, - { &joystick_sw_pad }, - { &joystick_tm_fcs }, - { NULL } + { &joystick_none }, + { &joystick_2axis_2button }, + { &joystick_2axis_4button }, + { &joystick_2axis_6button }, + { &joystick_2axis_8button }, + { &joystick_3axis_2button }, + { &joystick_3axis_4button }, + { &joystick_4axis_4button }, + { &joystick_ch_flightstick_pro }, + { &joystick_ch_flightstick_pro_ch_pedals }, + { &joystick_sw_pad }, + { &joystick_tm_fcs }, + { &joystick_tm_fcs_rcs }, + { NULL } }; static joystick_instance_t *joystick_instance[GAMEPORT_MAX] = { NULL, NULL }; diff --git a/src/game/joystick_ch_flightstick_pro.c b/src/game/joystick_ch_flightstick_pro.c index 6aaaa5dc5..5b240f3f4 100644 --- a/src/game/joystick_ch_flightstick_pro.c +++ b/src/game/joystick_ch_flightstick_pro.c @@ -112,6 +112,26 @@ ch_flightstick_pro_read_axis(UNUSED(void *priv), int axis) } } +static int +ch_flightstick_pro_ch_pedals_read_axis(UNUSED(void *priv), int axis) +{ + if (!JOYSTICK_PRESENT(0, 0)) + return AXIS_NOT_PRESENT; + + switch (axis) { + case 0: + return joystick_state[0][0].axis[0]; + case 1: + return joystick_state[0][0].axis[1]; + case 2: + return joystick_state[0][0].axis[3]; + case 3: + return joystick_state[0][0].axis[2]; + default: + return 0; + } +} + static void ch_flightstick_pro_a0_over(UNUSED(void *priv)) { @@ -135,3 +155,21 @@ const joystick_if_t joystick_ch_flightstick_pro = { .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, .pov_names = { "POV" } }; + +const joystick_if_t joystick_ch_flightstick_pro_ch_pedals = { + .name = "CH Flightstick Pro + CH Pedals", + .internal_name = "ch_flightstick_pro_ch_pedals", + .init = ch_flightstick_pro_init, + .close = ch_flightstick_pro_close, + .read = ch_flightstick_pro_read, + .write = ch_flightstick_pro_write, + .read_axis = ch_flightstick_pro_ch_pedals_read_axis, + .a0_over = ch_flightstick_pro_a0_over, + .axis_count = 4, + .button_count = 4, + .pov_count = 1, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Throttle", "Rudder" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { "POV" } +}; diff --git a/src/game/joystick_tm_fcs.c b/src/game/joystick_tm_fcs.c index 4440b039e..52d77d8fb 100644 --- a/src/game/joystick_tm_fcs.c +++ b/src/game/joystick_tm_fcs.c @@ -112,6 +112,36 @@ tm_fcs_read_axis(UNUSED(void *priv), int axis) } } +static int +tm_fcs_rcs_read_axis(UNUSED(void *priv), int axis) +{ + if (!JOYSTICK_PRESENT(0, 0)) + return AXIS_NOT_PRESENT; + + switch (axis) { + case 0: + return joystick_state[0][0].axis[0]; + case 1: + return joystick_state[0][0].axis[1]; + case 2: + return joystick_state[0][0].axis[2]; + case 3: + if (joystick_state[0][0].pov[0] == -1) + return 32767; + if (joystick_state[0][0].pov[0] > 315 || joystick_state[0][0].pov[0] < 45) + return -32768; + if (joystick_state[0][0].pov[0] >= 45 && joystick_state[0][0].pov[0] < 135) + return -16384; + if (joystick_state[0][0].pov[0] >= 135 && joystick_state[0][0].pov[0] < 225) + return 0; + if (joystick_state[0][0].pov[0] >= 225 && joystick_state[0][0].pov[0] < 315) + return 16384; + return 0; + default: + return 0; + } +} + static void tm_fcs_a0_over(UNUSED(void *priv)) { @@ -135,3 +165,21 @@ const joystick_if_t joystick_tm_fcs = { .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, .pov_names = { "POV" } }; + +const joystick_if_t joystick_tm_fcs_rcs = { + .name = "Thrustmaster FCS + Rudder Control System", + .internal_name = "thrustmaster_fcs_rcs", + .init = tm_fcs_init, + .close = tm_fcs_close, + .read = tm_fcs_read, + .write = tm_fcs_write, + .read_axis = tm_fcs_rcs_read_axis, + .a0_over = tm_fcs_a0_over, + .axis_count = 3, + .button_count = 4, + .pov_count = 1, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Rudder" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { "POV" } +}; diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index c5fc1d192..7928cdd30 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -179,10 +179,12 @@ extern const joystick_if_t joystick_2axis_6button; extern const joystick_if_t joystick_2axis_8button; extern const joystick_if_t joystick_ch_flightstick_pro; +extern const joystick_if_t joystick_ch_flightstick_pro_ch_pedals; extern const joystick_if_t joystick_sw_pad; extern const joystick_if_t joystick_tm_fcs; +extern const joystick_if_t joystick_tm_fcs_rcs; extern int gameport_available(int); extern int gameport_has_config(int); From 99e8d13afa047e3dc7d8aa7afae188e4748055a8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 30 Mar 2024 16:21:41 +0600 Subject: [PATCH 214/218] Implement NEC V20/V30's i8080 emulation mode --- src/cpu/8080.c | 290 ------------- src/cpu/808x.c | 168 +++++++- src/cpu/CMakeLists.txt | 2 +- src/cpu/i8080.c | 826 ++++++++++++++++++++++++++++++++++++++ src/cpu/i8080.h | 35 ++ src/include/86box/i8080.h | 69 ---- 6 files changed, 1025 insertions(+), 365 deletions(-) delete mode 100644 src/cpu/8080.c create mode 100644 src/cpu/i8080.c create mode 100644 src/cpu/i8080.h delete mode 100644 src/include/86box/i8080.h diff --git a/src/cpu/8080.c b/src/cpu/8080.c deleted file mode 100644 index 7a7e7b96c..000000000 --- a/src/cpu/8080.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * 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. - * - * 8080 CPU emulation. - * - * Authors: Cacodemon345 - * - * Copyright 2022 Cacodemon345 - */ - -#include -#include -#include "cpu.h" -#include <86box/timer.h> -#include <86box/i8080.h> -#include <86box/mem.h> -#include <86box/plat_unused.h> - -static int completed = 1; -static int in_rep = 0; -static int repeating = 0; -static int rep_c_flag = 0; -static int oldc; -static int cycdiff; -#ifdef UNUSED_8080_VARS -static int prefetching = 1; -static int refresh = 0; -static int clear_lock = 0; - -static uint32_t cpu_src = 0; -static uint32_t cpu_dest = 0; -static uint32_t cpu_data = 0; -#endif - -static void -clock_start(void) -{ - cycdiff = cycles; -} - -static void -clock_end(void) -{ - int diff = cycdiff - cycles; - - /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ - tsc += (uint64_t) diff * (xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) - timer_process(); -} - -static void -i8080_wait(int c, int bus) -{ - cycles -= c; - if (bus < 2) { - clock_end(); - clock_start(); - } -} - -#ifdef UNUSED_8080_FUNCS -static uint8_t -readmemb(uint32_t a) -{ - uint8_t ret; - - i8080_wait(4, 1); - ret = read_mem_b(a); - - return ret; -} - -static uint8_t -ins_fetch(i8080 *cpu) -{ - uint8_t ret = cpu->readmembyte(cpu->pmembase + cpu->pc); - - cpu->pc++; - return ret; -} -#endif - -void -transfer_from_808x(i8080 *cpu) -{ - cpu->hl = BX; - cpu->bc = CX; - cpu->de = DX; - cpu->a = AL; - cpu->flags = cpu_state.flags & 0xFF; - cpu->sp = BP; - cpu->pc = cpu_state.pc; - cpu->oldpc = cpu_state.oldpc; - cpu->pmembase = cs; - cpu->dmembase = ds; -} - -void -transfer_to_808x(i8080 *cpu) -{ - BX = cpu->hl; - CX = cpu->bc; - DX = cpu->de; - AL = cpu->a; - cpu_state.flags &= 0xFF00; - cpu_state.flags |= cpu->flags & 0xFF; - BP = cpu->sp; - cpu_state.pc = cpu->pc; -} - -uint8_t -getreg_i8080(i8080 *cpu, uint8_t reg) -{ - uint8_t ret = 0xFF; - switch (reg) { - case 0x0: - ret = cpu->b; - break; - case 0x1: - ret = cpu->c; - break; - case 0x2: - ret = cpu->d; - break; - case 0x3: - ret = cpu->e; - break; - case 0x4: - ret = cpu->h; - break; - case 0x5: - ret = cpu->l; - break; - case 0x6: - ret = cpu->readmembyte(cpu->dmembase + cpu->sp); - break; - case 0x7: - ret = cpu->a; - break; - } - return ret; -} - -uint8_t -getreg_i8080_emu(i8080 *cpu, uint8_t reg) -{ - uint8_t ret = 0xFF; - switch (reg) { - case 0x0: - ret = CH; - break; - case 0x1: - ret = CL; - break; - case 0x2: - ret = DH; - break; - case 0x3: - ret = DL; - break; - case 0x4: - ret = BH; - break; - case 0x5: - ret = BL; - break; - case 0x6: - ret = cpu->readmembyte(cpu->dmembase + BP); - break; - case 0x7: - ret = AL; - break; - } - return ret; -} - -void -setreg_i8080_emu(i8080 *cpu, uint8_t reg, uint8_t val) -{ - switch (reg) { - case 0x0: - CH = val; - break; - case 0x1: - CL = val; - break; - case 0x2: - DH = val; - break; - case 0x3: - DL = val; - break; - case 0x4: - BH = val; - break; - case 0x5: - BL = val; - break; - case 0x6: - cpu->writemembyte(cpu->dmembase + BP, val); - break; - case 0x7: - AL = val; - break; - } -} - -void -setreg_i8080(i8080 *cpu, uint8_t reg, uint8_t val) -{ - switch (reg) { - case 0x0: - cpu->b = val; - break; - case 0x1: - cpu->c = val; - break; - case 0x2: - cpu->d = val; - break; - case 0x3: - cpu->e = val; - break; - case 0x4: - cpu->h = val; - break; - case 0x5: - cpu->l = val; - break; - case 0x6: - cpu->writemembyte(cpu->dmembase + cpu->sp, val); - break; - case 0x7: - cpu->a = val; - break; - } -} - -void -interpret_exec8080(UNUSED(i8080 *cpu), uint8_t opcode) -{ - switch (opcode) { - case 0x00: - { - break; - } - } -} - -/* Actually implement i8080 emulation. */ -void -exec8080(i8080 *cpu, int cycs) -{ -#ifdef UNUSED_8080_VARS - uint8_t temp = 0, temp2; - uint8_t old_af; - uint8_t handled = 0; - uint16_t addr, tempw; - uint16_t new_ip; - int bits; -#endif - - cycles += cycs; - - while (cycles > 0) { - cpu->startclock(); - - if (!repeating) { - cpu->oldpc = cpu->pc; - opcode = cpu->fetchinstruction(cpu); - oldc = cpu->flags & C_FLAG_I8080; - i8080_wait(1, 0); - } - completed = 1; - if (completed) { - repeating = 0; - in_rep = 0; - rep_c_flag = 0; - cpu->endclock(); - if (cpu->checkinterrupts) - cpu->checkinterrupts(); - } - } -} diff --git a/src/cpu/808x.c b/src/cpu/808x.c index e3a326503..4ce1fa3b9 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -18,10 +18,13 @@ #include #include #include +#include #include #include #include +#include "i8080.h" + #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" @@ -70,6 +73,9 @@ static int in_rep = 0, repeating = 0, rep_c_flag = 0; static int oldc, clear_lock = 0; static int refresh = 0, cycdiff; +static i8080 emulated_processor; +static bool cpu_md_write_disable = 1; + /* Various things needed for 8087. */ #define OP_TABLE(name) ops_##name @@ -195,6 +201,54 @@ prefetch_queue_get_size(void) { return pfq_size; } +static void set_if(int cond); + +void +sync_from_i8080(void) +{ + AL = emulated_processor.a; + BH = emulated_processor.h; + BL = emulated_processor.l; + CH = emulated_processor.b; + CL = emulated_processor.c; + DH = emulated_processor.d; + DL = emulated_processor.e; + BP = emulated_processor.sp; + + cpu_state.pc = emulated_processor.pc; + cpu_state.flags &= 0xFF00; + cpu_state.flags |= emulated_processor.sf << 7; + cpu_state.flags |= emulated_processor.zf << 6; + cpu_state.flags |= emulated_processor.hf << 4; + cpu_state.flags |= emulated_processor.pf << 2; + cpu_state.flags |= 1 << 1; + cpu_state.flags |= emulated_processor.cf << 0; + set_if(emulated_processor.iff); +} + +void +sync_to_i8080(void) +{ + emulated_processor.a = AL; + emulated_processor.h = BH; + emulated_processor.l = BL; + emulated_processor.b = CH; + emulated_processor.c = CL; + emulated_processor.d = DH; + emulated_processor.e = DL; + emulated_processor.sp = BP; + emulated_processor.pc = cpu_state.pc; + emulated_processor.iff = !!(cpu_state.flags & I_FLAG); + + emulated_processor.sf = (cpu_state.flags >> 7) & 1; + emulated_processor.zf = (cpu_state.flags >> 6) & 1; + emulated_processor.hf = (cpu_state.flags >> 4) & 1; + emulated_processor.pf = (cpu_state.flags >> 2) & 1; + emulated_processor.cf = (cpu_state.flags >> 0) & 1; + + emulated_processor.interrupt_delay = noint; +} + uint16_t get_last_addr(void) @@ -582,6 +636,33 @@ load_seg(uint16_t seg, x86seg *s) s->seg = seg & 0xffff; } +uint8_t fetch_i8080_opcode(UNUSED(void* priv), uint16_t addr) +{ + return readmemb(cs + addr); +} + +uint8_t fetch_i8080_data(UNUSED(void* priv), uint16_t addr) +{ + return readmemb(ds + addr); +} + +void put_i8080_data(UNUSED(void* priv), uint16_t addr, uint8_t val) +{ + writememb(ds, addr, val); +} + +static uint8_t i8080_port_in(UNUSED(void* priv), uint8_t port) +{ + cpu_io(8, 0, port); + return AL; +} + +static void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val) +{ + AL = val; + cpu_io(8, 1, port); +} + void reset_808x(int hard) { @@ -619,6 +700,14 @@ reset_808x(int hard) use_custom_nmi_vector = 0x00; custom_nmi_vector = 0x00000000; + + cpu_md_write_disable = 1; + i8080_init(&emulated_processor); + emulated_processor.write_byte = put_i8080_data; + emulated_processor.read_byte = fetch_i8080_data; + emulated_processor.read_byte_seg = fetch_i8080_opcode; + emulated_processor.port_in = i8080_port_in; + emulated_processor.port_out = i8080_port_out; } static void @@ -994,6 +1083,11 @@ interrupt(uint16_t addr) uint16_t new_cs, new_ip; uint16_t tempf; + if (!(cpu_state.flags & MD_FLAG) && is_nec) { + sync_from_i8080(); + pclog("CALLN/INT#/NMI#\n"); + } + addr <<= 2; cpu_state.eaaddr = addr; old_cs = CS; @@ -1010,6 +1104,8 @@ interrupt(uint16_t addr) tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); + if (is_nec) + cpu_state.flags |= MD_FLAG; access(40, 16); push(&old_cs); old_ip = cpu_state.pc; @@ -1020,6 +1116,56 @@ interrupt(uint16_t addr) push(&old_ip); } +/* Ditto, but for breaking into emulation mode. */ +static void +interrupt_brkem(uint16_t addr) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + uint16_t tempf; + + addr <<= 2; + cpu_state.eaaddr = addr; + old_cs = CS; + access(5, 16); + new_ip = readmemw(0, cpu_state.eaaddr); + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + access(6, 16); + new_cs = readmemw(0, cpu_state.eaaddr); + prefetching = 0; + pfq_clear(); + ovr_seg = NULL; + access(39, 16); + tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); + push(&tempf); + cpu_state.flags &= ~(MD_FLAG); + cpu_md_write_disable = 0; + access(40, 16); + push(&old_cs); + old_ip = cpu_state.pc; + load_cs(new_cs); + access(68, 16); + set_ip(new_ip); + access(41, 16); + push(&old_ip); + sync_to_i8080(); + pclog("BRKEM mode\n"); +} + +void +retem_i8080(void) +{ + sync_from_i8080(); + + cpu_state.pc = pop(); + CS = pop(); + cpu_state.flags = pop() | MD_FLAG; + + cpu_md_write_disable = 1; + pclog("RETEM mode\n"); +} + void interrupt_808x(uint16_t addr) { @@ -1771,6 +1917,15 @@ execx86(int cycs) while (cycles > 0) { clock_start(); + if (is_nec && !(cpu_state.flags & MD_FLAG)) { + i8080_step(&emulated_processor); + set_if(emulated_processor.iff); + cycles -= emulated_processor.cyc; + emulated_processor.cyc = 0; + completed = 1; + goto exec_completed; + } + if (!repeating) { cpu_state.oldpc = cpu_state.pc; opcode = pfq_fetchb(); @@ -2344,8 +2499,8 @@ execx86(int cycs) break; case 0xFF: /* BRKEM */ - /* Unimplemented for now. */ - fatal("808x: Unsupported 8080 emulation mode attempted to enter into!"); + interrupt_brkem(pfq_fetchb()); + handled = 1; break; default: @@ -2857,11 +3012,12 @@ execx86(int cycs) break; case 0x9D: /*POPF*/ access(25, 16); - if (is_nec) + if (is_nec && cpu_md_write_disable) cpu_state.flags = pop() | 0x8002; else cpu_state.flags = pop() | 0x0002; wait(1, 0); + sync_to_i8080(); break; case 0x9E: /*SAHF*/ wait(1, 0); @@ -3127,13 +3283,15 @@ execx86(int cycs) access(62, 8); set_ip(new_ip); access(45, 8); - if (is_nec) + if (is_nec && cpu_md_write_disable) cpu_state.flags = pop() | 0x8002; else cpu_state.flags = pop() | 0x0002; wait(5, 0); noint = 1; nmi_enable = 1; + if (is_nec && !(cpu_state.flags & MD_FLAG)) + sync_to_i8080(); break; case 0xD0: @@ -3659,7 +3817,7 @@ execx86(int cycs) break; } } - +exec_completed: if (completed) { repeating = 0; ovr_seg = NULL; diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt index 9c1385d4f..dc7f5ac11 100644 --- a/src/cpu/CMakeLists.txt +++ b/src/cpu/CMakeLists.txt @@ -29,7 +29,7 @@ add_library(cpu OBJECT x86seg_2386.c x87.c x87_timings.c - 8080.c + i8080.c ) if(AMD_K5) diff --git a/src/cpu/i8080.c b/src/cpu/i8080.c new file mode 100644 index 000000000..688923997 --- /dev/null +++ b/src/cpu/i8080.c @@ -0,0 +1,826 @@ +/* + * 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. + * + * Intel 8080 CPU emulation + * + * Authors: Cacodemon345 + * Nicolas Allemand + * + * Copyright (c) 2018 Nicolas Allemand + * Copyright (c) 2024 Cacodemon345 + * + */ + +#include "i8080.h" +#include + +// Changes from upstream: +// Add CALLN and RETEM instructions. +// Add code for instruction fetches. + +// this array defines the number of cycles one opcode takes. +// note that there are some special cases: conditional RETs and CALLs +// add +6 cycles if the condition is met +// clang-format off +static const uint8_t OPCODES_CYCLES[256] = { +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 0 + 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 1 + 4, 10, 16, 5, 5, 5, 7, 4, 4, 10, 16, 5, 5, 5, 7, 4, // 2 + 4, 10, 13, 5, 10, 10, 10, 4, 4, 10, 13, 5, 5, 5, 7, 4, // 3 + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 4 + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 5 + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 6 + 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5, // 7 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B + 5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // C + 5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // D + 5, 10, 10, 18, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11, // E + 5, 10, 10, 4, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11 // F +}; +// clang-format on + +static const char* DISASSEMBLE_TABLE[] = {"nop", "lxi b,#", "stax b", "inx b", + "inr b", "dcr b", "mvi b,#", "rlc", "ill", "dad b", "ldax b", "dcx b", + "inr c", "dcr c", "mvi c,#", "rrc", "ill", "lxi d,#", "stax d", "inx d", + "inr d", "dcr d", "mvi d,#", "ral", "ill", "dad d", "ldax d", "dcx d", + "inr e", "dcr e", "mvi e,#", "rar", "ill", "lxi h,#", "shld", "inx h", + "inr h", "dcr h", "mvi h,#", "daa", "ill", "dad h", "lhld", "dcx h", + "inr l", "dcr l", "mvi l,#", "cma", "ill", "lxi sp,#", "sta $", "inx sp", + "inr M", "dcr M", "mvi M,#", "stc", "ill", "dad sp", "lda $", "dcx sp", + "inr a", "dcr a", "mvi a,#", "cmc", "mov b,b", "mov b,c", "mov b,d", + "mov b,e", "mov b,h", "mov b,l", "mov b,M", "mov b,a", "mov c,b", "mov c,c", + "mov c,d", "mov c,e", "mov c,h", "mov c,l", "mov c,M", "mov c,a", "mov d,b", + "mov d,c", "mov d,d", "mov d,e", "mov d,h", "mov d,l", "mov d,M", "mov d,a", + "mov e,b", "mov e,c", "mov e,d", "mov e,e", "mov e,h", "mov e,l", "mov e,M", + "mov e,a", "mov h,b", "mov h,c", "mov h,d", "mov h,e", "mov h,h", "mov h,l", + "mov h,M", "mov h,a", "mov l,b", "mov l,c", "mov l,d", "mov l,e", "mov l,h", + "mov l,l", "mov l,M", "mov l,a", "mov M,b", "mov M,c", "mov M,d", "mov M,e", + "mov M,h", "mov M,l", "hlt", "mov M,a", "mov a,b", "mov a,c", "mov a,d", + "mov a,e", "mov a,h", "mov a,l", "mov a,M", "mov a,a", "add b", "add c", + "add d", "add e", "add h", "add l", "add M", "add a", "adc b", "adc c", + "adc d", "adc e", "adc h", "adc l", "adc M", "adc a", "sub b", "sub c", + "sub d", "sub e", "sub h", "sub l", "sub M", "sub a", "sbb b", "sbb c", + "sbb d", "sbb e", "sbb h", "sbb l", "sbb M", "sbb a", "ana b", "ana c", + "ana d", "ana e", "ana h", "ana l", "ana M", "ana a", "xra b", "xra c", + "xra d", "xra e", "xra h", "xra l", "xra M", "xra a", "ora b", "ora c", + "ora d", "ora e", "ora h", "ora l", "ora M", "ora a", "cmp b", "cmp c", + "cmp d", "cmp e", "cmp h", "cmp l", "cmp M", "cmp a", "rnz", "pop b", + "jnz $", "jmp $", "cnz $", "push b", "adi #", "rst 0", "rz", "ret", "jz $", + "ill", "cz $", "call $", "aci #", "rst 1", "rnc", "pop d", "jnc $", "out p", + "cnc $", "push d", "sui #", "rst 2", "rc", "ill", "jc $", "in p", "cc $", + "ill", "sbi #", "rst 3", "rpo", "pop h", "jpo $", "xthl", "cpo $", "push h", + "ani #", "rst 4", "rpe", "pchl", "jpe $", "xchg", "cpe $", "ill", "xri #", + "rst 5", "rp", "pop psw", "jp $", "di", "cp $", "push psw", "ori #", + "rst 6", "rm", "sphl", "jm $", "ei", "cm $", "ill", "cpi #", "rst 7"}; + +#define SET_ZSP(c, val) \ + do { \ + c->zf = (val) == 0; \ + c->sf = (val) >> 7; \ + c->pf = parity(val); \ + } while (0) + +// memory helpers (the only four to use `read_byte` and `write_byte` function +// pointers) + +// reads a byte from memory +static inline uint8_t i8080_rb(i8080* const c, uint16_t addr) { + return c->read_byte(c->userdata, addr); +} + +// writes a byte to memory +static inline void i8080_wb(i8080* const c, uint16_t addr, uint8_t val) { + c->write_byte(c->userdata, addr, val); +} + +// reads a word from memory +static inline uint16_t i8080_rw(i8080* const c, uint16_t addr) { + return c->read_byte(c->userdata, addr + 1) << 8 | + c->read_byte(c->userdata, addr); +} + +// writes a word to memory +static inline void i8080_ww(i8080* const c, uint16_t addr, uint16_t val) { + c->write_byte(c->userdata, addr, val & 0xFF); + c->write_byte(c->userdata, addr + 1, val >> 8); +} + +// returns the next byte in memory (and updates the program counter) +static inline uint8_t i8080_next_byte(i8080* const c) { + return c->read_byte_seg ? (c->read_byte_seg(c->userdata, c->pc++)) : i8080_rb(c, c->pc++); +} + +// returns the next word in memory (and updates the program counter) +static inline uint16_t i8080_next_word(i8080* const c) { + uint16_t result = 0; + if (c->read_byte_seg) + result = c->read_byte_seg(c, c->pc) | (c->read_byte_seg(c, c->pc + 1) << 8); + else + result = i8080_rw(c, c->pc); + c->pc += 2; + return result; +} + +// paired registers helpers (setters and getters) +static inline void i8080_set_bc(i8080* const c, uint16_t val) { + c->b = val >> 8; + c->c = val & 0xFF; +} + +static inline void i8080_set_de(i8080* const c, uint16_t val) { + c->d = val >> 8; + c->e = val & 0xFF; +} + +static inline void i8080_set_hl(i8080* const c, uint16_t val) { + c->h = val >> 8; + c->l = val & 0xFF; +} + +static inline uint16_t i8080_get_bc(i8080* const c) { + return (c->b << 8) | c->c; +} + +static inline uint16_t i8080_get_de(i8080* const c) { + return (c->d << 8) | c->e; +} + +static inline uint16_t i8080_get_hl(i8080* const c) { + return (c->h << 8) | c->l; +} + +// stack helpers + +// pushes a value into the stack and updates the stack pointer +static inline void i8080_push_stack(i8080* const c, uint16_t val) { + c->sp -= 2; + i8080_ww(c, c->sp, val); +} + +// pops a value from the stack and updates the stack pointer +static inline uint16_t i8080_pop_stack(i8080* const c) { + uint16_t val = i8080_rw(c, c->sp); + c->sp += 2; + return val; +} + +// opcodes + +// returns the parity of byte: 0 if number of 1 bits in `val` is odd, else 1 +static inline bool parity(uint8_t val) { + uint8_t nb_one_bits = 0; + for (int i = 0; i < 8; i++) { + nb_one_bits += ((val >> i) & 1); + } + + return (nb_one_bits & 1) == 0; +} + +// returns if there was a carry between bit "bit_no" and "bit_no - 1" when +// executing "a + b + cy" +static inline bool carry(int bit_no, uint8_t a, uint8_t b, bool cy) { + int16_t result = a + b + cy; + int16_t carry = result ^ a ^ b; + return carry & (1 << bit_no); +} + +// adds a value (+ an optional carry flag) to a register +static inline void i8080_add( + i8080* const c, uint8_t* const reg, uint8_t val, bool cy) { + uint8_t result = *reg + val + cy; + c->cf = carry(8, *reg, val, cy); + c->hf = carry(4, *reg, val, cy); + SET_ZSP(c, result); + *reg = result; +} + +// substracts a byte (+ an optional carry flag) from a register +// see https://stackoverflow.com/a/8037485 +static inline void i8080_sub( + i8080* const c, uint8_t* const reg, uint8_t val, bool cy) { + i8080_add(c, reg, ~val, !cy); + c->cf = !c->cf; +} + +// adds a word to HL +static inline void i8080_dad(i8080* const c, uint16_t val) { + c->cf = ((i8080_get_hl(c) + val) >> 16) & 1; + i8080_set_hl(c, i8080_get_hl(c) + val); +} + +// increments a byte +static inline uint8_t i8080_inr(i8080* const c, uint8_t val) { + uint8_t result = val + 1; + c->hf = (result & 0xF) == 0; + SET_ZSP(c, result); + return result; +} + +// decrements a byte +static inline uint8_t i8080_dcr(i8080* const c, uint8_t val) { + uint8_t result = val - 1; + c->hf = !((result & 0xF) == 0xF); + SET_ZSP(c, result); + return result; +} + +// executes a logic "and" between register A and a byte, then stores the +// result in register A +static inline void i8080_ana(i8080* const c, uint8_t val) { + uint8_t result = c->a & val; + c->cf = 0; + c->hf = ((c->a | val) & 0x08) != 0; + SET_ZSP(c, result); + c->a = result; +} + +// executes a logic "xor" between register A and a byte, then stores the +// result in register A +static inline void i8080_xra(i8080* const c, uint8_t val) { + c->a ^= val; + c->cf = 0; + c->hf = 0; + SET_ZSP(c, c->a); +} + +// executes a logic "or" between register A and a byte, then stores the +// result in register A +static inline void i8080_ora(i8080* const c, uint8_t val) { + c->a |= val; + c->cf = 0; + c->hf = 0; + SET_ZSP(c, c->a); +} + +// compares the register A to another byte +static inline void i8080_cmp(i8080* const c, uint8_t val) { + int16_t result = c->a - val; + c->cf = result >> 8; + c->hf = ~(c->a ^ result ^ val) & 0x10; + SET_ZSP(c, result & 0xFF); +} + +// sets the program counter to a given address +static inline void i8080_jmp(i8080* const c, uint16_t addr) { + c->pc = addr; +} + +// jumps to next address pointed by the next word in memory if a condition +// is met +static inline void i8080_cond_jmp(i8080* const c, bool condition) { + uint16_t addr = i8080_next_word(c); + if (condition) { + c->pc = addr; + } +} + +// pushes the current pc to the stack, then jumps to an address +static inline void i8080_call(i8080* const c, uint16_t addr) { + i8080_push_stack(c, c->pc); + i8080_jmp(c, addr); +} + +// calls to next word in memory if a condition is met +static inline void i8080_cond_call(i8080* const c, bool condition) { + uint16_t addr = i8080_next_word(c); + if (condition) { + i8080_call(c, addr); + c->cyc += 6; + } +} + +// returns from subroutine +static inline void i8080_ret(i8080* const c) { + c->pc = i8080_pop_stack(c); +} + +// returns from subroutine if a condition is met +static inline void i8080_cond_ret(i8080* const c, bool condition) { + if (condition) { + i8080_ret(c); + c->cyc += 6; + } +} + +// pushes register A and the flags into the stack +static inline void i8080_push_psw(i8080* const c) { + // note: bit 3 and 5 are always 0 + uint8_t psw = 0; + psw |= c->sf << 7; + psw |= c->zf << 6; + psw |= c->hf << 4; + psw |= c->pf << 2; + psw |= 1 << 1; // bit 1 is always 1 + psw |= c->cf << 0; + i8080_push_stack(c, c->a << 8 | psw); +} + +// pops register A and the flags from the stack +static inline void i8080_pop_psw(i8080* const c) { + uint16_t af = i8080_pop_stack(c); + c->a = af >> 8; + uint8_t psw = af & 0xFF; + + c->sf = (psw >> 7) & 1; + c->zf = (psw >> 6) & 1; + c->hf = (psw >> 4) & 1; + c->pf = (psw >> 2) & 1; + c->cf = (psw >> 0) & 1; +} + +// rotate register A left +static inline void i8080_rlc(i8080* const c) { + c->cf = c->a >> 7; + c->a = (c->a << 1) | c->cf; +} + +// rotate register A right +static inline void i8080_rrc(i8080* const c) { + c->cf = c->a & 1; + c->a = (c->a >> 1) | (c->cf << 7); +} + +// rotate register A left with the carry flag +static inline void i8080_ral(i8080* const c) { + bool cy = c->cf; + c->cf = c->a >> 7; + c->a = (c->a << 1) | cy; +} + +// rotate register A right with the carry flag +static inline void i8080_rar(i8080* const c) { + bool cy = c->cf; + c->cf = c->a & 1; + c->a = (c->a >> 1) | (cy << 7); +} + +// Decimal Adjust Accumulator: the eight-bit number in register A is adjusted +// to form two four-bit binary-coded-decimal digits. +// For example, if A=$2B and DAA is executed, A becomes $31. +static inline void i8080_daa(i8080* const c) { + bool cy = c->cf; + uint8_t correction = 0; + + uint8_t lsb = c->a & 0x0F; + uint8_t msb = c->a >> 4; + + if (c->hf || lsb > 9) { + correction += 0x06; + } + + if (c->cf || msb > 9 || (msb >= 9 && lsb > 9)) { + correction += 0x60; + cy = 1; + } + + i8080_add(c, &c->a, correction, 0); + c->cf = cy; +} + +// switches the value of registers DE and HL +static inline void i8080_xchg(i8080* const c) { + uint16_t de = i8080_get_de(c); + i8080_set_de(c, i8080_get_hl(c)); + i8080_set_hl(c, de); +} + +// switches the value of a word at (sp) and HL +static inline void i8080_xthl(i8080* const c) { + uint16_t val = i8080_rw(c, c->sp); + i8080_ww(c, c->sp, i8080_get_hl(c)); + i8080_set_hl(c, val); +} + +extern void interrupt_808x(uint16_t addr); +extern void retem_i8080(void); +// executes one opcode +static inline void i8080_execute(i8080* const c, uint8_t opcode) { + c->cyc += OPCODES_CYCLES[opcode]; + + // when DI is executed, interrupts won't be serviced + // until the end of next instruction: + if (c->interrupt_delay > 0) { + c->interrupt_delay -= 1; + } + + switch (opcode) { + case 0x7F: c->a = c->a; break; // MOV A,A + case 0x78: c->a = c->b; break; // MOV A,B + case 0x79: c->a = c->c; break; // MOV A,C + case 0x7A: c->a = c->d; break; // MOV A,D + case 0x7B: c->a = c->e; break; // MOV A,E + case 0x7C: c->a = c->h; break; // MOV A,H + case 0x7D: c->a = c->l; break; // MOV A,L + case 0x7E: c->a = i8080_rb(c, i8080_get_hl(c)); break; // MOV A,M + + case 0x0A: c->a = i8080_rb(c, i8080_get_bc(c)); break; // LDAX B + case 0x1A: c->a = i8080_rb(c, i8080_get_de(c)); break; // LDAX D + case 0x3A: c->a = i8080_rb(c, i8080_next_word(c)); break; // LDA word + + case 0x47: c->b = c->a; break; // MOV B,A + case 0x40: c->b = c->b; break; // MOV B,B + case 0x41: c->b = c->c; break; // MOV B,C + case 0x42: c->b = c->d; break; // MOV B,D + case 0x43: c->b = c->e; break; // MOV B,E + case 0x44: c->b = c->h; break; // MOV B,H + case 0x45: c->b = c->l; break; // MOV B,L + case 0x46: c->b = i8080_rb(c, i8080_get_hl(c)); break; // MOV B,M + + case 0x4F: c->c = c->a; break; // MOV C,A + case 0x48: c->c = c->b; break; // MOV C,B + case 0x49: c->c = c->c; break; // MOV C,C + case 0x4A: c->c = c->d; break; // MOV C,D + case 0x4B: c->c = c->e; break; // MOV C,E + case 0x4C: c->c = c->h; break; // MOV C,H + case 0x4D: c->c = c->l; break; // MOV C,L + case 0x4E: c->c = i8080_rb(c, i8080_get_hl(c)); break; // MOV C,M + + case 0x57: c->d = c->a; break; // MOV D,A + case 0x50: c->d = c->b; break; // MOV D,B + case 0x51: c->d = c->c; break; // MOV D,C + case 0x52: c->d = c->d; break; // MOV D,D + case 0x53: c->d = c->e; break; // MOV D,E + case 0x54: c->d = c->h; break; // MOV D,H + case 0x55: c->d = c->l; break; // MOV D,L + case 0x56: c->d = i8080_rb(c, i8080_get_hl(c)); break; // MOV D,M + + case 0x5F: c->e = c->a; break; // MOV E,A + case 0x58: c->e = c->b; break; // MOV E,B + case 0x59: c->e = c->c; break; // MOV E,C + case 0x5A: c->e = c->d; break; // MOV E,D + case 0x5B: c->e = c->e; break; // MOV E,E + case 0x5C: c->e = c->h; break; // MOV E,H + case 0x5D: c->e = c->l; break; // MOV E,L + case 0x5E: c->e = i8080_rb(c, i8080_get_hl(c)); break; // MOV E,M + + case 0x67: c->h = c->a; break; // MOV H,A + case 0x60: c->h = c->b; break; // MOV H,B + case 0x61: c->h = c->c; break; // MOV H,C + case 0x62: c->h = c->d; break; // MOV H,D + case 0x63: c->h = c->e; break; // MOV H,E + case 0x64: c->h = c->h; break; // MOV H,H + case 0x65: c->h = c->l; break; // MOV H,L + case 0x66: c->h = i8080_rb(c, i8080_get_hl(c)); break; // MOV H,M + + case 0x6F: c->l = c->a; break; // MOV L,A + case 0x68: c->l = c->b; break; // MOV L,B + case 0x69: c->l = c->c; break; // MOV L,C + case 0x6A: c->l = c->d; break; // MOV L,D + case 0x6B: c->l = c->e; break; // MOV L,E + case 0x6C: c->l = c->h; break; // MOV L,H + case 0x6D: c->l = c->l; break; // MOV L,L + case 0x6E: c->l = i8080_rb(c, i8080_get_hl(c)); break; // MOV L,M + + case 0x77: i8080_wb(c, i8080_get_hl(c), c->a); break; // MOV M,A + case 0x70: i8080_wb(c, i8080_get_hl(c), c->b); break; // MOV M,B + case 0x71: i8080_wb(c, i8080_get_hl(c), c->c); break; // MOV M,C + case 0x72: i8080_wb(c, i8080_get_hl(c), c->d); break; // MOV M,D + case 0x73: i8080_wb(c, i8080_get_hl(c), c->e); break; // MOV M,E + case 0x74: i8080_wb(c, i8080_get_hl(c), c->h); break; // MOV M,H + case 0x75: i8080_wb(c, i8080_get_hl(c), c->l); break; // MOV M,L + + case 0x3E: c->a = i8080_next_byte(c); break; // MVI A,byte + case 0x06: c->b = i8080_next_byte(c); break; // MVI B,byte + case 0x0E: c->c = i8080_next_byte(c); break; // MVI C,byte + case 0x16: c->d = i8080_next_byte(c); break; // MVI D,byte + case 0x1E: c->e = i8080_next_byte(c); break; // MVI E,byte + case 0x26: c->h = i8080_next_byte(c); break; // MVI H,byte + case 0x2E: c->l = i8080_next_byte(c); break; // MVI L,byte + case 0x36: + i8080_wb(c, i8080_get_hl(c), i8080_next_byte(c)); + break; // MVI M,byte + + case 0x02: i8080_wb(c, i8080_get_bc(c), c->a); break; // STAX B + case 0x12: i8080_wb(c, i8080_get_de(c), c->a); break; // STAX D + case 0x32: i8080_wb(c, i8080_next_word(c), c->a); break; // STA word + + case 0x01: i8080_set_bc(c, i8080_next_word(c)); break; // LXI B,word + case 0x11: i8080_set_de(c, i8080_next_word(c)); break; // LXI D,word + case 0x21: i8080_set_hl(c, i8080_next_word(c)); break; // LXI H,word + case 0x31: c->sp = i8080_next_word(c); break; // LXI SP,word + case 0x2A: i8080_set_hl(c, i8080_rw(c, i8080_next_word(c))); break; // LHLD + case 0x22: i8080_ww(c, i8080_next_word(c), i8080_get_hl(c)); break; // SHLD + case 0xF9: c->sp = i8080_get_hl(c); break; // SPHL + + case 0xEB: i8080_xchg(c); break; // XCHG + case 0xE3: i8080_xthl(c); break; // XTHL + + case 0x87: i8080_add(c, &c->a, c->a, 0); break; // ADD A + case 0x80: i8080_add(c, &c->a, c->b, 0); break; // ADD B + case 0x81: i8080_add(c, &c->a, c->c, 0); break; // ADD C + case 0x82: i8080_add(c, &c->a, c->d, 0); break; // ADD D + case 0x83: i8080_add(c, &c->a, c->e, 0); break; // ADD E + case 0x84: i8080_add(c, &c->a, c->h, 0); break; // ADD H + case 0x85: i8080_add(c, &c->a, c->l, 0); break; // ADD L + case 0x86: + i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0); + break; // ADD M + case 0xC6: i8080_add(c, &c->a, i8080_next_byte(c), 0); break; // ADI byte + + case 0x8F: i8080_add(c, &c->a, c->a, c->cf); break; // ADC A + case 0x88: i8080_add(c, &c->a, c->b, c->cf); break; // ADC B + case 0x89: i8080_add(c, &c->a, c->c, c->cf); break; // ADC C + case 0x8A: i8080_add(c, &c->a, c->d, c->cf); break; // ADC D + case 0x8B: i8080_add(c, &c->a, c->e, c->cf); break; // ADC E + case 0x8C: i8080_add(c, &c->a, c->h, c->cf); break; // ADC H + case 0x8D: i8080_add(c, &c->a, c->l, c->cf); break; // ADC L + case 0x8E: + i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf); + break; // ADC M + case 0xCE: i8080_add(c, &c->a, i8080_next_byte(c), c->cf); break; // ACI byte + + case 0x97: i8080_sub(c, &c->a, c->a, 0); break; // SUB A + case 0x90: i8080_sub(c, &c->a, c->b, 0); break; // SUB B + case 0x91: i8080_sub(c, &c->a, c->c, 0); break; // SUB C + case 0x92: i8080_sub(c, &c->a, c->d, 0); break; // SUB D + case 0x93: i8080_sub(c, &c->a, c->e, 0); break; // SUB E + case 0x94: i8080_sub(c, &c->a, c->h, 0); break; // SUB H + case 0x95: i8080_sub(c, &c->a, c->l, 0); break; // SUB L + case 0x96: + i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0); + break; // SUB M + case 0xD6: i8080_sub(c, &c->a, i8080_next_byte(c), 0); break; // SUI byte + + case 0x9F: i8080_sub(c, &c->a, c->a, c->cf); break; // SBB A + case 0x98: i8080_sub(c, &c->a, c->b, c->cf); break; // SBB B + case 0x99: i8080_sub(c, &c->a, c->c, c->cf); break; // SBB C + case 0x9A: i8080_sub(c, &c->a, c->d, c->cf); break; // SBB D + case 0x9B: i8080_sub(c, &c->a, c->e, c->cf); break; // SBB E + case 0x9C: i8080_sub(c, &c->a, c->h, c->cf); break; // SBB H + case 0x9D: i8080_sub(c, &c->a, c->l, c->cf); break; // SBB L + case 0x9E: + i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf); + break; // SBB M + case 0xDE: i8080_sub(c, &c->a, i8080_next_byte(c), c->cf); break; // SBI byte + + case 0x09: i8080_dad(c, i8080_get_bc(c)); break; // DAD B + case 0x19: i8080_dad(c, i8080_get_de(c)); break; // DAD D + case 0x29: i8080_dad(c, i8080_get_hl(c)); break; // DAD H + case 0x39: i8080_dad(c, c->sp); break; // DAD SP + + case 0xF3: c->iff = 0; break; // DI + case 0xFB: + c->iff = 1; + c->interrupt_delay = 1; + break; // EI + case 0x00: break; // NOP + case 0x76: c->halted = 1; break; // HLT + + case 0x3C: c->a = i8080_inr(c, c->a); break; // INR A + case 0x04: c->b = i8080_inr(c, c->b); break; // INR B + case 0x0C: c->c = i8080_inr(c, c->c); break; // INR C + case 0x14: c->d = i8080_inr(c, c->d); break; // INR D + case 0x1C: c->e = i8080_inr(c, c->e); break; // INR E + case 0x24: c->h = i8080_inr(c, c->h); break; // INR H + case 0x2C: c->l = i8080_inr(c, c->l); break; // INR L + case 0x34: + i8080_wb(c, i8080_get_hl(c), i8080_inr(c, i8080_rb(c, i8080_get_hl(c)))); + break; // INR M + + case 0x3D: c->a = i8080_dcr(c, c->a); break; // DCR A + case 0x05: c->b = i8080_dcr(c, c->b); break; // DCR B + case 0x0D: c->c = i8080_dcr(c, c->c); break; // DCR C + case 0x15: c->d = i8080_dcr(c, c->d); break; // DCR D + case 0x1D: c->e = i8080_dcr(c, c->e); break; // DCR E + case 0x25: c->h = i8080_dcr(c, c->h); break; // DCR H + case 0x2D: c->l = i8080_dcr(c, c->l); break; // DCR L + case 0x35: + i8080_wb(c, i8080_get_hl(c), i8080_dcr(c, i8080_rb(c, i8080_get_hl(c)))); + break; // DCR M + + case 0x03: i8080_set_bc(c, i8080_get_bc(c) + 1); break; // INX B + case 0x13: i8080_set_de(c, i8080_get_de(c) + 1); break; // INX D + case 0x23: i8080_set_hl(c, i8080_get_hl(c) + 1); break; // INX H + case 0x33: c->sp += 1; break; // INX SP + + case 0x0B: i8080_set_bc(c, i8080_get_bc(c) - 1); break; // DCX B + case 0x1B: i8080_set_de(c, i8080_get_de(c) - 1); break; // DCX D + case 0x2B: i8080_set_hl(c, i8080_get_hl(c) - 1); break; // DCX H + case 0x3B: c->sp -= 1; break; // DCX SP + + case 0x27: i8080_daa(c); break; // DAA + case 0x2F: c->a = ~c->a; break; // CMA + case 0x37: c->cf = 1; break; // STC + case 0x3F: c->cf = !c->cf; break; // CMC + + case 0x07: i8080_rlc(c); break; // RLC (rotate left) + case 0x0F: i8080_rrc(c); break; // RRC (rotate right) + case 0x17: i8080_ral(c); break; // RAL + case 0x1F: i8080_rar(c); break; // RAR + + case 0xA7: i8080_ana(c, c->a); break; // ANA A + case 0xA0: i8080_ana(c, c->b); break; // ANA B + case 0xA1: i8080_ana(c, c->c); break; // ANA C + case 0xA2: i8080_ana(c, c->d); break; // ANA D + case 0xA3: i8080_ana(c, c->e); break; // ANA E + case 0xA4: i8080_ana(c, c->h); break; // ANA H + case 0xA5: i8080_ana(c, c->l); break; // ANA L + case 0xA6: i8080_ana(c, i8080_rb(c, i8080_get_hl(c))); break; // ANA M + case 0xE6: i8080_ana(c, i8080_next_byte(c)); break; // ANI byte + + case 0xAF: i8080_xra(c, c->a); break; // XRA A + case 0xA8: i8080_xra(c, c->b); break; // XRA B + case 0xA9: i8080_xra(c, c->c); break; // XRA C + case 0xAA: i8080_xra(c, c->d); break; // XRA D + case 0xAB: i8080_xra(c, c->e); break; // XRA E + case 0xAC: i8080_xra(c, c->h); break; // XRA H + case 0xAD: i8080_xra(c, c->l); break; // XRA L + case 0xAE: i8080_xra(c, i8080_rb(c, i8080_get_hl(c))); break; // XRA M + case 0xEE: i8080_xra(c, i8080_next_byte(c)); break; // XRI byte + + case 0xB7: i8080_ora(c, c->a); break; // ORA A + case 0xB0: i8080_ora(c, c->b); break; // ORA B + case 0xB1: i8080_ora(c, c->c); break; // ORA C + case 0xB2: i8080_ora(c, c->d); break; // ORA D + case 0xB3: i8080_ora(c, c->e); break; // ORA E + case 0xB4: i8080_ora(c, c->h); break; // ORA H + case 0xB5: i8080_ora(c, c->l); break; // ORA L + case 0xB6: i8080_ora(c, i8080_rb(c, i8080_get_hl(c))); break; // ORA M + case 0xF6: i8080_ora(c, i8080_next_byte(c)); break; // ORI byte + + case 0xBF: i8080_cmp(c, c->a); break; // CMP A + case 0xB8: i8080_cmp(c, c->b); break; // CMP B + case 0xB9: i8080_cmp(c, c->c); break; // CMP C + case 0xBA: i8080_cmp(c, c->d); break; // CMP D + case 0xBB: i8080_cmp(c, c->e); break; // CMP E + case 0xBC: i8080_cmp(c, c->h); break; // CMP H + case 0xBD: i8080_cmp(c, c->l); break; // CMP L + case 0xBE: i8080_cmp(c, i8080_rb(c, i8080_get_hl(c))); break; // CMP M + case 0xFE: i8080_cmp(c, i8080_next_byte(c)); break; // CPI byte + + case 0xC3: i8080_jmp(c, i8080_next_word(c)); break; // JMP + case 0xC2: i8080_cond_jmp(c, c->zf == 0); break; // JNZ + case 0xCA: i8080_cond_jmp(c, c->zf == 1); break; // JZ + case 0xD2: i8080_cond_jmp(c, c->cf == 0); break; // JNC + case 0xDA: i8080_cond_jmp(c, c->cf == 1); break; // JC + case 0xE2: i8080_cond_jmp(c, c->pf == 0); break; // JPO + case 0xEA: i8080_cond_jmp(c, c->pf == 1); break; // JPE + case 0xF2: i8080_cond_jmp(c, c->sf == 0); break; // JP + case 0xFA: i8080_cond_jmp(c, c->sf == 1); break; // JM + + case 0xE9: c->pc = i8080_get_hl(c); break; // PCHL + case 0xCD: i8080_call(c, i8080_next_word(c)); break; // CALL + + case 0xC4: i8080_cond_call(c, c->zf == 0); break; // CNZ + case 0xCC: i8080_cond_call(c, c->zf == 1); break; // CZ + case 0xD4: i8080_cond_call(c, c->cf == 0); break; // CNC + case 0xDC: i8080_cond_call(c, c->cf == 1); break; // CC + case 0xE4: i8080_cond_call(c, c->pf == 0); break; // CPO + case 0xEC: i8080_cond_call(c, c->pf == 1); break; // CPE + case 0xF4: i8080_cond_call(c, c->sf == 0); break; // CP + case 0xFC: i8080_cond_call(c, c->sf == 1); break; // CM + + case 0xC9: i8080_ret(c); break; // RET + case 0xC0: i8080_cond_ret(c, c->zf == 0); break; // RNZ + case 0xC8: i8080_cond_ret(c, c->zf == 1); break; // RZ + case 0xD0: i8080_cond_ret(c, c->cf == 0); break; // RNC + case 0xD8: i8080_cond_ret(c, c->cf == 1); break; // RC + case 0xE0: i8080_cond_ret(c, c->pf == 0); break; // RPO + case 0xE8: i8080_cond_ret(c, c->pf == 1); break; // RPE + case 0xF0: i8080_cond_ret(c, c->sf == 0); break; // RP + case 0xF8: i8080_cond_ret(c, c->sf == 1); break; // RM + + case 0xC7: i8080_call(c, 0x00); break; // RST 0 + case 0xCF: i8080_call(c, 0x08); break; // RST 1 + case 0xD7: i8080_call(c, 0x10); break; // RST 2 + case 0xDF: i8080_call(c, 0x18); break; // RST 3 + case 0xE7: i8080_call(c, 0x20); break; // RST 4 + case 0xEF: i8080_call(c, 0x28); break; // RST 5 + case 0xF7: i8080_call(c, 0x30); break; // RST 6 + case 0xFF: i8080_call(c, 0x38); break; // RST 7 + + case 0xC5: i8080_push_stack(c, i8080_get_bc(c)); break; // PUSH B + case 0xD5: i8080_push_stack(c, i8080_get_de(c)); break; // PUSH D + case 0xE5: i8080_push_stack(c, i8080_get_hl(c)); break; // PUSH H + case 0xF5: i8080_push_psw(c); break; // PUSH PSW + case 0xC1: i8080_set_bc(c, i8080_pop_stack(c)); break; // POP B + case 0xD1: i8080_set_de(c, i8080_pop_stack(c)); break; // POP D + case 0xE1: i8080_set_hl(c, i8080_pop_stack(c)); break; // POP H + case 0xF1: i8080_pop_psw(c); break; // POP PSW + + case 0xDB: c->a = c->port_in(c->userdata, i8080_next_byte(c)); break; // IN + case 0xD3: c->port_out(c->userdata, i8080_next_byte(c), c->a); break; // OUT + + case 0x08: + case 0x10: + case 0x18: + case 0x20: + case 0x28: + case 0x30: + case 0x38: break; // undocumented NOPs + + case 0xD9: i8080_ret(c); break; // undocumented RET + + case 0xDD: + case 0xED: + { + if (opcode == 0xED) { + uint8_t data = i8080_next_byte(c); + if (data == 0xED) { + interrupt_808x(i8080_next_byte(c)); + break; + } else if (data == 0xFD) { + retem_i8080(); + break; + } + else { + i8080_call(c, (i8080_next_byte(c) << 8) | data); break; + } + } + } + case 0xFD: i8080_call(c, i8080_next_word(c)); break; // undocumented CALLs + + case 0xCB: i8080_jmp(c, i8080_next_word(c)); break; // undocumented JMP + } +} + +// initialises the emulator with default values +void i8080_init(i8080* const c) { + c->read_byte = NULL; + c->write_byte = NULL; + c->port_in = NULL; + c->port_out = NULL; + c->userdata = NULL; + + c->cyc = 0; + + c->pc = 0; + c->sp = 0; + + c->a = 0; + c->b = 0; + c->c = 0; + c->d = 0; + c->e = 0; + c->h = 0; + c->l = 0; + + c->sf = 0; + c->zf = 0; + c->hf = 0; + c->pf = 0; + c->cf = 0; + c->iff = 0; + + c->halted = 0; + c->interrupt_pending = 0; + c->interrupt_vector = 0; + c->interrupt_delay = 0; +} + +// executes one instruction +void i8080_step(i8080* const c) { + // interrupt processing: if an interrupt is pending and IFF is set, + // we execute the interrupt vector passed by the user. + if (c->interrupt_pending && c->iff && c->interrupt_delay == 0) { + c->interrupt_pending = 0; + c->iff = 0; + c->halted = 0; + + i8080_execute(c, c->interrupt_vector); + } else if (!c->halted) { + i8080_execute(c, i8080_next_byte(c)); + } +} + +// asks for an interrupt to be serviced +void i8080_interrupt(i8080* const c, uint8_t opcode) { + c->interrupt_pending = 1; + c->interrupt_vector = opcode; +} + +// outputs a debug trace of the emulator state to the standard output, +// including registers and flags +void i8080_debug_output(i8080* const c, bool print_disassembly) { + uint8_t f = 0; + f |= c->sf << 7; + f |= c->zf << 6; + f |= c->hf << 4; + f |= c->pf << 2; + f |= 1 << 1; // bit 1 is always 1 + f |= c->cf << 0; + + printf("PC: %04X, AF: %04X, BC: %04X, DE: %04X, HL: %04X, SP: %04X, CYC: %lu", + c->pc, c->a << 8 | f, i8080_get_bc(c), i8080_get_de(c), i8080_get_hl(c), + c->sp, c->cyc); + + printf("\t(%02X %02X %02X %02X)", i8080_rb(c, c->pc), i8080_rb(c, c->pc + 1), + i8080_rb(c, c->pc + 2), i8080_rb(c, c->pc + 3)); + + if (print_disassembly) { + printf(" - %s", DISASSEMBLE_TABLE[i8080_rb(c, c->pc)]); + } + + printf("\n"); +} + +#undef SET_ZSP diff --git a/src/cpu/i8080.h b/src/cpu/i8080.h new file mode 100644 index 000000000..43406e43e --- /dev/null +++ b/src/cpu/i8080.h @@ -0,0 +1,35 @@ +#ifndef I8080_I8080_H_ +#define I8080_I8080_H_ + +#include +#include +#include + +typedef struct i8080 { + // memory + io interface + uint8_t (*read_byte)(void*, uint16_t); // user function to read from memory + void (*write_byte)(void*, uint16_t, uint8_t); // same for writing to memory + uint8_t (*read_byte_seg)(void*, uint16_t); // user function to read from memory (Code segment) + uint8_t (*port_in)(void*, uint8_t); // user function to read from port + void (*port_out)(void*, uint8_t, uint8_t); // same for writing to port + void* userdata; // user custom pointer + + unsigned long cyc; // cycle count + + uint16_t pc, sp; // program counter, stack pointer + uint8_t a, b, c, d, e, h, l; // registers + // flags: sign, zero, half-carry, parity, carry, interrupt flip-flop + bool sf : 1, zf : 1, hf : 1, pf : 1, cf : 1, iff : 1; + bool halted : 1; + + bool interrupt_pending : 1; + uint8_t interrupt_vector; + uint8_t interrupt_delay; +} i8080; + +void i8080_init(i8080* const c); +void i8080_step(i8080* const c); +void i8080_interrupt(i8080* const c, uint8_t opcode); +void i8080_debug_output(i8080* const c, bool print_disassembly); + +#endif // I8080_I8080_H_ diff --git a/src/include/86box/i8080.h b/src/include/86box/i8080.h deleted file mode 100644 index 9a25b5d1b..000000000 --- a/src/include/86box/i8080.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. - * - * 8080 CPU emulation (header). - * - * - * - * Authors: Cacodemon345 - * - * Copyright 2022 Cacodemon345 - */ - -#include - -typedef struct i8080 { - union { - uint16_t af; /* Intended in case we also go for μPD9002 emulation, which also has a Z80 emulation mode. */ - struct { - uint8_t a; - uint8_t flags; - }; - }; - union { - uint16_t bc; - struct { - uint8_t b; - uint8_t c; - }; - }; - union { - uint16_t de; - struct { - uint8_t d; - uint8_t e; - }; - }; - union { - uint16_t hl; - struct { - uint8_t h; - uint8_t l; - }; - }; - uint16_t pc; - uint16_t sp; - uint16_t oldpc; - uint16_t ei; - uint32_t pmembase; - uint32_t dmembase; /* Base from where i8080 starts. */ - uint8_t emulated; /* 0 = not emulated, use separate registers, 1 = emulated, use x86 registers. */ - uint16_t *cpu_flags; - void (*writemembyte)(uint32_t, uint8_t); - uint8_t (*readmembyte)(uint32_t); - void (*startclock)(void); - void (*endclock)(void); - void (*checkinterrupts)(void); - uint8_t (*fetchinstruction)(void *); -} i8080; - -#define C_FLAG_I8080 (1 << 0) -#define P_FLAG_I8080 (1 << 2) -#define AC_FLAG_I8080 (1 << 4) -#define Z_FLAG_I8080 (1 << 6) -#define S_FLAG_I8080 (1 << 7) From 2b107725bdc9a30f94d4af0b55483c37047744aa Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 20:17:13 +0600 Subject: [PATCH 215/218] Custom NMI handling for i8080 emulation --- src/cpu/808x.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 4ce1fa3b9..c07e583ae 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1179,6 +1179,11 @@ custom_nmi(void) uint16_t new_cs, new_ip; uint16_t tempf; + if (!(cpu_state.flags & MD_FLAG) && is_nec) { + sync_from_i8080(); + pclog("NMI# (CUTSOM)\n"); + } + cpu_state.eaaddr = 0x0002; old_cs = CS; access(5, 16); @@ -1196,6 +1201,8 @@ custom_nmi(void) tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); + if (is_nec) + cpu_state.flags |= MD_FLAG; access(40, 16); push(&old_cs); old_ip = cpu_state.pc; From 929a9fb25e4a6ce86dfa81305e63e4267545d444 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 26 Mar 2025 19:30:21 +0500 Subject: [PATCH 216/218] Network settings page redesign Co-Authored-By: cold-brewed <47337035+cold-brewed@users.noreply.github.com> --- src/qt/qt_settingsnetwork.cpp | 61 +++- src/qt/qt_settingsnetwork.ui | 606 ++++++++++++++++++---------------- 2 files changed, 369 insertions(+), 298 deletions(-) diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index 2aa3705fd..a0acd7a3f 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -35,25 +35,58 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) for (int i = 0; i < NET_CARD_MAX; ++i) { auto *nic_cbox = findChild(QString("comboBoxNIC%1").arg(i + 1)); auto *net_type_cbox = findChild(QString("comboBoxNet%1").arg(i + 1)); + + auto *intf_label = findChild(QString("interfaceLabel%1").arg(i + 1)); auto *intf_cbox = findChild(QString("comboBoxIntf%1").arg(i + 1)); + auto *conf_btn = findChild(QString("pushButtonConf%1").arg(i + 1)); +// auto *net_type_conf_btn = findChild(QString("pushButtonNetTypeConf%1").arg(i + 1)); + + auto *vde_socket_label = findChild(QString("socketVDELabel%1").arg(i + 1)); auto *socket_line = findChild(QString("socketVDENIC%1").arg(i + 1)); - int netType = net_type_cbox->currentData().toInt(); - bool adaptersEnabled = netType == NET_TYPE_NONE - || netType == NET_TYPE_SLIRP - || netType == NET_TYPE_VDE - || (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0); + auto *option_list_label = findChild(QString("optionListLabel%1").arg(i + 1)); + auto *option_list_line = findChild(QString("optionListLine%1").arg(i + 1)); intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP); - nic_cbox->setEnabled(adaptersEnabled); - int netCard = nic_cbox->currentData().toInt(); - if ((i == 0) && (netCard == NET_INTERNAL)) - conf_btn->setEnabled(adaptersEnabled && machine_has_flags(machineId, MACHINE_NIC) && - device_has_config(machine_get_net_device(machineId))); - else - conf_btn->setEnabled(adaptersEnabled && network_card_has_config(nic_cbox->currentData().toInt())); - socket_line->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_VDE); + conf_btn->setEnabled(network_card_has_config(nic_cbox->currentData().toInt())); +// net_type_conf_btn->setEnabled(network_type_has_config(netType)); + + // Option list label and line + option_list_label->setVisible(false); + option_list_line->setVisible(false); + + + // VDE + vde_socket_label->setVisible(false); + socket_line->setVisible(false); + + // PCAP + intf_cbox->setVisible(false); + intf_label->setVisible(false); + + // Don't enable anything unless there's a nic selected + if(nic_cbox->currentData().toInt() != 0) { + // Then only enable as needed based on network type + switch (net_type_cbox->currentData().toInt()) { + case NET_TYPE_VDE: + // option_list_label->setText("VDE Options"); + option_list_label->setVisible(true); + option_list_line->setVisible(true); + + vde_socket_label->setVisible(true); + socket_line->setVisible(true); + break; + case NET_TYPE_PCAP: + // option_list_label->setText("PCAP Options"); + option_list_label->setVisible(true); + option_list_line->setVisible(true); + + intf_cbox->setVisible(true); + intf_label->setVisible(true); + break; + } + } } } @@ -154,7 +187,7 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) } model->removeRows(0, removeRows); - cbox->setCurrentIndex(net_cards_conf[i].net_type); + cbox->setCurrentIndex(cbox->findData(net_cards_conf[i].net_type)); selectedRow = 0; diff --git a/src/qt/qt_settingsnetwork.ui b/src/qt/qt_settingsnetwork.ui index 8f1eb5a79..741b60648 100644 --- a/src/qt/qt_settingsnetwork.ui +++ b/src/qt/qt_settingsnetwork.ui @@ -36,20 +36,7 @@ Network Card #1 - - - - - 0 - 0 - - - - Mode - - - - + 30 @@ -63,32 +50,6 @@ - - - - 0 - 0 - - - - Interface - - - - - - - 30 - - - - 0 - 0 - - - - - @@ -101,23 +62,40 @@ - - - - 30 + + + + Qt::Vertical + + + 20 + 40 + + + + + + - + 0 0 - - QComboBox::AdjustToContents + + Mode - + + + + Qt::Horizontal + + + + @@ -130,21 +108,74 @@ + + + + Options + + + - + + + + 0 + 0 + + + + Interface + + + + + VDE Socket - + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 30 + + + + 127 - + + + + + 0 + 0 + + + + + + + + + Network Card #2 + + + Qt::Vertical @@ -157,13 +188,26 @@ - - - - - Network Card #2 - - + + + + + 0 + 0 + + + + Interface + + + + + + + Options + + + @@ -177,7 +221,7 @@ - + 30 @@ -190,33 +234,21 @@ - - - - - 0 - 0 - - + + - Interface + VDE Socket - - - - 30 - - - - 0 - 0 - + + + + Qt::Horizontal - + @@ -229,7 +261,20 @@ - + + + + + 0 + 0 + + + + Configure + + + + 30 @@ -245,40 +290,19 @@ - - - - Configure + + + + + + + + 0 + 0 + - - - - VDE Socket - - - - - - - 127 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -286,6 +310,69 @@ Network Card #3 + + + + 30 + + + + 0 + 0 + + + + + + + + VDE Socket + + + + + + + Options + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 30 + + + + + + + + 0 + 0 + + + + Interface + + + + + + + Qt::Horizontal + + + @@ -299,75 +386,7 @@ - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Interface - - - - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Adapter - - - - - - - 30 - - - - 0 - 0 - - - - QComboBox::AdjustToContents - - - - + @@ -380,21 +399,33 @@ - - + + + + + 0 + 0 + + - VDE Socket + Adapter - - - - 127 + + + + + + + + 0 + 0 + - + Qt::Vertical @@ -414,6 +445,13 @@ Network Card #4 + + + + Options + + + @@ -427,102 +465,7 @@ - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Interface - - - - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Adapter - - - - - - - 30 - - - - 0 - 0 - - - - QComboBox::AdjustToContents - - - - - - - - 0 - 0 - - - - Configure - - - - - - - 127 - - - - - - - VDE Socket - - - - + Qt::Vertical @@ -535,6 +478,101 @@ + + + + VDE Socket + + + + + + + + 0 + 0 + + + + Adapter + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Interface + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 30 + + + + + + + 30 + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + + + + 0 + 0 + + + + From ad4e90e345308cdd186e3e5ce368aa11f1d41d0c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 23:01:09 +0600 Subject: [PATCH 217/218] Finally fix RETEM --- src/cpu/808x.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index c07e583ae..ac23cd99a 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1158,11 +1158,20 @@ retem_i8080(void) { sync_from_i8080(); - cpu_state.pc = pop(); - CS = pop(); - cpu_state.flags = pop() | MD_FLAG; + prefetching = 0; + pfq_clear(); + + set_ip(pop()); + load_cs(pop()); + cpu_state.flags = pop(); + + emulated_processor.iff = !!(cpu_state.flags & I_FLAG); cpu_md_write_disable = 1; + + noint = 1; + nmi_enable = 1; + pclog("RETEM mode\n"); } @@ -3298,7 +3307,7 @@ execx86(int cycs) noint = 1; nmi_enable = 1; if (is_nec && !(cpu_state.flags & MD_FLAG)) - sync_to_i8080(); + sync_to_i8080(); break; case 0xD0: From abbae5efd2b1732ceefb7af11effa757bfe5f034 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 23:18:36 +0600 Subject: [PATCH 218/218] Cleanups --- src/cpu/808x.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index ac23cd99a..e98b7de3d 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -229,6 +229,8 @@ sync_from_i8080(void) void sync_to_i8080(void) { + if (!is_nec) + return; emulated_processor.a = AL; emulated_processor.h = BH; emulated_processor.l = BL; @@ -1085,7 +1087,7 @@ interrupt(uint16_t addr) if (!(cpu_state.flags & MD_FLAG) && is_nec) { sync_from_i8080(); - pclog("CALLN/INT#/NMI#\n"); + x808x_log("CALLN/INT#/NMI#\n"); } addr <<= 2; @@ -1150,7 +1152,7 @@ interrupt_brkem(uint16_t addr) access(41, 16); push(&old_ip); sync_to_i8080(); - pclog("BRKEM mode\n"); + x808x_log("BRKEM mode\n"); } void @@ -1172,7 +1174,7 @@ retem_i8080(void) noint = 1; nmi_enable = 1; - pclog("RETEM mode\n"); + x808x_log("RETEM mode\n"); } void