▼
Posts: 189
Threads: 39
Joined: Nov 2011
Here are some random wish list items that I would love to see on the 43S. (Actually, I would love to see them on the 34S, but I believe that that ship has already sailed).
1) An instruction (e.g. RepI) which replaces the contents of register X with whatever X is pointing to, without impacting the rest of the stack. This would make writing routines that use indirect addressing a little less clunky.
2) While performing simple calculations, I often want to enter an integer hex value without leaving decimal mode. I would love to have a super easy way to do that. (And no, I do not care about all the other bases. If you do, you can write your own wish list ;)
3) On the 34S, a function call can access its parent's local registers only if the that function call did not allocate any locally registers itself. Getting rid of this restriction would make it easier for functions to be good citizens and not use global registers. That in turn make it easier to write a true library of routines that don't have global register depedencies, yet operate on more complex data sets than can be passed on the stack.
4) Having a way to view the current SRS (subroutine return stack in 34s terminology), as one can registers, would be very useful for debugging user routines.
5) I like the idea of CAT on the 34s, but it is cluttered with lables and end statements, and all I really want to see is the list of user programs which isn't necessarily the same thing as the list of global labels. Maybe there should be different classes of LBL statements which don't have different functionality but do allow more intelligent filtering of labels to display in the catalog.
▼
Posts: 3,229
Threads: 42
Joined: Jul 2006
Quote: 1) An instruction (e.g. RepI) which replaces the contents of register X with whatever X is pointing to, without impacting the rest of the stack. This would make writing routines that use indirect addressing a little less clunky.
Why not add a library routine to do this:
LBL'REP'
STO L
DROP
RCL-> L
RTN
This is almost as good as a built in instruction. If you don't want X preserved in L, as a built in command would do, allocate and use a local register instead.
Quote: 3) On the 34S, a function call can access its parent's local registers only if the that function call did not allocate any locally registers itself. Getting rid of this restriction would make it easier for functions to be good citizens and not use global registers. That in turn make it easier to write a true library of routines that don't have global register depedencies, yet operate on more complex data sets than can be passed on the stack.
How would this operation be defined? A whole new suite of commands for accessing up the local variable stack?
We could allow local registers of greater number than the current frame has to keep searching. I'm not convinced this is a good idea due to the problems it could introduce. Named locals would fix the locating of the variable but might introduce other issues.
Quote: 5) I like the idea of CAT on the 34s, but it is cluttered with lables and end statements, and all I really want to see is the list of user programs which isn't necessarily the same thing as the list of global labels. Maybe there should be different classes of LBL statements which don't have different functionality but do allow more intelligent filtering of labels to display in the catalog.
Isn't this exactly what local (numeric & A-D) labels are for?
- Pauli
▼
Posts: 189
Threads: 39
Joined: Nov 2011
Quote:
Why not add a library routine to do this:
LBL'REP'
STO L
DROP
RCL-> L
RTN
This is almost as good as a built in instruction. If you don't want X preserved in L, as a built in command would do, allocate and use a local register instead.
It is just as good as a built in instruction, except for the performance issue. Having one built in instruction versus several instructions and a subroutine call is not a good trade in that regard.
The reason RPN works so well for general computation is that one can do a long sequence of calculation without housekeeping. Operands get pushed on the stack, operations consume them and push new results on, ready for the next operation. When you start using indirect addressing where the pointer is on the stack, this model gets broken because the operation of "fetching the operand" does not consume its parameter like other operations do and it is up to you to do the housekeeping to clean up the stack.
Yes, it can be handled with existing instructions, but I propose that if there was some mechanism where indirect operands on the stack did not leave fodder that had to be cleaned up, it would be more in the spirit of the RPN paradigm.
Quote:
How would this operation be defined? A whole new suite of commands for accessing up the local variable stack?
We could allow local registers of greater number than the current frame has to keep searching. I'm not convinced this is a good idea due to the problems it could introduce. Named locals would fix the locating of the variable but might introduce other issues.
In the 34s, for example, the global address for the current local register set starts at 112. One thought I had was that every subroutine instance on the call stack gets its own unique "base". A new instruction "GetBase" would give the calling function its base. If it wanted to pass a pointer to its local registers to other functions, it would pass the local register number + its own base. This reference could be passed as far down the calling tree as you wanted and still be valid.
Quote:
Isn't this exactly what local (numeric & A-D) labels are for?
Not really because they are local to the program. In the library one can have global labels that are generally intended as top level programs - e.g. TVM program. But there are also global labels that are intended as programmer utilities: you proposed library routine of 'REP' above being one of those. My point was that as the library fills up, it might be nice to be able to categorize those in some way. Not in a way that enforces how they are used, but in a way that helps identify them. For builtin functions the creators of the calculator have categorized the functions into logical groups. Why not give the user a way to categorize the contents of their library into logical groups?
▼
Posts: 3,229
Threads: 42
Joined: Jul 2006
Quote: It is just as good as a built in instruction, except for the performance issue. Having one built in instruction versus several instructions and a subroutine call is not a good trade in that regard.
If I were to implement this function in the 34S it would be in XROM and would consist of the user code I posted above more or less. A C implementation would be much larger and flash is rather full.
Fortunately, we're discussing possibilities for the 43S but again there are an infinite number of functions possible (okay, it is actually finite but very very large) and at some point the decision will have to be made as to which to include and which to exclude.
- Pauli
Posts: 528
Threads: 40
Joined: Dec 2008
Quote:
3) On the 34S, a function call can access its parent's local registers only if the that function call did not allocate any locally registers itself. Getting rid of this restriction would make it easier for functions to be good citizens and not use global registers.
In this case, the parent's local registers can be viewed as arguments to the called function. In essence, you're asking for space to pass more arguments.
Consider setting the stack size to 8. That's a lot of parameters.
Dave
▼
Posts: 189
Threads: 39
Joined: Nov 2011
1) If I have a set of data points and library functions that operate on those data points, then 8 is often not going to be enough.
2) If you pass a bunch of data on the stack like that, there is a good chance that the library routine will need to stuff it into temporary registers so that it can operate on it. Now you have created a second copy of the data which is time consuming, required a bunch of extra instructions that were just shuffling data around and had nothing to do with the problem you are trying to solve, and used up precious memory.
So, the current approach that you can use is to stuff the data in global registers and have the calling routine tell the library routine which registers its in. As far as the library routine is concerned, that nice and tidy. No moving or duplciating of data. Just focus on the problem. However, it means that the parent routine is hard-coded to use a set of global registers and so is less likely to inter-operate with other routines that use global registers.
So, if there was a way to pass a reference to local registers to the library routines, then we could get rid of the dependency on global registers and routines could inter-operate more reliably.
The library routines shouldn't really need to care if the caller passed them a reference to a global register or a local one. Right now, on the wp-34s, that works,..... until the library routine decides to allocate local registers itself. At that point its screwed because it can no longer access the data that was passed in to it.
That's what I would like to see changed.
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
The only way I can see to implement your suggestion would be to allow addresses beyond the own local range. If you do not allocate any local registers this range starts at 112. For technical reasons, the maximum address is 255. Assume the following code:
LBL A
LocR 003
...
XEQ B
...
RTN
LBL B
LocR 008
...
RTN
If we implement the suggestion, subroutine B would have access to local registers 112 to 119 (its own block) and 120 to 122 (the block inherited from A). This is certainly doable but not trivial (as is the whole register addressing thing anyway). The main chore is proper range checking because all stack frames have to be parsed for local registers and their sizes to be summed up for the total limit. Let's see what Walter and Pauli think about such a change.
▼
Posts: 3,229
Threads: 42
Joined: Jul 2006
The 43S will support an array type. That ought to remove a lot of the need to access local variables further up the call chain.
Named variables will also alleviate the need for accessing non-local locals.
Allowing access to something else's locals is the antithesis of structured programming. Not that keystroke programs are particularly structure but let's not make things worse unnecessarily.
- Pauli
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
To Add to Pauli's comment: A short look at the current implementation has convinced me that adding such a feature to the 34S wouldn't be much fun. For the time being, shared data needs to be put in global registers. That's what they are meant for.
▼
Posts: 3,229
Threads: 42
Joined: Jul 2006
Or allocate enough local registers at the start of your library routine and use them in any subroutines. This is the purpose I see for accessing local registers of a caller.
- Pauli
▼
Posts: 4,587
Threads: 105
Joined: Jul 2005
Posts: 189
Threads: 39
Joined: Nov 2011
Here is the use case which got me thinking about this.
I've been working on a general purpose multi-dimensional minimization routine. Right now it uses tons of memory and it's mostly in global registers. I've been thinking about how to clean it up so that it would be useful as a library routine. The most obvious thought is to have it allocate all its memory as local registers as you say.
However, to use it, the user writes a subroutine that evaluates the function, just like one uses a solver. Because it supports an arbitrary number of dimensions, the most obvious way to pass the parameters to the solver is in an array - a reference to the starting register.
Now comes the problem. If my minimization routine is doing all of its work in local registers, the register reference it is going to pass the evaluation function will be a local one. And, that means that the the evaluation function cannot use local variables.
It's not a huge deal, but conceptually it bothers me. Local registers are great when used within a function. The fact that they are global addressable (i.e. 112+) invites one to pass them as references to subroutines. However, it turns out that the limitations of the implementation mean that you have to be careful that the subroutine not allocate any local registers. That is OK, if it is a private subroutine in the program you are working on; but if its a library sub-routine you didn't write, you don't really know whether it uses local registers or not. So now there is a situation where library subroutines that take register references either have to avoid using local registers themselves, or have to constrain the caller from passing them references to local registers. It just feels messy.
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
Extending the address range to include the caller's local data won't help here because the addresses would need to shift by the amount of registers local to the callee. Only for local registers of course which adds to the complexity of the called function. There is no way to absolutely address a local register, addresses aren't pointers but index values. Things are even more complicated because the physical address varies with the precision of the addressed item, think of sRCL or dRCL. If a subroutine (de)allocates the summation registers, data may even move around in memory.
A new idea comes up: A hypothetical FRAME command with an index argument might be useful to switch to a different local register frame. FRAME 0 would denote the own local frame, FRAME 1 the caller's frame and so on. Only the selected frame is visible to the program. The problem here is that this value needs a place in non volatile memory. It will cost at least a return address and at most a register.
Edited: 11 July 2013, 11:59 a.m.
▼
Posts: 189
Threads: 39
Joined: Nov 2011
Quote:
A new idea comes up: A hypothetical FRAME command with an index argument might be useful to switch to a different local register frame. FRAME 0 would denote the own local frame, FRAME 1 the caller's frame and so on. Only the selected frame is visible to the program. The problem here is that this value needs a place in non volatile memory. It will cost at least a return address and at most a register.
The callee would not necessarilly know how far up the call stack to go. The "pointer" to the local register could have been passed down through several subroutine calls.
What you really want is the ability to tell a subroutine "here is a reference to my local registers" and have the reference be valid down the call chain if the subroutine chooses to pass that reference down to other subroutines.
So, how's this for a truly scary suggestion (from someone who does not have to write the code :) -- When using indirect addressing, the values are not simply indexes as they are now. They are actually a form of banked addressing with the high order bits defining the frame, and the low order bits defining the register index. A frame of 0 would refer to the global address space.
So, for accessing global registers, nothing changes. For passing a reference to a local register, a routine has to use a special instruction "make reference" which puts the callers frame number into the high order bits and the register index into the low order bits.
It is not really a radical change because it only affects how one constructs indirect references to local registers. Right now on the WP34s you have to add 112, which is pretty arbitrary and could stand to be encapsulated in a "make local reference" instruction.
Internally, I suppose, the operations that fetch indirect addresses would have to examine the high order bits, determine if there is a non-global frame reference and if there is, go to that index in the subroutine call stack and use the correct register.
From a user standpoint, all we have done is added one instruction and define a new way to pass references to local registers. One, which I might add, is conceptually simpler than the current approach of having to add 112.
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
Indirect addressing is limited to values up to 255. We don't have an easy path (and no plans) to change this.
▼
Posts: 4,587
Threads: 105
Joined: Jul 2005
Quote:
Indirect addressing is limited to values up to 255. We don't have an easy path (and no plans) to change this
... for the WP 34S. For the 43S, however, things may change.
d:-)
▼
Posts: 1,193
Threads: 43
Joined: Jul 2005
From an old (perhaps outdated) message from Eric Smith, I understood that the 43S was based on Thomas Okken Free42 software. Is it so?
Thanks in advance, best regards.
▼
Posts: 4,587
Threads: 105
Joined: Jul 2005
Quote:
I understood that the 43S was based on Thomas Okken Free42 software. Is it so?
Not AFAIK. The 43S is based on hardware to be developed and supplied by Eric Smith and Richard Ottosen and software and UI to be developed and supplied by the WP 34S team. Software-wise, the (HP or Free) 42S may be regarded the grandfather of the 43S while the WP 34S is its father.
d:-)
Posts: 3,229
Threads: 42
Joined: Jul 2006
There is a nice workaround here: the user's function can copy its parent's local registers to globals before allocating its own local frame. It is the user's code so they'll know what can be replaced or not and the block register functions are very fast. Internally, we memory copy stuff around quite a bit -- Marcus hinted at some of this in his reply.
- Pauli
|