Infinite loop while waiting for VB in Antartic Adventure

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
Paul_Atreides
Posts: 12
Joined: Mon Apr 13, 2020 5:24 am

Infinite loop while waiting for VB in Antartic Adventure

Post by Paul_Atreides » Sun Jul 12, 2020 2:44 pm

First off, the code if you're interested:
https://github.com/DiasparCitizen/eNESimo

This game is never launching due to an infinite loop while the game is waiting for VB to be set to 1.

In the following trace you'll see pretty well what's going on.
As a summary:
- The CPU loops between F74E and F751 waiting for Vblank bit to be set
- Vblank is set to 1 when the PPU reaches the correct scanline
- A NMI is triggered, the CPU jumps to F294 to execute the NMI routine
- In the NMI routine, the thread reads PPU_status, thereby clearing Vblank
- When the thread is back in the loop, the Vblank bit is lost

/* INFINITE LOOP */
48753 F74E 173:LDA-abs(4+0) $220 A:00 X:00 Y:01 P:27 SP:F3 CYC:309 SL:240 FC:7 CPUCycle:174748 STA:0 MSK:6
48754 F751 16:BPL-rel(2+0) $FBC6 A:00 X:00 Y:01 P:27 SP:F3 CYC:321 SL:240 FC:7 CPUCycle:174752 STA:0 MSK:6
vertical blank to 0 (STATUS READ)
48755 F74E 173:LDA-abs(4+0) $220 A:00 X:00 Y:01 P:27 SP:F3 CYC:330 SL:240 FC:7 CPUCycle:174755 STA:0 MSK:6
48756 F751 16:BPL-rel(2+0) $FBC6 A:00 X:00 Y:01 P:27 SP:F3 CYC:1 SL:241 FC:7 CPUCycle:174759 STA:0 MSK:6
vertical blank to 1
/* START OF NMI ROUTINE */
48757 F294 72:PHA-imp(3+0) $8A48 A:00 X:00 Y:01 P:37 SP:F0 CYC:31 SL:241 FC:7 CPUCycle:174769 STA:80 MSK:6
48758 F295 138:TXA-imp(2+0) $4898 A:00 X:00 Y:01 P:37 SP:EF CYC:40 SL:241 FC:7 CPUCycle:174772 STA:80 MSK:6
48759 F296 72:PHA-imp(3+0) $9848 A:00 X:00 Y:01 P:37 SP:EF CYC:46 SL:241 FC:7 CPUCycle:174774 STA:80 MSK:6
48760 F297 152:TYA-imp(2+0) $48AD A:00 X:00 Y:01 P:37 SP:EE CYC:55 SL:241 FC:7 CPUCycle:174777 STA:80 MSK:6
48761 F298 72:PHA-imp(3+0) $AD2 A:01 X:00 Y:01 P:35 SP:EE CYC:61 SL:241 FC:7 CPUCycle:174779 STA:80 MSK:6
vertical blank to 0 (STATUS READ)
48762 F299 173:LDA-abs(4+0) $220 A:01 X:00 Y:01 P:35 SP:ED CYC:70 SL:241 FC:7 CPUCycle:174782 STA:80 MSK:6
48763 F29C 165:LDA-zpg(3+0) $4D0 A:80 X:00 Y:01 P:B5 SP:ED CYC:82 SL:241 FC:7 CPUCycle:174786 STA:0 MSK:6
48764 F29E 208:BNE-rel(2+0) $76E6 A:02 X:00 Y:01 P:35 SP:ED CYC:91 SL:241 FC:7 CPUCycle:174789 STA:0 MSK:6
48765 F316 32:JSR-abs(6+0) $F2F8 A:02 X:00 Y:01 P:35 SP:ED CYC:103 SL:241 FC:7 CPUCycle:174793 STA:0 MSK:6
vertical blank to 0 (STATUS READ)
48766 F8F2 174:LDX-abs(4+0) $220 A:02 X:00 Y:01 P:35 SP:EB CYC:121 SL:241 FC:7 CPUCycle:174799 STA:0 MSK:6
48767 F8F5 166:LDX-zpg(3+0) $558E A:02 X:00 Y:01 P:37 SP:EB CYC:133 SL:241 FC:7 CPUCycle:174803 STA:0 MSK:6



Now, this is a trace from MESEN.
You'll see that the CPU is not jumping to the NMI routine after Vblank is set:

