Subroutines

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

Post Reply
Roth
Posts: 401
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Subroutines

Post by Roth »

Since tokumaru posted that link to the 6502 Simulator, I've been able to actually try some of this basic stuff that I've been reading.... and I mean VERY basic. I'm pretty much just trying to learn my way around the 6502 right now. Something that bugs me is the concept of subroutines. I've been thinking of them in terms of functions, but I'm not sure if that's the correct way to think of them. I thought maybe it was something you could call on when needed. Anyway, I've been fiddling with the simulator, and did this (this isn't supposed to make sense):

Code: Select all

	.ORG $8000
	
	LDX #$40
	STX $01
	LDA #$30
	STA $02
	LDY #$20
	STY $03
	JSR testit
	LDX #$50

testit:
	CLC
	CLD
	LDA $02
	ADC $03
	STA $04
	RTS
When I look at the Command Log, it shows that after jumping back from the subroutine, that it loads the #$50 into X, then it runs through the subroutine again. I'm not sure how I would get it to skip over the subroutine, or if I should be housing it somewhere else in the code so it won't read unless called upon...

Also, in my book it says something about the stack is used by subroutines... but I can't understand what it means. When I look at the Register window in the simulator, the stack is filled with 00 all across the board. Any tips would be appreciated.
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: Subroutines

Post by Disch »

Roth wrote:When I look at the Command Log, it shows that after jumping back from the subroutine, that it loads the #$50 into X, then it runs through the subroutine again.
This is because the instruction after LDX #$50 is the start of the subroutine. Code does NOT stop when it reaches a label... labels are non-existant when the code is executing, they're just there for your reference.

If you want the code to stop without crashing and burning, you could drive it into an infinite loop:

Code: Select all

  .ORG $8000

  LDX #$40
  JSR testit
  LDX #$50   ;after this line is executed, the code will go right into
             ; the next line.  Regardless of whether or not a label is there

InfiniteLoop:
  JMP InfiniteLoop   ;  This is the next line of code, so this will be done
                     ;after that above LDX.  This will perform an infinite loop by
                     ;repeatedly jumping to the same point

testit:
  CLC
  CLD
  ADC #$10
  RTS
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Well, in the simulator you have two options:
1. Use the BRK opcode to tell the simulator the program should end;
2. Make an infinite loop as Disch said;

The first option is cleaner for testing purposes, but option 2 is more realistic when it comes to game programming. A game is usually divided in parts, wich are usually loops, that jump to each other and will never leak to the subroutines. There is for example, the title screen loop, the character selection loop, the main engine loop, etc. Since they are all loops, the program will never get out of these loops unless you explicitally tell it to (by calling the subroutines, for example).

As for the stack, it is used to store the returning address of the subroutine. From your code, I can see you understand the concept of subroutines: you jump to the routine; when it's finished you jump BACK. But where exactly is "back"? The processor knows where to return to because it stored the return address when you called the subroutine. Then, when later you used RTS the CPU took that address from the stack and jumped to it, effectivelly returning to where it left off.

The stack MAY also be used for passing parameters to the routines, but that is by no means mandatory. In your code, you stored the numbers in a specific location. Then the subroutine read those numbers and added them, that works just fine. But sometimes you may have recursive subroutines, where you call a subroutine from inside itself. Then you can't use absolute variable locations anymore, since that will destroy previously calculated values as you go deeper and deeper in the function. Thus, you use the stack to pass the parameters and they will never be overwritten (actually not "never", they will if you go over the stack limit). This is how functions work in high level languages. If you have never heard about that before don't worry, you aren't likely to need it anyway. =) But if you're interested, just ask more!
Roth
Posts: 401
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Post by Roth »

Thanks for the responses guys. It's given me some stuff to think about and work with. After Disch posted the tip about looping, I started actually realizing how many loops are in various game sources. It made me wonder how I should break out of a loop, so I just started working with branching. My first test on it when really well, and came out exactly like I thought it would when entering the code in.

Code: Select all

	.ORG $8000
	
	LDX #$02

	STX $01
	
testit:
	DEX
	BEQ testmore
	JMP testit
	
skipthis:            
	LDA #$50 
	STA $30
	
testmore:
	LDY #$30
	STY $10
	BRK
Just a Branch On Zero... a simple test, but it worked like I wanted it too :) I'm going to start learning more of these branching techniques and figure out how to manipulate all these commands... should be frustratingly fun :P

Thanks for the insight on the BRK command with the simulator Tokumaru! That really helps alot being able to halt the program in various places so I can check out what's going on with the flags and the like. You guys have been really helpful just with those two posts. I still have ALOT to experiment with (the entire language :P ), but now I don't feel as frustrated... funny how the most simple things can make something pop in your mind and you look differently at something. Thanks tons guys!
Post Reply