Page 8 of 105
Posted: Mon Jun 06, 2011 2:14 pm
by qbradq
Local variables in C and C++ are allocated on the stack (a sliding window of RAM used just for locals and function parameters). On a 6502 you don't have such a thing.
In 6502 ASM a "local" variable is one that is only used by one particular subroutine. Assemblers that support scoping can make this easier by making access to labels from the outside harder. This
does not support recursion, so if your subroutine calls itself it will stomp on the local variables, unlike C and C++.
What Tokumaru was describing was something different. I will try to explain in more round terms:
Hypothetical Man wrote:I have a routine that handles the title screen. It needs 500 bytes of RAM, which I allocate starting at $0300.
I have another routine that implements my game. It needs 1500 bytes of RAM. Because I know that the game and the title screen will never be running at the same time, I also start allocating RAM at $0300.
So now I have two routines that use the same memory locations for variables, but because they never run at the same time (and do not care what is in RAM when they start) they do not step on each other's toes.
I think this approach is fine when you are dealing with distinct modes of operation, like our title screen / game example. If your game is a series of mini games (like Pirates!), each mini-game might reuse the same area of RAM for variables, and then you might have a small protected segment to keep game state variables.
Personally I do not like doing this within a game mode. It's true, my sprite generator never runs at the same time as my object updates, but this type of data interleaving over-complicates your code. Only if I were
very desperate for RAM would this be an option for me.
Posted: Mon Jun 06, 2011 2:22 pm
by tokumaru
unregistered wrote:So that means we could declare a variable... and then, later on, since the previous variable was local... and we are in a different area of code, we could declare another variable in the same spot!?
That's the idea. Since not all variables must exist at all times, many variables can share memory locations, and the code I wrote before is the most organized way I can think of doing that.
Just like local variables in C++?
Kinda... In the sample code I wrote they aren't exactly local, because technically you could still use them anywhere in the program (i.e. the labels are global). Of course you wouldn't want to use one module's variables in another module, because that would crash the program. You could probably use ASM6's local labels (they start with a period, I think) though, and they would be more like local variables. Something like this:
Code: Select all
SomeFunction:
.enum LocalVariables3
.LocalVariable1 .dsb 1
.LocalVariable2 .dsb 1
.LocalPointer .dsb 2
.ende
;the variables declared above can only be seen here
;return
rts
If all of the files combine in to one single .asm file then how does this work when there is just one file?
There's really no difference between 1 file vs. multiple files... When you include a file, it's the same as if you were copying and pasting its contents directly into the first file. The only reason to separate the source into multiple files and use includes is organization. Scrolling through a 20,000 line program looking for a piece of code is hell.
Posted: Mon Jun 06, 2011 2:31 pm
by tokumaru
qbradq wrote:Personally I do not like doing this within a game mode. It's true, my sprite generator never runs at the same time as my object updates, but this type of data interleaving over-complicates your code. Only if I were very desperate for RAM would this be an option for me.
I wouldn't be able to make my game without this. The main engine uses every last byte of RAM, so I can't afford to have memory allocated for a bunch of stuff that just isn't running during gameplay (title screen, menus, bonus stages, etc). The main systems, like the ones dealing with music, sprites, etc. use global variables, because those are used by all program modes. It's not a difficult thing to manage at all: whatever is used by multiple program modes is global.
Posted: Mon Jun 06, 2011 2:48 pm
by unregistered
qbradq and tokumaru, thanks so much for helping me through this!

I understand everything yall said now!
tokumaru, thank you also for telling us about your best way to make variables!

Posted: Thu Jun 09, 2011 12:20 pm
by unregistered
Shiru, in famitone's [color=orange]readme.txt[/color], wrote:Warning: don't forget that active DMC conflicts with $2002 and controllers polling, read docs to learn how to avoid it (generally don't use $2002 polling and poll controllers three times in a row, then use matching result).
What is active DMC? I know $2002 is in the first group of I/O registers... I guess it allows interaction with the controllers. In my code I'm using $4016 to read the controller... $4016 is from the second and last group of I/O registers. When I read the controller from $4016 is that called 'polling' too?

Posted: Thu Jun 09, 2011 12:46 pm
by Dwedit
Any reading that has side effects may screw up, because DMC adds one extra read. Examples of reads with side effects include reading the controller or reading bytes from PPU Data. Reading PPU status is okay, since one extra read won't hurt anything.
Posted: Fri Jun 10, 2011 1:59 pm
by unregistered
Dwedit wrote:Any reading that has side effects may screw up... Examples of reads with side effects include reading the controller
Yes, I agree, now (after reading some more about reading). : ) My song wont play for me.

And so I'm wondering if it has something to do with the way I've worked the callling code into the controller reading part. Here is what i've got (
the famitone code is between the ---\/-- and the ---^---):
Code: Select all
react_to_input:
lda #$01 ; strobe joypad
sta $4016
lda #$00
sta $4016
lda $4016 ; Is the A button down?
and #1
beq @not_a
ldx aHasbeenpressed
bne @b
sta aHasbeenpressed
inc aFrame ;run only once per press.
jmp @b
@not_a: sta aHasbeenpressed
@b: lda $4016 ;Is the B button down?
and #1
beq @select
lda #0
sta aFrame
jsr low_c ;low_c is just small code that plays a note
;-----------------------\/------------------------------------------
@select lda $4016 ; Select does something(music no working)
and #1
beq @start
ldx <musicA_module ;also songA
ldy >musicA_module
jsr FamiToneMusicStart
@start lda $4016 ; Start does nothing
and #1
beq @up
jsr FamiToneMusicStop
;-----------------------^-------------------------------------------
@up lda $4016 ;Is Up down?
and #1
beq @down
dec oY
@down lda $4016 ;is Down down?
and #1
beq @left
inc oY
@left lda $4016 ;is Left down?
and #1
beq @right
dec oX
@right lda $4016 ;Is Right down?
and #1
beq not_dn
inc oX
not_dn: rts
Thank you for spending time reading that big amount of code. Sorry, though, I hope there is something wrong there.

