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.
Pages: 1 2
I have a problem with the WLA-GB configuration. I don't know how to correctly define BANKS and SLOTS numbers. Generally I want $ 0000 (16KB) as fixed bank and $ 4000 (16KB) as swappable and switchable to other banks (2-7).
Two examples of setting up banks: Both work and this is unclear to me.
First example I have BANK 0 in SLOT 0 as .ORGA $ 0000 by default, another BANK 1 in SLOT 1 as .ORGA $ 4000 and the other BANK 2-7 as .ORGA $ 4000 (they are switchable from SLOT 1 $ 4000 so I guess it should be?)
Second example I have BANK 0 in SLOT 0 as .ORG $ 0000, another BANK 1 in SLOT 1 as also .ORG $ 0000 and the other BANKS also .ORG $ 0000 (when .ORGA was there, it wouldn't compile and a compile error popped up).
I don't know what is correct because both examples work ....
Should DEFAULTSLOT stay as 1 or 0?
#####################
BANK 0 ORGA $0000
OTHER BANKS (1-7) ORGA $4000:
#####################
.GBHEADER NAME "MBC1 DEMO" CARTRIDGETYPE $01 ; MBC1 (00-ROMONLY,01-MBC1,$05-MBC2...) RAMSIZE $00 ; no external RAM in the cartridge (00-no,01-2KB,02-8KB,03-32KB...) COUNTRYCODE $01 ; outside Japan NINTENDOLOGO LICENSEECODENEW "SV" ROMDMG ; DMG rom .ENDGB .MEMORYMAP DEFAULTSLOT 1 ; 0 or 1 ?? SLOTSIZE $4000 SLOT 0 $0000 SLOT 1 $4000 .ENDME .ROMBANKSIZE $4000 .ROMBANKS 8 ; 128KB ;--------------BANKS: .BANK 0 SLOT 0 ; SLOT 0 default BANK 0 (fixed slot) .ORGA $0000 .BANK 1 SLOT 1 ; SLOT 1 default BANK 1 (swappable slot) .ORGA $4000 .BANK 2 ; banks 2-7 switchable in SLOT 1 .ORGA $4000 .BANK 3 .ORGA $4000 .BANK 4 .ORGA $4000 .BANK 5 .ORGA $4000 .BANK 6 .ORGA $4000 .BANK 7 .ORGA $4000
#####################
ALL BANKS ORG $0000
#####################
.GBHEADER NAME "MBC1 DEMO" CARTRIDGETYPE $01 ; MBC1 (00-ROMONLY,01-MBC1,$05-MBC2...) RAMSIZE $00 ; no external RAM in the cartridge (00-no,01-2KB,02-8KB,03-32KB...) COUNTRYCODE $01 ; outside Japan NINTENDOLOGO LICENSEECODENEW "SV" ROMDMG ; DMG rom .ENDGB .MEMORYMAP DEFAULTSLOT 1 ; 0 or 1? SLOTSIZE $4000 SLOT 0 $0000 SLOT 1 $4000 .ENDME .ROMBANKSIZE $4000 .ROMBANKS 8 ; 128KB ;--------------BANKS: .BANK 0 SLOT 0 .ORG $0000 .BANK 1 SLOT 1 .ORG $0000 .BANK 2 .ORG $0000 .BANK 3 .ORG $0000 .BANK 4 .ORG $0000 .BANK 5 .ORG $0000 .BANK 6 .ORG $0000 .BANK 7 .ORG $0000
Last edited by siudym (2021-11-07 05:03:42)
Offline
Looking at some of my really old source I can confirm. All banks are org'ed at $0000. I remember WLA-DX was somewhat quirky, at least compared to RGBDS. I used it only because there was nothing better for GG/SMS development. As for Game Boy I prefer ISAS and RGBDS - you just create group or section and go with the code. No need to bother with initial setup and org makes sense too.
Offline
So how do I have ORG $ 4000 and it only works because by default such a bank is recognized as $ 0000 anyway?
I also have another problem with WLA-GB - I can not use the command such as ADD A, B or ADD A, C - it displays the error "main.asm: 342: ERROR: Unknown symbol" ADD "."
Is this some kind of problem with the WLA itself?
Last edited by siudym (2021-11-06 08:07:04)
Offline
try "ADD B" or "ADD C". for 8-bit addition the only available destination is A, so common syntax is "ADD <r8>"
Offline
I've already done it and it works. But I noticed I had an older version of WLA-GB, the newer one works with ADD A, B / but noticed another problem:
It also doesn't work in the newer version:
LD (addbackup),HL LD HL,(addrbackup)
I had to use a replacement:
LD A,L LD (addrbackup_LO),A LD A,H LD (addrbackup_HI),A LD A,(addrbackup_LO) LD L,A LD A,(addrbackup_HI) LD H,A
I'm using version 9.12 and latest 10.
Last edited by siudym (2021-11-07 03:31:39)
Offline
That's perfectly normal. Take a look at instruction set. You can do it only with stack register.
Replacement is the right way.
Offline
there is no single instruction for storing hl by immediate address, because SM83 is not a Z80.
Offline
I have a problem with strange behavior of objects on the screen (e.g. when moving, many can disappear from the screen).
I am not sure if I am saving sprites values correctly because I am doing it directly to OAM. For example, it immediately defines the YXTileFlags items as variables in RAM:
.ENUM $FE00 ; OAM PLAYER_Y db PLAYER_X db PLAYER_T db PLAYER_F db ENEMY0_Y db ENEMY0_X db ENEMY0_T db ENEMY0_F db ENEMY1_Y db ENEMY1_X db ENEMY1_T db ENEMY1_F db .ENDE
Is it correct and you can write to OAM in the main loop without any problems or do you need to make a buffer and transfer it to OAM, e.g. during VBLANK?
Offline
manipulating OAM directly is not an easy task, you must be sure you access it during LCD mode 0 or 1: https://gbdev.io/pandocs/pixel_fifo.html
there is also "OAM bug": https://gbdev.io/pandocs/OAM_Corruption_Bug.html
suggested way is using of OAM DMA: https://gbdev.io/pandocs/OAM_DMA_Transfer.html
Last edited by toxa (2021-11-09 14:37:49)
Offline
Right now, I've read a lot about OAM in GB, tried to analyze the sources of other games, but really .... I'm totally confused. : /
In NES or SMS everything is clear and simple - I have OAM / SAT in PPU / VDM, I reserve a buffer in memory wram, where I set the variables corresponding to the objects (y, x, t, a) and I'm sending the buffer to OAM / SAT.
In GB, I am not able to understand this. Could someone describe to me step by step how to perform a similar procedure, i.e. a buffer in eg C000-C09F, sending the whole thing to OAM.
Does sending the buffer to OAM have to be VBLANK timing or can it be in the cpu (main) loop?
I don't know if I understood it correctly - the "Run_DMA" function copies the buffer from WRAM to OAM? Should it be in the VBLANK?
.DEFINE OAMBuffer $C000 Run_DMA: LD A,>OAMBuffer LDH [R_DMA],A ; ($FF46) start DMA transfer (starts right after instruction) LD A,40 ; delay for a total of 4×40 = 160 cycles Run_DMA_Loop: DEC A ; 1 cycle JR NZ,Run_DMA_Loop ; 3 cycles RET
When placed in VBLANK it gives me an error:
MEM_INSERT: 1. write into $0048 (old: $00, new: $d9).
^ main.asm:180: Writing a byte
Last edited by siudym (2021-11-09 16:34:57)
Offline
Have you tried my assembly examples for beginners? There's some basic stuff with comments.
As for your question:
- reserve a buffer (nn sprites * 4 bytes (y, x, chr, attr)) in RAM at even address ie. $C000, $C100, $C200, etc.
- copy DMA procedure to HRAM, preferably at $FF80 (make sure buffer and number of sprites makes sense)
- call $FF80 every vblank
That's it. If you want to update OAM outside vblank it's more complicated but also doable. Sprite multiplexers work that way.
Last edited by tmk (2021-11-10 05:38:36)
Offline
Thanks a lot. I am seeing an example code "sprite.asm". From what I can see Buffor OAM was used in $ C000- $ C09F the order is:
C000 = spr0_Y, C001 = spr0_X, C002 = spr0_T, C003 = spr0_A
C004 = spr1_Y, C005 = spr1_X, C006 = spr1_T, C007 = spr1_A
(...)
C09C = spr39_Y, C09D = spr39_X, C09E = spr39_T, C09F = spr39_A
?
I think I will give up WLA-GB and start using RGBASM. Is it better?
I want to define myself variables for sprites in C000, unfortunately I am doing something wrong:
SECTION "OAMBuffVariables",RAM[$C000]
PLAYER_Y: DS 1
PLAYER_X: DS 1
Last edited by siudym (2021-11-10 08:52:22)
Offline
I'm not a fan of RGBASM but it is less confusing and you'll find more examples to try. So it's good choice.
As for your problem... it's typical RTFM case.
SECTION "OAMBuffVariables",WRAM0[$C000]
This ^
Last edited by tmk (2021-11-10 12:44:33)
Offline
siudym wrote:
I don't know if I understood it correctly - the "Run_DMA" function copies the buffer from WRAM to OAM? Should it be in the VBLANK?
game boy has special area HRAM: 256 bytes at the end of CPU address space. some space is allocated for the hardware registers, but there are some few bytes that might be used as variables OR code. that area is the only space that is accessible while DMA transfer. that means that your code, that triggers the DMA transfer must be inside that HRAM. it should also wait there until transfer is finished or else CPU will read something but not your code.
so, the idea is to write relocatable code, put somewhere in rom. then in the beginning of your program copy that code somewhere in HRAM. call that code in HRAM when you want to perform the transfer.
you can call that transfer whenever you want, not during VBlank, that is not a problem. usually it is called in VBlank interrupt.
you can use any assembler to perform that trick with copying of DMA-transfer routine, WLA-DX fits.
ps: your shadow OAM must be aligned to the 256-byte boundary.
Last edited by toxa (2021-11-10 13:23:03)
Offline
Using hram $ ff80- $ ffe can I use 19 sprites (76 bytes) without problems? because I see there is so much space.
I read that it is possible to directly access oam in vblank interrupt. ? Is it possible to copy e.g. 160 bytes from $ c100-9F to $ FE00-9F at vblank irq and then use the buffer to eg move sprites?
Offline
HRAM is used to store procedure that uses DMA to copy your buffer to OAM. Buffer is located in WRAM. Its usage depends on your needs - you can use 1 to 40 possible sprites. Then you call $FF80 during vblank to update OAM and while outside the vblank you modify buffer which is really a copy of OAM you can access without penalty any time. You can find more details in the manual.
Edited some stuff regarding DMA procedure, my mistake, added manual url.
Last edited by tmk (2021-11-11 14:51:20)
Offline
Clear. I completely misunderstood everything, I thought that the FF80-FFFE would be like some other buffer between oam and wram.
I can see that VBL jumps to FF80 but no register protection - are they unnecessary here?
vbl: call $FF80 ; copy OAM mirror table using DMA reti
vbl: push af push bc push de push hl call $FF80 ; copy OAM mirror table using DMA pop hl pop de pop bc pop af reti
If I wanted to define RGBASM banks, e.g. for MBC1, how to do it correctly? Or so:
SECTION "BANK1",ROM1[$4000] ;code here SECTION "BANK2",ROM1[$4000] ;code here SECTION "BANK3",ROM1[$4000] ;code here SECTION "BANK4",ROM1[$4000] ;code here SECTION "BANK5",ROM1[$4000] ;code here SECTION "BANK6",ROM1[$4000] ;code here SECTION "BANK7",ROM1[$4000] ;code here
Returning to the main topic, I already know how to correctly set up WLA-GB banks:
.MEMORYMAP DEFAULTSLOT 1 SLOTSIZE $4000 SLOT 0 $0000 SLOT 1 $4000 .ENDME .ROMBANKSIZE $4000 .ROMBANKS 8 ; 128KB .BANK $00 SLOT 0 .ORG $0 .BANK $01 SLOT 1 .ORG 0 .BANK $02 SLOT 1 .ORG 0 .BANK $03 SLOT 1 .ORG 0 .BANK $04 SLOT 1 .ORG 0 .BANK $05 SLOT 1 .ORG 0 .BANK $06 SLOT 1 .ORG 0 .BANK $07 SLOT 1 .ORG 0
Last edited by siudym (2021-11-12 07:49:58)
Offline
Well, as general rule, no matter what platform, you have to push/pop registers that are in use while handling interrupt. In this example nothing goes on in the main loop so it's not necessary.
SECTION "Graphics",ROMX,BANK[1] ;code here SECTION "Maps",ROMX,BANK[2] ;code here SECTION "Music",ROMX,BANK[3] ;code here SECTION "Stuff",ROMX,BANK[4] ;code here
I think it makes more sense than WLA mess.
Offline
Thanks. WLA-GB seems to have too many problems - again I found an instruction that did not work for WLA: LD A,(C) and LD (C),A
Offline
siudym wrote:
again I found an instruction that did not work for WLA: LD A,(C) and LD (C),A
because instructions are LDH A, (C) and LDH (C), A
Offline
because they comply to Z80's OUT (C), A and IN A, (C) rather than LD
Offline
I also do not know why, when I have secured registers in VBLANK, WLA-GB during compilation shows me this error:
; MEM_INSERT: 2. write into $0048 (old: $d1, new: $d9).
; ^ main.asm:0: Writing a byte
.ORG $40 ; Vblank IRQ Vector push af ; push bc ; push de push hl call $FF80 ; copy OAM mirror table using DMA pop hl ; pop de ; pop bc pop af reti
This only happens when I have PUSH BC / DE and POP DE / BC added (when I only have push / pop AF left and HL compiles correctly ...)
Another thing is the "NINTENDO LOGO" bytes - Do they have to be somewhere in the ROM at the exact address or anywhere?
;* Nintendo scrolling logo
;* (Code won't work on a real GameBoy)
;* (if next six lines are altered.)
.DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D
.DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99
.DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E
Unchecking them completely doesn't change anything during the compilation and operation of the rom.
Last edited by siudym (2021-11-15 06:15:34)
Offline
because of the next interrupt handler, located at 0x0048. you have only 8 bytes. that also has nothing to do with WLA. if you need larger routine you should put jump by the vector address, and ISR implementation somewhere else.
siudym wrote:
Another thing is the "NINTENDO LOGO" bytes - Do they have to be somewhere in the ROM at the exact address or anywhere?
https://gbdev.io/pandocs/The_Cartridge_Header.html
without nintendo logo bytes rom will not start on the real hardware.
Last edited by toxa (2021-11-15 09:46:19)
Offline
Do I have to put nintendo logo bytes after .org $ 104? There is no such solution in the helloworld RGBASM code, there is only the "NINTENDO_LOGO:" label - will RGBASM automatically set these bytes to the address 0104-0133?
Exactly, I have "LCD IRQ Vector" under .org $48 - when I removed it, the VBLANK code works fine. Sorry for asking, but still a lot of things are not clear to me in GB, and additionally depending on the different "hello world" source codes look different.
.ORG $00 ; Reset $00 JP $100 .ORG $08 ; Reset $08 JP $100 .ORG $10 ; Reset $10 JP $100 .ORG $18 ; Reset $18 JP $100 .ORG $20 ; Reset $20 JP $100 .ORG $28 ; Reset $28 JP $100 .ORG $30 ; Reset $30 JP $100 .ORG $38 ; Reset $38 JP $100 .ORG $40 ; Vblank IRQ Vector push af push bc push de push hl call $ff80 pop hl pop de pop bc pop af RETI ;.ORG $48 ; LCD IRQ Vector ; RETI .ORG $50 ; Timer IRQ Vector RETI .ORG $58 ; Serial IRQ Vector RETI .ORG $60 ; Joypad IRQ Vector RETI .ORG $100 ; Code Execution Start NOP JP Start
The question is: can I remove .org $48 without problems when I'm not using this interrupt? I thought he had to be declared.
Or do this: ??
.org $40 jp updateoam updateoam: push af push bc push de push hl call $ff80 pop hl pop de pop bc pop af reti
Coming back to OAM:
I did a test of the two possibilities of transferring the oam buffer to the OAM. The first is through the DMA channels and the second is by simply sending a buffer to the OAM in a VBLANK interrupt (without using DMA). Both cases work and I wonder what is the main difference? My guess is using DMA will be faster?
Without using DMA:
.ORG $40 ; Vblank IRQ Vector push af push bc push de push hl call copyoam pop hl pop de pop bc pop af RETI ;------- copyoam: LD HL,$C000 LD DE,$FE00 LD BC,80 copyoamloop: LDI A,(HL) LD (DE),A INC DE DEC BC LD A,B OR C JR NZ,copyoamloop RET
I would also like to know what is the best GB emulator for testing? Ideally, it should be able to "fake" the state of console chips, memory like real hardware (eg random values in memory during console startup, etc.).
I am currently using BGB and can see it has some useful options - but maybe there are others even better?
Last edited by siudym (2021-11-15 15:11:37)
Offline
you can remove vector by 0x48 if you don't use LCD interrupt, but the best practice is to put a jump by 0x40.
OAM DMA is faster and it is also safer, because you can call that copy function anytime, not only during VBLANK.
probably, the best emulator for windows is BGB.
Offline
Pages: 1 2