Forums

subroutine problem

Started by bal_gill21 November 13, 2004

Hi,
I have a main program that is calling subroutines, however when it
has finished with the subroutine I issue the RTS command. In some of
my program it works absolutly fine and other times it just returns to
a random address. I have then issued a JMP (followed by appropriate
address)at the end of my subroutine to return to the main program and
it works fine. It becomes a problem when a subroutine calls another
subroutine, because then I really need a RTS command. I am using a
development kit for this to single step the code and I just cannot
work out why this is happening.

thanks

Bal




In addition, verify that you are maintaining stack integrity with paired
pushes and pops in your subroutine.

Bill

At 11:03 AM 11/13/2004, you wrote:

>First things first. You have got to remove any and all JMP instructions
>at the end of subroutines. If you attempt to do this it may seem to
>work, but it will leave the stack pointing to garbage. Your symptom of
>having problems with nested subroutines is a good way to see this: when
>the inner subroutine exits the stack will no longer be pointing to the
>return address of the outer when it exits, so you will be exiting to the
>wring place.
>
>Cardinal rule: never leave a subroutine using a JMP.
>
>When you have fixed this, try the program again and see what happens.
>If it is still playing up, you need to made sure the stack has enought
>space for all the levels of nesting that you are using.
>
>Regards,
>Nigel >
>bal_gill21 wrote:
>
> >Hi,
> >I have a main program that is calling subroutines, however when it
> >has finished with the subroutine I issue the RTS command. In some of
> >my program it works absolutly fine and other times it just returns to
> >a random address. I have then issued a JMP (followed by appropriate
> >address)at the end of my subroutine to return to the main program and
> >it works fine. It becomes a problem when a subroutine calls another
> >subroutine, because then I really need a RTS command. I am using a
> >development kit for this to single step the code and I just cannot
> >work out why this is happening.
> >
> >thanks
> >
> >Bal
> >
> >
> >
> >
> >
> >
> >
> >Yahoo! Groups Links
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >--
>Nigel Johnson
>MCSE, MIEEE
>VE3ID/G4AJQ
>
>If time travel ever will be possible, it already is. Ask me again yesterday >
>Yahoo! Groups Links >
>




Either you did not allow enough space for your stack, or some part of your program is writing in the stack RAM

Dave

>
> From: "bal_gill21" <>
> Date: 2004/11/13 Sat AM 11:40:59 EST
> To:
> Subject: [m68HC11] subroutine problem >
> Hi,
> I have a main program that is calling subroutines, however when it
> has finished with the subroutine I issue the RTS command. In some of
> my program it works absolutly fine and other times it just returns to
> a random address. I have then issued a JMP (followed by appropriate
> address)at the end of my subroutine to return to the main program and
> it works fine. It becomes a problem when a subroutine calls another
> subroutine, because then I really need a RTS command. I am using a
> development kit for this to single step the code and I just cannot
> work out why this is happening.
>
> thanks
>
> Bal >
>
> Yahoo! Groups Links




The debugging technique for this kind of problem is to check the stach
contents on entry to the subroutine and then just before the RTS. any
difference in address is a push, pop or BSR misuse. if the current stack
address is the same, but the contents are different you will need to
step through the subroutine (or any other potentially concurrent routine
or interrupt for that matter) to see what is corrupting the return
address in the stack.

Jim

bal_gill21 wrote:

>Hi,
>I have a main program that is calling subroutines, however when it
>has finished with the subroutine I issue the RTS command. In some of
>my program it works absolutly fine and other times it just returns to
>a random address. I have then issued a JMP (followed by appropriate
>address)at the end of my subroutine to return to the main program and
>it works fine. It becomes a problem when a subroutine calls another
>subroutine, because then I really need a RTS command. I am using a
>development kit for this to single step the code and I just cannot
>work out why this is happening.
>
>thanks
>
>Bal >
>
>Yahoo! Groups Links >
>





--- In , "bal_gill21" <bal_gill21@y...> wrote:

> I have a main program that is calling subroutines, however when
> it has finished with the subroutine I issue the RTS command. In
> some of my program it works absolutly fine and other times it just
> returns to a random address.

