I'm trying to organize my code to do a basic game. So I've declared some const & variables like that :
Code:
.rsset $0000 ; start at ram addr 0x0000
gameState .rs 1 ; gameState = 1 byte
STATE_MENU = $00 ; STATE_MENU := 0
STATE_PLAY = $01 ; STATE_PLAY := 1
STATE_OVER = $02 ; STATE_OVER := 2
.bank 0
.org $C000
Init:
[...]
When my game enter the
Menu or
Play state, it's fine. But not the
Over state. I don't know why but if I change the code to
Code:
STATE_OVER = $04
it worked! But It ain't with $02 or $03
Did I missed something(s)? Or I'm I somehow overlapping in memory? Is there another way (i.e. A better way) to declare variables and const ?
Are you putting a "#" before the names of your constants when using them?
You probably want:
Code:
lda #STATE_OVER
sta gameState
...which puts a 2 into memory location $00.
And not:
Code:
lda STATE_OVER
sta gameState
...which copies the contents of memory location $02 to memory location $00.
If that's not the problem, I'll ask you to post some of the code that uses the constants and the variables, because I don't see anything wrong with the code you posted.
Declaration :
Code:
.inesprg 1
.ineschr 1
.inesmap 0
.inesmir 1
.rsset $0000
gameState .rs 1
STATE_MENU = $00
STATE_PLAY = $01
STATE_OVER = $02
.bank 0
.org $C000
Reset:
Initialization :
Code:
;lda #STATE_PLAY
;lda #STATE_MENU
lda #STATE_OVER
sta gameState
(Note : It works for STATE_PLAY and STATE_MENU but not STATE_OVER)Usage:
Code:
lda gameState
cmp #STATE_MENU
beq EngineMenu
lda gameState
cmp #STATE_OVER
beq EngineOver
lda gameState
cmp #STATE_PLAY
beq EnginePlay
jmp GameEngineDone
(Note: I'm trying to do a template, this is my first itteration)
You seem to have a few RTSs screwing up your logic. You game logic is included after the joypad reading, meaning that the code at "GameEngine:" will be executed directly, not as a subroutine. There you have the game state compares, and you branch to one of 3 labels depending on the value of the variable.
In each of the 3 labels, you call a subroutine. When the called routine finishes and returns, there is another RTS. I ask of you: where will the program return to? There is no return address in the stack at that point (except for the one that will be used by the RTI command that follows, but it's accompanied by the processor flags and you can't mess with them because they are needed by the RTI). To fix this you have to replace those 3 RTSs with "jmp GameEngineDone".
I don't know if that's what's causing the apparent error you described (sometimes the problem is just not where we thought), but it's the only really wrong thing I noticed in your code.
I just noticed another very serious flaw in your code, and it has to do with RTS too. You jump to the "InitNintendo" routine, and the return address is placed on the stack. However, inside this subroutine you clear all the RAM, including the return address, along with the whole stack.
This is one of the evils of clearing the whole memory. Personally, I'm against it (I favor proper initialization - not necessarily to 0 - of each and every variable prior to their use), but it seems I'm part of a minority in this case.
Notice that you did more than just wiping out the return address. You jumped to a routine with an unitialized stack pointer. This alone shouldn't cause any trouble (any stack pointer value is valid if the whole page is used for the stack), but inside that routine you changed the stack pointer, so it wasn't pointing to the return address anymore. Even if was already lost anyway you overwrote it with 0's.
Anyway, since the return address is corrupted, the CPU will try to execute an instruction at address $0001 (the address pulled from the stack + 1). The instruction found is a BRK ($00) which causes a jump to the IRQ address. Your IRQ address is $0000, and at that location is your game mode variable, which can be interpreted as an invalid opcode depending on what you put there. This is probably why you are having different results depending on the values you assign to the constants, since that's the value that will be executed by the CPU when it derails.
I know it looks pretty neat to have everything organized as subroutines and all, but believe me: the basic initialization steps work better if placed directly at the reset address. Just initialize the stack and clear the memory before using any subroutines.
It's all fixed. Thx to you.
Quote:
I ask of you: where will the program return to? There is no return address in the stack at that point
I thought BEQ was adding a return address. From what I've learned with you, it's not. It's more like a "jump" on Equal and not a "Call-that-subroutine" on Equal...
Edgyr wrote:
I thought BEQ was adding a return address. From what I've learned with you, it's not.
Exactly. Only JSR places a return address on the stack (branches and jumps don't), so be sure that your JSRs and RTSs are correctly distributed (for every JSR executed a RTS must be executed afterwards).
Interrupts also place return addresses on the stack (along with the processor flags), but those are not compatible with RTS, only with RTI.
There are also some tricks involving JSR and RTS that break the rules a bit, but you shouldn't worry about those right now.
Variables are what make your programs zoom. Programming just can't get done without them. So if you haven't been introduced to variables yet, here you go.
simulation credit immo - Simulation credit immo. L’Internet a rendu encore plus facile d’obtenir de l’aide pour trouver le credit immo.