Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)
You are not logged in.
Hello everyone,
I couldn't find any topic about this kind of issue.
I'm trying to load a complete background during a V-Blank IRQ but I was getting some odd result with bgb emulator.
I reduced my code to the basics and it appears that some bytes of the aren't refreshed during V-Blank. Here the code is loading a grey background and then try to load a black background during V-Blank. Here the code and the result result I'm getting with bgb :
;/////////////////////////////////////////////////////////////// ;//// HEADER DIRECTIVES //// ;/////////////////////////////////////////////////////////////// .ROMDMG .NAME "GB2dB" .CARTRIDGETYPE 2 .RAMSIZE 2 .COMPUTEGBCHECKSUM .COMPUTEGBCOMPLEMENTCHECK .LICENSEECODENEW "17" .EMPTYFILL $00 .MEMORYMAP SLOTSIZE $4000 DEFAULTSLOT 0 SLOT 0 $0000 SLOT 1 $4000 .ENDME .ROMBANKSIZE $4000 .ROMBANKS 2 .BANK 0 SLOT 0 ;/////////////////////////////////////////////////////////////// ;//// PROGRAM FIRST BYTES //// ;/////////////////////////////////////////////////////////////// .ORG $0040 call VBlank reti .ORG $0100 nop jp start ;//// Mandatory Nintendo logo .ORG $0104 .DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C .DB $00,$0D,$00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6 .DB $DD,$DD,$D9,$99,$BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC .DB $99,$9F,$BB,$B9,$33,$3E ;/////////////////////////////////////////////////////////////// ;//// INITIALIZATION //// ;/////////////////////////////////////////////////////////////// .org $0150 start: di ; Deactivate interrupts ld sp,$FFF4 ; Load SP register with $FFF4 as Nintendo advices xor a ; A = 0 ld ($FF26),a ; Deactivate GB sound waitVBlank: ld a,($FF44) ; Load LCD Y position into A cp 144 ; Compare A to 144 jr c,waitVBlank ; jump back to label if A<144 xor a ; A=00 ld ($FF40),a ; Shutting down LCD screen ;//// LOADING GRAPHICS GLVL //// ld bc,64 ld de,graphics_glvl ld hl,$8000 loadTiles ld a,(de) ldi (hl),a inc de dec bc ld a,b or c jr nz,loadTiles ;//// CLEANING BACKGROUND //// ld de,32*32 ld hl,$9800 clearBG: ;xor a ld a,$01 ;Use tile 1 as background for test ldi (hl),a dec de ld a,e or d jr nz,clearBG xor a ld ($FF43),a ; Reset background X position ld ($FF42),a ; Reset background Y position ;//// CLEANING OAM /// ld hl,$FE00 ld b,160 clearOAM: ld (hl),$00 inc l dec b jr nz,clearOAM ;//// SCREEN ACTIVATION //// ld a,%11100100 ;Background palette setting ld ($FF47),a ld a,%10010001 ;Backrgound display activation ld ($FF40),a ld a,%00010001 ;Mode flag selection ld ($FF41),a ld a,%00000001 ;V-Blank interrupt actvation ld ($FFFF),a ei ;Enable interrupts loop: nop jr loop VBlank: call SetFrameTest4 ret SetFrameTest4: ld d,18 ld hl,$9800 printLine: ld e,20 printChar: ld a,$02 ldi (hl),a dec e jr nz,printChar inc hl inc hl inc hl inc hl inc hl inc hl inc hl inc hl inc hl inc hl inc hl inc hl dec d jr nz,printLine ret graphics_glvl: .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .DB $FF,$00,$FF,$00,$FF,$00,$FF,$00,$FF,$00,$FF,$00,$FF,$00,$FF,$00 .DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF .DB $00,$00,$00,$00,$00,$00,$00,$00,$C0,$C0,$20,$E0,$90,$F0,$C8,$78
I tried the same code with Visual Boy Advance and it's seems to run correctly (I'm getting a complete black background).
Does anyone has an idea about what could lead to this behavior ? Is there anything about V-Blank timing I missed here ?
Thanks
Last edited by Ben (2020-04-27 17:36:19)
Offline
What assembler is this? I don't recognize it.
The fact that you get different gfx on BGB and VBA strongly hints at VRAM locking problems. Tick every checkbox in BGB's options, tab "Exceptions", except SGB transfers. This will point out a lot of problems when they happen.
I'm pretty sure you're just overflowing VBlank time.
More general comments on your code:
There's no need to fix the location of the init code if you're `jp`-ing to it. It would make more sense if it was a `jr`, but not here.
`sp` is better put outside of HRAM. (See the second half of this post.)
You don't have names for hardware registers? If you were using RGBDS, I'd strongly recommend hardware.inc, but I don't know for this one.
Instead of hardcoding the size of the block copied to VRAM (`graphics_glvl`), you should put a label at the end of that block, and take the difference between the start and end labels as the length.
Clearing the entire tilemap isn't really useful, since you're only going to display a small part. You can just clear 32 (width of a "line") * 18 (height of the screen) bytes, or only clear the first 20 bytes of the first 18 lines.
Clearing OAM isn't necessary, since you wouldn't be displaying it anyways (not setting bit 1 of LCDC).
Writing to STAT isn't useful if you don't use the STAT interrupt. I'm especially not sure why you're writing to the bottom 2 bits, as they are read-only.
Be careful when enabling interrupts again, they may have "accumulated" before. You should clear IF too, though the best way isn't exactly obvious:
xor a ei ; Only takes effect *after* the next instruction! ld ($FF0F), a
You don't really need a `nop` in your loop. `halt` is better because it allows the CPU to go in low power, saving some battery.
Instead of all those `inc hl|, you could add 12 to hl:
ld a, l add a, 12 ; This would be better as a constant, though ld l, a adc a, h sub l ld h, a
(Explanation.)
Instead of hardcoding the gfx in code, you may want to try storing an image instead, and having your build system convert that to a binary file (for example, using RGBGFX). Though I don't know how you would do the equivalent of `INCBIN` in that assembler; worst case, you can have a script generate a stream of `db` and include that.
Offline
Thank you for your answer!
I'm pretty sure you're just overflowing VBlank time.
That's what I was also thinking of, but V-Blank being this short was bugging me. I mean, not even half of the background can be refreshed at the same time!
I tried running it with all exceptions enabled, as you pointed, and it indeed break on a "inaccessible VRAM". It is strange because none of the background tiles was refreshed before it happens, or maybe it was just BGB not refreshing the map viewer...
Anyway, thanks a lot for your answer, I'll try to work my way around to get the background refreshed in 3 V-Blank instead of one.
Also, thanks for all the advices and tips you gave me. And to answer your question, I'm using WLA-DX assembler (which does come with the .INCBIN directive )
Offline
Ben wrote:
Thank you for your answer!
I'm pretty sure you're just overflowing VBlank time.
That's what I was also thinking of, but V-Blank being this short was bugging me. I mean, not even half of the background can be refreshed at the same time!
I tried running it with all exceptions enabled, as you pointed, and it indeed break on a "inaccessible VRAM". It is strange because none of the background tiles was refreshed before it happens, or maybe it was just BGB not refreshing the map viewer...
Anyway, thanks a lot for your answer, I'll try to work my way around to get the background refreshed in 3 V-Blank instead of one.
Yes, VBlank is quite short; generally, only a third of a screen's worth of tilemap has time to be refreshed. But, why are you trying to write to it in the VBlank handler, anyways?
BGB's map viewer auto-updates always, so I guess you did some invalid accesses early in the code.
Ben wrote:
Also, thanks for all the advices and tips you gave me. And to answer your question, I'm using WLA-DX assembler (which does come with the .INCBIN directive )
Ah, I see. You may want to try RGBDS instead, since it's tailored for the Game Boy, and so should have a bunch of useful features for it.
Offline
But, why are you trying to write to it in the VBlank handler, anyways?
For my amount of experience of programming for the GB, it was easier than setting a timer up to load some data repetitively to the background (Guess you're not the only one high on the laziness scale ). As the code is not doing a lot and because I wasn't expecting V-Blank to be this short, it seems the best option
You may want to try RGBDS instead
I'll give it a shot, hope it's not too different
Offline