F74E $AD $02 $20 LDA PpuStatus_2002 A:00 X:00 Y:00 P:06 SP:FB CYC:330 SL:240 FC:2 CPU Cycle:27389
F751 $10 $FB BPL $F74E A:00 X:00 Y:00 P:06 SP:FB CYC:1 SL:241 FC:2 CPU Cycle:27393
F74E $AD $02 $20 LDA PpuStatus_2002 A:00 X:00 Y:00 P:06 SP:FB CYC:10 SL:241 FC:2 CPU Cycle:27396
F751 $10 $FB BPL $F74E A:80 X:00 Y:00 P:84 SP:FB CYC:22 SL:241 FC:2 CPU Cycle:27400
/* THREAD SUCCESSFULLY ESCAPES LOOP */
F753 $C6 $04 DEC $04 A:80 X:00 Y:00 P:84 SP:FB CYC:28 SL:241 FC:2 CPU Cycle:27402
F755 $A9 $00 LDA #$00 A:80 X:00 Y:00 P:06 SP:FB CYC:43 SL:241 FC:2 CPU Cycle:27407
F757 $8D $03 $20 STA OamAddr_2003 A:00 X:00 Y:00 P:06 SP:FB CYC:49 SL:241 FC:2 CPU Cycle:27409
F75A $A9 $02 LDA #$02 A:00 X:00 Y:00 P:06 SP:FB CYC:61 SL:241 FC:2 CPU Cycle:27413



Clearly the logic of my PPU contains an error.
Any ideas?
Last edited by Paul_Atreides on Sun Jul 26, 2020 2:05 pm, edited 1 time in total.

tepples
Posts: 22014
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Infinite loop while waiting for VB in Antartic Adventure

Post by tepples » Sun Jul 12, 2020 2:51 pm

If bit 7 of the last value written to $2000 is clear (0), the NMI handler is not called. When $F74E is run, what was the last value written to that PPU port?

At power up, the PPU behaves as if $00 was written to $2000.

Paul_Atreides
Posts: 12
Joined: Mon Apr 13, 2020 5:24 am

Re: Infinite loop while waiting for VB in Antartic Adventure

Post by Paul_Atreides » Mon Jul 13, 2020 2:11 pm

I made some logical changes and now the code does execute further.
However, an infinite loop ends up occurring at the same spot.
Here you can see what's going on at CPU instruction ~134k.

STA shows the content of the PPU status reg, and CTRL shows the value of the PPU control register.
As you can observe, CTRL is always 0x88, which enables the CPU thread to jump to the NMI routine as soon as Vblank is set.

Here is the trace:

Vertical blank to 0 (STATUS READ)
133953 F74E 173:LDA-abs(4+0) $220 A:00 X:00 Y:01 P:27 SP:F3 CYC:310 SL:240 FC:17 CPUCycle:472555 STA:0 MSK:6 CTRL:88
133954 F751 16:BPL-rel(2+0) $FBC6 A:00 X:00 Y:01 P:27 SP:F3 CYC:322 SL:240 FC:17 CPUCycle:472559 STA:0 MSK:6 CTRL:88
Vertical blank to 0 (STATUS READ)
133955 F74E 173:LDA-abs(4+0) $220 A:00 X:00 Y:01 P:27 SP:F3 CYC:331 SL:240 FC:17 CPUCycle:472562 STA:0 MSK:6 CTRL:88
Vertical blank to 1 --> jump to NMI routine!!!
133956 F751 16:BPL-rel(2+0) $FBC6 A:00 X:00 Y:01 P:27 SP:F3 CYC:2 SL:241 FC:17 CPUCycle:472566 STA:80 MSK:6 CTRL:88
133957 F294 72:PHA-imp(3+0) $8A48 A:00 X:00 Y:01 P:37 SP:F0 CYC:29 SL:241 FC:17 CPUCycle:472575 STA:80 MSK:6 CTRL:88
133958 F295 138:TXA-imp(2+0) $4898 A:00 X:00 Y:01 P:37 SP:EF CYC:38 SL:241 FC:17 CPUCycle:472578 STA:80 MSK:6 CTRL:88
133959 F296 72:PHA-imp(3+0) $9848 A:00 X:00 Y:01 P:37 SP:EF CYC:44 SL:241 FC:17 CPUCycle:472580 STA:80 MSK:6 CTRL:88
133960 F297 152:TYA-imp(2+0) $48AD A:00 X:00 Y:01 P:37 SP:EE CYC:53 SL:241 FC:17 CPUCycle:472583 STA:80 MSK:6 CTRL:88
133961 F298 72:PHA-imp(3+0) $AD2 A:01 X:00 Y:01 P:35 SP:EE CYC:59 SL:241 FC:17 CPUCycle:472585 STA:80 MSK:6 CTRL:88
Vertical blank to 0 (STATUS READ)
133962 F299 173:LDA-abs(4+0) $220 A:01 X:00 Y:01 P:35 SP:ED CYC:68 SL:241 FC:17 CPUCycle:472588 STA:80 MSK:6 CTRL:88
133963 F29C 165:LDA-zpg(3+0) $4D0 A:80 X:00 Y:01 P:B5 SP:ED CYC:80 SL:241 FC:17 CPUCycle:472592 STA:0 MSK:6 CTRL:88
133964 F29E 208:BNE-rel(2+0) $76E6 A:02 X:00 Y:01 P:35 SP:ED CYC:89 SL:241 FC:17 CPUCycle:472595 STA:0 MSK:6 CTRL:88