The advice given by both Nigel and William is valid, make sure you
follow it!

If you are using a monitor program (such as BUFFALO) or a bootstrap-
mode debugger (such as PCBug or JBug11), the stack pointer will be
pre-initialized to a location where there are at least a few bytes
available for (nested) subroutine calls. However, the stack space
available - esp. if using PCBug/JBug - is VERY limited! Several
levels of nested subroutines might be enough to cause PCBug/JBug to
fail, since the values (return addresses) getting pushed onto the
stack might wind up corrupting the RAM-based 'talker' that these
programs use.

If you are using a E-series device, or are working on a target
platform that has external RAM, you would be better off initializing
the stack pointer explicitly to a location where plenty of free RAM
is available. On a E-series device with no external RAM, setting
the stack pointer to $01FF would be advisable. If, for example, you
have RAM mapped at locations $8000-$9FFF, set the stack pointer to,
say, $80FF (and use RAM at $8100+ for variables and other data
storage). This will give you a comfortably large 256 bytes of stack
space.

FYI, a subroutine call (each nesting level) consumes a minimum of 2
bytes of stack space, plus whatever values are getting PSH'd inside
the subroutine itself. A interrupt service consumes 9 bytes (2 for
return address, 6 for registers, 1 for the status word). Monitor
programs such as Buffalo, PCBug and JBug utilize interrupt
processing to support breakpoints and single-stepping, so at least 9
bytes of your stack will be consumed no matter what else you do in
your program.

You can change the value of the stack pointer register in your
program using the LDS instruction; e.g.:

Stack EQU $01FF ;Stack at end of E-series RAM
...
Start LDS #Stack ;Initialize stack pointer

You will HAVE to initialize the stack pointer to a valid RAM
location/region if you intend on running your program in
a 'standalone' mode, without the aid of a monitor program. The HC11
does NOT initialize the stack pointer when it is reset! The value
in the stack pointer register will be random following a RESET.



Thanks for everyones sound advice. I have single stepped the code and
discovered that the program is going wrong in the following area:

cmpb #$64 ;compare a/d with 100 decimal
bhs devThre ;if a/d is >0 jump to 'devThre'
cmpb #$A ;compare a/d with 10 decimal
bhi devTwo ;if a/d is >10 jump to 'devTwo'

I am branching to an appropriate subroutine follwing the certain
conditions. As it happens this is happening before any JSR
instructions in the rest of the program, so I assume the stack is not
reaching its capacity. Would I need to branch to a seperate part of
my program and then use the JSR instruction to go to the subroutine,
because it is obviously not recording on the stack where it has come
from in the main program with the branch instructions.

Thanks

Bal




> -----Original Message-----
> From: bal_gill21 [mailto:]
> Sent: Sunday, November 14, 2004 5:23 AM
> To:
> Subject: [m68HC11] Re: subroutine problem >
> Thanks for everyones sound advice. I have single stepped the code and
> discovered that the program is going wrong in the following area:
>
> cmpb #$64 ;compare a/d with 100 decimal
> bhs devThre ;if a/d is >0 jump to 'devThre'

So if this condition is true, the processor goes to devThree.
This is NOT a SUBROUTINE call, it is an absolute GOTO.

I'd use the opposite logic...

Test and skip if LESS than 100,
Else (GTE), BSR or JSR to your service subroutine. > cmpb #$A ;compare a/d with 10 decimal
> bhi devTwo ;if a/d is >10 jump to 'devTwo'
>
> I am branching to an appropriate subroutine follwing the certain
> conditions. As it happens this is happening before any JSR
> instructions in the rest of the program, so I assume the stack is not
> reaching its capacity. Would I need to branch to a seperate part of
> my program and then use the JSR instruction to go to the subroutine,
> because it is obviously not recording on the stack where it has come
> from in the main program with the branch instructions.
>
> Thanks
>
> Bal
>
*
| __O Thomas C. Sefranek
|_-\<,_ Amateur Radio Operator: WA1RHP
(*)/ (*) Bicycle mobile on 145.41, PL 74.4

http://hamradio.cmcorp.com/inventory/Inventory.html
http://www.harvardrepeater.org



