EmbeddedRelated.com
Forums
Memfault Beyond the Launch

RTS problem

Started by nimish_sudan November 21, 2004

Hey guys, back again with another problem. I have the following
program:
BEGIN_PROG ...
JMP NON_WORKING_LOOP
...
...
...
NON_WORKING_LOOP PSHA
PSHB
...
JSR NON_WORKING_SR
...
NON_WORKING_SR ...
BEQ EXIT_LOOP
RTS

EXIT_LOOP PULB
PULA
*JMP WORKING_LOOP ;This point is successfully reached(checked)
RTS ;Problem is here

WORKING_LOOP ... As you can see, in the beginning of my program, I'm jumping to a loop
(NON_WORKING_LOOP) where is save the stack and then jump to another
subroutine(NON_WORKING_SR). This SR has a condition BEQ to
EXIT_LOOP, otherwise RTS. The problem I'm having(atleast I think
this is where the problem occurs) is that when I BEQ to EXIT_LOOP,
the RTS in EXIT_LOOP actually returns to NON_WORKING_LOOP rather
than BEGIN_PROG(where I thought it should go). Everything in the
code works because I've tested it with a JMP WORKING_LOOP statement
which is executted successfully. So my question is: Is that what is
really going on? Is the RTS from EXIT_LOOP returning to
NON_WORKING_LOOP? Or am I doing something else wrong? Here is what I
thought is going on:
BEGIN_PROG-->NON_WORKING_LOOP-->NON_WORKING_SR--/->NON_WORKING_LOOP
\->EXIT_LOOP---------
--->BEGIN_PROG

Any ideas on this would be appreciated!
Thanks!




I think the rule is: if you push n bytes then call a jsr, the jsr must rts,
then the caller must pull n bytes. One must NEVER jump out of a subroutine
with items on the stack.... unless you are writing a 'kernel' or 'task switcher'
or 'coroutines' or other comp-sci. The stack must grow and shrink
symmetrically




There are actually two things going on, and show that
you've missed the fundamental operation of the JSR/RTS
pair.

When you JSR, the 68hc11 pushes the address of the -next-
instruction (the one immediately following the JSR line)
onto the stack. That's two bytes. This is called the
"return address", since it's where you'll return to.

Then, in the subroutine, you can do anything you want
with the stack (push,pull)... but when you arrive at an
RTS instruction, the stack had better be back to where
it was at the start, so that it's pointing at those two
bytes pushed by the JSR. What the RTS -does- (pure and
simple) is pull the stack's contents into the Program Counter,
(PC) and that's it. The 68hc11 then uses the PC to fetch
the next instruction it should execute.
Since the JSR put the address of the line following the
JSR onto the stack, and the RTS pulled that address back
into the PC, then the next instruction which will execute
will be the one following the JSR.

It's perfectly legal (but usually bad practice) to push
something onto the stack before doing the JSR, and have
the subroutine -reference- it. (not PUL, but merely
look at it). Then, when you return from the subroutine,
you can pop it to restore the stack to its original state.

The buggy program example has two faults:
(a) depending upon the path at the BEQ EXIT_LOOP
you may or may not do that PUL. (so the stack condition
would be messed up on one brach, but not the other. Life
in the calling program would therefore become confused)
(b) your PUL grabbed one of the JSR'd address bytes, NOT
the register you pushed on the stack before the JSR.

Advanced programmers sometimes -do- intentionally mess
up the stack, but they will take additional steps to
handle the situation. One example would be, in the
subroutine, to PULY the "return address" into the Y register,
do whatever fiddles the subroutine needed to do, and then
(instead of an RTS), do a JMP 0,Y as the "return".

