program calling with BS2sx, BS2e, BS2p
Hi Peter,
You've really been burning the midnight oil on this program!
There still seems to be an awful lot of machinery. For example, it
looks like it takes 8 instructions at the top of a bank just to parse
a return address. I'm still skeptical about the need for all the
different variables.
I do use cross bank calls in my own BS2e programs. Please bear with
me as I lay out my own approach. I too have given the issue a lot of
thought.
I'm happy with a single level stack, and also with a single byte for
the return vector. The bank number is in the low nib and the target
ID in the high nib. As you aptly observed, that does indeed limit it
to only 16 return points in each bank.
Honestly, I think I would go crazy if I had a program with more
return points than that. Having only 16 makes me work hard to
optimize code and preplan to keep the (inefficient) crossbank calls
to a minimum. Having only a single level "stack" means that there is
no stack pointer math, which simplifies things considerably. (Is
that "turning shortcomings into features", or what?!) KISS.
{Do you have an equivalent expression in Dutch--KISS="Keep It
Simple,Stupid". If KISS does not work, we turn to "Things should be
as simple as possible, but no simpler" (attr:A.Einstein)}
One advantage of single byte target IDs is that they can be
conveniently named as HEX constants in the program header, for
example:
XWindAverageDriver con $14 ' routine 1 in bank 4
Xbackhere con $31 ' return target 3 in bank 1
Xinitialization con $00 ' routine 0 in bank 0 (reset vector)
To run a routine, my program does the following:
PUT stack,Xbackhere ' stack the return vector =$31
sxgo=XWindAverageDriver ' ID of the target, $14 in this example
RUN sxgo ' do it
backhere: ' will return here
The RUN command ignores everything but the low three bits of the $14
target, so it happily RUNS the program in Bank 4. At the top of bank
4, I have a BRANCH as the first instruction:
BRANCH sxgo.nib1,[noparse][[/noparse]routine0,windAverageDriver,routine2, etc...]
..where in this case windAverageDriver will run, because,
sxgo.nib1=1. Note the distinction between XwindAverageDriver, with an
"X" prefix, the index vector, and windAverageDriver, the actual
address that the index vector refers to.
That one BRANCH command is the only machinery necessary at the top of a bank.
At the end of the target routine, the program pops the return vector
off the stack and simply RUNs it:
GET stack,sxgo ' sxgo=$31 from above
RUN sxgo ' the return vector to bank 1
Once back in bank 1, it first hits another BRANCH command, and in
this example sxgo.nib1=3:
BRANCH sxgo.nib1,[noparse][[/noparse]routine0,routine1,routine2,backhere, ...]
which takes the program execution back to the point "backhere" where
it left off before the crossbank call.
When the computer is reset, the variable sxgo is initialized to zero,
which branches to routine 0 in bank 0, which is my reset routine.
The crossbank machinery is compact and oiled for speed, but it is
still takes two milliseconds of overhead for each crossbank
execution. The RUN command itself takes over 800 microseconds on the
BS2e. Even such as it is, it is difficult to explain how the
crossbank stuff works, and it takes a lot of advance planning to
implement it. We love our stamps anyway!
----
Peter, I appreciate that you are building a deeper return stack.
Keep up the good work! Maybe the above can help in your code
optimization. The real test is how it works with the applications
you need to implement!
-- regards,
Tracy Allen
electronically monitored ecosystems
mailto:tracy@e...
http://www.emesystems.com/BS2index.htm
You've really been burning the midnight oil on this program!
There still seems to be an awful lot of machinery. For example, it
looks like it takes 8 instructions at the top of a bank just to parse
a return address. I'm still skeptical about the need for all the
different variables.
I do use cross bank calls in my own BS2e programs. Please bear with
me as I lay out my own approach. I too have given the issue a lot of
thought.
I'm happy with a single level stack, and also with a single byte for
the return vector. The bank number is in the low nib and the target
ID in the high nib. As you aptly observed, that does indeed limit it
to only 16 return points in each bank.
Honestly, I think I would go crazy if I had a program with more
return points than that. Having only 16 makes me work hard to
optimize code and preplan to keep the (inefficient) crossbank calls
to a minimum. Having only a single level "stack" means that there is
no stack pointer math, which simplifies things considerably. (Is
that "turning shortcomings into features", or what?!) KISS.
{Do you have an equivalent expression in Dutch--KISS="Keep It
Simple,Stupid". If KISS does not work, we turn to "Things should be
as simple as possible, but no simpler" (attr:A.Einstein)}
One advantage of single byte target IDs is that they can be
conveniently named as HEX constants in the program header, for
example:
XWindAverageDriver con $14 ' routine 1 in bank 4
Xbackhere con $31 ' return target 3 in bank 1
Xinitialization con $00 ' routine 0 in bank 0 (reset vector)
To run a routine, my program does the following:
PUT stack,Xbackhere ' stack the return vector =$31
sxgo=XWindAverageDriver ' ID of the target, $14 in this example
RUN sxgo ' do it
backhere: ' will return here
The RUN command ignores everything but the low three bits of the $14
target, so it happily RUNS the program in Bank 4. At the top of bank
4, I have a BRANCH as the first instruction:
BRANCH sxgo.nib1,[noparse][[/noparse]routine0,windAverageDriver,routine2, etc...]
..where in this case windAverageDriver will run, because,
sxgo.nib1=1. Note the distinction between XwindAverageDriver, with an
"X" prefix, the index vector, and windAverageDriver, the actual
address that the index vector refers to.
That one BRANCH command is the only machinery necessary at the top of a bank.
At the end of the target routine, the program pops the return vector
off the stack and simply RUNs it:
GET stack,sxgo ' sxgo=$31 from above
RUN sxgo ' the return vector to bank 1
Once back in bank 1, it first hits another BRANCH command, and in
this example sxgo.nib1=3:
BRANCH sxgo.nib1,[noparse][[/noparse]routine0,routine1,routine2,backhere, ...]
which takes the program execution back to the point "backhere" where
it left off before the crossbank call.
When the computer is reset, the variable sxgo is initialized to zero,
which branches to routine 0 in bank 0, which is my reset routine.
The crossbank machinery is compact and oiled for speed, but it is
still takes two milliseconds of overhead for each crossbank
execution. The RUN command itself takes over 800 microseconds on the
BS2e. Even such as it is, it is difficult to explain how the
crossbank stuff works, and it takes a lot of advance planning to
implement it. We love our stamps anyway!
----
Peter, I appreciate that you are building a deeper return stack.
Keep up the good work! Maybe the above can help in your code
optimization. The real test is how it works with the applications
you need to implement!
-- regards,
Tracy Allen
electronically monitored ecosystems
mailto:tracy@e...
http://www.emesystems.com/BS2index.htm