Skip to content

Commit 4c9002f

Browse files
authored
Merge pull request #13 from bxparks/develop
merge 0.8.0 into master
2 parents 170496b + c61a1bd commit 4c9002f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2298
-507
lines changed

CHANGELOG.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,57 @@
11
# Changelog
22

33
- Unreleased
4+
- 0.8.0 (2023-12-03)
5+
- **Breaking**: Flip the order of polar-rectangular conversion menu function
6+
(`>POL` and `>REC`) so that they are consistent with the HP-42S. I don't
7+
know why I had them reversed.
8+
- `Y` register holds the `y` or `theta` value, entered first, and
9+
- `X` register holds the `x` or `r` value, entered second.
10+
- **Breaking**: Flip the order of `(X, Y)` coordinates of the `ATN2` menu
11+
function, so that they are consistent with the `>POL` function.
12+
- `Y` register holds the `y` value, which is entered first, then
13+
- `X` register holds the `x` value, which is entered second.
14+
- **Breaking**: Change `WSIZ` to prompt the user for the base word size
15+
using `WSIZ _ _` prompt, instead of using the value in the `X` register.
16+
- Solves a major usability problem where the user was forced to enter
17+
the word size using the currently selected base mode (e.g. `HEX` or
18+
`BIN`). For example, the word size `16` was required to be entered as
19+
`10000` in `BIN` mode, which was too confusing.
20+
- See [Base Word Size](USER_GUIDE.md#base-word-size) for more details.
21+
- **Bug Fix**: Tweak the stack-lift logic so that certain operations
22+
(RollDown, RollUp, X<>Y) enable stack lift even if the previous command
23+
was a `CLEAR` or `CLX`.
24+
- The `rpnFlagsLiftEnabled` was not set properly for RollDown, RollUp,
25+
X<>Y and potentially other commands.
26+
- So a `CLEAR RollDown RollDown RollDown RollDown` followed by a number
27+
would overwrite the `X` register, instead of doing a stack lift.
28+
- Increase execution speed by 2.5X on 83+SE, 84+, 84+SE
29+
- set CPU speed to 15 MHz when supported by hardware
30+
- remain at 6 MHz on the 83+
31+
- `SHOW` display mode
32+
- implement "Show" function using `2ND` `ENTRY` on TI keyboard
33+
- displays all 14 internal digits of the TI-OS floating point number
34+
- if integer < 10^14: display as integer
35+
- otherwise: display in scientific notation
36+
- `BASE` mode variation
37+
- `BIN` mode: display `WSIZ` digits in groups of 4, using up to 4
38+
display lines
39+
- all other `BASE` modes: display underlying floating point number
40+
- see [SHOW Mode](USER_GUIDE.md#show-mode) for details
41+
- `BASE` input limit
42+
- limit the number of digits that can be entered in `BASE` mode to a
43+
maximum that is appropriate for the selected `WSIZ` and the baseNumber
44+
selected by `HEX`, `DEC`, `OCT` and `BIN`
45+
- for example, selecting `HEX` and `WSIZ` 16 will allow only 4 hex
46+
digits to be entered
47+
- see [Base Input Digit Limit](USER_GUIDE.md#base-input-digit-limit) for
48+
details
49+
- HELP pages
50+
- Add page for `CONV` functions to show order of (x, y, r, theta)
51+
variables on RPN stack
52+
- Add page for `STAT` functions
53+
- Add page for `NUM` functions
54+
- Add page for various display MODEs
455
- 0.7.0 (2023-11-20)
556
- `STAT`
657
- fix broken `Sigma+` and `Sigma-` when `Y==0`

DEVELOPER.md

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,73 @@
33
Notes for the developers of the RPN83P app, likely myself in 6 months when I
44
cannot remember how the code works.
55

6+
**Version**: 0.8.0-dev (2023-11-29)
7+
8+
**Project Home**: https://github.com/bxparks/rpn83p
9+
10+
## Table of Contents
11+
12+
- [Debug Statements](#debug-statements)
13+
- [DRAW Mode](#draw-mode)
14+
- [PRIM Prime Factor](#prim-prime-factor)
15+
- [Prime Factor Algorithm](#prime-factor-algorithm)
16+
- [Prime Factor Improvements](#prime-factor-improvements)
17+
- [TVM Algorithms](#tvm-algorithms)
18+
19+
## Debug Statements
20+
21+
Debugging a TI calculator app written in Z80 assembly language is a royal pain
22+
in the neck. Maybe there exist Z80 debuggers that are useful, but I don't know
23+
how to use any of them. The `debug.asm` file contains a number of routines that
24+
I have incrementally added to help me debug this app.
25+
26+
They are normally excluded from the binary. They are included only when the
27+
`DEBUG` macro is defined with the `-DDEBUG` flag like this in the `Makefile`:
28+
29+
```
30+
$(SPASM) -DDEBUG -I $(SPASM_INC) -N rpn83p.asm $@
31+
```
32+
33+
Currently, all debug routines are placed in Flash Page 1, but they could easily
34+
be moved to another Flash Page if needed. The routines are placed in the branch
35+
table in `rpn83p.asm`, and all of them start with the prefix `_Debug`:
36+
37+
- `_DebugInputBuf`
38+
- `_DebugParseBuf`
39+
- `_DebugString`
40+
- `_DebugPString`
41+
- `_DebugClear`
42+
- `_DebugOP1`
43+
- `_DebugEEPos`
44+
- `_DebugUnsignedA`
45+
- `_DebugSignedA`
46+
- `_DebugFlags`
47+
- `_DebugU32AsHex`
48+
- `_DebugHLAsHex`
49+
- `_DebugPause`
50+
- `_DebugU32DEAsHex`
51+
52+
They are called with the usual `bcall()` convention like
53+
`bcall(_DebugUnsignedA)`. Most of these debugging functions write to the empty
54+
line on the LCD, just below the top Status line. That line is purposely left
55+
unused in the RPN83P app, for the explicit goal of allowing these debug routines
56+
to print to that line without interfering with the normal operation of the app.
57+
58+
These debug statements are intended to have no side effects so that they can be
59+
inserted into most places in the application code, without affecting the logic
60+
of the code being debugged. They should save all modified registers (including
61+
the accumulator A and the flags with the `AF` register), save the display cursor
62+
variables `CurRow` and `CurCol`, and restore these variables at the end of the
63+
routine. It is probably a bug if any of these routines cause side effects,
64+
because that means that adding a debug statement would cause the normal flow of
65+
the application code to change.
66+
667
## DRAW Mode
768

8-
The secret `DRAW` (maybe call it "Debug") modes are activated by the `2ND DRAW`
9-
command. It prompts the user for a number, like the `FIX` or `STO` command.
10-
Currently 4 modes defined:
69+
The secret `DRAW` modes are activated by the `2ND DRAW` command. It prompts the
70+
user for a number, like the `FIX` or `STO` command. Currently 4 modes defined:
1171

12-
- 0 (drawNodeNormal): Normal rendering, this is the default.
72+
- 0 (drawModeNormal): Normal rendering, this is the default.
1373
- 1 (drawModeTvmSolverI): Single step through the `I%YR` TVM Solver
1474
calculations, and show the iteration counter (`tvmSolverCount`), and the
1575
internal interest rate variables (`tvmI0`, `tvmI1`) in place of the RPN stack
@@ -23,3 +83,92 @@ Currently 4 modes defined:
2383
always shown, instead of being overwritten by the `inputBuf` in Edit mode.
2484
This helps debugging the complex interaction between the input buffer and the
2585
X register.
86+
87+
Any other value is treated to be the same as 0 (drawModeNormal).
88+
89+
## PRIM Prime Factor
90+
91+
### Prime Factor Algorithm
92+
93+
The [USER_GUIDE.md#prime-factors](USER_GUIDE.md#prime-factors) section explains
94+
how to use the `PRIM` menu function to successively calculate all the prime
95+
factors of an integer `N` from `[0, 2^32)`. The largest prime less than 2^16 is
96+
`65521`. Therefore the longest time that `PRIM` can spend is the factorization
97+
of `65521*65521=4 293 001 441`. On a TI-84 Plus, that calculation takes 33
98+
seconds (at 6 MHz) and 13 seconds (at 15 MHz).
99+
100+
Here are some notes about how the `PRIM` algorithm works:
101+
102+
- The basics of the algorithm is to test all the candidate prime factors from 2
103+
to `sqrt(N)`.
104+
- We could simply start at 3 and increment by 2 to test every odd number to
105+
`sqrt(N)`. But we can do slightly better. All prime numbers `>=5` are of the
106+
form `6k-1` and `6k+1`. So each iteration can increment by 6, but perform 2
107+
checks. This effectively means that we step by 3 through the candidate prime
108+
factors, instead of just by 2 (for all odd numbers), which makes the loop 50%
109+
faster.
110+
- We use integer operations instead of TI-OS floating point ops. If I recall,
111+
this makes it about 2-3X faster (floating point ops in TI-OS are surprisingly
112+
fast).
113+
- Z80 does not support integer division operations in hardware, so we have to
114+
write our own in software. The integer size of `N` is limited to 32 bits, so
115+
we need to write a `div(u32, u32)` routine.
116+
- But the loop only needs to go up to `sqrt(N)`, so we actually only need a
117+
`div(u32, u16)` routine, which if I recall is about 2X faster. This is because
118+
the bit-wise loop is reduced by 2X, but also because the dividend can be
119+
stored in a 16-bit Z80 register, instead of stored in 4 bytes of RAM.
120+
- Finally, we actually don't need a full `div()` operation for the `PRIM`
121+
function. We don't need the quotient, we need only the remainder. So we
122+
implement a custom `mod(u32, u16)` function which is about 25% faster than the
123+
full `div(u32, u16)` function.
124+
125+
I think there are additional micro-optimizations left on the table that could
126+
make the `PRIM` function maybe 1.5X to 2X faster, without resorting to a
127+
completely different algorithm. But I suspect that the resulting code would be
128+
difficult to understand and maintain. So I decided to stop here.
129+
130+
### Prime Factor Improvements
131+
132+
For completeness, here are some improvements that could be made in the prime
133+
factoring algorithm:
134+
135+
1. The `PRIM` function currently returns only the smallest prime factor. It must
136+
be manually called repeatedly to get additional prime factors. But each time
137+
it is called, the search for the next prime factor restarts at 2 and loops to
138+
sqrt(N).
139+
140+
This is inefficient because the search should have started at the *last*
141+
prime factor, since all candidates smaller than that number have already been
142+
tested. We could implement another function (maybe call it`PRFS`) that
143+
returned *all* prime factors of a number `N` . It could be more efficient
144+
by restarting the loop at the previous prime factor. However, this new
145+
function would need support for vectors in the RPN83P app so that it can
146+
return multiple numbers as the result. Vectors unfortunately are not
147+
currently (v0.7.0) supported.
148+
1. The [Prime Number
149+
Theorem](https://en.wikipedia.org/wiki/Prime_number_theorem) tells us that
150+
the number of prime numbers less than `n` is roughly `n/ln(n)`. Since we
151+
restrict our input to the `PRIM` function to 32-bit unsigned integers, the
152+
largest prime factor that we need to consider is `sqrt(2^32)` or `2^16`. That
153+
means that the number of candidate prime factors that we need to consider is
154+
roughly `65536/ln(65535)` or about `5909`. According to the [Prime Counting
155+
Function](https://www.dcode.fr/prime-number-pi-count), the actual number is
156+
`6542`. (Apparently, the `n/ln(n)` expression *underestimates* the actual
157+
number of primes).
158+
159+
We could pre-calculate those 6542 prime numbers into a table, consuming 13084
160+
bytes (using 16-bit integers), which is less than one flash page (16 kiB) of
161+
a TI calculator. The `PRIM` function would need to iterate only 6542 times
162+
through this table. In comparison, the current algorithm effectively
163+
increments through the candidates by 3, up to `2^16`, so about 21845
164+
iterations. The lookup table method would be 3.3X faster, but would increase
165+
the app flash memory size by at least 13084 bytes (most likely another flash
166+
page, so 16 kiB).
167+
168+
I'm not sure if the increase in flash size is worth it, but the `PRIM`
169+
function could be made blindingly fast, finishing the toughest prime factor
170+
problem (of less than `2^32`) in about 10 seconds on a TI-84+ calculator.
171+
172+
## TVM Algorithms
173+
174+
See [TVM Algorithms](TVM.md).

README.md

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,33 @@ features from the
1313
[HP-16C](https://en.wikipedia.org/wiki/HP-16C).
1414

1515

16-
The RPN83P is a flash application that consumes 2 pages (32 kiB) of flash
17-
memory. Since it is stored in flash, it is preserved if the RAM is cleared. It
18-
consumes about 400 bytes of TI-OS RAM: 2 list variables named `REGS` and `STK`,
19-
and an appVar named `RPN83SAV`.
16+
The RPN83P is a flash application written in Z80 assembly language that consumes
17+
2 pages (32 kiB) of flash memory. Since it is stored in flash, it is preserved
18+
if the RAM is cleared. It consumes about 400 bytes of TI-OS RAM: 2 list
19+
variables named `REGS` (240 bytes) and `STK` (59 byte), and an appVar named
20+
`RPN83SAV` (101 bytes).
2021

21-
Here is a quick summary of its features:
22+
Summary of features:
2223

23-
- traditional 4-level RPN stack (`X`, `Y`, `Z`, `T` registers)
24-
- support for `lastX` register
24+
- traditional 4-level RPN stack (`X`, `Y`, `Z`, `T`), with `LastX` register
2525
- 8-line display showing all stack registers
26-
- 25 storage registers (`STO 00`, `RCL 00`, ..., `STO 24`, `RCL 24`)
2726
- hierarchical menu system similar to HP-42S
27+
- quick reference `HELP` menu
28+
- storage registers
29+
- store and recall:`STO nn`, `RCL nn`
30+
- storage arithmetics: `STO+ nn`, `STO- nn`, `STO* nn`, `STO/ nn`, `RCL+
31+
nn`, `RCL- nn`, `RCL* nn`, `RCL/ nn`
32+
- 25 storage registers: `nn = 00..24`
2833
- support for all math functions with dedicated buttons on the TI-83 Plus and
2934
TI-84 Plus
3035
- arithmetic: `/`, `*`, `-`, `+`
3136
- trigonometric: `SIN`, `COS`, `TAN`, etc.
32-
- `1/X`, `X^2`, `SQRT`
33-
- `^` (i.e. `Y^X`),
34-
- `LOG`, `10^X`, `LN`, `e^X`
37+
- algebraic: `1/X`, `X^2`, `SQRT`, `^` (i.e. `Y^X`)
38+
- transcendental: `LOG`, `10^X`, `LN`, `e^X`
3539
- constants: `pi` and `e`
3640
- additional menu functions:
3741
- `X^3`, `3RootX`, `XRootY`, `ATN2`, `2^X`, `LOG2`, `LOGB`
38-
- `%`, `%CH`, `GCD`, `LCM`, `PRIM` (is prime)
42+
- `%`, `%CH`, `GCD`, `LCM`, `PRIM` (prime factor)
3943
- `IP` (integer part), `FP` (fractional part), `FLR` (floor), `CEIL`
4044
(ceiling), `NEAR` (nearest integer)
4145
- `ABS`, `SIGN`, `MOD`, `MIN`, `MAX`
@@ -49,7 +53,7 @@ Here is a quick summary of its features:
4953
`SDEV` (sample standard deviation), `SCOV` (sample covariance),
5054
`PDEV` (population standard deviation), `PCOV` (population covariance)
5155
- curve fitting: `Y>X`, `X>Y`, `SLOP` (slope), `YINT` (y intercept), `CORR`
52-
(correlation coefficent)
56+
(correlation coefficient)
5357
- curve fit models: `LINF` (linear), `LOGF` (logarithmic), `EXPF`
5458
(exponential), `PWRF` (power)
5559
- features inspired by HP-16C and HP-42S
@@ -61,6 +65,7 @@ Here is a quick summary of its features:
6165
- shift and rotate: `SL`, `SR`, `ASR`, `RL`, `RR`, `RLC`, `RRC`,
6266
`SLn`, `SRn`, `RLn`, `RRn`, `RLCn`, `RRCn`
6367
- carry flag and bit masks: `CCF`, `SCF`, `CF?`, `CB`, `SB`, `B?`
68+
- word sizes: `WSIZ`, `WSZ?`: 8, 16, 24, 32 bits
6469
- features inspired by HP-12C and HP-30b
6570
- time value of money (TVM): `N`, `I%YR`, `PV`, `PMT`, `FV`, `P/YR`, `BEG`,
6671
`END`, `CLTV` (clear TVM)
@@ -69,14 +74,15 @@ Here is a quick summary of its features:
6974
- `FIX` (fixed point 0-9 digits)
7075
- `SCI` (scientific 0-9 digits)
7176
- `ENG` (engineering 0-9 digits)
77+
- `SHOW` (`2ND ENTRY`) to display all 14 internal floating point digits
7278

73-
Here are some missing features which may be added in the future:
79+
Missing features (partial list):
7480

7581
- vectors and matrices
7682
- complex numbers
7783
- keystroke programming
7884

79-
**Version**: 0.7.0 (2023-11-20)
85+
**Version**: 0.8.0 (2023-12-03)
8086

8187
**Changelog**: [CHANGELOG.md](CHANGELOG.md)
8288

@@ -123,25 +129,33 @@ The RPN83P app starts directly into the calculator mode, like this:
123129

124130
![RPN83P Hello 1](docs/rpn83p-screenshot-initial.png)
125131

126-
Since the RPN83P is a flash app, it is preserved when the RAM is cleared. It
127-
consumes about 300 bytes of RAM space for its internal RPN and storage
128-
registers.
129-
130132
### Supported Hardware
131133

132134
This app was designed for TI calculators using the Z80 processor:
133135

134-
- TI-83 Plus
135-
- TI-83 Plus Silver Edition
136-
- TI-84 Plus
137-
- TI-84 Plus Silver Edition
136+
- TI-83 Plus (6 MHz Z80, 24 kB accessible RAM, 160 kB accessible flash)
137+
- TI-83 Plus Silver Edition (6/15 MHz Z80, 24 kB accessible RAM, 1.5 MB
138+
accessible flash)
139+
- TI-84 Plus (6/15 MHz Z80, 24 kB accessible RAM, 480 kB accessible flash)
140+
- TI-84 Plus Silver Edition (6/15 MHz Z80, 24 kB accessible RAM, 1.5 MB
141+
accessible flash)
142+
143+
The app configures itself to run at 15 MHz on supported hardware, while
144+
remaining at 6 MHz on the TI-83+.
138145

139-
I have tested it on the two calculators that I own:
146+
I have tested it on the following calculators that I own:
140147

148+
- TI-83 Plus, OS v1.19
141149
- TI-83 Plus Silver Edition, OS v1.19
142150
- TI-84 Plus Silver Edition, OS v2.55MP
143151

144-
It *should* work on the others, but I have not actually tested them.
152+
It *should* work on the TI-84 Plus, but I have not actually tested it.
153+
154+
The following calculators are *not* supported because their internal hardware is
155+
too different:
156+
157+
- TI-84 Plus C Silver Edition
158+
- TI-84 Plus CE
145159

146160
## Quick Examples
147161

0 commit comments

Comments
 (0)