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

Halt is not immediate #333

Open
alyosha-tas opened this issue Oct 20, 2023 · 8 comments
Open

Halt is not immediate #333

alyosha-tas opened this issue Oct 20, 2023 · 8 comments
Assignees

Comments

@alyosha-tas
Copy link

Here is a test that demonstrates that Halt takes (at least) 1 cycle to take effect:

https://github.com/alyosha-tas/gba-tests/blob/master/irq/halt_pc.gba

All it does is read what PC address is pushed to the stack by the IRQ handler after a halt has occurred.

Nanoboyadvance currently returns what would be the next address after the write to Halt control. On console it is the address that the branch (the next instruction after halt) branches to. So at least the branch cycle occurs before halting.

I'm pretty sure this will eventually lead to a solution to the DMA set test case in your current iteration of haltcnt.gba, but I haven't worked out the details yet.

@fleroviux
Copy link
Member

Interesting. What you describe sounds to me like it would also be affected by general IRQ timing. In particular I know that I have an inaccuracy regarding the exact cycle that the irq_line_high && !cpsr_irq_disable condition is evaluated on by the CPU core. That is also what would be needed for NBA to pass the irq_delay test ROM. Though it is kind of hard to implement with my current architecture and might warrant some rewriting of the CPU core.

@alyosha-tas
Copy link
Author

alyosha-tas commented Oct 22, 2023

I updated the test to provide timing info as well. The timing indicates that IRQ happens after the branch instruction after halt.

The following model passes both my new test and the DMA test in haltcnt.gba (as well as all the other ones):

Halt takes one cycle to take effect. In other words one cycle in the cpu is run after the write to halt.
Halt takes one cycle to exit after irq conditions are met.

The reason this works for the DMA test is that the DMA still has the cpu stopped for an extra cycle after the halt write, so the extra cycle the cpu could have been used after halt is not used in this case. Otherwise you would get 4153 instead of 4154.

Everything seems to work with this model, though I still need to do some edge case testing.

@fleroviux
Copy link
Member

fleroviux commented Oct 23, 2023

Halt takes one cycle to take effect. In other words one cycle in the cpu is run after the write to halt.

So there's a single clock cycle delay for the write to take effect and then is the CPU halted immediately on the next clock cycle or does the CPU finish its bus cycle if it's performing a memory access?

Also if this is true it supports something I have been suspecting for a while that there might be a general one clock cycle delay for IO writes to take effect. Current other known cases of this are as far as I know:

  • TM[x]CNT
  • IE, IF, IME
  • DMA might be a candidate for this too and I've heard someone suggest there might be a delay, but needs testing

Finally I haven't probed the PPU about this yet, but I did notice something regarding WIN[x]H fetch timing that might indicate a write delay as well, see here.

@alyosha-tas
Copy link
Author

I don't think there is a way for a multi-cycle bus access to occur following the write halt, at least i cant think of one.

I'm pretty sure writes to Wait control take effect immediately. I believe i tested this at some point.

Also I think the interrupt regs are immediate? At least if an interrupt flag is set and cleared by write to IF on the same cycle, the flag should not be set and no interrupt triggered.

@fleroviux
Copy link
Member

I don't think there is a way for a multi-cycle bus access to occur following the write halt, at least i cant think of one.

True. Maybe it could be tested with that undocumented bit which allows swapping EWRAM and BIOS, though I'm not entirely sure if the HALTCNT protection can be bypassed that way. Alternately maybe could be tested with some open bus shenanigans (see: https://gist.github.com/merryhime/797c523724e2dc02ada86a1cfadea3ee)

Also I think the interrupt regs are immediate? At least if an interrupt flag is set and cleared by write to IF on the same cycle, the flag should not be set and no interrupt triggered.

As far as I could tell and remember writes to IME, IE and IF are delayed by one cycle, but so is requesting the IRQ in IF. For example if a timer with an enabled IRQ overflows I remember observing that the flag in IF is set only one cycle after the overflow. I need to see if I can find the mini test that I wrote for this back. But with that model what you describe should still work.

@alyosha-tas
Copy link
Author

As far as I could tell and remember writes to IME, IE and IF are delayed by one cycle, but so is requesting the IRQ in IF. For example if a timer with an enabled IRQ overflows I remember observing that the flag in IF is set only one cycle after the overflow. I need to see if I can find the mini test that I wrote for this back. But with that model what you describe should still work.

Interesting, none of my IRQ regs are delayed by a cycle yet I pass all the available IRQ tests. I thought I had made some tests specifically to test this but I don't have anything written down about it. I'll look at making some when I get a chance.

I added tests halt_pc_2,3,4 to my tests. These trigger an IRQ at cycles 0,-1,+1 around where a halt occurs. NanoboyAdvacne currently fails test 3. The results are consistent with the model I mentioned.

@fleroviux
Copy link
Member

fleroviux commented Oct 23, 2023

Looking at my folder of unpolished and WIP tests I did find the test that proves that asserting an IRQ takes a cycle to show up in IF, but GBAHawk is already passing that (and from the looks of it also seems to delay setting the IRQ flag in the IF register). But I can't find proper tests for CPU writes to IME, IE and IF and I'm not sure anymore if I tested that properly or if it was something I did to fix another issue.

timer-irq-if-flag.zip

@alyosha-tas
Copy link
Author

I sorted out my IRQ reg tests and NanoboyAdvance passes all of them, so I guess we are both talking about the same thing in different ways.

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

No branches or pull requests

2 participants