Submitted by Steve Fewell
Routine: Integer Division
Name: Integer Division
Starting Address: &80F9
Entry criteria: Either the IWA or FWA
contain the Dividend (Integer A), The BASIC Expression pointed to by BASICs
second text pointer (&19, &1A) evaluates to the Divisor value (Integer
B).
Exit: The routine evaluates the expression Integer A / Integer B.
Addresses &39 to &3C & the Carry-flag [so that odd-numbers are
handled correctly] contain half of the quotient (result) value. Addresses
&3D to &40 contain the remainder.
Description:
Check the current variable type (A), and if the current value is Floating-Point,
convert the Floating-Point value to an Integer (IWA).
Next, prepare the Dividend value by pushing its sign-byte (&2D) to the 6502
stack, and making the dividend positive (so that we only need to deal with
positive numbers).
Next call BASICs Integer expression handler &A00F to push the current integer to the BASIC stack, read the BASIC expression from the second Text Pointer (&19, &1A), evaluate it and return a numeric result. Check the variable type (A) of the numeric result, and if the current value is Floating-Point, convert the Floating-Point value to an Integer (IWA).
Retrieve the sign-byte for the Dividend (from the 6502 stack), Store it in &38 - This is the sign of the Remainder. EOR the Dividend's sign-byte with the sign-byte of the Divisor to obtain the sign of the result, store this in &37.
Next, as we already have determined the signs of our remainder and result, prepare the Divisor value by making it positive (so that we only need to deal with division of positive numbers).
Retrieve the Dividend from the BASIC stack to locations &39, &3A, &3B and &3C and clear locations &3D, &3E, &3F and &40 (the remainder). So that the IWA contains the Divisor, &39-&3C contain the Dividend/result and &3D-&40 contain the remainder.
If all bytes of the Divisor are zero (indicating a zero value), then give a Division by zero error and exit.
Set Y to 32 (this is the number of Dividend digits that we need to process, assume a 32-bit Integer).
&812D-&8139 keep decrementing Y and shifting the Dividend value left (towards the Most significant byte &3C), until we find a bit that is not zero. Now we know exactly how many bits in the Dividend we need to process (as we have removed the leading zeros).
This is the main loop, which performs binary long division on the two numbers:
*1) Shift the Result left 1 place. &813A-8141. (This is the same as the shift in step *2), but is specified here for clarity, as a different value is affected).
*2) Shift the Dividend left 1 place, loosing the top-most bit and shift the bit that was just lost from the Dividend into the lower-end of the Remainder (moving the remainders other bits left a place). &813A-&8149.
*3) Subtract the Divisor from the Remainder (least significant byte first), storing the 32-bit result in these 4 locations: 6502 stack (2 bytes), in X (1 byte) and in A (1 byte). &814A-&815D.
*4) If a borrow did not occur (the Divisor was successfully subtracted), then [&815E-&816B] store the result as the new remainder (&3D to &40). The next time step *2) is executed, shift 1 into the upper-end [right] of the Dividend, this will form the next bit of the result, when the Dividends bits are shifted left. BASIC cleverly uses the same 4-bytes to store the result, and the bits which are still left to be processed of the Dividend. Note: as the values are Binary, only 1 subtraction is required.
*5) Decrement Y
Keep looping until Y has reached zero. This indicates that no digits of the Dividend remain to be processed, and that locations &39-&3C contain the result. Note: The result has not been updated with the number of times the Divisor could be subtracted from the Remainder (in step *4)), so it is up to the calling routine to shift the carry-flag value into the bottom-end of the Result, shifting its other bits left a place. The calling routine also needs to convert the result (using &37) and/or Remainder (using &38) to the correct sign.
To simplify what this division routine is dong, here is the same routine using Base-10 Integer numbers:
ResultAdd = 0
Result = 0
Remainder = 0
Base = 10
Y = Len(Dividend)
Repeat
*1) Result = (Result * Base) + ResultAdd
*2) Remainder = (Remainder * Base) + Next-Digit-of-Dividend
*3a) Temp = Remainder
*3b) ResultAdd = 0
*3c) For Counter = 1 to Base-1
*3d) Temp = Temp - Divisor
*3e) if Temp > 0 then Remainder =
Temp : ResultAdd = ResultAdd + 1
*3f) Next Counter
*4) Rem Not required
*5) Y = Y - 1
Until Y = 0
E.g. 324 / 5 would produce the following workings:
Y = 3
Divisor = 5
Dividend = 324
*1) Result = (0 * 10) + 0 = 0
*2) Remainder = (0 * 10) + 3 = 3
*4) Remainder = 3; ResultAdd = 0
*5) Y = 2
*1) Result = (0 * 10) + 0 = 0
*2) Remainder = (3 * 10) + 2 = 32
*4) Remainder = 2; ResultAdd = 6
*5) Y = 1
*1) Result = (0 * 10) + 6 = 6
*2) Remainder = (2 * 10) + 4 = 24
*4) Remainder = 4; ResultAdd = 4
*5) Y = 0
Now to get the correct Result we need to do step *1) again :
*1) Result = (6 * 10) + 4 = 64
So, the result of 324/5 is 64, and the remainder is 4.
Disassembly for the Integer Division routine
80F9 | 032 190 150 | 20 BE 96 | JSR &96BE Check if Integer and Convert if Float | |
80FC | - | 165 045 | A5 2D | LDA &2D |
80FE | H | 072 | 48 | PHA |
80FF | 032 190 172 | 20 BE AC | JSR &ACBE Integer Positive | |
8102 | 032 015 160 | 20 0F A0 | JSR &A00F Push Integer to Stack and Get result of expression | |
8105 | ' | 134 039 | 86 27 | STX &27 |
8107 | 032 190 150 | 20 BE 96 | JSR &96BE Check if Integer and Convert if Float | |
810A | h | 104 | 68 | PLA |
810B | 8 | 133 056 | 85 38 | STA &38 |
810D | E- | 069 045 | 45 2D | EOR &2D |
810F | 7 | 133 055 | 85 37 | STA &37 |
8111 | 032 190 172 | 20 BE AC | JSR &ACBE Integer Positive | |
8114 | 9 | 162 057 | A2 39 | LDX#&39 |
8116 | 032 008 189 | 20 08 BD | JSR &BD08 Pop Integer from BASIC Stack Zero-page | |
8119 | d= | 100 061 | 64 3D | STZ &3D |
811B | d> | 100 062 | 64 3E | STZ &3E |
811D | d? | 100 063 | 64 3F | STZ &3F |
811F | d@ | 100 064 | 64 40 | STZ &40 |
8121 | - | 165 045 | A5 2D | LDA &2D |
8123 | * | 005 042 | 05 2A | ORA &2A |
8125 | + | 005 043 | 05 2B | ORA &2B |
8127 | , | 005 044 | 05 2C | ORA &2C |
8129 | G | 240 071 | F0 47 | BEQ 71 --> &8172 Division by zero error |
812B | 160 032 | A0 20 | LDY#&20 | |
812D | 136 | 88 | DEY | |
812E | A | 240 065 | F0 41 | BEQ 65 --> &8171 |
8130 | 9 | 006 057 | 06 39 | ASL &39 |
8132 | &: | 038 058 | 26 3A | ROL &3A |
8134 | &; | 038 059 | 26 3B | ROL &3B |
8136 | &< | 038 060 | 26 3C | ROL &3C |
8138 | 016 243 | 10 F3 | BPL -13 --> &812D | |
813A | &9 | 038 057 | 26 39 | ROL &39 |
813C | &: | 038 058 | 26 3A | ROL &3A |
813E | &; | 038 059 | 26 3B | ROL &3B |
8140 | &< | 038 060 | 26 3C | ROL &3C |
8142 | &= | 038 061 | 26 3D | ROL &3D |
8144 | &> | 038 062 | 26 3E | ROL &3E |
8146 | &? | 038 063 | 26 3F | ROL &3F |
8148 | &@ | 038 064 | 26 40 | ROL &40 |
814A | 8 | 056 | 38 | SEC |
814B | = | 165 061 | A5 3D | LDA &3D |
814D | * | 229 042 | E5 2A | SBC &2A |
814F | H | 072 | 48 | PHA |
8150 | > | 165 062 | A5 3E | LDA &3E |
8152 | + | 229 043 | E5 2B | SBC &2B |
8154 | H | 072 | 48 | PHA |
8155 | ? | 165 063 | A5 3F | LDA &3F |
8157 | , | 229 044 | E5 2C | SBC &2C |
8159 | 170 | AA | TAX | |
815A | @ | 165 064 | A5 40 | LDA &40 |
815C | - | 229 045 | E5 2D | SBC &2D |
815E | 144 012 | 90 0C | BCC 12 --> &816C | |
8160 | @ | 133 064 | 85 40 | STA &40 |
8162 | ? | 134 063 | 86 3F | STX &3F |
8164 | h | 104 | 68 | PLA |
8165 | > | 133 062 | 85 3E | STA &3E |
8167 | h | 104 | 68 | PLA |
8168 | = | 133 061 | 85 3D | STA &3D |
816A | 176 002 | B0 02 | BCS 2 --> &816E | |
816C | h | 104 | 68 | PLA |
816D | h | 104 | 68 | PLA |
816E | 136 | 88 | DEY | |
816F | 208 201 | D0 C9 | BNE -55 --> &813A | |
8171 | ` | 096 | 60 | RTS |