; The small things every other part of the assembler needs: sixteen bit arithmetic, for ; something that counts in addresses, and one string comparison. ; ; sbfs.asm has routines like these and the assembler cannot use them: it does not include ; the filesystem, because it reaches the disk through the system's services instead. That ; is the no-linker tax, paid in about a hundred and fifty bytes, and it is cheaper than the ; two and a half kilobytes including sbfs.asm would cost. ; ; Everything here works on numbers in memory rather than in registers, because a CALL puts ; A, B and Data Pointers 0 to 2 back as it found them. Only memory survives a return. ; ; Numbers are stored most significant byte first, the way every number on this machine is. ; ; Written by Anachronaut #Program ; The two byte number at DP0 becomes the one at DP2. Destination first, so a call reads ; the way an assignment does. numSet: LDA.2 STA.0 INCD.2 INCD.0 LDA.2 STA.0 RET ; The two byte number at DP0 becomes itself plus the one at DP2. numAdd: INCD.0 INCD.2 LDA.0 LDB.2 CCF ADD MVQA STA.0 DECD.0 DECD.2 LDA.0 LDB.2 ADD ; Carries in from the low half. Nothing between touches it. MVQA STA.0 RET ; The two byte number at DP0 becomes itself less the one at DP2. numTake: INCD.0 INCD.2 LDA.0 LDB.2 CCF SUB MVQA STA.0 DECD.0 DECD.2 LDA.0 LDB.2 SUB ; Borrows in from the low half. MVQA STA.0 RET ; Adds the byte in A to the two byte number at DP0. numAddByte: INCD.0 LDB.0 CCF ADD MVQA STA.0 BNC numAddByteDone DECD.0 LDA.0 INCA STA.0 numAddByteDone: RET ; Adds one to the two byte number at DP0. numStep: INCD.0 LDA.0 INCA STA.0 BNC numStepDone ; It did not wrap, so the high byte is untouched. DECD.0 LDA.0 INCA STA.0 numStepDone: RET ; Compares the two byte number at DP0 with the one at DP2. Q is zero if they are equal, ; and the Carry Flag is set if the one at DP0 is the smaller. Both come back, because ; neither Q nor the Status register is put back by a return. numCompare: LDA.0 LDB.2 CCF SUB ; The high bytes settle it unless they are the same. BNQ numCompareDone INCD.0 INCD.2 LDA.0 LDB.2 CCF SUB numCompareDone: RET ; Takes one off the two byte number at DP0. The mirror of numStep, and wanted for the same ; reason: walking an index backwards is what moving a run of entries up needs. numBack: INCD.0 LDA.0 BNA numBackLow ; The low half has something to take, so the high half is safe. DECD.0 LDA.0 DECA STA.0 INCD.0 LDA.0 numBackLow: DECA STA.0 RET ; The two byte number at DP0 becomes half of itself. ; ; A and B are a CIRCULAR sixteen bit register, so a rotate right brings bit nought back in at ; the top rather than dropping it - which is a halving only once that bit is taken off again. ; The numbers this is asked about are index positions, well under thirty two thousand, so the ; top bit was nought before the rotate and clearing it afterwards loses nothing. numHalve: LDA.0 INCD.0 LDB.0 SHR ; The low half goes down FIRST, because taking the wrapped bit off the high half wants B ; for the mask and there is nowhere else to keep it. STB.0 INIB 0x7F AND MVQA DECD.0 STA.0 RET ; Q is zero if the strings at DP0 and DP1 are the same, both ending in a zero byte. ; ; Down here rather than with the label table, where it started, because four separate ; parts want it: labels, vector names, which file has already been included, and which ; directive a keyword is. sameText: LDA.0 LDB.1 CCF SUB BNQ sameTextDone LDA.0 BRA sameTextDone ; They ended together, so they matched all the way. INCD.0 INCD.1 BRI sameText sameTextDone: RET ; The two byte number at DP0 becomes zero. numZero: RSTA STA.0 INCD.0 STA.0 RET