have fun
--dick
--- In , "nimish_sudan" <nimish_sudan@y...> wrote:
>
> Hey guys, back again with another problem. I have the following
> program:
> BEGIN_PROG ...
> JMP NON_WORKING_LOOP
> ...
> ...
> ...
> NON_WORKING_LOOP PSHA
> PSHB
> ...
> JSR NON_WORKING_SR
> ...
> NON_WORKING_SR ...
> BEQ EXIT_LOOP
> RTS
>
> EXIT_LOOP PULB
> PULA
> *JMP WORKING_LOOP ;This point is successfully reached(checked)
> RTS ;Problem is here
>
> WORKING_LOOP ... > As you can see, in the beginning of my program, I'm jumping to a loop
> (NON_WORKING_LOOP) where is save the stack and then jump to another
> subroutine(NON_WORKING_SR). This SR has a condition BEQ to
> EXIT_LOOP, otherwise RTS. The problem I'm having(atleast I think
> this is where the problem occurs) is that when I BEQ to EXIT_LOOP,
> the RTS in EXIT_LOOP actually returns to NON_WORKING_LOOP rather
> than BEGIN_PROG(where I thought it should go). Everything in the
> code works because I've tested it with a JMP WORKING_LOOP statement
> which is executted successfully. So my question is: Is that what is
> really going on? Is the RTS from EXIT_LOOP returning to
> NON_WORKING_LOOP? Or am I doing something else wrong? Here is what I
> thought is going on:
> BEGIN_PROG-->NON_WORKING_LOOP-->NON_WORKING_SR--/->NON_WORKING_LOOP
> \->EXIT_LOOP---------
> --->BEGIN_PROG
>
> Any ideas on this would be appreciated!
> Thanks!



At 2004-11-21 19:09, wrote:
>I think the rule is: if you push n bytes then call a jsr, the jsr must rts,
>then the caller must pull n bytes. One must NEVER jump out of a subroutine
>with items on the stack.... unless you are writing a 'kernel' or 'task switcher'
>or 'coroutines' or other comp-sci. The stack must grow and shrink
>symmetrically

People that don't understand things like these
shouldn't program in assembler but should program
in a language like C which will take care of these
things.

By the way, nobody should have to program in
assembler anymore (unless for fun or to write
task switchers etc.) It's a complete waste of
human energy and especially in the case of the
6811 you can't write much more effective code
than a good compiler can (perhaps you can squeeze
out 30% better code, but it will be totally
unreadable) and ROM is cheap by now.

I consider writing in assembler a modern form
of torture (often self-torture unfortunately ;-). Greetings,
Jaap

-- Chip Directory
-- http://www.chipdir.biz/
-- http://www.chipdir.info/
-- http://www.chipdir.net/
-- http://www.chipdir.nl/
-- http://www.chipdir.org/
-- And about 30 other mirror sites world-wide.
--
-- To subscribe to a free 'chip issues, questions and answers'
-- mailing list, send a message to with
-- in the body 'subscribe chipdir-L'. About 500 experts are
-- willing to think with you about electronics problems etc.


----- Original Message -----
From: "Jaap van Ganswijk" <>
To: <>
Sent: Tuesday, November 23, 2004 10:09 AM
Subject: Re: [m68HC11] RTS problem > At 2004-11-21 19:09, wrote:
> >I think the rule is: if you push n bytes then call a jsr, the jsr must rts,
> >then the caller must pull n bytes. One must NEVER jump out of a subroutine
> >with items on the stack.... unless you are writing a 'kernel' or 'task
switcher'
> >or 'coroutines' or other comp-sci. The stack must grow and shrink
> >symmetrically
>
> People that don't understand things like these
> shouldn't program in assembler but should program
> in a language like C which will take care of these
> things.

I'd go further and say people who don't understand such things should not
program at all until they learn some more about how CPUs work. The notion that
programming in a higher-level language is OK without sufficient knowledge of the
underlying CPU is, to me at least, mistaken. Programming, no matter what the
language, is still based on a machine, and a programmer must know how that
machine works.

> By the way, nobody should have to program in
> assembler anymore (unless for fun or to write
> task switchers etc.) It's a complete waste of
> human energy and especially in the case of the
> 6811 you can't write much more effective code
> than a good compiler can (perhaps you can squeeze
> out 30% better code, but it will be totally
> unreadable) and ROM is cheap by now.

