Skip to content

Commit

Permalink
Merge pull request #13 from bxparks/develop
Browse files Browse the repository at this point in the history
merge 0.8.0 into master
  • Loading branch information
bxparks authored Dec 4, 2023
2 parents 170496b + c61a1bd commit 4c9002f
Show file tree
Hide file tree
Showing 47 changed files with 2,298 additions and 507 deletions.
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,57 @@
# Changelog

- Unreleased
- 0.8.0 (2023-12-03)
- **Breaking**: Flip the order of polar-rectangular conversion menu function
(`>POL` and `>REC`) so that they are consistent with the HP-42S. I don't
know why I had them reversed.
- `Y` register holds the `y` or `theta` value, entered first, and
- `X` register holds the `x` or `r` value, entered second.
- **Breaking**: Flip the order of `(X, Y)` coordinates of the `ATN2` menu
function, so that they are consistent with the `>POL` function.
- `Y` register holds the `y` value, which is entered first, then
- `X` register holds the `x` value, which is entered second.
- **Breaking**: Change `WSIZ` to prompt the user for the base word size
using `WSIZ _ _` prompt, instead of using the value in the `X` register.
- Solves a major usability problem where the user was forced to enter
the word size using the currently selected base mode (e.g. `HEX` or
`BIN`). For example, the word size `16` was required to be entered as
`10000` in `BIN` mode, which was too confusing.
- See [Base Word Size](USER_GUIDE.md#base-word-size) for more details.
- **Bug Fix**: Tweak the stack-lift logic so that certain operations
(RollDown, RollUp, X<>Y) enable stack lift even if the previous command
was a `CLEAR` or `CLX`.
- The `rpnFlagsLiftEnabled` was not set properly for RollDown, RollUp,
X<>Y and potentially other commands.
- So a `CLEAR RollDown RollDown RollDown RollDown` followed by a number
would overwrite the `X` register, instead of doing a stack lift.
- Increase execution speed by 2.5X on 83+SE, 84+, 84+SE
- set CPU speed to 15 MHz when supported by hardware
- remain at 6 MHz on the 83+
- `SHOW` display mode
- implement "Show" function using `2ND` `ENTRY` on TI keyboard
- displays all 14 internal digits of the TI-OS floating point number
- if integer < 10^14: display as integer
- otherwise: display in scientific notation
- `BASE` mode variation
- `BIN` mode: display `WSIZ` digits in groups of 4, using up to 4
display lines
- all other `BASE` modes: display underlying floating point number
- see [SHOW Mode](USER_GUIDE.md#show-mode) for details
- `BASE` input limit
- limit the number of digits that can be entered in `BASE` mode to a
maximum that is appropriate for the selected `WSIZ` and the baseNumber
selected by `HEX`, `DEC`, `OCT` and `BIN`
- for example, selecting `HEX` and `WSIZ` 16 will allow only 4 hex
digits to be entered
- see [Base Input Digit Limit](USER_GUIDE.md#base-input-digit-limit) for
details
- HELP pages
- Add page for `CONV` functions to show order of (x, y, r, theta)
variables on RPN stack
- Add page for `STAT` functions
- Add page for `NUM` functions
- Add page for various display MODEs
- 0.7.0 (2023-11-20)
- `STAT`
- fix broken `Sigma+` and `Sigma-` when `Y==0`
Expand Down
157 changes: 153 additions & 4 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,73 @@
Notes for the developers of the RPN83P app, likely myself in 6 months when I
cannot remember how the code works.

**Version**: 0.8.0-dev (2023-11-29)

**Project Home**: https://github.com/bxparks/rpn83p

## Table of Contents

- [Debug Statements](#debug-statements)
- [DRAW Mode](#draw-mode)
- [PRIM Prime Factor](#prim-prime-factor)
- [Prime Factor Algorithm](#prime-factor-algorithm)
- [Prime Factor Improvements](#prime-factor-improvements)
- [TVM Algorithms](#tvm-algorithms)

## Debug Statements

Debugging a TI calculator app written in Z80 assembly language is a royal pain
in the neck. Maybe there exist Z80 debuggers that are useful, but I don't know
how to use any of them. The `debug.asm` file contains a number of routines that
I have incrementally added to help me debug this app.

They are normally excluded from the binary. They are included only when the
`DEBUG` macro is defined with the `-DDEBUG` flag like this in the `Makefile`:

```
$(SPASM) -DDEBUG -I $(SPASM_INC) -N rpn83p.asm $@
```

Currently, all debug routines are placed in Flash Page 1, but they could easily
be moved to another Flash Page if needed. The routines are placed in the branch
table in `rpn83p.asm`, and all of them start with the prefix `_Debug`:

- `_DebugInputBuf`
- `_DebugParseBuf`
- `_DebugString`
- `_DebugPString`
- `_DebugClear`
- `_DebugOP1`
- `_DebugEEPos`
- `_DebugUnsignedA`
- `_DebugSignedA`
- `_DebugFlags`
- `_DebugU32AsHex`
- `_DebugHLAsHex`
- `_DebugPause`
- `_DebugU32DEAsHex`

They are called with the usual `bcall()` convention like
`bcall(_DebugUnsignedA)`. Most of these debugging functions write to the empty
line on the LCD, just below the top Status line. That line is purposely left
unused in the RPN83P app, for the explicit goal of allowing these debug routines
to print to that line without interfering with the normal operation of the app.

These debug statements are intended to have no side effects so that they can be
inserted into most places in the application code, without affecting the logic
of the code being debugged. They should save all modified registers (including
the accumulator A and the flags with the `AF` register), save the display cursor
variables `CurRow` and `CurCol`, and restore these variables at the end of the
routine. It is probably a bug if any of these routines cause side effects,
because that means that adding a debug statement would cause the normal flow of
the application code to change.

## DRAW Mode

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

- 0 (drawNodeNormal): Normal rendering, this is the default.
- 0 (drawModeNormal): Normal rendering, this is the default.
- 1 (drawModeTvmSolverI): Single step through the `I%YR` TVM Solver
calculations, and show the iteration counter (`tvmSolverCount`), and the
internal interest rate variables (`tvmI0`, `tvmI1`) in place of the RPN stack
Expand All @@ -23,3 +83,92 @@ Currently 4 modes defined:
always shown, instead of being overwritten by the `inputBuf` in Edit mode.
This helps debugging the complex interaction between the input buffer and the
X register.

Any other value is treated to be the same as 0 (drawModeNormal).

## PRIM Prime Factor

### Prime Factor Algorithm

The [USER_GUIDE.md#prime-factors](USER_GUIDE.md#prime-factors) section explains
how to use the `PRIM` menu function to successively calculate all the prime
factors of an integer `N` from `[0, 2^32)`. The largest prime less than 2^16 is
`65521`. Therefore the longest time that `PRIM` can spend is the factorization
of `65521*65521=4 293 001 441`. On a TI-84 Plus, that calculation takes 33
seconds (at 6 MHz) and 13 seconds (at 15 MHz).

Here are some notes about how the `PRIM` algorithm works:

- The basics of the algorithm is to test all the candidate prime factors from 2
to `sqrt(N)`.
- We could simply start at 3 and increment by 2 to test every odd number to
`sqrt(N)`. But we can do slightly better. All prime numbers `>=5` are of the
form `6k-1` and `6k+1`. So each iteration can increment by 6, but perform 2
checks. This effectively means that we step by 3 through the candidate prime
factors, instead of just by 2 (for all odd numbers), which makes the loop 50%
faster.
- We use integer operations instead of TI-OS floating point ops. If I recall,
this makes it about 2-3X faster (floating point ops in TI-OS are surprisingly
fast).
- Z80 does not support integer division operations in hardware, so we have to
write our own in software. The integer size of `N` is limited to 32 bits, so
we need to write a `div(u32, u32)` routine.
- But the loop only needs to go up to `sqrt(N)`, so we actually only need a
`div(u32, u16)` routine, which if I recall is about 2X faster. This is because
the bit-wise loop is reduced by 2X, but also because the dividend can be
stored in a 16-bit Z80 register, instead of stored in 4 bytes of RAM.
- Finally, we actually don't need a full `div()` operation for the `PRIM`
function. We don't need the quotient, we need only the remainder. So we
implement a custom `mod(u32, u16)` function which is about 25% faster than the
full `div(u32, u16)` function.

I think there are additional micro-optimizations left on the table that could
make the `PRIM` function maybe 1.5X to 2X faster, without resorting to a
completely different algorithm. But I suspect that the resulting code would be
difficult to understand and maintain. So I decided to stop here.

### Prime Factor Improvements

For completeness, here are some improvements that could be made in the prime
factoring algorithm:

1. The `PRIM` function currently returns only the smallest prime factor. It must
be manually called repeatedly to get additional prime factors. But each time
it is called, the search for the next prime factor restarts at 2 and loops to
sqrt(N).

This is inefficient because the search should have started at the *last*
prime factor, since all candidates smaller than that number have already been
tested. We could implement another function (maybe call it`PRFS`) that
returned *all* prime factors of a number `N` . It could be more efficient
by restarting the loop at the previous prime factor. However, this new
function would need support for vectors in the RPN83P app so that it can
return multiple numbers as the result. Vectors unfortunately are not
currently (v0.7.0) supported.
1. The [Prime Number
Theorem](https://en.wikipedia.org/wiki/Prime_number_theorem) tells us that
the number of prime numbers less than `n` is roughly `n/ln(n)`. Since we
restrict our input to the `PRIM` function to 32-bit unsigned integers, the
largest prime factor that we need to consider is `sqrt(2^32)` or `2^16`. That
means that the number of candidate prime factors that we need to consider is
roughly `65536/ln(65535)` or about `5909`. According to the [Prime Counting
Function](https://www.dcode.fr/prime-number-pi-count), the actual number is
`6542`. (Apparently, the `n/ln(n)` expression *underestimates* the actual
number of primes).

We could pre-calculate those 6542 prime numbers into a table, consuming 13084
bytes (using 16-bit integers), which is less than one flash page (16 kiB) of
a TI calculator. The `PRIM` function would need to iterate only 6542 times
through this table. In comparison, the current algorithm effectively
increments through the candidates by 3, up to `2^16`, so about 21845
iterations. The lookup table method would be 3.3X faster, but would increase
the app flash memory size by at least 13084 bytes (most likely another flash
page, so 16 kiB).

I'm not sure if the increase in flash size is worth it, but the `PRIM`
function could be made blindingly fast, finishing the toughest prime factor
problem (of less than `2^32`) in about 10 seconds on a TI-84+ calculator.

## TVM Algorithms

See [TVM Algorithms](TVM.md).
64 changes: 39 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,33 @@ features from the
[HP-16C](https://en.wikipedia.org/wiki/HP-16C).


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

Here is a quick summary of its features:
Summary of features:

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

Here are some missing features which may be added in the future:
Missing features (partial list):

- vectors and matrices
- complex numbers
- keystroke programming

**Version**: 0.7.0 (2023-11-20)
**Version**: 0.8.0 (2023-12-03)

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

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

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

Since the RPN83P is a flash app, it is preserved when the RAM is cleared. It
consumes about 300 bytes of RAM space for its internal RPN and storage
registers.

### Supported Hardware

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

- TI-83 Plus
- TI-83 Plus Silver Edition
- TI-84 Plus
- TI-84 Plus Silver Edition
- TI-83 Plus (6 MHz Z80, 24 kB accessible RAM, 160 kB accessible flash)
- TI-83 Plus Silver Edition (6/15 MHz Z80, 24 kB accessible RAM, 1.5 MB
accessible flash)
- TI-84 Plus (6/15 MHz Z80, 24 kB accessible RAM, 480 kB accessible flash)
- TI-84 Plus Silver Edition (6/15 MHz Z80, 24 kB accessible RAM, 1.5 MB
accessible flash)

The app configures itself to run at 15 MHz on supported hardware, while
remaining at 6 MHz on the TI-83+.

I have tested it on the two calculators that I own:
I have tested it on the following calculators that I own:

- TI-83 Plus, OS v1.19
- TI-83 Plus Silver Edition, OS v1.19
- TI-84 Plus Silver Edition, OS v2.55MP

It *should* work on the others, but I have not actually tested them.
It *should* work on the TI-84 Plus, but I have not actually tested it.

The following calculators are *not* supported because their internal hardware is
too different:

- TI-84 Plus C Silver Edition
- TI-84 Plus CE

## Quick Examples

Expand Down
Loading

0 comments on commit 4c9002f

Please sign in to comment.