From 4fd8bf7b3f9b952ca16542ae999cb0f74da71fd2 Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Fri, 21 Aug 2026 18:16:27 -0400 Subject: [PATCH] Step a Data Pointer with INCD and DECD, not DPUP and DPDN by one DPUP takes an immediate, so an offset of one is legal and does exactly the right thing. It is also three bytes where INCD is two, and reads as "offset the pointer up by one" where INCD reads as "step the pointer". 56 of them across 15 files: the system, the assembler, the editor, and eight test programs. CosmOS is 9,564 bytes to 9,537, the native assembler 11,648 to 11,635, and every program in the repository together 49 bytes lighter. The worst offender was numbers.asm, written this week, where every sixteen bit helper reaches the low byte and comes back the long way round. It is the file every other part of the assembler includes, so it is the first thing anybody reads when they go looking - and it was teaching them the long way. Pattern matched off sbfs.asm rather than off the instruction table I had just embedded in two programs. THIS IS NOT TWO WAYS TO DO ONE THING. DPUP takes an arbitrary number, so one is inevitably among them; INCD earns its place by making the common case a byte cheaper. The overlap is structural and the choice is a usage question, which is a linter's job rather than an ISA's - "DPUP.n 0d01: INCD.n does this in a byte less" is a mechanical rule with no judgement in it. Nothing needed re-recording, which was not a foregone conclusion: cosmosBreak prints the system addresses the registers happened to hold, and they did not move. Both assemblers still produce identical bytes and CosmOS still builds itself to a fixed point. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW --- Programs/CosmOS/Apps/Edit.asm | 8 ++-- Programs/CosmOS/Apps/Stream.asm | 6 +-- Programs/CosmOS/Assembler/Asm.asm | 2 +- Programs/CosmOS/Assembler/numbers.asm | 24 +++++----- Programs/CosmOS/Source/cosmos.asm | 10 ++--- Programs/CosmOS/Source/sbfs.asm | 44 +++++++++---------- Programs/testPrograms/blitTest.asm | 2 +- Programs/testPrograms/controllerWriteTest.asm | 2 +- Programs/testPrograms/faultResumeTest.asm | 2 +- Programs/testPrograms/fenceTest.asm | 2 +- Programs/testPrograms/refusalTest.asm | 2 +- Programs/testPrograms/registerBankTest.asm | 2 +- Programs/testPrograms/sbfsReadTest.asm | 2 +- Programs/testPrograms/sbfsWalkTest.asm | 2 +- Programs/testPrograms/stackPointerTest.asm | 2 +- 15 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Programs/CosmOS/Apps/Edit.asm b/Programs/CosmOS/Apps/Edit.asm index d28e7fc..0ba9265 100644 --- a/Programs/CosmOS/Apps/Edit.asm +++ b/Programs/CosmOS/Apps/Edit.asm @@ -653,12 +653,12 @@ appendNode: ; DP2 is a two byte count. Takes one off it. takeOneOff: - DPUP.2 0d01 + INCD.2 LDA.2 DECA STA.2 BNC takeOneDone ; No borrow, so the high half is untouched. - DPDN.2 0d01 + DECD.2 LDA.2 DECA STA.2 @@ -766,12 +766,12 @@ printWord: ; DP0 is a two byte number, A is a byte. Adds the one to the other. addByteToWord: - DPUP.0 0d01 + INCD.0 LDB.0 CCF ADD STQ.0 - DPDN.0 0d01 + DECD.0 LDA.0 RSTB ADD diff --git a/Programs/CosmOS/Apps/Stream.asm b/Programs/CosmOS/Apps/Stream.asm index baf6ae6..f724020 100644 --- a/Programs/CosmOS/Apps/Stream.asm +++ b/Programs/CosmOS/Apps/Stream.asm @@ -290,11 +290,11 @@ checksumLoop: INCD.2 LDA.2 BNA checksumLow - DPDN.2 0d01 + DECD.2 LDA.2 DECA STA.2 ; Borrow out of the high byte. - DPUP.2 0d01 + INCD.2 INIA 0xFF STA.2 BRI checksumTest @@ -333,7 +333,7 @@ stepIndex: INCA STA.2 BNC stepIndexDone - DPDN.2 0d01 + DECD.2 LDA.2 INCA STA.2 diff --git a/Programs/CosmOS/Assembler/Asm.asm b/Programs/CosmOS/Assembler/Asm.asm index 5c5c4c2..9b6722a 100644 --- a/Programs/CosmOS/Assembler/Asm.asm +++ b/Programs/CosmOS/Assembler/Asm.asm @@ -735,7 +735,7 @@ emitStringLoop: CALL numStep SETD.1 EmitWalk LDD.0.1 - DPDN.0 0d01 + DECD.0 LDA.0 BNA emitStringLoop ; The zero goes out with the rest and then stops the loop. BRI emitDone diff --git a/Programs/CosmOS/Assembler/numbers.asm b/Programs/CosmOS/Assembler/numbers.asm index 279284c..660c4f6 100644 --- a/Programs/CosmOS/Assembler/numbers.asm +++ b/Programs/CosmOS/Assembler/numbers.asm @@ -28,16 +28,16 @@ numSet: ; The two byte number at DP0 becomes itself plus the one at DP2. numAdd: - DPUP.0 0d01 - DPUP.2 0d01 + INCD.0 + INCD.2 LDA.0 LDB.2 CCF ADD MVQA STA.0 - DPDN.0 0d01 - DPDN.2 0d01 + DECD.0 + DECD.2 LDA.0 LDB.2 ADD ; Carries in from the low half. Nothing between touches it. @@ -47,16 +47,16 @@ numAdd: ; The two byte number at DP0 becomes itself less the one at DP2. numTake: - DPUP.0 0d01 - DPUP.2 0d01 + INCD.0 + INCD.2 LDA.0 LDB.2 CCF SUB MVQA STA.0 - DPDN.0 0d01 - DPDN.2 0d01 + DECD.0 + DECD.2 LDA.0 LDB.2 SUB ; Borrows in from the low half. @@ -66,14 +66,14 @@ numTake: ; Adds the byte in A to the two byte number at DP0. numAddByte: - DPUP.0 0d01 + INCD.0 LDB.0 CCF ADD MVQA STA.0 BNC numAddByteDone - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 @@ -82,12 +82,12 @@ numAddByteDone: ; Adds one to the two byte number at DP0. numStep: - DPUP.0 0d01 + INCD.0 LDA.0 INCA STA.0 BNC numStepDone ; It did not wrap, so the high byte is untouched. - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 diff --git a/Programs/CosmOS/Source/cosmos.asm b/Programs/CosmOS/Source/cosmos.asm index 700e780..eed37c7 100644 --- a/Programs/CosmOS/Source/cosmos.asm +++ b/Programs/CosmOS/Source/cosmos.asm @@ -262,7 +262,7 @@ dirCheck: ; A file's length is its block count times 256 plus its tail, which is the block count ; in the high byte and the tail in the low one. Nothing has to multiply anything. SETD.0 SbfsFileBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 DirSize STA.1 @@ -1281,14 +1281,14 @@ breakAddress: SETD.0 SRegText PSHD.3 POPD.1 - DPUP.1 0d1 + INCD.1 CALL breakByte ; And which bits of it those are, since a debug dump that makes you look the number up is ; only half of one. Halt is not among them: the machine is plainly not halted. PSHD.3 POPD.1 - DPUP.1 0d1 + INCD.1 LDA.1 PSHA INIB 0x01 @@ -2283,12 +2283,12 @@ assembleNeedsValue: ; DP0 is a two byte address and A is how far to move it on. stepCursor: - DPUP.0 0d01 + INCD.0 LDB.0 CCF ADD STQ.0 - DPDN.0 0d01 + DECD.0 LDA.0 RSTB ADD diff --git a/Programs/CosmOS/Source/sbfs.asm b/Programs/CosmOS/Source/sbfs.asm index ddf23aa..e39871d 100644 --- a/Programs/CosmOS/Source/sbfs.asm +++ b/Programs/CosmOS/Source/sbfs.asm @@ -101,7 +101,7 @@ sbfsFind: SETD.1 SbfsBlock CALL sbfsCopyWord SETD.0 SbfsDirBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 SbfsLeft STA.1 ; Only the low byte: a directory of 256 blocks is 2048 files. @@ -163,7 +163,7 @@ sbfsFindFound: PSHD.3 POPD.0 - DPUP.0 0d01 + INCD.0 SETD.1 SbfsFileStart CALL sbfsCopyWord @@ -208,7 +208,7 @@ sbfsFirst: SETD.1 SbfsWalkBlock CALL sbfsCopyWord SETD.0 SbfsDirBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 SbfsWalkLeft STA.1 ; Only the low byte, the same as sbfsFind. @@ -308,7 +308,7 @@ sbfsWalkEnd: sbfsWalkTake: SETD.1 SbfsWalkAt LDD.0.1 - DPUP.0 0d01 + INCD.0 SETD.1 SbfsFileStart CALL sbfsCopyWord @@ -428,7 +428,7 @@ sbfsRead: CALL sbfsCopyWord SETD.0 SbfsFileBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 SbfsLeft STA.1 @@ -456,7 +456,7 @@ sbfsReadGot: ; On by a whole block. DPUP carries one byte at a time, so 256 takes two of them. DPUP.3 0xFF - DPUP.3 0x01 + INCD.3 SETD.0 SbfsBlock CALL sbfsStepWord @@ -534,7 +534,7 @@ sbfsEntryBounds: POPD.3 PSHD.3 POPD.0 - DPUP.0 0d01 + INCD.0 SETD.1 SbfsEntryStart CALL sbfsCopyWord SETD.0 SbfsEntryEnd @@ -586,7 +586,7 @@ sbfsAllocTry: SETD.1 SbfsBlock CALL sbfsCopyWord SETD.0 SbfsDirBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 SbfsLeft STA.1 @@ -682,16 +682,16 @@ sbfsSetWord: ; The two byte number at DP0 becomes itself less the one at DP2. sbfsSubWord: - DPUP.0 0d01 - DPUP.2 0d01 + INCD.0 + INCD.2 LDA.0 LDB.2 CCF SUB MVQA STA.0 - DPDN.0 0d01 - DPDN.2 0d01 + DECD.0 + DECD.2 LDA.0 LDB.2 SUB ; Borrows in from the low half. @@ -730,7 +730,7 @@ sbfsCreate: SETD.1 SbfsBlock CALL sbfsCopyWord SETD.0 SbfsDirBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 SbfsLeft STA.1 @@ -781,7 +781,7 @@ sbfsCreateFill: PSHD.3 POPD.1 - DPUP.1 0d01 + INCD.1 SETD.0 SbfsFileStart CALL sbfsCopyWord @@ -859,7 +859,7 @@ sbfsWriteFile: CALL sbfsSetWord CALL sbfsFileExtent SETD.0 SbfsWantBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 SbfsLeft STA.1 @@ -872,7 +872,7 @@ sbfsWriteLoop: CALL sbfsWriteBlock BNQ sbfsWriteFailed DPUP.3 0xFF - DPUP.3 0x01 + INCD.3 SETD.0 SbfsBlock CALL sbfsStepWord SETD.0 SbfsLeft @@ -983,12 +983,12 @@ sbfsCopyWord: ; Adds one to the two byte number at DP0. sbfsStepWord: - DPUP.0 0d01 + INCD.0 LDA.0 INCA STA.0 BNC sbfsStepDone ; It did not wrap, so the high byte is untouched. - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 @@ -998,16 +998,16 @@ sbfsStepDone: ; The two byte number at DP0 becomes itself plus the one at DP2. Only memory changes, so ; it survives the return: a routine cannot hand back a pointer or a register. sbfsAddWord: - DPUP.0 0d01 - DPUP.2 0d01 + INCD.0 + INCD.2 LDA.0 LDB.2 CCF ADD MVQA STA.0 - DPDN.0 0d01 - DPDN.2 0d01 + DECD.0 + DECD.2 LDA.0 LDB.2 ADD ; Carries in from the low half. Nothing between the two touches it. diff --git a/Programs/testPrograms/blitTest.asm b/Programs/testPrograms/blitTest.asm index ee11e09..d22e405 100644 --- a/Programs/testPrograms/blitTest.asm +++ b/Programs/testPrograms/blitTest.asm @@ -179,7 +179,7 @@ refusedHandler: BRC refusedCarried RETI refusedCarried: - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 diff --git a/Programs/testPrograms/controllerWriteTest.asm b/Programs/testPrograms/controllerWriteTest.asm index b416c82..38a729a 100644 --- a/Programs/testPrograms/controllerWriteTest.asm +++ b/Programs/testPrograms/controllerWriteTest.asm @@ -102,7 +102,7 @@ stepPastRefusal: BRC carried RETI carried: - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 diff --git a/Programs/testPrograms/faultResumeTest.asm b/Programs/testPrograms/faultResumeTest.asm index a4d2b4f..795f972 100644 --- a/Programs/testPrograms/faultResumeTest.asm +++ b/Programs/testPrograms/faultResumeTest.asm @@ -41,7 +41,7 @@ faultHandler: RETI carried: - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 diff --git a/Programs/testPrograms/fenceTest.asm b/Programs/testPrograms/fenceTest.asm index 3c2e3d9..9664bb6 100644 --- a/Programs/testPrograms/fenceTest.asm +++ b/Programs/testPrograms/fenceTest.asm @@ -143,7 +143,7 @@ guardHandler: BRC stepCarried RETI stepCarried: - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 diff --git a/Programs/testPrograms/refusalTest.asm b/Programs/testPrograms/refusalTest.asm index 82ab88e..966dff0 100644 --- a/Programs/testPrograms/refusalTest.asm +++ b/Programs/testPrograms/refusalTest.asm @@ -50,7 +50,7 @@ refusalHandler: RETI carried: - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 diff --git a/Programs/testPrograms/registerBankTest.asm b/Programs/testPrograms/registerBankTest.asm index 8d37892..8f4bfb6 100644 --- a/Programs/testPrograms/registerBankTest.asm +++ b/Programs/testPrograms/registerBankTest.asm @@ -114,7 +114,7 @@ bankHandler: BRC bankCarried RETI bankCarried: - DPDN.0 0d01 + DECD.0 LDA.0 INCA STA.0 diff --git a/Programs/testPrograms/sbfsReadTest.asm b/Programs/testPrograms/sbfsReadTest.asm index fa8c0fd..852f53b 100644 --- a/Programs/testPrograms/sbfsReadTest.asm +++ b/Programs/testPrograms/sbfsReadTest.asm @@ -89,7 +89,7 @@ showFound: showContents: SETD.0 Landing SETD.1 SbfsFileBlocks - DPUP.1 0d01 + INCD.1 LDA.1 SETD.1 LeftHigh STA.1 diff --git a/Programs/testPrograms/sbfsWalkTest.asm b/Programs/testPrograms/sbfsWalkTest.asm index a08c0c0..c8c24e1 100644 --- a/Programs/testPrograms/sbfsWalkTest.asm +++ b/Programs/testPrograms/sbfsWalkTest.asm @@ -60,7 +60,7 @@ walkCheck: ; A file is its blocks times 256 plus its tail, which is the block count in the high ; byte and the tail in the low one. Nothing has to multiply anything. SETD.0 SbfsFileBlocks - DPUP.0 0d01 + INCD.0 LDA.0 SETD.1 Size STA.1 diff --git a/Programs/testPrograms/stackPointerTest.asm b/Programs/testPrograms/stackPointerTest.asm index f28cb7c..0bd2a05 100644 --- a/Programs/testPrograms/stackPointerTest.asm +++ b/Programs/testPrograms/stackPointerTest.asm @@ -24,7 +24,7 @@ start: ; The Stack Pointer points at the next free slot, so the byte pushed last sits one ; above it, and the one before that sits two above. MVSD.0 - DPUP.0 0d01 + INCD.0 LDA.0 ; 'K', the last one pushed. INCD.0 LDB.0 ; 'O', the one before it.