8x16 and whatever else unreg wants to know

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
qbradq
Posts: 951
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq » Mon Jun 06, 2011 2:14 pm

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.

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Mon Jun 06, 2011 2:22 pm

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.

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Mon Jun 06, 2011 2:31 pm

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.

unregistered
Posts: 1075
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered » Mon Jun 06, 2011 2:48 pm

qbradq and tokumaru, thanks so much for helping me through this! :D I understand everything yall said now! :D

tokumaru, thank you also for telling us about your best way to make variables! :D

unregistered
Posts: 1075
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered » Thu Jun 09, 2011 12:20 pm

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? :?

User avatar
Dwedit
Posts: 4352
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit » Thu Jun 09, 2011 12:46 pm

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.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!

unregistered
Posts: 1075
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered » Fri Jun 10, 2011 1:59 pm

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. :|

unregistered
Posts: 1075
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered » Fri Jun 10, 2011 6:43 pm

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? :?

3gengames
Formerly 65024U
Posts: 2277
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames » Fri Jun 10, 2011 8:03 pm

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.

unregistered
Posts: 1075
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered » Sat Jun 11, 2011 1:35 pm

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  

3gengames
Formerly 65024U
Posts: 2277
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames » Sat Jun 11, 2011 3:06 pm

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.

unregistered
Posts: 1075
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered » Wed Jun 15, 2011 5:31 pm

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.)

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Wed Jun 15, 2011 6:00 pm

"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.

3gengames
Formerly 65024U
Posts: 2277
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames » Wed Jun 15, 2011 6:05 pm

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!
Last edited by 3gengames on Thu Jun 16, 2011 12:19 pm, edited 1 time in total.

User avatar
tokumaru
Posts: 11858
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Wed Jun 15, 2011 6:25 pm

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?

Post Reply