Gameboy Development Forum

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.

#1 2020-11-28 19:52:41

albs_br
Member
Registered: 2020-11-28
Posts: 13

New to forum

Hi guys, I'm not sure if this is the right place to put it.
I am learning to develop homebrew games for gameboy, it looks very interesting.
I have some experience programming in Assembly for the MSX computer, I even made a game called Pacific (https://andrebaptista.com.br/?page=PacificMsx).

I already made a simple Arkanoid clone for Gameboy  as POC and learning exercise (is there any way to put a .gb ROM file here?)

Cheers

Offline

 

#2 2020-11-29 22:03:20

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

Just put it on github:
https://github.com/albs-br/paranoid

Pretty simple game, I will be adding things as I learn.

Offline

 

#3 2020-12-01 06:47:57

toxa
Member
Registered: 2020-02-13
Posts: 309

Re: New to forum

nice start! smile you rom has at least two issues:
1. rom size does not match the header, and
2. you are trying to access VRAM when it is not readable.

both exceptions are shown in BGB emulator - i suggest to use it for debugging.

Offline

 

#4 2020-12-01 20:03:10

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

Thank you for the observations.

1 - I've already seen this one.There is no ROM_SIZE_16KBYTE constant in gbhw,inc. The smallest is ROM_SIZE_32KBYTE. Also, I have no idea on how to set the ROM to 32Kb (is it an assembler directive?)

2- Where can I find this info? I'm using BGB emulator.

Offline

 

#5 2020-12-02 05:38:27

nitro2k01
Administrator
Registered: 2008-02-22
Posts: 249

Re: New to forum

The usual way to handle the ROM size is using rgbfix. Add the flag "-p 0xff" to rgbfix to pad the ROM up to the closest valid size and update the ROM size field in the header.


Blog: Gameboy Genius
"A journey of a thousand miles begins with one small step"
Old Chinese Proverb

Offline

 

#6 2020-12-02 17:15:17

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

Thanks @nitro2k01, the ROM size issue is solved.

But about the invalid access to VRAM, I haven't seen it. I do have the "break on access inaccessible VRAM" checked on BGB options, but it's never reached...

Offline

 

#7 2020-12-08 16:08:59

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

Hi guys, this is my main game loop:

Code:

GameLoop:

    call ReadInput
    call GameLogic

.waitVBlank:
    ld      a, [rLY]
    cp      145
    jr      nz, .waitVBlank

    call UpdateVram
    call UpdateOAMRam

    jp GameLoop

My question: Is this the right/recommended way of doing this? Good practice? Is this wasting CPU cycles/battery energy? Should I use HALT and interruption for updating VRAM at VBlank? Can someone provide an example code?

Last edited by albs_br (2020-12-08 16:09:54)

Offline

 

#8 2020-12-08 17:35:32

AntonioND
Member
Registered: 2014-06-17
Posts: 134
Website

Re: New to forum

That isn't good practice. Normally you want to have a IRQ handler at address 0x0040 (VBL handler), you want to set bit 0 of IE to 1 to enable the VBL interrupt, and you want to call update oam from there. You can call UpdateVram from the game loop, though.

If you really want to talk to people in real time, there is a link to the gbdev discord here: https://gbdev.io/ You may find more help there, as most tutorials are quite lacking...

Offline

 

#9 2020-12-09 23:22:24

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

Thanks for helping.

I managed to implement the sugestions, following an example found on a pdf online:

Code:

GameLoop:
    halt                             ; stop system clock
                                    ; return from halt when
                                    ; interrupted
    nop                             ; (See WARNING on http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf, page 20)

    ld         a, [VblankFlag]
    or         a                         ; V-Blank interrupt ?
    jr         z, GameLoop             ; No, some other interrupt
    xor     a
    ld         [VblankFlag], a             ; Clear V-Blank flag
    
    call     ReadInput
    call     GameLogic
    
     call     UpdateVram

    jp         GameLoop

And:

Code:

VblankInt:
    push     af
    push     bc
    push     de
    push     hl
    
    ; call SpriteDma ; Do sprite updates
    call    UpdateOAMRam
    
    ld         a, 1
    ld         [VblankFlag], a
    
    pop     hl
    pop     de
    pop     bc
    pop     af

    reti

Far better now.

Offline

 

#10 2020-12-10 17:10:23

AntonioND
Member
Registered: 2014-06-17
Posts: 134
Website

Re: New to forum

Ok, great! However, that manual you have in your comment isn't considered a good document, as far as I'm aware.

Offline

 

#11 2020-12-11 18:16:57

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

That's the only game loop example I found so far. What's the best documentation?

Offline

 

#12 2020-12-12 09:17:29

AntonioND
Member
Registered: 2014-06-17
Posts: 134
Website

Re: New to forum

Offline

 

#13 2020-12-12 22:48:04

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

Now I'm stuck in a difference in behavior between BGB emulator and Emulicious. The issue is enabling/disabling the Window mid frame, using LYC=LY int.

Code:

LCDCInt:
    push     af
    push     bc
    push     de
    push     hl

    ; Read STAT (LCD Status Register)
    ; Bit 6 - LYC=LY Coincidence Interrupt (1=Enable) (Read/Write)
    ; Bit 5 - Mode 2 OAM Interrupt         (1=Enable) (Read/Write)
    ; Bit 4 - Mode 1 V-Blank Interrupt     (1=Enable) (Read/Write)
    ; Bit 3 - Mode 0 H-Blank Interrupt     (1=Enable) (Read/Write)
    ; Bit 2 - Coincidence Flag  (0:LYC<>LY, 1:LYC=LY) (Read Only)
    ; Bit 1-0 - Mode Flag       (Mode 0-3, see below) (Read Only)    

    ld      a, [rSTAT]
    and        STATF_LYCF
    jp        nz, .LYCequalLY
    jp        .reti

.LYCequalLY:

    ld      a, [rLY]

    cp      80                         ; 
    jp        z, .ly80                ; 
    cp      40                         ; 
    jp      z, .ly40                 ; 

.ly40:
    ; Enable window
    ld      a, [rLCDC]                ; load current value
    set        5, a                    ; enable window
    ld      [rLCDC], a                ; save

    ld      a, 80                   ; line to trigger the next interrupt
    ld      [rLYC], a
    jp        .reti

.ly80:
    ; Disable window
    ld      a, [rLCDC]                ; load current value
    res        5, a                    ; enable window
    ld      [rLCDC], a                ; save

    ld      a, 40                   ; line to trigger the next interrupt
    ld      [rLYC], a

.reti:
    pop     hl
    pop     de
    pop     bc
    pop     af

    reti

Both source and compiled ROM can be found here: https://github.com/albs-br/paranoid

Thanks

Last edited by albs_br (2020-12-12 23:08:24)

Offline

 

#14 2020-12-12 23:07:55

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

I forgot to explain, It's working on Emulicious and not working on BGB.
On Emulicious you can see the window midscreen (between lines 40 and 80) and nothing is displayed on BGB.

With the Window at a fixed position it works like a charm on both... So it has to be something with the way BGB handle the LCDC int (I suppose it's the right behavior, as BGB is considered the most accurate emulator).

Offline

 

#15 2020-12-13 13:00:37

nitro2k01
Administrator
Registered: 2008-02-22
Posts: 249

Re: New to forum

The background is not a "layer" like the BG layers on SNES etc, but more a hardware hack to change the data source for the background at a given pixel and to the end of the scanline. The way the window works (roughly speaking) is that if the window is activated in LCDC while the pixel corresponding to WX,WY is being drawn, the window starts drawing. When the window has started drawing for the first time, it starts drawing on every new scanline at WX. Since in your case, WY=0 and the window is only activated in LCDC between scanlines $40 and $60, the starting condition is never true and the window never starts drawing.

What do you want to achieve? Show the window between scanlines $40 and $60? Do this:
* Set WY permanently to $40.
* Enable the window in VBlank. It will now start drawing at scanline $40 because of the WY setting.
* Use the LCD interrupt to disable the window at scanline $60.

Last edited by nitro2k01 (2020-12-13 13:06:00)


Blog: Gameboy Genius
"A journey of a thousand miles begins with one small step"
Old Chinese Proverb

Offline

 

#16 2020-12-14 17:36:33

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

nitro2k01 wrote:

Since in your case, WY=0 and the window is only activated in LCDC between scanlines $40 and $60, the starting condition is never true and the window never starts drawing.

In other words the emulicious has a wrong implementation of the bg/window drawing.

Offline

 

#17 2020-12-14 19:08:36

nitro2k01
Administrator
Registered: 2008-02-22
Posts: 249

Re: New to forum

albs_br wrote:

nitro2k01 wrote:

Since in your case, WY=0 and the window is only activated in LCDC between scanlines $40 and $60, the starting condition is never true and the window never starts drawing.

In other words the emulicious has a wrong implementation of the bg/window drawing.

Indeed. I tried it on hardware as well to be sure, and the window section is not drawn.


Blog: Gameboy Genius
"A journey of a thousand miles begins with one small step"
Old Chinese Proverb

Offline

 

#18 2020-12-15 22:10:06

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

New question: how is the best way to pass parameters to a subroutine? On Z80 I am used to the IX + n instructions, but on the GB CPU they are missing.

Ex:

Code:

MoveEnemy_1:
   ld a, [enemy_1_x]
   inc a
   ld [enemy_1_x], a

; same for other properties of enemy
ret

One possible approach whould be to pass a pointer for the first property address on HL and "navigate" up and down to the others

Code:

ld hl, enemy_1_x      ; addr of first property of enemy 1, ie. addr of enemy 1
call MoveEnemy

ld hl, enemy_2_x
call MoveEnemy

MoveEnemy:
   ld a, [hl]       ; load x of enemy
   inc a
   ld [hl], a

   inc hl
   ld a, [hl]       ; load y of enemy
   ; do something with the second property
   ld [hl], a

ret

This approach has some seriuos disadvantages, besides being "ugly": if I have to add properties to the enemy, they should be at the end, or a great refactory on the sub will be needed.

Offline

 

#19 2020-12-16 00:26:55

nitro2k01
Administrator
Registered: 2008-02-22
Posts: 249

Re: New to forum

Essentially, you're right. The Gameboy CPU is not Z80 but a Sharp architecture which by all evidence is called SM83. There are no index registers, no shadow registers and what you show in your example is what you have to do.

There are a couple of potential small improvements to your example. Loading to/from HL, you can get a free increment/decrement of HL. I believe the same exists on Z80.

Code:

ld [hl+], a ; Store a to [hl] and post-increment hl.

Also, if you're applying the same operation on all actors (such as applying movement) you may just want to ditch the call and put it in a loop to save on a call/ret for every iteration. Then you would have to make sure that HL points to the first member of the actor's struct at the end of the loop.

This is basic stuff but can be worth pointing out.

In asm you obviously choose whatever calling convention you want. In C, arguments are pushed to the stack and you would use the ld HL,SP+xx opcode to get a pointer to an argument. The return value is stored in DE. Also note that if you ever need to interface C code, the BC register needs to be preserved through the call, whereas other registers can destroyed.


Blog: Gameboy Genius
"A journey of a thousand miles begins with one small step"
Old Chinese Proverb

Offline

 

#20 2021-04-21 16:55:43

albs_br
Member
Registered: 2020-11-28
Posts: 13

Re: New to forum

Only today I remembered to put a video of the "final" version on Youtube:

https://www.youtube.com/watch?v=5ks1Bf9HxOY

Nothing special, just some tests to check the GB capabilities, maybe someday I make a complete game.

Last edited by albs_br (2021-04-21 19:55:37)

Offline

 

Board footer

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson