diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e09b5636f..9e5521cf4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,6 +5,7 @@ _Briefly describe what you are submitting._ Checklist ========= * [ ] Closes #xxx +* [ ] I have tested my changes locally and validated that the functionality works as intended * [ ] I have discussed this with core contributors already * [ ] This pull request requires changes to the ROM set * [ ] I have opened a roms pull request - https://github.com/86Box/roms/pull/changeme/ diff --git a/.github/workflows/codeql_linux.yml b/.github/workflows/codeql_linux.yml index 957c7090b..855571782 100644 --- a/.github/workflows/codeql_linux.yml +++ b/.github/workflows/codeql_linux.yml @@ -121,7 +121,7 @@ jobs: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Install Build Wrapper - uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5 + uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -149,7 +149,7 @@ jobs: - name: SonarQube Scan if: matrix.build.preset == 'dev_debug' && matrix.dynarec.new == 'on' && matrix.ui.qt == 'on' && env.SONAR_TOKEN != '' # if: 0 - uses: SonarSource/sonarqube-scan-action@v5 + uses: SonarSource/sonarqube-scan-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/codeql_macos.yml b/.github/workflows/codeql_macos.yml index 488cbfd49..74365cd56 100644 --- a/.github/workflows/codeql_macos.yml +++ b/.github/workflows/codeql_macos.yml @@ -109,7 +109,7 @@ jobs: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Install Build Wrapper - uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5 + uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -140,7 +140,7 @@ jobs: - name: SonarQube Scan # if: matrix.build.preset == 'dev_debug' && matrix.dynarec.new == 'on' && matrix.ui.qt == 'on' && env.SONAR_TOKEN != '' if: 0 - uses: SonarSource/sonarqube-scan-action@v5 + uses: SonarSource/sonarqube-scan-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/codeql_windows_msys2.yml b/.github/workflows/codeql_windows_msys2.yml index d70c6fd5f..9673ab650 100644 --- a/.github/workflows/codeql_windows_msys2.yml +++ b/.github/workflows/codeql_windows_msys2.yml @@ -169,7 +169,7 @@ jobs: - name: SonarQube Scan # if: matrix.build.preset == 'dev_debug' && matrix.dynarec.new == 'on' && matrix.ui.qt == 'on' && env.SONAR_TOKEN != '' if: 0 - uses: SonarSource/sonarqube-scan-action@v5 + uses: SonarSource/sonarqube-scan-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav b/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav deleted file mode 100644 index 90897531e..000000000 Binary files a/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_start_48000_16_1_PCM.wav b/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_start_48000_16_1_PCM.wav deleted file mode 100644 index 16181d337..000000000 Binary files a/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_start_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav b/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav deleted file mode 100644 index f76e0281a..000000000 Binary files a/samples/Panasonic_JU-475-5_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/Panasonic_JU-475-5_5.25_1.2MB_seekdown_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav b/samples/Panasonic_JU-475-5_5.25_1.2MB_seekdown_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav deleted file mode 100644 index 3330fc7b8..000000000 Binary files a/samples/Panasonic_JU-475-5_5.25_1.2MB_seekdown_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/Panasonic_JU-475-5_5.25_1.2MB_seekup_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav b/samples/Panasonic_JU-475-5_5.25_1.2MB_seekup_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav deleted file mode 100644 index 620a32d4d..000000000 Binary files a/samples/Panasonic_JU-475-5_5.25_1.2MB_seekup_40_tracks_285ms_5ms_per_track_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/Panasonic_JU-475-5_5.25_1.2MB_track_step_48000_16_1_PCM.wav b/samples/Panasonic_JU-475-5_5.25_1.2MB_track_step_48000_16_1_PCM.wav deleted file mode 100644 index fd1c60833..000000000 Binary files a/samples/Panasonic_JU-475-5_5.25_1.2MB_track_step_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/TeacFD-55GFR_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav b/samples/TeacFD-55GFR_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav deleted file mode 100644 index bd8a4cce5..000000000 Binary files a/samples/TeacFD-55GFR_5.25_1.2MB_motor_loop_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/TeacFD-55GFR_5.25_1.2MB_motor_start_48000_16_1_PCM.wav b/samples/TeacFD-55GFR_5.25_1.2MB_motor_start_48000_16_1_PCM.wav deleted file mode 100644 index be3bddd70..000000000 Binary files a/samples/TeacFD-55GFR_5.25_1.2MB_motor_start_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/TeacFD-55GFR_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav b/samples/TeacFD-55GFR_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav deleted file mode 100644 index 6c6c4988c..000000000 Binary files a/samples/TeacFD-55GFR_5.25_1.2MB_motor_stop_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/TeacFD-55GFR_5.25_1.2MB_track_step_48000_16_1_PCM.wav b/samples/TeacFD-55GFR_5.25_1.2MB_track_step_48000_16_1_PCM.wav deleted file mode 100644 index cc26c4809..000000000 Binary files a/samples/TeacFD-55GFR_5.25_1.2MB_track_step_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/TeacFD_55GFR_5.25_1.2MB_seekupdown_80_tracks1100ms_48000_16_1_PCM.wav b/samples/TeacFD_55GFR_5.25_1.2MB_seekupdown_80_tracks1100ms_48000_16_1_PCM.wav deleted file mode 100644 index 0b6be1124..000000000 Binary files a/samples/TeacFD_55GFR_5.25_1.2MB_seekupdown_80_tracks1100ms_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/mitsumi_offseek_80_tracks_1000ms_48000_16_1_PCM.wav b/samples/mitsumi_offseek_80_tracks_1000ms_48000_16_1_PCM.wav deleted file mode 100644 index afd95b8d0..000000000 Binary files a/samples/mitsumi_offseek_80_tracks_1000ms_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/mitsumi_seek_80_tracks_380ms_48000_16_1_PCM.wav b/samples/mitsumi_seek_80_tracks_380ms_48000_16_1_PCM.wav deleted file mode 100644 index a5516cae8..000000000 Binary files a/samples/mitsumi_seek_80_tracks_380ms_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/mitsumi_seek_80_tracks_495ms_48000_16_1_PCM.wav b/samples/mitsumi_seek_80_tracks_495ms_48000_16_1_PCM.wav deleted file mode 100644 index da8b6f974..000000000 Binary files a/samples/mitsumi_seek_80_tracks_495ms_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/mitsumi_spindle_motor_loop_48000_16_1_PCM.wav b/samples/mitsumi_spindle_motor_loop_48000_16_1_PCM.wav deleted file mode 100644 index 190dfda3e..000000000 Binary files a/samples/mitsumi_spindle_motor_loop_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/mitsumi_spindle_motor_start_48000_16_1_PCM.wav b/samples/mitsumi_spindle_motor_start_48000_16_1_PCM.wav deleted file mode 100644 index 2595ed089..000000000 Binary files a/samples/mitsumi_spindle_motor_start_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/mitsumi_spindle_motor_stop_48000_16_1_PCM.wav b/samples/mitsumi_spindle_motor_stop_48000_16_1_PCM.wav deleted file mode 100644 index 1411fd9e3..000000000 Binary files a/samples/mitsumi_spindle_motor_stop_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/mitsumi_track_step_48000_16_1_PCM.wav b/samples/mitsumi_track_step_48000_16_1_PCM.wav deleted file mode 100644 index 258793df5..000000000 Binary files a/samples/mitsumi_track_step_48000_16_1_PCM.wav and /dev/null differ diff --git a/samples/readme.txt b/samples/readme.txt deleted file mode 100644 index 55d8f1590..000000000 --- a/samples/readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -Mitsumi samples have been edited from Shiru's recordings. - -Original Mitsumi samples can be found here: -http://shiru.untergrund.net/files/flopster.zip - -Samples can edited and used separately from the Flopster VSTi under the -Creative Commons Attribution (CC-BY) license terms. \ No newline at end of file diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 64f6a1d5f..3129cd1c8 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -25,6 +25,7 @@ #include <86box/io.h> #include <86box/isapnp.h> #include <86box/plat_unused.h> +#include "cpu.h" #define CHECK_CURRENT_LD() \ if (!ld) { \ @@ -42,6 +43,11 @@ const uint8_t isapnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; +/* Required for the RTL8019AS. */ +const uint8_t isapnp_init_key2[32] = { 0xDA, 0x6D, 0x36, 0x1B, 0x8D, 0x46, 0x23, 0x91, + 0x48, 0xA4, 0xD2, 0x69, 0x34, 0x9A, 0x4D, 0x26, + 0x13, 0x89, 0x44, 0xA2, 0x51, 0x28, 0x94, 0xCA, + 0x65, 0x32, 0x19, 0x0C, 0x86, 0x43, 0xA1, 0x50 }; static const device_t isapnp_device; #ifdef ENABLE_ISAPNP_LOG @@ -71,6 +77,7 @@ enum { typedef struct _isapnp_device_ { uint8_t number; + uint8_t defs[256]; uint8_t regs[256]; uint8_t mem_upperlimit; uint8_t irq_types; @@ -85,11 +92,15 @@ typedef struct _isapnp_card_ { uint8_t enable; uint8_t state; uint8_t csn; + uint8_t csnsav; uint8_t ld; uint8_t id_checksum; uint8_t serial_read; uint8_t serial_read_pair; uint8_t serial_read_pos; + uint8_t is_rt; + uint8_t normal; + uint8_t multiple_lds; uint8_t *rom; uint16_t rom_pos; uint16_t rom_size; @@ -109,6 +120,7 @@ typedef struct _isapnp_card_ { typedef struct { uint8_t in_isolation; + uint8_t using_key2; uint8_t reg; uint8_t key_pos : 5; uint16_t read_data_addr; @@ -166,7 +178,7 @@ isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld) } for (uint8_t i = 0; i < 8; i++) { reg_base = 0x60 + (2 * i); - if (ld->regs[0x31] & 0x02) + if (!(ld->regs[0x30] & 0x01) && (ld->regs[0x31] & 0x02)) card->config.io[i].base = 0; /* let us handle I/O range check reads */ else card->config.io[i].base = (ld->regs[reg_base] << 8) | ld->regs[reg_base + 1]; @@ -174,7 +186,7 @@ isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld) for (uint8_t i = 0; i < 2; i++) { reg_base = 0x70 + (2 * i); card->config.irq[i].irq = ld->regs[reg_base]; - card->config.irq[i].level = ld->regs[reg_base + 1] & 0x02; + card->config.irq[i].level = !!(ld->regs[reg_base + 1] & 0x02); card->config.irq[i].type = ld->regs[reg_base + 1] & 0x01; } for (uint8_t i = 0; i < 2; i++) { @@ -256,17 +268,29 @@ isapnp_reset_ld_regs(isapnp_device_t *ld) /* Set the default IRQ type bits. */ for (uint8_t i = 0; i < 2; i++) { if (ld->irq_types & (0x1 << (4 * i))) - ld->regs[0x70 + (2 * i)] = 0x02; + ld->regs[0x71 + (2 * i)] = 0x02; else if (ld->irq_types & (0x2 << (4 * i))) - ld->regs[0x70 + (2 * i)] = 0x00; + ld->regs[0x71 + (2 * i)] = 0x00; else if (ld->irq_types & (0x4 << (4 * i))) - ld->regs[0x70 + (2 * i)] = 0x03; + ld->regs[0x71 + (2 * i)] = 0x03; else if (ld->irq_types & (0x8 << (4 * i))) - ld->regs[0x70 + (2 * i)] = 0x01; + ld->regs[0x71 + (2 * i)] = 0x01; } /* Reset configuration registers to match the default configuration. */ isapnp_reset_ld_config(ld); + + if (ld->defs[0x30] != 0x00) + ld->regs[0x30] = ld->defs[0x30]; + + if (ld->defs[0x60] != 0x00) + ld->regs[0x60] = ld->defs[0x60]; + + if (ld->defs[0x61] != 0x00) + ld->regs[0x61] = ld->defs[0x61]; + + if (ld->defs[0x70] != 0x00) + ld->regs[0x70] = ld->defs[0x70]; } static uint8_t @@ -288,7 +312,7 @@ isapnp_read_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uint case 0x01: /* Serial Isolation */ card = dev->first_card; while (card) { - if (card->enable && card->rom && (card->state == PNP_STATE_ISOLATION)) + if (card->enable && (card->rom != NULL) && (card->state == PNP_STATE_ISOLATION)) break; card = card->next; } @@ -374,6 +398,7 @@ vendor_defined: default: if (reg >= 0x30) { + CHECK_CURRENT_CARD(); CHECK_CURRENT_LD(); isapnp_log("ISAPnP: Read register %02X from CSN %02X device %02X\n", reg, card->csn, ld->number); ret = ld->regs[reg]; @@ -397,7 +422,8 @@ isapnp_read_data(UNUSED(uint16_t addr), void *priv) card = card->next; } - isapnp_log("ISAPnP: read_data() => "); + // isapnp_log("ISAPnP: read_data() => "); + isapnp_log("[%04X:%08X] ISAPnP: read_data() => ", CS, cpu_state.pc); return isapnp_read_common(dev, card, dev->current_ld, dev->reg); } @@ -432,26 +458,60 @@ isapnp_write_addr(UNUSED(uint16_t addr), uint8_t val, void *priv) if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */ /* Check written value against LFSR key. */ - if (val == isapnp_init_key[dev->key_pos]) { + if ((val == isapnp_init_key[dev->key_pos]) || (val == isapnp_init_key2[dev->key_pos])) { + dev->using_key2 = (val == isapnp_init_key2[dev->key_pos]); dev->key_pos++; if (!dev->key_pos) { isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n"); while (card) { - if (card->enable && (card->enable != ISAPNP_CARD_NO_KEY) && (card->state == PNP_STATE_WAIT_FOR_KEY)) + int match_rt = (dev->using_key2 && card->is_rt); + int match_normal = (!dev->using_key2 && card->normal); + if (card->enable && (match_rt || match_normal) && + (card->enable != ISAPNP_CARD_NO_KEY) && (card->state == PNP_STATE_WAIT_FOR_KEY)) card->state = PNP_STATE_SLEEP; card = card->next; } } - } else { + } else dev->key_pos = 0; - } + } +} + +static void +isapnp_ld_io_remove(isapnp_device_t *ld) +{ + uint16_t io_addr; + + for (uint8_t i = 0; i < 8; i++) { + if (!ld->io_len[i]) + continue; + + io_addr = (ld->regs[0x60 + (2 * i)] << 8) | ld->regs[0x61 + (2 * i)]; + + io_removehandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); + } +} + +static void +isapnp_ld_io_set(isapnp_device_t *ld) +{ + uint16_t io_addr; + + for (uint8_t i = 0; i < 8; i++) { + if (!ld->io_len[i]) + continue; + + io_addr = (ld->regs[0x60 + (2 * i)] << 8) | ld->regs[0x61 + (2 * i)]; + int ior = !(ld->regs[0x30] & 0x01) && (ld->regs[0x31] & 0x02); + + if (ior) + io_sethandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); } } static void isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uint8_t reg, uint8_t val) { - uint16_t io_addr; uint16_t reset_cards = 0; isapnp_log("ISAPnP: write_common(%02X, %02X)\n", reg, val); @@ -493,6 +553,7 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin card->state = PNP_STATE_WAIT_FOR_KEY; card = card->next; } + dev->key_pos = 0; } if (val & 0x04) { isapnp_log("ISAPnP: Reset CSN\n"); @@ -513,8 +574,22 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin if (card->csn == val) { card->rom_pos = 0; card->id_checksum = isapnp_init_key[0]; - if (card->state == PNP_STATE_SLEEP) + if (card->state == PNP_STATE_SLEEP) { card->state = (val == 0) ? PNP_STATE_ISOLATION : PNP_STATE_CONFIG; + + if (!card->multiple_lds) { + ld = card->first_ld; + while (ld) { + if (ld->number == 0x00) { + isapnp_log("ISAPnP: Select CSN %02X device 00\n", card->csn); + dev->current_ld_card = card; + dev->current_ld = ld; + break; + } + ld = ld->next; + } + } + } } else card->state = PNP_STATE_SLEEP; @@ -535,56 +610,47 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin break; case 0x07: /* Logical Device Number */ - CHECK_CURRENT_CARD(); + if (card->multiple_lds) { + CHECK_CURRENT_CARD(); - card->ld = val; - ld = card->first_ld; - while (ld) { - if (ld->number == val) { - isapnp_log("ISAPnP: Select CSN %02X device %02X\n", card->csn, val); - dev->current_ld_card = card; - dev->current_ld = ld; - break; + card->ld = val; + ld = card->first_ld; + while (ld) { + if (ld->number == val) { + isapnp_log("ISAPnP: Select CSN %02X device %02X\n", card->csn, val); + dev->current_ld_card = card; + dev->current_ld = ld; + break; + } + ld = ld->next; } - ld = ld->next; - } - if (!ld) { - isapnp_log("ISAPnP: CSN %02X has no device %02X, creating one\n", card->csn, val); - dev->current_ld_card = card; - dev->current_ld = isapnp_create_ld(card); - dev->current_ld->number = val; + if (!ld) { + isapnp_log("ISAPnP: CSN %02X has no device %02X, creating one\n", card->csn, val); + dev->current_ld_card = card; + dev->current_ld = isapnp_create_ld(card); + dev->current_ld->number = val; + } } - break; case 0x30: /* Activate */ - CHECK_CURRENT_LD(); - - isapnp_log("ISAPnP: %sctivate CSN %02X device %02X\n", (val & 0x01) ? "A" : "Dea", card->csn, ld->number); - - ld->regs[reg] = val & 0x01; - isapnp_device_config_changed(card, ld); - - break; - case 0x31: /* I/O Range Check */ CHECK_CURRENT_LD(); - for (uint8_t i = 0; i < 8; i++) { - if (!ld->io_len[i]) - continue; + isapnp_log("ISAPnP: %sctivate CSN %02X device %02X\n", (ld->regs[0x30] & 0x01) ? "A" : "Dea", + card->csn, ld->number); - io_addr = (ld->regs[0x60 + (2 * i)] << 8) | ld->regs[0x61 + (2 * i)]; - if (ld->regs[reg] & 0x02) - io_removehandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); - if (val & 0x02) - io_sethandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld); - } + isapnp_ld_io_remove(ld); + + if (reg == 0x30) + ld->regs[reg] = val & 0x01; + else + ld->regs[reg] = val & 0x03; + + isapnp_ld_io_set(ld); - ld->regs[reg] = val & 0x03; isapnp_device_config_changed(card, ld); - break; case 0x20 ... 0x2f: @@ -601,6 +667,7 @@ vendor_defined: default: if (reg >= 0x40) { + CHECK_CURRENT_CARD(); CHECK_CURRENT_LD(); isapnp_log("ISAPnP: Write %02X to register %02X on CSN %02X device %02X\n", val, reg, card->csn, ld->number); @@ -649,7 +716,9 @@ vendor_defined: break; } + isapnp_ld_io_remove(ld); ld->regs[reg] = val; + isapnp_ld_io_set(ld); isapnp_device_config_changed(card, ld); } break; @@ -670,7 +739,8 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv) } } - isapnp_log("ISAPnP: write_data(%02X) => ", val); + // isapnp_log("ISAPnP: write_data(%02X) => ", val); + isapnp_log("[%04X:%08X] ISAPnP: write_data(%02X) => ", CS, cpu_state.pc, val); isapnp_write_common(dev, card, dev->current_ld, dev->reg, val); } @@ -729,11 +799,13 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, isapnp_card_t *card = (isapnp_card_t *) calloc(1, sizeof(isapnp_card_t)); card->enable = 1; + card->normal = 1; card->priv = priv; card->config_changed = config_changed; card->csn_changed = csn_changed; card->read_vendor_reg = read_vendor_reg; card->write_vendor_reg = write_vendor_reg; + card->multiple_lds = 1; if (!dev->first_card) { dev->first_card = card; @@ -1163,6 +1235,63 @@ isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg) return isapnp_read_common(device_get_priv(&isapnp_device), card, ld, reg); } +void +isapnp_set_rt(void *priv, uint8_t is_rt) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + card->is_rt = is_rt; +} + +void +isapnp_set_normal(void *priv, uint8_t normal) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + card->normal = normal; +} + +void +isapnp_activate(void *priv, uint16_t base, uint8_t irq, int active) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + isapnp_device_t *ld = card->first_ld; + + while (ld) { + if (ld->number == 0x00) + break; + ld = ld->next; + } + + if (ld != NULL) { + ld->defs[0x30] = active; + ld->defs[0x60] = base >> 8; + if (!(ld->io_16bit & (1 << ((0x60 >> 1) & 0x07)))) + ld->defs[0x60] &= 0x03; + ld->defs[0x61] = base & 0xff; + ld->defs[0x70] = irq; + + isapnp_reset_ld_regs(ld); + } +} + +void +isapnp_set_single_ld(void *priv) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + card->multiple_lds = 0; + card->ld = 0x00; +} + +uint8_t * +isapnp_get_csnsav(void *priv) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + return &card->csnsav; +} + void isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val) { diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index bcf4a1299..4693890e3 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -184,7 +184,7 @@ fdc_ctrl_reset(void *priv) { fdc_t *fdc = (fdc_t *) priv; - fdc->stat = 0x80; + fdc->stat = 0x10; fdc->pnum = fdc->ptot = 0; fdc->st0 = 0; fdc->head = 0; @@ -470,9 +470,9 @@ uint8_t fdc_get_shadow(fdc_t *fdc) { uint8_t ret = (fdc->rate & 0x03) | - ((fdc->pretrk & 0x07) << 2) | - (fdc->power_down ? 0x40 : 0x00) | - ((fdc_read(0x03f2, fdc) & 0x04) ? 0x80 : 0x00); + ((fdc->pretrk & 0x07) << 2) | + (fdc->power_down ? 0x40 : 0x00) | + ((fdc_read(0x03f2, fdc) & 0x04) ? 0x80 : 0x00); return ret; } @@ -532,36 +532,36 @@ fdc_update_rate(fdc_t *fdc, int drive) fdc->enh_mode && !(fdc->flags & FDC_FLAG_SMC661)) fdc->bit_rate = 500; else if ((fdc->rwc[drive] == 3) && fdc->enh_mode && - !(fdc->flags & FDC_FLAG_SMC661)) + !(fdc->flags & FDC_FLAG_SMC661)) fdc->bit_rate = 250; else switch (fdc->rate) { - default: - break; - case 0: /*High density*/ - fdc->bit_rate = 500; - break; - case 1: /*Double density (360 rpm)*/ - switch (fdc->drvrate[drive]) { - default: - break; - case 0: - fdc->bit_rate = 300; - break; - case 1: - fdc->bit_rate = 500; - break; - case 2: - fdc->bit_rate = 2000; - break; - } - break; - case 2: /*Double density*/ - fdc->bit_rate = 250; - break; - case 3: /*Extended density*/ - fdc->bit_rate = 1000; - break; - } + default: + break; + case 0: /*High density*/ + fdc->bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + switch (fdc->drvrate[drive]) { + default: + break; + case 0: + fdc->bit_rate = 300; + break; + case 1: + fdc->bit_rate = 500; + break; + case 2: + fdc->bit_rate = 2000; + break; + } + break; + case 2: /*Double density*/ + fdc->bit_rate = 250; + break; + case 3: /*Extended density*/ + fdc->bit_rate = 1000; + break; + } fdc->bitcell_period = (1000000 / fdc->bit_rate) * 2; /*Bitcell period in ns*/ } @@ -695,7 +695,7 @@ void fdc_seek(fdc_t *fdc, int drive, int params) { fdd_seek(real_drive(fdc, drive), params); - fdc->stat |= (1 << fdc->drive); + fdc->stat = (fdc->stat & 0x0F) | 0x10 | (1 << fdc->drive); } static void @@ -719,8 +719,10 @@ fdc_io_command_phase1(fdc_t *fdc, int out) fdc->dtl = fdc->params[7]; fdc->rw_track = fdc->params[1]; + int implied_seek = 0; if (fdc->config & 0x40) { if (fdc->rw_track != fdc->pcn[fdc->params[0] & 3]) { + implied_seek = 1; fdc_seek(fdc, fdc->drive, ((int) fdc->rw_track) - ((int) fdc->pcn[fdc->params[0] & 3])); fdc->pcn[fdc->params[0] & 3] = fdc->rw_track; } @@ -730,6 +732,12 @@ fdc_io_command_phase1(fdc_t *fdc, int out) ui_sb_update_icon_write(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); else ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); + + if (implied_seek) { + fdc->stat = (fdc->stat & 0x0F) | 0x10 | (1 << real_drive(fdc, fdc->drive)); /* CB=1, per-drive busy */ + return; + } + fdc->stat = out ? 0x10 : 0x50; if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) { fdc->stat |= 0x20; @@ -791,7 +799,7 @@ fdc_soft_reset(fdc_t *fdc) } fdc_ctrl_reset(fdc); - } + } } static void @@ -806,565 +814,566 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) cycles -= ISA_CYCLES(8); - if (!fdc->power_down || ((addr & 7) == 2) || ((addr & 7) == 4)) switch (addr & 7) { - case 0: - return; - case 1: - return; - case 2: /*DOR*/ - if (fdc->flags & FDC_FLAG_PCJR) { - if ((fdc->dor & 0x40) && !(val & 0x40)) { - timer_set_delay_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); - fdc->watchdog_count = 1000; - picintc(1 << fdc->irq); - } - if ((val & 0x80) && !(fdc->dor & 0x80)) { - timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); - fdc->interrupt = -1; - ui_sb_update_icon(SB_FLOPPY | 0, 0); - ui_sb_update_icon_write(SB_FLOPPY | 0, 0); - fdc_ctrl_reset(fdc); - } - if (!fdd_get_flags(0)) - val &= 0xfe; - fdd_set_motor_enable(0, val & 0x01); - fdc->st0 &= ~0x07; - fdc->st0 |= (fdd_get_head(0) ? 4 : 0); - } else { - /* - Writing this bit to logic "1" will enable the DRQ, - nDACK, TC and FINTR outputs. This bit being a - logic "0" will disable the nDACK and TC inputs, and - hold the DRQ and FINTR outputs in a high - impedance state. - */ - if (!(val & 8) && (fdc->dor & 8) && !(fdc->flags & FDC_FLAG_PS2_MCA)) { - fdc->tc = 1; - fdc->fintr = 0; - picintc(1 << fdc->irq); - } - if (!(val & 4)) { - fdd_stop(real_drive(fdc, val & 3)); - fdc->stat = 0x00; - fdc->pnum = fdc->ptot = 0; - } - if ((val & 4) && !(fdc->dor & 4)) - fdc_soft_reset(fdc); - /* We can now simplify this since each motor now spins separately. */ - for (int i = 0; i < FDD_NUM; i++) { - drive_num = real_drive(fdc, i); - if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) - val &= ~(0x10 << drive_num); - else - fdd_set_motor_enable(i, (val & (0x10 << drive_num))); - } - drive_num = real_drive(fdc, val & 0x03); - current_drive = drive_num; - fdc->st0 = (fdc->st0 & 0xf8) | (val & 0x03) | (fdd_get_head(drive_num) ? 4 : 0); - } - fdc->dor = val; - return; - case 3: /* TDR */ - if (fdc->enh_mode) { - if (fdc->flags & FDC_FLAG_SMC661) { - fdc_set_swap(fdc, !!(val & 0x20)); - fdc_update_densel_force(fdc, (val & 0x18) >> 3); + if (!fdc->power_down || ((addr & 7) == 2) || ((addr & 7) == 4)) + switch (addr & 7) { + case 0: + return; + case 1: + return; + case 2: /*DOR*/ + if (fdc->flags & FDC_FLAG_PCJR) { + if ((fdc->dor & 0x40) && !(val & 0x40)) { + timer_set_delay_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); + fdc->watchdog_count = 1000; + picintc(1 << fdc->irq); + } + if ((val & 0x80) && !(fdc->dor & 0x80)) { + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); + fdc->interrupt = -1; + ui_sb_update_icon(SB_FLOPPY | 0, 0); + ui_sb_update_icon_write(SB_FLOPPY | 0, 0); + fdc_ctrl_reset(fdc); + } + if (!fdd_get_flags(0)) + val &= 0xfe; + fdd_set_motor_enable(0, val & 0x01); + fdc->st0 &= ~0x07; + fdc->st0 |= (fdd_get_head(0) ? 4 : 0); } else { - drive = real_drive(fdc, fdc->dor & 3); - fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); + /* + Writing this bit to logic "1" will enable the DRQ, + nDACK, TC and FINTR outputs. This bit being a + logic "0" will disable the nDACK and TC inputs, and + hold the DRQ and FINTR outputs in a high + impedance state. + */ + if (!(val & 8) && (fdc->dor & 8) && !(fdc->flags & FDC_FLAG_PS2_MCA)) { + fdc->tc = 1; + fdc->fintr = 0; + picintc(1 << fdc->irq); + } + if (!(val & 4)) { + fdd_stop(real_drive(fdc, val & 3)); + fdc->stat = 0x00; + fdc->pnum = fdc->ptot = 0; + } + if ((val & 4) && !(fdc->dor & 4)) + fdc_soft_reset(fdc); + /* We can now simplify this since each motor now spins separately. */ + for (int i = 0; i < FDD_NUM; i++) { + drive_num = real_drive(fdc, i); + if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) + val &= ~(0x10 << drive_num); + else + fdd_set_motor_enable(i, (val & (0x10 << drive_num))); + } + drive_num = real_drive(fdc, val & 0x03); + current_drive = drive_num; + fdc->st0 = (fdc->st0 & 0xf8) | (val & 0x03) | (fdd_get_head(drive_num) ? 4 : 0); } - } - /* Bit 2: FIFO test mode (PS/55 5550-S,T only. Undocumented) - The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. - If it fails, then floppy drives will be treated as DD drives. */ - if (fdc->flags & FDC_FLAG_PS2_MCA) { - if (val & 0x04) { - fdc->tfifo = 8; - fdc->fifointest = 1; - } else { - fdc->tfifo = 1; - fdc->fifointest = 0; + fdc->dor = val; + return; + case 3: /* TDR */ + if (fdc->enh_mode) { + if (fdc->flags & FDC_FLAG_SMC661) { + fdc_set_swap(fdc, !!(val & 0x20)); + fdc_update_densel_force(fdc, (val & 0x18) >> 3); + } else { + drive = real_drive(fdc, fdc->dor & 3); + fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); + } } - fifo_reset(fdc->fifo_p); - fifo_set_len(fdc->fifo_p, fdc->tfifo + 1); - fifo_set_trigger_len(fdc->fifo_p, fdc->tfifo + 1); - } - return; - case 4: /* DSR */ - if (!(fdc->flags & FDC_FLAG_NO_DSR_RESET)) { - if (!(val & 0x80)) { - timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); - fdc->interrupt = -6; + /* Bit 2: FIFO test mode (PS/55 5550-S,T only. Undocumented) + The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. + If it fails, then floppy drives will be treated as DD drives. */ + if (fdc->flags & FDC_FLAG_PS2_MCA) { + if (val & 0x04) { + fdc->tfifo = 8; + fdc->fifointest = 1; + } else { + fdc->tfifo = 1; + fdc->fifointest = 0; + } + fifo_reset(fdc->fifo_p); + fifo_set_len(fdc->fifo_p, fdc->tfifo + 1); + fifo_set_trigger_len(fdc->fifo_p, fdc->tfifo + 1); } - if (fdc->power_down || ((val & 0x80) && !(fdc->dsr & 0x80))) - fdc_soft_reset(fdc); - } - fdc->dsr = val; - return; - case 5: /*Command register*/ - if (fdc->fifointest) { - /* Write FIFO buffer in the test mode (PS/55) */ - fdc_log("FIFO buffer position = %X\n", ((fifo_t *) fdc->fifo_p)->end); - fifo_write(val, fdc->fifo_p); - if (fifo_get_full(fdc->fifo_p)) - fdc->stat &= ~0x80; - break; - } - if ((fdc->stat & 0xf0) == 0xb0) { - if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { - fdc->dat = val; - fdc->stat &= ~0x80; - } else { + return; + case 4: /* DSR */ + if (!(fdc->flags & FDC_FLAG_NO_DSR_RESET)) { + if (!(val & 0x80)) { + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); + fdc->interrupt = -6; + } + if (fdc->power_down || ((val & 0x80) && !(fdc->dsr & 0x80))) + fdc_soft_reset(fdc); + } + fdc->dsr = val; + return; + case 5: /*Command register*/ + if (fdc->fifointest) { + /* Write FIFO buffer in the test mode (PS/55) */ + fdc_log("FIFO buffer position = %X\n", ((fifo_t *) fdc->fifo_p)->end); fifo_write(val, fdc->fifo_p); if (fifo_get_full(fdc->fifo_p)) fdc->stat &= ~0x80; + break; } - break; - } - if (fdc->pnum == fdc->ptot) { - if ((fdc->stat & 0xf0) != 0x80) { - /* If bit 4 of the MSR is set, or the MSR is 0x00, - the fdc_t is NOT in the command phase, therefore - do NOT accept commands. */ - return; + if ((fdc->stat & 0xf0) == 0xb0) { + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { + fdc->dat = val; + fdc->stat &= ~0x80; + } else { + fifo_write(val, fdc->fifo_p); + if (fifo_get_full(fdc->fifo_p)) + fdc->stat &= ~0x80; + } + break; } + if (fdc->pnum == fdc->ptot) { + if ((fdc->stat & 0xf0) != 0x80) { + /* If bit 4 of the MSR is set, or the MSR is 0x00, + the fdc_t is NOT in the command phase, therefore + do NOT accept commands. */ + return; + } - fdc->stat &= 0xf; + fdc->stat &= 0xf; - fdc->tc = 0; - fdc->data_ready = 0; + fdc->tc = 0; + fdc->data_ready = 0; - fdc->command = val; - fdc->stat |= 0x10; - fdc_log("Starting FDC command %02X\n", fdc->command); - fdc->error = 0; + fdc->command = val; + fdc->stat |= 0x10; + fdc_log("Starting FDC command %02X\n", fdc->command); + fdc->error = 0; - if (((fdc->command & 0x1f) == 0x02) || ((fdc->command & 0x1f) == 0x05) || - ((fdc->command & 0x1f) == 0x06) || ((fdc->command & 0x1f) == 0x0a) || - ((fdc->command & 0x1f) == 0x0c) || ((fdc->command & 0x1f) == 0x0d) || - ((fdc->command & 0x1f) == 0x11) || ((fdc->command & 0x1f) == 0x16) || - ((fdc->command & 0x1f) == 0x19) || ((fdc->command & 0x1f) == 0x1d)) - fdc->processed_cmd = fdc->command & 0x1f; - else - fdc->processed_cmd = fdc->command; + if (((fdc->command & 0x1f) == 0x02) || ((fdc->command & 0x1f) == 0x05) || + ((fdc->command & 0x1f) == 0x06) || ((fdc->command & 0x1f) == 0x0a) || + ((fdc->command & 0x1f) == 0x0c) || ((fdc->command & 0x1f) == 0x0d) || + ((fdc->command & 0x1f) == 0x11) || ((fdc->command & 0x1f) == 0x16) || + ((fdc->command & 0x1f) == 0x19) || ((fdc->command & 0x1f) == 0x1d)) + fdc->processed_cmd = fdc->command & 0x1f; + else + fdc->processed_cmd = fdc->command; - switch (fdc->processed_cmd) { - case 0x01: /*Mode*/ - if (fdc->flags & FDC_FLAG_NSC) { - fdc->pnum = 0; - fdc->ptot = 4; + switch (fdc->processed_cmd) { + case 0x01: /*Mode*/ + if (fdc->flags & FDC_FLAG_NSC) { + fdc->pnum = 0; + fdc->ptot = 4; + fdc->stat |= 0x90; + fdc->format_state = 0; + } else + fdc_bad_command(fdc); + break; + case 0x02: /*Read track*/ + fdc->satisfying_sectors = 0; + fdc->sc = 0; + fdc->wrong_am = 0; + fdc->pnum = 0; + fdc->ptot = 8; fdc->stat |= 0x90; - fdc->format_state = 0; - } else - fdc_bad_command(fdc); - break; - case 0x02: /*Read track*/ - fdc->satisfying_sectors = 0; - fdc->sc = 0; - fdc->wrong_am = 0; - fdc->pnum = 0; - fdc->ptot = 8; - fdc->stat |= 0x90; - fdc->mfm = (fdc->command & 0x40) ? 1 : 0; - break; - case 0x03: /*Specify*/ - fdc->pnum = 0; - fdc->ptot = 2; - fdc->stat |= 0x90; - break; - case 0x04: /*Sense drive status*/ - fdc->pnum = 0; - fdc->ptot = 1; - fdc->stat |= 0x90; - break; - case 0x05: /*Write data*/ - case 0x09: /*Write deleted data*/ - fdc->satisfying_sectors = 0; - fdc->sc = 0; - fdc->wrong_am = 0; - fdc->deleted = ((fdc->command & 0x1F) == 9) ? 1 : 0; - fdc->pnum = 0; - fdc->ptot = 8; - fdc->stat |= 0x90; - fdc->mfm = (fdc->command & 0x40) ? 1 : 0; - break; - case 0x06: /*Read data*/ - case 0x0c: /*Read deleted data*/ - case 0x11: /*Scan equal*/ - case 0x19: /*Scan low or equal*/ - case 0x16: /*Verify*/ - case 0x1d: /*Scan high or equal*/ - fdc->satisfying_sectors = 0; - fdc->sc = 0; - fdc->wrong_am = 0; - fdc->deleted = ((fdc->command & 0x1F) == 0xC) ? 1 : 0; - if ((fdc->command & 0x1F) == 0x16) - fdc->deleted = 2; - fdc->deleted |= (fdc->command & 0x20); - fdc->pnum = 0; - fdc->ptot = 8; - fdc->stat |= 0x90; - fdc->mfm = (fdc->command & 0x40) ? 1 : 0; - break; - case 0x17: /*Powerdown mode*/ - if (!(fdc->flags & FDC_FLAG_ALI)) { - fdc_bad_command(fdc); + fdc->mfm = (fdc->command & 0x40) ? 1 : 0; break; - } - fallthrough; - case 0x07: /*Recalibrate*/ - fdc->pnum = 0; - fdc->ptot = 1; - fdc->stat |= 0x90; - break; - case 0x08: /*Sense interrupt status*/ - fdc_log("fdc->fintr = %i, fdc->reset_stat = %i\n", fdc->fintr, fdc->reset_stat); - fdc->lastdrive = fdc->drive; - fdc_sis(fdc); - break; - case 0x0a: /*Read sector ID*/ - fdc->pnum = 0; - fdc->ptot = 1; - fdc->stat |= 0x90; - fdc->mfm = (fdc->command & 0x40) ? 1 : 0; - break; - case 0x0d: /*Format track*/ - fdc->pnum = 0; - fdc->ptot = 5; - fdc->stat |= 0x90; - fdc->mfm = (fdc->command & 0x40) ? 1 : 0; - fdc->format_state = 0; - break; - case 0x0e: /*Dump registers*/ - if (fdc->flags & FDC_FLAG_NEC) { - fdc_bad_command(fdc); + case 0x03: /*Specify*/ + fdc->pnum = 0; + fdc->ptot = 2; + fdc->stat |= 0x90; break; - } - fdc->lastdrive = fdc->drive; - fdc->interrupt = 0x0e; - fdc_callback(fdc); - break; - case 0x0f: /*Seek*/ - fdc->pnum = 0; - fdc->ptot = 2; - fdc->stat |= 0x90; - break; - case 0x18: /*NSC*/ - if (!(fdc->flags & FDC_FLAG_NSC)) { - fdc_bad_command(fdc); - break; - } - fallthrough; - case 0x10: /*Get version*/ - case 0x14: /*Unlock*/ - case 0x94: /*Lock*/ - if (fdc->flags & FDC_FLAG_NEC) { - fdc_bad_command(fdc); - break; - } - fdc->lastdrive = fdc->drive; - fdc->interrupt = fdc->command; - fdc_callback(fdc); - break; - case 0x12: /*Set perpendicular mode*/ - if ((fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_PCJR)) { + case 0x04: /*Sense drive status*/ fdc->pnum = 0; fdc->ptot = 1; fdc->stat |= 0x90; - } else - fdc_bad_command(fdc); - break; - case 0x13: /*Configure*/ - if (fdc->flags & FDC_FLAG_NEC) { - fdc_bad_command(fdc); break; - } - fdc->pnum = 0; - fdc->ptot = 3; - fdc->stat |= 0x90; - break; - default: - fdc_bad_command(fdc); - break; - } - } else { - fdc->stat = 0x10 | (fdc->stat & 0xf); - fdc->params[fdc->pnum++] = val; - if (fdc->pnum == 1) { - if (command_has_drivesel[fdc->command & 0x1F]) { - if (fdc->flags & FDC_FLAG_PCJR) - fdc->drive = 0; - else - fdc->drive = fdc->dor & 3; - fdc->rw_drive = fdc->params[0] & 3; - if (((fdc->command & 0x1F) == 7) || ((fdc->command & 0x1F) == 15)) - fdc->stat |= (1 << real_drive(fdc, fdc->drive)); - } - } - if (fdc->pnum == fdc->ptot) { - fdc_log("Got all params %02X\n", fdc->command); - fifo_reset(fdc->fifo_p); - fdc->interrupt = fdc->processed_cmd; - fdc->reset_stat = 0; - /* Disable timer if enabled. */ - timer_disable(&fdc->timer); - /* Start timer if needed at this point. */ - switch (fdc->interrupt & 0x1f) { - case 0x02: /* Read a track */ - case 0x03: /* Specify */ - case 0x0a: /* Read sector ID */ - case 0x05: /* Write data */ - case 0x06: /* Read data */ - case 0x09: /* Write deleted data */ - case 0x0c: /* Read deleted data */ - case 0x11: /* Scan equal */ - case 0x12: /* Perpendicular mode */ - case 0x16: /* Verify */ - case 0x19: /* Scan low or equal */ - case 0x1d: /* Scan high or equal */ - /* Do nothing. */ + case 0x05: /*Write data*/ + case 0x09: /*Write deleted data*/ + fdc->satisfying_sectors = 0; + fdc->sc = 0; + fdc->wrong_am = 0; + fdc->deleted = ((fdc->command & 0x1F) == 9) ? 1 : 0; + fdc->pnum = 0; + fdc->ptot = 8; + fdc->stat |= 0x90; + fdc->mfm = (fdc->command & 0x40) ? 1 : 0; break; - case 0x07: /* Recalibrate */ - case 0x0f: /* Seek */ - if (fdc->flags & FDC_FLAG_PCJR) - timer_set_delay_u64(&fdc->timer, 1000 * TIMER_USEC); - else - timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); + case 0x06: /*Read data*/ + case 0x0c: /*Read deleted data*/ + case 0x11: /*Scan equal*/ + case 0x19: /*Scan low or equal*/ + case 0x16: /*Verify*/ + case 0x1d: /*Scan high or equal*/ + fdc->satisfying_sectors = 0; + fdc->sc = 0; + fdc->wrong_am = 0; + fdc->deleted = ((fdc->command & 0x1F) == 0xC) ? 1 : 0; + if ((fdc->command & 0x1F) == 0x16) + fdc->deleted = 2; + fdc->deleted |= (fdc->command & 0x20); + fdc->pnum = 0; + fdc->ptot = 8; + fdc->stat |= 0x90; + fdc->mfm = (fdc->command & 0x40) ? 1 : 0; break; - default: - timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); - break; - } - /* Process the firt phase of the command. */ - switch (fdc->processed_cmd) { - case 0x02: /* Read a track */ - fdc_io_command_phase1(fdc, 0); - fdc->read_track_sector.id.c = fdc->params[1]; - fdc->read_track_sector.id.h = fdc->params[2]; - fdc->read_track_sector.id.r = 1; - fdc->read_track_sector.id.n = fdc->params[4]; - if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { - fdc_noidam(fdc); - return; + case 0x17: /*Powerdown mode*/ + if (!(fdc->flags & FDC_FLAG_ALI)) { + fdc_bad_command(fdc); + break; } - fdd_readsector(real_drive(fdc, fdc->drive), SECTOR_FIRST, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); - break; - case 0x03: /* Specify */ - fdc->stat = 0x80; - fdc->specify[0] = fdc->params[0]; - fdc->specify[1] = fdc->params[1]; - fdc->dma = (fdc->specify[1] & 1) ^ 1; - if (!fdc->dma) - dma_set_drq(fdc->dma_ch, 0); - break; - case 0x04: /*Sense drive status*/ - fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - break; - case 0x05: /* Write data */ - case 0x09: /* Write deleted data */ - fdc_io_command_phase1(fdc, 1); - if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { - fdc_noidam(fdc); - return; - } - fdd_writesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); - break; - case 0x11: /* Scan equal */ - case 0x19: /* Scan low or equal */ - case 0x1d: /* Scan high or equal */ - fdc_io_command_phase1(fdc, 1); - if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { - fdc_noidam(fdc); - return; - } - fdd_comparesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); - break; - case 0x16: /* Verify */ - if (fdc->params[0] & 0x80) - fdc->sc = fdc->params[7]; fallthrough; - case 0x06: /* Read data */ - case 0x0c: /* Read deleted data */ - fdc_io_command_phase1(fdc, 0); - fdc_log("Reading sector (drive %i) (%i) (%i %i %i %i) (%i %i %i)\n", fdc->drive, fdc->params[0], fdc->params[1], fdc->params[2], fdc->params[3], fdc->params[4], fdc->params[5], fdc->params[6], fdc->params[7]); - if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { - fdc_noidam(fdc); - return; - } - if (((dma_mode(2) & 0x0C) == 0x00) && !(fdc->flags & FDC_FLAG_PCJR) && fdc->dma) { - /* DMA is in verify mode, treat this like a VERIFY command. */ - fdc_log("Verify-mode read!\n"); - fdc->tc = 1; - fdc->deleted |= 2; - } - fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + case 0x07: /*Recalibrate*/ + fdc->pnum = 0; + fdc->ptot = 1; + fdc->stat |= 0x90; break; - - case 0x07: /* Recalibrate */ - fdc->rw_drive = fdc->params[0] & 3; - fdc->stat = (1 << real_drive(fdc, fdc->drive)); - if (!(fdc->flags & FDC_FLAG_PCJR)) - fdc->stat |= 0x80; - fdc->st0 = fdc->params[0] & 3; - fdc->st0 |= fdd_get_head(real_drive(fdc, fdc->drive)) ? 0x04 : 0x00; - fdc->st0 |= 0x80; - drive_num = real_drive(fdc, fdc->drive); - /* Three conditions under which the command should fail. */ - if ((drive_num >= FDD_NUM) || !fdd_get_flags(drive_num) || !motoron[drive_num] || fdd_track0(drive_num)) { - fdc_log("Failed recalibrate\n"); - if ((drive_num >= FDD_NUM) || !fdd_get_flags(drive_num) || !motoron[drive_num]) - fdc->st0 = 0x70 | (fdc->params[0] & 3); - else - fdc->st0 = 0x20 | (fdc->params[0] & 3); - fdc->pcn[fdc->params[0] & 3] = 0; - if (fdc->flags & FDC_FLAG_PCJR) { - fdc->fintr = 1; - fdc->interrupt = -4; - } else { - timer_disable(&fdc->timer); - fdc->interrupt = -3; - fdc_callback(fdc); - } + case 0x08: /*Sense interrupt status*/ + fdc_log("fdc->fintr = %i, fdc->reset_stat = %i\n", fdc->fintr, fdc->reset_stat); + fdc->lastdrive = fdc->drive; + fdc_sis(fdc); + break; + case 0x0a: /*Read sector ID*/ + fdc->pnum = 0; + fdc->ptot = 1; + fdc->stat |= 0x90; + fdc->mfm = (fdc->command & 0x40) ? 1 : 0; + break; + case 0x0d: /*Format track*/ + fdc->pnum = 0; + fdc->ptot = 5; + fdc->stat |= 0x90; + fdc->mfm = (fdc->command & 0x40) ? 1 : 0; + fdc->format_state = 0; + break; + case 0x0e: /*Dump registers*/ + if (fdc->flags & FDC_FLAG_NEC) { + fdc_bad_command(fdc); break; } - if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) - fdc_seek(fdc, fdc->drive, -fdc->max_track); - fdc_log("Recalibrating...\n"); - fdc->seek_dir = fdc->step = 1; + fdc->lastdrive = fdc->drive; + fdc->interrupt = 0x0e; + fdc_callback(fdc); break; - case 0x0a: /* Read sector ID */ - fdc_rate(fdc, fdc->drive); - fdc->head = (fdc->params[0] & 4) ? 1 : 0; - fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { - fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); - if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) - fdc->stat = 0x70; - else - fdc->stat = 0x50; + case 0x0f: /*Seek*/ + fdc->pnum = 0; + fdc->ptot = 2; + fdc->stat |= 0x90; + break; + case 0x18: /*NSC*/ + if (!(fdc->flags & FDC_FLAG_NSC)) { + fdc_bad_command(fdc); + break; + } + fallthrough; + case 0x10: /*Get version*/ + case 0x14: /*Unlock*/ + case 0x94: /*Lock*/ + if (fdc->flags & FDC_FLAG_NEC) { + fdc_bad_command(fdc); + break; + } + fdc->lastdrive = fdc->drive; + fdc->interrupt = fdc->command; + fdc_callback(fdc); + break; + case 0x12: /*Set perpendicular mode*/ + if ((fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_PCJR)) { + fdc->pnum = 0; + fdc->ptot = 1; + fdc->stat |= 0x90; } else - fdc_noidam(fdc); + fdc_bad_command(fdc); break; - case 0x0d: /* Format */ - fdc_rate(fdc, fdc->drive); - fdc->head = (fdc->params[0] & 4) ? 1 : 0; - fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - fdc->gap = fdc->params[3]; - fdc->format_sectors = fdc->params[2]; - fdc->format_n = fdc->params[1]; - fdc->format_state = 1; - fdc->stat = 0x10; - break; - case 0x0f: /* Seek */ - fdc->rw_drive = fdc->params[0] & 3; - fdc->stat = (1 << fdc->drive); - if (!(fdc->flags & FDC_FLAG_PCJR)) - fdc->stat |= 0x80; - fdc->head = 0; /* TODO: See if this is correct. */ - fdc->st0 = fdc->params[0] & 0x03; - fdc->st0 |= (fdc->params[0] & 4); - fdc->st0 |= 0x80; - fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - drive_num = real_drive(fdc, fdc->drive); - /* Three conditions under which the command should fail. */ - if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num]) { - /* Yes, failed SEEK's still report success, unlike failed RECALIBRATE's. */ - fdc->st0 = 0x20 | (fdc->params[0] & 3); - if (fdc->command & 0x80) { - if (fdc->command & 0x40) - fdc->pcn[fdc->params[0] & 3] += fdc->params[1]; - else - fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; - } else - fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; - if (fdc->flags & FDC_FLAG_PCJR) { - fdc->fintr = 1; - fdc->interrupt = -4; - } else { - timer_disable(&fdc->timer); - fdc->interrupt = -3; - fdc_callback(fdc); - } + case 0x13: /*Configure*/ + if (fdc->flags & FDC_FLAG_NEC) { + fdc_bad_command(fdc); break; } - if (fdc->command & 0x80) { - if (fdc->params[1]) { - if (fdc->command & 0x40) { - /* Relative seek inwards. */ - fdc->seek_dir = 0; - fdc_seek(fdc, fdc->drive, fdc->params[1]); - fdc->pcn[fdc->params[0] & 3] += fdc->params[1]; - } else { - /* Relative seek outwards. */ - fdc->seek_dir = 1; - fdc_seek(fdc, fdc->drive, -fdc->params[1]); - fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; - } - fdc->step = 1; - } else { - fdc->st0 = 0x20 | (fdc->params[0] & 3); - if (fdc->flags & FDC_FLAG_PCJR) { - fdc->fintr = 1; - fdc->interrupt = -4; - } else { - timer_disable(&fdc->timer); - fdc->interrupt = -3; - fdc_callback(fdc); - } - break; - } - } else { - fdc_log("Seeking to track %i (PCN = %i)...\n", fdc->params[1], fdc->pcn[fdc->params[0] & 3]); - if ((fdc->params[1] - fdc->pcn[fdc->params[0] & 3]) == 0) { - fdc_log("Failed seek\n"); - fdc->st0 = 0x20 | (fdc->params[0] & 3); - if (fdc->flags & FDC_FLAG_PCJR) { - fdc->fintr = 1; - fdc->interrupt = -4; - } else { - timer_disable(&fdc->timer); - fdc->interrupt = -3; - fdc_callback(fdc); - } - break; - } - if (fdc->params[1] > fdc->pcn[fdc->params[0] & 3]) - fdc->seek_dir = 0; - else - fdc->seek_dir = 1; - fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); - fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; - fdc->step = 1; - } + fdc->pnum = 0; + fdc->ptot = 3; + fdc->stat |= 0x90; break; - case 0x12: /* Perpendicular mode */ - fdc->stat = 0x80; - if (fdc->params[0] & 0x80) - fdc->perp = fdc->params[0] & 0x3f; - else { - fdc->perp &= 0xfc; - fdc->perp |= (fdc->params[0] & 0x03); - } - return; - default: + fdc_bad_command(fdc); break; } - } else - fdc->stat = 0x90 | (fdc->stat & 0xf); - } - return; - case 7: - if (!(fdc->flags & FDC_FLAG_TOSHIBA) && !(fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_UMC)) - return; - fdc->rate = val & 0x03; - if (fdc->flags & FDC_FLAG_PS2) - fdc->noprec = !!(val & 0x04); - return; + } else { + fdc->stat = 0x10 | (fdc->stat & 0xf); + fdc->params[fdc->pnum++] = val; + if (fdc->pnum == 1) { + if (command_has_drivesel[fdc->command & 0x1F]) { + if (fdc->flags & FDC_FLAG_PCJR) + fdc->drive = 0; + else + fdc->drive = fdc->dor & 3; + fdc->rw_drive = fdc->params[0] & 3; + if (((fdc->command & 0x1F) == 7) || ((fdc->command & 0x1F) == 15)) + fdc->stat |= (1 << real_drive(fdc, fdc->drive)); + } + } + if (fdc->pnum == fdc->ptot) { + fdc_log("Got all params %02X\n", fdc->command); + fifo_reset(fdc->fifo_p); + fdc->interrupt = fdc->processed_cmd; + fdc->reset_stat = 0; + /* Disable timer if enabled. */ + timer_disable(&fdc->timer); + /* Start timer if needed at this point. */ + switch (fdc->interrupt & 0x1f) { + case 0x02: /* Read a track */ + case 0x03: /* Specify */ + case 0x0a: /* Read sector ID */ + case 0x05: /* Write data */ + case 0x06: /* Read data */ + case 0x09: /* Write deleted data */ + case 0x0c: /* Read deleted data */ + case 0x11: /* Scan equal */ + case 0x12: /* Perpendicular mode */ + case 0x16: /* Verify */ + case 0x19: /* Scan low or equal */ + case 0x1d: /* Scan high or equal */ + /* Do nothing. */ + break; + case 0x07: /* Recalibrate */ + case 0x0f: /* Seek */ + if (fdc->flags & FDC_FLAG_PCJR) + timer_set_delay_u64(&fdc->timer, 1000 * TIMER_USEC); + else + timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); + break; + default: + timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); + break; + } + /* Process the firt phase of the command. */ + switch (fdc->processed_cmd) { + case 0x02: /* Read a track */ + fdc_io_command_phase1(fdc, 0); + fdc->read_track_sector.id.c = fdc->params[1]; + fdc->read_track_sector.id.h = fdc->params[2]; + fdc->read_track_sector.id.r = 1; + fdc->read_track_sector.id.n = fdc->params[4]; + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + fdd_readsector(real_drive(fdc, fdc->drive), SECTOR_FIRST, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; + case 0x03: /* Specify */ + fdc->stat = 0x80; + fdc->specify[0] = fdc->params[0]; + fdc->specify[1] = fdc->params[1]; + fdc->dma = (fdc->specify[1] & 1) ^ 1; + if (!fdc->dma) + dma_set_drq(fdc->dma_ch, 0); + break; + case 0x04: /*Sense drive status*/ + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + break; + case 0x05: /* Write data */ + case 0x09: /* Write deleted data */ + fdc_io_command_phase1(fdc, 1); + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + fdd_writesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; + case 0x11: /* Scan equal */ + case 0x19: /* Scan low or equal */ + case 0x1d: /* Scan high or equal */ + fdc_io_command_phase1(fdc, 1); + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + fdd_comparesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; + case 0x16: /* Verify */ + if (fdc->params[0] & 0x80) + fdc->sc = fdc->params[7]; + fallthrough; + case 0x06: /* Read data */ + case 0x0c: /* Read deleted data */ + fdc_io_command_phase1(fdc, 0); + fdc_log("Reading sector (drive %i) (%i) (%i %i %i %i) (%i %i %i)\n", fdc->drive, fdc->params[0], fdc->params[1], fdc->params[2], fdc->params[3], fdc->params[4], fdc->params[5], fdc->params[6], fdc->params[7]); + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + if (((dma_mode(2) & 0x0C) == 0x00) && !(fdc->flags & FDC_FLAG_PCJR) && fdc->dma) { + /* DMA is in verify mode, treat this like a VERIFY command. */ + fdc_log("Verify-mode read!\n"); + fdc->tc = 1; + fdc->deleted |= 2; + } + fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; - default: - break; - } + case 0x07: /* Recalibrate */ + fdc->rw_drive = fdc->params[0] & 3; + fdc->stat = (1 << real_drive(fdc, fdc->drive)); + if (!(fdc->flags & FDC_FLAG_PCJR)) + fdc->stat |= 0x80; + fdc->st0 = fdc->params[0] & 3; + fdc->st0 |= fdd_get_head(real_drive(fdc, fdc->drive)) ? 0x04 : 0x00; + fdc->st0 |= 0x80; + drive_num = real_drive(fdc, fdc->drive); + /* Three conditions under which the command should fail. */ + if ((drive_num >= FDD_NUM) || !fdd_get_flags(drive_num) || !motoron[drive_num] || fdd_track0(drive_num)) { + fdc_log("Failed recalibrate\n"); + if ((drive_num >= FDD_NUM) || !fdd_get_flags(drive_num) || !motoron[drive_num]) + fdc->st0 = 0x70 | (fdc->params[0] & 3); + else + fdc->st0 = 0x20 | (fdc->params[0] & 3); + fdc->pcn[fdc->params[0] & 3] = 0; + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + } else { + timer_disable(&fdc->timer); + fdc->interrupt = -3; + fdc_callback(fdc); + } + break; + } + if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) + fdc_seek(fdc, fdc->drive, -fdc->max_track); + fdc_log("Recalibrating...\n"); + fdc->seek_dir = fdc->step = 1; + break; + case 0x0a: /* Read sector ID */ + fdc_rate(fdc, fdc->drive); + fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { + fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0x70; + else + fdc->stat = 0x50; + } else + fdc_noidam(fdc); + break; + case 0x0d: /* Format */ + fdc_rate(fdc, fdc->drive); + fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + fdc->gap = fdc->params[3]; + fdc->format_sectors = fdc->params[2]; + fdc->format_n = fdc->params[1]; + fdc->format_state = 1; + fdc->stat = 0x10; + break; + case 0x0f: /* Seek */ + fdc->rw_drive = fdc->params[0] & 3; + fdc->stat = (1 << fdc->drive); + if (!(fdc->flags & FDC_FLAG_PCJR)) + fdc->stat |= 0x80; + fdc->head = 0; /* TODO: See if this is correct. */ + fdc->st0 = fdc->params[0] & 0x03; + fdc->st0 |= (fdc->params[0] & 4); + fdc->st0 |= 0x80; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + drive_num = real_drive(fdc, fdc->drive); + /* Three conditions under which the command should fail. */ + if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num]) { + /* Yes, failed SEEK's still report success, unlike failed RECALIBRATE's. */ + fdc->st0 = 0x20 | (fdc->params[0] & 3); + if (fdc->command & 0x80) { + if (fdc->command & 0x40) + fdc->pcn[fdc->params[0] & 3] += fdc->params[1]; + else + fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; + } else + fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + } else { + timer_disable(&fdc->timer); + fdc->interrupt = -3; + fdc_callback(fdc); + } + break; + } + if (fdc->command & 0x80) { + if (fdc->params[1]) { + if (fdc->command & 0x40) { + /* Relative seek inwards. */ + fdc->seek_dir = 0; + fdc_seek(fdc, fdc->drive, fdc->params[1]); + fdc->pcn[fdc->params[0] & 3] += fdc->params[1]; + } else { + /* Relative seek outwards. */ + fdc->seek_dir = 1; + fdc_seek(fdc, fdc->drive, -fdc->params[1]); + fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; + } + fdc->step = 1; + } else { + fdc->st0 = 0x20 | (fdc->params[0] & 3); + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + } else { + timer_disable(&fdc->timer); + fdc->interrupt = -3; + fdc_callback(fdc); + } + break; + } + } else { + fdc_log("Seeking to track %i (PCN = %i)...\n", fdc->params[1], fdc->pcn[fdc->params[0] & 3]); + if ((fdc->params[1] - fdc->pcn[fdc->params[0] & 3]) == 0) { + fdc_log("Failed seek\n"); + fdc->st0 = 0x20 | (fdc->params[0] & 3); + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + } else { + timer_disable(&fdc->timer); + fdc->interrupt = -3; + fdc_callback(fdc); + } + break; + } + if (fdc->params[1] > fdc->pcn[fdc->params[0] & 3]) + fdc->seek_dir = 0; + else + fdc->seek_dir = 1; + fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); + fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; + fdc->step = 1; + } + break; + case 0x12: /* Perpendicular mode */ + fdc->stat = 0x80; + if (fdc->params[0] & 0x80) + fdc->perp = fdc->params[0] & 0x3f; + else { + fdc->perp &= 0xfc; + fdc->perp |= (fdc->params[0] & 0x03); + } + return; + + default: + break; + } + } else + fdc->stat = 0x90 | (fdc->stat & 0xf); + } + return; + case 7: + if (!(fdc->flags & FDC_FLAG_TOSHIBA) && !(fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_UMC)) + return; + fdc->rate = val & 0x03; + if (fdc->flags & FDC_FLAG_PS2) + fdc->noprec = !!(val & 0x04); + return; + + default: + break; + } } uint8_t @@ -1376,213 +1385,214 @@ fdc_read(uint16_t addr, void *priv) cycles -= ISA_CYCLES(8); - if (!fdc->power_down || ((addr & 7) == 2)) switch (addr & 7) { - case 0: /* STA */ - if (fdc->flags & FDC_FLAG_PS2) { - drive = real_drive(fdc, fdc->dor & 3); - ret = 0x00; - /* TODO: - Bit 2: INDEX (best return always 0 as it goes by very fast) - */ - if (fdc->seek_dir) /* nDIRECTION */ - ret |= 0x01; - if (writeprot[drive]) /* WRITEPROT */ - ret |= 0x02; - if (!fdd_get_head(drive)) /* nHDSEL */ - ret |= 0x08; - if (fdd_track0(drive)) /* TRK0 */ - ret |= 0x10; - if (fdc->step) /* STEP */ - ret |= 0x20; - if (dma_get_drq(fdc->dma_ch)) /* DRQ */ - ret |= 0x40; - if (fdc->fintr || fdc->reset_stat) /* INTR */ - ret |= 0x80; - } else if (fdc->flags & FDC_FLAG_PS2_MCA) { - drive = real_drive(fdc, fdc->dor & 3); - ret = 0x04; - /* TODO: - Bit 2: nINDEX (best return always 1 as it goes by very fast) - */ - if (!fdc->seek_dir) /* DIRECTION */ - ret |= 0x01; - if (!writeprot[drive]) /* nWRITEPROT */ - ret |= 0x02; - if (fdd_get_head(drive)) /* HDSEL */ - ret |= 0x08; - if (!fdd_track0(drive)) /* nTRK0 */ - ret |= 0x10; - if (fdc->step) /* STEP */ - ret |= 0x20; - if (!fdd_get_type(1)) /* -Drive 2 Installed */ - ret |= 0x40; - if (fdc->fintr || fdc->reset_stat) /* INTR */ - ret |= 0x80; - } else - ret = 0xff; - break; - case 1: /* STB */ - if (fdc->flags & FDC_FLAG_PS2) { - drive = real_drive(fdc, fdc->dor & 3); - ret = 0x00; - if (!fdd_get_type(1)) /* -Drive 2 Installed */ - ret |= 0x80; - switch (drive) { /* -Drive Select 1,0 */ - case 0: - ret |= 0x43; - break; - case 1: - ret |= 0x23; - break; - case 2: - ret |= 0x62; - break; - case 3: - ret |= 0x61; - break; - - default: - break; - } - } else if (fdc->flags & FDC_FLAG_PS2_MCA) { - drive = real_drive(fdc, fdc->dor & 3); - ret = 0xc0; - ret |= (fdc->dor & 0x01) << 5; /* Drive Select 0 */ - ret |= (fdc->dor & 0x30) >> 4; /* Motor Select 1, 0 */ - } else { - if (is486 || !fdc->enable_3f1) + if (!fdc->power_down || ((addr & 7) == 2)) + switch (addr & 7) { + case 0: /* STA */ + if (fdc->flags & FDC_FLAG_PS2) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x00; + /* TODO: + Bit 2: INDEX (best return always 0 as it goes by very fast) + */ + if (fdc->seek_dir) /* nDIRECTION */ + ret |= 0x01; + if (writeprot[drive]) /* WRITEPROT */ + ret |= 0x02; + if (!fdd_get_head(drive)) /* nHDSEL */ + ret |= 0x08; + if (fdd_track0(drive)) /* TRK0 */ + ret |= 0x10; + if (fdc->step) /* STEP */ + ret |= 0x20; + if (dma_get_drq(fdc->dma_ch)) /* DRQ */ + ret |= 0x40; + if (fdc->fintr || fdc->reset_stat) /* INTR */ + ret |= 0x80; + } else if (fdc->flags & FDC_FLAG_PS2_MCA) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x04; + /* TODO: + Bit 2: nINDEX (best return always 1 as it goes by very fast) + */ + if (!fdc->seek_dir) /* DIRECTION */ + ret |= 0x01; + if (!writeprot[drive]) /* nWRITEPROT */ + ret |= 0x02; + if (fdd_get_head(drive)) /* HDSEL */ + ret |= 0x08; + if (!fdd_track0(drive)) /* nTRK0 */ + ret |= 0x10; + if (fdc->step) /* STEP */ + ret |= 0x20; + if (!fdd_get_type(1)) /* -Drive 2 Installed */ + ret |= 0x40; + if (fdc->fintr || fdc->reset_stat) /* INTR */ + ret |= 0x80; + } else ret = 0xff; - else { - if (fdc->flags & FDC_FLAG_UMC) { - drive = real_drive(fdc, fdc->dor & 1); - ret = !fdd_is_dd(drive) ? ((fdc->dor & 1) ? 2 : 1) : 0; - } else { - /* TODO: What is this and what is it used for? - It's almost identical to the PS/2 MCA mode. */ - drive = real_drive(fdc, fdc->dor & 3); - ret = 0x70; - ret &= ~(drive ? 0x40 : 0x20); - ret |= (fdc->dor & 0x30) >> 4; /* Motor Select 1, 0 */ + break; + case 1: /* STB */ + if (fdc->flags & FDC_FLAG_PS2) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x00; + if (!fdd_get_type(1)) /* -Drive 2 Installed */ + ret |= 0x80; + switch (drive) { /* -Drive Select 1,0 */ + case 0: + ret |= 0x43; + break; + case 1: + ret |= 0x23; + break; + case 2: + ret |= 0x62; + break; + case 3: + ret |= 0x61; + break; + + default: + break; + } + } else if (fdc->flags & FDC_FLAG_PS2_MCA) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0xc0; + ret |= (fdc->dor & 0x01) << 5; /* Drive Select 0 */ + ret |= (fdc->dor & 0x30) >> 4; /* Motor Select 1, 0 */ + } else { + if (is486 || !fdc->enable_3f1) + ret = 0xff; + else { + if (fdc->flags & FDC_FLAG_UMC) { + drive = real_drive(fdc, fdc->dor & 1); + ret = !fdd_is_dd(drive) ? ((fdc->dor & 1) ? 2 : 1) : 0; + } else { + /* TODO: What is this and what is it used for? + It's almost identical to the PS/2 MCA mode. */ + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x70; + ret &= ~(drive ? 0x40 : 0x20); + ret |= (fdc->dor & 0x30) >> 4; /* Motor Select 1, 0 */ + } } } - } - break; - case 2: - ret = fdc->dor; - break; - case 3: - drive = real_drive(fdc, fdc->dor & 3); - /* TODO: FDC_FLAG_PS2_TDR? */ - if ((fdc->flags & FDC_FLAG_PS2) || (fdc->flags & FDC_FLAG_PS2_MCA)) { - /* PS/1 Model 2121 seems return drive type in port - * 0x3f3, despite the 82077AA fdc_t not implementing - * this. This is presumably implemented outside the - * fdc_t on one of the motherboard's support chips. - * - * Confirmed: 00=1.44M 3.5 - * 10=2.88M 3.5 - * 20=1.2M 5.25 - * 30=1.2M 5.25 - * - * as reported by Configur.exe. - */ - if (fdd_is_525(drive)) - ret = 0x20; - else if (fdd_is_ed(drive)) - ret = 0x10; - else - ret = 0x00; - /* PS/55 POST throws an error and halt if ret = 1 or 2, somehow. */ - } else if (!fdc->enh_mode) - ret = 0x20; - else if (fdc->flags & FDC_FLAG_SMC661) - ret = (fdc->densel_force << 3) | ((!!fdc->swap) << 5) | (fdc->media_id << 6); - else - ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6); - break; - case 4: /*Status*/ - ret = fdc->stat; - break; - case 5: /*Data*/ - if (fdc->fifointest) { - /* Read FIFO buffer in the test mode (PS/55) */ - ret = fifo_read(fdc->fifo_p); break; - } - if ((fdc->stat & 0xf0) == 0xf0) { - fdc->stat &= ~0x80; - if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { - fdc->data_ready = 0; - ret = fdc->dat; - } else - ret = fifo_read(fdc->fifo_p); + case 2: + ret = fdc->dor; break; - } - if (fdc->paramstogo) { - fdc->stat &= ~0x80; - fdc_log("%i parameters to go\n", fdc->paramstogo); - fdc->paramstogo--; - ret = fdc->res[10 - fdc->paramstogo]; - if (!fdc->paramstogo) - fdc->stat = 0x80; - else - fdc->stat |= 0xC0; - } else if (fdc->dma) { - ret = fdc->dat; - break; - } else { - fdc->stat &= ~0x80; - if (lastbyte) - fdc->stat = 0x80; - lastbyte = 0; - ret = fdc->dat; - fdc->data_ready = 0; - } - fdc->stat &= 0xf0; - break; - case 7: /*Disk change*/ - drive = real_drive(fdc, fdc->dor & 3); - - if (fdc->flags & FDC_FLAG_PS2) { - if (fdc->dor & (0x10 << drive)) { - ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x00 : 0x80; - ret |= (fdc->dor & 0x08); - ret |= (fdc->noprec << 2); - ret |= (fdc->rate & 0x03); - } else - ret = 0x00; - } else if (fdc->flags & FDC_FLAG_PS2_MCA) { - if (fdc->dor & (0x10 << drive)) { - ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; - ret |= ((fdc->rate & 0x03) << 1); - ret |= fdc_get_densel(fdc, drive); - ret |= 0x78; - } else - ret = 0xf9; - } else { - if (fdc->dor & (0x10 << drive)) { - if ((drive == 1) && (fdc->flags & FDC_FLAG_TOSHIBA)) - ret = 0x00; + case 3: + drive = real_drive(fdc, fdc->dor & 3); + /* TODO: FDC_FLAG_PS2_TDR? */ + if ((fdc->flags & FDC_FLAG_PS2) || (fdc->flags & FDC_FLAG_PS2_MCA)) { + /* PS/1 Model 2121 seems return drive type in port + * 0x3f3, despite the 82077AA fdc_t not implementing + * this. This is presumably implemented outside the + * fdc_t on one of the motherboard's support chips. + * + * Confirmed: 00=1.44M 3.5 + * 10=2.88M 3.5 + * 20=1.2M 5.25 + * 30=1.2M 5.25 + * + * as reported by Configur.exe. + */ + if (fdd_is_525(drive)) + ret = 0x20; + else if (fdd_is_ed(drive)) + ret = 0x10; else + ret = 0x00; + /* PS/55 POST throws an error and halt if ret = 1 or 2, somehow. */ + } else if (!fdc->enh_mode) + ret = 0x20; + else if (fdc->flags & FDC_FLAG_SMC661) + ret = (fdc->densel_force << 3) | ((!!fdc->swap) << 5) | (fdc->media_id << 6); + else + ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6); + break; + case 4: /*Status*/ + ret = fdc->stat; + break; + case 5: /*Data*/ + if (fdc->fifointest) { + /* Read FIFO buffer in the test mode (PS/55) */ + ret = fifo_read(fdc->fifo_p); + break; + } + if ((fdc->stat & 0xf0) == 0xf0) { + fdc->stat &= ~0x80; + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { + fdc->data_ready = 0; + ret = fdc->dat; + } else + ret = fifo_read(fdc->fifo_p); + break; + } + if (fdc->paramstogo) { + fdc->stat &= ~0x80; + fdc_log("%i parameters to go\n", fdc->paramstogo); + fdc->paramstogo--; + ret = fdc->res[10 - fdc->paramstogo]; + if (!fdc->paramstogo) + fdc->stat = 0x80; + else + fdc->stat |= 0xC0; + } else if (fdc->dma) { + ret = fdc->dat; + break; + } else { + fdc->stat &= ~0x80; + if (lastbyte) + fdc->stat = 0x80; + lastbyte = 0; + ret = fdc->dat; + fdc->data_ready = 0; + } + fdc->stat &= 0xf0; + break; + case 7: /*Disk change*/ + drive = real_drive(fdc, fdc->dor & 3); + + if (fdc->flags & FDC_FLAG_PS2) { + if (fdc->dor & (0x10 << drive)) { + ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x00 : 0x80; + ret |= (fdc->dor & 0x08); + ret |= (fdc->noprec << 2); + ret |= (fdc->rate & 0x03); + } else + ret = 0x00; + } else if (fdc->flags & FDC_FLAG_PS2_MCA) { + if (fdc->dor & (0x10 << drive)) { ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; - } else - ret = 0x00; - if (fdc->flags & FDC_FLAG_DISKCHG_ACTLOW) /*PC2086/3086 seem to reverse this bit*/ - ret ^= 0x80; + ret |= ((fdc->rate & 0x03) << 1); + ret |= fdc_get_densel(fdc, drive); + ret |= 0x78; + } else + ret = 0xf9; + } else { + if (fdc->dor & (0x10 << drive)) { + if ((drive == 1) && (fdc->flags & FDC_FLAG_TOSHIBA)) + ret = 0x00; + else + ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; + } else + ret = 0x00; + if (fdc->flags & FDC_FLAG_DISKCHG_ACTLOW) /*PC2086/3086 seem to reverse this bit*/ + ret ^= 0x80; - /* 0 = ????, 1 = Ext. FDD off, 2 = Ext. FDD = FDD A, 3 = Ext. FDD = FDD B */ - if (fdc->flags & FDC_FLAG_TOSHIBA) { - ret |= (3 << 5); - ret |= 0x01; - } else - ret |= 0x7F; - } + /* 0 = ????, 1 = Ext. FDD off, 2 = Ext. FDD = FDD A, 3 = Ext. FDD = FDD B */ + if (fdc->flags & FDC_FLAG_TOSHIBA) { + ret |= (3 << 5); + ret |= 0x01; + } else + ret |= 0x7F; + } - fdc->step = 0; - break; - default: - ret = 0xff; - } + fdc->step = 0; + break; + default: + ret = 0xff; + } fdc_log("[%04X:%08X] Read FDC %04X %02X [%i:%02X]\n", CS, cpu_state.pc, addr, ret, drive, fdc->dor & (0x10 << drive)); return ret; } @@ -1886,7 +1896,7 @@ fdc_callback(void *priv) } else fdc->interrupt = -3; timer_set_delay_u64(&fdc->timer, 2048 * TIMER_USEC); - fdc->stat = 0x80 | (1 << fdc->rw_drive); + fdc->stat = 0x10 | (1 << fdc->rw_drive); return; case 0x0d: /*Format track*/ if (fdc->format_state == 1) { @@ -1929,7 +1939,7 @@ fdc_callback(void *priv) return; case 0x0f: /*Seek*/ fdc->st0 = 0x20 | (fdc->params[0] & 3); - fdc->stat = 0x80 | (1 << fdc->rw_drive); + fdc->stat = 0x10 | (1 << fdc->rw_drive); // Interrupts and callbacks in the fdd callback function return; case 0x10: /*Version*/ @@ -2863,4 +2873,4 @@ const device_t fdc_ps2_mca_device = { .speed_changed = NULL, .force_redraw = NULL, .config = NULL -}; +}; \ No newline at end of file diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index a0bef7ac6..212317f49 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -79,11 +79,34 @@ typedef struct fdd_t { fdd_t fdd[FDD_NUM]; +enum { + FDD_OP_NONE = 0, + FDD_OP_READ, + FDD_OP_WRITE, + FDD_OP_COMPARE, + FDD_OP_READADDR, + FDD_OP_FORMAT +}; + +typedef struct fdd_pending_op_t { + int pending; + int op; + int sector; + int track; + int side; + int density; + int sector_size; + uint8_t fill; +} fdd_pending_op_t; + +static fdd_pending_op_t fdd_pending[FDD_NUM]; + char floppyfns[FDD_NUM][512]; char *fdd_image_history[FDD_NUM][FLOPPY_IMAGE_HISTORY]; pc_timer_t fdd_poll_time[FDD_NUM]; pc_timer_t fdd_seek_timer[FDD_NUM]; +int fdd_seek_in_progress[FDD_NUM] = { 0, 0, 0, 0 }; static int fdd_notfound = 0; static int driveloaders[FDD_NUM]; @@ -293,10 +316,49 @@ fdd_seek_complete_callback(void *priv) { DRIVE *drive = (DRIVE *) priv; + fdd_seek_in_progress[drive->id] = 0; + fdd_log("fdd_seek_complete_callback(drive=%d) - TIMER FIRED! seek_in_progress=1\n", drive->id); fdd_log("Notifying FDC of seek completion\n"); fdd_do_seek(drive->id, fdd[drive->id].track); - fdc_seek_complete_interrupt(fdd_fdc, drive->id); + + int had_pending = fdd_pending[drive->id].pending; + if (had_pending) { + fdd_pending_op_t *po = &fdd_pending[drive->id]; + fdd_log("Starting deferred op %d after seek on drive %d (trk=%d, side=%d, sec=%d)\n", + po->op, drive->id, po->track, po->side, po->sector); + + switch (po->op) { + case FDD_OP_READ: + if (drives[drive->id].readsector) + drives[drive->id].readsector(drive->id, po->sector, po->track, po->side, po->density, po->sector_size); + break; + case FDD_OP_WRITE: + if (drives[drive->id].writesector) + drives[drive->id].writesector(drive->id, po->sector, po->track, po->side, po->density, po->sector_size); + break; + case FDD_OP_COMPARE: + if (drives[drive->id].comparesector) + drives[drive->id].comparesector(drive->id, po->sector, po->track, po->side, po->density, po->sector_size); + break; + case FDD_OP_READADDR: + if (drives[drive->id].readaddress) + drives[drive->id].readaddress(drive->id, po->side, po->density); + break; + case FDD_OP_FORMAT: + if (drives[drive->id].format) + drives[drive->id].format(drive->id, po->side, po->density, po->fill); + break; + default: + break; + } + + po->pending = 0; + po->op = FDD_OP_NONE; + } + + if (!had_pending) + fdc_seek_complete_interrupt(fdd_fdc, drive->id); } void @@ -306,6 +368,11 @@ fdd_seek(int drive, int track_diff) if (!track_diff) return; + if (fdd_seek_in_progress[drive]) { + fdd_log("Seek already in progress for drive %d, ignoring new seek request\n", drive); + return; + } + int old_track = fdd[drive].track; fdd[drive].track += track_diff; @@ -327,12 +394,14 @@ fdd_seek(int drive, int track_diff) /* Multi-track seek */ fdd_audio_play_multi_track_seek(drive, old_track, fdd[drive].track); } - + if (old_track + track_diff < 0) { fdd_do_seek(drive, fdd[drive].track); return; } + fdd_seek_in_progress[drive] = 1; + if (!fdd_seek_timer[drive].callback) { timer_add(&(fdd_seek_timer[drive]), fdd_seek_complete_callback, &drives[drive], 0); } @@ -629,7 +698,7 @@ fdd_set_motor_enable(int drive, int motor_enable) { fdd_log("fdd_set_motor_enable(%d, %d)\n", drive, motor_enable); fdd_audio_set_motor_enable(drive, motor_enable); - + if (motor_enable && !motoron[drive]) { timer_set_delay_u64(&fdd_poll_time[drive], fdd_byteperiod(drive)); } else if (!motor_enable && motoron[drive]) { @@ -700,6 +769,22 @@ void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) { fdd_log("fdd_readsector(%d, %d, %d, %d, %d, %d)\n", drive, sector, track, side, density, sector_size); + + if (fdd_seek_in_progress[drive]) { + fdd_log("Seek in progress on drive %d, deferring READ (trk=%d->%d, side=%d, sec=%d)\n", + drive, fdd[drive].track, track, side, sector); + fdd_pending[drive] = (fdd_pending_op_t) { + .pending = 1, + .op = FDD_OP_READ, + .sector = sector, + .track = track, + .side = side, + .density = density, + .sector_size = sector_size + }; + return; + } + if (drives[drive].readsector) drives[drive].readsector(drive, sector, track, side, density, sector_size); else @@ -710,6 +795,22 @@ void fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) { fdd_log("fdd_writesector(%d, %d, %d, %d, %d, %d)\n", drive, sector, track, side, density, sector_size); + + if (fdd_seek_in_progress[drive]) { + fdd_log("Seek in progress on drive %d, deferring WRITE (trk=%d->%d, side=%d, sec=%d)\n", + drive, fdd[drive].track, track, side, sector); + fdd_pending[drive] = (fdd_pending_op_t) { + .pending = 1, + .op = FDD_OP_WRITE, + .sector = sector, + .track = track, + .side = side, + .density = density, + .sector_size = sector_size + }; + return; + } + if (drives[drive].writesector) drives[drive].writesector(drive, sector, track, side, density, sector_size); else @@ -719,6 +820,21 @@ fdd_writesector(int drive, int sector, int track, int side, int density, int sec void fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) { + if (fdd_seek_in_progress[drive]) { + fdd_log("Seek in progress on drive %d, deferring COMPARE (trk=%d->%d, side=%d, sec=%d)\n", + drive, fdd[drive].track, track, side, sector); + fdd_pending[drive] = (fdd_pending_op_t) { + .pending = 1, + .op = FDD_OP_COMPARE, + .sector = sector, + .track = track, + .side = side, + .density = density, + .sector_size = sector_size + }; + return; + } + if (drives[drive].comparesector) drives[drive].comparesector(drive, sector, track, side, density, sector_size); else @@ -728,6 +844,19 @@ fdd_comparesector(int drive, int sector, int track, int side, int density, int s void fdd_readaddress(int drive, int side, int density) { + if (fdd_seek_in_progress[drive]) { + fdd_log("Seek in progress on drive %d, deferring READADDRESS (trk=%d, side=%d)\n", + drive, fdd[drive].track, side); + fdd_pending[drive] = (fdd_pending_op_t) { + .pending = 1, + .op = FDD_OP_READADDR, + .track = fdd[drive].track, + .side = side, + .density = density + }; + return; + } + if (drives[drive].readaddress) drives[drive].readaddress(drive, side, density); } @@ -735,6 +864,20 @@ fdd_readaddress(int drive, int side, int density) void fdd_format(int drive, int side, int density, uint8_t fill) { + if (fdd_seek_in_progress[drive]) { + fdd_log("Seek in progress on drive %d, deferring FORMAT (trk=%d, side=%d)\n", + drive, fdd[drive].track, side); + fdd_pending[drive] = (fdd_pending_op_t) { + .pending = 1, + .op = FDD_OP_FORMAT, + .track = fdd[drive].track, + .side = side, + .density = density, + .fill = fill + }; + return; + } + if (drives[drive].format) drives[drive].format(drive, side, density, fill); else @@ -777,7 +920,7 @@ fdd_init(void) if (fdd_sounds_enabled) { fdd_audio_init(); - } + } } void diff --git a/src/gdbstub.c b/src/gdbstub.c index cbbf0ede7..6e1e9af26 100644 --- a/src/gdbstub.c +++ b/src/gdbstub.c @@ -879,6 +879,7 @@ e22: /* Read by qwords, then by dwords, then by words, then by bytes. */ i = 0; + cpl_override = 1; if (is386) { for (; i < (k & ~7); i += 8) { *((uint64_t *) buf) = readmemql(j); @@ -900,6 +901,7 @@ e22: buf[0] = readmembl(j++); gdbstub_client_respond_hex(client, buf, 1); } + cpl_override = 0; break; case 'M': /* write memory */ @@ -934,6 +936,7 @@ e22: /* Write by qwords, then by dwords, then by words, then by bytes. */ p = client->packet; i = 0; + cpl_override = 1; if (is386) { for (; i < (k & ~7); i += 8) { writememql(j, *((uint64_t *) p)); @@ -955,6 +958,7 @@ e22: writemembl(j++, p[0]); p++; } + cpl_override = 0; /* Respond positively. */ goto ok; diff --git a/src/include/86box/filters.h b/src/include/86box/filters.h index d11e79512..3e20fa653 100644 --- a/src/include/86box/filters.h +++ b/src/include/86box/filters.h @@ -75,7 +75,7 @@ adgold_lowpass_iir(int c, int i, float NewSample) /* fc=56Hz */ static inline float -adgold_pseudo_stereo_iir(float NewSample) +adgold_pseudo_stereo_iir(int i, float NewSample) { float ACoef[NCoef + 1] = { 0.00001409030866231767, @@ -89,23 +89,23 @@ adgold_pseudo_stereo_iir(float NewSample) 0.98738361004063568000 }; - static float y[NCoef + 1]; /* output samples */ - static float x[NCoef + 1]; /* input samples */ + static float y[2][NCoef + 1]; /* output samples */ + static float x[2][NCoef + 1]; /* input samples */ int n; /* shift the old samples */ for (n = NCoef; n > 0; n--) { - x[n] = x[n - 1]; - y[n] = y[n - 1]; + x[i][n] = x[i][n - 1]; + y[i][n] = y[i][n - 1]; } /* Calculate the new output */ - x[0] = NewSample; - y[0] = ACoef[0] * x[0]; + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; for (n = 1; n <= NCoef; n++) - y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - return y[0]; + return y[i][0]; } /* fc=3.2kHz - probably incorrect */ diff --git a/src/include/86box/isapnp.h b/src/include/86box/isapnp.h index 6f7eb1185..9fedd656c 100644 --- a/src/include/86box/isapnp.h +++ b/src/include/86box/isapnp.h @@ -57,19 +57,24 @@ typedef struct isapnp_device_config_t { extern const uint8_t isapnp_init_key[32]; -void *isapnp_add_card(uint8_t *rom, uint16_t rom_size, - void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv), - void (*csn_changed)(uint8_t csn, void *priv), - uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), - void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), - void *priv); -void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size); -void isapnp_enable_card(void *priv, uint8_t enable); -void isapnp_set_csn(void *priv, uint8_t csn); -uint8_t isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg); -void isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val); -void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config); -void isapnp_reset_card(void *priv); -void isapnp_reset_device(void *priv, uint8_t ld); +extern void *isapnp_add_card(uint8_t *rom, uint16_t rom_size, + void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv), + void (*csn_changed)(uint8_t csn, void *priv), + uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), + void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), + void *priv); +extern void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size); +extern void isapnp_enable_card(void *priv, uint8_t enable); +extern void isapnp_set_csn(void *priv, uint8_t csn); +extern uint8_t isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg); +extern void isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val); +extern void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config); +extern void isapnp_reset_card(void *priv); +extern void isapnp_reset_device(void *priv, uint8_t ld); +extern void isapnp_set_rt(void *priv, uint8_t is_rt); +extern void isapnp_set_normal(void *priv, uint8_t normal); +extern void isapnp_activate(void *priv, uint16_t base, uint8_t irq, int active); +extern void isapnp_set_single_ld(void *priv); +extern uint8_t *isapnp_get_csnsav(void *priv); #endif /*EMU_ISAPNP_H*/ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 101ed2934..b88d8f492 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1117,6 +1117,9 @@ extern int machine_at_p65up5_cpknd_init(const machine_t *); extern int machine_at_kn97_init(const machine_t *); /* i440LX */ +#ifdef EMU_DEVICE_H +extern const device_t lx6_device; +#endif extern int machine_at_lx6_init(const machine_t *); extern int machine_at_optiplexgxa_init(const machine_t *); extern int machine_at_spitfire_init(const machine_t *); diff --git a/src/include/86box/snd_ym7128.h b/src/include/86box/snd_ym7128.h index a0796b1fa..f0657425f 100644 --- a/src/include/86box/snd_ym7128.h +++ b/src/include/86box/snd_ym7128.h @@ -19,18 +19,18 @@ typedef struct ym7128_t { int c1; int t[9]; - int16_t filter_dat; - int16_t prev_l; - int16_t prev_r; + int16_t filter_dat[2]; + int16_t prev_l[2]; + int16_t prev_r[2]; - int16_t delay_buffer[2400]; - int delay_pos; + int16_t delay_buffer[2][2400]; + int delay_pos[2]; int16_t last_samp; } ym7128_t; void ym7128_init(ym7128_t *ym7128); void ym7128_write(ym7128_t *ym7128, uint8_t val); -void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len); +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int i, int len); #endif /*SOUND_YM7128_H*/ diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 4c25799f6..22d6baac8 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -151,17 +151,57 @@ machine_at_kn97_init(const machine_t *model) } /* i440LX */ +static const device_config_t lx6_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "lx6", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "Award Modular BIOS v4.51PG - Revision LY", .internal_name = "lx6", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/lx6/LX6C_LY.BIN", "" } }, + { .name = "Award Modular BIOS v4.51PG - Revision PZ Beta", .internal_name = "lx6_beta", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/lx6/LX6C_PZ.B00", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t lx6_device = { + .name = "ABIT AB-LX6", + .internal_name = "lx6_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = lx6_config +}; + int machine_at_lx6_init(const machine_t *model) { - int ret; + int ret = 0; + const char* fn; - ret = bios_load_linear("roms/machines/lx6/LX6C_PZ.B00", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) + /* No ROMs available */ + if (!device_available(model->device)) return ret; + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); + machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1); diff --git a/src/machine/m_at_socket3.c b/src/machine/m_at_socket3.c index 8d460186c..d882dbd4d 100644 --- a/src/machine/m_at_socket3.c +++ b/src/machine/m_at_socket3.c @@ -216,7 +216,7 @@ machine_at_403tg_init(const machine_t *model) return ret; device_context(model->device); - int nvr_hack = !strcmp(device_get_config_bios("bios"), "403tg_d"); + int nvr_hack = !strcmp(device_get_config_bios("bios"), "403tg"); fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); ret = bios_load_linear(fn, 0x000f0000, 65536, 0); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index cbc48db1d..8c8dc6b91 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -12388,7 +12388,7 @@ const machine_t machines[] = { }, /* The BIOS sends KBC command B3 which indicates an AMI (or VIA VT82C42N) KBC. */ { - .name = "[i430FX] NEC PowerMate V", + .name = "[i430FX] NEC PowerMate Vxxx", .internal_name = "powermatev", .type = MACHINE_TYPE_SOCKET5, .chipset = MACHINE_CHIPSET_INTEL_430FX, @@ -12973,7 +12973,7 @@ const machine_t machines[] = { /* Has a SM(S)C FDC37C932 Super I/O chip with on-chip KBC with AMI MegaKey (revision '5') KBC firmware. */ { - .name = "[i430FX] HP Vectra VL 5 Series 4", + .name = "[i430FX] HP Vectra VL 5/xxx Series 4 (Chimay)", .internal_name = "vectra54", .type = MACHINE_TYPE_SOCKET7_3V, .chipset = MACHINE_CHIPSET_INTEL_430FX, @@ -15329,7 +15329,7 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* This has the Phoenix MultiKey KBC firmware on the NSC Suepr I/O chip. */ + /* This has the Phoenix MultiKey KBC firmware on the NSC Super I/O chip. */ { .name = "[i430TX] Packard Bell PB790", .internal_name = "an430tx", @@ -16009,7 +16009,7 @@ const machine_t machines[] = { }, /* M1534c kbc */ { - .name = "[ALi ALADDiN V] Gateway Lucas", + .name = "[ALi ALADDiN V] Gateway Lucas (MSI MS-5185)", .internal_name = "gwlucas", .type = MACHINE_TYPE_SOCKETS7, .chipset = MACHINE_CHIPSET_ALI_ALADDIN_V, @@ -17217,7 +17217,7 @@ const machine_t machines[] = { .kbc_p1 = 0x00000cf0, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &lx6_device, .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index 7f3490877..0bf3e9d3b 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -514,7 +514,7 @@ dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, UNUSED(unsigned le { uint8_t val2; - dp8390_log("DP839: Page0 write to register 0x%02x, value=0x%02x\n", + dp8390_log("DP8390: Page0 write to register 0x%02x, value=0x%02x\n", off, val); switch (off) { diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 0ce0190ac..3e2e7dd38 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -65,9 +65,11 @@ #include <86box/network.h> #include <86box/net_dp8390.h> #include <86box/net_ne2000.h> +#include <86box/nmc93cxx.h> #include <86box/isapnp.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> +#include "cpu.h" /* ROM BIOS file paths. */ #define ROM_PATH_NE1000 "roms/network/ne1000/ne1000.rom" @@ -85,30 +87,33 @@ typedef struct nic_t { const char *name; - uint8_t pnp_csnsav; uint8_t pci_slot; uint8_t irq_state; - uint8_t pad; + uint8_t csnsav; /* RTL8019AS/RTL8029AS registers */ + uint8_t _9346cr; uint8_t config0; + uint8_t config1; uint8_t config2; uint8_t config3; - uint8_t _9346cr; + uint8_t res; uint8_t pci_regs[PCI_REGSIZE]; - uint8_t eeprom[128]; /* for RTL8029AS */ uint8_t maclocal[6]; /* configured MAC (local) address */ /* POS registers, MCA boards only */ uint8_t pos_regs[8]; + uint8_t eeprom_data[128]; + int board; int is_pci; int is_mca; int is_8bit; int base_irq; + int irq_level; int has_bios; uint32_t base_address; @@ -121,6 +126,9 @@ typedef struct nic_t { rom_t bios_rom; void *pnp_card; + uint8_t *pnp_csnsav; + + nmc93cxx_eeprom_t *eeprom; } nic_t; #ifdef ENABLE_NE2K_LOG @@ -144,7 +152,14 @@ nelog(int lvl, const char *fmt, ...) static void nic_interrupt(void *priv, int set) { - nic_t *dev = (nic_t *) priv; + nic_t *dev = (nic_t *) priv; + int enabled = 1; + + if (!dev->irq_level) + set ^= 1; + + if (dev->board == NE2K_RTL8019AS_PNP) + enabled = dev->config1 & 0x80; if (dev->is_pci) { if (set) @@ -152,13 +167,32 @@ nic_interrupt(void *priv, int set) else pci_clear_irq(dev->pci_slot, PCI_INTA, &dev->irq_state); } else { - if (set) - picint(1 << dev->base_irq); - else + if (enabled && (dev->base_irq != 0x02)) { + if (set) + picint(1 << dev->base_irq); + else + picintc(1 << dev->base_irq); + } else if (dev->base_irq != 0x02) picintc(1 << dev->base_irq); } } +static void +nic_config_reset(void *priv) +{ + nic_t *dev = (nic_t *) priv; + + uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom); + + dev->config1 = (data[0x00] & 0x7f) | 0x80; + dev->config2 = (data[0x01] & 0xdf); + dev->config3 = (data[0x02] & 0xf7); + dev->irq_level = 0x02; + + if (dev->pnp_card != NULL) + isapnp_set_normal(dev->pnp_card, !!(dev->config3 & 0x80)); +} + /* reset - restore state to power-up, cancelling all i/o */ static void nic_reset(void *priv) @@ -168,6 +202,11 @@ nic_reset(void *priv) nelog(1, "%s: reset\n", dev->name); dp8390_reset(dev->dp8390); + + if (dev->board >= NE2K_RTL8019AS_PNP) + nic_config_reset(priv); + else + dev->irq_level = 0x02; } static void @@ -176,6 +215,11 @@ nic_soft_reset(void *priv) nic_t *dev = (nic_t *) priv; dp8390_soft_reset(dev->dp8390); + + if (dev->board >= NE2K_RTL8019AS_PNP) + nic_config_reset(priv); + else + dev->irq_level = 0x02; } /* @@ -236,6 +280,7 @@ asic_read(nic_t *dev, uint32_t off, unsigned int len) /* If all bytes have been written, signal remote-DMA complete */ if (dev->dp8390->remote_bytes == 0) { + nelog(3, "%s: DMA read: done (%i)\n", dev->name, dev->dp8390->IMR.rdma_inte); dev->dp8390->ISR.rdma_done = 1; if (dev->dp8390->IMR.rdma_inte) nic_interrupt(dev, 1); @@ -262,6 +307,11 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) dev->name, (unsigned) off, (unsigned) val); switch (off) { + default: /* this is invalid, but happens under win95 device detection */ + nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", + dev->name, (unsigned) off); + break; + case 0x00: /* Data register - see asic_read for a description */ if ((len > 1) && (dev->dp8390->DCR.wdsize == 0)) { nelog(3, "%s: DMA write length %d on byte mode operation\n", @@ -299,11 +349,6 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) case 0x0f: /* Reset register */ /* end of reset pulse */ break; - - default: /* this is invalid, but happens under win95 device detection */ - nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", - dev->name, (unsigned) off); - break; } } @@ -311,59 +356,159 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) static uint32_t page3_read(nic_t *dev, uint32_t off, UNUSED(unsigned int len)) { + uint8_t ret = 0x00; + if (dev->board >= NE2K_RTL8019AS_PNP) switch (off) { - case 0x1: /* 9346CR */ - return (dev->_9346cr); + default: + break; - case 0x3: /* CONFIG0 */ - return 0x00; /* Cable not BNC */ + case 0x1: /* 9346CR */ + ret = (dev->_9346cr & 0xfe); + + if (((ret & 0xc0) == 0x80) && nmc93cxx_eeprom_read(dev->eeprom)) + ret |= 0x01; + break; + + case 0x3: /* CONFIG0 */ + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->config0; + else + ret = 0x00; /* Cable not BNC */ + break; + + case 0x4: /* CONFIG1 */ + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->config1; + break; case 0x5: /* CONFIG2 */ - return (dev->config2 & 0xe0); + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->config2; + else + ret = (dev->config2 & 0xe0); + break; case 0x6: /* CONFIG3 */ - return (dev->config3 & 0x46); + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->config3; + else + ret = (dev->config3 & 0x46); + break; + + case 0x7: /* Reserved, Do not write */ + if (dev->board == NE2K_RTL8019AS_PNP) + ret = dev->res; + break; case 0x8: /* CSNSAV */ - return ((dev->board == NE2K_RTL8019AS_PNP) ? dev->pnp_csnsav : 0x00); + ret = ((dev->board == NE2K_RTL8019AS_PNP) ? *dev->pnp_csnsav : 0x00); + break; + + case 0x9: case 0xa: + case 0xc: + ret = 0xff; + break; + + case 0xb: /* INTR */ + if (dev->board == NE2K_RTL8019AS_PNP) { + ret = (pic2.irr & 0x02) ? 0x01 : 0x00; + ret |= (pic.irr & 0x08) ? 0x02 : 0x00; + ret |= (pic.irr & 0x10) ? 0x04 : 0x00; + ret |= (pic.irr & 0x20) ? 0x08 : 0x00; + ret |= (pic2.irr & 0x04) ? 0x10 : 0x00; + ret |= (pic2.irr & 0x08) ? 0x20 : 0x00; + ret |= (pic2.irr & 0x10) ? 0x40 : 0x00; + ret |= (pic2.irr & 0x80) ? 0x80 : 0x00; + } + break; + + case 0xd: /* CONFIG4 */ + if (dev->board == NE2K_RTL8019AS_PNP) { + uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom); + ret = data[0x03]; + } + break; case 0xe: /* 8029ASID0 */ if (dev->board == NE2K_RTL8029AS) - return 0x29; + ret = 0x29; + else + ret = 0xff; break; case 0xf: /* 8029ASID1 */ if (dev->board == NE2K_RTL8029AS) - return 0x80; - break; - - default: + ret = 0x80; + else + ret = 0xff; break; } - nelog(3, "%s: Page3 read register 0x%02x attempted\n", dev->name, off); - return 0x00; + nelog(3, "%s: Page3 read register 0x%02x, value=0x%04x\n", dev->name, off, ret); + return ret; } static void page3_write(nic_t *dev, uint32_t off, uint32_t val, UNUSED(unsigned len)) { + int cfg_write_enable = ((dev->_9346cr & 0xc0) == 0xc0); + if (dev->board >= NE2K_RTL8019AS_PNP) { - nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", + nelog(3, "%s: Page3 write to register 0x%02x, len=%u, value=0x%04x\n", dev->name, off, len, val); switch (off) { case 0x01: /* 9346CR */ dev->_9346cr = (val & 0xfe); + if ((val & 0xc0) == 0x80) + nmc93cxx_eeprom_write(dev->eeprom, !!(val & 0x08), !!(val & 0x04), !!(val & 0x02)); + else if ((val & 0xc0) == 0x40) { + uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom); + + dev->config1 = (data[0x00] & 0x7f) | 0x80; + dev->config2 = (data[0x01] & 0xdf); + dev->config3 = (data[0x02] & 0xf7); + dev->_9346cr = 0x21; + + isapnp_set_normal(dev->pnp_card, !!(dev->config3 & 0x80)); + } + break; + + case 0x03: /* CONFIG0 */ + if (cfg_write_enable && (dev->board == NE2K_RTL8019AS_PNP)) + dev->config0 = (dev->config0 & 0x3f) | (val & 0xc0); + break; + + case 0x04: /* CONFIG1 */ + if (cfg_write_enable && (dev->board == NE2K_RTL8019AS_PNP)) { + dev->config1 = (dev->config1 & 0x7f) | (val & 0x80); + if (val & 0x80) + nic_interrupt(dev, 1); + } break; case 0x05: /* CONFIG2 */ - dev->config2 = (val & 0xe0); + if (cfg_write_enable) { + if (dev->board == NE2K_RTL8019AS_PNP) + dev->config2 = (dev->config2 & 0x1f) | (val & 0xe0); + else + dev->config2 = (val & 0xe0); + } break; case 0x06: /* CONFIG3 */ - dev->config3 = (val & 0x46); + if (cfg_write_enable) { + if (dev->board == NE2K_RTL8019AS_PNP) + dev->config3 = (dev->config3 & 0xf9) | (val & 0x06); + else + dev->config3 = (val & 0x46); + } + break; + + case 0x7: /* Reserved, Do not write */ + if (dev->board == NE2K_RTL8019AS_PNP) + dev->res = val; break; case 0x09: /* HLTCLK */ @@ -491,6 +636,10 @@ static void nic_ioremove(nic_t *dev, uint16_t addr); static void nic_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { + uint8_t irq_map[16] = { 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x50, 0x60, 0x00, 0x00, 0x70 }; + uint8_t ios = 0x00; + if (ld) return; @@ -502,10 +651,22 @@ nic_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) } dev->base_address = config->io[0].base; - dev->base_irq = config->irq[0].irq; - if (config->activate && (dev->base_address != ISAPNP_IO_DISABLED)) + dev->base_irq = config->irq[0].irq; + dev->irq_level = config->irq[0].level; + if ((dev->base_irq >= 0x00) && (dev->base_irq <= 0x0f)) + dev->config1 = (dev->config1 & 0x8f) | irq_map[dev->base_irq]; + else + dev->config1 = (dev->config1 & 0x8f); + + if (config->activate && (dev->base_address != ISAPNP_IO_DISABLED)) { nic_ioset(dev, dev->base_address); + ios |= (dev->base_address & 0x0100) ? 0x00 : 0x04; + ios |= (dev->base_address & 0x0080) ? 0x08 : 0x00; + ios |= (dev->base_address & 0x0040) ? 0x02 : 0x00; + ios |= (dev->base_address & 0x0020) ? 0x01 : 0x00; + dev->config1 = (dev->config1 & 0xf0) | ios; + } } static void @@ -513,35 +674,44 @@ nic_pnp_csn_changed(uint8_t csn, void *priv) { nic_t *dev = (nic_t *) priv; - dev->pnp_csnsav = csn; + *dev->pnp_csnsav = csn; } static uint8_t nic_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv) { - if (ld != 0) - return 0x00; + uint8_t ret = 0x00; const nic_t *dev = (nic_t *) priv; - switch (reg) { - case 0xF0: - return dev->config0; - - case 0xF2: - return dev->config2; - - case 0xF3: - return dev->config3; - - case 0xF5: - return dev->pnp_csnsav; - + if (ld == 0) switch (reg) { default: break; + + case 0xf0: /* CONFIG0 */ + ret = dev->config0; + break; + + case 0xf1: /* CONFIG1 */ + ret = dev->config1; + break; + + case 0xf2: /* CONFIG2 */ + ret = dev->config2; + break; + + case 0xf3: /* CONFIG3 */ + ret = dev->config3; + break; + + case 0xf5: + ret = *dev->pnp_csnsav; + break; } - return 0x00; + nelog(3, "[R] Vendor register: %02X (LD = %02X) = %02X\n", reg, ld, ret); + + return ret; } static void @@ -549,10 +719,12 @@ nic_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) { nic_t *dev = (nic_t *) priv; + nelog(3, "[W] Vendor register: %02X (LD = %02X) = %02X\n", reg, ld, val); + if ((ld == 0) && (reg == 0xf6) && (val & 0x04)) { - uint8_t csn = dev->pnp_csnsav; + uint8_t csn = *dev->pnp_csnsav; isapnp_set_csn(dev->pnp_card, 0); - dev->pnp_csnsav = csn; + *dev->pnp_csnsav = csn; } } @@ -913,6 +1085,7 @@ nic_init(const device_t *info) char *rom = NULL; nic_t *dev; int set_oui = 0; + int use_nvr = 0; dev = calloc(1, sizeof(nic_t)); dev->name = info->name; @@ -1144,26 +1317,33 @@ nic_init(const device_t *info) } /* Initialize the RTL80x9 EEPROM. */ - memset(dev->eeprom, 0x00, sizeof(dev->eeprom)); + memset(dev->eeprom_data, 0x00, sizeof(dev->eeprom_data)); if (dev->board == NE2K_RTL8029AS) { - memcpy(&dev->eeprom[0x02], dev->maclocal, 6); + dev->eeprom_data[0x00] = 0x00; + dev->eeprom_data[0x01] = 0x00; - dev->eeprom[0x76] = dev->eeprom[0x7A] = dev->eeprom[0x7E] = (PCI_DEVID & 0xff); - dev->eeprom[0x77] = dev->eeprom[0x7B] = dev->eeprom[0x7F] = (PCI_DEVID >> 8); - dev->eeprom[0x78] = dev->eeprom[0x7C] = (PCI_VENDID & 0xff); - dev->eeprom[0x79] = dev->eeprom[0x7D] = (PCI_VENDID >> 8); + memcpy(&dev->eeprom_data[0x02], dev->maclocal, 6); + + dev->eeprom_data[0x76] = dev->eeprom_data[0x7a] = dev->eeprom_data[0x7e] = (PCI_DEVID & 0xff); + dev->eeprom_data[0x77] = dev->eeprom_data[0x7b] = dev->eeprom_data[0x7f] = (PCI_DEVID >> 8); + dev->eeprom_data[0x78] = dev->eeprom_data[0x7c] = (PCI_VENDID & 0xff); + dev->eeprom_data[0x79] = dev->eeprom_data[0x7d] = (PCI_VENDID >> 8); + + use_nvr = 1; } else { const char *pnp_rom_file = NULL; int pnp_rom_len = 0x4a; switch (dev->board) { case NE2K_RTL8019AS_PNP: pnp_rom_file = "roms/network/rtl8019as/RTL8019A.BIN"; + use_nvr = 1; break; case NE2K_DE220P: pnp_rom_file = "roms/network/de220p/dlk2201a.bin"; - pnp_rom_len = 0x43; + pnp_rom_len = 0x43; + use_nvr = 1; break; default: @@ -1174,8 +1354,8 @@ nic_init(const device_t *info) if (pnp_rom_file) { FILE *fp = rom_fopen(pnp_rom_file, "rb"); if (fp) { - if (fread(&dev->eeprom[0x12], 1, pnp_rom_len, fp) == pnp_rom_len) - pnp_rom = &dev->eeprom[0x12]; + if (fread(&dev->eeprom_data[0x12], 1, pnp_rom_len, fp) == pnp_rom_len) + pnp_rom = &dev->eeprom_data[0x12]; fclose(fp); } } @@ -1183,10 +1363,22 @@ nic_init(const device_t *info) switch (info->local) { case NE2K_RTL8019AS_PNP: case NE2K_DE220P: - dev->pnp_card = isapnp_add_card(pnp_rom, pnp_rom_len, - nic_pnp_config_changed, nic_pnp_csn_changed, - nic_pnp_read_vendor_reg, nic_pnp_write_vendor_reg, - dev); + dev->pnp_card = isapnp_add_card(pnp_rom, pnp_rom_len, + nic_pnp_config_changed, nic_pnp_csn_changed, + nic_pnp_read_vendor_reg, nic_pnp_write_vendor_reg, + dev); + dev->pnp_csnsav = isapnp_get_csnsav(dev->pnp_card); + dev->config0 = 0x10 /* Cable not BNC */; + dev->config1 = 0x80; + dev->config2 = 0x00; + dev->config3 = 0x80; + isapnp_set_rt(dev->pnp_card, 1); + + dev->eeprom_data[0x00] = 0x80; + dev->eeprom_data[0x01] = 0x00; + dev->eeprom_data[0x02] = 0x81; + dev->eeprom_data[0x03] = 0x01; + memcpy(&dev->eeprom_data[0x04], dev->maclocal, 6); break; default: @@ -1195,6 +1387,50 @@ nic_init(const device_t *info) } } + if (use_nvr) { + nmc93cxx_eeprom_params_t params; + char filename[1024] = { 0 }; + + params.nwords = 64; + params.default_content = (uint16_t *) dev->eeprom_data; + params.filename = filename; + int inst = device_get_instance(); + snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, inst); + dev->eeprom = device_add_inst_params(&nmc93cxx_device, inst, ¶ms); + if (dev->eeprom == NULL) { + free(dev); + return NULL; + } + if (info->local == NE2K_RTL8019AS_PNP) { + uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom); + + dev->config1 = (data[0x00] & 0x7f) | 0x80; + dev->config2 = (data[0x01] & 0xdf); + dev->config3 = (data[0x02] & 0xf7); + + isapnp_set_normal(dev->pnp_card, !!(dev->config3 & 0x80)); + isapnp_set_single_ld(dev->pnp_card); + + uint8_t irq_map[8] = { 9, 3, 4, 5, 10, 11, 12, 15 }; + + dev->base_address = 0x0200; + dev->base_address |= (dev->config1 & 0x01) ? 0x0020 : 0x0000; + dev->base_address |= (dev->config1 & 0x02) ? 0x0040 : 0x0000; + dev->base_address |= (dev->config1 & 0x04) ? 0x0000 : 0x0100; + dev->base_address |= (dev->config1 & 0x08) ? 0x0080 : 0x0000; + + dev->base_irq = irq_map[(dev->config1 >> 4) & 0x07]; + + if (!(dev->config3 & 0x01)) + nic_ioset(dev, dev->base_address); + + isapnp_activate(dev->pnp_card, dev->base_address, dev->base_irq, !(dev->config3 & 0x01)); + } + } + + if (dev->pnp_csnsav == NULL) + dev->pnp_csnsav = &dev->csnsav; + if (dev->board != NE2K_ETHERNEXT_MC) /* Reset the board. */ nic_reset(dev); @@ -1773,7 +2009,7 @@ const device_t rtl8019as_pnp_device = { .local = NE2K_RTL8019AS_PNP, .init = nic_init, .close = nic_close, - .reset = NULL, + .reset = nic_config_reset, .available = rtl8019as_available, .speed_changed = NULL, .force_redraw = NULL, @@ -1787,7 +2023,7 @@ const device_t de220p_device = { .local = NE2K_DE220P, .init = nic_init, .close = nic_close, - .reset = NULL, + .reset = nic_config_reset, .available = de220p_available, .speed_changed = NULL, .force_redraw = NULL, @@ -1801,7 +2037,7 @@ const device_t rtl8029as_device = { .local = NE2K_RTL8029AS, .init = nic_init, .close = nic_close, - .reset = NULL, + .reset = nic_config_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index a48fde924..d667cfdb9 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -542,6 +542,17 @@ main(int argc, char *argv[]) #endif QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); + QSurfaceFormat fmt = QSurfaceFormat::defaultFormat(); + fmt.setSwapInterval(0); + fmt.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); + fmt.setRenderableType(QSurfaceFormat::OpenGL); +#ifdef Q_OS_MACOS + fmt.setVersion(4, 1); +#else + fmt.setVersion(3, 2); +#endif + QSurfaceFormat::setDefaultFormat(fmt); + QApplication app(argc, argv); QLocale::setDefault(QLocale::C); setlocale(LC_NUMERIC, "C"); @@ -573,9 +584,6 @@ main(int argc, char *argv[]) Q_INIT_RESOURCE(qt_resources); Q_INIT_RESOURCE(qt_translations); - QSurfaceFormat fmt = QSurfaceFormat::defaultFormat(); - fmt.setSwapInterval(0); - QSurfaceFormat::setDefaultFormat(fmt); #ifdef __APPLE__ CocoaEventFilter cocoafilter; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 954547078..e88bedd90 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -84,6 +84,7 @@ extern bool cpu_thread_running; #include #include #include +#include #include #include #include @@ -171,8 +172,6 @@ extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index); extern MainWindow *main_window; -bool MainWindow::s_adjustingForce43 = false; - MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) @@ -933,11 +932,18 @@ MainWindow::closeEvent(QCloseEvent *event) } } if (window_remember) { - window_w = ui->stackedWidget->width(); - window_h = ui->stackedWidget->height(); + // If maximized, persist the normal (restorable) geometry + const bool wasMax = isMaximized(); + QRect normal = wasMax ? this->normalGeometry() : this->geometry(); + // Save WINDOW size (not the content widget’s 4:3 box) + const int chromeHeight = geometry().height() - ui->stackedWidget->height(); + window_w = normal.width(); + window_h = normal.height() - chromeHeight; + if (window_h < 0) + window_h = 0; if (!QApplication::platformName().contains("wayland")) { - window_x = this->geometry().x(); - window_y = this->geometry().y(); + window_x = normal.x(); + window_y = normal.y(); } for (int i = 1; i < MONITORS_NUM; i++) { if (renderers[i]) { @@ -1021,65 +1027,56 @@ void MainWindow::updateShortcuts() seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionMute_Unmute->setShortcut(seq); } - -void -MainWindow::adjustForForce43(const QSize &newWinSize) + +void +MainWindow::applyContentLayoutForCurrentState() { - // Only act in resizable mode with Force 4:3 enabled and not fullscreen - if (!(vid_resize == 1 && force_43 > 0) || video_fullscreen || s_adjustingForce43) - return; + auto applyFill = [this](const QRect& r){ + ui->stackedWidget->setGeometry(r); + ui->stackedWidget->onResize(r.width(), r.height()); + if (monitors[0].mon_scrnsz_x != r.width() || monitors[0].mon_scrnsz_y != r.height()) { + monitors[0].mon_scrnsz_x = r.width(); + monitors[0].mon_scrnsz_y = r.height(); + plat_resize_request(r.width(), r.height(), 0); + } + }; - s_adjustingForce43 = true; + auto apply43 = [this](const QRect& area){ + int areaW = area.width(); + int areaH = area.height(); + if (areaW <= 0 || areaH <= 0) return; - // Height consumed by menu/status/toolbars - int chromeH = menuBar()->height() - + (hide_status_bar ? 0 : statusBar()->height()) - + (hide_tool_bar ? 0 : ui->toolBar->height()); + int targetW = areaW; + int targetH = (areaW * 3) / 4; + if (targetH > areaH) { + targetH = areaH; + targetW = (areaH * 4) / 3; + } - // Compute client area size in device‑independent pixels - double dpr = (!dpi_scale ? util::screenOfWidget(this)->devicePixelRatio() : 1.0); - int winW = newWinSize.width(); - int winH = newWinSize.height(); - int clientW = static_cast(winW / dpr); - int clientH = static_cast((winH - chromeH) / dpr); + const int x = area.x() + (areaW - targetW) / 2; + const int y = area.y() + (areaH - targetH) / 2; - if (clientW <= 0 || clientH <= 0) { - s_adjustingForce43 = false; - return; - } + ui->stackedWidget->setGeometry(x, y, targetW, targetH); + ui->stackedWidget->onResize(targetW, targetH); - // Decide which dimension the user changed most – adjust the other - int curW = static_cast(width() / dpr); - int curH = static_cast((height() - chromeH) / dpr); - bool widthChanged = std::abs(clientW - curW) >= std::abs(clientH - curH); + if (monitors[0].mon_scrnsz_x != targetW || monitors[0].mon_scrnsz_y != targetH) { + monitors[0].mon_scrnsz_x = targetW; + monitors[0].mon_scrnsz_y = targetH; + plat_resize_request(targetW, targetH, 0); + } + }; - int targetW, targetH; - if (widthChanged) { - // user dragged width – compute matching height for 4:3 - targetW = clientW; - targetH = (clientW * 3) / 4; - } else { - // user dragged height – compute matching width for 4:3 - targetH = clientH; - targetW = (clientH * 4) / 3; - } + QWidget *cw = this->centralWidget(); + if (!cw) return; - // Convert back to window size including chrome and apply - int newW = static_cast(targetW * dpr); - int newH = static_cast(targetH * dpr) + chromeH; - if (newW != winW || newH != winH) - resize(newW, newH); + const QRect area = cw->contentsRect(); - // Update emulator framebuffer size and notify platform - monitors[0].mon_scrnsz_x = targetW; - monitors[0].mon_scrnsz_y = targetH; - plat_resize_request(targetW, targetH, 0); + // Fullscreen always fills (legacy behavior) + if (video_fullscreen) { applyFill(area); return; } - // Allow renderer widget to grow and recompute scaling - ui->stackedWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); - ui->stackedWidget->onResize(width(), height()); - - s_adjustingForce43 = false; + // Windowed: enforce 4:3 only when requested, otherwise fill + if (force_43 > 0) apply43(area); + else applyFill(area); } void @@ -1088,26 +1085,10 @@ MainWindow::resizeEvent(QResizeEvent *event) //qDebug() << pos().x() + event->size().width(); //qDebug() << pos().y() + event->size().height(); - // Enforce 4:3 aspect ratio in resizable mode when the option is set - adjustForForce43(event->size()); - - if (vid_resize == 1 || video_fullscreen) - return; + // Always let QMainWindow do its layout first + QMainWindow::resizeEvent(event); - 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); + applyContentLayoutForCurrentState(); } void @@ -1201,12 +1182,25 @@ MainWindow::showEvent(QShowEvent *event) monitors[0].mon_scrnsz_y = fixed_size_y; } if (window_remember && vid_resize == 1) { - ui->stackedWidget->setFixedSize(window_w, window_h); + const QSize target(window_w, window_h); + const QSize prevMin = ui->stackedWidget->minimumSize(); + const QSize prevMax = ui->stackedWidget->maximumSize(); + + ui->stackedWidget->setMinimumSize(target); + ui->stackedWidget->setMaximumSize(target); #ifndef Q_OS_MACOS QApplication::processEvents(); #endif this->adjustSize(); + + ui->stackedWidget->setMinimumSize(prevMin); + ui->stackedWidget->setMaximumSize(prevMax); + ui->stackedWidget->resize(target); } + + QTimer::singleShot(0, this, [this]{ + applyContentLayoutForCurrentState(); + }); } void @@ -1509,6 +1503,7 @@ MainWindow::on_actionFullscreen_triggered() { if (video_fullscreen > 0) { showNormal(); + QTimer::singleShot(0, this, [this]{ applyContentLayoutForCurrentState(); }); ui->menubar->show(); if (!hide_status_bar) ui->statusbar->show(); @@ -2146,16 +2141,7 @@ MainWindow::on_actionForce_4_3_display_ratio_triggered() { video_toggle_option(ui->actionForce_4_3_display_ratio, &force_43); - // When turning on Force 4:3 in resizable mode, immediately snap to 4:3 - if (vid_resize == 1 && !video_fullscreen) { - ui->stackedWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); - if (force_43 > 0) { - adjustForForce43(size()); - } else { - // Turning off: refresh renderer scaling - ui->stackedWidget->onResize(width(), height()); - } - } + QTimer::singleShot(0, this, [this]{ applyContentLayoutForCurrentState(); }); } void @@ -2524,4 +2510,3 @@ void MainWindow::on_actionCGA_composite_settings_triggered() isNonPause = false; config_save(); } - diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index f562c2ea9..77e8fe7c4 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -179,8 +179,8 @@ private: std::shared_ptr mm; static bool s_adjustingForce43; // guard against recursion - void adjustForForce43(const QSize &newWinSize); - + void applyContentLayoutForCurrentState(); + void updateShortcuts(); void processKeyboardInput(bool down, uint32_t keycode); #ifdef Q_OS_MACOS diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index b74b74202..492acb630 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -75,7 +75,11 @@ extern int video_focus_dim; extern int video_refresh_rate; 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" @@ -89,7 +93,11 @@ const char* vertex_shader_default_tex_src = "}\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" @@ -103,7 +111,11 @@ const char* fragment_shader_default_tex_src = "}\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" @@ -117,7 +129,11 @@ const char* vertex_shader_default_color_src = "}\n"; const char* fragment_shader_default_color_src = +#ifdef __APPLE__ "#version 150\n" +#else + "#version 130\n" +#endif "\n" "in vec4 color;\n" "\n" @@ -814,11 +830,9 @@ OpenGLRenderer::OpenGLRenderer(QWidget *parent) format.setVersion(3, 2); #endif format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) - format.setRenderableType(QSurfaceFormat::OpenGLES); - + format.setRenderableType(QSurfaceFormat::OpenGL); format.setSwapInterval(video_vsync ? 1 : 0); + format.setAlphaBufferSize(0); setFormat(format); diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 32b017b92..4a2e39bbe 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -441,6 +441,7 @@ RendererStack::createRenderer(Renderer renderer) current->setFocusProxy(this); current->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); current->setStyleSheet("background-color: black"); + current->setAttribute(Qt::WA_AlwaysStackOnTop); addWidget(current.get()); this->setStyleSheet("background-color: black"); diff --git a/src/qt/qt_vmmanager_system.cpp b/src/qt/qt_vmmanager_system.cpp index 988d3ed5e..dec503fce 100644 --- a/src/qt/qt_vmmanager_system.cpp +++ b/src/qt/qt_vmmanager_system.cpp @@ -654,6 +654,9 @@ VMManagerSystem::setupVars() { voodoo_name = tr("3Dfx Voodoo 2"); break; } + + if (voodoo_config["sli"].toInt() == 1) + voodoo_name.append(" (SLI)"); } display_table[VMManager::Display::Name::Voodoo] = voodoo_name; diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 360da3fec..f8c89c554 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -82,7 +82,8 @@ typedef struct adgold_t { int treble; int bass; - int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t samp_buffer[SOUNDBUFLEN * 2]; + int16_t opl_buffer[MUSICBUFLEN * 2]; int16_t mma_buffer[2][SOUNDBUFLEN]; int pos; @@ -90,6 +91,8 @@ typedef struct adgold_t { int gameport_enabled; int surround_enabled; + + int finish_dma; } adgold_t; static int attenuation[0x40]; @@ -173,33 +176,41 @@ adgold_update_irq_status(adgold_t *adgold) temp &= ~2; if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2)) temp &= ~2; + adgold->adgold_status = temp; - if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) { + if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) picint(1 << adgold->irq); - } + else if (!(adgold->adgold_status ^ 0xf) && adgold->adgold_irq_status) + picintc(1 << adgold->irq); adgold->adgold_irq_status = adgold->adgold_status ^ 0xf; } -int +void adgold_getsamp_dma(adgold_t *adgold, int channel) { - int temp; - dma_set_drq(adgold->dma, 1); + int dma_dat; - if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) - return 2; + adgold->finish_dma = 0; - temp = dma_channel_read(adgold->dma); - if (temp == DMA_NODATA) { - return 1; + if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) { + adgold->finish_dma = 1; + return; } - adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; - adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + + dma_set_drq(adgold->dma, 1); + dma_dat = dma_channel_read(adgold->dma); + if (dma_dat == DMA_NODATA) + return; + + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = dma_dat; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; if (adgold->adgold_mma_regs[channel][0xc] & 0x60) { - temp = dma_channel_read(adgold->dma); - adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + dma_dat = dma_channel_read(adgold->dma); + if (dma_dat == DMA_NODATA) + return; + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = dma_dat; adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; } if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel]) { @@ -207,8 +218,6 @@ adgold_getsamp_dma(adgold_t *adgold, int channel) adgold_update_irq_status(adgold); dma_set_drq(adgold->dma, 0); } - - return 0; } void @@ -291,7 +300,8 @@ adgold_write(uint16_t addr, uint8_t val, void *priv) case 0x18: /*Surround*/ adgold->adgold_38x_regs[0x18] = val; - ym7128_write(&adgold->ym7128, val); + if (adgold->surround_enabled) + ym7128_write(&adgold->ym7128, val); break; default: @@ -379,16 +389,10 @@ adgold_write(uint16_t addr, uint8_t val, void *priv) adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) { - if (adgold_getsamp_dma(adgold, 0)) { - adgold->adgold_mma_fifo_end[0] = 0; - adgold->adgold_mma_fifo_start[0] = 0; + adgold_getsamp_dma(adgold, 0); + adgold_getsamp_dma(adgold, 1); + if (adgold->finish_dma) break; - } - if (adgold_getsamp_dma(adgold, 1)) { - adgold->adgold_mma_fifo_end[1] = 0; - adgold->adgold_mma_fifo_start[1] = 0; - break; - } } if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) { adgold->adgold_mma_status &= ~0x01; @@ -402,11 +406,9 @@ adgold_write(uint16_t addr, uint8_t val, void *priv) } } else { while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) { - if (adgold_getsamp_dma(adgold, 0)) { - adgold->adgold_mma_fifo_end[0] = 0; - adgold->adgold_mma_fifo_start[0] = 0; + adgold_getsamp_dma(adgold, 0); + if (adgold->finish_dma) break; - } } if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) { adgold->adgold_mma_status &= ~0x01; @@ -516,11 +518,9 @@ adgold_write(uint16_t addr, uint8_t val, void *priv) if (adgold->adgold_mma_regs[1][0xc] & 1) { while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) { - if (adgold_getsamp_dma(adgold, 1)) { - adgold->adgold_mma_fifo_end[1] = 0; - adgold->adgold_mma_fifo_start[1] = 0; + adgold_getsamp_dma(adgold, 1); + if (adgold->finish_dma) break; - } } } } @@ -598,7 +598,6 @@ adgold_read(uint16_t addr, void *priv) temp = adgold->adgold_mma_status; adgold->adgold_mma_status &= ~0xf3; /*JUKEGOLD expects timer status flags to auto-clear*/ adgold_update_irq_status(adgold); - picintc(1 << adgold->irq); break; case 5: if (adgold->adgold_mma_addr >= 0xf) @@ -693,11 +692,9 @@ adgold_mma_poll(adgold_t *adgold, int channel) } if (adgold->adgold_mma_regs[channel][0xc] & 1) { - if (adgold_getsamp_dma(adgold, channel)) { - adgold->adgold_mma_fifo_end[channel] = 0; - adgold->adgold_mma_fifo_start[channel] = 0; + adgold_getsamp_dma(adgold, channel); + if (adgold->finish_dma) return; - } } if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) { adgold->adgold_mma_status |= (1 << channel); @@ -782,34 +779,30 @@ static void adgold_get_buffer(int32_t *buffer, int len, void *priv) { adgold_t *adgold = (adgold_t *) priv; - int16_t *adgold_buffer = malloc(sizeof(int16_t) * len * 2); - if (adgold_buffer == NULL) - fatal("adgold_buffer = NULL"); - int c; adgold_update(adgold); for (c = 0; c < len * 2; c += 2) { - adgold_buffer[c] = ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; - adgold_buffer[c + 1] = ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; + adgold->samp_buffer[c] = ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; + adgold->samp_buffer[c + 1] = ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; } if (adgold->surround_enabled) - ym7128_apply(&adgold->ym7128, adgold_buffer, len); + ym7128_apply(&adgold->ym7128, adgold->samp_buffer, 0, len); switch (adgold->adgold_38x_regs[0x8] & 6) { case 0: for (c = 0; c < len * 2; c++) - adgold_buffer[c] = 0; + adgold->samp_buffer[c] = 0; break; case 2: /*Left channel only*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c + 1] = adgold_buffer[c]; + adgold->samp_buffer[c + 1] = adgold->samp_buffer[c]; break; case 4: /*Right channel only*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] = adgold_buffer[c + 1]; + adgold->samp_buffer[c] = adgold->samp_buffer[c + 1]; break; case 6: /*Left and right channels*/ break; @@ -821,7 +814,7 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) switch (adgold->adgold_38x_regs[0x8] & 0x18) { case 0x00: /*Forced mono*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] = adgold_buffer[c + 1] = ((int32_t) adgold_buffer[c] + (int32_t) adgold_buffer[c + 1]) / 2; + adgold->samp_buffer[c] = adgold->samp_buffer[c + 1] = ((int32_t) adgold->samp_buffer[c] + (int32_t) adgold->samp_buffer[c + 1]) / 2; break; case 0x08: /*Linear stereo*/ break; @@ -829,17 +822,17 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) /*Filter left channel, leave right channel unchanged*/ /*Filter cutoff is largely a guess*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); + adgold->samp_buffer[c] += adgold_pseudo_stereo_iir(0, adgold->samp_buffer[c]); break; case 0x18: /*Spatial stereo*/ /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet and a very vague understanding of how op-amps work to go on*/ for (c = 0; c < len * 2; c += 2) { - int16_t l = adgold_buffer[c]; - int16_t r = adgold_buffer[c + 1]; + int16_t l = adgold->samp_buffer[c]; + int16_t r = adgold->samp_buffer[c + 1]; - adgold_buffer[c] += (r / 3) + ((l * 2) / 3); - adgold_buffer[c + 1] += (l / 3) + ((r * 2) / 3); + adgold->samp_buffer[c] += (r / 3) + ((l * 2) / 3); + adgold->samp_buffer[c + 1] += (l / 3) + ((r * 2) / 3); } break; @@ -853,7 +846,7 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) int32_t highpass; /*Output is deliberately halved to avoid clipping*/ - temp = ((int32_t) adgold_buffer[c] * adgold->vol_l) >> 17; + temp = ((int32_t) adgold->samp_buffer[c] * adgold->vol_l) >> 17; lowpass = adgold_lowpass_iir(0, 0, temp); highpass = adgold_highpass_iir(0, 0, temp); if (adgold->bass > 6) @@ -870,7 +863,7 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) temp = 32767; buffer[c] += temp; - temp = ((int32_t) adgold_buffer[c + 1] * adgold->vol_r) >> 17; + temp = ((int32_t) adgold->samp_buffer[c + 1] * adgold->vol_r) >> 17; lowpass = adgold_lowpass_iir(0, 1, temp); highpass = adgold_highpass_iir(0, 1, temp); if (adgold->bass > 6) @@ -889,42 +882,36 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) } adgold->pos = 0; - - free(adgold_buffer); } static void adgold_get_music_buffer(int32_t *buffer, int len, void *priv) { adgold_t *adgold = (adgold_t *) priv; - int16_t *adgold_buffer = malloc(sizeof(int16_t) * len * 2); - if (adgold_buffer == NULL) - fatal("adgold_buffer = NULL"); - int c; const int32_t *opl_buf = adgold->opl.update(adgold->opl.priv); for (c = 0; c < len * 2; c += 2) { - adgold_buffer[c] = ((opl_buf[c] * adgold->fm_vol_l) >> 7) / 2; - adgold_buffer[c + 1] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; + adgold->opl_buffer[c] = ((opl_buf[c] * adgold->fm_vol_l) >> 7) / 2; + adgold->opl_buffer[c + 1] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; } if (adgold->surround_enabled) - ym7128_apply(&adgold->ym7128, adgold_buffer, len); + ym7128_apply(&adgold->ym7128, adgold->opl_buffer, 1, len); switch (adgold->adgold_38x_regs[0x8] & 6) { case 0: for (c = 0; c < len * 2; c++) - adgold_buffer[c] = 0; + adgold->opl_buffer[c] = 0; break; case 2: /*Left channel only*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c + 1] = adgold_buffer[c]; + adgold->opl_buffer[c + 1] = adgold->opl_buffer[c]; break; case 4: /*Right channel only*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] = adgold_buffer[c + 1]; + adgold->opl_buffer[c] = adgold->opl_buffer[c + 1]; break; case 6: /*Left and right channels*/ break; @@ -936,7 +923,7 @@ adgold_get_music_buffer(int32_t *buffer, int len, void *priv) switch (adgold->adgold_38x_regs[0x8] & 0x18) { case 0x00: /*Forced mono*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] = adgold_buffer[c + 1] = ((int32_t) adgold_buffer[c] + (int32_t) adgold_buffer[c + 1]) / 2; + adgold->opl_buffer[c] = adgold->opl_buffer[c + 1] = ((int32_t) adgold->opl_buffer[c] + (int32_t) adgold->opl_buffer[c + 1]) / 2; break; case 0x08: /*Linear stereo*/ break; @@ -944,17 +931,17 @@ adgold_get_music_buffer(int32_t *buffer, int len, void *priv) /*Filter left channel, leave right channel unchanged*/ /*Filter cutoff is largely a guess*/ for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); + adgold->opl_buffer[c] += adgold_pseudo_stereo_iir(1, adgold->opl_buffer[c]); break; case 0x18: /*Spatial stereo*/ /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet and a very vague understanding of how op-amps work to go on*/ for (c = 0; c < len * 2; c += 2) { - int16_t l = adgold_buffer[c]; - int16_t r = adgold_buffer[c + 1]; + int16_t l = adgold->opl_buffer[c]; + int16_t r = adgold->opl_buffer[c + 1]; - adgold_buffer[c] += (r / 3) + ((l * 2) / 3); - adgold_buffer[c + 1] += (l / 3) + ((r * 2) / 3); + adgold->opl_buffer[c] += (r / 3) + ((l * 2) / 3); + adgold->opl_buffer[c + 1] += (l / 3) + ((r * 2) / 3); } break; @@ -968,7 +955,7 @@ adgold_get_music_buffer(int32_t *buffer, int len, void *priv) int32_t highpass; /*Output is deliberately halved to avoid clipping*/ - temp = ((int32_t) adgold_buffer[c] * adgold->vol_l) >> 17; + temp = ((int32_t) adgold->opl_buffer[c] * adgold->vol_l) >> 17; lowpass = adgold_lowpass_iir(1, 0, temp); highpass = adgold_highpass_iir(1, 0, temp); if (adgold->bass > 6) @@ -985,7 +972,7 @@ adgold_get_music_buffer(int32_t *buffer, int len, void *priv) temp = 32767; buffer[c] += temp; - temp = ((int32_t) adgold_buffer[c + 1] * adgold->vol_r) >> 17; + temp = ((int32_t) adgold->opl_buffer[c + 1] * adgold->vol_r) >> 17; lowpass = adgold_lowpass_iir(1, 1, temp); highpass = adgold_highpass_iir(1, 1, temp); if (adgold->bass > 6) @@ -1004,8 +991,6 @@ adgold_get_music_buffer(int32_t *buffer, int len, void *priv) } adgold->opl.reset_buffer(adgold->opl.priv); - - free(adgold_buffer); } static void @@ -1073,7 +1058,7 @@ adgold_init(UNUSED(const device_t *info)) adgold->surround_enabled = device_get_config_int("surround"); adgold->gameport_enabled = device_get_config_int("gameport"); - fm_driver_get(FM_YMF262, &adgold->opl); + fm_driver_get(FM_YMF289B, &adgold->opl); if (adgold->surround_enabled) ym7128_init(&adgold->ym7128); diff --git a/src/sound/snd_ym7128.c b/src/sound/snd_ym7128.c index 59e5691e9..08b33f414 100644 --- a/src/sound/snd_ym7128.c +++ b/src/sound/snd_ym7128.c @@ -111,10 +111,10 @@ ym7128_write(ym7128_t *ym7128, uint8_t val) ym7128->a0 = new_a0; } -#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos - offset) < 0) ? ym7128->delay_buffer[(ym7128->delay_pos - offset) + 2400] : ym7128->delay_buffer[ym7128->delay_pos - offset]) +#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos[i] - offset) < 0) ? ym7128->delay_buffer[i][(ym7128->delay_pos[i] - offset) + 2400] : ym7128->delay_buffer[i][ym7128->delay_pos[i] - offset]) void -ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) +ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int i, int len) { for (int c = 0; c < len * 2; c += 4) { /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ @@ -125,13 +125,13 @@ ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) int32_t samp_r = 0; filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); - filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); + filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat[i] * ym7128->c1) >> 11); filter_out = (filter_out * ym7128->vc) >> 16; samp = (samp * ym7128->vm) >> 16; samp += filter_out; - ym7128->delay_buffer[ym7128->delay_pos] = samp; + ym7128->delay_buffer[i][ym7128->delay_pos[i]] = samp; for (uint8_t d = 0; d < 8; d++) { samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d + 1]) * ym7128->gl[d]) >> 16; @@ -141,17 +141,17 @@ ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) samp_l = (samp_l * ym7128->vl * 2) >> 16; samp_r = (samp_r * ym7128->vr * 2) >> 16; - buffer[c] += (samp_l + (int32_t) ym7128->prev_l) / 2; - buffer[c + 1] += (samp_r + (int32_t) ym7128->prev_r) / 2; + buffer[c] += (samp_l + (int32_t) ym7128->prev_l[i]) / 2; + buffer[c + 1] += (samp_r + (int32_t) ym7128->prev_r[i]) / 2; buffer[c + 2] += samp_l; buffer[c + 3] += samp_r; - ym7128->delay_pos++; - if (ym7128->delay_pos >= 2400) - ym7128->delay_pos = 0; + ym7128->delay_pos[i]++; + if (ym7128->delay_pos[i] >= 2400) + ym7128->delay_pos[i] = 0; - ym7128->filter_dat = filter_temp; - ym7128->prev_l = samp_l; - ym7128->prev_r = samp_r; + ym7128->filter_dat[i] = filter_temp; + ym7128->prev_l[i] = samp_l; + ym7128->prev_r[i] = samp_r; } } diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 6a9b9ea34..221af0d3f 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -39,6 +39,7 @@ #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> #include <86box/vid_ati_eeprom.h> +#include <86box/bswap.h> #ifdef CLAMP # undef CLAMP @@ -80,6 +81,7 @@ enum { typedef struct mach64_t { mem_mapping_t linear_mapping; mem_mapping_t mmio_mapping; + mem_mapping_t linear_mapping_big_endian; mem_mapping_t mmio_linear_mapping; mem_mapping_t mmio_linear_mapping_2; @@ -98,6 +100,8 @@ typedef struct mach64_t { uint8_t pci_slot; uint8_t irq_state; + uint8_t on_board; + uint8_t pci_regs[256]; uint8_t int_line; @@ -272,7 +276,7 @@ typedef struct mach64_t { uint32_t cur_clr0; uint32_t cur_clr1; - uint32_t overlay_dat[1024]; + uint32_t overlay_dat[2048]; uint32_t overlay_graphics_key_clr; uint32_t overlay_graphics_key_msk; uint32_t overlay_video_key_clr; @@ -286,12 +290,17 @@ typedef struct mach64_t { uint32_t scaler_height_width; int scaler_format; int scaler_update; + int scaler_yuv_aper; uint32_t buf_offset[2]; uint32_t buf_pitch[2]; int overlay_v_acc; + uint32_t overlay_uv_addr; + uint32_t overlay_cur_y; + uint32_t overlay_base; + uint8_t thread_run; void *i2c; void *ddc; @@ -381,6 +390,9 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv); void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv); void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv); +uint8_t mach64_readb_be(uint32_t addr, void *priv); +void mach64_writeb_be(uint32_t addr, uint8_t val, void *priv); + #ifdef ENABLE_MACH64_LOG int mach64_do_log = ENABLE_MACH64_LOG; @@ -591,6 +603,7 @@ mach64_updatemapping(mach64_t *mach64) mach64_log("Update mapping - PCI disabled\n"); mem_mapping_disable(&svga->mapping); mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->linear_mapping_big_endian); mem_mapping_disable(&mach64->mmio_mapping); mem_mapping_disable(&mach64->mmio_linear_mapping); mem_mapping_disable(&mach64->mmio_linear_mapping_2); @@ -645,14 +658,16 @@ mach64_updatemapping(mach64_t *mach64) } } else { /*2*8 MB aperture*/ - mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); - mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); - mem_mapping_set_addr(&mach64->mmio_linear_mapping_2, mach64->linear_base + ((16 << 20) - 0x4000), 0x4000); + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 4096); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 4096), 4096); + mem_mapping_set_addr(&mach64->linear_mapping_big_endian, mach64->linear_base + (8 << 20), (8 << 20) - 0x1000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping_2, mach64->linear_base + ((16 << 20) - 0x1000), 0x1000); } } else { mem_mapping_disable(&mach64->linear_mapping); mem_mapping_disable(&mach64->mmio_linear_mapping); mem_mapping_disable(&mach64->mmio_linear_mapping_2); + mem_mapping_disable(&mach64->linear_mapping_big_endian); } } @@ -2310,8 +2325,11 @@ mach64_vblank_start(svga_t *svga) svga->overlay.ena = (mach64->overlay_scale_cntl & OVERLAY_EN) && (overlay_cmp_mix != 1); - mach64->overlay_v_acc = 0; - mach64->scaler_update = 1; + mach64->overlay_v_acc = 0; + mach64->scaler_update = 1; + mach64->overlay_uv_addr = svga->overlay.addr; + mach64->overlay_cur_y = 0; + mach64->overlay_base = svga->overlay.addr; } uint8_t @@ -2389,6 +2407,10 @@ mach64_ext_readb(uint32_t addr, void *priv) case 0x4a: ret = mach64->scaler_format; break; + + case 0x4b: + ret = mach64->scaler_yuv_aper; + break; default: ret = 0xff; @@ -2558,7 +2580,7 @@ mach64_ext_readb(uint32_t addr, void *priv) case 0xc7: READ8(addr, mach64->dac_cntl); - if (mach64->type == MACH64_VT2) { + if (mach64->type >= MACH64_VT2) { ret &= 0xf9; if (i2c_gpio_get_scl(mach64->i2c)) ret |= 0x04; @@ -2957,7 +2979,8 @@ mach64_ext_readw(uint32_t addr, void *priv) if (!(addr & 0x400)) { mach64_log("mach64_ext_readw: addr=%04x\n", addr); - ret = 0xffff; + ret = mach64_ext_readb(addr, priv); + ret |= mach64_ext_readb(addr + 1, priv) << 8; } else switch (addr & 0x3ff) { case 0xb4: @@ -2986,7 +3009,8 @@ mach64_ext_readl(uint32_t addr, void *priv) if (!(addr & 0x400)) { mach64_log("mach64_ext_readl: addr=%04x\n", addr); - ret = 0xffffffff; + ret = mach64_ext_readw(addr, priv); + ret |= mach64_ext_readw(addr + 2, priv) << 16; } else switch (addr & 0x3ff) { case 0x18: @@ -3087,6 +3111,10 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) case 0x4a: mach64->scaler_format = val & 0xf; break; + + case 0x4b: + mach64->scaler_yuv_aper = val; + break; case 0x80: case 0x81: @@ -4106,76 +4134,113 @@ mach64_int_hwcursor_draw(svga_t *svga, int displine) } \ } while (0) -#define DECODE_VYUY422() \ - do { \ - for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x += 2) { \ - uint8_t y1, y2; \ - int8_t u, v; \ - int dR, dG, dB; \ - int r, g, b; \ - \ - y1 = src[0]; \ - u = src[1] - 0x80; \ - y2 = src[2]; \ - v = src[3] - 0x80; \ - src += 4; \ - \ - dR = (359 * v) >> 8; \ - dG = (88 * u + 183 * v) >> 8; \ - dB = (453 * u) >> 8; \ - \ - r = y1 + dR; \ - CLAMP(r); \ - g = y1 - dG; \ - CLAMP(g); \ - b = y1 + dB; \ - CLAMP(b); \ - mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ - \ - r = y2 + dR; \ - CLAMP(r); \ - g = y2 - dG; \ - CLAMP(g); \ - b = y2 + dB; \ - CLAMP(b); \ - mach64->overlay_dat[x + 1] = (r << 16) | (g << 8) | b; \ - } \ +#define DECODE_VYUY422() \ + do { \ + for (x = 0; x < src_w; x += 1) { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + y1 = src[0]; \ + u = src[1] - 0x80; \ + y2 = src[2]; \ + v = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359 * v) >> 8; \ + dG = (88 * u + 183 * v) >> 8; \ + dB = (453 * u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x * 2] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[(x * 2) + 1] = (r << 16) | (g << 8) | b; \ + } \ } while (0) -#define DECODE_YVYU422() \ - do { \ - for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x += 2) { \ - uint8_t y1, y2; \ - int8_t u, v; \ - int dR, dG, dB; \ - int r, g, b; \ - \ - u = src[0] - 0x80; \ - y1 = src[1]; \ - v = src[2] - 0x80; \ - y2 = src[3]; \ - src += 4; \ - \ - dR = (359 * v) >> 8; \ - dG = (88 * u + 183 * v) >> 8; \ - dB = (453 * u) >> 8; \ - \ - r = y1 + dR; \ - CLAMP(r); \ - g = y1 - dG; \ - CLAMP(g); \ - b = y1 + dB; \ - CLAMP(b); \ - mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ - \ - r = y2 + dR; \ - CLAMP(r); \ - g = y2 - dG; \ - CLAMP(g); \ - b = y2 + dB; \ - CLAMP(b); \ - mach64->overlay_dat[x + 1] = (r << 16) | (g << 8) | b; \ - } \ +#define DECODE_YVYU422() \ + do { \ + for (x = 0; x < src_w; x += 1) { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + u = src[0] - 0x80; \ + y1 = src[1]; \ + v = src[2] - 0x80; \ + y2 = src[3]; \ + src += 4; \ + \ + dR = (359 * v) >> 8; \ + dG = (88 * u + 183 * v) >> 8; \ + dB = (453 * u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x * 2] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[(x * 2) + 1] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_YUV12_PACKED() \ + do { \ + for (x = 0; x < src_w; x += 1) { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + u = uvsrc[3] - 0x80; \ + y1 = src[0]; \ + v = uvsrc[2] - 0x80; \ + y2 = src[1]; \ + src += 4; \ + uvsrc += 4; \ + \ + dR = (359 * v) >> 8; \ + dG = (88 * u + 183 * v) >> 8; \ + dB = (453 * u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x * 2] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[(x * 2) + 1] = (r << 16) | (g << 8) | b; \ + } \ } while (0) void @@ -4185,11 +4250,13 @@ mach64_overlay_draw(svga_t *svga, int displine) int x; int h_acc = 0; int h_max = (mach64->scaler_height_width >> 16) & 0x3ff; + int src_w = h_max; int h_inc = mach64->overlay_scale_inc >> 16; int v_max = mach64->scaler_height_width & 0x3ff; int v_inc = mach64->overlay_scale_inc & 0xffff; uint32_t *p; uint8_t *src = &svga->vram[svga->overlay.addr]; + uint8_t *uvsrc = src; int old_y = mach64->overlay_v_acc; int y_diff; int video_key_fn = mach64->overlay_key_cntl & 5; @@ -4198,6 +4265,11 @@ mach64_overlay_draw(svga_t *svga, int displine) p = &buffer32->line[displine][svga->x_add + mach64->svga.overlay_latch.x]; + if (mach64->overlay_cur_y >= 2) { + /* Avoid corrupt UV data on YUV12 packed modes */ + uvsrc = &svga->vram[mach64->overlay_base + svga->overlay.pitch * 2 * (!(mach64->overlay_cur_y & 1) ? (mach64->overlay_cur_y + 1) : mach64->overlay_cur_y)]; + } + if (mach64->scaler_update) { switch (mach64->scaler_format) { case 0x3: @@ -4209,6 +4281,9 @@ mach64_overlay_draw(svga_t *svga, int displine) case 0x6: DECODE_ARGB8888(); break; + case 0xa: + DECODE_YUV12_PACKED(); + break; case 0xb: DECODE_VYUY422(); break; @@ -4217,7 +4292,7 @@ mach64_overlay_draw(svga_t *svga, int displine) break; default: - mach64_log("Unknown Mach64 scaler format %x\n", mach64->scaler_format); + pclog("Unknown Mach64 scaler format %x\n", mach64->scaler_format); /*Fill buffer with something recognisably wrong*/ for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) mach64->overlay_dat[x] = 0xff00ff; @@ -4354,6 +4429,7 @@ mach64_overlay_draw(svga_t *svga, int displine) svga->overlay.addr += svga->overlay.pitch * 2 * y_diff; mach64->scaler_update = y_diff; + mach64->overlay_cur_y += y_diff; } static void @@ -4389,7 +4465,7 @@ mach64_io_remove(mach64_t *mach64) io_removehandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); if (mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) - io_removehandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); + io_removehandler(mach64->block_decoded_io, 0x0100, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); } static void @@ -4429,7 +4505,7 @@ mach64_io_set(mach64_t *mach64) io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); if (mach64->use_block_decoded_io && mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) - io_sethandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); + io_sethandler(mach64->block_decoded_io, 0x0100, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); } static uint8_t @@ -4478,7 +4554,6 @@ static void mach64_write_linear(uint32_t addr, uint8_t val, void *priv) { svga_t *svga = (svga_t *) priv; - cycles -= svga->monitor->mon_video_timing_write_b; addr &= svga->decode_mask; @@ -4507,10 +4582,38 @@ mach64_writew_linear(uint32_t addr, uint16_t val, void *priv) static void mach64_writel_linear(uint32_t addr, uint32_t val, void *priv) { - svga_t *svga = (svga_t *) priv; + svga_t *svga = (svga_t *) priv; + mach64_t *mach64 = (mach64_t *) svga->priv; cycles -= svga->monitor->mon_video_timing_write_l; + if (((mach64->scaler_yuv_aper >> 4) & 0xc) && !!(addr & 0x800000) == !(mach64->scaler_yuv_aper & 0x20)) { + uint32_t offset_from_base = addr & 0x7FFFFF; + if (addr & 0x800000) bswap32s(&val); + if (((mach64->scaler_yuv_aper >> 4) & 0xc) == 0x4) { // Y plane + offset_from_base <<= 1; + svga->vram[offset_from_base & svga->vram_mask] = (val & 0xFF); + svga->vram[(offset_from_base + 1) & svga->vram_mask] = ((val >> 8) & 0xFF); + svga->vram[(offset_from_base + 4) & svga->vram_mask] = ((val >> 16) & 0xFF); + svga->vram[(offset_from_base + 5) & svga->vram_mask] = ((val >> 24) & 0xFF); + } + else if (((mach64->scaler_yuv_aper >> 4) & 0xc) == 0x8 || ((mach64->scaler_yuv_aper >> 4) & 0xc) == 0xc) { + offset_from_base <<= 2; + if (((mach64->scaler_yuv_aper >> 4) & 0xc) == 0x8) { // U plane + svga->vram[(offset_from_base + 3) & svga->vram_mask] = (val & 0xFF); + svga->vram[(offset_from_base + 7) & svga->vram_mask] = ((val >> 8) & 0xFF); + svga->vram[(offset_from_base + 11) & svga->vram_mask] = ((val >> 16) & 0xFF); + svga->vram[(offset_from_base + 15) & svga->vram_mask] = ((val >> 24) & 0xFF); + } else { // V plane + svga->vram[(offset_from_base + 2) & svga->vram_mask] = (val & 0xFF); + svga->vram[(offset_from_base + 6) & svga->vram_mask] = ((val >> 8) & 0xFF); + svga->vram[(offset_from_base + 10) & svga->vram_mask] = ((val >> 16) & 0xFF); + svga->vram[(offset_from_base + 14) & svga->vram_mask] = ((val >> 24) & 0xFF); + } + } + return; + } + addr &= svga->decode_mask; if (addr >= svga->vram_max) return; @@ -4519,6 +4622,42 @@ mach64_writel_linear(uint32_t addr, uint32_t val, void *priv) *(uint32_t *) &svga->vram[addr] = val; } +uint8_t +mach64_readb_be(uint32_t addr, void *priv) +{ + return mach64_read_linear(addr, priv); +} + +uint16_t +mach64_readw_be(uint32_t addr, void *priv) +{ + return bswap16(mach64_readw_linear(addr, priv)); +} + +uint32_t +mach64_readl_be(uint32_t addr, void *priv) +{ + return bswap32(mach64_readl_linear(addr, priv)); +} + +void +mach64_writeb_be(uint32_t addr, uint8_t val, void *priv) +{ + return mach64_write_linear(addr, val, priv); +} + +void +mach64_writew_be(uint32_t addr, uint16_t val, void *priv) +{ + return mach64_writew_linear(addr, bswap16(val), priv); +} + +void +mach64_writel_be(uint32_t addr, uint32_t val, void *priv) +{ + return mach64_writel_linear(addr, bswap32(val), priv); +} + uint8_t mach64_pci_read(UNUSED(int func), int addr, void *priv) { @@ -4564,30 +4703,31 @@ mach64_pci_read(UNUSED(int func), int addr, void *priv) return mach64->linear_base >> 24; case 0x14: - if (mach64->type == MACH64_VT2) + if (mach64->type >= MACH64_VT2) return 0x01; /*Block decoded IO address*/ return 0x00; case 0x15: - if (mach64->type == MACH64_VT2) + if (mach64->type >= MACH64_VT2) return mach64->block_decoded_io >> 8; return 0x00; case 0x16: - if (mach64->type == MACH64_VT2) + if (mach64->type >= MACH64_VT2) return mach64->block_decoded_io >> 16; return 0x00; case 0x17: - if (mach64->type == MACH64_VT2) + if (mach64->type >= MACH64_VT2) return mach64->block_decoded_io >> 24; return 0x00; + case 0x30: - return mach64->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + return (mach64->on_board) ? 0 : (mach64->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ case 0x31: return 0x00; case 0x32: - return mach64->pci_regs[0x32]; + return (mach64->on_board) ? 0 : mach64->pci_regs[0x32]; case 0x33: - return mach64->pci_regs[0x33]; + return (mach64->on_board) ? 0 : mach64->pci_regs[0x33]; case 0x3c: return mach64->int_line; @@ -4619,7 +4759,7 @@ mach64_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) break; case 0x12: - if (mach64->type == MACH64_VT2) + if (mach64->type >= MACH64_VT2) val = 0; mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0x80) << 16); mach64_updatemapping(mach64); @@ -4630,16 +4770,16 @@ mach64_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) break; case 0x15: - if (mach64->type == MACH64_VT2) { + if (mach64->type >= MACH64_VT2) { if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) mach64_io_remove(mach64); - mach64->block_decoded_io = (mach64->block_decoded_io & 0xffff0000) | ((val & 0xfc) << 8); + mach64->block_decoded_io = (mach64->block_decoded_io & 0xffff0000) | ((val & 0xff) << 8); if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) mach64_io_set(mach64); } break; case 0x16: - if (mach64->type == MACH64_VT2) { + if (mach64->type >= MACH64_VT2) { if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) mach64_io_remove(mach64); mach64->block_decoded_io = (mach64->block_decoded_io & 0xff00fc00) | (val << 16); @@ -4648,7 +4788,7 @@ mach64_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) } break; case 0x17: - if (mach64->type == MACH64_VT2) { + if (mach64->type >= MACH64_VT2) { if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) mach64_io_remove(mach64); mach64->block_decoded_io = (mach64->block_decoded_io & 0x00fffc00) | (val << 24); @@ -4660,6 +4800,7 @@ mach64_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) case 0x30: case 0x32: case 0x33: + if (mach64->on_board) return; mach64->pci_regs[addr] = val; if (mach64->pci_regs[0x30] & 0x01) { uint32_t biosaddr = (mach64->pci_regs[0x32] << 16) | (mach64->pci_regs[0x33] << 24); @@ -4679,7 +4820,7 @@ mach64_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) mach64_io_remove(mach64); mach64->io_base = val & 0x03; - if (mach64->type == MACH64_VT2) + if (mach64->type >= MACH64_VT2) mach64->use_block_decoded_io = val & 0x04; if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) mach64_io_set(mach64); @@ -4700,7 +4841,7 @@ mach64_common_init(const device_t *info) svga = &mach64->svga; mach64->type = info->local & 0xff; - mach64->vram_size = device_get_config_int("memory"); + mach64->vram_size = (info->local & (1 << 20)) ? 4 : device_get_config_int("memory"); mach64->vram_mask = (mach64->vram_size << 20) - 1; if (mach64->type > MACH64_GX) @@ -4717,9 +4858,10 @@ mach64_common_init(const device_t *info) mach64_overlay_draw); mem_mapping_add(&mach64->linear_mapping, 0, 0, mach64_read_linear, mach64_readw_linear, mach64_readl_linear, mach64_write_linear, mach64_writew_linear, mach64_writel_linear, NULL, MEM_MAPPING_EXTERNAL, svga); + mem_mapping_add(&mach64->linear_mapping_big_endian, 0, 0, mach64_readb_be, mach64_readw_be, mach64_readl_be, mach64_writeb_be, mach64_writew_be, mach64_writel_be, NULL, MEM_MAPPING_EXTERNAL, svga); mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); - mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbf000, 0x1000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); mem_mapping_disable(&mach64->mmio_mapping); mach64_io_set(mach64); diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index d9e1d91ef..ac96aedef 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -1952,9 +1952,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x8190: virge->streams.sec_ctrl = val; - virge->streams.dda_horiz_accumulator = val & 0xfff; - if (val & 0x1000) - virge->streams.dda_horiz_accumulator |= ~0xfff; + virge->streams.dda_horiz_accumulator = val & 0x7ff; + if (val & 0x800) + virge->streams.dda_horiz_accumulator |= ~0x7ff; virge->streams.sdif = (val >> 24) & 7; break; @@ -2030,9 +2030,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.k2_vert_scale |= ~0x7ff; break; case 0x81e8: - virge->streams.dda_vert_accumulator = val & 0xfff; - if (val & 0x1000) - virge->streams.dda_vert_accumulator |= ~0xfff; + virge->streams.dda_vert_accumulator = val & 0x7ff; + if (val & 0x800) + virge->streams.dda_vert_accumulator |= ~0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount;