[34S] Proposal for Entry RPN mode with dynamic stack
|
02-15-2015, 10:28 PM
(This post was last modified: 02-18-2015 03:00 AM by matthiaspaul.)
Post: #1
|
|||
|
|||
[34S] Proposal for Entry RPN mode with dynamic stack
Based on discussions with friends and my own experience as (mostly) RPL user, I'd like to suggest two possible new features for the WP 34S (or derivatives and successors) to make it more attractive to a broader user base.
I understand that traditional users of HP RPN calculators appreciate and sometimes depend on the special mechanics of the 4-level automatic stack (conditional duplication of X value into Y on ENTER, and duplication of T value into Z when dropping a stack level). Nevertheless, Hewlett-Packard abandoned these features when they introduced RPL with its "unlimited stack" decades ago, and they even dropped these features in all recent RPN calculators (except for models which emulate traditional RPN calculators). Also, many third-party RPN solutions do not implement them as well, so there are quite many RPL/RPN users, who are puzzled when they find out, that, on the WP34S (which implements "Classical RPN"), 3 ENTER 4 ENTER + does not produce the same result (8 versus 7) as 3 ENTER 4 + I would therefore like to propose to add an "Entry RPN" mode to the WP 34S, which should be active, when the previously unused flag 50 is set. If flag 50 is cleared, the calculator should continue to work exactly as before in "Classical RPN" mode. We could also add an "RPNMODE" command with arguments 1 ("Classical RPN") and 2 ("Entry RPN") to ease mode switches. This should be very easy to implement and at almost no costs in regard to code size. While the special behaviour of the ENTER key can cause confusion and wrong results if used inappropriately, and it therefore should become configurable by this new command, I don't think the duplication of the T register into Z can cause any harm, so, there's no need to disable this as well (at least not in this "minimal" implementation). In addition to this, there's another feature which could be bound to the same flag 50 as well: Dynamic stack. While the limited memory capabilities of the WP 34S hardware do not allow for a really "unlimited" stack, I think, the idea of having a larger stack does not face resistance even among traditional RPN users who have learnt to master almost all problems with a 4-level stack only - at least, if it could be had "for free" and does not get into their way. The WP 34S even implements an optional 8-level stack, however, even this might be unsufficient in some situations. (For example, I would love to use the WP 34S as a "scratchpad" for bit manipulation and optimization tasks in integer mode, which requires that a "stream" of parallel bit data would have to be kept on the stack.) My idea of a dynamic stack is to let the 4- or 8-level base stack grow into currently unused R registers from top to bottom, if two conditions are met: a special dynamic stack mode is enabled, and the register to be occupied for the stack does not hold a non-zero value. All we'd need for this to work would be a pointer indicating the current "top of stack" inside the register memory area. It does not conflict with memory allocated for programs or dynamically allocated memory for statistical data. This dynamic stack allocation would continue to work for as long as we don't run out of registers (that is reach R00 -- letter-named registers will always remain available), or if the register to be occupied would hold a value other than 0, indicating that it is in use already and we mustn't loose its contents. In this case, the dynamic stack cannot grow any larger for as long as this register value isn't changed to 0 first. Instead, the earliest stored value inside the dynamic stack area would be dropped, thereby making room for the new value to be stored on the other end of the dynamic stack. A second circular pointer inside this dynamically allocated stack area would be used to indirectly address the last stored value. When the size of the buffer changes later on, the buffer would have to be normalized again. This would happen, when the "blocking" register holding a non-zero value would be changed to 0 and a new value be stored on the stack, thereby growing the dynamic stack's size by one. It would also happen as soon as the dynamic stack shrinks. This double-pointer-indirection would reduce necessary memory copying to a minimum. When the stack shrinks, the contents of the last stored value in the dynamic stack would be dropped back into the T register, the register set to 0 and deallocated from stack use by (normalizing the buffer and) adjusting the stack pointer accordingly. I'm undecided if the traditional T register duplication should happen again as soon as the dynamic stack is fully deallocated, of if it would be better to insert 0 then. I'm tending towards leaving it as it is, so that the dynamic stack is transparent to users of "Classical RPN". Mind, that, in contrast to the unlimited stack in RPL, in this dynamic RPN stack implementation, a minimum of 4 or 8 stack levels would always remain available for compatibility. Once a register is dynamically allocated to hold stack rather than register data, it no longer exists as actual R register. Assuming, the dynamic stack would have allocated R99 above, the next stack-up operation(s) would attempt to dynamically allocate R98, R97, R96, respectively, and consequently those registers would no longer be available. However, recalling these (no longer existing) registers would still be possible, because we know that their value was 0 before it was allocated as dynamic stack. When attempting to store values in these no longer existing registers, the dynamic stack would automatically make room and shrink downto the size necessary to make the memory available as register again. If the dynamic stack content is more important than the register values, the user can always use lower registers. In order to address the elements on the stack, we could extend the addressing methods for [c]STO, [c]RCL and [c]x<> by a "R/S 1 .. 100" stack-relative addressing scheme. 1 would be stack level 1, that is X. In 4-level stack mode, RCL R/S 5 would recall the first value on the dynamically allocated stack (beyond T), RCL R/S 6 the second value, and so on. Addressing unavailable stack levels would result in an error. Regarding stack manipulation commands, I think, they should continue to work as before, except for [c]R^ and [c]Rv, which either should work on the whole dynamically stack, or better new [c]ROLL^ and [c]ROLLv commands would have to be added in order to provide the facility to work on the whole stack instead of the base stack ([c]R^/v aka ROT) only. Of course, there are race conditions and side effects: A user (or program) could attempt to store a value in a register, which is temporarily allocated for stack use. There are no restrictions in doing so except for that storing values in such non-existing registers will shrink the dynamic stack and thereby loose old stack data. From the stack's perspective, a specific stack size (above the 4- or 8-level base stack) cannot be guaranteed under all conditions. If the stack cannot grow any larger, the contents at the top of the stack will get lost - as it would have happened much earlier already, if the stack couldn't grow at all. This isn't a problem in itself, but user cooperation is required if s/he or a program depends on a particular stack depth (beyond the base stack). These problems could be worked around either by increasing the memory allocated for registers via REGS (if there is free program memory available) or at least remedied by making it a rule to use up registers from the bottom to the top (instead of using f.e. R90 before R10). If these features or effects are undesired, it is always possible to switch back to RPNMODE 1 for "Classical RPN" with old ENTER key behaviour and no dynamic stack. Comments? Greetings, Matthias -- "Programs are poems for computers." |
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 2 Guest(s)