CTRL is set to 0x88 quite early in the execution, around instruction #21137.
From that moment onward, it keeps that value.

21134 F80B 169:LDA-imm(2+0) $8885 A:1E X:00 Y:00 P:25 SP:FD CYC:76 SL:166 FC:3 CPUCycle:77429 STA:20 MSK:0 CTRL:0
21135 F80D 133:STA-zpg(3+0) $538D A:88 X:00 Y:00 P:A5 SP:FD CYC:82 SL:166 FC:3 CPUCycle:77431 STA:20 MSK:0 CTRL:0
21136 F80F 141:STA-abs(4+0) $020 A:88 X:00 Y:00 P:A5 SP:FD CYC:91 SL:166 FC:3 CPUCycle:77434 STA:20 MSK:0 CTRL:0
21137 F812 96:RTS-imp(6+0) $201A A:88 X:00 Y:00 P:A5 SP:FD CYC:103 SL:166 FC:3 CPUCycle:77438 STA:20 MSK:0 CTRL:88 ***
21138 F291 76:JMP-abs(3+0) $91F2 A:88 X:00 Y:00 P:A5 SP:FF CYC:121 SL:166 FC:3 CPUCycle:77444 STA:20 MSK:0 CTRL:88
21139 F291 76:JMP-abs(3+0) $91F2 A:88 X:00 Y:00 P:A5 SP:FF CYC:130 SL:166 FC:3 CPUCycle:77447 STA:20 MSK:0 CTRL:88
21140 F291 76:JMP-abs(3+0) $91F2 A:88 X:00 Y:00 P:A5 SP:FF CYC:139 SL:166 FC:3 CPUCycle:77450 STA:20 MSK:0 CTRL:88


Some strange condition is being created by this simple mapper 0 game, Antartic Adventure.
I've tried the emulator with games such as Mario, Donkey, Megaman, Castlevania, and the emulation is rather good (sound could be better, though).

User avatar
Zepper
Formerly Fx3
Posts: 3194
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Infinite loop while waiting for VB in Antartic Adventure

Post by Zepper » Mon Jul 20, 2020 2:35 pm

Man... use the PPU tests, running them in order.
It's located in the wiki.

User avatar
Quietust
Posts: 1566
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Infinite loop while waiting for VB in Antartic Adventure

Post by Quietust » Mon Jul 20, 2020 9:03 pm

The "LDA $2002" instruction takes 4 cycles to execute: one to read the opcode, two to read the address, and one to read the actual value. Additionally, interrupts can only be serviced at the beginning of an instruction, so if the PPU enters VBLANK in the middle of that instruction, the instruction will finish running and read D7=1 before proceeding to handle the interrupt.

Do note that the PPU also suffers from a race condition if the final cycle of LDA $2002 coincides with the PPU entering VBLANK - the CPU will read D7=0 and the interrupt will not be triggered, causing the program to delay for an extra frame.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

User avatar
Zepper
Formerly Fx3
Posts: 3194
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Infinite loop while waiting for VB in Antartic Adventure

Post by Zepper » Tue Jul 21, 2020 6:34 am

Quietust wrote:
Mon Jul 20, 2020 9:03 pm
(...)interrupts can only be serviced at the beginning of an instruction
Do you mean the first read, the opcode fetch?

User avatar
Quietust
Posts: 1566
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Infinite loop while waiting for VB in Antartic Adventure

Post by Quietust » Tue Jul 21, 2020 8:44 am

Zepper wrote:
Tue Jul 21, 2020 6:34 am
Quietust wrote:
Mon Jul 20, 2020 9:03 pm
(...)interrupts can only be serviced at the beginning of an instruction
Do you mean the first read, the opcode fetch?
My main point is that CPU instructions aren't "atomic" - other devices attached to it can change their state while a single instruction is being executed, so the result of reading from a memory-mapped I/O register cannot be determined solely based on the system's state at the start of the instruction.

In this particular case, the PPU could set the VBLANK flag and generate an NMI in the middle of an instruction, but while the NMI won't have any effect until the instruction is finished, the VBLANK flag being set takes effect immediately and would affect the value read from $2002.

The exact details of interrupt latency should be on the wiki somewhere.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

Post Reply