--- In , "bal_gill21" <bal_gill21@y...> wrote:
>
> Thanks for everyones sound advice. I have single stepped the code
> and discovered that the program is going wrong in the following
> area:
>
> cmpb #$64 ;compare a/d with 100 decimal
> bhs devThre ;if a/d is >0 jump to 'devThre'
> cmpb #$A ;compare a/d with 10 decimal
> bhi devTwo ;if a/d is >10 jump to 'devTwo'

Ahh, the problem (and solution) now become clear!

The conditional branch instructions, such as BHS and BHI used above,
are *NOT* subroutine calls! They work like the relative (BRA) and
absolute (JMP) instructions - they are GOTOs. These instructions do
not save a return address on the stack.

The HC11 does not, alas, provide any conditional subroutine call
instructions. The only instructions that truly act as subroutine
calls are BSR (relative) and JSR (absolute).

You could rewrite your program as shown below to achieve the desired
result:

CMPA #100 ;Check ADC return value
BLO NoDev3 ;If >= 100:
BSR DevThre ; Handle >= 100 case
BRA Next ; Skip over >10 check
NoDev3 CMPA #10 ;Check ADC value again
BLS NoDev2 ;If > 10:
BSR DevTwo ; Handle > 10 case
BRA Next ; Skip over additional checks
NoDev2 ... ;Do more checks if needed

Next ... ;Continuation point

If you actually wish to perform the >10 check after the subroutine
for the >0 check is called, remove the "BRA Next" line(s). You
will need to ensure that the subroutine(s) you call preserve the
value in the A register if this is the case. Use PSHA near the
start of your subroutine to save the value in A, and use PULA just
before the subroutine RTS to restore it.

Note how the use of "reverse logic" branches were used to acheive
the desired result. BLO is the logical inverse of BHS, and BLS is
the logical inverse of BHI. Other complimentary pairs include:
BLT/BGE, BLE/BGT, BEQ/BNE, BCS/BCC, BMI/BPL, and BVC/BVS.

Keep on plugging away at it, it will eventually start to fall into
place.

-- Mark


As other have noted the proble is "clear" (to the experienced eye that
is). I don't think anyone actually stated that the only correct calls to
a subroutine are BSR and JSR. Under no circumstances should you Branch
or JMP to a piece of code that ends in RTS unless you expect that to be
the return from the currently called subroutine. I suspect the stack
size issue is still present. The key phrase in your discussion was "I am
branching to an appropriate subroutine..." We therefore assume that
DevThre and DevTwo are labels with a sequence of instructions that end
in RTS.

Worth noting is the fact that a program is a "holistic" mechanism.
snippets of logic may appear coherent, but fail due to the way they are
invoked or implemented. These kinds of details are usually expressed in
some form of "software design". many of the most confusing problems stem
from failing to establish a clear design but instead just begin
programming in the hope that eventually a sequence of instructions that
works will occur.

In the kindest and most constructive way I can, I suggest you read the
HC11 instruction reference for each instructions you are using. Be sure
you understand the condition code set by each, and the instruction
relationships {such as BSR JSR to RTS vs BRA and JMP). also, do a searh
in the reference for the instruction you are about to use to find usage
examples there. Those examples are at least generally accepted as good
practice.

Good luck, and hang in there.
Jim

bal_gill21 wrote:

>Thanks for everyones sound advice. I have single stepped the code and
>discovered that the program is going wrong in the following area:
>
>cmpb #$64 ;compare a/d with 100 decimal
>bhs devThre ;if a/d is >0 jump to 'devThre'
>cmpb #$A ;compare a/d with 10 decimal
>bhi devTwo ;if a/d is >10 jump to 'devTwo'
>
>I am branching to an appropriate subroutine follwing the certain
>conditions. As it happens this is happening before any JSR
>instructions in the rest of the program, so I assume the stack is not
>reaching its capacity. Would I need to branch to a seperate part of
>my program and then use the JSR instruction to go to the subroutine,
>because it is obviously not recording on the stack where it has come
>from in the main program with the branch instructions.
>
>Thanks
>
>Bal >
>
>Yahoo! Groups Links >
>