Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Acknowledge the interrupt request #101

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

leiradel
Copy link
Contributor

@leiradel leiradel commented Jul 6, 2024

When the Z80 has /M1 and /IORQ low, an 8-bit interrupt vector must be placed in the data bus.

This PR fixes Parap Shock crashing in the menu, and likely other games that also use IM2.

Thanks to r-lyeh for pointing out the fix.

@floooh
Copy link
Owner

floooh commented Jul 7, 2024

Hmm interesting, I thought that the ZX doesn't have special logic to place an interrupt vector on the data bus when an IM2 interrupt happens, but instead it takes whatever random value is currently on the data bus.

But maybe what makes more sense is that if an IORQ happens, that any IO port 'address' that isn't handled by the system puts an 0xFF on the databus?

For instance instead of the special check if (pins & Z80_M1) { ...}, the 0xFF would be set in a final else branch at the end of all the address tests? ...let me check the schematic (I want to see if the M1 pin is actually connected to the ULA or anywhere else).

...we basically need to answer the question: what happens when an IO request happens that has neither the RD or WR pin active...

@floooh
Copy link
Owner

floooh commented Jul 7, 2024

...in the schematics, the CPU M1 pin doesn't seem to be connected to anything else:
image

...so there's two scenarios to figure out (since M1 is out of the race):

  • what happens when the IORQ pin is active, but neither the RD and WR are active (this is a situation that the ULA could check and handle, or maybe it's a "fallthough situation" that pulls all data bus pins to 1)
  • alternatively, what happens for a regular IO request with IORQ and either the WR or RD pin active, but it's for address that's not handled (e.g. an odd address, that's also not a memory mapping or sound chip request), this could actually be the same fallthrough situation...

Both situations are currently ignored in the emulator, and the data bus remains at the value it already had.

In the very least I would change your PR like this, instead of checking if M1 is active (since that is definitely ignored by the hardware), check if RD and WR are both inactive:

E.g. replace:

        if (pins & Z80_M1) {
            Z80_SET_DATA(pins, 0xFF);
        }

...with:

        if (0 == (pins & (Z80_RD|Z80_WR))) {
            Z80_SET_DATA(pins, 0xFF);
        }

...this would also trigger on an interrupt request, but not via the M1 pin but instead the inactivity of both the RD and WR pin in combination with IORQ.

...we could also do a fallthrough and put a else branch at the end, but in that case the top-level if statements need to be modified too (basically move the nested ifs in the block that handles ULA requests up to the top-level of if-checks).

@floooh
Copy link
Owner

floooh commented Jul 7, 2024

PS, the 'fallthrough' fix would look like this:

if ((pins & (Z80_A0|Z80_RD)) == Z80_RD) {
    // read from ULA
    ...
} else if (if ((pins & (Z80_A0|Z80_WR)) == Z80_WR) {
    // write to ULA
    ...
} else if (((pins & (Z80_WR|Z80_A15|Z80_A1)) == Z80_WR) && (sys->type == ZX_TYPE_128)) {
    // Spectrum 128 memory control..
    ...
} else if (((pins & (Z80_A15|Z80_A1)) == Z80_A15) && (sys->type == ZX_TYPE_128)) {
    // AY-3-8912 access
    ...
} else if ((pins & (Z80_RD|Z80_A7|Z80_A6|Z80_A5)) == Z80_RD) {
    // Kempston Joystick (........000.....)
    ...
} else {
    // fallthrough: unhandled IO address or interrupt request
    Z80_SET_DATA(pins, 0xFF);
}

@leiradel
Copy link
Contributor Author

leiradel commented Jul 7, 2024

Right, not checking /M1 is more faithful to how the Speccy works.

I've updated the PR to set the data bus to 0xFF if no other peripheral and neither the Z80 has put something on it.

@leiradel
Copy link
Contributor Author

leiradel commented Jul 7, 2024

Hm I may have the AY-3-8912 wiring wrong, checking...

@leiradel
Copy link
Contributor Author

leiradel commented Jul 7, 2024

Hm I may have the AY-3-8912 wiring wrong, checking...

Scratch that, I think it's ok.

@leiradel
Copy link
Contributor Author

leiradel commented Jul 7, 2024

I've implemented a simpler version, where the data bus is set to 0xFF by default if the CPU is not writing. Then, if a peripheral puts something in the data base, it's overwritten.

I'm not sure what happened, but I brought the latest zx.h from the master branch and it has many differences from the one in this PR. Please be careful as I may have messed things up. I can redo the PR if necessary.

@floooh floooh marked this pull request as draft July 8, 2024 09:45
@floooh
Copy link
Owner

floooh commented Jul 8, 2024

Hmm yeah, the actual PR diff looks scary and has a lot of unrelated changes. I will probably integrate your tick function changes manually.

PS: I've converted the PR to Draft so I don't accidentially click on the merge button :)

@leiradel
Copy link
Contributor Author

leiradel commented Jul 8, 2024

I will probably integrate your tick function changes manually.

Yeah it'll be safer. It's really just these lines just before checking Z80_MREQ and Z80_IORQ:

if ((pins & Z80_WR) == 0) {
    // if no one puts data on the bus, it's floating
    Z80_SET_DATA(pins, 0xFF);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants