From 292f7c890674ff6c4321fe9f95917046f0800ad8 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 24 Jun 2024 17:10:04 -0700 Subject: [PATCH 01/39] README.md: add 'C/YR' menu under TVM --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 36c288da..6da494db 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,8 @@ Summary of features: - carry flag and bit masks: `CCF`, `SCF`, `CF?`, `CB`, `SB`, `B?` - word sizes: `WSIZ`, `WSZ?`: 8, 16, 24, 32 bits - time value of money (TVM), inspired by HP-12C, HP-17B, and HP-30b - - `N`, `I%YR`, `PV`, `PMT`, `FV`, `P/YR`, `BEG`, `END`, `CLTV` (clear TVM) + - `N`, `I%YR`, `PV`, `PMT`, `FV` + - `P/YR`, `C/YR`, `BEG`, `END`, `CLTV` (clear TVM) - complex numbers, inspired by HP-42S and HP-35s - stored in RPN stack registers (`X`, `Y`, `Z`, `T`, `LASTX`) and storage registers `R00-R99` From c7e6d214802c3bd530ddc2b503dcc454775e4deb Mon Sep 17 00:00:00 2001 From: Brian Park Date: Tue, 25 Jun 2024 12:49:36 -0700 Subject: [PATCH 02/39] src: add -A flag to 'spasm' to enable case-sensitivity; fix resulting typos; no logic change --- src/Makefile | 10 +++-- src/common.asm | 2 +- src/debug1.asm | 92 ++++++++++++++++++++--------------------- src/display.asm | 78 +++++++++++++++++----------------- src/display2.asm | 22 +++++----- src/handlertab.asm | 2 +- src/helpscanner1.asm | 2 +- src/main.asm | 2 +- src/menudef.asm | 8 ++-- src/menuhandlers.asm | 2 +- src/offsetdatetime2.asm | 2 +- src/print.asm | 14 +++---- src/print1.asm | 10 ++--- src/show2.asm | 2 +- src/showscanner.asm | 2 +- src/tvm2.asm | 2 +- src/universal.asm | 10 ++--- 17 files changed, 132 insertions(+), 130 deletions(-) diff --git a/src/Makefile b/src/Makefile index 27fb776e..63f64bb7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,19 +3,21 @@ TARGETS := rpn83p.8xk rpn83p.8xp rpn83p.lst SPASM_DIR := ../../spasm SPASM_INC := $(SPASM_DIR)/inc SPASM := $(SPASM_DIR)/spasm +SPASM_FLAGS := -A -I $(SPASM_INC) -N + SRCS := $(wildcard *.asm) # TI Flash app. Use -DDEBUG to activate functions in debug1.asm. rpn83p.8xk: $(SRCS) Makefile - $(SPASM) -I $(SPASM_INC) -N rpn83p.asm $@ - @#$(SPASM) -DDEBUG -I $(SPASM_INC) -N rpn83p.asm $@ + $(SPASM) $(SPASM_FLAGS) rpn83p.asm $@ + @#$(SPASM) $(SPASM_FLAGS) -DDEBUG rpn83p.asm $@ # TI assembly program. No longer works because the program is > 8 kiB. #rpn83p.8xp: $(SRCS) Makefile -# $(SPASM) -I $(SPASM_INC) -N rpn83p.asm $@ +# $(SPASM) $(SPASM_FLAGS) rpn83p.asm $@ rpn83p.lst: $(SRCS) Makefile rpn83p.8xk - $(SPASM) -I $(SPASM_INC) -N -T rpn83p.asm rpn83p.8xk + $(SPASM) $(SPASM_FLAGS) -T rpn83p.asm rpn83p.8xk menudef.asm: menudef.txt ../tools/compilemenu.py ../tools/compilemenu.py -o $@ $< diff --git a/src/common.asm b/src/common.asm index 8e40e5c4..7666c961 100644 --- a/src/common.asm +++ b/src/common.asm @@ -17,7 +17,7 @@ ; - HL:(const void* const*)=pointer to a list of pointers to subroutines ; Output: depends on the routine called ; Destroys: DE, HL, and others depending on the routine called -jumpAofHL: +jumpAOfHL: call getString ; [[fallthrough]] diff --git a/src/debug1.asm b/src/debug1.asm index 2ad0f2e6..7e2e1380 100644 --- a/src/debug1.asm +++ b/src/debug1.asm @@ -21,11 +21,11 @@ DebugInputBuf: push bc push de push hl - ld hl, (CurRow) + ld hl, (curRow) push hl ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ld hl, inputBuf call putPSPageOne ld a, cursorCharAlt @@ -33,7 +33,7 @@ DebugInputBuf: bcall(_EraseEOL) pop hl - ld (CurRow), hl + ld (curRow), hl pop hl pop de pop bc @@ -51,11 +51,11 @@ DebugParseBuf: push bc push de push hl - ld hl, (CurRow) + ld hl, (curRow) push hl ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ld hl, parseBuf call putPSPageOne ld a, cursorCharAlt @@ -63,7 +63,7 @@ DebugParseBuf: bcall(_EraseEOL) pop hl - ld (CurRow), hl + ld (curRow), hl pop hl pop de pop bc @@ -81,16 +81,16 @@ DebugString: push bc push de push hl - ld de, (CurRow) + ld de, (curRow) push de ld de, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), de + ld (curRow), de call putSPageOne bcall(_EraseEOL) pop de - ld (CurRow), de + ld (curRow), de pop hl pop de pop bc @@ -106,16 +106,16 @@ DebugPString: push bc push de push hl - ld de, (CurRow) + ld de, (curRow) push de ld de, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), de + ld (curRow), de call putPSPageOne bcall(_EraseEOL) pop de - ld (CurRow), de + ld (curRow), de pop hl pop de pop bc @@ -128,15 +128,15 @@ DebugPString: ; Destroys: none DebugClear: push hl - ld hl, (CurRow) + ld hl, (curRow) push hl ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl bcall(_EraseEOL) pop hl - ld (CurRow), hl + ld (curRow), hl pop hl ret @@ -151,11 +151,11 @@ DebugOP1: push bc push de push hl - ld hl, (CurRow) + ld hl, (curRow) push hl ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ld a, 15 ; width of output bcall(_FormReal) ld hl, OP3 @@ -163,7 +163,7 @@ DebugOP1: bcall(_EraseEOL) pop hl - ld (CurRow), hl + ld (curRow), hl pop hl pop de pop bc @@ -184,11 +184,11 @@ DebugUnsignedA: push de push hl push ix - ; Save CurRow/CurCol - ld hl, (CurRow) + ; Save curRow/CurCol + ld hl, (curRow) push hl ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ; Create 4-byte buffer on the stack push hl push hl @@ -206,9 +206,9 @@ DebugUnsignedA: ; Clean up stack buffer pop hl pop hl - ; Restore CurRow/CurCol + ; Restore curRow/CurCol pop hl - ld (CurRow), hl + ld (curRow), hl ; Restore all registers. pop ix pop hl @@ -231,11 +231,11 @@ DebugSignedA: push de push hl push ix - ; Save CurRow/CurCol - ld hl, (CurRow) + ; Save curRow/CurCol + ld hl, (curRow) push hl ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ; Create 4-byte buffer on the stack push hl push hl @@ -263,9 +263,9 @@ debugSignedAPrint: ; Clean up stack buffer pop hl pop hl - ; Restore CurRow/CurCol + ; Restore curRow/CurCol pop hl - ld (CurRow), hl + ld (curRow), hl ; Restore all registers. pop ix pop hl @@ -289,11 +289,11 @@ DebugFlags: push bc push de push hl - ld hl, (CurRow) + ld hl, (curRow) push hl ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ; Print Input dirty flag bit dirtyFlagsInput, (iy + dirtyFlags) @@ -326,7 +326,7 @@ DebugFlags: bcall(_EraseEOL) pop hl - ld (CurRow), hl + ld (curRow), hl pop hl pop de pop bc @@ -364,10 +364,10 @@ DebugU32AsHex: push de push hl ; Set cursor position, saving the previous on the stack. - ld de, (CurRow) + ld de, (curRow) push de ld de, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), de + ld (curRow), de ; Prep loop ld b, 4 debugU32AsHexLoop: @@ -379,7 +379,7 @@ debugU32AsHexLoop: djnz debugU32AsHexLoop ; pop de - ld (CurRow), de + ld (curRow), de pop hl pop de pop bc @@ -423,10 +423,10 @@ DebugU40AsHex: push de push hl ; Set cursor position, saving the previous on the stack. - ld de, (CurRow) + ld de, (curRow) push de ld de, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), de + ld (curRow), de ; Prep loop ld b, 5 debugU40AsHexLoop: @@ -438,7 +438,7 @@ debugU40AsHexLoop: djnz debugU40AsHexLoop ; pop de - ld (CurRow), de + ld (curRow), de pop hl pop de pop bc @@ -460,11 +460,11 @@ DebugHL: bcall(_PushRealO4) ; up to 16 bytes starting at OP3, which spills into OP4 pop hl push hl - ld de, (CurRow) + ld de, (curRow) push de ; ld de, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), de + ld (curRow), de ; Converting to float is not efficient, but ok for debugging. bcall(_SetXXXXOP2) ; OP2=float(HL) bcall(_OP2ToOP1) ; OP1=float(HL) @@ -475,7 +475,7 @@ DebugHL: bcall(_EraseEOL) ; pop de - ld (CurRow), de + ld (curRow), de bcall(_PopRealO4) bcall(_PopRealO3) bcall(_PopRealO2) @@ -494,11 +494,11 @@ DebugHLAsHex: push bc push de push hl - ld de, (CurRow) + ld de, (curRow) push de ; ld de, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), de + ld (curRow), de ; ld a, h call debugUnsignedAAsHex @@ -507,7 +507,7 @@ DebugHLAsHex: bcall(_EraseEOL) ; pop de - ld (CurRow), de + ld (curRow), de pop hl pop de pop bc @@ -522,11 +522,11 @@ DebugDEHLAsHex: push bc push de push hl - ld bc, (CurRow) + ld bc, (curRow) push bc ; ld bc, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), bc + ld (curRow), bc ; ld a, d call debugUnsignedAAsHex @@ -541,7 +541,7 @@ DebugDEHLAsHex: bcall(_EraseEOL) ; pop bc - ld (CurRow), bc + ld (curRow), bc pop hl pop de pop bc diff --git a/src/display.asm b/src/display.asm index 67e4109a..7dd9f438 100644 --- a/src/display.asm +++ b/src/display.asm @@ -207,7 +207,7 @@ displayStatusArrow: bit dirtyFlagsMenu, (iy + dirtyFlags) ret z ld hl, statusPenRow*$100 + statusMenuPenCol; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ; check arrow status bcall(_GetCurrentMenuArrowStatus) ; B=menuArrowStatus call displayStatusArrowLeft @@ -268,7 +268,7 @@ displayStatusFloatMode: bit dirtyFlagsStatus, (iy + dirtyFlags) ret z ld hl, statusPenRow*$100 + statusFloatModePenCol; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ; check float mode bit fmtExponent, (iy + fmtFlags) jr nz, displayStatusFloatModeSciOrEng @@ -305,7 +305,7 @@ displayStatusTrig: bit dirtyFlagsStatus, (iy + dirtyFlags) ret z ld hl, statusPenRow*$100 + statusTrigPenCol; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl bit trigDeg, (iy + trigFlags) jr z, displayStatusTrigRad displayStatusTrigDeg: @@ -324,7 +324,7 @@ displayStatusBase: bit dirtyFlagsStatus, (iy + dirtyFlags) ret z ld hl, statusPenRow*$100 + statusBasePenCol; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ; Determine state of Carry Flag. ld a, (baseCarryFlag) or a @@ -345,7 +345,7 @@ displayStatusComplexMode: bit dirtyFlagsStatus, (iy + dirtyFlags) ret z ld hl, statusPenRow*$100 + statusComplexModePenCol; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ; Determine state of complexMode ld a, (complexMode) ; Check complexModeRad @@ -381,7 +381,7 @@ displayStatusStackMode: bit dirtyFlagsStatus, (iy + dirtyFlags) ret z ld hl, statusPenRow*$100 + statusStackModePenCol; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ; print the stackSize variable first ld a, (stackSize) add a, '0' @@ -407,7 +407,7 @@ displayErrorCode: ; Display nothing if errorCode == OK (0) res fracDrawLFont, (iy + fontFlags) ; use small font ld hl, errorPenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld a, (errorCode) or a jr z, displayErrorCodeEnd @@ -468,39 +468,39 @@ displayStack: displayStackYZT: ; print T label ld hl, stTPenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgTLabel call vPutSmallS ; print T value ld hl, stTCurCol*$100 + stTCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl call rclT ld b, displayStackFontFlagsT call printOP1 ; print Z label ld hl, stZPenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgZLabel call vPutSmallS ; print Z value ld hl, stZCurCol*$100 + stZCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl call rclZ ld b, displayStackFontFlagsZ call printOP1 ; print Y label ld hl, stYPenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgYLabel call vPutSmallS ; print Y value ld hl, stYCurCol*$100 + stYCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl call rclY ld b, displayStackFontFlagsY call printOP1 @@ -542,7 +542,7 @@ displayStackXNormal: call displayStackXLabel ; print the X register ld hl, stXCurCol*$100 + stXCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl call rclX ld b, displayStackFontFlagsX jp printOP1 @@ -551,7 +551,7 @@ displayStackXInput: call displayStackXLabel ; print the inputBuf ld hl, inputCurCol*$100 + inputCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ld b, displayStackFontFlagsX call displayStackSetLargeFont bcall(_PrintInputBuf) @@ -560,7 +560,7 @@ displayStackXInput: ; Display the inputBuf in the debug line. Used for DRAW mode 3. displayStackXInputAtDebug: ld hl, debugCurCol*$100+debugCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl bcall(_PrintInputBuf) ret @@ -570,14 +570,14 @@ displayStackXLabel: bit dirtyFlagsXLabel, (iy + dirtyFlags) jr nz, displayStackXLabelContinue ld hl, 0*$100 + stXCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ld a, Lspace bcall(_PutC) res dirtyFlagsXLabel, (iy + dirtyFlags) displayStackXLabelContinue: ; print X label ld hl, inputPenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgXLabel call vPutSmallS ret @@ -586,23 +586,23 @@ displayStackXLabelContinue: ; Display the argBuf in the X register line. ; Input: (argBuf) -; Output: (CurCol) updated +; Output: (curCol) updated displayStackXArg: ; Set commandArg cursor position. ld hl, argCurCol*$100 + argCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ld b, displayStackFontFlagsX ; [[fallthrough]] -; Description: Print the arg buffer at the (CurRow) and (CurCol). +; Description: Print the arg buffer at the (curRow) and (curCol). ; Input: ; - B=displayFontMask ; - argBuf (same as inputBuf) ; - argPrompt ; - argModifier -; - (CurCol) cursor position +; - (curCol) cursor position ; Output: -; - (CurCol) is updated +; - (curCol) is updated ; - (displayStackFontFlagsX) cleared to indicate large font ; Destroys: A, HL; BC destroyed by PutPS() printArgBuf: @@ -673,65 +673,65 @@ msgArgModifierIndirect: displayTvm: ; print TVM n label ld hl, tvmNPenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgTvmNLabel call vPutSmallS ; print TVM n value ld hl, tvmNCurCol*$100 + tvmNCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl bcall(_RclTvmSolverCount) ld b, displayStackFontFlagsA call printOP1 ; print TVM i0 label ld hl, tvmI0PenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgTvmI0Label call vPutSmallS ; print TVM i0 value ld hl, tvmI0CurCol*$100 + tvmI0CurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl bcall(_RclTvmI0) ld b, displayStackFontFlagsZ call printOP1 ; print TVM i1 label ld hl, tvmI1PenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgTvmI1Label call vPutSmallS ; print TVM i1 value ld hl, tvmI1CurCol*$100 + tvmI1CurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl bcall(_RclTvmI1) ld b, displayStackFontFlagsY call printOP1 ; print TVM f0 label ld hl, tvmF0PenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgTvmF0Label call vPutSmallS ; print TVM f0 value ld hl, tvmF0CurCol*$100 + tvmF0CurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl bcall(_RclTvmNPMT0) ld b, displayStackFontFlagsZ call printOP1 ; print TVM f1 label ld hl, tvmF1PenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgTvmF1Label call vPutSmallS ; print TVM f1 value ld hl, tvmF1CurCol*$100 + tvmF1CurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl bcall(_RclTvmNPMT1) ld b, displayStackFontFlagsX call printOP1 @@ -784,12 +784,12 @@ msgShowLabel: displayShow: ; Print 'SHOW' label on Error Code line ld hl, errorPenRow*$100 ; $(penRow)(penCol) - ld (PenCol), hl + ld (penCol), hl ld hl, msgShowLabel call printSmallHLString ; Call special FormShowable() function to show all digits of OP1. ld hl, showCurCol*$100 + showCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl call rclX ; fmtString is a buffer of 65 bytes used by FormDCplx(). There should be no ; problems using it as our string buffer. @@ -804,13 +804,13 @@ displayShow: ; Destroys: A, B, HL clearShowArea: ld hl, errorCurCol*$100 + errorCurRow ; $(curCol)(curRow) - ld (CurRow), hl + ld (curRow), hl ld b, 5 clearShowAreaLoop: bcall(_EraseEOL) ; saves all registers - ld hl, (CurRow) + ld hl, (curRow) inc l - ld (CurRow), hl + ld (curRow), hl djnz clearShowAreaLoop ret @@ -1005,7 +1005,7 @@ printOP1AsFloat: ; Destroys: A, HL printHLString: call putS - ld a, (CurCol) + ld a, (curCol) or a ret z ; if spilled to next line, don't call EraseEOL bcall(_EraseEOL) diff --git a/src/display2.asm b/src/display2.asm index 01bcd27c..f5881eb5 100644 --- a/src/display2.asm +++ b/src/display2.asm @@ -50,11 +50,11 @@ PrintMenuNameAtC: push af ; stack=[numRows] push bc ; stack=[numRows, loopCounter/penCol] push de ; stack=[numRows, loopCounter/penCol,menuIndex] - ; Set (PenCol,PenRow), preserving HL + ; Set (penCol,penRow), preserving HL ld a, c ; A=penCol - ld (PenCol), a + ld (penCol), a ld a, menuPenRow - ld (PenRow), a + ld (penRow), a ; Predict the width of menu name. ld de, menuName ld c, menuNameBufMax @@ -186,10 +186,10 @@ displayMenuFolderEnd: ; Description: Print the input buffer. ; Input: ; - inputBuf -; - (CurRow) cursor row -; - (CurCol) cursor column +; - (curRow) cursor row +; - (curCol) cursor column ; Output: -; - (CurCol) updated +; - (curCol) updated ; - (renderWindowStart) updated ; - (renderWindowEnd) updated ; - (cursorRenderPos) updated @@ -437,7 +437,7 @@ printRenderWindowPutC: ; Skip EraseEOL() if the PutC() above wrapped to next line. ; Destroys: A clearEndOfRenderLine: - ld a, (CurCol) + ld a, (curCol) or a ret z bcall(_EraseEOL) @@ -449,8 +449,8 @@ clearEndOfRenderLine: ; - cursorRenderPos ; Output: ; - cursorScreenPos updated -; - CurCol updated -; - CurRow updated +; - curCol updated +; - curRow updated setInputCursor: ; update cursor screen logical position ld a, (renderWindowStart) @@ -463,9 +463,9 @@ setInputCursor: ; beginning of th line. Also update physical row, because the TI-OS cursor ; could have wrapped to the next row add a, inputCurCol - ld (CurCol), a + ld (curCol), a ld a, inputCurRow - ld (CurRow), a + ld (curRow), a ; update cursor-under character ld hl, renderBuf inc hl diff --git a/src/handlertab.asm b/src/handlertab.asm index 1b9efcd6..8a187785 100644 --- a/src/handlertab.asm +++ b/src/handlertab.asm @@ -234,7 +234,7 @@ keyCodeHandlerTable: ; `Rollup` soft menu key in the `STK` menufolder. ; 2) The `u` can be a mnemonic for the "Rollup" name of the command. .db kunA - .dw handleKeyRollup + .dw handleKeyRollUp ; bind ANS to lastX. .db kAns ; ANS diff --git a/src/helpscanner1.asm b/src/helpscanner1.asm index a70df678..2fec1605 100644 --- a/src/helpscanner1.asm +++ b/src/helpscanner1.asm @@ -96,7 +96,7 @@ displayHelpPage: bcall(_ClrLCDFull) ld hl, 0 - ld (PenCol), hl + ld (penCol), hl ; Get the string for page A, and display it. ld hl, helpPages ; HL = (char**) diff --git a/src/main.asm b/src/main.asm index 21d85705..2cca7e26 100644 --- a/src/main.asm +++ b/src/main.asm @@ -71,7 +71,7 @@ mainExit: set appAutoScroll, (iy + appFlags) ld (iy + textFlags), 0 ; reset text flags bcall(_ClrLCDFull) - bcall(_HomeUp) + bcall(_homeup) ; Restore various OS states. bcall(_RestoreOSState) diff --git a/src/menudef.asm b/src/menudef.asm index 44e239ce..b79b836a 100644 --- a/src/menudef.asm +++ b/src/menudef.asm @@ -3530,13 +3530,13 @@ mCommaEESwappedName: mCommaEESwappedAltName: .db 'E', 'E', Scomma, Sblock, 0 mFormatRecordRawName: - .db SlBrace, SPeriod, SPeriod, SrBrace, 0 + .db SlBrace, Speriod, Speriod, SrBrace, 0 mFormatRecordRawAltName: - .db SlBrace, SPeriod, SPeriod, SrBrace, Sblock, 0 + .db SlBrace, Speriod, Speriod, SrBrace, Sblock, 0 mFormatRecordStringName: - .db Squote, SPeriod, SPeriod, Squote, 0 + .db Squote, Speriod, Speriod, Squote, 0 mFormatRecordStringAltName: - .db Squote, SPeriod, SPeriod, Squote, Sblock, 0 + .db Squote, Speriod, Speriod, Squote, Sblock, 0 mStackDupName: .db "DUP", 0 mStackRollUpName: diff --git a/src/menuhandlers.asm b/src/menuhandlers.asm index cdb0ce2f..bcb5c574 100644 --- a/src/menuhandlers.asm +++ b/src/menuhandlers.asm @@ -630,7 +630,7 @@ mPToRHandler: ; Output: ; - Y: theta ; - X: r -mRtoPHandler: +mRToPHandler: call closeInputAndRecallXY ; OP1=Y; OP2=X call op1ExOp2 ; OP1=x; OP2=y call rectToPolar ; OP1=r; OP2=theta diff --git a/src/offsetdatetime2.asm b/src/offsetdatetime2.asm index 575a9356..5a630db5 100644 --- a/src/offsetdatetime2.asm +++ b/src/offsetdatetime2.asm @@ -238,7 +238,7 @@ SubRpnOffsetDateTimeByObject: call getOp3RpnObjectTypePageTwo ; A=type; HL=OP3 cp rpnObjectTypeReal jr z, subRpnOffsetDateTimeBySeconds - cp RpnObjectTypeOffsetDateTime ; ZF=1 if RpnOffsetDateTime + cp rpnObjectTypeOffsetDateTime ; ZF=1 if RpnOffsetDateTime jr z, subRpnOffsetDateTimeByRpnOffsetDateTime cp rpnObjectTypeDuration jr z, subRpnOffsetDateTimeByRpnDuration diff --git a/src/print.asm b/src/print.asm index aafa2188..717dfd69 100644 --- a/src/print.asm +++ b/src/print.asm @@ -118,15 +118,15 @@ vEraseEOLLoop2: ; string is too long to fit into the current line, we print 2 dots (4 pixels ; wide) are printed at the end to indicate truncation. ; -; I would have thought that checking for PenCol>=92 would have been sufficient, +; I would have thought that checking for penCol>=92 would have been sufficient, ; since the display is 96 pixels wide, and a dot is only 2 pixels wide. But it ; turns out that VPutMap() function has some strange, undocumented behavior, so -; PenCol>=89 seems to work a lot better. +; penCol>=89 seems to work a lot better. ; ; It has been hard to characterize the exact behavior of VPutMap() at the end ; of the line. Even if there are 4 pixels available at the end of the line, it ; does not want to write a 4-pixel wide character. Furthermore, if the -; character does not fit, it is simply ignored, PenCol is not updated, and a +; character does not fit, it is simply ignored, penCol is not updated, and a ; subsequent call to VPutMap() with a narrow enough character will print that ; narrow character into that space. So sometimes, some random character at the ; end seems to have been lost. @@ -150,7 +150,7 @@ vPutSmallSLoop: ; funny business with vPutMap() that I cannot quite characterize. With 8 ; spaces, we get more flexibility. ld b, a ; B=saved A - ld a, (PenCol) + ld a, (penCol) cp 88 jr nc, vPutSmallSMaybeTruncate ld a, b ; A=restored A @@ -237,10 +237,10 @@ putSEnd: putSEnter: ; Handle newline push hl - ld hl, (CurRow) - inc l ; CurRow++ + ld hl, (curRow) + inc l ; curRow++ ld h, 0 ; CurCol=0 - ld (CurRow), hl + ld (curRow), hl pop hl jr putSCheck diff --git a/src/print1.asm b/src/print1.asm index 4f958106..06fd9d88 100644 --- a/src/print1.asm +++ b/src/print1.asm @@ -61,9 +61,9 @@ eVPutSEnter: ; move to the next line push af push hl - ld hl, PenCol + ld hl, penCol xor a - ld (hl), a ; PenCol = 0 + ld (hl), a ; penCol = 0 inc hl ; PenRow ld a, (hl) ; A = PenRow add a, c ; A += C (font height) @@ -136,10 +136,10 @@ putSPageOneEnd: putSPageOneEnter: ; Handle newline push hl - ld hl, (CurRow) - inc l ; CurRow++ + ld hl, (curRow) + inc l ; curRow++ ld h, 0 ; CurCol=0 - ld (CurRow), hl + ld (curRow), hl pop hl jr putSPageOneCheck diff --git a/src/show2.asm b/src/show2.asm index d9d3deb1..4c5647e7 100644 --- a/src/show2.asm +++ b/src/show2.asm @@ -315,7 +315,7 @@ msgShowComplexDegSpacer: ; Destroys: OP1, OP2 formRealString: push de - bcall(_CkOp1FP0) ; if OP1==0: ZF=1 + bcall(_CkOP1FP0) ; if OP1==0: ZF=1 pop de jr nz, formRealStringNonZero ; Generate just a "0" if zero. diff --git a/src/showscanner.asm b/src/showscanner.asm index a26bbcff..7d7d9828 100644 --- a/src/showscanner.asm +++ b/src/showscanner.asm @@ -18,7 +18,7 @@ processShowCommands: bcall(_GetKey) res onInterrupt, (iy + onFlags) ; Quit the app on QUIT. - cp a, KQuit + cp a, kQuit jp z, mainExit ; Anything else exits the SHOW mode. call clearShowArea diff --git a/src/tvm2.asm b/src/tvm2.asm index 1159e623..1bda8704 100644 --- a/src/tvm2.asm +++ b/src/tvm2.asm @@ -748,7 +748,7 @@ calculateNextSecantInterest: call op1ToOp2PageTwo call RclTvmNPMT1 bcall(_FPSub) ; OP1=npmt1-npmt0 - bcall(_CkOp1FP0) ; ZF=1 if OP1==0 + bcall(_CkOP1FP0) ; ZF=1 if OP1==0 jr z, calculateNextSecantInterestDenomZero call pushRaw9Op1 ; FPS=[npmt1-npmt0] ; calculate i0*npmt1 diff --git a/src/universal.asm b/src/universal.asm index 2eeebc13..6f4e8a10 100644 --- a/src/universal.asm +++ b/src/universal.asm @@ -696,7 +696,7 @@ universalCubeReal: ret universalCubeComplex: call cp1ToCp5 ; CP5=CP1 - bcall(_Csquare) ; CP1=CP1^2 + bcall(_CSquare) ; CP1=CP1^2 bcall(_PushOP1) ; FPS=[CP1^2] call cp5ToCp1 ; CP1=CP5 bcall(_CMult) ; CP1=CP1^3; FPS=[] @@ -723,7 +723,7 @@ universalCubeRootComplex: bcall(_OP1Set3) ; OP1=3 call convertOp1ToCp1 ; CP1=(3i0) bcall(_PushOP1) ; FPS=[3i0] - call cp3Tocp1 ; CP1=CP3 + call cp3ToCp1 ; CP1=CP3 bcall(_CXrootY) ; CP1=CP1^(1/3); FPS=[] ret @@ -836,7 +836,7 @@ universalXRootYComplexByReal: call convertOp3ToCp3 ; [[fallthrough]] universalXRootYComplexByComplex: - bcall(_PushOp3) ; FPS=[X] + bcall(_PushOP3) ; FPS=[X] bcall(_CXrootY) ; CP1=CP1^(1/FPS)=Y^(1/X); FPS=[] ret @@ -937,7 +937,7 @@ universalExp: universlExpErr: bcall(_ErrDataType) universalExpReal: - bcall(_EtoX) + bcall(_EToX) ret universalExpComplex: bcall(_CEtoX) @@ -961,7 +961,7 @@ universalTwoPowReal: universalTwoPowComplex: bcall(_OP3Set2) ; OP3=2 call convertOp3ToCp3 ; CP3=2i0 - bcall(_PushOp3) ; FPS=[2i0] + bcall(_PushOP3) ; FPS=[2i0] bcall(_CYtoX) ; CP1=FPS^CP1=2^(X); FPS=[] ret From 7643e9dc23f416136fef5aa85e00d7be8a2a70be Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 27 Jun 2024 14:54:06 -0700 Subject: [PATCH 03/39] tvm2.asm: adjust transition to 'small-i' equation at 3e-5 instead of 1e-10 --- src/const2.asm | 13 ++++++++++++- src/help1.asm | 4 ++-- src/tvm2.asm | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/const2.asm b/src/const2.asm index 1b3d4806..c45b8515 100644 --- a/src/const2.asm +++ b/src/const2.asm @@ -29,6 +29,14 @@ op2Set1EM10PageTwo: ;----------------------------------------------------------------------------- +; Description: Set OP2 to 3e-5 +; Destroys: all, HL +op2Set3EM5PageTwo: + ld hl, const3EM5PageTwo + jp move9ToOp2PageTwo + +;----------------------------------------------------------------------------- + ; Description: Set OP2 to 1. ; Destroys: all, HL op2Set1PageTwo: @@ -115,9 +123,12 @@ constM50PageTwo: ; -50 const0PageTwo: ; 0.0 .db $00, $80, $00, $00, $00, $00, $00, $00, $00 -const1EM10PageTwo: ; 10^-10 +const1EM10PageTwo: ; 1E-10 .db $00, $76, $10, $00, $00, $00, $00, $00, $00 +const3EM5PageTwo: ; 3E-5 + .db $00, $7B, $30, $00, $00, $00, $00, $00, $00 + const1PageTwo: ; 1 .db $00, $80, $10, $00, $00, $00, $00, $00, $00 diff --git a/src/help1.asm b/src/help1.asm index c3d5b9c1..51574224 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,8 +34,8 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - ; .db escapeSmallFont, "v0.12.0", Shyphen, "rc3 (2024", Shyphen, "06", Shyphen, "21)", Senter - .db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "24)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "06", Shyphen, "27)", Senter + ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter .db "An RPN calculator for the", Senter diff --git a/src/tvm2.asm b/src/tvm2.asm index 1bda8704..7d176848 100644 --- a/src/tvm2.asm +++ b/src/tvm2.asm @@ -611,12 +611,12 @@ inverseCompoundingFactorZero: ; Output: OP1=NPMT(i) ; Destroys: OP1-OP5 nominalPMT: - ; Check if N*i <~ tol; tol=1e-10 + ; Check if (N^2-1)*i^2/12 <~ tol; tol=1e-10. In other words, N*i <~ 3e-5. call op1ToOp2PageTwo ; OP2=i call RclTvmN ; OP1=N bcall(_FPMult) ; OP1=i*N; OP2=i call pushRaw9Op2 ; FPS=[i] - call op2Set1EM10PageTwo ; OP2=1e-10 + call op2Set3EM5PageTwo ; OP2=3e-5 bcall(_AbsO1O2Cp) ; CF=1 if OP1 Date: Fri, 28 Jun 2024 08:26:21 -0700 Subject: [PATCH 04/39] tvm2.asm: adjust the transition point of small-i using more rigorous estimation --- CHANGELOG.md | 2 ++ src/const2.asm | 10 +++++----- src/help1.asm | 2 +- src/tvm2.asm | 9 +++++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 223a1eab..2b3f22eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog - Unreleased + - Change the criteria for using the small-i approximation to the following: + N*i <~ 6e-5. - 0.12.0 (2024-06-24) - **Bug Fix**: update logic that determines when the comma `,` character can be inserted into the input buffer diff --git a/src/const2.asm b/src/const2.asm index c45b8515..6dfe40f1 100644 --- a/src/const2.asm +++ b/src/const2.asm @@ -29,10 +29,10 @@ op2Set1EM10PageTwo: ;----------------------------------------------------------------------------- -; Description: Set OP2 to 3e-5 +; Description: Set OP2 to 6e-5 ; Destroys: all, HL -op2Set3EM5PageTwo: - ld hl, const3EM5PageTwo +op2Set6EM5PageTwo: + ld hl, const6EM5PageTwo jp move9ToOp2PageTwo ;----------------------------------------------------------------------------- @@ -126,8 +126,8 @@ const0PageTwo: ; 0.0 const1EM10PageTwo: ; 1E-10 .db $00, $76, $10, $00, $00, $00, $00, $00, $00 -const3EM5PageTwo: ; 3E-5 - .db $00, $7B, $30, $00, $00, $00, $00, $00, $00 +const6EM5PageTwo: ; 6E-5 + .db $00, $7B, $60, $00, $00, $00, $00, $00, $00 const1PageTwo: ; 1 .db $00, $80, $10, $00, $00, $00, $00, $00, $00 diff --git a/src/help1.asm b/src/help1.asm index 51574224..cca9d7cf 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "06", Shyphen, "27)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "06", Shyphen, "28)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/tvm2.asm b/src/tvm2.asm index 7d176848..73397f4e 100644 --- a/src/tvm2.asm +++ b/src/tvm2.asm @@ -611,12 +611,17 @@ inverseCompoundingFactorZero: ; Output: OP1=NPMT(i) ; Destroys: OP1-OP5 nominalPMT: - ; Check if (N^2-1)*i^2/12 <~ tol; tol=1e-10. In other words, N*i <~ 3e-5. + ; Check if if the 3rd order term of the Ni/((1+i)^N-1) term is less than + ; the last digit that can be represented by the TI-OS floating point + ; (14-digits). So we need to check if (N^2-1)*i^3/24 <~ tol; tol=1e-14. + ; This is equivalent to N*i <~ N^(1/3)*6e-5. But N can be assumed to be + ; greater than 1. So we can use N*i <~ 6e-5, and still satify the original + ; constraint. call op1ToOp2PageTwo ; OP2=i call RclTvmN ; OP1=N bcall(_FPMult) ; OP1=i*N; OP2=i call pushRaw9Op2 ; FPS=[i] - call op2Set3EM5PageTwo ; OP2=3e-5 + call op2Set6EM5PageTwo ; OP2=6e-5 bcall(_AbsO1O2Cp) ; CF=1 if OP1 Date: Fri, 28 Jun 2024 11:25:04 -0700 Subject: [PATCH 05/39] TVM.md: describe small-i quadratic approximation of ICFN(i,N) used in inverseCompoundingFactor() --- docs/TVM.md | 99 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/docs/TVM.md b/docs/TVM.md index 954e110a..94ac34a1 100644 --- a/docs/TVM.md +++ b/docs/TVM.md @@ -18,6 +18,7 @@ Money (TVM) variables in the RPN83P calculator app. - [TVM Solver](#tvm-solver) - [Number of Solutions](#number-of-solutions) - [Taming Overflows](#taming-overflows) + - [Small i Approximation](#small-i-approximation) - [Secant Method](#secant-method) - [Initial Guesses](#initial-guesses) - [Terminating Conditions](#terminating-conditions) @@ -381,7 +382,9 @@ the `1e-99` limit of the TI-OS. The solution provided by Albert Chan is brilliant. It uses the fact that when we are solving for the zeros of an equation, we can divide the equation by an arbitrary function whose values are `> 0` everywhere, and the roots of the -equation are *unchanged*. Let's define a new term `CFN(i,N)`: +equation are *unchanged*. + +Let's define a new term `CFN(i,N)`: ``` CFN(i,N) = CF2(i)/N = [(1+i)^N-1]/Ni @@ -395,7 +398,7 @@ CFN(i,N) = CF2(i)/N = [(1+i)^N-1]/Ni (Note that this is slightly different than the `C(i,N)` function defined by Albert Chan in [TVM formula error in programming -manual?](https://www.hpmuseum.org/forum/thread-20739.html) (2023)) The +manual?](https://www.hpmuseum.org/forum/thread-20739.html) (2023)) Our `CFN(i,N)` function normalized by `N` compared to `CF2(i)` so that it evaluates to `1` at `i=0` for all `N`. @@ -417,6 +420,30 @@ same as the `FV` term but with the `N` replaced with `-N`. In other words: CFN(i,-N) = CFN(i,N)/(1+i)^N ``` +For implementation purposes, it is convenient to define the `ICFN(i,N)` +function which is the reciprocal of `CFN(i,N)` which allows us to avoid at +least 2 floating point division operations (which are expensive relative to +multiplication): + +``` +ICFN(i,N) = 1/CFN(i,N) = Ni/((1+i)^N-1) +``` + +This function is computed in the `inverseCompoundingFactor()` routine in the +code. + +(The `ICFN(i,N)` function is similar to the `C(n)` function given by Albert Chan +in [TVM formula error in programming +manual?](https://www.hpmuseum.org/forum/thread-20739-post-179371.html#pid179371) +(2023), within a factor of `(1+i)^N`, or equivalently, a substitution of `-N` +for `N`.) + +Combining all these, the equation solved by the TVM Solver is: + +``` +NPMT(i,n) = PV * ICFN(i,-N) + (1+ip)N*PMT + FV * ICFN(i,N) = 0 +``` + Solving the roots of `NPMT(i)=0` will yield that exactly the same roots as solving for `NFV(i)=0`, because the `CFN(i,n)` function is positive for all `i` over the domain of interest `(1+i)>0`. @@ -463,21 +490,65 @@ beginning or end of the cash flow. The `NPMT(i)` function essentially averages all 3 terms over the entire duration of the `N` payment periods, instead of pulling everything to the present or pushing everything to the future. -**Implementation Note**: +### Small i Approximation -The `inverseCompoundingFactor()` routine calculates the reciprocal of -`CFN(i,N)`. In other words, it calculates +When `i` is large enough, we can compute `ICFN(i,N)` using the usual conversion +to `expm1()` and `log1p()` functions: ``` -ICFN(i,N) = 1/CFN(i,N) = Ni/((1+i)^N-1) +ICFN(i,N) = 1/CFN(i,N) + = Ni/((1+i)^N-1) + = Ni / expm1(N*log1p(i)) ``` -for a slight gain in efficiency by avoiding a division or two. This makes -`ICFN(i,N)` similar to the `C(n)` function given by Albert Chan in [TVM formula -error in programming -manual?](https://www.hpmuseum.org/forum/thread-20739-post-179371.html#pid179371) -(2023), within a factor of `(1+i)^N`, or equivalently, a substitution of `-N` -for `N`. +But when `i` becomes very close to 0, even the `expm1()` and `log1p()` functions +cannot prevent significant rounding errors. In this region of very small `i`, we +can use the Taylor series expansion of `ICFN(i,N)`: + +``` +ICFN(i,N) = 1 - ((N-1)/2) i + ((N^2-1)/12) i^2 - ((N^2-1)/24) i^3 + O(i^4) +``` + +When `i` becomes very small, we want to use the quadratic truncation of the +Taylor series. Ideally, the transition to the quadratic approximation should +happen when the error relative to the full equation is less than the limit of +the floating point format of the TI-83+/84+ calculator (14 digits). My guess is +that error in the quadratic equation is roughly equal to the 3rd order term of +the Taylor series, in other words: + +``` +err =~ ((N^2-1)/24) i^3 +``` + +So that means we want to use the small-i quadratic approximation when: + +``` +err <~ 1e-14 + +=> (N^2-1)/24) i^3 <~ 1e-14 + +=> N*i <~ N^(1/3) * 6.2e-5 +``` + +Let's assume that `N>1` for all real-life problems. Then it is reasonable to +replace the above with a more conservative (and easier to calculate) constraint: + +``` +N*i <~ 6e-5 +``` + +which satisfies the original constraint for `N>1`. + +Finally, we get the formula that the `inverseCompoundingFactor()` routine uses +to calculate the `ICFN(i,n)` function: + +``` + Ni / expm1(N*log1p(i)) (when N*i >= 6e-5) + / +ICFN(i,N) = + \ + 1 - ((N-1)/2) i + ((N^2-1)/12) i^2 (when N*i < 6e-5) +``` ### Secant Method @@ -504,8 +575,8 @@ tedious to translate to Z80 assembly. convergence characteristics of the Newton's method (quadratic convergence) or Halley's method (cubic convergence). -The convergence of the Secant method seems to be fast enough for get a tolerance -of about 1e-8 within 7-8 iterations. +The convergence of the Secant method seems to be fast enough to get answers to +within a tolerance of about 1e-10 within 7-8 iterations. ### Initial Guesses From b98bd252e3cc8cf31b8916f909700db3ae9488bb Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 1 Jul 2024 13:44:29 -0700 Subject: [PATCH 06/39] TVM.md: add links to TVM puzzles; tweak subsection title --- docs/TVM.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/TVM.md b/docs/TVM.md index 94ac34a1..330b9fce 100644 --- a/docs/TVM.md +++ b/docs/TVM.md @@ -12,7 +12,8 @@ Money (TVM) variables in the RPN83P calculator app. - [TVM Basics](#tvm-algorithms) - [Interest Rate Conversions](#interest-rate-conversions) - [TVM Formulas](#tvm-formulas) -- [Small Interest Limits](#small-interest-limits) +- [Small Interest Accuracy](#small-interest-accuracy) + - [expm1() and log1p() Functions](#expm1-and-log1p-functions) - [CF1 and CF2](#cf1-and-cf2) - [N and N0](#n-and-n0) - [TVM Solver](#tvm-solver) @@ -24,6 +25,7 @@ Money (TVM) variables in the RPN83P calculator app. - [Terminating Conditions](#terminating-conditions) - [Maximum Iterations](#maximum-iterations) - [Convergence](#convergence) +- [TVM Puzzles](#tvm-puzzles) - [References](#references) Notes about the equations and algorithms used by the TVM functions. @@ -171,13 +173,17 @@ later. Also, the `(1+ip)` term is always associated with `CF2(i)`, so the `compoundingFactors()` routine in the code calculates both `CF1(i)` and `CF3(i)=(1+ip)CF2(i)` at once. -## Small Interest Limits +## Small Interest Accuracy When the interest rate `i` is small (say, smaller than 1e-6), special precautions are needed to ensure that numerical cancellation errors are reduced -so that the correct answers are returned. To accomplish this, we need to take a -side trip to define 2 new functions. These functions are designed to return -accurate values when `x` is very small: +so that the correct answers are returned. + +### expm1() and log1p() Functions + +To obtain the most accuracy results when when `i` is small, we need to take a +side trip to define 2 new functions which are designed to return accurate values +when `x` is very small: ``` expm1(x) = e^x-1 @@ -673,6 +679,16 @@ of his posts, for example [TVM solve for interest rate, revisited](https://www.hpmuseum.org/forum/thread-18359.html) (2022), but I have not yet digested these posts. +## TVM Puzzles + +Duncan Murray has evaluated the performance and accuracy of TVM solvers on +various calculators (including RPN83P) using a number of TVM puzzles. The +puzzles and the results are available here: + +- [Looking for financial/TVM + solutions](https://forum.swissmicros.com/viewtopic.php?f=2&t=3987) +- [TVM puzzles 1:12 in 5 minutes](https://www.youtube.com/watch?v=7ragp9pMR3w) + ## References Here is an incomplete list of references that I consulted: From 53fa12f238aea5d518b5e3fecfbd685577b42785 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Tue, 2 Jul 2024 09:46:14 -0700 Subject: [PATCH 07/39] prime2.asm: fix modOP1ByBC() internal labels; no functional change --- src/help1.asm | 2 +- src/prime2.asm | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/help1.asm b/src/help1.asm index cca9d7cf..7b9cb106 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "06", Shyphen, "28)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "02)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/prime2.asm b/src/prime2.asm index 738ad298..d087761d 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -349,7 +349,8 @@ primeFactorModCheckDiv: ; - OP1:u32=dividend ; - BC:u16=divisor ; Output: -; - DE:u16=dividend +; - DE:u16=remainder +; Destroys: A, HL modOP1ByBC: ; push the dividend (x) to a combination of HL and the stack ld hl, (OP1+2) ; HL=high16 @@ -358,7 +359,7 @@ modOP1ByBC: ; ld de, 0 ; DE=remainder ld a, 32 -primeFactorModCheckDivLoop: +modOP1ByBCCheckDivLoop: ; shift x by one bit to the left add hl, hl ex (sp), hl ; stack=[low16]; HL=high16 @@ -368,19 +369,19 @@ primeFactorModCheckDivLoop: rl e rl d ; DE=remainder ex de, hl ; HL=remainder; DE=dividend - jp c, primeFactorModCheckDivOverflow ; remainder overflowed, so substract + jp c, modOP1ByBCCheckDivOverflow ; remainder overflowed, so substract or a ; CF=0 sbc hl, bc ; HL(remainder) -= divisor - jp nc, primeFactorModCheckDivNextBit + jp nc, modOP1ByBCCheckDivNextBit add hl, bc ; revert the subtraction - jp primeFactorModCheckDivNextBit -primeFactorModCheckDivOverflow: + jp modOP1ByBCCheckDivNextBit +modOP1ByBCCheckDivOverflow: or a ; reset CF sbc hl, bc ; HL(remainder) -= divisor -primeFactorModCheckDivNextBit: +modOP1ByBCCheckDivNextBit: ex de, hl ; DE=remainder; HL=dividend dec a - jp nz, primeFactorModCheckDivLoop + jp nz, modOP1ByBCCheckDivLoop pop hl ; stack=[]; HL=high16 ret From 8043e397630557c1959f92a85fb96493b72c8dea Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 3 Jul 2024 06:51:10 -0700 Subject: [PATCH 08/39] prime2.asm:modOP1ByBC(): use IX register instead of (SP), improving PRIM by 25% --- src/prime2.asm | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/prime2.asm b/src/prime2.asm index d087761d..23bd5ded 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -237,13 +237,20 @@ primeFactorIntCheckDiv: ; - 65521*65521: 12.9 seconds ; - About 5000 effective-candidates / second. ; -; Benchmarks (15 MHz, modOP1ByBC): +; Benchmarks (15 MHz, modOP1ByBC using (SP)): ; - 4001*4001: 0.85 seconds ; - 10007*10007: 1.6 seconds ; - 19997*19997: 2.9 seconds ; - 65521*65521: 9.0 seconds ; - About 7280 effective-candidates / second. ; +; Benchmarks (15 MHz, modOP1ByBC using IX): +; - 4001*4001: 0.75 seconds +; - 10007*10007: 1.3 seconds +; - 19997*19997: 2.4 seconds +; - 65521*65521: 7.2 seconds +; - About 9000 effective-candidates / second. +; ; Input: OP1: an integer in the range of [2, 2^32-1]. ; Output: OP1: 1 if prime, smallest prime factor if not ; Destroys: all registers, OP1-OP3 @@ -353,18 +360,14 @@ primeFactorModCheckDiv: ; Destroys: A, HL modOP1ByBC: ; push the dividend (x) to a combination of HL and the stack + ld ix, (OP1) ; IX=low16 ld hl, (OP1+2) ; HL=high16 - push hl ; stack=[high16] - ld hl, (OP1) ; HL=low16 - ; ld de, 0 ; DE=remainder ld a, 32 modOP1ByBCCheckDivLoop: - ; shift x by one bit to the left - add hl, hl - ex (sp), hl ; stack=[low16]; HL=high16 + ; shift dividend by one bit to the left + add ix, ix adc hl, hl - ex (sp), hl ; stack=[high16]; HL=low16 ; shift bit into remainder rl e rl d ; DE=remainder @@ -382,7 +385,6 @@ modOP1ByBCCheckDivNextBit: ex de, hl ; DE=remainder; HL=dividend dec a jp nz, modOP1ByBCCheckDivLoop - pop hl ; stack=[]; HL=high16 ret ;----------------------------------------------------------------------------- From 6d2dbbcc5347c73173197f88d13f03deeb71be5c Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 3 Jul 2024 07:08:46 -0700 Subject: [PATCH 09/39] prime2.asm: modHLIXByBC(): use 'adc hl, hl' instead of 2 'rl'; improves PRIM by 3-4% --- src/help1.asm | 2 +- src/prime2.asm | 56 +++++++++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/help1.asm b/src/help1.asm index 7b9cb106..75e43d92 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "02)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "03)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/prime2.asm b/src/prime2.asm index 23bd5ded..73926602 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -244,12 +244,12 @@ primeFactorIntCheckDiv: ; - 65521*65521: 9.0 seconds ; - About 7280 effective-candidates / second. ; -; Benchmarks (15 MHz, modOP1ByBC using IX): -; - 4001*4001: 0.75 seconds -; - 10007*10007: 1.3 seconds -; - 19997*19997: 2.4 seconds -; - 65521*65521: 7.2 seconds -; - About 9000 effective-candidates / second. +; Benchmarks (15 MHz, modHLIXByBC): +; - 4001*4001: 0.67 seconds +; - 10007*10007: 1.2 seconds +; - 19997*19997: 2.3 seconds +; - 65521*65521: 7.0 seconds +; - About 9360 effective-candidates / second. ; ; Input: OP1: an integer in the range of [2, 2^32-1]. ; Output: OP1: 1 if prime, smallest prime factor if not @@ -340,51 +340,55 @@ primeFactorModCheckDiv: ex de, hl ; HL=OP3 call modU32ByBC ; DE:u16=remainder; destroys (*HL); preserves BC=candidate #else - call modOP1ByBC + ld ix, (OP1) ; IX=low16 + ld hl, (OP1+2) ; HL=high16 + call modHLIXByBC #endif ld a, d or e ; if remainder==0: ZF=1 ret ; Decription: Highly specialized version of modU32ByBC() to get the highest -; performance. For example, uses 'jp' instead 'jr' because 'jp' is faster. I -; tried to use IX instead of the stack (SP), but the Z80 does not support 'add -; ix,ix' or 'adc ix,ix' which forced the use of the stack anyway. The benchmark -; says that this is about 45% faster than modU32ByBC(). +; performance. For example, uses 'jp' instead 'jr' because 'jp' is faster. +; - The first version of this used (SP) to store the high16 bits. This makes +; PRIM about 45% faster than modU32ByBC(). +; - The next version uses the IX register instead of (SP) to store the high16 +; bits. This improves PRIM by another 25%. (I was using a Z80 instruction +; cheatsheet which incorrectly said that the `add ix, ix` instruction did not +; exist. But it does.) +; - Another 3-4% came from replacing `rl e; rl d; ex de, hl` with `ex +; de, hl; adc hl, hl`. ; ; Input: -; - OP1:u32=dividend +; - HL:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend ; - BC:u16=divisor ; Output: ; - DE:u16=remainder -; Destroys: A, HL -modOP1ByBC: - ; push the dividend (x) to a combination of HL and the stack - ld ix, (OP1) ; IX=low16 - ld hl, (OP1+2) ; HL=high16 +; Destroys: A, HL, IX +modHLIXByBC: ld de, 0 ; DE=remainder ld a, 32 -modOP1ByBCCheckDivLoop: +modHLIXByBCCheckDivLoop: ; shift dividend by one bit to the left add ix, ix adc hl, hl ; shift bit into remainder - rl e - rl d ; DE=remainder ex de, hl ; HL=remainder; DE=dividend - jp c, modOP1ByBCCheckDivOverflow ; remainder overflowed, so substract + adc hl, hl + jp c, modHLIXByBCCheckDivOverflow ; remainder overflowed, so substract or a ; CF=0 sbc hl, bc ; HL(remainder) -= divisor - jp nc, modOP1ByBCCheckDivNextBit + jp nc, modHLIXByBCCheckDivNextBit add hl, bc ; revert the subtraction - jp modOP1ByBCCheckDivNextBit -modOP1ByBCCheckDivOverflow: + jp modHLIXByBCCheckDivNextBit +modHLIXByBCCheckDivOverflow: or a ; reset CF sbc hl, bc ; HL(remainder) -= divisor -modOP1ByBCCheckDivNextBit: +modHLIXByBCCheckDivNextBit: ex de, hl ; DE=remainder; HL=dividend dec a - jp nz, modOP1ByBCCheckDivLoop + jp nz, modHLIXByBCCheckDivLoop ret ;----------------------------------------------------------------------------- From e947ad6da40ef143efa6a7b232ce14957f2e4e2a Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 3 Jul 2024 08:36:01 -0700 Subject: [PATCH 10/39] USER_GUIDE.md: update latest benchmarks for PRIM, ~28% faster --- CHANGELOG.md | 7 +++++++ docs/DEVELOPER.md | 7 +++++++ docs/USER_GUIDE.md | 10 +++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b3f22eb..3ae73d4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ - Unreleased - Change the criteria for using the small-i approximation to the following: N*i <~ 6e-5. + - Improve performance of `PRIM` by 28-52% + - convert `modOP1ByBC()` using the `(SP)` stack to `modHLIXByBC()` which + uses only the CPU registers without touching RAM + - speed increases ~28% on the TI-83+, TI-83+SE, TI-84+SE + - speed increases ~52% on the TI-Nspire w/ TI-84 keypad (my guess is + that the Z80 emulator cannot access the emulated RAM as fast as it can + access the emulated CPU registers) - 0.12.0 (2024-06-24) - **Bug Fix**: update logic that determines when the comma `,` character can be inserted into the input buffer diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index e663d494..546df2a2 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -149,6 +149,13 @@ Here are some notes about how the `PRIM` algorithm works: `ex (sp), hl` instruction of the Z80 to swap the 2 halves back and forth. This made the `mod(u32,u16)` function about 40-50% faster compared to v0.9.0. +- In v0.13, the inner loop `mod(u32,u16)` was made another 28% faster. + - I discovered that my Z80 instruction cheatsheet incorrectly stated that + the `add ix, ix` did not exist. It does. + - Replacing the `ex (sp), hl; add hl, hl` combo with a `add ix, ix` gave us + a 25% speed improvement. + - Another 3-4% was gained by replacing a `rl e; rl d` combo with an `adc hl, + hl` instruction. I can think of one additional optimization that *may* give us a 10-20% speed increase, but it would come at the cost of code that would be significantly diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 42ebf415..6cb1d0e3 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -1997,7 +1997,7 @@ For example, let's find the prime factors of `2_122_438_477 = 53 * 4001 * For computational efficiency, `PRIM` supports only integers between `2` and `2^32-1` (4 294 967 295). This allows `PRIM` to use integer arithmetic, making -it about 10X faster than the equivalent algorithm using floating point routines. +it about 13X faster than the equivalent algorithm using floating point routines. Any number outside of this range produces an `Err: Domain` message. (The number `1` is not considered a prime number.) @@ -2008,10 +2008,10 @@ times of the `PRIM` function for this number for various TI models that I own: | **Model** | **PRIM Running Time** | | --- | --- | -| TI-83+ (6 MHz) | 20 s | -| TI-83+SE (15 MHz) | 7.7 s | -| TI-84+SE (15 MHz) | 9.5 s | -| TI-Nspire w/ TI-84+ keypad | 8.2 s | +| TI-83+ (6 MHz) | 15.7 s | +| TI-83+SE (15 MHz) | 6.0 s | +| TI-84+SE (15 MHz) | 7.4 s | +| TI-Nspire w/ TI-84+ keypad | 5.4 s | During the calculation, the "run indicator" on the upper-right corner will be active. You can press the `ON` key to break from the `PRIM` loop with an `Err: From c3f2d21453fe7f49fbaaea70a9e1ad7e4e5786b8 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 3 Jul 2024 16:47:49 -0700 Subject: [PATCH 11/39] prime1.asm: improve speed of PRIM another 11%, for a total of 43% since v0.12.0 --- CHANGELOG.md | 6 +++--- docs/USER_GUIDE.md | 10 +++++----- src/prime2.asm | 37 +++++++++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae73d4e..1fedb76a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,11 @@ - Unreleased - Change the criteria for using the small-i approximation to the following: N*i <~ 6e-5. - - Improve performance of `PRIM` by 28-52% + - Improve performance of `PRIM` by 43-67% - convert `modOP1ByBC()` using the `(SP)` stack to `modHLIXByBC()` which uses only the CPU registers without touching RAM - - speed increases ~28% on the TI-83+, TI-83+SE, TI-84+SE - - speed increases ~52% on the TI-Nspire w/ TI-84 keypad (my guess is + - speed increases ~43% on the TI-83+, TI-83+SE, TI-84+SE + - speed increases ~67% on the TI-Nspire w/ TI-84 keypad (my guess is that the Z80 emulator cannot access the emulated RAM as fast as it can access the emulated CPU registers) - 0.12.0 (2024-06-24) diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 6cb1d0e3..9cf0f14d 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -1997,7 +1997,7 @@ For example, let's find the prime factors of `2_122_438_477 = 53 * 4001 * For computational efficiency, `PRIM` supports only integers between `2` and `2^32-1` (4 294 967 295). This allows `PRIM` to use integer arithmetic, making -it about 13X faster than the equivalent algorithm using floating point routines. +it about 15X faster than the equivalent algorithm using floating point routines. Any number outside of this range produces an `Err: Domain` message. (The number `1` is not considered a prime number.) @@ -2008,10 +2008,10 @@ times of the `PRIM` function for this number for various TI models that I own: | **Model** | **PRIM Running Time** | | --- | --- | -| TI-83+ (6 MHz) | 15.7 s | -| TI-83+SE (15 MHz) | 6.0 s | -| TI-84+SE (15 MHz) | 7.4 s | -| TI-Nspire w/ TI-84+ keypad | 5.4 s | +| TI-83+ (6 MHz) | 14.0 s | +| TI-83+SE (15 MHz) | 5.4 s | +| TI-84+SE (15 MHz) | 6.7 s | +| TI-Nspire w/ TI-84+ keypad | 4.9 s | During the calculation, the "run indicator" on the upper-right corner will be active. You can press the `ON` key to break from the `PRIM` loop with an `Err: diff --git a/src/prime2.asm b/src/prime2.asm index 73926602..509dd360 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -251,6 +251,18 @@ primeFactorIntCheckDiv: ; - 65521*65521: 7.0 seconds ; - About 9360 effective-candidates / second. ; +; Benchmarks (15 MHz, modHLIXByBC, rearrange code assuming rare overflow): +; - 65521*65521: 6.7 seconds +; - About 9880 effective-candidates / second. +; +; Benchmarks (15 MHz, modHLIXByBC, use JR instead of JP on rare branch): +; - 65521*65521: 6.6 seconds +; - About 9927 effective-candidates / second +; +; Benchmarks (15 MHz, modHLIXByBC, remove unnecessary 'or a') +; - 65521*65521: 6.3 seconds +; - About 10400 effective-candidates / second +; ; Input: OP1: an integer in the range of [2, 2^32-1]. ; Output: OP1: 1 if prime, smallest prime factor if not ; Destroys: all registers, OP1-OP3 @@ -376,20 +388,33 @@ modHLIXByBCCheckDivLoop: ; shift bit into remainder ex de, hl ; HL=remainder; DE=dividend adc hl, hl - jp c, modHLIXByBCCheckDivOverflow ; remainder overflowed, so substract - or a ; CF=0 + ; Use 'jr c' instead of 'jp c' because the common case is expected to be + ; CF=0, so the branch is not taken, which means only 7 T cycles in the + ; common case. + jr c, modHLIXByBCCheckDivOverflow ; remainder overflowed, so substract sbc hl, bc ; HL(remainder) -= divisor + ; I *think* CF=0 and CF=1 will occur in equal probability, so it makes + ; almost no difference whether we use 'jr nc' or 'jp nc'. The 'jr nc' + ; instruction takes 7 T cycles if the branch is not taken, and 12 cycles if + ; the branch is taken, for an average of 9.5 cycles. The 'jp nc' + ; instruction takes 10 cycles whether or not the branch is taken. The + ; difference is so small, I prefer the predictability of 'jp nc' always + ; taking 10 cycles. jp nc, modHLIXByBCCheckDivNextBit add hl, bc ; revert the subtraction - jp modHLIXByBCCheckDivNextBit -modHLIXByBCCheckDivOverflow: - or a ; reset CF - sbc hl, bc ; HL(remainder) -= divisor modHLIXByBCCheckDivNextBit: ex de, hl ; DE=remainder; HL=dividend dec a + ; Use 'jp nz' instead of 'jr nz' because 'jp nz' is faster in the common + ; case of ZF=0 when the branch is taken 32 times. jp nz, modHLIXByBCCheckDivLoop ret +modHLIXByBCCheckDivOverflow: + ; This branch (CF=1) is more rare than (CF=0) because it will happen only + ; after the 16th iteration. + or a ; reset CF + sbc hl, bc ; HL(remainder) -= divisor + jp modHLIXByBCCheckDivNextBit ;----------------------------------------------------------------------------- From 8fa4c5f1a1834b1c6f197ddbbb372b2898514a9d Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 8 Jul 2024 06:05:28 -0700 Subject: [PATCH 12/39] USER_GUIDE.md: fix grammar typo --- docs/USER_GUIDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 9cf0f14d..41ecedc0 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -830,7 +830,7 @@ others were not. the number. - Since the `ON/EXIT` button is used to navigate the menu hierarchy, it cannot cause input termination, unlike the HP-42S. - - The only exceptions are menus which changes the rendering of the values on + - The only exceptions are menus which change the rendering of the values on the RPN stack, for example: - `BASE` menu folder, which interprets the values on the RPN stack as integers not floating point numbers From dda5b1c1354d1202b2748924450d0b385193c299 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 10 Jul 2024 16:00:53 -0700 Subject: [PATCH 13/39] prime2.asm: consolidate benchmarks; fix primeFactorInt() breakage after past refactoring --- src/help1.asm | 2 +- src/prime2.asm | 233 ++++++++++++++++++++++++------------------------- 2 files changed, 116 insertions(+), 119 deletions(-) diff --git a/src/help1.asm b/src/help1.asm index 75e43d92..662f314d 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "03)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "10)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/prime2.asm b/src/prime2.asm index 509dd360..df43c0bb 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -3,7 +3,53 @@ ; Copyright (c) 2023 Brian T. Park ; ; Various implementations of the primeFactor() function which calculates -; the smallest prime factor, or 1 if the number is a prime. +; the smallest prime factor, or returns 1 if the number is a prime. +; +; There are at least 4 versions. Each can be selected passing the appropriate +; `-D` flag to `spasm` in the Makefile: +; +; - USE_PRIME_FACTOR_FLOAT +; - uses TI-OS _FPDiv() and _Frac() routines to determine if `candidate` is a +; factor of `input` +; - Benchmarks (15 MHz, TilEm): +; - 19997*19997: 28.6 seconds +; - 65521*65521: 94.5 seconds +; - About 693 effective-candidates / second. +; - USE_PRIME_FACTOR_INT +; - uses divU32U32() to determine if `candidate` is a factor of `input` +; - Benchmarks (15 MHz, TilEm, divU32U32): +; - 19997*19997: 10.7 seconds +; - 65521*65521: 34.4 seconds +; - About 1905 effective-candidates / second +; - USE_PRIME_FACTOR_MOD_U32_BY_BC +; - uses modU32ByBC() to determine if `candidate` is a factor of `input` +; - Benchmarks (15 MHz, TilEm, modU32ByBC): +; - 19997*19997: 4.2 seconds +; - 65521*65521: 12.9 seconds +; - About 5079 effective-candidates / second. +; - USE_PRIME_FACTOR_MOD_HLSP_BY_BC +; - uses modHLSPByBC() to determine if `candidate` is a factor of `input` +; - Benchmarks (15 MHz, TilEm, modOP1ByBC using (SP)): +; - 19997*19997: 2.9 seconds +; - 65521*65521: 9.0 seconds +; - About 7280 effective-candidates / second. +; - USE_PRIME_FACTOR_MOD_HLIX_BY_BC (default) +; - uses modHLIXByBC() to determine if `candidate` is a factor of `input` +; - Benchmarks (15 MHz, TilEm, modHLIXByBC): +; - 65521*65521: 7.0 seconds +; - About 9360 effective-candidates / second. +; - Benchmarks (15 MHz, TilEm, modHLIXByBC, rearrange code assuming rare +; overflow): +; - 65521*65521: 6.7 seconds +; - About 9880 effective-candidates / second. +; - Benchmarks (15 MHz, modHLIXByBC, use JR instead of JP on rare branch): +; - 65521*65521: 6.6 seconds +; - About 9927 effective-candidates / second +; - Benchmarks (15 MHz, modHLIXByBC, remove unnecessary 'or a') +; - 65521*65521: 6.3 seconds +; - About 10400 effective-candidates / second +; +; The modHLIXByBC() version is now 15X faster than the floating point version. ; ; All of these take advantage of the fact that every prime above 3 is of the ; form (6n-1) or (6n+1), where n=1,2,3,... It checks candidate divisors from 5 @@ -12,6 +58,53 @@ ; end of the iteration, then no prime factor was found, so X is a prime. ;----------------------------------------------------------------------------- +; Description: Choose one of the various primeFactorXXX() routines. +; Input: +; - OP1:real=input +; Output: +; - OP1=1 if prime, or its smallest prime factor (>1) otherwise +; Throws: Err:Domain if OP1 is not an integer in the interval [2,2^32-1]. +PrimeFactor: + ; TODO: Replace the following validation with convertOP1ToU32(). I think we + ; just need to check for 0 and 1. Oh, and create a sqrtU32() replacement + ; for the floating point function _SqRoot(). + ; + ; Check 0 + bcall(_CkOP1FP0) + jr z, primeFactorError + ; Check 1 + bcall(_OP2Set1) ; OP2 = 1 + bcall(_CpOP1OP2) ; if OP1==1: ZF=1 + jr z, primeFactorError + bcall(_OP1ToOP4) ; save OP4 = X + ; Check integer >= 0 + bcall(_CkPosInt) ; if OP1 >= 0: ZF=1 + jr nz, primeFactorError + ; Check unsigned 32-bit integer, i.e. < 2^32. + call op2Set2Pow32PageTwo ; if OP1 >= 2^32: CF=0 + bcall(_CpOP1OP2) + jr nc, primeFactorError + +#ifdef USE_PRIME_FACTOR_FLOAT + jp primeFactorFloat +#else + #ifdef USE_PRIME_FACTOR_INT + jp primeFactorInt + #else + jp primeFactorMod + #endif +#endif + +primeFactorError: + bcall(_ErrDomain) ; throw exception + +primeFactorBreak: + bcall(_RunIndicOff) ; disable run indicator + res onInterrupt, (iy + onFlags) + bcall(_ErrBreak) ; throw exception + +;----------------------------------------------------------------------------- + #ifdef USE_PRIME_FACTOR_FLOAT ; Description determine if OP1 is a prime using floating point routines @@ -21,11 +114,6 @@ ; Output: OP1: 1 if prime, smallest prime factor if not ; Destroys: all registers, OP2, OP4, OP5, OP6 ; -; Benchmarks (6 MHz): -; - 4001*4001: 15 seconds -; - 10007*10007: 36 seconds -; - 19997*19997: 72 seconds -; - About 280 effective-candidates / second. primeFactorFloat: ; Check 2 bcall(_OP2Set2) ; OP2 = 2 @@ -104,13 +192,6 @@ primeFactorFloatCheckDiv: ;----------------------------------------------------------------------------- -primeFactorBreak: - bcall(_RunIndicOff) ; disable run indicator - res onInterrupt, (iy + onFlags) - bcall(_ErrBreak) ; throw exception - -;----------------------------------------------------------------------------- - #ifdef USE_PRIME_FACTOR_INT ; Description determine if OP1 is a prime using divU32U32() routine. This is @@ -119,30 +200,24 @@ primeFactorBreak: ; Input: OP1: an integer in the range of [2, 2^32-1]. ; Output: OP1: 1 if prime, smallest prime factor if not ; Destroys: all registers, OP1, OP2, OP3, OP4, OP5, OP6 -; -; Benchmarks (6 MHz): -; -; Using divU32U32(): -; - 4001*4001: 5 seconds -; - 10007*10007: 14 seconds -; - 19997*19997: 27 seconds -; - About 750-800 effective-candidates / second. +; Throws: if OP1 not an integer primeFactorInt: - ld hl, OP4 - call convertOP1ToU32 ; OP4=X - ; Calc root(X) to OP5, to get it out of the way. The sqrt() function could - ; be done using integer operations, but it's done only once in the routine, - ; so we don't gain much speed improvement. - bcall(_SqRoot) ; OP1 = sqrt(OP1), uses OP1-OP3 + bcall(_OP1ToOP4) ; OP4=X + call convertOP1ToU32 ; OP1=int(X); throws if not integer + ; Calc limit=sqrt(X). The sqrt() function could be done using integer + ; operations, but it's done only once in the routine, so we don't gain much + ; speed improvement. + bcall(_OP1ExOP4) ; OP1=X; OP4=int(X) + bcall(_SqRoot) ; OP1=sqrt(X), uses OP1-OP3 bcall(_RndGuard) - bcall(_Trunc) ; OP1 = trunc(sqrt(X)), uses OP1,OP2 - ld hl, OP5 - call convertOP1ToU32 ; OP5=limit=sqrt(X) + bcall(_Trunc) ; OP1=trunc(sqrt(X)), uses OP1,OP2 + call convertOP1ToU32 ; OP1=limit=int(trunc(sqrt(X))) + bcall(_OP1ToOP5) ; OP5=limit ; Check 2 ld a, 2 ld hl, OP6 call setU32ToA ; OP6=candidate=2 - ld de, OP4 + ld de, OP4 ; OP4=int(X) call cmpU32U32 ; if X==2: ZF=1 jr z, primeFactorIntYes ; Check divisible by 2 @@ -190,15 +265,16 @@ primeFactorIntLoop: call addU32ByA jr primeFactorIntLoop primeFactorIntNo: - ld hl, OP6 - call convertU32ToOP1 + bcall(_OP6ToOP1) ; OP1=candidate + call convertU32ToOP1 ; OP1=float(candidate) ret primeFactorIntYes: bcall(_OP1Set1) ret +; Description: Check if `candidate` (OP6) is an integer factor of `input` (OP4). ; Input: -; - OP4=X +; - OP4=input ; - OP6=candidate ; Output: ; - OP1=quotient @@ -223,46 +299,6 @@ primeFactorIntCheckDiv: ; Description determine if OP1 is a prime using the modU32ByBC() routine. This ; is 7X faster than primeFactorFloat(), and 2.5X faster than primeFactorInt(). ; -; Benchmarks (6 MHz, modU32ByBC): -; - 4001*4001: 2.4 seconds -; - 10007*10007: 5.5 seconds -; - 19997*19997: 10.5 seconds -; - 65521*65521: 33 seconds -; - About 2000 effective-candidates / second. -; -; Benchmarks (15 MHz, modU32ByBC): -; - 4001*4001: 1.0 seconds -; - 10007*10007: 2.3 seconds -; - 19997*19997: 4.2 seconds -; - 65521*65521: 12.9 seconds -; - About 5000 effective-candidates / second. -; -; Benchmarks (15 MHz, modOP1ByBC using (SP)): -; - 4001*4001: 0.85 seconds -; - 10007*10007: 1.6 seconds -; - 19997*19997: 2.9 seconds -; - 65521*65521: 9.0 seconds -; - About 7280 effective-candidates / second. -; -; Benchmarks (15 MHz, modHLIXByBC): -; - 4001*4001: 0.67 seconds -; - 10007*10007: 1.2 seconds -; - 19997*19997: 2.3 seconds -; - 65521*65521: 7.0 seconds -; - About 9360 effective-candidates / second. -; -; Benchmarks (15 MHz, modHLIXByBC, rearrange code assuming rare overflow): -; - 65521*65521: 6.7 seconds -; - About 9880 effective-candidates / second. -; -; Benchmarks (15 MHz, modHLIXByBC, use JR instead of JP on rare branch): -; - 65521*65521: 6.6 seconds -; - About 9927 effective-candidates / second -; -; Benchmarks (15 MHz, modHLIXByBC, remove unnecessary 'or a') -; - 65521*65521: 6.3 seconds -; - About 10400 effective-candidates / second -; ; Input: OP1: an integer in the range of [2, 2^32-1]. ; Output: OP1: 1 if prime, smallest prime factor if not ; Destroys: all registers, OP1-OP3 @@ -310,7 +346,7 @@ primeFactorModLoop: jr c, primeFactorModYes ; Check for ON/Break bit onInterrupt, (iy + onFlags) - jr nz, primeFactorBreak + jp nz, primeFactorBreak ; Check (6n-1) call primeFactorModCheckDiv ; ZF=1 if remainder==0 jr z, primeFactorModNo @@ -336,6 +372,7 @@ primeFactorModYes: bcall(_OP1Set1) ret +; Description: Check if `candidate` (BC) is an integer factor of `input` (OP1). ; Input: ; - OP1:u32=x ; - BC:u16=candidate @@ -345,7 +382,7 @@ primeFactorModYes: ; Destroys: A, DE, HL, OP3 ; Preserves: BC, OP1 primeFactorModCheckDiv: -#ifdef USE_PRIME_FACTOR_U32_BY_BC +#ifdef USE_PRIME_FACTOR_MOD_U32_BY_BC ld hl, OP1 ld de, OP3 call copyU32HLToDE ; OP3=x; preserves BC @@ -360,6 +397,8 @@ primeFactorModCheckDiv: or e ; if remainder==0: ZF=1 ret +;----------------------------------------------------------------------------- + ; Decription: Highly specialized version of modU32ByBC() to get the highest ; performance. For example, uses 'jp' instead 'jr' because 'jp' is faster. ; - The first version of this used (SP) to store the high16 bits. This makes @@ -415,45 +454,3 @@ modHLIXByBCCheckDivOverflow: or a ; reset CF sbc hl, bc ; HL(remainder) -= divisor jp modHLIXByBCCheckDivNextBit - -;----------------------------------------------------------------------------- - -; Description: Choose one of the various primeFactorXXX() routines. -; Input: -; - OP1:real=input -; Output: -; - OP1=1 if prime, or its smallest prime factor (>1) otherwise -; Throws: Err:Domain if OP1 is not an integer in the interval [2,2^32-1]. -PrimeFactor: - ; TODO: Replace the following validation with convertOP1ToU32(). I think we - ; just need to check for 0 and 1. Oh, and create a sqrtU32() replacement - ; for the floating point function _SqRoot(). - ; - ; Check 0 - bcall(_CkOP1FP0) - jr z, primeFactorError - ; Check 1 - bcall(_OP2Set1) ; OP2 = 1 - bcall(_CpOP1OP2) ; if OP1==1: ZF=1 - jr z, primeFactorError - bcall(_OP1ToOP4) ; save OP4 = X - ; Check integer >= 0 - bcall(_CkPosInt) ; if OP1 >= 0: ZF=1 - jr nz, primeFactorError - ; Check unsigned 32-bit integer, i.e. < 2^32. - call op2Set2Pow32PageTwo ; if OP1 >= 2^32: CF=0 - bcall(_CpOP1OP2) - jr nc, primeFactorError - -#ifdef USE_PRIME_FACTOR_FLOAT - jp primeFactorFloat -#else - #ifdef USE_PRIME_FACTOR_INT - jp primeFactorInt - #else - jp primeFactorMod - #endif -#endif - -primeFactorError: - bcall(_ErrDomain) ; throw exception From 59f6431f2f5b56ad21fda28870579c20e0d5eb47 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 10 Jul 2024 17:03:08 -0700 Subject: [PATCH 14/39] prime2.asm: readd modHLSPByBC(), guarded by USE_PRIME_FACTOR_MOD_HLSP_BY_BC, for benchmarking purposes --- docs/DEVELOPER.md | 19 +++++---- src/prime2.asm | 106 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 92 insertions(+), 33 deletions(-) diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index 546df2a2..d4c4fcf5 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -134,7 +134,7 @@ Here are some notes about how the `PRIM` algorithm works: implement a custom `mod(u32, u16)` function which is about 25% faster than the full `div(u32, u16)` function. - In v0.10, the inner loop of the `mod(u32,u16)` function was made 40-50% faster - using the following observations: + through the `modHLSPByBC()` function using the following observations: - The Z80 has only 16-bit registers, so the `u32` type must typically be stored in 4 bytes of RAM, and the `u32` operations must work against the 4 bytes of RAM. @@ -149,17 +149,20 @@ Here are some notes about how the `PRIM` algorithm works: `ex (sp), hl` instruction of the Z80 to swap the 2 halves back and forth. This made the `mod(u32,u16)` function about 40-50% faster compared to v0.9.0. -- In v0.13, the inner loop `mod(u32,u16)` was made another 28% faster. +- In v0.13, the inner loop `mod(u32,u16)` became another ~42% faster using the + `modHLIXByBC()` function: - I discovered that my Z80 instruction cheatsheet incorrectly stated that the `add ix, ix` did not exist. It does. - - Replacing the `ex (sp), hl; add hl, hl` combo with a `add ix, ix` gave us - a 25% speed improvement. - - Another 3-4% was gained by replacing a `rl e; rl d` combo with an `adc hl, + - Replacing the `ex (sp), hl; add hl, hl` combo with an `add ix, ix` + instruction gave us a ~29% speed improvement. + - Another ~4% was gained by replacing a `rl e; rl d` combo with an `adc hl, hl` instruction. + - Another ~5% was gained by deleting an unnecessary `or a` instruction. + - About 1-2% was gained through rearranging some code to eliminate a branch + in the common case, and selecting `jr` or `jp` judiciously. -I can think of one additional optimization that *may* give us a 10-20% speed -increase, but it would come at the cost of code that would be significantly -harder to maintain, so I don't think it's worth it. +Looking at the `modHLIXByBC()` routine, I cannot think of any additional +performance improvements. But who knows, I may have overlooked something. ### Prime Factor Improvements diff --git a/src/prime2.asm b/src/prime2.asm index df43c0bb..36cdad0d 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -29,7 +29,7 @@ ; - About 5079 effective-candidates / second. ; - USE_PRIME_FACTOR_MOD_HLSP_BY_BC ; - uses modHLSPByBC() to determine if `candidate` is a factor of `input` -; - Benchmarks (15 MHz, TilEm, modOP1ByBC using (SP)): +; - Benchmarks (15 MHz, TilEm, modHLSPByBC using (SP)): ; - 19997*19997: 2.9 seconds ; - 65521*65521: 9.0 seconds ; - About 7280 effective-candidates / second. @@ -110,10 +110,9 @@ primeFactorBreak: ; Description determine if OP1 is a prime using floating point routines ; provided by the TI-OS. This is the slowest. ; -; Input: OP1: an integer in the range of [2, 2^32-1]. -; Output: OP1: 1 if prime, smallest prime factor if not +; Input: OP1:real=input, an integer in the range of [2, 2^32-1]. +; Output: OP1:real=1 if prime, or the smallest prime factor if not ; Destroys: all registers, OP2, OP4, OP5, OP6 -; primeFactorFloat: ; Check 2 bcall(_OP2Set2) ; OP2 = 2 @@ -197,8 +196,8 @@ primeFactorFloatCheckDiv: ; Description determine if OP1 is a prime using divU32U32() routine. This is ; almost 3X fastger than primeFactorFloat() but I think we can better. ; -; Input: OP1: an integer in the range of [2, 2^32-1]. -; Output: OP1: 1 if prime, smallest prime factor if not +; Input: OP1:real=an integer in the range of [2, 2^32-1]. +; Output: OP1:real=1 if prime, or the smallest prime factor if not ; Destroys: all registers, OP1, OP2, OP3, OP4, OP5, OP6 ; Throws: if OP1 not an integer primeFactorInt: @@ -274,11 +273,11 @@ primeFactorIntYes: ; Description: Check if `candidate` (OP6) is an integer factor of `input` (OP4). ; Input: -; - OP4=input -; - OP6=candidate +; - OP4:u32=input +; - OP6:u32=candidate ; Output: -; - OP1=quotient -; - OP2=remainder +; - OP1:u32=quotient +; - OP2:u32=remainder ; - ZF=1 if remainder==0 ; Destroys: A, BC, DE, HL primeFactorIntCheckDiv: @@ -299,8 +298,8 @@ primeFactorIntCheckDiv: ; Description determine if OP1 is a prime using the modU32ByBC() routine. This ; is 7X faster than primeFactorFloat(), and 2.5X faster than primeFactorInt(). ; -; Input: OP1: an integer in the range of [2, 2^32-1]. -; Output: OP1: 1 if prime, smallest prime factor if not +; Input: OP1:real=an integer in the range of [2, 2^32-1]. +; Output: OP1:real=1 if prime, or the smallest prime factor if not ; Destroys: all registers, OP1-OP3 primeFactorMod: call pushRaw9Op1 ; FPS=[X]; HL=X @@ -389,9 +388,13 @@ primeFactorModCheckDiv: ex de, hl ; HL=OP3 call modU32ByBC ; DE:u16=remainder; destroys (*HL); preserves BC=candidate #else - ld ix, (OP1) ; IX=low16 - ld hl, (OP1+2) ; HL=high16 - call modHLIXByBC + #ifdef USE_PRIME_FACTOR_MOD_HLSP_BY_BC + call modHLSPByBC + #else + ld ix, (OP1) ; IX=low16 + ld hl, (OP1+2) ; HL=high16 + call modHLIXByBC + #endif #endif ld a, d or e ; if remainder==0: ZF=1 @@ -399,16 +402,69 @@ primeFactorModCheckDiv: ;----------------------------------------------------------------------------- -; Decription: Highly specialized version of modU32ByBC() to get the highest -; performance. For example, uses 'jp' instead 'jr' because 'jp' is faster. -; - The first version of this used (SP) to store the high16 bits. This makes -; PRIM about 45% faster than modU32ByBC(). -; - The next version uses the IX register instead of (SP) to store the high16 -; bits. This improves PRIM by another 25%. (I was using a Z80 instruction -; cheatsheet which incorrectly said that the `add ix, ix` instruction did not -; exist. But it does.) -; - Another 3-4% came from replacing `rl e; rl d; ex de, hl` with `ex -; de, hl; adc hl, hl`. +#ifdef USE_PRIME_FACTOR_MOD_HLSP_BY_BC + +; Decription: A specialized version of modU32ByBC() which is faster by storing +; 16-bits of the u32 in HL and the other 16-bits on the stack (SP). I +; implemented this version because my Z80 cheatsheet said (incorrectly) that +; the `add ix, ix` instruction did not exist. Once I realized that `add ix, ix` +; is available, I implemented modHLIXByBC() below. +; +; The benchmark says that this is about 45% faster than modU32ByBC(). +; +; Input: +; - OP1:u32=dividend +; - BC:u16=divisor +; Output: +; - DE:u16=remainder +; Destroys: A, HL +modHLSPByBC: + ; push the dividend (x) to a combination of HL and the stack + ld hl, (OP1+2) ; HL=high16 + push hl ; stack=[high16] + ld hl, (OP1) ; HL=low16 + ; + ld de, 0 ; DE=remainder + ld a, 32 +modHLSPByBCCheckDivLoop: + ; shift x by one bit to the left + add hl, hl + ex (sp), hl ; stack=[low16]; HL=high16 + adc hl, hl + ex (sp), hl ; stack=[high16]; HL=low16 + ; shift bit into remainder + rl e + rl d ; DE=remainder + ex de, hl ; HL=remainder; DE=dividend + jp c, modHLSPByBCCheckDivOverflow ; remainder overflowed, so substract + or a ; CF=0 + sbc hl, bc ; HL(remainder) -= divisor + jp nc, modHLSPByBCCheckDivNextBit + add hl, bc ; revert the subtraction + jp modHLSPByBCCheckDivNextBit +modHLSPByBCCheckDivOverflow: + or a ; reset CF + sbc hl, bc ; HL(remainder) -= divisor +modHLSPByBCCheckDivNextBit: + ex de, hl ; DE=remainder; HL=dividend + dec a + jp nz, modHLSPByBCCheckDivLoop + pop hl ; stack=[]; HL=high16 + ret + +#endif + +;----------------------------------------------------------------------------- + +; Decription: An improved version of modHLSPByBC() which uses IX instead of +; 2 bytes on the stack (SP). This means that the entire computation can be +; performed using just the Z80 registers, without touching RAM. This improves +; PRIM by another 25%. Another 3-4% comes from replacing the sequence of `rl e; +; rl d; ex de, hl` with `ex de, hl; adc hl, hl`. We get a few extra percent +; improvement from selecting a 'jr' or 'jp' instruction judiciously. And +; another 5 percent comes from from deleting an unnecessary 'or a' instruction +; in one of the branches. Overall, this version is a surprising 43% faster than +; modHLSPByBC(). See benchmarks above. ; ; Input: ; - HL:u16=high 16 bits of u32 dividend From bc5c6225711bb96b1b67b9c1f67b19598d829c75 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 11 Jul 2024 11:03:40 -0700 Subject: [PATCH 15/39] READM.md: use angle and degree unicode characters to make Example 4 easier to read --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6da494db..b570532f 100644 --- a/README.md +++ b/README.md @@ -332,8 +332,8 @@ the 4 ways that complex numbers can be entered into RPN83P: - `100 - i/(2*pi*60*(1e-5))` using `2ND LINK` - `100 + 250i` using `2ND i` -- `200 e^(i 10deg)` using `2ND ANGLE` -- `300 e^(i 0.1)` using `2ND ANGLE 2ND ANGLE` +- `200 ∠ 10°` using `2ND ANGLE` +- `300 ∠ 0.1` using `2ND ANGLE 2ND ANGLE` The keystrokes are: @@ -341,17 +341,17 @@ The keystrokes are: - Press `MODE` button, `downarrow`, `RECT`: ![MODE MenuRow 2](docs/images/menu-root-mode-2.png) - Press `100` `ENTER` -- Press `2` `PI` `*` `60` `*` `1 EE 5` `(-)` `*` `1/X` `(-)` (-265.26) -- Press `2ND LINK` (100-265.26i) -- Press `100` `2ND i` `250` `+` (200-15.26i) -- Press `200` `2ND ANGLE` `10` `+` (396.96+19.47i) -- Press `300` `2ND ANGLE` `2ND ANGLE` `0.1` `+` (695.46+49.42i) -- Press `4` `/` (173.89+12.35i) -- Press `PRAD` (174.30 e^(i 0.07) -- Press `PDEG` (174.30 e^(i 4.04deg)) +- Press `2` `PI` `*` `60` `*` `1 EE 5` `(-)` `*` `1/X` `(-)` (X: -265.26) +- Press `2ND LINK` (X: 100 i -265.26) +- Press `100` `2ND i` `250` `+` (X: 200 i -15.26) +- Press `200` `2ND ANGLE` `10` `+` (X: 396.96 i 19.47) +- Press `300` `2ND ANGLE` `2ND ANGLE` `0.1` `+` (X: 695.46 i 49.42) +- Press `4` `/` (X: 173.89 i 12.35) +- Press `PRAD` (X: 174.30 ∠ 0.07) +- Press `PDEG` (X: 174.30 ∠° 4.04) - Press `MATH` button `CPLX`: ![CPLX MenuRow 1](docs/images/menu-root-cplx-1.png) -- Press `CABS` (174.30) +- Press `CABS` (X: 174.30) ![RPN83P Example 4 GIF](docs/images/rpn83p-example4.gif) From 0791add66181df1ab90f92bad65b5d36e8b53441 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 11 Jul 2024 15:34:52 -0700 Subject: [PATCH 16/39] prime2.asm: remove unnecessary 'CheckDiv' substring from various labels; no code change --- src/prime2.asm | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/prime2.asm b/src/prime2.asm index 36cdad0d..4e4bc5cb 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -426,7 +426,7 @@ modHLSPByBC: ; ld de, 0 ; DE=remainder ld a, 32 -modHLSPByBCCheckDivLoop: +modHLSPByBCLoop: ; shift x by one bit to the left add hl, hl ex (sp), hl ; stack=[low16]; HL=high16 @@ -436,19 +436,19 @@ modHLSPByBCCheckDivLoop: rl e rl d ; DE=remainder ex de, hl ; HL=remainder; DE=dividend - jp c, modHLSPByBCCheckDivOverflow ; remainder overflowed, so substract + jp c, modHLSPByBCOverflow ; remainder overflowed, so substract or a ; CF=0 sbc hl, bc ; HL(remainder) -= divisor - jp nc, modHLSPByBCCheckDivNextBit + jp nc, modHLSPByBCNextBit add hl, bc ; revert the subtraction - jp modHLSPByBCCheckDivNextBit -modHLSPByBCCheckDivOverflow: + jp modHLSPByBCNextBit +modHLSPByBCOverflow: or a ; reset CF sbc hl, bc ; HL(remainder) -= divisor -modHLSPByBCCheckDivNextBit: +modHLSPByBCNextBit: ex de, hl ; DE=remainder; HL=dividend dec a - jp nz, modHLSPByBCCheckDivLoop + jp nz, modHLSPByBCLoop pop hl ; stack=[]; HL=high16 ret @@ -456,7 +456,7 @@ modHLSPByBCCheckDivNextBit: ;----------------------------------------------------------------------------- -; Decription: An improved version of modHLSPByBC() which uses IX instead of +; Description: An improved version of modHLSPByBC() which uses IX instead of ; 2 bytes on the stack (SP). This means that the entire computation can be ; performed using just the Z80 registers, without touching RAM. This improves ; PRIM by another 25%. Another 3-4% comes from replacing the sequence of `rl e; @@ -476,7 +476,7 @@ modHLSPByBCCheckDivNextBit: modHLIXByBC: ld de, 0 ; DE=remainder ld a, 32 -modHLIXByBCCheckDivLoop: +modHLIXByBCLoop: ; shift dividend by one bit to the left add ix, ix adc hl, hl @@ -486,7 +486,7 @@ modHLIXByBCCheckDivLoop: ; Use 'jr c' instead of 'jp c' because the common case is expected to be ; CF=0, so the branch is not taken, which means only 7 T cycles in the ; common case. - jr c, modHLIXByBCCheckDivOverflow ; remainder overflowed, so substract + jr c, modHLIXByBCOverflow ; remainder overflowed, so subtract sbc hl, bc ; HL(remainder) -= divisor ; I *think* CF=0 and CF=1 will occur in equal probability, so it makes ; almost no difference whether we use 'jr nc' or 'jp nc'. The 'jr nc' @@ -495,18 +495,18 @@ modHLIXByBCCheckDivLoop: ; instruction takes 10 cycles whether or not the branch is taken. The ; difference is so small, I prefer the predictability of 'jp nc' always ; taking 10 cycles. - jp nc, modHLIXByBCCheckDivNextBit + jp nc, modHLIXByBCNextBit add hl, bc ; revert the subtraction -modHLIXByBCCheckDivNextBit: +modHLIXByBCNextBit: ex de, hl ; DE=remainder; HL=dividend dec a ; Use 'jp nz' instead of 'jr nz' because 'jp nz' is faster in the common ; case of ZF=0 when the branch is taken 32 times. - jp nz, modHLIXByBCCheckDivLoop + jp nz, modHLIXByBCLoop ret -modHLIXByBCCheckDivOverflow: +modHLIXByBCOverflow: ; This branch (CF=1) is more rare than (CF=0) because it will happen only ; after the 16th iteration. or a ; reset CF sbc hl, bc ; HL(remainder) -= divisor - jp modHLIXByBCCheckDivNextBit + jp modHLIXByBCNextBit From b1fb95f5219a1fed42629dca95613dd97bce48fb Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 14 Jul 2024 13:17:42 -0700 Subject: [PATCH 17/39] prime2.asm: move terminating condition to end (do-while-loop); explain why seemingly incorrect terminating condition actually works for limit>=65531 --- src/Makefile | 2 +- src/help1.asm | 2 +- src/prime2.asm | 43 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/Makefile b/src/Makefile index 63f64bb7..98fc3862 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,13 +4,13 @@ SPASM_DIR := ../../spasm SPASM_INC := $(SPASM_DIR)/inc SPASM := $(SPASM_DIR)/spasm SPASM_FLAGS := -A -I $(SPASM_INC) -N +#SPASM_FLAGS := -A -I $(SPASM_INC) -N -DDEBUG SRCS := $(wildcard *.asm) # TI Flash app. Use -DDEBUG to activate functions in debug1.asm. rpn83p.8xk: $(SRCS) Makefile $(SPASM) $(SPASM_FLAGS) rpn83p.asm $@ - @#$(SPASM) $(SPASM_FLAGS) -DDEBUG rpn83p.asm $@ # TI assembly program. No longer works because the program is > 8 kiB. #rpn83p.8xp: $(SRCS) Makefile diff --git a/src/help1.asm b/src/help1.asm index 662f314d..09c34046 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "10)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "14)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/prime2.asm b/src/prime2.asm index 4e4bc5cb..d81ea3f3 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -339,13 +339,9 @@ primeFactorModSetup: ; OP2:u16=limit ; BC:u16=candidate primeFactorModLoop: - ld hl, (OP2) ; HL=limit - or a ; clear CF - sbc hl, bc ; CF=1 if candidate>limit - jr c, primeFactorModYes ; Check for ON/Break bit onInterrupt, (iy + onFlags) - jp nz, primeFactorBreak + jr nz, primeFactorBreak ; Check (6n-1) call primeFactorModCheckDiv ; ZF=1 if remainder==0 jr z, primeFactorModNo @@ -360,16 +356,45 @@ primeFactorModLoop: inc bc inc bc inc bc - jr primeFactorModLoop + ; Terminate if all candidates have been checked. + ; NOTE 1: At first glance, the 'sbc' instruction that checks for the + ; terminating (candidate>limit) will fail if `limit=sqrt(input)=65535` + ; because no 16-bit candiate value will satisfy the terminating condition. + ; It actually looks worse than that. The candidate prime factor increments + ; in steps of 6 (first by 2, then by 4) through each iteration of the loop, + ; so at the upper end, the candidate goes from 65531, to 65533, then to + ; 65537, which wraps to 1 since BC is an unsigned 16-bit integer. So it + ; looks like this terminating condition will fail for `limit>=65531`. + ; However, through pure luck, when the candidate wraps around to 1 (i.e. + ; 65537), the mod(u32,u16) function returns 0 (since 1 divides into any + ; number), so the primeFactorModCheckDiv() function will return ZF=1, which + ; then branches to 'primeFactorModNo', but returns the prime factor as *1*, + ; which then correctly identifies the dividend as a prime number. This is a + ; dirty hack, but the end result is that we don't need any additional code + ; to correctly handle `dividend>=65531^2`, which makes this loop faster. + ; If the size of the dividend is changed from u32 to a larger integer type, + ; the terminating condition *must* be reexamined. + ; NOTE 2: We can place the check for the terminating condition at the end + ; of the 'primeFactorModLoop' (i.e. a do-while-loop) instead of at the + ; beginning (i.e. a while-loop) without affecting correctness. The loop + ; will perform a handful of unnecessary iterations for `dividend<=121=11^2` + ; because the candidate must reach 11 before the loop terminates. But on + ; the flip side, moving the terminating condition to the end allows us to + ; eliminate an extra 'jp' instruction for each loop, which makes the PRIM + ; function faster for large input values. + ld hl, (OP2) ; HL=limit + or a ; clear CF + sbc hl, bc ; CF=1 if candidate>limit + jp nc, primeFactorModLoop +primeFactorModYes: + bcall(_OP1Set1) + ret primeFactorModNo: ld (OP1), bc ; OP1=candidate ld hl, 0 ld (OP1+2), hl call convertU32ToOP1 ; OP1=real(candidate) ret -primeFactorModYes: - bcall(_OP1Set1) - ret ; Description: Check if `candidate` (BC) is an integer factor of `input` (OP1). ; Input: From 9cc0464f222449b911a072f4ceef258f9f9932ba Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sun, 14 Jul 2024 23:09:35 -0700 Subject: [PATCH 18/39] USER_GUIDE_COMPLEX.md: replace 'it' with the subject that it is actually referring to --- docs/USER_GUIDE_COMPLEX.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/USER_GUIDE_COMPLEX.md b/docs/USER_GUIDE_COMPLEX.md index b15bd966..d8ef5ef9 100644 --- a/docs/USER_GUIDE_COMPLEX.md +++ b/docs/USER_GUIDE_COMPLEX.md @@ -89,8 +89,8 @@ For example, the number `1-2i` would be entered like this: Notice that the RPN83P follows the convention used by the HP-35s in rendering the complex number with an imaginary `i` delimiter between the two components. -The negative sign on the `-2` appears *after* the `i`, because it is a delimiter -not a multiplier of the number `-2`. +The negative sign on the `-2` appears *after* the `i`, because `i` is a +delimiter not a multiplier of the number `-2`. Pressing `2ND LINK` on a complex number performs the *reverse* operation. The complex number is broken up into its real components, with the real part going From a48488a486611dcf5ab56dd6d5ddc2d63a6e3e33 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 15 Jul 2024 10:44:20 -0700 Subject: [PATCH 19/39] README.md: fix typo, 'SIZ?' -> 'SSZ?' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b570532f..6e5d560e 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ bytes), `RPN83SAV` (140 byte), `RPN83STA` (272 bytes), and `RPN83STK` (120 to Summary of features: - traditional RPN stack (`X`, `Y`, `Z`, `T`), with `LASTX` register - - configurable stack levels between 4 and 8: `SSIZ`, `SIZ?` + - configurable stack levels between 4 and 8: `SSIZ`, `SSZ?` - input edit line with scrollable cursor using arrow keys - `LEFT`, `RIGHT`, `2ND LEFT`, `2ND RIGHT` - 8-line display showing 4 stack registers From 7caff9d93ddd21b72bdec2d54c933844b0b961f6 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 17 Jul 2024 10:55:17 -0700 Subject: [PATCH 20/39] prime2.asm: improve performance of PRIM by another 60-70%, total of 2.4X over v0.12 --- CHANGELOG.md | 18 +-- docs/USER_GUIDE.md | 8 +- src/help1.asm | 2 +- src/prime2.asm | 271 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 276 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fedb76a..d93d9137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,17 @@ - Unreleased - Change the criteria for using the small-i approximation to the following: N*i <~ 6e-5. - - Improve performance of `PRIM` by 43-67% - - convert `modOP1ByBC()` using the `(SP)` stack to `modHLIXByBC()` which - uses only the CPU registers without touching RAM - - speed increases ~43% on the TI-83+, TI-83+SE, TI-84+SE - - speed increases ~67% on the TI-Nspire w/ TI-84 keypad (my guess is - that the Z80 emulator cannot access the emulated RAM as fast as it can - access the emulated CPU registers) + - Improve performance of `PRIM` by 2.4X + - convert `modOP1ByBC()` to use the `IX` register instead of the stack + `(SP)`: 43-67% faster + - use DEIX instead of HLIX: ~12% faster + - process using in 8-bit chunks instead of 1-bit: ~18% faster + - use `A` register instead of `D` register for chunks: ~5% faster + - use nonrestoring division algorithm: ~11% faster + - unroll the 8-bit division loop 8 times: ~11% faster + - thanks go to the responders of [this Cemetech + thread](https://www.cemetech.net/forum/viewtopic.php?p=307636) for + improving the `modHLIXByBC()` algorithm - 0.12.0 (2024-06-24) - **Bug Fix**: update logic that determines when the comma `,` character can be inserted into the input buffer diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 41ecedc0..5c8748d6 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -2008,10 +2008,10 @@ times of the `PRIM` function for this number for various TI models that I own: | **Model** | **PRIM Running Time** | | --- | --- | -| TI-83+ (6 MHz) | 14.0 s | -| TI-83+SE (15 MHz) | 5.4 s | -| TI-84+SE (15 MHz) | 6.7 s | -| TI-Nspire w/ TI-84+ keypad | 4.9 s | +| TI-83+ (6 MHz) | 8.3 s | +| TI-83+SE (15 MHz) | 3.3 s | +| TI-84+SE (15 MHz) | 3.9 s | +| TI-Nspire w/ TI-84+ keypad | 3.1 s | During the calculation, the "run indicator" on the upper-right corner will be active. You can press the `ON` key to break from the `PRIM` loop with an `Err: diff --git a/src/help1.asm b/src/help1.asm index 09c34046..1570661d 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "14)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "17)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/prime2.asm b/src/prime2.asm index d81ea3f3..bddfc30e 100644 --- a/src/prime2.asm +++ b/src/prime2.asm @@ -33,7 +33,7 @@ ; - 19997*19997: 2.9 seconds ; - 65521*65521: 9.0 seconds ; - About 7280 effective-candidates / second. -; - USE_PRIME_FACTOR_MOD_HLIX_BY_BC (default) +; - USE_PRIME_FACTOR_MOD_HLIX_BY_BC ; - uses modHLIXByBC() to determine if `candidate` is a factor of `input` ; - Benchmarks (15 MHz, TilEm, modHLIXByBC): ; - 65521*65521: 7.0 seconds @@ -48,8 +48,16 @@ ; - Benchmarks (15 MHz, modHLIXByBC, remove unnecessary 'or a') ; - 65521*65521: 6.3 seconds ; - About 10400 effective-candidates / second +; - USE_PRIME_FACTOR_MOD_DEIX_BY_BC (default) +; - Benchmarks (15 MHz, modDEIXByBC) +; - 65521*65521: 3.8 seconds +; - About 17242 effective-candidates / second +; - thankss goes to the responders of the +; https://www.cemetech.net/forum/viewtopic.php?p=307636 thread for various +; ideas on improving this algorithm ; -; The modHLIXByBC() version is now 15X faster than the floating point version. +; The USE_PRIME_FACTOR_MOD_DEIX_BY_BC version is now 25X faster than the +; floating point version. ; ; All of these take advantage of the fact that every prime above 3 is of the ; form (6n-1) or (6n+1), where n=1,2,3,... It checks candidate divisors from 5 @@ -401,7 +409,6 @@ primeFactorModNo: ; - OP1:u32=x ; - BC:u16=candidate ; Output: -; - DE:u16=remainder ; - ZF=1 if remainder==0 ; Destroys: A, DE, HL, OP3 ; Preserves: BC, OP1 @@ -412,17 +419,29 @@ primeFactorModCheckDiv: call copyU32HLToDE ; OP3=x; preserves BC ex de, hl ; HL=OP3 call modU32ByBC ; DE:u16=remainder; destroys (*HL); preserves BC=candidate -#else - #ifdef USE_PRIME_FACTOR_MOD_HLSP_BY_BC - call modHLSPByBC - #else - ld ix, (OP1) ; IX=low16 - ld hl, (OP1+2) ; HL=high16 - call modHLIXByBC - #endif + ld a, d + or e ; if remainder==0: ZF=1 +#endif + +#ifdef USE_PRIME_FACTOR_MOD_HLSP_BY_BC + call modHLSPByBC + ld a, d + or e ; if remainder==0: ZF=1 #endif + +#ifdef USE_PRIME_FACTOR_MOD_HLIX_BY_BC + call modHLIXByBC ld a, d or e ; if remainder==0: ZF=1 +#endif + +; #ifdef USE_PRIME_FACTOR_MOD_DEIX_BY_BC + ld ix, (OP1) ; low16 + ld de, (OP1+2) ; high16 + call modDEIXByBC + ld a, h + or l ; if remainder==0: ZF=1 +; #endif ret ;----------------------------------------------------------------------------- @@ -481,6 +500,8 @@ modHLSPByBCNextBit: ;----------------------------------------------------------------------------- +#ifdef USE_PRIME_FACTOR_MOD_HLIX_BY_BC + ; Description: An improved version of modHLSPByBC() which uses IX instead of ; 2 bytes on the stack (SP). This means that the entire computation can be ; performed using just the Z80 registers, without touching RAM. This improves @@ -535,3 +556,231 @@ modHLIXByBCOverflow: or a ; reset CF sbc hl, bc ; HL(remainder) -= divisor jp modHLIXByBCNextBit + +#endif + +;----------------------------------------------------------------------------- + +; #ifdef USE_PRIME_FACTOR_MOD_DEIX_BY_BC + +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; +; This is an improved version of modHLIXByBC() which uses a nonrestoring +; division algorith, with various tricks for a 1.75X speed increase: chunking +; into 8 bit registers, using register A instead of A for chunking, using DEIX +; instead of HLIX for the dividend, unrolling the 8-bit loop. +; +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: AF +; Preserves: BC, DE, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + or a ; CF=0 + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + push ix + pop de + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + ; if the remainder is negative, restore it + ret nc + add hl, bc + ret +; Description: Process an 8-bit chunk of the dividend with the 8 loop +; iterations unrolled for performance. +; Input: +; - A:u8=8-bit chunks of the dividend +; Output: +; - HL:u16=remainder +modDEIXByBC8: +modDEIXByBC8Bit0: + jp c, modDEIXByBC8Bit0Neg +modDEIXByBC8Bit0Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit0PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit1 +modDEIXByBC8Bit0PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit1Pos +modDEIXByBC8Bit0Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit0NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit1Neg +modDEIXByBC8Bit0NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit1: + jp c, modDEIXByBC8Bit1Neg +modDEIXByBC8Bit1Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit1PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit2 +modDEIXByBC8Bit1PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit2Pos +modDEIXByBC8Bit1Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit1NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit2Neg +modDEIXByBC8Bit1NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit2: + jp c, modDEIXByBC8Bit2Neg +modDEIXByBC8Bit2Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit2PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit3 +modDEIXByBC8Bit2PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit3Pos +modDEIXByBC8Bit2Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit2NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit3Neg +modDEIXByBC8Bit2NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit3: + jp c, modDEIXByBC8Bit3Neg +modDEIXByBC8Bit3Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit3PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit4 +modDEIXByBC8Bit3PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit4Pos +modDEIXByBC8Bit3Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit3NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit4Neg +modDEIXByBC8Bit3NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit4: + jp c, modDEIXByBC8Bit4Neg +modDEIXByBC8Bit4Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit4PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit5 +modDEIXByBC8Bit4PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit5Pos +modDEIXByBC8Bit4Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit4NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit5Neg +modDEIXByBC8Bit4NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit5: + jp c, modDEIXByBC8Bit5Neg +modDEIXByBC8Bit5Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit5PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit6 +modDEIXByBC8Bit5PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit6Pos +modDEIXByBC8Bit5Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit5NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit6Neg +modDEIXByBC8Bit5NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit6: + jp c, modDEIXByBC8Bit6Neg +modDEIXByBC8Bit6Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit6PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit7 +modDEIXByBC8Bit6PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit7Pos +modDEIXByBC8Bit6Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit6NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit7Neg +modDEIXByBC8Bit6NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit7: + jp c, modDEIXByBC8Bit7Neg +modDEIXByBC8Bit7Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit7PosOverflow + sbc hl, bc ; remainder -= divisor + ret +modDEIXByBC8Bit7PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + or a ; always clear CF + ret +modDEIXByBC8Bit7Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit7NegOverflow + add hl, bc ; remainder += divisor + scf + ret +modDEIXByBC8Bit7NegOverflow: + add hl, bc ; remainder += divisor + ccf +; + ret + +; #endif From 8d9d22a07b0a1cafef26eadfbf781453b70a0d13 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 17 Jul 2024 11:06:23 -0700 Subject: [PATCH 21/39] misc/prime: benchmarks for various modDEIXByBC() implementations used by PRIM --- misc/prime/Makefile | 18 + misc/prime/modu32u16.asm | 1010 ++++++++++++++++++++++++++++++++++++++ misc/prime/prime.asm | 41 ++ misc/prime/print.asm | 72 +++ misc/prime/validate.asm | 205 ++++++++ 5 files changed, 1346 insertions(+) create mode 100644 misc/prime/Makefile create mode 100644 misc/prime/modu32u16.asm create mode 100644 misc/prime/prime.asm create mode 100644 misc/prime/print.asm create mode 100644 misc/prime/validate.asm diff --git a/misc/prime/Makefile b/misc/prime/Makefile new file mode 100644 index 00000000..8b6bb147 --- /dev/null +++ b/misc/prime/Makefile @@ -0,0 +1,18 @@ +TARGETS := prime.8xp validate.8xp + +SPASM_DIR := ../../../spasm +SPASM_INC := $(SPASM_DIR)/inc +SPASM := $(SPASM_DIR)/spasm +SPASM_FLAGS := -A -N -I $(SPASM_INC) \ + -DMOD_DEIX_BY_BC_NONRESTORING_CHUNK8_REGA_UNROLLED + +all: $(TARGETS) + +prime.8xp: prime.asm modu32u16.asm Makefile + $(SPASM) $(SPASM_FLAGS) $< $@ + +validate.8xp: validate.asm modu32u16.asm print.asm Makefile + $(SPASM) $(SPASM_FLAGS) $< $@ + +clean: + rm -f $(TARGETS) diff --git a/misc/prime/modu32u16.asm b/misc/prime/modu32u16.asm new file mode 100644 index 00000000..e0a8378a --- /dev/null +++ b/misc/prime/modu32u16.asm @@ -0,0 +1,1010 @@ +;----------------------------------------------------------------------------- +; Various implementations of the mod(u32,u16) function. +; +; The RESTORING division algorithm is fairly straightforward. See for example, +; https://tutorials.eeems.ca/Z80ASM/part4.htm. + +; The NONRESTORING algorithm is more obscure. The Wikipedia entry +; (https://en.wikipedia.org/wiki/Division_algorithm#Non-restoring_division) is +; impenetrable. A better explanation is the flowchart in this StackOverflow +; (https://stackoverflow.com/questions/12133810) post. However, there is a +; complexity when trying to implement that flowchart into a Z80 processor: the +; remainder (HL) requires an extra bit (17 bits total, instead of 16 bits) in +; addition to the Carry Flag (CF). So the extra bit of information gets encoded +; into 2 separate code paths, one for positive remainder and one for negative +; remainder. The resulting implementation looks twice as complex as the +; flowchart, but it's actually implementing the same thing. +; +; Benchmarks: +; - MOD_HLIX_BY_BC_RESTORING_MONOLITH (original): 20.5 s +; - MOD_HLIX_BY_BC_RESTORING_MONOLITH (remove 'jp'): 20.4 s +; - MOD_HLIX_BY_BC_RESTORING_UNROLLED: 19.5 s +; - MOD_HLIX_BY_BC_RESTORING_CHUNK8: 17.4 s +; - MOD_DEIX_BY_BC_RESTORING_CHUNK8: 15.6 s +; - MOD_DEIX_BY_BC_RESTORING_CHUNK8_REGA: 14.9 s +; - MOD_DEIX_BY_BC_RESTORING_CHUNK8_REGA_TAILLOOP: 15.8 s +; - MOD_DEIX_BY_BC_RESTORING_CHUNK8_REGA_UNROLLED: 13.4 s +; +; - MOD_HLIX_BY_BC_NONRESTORING_MONOLITH: 18.9 s +; - MOD_DEIX_BY_BC_NONRESTORING_CHUNK8: 14.4 s +; - MOD_DEIX_BY_BC_NONRESTORING_CHUNK8_REGA: 13.7 s +; - MOD_DEIX_BY_BC_NONRESTORING_CHUNK8_REGA_UNROLLED: 11.8 s +; - MOD_DEIX_BY_BC_NONRESTORING_CALC84MANIAC: 11.9 s +;----------------------------------------------------------------------------- + +#ifdef MOD_HLIX_BY_BC_RESTORING_MONOLITH +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ex de, hl + call modHLIXByBC + ex de, hl + ret + +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - HL:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - DE:u16=remainder +; Destroys: A, HL, IX +modHLIXByBC: + ld de, 0 ; DE=remainder + ld a, 32 +modHLIXByBCLoop: + add ix, ix + adc hl, hl + ex de, hl ; HL=remainder; DE=dividend + adc hl, hl + jr c, modHLIXByBCOverflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modHLIXByBCNextBit + add hl, bc ; revert the subtraction +modHLIXByBCNextBit: + ex de, hl ; DE=remainder; HL=dividend + dec a + jp nz, modHLIXByBCLoop + ret +modHLIXByBCOverflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + jp modHLIXByBCNextBit +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_HLIX_BY_BC_RESTORING_UNROLLED +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ex de, hl + call modHLIXByBC + ex de, hl + ret + +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - HL:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - DE:u16=remainder +; Destroys: A, HL, IX +modHLIXByBC: + ld de, 0 ; DE=remainder + call modHLIXByBCSansSpill + ; if divisor < $8000: spill into carry cannot occur + bit 7, b + jr nz, modHLIXByBCWithSpill + ; [[fallthrough]] +modHLIXByBCSansSpill: + ld a, 16 +modHLIXByBCSansSpillLoop: + add ix, ix + adc hl, hl + ex de, hl ; HL=remainder; DE=dividend + adc hl, hl + sbc hl, bc ; remainder -= divisor + jp nc, modHLIXByBCSansSpillNextBit + add hl, bc ; revert the subtraction +modHLIXByBCSansSpillNextBit: + ex de, hl ; DE=remainder; HL=dividend + dec a + jp nz, modHLIXByBCSansSpillLoop + ret +; +modHLIXByBCWithSpill: + ld a, 16 +modHLIXByBCWithSpillLoop: + add ix, ix + adc hl, hl + ex de, hl ; HL=remainder; DE=dividend + adc hl, hl + jr c, modHLIXByBCWithSpillOverflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modHLIXByBCWithSpillNextBit + add hl, bc ; revert the subtraction +modHLIXByBCWithSpillNextBit: + ex de, hl ; DE=remainder; HL=dividend + dec a + jp nz, modHLIXByBCWithSpillLoop + ret +modHLIXByBCWithSpillOverflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; duplicate modHLIXByBCWithSpillNextBit to save a 'jp' + ex de, hl ; DE=remainder; HL=dividend + dec a + jp nz, modHLIXByBCWithSpillLoop + ret +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_HLIX_BY_BC_RESTORING_CHUNK8 +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ex de, hl + call modHLIXByBC + ex de, hl + ret + +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - HL:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - DE:u16=remainder +; Destroys: A, HL, IX +modHLIXByBC: + ld de, 0 ; DE=remainder + call modHLIXByBC8 + ld h, l + call modHLIXByBC8 + push ix + pop hl + call modHLIXByBC8 + ld h, l + ; [[fallthrough]] +; Input: H:u8=high 8 bits of the shifted dividend +; Output: DE:u16=remainder +modHLIXByBC8: + ld a, 8 +modHLIXByBCLoop: + sla h + ex de, hl ; HL=remainder; DE=dividend + adc hl, hl + jr c, modHLIXByBCOverflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modHLIXByBCNextBit + add hl, bc ; revert the subtraction +modHLIXByBCNextBit: + ex de, hl ; DE=remainder; HL=dividend + dec a + jp nz, modHLIXByBCLoop + ret +modHLIXByBCOverflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + jp modHLIXByBCNextBit +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_DEIX_BY_BC_RESTORING_CHUNK8 +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + call modDEIXByBC8 + ld d, e + call modDEIXByBC8 + push ix + pop de + call modDEIXByBC8 + ld d, e + ; [[fallthrough]] +; Input: D:u8=high 8 bits of the shifted dividend +; Output: HL:u16=remainder +modDEIXByBC8: + ld a, 8 +modDEIXByBCLoop: + sla d + adc hl, hl + jr c, modDEIXByBCOverflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCNextBit + add hl, bc ; revert the subtraction +modDEIXByBCNextBit: + dec a + jp nz, modDEIXByBCLoop + ret +modDEIXByBCOverflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + dec a + jp nz, modDEIXByBCLoop + ret +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_DEIX_BY_BC_RESTORING_CHUNK8_REGA +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + push ix + pop de + ld a, d + call modDEIXByBC8 + ld a, e + ; [[fallthrough]] +; Input: A:u8=high 8 bits of the shifted dividend +; Output: HL:u16=remainder +modDEIXByBC8: + ld d, 8 +modDEIXByBCLoop: + rla + adc hl, hl + jr c, modDEIXByBCOverflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCNextBit + add hl, bc ; revert the subtraction +modDEIXByBCNextBit: + dec d + jp nz, modDEIXByBCLoop + ret +modDEIXByBCOverflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + dec d + jp nz, modDEIXByBCLoop + ret +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_DEIX_BY_BC_RESTORING_CHUNK8_REGA_TAILLOOP +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + push ix + pop de + ld a, d + call modDEIXByBC8 + ld a, e + ; [[fallthrough]] +; Input: A:u8=high 8 bits of the shifted dividend +; Output: HL:u16=remainder +modDEIXByBC8: + call modDEIXByBCTail4 +modDEIXByBCTail4: + call modDEIXByBCTail2 +modDEIXByBCTail2: + call modDEIXByBCTail1 +modDEIXByBCTail1: + rla + adc hl, hl + jr c, modDEIXByBCOverflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + ret nc + add hl, bc ; revert the subtraction + ret +modDEIXByBCOverflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ret +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_DEIX_BY_BC_RESTORING_CHUNK8_REGA_UNROLLED +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + push ix + pop de + ld a, d + call modDEIXByBC8 + ld a, e + ; [[fallthrough]] +; Input: A:u8=high 8 bits of the shifted dividend +; Output: HL:u16=remainder +modDEIXByBC8: + rla + adc hl, hl + jr c, modDEIXByBCBit0Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit1 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit1 +modDEIXByBCBit0Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit1: + rla + adc hl, hl + jr c, modDEIXByBCBit1Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit2 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit2 +modDEIXByBCBit1Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit2: + rla + adc hl, hl + jr c, modDEIXByBCBit2Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit3 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit3 +modDEIXByBCBit2Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit3: + rla + adc hl, hl + jr c, modDEIXByBCBit3Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit4 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit4 +modDEIXByBCBit3Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit4: + rla + adc hl, hl + jr c, modDEIXByBCBit4Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit5 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit5 +modDEIXByBCBit4Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit5: + rla + adc hl, hl + jr c, modDEIXByBCBit5Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit6 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit6 +modDEIXByBCBit5Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit6: + rla + adc hl, hl + jr c, modDEIXByBCBit6Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit7 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit7 +modDEIXByBCBit6Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit7: + rla + adc hl, hl + jr c, modDEIXByBCBit7Overflow ; remainder overflowed, so subtract + sbc hl, bc ; remainder -= divisor + jp nc, modDEIXByBCBit8 + add hl, bc ; revert the subtraction + jp modDEIXByBCBit8 +modDEIXByBCBit7Overflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + ; +modDEIXByBCBit8: + ret +#endif + +;============================================================================ + +#ifdef MOD_HLIX_BY_BC_NONRESTORING_MONOLITH +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ex de, hl + call modHLIXByBC + ex de, hl + ret + +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - HL:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - DE:u16=remainder +; Destroys: A, HL, IX +modHLIXByBC: + ld de, 0 ; DE=remainder + ld a, 32 + or a ; CF=0 +modHLIXByBCLoop: + jp c, modHLIXByBCNeg +modHLIXByBCPos: + add ix, ix + adc hl, hl + ex de, hl ; HL=remainder; DE=dividend + adc hl, hl + jr c, modHLIXByBCPosOverflow + sbc hl, bc ; remainder -= divisor + ex de, hl ; HL=dividend; DE=remainder + dec a + jp nz, modHLIXByBCLoop + jp modHLIXByBCEnd +modHLIXByBCPosOverflow: + or a ; CF=0 + sbc hl, bc ; remainder -= divisor + ex de, hl ; HL=dividend; DE=remainder + dec a + jp nz, modHLIXByBCPos + or a ; always clear CF + jp modHLIXByBCEnd +modHLIXByBCNeg: + add ix, ix + adc hl, hl + ex de, hl ; HL=remainder; DE=dividend + adc hl, hl + jp c, modHLIXByBCNegOverflow +modHLIXByBCNegPos: + ; Left-shift of A generated CF=0. Add M will always generate a negative + ; remainder. + add hl, bc ; remainder += divisor + ex de, hl ; HL=dividend; DE=remainder + dec a + jp nz, modHLIXByBCNeg + scf ; set the CF=1 before returning to indicate negative remainder + jp modHLIXByBCEnd +modHLIXByBCNegOverflow: + ; Left-shift of A generated CF=1. Add M, then look at the CF again. If it + ; transitions to a 1 again, then the resulting remainder becomes positive, + ; so set CF=0 for the next iteration. + add hl, bc ; remainder += divisor + ex de, hl ; HL=dividend; DE=remainder + ccf ; CF=0 if positive, 1 if negative + dec a + jp nz, modHLIXByBCLoop + ; [[fallthrough]] +modHLIXByBCEnd: + ; if the remainder is negative, restore it + ret nc + ex de, hl + add hl, bc + ex de, hl + ret +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_DEIX_BY_BC_NONRESTORING_CHUNK8 +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, DE, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + or a ; CF=0 + call modDEIXByBC8 + ld d, e + call modDEIXByBC8 + push ix + pop de + call modDEIXByBC8 + ld d, e + call modDEIXByBC8 + ; if the remainder is negative, restore it + ret nc + add hl, bc + ret +; Description: Process an 8-bit chunk of the dividend. +; Input: +; - D:u8=8-bit chunks of the dividend +; Output: +; - HL:u16=remainder +; - CF=1 if remainder is negative +modDEIXByBC8: + ld a, 8 +modDEIXByBC8Loop: + jp c, modDEIXByBC8Neg +modDEIXByBC8Pos: + sla d + adc hl, hl + jp c, modDEIXByBC8PosOverflow + sbc hl, bc ; remainder -= divisor + dec a + jp nz, modDEIXByBC8Loop + ret +modDEIXByBC8PosOverflow: + ; Left-shift of A generated CF=1. Subtract M will always produce a positive + ; remainder. + or a + sbc hl, bc ; remainder -= divisor + dec a + jp nz, modDEIXByBC8Pos + or a ; set CF=0 before returning to indicate positive remainder + ret +modDEIXByBC8Neg: + sla d + adc hl, hl + jp c, modDEIXByBC8NegOverflow + ; Left-shift of A generated CF=0. Add M will always generate a negative + ; remainder. + add hl, bc ; remainder += divisor + dec a + jp nz, modDEIXByBC8Neg + scf ; set CF=1 returning to indicate negative remainder + ret +modDEIXByBC8NegOverflow: + ; Left-shift of A generated CF=1. Add M generates a positive remainder + ; if CF=1 (which cascades to change the implicit sign bit to 0), or a + ; negative remainder if CF=0 (retains the implicit sign bit of 1). We can + ; capture both conditions by inverting the CF using CCF. + add hl, bc ; remainder += divisor + ccf + dec a + jp nz, modDEIXByBC8Loop + ret +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_DEIX_BY_BC_NONRESTORING_CHUNK8_REGA +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: A, D +; Preserves: BC, E, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + or a ; CF=0 + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + push ix + pop de + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + ; if the remainder is negative, restore it + ret nc + add hl, bc + ret +; Description: Process an 8-bit chunk of the dividend. +; Input: +; - A:u8=8-bit chunks of the dividend +; Output: +; - HL:u16=remainder +; - CF=1 if remainder is negative +; Destroys: D +modDEIXByBC8: + ld d, 8 +modDEIXByBC8Loop: + jp c, modDEIXByBC8Neg +modDEIXByBC8Pos: + ; We are here if the remainder A is positive. + rla + adc hl, hl + jp c, modDEIXByBC8PosOverflow + sbc hl, bc ; remainder -= divisor + dec d + jp nz, modDEIXByBC8Loop + ret +modDEIXByBC8PosOverflow: + ; Left-shift of A generated CF=1. Subtract M will always produce a positive + ; remainder. + or a + sbc hl, bc ; remainder -= divisor + dec d + jp nz, modDEIXByBC8Pos + or a ; set CF=0 before returning to indicate positive remainder + ret +modDEIXByBC8Neg: + ; We are here if the remainder A is negative. + rla + adc hl, hl + jp c, modDEIXByBC8NegOverflow + ; Left-shift of A generated CF=0. Add M will always generate a negative + ; remainder. + add hl, bc ; remainder += divisor + dec d + jp nz, modDEIXByBC8Neg + scf ; set CF=1 before returning to indicate negative remainder + ret +modDEIXByBC8NegOverflow: + ; Left-shift of A generated CF=1. Add M generates a positive remainder + ; if CF=1 (which cascades to change the implicit sign bit to 0), or a + ; negative remainder if CF=0 (retains the implicit sign bit of 1). We can + ; capture both conditions by inverting the CF using CCF. + add hl, bc ; remainder += divisor + ccf + dec d + jp nz, modDEIXByBC8Loop + ret +#endif + +;----------------------------------------------------------------------------- + +#ifdef MOD_DEIX_BY_BC_NONRESTORING_CHUNK8_REGA_UNROLLED +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend +; is divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: AF +; Preserves: BC, DE, IX +modDEIXByBC: + ld hl, 0 ; HL=remainder + or a ; CF=0 + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + push ix + pop de + ld a, d + call modDEIXByBC8 + ld a, e + call modDEIXByBC8 + ; if the remainder is negative, restore it + ret nc + add hl, bc + ret +; Description: Process an 8-bit chunk of the dividend with the 8 loop +; iterations unrolled for performance. +; Input: +; - A:u8=8-bit chunks of the dividend +; Output: +; - HL:u16=remainder +modDEIXByBC8: +modDEIXByBC8Bit0: + jp c, modDEIXByBC8Bit0Neg +modDEIXByBC8Bit0Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit0PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit1 +modDEIXByBC8Bit0PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit1Pos +modDEIXByBC8Bit0Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit0NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit1Neg +modDEIXByBC8Bit0NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit1: + jp c, modDEIXByBC8Bit1Neg +modDEIXByBC8Bit1Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit1PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit2 +modDEIXByBC8Bit1PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit2Pos +modDEIXByBC8Bit1Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit1NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit2Neg +modDEIXByBC8Bit1NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit2: + jp c, modDEIXByBC8Bit2Neg +modDEIXByBC8Bit2Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit2PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit3 +modDEIXByBC8Bit2PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit3Pos +modDEIXByBC8Bit2Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit2NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit3Neg +modDEIXByBC8Bit2NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit3: + jp c, modDEIXByBC8Bit3Neg +modDEIXByBC8Bit3Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit3PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit4 +modDEIXByBC8Bit3PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit4Pos +modDEIXByBC8Bit3Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit3NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit4Neg +modDEIXByBC8Bit3NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit4: + jp c, modDEIXByBC8Bit4Neg +modDEIXByBC8Bit4Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit4PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit5 +modDEIXByBC8Bit4PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit5Pos +modDEIXByBC8Bit4Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit4NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit5Neg +modDEIXByBC8Bit4NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit5: + jp c, modDEIXByBC8Bit5Neg +modDEIXByBC8Bit5Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit5PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit6 +modDEIXByBC8Bit5PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit6Pos +modDEIXByBC8Bit5Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit5NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit6Neg +modDEIXByBC8Bit5NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit6: + jp c, modDEIXByBC8Bit6Neg +modDEIXByBC8Bit6Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit6PosOverflow + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit7 +modDEIXByBC8Bit6PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + jp modDEIXByBC8Bit7Pos +modDEIXByBC8Bit6Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit6NegOverflow + add hl, bc ; remainder += divisor + jp modDEIXByBC8Bit7Neg +modDEIXByBC8Bit6NegOverflow: + add hl, bc ; remainder += divisor + ccf +; +modDEIXByBC8Bit7: + jp c, modDEIXByBC8Bit7Neg +modDEIXByBC8Bit7Pos: + rla + adc hl, hl + jp c, modDEIXByBC8Bit7PosOverflow + sbc hl, bc ; remainder -= divisor + ret +modDEIXByBC8Bit7PosOverflow: + or a + sbc hl, bc ; remainder -= divisor + or a ; always clear CF + ret +modDEIXByBC8Bit7Neg: + rla + adc hl, hl + jp c, modDEIXByBC8Bit7NegOverflow + add hl, bc ; remainder += divisor + scf + ret +modDEIXByBC8Bit7NegOverflow: + add hl, bc ; remainder += divisor + ccf +; + ret +#endif + +#ifdef MOD_DEIX_BY_BC_NONRESTORING_CALC84MANIAC +; Description: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend is +; divided by a u16 divisor. +; Input: +; - DE:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - HL:u16=remainder +; Destroys: AF, DE +modDEIXByBC: + ld hl, 0 ; HL=remainder + scf ; Initialize input CF + call modBCIter16 + push ix + pop de +; Process the dividend bits in DE +; Input: HL=remainder, DE=dividend bits, CF is set +; Output: HL=remainder, A=0, CF is set +modBCIter16: + ld a, d + call modBCIter8 + ld a, e +; Process the dividend bits in A +; Input: HL=remainder, A=dividend bits, CF is set +; Output: HL=remainder, A=0, CF is set +modBCIter8: + ; CF is set only on the first iteration +modBCPositiveLoop: + adc a, a ; Always sets CF when the result is zero + ret z +modBCPositiveContinue: + adc hl, hl + jr c, modBCOverflow ; remainder overflowed, so subtract +modBCNoOverflow: + sbc hl, bc ; HL(remainder) -= divisor + jp nc, modBCPositiveLoop +modBCNegativeLoop: + add a, a + jr z, modBCNegativeEnd +modBCNegativeContinue: + adc hl, hl + jr nc, modBCUnderflow ; remainder underflowed, so add + add hl, bc ; HL(remainder) += divisor + jp nc, modBCNegativeLoop + add a, a ; Always sets CF when the result is zero + ret z + adc hl, hl + jp nc, modBCNoOverflow +modBCOverflow: + or a ;reset CF + sbc hl, bc ; HL(remainder) -= divisor + add a, a ; Always sets CF when the result is zero + jp nz, modBCPositiveContinue + ret +; +modBCUnderflow: + add hl, bc ; HL(remainder) += divisor + add a, a + jp nz, modBCNegativeContinue +modBCNegativeEnd: + add hl, bc ; Restore remainder, always sets CF + ret +#endif diff --git a/misc/prime/prime.asm b/misc/prime/prime.asm new file mode 100644 index 00000000..e79ee3b5 --- /dev/null +++ b/misc/prime/prime.asm @@ -0,0 +1,41 @@ +;----------------------------------------------------------------------------- +; Test the performance of the modDEIXByBC() routine selected by the `-D` flag +; in the Makefile by searching for the prime factor of a large number +; (input=65521*65521). +; +; On a TI-83+/84+, this program runs at 6 MHz by default. The main loop +; iterates through every odd number between 3 and 65521 in steps of 2 (i.e. +; 32759 iterations). According to the benchmarks listed in modu32u16.asm, the +; reference implementation (MOD_HLIX_BY_BC_RESTORING_MONOLITH) takes 20.5 +; seconds. The fastest (MOD_DEIX_BY_BC_NONRESTORING_CHUNK8_REGA_UNROLLED) takes +; 11.8 seconds. +;----------------------------------------------------------------------------- + +.nolist +#include "ti83plus.inc" +.list +.org userMem - 2 +.db t2ByteTok, tasmCmp + +input equ (65521*65521) +inputHigh16 equ ((input & $ffff0000) >> 16) +inputLow16 equ (input & $ffff) + +main: + bcall(_homeup) + bcall(_ClrLCDFull) + ld bc, 3 ; check all odd numbers from 3 to 65521 +primeLoop: + ld de, inputHigh16 + ld ix, inputLow16 + call modDEIXByBC ; HL=remainder + inc bc + inc bc + ld a, h + or l + jp nz, primeLoop + ret + +#include "modu32u16.asm" + +.end diff --git a/misc/prime/print.asm b/misc/prime/print.asm new file mode 100644 index 00000000..89ce1ca4 --- /dev/null +++ b/misc/prime/print.asm @@ -0,0 +1,72 @@ +;----------------------------------------------------------------------------- +; Print routines. +;----------------------------------------------------------------------------- + +; Description: Print the 4 bytes pointed by HL in little-endian format at the +; current curCol/CurRow. +; Input: HL: pointer to 4 bytes +; Destroys: None +PrintU32AsHex: + push af + push bc + push de + push hl + ; Prep loop + ld b, 4 +printU32AsHexLoop: + ld a, (hl) + call printUnsignedAAsHex + inc hl + ld a, ' ' + bcall(_PutC) ; preserves B + djnz printU32AsHexLoop + pop hl + pop de + pop bc + pop af + ret + +; Description: Print HL as a 4-digit hex, little-endian format. +; Destroys: A +; Preserves: BC, DE, HL +PrintUnsignedHLAsHex: + ld a, l + call printUnsignedAAsHex + ld a, ' ' + bcall(_PutC) ; preserves B + ld a, h + call printUnsignedAAsHex + ret + +;----------------------------------------------------------------------------- + +; Description: Print A has a 2-digit hex. +; Destroys: A +; Preserves: BC, DE, HL +printUnsignedAAsHex: + push af + srl a + srl a + srl a + srl a + call convertAToChar + bcall(_PutC) + ; + pop af + and $0F + call convertAToChar + bcall(_PutC) + ret + +; Description: Convert A into an Ascii Char ('0'-'9','A'-'F'). +; Destroys: A +; Preserves: BC, DE, HL +convertAToChar: + cp 10 + jr c, convertAToCharDecimal + sub 10 + add a, 'A' + ret +convertAToCharDecimal: + add a, '0' + ret diff --git a/misc/prime/validate.asm b/misc/prime/validate.asm new file mode 100644 index 00000000..037c55e7 --- /dev/null +++ b/misc/prime/validate.asm @@ -0,0 +1,205 @@ +;----------------------------------------------------------------------------- +; Validate a particular mod(u32,u16) routine against the reference +; implementation (modHLIXByBCRef()). Examine a bunch of prime numbers < 2^32 +; and verify that the modDEIXByBC() routine gives the same answer as the +; reference. +; +; The Makefile rule for 'validate.8xp' should contain the `-D` define that +; identifies the specific mod(u32,u16) routine that is being tested. +;----------------------------------------------------------------------------- + +.nolist +#include "ti83plus.inc" +.list +.org userMem - 2 +.db t2ByteTok, tasmCmp + +;input equ (4001*4001) +;input equ (10007*10007) +;input equ (19997*19997) +;input equ (40013*40013) +input equ (65521*65521) +inputHigh16 equ ((input & $ffff0000) >> 16) +inputLow16 equ (input & $ffff) + +main: + ; Initialize OS. + call setFastSpeed + bcall(_homeup) + bcall(_ClrLCDFull) + + ; Initialize app. + ld hl, inputLow16 + ld (OP1), hl + ld hl, inputHigh16 + ld (OP1+2), hl + ; [[fallthrough]] + +; Description: Validate modDEIXByC() using the u32 at OP1, starting with 3 +; until a prime factor is found. +; Input: +; - OP1:u32=dividend +validate: + ld bc, 3 ; check all odd numbers from 3 to a prime factor of OP1 +validateLoop: + ; Check for ON/Break + bit onInterrupt, (iy + onFlags) + jr nz, validateBreak + ; + ld hl, (OP1+2) ; inputHigh16 + ld ix, (OP1) ; inputLow16 + call modHLIXByBCRef ; DE=remainder + push de ; stack=[expected] + ; + ld de, inputHigh16 + ld ix, inputLow16 + call modDEIXByBC ; HL=remainder + pop de ; stack=[]; DE=expected + ; compare the result + or a + push hl + sbc hl, de + pop hl + jr nz, validateFailed + ; + inc bc + inc bc + ld a, h + or l + jp nz, validateLoop + ; [[fallthrough]] + +validateOk: + ld hl, msgOk + bcall(_PutS) + bcall(_NewLine) + ret + +validateBreak: + ld hl, msgBreak + bcall(_PutS) + bcall(_NewLine) + ret + +; Description: Print failure message. +; Input: +; - OP1:u32=dividend +; - BC:u16=divisor +; - DE:u16=expected +; - HL:u16=observed +validateFailed: + push hl ; stack=[observed] + ; + ld hl, msgFailed + bcall(_PutS) + bcall(_NewLine) + ; + ld hl, msgDividend + bcall(_PutS) + ld hl, OP1 + call PrintU32AsHex + bcall(_NewLine) + ; + ld hl, msgDivisor + bcall(_PutS) + ld h, b + ld l, c + call PrintUnsignedHLAsHex + bcall(_NewLine) + ; + ld hl, msgExpected + bcall(_PutS) + ld h, d + ld l, e + call PrintUnsignedHLAsHex + bcall(_NewLine) + ; + ld hl, msgObserved + bcall(_PutS) + pop hl ; stack=[]; HL=observed + call PrintUnsignedHLAsHex + bcall(_NewLine) + ret + +msgOk: + .db "Ok", 0 + +msgFailed: + .db "Failed!", 0 + +msgBreak: + .db "Break", 0 + +msgDividend: + .db "D:", 0 + +msgDivisor: + .db "V:", 0 + +msgExpected: + .db "Exp:", 0 + +msgObserved: + .db "Obs:", 0 + +;----------------------------------------------------------------------------- + +; Decription: Calculate mod(u32,u16), i.e. the remainder when a u32 dividend is +; divided by a u16 divisor. This is the reference implementation, which uses +; the same algorithm as MOD_HLIX_BY_BC_RESTORING_MONOLITH. +; Input: +; - HL:u16=high 16 bits of u32 dividend +; - IX:u16=low 16 bits of u32 dividend +; - BC:u16=divisor +; Output: +; - DE:u16=remainder +; Destroys: A, HL, IX +modHLIXByBCRef: + ld de, 0 ; DE=remainder + ld a, 32 +modHLIXByBCRefLoop: + add ix, ix + adc hl, hl + ex de, hl ; HL=remainder; DE=dividend + adc hl, hl + jr c, modHLIXByBCRefOverflow ; remainder overflowed, so substract + sbc hl, bc ; remainder -= divisor + jp nc, modHLIXByBCRefNextBit + add hl, bc ; revert the subtraction +modHLIXByBCRefNextBit: + ex de, hl ; DE=remainder; HL=dividend + dec a + jp nz, modHLIXByBCRefLoop + ret +modHLIXByBCRefOverflow: + or a ; reset CF + sbc hl, bc ; remainder -= divisor + jp modHLIXByBCRefNextBit + +;----------------------------------------------------------------------------- + +; Description: Set CPU speed to 15 MHz on supported hardware (83+SE, 84+, +; 84+SE) on OS 1.13 or higher. See TI-83 Plus SDK reference for SetExSpeed(). +setFastSpeed: + call checkOS113 ; CF=0 if OS>=1.13 + ret c + ld a, $ff + bcall(_SetExSpeed) + ret + +; Description: Check if OS is >= 1.13. +; Output: CF=0 if OS >= 1.13; 1 otherwise +checkOS113: + bcall(_GetBaseVer) ; OS version in A (major), B (minor) + cp 1 ; CF=1 if major < 1; CF=0 and ZF=0 if major > 1 + ret nz ; returns if major >= 2 or < 1 + ld a, b + cp 13 ; CF=0 if minor version > 13, otherwise CF=1 + ret + +;----------------------------------------------------------------------------- + +#include "modu32u16.asm" +#include "print.asm" + +.end From 15d373dfe453859c027258c1155cc428ba22becd Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 17 Jul 2024 11:06:55 -0700 Subject: [PATCH 22/39] misc/cursorinfo/Makefile: update spasm-ng path --- misc/cursorinfo/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/cursorinfo/Makefile b/misc/cursorinfo/Makefile index b64f9149..196012a3 100644 --- a/misc/cursorinfo/Makefile +++ b/misc/cursorinfo/Makefile @@ -1,6 +1,6 @@ TARGETS := cursorinfo.8xp cursorinfo.8xk -SPASM_DIR := /home/brian/Downloads/TICalc/Z80/dev/spasm +SPASM_DIR := ../../../spasm SPASM_INC := $(SPASM_DIR)/inc SPASM := $(SPASM_DIR)/spasm From 1c62f13ec7aaef96df57967eb142ba4365ad9795 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 18 Jul 2024 11:06:08 -0700 Subject: [PATCH 23/39] modes2.asm: add Trig, Floating Display, Floating Digits to ColdInitMode() --- CHANGELOG.md | 12 ++++++++++-- src/help1.asm | 2 +- src/menuhandlers.asm | 2 +- src/modes2.asm | 24 ++++++++++++++++++++++-- src/rpn83p.asm | 7 +++++++ 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d93d9137..4f8f3514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ # Changelog - Unreleased - - Change the criteria for using the small-i approximation to the following: - N*i <~ 6e-5. + - TVM + - Change the criteria for using the small-i approximation to the + following: N*i <~ 6e-5. - Improve performance of `PRIM` by 2.4X - convert `modOP1ByBC()` to use the `IX` register instead of the stack `(SP)`: 43-67% faster @@ -14,6 +15,13 @@ - thanks go to the responders of [this Cemetech thread](https://www.cemetech.net/forum/viewtopic.php?p=307636) for improving the `modHLIXByBC()` algorithm + - MODE + - set Trig, Floating Display, and Display Digits settings to a known + state if the restoration of RPN83SAV fails, instead of inheriting the + modes from the TI-OS + - trig mode: RAD + - floating display: FIX + - display digits: floating - 0.12.0 (2024-06-24) - **Bug Fix**: update logic that determines when the comma `,` character can be inserted into the input buffer diff --git a/src/help1.asm b/src/help1.asm index 1570661d..85cf8b4a 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "17)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "18)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/menuhandlers.asm b/src/menuhandlers.asm index bcb5c574..a1b06c68 100644 --- a/src/menuhandlers.asm +++ b/src/menuhandlers.asm @@ -708,7 +708,7 @@ saveFormatDigits: ld a, (argValue) cp 10 jr c, saveFormatDigitsContinue - ld a, $FF ; variable number of digits, not fixed + ld a, fmtDigitsFloating ; "floating" number of digits, i.e. not fixed saveFormatDigitsContinue: ld (fmtDigits), a ret diff --git a/src/modes2.asm b/src/modes2.asm index c5be00fe..27ede242 100644 --- a/src/modes2.asm +++ b/src/modes2.asm @@ -7,9 +7,29 @@ ; Description: Initialize miscellaneous settings under the MODES menu. ColdInitModes: - ld a, commaEEModeNormal ; set ',EE' button to act as labeled on keypad + ; set ',EE' button to act as labeled on keypad + ld a, commaEEModeNormal ld (commaEEMode), a - ; + ; set to {..} mode instead of ".." mode ld a, formatRecordModeRaw ld (formatRecordMode), a + ; [[fallthrough]] + +; Description: Set the Trig, Display, and Display Digit modes which are shared +; with TI-OS to a known state. +; +; The complex result modes (RRES, CRES) are also shared with the TI-OS through +; the `numMode` variable (which is the same byte as the `fmtFlags`), but those +; are cold initialized by ColdInitComplex(), so we don't need to initialize +; them here. +; +; Destroys: A +coldInitOSModes: + ; set to RAD (instead of DEG) + res trigDeg, (iy + trigFlags) + ; set to FIX (instead of SCI or ENG) + res fmtExponent, (iy + fmtFlags) + ; set number of digits to "floating" + ld a, fmtDigitsFloating + ld (fmtDigits), a ret diff --git a/src/rpn83p.asm b/src/rpn83p.asm index 47125d10..92e91f4b 100644 --- a/src/rpn83p.asm +++ b/src/rpn83p.asm @@ -317,10 +317,17 @@ appStateInputBufFlags equ appStateRpnFlags + 1 ; u8 ; Copy of the trigFlags, fmtFlags, and fmtDigits as used by this app. When the ; app starts, these values will be used to configure the corresponding OS ; settings. When the app quits, the OS settings are copied here. +; +; The `numMode` flags (fmtReal, fmtRect, fmtPolar) are stored in the same +; location as the `fmtFlags`, so we don't have to save the `numMode flags +; separately. appStateTrigFlags equ appStateInputBufFlags + 1 ; u8 appStateFmtFlags equ appStateTrigFlags + 1 ; u8 appStateFmtDigits equ appStateFmtFlags + 1 ; u8 +; fmtDigits value that indicates "floating" number of digits +fmtDigitsFloating equ $ff + ; The result code after the execution of each handler. Success is code 0. If a ; TI-OS exception is thrown (through a `bcall(ErrXxx)`), the exception handler ; places a system error code into here. Before calling a handler, set this to 0 From 5aa1f28c1b10990f911448c950efbe7a3d73f90d Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 18 Jul 2024 12:09:09 -0700 Subject: [PATCH 24/39] show2.asm: move clearShowArea() to Flash Page 2 --- src/display.asm | 15 --------------- src/rpn83p.asm | 4 ++++ src/show2.asm | 17 +++++++++++++++++ src/showscanner.asm | 4 ++-- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/display.asm b/src/display.asm index 7dd9f438..2b0c41b2 100644 --- a/src/display.asm +++ b/src/display.asm @@ -799,21 +799,6 @@ displayShow: call putS ret -; Clear the display area used by the SHOW feature (errorCode, T, Z, Y, X). -; Input: none -; Destroys: A, B, HL -clearShowArea: - ld hl, errorCurCol*$100 + errorCurRow ; $(curCol)(curRow) - ld (curRow), hl - ld b, 5 -clearShowAreaLoop: - bcall(_EraseEOL) ; saves all registers - ld hl, (curRow) - inc l - ld (curRow), hl - djnz clearShowAreaLoop - ret - ;----------------------------------------------------------------------------- ; Low-level helper routines. ;----------------------------------------------------------------------------- diff --git a/src/rpn83p.asm b/src/rpn83p.asm index 92e91f4b..7fa59cd8 100644 --- a/src/rpn83p.asm +++ b/src/rpn83p.asm @@ -1856,6 +1856,10 @@ _FormatAToString equ _FormatAToStringLabel-branchTableBase .db 2 ; show2.asm +_ClearShowAreaLabel: +_ClearShowArea equ _ClearShowAreaLabel-branchTableBase + .dw ClearShowArea + .db 2 _FormShowableLabel: _FormShowable equ _FormShowableLabel-branchTableBase .dw FormShowable diff --git a/src/show2.asm b/src/show2.asm index 4c5647e7..7bfe89a0 100644 --- a/src/show2.asm +++ b/src/show2.asm @@ -13,6 +13,23 @@ ; entry. ;------------------------------------------------------------------------------ +; Clear the display area used by the SHOW feature (errorCode, T, Z, Y, X). +; Input: none +; Destroys: A, B, HL +ClearShowArea: + ld hl, errorCurCol*$100 + errorCurRow ; $(curCol)(curRow) + ld (curRow), hl + ld b, 5 +clearShowAreaLoop: + bcall(_EraseEOL) ; saves all registers + ld hl, (curRow) + inc l + ld (curRow), hl + djnz clearShowAreaLoop + ret + +;------------------------------------------------------------------------------ + ; Description: Format the number in OP1 to a NUL terminated string that shows ; all significant digits, suitable for a SHOW function. ; Input: diff --git a/src/showscanner.asm b/src/showscanner.asm index 7d7d9828..fab73255 100644 --- a/src/showscanner.asm +++ b/src/showscanner.asm @@ -9,7 +9,7 @@ ; Description: Read loop for the SHOW mode. processShowCommands: - call clearShowArea + bcall(_ClearShowArea) set rpnFlagsShowModeEnabled, (iy + rpnFlags) set dirtyFlagsStack, (iy + dirtyFlags) ; Show the new display. @@ -21,7 +21,7 @@ processShowCommands: cp a, kQuit jp z, mainExit ; Anything else exits the SHOW mode. - call clearShowArea + bcall(_ClearShowArea) res rpnFlagsShowModeEnabled, (iy + rpnFlags) set dirtyFlagsStack, (iy + dirtyFlags) set dirtyFlagsErrorCode, (iy + dirtyFlags) ; errorCode displays "SHOW" From 519250db08a7fd3acc373cad9918ac1e304e3071 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 18 Jul 2024 12:49:38 -0700 Subject: [PATCH 25/39] menuhandlers.asm: add CLD (clear display) function under CLR folder --- CHANGELOG.md | 5 + src/menudef.asm | 500 ++++++++++++++++++++++++------------------- src/menudef.txt | 7 +- src/menuhandlers.asm | 6 + 4 files changed, 291 insertions(+), 227 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f8f3514..02b0e0a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ - trig mode: RAD - floating display: FIX - display digits: floating + - CLR + - add `CLD` (clear display) menu under the `CLR` menu folder + - clear the display and re-render everything + - should almost never be needed, except during debugging + - analogous to the `CLD` command on the HP-42S - 0.12.0 (2024-06-24) - **Bug Fix**: update logic that determines when the comma `,` character can be inserted into the input buffer diff --git a/src/menudef.asm b/src/menudef.asm index b79b836a..313d013f 100644 --- a/src/menudef.asm +++ b/src/menudef.asm @@ -29,7 +29,7 @@ ; DO NOT EDIT: This file was autogenerated. ;----------------------------------------------------------------------------- -mMenuTableSize equ 272 +mMenuTableSize equ 277 mMenuTable: mNull: mNullId equ 0 @@ -148,7 +148,7 @@ mClearId equ 12 .dw mClearId ; id .dw mRootId ; parentId .dw mClearNameId ; nameId - .db 1 ; numRows + .db 2 ; numRows .dw mClearXId ; rowBeginId or altNameId .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector @@ -1672,10 +1672,56 @@ mClearTvmId equ 176 .dw 0 ; rowBeginId or altNameId .dw mClearTvmHandler ; handler (to be implemented) .dw 0 ; nameSelector +; MenuGroup CLR: children: row 1 +mClearDisplay: +mClearDisplayId equ 177 + .dw mClearDisplayId ; id + .dw mClearId ; parentId + .dw mClearDisplayNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mClearDisplayHandler ; handler (to be implemented) + .dw 0 ; nameSelector +mBlank178: +mBlank178Id equ 178 + .dw mBlank178Id ; id + .dw mClearId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector +mBlank179: +mBlank179Id equ 179 + .dw mBlank179Id ; id + .dw mClearId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector +mBlank180: +mBlank180Id equ 180 + .dw mBlank180Id ; id + .dw mClearId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector +mBlank181: +mBlank181Id equ 181 + .dw mBlank181Id ; id + .dw mClearId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector ; MenuGroup MODE: children ; MenuGroup MODE: children: row 0 mFix: -mFixId equ 177 +mFixId equ 182 .dw mFixId ; id .dw mModeId ; parentId .dw mFixNameId ; nameId @@ -1684,7 +1730,7 @@ mFixId equ 177 .dw mFixHandler ; handler (to be implemented) .dw mFixNameSelector ; nameSelector mSci: -mSciId equ 178 +mSciId equ 183 .dw mSciId ; id .dw mModeId ; parentId .dw mSciNameId ; nameId @@ -1693,7 +1739,7 @@ mSciId equ 178 .dw mSciHandler ; handler (to be implemented) .dw mSciNameSelector ; nameSelector mEng: -mEngId equ 179 +mEngId equ 184 .dw mEngId ; id .dw mModeId ; parentId .dw mEngNameId ; nameId @@ -1702,7 +1748,7 @@ mEngId equ 179 .dw mEngHandler ; handler (to be implemented) .dw mEngNameSelector ; nameSelector mRad: -mRadId equ 180 +mRadId equ 185 .dw mRadId ; id .dw mModeId ; parentId .dw mRadNameId ; nameId @@ -1711,7 +1757,7 @@ mRadId equ 180 .dw mRadHandler ; handler (to be implemented) .dw mRadNameSelector ; nameSelector mDeg: -mDegId equ 181 +mDegId equ 186 .dw mDegId ; id .dw mModeId ; parentId .dw mDegNameId ; nameId @@ -1721,7 +1767,7 @@ mDegId equ 181 .dw mDegNameSelector ; nameSelector ; MenuGroup MODE: children: row 1 mNumResultModeReal: -mNumResultModeRealId equ 182 +mNumResultModeRealId equ 187 .dw mNumResultModeRealId ; id .dw mModeId ; parentId .dw mNumResultModeRealNameId ; nameId @@ -1730,7 +1776,7 @@ mNumResultModeRealId equ 182 .dw mNumResultModeRealHandler ; handler (to be implemented) .dw mNumResultModeRealNameSelector ; nameSelector mNumResultModeComplex: -mNumResultModeComplexId equ 183 +mNumResultModeComplexId equ 188 .dw mNumResultModeComplexId ; id .dw mModeId ; parentId .dw mNumResultModeComplexNameId ; nameId @@ -1739,7 +1785,7 @@ mNumResultModeComplexId equ 183 .dw mNumResultModeComplexHandler ; handler (to be implemented) .dw mNumResultModeComplexNameSelector ; nameSelector mComplexModeRect: -mComplexModeRectId equ 184 +mComplexModeRectId equ 189 .dw mComplexModeRectId ; id .dw mModeId ; parentId .dw mComplexModeRectNameId ; nameId @@ -1748,7 +1794,7 @@ mComplexModeRectId equ 184 .dw mComplexModeRectHandler ; handler (to be implemented) .dw mComplexModeRectNameSelector ; nameSelector mComplexModeRad: -mComplexModeRadId equ 185 +mComplexModeRadId equ 190 .dw mComplexModeRadId ; id .dw mModeId ; parentId .dw mComplexModeRadNameId ; nameId @@ -1757,7 +1803,7 @@ mComplexModeRadId equ 185 .dw mComplexModeRadHandler ; handler (to be implemented) .dw mComplexModeRadNameSelector ; nameSelector mComplexModeDeg: -mComplexModeDegId equ 186 +mComplexModeDegId equ 191 .dw mComplexModeDegId ; id .dw mModeId ; parentId .dw mComplexModeDegNameId ; nameId @@ -1767,7 +1813,7 @@ mComplexModeDegId equ 186 .dw mComplexModeDegNameSelector ; nameSelector ; MenuGroup MODE: children: row 2 mSetRegSize: -mSetRegSizeId equ 187 +mSetRegSizeId equ 192 .dw mSetRegSizeId ; id .dw mModeId ; parentId .dw mSetRegSizeNameId ; nameId @@ -1776,7 +1822,7 @@ mSetRegSizeId equ 187 .dw mSetRegSizeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetRegSize: -mGetRegSizeId equ 188 +mGetRegSizeId equ 193 .dw mGetRegSizeId ; id .dw mModeId ; parentId .dw mGetRegSizeNameId ; nameId @@ -1784,9 +1830,9 @@ mGetRegSizeId equ 188 .dw 0 ; rowBeginId or altNameId .dw mGetRegSizeHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank189: -mBlank189Id equ 189 - .dw mBlank189Id ; id +mBlank194: +mBlank194Id equ 194 + .dw mBlank194Id ; id .dw mModeId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -1794,7 +1840,7 @@ mBlank189Id equ 189 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mSetStackSize: -mSetStackSizeId equ 190 +mSetStackSizeId equ 195 .dw mSetStackSizeId ; id .dw mModeId ; parentId .dw mSetStackSizeNameId ; nameId @@ -1803,7 +1849,7 @@ mSetStackSizeId equ 190 .dw mSetStackSizeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetStackSize: -mGetStackSizeId equ 191 +mGetStackSizeId equ 196 .dw mGetStackSizeId ; id .dw mModeId ; parentId .dw mGetStackSizeNameId ; nameId @@ -1813,7 +1859,7 @@ mGetStackSizeId equ 191 .dw 0 ; nameSelector ; MenuGroup MODE: children: row 3 mCommaEENormal: -mCommaEENormalId equ 192 +mCommaEENormalId equ 197 .dw mCommaEENormalId ; id .dw mModeId ; parentId .dw mCommaEENormalNameId ; nameId @@ -1822,7 +1868,7 @@ mCommaEENormalId equ 192 .dw mCommaEENormalHandler ; handler (to be implemented) .dw mCommaEENormalNameSelector ; nameSelector mCommaEESwapped: -mCommaEESwappedId equ 193 +mCommaEESwappedId equ 198 .dw mCommaEESwappedId ; id .dw mModeId ; parentId .dw mCommaEESwappedNameId ; nameId @@ -1830,9 +1876,9 @@ mCommaEESwappedId equ 193 .dw mCommaEESwappedAltNameId ; rowBeginId or altNameId .dw mCommaEESwappedHandler ; handler (to be implemented) .dw mCommaEESwappedNameSelector ; nameSelector -mBlank194: -mBlank194Id equ 194 - .dw mBlank194Id ; id +mBlank199: +mBlank199Id equ 199 + .dw mBlank199Id ; id .dw mModeId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -1840,7 +1886,7 @@ mBlank194Id equ 194 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mFormatRecordRaw: -mFormatRecordRawId equ 195 +mFormatRecordRawId equ 200 .dw mFormatRecordRawId ; id .dw mModeId ; parentId .dw mFormatRecordRawNameId ; nameId @@ -1849,7 +1895,7 @@ mFormatRecordRawId equ 195 .dw mFormatRecordRawHandler ; handler (to be implemented) .dw mFormatRecordRawNameSelector ; nameSelector mFormatRecordString: -mFormatRecordStringId equ 196 +mFormatRecordStringId equ 201 .dw mFormatRecordStringId ; id .dw mModeId ; parentId .dw mFormatRecordStringNameId ; nameId @@ -1860,7 +1906,7 @@ mFormatRecordStringId equ 196 ; MenuGroup STK: children ; MenuGroup STK: children: row 0 mStackDup: -mStackDupId equ 197 +mStackDupId equ 202 .dw mStackDupId ; id .dw mStackId ; parentId .dw mStackDupNameId ; nameId @@ -1869,7 +1915,7 @@ mStackDupId equ 197 .dw mStackDupHandler ; handler (to be implemented) .dw 0 ; nameSelector mStackRollUp: -mStackRollUpId equ 198 +mStackRollUpId equ 203 .dw mStackRollUpId ; id .dw mStackId ; parentId .dw mStackRollUpNameId ; nameId @@ -1878,7 +1924,7 @@ mStackRollUpId equ 198 .dw mStackRollUpHandler ; handler (to be implemented) .dw 0 ; nameSelector mStackRollDown: -mStackRollDownId equ 199 +mStackRollDownId equ 204 .dw mStackRollDownId ; id .dw mStackId ; parentId .dw mStackRollDownNameId ; nameId @@ -1887,7 +1933,7 @@ mStackRollDownId equ 199 .dw mStackRollDownHandler ; handler (to be implemented) .dw 0 ; nameSelector mStackDrop: -mStackDropId equ 200 +mStackDropId equ 205 .dw mStackDropId ; id .dw mStackId ; parentId .dw mStackDropNameId ; nameId @@ -1896,7 +1942,7 @@ mStackDropId equ 200 .dw mStackDropHandler ; handler (to be implemented) .dw 0 ; nameSelector mStackExchangeXY: -mStackExchangeXYId equ 201 +mStackExchangeXYId equ 206 .dw mStackExchangeXYId ; id .dw mStackId ; parentId .dw mStackExchangeXYNameId ; nameId @@ -1907,7 +1953,7 @@ mStackExchangeXYId equ 201 ; MenuGroup UNIT: children ; MenuGroup UNIT: children: row 0 mFToC: -mFToCId equ 202 +mFToCId equ 207 .dw mFToCId ; id .dw mUnitId ; parentId .dw mFToCNameId ; nameId @@ -1916,7 +1962,7 @@ mFToCId equ 202 .dw mFToCHandler ; handler (to be implemented) .dw 0 ; nameSelector mCToF: -mCToFId equ 203 +mCToFId equ 208 .dw mCToFId ; id .dw mUnitId ; parentId .dw mCToFNameId ; nameId @@ -1924,9 +1970,9 @@ mCToFId equ 203 .dw 0 ; rowBeginId or altNameId .dw mCToFHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank204: -mBlank204Id equ 204 - .dw mBlank204Id ; id +mBlank209: +mBlank209Id equ 209 + .dw mBlank209Id ; id .dw mUnitId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -1934,7 +1980,7 @@ mBlank204Id equ 204 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mInhgToHpa: -mInhgToHpaId equ 205 +mInhgToHpaId equ 210 .dw mInhgToHpaId ; id .dw mUnitId ; parentId .dw mInhgToHpaNameId ; nameId @@ -1943,7 +1989,7 @@ mInhgToHpaId equ 205 .dw mInhgToHpaHandler ; handler (to be implemented) .dw 0 ; nameSelector mHpaToInhg: -mHpaToInhgId equ 206 +mHpaToInhgId equ 211 .dw mHpaToInhgId ; id .dw mUnitId ; parentId .dw mHpaToInhgNameId ; nameId @@ -1953,7 +1999,7 @@ mHpaToInhgId equ 206 .dw 0 ; nameSelector ; MenuGroup UNIT: children: row 1 mMiToKm: -mMiToKmId equ 207 +mMiToKmId equ 212 .dw mMiToKmId ; id .dw mUnitId ; parentId .dw mMiToKmNameId ; nameId @@ -1962,7 +2008,7 @@ mMiToKmId equ 207 .dw mMiToKmHandler ; handler (to be implemented) .dw 0 ; nameSelector mKmToMi: -mKmToMiId equ 208 +mKmToMiId equ 213 .dw mKmToMiId ; id .dw mUnitId ; parentId .dw mKmToMiNameId ; nameId @@ -1970,9 +2016,9 @@ mKmToMiId equ 208 .dw 0 ; rowBeginId or altNameId .dw mKmToMiHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank209: -mBlank209Id equ 209 - .dw mBlank209Id ; id +mBlank214: +mBlank214Id equ 214 + .dw mBlank214Id ; id .dw mUnitId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -1980,7 +2026,7 @@ mBlank209Id equ 209 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mFtToM: -mFtToMId equ 210 +mFtToMId equ 215 .dw mFtToMId ; id .dw mUnitId ; parentId .dw mFtToMNameId ; nameId @@ -1989,7 +2035,7 @@ mFtToMId equ 210 .dw mFtToMHandler ; handler (to be implemented) .dw 0 ; nameSelector mMToFt: -mMToFtId equ 211 +mMToFtId equ 216 .dw mMToFtId ; id .dw mUnitId ; parentId .dw mMToFtNameId ; nameId @@ -1999,7 +2045,7 @@ mMToFtId equ 211 .dw 0 ; nameSelector ; MenuGroup UNIT: children: row 2 mInToCm: -mInToCmId equ 212 +mInToCmId equ 217 .dw mInToCmId ; id .dw mUnitId ; parentId .dw mInToCmNameId ; nameId @@ -2008,7 +2054,7 @@ mInToCmId equ 212 .dw mInToCmHandler ; handler (to be implemented) .dw 0 ; nameSelector mCmToIn: -mCmToInId equ 213 +mCmToInId equ 218 .dw mCmToInId ; id .dw mUnitId ; parentId .dw mCmToInNameId ; nameId @@ -2016,9 +2062,9 @@ mCmToInId equ 213 .dw 0 ; rowBeginId or altNameId .dw mCmToInHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank214: -mBlank214Id equ 214 - .dw mBlank214Id ; id +mBlank219: +mBlank219Id equ 219 + .dw mBlank219Id ; id .dw mUnitId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2026,7 +2072,7 @@ mBlank214Id equ 214 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mMilToMicron: -mMilToMicronId equ 215 +mMilToMicronId equ 220 .dw mMilToMicronId ; id .dw mUnitId ; parentId .dw mMilToMicronNameId ; nameId @@ -2035,7 +2081,7 @@ mMilToMicronId equ 215 .dw mMilToMicronHandler ; handler (to be implemented) .dw 0 ; nameSelector mMicronToMil: -mMicronToMilId equ 216 +mMicronToMilId equ 221 .dw mMicronToMilId ; id .dw mUnitId ; parentId .dw mMicronToMilNameId ; nameId @@ -2045,7 +2091,7 @@ mMicronToMilId equ 216 .dw 0 ; nameSelector ; MenuGroup UNIT: children: row 3 mLbsToKg: -mLbsToKgId equ 217 +mLbsToKgId equ 222 .dw mLbsToKgId ; id .dw mUnitId ; parentId .dw mLbsToKgNameId ; nameId @@ -2054,7 +2100,7 @@ mLbsToKgId equ 217 .dw mLbsToKgHandler ; handler (to be implemented) .dw 0 ; nameSelector mKgToLbs: -mKgToLbsId equ 218 +mKgToLbsId equ 223 .dw mKgToLbsId ; id .dw mUnitId ; parentId .dw mKgToLbsNameId ; nameId @@ -2062,9 +2108,9 @@ mKgToLbsId equ 218 .dw 0 ; rowBeginId or altNameId .dw mKgToLbsHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank219: -mBlank219Id equ 219 - .dw mBlank219Id ; id +mBlank224: +mBlank224Id equ 224 + .dw mBlank224Id ; id .dw mUnitId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2072,7 +2118,7 @@ mBlank219Id equ 219 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mOzToG: -mOzToGId equ 220 +mOzToGId equ 225 .dw mOzToGId ; id .dw mUnitId ; parentId .dw mOzToGNameId ; nameId @@ -2081,7 +2127,7 @@ mOzToGId equ 220 .dw mOzToGHandler ; handler (to be implemented) .dw 0 ; nameSelector mGToOz: -mGToOzId equ 221 +mGToOzId equ 226 .dw mGToOzId ; id .dw mUnitId ; parentId .dw mGToOzNameId ; nameId @@ -2091,7 +2137,7 @@ mGToOzId equ 221 .dw 0 ; nameSelector ; MenuGroup UNIT: children: row 4 mGalToL: -mGalToLId equ 222 +mGalToLId equ 227 .dw mGalToLId ; id .dw mUnitId ; parentId .dw mGalToLNameId ; nameId @@ -2100,7 +2146,7 @@ mGalToLId equ 222 .dw mGalToLHandler ; handler (to be implemented) .dw 0 ; nameSelector mLToGal: -mLToGalId equ 223 +mLToGalId equ 228 .dw mLToGalId ; id .dw mUnitId ; parentId .dw mLToGalNameId ; nameId @@ -2108,9 +2154,9 @@ mLToGalId equ 223 .dw 0 ; rowBeginId or altNameId .dw mLToGalHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank224: -mBlank224Id equ 224 - .dw mBlank224Id ; id +mBlank229: +mBlank229Id equ 229 + .dw mBlank229Id ; id .dw mUnitId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2118,7 +2164,7 @@ mBlank224Id equ 224 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mFlozToMl: -mFlozToMlId equ 225 +mFlozToMlId equ 230 .dw mFlozToMlId ; id .dw mUnitId ; parentId .dw mFlozToMlNameId ; nameId @@ -2127,7 +2173,7 @@ mFlozToMlId equ 225 .dw mFlozToMlHandler ; handler (to be implemented) .dw 0 ; nameSelector mMlToFloz: -mMlToFlozId equ 226 +mMlToFlozId equ 231 .dw mMlToFlozId ; id .dw mUnitId ; parentId .dw mMlToFlozNameId ; nameId @@ -2137,7 +2183,7 @@ mMlToFlozId equ 226 .dw 0 ; nameSelector ; MenuGroup UNIT: children: row 5 mCalToKj: -mCalToKjId equ 227 +mCalToKjId equ 232 .dw mCalToKjId ; id .dw mUnitId ; parentId .dw mCalToKjNameId ; nameId @@ -2146,7 +2192,7 @@ mCalToKjId equ 227 .dw mCalToKjHandler ; handler (to be implemented) .dw 0 ; nameSelector mKjToCal: -mKjToCalId equ 228 +mKjToCalId equ 233 .dw mKjToCalId ; id .dw mUnitId ; parentId .dw mKjToCalNameId ; nameId @@ -2154,9 +2200,9 @@ mKjToCalId equ 228 .dw 0 ; rowBeginId or altNameId .dw mKjToCalHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank229: -mBlank229Id equ 229 - .dw mBlank229Id ; id +mBlank234: +mBlank234Id equ 234 + .dw mBlank234Id ; id .dw mUnitId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2164,7 +2210,7 @@ mBlank229Id equ 229 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mHpToKw: -mHpToKwId equ 230 +mHpToKwId equ 235 .dw mHpToKwId ; id .dw mUnitId ; parentId .dw mHpToKwNameId ; nameId @@ -2173,7 +2219,7 @@ mHpToKwId equ 230 .dw mHpToKwHandler ; handler (to be implemented) .dw 0 ; nameSelector mKwToHp: -mKwToHpId equ 231 +mKwToHpId equ 236 .dw mKwToHpId ; id .dw mUnitId ; parentId .dw mKwToHpNameId ; nameId @@ -2184,7 +2230,7 @@ mKwToHpId equ 231 ; MenuGroup DATE: children ; MenuGroup DATE: children: row 0 mLeapYear: -mLeapYearId equ 232 +mLeapYearId equ 237 .dw mLeapYearId ; id .dw mDateId ; parentId .dw mLeapYearNameId ; nameId @@ -2193,7 +2239,7 @@ mLeapYearId equ 232 .dw mLeapYearHandler ; handler (to be implemented) .dw 0 ; nameSelector mDayOfWeek: -mDayOfWeekId equ 233 +mDayOfWeekId equ 238 .dw mDayOfWeekId ; id .dw mDateId ; parentId .dw mDayOfWeekNameId ; nameId @@ -2201,9 +2247,9 @@ mDayOfWeekId equ 233 .dw 0 ; rowBeginId or altNameId .dw mDayOfWeekHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank234: -mBlank234Id equ 234 - .dw mBlank234Id ; id +mBlank239: +mBlank239Id equ 239 + .dw mBlank239Id ; id .dw mDateId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2211,7 +2257,7 @@ mBlank234Id equ 234 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mDateToEpochDays: -mDateToEpochDaysId equ 235 +mDateToEpochDaysId equ 240 .dw mDateToEpochDaysId ; id .dw mDateId ; parentId .dw mDateToEpochDaysNameId ; nameId @@ -2220,7 +2266,7 @@ mDateToEpochDaysId equ 235 .dw mDateToEpochDaysHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochDaysToDate: -mEpochDaysToDateId equ 236 +mEpochDaysToDateId equ 241 .dw mEpochDaysToDateId ; id .dw mDateId ; parentId .dw mEpochDaysToDateNameId ; nameId @@ -2230,7 +2276,7 @@ mEpochDaysToDateId equ 236 .dw 0 ; nameSelector ; MenuGroup DATE: children: row 1 mDateRelatedToSeconds: -mDateRelatedToSecondsId equ 237 +mDateRelatedToSecondsId equ 242 .dw mDateRelatedToSecondsId ; id .dw mDateId ; parentId .dw mDateRelatedToSecondsNameId ; nameId @@ -2239,7 +2285,7 @@ mDateRelatedToSecondsId equ 237 .dw mDateRelatedToSecondsHandler ; handler (to be implemented) .dw 0 ; nameSelector mSecondsToDuration: -mSecondsToDurationId equ 238 +mSecondsToDurationId equ 243 .dw mSecondsToDurationId ; id .dw mDateId ; parentId .dw mSecondsToDurationNameId ; nameId @@ -2248,7 +2294,7 @@ mSecondsToDurationId equ 238 .dw mSecondsToDurationHandler ; handler (to be implemented) .dw 0 ; nameSelector mSecondsToTime: -mSecondsToTimeId equ 239 +mSecondsToTimeId equ 244 .dw mSecondsToTimeId ; id .dw mDateId ; parentId .dw mSecondsToTimeNameId ; nameId @@ -2257,7 +2303,7 @@ mSecondsToTimeId equ 239 .dw mSecondsToTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochSecondsToAppDateTime: -mEpochSecondsToAppDateTimeId equ 240 +mEpochSecondsToAppDateTimeId equ 245 .dw mEpochSecondsToAppDateTimeId ; id .dw mDateId ; parentId .dw mEpochSecondsToAppDateTimeNameId ; nameId @@ -2266,7 +2312,7 @@ mEpochSecondsToAppDateTimeId equ 240 .dw mEpochSecondsToAppDateTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochSecondsToUTCDateTime: -mEpochSecondsToUTCDateTimeId equ 241 +mEpochSecondsToUTCDateTimeId equ 246 .dw mEpochSecondsToUTCDateTimeId ; id .dw mDateId ; parentId .dw mEpochSecondsToUTCDateTimeNameId ; nameId @@ -2276,7 +2322,7 @@ mEpochSecondsToUTCDateTimeId equ 241 .dw 0 ; nameSelector ; MenuGroup DATE: children: row 2 mTimeZoneToHours: -mTimeZoneToHoursId equ 242 +mTimeZoneToHoursId equ 247 .dw mTimeZoneToHoursId ; id .dw mDateId ; parentId .dw mTimeZoneToHoursNameId ; nameId @@ -2285,7 +2331,7 @@ mTimeZoneToHoursId equ 242 .dw mTimeZoneToHoursHandler ; handler (to be implemented) .dw 0 ; nameSelector mHoursToTimeZone: -mHoursToTimeZoneId equ 243 +mHoursToTimeZoneId equ 248 .dw mHoursToTimeZoneId ; id .dw mDateId ; parentId .dw mHoursToTimeZoneNameId ; nameId @@ -2294,7 +2340,7 @@ mHoursToTimeZoneId equ 243 .dw mHoursToTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mDops: -mDopsId equ 244 +mDopsId equ 249 .dw mDopsId ; id .dw mDateId ; parentId .dw mDopsNameId ; nameId @@ -2303,7 +2349,7 @@ mDopsId equ 244 .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector mEpoch: -mEpochId equ 245 +mEpochId equ 250 .dw mEpochId ; id .dw mDateId ; parentId .dw mEpochNameId ; nameId @@ -2312,7 +2358,7 @@ mEpochId equ 245 .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector mClk: -mClkId equ 246 +mClkId equ 251 .dw mClkId ; id .dw mDateId ; parentId .dw mClkNameId ; nameId @@ -2323,7 +2369,7 @@ mClkId equ 246 ; MenuGroup DOPS: children ; MenuGroup DOPS: children: row 0 mDateShrink: -mDateShrinkId equ 247 +mDateShrinkId equ 252 .dw mDateShrinkId ; id .dw mDopsId ; parentId .dw mDateShrinkNameId ; nameId @@ -2332,7 +2378,7 @@ mDateShrinkId equ 247 .dw mDateShrinkHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateExtend: -mDateExtendId equ 248 +mDateExtendId equ 253 .dw mDateExtendId ; id .dw mDopsId ; parentId .dw mDateExtendNameId ; nameId @@ -2341,7 +2387,7 @@ mDateExtendId equ 248 .dw mDateExtendHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateCut: -mDateCutId equ 249 +mDateCutId equ 254 .dw mDateCutId ; id .dw mDopsId ; parentId .dw mDateCutNameId ; nameId @@ -2350,7 +2396,7 @@ mDateCutId equ 249 .dw mDateCutHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateLink: -mDateLinkId equ 250 +mDateLinkId equ 255 .dw mDateLinkId ; id .dw mDopsId ; parentId .dw mDateLinkNameId ; nameId @@ -2358,9 +2404,9 @@ mDateLinkId equ 250 .dw 0 ; rowBeginId or altNameId .dw mDateLinkHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank251: -mBlank251Id equ 251 - .dw mBlank251Id ; id +mBlank256: +mBlank256Id equ 256 + .dw mBlank256Id ; id .dw mDopsId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2370,7 +2416,7 @@ mBlank251Id equ 251 ; MenuGroup EPCH: children ; MenuGroup EPCH: children: row 0 mEpochUnix: -mEpochUnixId equ 252 +mEpochUnixId equ 257 .dw mEpochUnixId ; id .dw mEpochId ; parentId .dw mEpochUnixNameId ; nameId @@ -2379,7 +2425,7 @@ mEpochUnixId equ 252 .dw mEpochUnixHandler ; handler (to be implemented) .dw mEpochUnixNameSelector ; nameSelector mEpochNtp: -mEpochNtpId equ 253 +mEpochNtpId equ 258 .dw mEpochNtpId ; id .dw mEpochId ; parentId .dw mEpochNtpNameId ; nameId @@ -2388,7 +2434,7 @@ mEpochNtpId equ 253 .dw mEpochNtpHandler ; handler (to be implemented) .dw mEpochNtpNameSelector ; nameSelector mEpochGps: -mEpochGpsId equ 254 +mEpochGpsId equ 259 .dw mEpochGpsId ; id .dw mEpochId ; parentId .dw mEpochGpsNameId ; nameId @@ -2397,7 +2443,7 @@ mEpochGpsId equ 254 .dw mEpochGpsHandler ; handler (to be implemented) .dw mEpochGpsNameSelector ; nameSelector mEpochTios: -mEpochTiosId equ 255 +mEpochTiosId equ 260 .dw mEpochTiosId ; id .dw mEpochId ; parentId .dw mEpochTiosNameId ; nameId @@ -2406,7 +2452,7 @@ mEpochTiosId equ 255 .dw mEpochTiosHandler ; handler (to be implemented) .dw mEpochTiosNameSelector ; nameSelector mEpochY2k: -mEpochY2kId equ 256 +mEpochY2kId equ 261 .dw mEpochY2kId ; id .dw mEpochId ; parentId .dw mEpochY2kNameId ; nameId @@ -2416,7 +2462,7 @@ mEpochY2kId equ 256 .dw mEpochY2kNameSelector ; nameSelector ; MenuGroup EPCH: children: row 1 mEpochCustom: -mEpochCustomId equ 257 +mEpochCustomId equ 262 .dw mEpochCustomId ; id .dw mEpochId ; parentId .dw mEpochCustomNameId ; nameId @@ -2424,18 +2470,18 @@ mEpochCustomId equ 257 .dw mEpochCustomAltNameId ; rowBeginId or altNameId .dw mEpochCustomHandler ; handler (to be implemented) .dw mEpochCustomNameSelector ; nameSelector -mBlank258: -mBlank258Id equ 258 - .dw mBlank258Id ; id +mBlank263: +mBlank263Id equ 263 + .dw mBlank263Id ; id .dw mEpochId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows .dw 0 ; rowBeginId or altNameId .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector -mBlank259: -mBlank259Id equ 259 - .dw mBlank259Id ; id +mBlank264: +mBlank264Id equ 264 + .dw mBlank264Id ; id .dw mEpochId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2443,7 +2489,7 @@ mBlank259Id equ 259 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mEpochSetCustom: -mEpochSetCustomId equ 260 +mEpochSetCustomId equ 265 .dw mEpochSetCustomId ; id .dw mEpochId ; parentId .dw mEpochSetCustomNameId ; nameId @@ -2452,7 +2498,7 @@ mEpochSetCustomId equ 260 .dw mEpochSetCustomHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochGetCustom: -mEpochGetCustomId equ 261 +mEpochGetCustomId equ 266 .dw mEpochGetCustomId ; id .dw mEpochId ; parentId .dw mEpochGetCustomNameId ; nameId @@ -2463,7 +2509,7 @@ mEpochGetCustomId equ 261 ; MenuGroup CLK: children ; MenuGroup CLK: children: row 0 mGetNow: -mGetNowId equ 262 +mGetNowId equ 267 .dw mGetNowId ; id .dw mClkId ; parentId .dw mGetNowNameId ; nameId @@ -2472,7 +2518,7 @@ mGetNowId equ 262 .dw mGetNowHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowDate: -mGetNowDateId equ 263 +mGetNowDateId equ 268 .dw mGetNowDateId ; id .dw mClkId ; parentId .dw mGetNowDateNameId ; nameId @@ -2481,7 +2527,7 @@ mGetNowDateId equ 263 .dw mGetNowDateHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowTime: -mGetNowTimeId equ 264 +mGetNowTimeId equ 269 .dw mGetNowTimeId ; id .dw mClkId ; parentId .dw mGetNowTimeNameId ; nameId @@ -2490,7 +2536,7 @@ mGetNowTimeId equ 264 .dw mGetNowTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowAppDateTime: -mGetNowAppDateTimeId equ 265 +mGetNowAppDateTimeId equ 270 .dw mGetNowAppDateTimeId ; id .dw mClkId ; parentId .dw mGetNowAppDateTimeNameId ; nameId @@ -2499,7 +2545,7 @@ mGetNowAppDateTimeId equ 265 .dw mGetNowAppDateTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowUTCDateTime: -mGetNowUTCDateTimeId equ 266 +mGetNowUTCDateTimeId equ 271 .dw mGetNowUTCDateTimeId ; id .dw mClkId ; parentId .dw mGetNowUTCDateTimeNameId ; nameId @@ -2509,7 +2555,7 @@ mGetNowUTCDateTimeId equ 266 .dw 0 ; nameSelector ; MenuGroup CLK: children: row 1 mSetTimeZone: -mSetTimeZoneId equ 267 +mSetTimeZoneId equ 272 .dw mSetTimeZoneId ; id .dw mClkId ; parentId .dw mSetTimeZoneNameId ; nameId @@ -2518,7 +2564,7 @@ mSetTimeZoneId equ 267 .dw mSetTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetTimeZone: -mGetTimeZoneId equ 268 +mGetTimeZoneId equ 273 .dw mGetTimeZoneId ; id .dw mClkId ; parentId .dw mGetTimeZoneNameId ; nameId @@ -2527,7 +2573,7 @@ mGetTimeZoneId equ 268 .dw mGetTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mSetClockTimeZone: -mSetClockTimeZoneId equ 269 +mSetClockTimeZoneId equ 274 .dw mSetClockTimeZoneId ; id .dw mClkId ; parentId .dw mSetClockTimeZoneNameId ; nameId @@ -2536,7 +2582,7 @@ mSetClockTimeZoneId equ 269 .dw mSetClockTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetClockTimeZone: -mGetClockTimeZoneId equ 270 +mGetClockTimeZoneId equ 275 .dw mGetClockTimeZoneId ; id .dw mClkId ; parentId .dw mGetClockTimeZoneNameId ; nameId @@ -2545,7 +2591,7 @@ mGetClockTimeZoneId equ 270 .dw mGetClockTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mSetClock: -mSetClockId equ 271 +mSetClockId equ 276 .dw mSetClockId ; id .dw mClkId ; parentId .dw mSetClockNameId ; nameId @@ -2555,7 +2601,7 @@ mSetClockId equ 271 .dw 0 ; nameSelector ; Table of 2-byte pointers to names in the pool of strings below. -mMenuNameTableSize equ 280 +mMenuNameTableSize equ 281 mMenuNameTable: mNullNameId equ 0 .dw mNullName @@ -2911,211 +2957,213 @@ mClearStatNameId equ 175 .dw mClearStatName mClearTvmNameId equ 176 .dw mClearTvmName -mFixNameId equ 177 +mClearDisplayNameId equ 177 + .dw mClearDisplayName +mFixNameId equ 178 .dw mFixName -mFixAltNameId equ 178 +mFixAltNameId equ 179 .dw mFixAltName -mSciNameId equ 179 +mSciNameId equ 180 .dw mSciName -mSciAltNameId equ 180 +mSciAltNameId equ 181 .dw mSciAltName -mEngNameId equ 181 +mEngNameId equ 182 .dw mEngName -mEngAltNameId equ 182 +mEngAltNameId equ 183 .dw mEngAltName -mRadNameId equ 183 +mRadNameId equ 184 .dw mRadName -mRadAltNameId equ 184 +mRadAltNameId equ 185 .dw mRadAltName -mDegNameId equ 185 +mDegNameId equ 186 .dw mDegName -mDegAltNameId equ 186 +mDegAltNameId equ 187 .dw mDegAltName -mNumResultModeRealNameId equ 187 +mNumResultModeRealNameId equ 188 .dw mNumResultModeRealName -mNumResultModeRealAltNameId equ 188 +mNumResultModeRealAltNameId equ 189 .dw mNumResultModeRealAltName -mNumResultModeComplexNameId equ 189 +mNumResultModeComplexNameId equ 190 .dw mNumResultModeComplexName -mNumResultModeComplexAltNameId equ 190 +mNumResultModeComplexAltNameId equ 191 .dw mNumResultModeComplexAltName -mComplexModeRectNameId equ 191 +mComplexModeRectNameId equ 192 .dw mComplexModeRectName -mComplexModeRectAltNameId equ 192 +mComplexModeRectAltNameId equ 193 .dw mComplexModeRectAltName -mComplexModeRadNameId equ 193 +mComplexModeRadNameId equ 194 .dw mComplexModeRadName -mComplexModeRadAltNameId equ 194 +mComplexModeRadAltNameId equ 195 .dw mComplexModeRadAltName -mComplexModeDegNameId equ 195 +mComplexModeDegNameId equ 196 .dw mComplexModeDegName -mComplexModeDegAltNameId equ 196 +mComplexModeDegAltNameId equ 197 .dw mComplexModeDegAltName -mSetRegSizeNameId equ 197 +mSetRegSizeNameId equ 198 .dw mSetRegSizeName -mGetRegSizeNameId equ 198 +mGetRegSizeNameId equ 199 .dw mGetRegSizeName -mSetStackSizeNameId equ 199 +mSetStackSizeNameId equ 200 .dw mSetStackSizeName -mGetStackSizeNameId equ 200 +mGetStackSizeNameId equ 201 .dw mGetStackSizeName -mCommaEENormalNameId equ 201 +mCommaEENormalNameId equ 202 .dw mCommaEENormalName -mCommaEENormalAltNameId equ 202 +mCommaEENormalAltNameId equ 203 .dw mCommaEENormalAltName -mCommaEESwappedNameId equ 203 +mCommaEESwappedNameId equ 204 .dw mCommaEESwappedName -mCommaEESwappedAltNameId equ 204 +mCommaEESwappedAltNameId equ 205 .dw mCommaEESwappedAltName -mFormatRecordRawNameId equ 205 +mFormatRecordRawNameId equ 206 .dw mFormatRecordRawName -mFormatRecordRawAltNameId equ 206 +mFormatRecordRawAltNameId equ 207 .dw mFormatRecordRawAltName -mFormatRecordStringNameId equ 207 +mFormatRecordStringNameId equ 208 .dw mFormatRecordStringName -mFormatRecordStringAltNameId equ 208 +mFormatRecordStringAltNameId equ 209 .dw mFormatRecordStringAltName -mStackDupNameId equ 209 +mStackDupNameId equ 210 .dw mStackDupName -mStackRollUpNameId equ 210 +mStackRollUpNameId equ 211 .dw mStackRollUpName -mStackRollDownNameId equ 211 +mStackRollDownNameId equ 212 .dw mStackRollDownName -mStackDropNameId equ 212 +mStackDropNameId equ 213 .dw mStackDropName -mStackExchangeXYNameId equ 213 +mStackExchangeXYNameId equ 214 .dw mStackExchangeXYName -mFToCNameId equ 214 +mFToCNameId equ 215 .dw mFToCName -mCToFNameId equ 215 +mCToFNameId equ 216 .dw mCToFName -mInhgToHpaNameId equ 216 +mInhgToHpaNameId equ 217 .dw mInhgToHpaName -mHpaToInhgNameId equ 217 +mHpaToInhgNameId equ 218 .dw mHpaToInhgName -mMiToKmNameId equ 218 +mMiToKmNameId equ 219 .dw mMiToKmName -mKmToMiNameId equ 219 +mKmToMiNameId equ 220 .dw mKmToMiName -mFtToMNameId equ 220 +mFtToMNameId equ 221 .dw mFtToMName -mMToFtNameId equ 221 +mMToFtNameId equ 222 .dw mMToFtName -mInToCmNameId equ 222 +mInToCmNameId equ 223 .dw mInToCmName -mCmToInNameId equ 223 +mCmToInNameId equ 224 .dw mCmToInName -mMilToMicronNameId equ 224 +mMilToMicronNameId equ 225 .dw mMilToMicronName -mMicronToMilNameId equ 225 +mMicronToMilNameId equ 226 .dw mMicronToMilName -mLbsToKgNameId equ 226 +mLbsToKgNameId equ 227 .dw mLbsToKgName -mKgToLbsNameId equ 227 +mKgToLbsNameId equ 228 .dw mKgToLbsName -mOzToGNameId equ 228 +mOzToGNameId equ 229 .dw mOzToGName -mGToOzNameId equ 229 +mGToOzNameId equ 230 .dw mGToOzName -mGalToLNameId equ 230 +mGalToLNameId equ 231 .dw mGalToLName -mLToGalNameId equ 231 +mLToGalNameId equ 232 .dw mLToGalName -mFlozToMlNameId equ 232 +mFlozToMlNameId equ 233 .dw mFlozToMlName -mMlToFlozNameId equ 233 +mMlToFlozNameId equ 234 .dw mMlToFlozName -mCalToKjNameId equ 234 +mCalToKjNameId equ 235 .dw mCalToKjName -mKjToCalNameId equ 235 +mKjToCalNameId equ 236 .dw mKjToCalName -mHpToKwNameId equ 236 +mHpToKwNameId equ 237 .dw mHpToKwName -mKwToHpNameId equ 237 +mKwToHpNameId equ 238 .dw mKwToHpName -mLeapYearNameId equ 238 +mLeapYearNameId equ 239 .dw mLeapYearName -mDayOfWeekNameId equ 239 +mDayOfWeekNameId equ 240 .dw mDayOfWeekName -mDateToEpochDaysNameId equ 240 +mDateToEpochDaysNameId equ 241 .dw mDateToEpochDaysName -mEpochDaysToDateNameId equ 241 +mEpochDaysToDateNameId equ 242 .dw mEpochDaysToDateName -mDateRelatedToSecondsNameId equ 242 +mDateRelatedToSecondsNameId equ 243 .dw mDateRelatedToSecondsName -mSecondsToDurationNameId equ 243 +mSecondsToDurationNameId equ 244 .dw mSecondsToDurationName -mSecondsToTimeNameId equ 244 +mSecondsToTimeNameId equ 245 .dw mSecondsToTimeName -mEpochSecondsToAppDateTimeNameId equ 245 +mEpochSecondsToAppDateTimeNameId equ 246 .dw mEpochSecondsToAppDateTimeName -mEpochSecondsToUTCDateTimeNameId equ 246 +mEpochSecondsToUTCDateTimeNameId equ 247 .dw mEpochSecondsToUTCDateTimeName -mTimeZoneToHoursNameId equ 247 +mTimeZoneToHoursNameId equ 248 .dw mTimeZoneToHoursName -mHoursToTimeZoneNameId equ 248 +mHoursToTimeZoneNameId equ 249 .dw mHoursToTimeZoneName -mDopsNameId equ 249 +mDopsNameId equ 250 .dw mDopsName -mEpochNameId equ 250 +mEpochNameId equ 251 .dw mEpochName -mClkNameId equ 251 +mClkNameId equ 252 .dw mClkName -mDateShrinkNameId equ 252 +mDateShrinkNameId equ 253 .dw mDateShrinkName -mDateExtendNameId equ 253 +mDateExtendNameId equ 254 .dw mDateExtendName -mDateCutNameId equ 254 +mDateCutNameId equ 255 .dw mDateCutName -mDateLinkNameId equ 255 +mDateLinkNameId equ 256 .dw mDateLinkName -mEpochUnixNameId equ 256 +mEpochUnixNameId equ 257 .dw mEpochUnixName -mEpochUnixAltNameId equ 257 +mEpochUnixAltNameId equ 258 .dw mEpochUnixAltName -mEpochNtpNameId equ 258 +mEpochNtpNameId equ 259 .dw mEpochNtpName -mEpochNtpAltNameId equ 259 +mEpochNtpAltNameId equ 260 .dw mEpochNtpAltName -mEpochGpsNameId equ 260 +mEpochGpsNameId equ 261 .dw mEpochGpsName -mEpochGpsAltNameId equ 261 +mEpochGpsAltNameId equ 262 .dw mEpochGpsAltName -mEpochTiosNameId equ 262 +mEpochTiosNameId equ 263 .dw mEpochTiosName -mEpochTiosAltNameId equ 263 +mEpochTiosAltNameId equ 264 .dw mEpochTiosAltName -mEpochY2kNameId equ 264 +mEpochY2kNameId equ 265 .dw mEpochY2kName -mEpochY2kAltNameId equ 265 +mEpochY2kAltNameId equ 266 .dw mEpochY2kAltName -mEpochCustomNameId equ 266 +mEpochCustomNameId equ 267 .dw mEpochCustomName -mEpochCustomAltNameId equ 267 +mEpochCustomAltNameId equ 268 .dw mEpochCustomAltName -mEpochSetCustomNameId equ 268 +mEpochSetCustomNameId equ 269 .dw mEpochSetCustomName -mEpochGetCustomNameId equ 269 +mEpochGetCustomNameId equ 270 .dw mEpochGetCustomName -mGetNowNameId equ 270 +mGetNowNameId equ 271 .dw mGetNowName -mGetNowDateNameId equ 271 +mGetNowDateNameId equ 272 .dw mGetNowDateName -mGetNowTimeNameId equ 272 +mGetNowTimeNameId equ 273 .dw mGetNowTimeName -mGetNowAppDateTimeNameId equ 273 +mGetNowAppDateTimeNameId equ 274 .dw mGetNowAppDateTimeName -mGetNowUTCDateTimeNameId equ 274 +mGetNowUTCDateTimeNameId equ 275 .dw mGetNowUTCDateTimeName -mSetTimeZoneNameId equ 275 +mSetTimeZoneNameId equ 276 .dw mSetTimeZoneName -mGetTimeZoneNameId equ 276 +mGetTimeZoneNameId equ 277 .dw mGetTimeZoneName -mSetClockTimeZoneNameId equ 277 +mSetClockTimeZoneNameId equ 278 .dw mSetClockTimeZoneName -mGetClockTimeZoneNameId equ 278 +mGetClockTimeZoneNameId equ 279 .dw mGetClockTimeZoneName -mSetClockNameId equ 279 +mSetClockNameId equ 280 .dw mSetClockName ; Table of names as NUL terminated C strings. @@ -3473,6 +3521,8 @@ mClearStatName: .db 'C', 'L', ScapSigma, 0 mClearTvmName: .db "CLTV", 0 +mClearDisplayName: + .db "CLD", 0 mFixName: .db "FIX", 0 mFixAltName: diff --git a/src/menudef.txt b/src/menudef.txt index 7ec7b084..9983256b 100644 --- a/src/menudef.txt +++ b/src/menudef.txt @@ -311,6 +311,9 @@ MenuGroup root mRoot [ MenuItem CL mClearStat MenuItem CLTV mClearTvm ] + MenuRow [ + MenuItem CLD mClearDisplay + ] ] MenuGroup MODE mMode [ MenuRow [ @@ -338,8 +341,8 @@ MenuGroup root mRoot [ MenuItemAlt EE EE mCommaEENormal MenuItemAlt EE EE mCommaEESwapped MenuItem * * - MenuItemAlt mFormatRecordRaw - MenuItemAlt mFormatRecordString + MenuItemAlt mFormatRecordRaw + MenuItemAlt mFormatRecordString ] ] MenuGroup STK mStack [ diff --git a/src/menuhandlers.asm b/src/menuhandlers.asm index a1b06c68..ce8c80d2 100644 --- a/src/menuhandlers.asm +++ b/src/menuhandlers.asm @@ -1030,3 +1030,9 @@ mClearStatHandler: mClearTvmHandler: jp mTvmClearHandler + +mClearDisplayHandler: + bcall(_ClrLCDFull) + bcall(_ColdInitDisplay) + bcall(_InitDisplay) + ret From 37416143dcefd6c3b0464a1798e72e97562e45fd Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 18 Jul 2024 15:41:26 -0700 Subject: [PATCH 26/39] handlers.asm: CLEAR clears only to end of line if cursor is in the interior of inputBuf --- CHANGELOG.md | 8 ++++++++ src/handlers.asm | 22 +++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02b0e0a8..0d31e450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Changelog - Unreleased + - User Interface + - `CLEAR` button clears only to the end of the line if the cursor is in + the interior of the input buffer + - if the cursor is at the beginning or the end of the input buffer, + the entire buffer is cleared + - identical to the CLEAR button on the TI-89/92+/Voyage 200 + - similar to 2ND CLEAR on HP-50g in Algebraic mode (but not in RPN + mode) - TVM - Change the criteria for using the small-i approximation to the following: N*i <~ 6e-5. diff --git a/src/handlers.asm b/src/handlers.asm index b854b7a8..c2fbfefc 100644 --- a/src/handlers.asm +++ b/src/handlers.asm @@ -581,11 +581,27 @@ handleKeyClearNormal: ; mode with an empty inputBuf. bit rpnFlagsEditing, (iy + rpnFlags) jr z, handleKeyClearToEmptyInput - ; We are here if clearing the inputBuf. +handleKeyClearInEditMode: + ; We are here if CLEAR was pressed in edit mode. ld a, (inputBuf) or a - ; If the inputBuf has stuff, then clear the inputBuf. - jr nz, handleKeyClearToEmptyInput + jr z, handleKeyClearWhileClear +handleKeyClearInputBufNotEmpty: + ; We are here if the inputBuf is not empty. There are 3 cases: + ; 1) If cursor is at the beginning, clear the entire inputBuf. + ; 2) If cursor is at the end, clear the entire inputBuf. + ; 3) If cursor is in the middle, clear only to the end of line. + ld b, a ; B=inputBufLen + ld a, (cursorInputPos) ; A=cursorInputPos + or a + jr z, handleKeyClearToEmptyInput + cp b + jr z, handleKeyClearToEmptyInput +handleKeyClearToEndOfLine: + ; We are here if the cursor is in middle of inputBuf. Clear to end of line. + ld (inputBuf), a + set dirtyFlagsInput, (iy + dirtyFlags) + ret handleKeyClearWhileClear: ; We are here if CLEAR was pressed while the inputBuffer was already empty. ; Go into ClearAgain mode, where the next CLEAR invokes CLST. From f18739a495daad26fe06f06d0f26449bb18e8d2a Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 18 Jul 2024 18:04:07 -0700 Subject: [PATCH 27/39] errorcode1.asm: add 'Err: Archived', generated by STO or RCL using archived variables --- CHANGELOG.md | 3 +++ src/errorcode1.asm | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d31e450..5d1d50bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ - identical to the CLEAR button on the TI-89/92+/Voyage 200 - similar to 2ND CLEAR on HP-50g in Algebraic mode (but not in RPN mode) + - Variables + - print 'Err: Archived' error message if `STO` or `RCL` act on + a variable (A-Z,Theta) that's been archived - TVM - Change the criteria for using the small-i approximation to the following: N*i <~ 6e-5. diff --git a/src/errorcode1.asm b/src/errorcode1.asm index b70d44d9..b08e4c42 100644 --- a/src/errorcode1.asm +++ b/src/errorcode1.asm @@ -191,7 +191,8 @@ errorCodeLinkXmit equ 31 .dw errorStrUnknown ; 44 .dw errorStrUnknown ; 45 .dw errorStrUnknown ; 46 - .dw errorStrUnknown ; 47 +errorCodeArchived equ 47 + .dw errorStrArchived .dw errorStrUnknown ; 48 .dw errorStrUnknown ; 49 .dw errorStrUnknown ; 50 @@ -312,6 +313,11 @@ errorStrTolTooSmall: errorStrUndefined: .db "Err: Undefined", 0 ; indicates the system error "Undefined" +; Additional errors that RPN83P has encountered, verified by +; https://learn.cemetech.net/index.php?title=Z80:Error_Codes +errorStrArchived: + .db "Err: Archived", 0 + ; Start of RPN83P custom messages, which map to a specific custom handler code. ; This part of the application feels clunky, but I have not figure out an ; elegant architecture to handle the different types of handler From c084d184a6a92892e9c51a10fe733df6d258acb6 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 08:43:59 -0700 Subject: [PATCH 28/39] vars2.asm: add skeleton implementation of a 'clear variables' command, not implemented as noted --- CHANGELOG.md | 4 ++-- src/help1.asm | 2 +- src/menuhandlers.asm | 4 ++++ src/vars2.asm | 54 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/vars2.asm diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d1d50bb..18a9691d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,8 +33,8 @@ - trig mode: RAD - floating display: FIX - display digits: floating - - CLR - - add `CLD` (clear display) menu under the `CLR` menu folder + - CLR folder + - add `CLD` (clear display) menu item - clear the display and re-render everything - should almost never be needed, except during debugging - analogous to the `CLD` command on the HP-42S diff --git a/src/help1.asm b/src/help1.asm index 85cf8b4a..d4d768bc 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,7 +34,7 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "18)", Senter + .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "19)", Senter ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter diff --git a/src/menuhandlers.asm b/src/menuhandlers.asm index ce8c80d2..b58bb56f 100644 --- a/src/menuhandlers.asm +++ b/src/menuhandlers.asm @@ -1036,3 +1036,7 @@ mClearDisplayHandler: bcall(_ColdInitDisplay) bcall(_InitDisplay) ret + +; mClearVarsHandler: +; bcall(_ClearVars) +; ret diff --git a/src/vars2.asm b/src/vars2.asm new file mode 100644 index 00000000..4a6efc4d --- /dev/null +++ b/src/vars2.asm @@ -0,0 +1,54 @@ +;----------------------------------------------------------------------------- +; MIT License +; Copyright (c) 2024 Brian T. Park +; +; Routines for manipulating the storage variables (A-Z,Theta). +;----------------------------------------------------------------------------- + +; Description: Delete all single-letter variables (A-Z,Theta), unless they are +; archived. Certain variables are allowed to be archived by the OS: R, T, X, Y, +; and Theta. Interestingly, both N and Z can be archived even though there +; exist direct OS functions for _StoN() and _RclN(). +; +; Commented out for now, because the CLV command on the HP-42S deletes only a +; single variable, not *all* variables. Upon reflection, a CLV command is +; needed on the HP-42S because variables can be user-defined up to 7 characters +; long, so there needs to be a way to delete them. But on the TI-83+/84+, there +; are only fixed number of single-letter variables, 27. So it is not critical +; to be able to delete a single variable, or even the whole group of them. +; +; ClearVars: +; ; Set OP1 to the variable name 'A', 4 bytes: [RealObj, tA, 0, 0]. +; ld hl, RealObj + (tA * 256) +; ld (OP1), hl +; ld hl, 0 +; ld (OP1 + 2), hl +; ; Setup loop for A-Z and Theta. TI-OS cleverly placed the tTheta token +; ; ($5B) to be just after the tZ token ($5A), so we can just loop 27 times +; ; starting with tA ($41). +; ; variables. +; ld hl, OP1 +; ld b, 27 +; clearVarsLoop: +; call clearVar +; inc hl +; inc (hl) ; increment the variable name tA to tTheta +; dec hl +; djnz clearVarsLoop +; ld a, errorCodeVarsDeleted +; ld (handlerCode), a +; ret +; ; +; clearVar: +; push bc +; push hl +; bcall(_FindSym) ; CF=1 if not found; B!=0 if archived +; jr c, clearVarEnd +; ld a, b +; or a +; jr nz, clearVarEnd +; bcall(_DelVarNoArc) +; clearVarEnd: +; pop hl +; pop bc +; ret From bb1716526d53191d0cd6c7d3aa804d0f462fd15f Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 11:19:01 -0700 Subject: [PATCH 29/39] menudef.txt,menuhandlers.asm: add conversions for mpg,L/100km,kPa,psi --- CHANGELOG.md | 6 ++ src/const.asm | 16 +-- src/menudef.asm | 248 +++++++++++++++++++++++++++---------------- src/menudef.txt | 14 +-- src/menuhandlers.asm | 63 +++++++++++ 5 files changed, 236 insertions(+), 111 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18a9691d..db30ba59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,12 @@ - clear the display and re-render everything - should almost never be needed, except during debugging - analogous to the `CLD` command on the HP-42S + - UNIT + - add `>Lkm`: convert mpg (miles per US gallon) to L/100km (liters per + 100 km) + - add `>mpg`: convert L/100km to mpg + - add `>kPa`: convert psi (pounds per square inch) to kPa (kiloPascal) + - add `>psi`: convert kPa to psi - 0.12.0 (2024-06-24) - **Bug Fix**: update logic that determines when the comma `,` character can be inserted into the input buffer diff --git a/src/const.asm b/src/const.asm index e91959c6..85a069bd 100644 --- a/src/const.asm +++ b/src/const.asm @@ -116,17 +116,11 @@ op1SetMaxFloat: ;----------------------------------------------------------------------------- -; Description: Set OP1 to StandardGravity. -; Destroys: all, HL -; op1SetStandardGravity: -; ld hl, constStandardGravity -; jp move9ToOp1 - ; Description: Set OP2 to StandardGravity. ; Destroys: all, HL -; op2SetStandardGravity: -; ld hl, constStandardGravity -; jp move9ToOp2 +op2SetStandardGravity: + ld hl, constStandardGravity + jp move9ToOp2 ;----------------------------------------------------------------------------- @@ -241,8 +235,8 @@ constEuler: ; 2.7182818284594(0452) constMaxFloat: ; 9.9999999999999E99 .db $00, $E3, $99, $99, $99, $99, $99, $99, $99 -; constStandardGravity: ; g_0 = 9.806 65 m/s^2, exact -; .db $00, $80, $98, $06, $65, $00, $00, $00, $00 +constStandardGravity: ; g_0 = 9.806 65 m/s^2, exact + .db $00, $80, $98, $06, $65, $00, $00, $00, $00 constKmPerMi: ; 1.609344 km/mi, exact .db $00, $80, $16, $09, $34, $40, $00, $00, $00 diff --git a/src/menudef.asm b/src/menudef.asm index 313d013f..58e47363 100644 --- a/src/menudef.asm +++ b/src/menudef.asm @@ -29,7 +29,7 @@ ; DO NOT EDIT: This file was autogenerated. ;----------------------------------------------------------------------------- -mMenuTableSize equ 277 +mMenuTableSize equ 282 mMenuTable: mNull: mNullId equ 0 @@ -175,7 +175,7 @@ mUnitId equ 15 .dw mUnitId ; id .dw mRootId ; parentId .dw mUnitNameId ; nameId - .db 6 ; numRows + .db 7 ; numRows .dw mFToCId ; rowBeginId or altNameId .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector @@ -2227,10 +2227,56 @@ mKwToHpId equ 236 .dw 0 ; rowBeginId or altNameId .dw mKwToHpHandler ; handler (to be implemented) .dw 0 ; nameSelector +; MenuGroup UNIT: children: row 6 +mMpgToLkm: +mMpgToLkmId equ 237 + .dw mMpgToLkmId ; id + .dw mUnitId ; parentId + .dw mMpgToLkmNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mMpgToLkmHandler ; handler (to be implemented) + .dw 0 ; nameSelector +mLkmToMpg: +mLkmToMpgId equ 238 + .dw mLkmToMpgId ; id + .dw mUnitId ; parentId + .dw mLkmToMpgNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mLkmToMpgHandler ; handler (to be implemented) + .dw 0 ; nameSelector +mBlank239: +mBlank239Id equ 239 + .dw mBlank239Id ; id + .dw mUnitId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector +mPsiToKpa: +mPsiToKpaId equ 240 + .dw mPsiToKpaId ; id + .dw mUnitId ; parentId + .dw mPsiToKpaNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mPsiToKpaHandler ; handler (to be implemented) + .dw 0 ; nameSelector +mKpaToPsi: +mKpaToPsiId equ 241 + .dw mKpaToPsiId ; id + .dw mUnitId ; parentId + .dw mKpaToPsiNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mKpaToPsiHandler ; handler (to be implemented) + .dw 0 ; nameSelector ; MenuGroup DATE: children ; MenuGroup DATE: children: row 0 mLeapYear: -mLeapYearId equ 237 +mLeapYearId equ 242 .dw mLeapYearId ; id .dw mDateId ; parentId .dw mLeapYearNameId ; nameId @@ -2239,7 +2285,7 @@ mLeapYearId equ 237 .dw mLeapYearHandler ; handler (to be implemented) .dw 0 ; nameSelector mDayOfWeek: -mDayOfWeekId equ 238 +mDayOfWeekId equ 243 .dw mDayOfWeekId ; id .dw mDateId ; parentId .dw mDayOfWeekNameId ; nameId @@ -2247,9 +2293,9 @@ mDayOfWeekId equ 238 .dw 0 ; rowBeginId or altNameId .dw mDayOfWeekHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank239: -mBlank239Id equ 239 - .dw mBlank239Id ; id +mBlank244: +mBlank244Id equ 244 + .dw mBlank244Id ; id .dw mDateId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2257,7 +2303,7 @@ mBlank239Id equ 239 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mDateToEpochDays: -mDateToEpochDaysId equ 240 +mDateToEpochDaysId equ 245 .dw mDateToEpochDaysId ; id .dw mDateId ; parentId .dw mDateToEpochDaysNameId ; nameId @@ -2266,7 +2312,7 @@ mDateToEpochDaysId equ 240 .dw mDateToEpochDaysHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochDaysToDate: -mEpochDaysToDateId equ 241 +mEpochDaysToDateId equ 246 .dw mEpochDaysToDateId ; id .dw mDateId ; parentId .dw mEpochDaysToDateNameId ; nameId @@ -2276,7 +2322,7 @@ mEpochDaysToDateId equ 241 .dw 0 ; nameSelector ; MenuGroup DATE: children: row 1 mDateRelatedToSeconds: -mDateRelatedToSecondsId equ 242 +mDateRelatedToSecondsId equ 247 .dw mDateRelatedToSecondsId ; id .dw mDateId ; parentId .dw mDateRelatedToSecondsNameId ; nameId @@ -2285,7 +2331,7 @@ mDateRelatedToSecondsId equ 242 .dw mDateRelatedToSecondsHandler ; handler (to be implemented) .dw 0 ; nameSelector mSecondsToDuration: -mSecondsToDurationId equ 243 +mSecondsToDurationId equ 248 .dw mSecondsToDurationId ; id .dw mDateId ; parentId .dw mSecondsToDurationNameId ; nameId @@ -2294,7 +2340,7 @@ mSecondsToDurationId equ 243 .dw mSecondsToDurationHandler ; handler (to be implemented) .dw 0 ; nameSelector mSecondsToTime: -mSecondsToTimeId equ 244 +mSecondsToTimeId equ 249 .dw mSecondsToTimeId ; id .dw mDateId ; parentId .dw mSecondsToTimeNameId ; nameId @@ -2303,7 +2349,7 @@ mSecondsToTimeId equ 244 .dw mSecondsToTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochSecondsToAppDateTime: -mEpochSecondsToAppDateTimeId equ 245 +mEpochSecondsToAppDateTimeId equ 250 .dw mEpochSecondsToAppDateTimeId ; id .dw mDateId ; parentId .dw mEpochSecondsToAppDateTimeNameId ; nameId @@ -2312,7 +2358,7 @@ mEpochSecondsToAppDateTimeId equ 245 .dw mEpochSecondsToAppDateTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochSecondsToUTCDateTime: -mEpochSecondsToUTCDateTimeId equ 246 +mEpochSecondsToUTCDateTimeId equ 251 .dw mEpochSecondsToUTCDateTimeId ; id .dw mDateId ; parentId .dw mEpochSecondsToUTCDateTimeNameId ; nameId @@ -2322,7 +2368,7 @@ mEpochSecondsToUTCDateTimeId equ 246 .dw 0 ; nameSelector ; MenuGroup DATE: children: row 2 mTimeZoneToHours: -mTimeZoneToHoursId equ 247 +mTimeZoneToHoursId equ 252 .dw mTimeZoneToHoursId ; id .dw mDateId ; parentId .dw mTimeZoneToHoursNameId ; nameId @@ -2331,7 +2377,7 @@ mTimeZoneToHoursId equ 247 .dw mTimeZoneToHoursHandler ; handler (to be implemented) .dw 0 ; nameSelector mHoursToTimeZone: -mHoursToTimeZoneId equ 248 +mHoursToTimeZoneId equ 253 .dw mHoursToTimeZoneId ; id .dw mDateId ; parentId .dw mHoursToTimeZoneNameId ; nameId @@ -2340,7 +2386,7 @@ mHoursToTimeZoneId equ 248 .dw mHoursToTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mDops: -mDopsId equ 249 +mDopsId equ 254 .dw mDopsId ; id .dw mDateId ; parentId .dw mDopsNameId ; nameId @@ -2349,7 +2395,7 @@ mDopsId equ 249 .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector mEpoch: -mEpochId equ 250 +mEpochId equ 255 .dw mEpochId ; id .dw mDateId ; parentId .dw mEpochNameId ; nameId @@ -2358,7 +2404,7 @@ mEpochId equ 250 .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector mClk: -mClkId equ 251 +mClkId equ 256 .dw mClkId ; id .dw mDateId ; parentId .dw mClkNameId ; nameId @@ -2369,7 +2415,7 @@ mClkId equ 251 ; MenuGroup DOPS: children ; MenuGroup DOPS: children: row 0 mDateShrink: -mDateShrinkId equ 252 +mDateShrinkId equ 257 .dw mDateShrinkId ; id .dw mDopsId ; parentId .dw mDateShrinkNameId ; nameId @@ -2378,7 +2424,7 @@ mDateShrinkId equ 252 .dw mDateShrinkHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateExtend: -mDateExtendId equ 253 +mDateExtendId equ 258 .dw mDateExtendId ; id .dw mDopsId ; parentId .dw mDateExtendNameId ; nameId @@ -2387,7 +2433,7 @@ mDateExtendId equ 253 .dw mDateExtendHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateCut: -mDateCutId equ 254 +mDateCutId equ 259 .dw mDateCutId ; id .dw mDopsId ; parentId .dw mDateCutNameId ; nameId @@ -2396,7 +2442,7 @@ mDateCutId equ 254 .dw mDateCutHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateLink: -mDateLinkId equ 255 +mDateLinkId equ 260 .dw mDateLinkId ; id .dw mDopsId ; parentId .dw mDateLinkNameId ; nameId @@ -2404,9 +2450,9 @@ mDateLinkId equ 255 .dw 0 ; rowBeginId or altNameId .dw mDateLinkHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank256: -mBlank256Id equ 256 - .dw mBlank256Id ; id +mBlank261: +mBlank261Id equ 261 + .dw mBlank261Id ; id .dw mDopsId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2416,7 +2462,7 @@ mBlank256Id equ 256 ; MenuGroup EPCH: children ; MenuGroup EPCH: children: row 0 mEpochUnix: -mEpochUnixId equ 257 +mEpochUnixId equ 262 .dw mEpochUnixId ; id .dw mEpochId ; parentId .dw mEpochUnixNameId ; nameId @@ -2425,7 +2471,7 @@ mEpochUnixId equ 257 .dw mEpochUnixHandler ; handler (to be implemented) .dw mEpochUnixNameSelector ; nameSelector mEpochNtp: -mEpochNtpId equ 258 +mEpochNtpId equ 263 .dw mEpochNtpId ; id .dw mEpochId ; parentId .dw mEpochNtpNameId ; nameId @@ -2434,7 +2480,7 @@ mEpochNtpId equ 258 .dw mEpochNtpHandler ; handler (to be implemented) .dw mEpochNtpNameSelector ; nameSelector mEpochGps: -mEpochGpsId equ 259 +mEpochGpsId equ 264 .dw mEpochGpsId ; id .dw mEpochId ; parentId .dw mEpochGpsNameId ; nameId @@ -2443,7 +2489,7 @@ mEpochGpsId equ 259 .dw mEpochGpsHandler ; handler (to be implemented) .dw mEpochGpsNameSelector ; nameSelector mEpochTios: -mEpochTiosId equ 260 +mEpochTiosId equ 265 .dw mEpochTiosId ; id .dw mEpochId ; parentId .dw mEpochTiosNameId ; nameId @@ -2452,7 +2498,7 @@ mEpochTiosId equ 260 .dw mEpochTiosHandler ; handler (to be implemented) .dw mEpochTiosNameSelector ; nameSelector mEpochY2k: -mEpochY2kId equ 261 +mEpochY2kId equ 266 .dw mEpochY2kId ; id .dw mEpochId ; parentId .dw mEpochY2kNameId ; nameId @@ -2462,7 +2508,7 @@ mEpochY2kId equ 261 .dw mEpochY2kNameSelector ; nameSelector ; MenuGroup EPCH: children: row 1 mEpochCustom: -mEpochCustomId equ 262 +mEpochCustomId equ 267 .dw mEpochCustomId ; id .dw mEpochId ; parentId .dw mEpochCustomNameId ; nameId @@ -2470,18 +2516,18 @@ mEpochCustomId equ 262 .dw mEpochCustomAltNameId ; rowBeginId or altNameId .dw mEpochCustomHandler ; handler (to be implemented) .dw mEpochCustomNameSelector ; nameSelector -mBlank263: -mBlank263Id equ 263 - .dw mBlank263Id ; id +mBlank268: +mBlank268Id equ 268 + .dw mBlank268Id ; id .dw mEpochId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows .dw 0 ; rowBeginId or altNameId .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector -mBlank264: -mBlank264Id equ 264 - .dw mBlank264Id ; id +mBlank269: +mBlank269Id equ 269 + .dw mBlank269Id ; id .dw mEpochId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2489,7 +2535,7 @@ mBlank264Id equ 264 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mEpochSetCustom: -mEpochSetCustomId equ 265 +mEpochSetCustomId equ 270 .dw mEpochSetCustomId ; id .dw mEpochId ; parentId .dw mEpochSetCustomNameId ; nameId @@ -2498,7 +2544,7 @@ mEpochSetCustomId equ 265 .dw mEpochSetCustomHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochGetCustom: -mEpochGetCustomId equ 266 +mEpochGetCustomId equ 271 .dw mEpochGetCustomId ; id .dw mEpochId ; parentId .dw mEpochGetCustomNameId ; nameId @@ -2509,7 +2555,7 @@ mEpochGetCustomId equ 266 ; MenuGroup CLK: children ; MenuGroup CLK: children: row 0 mGetNow: -mGetNowId equ 267 +mGetNowId equ 272 .dw mGetNowId ; id .dw mClkId ; parentId .dw mGetNowNameId ; nameId @@ -2518,7 +2564,7 @@ mGetNowId equ 267 .dw mGetNowHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowDate: -mGetNowDateId equ 268 +mGetNowDateId equ 273 .dw mGetNowDateId ; id .dw mClkId ; parentId .dw mGetNowDateNameId ; nameId @@ -2527,7 +2573,7 @@ mGetNowDateId equ 268 .dw mGetNowDateHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowTime: -mGetNowTimeId equ 269 +mGetNowTimeId equ 274 .dw mGetNowTimeId ; id .dw mClkId ; parentId .dw mGetNowTimeNameId ; nameId @@ -2536,7 +2582,7 @@ mGetNowTimeId equ 269 .dw mGetNowTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowAppDateTime: -mGetNowAppDateTimeId equ 270 +mGetNowAppDateTimeId equ 275 .dw mGetNowAppDateTimeId ; id .dw mClkId ; parentId .dw mGetNowAppDateTimeNameId ; nameId @@ -2545,7 +2591,7 @@ mGetNowAppDateTimeId equ 270 .dw mGetNowAppDateTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowUTCDateTime: -mGetNowUTCDateTimeId equ 271 +mGetNowUTCDateTimeId equ 276 .dw mGetNowUTCDateTimeId ; id .dw mClkId ; parentId .dw mGetNowUTCDateTimeNameId ; nameId @@ -2555,7 +2601,7 @@ mGetNowUTCDateTimeId equ 271 .dw 0 ; nameSelector ; MenuGroup CLK: children: row 1 mSetTimeZone: -mSetTimeZoneId equ 272 +mSetTimeZoneId equ 277 .dw mSetTimeZoneId ; id .dw mClkId ; parentId .dw mSetTimeZoneNameId ; nameId @@ -2564,7 +2610,7 @@ mSetTimeZoneId equ 272 .dw mSetTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetTimeZone: -mGetTimeZoneId equ 273 +mGetTimeZoneId equ 278 .dw mGetTimeZoneId ; id .dw mClkId ; parentId .dw mGetTimeZoneNameId ; nameId @@ -2573,7 +2619,7 @@ mGetTimeZoneId equ 273 .dw mGetTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mSetClockTimeZone: -mSetClockTimeZoneId equ 274 +mSetClockTimeZoneId equ 279 .dw mSetClockTimeZoneId ; id .dw mClkId ; parentId .dw mSetClockTimeZoneNameId ; nameId @@ -2582,7 +2628,7 @@ mSetClockTimeZoneId equ 274 .dw mSetClockTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetClockTimeZone: -mGetClockTimeZoneId equ 275 +mGetClockTimeZoneId equ 280 .dw mGetClockTimeZoneId ; id .dw mClkId ; parentId .dw mGetClockTimeZoneNameId ; nameId @@ -2591,7 +2637,7 @@ mGetClockTimeZoneId equ 275 .dw mGetClockTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mSetClock: -mSetClockId equ 276 +mSetClockId equ 281 .dw mSetClockId ; id .dw mClkId ; parentId .dw mSetClockNameId ; nameId @@ -2601,7 +2647,7 @@ mSetClockId equ 276 .dw 0 ; nameSelector ; Table of 2-byte pointers to names in the pool of strings below. -mMenuNameTableSize equ 281 +mMenuNameTableSize equ 285 mMenuNameTable: mNullNameId equ 0 .dw mNullName @@ -3081,89 +3127,97 @@ mHpToKwNameId equ 237 .dw mHpToKwName mKwToHpNameId equ 238 .dw mKwToHpName -mLeapYearNameId equ 239 +mMpgToLkmNameId equ 239 + .dw mMpgToLkmName +mLkmToMpgNameId equ 240 + .dw mLkmToMpgName +mPsiToKpaNameId equ 241 + .dw mPsiToKpaName +mKpaToPsiNameId equ 242 + .dw mKpaToPsiName +mLeapYearNameId equ 243 .dw mLeapYearName -mDayOfWeekNameId equ 240 +mDayOfWeekNameId equ 244 .dw mDayOfWeekName -mDateToEpochDaysNameId equ 241 +mDateToEpochDaysNameId equ 245 .dw mDateToEpochDaysName -mEpochDaysToDateNameId equ 242 +mEpochDaysToDateNameId equ 246 .dw mEpochDaysToDateName -mDateRelatedToSecondsNameId equ 243 +mDateRelatedToSecondsNameId equ 247 .dw mDateRelatedToSecondsName -mSecondsToDurationNameId equ 244 +mSecondsToDurationNameId equ 248 .dw mSecondsToDurationName -mSecondsToTimeNameId equ 245 +mSecondsToTimeNameId equ 249 .dw mSecondsToTimeName -mEpochSecondsToAppDateTimeNameId equ 246 +mEpochSecondsToAppDateTimeNameId equ 250 .dw mEpochSecondsToAppDateTimeName -mEpochSecondsToUTCDateTimeNameId equ 247 +mEpochSecondsToUTCDateTimeNameId equ 251 .dw mEpochSecondsToUTCDateTimeName -mTimeZoneToHoursNameId equ 248 +mTimeZoneToHoursNameId equ 252 .dw mTimeZoneToHoursName -mHoursToTimeZoneNameId equ 249 +mHoursToTimeZoneNameId equ 253 .dw mHoursToTimeZoneName -mDopsNameId equ 250 +mDopsNameId equ 254 .dw mDopsName -mEpochNameId equ 251 +mEpochNameId equ 255 .dw mEpochName -mClkNameId equ 252 +mClkNameId equ 256 .dw mClkName -mDateShrinkNameId equ 253 +mDateShrinkNameId equ 257 .dw mDateShrinkName -mDateExtendNameId equ 254 +mDateExtendNameId equ 258 .dw mDateExtendName -mDateCutNameId equ 255 +mDateCutNameId equ 259 .dw mDateCutName -mDateLinkNameId equ 256 +mDateLinkNameId equ 260 .dw mDateLinkName -mEpochUnixNameId equ 257 +mEpochUnixNameId equ 261 .dw mEpochUnixName -mEpochUnixAltNameId equ 258 +mEpochUnixAltNameId equ 262 .dw mEpochUnixAltName -mEpochNtpNameId equ 259 +mEpochNtpNameId equ 263 .dw mEpochNtpName -mEpochNtpAltNameId equ 260 +mEpochNtpAltNameId equ 264 .dw mEpochNtpAltName -mEpochGpsNameId equ 261 +mEpochGpsNameId equ 265 .dw mEpochGpsName -mEpochGpsAltNameId equ 262 +mEpochGpsAltNameId equ 266 .dw mEpochGpsAltName -mEpochTiosNameId equ 263 +mEpochTiosNameId equ 267 .dw mEpochTiosName -mEpochTiosAltNameId equ 264 +mEpochTiosAltNameId equ 268 .dw mEpochTiosAltName -mEpochY2kNameId equ 265 +mEpochY2kNameId equ 269 .dw mEpochY2kName -mEpochY2kAltNameId equ 266 +mEpochY2kAltNameId equ 270 .dw mEpochY2kAltName -mEpochCustomNameId equ 267 +mEpochCustomNameId equ 271 .dw mEpochCustomName -mEpochCustomAltNameId equ 268 +mEpochCustomAltNameId equ 272 .dw mEpochCustomAltName -mEpochSetCustomNameId equ 269 +mEpochSetCustomNameId equ 273 .dw mEpochSetCustomName -mEpochGetCustomNameId equ 270 +mEpochGetCustomNameId equ 274 .dw mEpochGetCustomName -mGetNowNameId equ 271 +mGetNowNameId equ 275 .dw mGetNowName -mGetNowDateNameId equ 272 +mGetNowDateNameId equ 276 .dw mGetNowDateName -mGetNowTimeNameId equ 273 +mGetNowTimeNameId equ 277 .dw mGetNowTimeName -mGetNowAppDateTimeNameId equ 274 +mGetNowAppDateTimeNameId equ 278 .dw mGetNowAppDateTimeName -mGetNowUTCDateTimeNameId equ 275 +mGetNowUTCDateTimeNameId equ 279 .dw mGetNowUTCDateTimeName -mSetTimeZoneNameId equ 276 +mSetTimeZoneNameId equ 280 .dw mSetTimeZoneName -mGetTimeZoneNameId equ 277 +mGetTimeZoneNameId equ 281 .dw mGetTimeZoneName -mSetClockTimeZoneNameId equ 278 +mSetClockTimeZoneNameId equ 282 .dw mSetClockTimeZoneName -mGetClockTimeZoneNameId equ 279 +mGetClockTimeZoneNameId equ 283 .dw mGetClockTimeZoneName -mSetClockNameId equ 280 +mSetClockNameId equ 284 .dw mSetClockName ; Table of names as NUL terminated C strings. @@ -3645,6 +3699,14 @@ mHpToKwName: .db Sconvert, 'k', 'W', 0 mKwToHpName: .db Sconvert, 'h', 'p', 0 +mMpgToLkmName: + .db Sconvert, 'L', 'k', 'm', 0 +mLkmToMpgName: + .db Sconvert, 'm', 'p', 'g', 0 +mPsiToKpaName: + .db Sconvert, 'k', 'P', 'a', 0 +mKpaToPsiName: + .db Sconvert, 'p', 's', 'i', 0 mLeapYearName: .db "LEAP", 0 mDayOfWeekName: diff --git a/src/menudef.txt b/src/menudef.txt index 9983256b..5f81473d 100644 --- a/src/menudef.txt +++ b/src/menudef.txt @@ -397,13 +397,13 @@ MenuGroup root mRoot [ MenuItem kW mHpToKw MenuItem hp mKwToHp ] - # MenuRow [ - # MenuItem Lkm mL100kmToMpg - # MenuItem mpg mMpgToL100km - # MenuItem * * - # MenuItem kPa mPsiToKpa - # MenuItem psi mKpaToPsi - # ] + MenuRow [ + MenuItem Lkm mMpgToLkm + MenuItem mpg mLkmToMpg + MenuItem * * + MenuItem kPa mPsiToKpa + MenuItem psi mKpaToPsi + ] # MenuRow [ # MenuItem ha mAcreToHectare # MenuItem acr mHectareToAcre diff --git a/src/menuhandlers.asm b/src/menuhandlers.asm index b58bb56f..883c4870 100644 --- a/src/menuhandlers.asm +++ b/src/menuhandlers.asm @@ -591,6 +591,69 @@ mKwToHpHandler: bcall(_FPDiv) jp replaceX +;----------------------------------------------------------------------------- + +; Description: Convert mpg (miles per US gallon) to lkm (Liters per 100 km): +; lkm = 100/[mpg * (km/mile) / (litre/gal)] +mMpgToLkmHandler: + call closeInputAndRecallX + call op2SetKmPerMi + bcall(_FPMult) + call op2SetLPerGal + bcall(_FPDiv) + call op1ToOp2 + call op1Set100 + bcall(_FPDiv) + jp replaceX + +; Description: Convert lkm to mpg: mpg = 100/lkm * (litre/gal) / (km/mile). +mLkmToMpgHandler: + call closeInputAndRecallX + call op1ToOp2 + call op1Set100 + bcall(_FPDiv) + call op2SetLPerGal + bcall(_FPMult) + call op2SetKmPerMi + bcall(_FPDiv) + jp replaceX + +; Description: Convert PSI (pounds per square inch) to kiloPascal. +; P(Pa) = P(psi) * 0.45359237 kg/lbf * (9.80665 m/s^2) / (0.0254 m/in)^2 +; P(Pa) = P(psi) * 0.45359237 kg/lbf * (9.80665 m/s^2) / (2.54 cm/in)^2 * 10000 +; P(kPa) = P(psi) * 0.45359237 kg/lbf * (9.80665 m/s^2) / (2.54 cm/in)^2 * 10 +; See https://en.wikipedia.org/wiki/Pound_per_square_inch. +mPsiToKpaHandler: + call closeInputAndRecallX + call op2SetKgPerLbs + bcall(_FPMult) + call op2SetStandardGravity + bcall(_FPMult) + call op2SetCmPerIn + bcall(_FPDiv) + call op2SetCmPerIn + bcall(_FPDiv) + call op2Set10 + bcall(_FPMult) + jp replaceX + +; Description: Convert PSI (pounds per square inch) to kiloPascal. +; P(psi) = P(kPa) / 10 * (2.54m/in)^2 / (0.45359237 kg/lbf) / (9.80665 m/s^2) +; See https://en.wikipedia.org/wiki/Pound_per_square_inch. +mKpaToPsiHandler: + call closeInputAndRecallX + call op2Set10 + bcall(_FPDiv) + call op2SetCmPerIn + bcall(_FPMult) + call op2SetCmPerIn + bcall(_FPMult) + call op2SetStandardGravity + bcall(_FPDiv) + call op2SetKgPerLbs + bcall(_FPDiv) + jp replaceX + ;----------------------------------------------------------------------------- ; Children nodes of CONV menu. ;----------------------------------------------------------------------------- From cefb08702e913d34ed11f55aa94ace787eb68b22 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 11:42:56 -0700 Subject: [PATCH 30/39] menudef.txt,menuhandlers.asm: add conversions for acre,hectare --- CHANGELOG.md | 16 ++- src/const.asm | 15 ++- src/menudef.asm | 240 ++++++++++++++++++++++++++----------------- src/menudef.txt | 14 +-- src/menuhandlers.asm | 36 +++++++ 5 files changed, 215 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db30ba59..e5c7f60c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,11 +39,17 @@ - should almost never be needed, except during debugging - analogous to the `CLD` command on the HP-42S - UNIT - - add `>Lkm`: convert mpg (miles per US gallon) to L/100km (liters per - 100 km) - - add `>mpg`: convert L/100km to mpg - - add `>kPa`: convert psi (pounds per square inch) to kPa (kiloPascal) - - add `>psi`: convert kPa to psi + - car fuel consumption + - add `>Lkm`: convert mpg (miles per US gallon) to L/100km (liters + per 100 km) + - add `>mpg`: convert L/100km to mpg + - car tire pressure + - add `>kPa`: convert psi (pounds per square inch) to kPa + (kiloPascal) + - add `>psi`: convert kPa to psi + - land area + - add `>ha`: convert acre to hectare + - add `>acr`: convert hectare to acre - 0.12.0 (2024-06-24) - **Bug Fix**: update logic that determines when the comma `,` character can be inserted into the input buffer diff --git a/src/const.asm b/src/const.asm index 85a069bd..4bcdeb58 100644 --- a/src/const.asm +++ b/src/const.asm @@ -196,7 +196,7 @@ op2SetKwPerHp: ;----------------------------------------------------------------------------- -; Description: Set OP2 to KwPerHp +; Description: Set OP2 to HpaPerInHg ; Destroys: all, HL op2SetHpaPerInhg: ld hl, constHpaPerInhg @@ -204,6 +204,14 @@ op2SetHpaPerInhg: ;----------------------------------------------------------------------------- +; Description: Set OP2 to SqFtPerAcre +; Destroys: all, HL +op2SetSqFtPerAcre: + ld hl, constSqFtPerAcre + jp move9ToOp2 + +;----------------------------------------------------------------------------- + constM1: ; -1 .db $80, $80, $10, $00, $00, $00, $00, $00, $00 @@ -277,3 +285,8 @@ constKwPerHp: ; 0.745 699 871 582 270 22 kW/hp, approx ; = 33.863 886 403 41 hPa (exact) constHpaPerInhg: .db $00, $81, $33, $86, $38, $86, $40, $34, $10 + +; Number of square feet in one acre = 66*660 = 43560, see +; https://en.wikipedia.org/wiki/Acre. +constSqFtPerAcre: + .db $00, $84, $43, $56, $00, $00, $00, $00, $00 diff --git a/src/menudef.asm b/src/menudef.asm index 58e47363..402c0c47 100644 --- a/src/menudef.asm +++ b/src/menudef.asm @@ -29,7 +29,7 @@ ; DO NOT EDIT: This file was autogenerated. ;----------------------------------------------------------------------------- -mMenuTableSize equ 282 +mMenuTableSize equ 287 mMenuTable: mNull: mNullId equ 0 @@ -175,7 +175,7 @@ mUnitId equ 15 .dw mUnitId ; id .dw mRootId ; parentId .dw mUnitNameId ; nameId - .db 7 ; numRows + .db 8 ; numRows .dw mFToCId ; rowBeginId or altNameId .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector @@ -2273,10 +2273,56 @@ mKpaToPsiId equ 241 .dw 0 ; rowBeginId or altNameId .dw mKpaToPsiHandler ; handler (to be implemented) .dw 0 ; nameSelector +; MenuGroup UNIT: children: row 7 +mAcreToHectare: +mAcreToHectareId equ 242 + .dw mAcreToHectareId ; id + .dw mUnitId ; parentId + .dw mAcreToHectareNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mAcreToHectareHandler ; handler (to be implemented) + .dw 0 ; nameSelector +mHectareToAcre: +mHectareToAcreId equ 243 + .dw mHectareToAcreId ; id + .dw mUnitId ; parentId + .dw mHectareToAcreNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mHectareToAcreHandler ; handler (to be implemented) + .dw 0 ; nameSelector +mBlank244: +mBlank244Id equ 244 + .dw mBlank244Id ; id + .dw mUnitId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector +mBlank245: +mBlank245Id equ 245 + .dw mBlank245Id ; id + .dw mUnitId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector +mBlank246: +mBlank246Id equ 246 + .dw mBlank246Id ; id + .dw mUnitId ; parentId + .dw mNullNameId ; nameId + .db 0 ; numRows + .dw 0 ; rowBeginId or altNameId + .dw mNullHandler ; handler (predefined) + .dw 0 ; nameSelector ; MenuGroup DATE: children ; MenuGroup DATE: children: row 0 mLeapYear: -mLeapYearId equ 242 +mLeapYearId equ 247 .dw mLeapYearId ; id .dw mDateId ; parentId .dw mLeapYearNameId ; nameId @@ -2285,7 +2331,7 @@ mLeapYearId equ 242 .dw mLeapYearHandler ; handler (to be implemented) .dw 0 ; nameSelector mDayOfWeek: -mDayOfWeekId equ 243 +mDayOfWeekId equ 248 .dw mDayOfWeekId ; id .dw mDateId ; parentId .dw mDayOfWeekNameId ; nameId @@ -2293,9 +2339,9 @@ mDayOfWeekId equ 243 .dw 0 ; rowBeginId or altNameId .dw mDayOfWeekHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank244: -mBlank244Id equ 244 - .dw mBlank244Id ; id +mBlank249: +mBlank249Id equ 249 + .dw mBlank249Id ; id .dw mDateId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2303,7 +2349,7 @@ mBlank244Id equ 244 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mDateToEpochDays: -mDateToEpochDaysId equ 245 +mDateToEpochDaysId equ 250 .dw mDateToEpochDaysId ; id .dw mDateId ; parentId .dw mDateToEpochDaysNameId ; nameId @@ -2312,7 +2358,7 @@ mDateToEpochDaysId equ 245 .dw mDateToEpochDaysHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochDaysToDate: -mEpochDaysToDateId equ 246 +mEpochDaysToDateId equ 251 .dw mEpochDaysToDateId ; id .dw mDateId ; parentId .dw mEpochDaysToDateNameId ; nameId @@ -2322,7 +2368,7 @@ mEpochDaysToDateId equ 246 .dw 0 ; nameSelector ; MenuGroup DATE: children: row 1 mDateRelatedToSeconds: -mDateRelatedToSecondsId equ 247 +mDateRelatedToSecondsId equ 252 .dw mDateRelatedToSecondsId ; id .dw mDateId ; parentId .dw mDateRelatedToSecondsNameId ; nameId @@ -2331,7 +2377,7 @@ mDateRelatedToSecondsId equ 247 .dw mDateRelatedToSecondsHandler ; handler (to be implemented) .dw 0 ; nameSelector mSecondsToDuration: -mSecondsToDurationId equ 248 +mSecondsToDurationId equ 253 .dw mSecondsToDurationId ; id .dw mDateId ; parentId .dw mSecondsToDurationNameId ; nameId @@ -2340,7 +2386,7 @@ mSecondsToDurationId equ 248 .dw mSecondsToDurationHandler ; handler (to be implemented) .dw 0 ; nameSelector mSecondsToTime: -mSecondsToTimeId equ 249 +mSecondsToTimeId equ 254 .dw mSecondsToTimeId ; id .dw mDateId ; parentId .dw mSecondsToTimeNameId ; nameId @@ -2349,7 +2395,7 @@ mSecondsToTimeId equ 249 .dw mSecondsToTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochSecondsToAppDateTime: -mEpochSecondsToAppDateTimeId equ 250 +mEpochSecondsToAppDateTimeId equ 255 .dw mEpochSecondsToAppDateTimeId ; id .dw mDateId ; parentId .dw mEpochSecondsToAppDateTimeNameId ; nameId @@ -2358,7 +2404,7 @@ mEpochSecondsToAppDateTimeId equ 250 .dw mEpochSecondsToAppDateTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochSecondsToUTCDateTime: -mEpochSecondsToUTCDateTimeId equ 251 +mEpochSecondsToUTCDateTimeId equ 256 .dw mEpochSecondsToUTCDateTimeId ; id .dw mDateId ; parentId .dw mEpochSecondsToUTCDateTimeNameId ; nameId @@ -2368,7 +2414,7 @@ mEpochSecondsToUTCDateTimeId equ 251 .dw 0 ; nameSelector ; MenuGroup DATE: children: row 2 mTimeZoneToHours: -mTimeZoneToHoursId equ 252 +mTimeZoneToHoursId equ 257 .dw mTimeZoneToHoursId ; id .dw mDateId ; parentId .dw mTimeZoneToHoursNameId ; nameId @@ -2377,7 +2423,7 @@ mTimeZoneToHoursId equ 252 .dw mTimeZoneToHoursHandler ; handler (to be implemented) .dw 0 ; nameSelector mHoursToTimeZone: -mHoursToTimeZoneId equ 253 +mHoursToTimeZoneId equ 258 .dw mHoursToTimeZoneId ; id .dw mDateId ; parentId .dw mHoursToTimeZoneNameId ; nameId @@ -2386,7 +2432,7 @@ mHoursToTimeZoneId equ 253 .dw mHoursToTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mDops: -mDopsId equ 254 +mDopsId equ 259 .dw mDopsId ; id .dw mDateId ; parentId .dw mDopsNameId ; nameId @@ -2395,7 +2441,7 @@ mDopsId equ 254 .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector mEpoch: -mEpochId equ 255 +mEpochId equ 260 .dw mEpochId ; id .dw mDateId ; parentId .dw mEpochNameId ; nameId @@ -2404,7 +2450,7 @@ mEpochId equ 255 .dw mGroupHandler ; handler (predefined) .dw 0 ; nameSelector mClk: -mClkId equ 256 +mClkId equ 261 .dw mClkId ; id .dw mDateId ; parentId .dw mClkNameId ; nameId @@ -2415,7 +2461,7 @@ mClkId equ 256 ; MenuGroup DOPS: children ; MenuGroup DOPS: children: row 0 mDateShrink: -mDateShrinkId equ 257 +mDateShrinkId equ 262 .dw mDateShrinkId ; id .dw mDopsId ; parentId .dw mDateShrinkNameId ; nameId @@ -2424,7 +2470,7 @@ mDateShrinkId equ 257 .dw mDateShrinkHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateExtend: -mDateExtendId equ 258 +mDateExtendId equ 263 .dw mDateExtendId ; id .dw mDopsId ; parentId .dw mDateExtendNameId ; nameId @@ -2433,7 +2479,7 @@ mDateExtendId equ 258 .dw mDateExtendHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateCut: -mDateCutId equ 259 +mDateCutId equ 264 .dw mDateCutId ; id .dw mDopsId ; parentId .dw mDateCutNameId ; nameId @@ -2442,7 +2488,7 @@ mDateCutId equ 259 .dw mDateCutHandler ; handler (to be implemented) .dw 0 ; nameSelector mDateLink: -mDateLinkId equ 260 +mDateLinkId equ 265 .dw mDateLinkId ; id .dw mDopsId ; parentId .dw mDateLinkNameId ; nameId @@ -2450,9 +2496,9 @@ mDateLinkId equ 260 .dw 0 ; rowBeginId or altNameId .dw mDateLinkHandler ; handler (to be implemented) .dw 0 ; nameSelector -mBlank261: -mBlank261Id equ 261 - .dw mBlank261Id ; id +mBlank266: +mBlank266Id equ 266 + .dw mBlank266Id ; id .dw mDopsId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2462,7 +2508,7 @@ mBlank261Id equ 261 ; MenuGroup EPCH: children ; MenuGroup EPCH: children: row 0 mEpochUnix: -mEpochUnixId equ 262 +mEpochUnixId equ 267 .dw mEpochUnixId ; id .dw mEpochId ; parentId .dw mEpochUnixNameId ; nameId @@ -2471,7 +2517,7 @@ mEpochUnixId equ 262 .dw mEpochUnixHandler ; handler (to be implemented) .dw mEpochUnixNameSelector ; nameSelector mEpochNtp: -mEpochNtpId equ 263 +mEpochNtpId equ 268 .dw mEpochNtpId ; id .dw mEpochId ; parentId .dw mEpochNtpNameId ; nameId @@ -2480,7 +2526,7 @@ mEpochNtpId equ 263 .dw mEpochNtpHandler ; handler (to be implemented) .dw mEpochNtpNameSelector ; nameSelector mEpochGps: -mEpochGpsId equ 264 +mEpochGpsId equ 269 .dw mEpochGpsId ; id .dw mEpochId ; parentId .dw mEpochGpsNameId ; nameId @@ -2489,7 +2535,7 @@ mEpochGpsId equ 264 .dw mEpochGpsHandler ; handler (to be implemented) .dw mEpochGpsNameSelector ; nameSelector mEpochTios: -mEpochTiosId equ 265 +mEpochTiosId equ 270 .dw mEpochTiosId ; id .dw mEpochId ; parentId .dw mEpochTiosNameId ; nameId @@ -2498,7 +2544,7 @@ mEpochTiosId equ 265 .dw mEpochTiosHandler ; handler (to be implemented) .dw mEpochTiosNameSelector ; nameSelector mEpochY2k: -mEpochY2kId equ 266 +mEpochY2kId equ 271 .dw mEpochY2kId ; id .dw mEpochId ; parentId .dw mEpochY2kNameId ; nameId @@ -2508,7 +2554,7 @@ mEpochY2kId equ 266 .dw mEpochY2kNameSelector ; nameSelector ; MenuGroup EPCH: children: row 1 mEpochCustom: -mEpochCustomId equ 267 +mEpochCustomId equ 272 .dw mEpochCustomId ; id .dw mEpochId ; parentId .dw mEpochCustomNameId ; nameId @@ -2516,18 +2562,18 @@ mEpochCustomId equ 267 .dw mEpochCustomAltNameId ; rowBeginId or altNameId .dw mEpochCustomHandler ; handler (to be implemented) .dw mEpochCustomNameSelector ; nameSelector -mBlank268: -mBlank268Id equ 268 - .dw mBlank268Id ; id +mBlank273: +mBlank273Id equ 273 + .dw mBlank273Id ; id .dw mEpochId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows .dw 0 ; rowBeginId or altNameId .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector -mBlank269: -mBlank269Id equ 269 - .dw mBlank269Id ; id +mBlank274: +mBlank274Id equ 274 + .dw mBlank274Id ; id .dw mEpochId ; parentId .dw mNullNameId ; nameId .db 0 ; numRows @@ -2535,7 +2581,7 @@ mBlank269Id equ 269 .dw mNullHandler ; handler (predefined) .dw 0 ; nameSelector mEpochSetCustom: -mEpochSetCustomId equ 270 +mEpochSetCustomId equ 275 .dw mEpochSetCustomId ; id .dw mEpochId ; parentId .dw mEpochSetCustomNameId ; nameId @@ -2544,7 +2590,7 @@ mEpochSetCustomId equ 270 .dw mEpochSetCustomHandler ; handler (to be implemented) .dw 0 ; nameSelector mEpochGetCustom: -mEpochGetCustomId equ 271 +mEpochGetCustomId equ 276 .dw mEpochGetCustomId ; id .dw mEpochId ; parentId .dw mEpochGetCustomNameId ; nameId @@ -2555,7 +2601,7 @@ mEpochGetCustomId equ 271 ; MenuGroup CLK: children ; MenuGroup CLK: children: row 0 mGetNow: -mGetNowId equ 272 +mGetNowId equ 277 .dw mGetNowId ; id .dw mClkId ; parentId .dw mGetNowNameId ; nameId @@ -2564,7 +2610,7 @@ mGetNowId equ 272 .dw mGetNowHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowDate: -mGetNowDateId equ 273 +mGetNowDateId equ 278 .dw mGetNowDateId ; id .dw mClkId ; parentId .dw mGetNowDateNameId ; nameId @@ -2573,7 +2619,7 @@ mGetNowDateId equ 273 .dw mGetNowDateHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowTime: -mGetNowTimeId equ 274 +mGetNowTimeId equ 279 .dw mGetNowTimeId ; id .dw mClkId ; parentId .dw mGetNowTimeNameId ; nameId @@ -2582,7 +2628,7 @@ mGetNowTimeId equ 274 .dw mGetNowTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowAppDateTime: -mGetNowAppDateTimeId equ 275 +mGetNowAppDateTimeId equ 280 .dw mGetNowAppDateTimeId ; id .dw mClkId ; parentId .dw mGetNowAppDateTimeNameId ; nameId @@ -2591,7 +2637,7 @@ mGetNowAppDateTimeId equ 275 .dw mGetNowAppDateTimeHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetNowUTCDateTime: -mGetNowUTCDateTimeId equ 276 +mGetNowUTCDateTimeId equ 281 .dw mGetNowUTCDateTimeId ; id .dw mClkId ; parentId .dw mGetNowUTCDateTimeNameId ; nameId @@ -2601,7 +2647,7 @@ mGetNowUTCDateTimeId equ 276 .dw 0 ; nameSelector ; MenuGroup CLK: children: row 1 mSetTimeZone: -mSetTimeZoneId equ 277 +mSetTimeZoneId equ 282 .dw mSetTimeZoneId ; id .dw mClkId ; parentId .dw mSetTimeZoneNameId ; nameId @@ -2610,7 +2656,7 @@ mSetTimeZoneId equ 277 .dw mSetTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetTimeZone: -mGetTimeZoneId equ 278 +mGetTimeZoneId equ 283 .dw mGetTimeZoneId ; id .dw mClkId ; parentId .dw mGetTimeZoneNameId ; nameId @@ -2619,7 +2665,7 @@ mGetTimeZoneId equ 278 .dw mGetTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mSetClockTimeZone: -mSetClockTimeZoneId equ 279 +mSetClockTimeZoneId equ 284 .dw mSetClockTimeZoneId ; id .dw mClkId ; parentId .dw mSetClockTimeZoneNameId ; nameId @@ -2628,7 +2674,7 @@ mSetClockTimeZoneId equ 279 .dw mSetClockTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mGetClockTimeZone: -mGetClockTimeZoneId equ 280 +mGetClockTimeZoneId equ 285 .dw mGetClockTimeZoneId ; id .dw mClkId ; parentId .dw mGetClockTimeZoneNameId ; nameId @@ -2637,7 +2683,7 @@ mGetClockTimeZoneId equ 280 .dw mGetClockTimeZoneHandler ; handler (to be implemented) .dw 0 ; nameSelector mSetClock: -mSetClockId equ 281 +mSetClockId equ 286 .dw mSetClockId ; id .dw mClkId ; parentId .dw mSetClockNameId ; nameId @@ -2647,7 +2693,7 @@ mSetClockId equ 281 .dw 0 ; nameSelector ; Table of 2-byte pointers to names in the pool of strings below. -mMenuNameTableSize equ 285 +mMenuNameTableSize equ 287 mMenuNameTable: mNullNameId equ 0 .dw mNullName @@ -3135,89 +3181,93 @@ mPsiToKpaNameId equ 241 .dw mPsiToKpaName mKpaToPsiNameId equ 242 .dw mKpaToPsiName -mLeapYearNameId equ 243 +mAcreToHectareNameId equ 243 + .dw mAcreToHectareName +mHectareToAcreNameId equ 244 + .dw mHectareToAcreName +mLeapYearNameId equ 245 .dw mLeapYearName -mDayOfWeekNameId equ 244 +mDayOfWeekNameId equ 246 .dw mDayOfWeekName -mDateToEpochDaysNameId equ 245 +mDateToEpochDaysNameId equ 247 .dw mDateToEpochDaysName -mEpochDaysToDateNameId equ 246 +mEpochDaysToDateNameId equ 248 .dw mEpochDaysToDateName -mDateRelatedToSecondsNameId equ 247 +mDateRelatedToSecondsNameId equ 249 .dw mDateRelatedToSecondsName -mSecondsToDurationNameId equ 248 +mSecondsToDurationNameId equ 250 .dw mSecondsToDurationName -mSecondsToTimeNameId equ 249 +mSecondsToTimeNameId equ 251 .dw mSecondsToTimeName -mEpochSecondsToAppDateTimeNameId equ 250 +mEpochSecondsToAppDateTimeNameId equ 252 .dw mEpochSecondsToAppDateTimeName -mEpochSecondsToUTCDateTimeNameId equ 251 +mEpochSecondsToUTCDateTimeNameId equ 253 .dw mEpochSecondsToUTCDateTimeName -mTimeZoneToHoursNameId equ 252 +mTimeZoneToHoursNameId equ 254 .dw mTimeZoneToHoursName -mHoursToTimeZoneNameId equ 253 +mHoursToTimeZoneNameId equ 255 .dw mHoursToTimeZoneName -mDopsNameId equ 254 +mDopsNameId equ 256 .dw mDopsName -mEpochNameId equ 255 +mEpochNameId equ 257 .dw mEpochName -mClkNameId equ 256 +mClkNameId equ 258 .dw mClkName -mDateShrinkNameId equ 257 +mDateShrinkNameId equ 259 .dw mDateShrinkName -mDateExtendNameId equ 258 +mDateExtendNameId equ 260 .dw mDateExtendName -mDateCutNameId equ 259 +mDateCutNameId equ 261 .dw mDateCutName -mDateLinkNameId equ 260 +mDateLinkNameId equ 262 .dw mDateLinkName -mEpochUnixNameId equ 261 +mEpochUnixNameId equ 263 .dw mEpochUnixName -mEpochUnixAltNameId equ 262 +mEpochUnixAltNameId equ 264 .dw mEpochUnixAltName -mEpochNtpNameId equ 263 +mEpochNtpNameId equ 265 .dw mEpochNtpName -mEpochNtpAltNameId equ 264 +mEpochNtpAltNameId equ 266 .dw mEpochNtpAltName -mEpochGpsNameId equ 265 +mEpochGpsNameId equ 267 .dw mEpochGpsName -mEpochGpsAltNameId equ 266 +mEpochGpsAltNameId equ 268 .dw mEpochGpsAltName -mEpochTiosNameId equ 267 +mEpochTiosNameId equ 269 .dw mEpochTiosName -mEpochTiosAltNameId equ 268 +mEpochTiosAltNameId equ 270 .dw mEpochTiosAltName -mEpochY2kNameId equ 269 +mEpochY2kNameId equ 271 .dw mEpochY2kName -mEpochY2kAltNameId equ 270 +mEpochY2kAltNameId equ 272 .dw mEpochY2kAltName -mEpochCustomNameId equ 271 +mEpochCustomNameId equ 273 .dw mEpochCustomName -mEpochCustomAltNameId equ 272 +mEpochCustomAltNameId equ 274 .dw mEpochCustomAltName -mEpochSetCustomNameId equ 273 +mEpochSetCustomNameId equ 275 .dw mEpochSetCustomName -mEpochGetCustomNameId equ 274 +mEpochGetCustomNameId equ 276 .dw mEpochGetCustomName -mGetNowNameId equ 275 +mGetNowNameId equ 277 .dw mGetNowName -mGetNowDateNameId equ 276 +mGetNowDateNameId equ 278 .dw mGetNowDateName -mGetNowTimeNameId equ 277 +mGetNowTimeNameId equ 279 .dw mGetNowTimeName -mGetNowAppDateTimeNameId equ 278 +mGetNowAppDateTimeNameId equ 280 .dw mGetNowAppDateTimeName -mGetNowUTCDateTimeNameId equ 279 +mGetNowUTCDateTimeNameId equ 281 .dw mGetNowUTCDateTimeName -mSetTimeZoneNameId equ 280 +mSetTimeZoneNameId equ 282 .dw mSetTimeZoneName -mGetTimeZoneNameId equ 281 +mGetTimeZoneNameId equ 283 .dw mGetTimeZoneName -mSetClockTimeZoneNameId equ 282 +mSetClockTimeZoneNameId equ 284 .dw mSetClockTimeZoneName -mGetClockTimeZoneNameId equ 283 +mGetClockTimeZoneNameId equ 285 .dw mGetClockTimeZoneName -mSetClockNameId equ 284 +mSetClockNameId equ 286 .dw mSetClockName ; Table of names as NUL terminated C strings. @@ -3707,6 +3757,10 @@ mPsiToKpaName: .db Sconvert, 'k', 'P', 'a', 0 mKpaToPsiName: .db Sconvert, 'p', 's', 'i', 0 +mAcreToHectareName: + .db Sconvert, 'h', 'a', 0 +mHectareToAcreName: + .db Sconvert, 'a', 'c', 'r', 0 mLeapYearName: .db "LEAP", 0 mDayOfWeekName: diff --git a/src/menudef.txt b/src/menudef.txt index 5f81473d..01571bb2 100644 --- a/src/menudef.txt +++ b/src/menudef.txt @@ -404,13 +404,13 @@ MenuGroup root mRoot [ MenuItem kPa mPsiToKpa MenuItem psi mKpaToPsi ] - # MenuRow [ - # MenuItem ha mAcreToHectare - # MenuItem acr mHectareToAcre - # MenuItem * * - # MenuItem * * - # MenuItem * * - # ] + MenuRow [ + MenuItem ha mAcreToHectare + MenuItem acr mHectareToAcre + MenuItem * * + MenuItem * * + MenuItem * * + ] ] MenuGroup DATE mDate [ MenuRow [ diff --git a/src/menuhandlers.asm b/src/menuhandlers.asm index 883c4870..4535a664 100644 --- a/src/menuhandlers.asm +++ b/src/menuhandlers.asm @@ -654,6 +654,42 @@ mKpaToPsiHandler: bcall(_FPDiv) jp replaceX +;----------------------------------------------------------------------------- + +; Description: Convert US acre (66 ft x 660 ft) to hectare (100 m)^2. See +; https://en.wikipedia.org/wiki/Acre, and +; https://en.wikipedia.org/wiki/Hectare. +; Area(ha) = Area(acre) * 43560 * (0.3048 m/ft)^2 / (100 m)^2 +mAcreToHectareHandler: + call closeInputAndRecallX + call op2SetSqFtPerAcre + bcall(_FPMult) + call op2SetMPerFt + bcall(_FPMult) + call op2SetMPerFt + bcall(_FPMult) + call op2Set100 + bcall(_FPDiv) + call op2Set100 + bcall(_FPDiv) + jp replaceX + +; Description: Convert hectare to US acre. +; Area(acre) = Area(ha) * (100 m)^2 / 43560 / (0.3048 m/ft)^2 +mHectareToAcreHandler: + call closeInputAndRecallX + call op2Set100 + bcall(_FPMult) + call op2Set100 + bcall(_FPMult) + call op2SetMPerFt + bcall(_FPDiv) + call op2SetMPerFt + bcall(_FPDiv) + call op2SetSqFtPerAcre + bcall(_FPDiv) + jp replaceX + ;----------------------------------------------------------------------------- ; Children nodes of CONV menu. ;----------------------------------------------------------------------------- From 0ade0d5aeaeca4afedf8bf06ae3c34cb05cf4c83 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 18 Jul 2024 13:35:11 -0700 Subject: [PATCH 31/39] USER_GUIDE.md: add CLR>CLD (clear display); add Troubleshooting section --- docs/USER_GUIDE.md | 59 ++++++++++++++++++++++++++++++++ docs/images/menu-root-clr-2.png | Bin 0 -> 191 bytes 2 files changed, 59 insertions(+) create mode 100644 docs/images/menu-root-clr-2.png diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 5c8748d6..a2715882 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -72,6 +72,10 @@ RPN calculator app for the TI-83 Plus and TI-84 Plus inspired by the HP-42S. - [Complex Numbers](#complex-numbers) - [DATE Functions](#date-functions) - [TI-OS Interaction](#ti-os-interaction) +- [Troubleshooting](#troubleshooting) + - [Clear Display](#clear-display) + - [Reset MODE to Factory Defaults](#reset-mode-to-factory-defaults) + - [Wipe to Factory State](#wipe-to-factory-state) - [Future Enhancements](#future-enhancements) ## Introduction @@ -1431,11 +1435,13 @@ buttons just under the LCD screen. Use the `UP`, `DOWN`, `ON` (EXIT/ESC), and - `RSTV`: reset TVM Solver parameters to factory defaults - ![ROOT > CLR](images/menu-root-clr.png) (`ROOT > CLR`) - ![ROOT > CLR > Row1](images/menu-root-clr-1.png) + - ![ROOT > CLR > Row2](images/menu-root-clr-2.png) - `CLX`: clear `X` stack register (stack lift disabled) - `CLST`: clear all RPN stack registers - `CLRG`: clear all storage registers `R00` to `R99` - `CLΣ`: clear STAT storage registers [`R11`, `R16`] or [`R11`, `R23`] - `CLTV`: clear TVM variables and parameters + - `CLD`: clear display and rerender everything - ![ROOT > MODE](images/menu-root-mode.png) (`ROOT > MODE`) - ![ROOT > MODE > Row1](images/menu-root-mode-1.png) - ![ROOT > MODE > Row2](images/menu-root-mode-2.png) @@ -2177,6 +2183,59 @@ The RPN83P app interacts with the underlying TI-OS in the following ways. Finance app is that these are the only RPN83P variables which are *not* saved in the `RPN83SAV` appVar. +## Troubleshooting + +### Clear Display + +It is possible for the display to contain leftover pixels or line segments that +did not get properly cleared or overwritten due to some bug. When this happens, +clearing the display using the `CLD` (Clear Display) function under the `CLR` +menu folder will probably fix the problem. This function is modeled after the +`CLD` function on the HP-42S. + +I have rarely seen display rendering bugs. In all cases that I can remember, I +was doing some internal debugging which would not be performed by normal users. + +### Reset MODE to Factory Defaults + +The RPN83P currently has only a handful of settings, and they can be reset +relatively easily through the `MODE` menu (or through the `MODE` button). There +is no explicit `CLxx` menu function under the `CLR` menu folder to reset the +MODE settings to their factory defaults. + +If for some reason the factory defaults must be explicitly set, the current +workaround is to use the TI-OS: + +- `2ND MEM` +- `2` (Mem Mgmt/Del) +- `B` (AppVars) +- scroll down to the `RPN83SAV` variable +- delete it using the `DEL` button + +Upon restarting RPN83P, the various MODE parameters will be set to their factory +defaults. + +### Wipe to Factory State + +I have resisted the temptation to add a `CLAL` (Clear All) menu function because +it seems too dangerous, and because I'm not sure that everyone has the same +idea about what "all" means. + +If RPN83P gets into a state where everything must be reset, a complete wipe +can be performed through the TI-OS: + +- `2ND MEM` +- `2` (Mem Mgmt/Del) +- `B` (AppVars) +- delete all variables with the pattern `RPN83***` using the `DEL` button: + - `RPN83REG` (storage registers) + - `RPN83SAV` (MODE settings) + - `RPN83STA` (STAT registers) + - `RPN83STK` (RPN stack) + +When RPN83P restarts, those appVars will be recreated with a completely clean +slate. + ## Future Enhancements Moved to [FUTURE.md](FUTURE.md). diff --git a/docs/images/menu-root-clr-2.png b/docs/images/menu-root-clr-2.png new file mode 100644 index 0000000000000000000000000000000000000000..cccd5197d76df24ce179fc8f5ff0aee636cd85ed GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^2Y^_Rg9%8o+%dTYq}n`P978f1-`;TKYB1n&2~^(u zf9h+c*$$qqd=WYSZgYgL=uXVqa_=|mnqB4l8UFP$I9~dblr}&2WxJa7yp77dES|IP z_szdC@14%e$CFnyur;aVF4$^ZdN0U=pO=M`v8jc@(WyZ}(P6@p;D|ZPA9c-MZ(M)X rk=gOnC-tf~lh(v$%$=2?;33y>SIgpjhQlAAix@mz{an^LB{Ts5l1WON literal 0 HcmV?d00001 From da276e4d15cd53d05328f7e33864d88b8c675fe9 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 18 Jul 2024 16:25:32 -0700 Subject: [PATCH 32/39] USER_GUIDE.md: update screenshots of the CLEAR button and its various behaviors --- docs/USER_GUIDE.md | 60 ++++++++++++++++++++++++---------- docs/images/input-clear-1.png | Bin 413 -> 384 bytes docs/images/input-clear-2.png | Bin 394 -> 395 bytes docs/images/input-clear-3.png | Bin 610 -> 478 bytes docs/images/input-clear-4.png | Bin 368 -> 395 bytes docs/images/input-clear-5.png | Bin 0 -> 464 bytes docs/images/input-clear-6.png | Bin 0 -> 435 bytes docs/images/input-clear-7.png | Bin 0 -> 395 bytes docs/images/input-clear-8.png | Bin 0 -> 609 bytes docs/images/input-clear-9.png | Bin 0 -> 367 bytes 10 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 docs/images/input-clear-5.png create mode 100644 docs/images/input-clear-6.png create mode 100644 docs/images/input-clear-7.png create mode 100644 docs/images/input-clear-8.png create mode 100644 docs/images/input-clear-9.png diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index a2715882..9ee88138 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -676,23 +676,49 @@ If the `X` line is *not* in edit mode (i.e. the cursor is not shown), then the #### CLEAR Key -The `CLEAR` key either clears the `X` register or clears the current input line. -If `CLEAR` is pressed when the input buffer is already empty , then it performs -the `CLST` (Clear Stack) operation. This condition will always happen if CLEAR -is pressed 3 times consecutively. Here is an example where we fill up the RPN -stack first, then hit `CLEAR` a few times: - -| **Keys** | **Display**| -| --------------------- | ---------- | -| `1` `ENTER` `2` `ENTER` `3` `ENTER` `4` | ![Input Clear](images/input-clear-1.png) | -| `CLEAR` | ![Input Clear](images/input-clear-2.png) | -| `CLEAR` | ![Input Clear](images/input-clear-3.png) | -| `CLEAR` | ![Input Clear](images/input-clear-4.png) | - -Hitting `CLEAR` 3 times is a convenient alternative to navigating the menu -system to the `CLST` menu function nested under the `ROOT > CLR` menu folder. -(Another alternative could have been `2ND CLEAR` but the TI-OS does not support -that keystroke because it returns the same key code as `CLEAR`.) +The `CLEAR` key performs slightly different functions depending on the context: + +- If the input has been terminated (i.e. not in edit mode), `CLEAR` clears the + `X` register, similar to the `CLX` (Clear X Register) menu function. +- If the input is in edit mode, then: + - If the cursor is at the end of the input line, `CLEAR` erases the entire + line. + - If the cursor is at the beginning of the input line, `CLEAR` also erases + the entire line. + - If the cursor is in the middle of the input line, then `CLEAR` erases + *only* to the end of the line. + - If the input line is already empty when `CLEAR` is pressed, then it + interprets that as a `CLST` (Clear Stack) operation, and warns the user + with a message. + - If the `CLEAR` is pressed again after the warning, then the `CLST` + operation is performed, clearing the RPN stack. + +The `CLEAR` button erases only to the end of line if the cursor is in the middle +of the input buffer, which is convenient when the input line becomes lengthy. I +borrowed this behavior from the `CLEAR` button on the TI-89, TI-89 Titanium, +TI-92+, and TI Voyage 200 calculators. (The `2ND CLEAR` on the HP-50g works in a +similar way, but only in Algebraic mode, not in RPN mode.) + +I hope the following example illustrates the different behaviors of `CLEAR` +clearly: + +| **Keys** | **Display** | +| --------------------- | ---------- | +| `1` `ENTER` `2` `ENTER` `3` `ENTER` | ![Input Clear](images/input-clear-1.png) | +| `CLEAR` (invokes `CLX`) | ![Input Clear](images/input-clear-2.png) | +| `4.5678` | ![Input Clear](images/input-clear-3.png) | +| `CLEAR` (clears entire line) | ![Input Clear](images/input-clear-4.png) | +| `4.5678` `LEFT` `LEFT` `LEFT` | ![Input Clear](images/input-clear-5.png) | +| `CLEAR` (clears to end of line) | ![Input Clear](images/input-clear-6.png) | +| `CLEAR` (clears entire line) | ![Input Clear](images/input-clear-7.png) | +| `CLEAR` (requests `CLST`) | ![Input Clear](images/input-clear-8.png) | +| `CLEAR` (invokes `CLST`) | ![Input Clear](images/input-clear-9.png) | + +In most cases, pressing `CLEAR` 3 times will invoke the `CLST` function. +This is often far more convenient than navigating to the `CLST` menu function +nested under the `ROOT > CLR` menu folder. (Another alternative could have been +`2ND CLEAR` but the TI-OS does not support that keystroke because it returns the +same key code as `CLEAR`.) An empty string will be interpreted as a `0` if the `ENTER` key or a function key is pressed. diff --git a/docs/images/input-clear-1.png b/docs/images/input-clear-1.png index 44419de51e42ac678abeeed4a5cbe1778e00e98e..91fd684925353dd7b1981795ed78b2bda64410b2 100644 GIT binary patch delta 357 zcmbQs+`v3RrQY4s#WAE}&f7Z&vknCav|YUO==c7jm>6-*>l-KknUZ9it}1x2wZ>`J{PT4Cc%2kK!pfRfr+1Va#Gon zmO8jZ{dRbFCO8nNvy}bCkE(sE4MRjaJa$g}arn58ea`J=4lQ!d{l@z1fGU>%7hh&8 z1Jr!&?vLxIFV6aMQlz7!7G(aCt^6r$ixxS!?2GMu7yq)*x5E?Y1mg+Si6t5Wg1;SH zfUbTinX&7dZrne4R;5c-b`vfI08O07@8Z(faf4k6sPzrAAW-C6V+TwJ)My*-*CuZ5 dK%byVl`Cf+c7FCC;uQlBc)I$ztaD0e0sy{Hn8^SD delta 386 zcmZo*p36Kzr9Q>e#WAE}&fB{O{SF%lxL%Za`oDgs&Y?pmd?dbivc9#{z7o{wTKf9d zWCOYWhu2xcoNak->?@!qW08N$V?v?;J&AwpAN;-}~vr=&Wj zG6`m$WwxBTd=XG*DO<+BpH*SWD>MWq7Abw4K0WepflND-;IF7JKb{>e7U?+gtu*o0 zVV}m1Eq;&Rw=Xt*IagCa@Uw%9NQXzZ+zF|UE+)aB+l24lf4Ncph%3+u*$U~2ASZy8 zocJd7;#17_3fpQfmnEh33QHFP?Ytx3(ZM8W$nWCP*pYKbJ|paJes9;gy;`hFMdx&1 zzWKhR*47y4=0dS;+qi)CN3N}#(|U2CgUhMaM!&S@{d@nR3S#$G$q=A)WxUjmy+O5}a<=2SBO=J@MxlHwHh)MhLCr1`IxZKJ(x#IMlsb6P4 zKmU22NQcMzxC;_x8UhnPaX+cyw-)K>knHGS63qO)G}2vZs#9ZqM~sHR8lbvLk!?oI z8-o;-qJKNAI};qJpj3O8ah804xM^D#lc1)#P<_Shm+g-&L^>`!zwr1(ceO~ziKq8l zGx?2Kl{S@{{`*<9MQtyTog@!3|K=@rBj!M$A@S#2-p_wo=-1)c*fGU;LU!Vt00pIQ zjU7N2oi@Huus$>Tk3E-5%Ikj)Ue2zK9Xsp=1Yu@ucI`^m26@SD`|>ItQC6i#{||x8dv~I{g-H;o>j`tR=(7-i3y10u+>ZPW*8?FU(%%_(F%4ed4x#dv>@tcI5om_ovz^7iT!QOnb+_!~|$h$8ToAKn0~|jU7OjLQG2Dqr7+b<;~uW9Tj10 zf~-nKVb`z9MsIX#?3j~Wy()JFP~mxQ6l3_#%N L>gTe~DWM4fOeLI( diff --git a/docs/images/input-clear-3.png b/docs/images/input-clear-3.png index 757e7821e388521401c4852ed12812fc0a099efd..6eb6e297e50ced1316270edd297f50bd1a0beaea 100644 GIT binary patch delta 465 zcmV;?0WSXH1l|LX7k@zr0ssI22vR&P0004{NklIIFVLxG5tA0X#@=ujXcW`7_e3Pfb|OS2z|R0;(m zGEpGdQy?PcDs0aT#GV2XY3&DcWuA%x5n1+ofVPj9B>wU?(+{`XO@Rn~ z4Lw#~oTETQroR`aJ!~luk=E7t+PfxCs|cbI00000NkvXX Hu0mjfy-L-v delta 598 zcmV-c0;&Dp1L6db7k^O*0ssI23xqzl0006hNkl zxJ_$tRVggldw%X4+`%^!MzOvPQdcNkXj=V;%DpLXx+2?09KC5qEm7izQ zxKFR9V<&y9@_+j}pTNBQdCgyyZ4!vcW-yh61R|mV5z&B%EH|KS+urNM47ZX%ME;Q_ zoe?X?ZX6^Kk!^K8${ph}ye|nvq#TWxF?2{EB4q<|zK0G8L_{Bmhy)_CFdt}sO)5W= z1R`QaA`uBhWZ}9neIP~>h)8Qbkdb*R5{SrNU2i&G`+o={2}Govk@%m@^nQ3e9ukPq z?@o^+FRqb5M3%1$lRcbCAR?{N`1#~$ne>xMAR^`i5s^SdTJwSQfv89zB7dEUzWb?L zd_NM1NZAK67Dk5zB4R!e5eY?>Sby7YRh9b$=j9Lq!4+aep8p5{QWTKtv=E z5%YnFNKYUlALl#LyE{FrBoGnL${-?vi0sw4x??LkBoLAPoITb5P?11HJTHuh1R}CK k@**LDh?oyVL;?}{1&`{*Zr2nD%>V!Z07*qoM6N<$f}N8SIsgCw diff --git a/docs/images/input-clear-4.png b/docs/images/input-clear-4.png index b0a257a0431f80c802666341ef050e9cadf5de61..df55c81bdaff7a59b8b56d88560f58bbe7291fde 100644 GIT binary patch delta 368 zcmeys)Xh9Wr9Q~h#WAE}&fB{O^9~sZxL%a_`M=&Wb_aL(y8w0nP*=ibD8SZ5R>-fPmU~baJiLna>eO8Q@_r9 ze*W`3kq(dbaTg@YGz2Do;(k)YZ!OZ%A=%NvB$)YoX{5W-RHw%Jju;JrH9&QhBHN6Z zHwGyvMgMkKcP2PcL8a6Ho8A zX7U@eDs3t?{r9tIi`rfwJ4qg7{>@wLM$CagL*mc5yr2KF(67U>v15wygzUsO0SZdr z8ase4I&FNRV0~uvAA2sBl-K_pyqsMdJ9gL$2*S+R$nWCP*kSX``qFM|+i*<*!T(bo zfdXG%?b?;B4f2xR_T^PPqO3}f{vQIF_wGb@3zHyF*AwPs(RHz^OHZUR0D-5gpUXO@ GgeCyBKA<)L literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^2Y}d-g9%7-1li~^Fff{Xx;TbZ%z1lvV_s7LLt9{G z#sBbS%skhk&m7IqkUBTB$I4=czCc~!&24WP=SMxizf0%zY2$r0HGjXdKd7(nJ@t6| zx;JlU*3bJLpfIWQ{qY-cP2AUjIm(5 zB7+K?TOVzbN8rQn2Ud RFknbBc)I$ztaD0e0s!NKlLP<& diff --git a/docs/images/input-clear-5.png b/docs/images/input-clear-5.png new file mode 100644 index 0000000000000000000000000000000000000000..099f4d90e90e841ef343c673661944fc9b1a9528 GIT binary patch literal 464 zcmV;>0WbcEP)wl_ORNQkZ5RrM^lAf;Qx3A9|(DRFCb`#t~ zfrt!T3){Bpm@DQIU3nD+A~ILg&lT6guK3n{b!=5il{%LK5h+(;)eN-u+R0=8)vdzr zp+H2s_5+RHzijj<-j@OqnfFU`t~*yoR$=#0AR_hy5%~t9AP!ZPx|lrx0000gI!((#dpg=_0(UPMseOJc+JpVuMNr8y$)e9QK3ejiI7I zM9PiCU*2Z=VcRwZBJ?%%xbos01tPNiyD;scr$9ue?#4e~j@G1ira(mO0})XmB2)W7 zW*{mGMC98^^!!PWGa(KNM5LU7+zVrd0uiwfL_~pzEYCoPbKT;86o|;w^MRCxiUJYw zd>|qUM8rN25d|W$@O+@&x$Cl-y&}6u*P=i~_P!-EUCAF`uOfG%KtvYqg^jH`$9dA7 zC=ijonton!FU+s*??-`%lviQZ4AfH&6o|;wKG5p(%U0jTbtw>${dsBrR&|D?N!O)7 dMC=0*`2_p?i;rU?Bvi8Np!GkCiCxvX+T-kSzQL<1tS zA1~Xs{aJMMijE~?59z$-dHwUJIRPWxlG;5{Srt ztvyz0QSBww@@lK`{rFwylJm@)r{K7JUbjw~&VRA_|I$zTyOUA^5!tV8*6$(B*RQtf z?BC~4`fTJmFUBKQFoS?R^r6$i)Pz+HAF-b@r!z4t-^-`}BOxR~>nc zUR9<9BC^lVYJ67TzA8V@q;a2KO~+39R^|6~et~)U^P0aZ+awT?&1gIc2}DE#BBB8i zS#Chvw!PPh8Ez$ki2Nf{cwZ8TNI4oWW9X1TM9K!_d=DKG zh=@KA5eYwB7ums z<^$;iQISAI{yGzV_fxm{ek2f)vJYe|j1CDz#C#wk5{SrhALwx3bF6qT5{O9a{y>t3 ziUcC!{y;<|5E1i%h)5tJ<^vItKtw*yccgcBdR9pwBA%5&L;?}nt8sP5R&+=pBKtXe vs`pTlKtwz*jEDpxvODr3A%TdP4@Be_qQJ#&;RxgU00000NkvXXu0mjf{oWwo literal 0 HcmV?d00001 diff --git a/docs/images/input-clear-9.png b/docs/images/input-clear-9.png new file mode 100644 index 0000000000000000000000000000000000000000..a2582485512a7eabd2dd95372640ea1f95da3c08 GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0vp^2Y}d-g9%7-1li~^Fff{Vx;TbZ%z1lvV_s7LLt9{G z#sBbS%skhk&m7IqkUBTB$H=0#@k96NZMpnEu3V3=XZ*Ll^xuWl$hdof`XU`qOtt#& z@7lCI{a@`n=SGifd*ze8?_E!|k$*G~DEUR}O>OnO-ACtY3Y^SrTsKd&(4Wht=%I{9 zwFFSa=)UOpLm);g(?O3$k2j4TA{|HMI$VIpe9XK4IlEfnUa-QX$67gWdTj-aMLJUE z?mtv?_9#$k-5ln(-;Uj2HUwIUqz%k`(sAmhu~lF5n?{R;4l3ex()M*+KudqM7*#8z zX$W*aXPyWrZ3Q}+Cf)!GU}c`P5_`J2KJY2fFA#^pEPEnd`tNGed-1Kcz<^}%boFyt I=akR{03xWGY5)KL literal 0 HcmV?d00001 From 189cd29b288450bcf1ba2137482e600bb8b16753 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 12:33:51 -0700 Subject: [PATCH 33/39] USER_GUIDE.md: add screenshots for new UNIT conversions: >Lkm,>mpg,>kPa,>psi,>ha,>acr --- README.md | 3 ++- docs/USER_GUIDE.md | 11 ++++++++++- docs/images/menu-root-unit-7.png | Bin 0 -> 300 bytes docs/images/menu-root-unit-8.png | Bin 0 -> 238 bytes 4 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 docs/images/menu-root-unit-7.png create mode 100644 docs/images/menu-root-unit-8.png diff --git a/README.md b/README.md index 6e5d560e..72e079af 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,8 @@ Summary of features: - angle conversions: `>DEG`, `>RAD`, `>HR`, `>HMS`, `>REC`, `>POL` - unit conversions: `>C`, `>F`, `>hPa`, `>inHg`, `>km`, `>mi`, `>m`, `>ft`, `>cm`, `>in`, `>um`, `>mil`, `>kg`, `>lbs`, `>g`, `>oz`, `>L`, `>gal`, - `>mL`, `>floz`, `>kJ`, `>cal`, `>kW`, `>hp` + `>mL`, `>floz`, `>kJ`, `>cal`, `>kW`, `>hp`, `>Lkm`, `>mpg`, `>kPa`, + `>psi`, `>ha`, `>acr` - statistics and curve fitting, inspired by HP-42S - statistics: `Σ+`, `Σ-`, `SUM`, `MEAN`, `WMN` (weighted mean), `SDEV` (sample standard deviation), `SCOV` (sample covariance), diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 9ee88138..4434d78e 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -134,7 +134,8 @@ Summary of features: - angle conversions: `>DEG`, `>RAD`, `>HR`, `>HMS`, `>REC`, `>POL` - unit conversions: `>C`, `>F`, `>hPa`, `>inHg`, `>km`, `>mi`, `>m`, `>ft`, `>cm`, `>in`, `>um`, `>mil`, `>kg`, `>lbs`, `>g`, `>oz`, `>L`, `>gal`, - `>mL`, `>floz`, `>kJ`, `>cal`, `>kW`, `>hp` + `>mL`, `>floz`, `>kJ`, `>cal`, `>kW`, `>hp`, `>Lkm`, `>mpg`, `>kPa`, + `>psi`, `>ha`, `>acr` - statistics and curve fitting, inspired by HP-42S - statistics: `Σ+`, `Σ-`, `SUM`, `MEAN`, `WMN` (weighted mean), `SDEV` (sample standard deviation), `SCOV` (sample covariance), @@ -1513,6 +1514,8 @@ buttons just under the LCD screen. Use the `UP`, `DOWN`, `ON` (EXIT/ESC), and - ![ROOT > UNIT > Row4](images/menu-root-unit-4.png) - ![ROOT > UNIT > Row5](images/menu-root-unit-5.png) - ![ROOT > UNIT > Row6](images/menu-root-unit-6.png) + - ![ROOT > UNIT > Row7](images/menu-root-unit-7.png) + - ![ROOT > UNIT > Row8](images/menu-root-unit-8.png) - `>C`: Fahrenheit to Celsius - `>F`: Celsius to Fahrenheit - `>hPa`: hectopascals (i.e. millibars) to inches of mercury (Hg) @@ -1537,6 +1540,12 @@ buttons just under the LCD screen. Use the `UP`, `DOWN`, `ON` (EXIT/ESC), and - `>cal`: kilo Joules to kilo calories - `>kW`: horsepowers (mechanical) to kilo Watts - `>hp`: kilo Watts to horsepowers (mechanical) + - `>Lkm`: miles per US gallon to liters per 100 km + - `>mpg`: liters per 100 km to miles per US gallon + - `>kPa`: pounds per square inch to kilo Pascals + - `>psi`: kilo Pascals to pounds per square inch + - `>ha`: acres to hectares + - `>acr`: hectares to acres - ![ROOT > DATE](images/menu-root-date.png) (`ROOT > DATE`) - ![ROOT > DATE > Row1](images/date/menu-root-date-1.png) - ![ROOT > DATE > Row2](images/date/menu-root-date-2.png) diff --git a/docs/images/menu-root-unit-7.png b/docs/images/menu-root-unit-7.png new file mode 100644 index 0000000000000000000000000000000000000000..2726c2549e885ac50c608a9334082fe1d2f1d011 GIT binary patch literal 300 zcmV+{0n`48P)L@pIabO5= zfeu6X6ifpP<$`8V*eOXk32CnbRYup=0N^CiXG!uYovbtG1;@beF4(U y<`eID#94iHO*TIrh(NUe`PYVuD-`KK1mXoe@y27hVN>A%0000=LNl`;FzbK!3*g!KfFN1=rL|VpvTvGn zd`CwT2$JvvGPB+Db+kU`+G?mr0ztBjZ$~@pc)iQ-$7ieg^=*av)4-RJK#&|HQ0HfQ zJoj_QnoPBEx{y8fNFYd32~;!FdKa>%9ti}=K?3DxS~>mrE>ShVPU_r?1cD??plGuF ozgXs}vt9D Date: Fri, 19 Jul 2024 12:52:03 -0700 Subject: [PATCH 34/39] USER_GUIDE.md: update latest PRIM benchmarks for various models --- docs/USER_GUIDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 4434d78e..5c1d2c95 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -2050,9 +2050,9 @@ times of the `PRIM` function for this number for various TI models that I own: | **Model** | **PRIM Running Time** | | --- | --- | | TI-83+ (6 MHz) | 8.3 s | -| TI-83+SE (15 MHz) | 3.3 s | +| TI-83+SE (15 MHz) | 3.2 s | | TI-84+SE (15 MHz) | 3.9 s | -| TI-Nspire w/ TI-84+ keypad | 3.1 s | +| TI-Nspire w/ TI-84+ keypad | 3.0 s | During the calculation, the "run indicator" on the upper-right corner will be active. You can press the `ON` key to break from the `PRIM` loop with an `Err: From 42cc7b6d2145cca3c2dfaa5eab5105087631c278 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 13:08:04 -0700 Subject: [PATCH 35/39] docs/DEVELOPER.md: describe performance improvement of PRIM by 2.4X --- docs/DEVELOPER.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index d4c4fcf5..20e4a645 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -149,20 +149,25 @@ Here are some notes about how the `PRIM` algorithm works: `ex (sp), hl` instruction of the Z80 to swap the 2 halves back and forth. This made the `mod(u32,u16)` function about 40-50% faster compared to v0.9.0. -- In v0.13, the inner loop `mod(u32,u16)` became another ~42% faster using the - `modHLIXByBC()` function: - - I discovered that my Z80 instruction cheatsheet incorrectly stated that - the `add ix, ix` did not exist. It does. - - Replacing the `ex (sp), hl; add hl, hl` combo with an `add ix, ix` - instruction gave us a ~29% speed improvement. - - Another ~4% was gained by replacing a `rl e; rl d` combo with an `adc hl, - hl` instruction. - - Another ~5% was gained by deleting an unnecessary `or a` instruction. - - About 1-2% was gained through rearranging some code to eliminate a branch - in the common case, and selecting `jr` or `jp` judiciously. - -Looking at the `modHLIXByBC()` routine, I cannot think of any additional -performance improvements. But who knows, I may have overlooked something. +- In v0.13.0-dev, the inner loop `mod(u32,u16)` became another ~42% faster: + - discovered that the Z80 supports `add ix, ix` instruction + - replacing `ex (sp), hl; add hl, hl` combo with `add ix, ix`: ~29% faster + - replacing `rl e; rl d` combo with `adc hl, hl`: ~4% faster + - deleting an unnecessary `or a` instruction: ~5% faster + - rearranging some code to eliminate a branch in the common case, and + selecting `jr` or `jp` judiciously: 1-2% faster +- In v1.0.0, the `mod(u32,u16)` became another 140-160% (i.e. 2.4X to 2.6X) + faster, based on the ideas from [this Cemetech + thread](https://www.cemetech.net/forum/viewtopic.php?t=19790): + - initial benchmark: 20.5 s + - chunking using 8-bit registers, instead of shifting the entire 32-bit + dividend: 18% faster + - using DEIX instead of HLIX, eliminating a bunch of 'ex de, hl': 12% faster + - using a nonrestoring division: 9-13% faster + - using register A instead of register D for each 8-bit chunk: 5% faster + - unrolling the 8-bit division loop eight times: 11-15% faster + - end result: 11.8 s or 74% faster, i.e. 1.74X faster + - total improvement from v0.12: 2.4X (83+/84+) to 2.6X (Nspire) faster ### Prime Factor Improvements From d8400a742f8bb0069ff542b7713e5ee7b0b21e36 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 13:22:06 -0700 Subject: [PATCH 36/39] README.md,docs,help1.asm: bump version to 1.0.0 --- CHANGELOG.md | 5 +++-- README.md | 2 +- docs/DEVELOPER.md | 2 +- docs/FUTURE.md | 4 ++-- docs/TVM.md | 2 +- docs/USER_GUIDE.md | 2 +- docs/USER_GUIDE_BASE.md | 2 +- docs/USER_GUIDE_COMPLEX.md | 2 +- docs/USER_GUIDE_DATE.md | 2 +- docs/USER_GUIDE_STAT.md | 2 +- docs/USER_GUIDE_TVM.md | 6 +++--- src/help1.asm | 4 ++-- 12 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5c7f60c..075a6a1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog - Unreleased +- 1.0.0 (2024-07-19) - User Interface - `CLEAR` button clears only to the end of the line if the cursor is in the interior of the input buffer @@ -10,8 +11,8 @@ - similar to 2ND CLEAR on HP-50g in Algebraic mode (but not in RPN mode) - Variables - - print 'Err: Archived' error message if `STO` or `RCL` act on - a variable (A-Z,Theta) that's been archived + - print 'Err: Archived' error message if `STO` or `RCL` acts on + a variable (A-Z,Theta) that is archived - TVM - Change the criteria for using the small-i approximation to the following: N*i <~ 6e-5. diff --git a/README.md b/README.md index 72e079af..b12d9e8d 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ Missing features (partial list): - vectors and matrices - keystroke programming -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Changelog**: [CHANGELOG.md](CHANGELOG.md) diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index 20e4a645..1677d56d 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -3,7 +3,7 @@ Notes for the developers of the RPN83P app, likely myself in 6 months when I cannot remember how the code works. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Project Home**: https://github.com/bxparks/rpn83p diff --git a/docs/FUTURE.md b/docs/FUTURE.md index d57cec80..1854eae6 100644 --- a/docs/FUTURE.md +++ b/docs/FUTURE.md @@ -14,7 +14,7 @@ because it is faster and easier to use compared to a web app, especially for small features that can be described in a few sentences. Usually only the larger and more complicated features will get their own GitHub tickets. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Parent Document**: [USER_GUIDE.md](USER_GUIDE.md) @@ -219,7 +219,7 @@ These are features which are unlikely to be implemented for various reasons: - The TI-OS supports only single-letter variables for real or complex types and access to these from RPN83P are provided through the `STO` and `RCL` commands. The TI-OS supports multi-letter user-defined names only for real - or complex Lists, which are not currently (v0.12.0) supported in RPN83P. + or complex Lists, which are not currently supported in RPN83P. - On the other hand, the HP-42S allows multi-letter user-defined variables for all types, and they which are accessible through the menu system. - To support multi-letter variables in RPN83P, we would have to write our diff --git a/docs/TVM.md b/docs/TVM.md index 330b9fce..980d83b7 100644 --- a/docs/TVM.md +++ b/docs/TVM.md @@ -3,7 +3,7 @@ Equations, algorithms, and other tricks used to calculate the Time Value of Money (TVM) variables in the RPN83P calculator app. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Project Home**: https://github.com/bxparks/rpn83p diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 5c1d2c95..be8849a5 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -2,7 +2,7 @@ RPN calculator app for the TI-83 Plus and TI-84 Plus inspired by the HP-42S. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Project Home**: https://github.com/bxparks/rpn83p diff --git a/docs/USER_GUIDE_BASE.md b/docs/USER_GUIDE_BASE.md index c70dc43c..1b2f2a4a 100644 --- a/docs/USER_GUIDE_BASE.md +++ b/docs/USER_GUIDE_BASE.md @@ -5,7 +5,7 @@ allow numbers to be converted between 4 different bases (DEC, HEX, OCT, and BIN) and support various arithmetic and bitwise operations similar to the HP-16C. It has been extracted from [USER_GUIDE.md](USER_GUIDE.md) due to its length. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Parent Document**: [USER_GUIDE.md](USER_GUIDE.md) diff --git a/docs/USER_GUIDE_COMPLEX.md b/docs/USER_GUIDE_COMPLEX.md index d8ef5ef9..dd7c324d 100644 --- a/docs/USER_GUIDE_COMPLEX.md +++ b/docs/USER_GUIDE_COMPLEX.md @@ -10,7 +10,7 @@ independent of each other. For example, a complex number can be entered in rectangular form, even if the current display mode is polar form. Internally, complex numbers are *always* stored in rectangular format. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Parent Document**: [USER_GUIDE.md](USER_GUIDE.md) diff --git a/docs/USER_GUIDE_DATE.md b/docs/USER_GUIDE_DATE.md index 63d5bc00..d47c671c 100644 --- a/docs/USER_GUIDE_DATE.md +++ b/docs/USER_GUIDE_DATE.md @@ -27,7 +27,7 @@ These features were inspired by various datetime libraries: - C# [Noda Time](https://nodatime.org) library - Python [datetime](https://docs.python.org/3/library/datetime.html) library -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Parent Document**: [USER_GUIDE.md](USER_GUIDE.md) diff --git a/docs/USER_GUIDE_STAT.md b/docs/USER_GUIDE_STAT.md index eaf5a3a1..3a0ffc72 100644 --- a/docs/USER_GUIDE_STAT.md +++ b/docs/USER_GUIDE_STAT.md @@ -3,7 +3,7 @@ This document describes the `STAT` functions of the RPN83P application which supports all statistical and curve fitting functionality of the HP-42S. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Parent Document**: [USER_GUIDE.md](USER_GUIDE.md) diff --git a/docs/USER_GUIDE_TVM.md b/docs/USER_GUIDE_TVM.md index 7e813621..857bfa5e 100644 --- a/docs/USER_GUIDE_TVM.md +++ b/docs/USER_GUIDE_TVM.md @@ -4,7 +4,7 @@ This document describes the `TVM` functions of the RPN83P application which solves the Time Value of Money equation. It has been extracted from [USER_GUIDE.md](USER_GUIDE.md) due to its length. -**Version**: 0.12.0 (2024-06-24) +**Version**: 1.0.0 (2024-07-19) **Parent Document**: [USER_GUIDE.md](USER_GUIDE.md) @@ -301,8 +301,8 @@ original menu with the addition of a question mark (e.g. `WSIZ` and `WSZ?`). This helps with discovery because each function is directly shown through the menu system, with no hidden features. But there are so many TVM variables and parameters, that adding the `?` variant of all those menu buttons would have -made the menu rows too cluttered and hard to navigate. Currently (v0.12.0), the -TVM submenu is the only place where the `2ND` button is used for hidden menu +made the menu rows too cluttered and hard to navigate. Currently, the TVM +submenu is the only place where the `2ND` button is used for hidden menu functionality.) ## TVM Examples diff --git a/src/help1.asm b/src/help1.asm index d4d768bc..60a04642 100644 --- a/src/help1.asm +++ b/src/help1.asm @@ -34,8 +34,8 @@ helpPageCount equ (helpPagesEnd-helpPages)/2 msgHelpPage1: .db escapeLargeFont, "RPN83P", Lenter - .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "19)", Senter - ;.db escapeSmallFont, "v0.12.0 (2024", Shyphen, "06", Shyphen, "27)", Senter + ; .db escapeSmallFont, "v0.13.0", Shyphen, "dev (2024", Shyphen, "07", Shyphen, "19)", Senter + .db escapeSmallFont, "v1.0.0 (2024", Shyphen, "07", Shyphen, "19)", Senter .db "(c) 2023", Shyphen, "2024 Brian T. Park", Senter .db Senter .db "An RPN calculator for the", Senter From 66cafd7483ead3f008a15629f0cb68de111761f8 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 13:26:22 -0700 Subject: [PATCH 37/39] USER_GUIDE.md: update that PRIM is now 25X (not 15X) faster than the floating point version --- docs/USER_GUIDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index be8849a5..897adf8d 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -2038,7 +2038,7 @@ For example, let's find the prime factors of `2_122_438_477 = 53 * 4001 * For computational efficiency, `PRIM` supports only integers between `2` and `2^32-1` (4 294 967 295). This allows `PRIM` to use integer arithmetic, making -it about 15X faster than the equivalent algorithm using floating point routines. +it about 25X faster than the equivalent algorithm using floating point routines. Any number outside of this range produces an `Err: Domain` message. (The number `1` is not considered a prime number.) From bc58dbfb0130c0d16ee5c3d60e33f7fc262dca7e Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 19 Jul 2024 13:49:00 -0700 Subject: [PATCH 38/39] USER_GUIDE.md: update screenshot for HELP; add 'Err: Archived' error code --- docs/USER_GUIDE.md | 3 ++- docs/images/help-page-1.png | Bin 1394 -> 1353 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 897adf8d..06232e1b 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -1156,7 +1156,7 @@ The Help pages are intended to capture some of the more obscure tidbits about the RPN83P app which may be hard to remember. Hopefully it reduces the number of times that this User Guide needs to be consulted. -The message at the bottom of each page is not completely honest. A number of +The message at the bottom of each page is not completely honest. A few navigational keys are recognized by the Help system: - `UP`, `LEFT`: previous page with wraparound @@ -1171,6 +1171,7 @@ listed in the TI-83 SDK. The SDK unfortunately does not describe how these errors are actually triggered. By trial-and-error, I could reverse engineer only a few of them as described below: +- `Err: Archived`: storage variable (A-Z,Theta) is archived - `Err: Argument`: incorrect number of arguments - `Err: Bad Guess` - `Err: Break` diff --git a/docs/images/help-page-1.png b/docs/images/help-page-1.png index fd1a500c9ae65b79694763bf9aa7c9b345220778..38be94ed71917b6f76771ba48ea15840024feda8 100644 GIT binary patch delta 1261 zcma))e>~H99LL>o_LwWBp-`f8oS#>6ZpIMKk9(L2p=**li9L*_Fq`kuqfV)%ngr+2a`6%vWV?an{DMsO*Uiqt$SR5-{-IQ=kfmWc)nk+_bN;PyXgab z5fv7aP+0$_p`SAS-B)2MCxhYfVt>e~P)Fp%7^RcE^y~-=b1g&^?R00R#58~|;v1w7 zV$=lO)v1W=k>sJq5t3|Q2|$D_&jhRi@K+e!f~#8#bxveP!tC!Td|#^)8^M1egE91B zfY8fB2b}So+&x&9ZpJY(g;W6JULGe2ilu`5<4n3$`14h)<4X&eiFGUXHY3zudneBX z$z6hgg?{qjUVnJXzG)4rW4r5)WE}5>>{m#s>2?$AA9f_`57=_mgL>3yHLkT*+IA*V z>BDo%D45y)A-*X%ZDp9LKom`27b_zkRY46WQXd=&4UF%p9onn}@}c1H+--+#1WJbA zw0~Bd+MUJGr;wF!D?GF1*_S$UG3`Ts_OBtpUu$I5lZfL zl%IU%-n@OcuG#;AKP)@|_13C#a<=R z?MmVX4dE&c*Pb&0^V|HYE_~aMZrme5GAuo*6X}6P}xKhK(dR8JdBK=6th8#^D@ zAq(<;Ot@W)EPjX3Ab`;us&)bB&VE}9Ymh}2oK|Z5pQ``!1J9bLCa9)+vbuWO6IIJS ztKV}uracaDs7G_1Qe(^MTHA~5T^)Ix+0I)HtGP7GP=$#pC_1m#91aCM(AiDDvzDHZ zy%|mHP`QfLaU%B|?>J?_P_-)O@ABZ%zPXm*UaK1h0y|}EM&oi%_?P#`jjl{1NDMNa zQ=t{+2?r#c1et2|#nYe*YJn}(`tnp^2iOTQgP7YxJ!WySRpXM%tNC(E@>=5~GEGmB zG|bAG()H?x0009y2lzF|16wfY^eU(@^Q_m&CZgH=OHVfTq0Ov;)D2EzkSwu*Z^X=T zLc;0w=!vOQZ?y~0iS$@+P_inkNCEo#6jQoFIMJ|p=(jBroP6A%1@CUB8|J<+Nk{eE zvb#AQbQJq!lwG2ik5_Dwh#{qYWtjoVO~7ZpxtDcWzD8IpS(2ot!Y@&kN27C$KwmAK zC&Q??4Xb*wWDG`I5c^0Ec5{GR;*ZK4BzC9bYa<>MuZyk|5av=w zD99H1bY1D6p;t#v_J}wBczy9bPQeSOGTGcuN!Uc44f{NawThEwe$x$8;&TtPipM^5 zvF_}wJOM!g@sQ5OV%8*ZV~v)z%u>0dvY+g^RiC*YSHG2^q!50VMK=3CZ79)g+l_YC zihb9H=&yZ5#gt8rE~&LP_S4;6I8{VGmO8jsGr7pV7Bn@HEj!TtcAo(6FpPK3y{q6p z+B62u9Ej0uZQKQ-7rDGBT~@}X+k3BM{ uA5ch+iV?soo0M_!&ulYqO&f_@ctmVVomrW&Z&3W^fMx delta 1259 zcmVcL_t(|ob8>_a@#r#MC*?K|Ce(g}~r5T0- zX%$?P1i?IhC47B-{rUOvc!+h@lB_&hQ`%Zcg4rP{Oxn2kE0}2Ed4@NdPpg>@O z1Azq&1QvgZ#w%;Fz5Qjqj#FQ;v#$8MCn}XQnMxm`<*YwSAN;=Qpg>^pa@abGUTe&1 zp)QZl>U&Q5*nd*a0(5(&sI2~p_MXbE8~eM5Li6Vi+t_j&j7lgXi9s!v%pBEF1p5C|Nn>rfyF~#WyBJF_OrJp zialAaDdqY)DE2n9qwLn~?SbjK<-hqUP#~}%8V?pI5Pw+UKwyCbfyHYl+K;*)_|fdl z&Ur0%Bi?nd{N3=CslL@MIu=kMuy~8czx`rpf2F(6q_i^Cq8_(*qV5OE*(3e4D?N|x zPR0LMP$01Q5RIQbmC~($ZW@+nXtuy~sTMb5rkL$|Y+!LFlZvu8EWxV=Ql-;E{b-NKQ90)fR#fo3xr z|IfK*^=H@L%zf5@{)wF7+L;2ea=-zwxau|1MAxfxrR>0t*}nEM61!yX62(Wq_YyXD{B=&Bs-Kdk0V;uy`tGP4vjNpTXIU z4c#G=yu0TcqwD%-xf>`DSUjVr>-nZzb!7WM*9;{p?&MPGJ@2YxeU5SO%)(F6AruHK zq-cD19uuF9OpUGCky_i)Pea!wdK~TkI)nm&g`_~Ur&ZQbRiF0FdZMeKK7zAeU4y>P zy_*`LKwv>M9xPCkPy{c33mgb6a3HXFJAka8z18!-qJ1SB{OtUS@3rQ%%b95Sr+E9D zsRzz&fsssgvOE3s8!((q^0Ra7*WcDXuWQEodj6}E&8LF`fyIZsusT1h&f?DM>&#}w zuQv4@_>8H$N9x-L>RSn%Ec!EU|3HDjqH$BbKVJ2xl={j@(q}VL_s>F~f;kY}h?fFo zs~-KEwYKA|^6GZ=jQ5y Date: Fri, 19 Jul 2024 13:52:52 -0700 Subject: [PATCH 39/39] CHANGELOG.md: add note about new 'Troubleshooting' section --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 075a6a1d..6d9ac4bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - Unreleased - 1.0.0 (2024-07-19) + - Documentation + - add "Troubleshooting" section to `USER_GUIDE.md` - User Interface - `CLEAR` button clears only to the end of the line if the cursor is in the interior of the input buffer