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.
im trying to figure out how to make variables. when i increment the A register and load i into _POS_X it doesnt seem to do anything, the screen dont move, but the screen starts with offsets by the initial value used by _POS_X(its 1).
i cant figure it out, i assume its something very simple im doing wrong
(im using RGBDS if it matters)
SECTION "variables", ROM0[$200] _POS_X: ds 1, 1 moveScreen: ld a, [_POS_X] inc a ld[_POS_X], a ret SECTION "game", ROM0[$250] ;stuff CALL moveScreen ld a, [_POS_X] ld [$FF43], a
Last edited by pinoda (2020-04-15 14:28:35)
Offline
you can't increment variables in rom. it's better to use ram for this.
Offline
oh thanks, how do i do it in ram?
Offline
i'm not sure, because i never used rgbds, but it might be something like this:
SECTION "variables", WRAM0
_POS_X: ds 1, 1
SECTION "code", ROM0
; code here
you should also initialize stack and everything else properly. i advise you to find some simple template where everything is done right, and fill it with your code.
Last edited by toxa (2020-04-15 15:35:25)
Offline
i had to use bytes between $C000-$CFFF that was the "internal ram", thanks for pointing me in the right direction, i would have spent a lot of time if not.
Offline
There are a bunch of problems with your code, that I have often seen from people following a certain Spanish tutorial with terrible advice. I don't know why it's still popular, but it is.
You don't want to hardcode the address of sections if you can avoid it.
This is because "floating" sections can be freely placed anywhere in the final ROM by RGBLINK. This allows automatically filling any gaps that may occur between two sections (for example, a 1-byte section can go between two 255-byte sections aligned to 256 bytes).
Manual assignment prevents RGBLINK from doing the job, instead shifting the burden onto you. You probably don't want to do this on top of everything else, programming in ASM is already quite taxing.
There are some cases in which you *want* to fix the address, mostly the header and vectors (rst and interrupts), but for most of the code, neither the bank (for banked memory) nor the address needs to be fixed.
ds uconst, reloc_8bit
I wonder where you got that `ds 1, 1` from. What do you expect it to do? It's only intended for ROM areas, so it shouldn't work in RAM (thus toxa's code shouldn't compile. If it does, it's a bug I have to fix).
Naming
I know naming conventions vary for everybody, but there are a few conventions that generally everyone follows. One of them is that UPPERCASE_SNAKE_CASE is reserved for constants; in RGBDS, this is typically symbols defined through EQU, SET, or EQUS, but not labels. (They're not really constants unless they're defined in a SECTION whose address is fixed, but as I said this should be a rare case)
If you want some reference, I explain my own naming conventions in this document.
Hardware register naming
One of the reasons why we use textual assembly instead of writing raw bytes directly is to be able to put names on things. (For labels, there's the additional benefit of all their references being automatically updated whenever their location change.)
You write to SCY using its address ($FF43) directly, which is not that obvious (you can learn them by heart, but most people prefer just using names).
There is a file the community considers a de-facto standard, hardware.inc.
Speaking of that tutorial, it usually points people to using `EQU` for variable allocation, which is a terrible idea. Good on you for not picking that up ^^
Since the topic of HRAM has been brought up, let's talk about it a bit.
HRAM is an interesting memory region, because as tmk brought up, it's possible to access it faster using the `ldh` instructions. There are some common misconceptions about it, though:
HRAM is not inherently faster. `ld a, [hl]`, for example, takes the same number of cycles whether it's accessing WRAM or HRAM. The reason why `ldh` is faster is because `ld a, [$FF42]` is 3 bytes (FA 42 FF, see here), whereas `ldh a, [$FF42]` is only 2 bytes (F0 42).
Thus, HRAM only has interesting properties when `ldh` can be used, which is either:
- Direct access (not through a register pair)
- Indirect access with only one 8-bit register, which is seldom useful—mostly when you're in a context where registers are tied up, to save spilling to memory. This happens very rarely in my experience.
This generally means that putting buffers in HRAM is not useful. Another consequence is that the stack is not faster when put in HRAM! Putting it there, however, means some of that memory cannot be used in the faster way, making it essentially a waste. I thus recommend putting the stack in WRAM (at the end of it, so $E000 when not using WRAM banks, and $D000 when using them).
The next thing to consider is what to put in HRAM. Simply put, variables that you access explicitly (i.e. not through a register pair), and that need to be accessed quickly.
Good examples are variables used in interrupt handlers, since you generally want those to be as fast as possible, given that they impact the entirety of the game. Or temporary variables inside loops; for example, my NPC rendering code has two nested loop (the outer one iterates on NPCs, the inner one iterates on their OAM draw list). The inner loop runs often, so I need it optimized; unfortunately, it uses a lot of registers (hl is the read pointer, de is the OAM write pointer, and bc are used for calculations). Thus, the loop counter has to be stored elsewhere, for which the naďve implemenation is something like this:
ld a, NB_ITERATIONS .loop push af ; Do magic here pop af dec a jr nz, .loop
`push` is 4 cycles, `pop` is 3 cycles. But we can do better using HRAM:
ld a, NB_ITERATIONS .loop ldh [hLoopCounter], a ; Do magic here ldh a, [hLoopCounter] dec a jr nz, .loop
Both of those HRAM accesses are 3 cycles, so this is more efficient by 1 cycle per iteration. (As I mentioned, this loop runs a lot, so it's definitely worth it.)
Offline