!lm10
!rm76
Correction

When I typed Rick Hatcher's code for "Hiding Things Under DOS", AAL April, 1981, page 10, I goofed.  Change line 110 of the little Applesoft code from "110 POKE 40194,211" to "110 POKE 40192,211".  Better yet, to reserve NP pages between the current bottom of DOS and DOS's buffers, use this code before any files are opened:

     100 POKE 40192,PEEK(40192)-NP
     110 CALL 42964



More About Multiplying on the 6502

You will remember Brooke Boering's article on this subject in MICRO last December; I mentioned it in AAL#5, and printed his 16x16 multiply subroutine.  Now Leo J. Scanlon, author of 6502 Software Design, published an eight-page article "Multiplying by 1's and 0's" in Kilobaud Microcomputing, June 1981, pages 110-120.

If you are serious and really want to learn, this article gets down to the nuts and bolts level.  Work your way through it, and you will have learned not only how to multiply, but also a lot about machine language in general.  Subroutines are listed for 8x8, 16x16, and NxM multiplication, for both signed and unsigned operands.

Not to be outdone, I have written my own subroutine to multiply an M-byte multiplicand by a N-byte multiplier (both unsigned), producing a product of M+N bytes.  It is written for clarity, not for size or speed (nevertheless, it is two bytes shorter than Scanlon's subroutine!).

The basic idea is to examine the bits of the multiplier one-by-one, starting on the right.  If the multiplier bit = 1, the multiplicand is added in to the product, at the left end of the product register.  In either case, the product register is then shifted right one bit position.  The process is repeated until the multiplier is used up.

I wrote subroutines to shift the product register right one bit position, to shift the multiplier right one bit position returning the bit shifted out in the CARRY status bit, and to add the multiplicand to the product register.  There is no reason these have to be subroutines; they could be coded in line, because they are only called from one place.  I did it to make the overall program easier for you to follow.

The multiplication loop is coded as two loops:  an outer loop for the number of bytes in the multiplier, and an inner loop for the number of bits in a byte.  This allows me to have up to 255 bytes in the multiplier, just so the product (M+N bytes) is not more than 256 bytes.   (Of course, if you want variables that long, you will have to move them out of page zero.)

There is one little trick you might not notice.  After ACCUMULATE.PARTIAL.PRODUCT, carry will be set if the sum overflows.  Then SHIFT.PRODUCT.RIGHT shifts the carry bit back into the product register, maintaining the right answer.
!np
Specialized Multiplications

Sometimes you need a multiplication routine that is not general at all.  For example, when you are converting from decimal to binary, you need a routine that will multiply be ten.  When you are computing the memory address of a character at a particular position on a particular line on the Apple Screen, you need to be able to multiply by 40 and 128.  Other cases may come to your mind.

The subroutine BASCALC in the Apple Monitor computes the address in screen memory.  Here is what it is really doing, written in Integer BASIC:
!lm15

100 ADDR = 1024 + (LINE MOD 8)*128 + (LINE/8)*40
!lm10

To do all that using a generalized multiply routine would take hundreds of microseconds; BASCALC takes only 40 microseconds.  Here is Woz's code, with a few extra comments:


<bascalc subroutine here>



A subroutine to multiply by ten usually takes advantage of the fact that ten in binary is "1010".  That is, 10*X is the same as 8*X + 2*X, or 2*(4*X+X).  In fact, even in machines that have hardware multiply instructions, it is usually faster to multiply by ten using "shift-twice-and-add" than using the built in MPY opcode!

Here is a short piece of code which multiplies a two-byte value by ten, storing the result back in the same bytes.


<example here>


Another way, much less sophisticated, to multiply by ten is to simply add the number to itself nine times.  If you have the S-C ASSEMBLER II Version 4.0, disassemble from $114A through $117A.  You will find my subroutine for converting line numbers to binary.  It is not elegant, but it does the job reasonably fast in a small amount of memory.  A counter is initialized to 10; the next digit is read from the input line and converted from ASCII to binary; the number accumulator is added to the digit ten times, and the sum placed back into the number accumulator.  The counter is in $52, and the number accumulator is in $50,51.

When you are converting from binary to decimal, you need to divide by ten.  Or multiply by one-tenth.  One-tenth written as a binary fraction is ".0001100110011001100....".  Does the repetitive pattern here suggest to you a short-cut way to multiply by one-tenth?  Maybe it would become even easier if we write one-tenth as 4/30 - 1/30.  In decimal, to 8 places, that looks like .13333333 - .03333333 = .10000000.  In binary, to 18 bits, it looks like .001000100010001000 - .000010001000100010 = .000110011001100110.  See what you can come up with for a fast way to multiply a 16-bit number by one-tenth.  I'll print the best version in AAL!