Although most will probably agree with you I think your opinion is subjective.
I think it's like driving. Some truck drivers, for example, may find it easier
to drive their trucks than their family car because they're on their truck's
wheel most of their lives and have acquired a 'natural' feel for that vehicle.

Similar with assembly language. If you've been programming in assembly a great
deal more than, say, in C, it actually IS easier to program in assembly language
because you think the solution directly in terms of *that* language. On the
other hand, if you've been programming mostly in C (or other higher-level
language), when you get to program in assembly you natually first think in C and
try to mentally translate the code to assembly. And that doesn't work very well
so it gives the (I believe) misleading impression that assembly programming is
harder.

> I consider writing in assembler a modern form
> of torture (often self-torture unfortunately ;-).

I understand you completely. I feel the same about C when it comes to
microcontrollers.

> Greetings,
> Jaap




I would have to agree with you Tony. When I write the few programs that I do write, for a microcontroller, I always write them in assembly. Just as you said, it's just natural. I once took a look at some C-code and I simply could not figure it out! To me, it wasn't intuitive such as Assembly and Visual Basic are; it didn't "Flow". I am attempting to learn Assembly for X86 processors, yes, your PC. I have been told that it is more efficient than using Visual Basic. This should be interesting. Just my thoughts.

Salute!

LF

Tony Papadimitriou <> wrote:

----- Original Message -----
From: "Jaap van Ganswijk"
To:
Sent: Tuesday, November 23, 2004 10:09 AM
Subject: Re: [m68HC11] RTS problem > At 2004-11-21 19:09, wrote:
> >I think the rule is: if you push n bytes then call a jsr, the jsr must rts,
> >then the caller must pull n bytes. One must NEVER jump out of a subroutine
> >with items on the stack.... unless you are writing a 'kernel' or 'task
switcher'
> >or 'coroutines' or other comp-sci. The stack must grow and shrink
> >symmetrically
>
> People that don't understand things like these
> shouldn't program in assembler but should program
> in a language like C which will take care of these
> things.

I'd go further and say people who don't understand such things should not
program at all until they learn some more about how CPUs work. The notion that
programming in a higher-level language is OK without sufficient knowledge of the
underlying CPU is, to me at least, mistaken. Programming, no matter what the
language, is still based on a machine, and a programmer must know how that
machine works.

> By the way, nobody should have to program in
> assembler anymore (unless for fun or to write
> task switchers etc.) It's a complete waste of
> human energy and especially in the case of the
> 6811 you can't write much more effective code
> than a good compiler can (perhaps you can squeeze
> out 30% better code, but it will be totally
> unreadable) and ROM is cheap by now.

Although most will probably agree with you I think your opinion is subjective.
I think it's like driving. Some truck drivers, for example, may find it easier
to drive their trucks than their family car because they're on their truck's
wheel most of their lives and have acquired a 'natural' feel for that vehicle.

Similar with assembly language. If you've been programming in assembly a great
deal more than, say, in C, it actually IS easier to program in assembly language
because you think the solution directly in terms of *that* language. On the
other hand, if you've been programming mostly in C (or other higher-level
language), when you get to program in assembly you natually first think in C and
try to mentally translate the code to assembly. And that doesn't work very well
so it gives the (I believe) misleading impression that assembly programming is
harder.

> I consider writing in assembler a modern form
> of torture (often self-torture unfortunately ;-).

I understand you completely. I feel the same about C when it comes to
microcontrollers.

> Greetings,
> Jaap

Yahoo! Groups Links
---------------------------------



On Wed, 2004-11-24 at 02:36, bart homerson wrote:
> I would have to agree with you Tony. When I write the few programs that
> I do write, for a microcontroller, I always write them in assembly.

My sentiments entirely.

> I am attempting to learn Assembly for X86 processors, yes, your PC. I
> have been told that it is more efficient than using Visual Basic. This
> should be interesting. Just my thoughts.

Again, you would be in good company FWIW, that of the few people who
*actually* know how PCs work, viz. Steve Gibson.