Posted: Fri Jun 10, 2011 6:43 pm
by unregistered
Dwedit wrote:Any reading that has side effects may screw up, because DMC adds one extra read.
DMC is
delta modulation channel. That is the fifth APU channel right? My song doesn't have anything in that channel... so that means there is one less read... and then the side effects don't happen?

Posted: Fri Jun 10, 2011 8:03 pm
by 3gengames
First off, you need to read the controller and store it into a variable. Doing it right off of the read is a terrible way to make an engine. Do a LSR and ROL it into a variable, then use that variable to see what needs to happen.
Posted: Sat Jun 11, 2011 1:35 pm
by unregistered
Thanks for your suggestion!

Here's my code now... does nothing... maybe i need to separate the reading code from the controller check code??
Code: Select all
react_to_input:
lda #$01 ; strobe joypad
sta $4016
lda #$00
sta $4016
;*****************Read Entire Controller*
lda #0
sta controller1
ldx #8
-read: lda $4016
ora controller1
lsr ;shift right one bit
ror ;rotate one bit right
sta controller1
dex
bne -read
;*******************************************
lda controller1 ; Is the A button down?
and #1
beq @not_a
ldx aHasbeenpressed
bne @b
sta aHasbeenpressed
inc aFrame ;run only once per press.
jmp @b
@not_a: sta aHasbeenpressed
@b: lda controller1 ;Is the B button down?
and #00000010b
beq @select
lda #0
sta aFrame
jsr low_c ;low_c is just small code that plays a note
;-----------------------\/------------------------------------------
@select lda controller1 ; Select does something(music no working)
and #00000100b
beq @start
ldx <musicA_module ;also songA
ldy >musicA_module
jsr FamiToneMusicStart
@start lda controller1 ; Start does nothing
and #00001000b
beq @up
jsr FamiToneMusicStop
;-----------------------^-------------------------------------------
@up lda controller1 ;Is Up down?
and #00010000b
beq @down
dec oY
@down lda controller1 ;is Down down?
and #00100000b
beq @left
inc oY
@left lda controller1 ;is Left down?
and #01000000b
beq @right
dec oX
@right lda controller1 ;Is Right down?
and #10000000b
beq not_dn
inc oX
not_dn: rts
Posted: Sat Jun 11, 2011 3:06 pm
by 3gengames
That's not right. This is what you need:
.rsset $300
ControllerButtons: .rs 1
LDX #$01
STA $4016
DEX
STX $4016
LDX #$08
Loop:
LDA $4016
LSR A
ROL ControllerButtons
DEX
BNE Loop
RTS ;Controller value in the variable ControllerButtons.
Maybe look into more 6502. Seems you don't have a good enough understanding of it or the hardware.
Posted: Wed Jun 15, 2011 5:31 pm
by unregistered
3gengames, I relpaced my code with your code and put this right after it
Code: Select all
jsr high_c
.if ControllerButtons != 0
.error "need help"
.endif
And while running my program it never ever stops and says need help no matther what I'm pressing on the controller. The controller works fine in other programs. It is continuealy reaching this code cause I can hear a high pitch C noise over and over.
In your code you've got
Code: Select all
Loop:
LDA $4016
LSR A
ROL ControllerButtons
DEX
BNE Loop
That lsr a writes its answer back into the accumulator right? And rol ControllerButtons writes its answer back into ControllerButtons right? So how is ControllerButtons updated? (These questions are for yall too.)
Posted: Wed Jun 15, 2011 6:00 pm
by tokumaru
"LDA $4016" puts the state of the current button into the accumulator; "LSR A" (or simply "LSR", depending on the assembler) shifts the bit out of the accumulator and into the carry flag; "ROL ControllerButtons" shifts the carry flag into ControllerButtons. Do this 8 times in a row and each bit of "ControllerButtons" will indicate the state of a buttom.
Posted: Wed Jun 15, 2011 6:05 pm
by 3gengames
the .rsset and Controller variable is any piece of RAM you want to point it at, here's a commented and better version:
Code: Select all
LDX #$01 ;X=1
STX $4016 ;Write high latch value to controller port.
DEX ;X=0
STX $4016 ;4016=0 now, can be read back.
LDX #$08 ;X=8
Loop: LDA $4016; Put the player 1 controller value into the accumulator. This will hold the value of ONE button.
LSR A ;Put DataLine1 [Controller] onto the Carry.
ROL ControllerButtons ;Shift ControllerButtons RAM one bit left with the carry. When done 8 times, will be updated with button statuses for each button. One bit will represent one button. The MSB will be first read, LSB last read. 1=Pressed, 0=Not pressed.
DEX ;X=X-1
BNE Loop;If X!=0 then loop.
RTS ;Return from subroutine. New controller status for Player 1 will be in the RAM byte ControllerButtons.
Does this make sense on how it works? Any qustions just ask. This program should work.
ETA: NINJA'D!
Posted: Wed Jun 15, 2011 6:25 pm
by tokumaru
3gengames wrote:Code: Select all
LSR $4016; Put the player 1 controller value into the CARRY bit.[/quote]
Does this really work? I mean, LSR absolute is a read-modify-write instruction, so you're effectively writing something back to $4016... Doesn't this interfere with the reading process?