I'm having trouble turning my screen off and on. Writing to Bit7 rLCDC pops up error (BGB) "disabling screen outside vblank" - so I made a buffer to which it writes changes in rLCDC, which transfers it in VBLANK:
LD A,%00010011 ; disable screen (off bit7)
LD [rLCDC_Buffer],A
LD A,%10010011 ; enable screen (on bit7)
LD [rLCDC_Buffer],A
in VBlank_Handler:
LD A,[rLCDC_Buffer]
LDH [rLCDC],A ; $FF40
Unfortunately, I still have this error (BGB "disabling screen outside vblank") when I write to the buffer, and yet it is transferred to rLCDC in the VBLANK interrupt, where do I make a mistake?
Please correct me in case of an error - GB, like NES, allows writing / reading in PPU and VRAM only during VBLANK or when the screen is off (set off bit7 rLCDC ($ FF40)?
disable/enable LCD screen (bit7 rLCDC $FF40)
Re: disable/enable LCD screen (bit7 rLCDC $FF40)
The Game boy permits writes to most of VRAM during hblank too, depending on how many sprites are present on the scanline, where exactly they are, and where the "window" is.
You should be able to check the contents of the LY register when the write happens - it should be in the range of 144 to 153 for it to be safe to turn off the LCD.
Also consider using Emulicious - I don't know how the two compare in terms of debugging capabilities.
You should be able to check the contents of the LY register when the write happens - it should be in the range of 144 to 153 for it to be safe to turn off the LCD.
Also consider using Emulicious - I don't know how the two compare in terms of debugging capabilities.
Re: disable/enable LCD screen (bit7 rLCDC $FF40)
Ok, I think everything is working, I also had to turn off interrupts before turning off the screen, and turn on interrupts after turning on the screen.
SELECT / START changes game screens, no bugs in BGB.
SELECT / START changes game screens, no bugs in BGB.
DisableScreen:
LDH A,[rLCDC]
AND A,%10000000
JR Z,Screen_OFF
LD B,$91
CALL wait_ly
LD A,%00010011
LDH [rLCDC],A
Screen_OFF:
RET
;----------
EnableScreen:
LD A,%10010011
LDH [rLCDC],A
RET
;----------
wait_ly:
LD C,LOW(rLY)
no_same_ly:
LD A,[$FF00+C]
CP A,B
JR NZ,no_same_ly
RET
;----------------------
DI
CALL DisableScreen
; update nametable and sprites
CALL EnableScreen
EI
- Attachments
-
- gbtest.gb
- (128 KiB) Downloaded 45 times
Re: disable/enable LCD screen (bit7 rLCDC $FF40)
I still have problems writing to VRAM during VBLANK. I have a simple code that transfers a value from variable frames to a screen address and displays the appropriate digits.
Everything should work, but BGB shows "accessing inaccessible VRAM" error. Of course, other emulators like Emulicious work fine, but it's weird nonetheless.
VBlank routine is executed whenever LY = 144. During this period video hardware is not using VRAM so it may be freely accessed.
So I don't understand why this is wrong. It may be "oversensitivity" of the BGB emulator, but it still makes me wonder why.
Everything should work, but BGB shows "accessing inaccessible VRAM" error. Of course, other emulators like Emulicious work fine, but it's weird nonetheless.
VBlank routine is executed whenever LY = 144. During this period video hardware is not using VRAM so it may be freely accessed.
So I don't understand why this is wrong. It may be "oversensitivity" of the BGB emulator, but it still makes me wonder why.
VBlank_Handler:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
CALL Run_DMA ; Update OAMMirror to OAM via DMA.
CALL UpdateScore ; Update BGR Score Tiles.
XOR A
LDH [rSCY],A ; ScrollY.
LDH [rSCX],A ; ScrollX.
LD A,1
LD [VBlank_Flag],A
POP HL
POP DE
POP BC
POP AF
RETI
UpdateScore:
LD HL,$9A07 ; vram nametable addres
LD B,$30 ; start tile graphics digits ($30-39 / 0-9)
LD A,[Score_Digit5]
ADD B
LD [HL],A
LD HL,$9A08
LD B,$30
LD A,[Score_Digit4]
ADD B
LD [HL],A
LD HL,$9A09
LD B,$30
LD A,[Score_Digit3]
ADD B
LD [HL],A
LD HL,$9A0A
LD B,$30
LD A,[Score_Digit2]
ADD B
LD [HL],A
LD HL,$9A0B
LD B,$30
LD A,[Score_Digit1]
ADD B
LD [HL],A
LD HL,$9A0C
LD B,$30
LD A,[Score_Digit0]
ADD B
LD [HL],A
RET
Re: disable/enable LCD screen (bit7 rLCDC $FF40)
On what value of LY does the first "inaccessible" write occur? The debugger in bgb should display that.
If the sum of Run_DMA and UpdateScore exceed 10 scanlines' worth of CPU time, which equals 1140 cycles, the last write will occur out of vblank. Something with several divisions by 10 is likely to cause that. UpdateScore as you've defined it doesn't appear to cause that. However:
The register IF contains a set of interrupts that are waiting to happen. While interrupts are disabled, these continue to accumulate. If you don't write 0 to IF before enabling interrupts, then all these interrupts will happen immediately. To see if this is the problem, put a breakpoint (ld b, b) just before the ei instruction and then step a few instructions in the debugger.
Your code:
To investigate:
If that ends up being the problem, the solution might look something like this:
If the sum of Run_DMA and UpdateScore exceed 10 scanlines' worth of CPU time, which equals 1140 cycles, the last write will occur out of vblank. Something with several divisions by 10 is likely to cause that. UpdateScore as you've defined it doesn't appear to cause that. However:
The register IF contains a set of interrupts that are waiting to happen. While interrupts are disabled, these continue to accumulate. If you don't write 0 to IF before enabling interrupts, then all these interrupts will happen immediately. To see if this is the problem, put a breakpoint (ld b, b) just before the ei instruction and then step a few instructions in the debugger.
Your code:
Code: Select all
CALL EnableScreen
EI
Code: Select all
CALL EnableScreen
ld b, b
EI
Code: Select all
CALL EnableScreen
xor a
ldh [rIF], a
EI
Re: disable/enable LCD screen (bit7 rLCDC $FF40)
LY was at 02.
Thanks! I didn't actually reset the rIF before EI
Everything works fine now.
XOR A
LDH [rIF], A
EI
---------
I still have a question related to waiting for the VBLANK - if I have the screen off, DI interrupt disabled and I would like to make a few or a dozen delay frames before turning the screen back on, how should I do it? HALT is blocked, so it will freezee my code completely. Do bit0 FF0F (rIF) status check need to be performed? (Reactivating the EI, doing a few HALTs, and disabling the DI will not work - Here I do not fully understand, why when I have the LCD off, EI cannot be performed?).
Thanks! I didn't actually reset the rIF before EI
Everything works fine now.
XOR A
LDH [rIF], A
EI
---------
I still have a question related to waiting for the VBLANK - if I have the screen off, DI interrupt disabled and I would like to make a few or a dozen delay frames before turning the screen back on, how should I do it? HALT is blocked, so it will freezee my code completely. Do bit0 FF0F (rIF) status check need to be performed? (Reactivating the EI, doing a few HALTs, and disabling the DI will not work - Here I do not fully understand, why when I have the LCD off, EI cannot be performed?).
DI
CALL Screen_OFF
; add few frames delay before enable LCD.
CALL Screen_ON
XOR A
LDH [rIF],A
EI
- Attachments
-
- gb_test.gb
- (512 KiB) Downloaded 39 times
Re: disable/enable LCD screen (bit7 rLCDC $FF40)
What you're seeing is that the vblank interrupt isn't generated while the LCD is off. This is true of the 8-bit Game Boy, in contrast with the NES, Super NES, and GBA. To keep time while the LCD is off, you'll need to use the timer (TIMA/TMA/TAC registers).
Aside: If interrupts are disabled (di), the halt instruction still works so long as interrupts are still getting generated. It waits for the next interrupt enabled in IE and doesn't call the handler. I do this in Border Crossing to wait for vblank while the screen is on. You have to remember to clear IF yourself each time, and if you have other interrupts enabled (STAT, timer, serial, or key input), you need to distinguish them from vblank somehow.
Aside: If interrupts are disabled (di), the halt instruction still works so long as interrupts are still getting generated. It waits for the next interrupt enabled in IE and doesn't call the handler. I do this in Border Crossing to wait for vblank while the screen is on. You have to remember to clear IF yourself each time, and if you have other interrupts enabled (STAT, timer, serial, or key input), you need to distinguish them from vblank somehow.
Re: disable/enable LCD screen (bit7 rLCDC $FF40)
It's working now. The problem was a bug in the INIT code. I didn't have the bit2 rIE flag set and the rTAC set - when I did it everything works. That's why HALT was freezing my code, even though I had EI and DI correctly used. All in all, I still do not understand why this was happening, after all Bit2 rIE should not affect it (and not set rTAC)?
HALT now works between screen off and on:LD A,%00000100 ; $FF07 - 4096Hz.
LDH [rTAC],A
XOR A
LDH [rIF],A
LD A,%00000101 ; Allow VBlanks and TIMER.
LDH [rIE],A
DI
CALL Screen_OFF
XOR A
LDH [rIF],A
EI
HALT ; delay
HALT
HALT
HALT
HALT
HALT
HALT
HALT
HALT
HALT
DI
CALL Screen_ON
XOR A
LDH [rIF],A
EI