I had to chuckle where a previous critique stated:

> It's perfectly legal (but usually bad practice) to push something onto
> the stack before doing the JSR, and have the subroutine reference it.

... as this is of course, *exactly* how C, Pascal and such function. It
went on to say:

> Advanced programmers sometimes -do- intentionally mess up the stack,
> but they will take additional steps to handle the situation.

... such as, by using such a language.

However, I wonder whether (many of) those who malign the use of
assembler, understand or recognise the distinction between "raw" and
*macro* assembler, which latter is I hope, our point of reference and
the use of which begins to resemble "C"?

--
Cheers,
Paul B.




--- In , "Tony Papadimitriou" <tonyp@m...>
wrote:
>> I consider writing in assembler a modern form
>> of torture (often self-torture unfortunately ;-).

> I understand you completely. I feel the same about C when it comes
> to microcontrollers.

Ahh, the classic "C vs. asm" argument that tends to pop up in groups
like this periodically.

FWIW, my own personal preference is to do smaller and/or more cost-
critical, resource-constrained applications in assembly language.
Even the best C compiler cannot produce code to match expertly hand-
optimized assembly code.

Some C-only proponents often use as an argument that asm is cryptic,
whereas C tends to be more "self documenting". I could not DISAGREE
more. The sad tendency of your typical C programmer to write gawd-
awful constructs like this:

if (ch=getch()=='\n') {

drives me nuts. And this is just a simple example (intended to be
comprehensible while still making my point) of much more complex
assignments-within-expressions-within-evaluations that I see all too
often in "professionally developed" C source.

When I write programs in C, I try to avoid complex expressions, or at
least break them up into multiple lines, assembly-language-style.

Ok, I'm ranting here, so let me get to my point: I am of the opinion
that the language is not as important as is the style in which one
writes code in any language. A properly commented, intelligently
structured C program can be a joy to behold - just as a properly
aligned, well structured assembly program with good label/variable
names can be. Organization, clarity, and consistency in style are
the keys to readability in ANY language.

One last comment on C in embedded/microcontroller systems - one of
the things I dislike most about your typical C compiler is the
complex (and usually poorly documented) procedure one has to figure
out to get the various memory regions and areas, or even individual
variables, mapped to where you want them to go. The C language
standard does not do a good job of allowing one to attach attributes
to variables indicating where in memory they should go. This task
usually falls to the linker, and of course there is no standard for
linker control 'languages' which means that it differs for every
compiler. This issue has been the single greatest obstacle that I've
encountered in my attempts to utilize the GNU HC11/12 toolset for my
own projects based on these parts.

-- Mark




--- In , "Paul B. Webster" <paulb@m...> wrote:
> ...
> However, I wonder whether (many of) those who malign the use of
> assembler, understand or recognise the distinction between "raw" and
> *macro* assembler, which latter is I hope, our point of reference
> and the use of which begins to resemble "C"?

Yes, macros can be awfully handy in a asm environment, as as Paul
implies, can go a long way to making asm source more 'readable' - not
to mention much easier to 'retarget' if the hardware changes.

It is regrettable that Tony P's otherwise outstanding ASM11 does not
have any support for user-defined macros (hint, hint ;)

-- Mark


> FWIW, my own personal preference is to do smaller and/or more cost-
> critical, resource-constrained applications in assembly language.
> Even the best C compiler cannot produce code to match expertly hand-
> optimized assembly code.

Quite true. Over the years the technique I've found most useful is to keep
asm routines small and C-callable (and before C, FORTRAN callable). By
making them C-callable, 1) I can use a quick 'n dirty C mainline to test
them, 2) it forces a uniform organization for passing arguments, stack
useage, and saving registers (which saves
frustration/self-cursing/sanity/...).

Also, whenever I start to write an asm routine I find there is a temptation to
keeping add more to the routine, which can lead to a monstrosity that is
difficult to debug/test, and has limited reusability.

Regards,

Donald E Haselwood




Memfault Beyond the Launch