I'm late to this discussion, but here is my contribution: Mark Percival wrote: > 16 bit integer * 8 bit integer = 32 bit integer result > Astually the 8 bit integer in the multiplication is > actually a constant, the number decimal 25. Wanted: Multiply a word (16-bits) by 25 in 6502 assembly language. Method: To multiply by twenty-five, multiply by five then multiply by five. To multiply by five, multiply by four then add the original. To multiply by four, shift left by two bits. Notes: Assume all numbers are unsigned. Ignore overflow. Code: ORG $1000 VALUE = $0300 TEMP = $0303 NUM = 1000 ;NUMBER TO BE MULTIPLIED LDA #NUM STA VALUE LDA #NUM/256 STA VALUE+1 LDA #0 STA VALUE+2 JSR TIMES25 RTS * MULTIPLY BY 25 TIMES25 JSR TIMES5 TIMES5 * TEMP := VALUE * 4 LDA VALUE ASL STA TEMP LDA VALUE+1 ROL STA TEMP+1 LDA VALUE+2 ROL STA TEMP+2 ASL TEMP ROL TEMP+1 ROL TEMP+2 * VALUE := TEMP + VALUE LDA TEMP CLC ADC VALUE STA VALUE LDA TEMP+1 ADC VALUE+1 STA VALUE+1 LDA TEMP+2 ADC VALUE+2 STA VALUE+2 RTS -- Paul R. Santa-Maria Monroe, Michigan USA Ok, just to confuse people more, let me explain exactly what I'm trying to accomplish here. I'm writing a utility to write disk images back to real disks. One of the last features this program needs is a progress bar that advances as the image is being written back to disk. My progress bar has space for 25 progress indicators and I have two variables, CurrBlock, the current block number that was written and EndBlock, the last block number for this image. CurrBlock and EndBlock are both 16-bit numbers. To get a number from 0 to 25 out of that I figure I have to do the following: CurrBlock * 25 x = -------------- EndBlock Where x ends up being how many inverse spaces I need to write in the progress bar. Thus I first need to multiply CurrBlock by 25. Since a disk image under ProDOS 8 could be up to 32767 ($7FFF) blocks, multiplying that by 25 could give me a number as large as 819175 ($0C7FE7). So I need at least 24 bits to store that. Again the result of that I'll have to divide by EndBlock and that should give me the 0-25 range integer in the end that I need. What I have found is at http://www.ffd2.com/fridge/math/mult-div.s This shows a 16-bit multiplication giving a 32-bit result which is perfect. However the division routine shown is only two 16 bit numbers giving a 16 bit result. So half the problem is solved with that page. Anybody have a 32 bit division routine that they've used? Mark R. Percival - RTC Host - Syndicomm Online Apple II Forum "Midweek Madness!" Every Wednesday Night : 7:00 PM - 9:00 PM Pacific Time http://www.syndicomm.com Mark Percival wrote: > My progress bar has space for 25 progress indicators and I have two > variables, CurrBlock, the current block number that was written and > EndBlock, the last block number for this image. CurrBlock and EndBlock are > both 16-bit numbers. > > To get a number from 0 to 25 out of that I figure I have to do the > following: > > CurrBlock * 25 > x = -------------- > EndBlock > > Where x ends up being how many inverse spaces I need to write in the > progress bar. Too bad you don't have room for 32 spaces; that'd make it trivial. If you cut it to 24, your multiply becomes: CurMult = (CurrBlock << 4) + (CurrBlock << 3) You still have to divide a 24-bit value by EndBlock though. One possible alternative is to compute an approximate value for EndBlock/24 like this (essentially multiply by 1/24): EndDiv = (EndBlock >> 5) + (EndBlock >> 7) + (EndBlock >> 9) + (EndBlock >> 11) + (EndBlock >> 13) + (EndBlock >> 15); Then x = CurrBlock / EndDiv, where both CurrBlock and EndDiv are 16-bit values. That allows you to avoid 32-bit math. -- Send mail to fadden@fadden.com (Andy McFadden) - http://www.fadden.com/ CD-Recordable FAQ - http://www.cdrfaq.org/ CiderPress Apple II archive utility for Windows - http://www.faddensoft.com/ Fight Internet Spam - http://spam.abuse.net/spam/ & http://spamcop.net/ Mark Percival wrote: > I could. There is nothing magic about 25 spaces. I can see how that would > help in the multiplication (shift left 5 times) but how would that help > with the division? Strictly speaking, it doesn't. The pre-divide step becomes trivial. A formal division isn't necessary, because your result is known to be a small value. int GetProgress(unsigned int currBlock, unsigned int endBlock) { int quotient = 0; int endDiv = endBlock >> 5; // divide by 32 if (endDiv == 0) return 0; assert(currBlock <= endBlock); assert(currBlock >= 0); assert(endDiv > 0); // "divide" endDiv by currBlock; iterates at most 32 times while (currBlock > 0) { currBlock -= endDiv; quotient++; } return quotient; } In 65816 this is easy (SBC until the carry clears or == 0), in 6502 it's a little more awkward because of the 16-bit subtraction. The loop iterates between 0 and 32 times, 16 on average. I'm guessing 16 iterations of 16-bit subtractions will be faster than a full 32-bit divide. It may be faster than a 16-bit divide. It's certainly faster than code you don't have. :-) -- Send mail to fadden@fadden.com (Andy McFadden) - http://www.fadden.com/ CD-Recordable FAQ - http://www.cdrfaq.org/ CiderPress Apple II archive utility for Windows - http://www.faddensoft.com/ Fight Internet Spam - http://spam.abuse.net/spam/ & http://spamcop.net/ Mark Percival writes: > Ok, just to confuse people more, let me explain exactly what I'm trying to > accomplish here. > > I'm writing a utility to write disk images back to real disks. One of the > last features this program needs is a progress bar that advances as the > image is being written back to disk. > > My progress bar has space for 25 progress indicators and I have two > variables, CurrBlock, the current block number that was written and > EndBlock, the last block number for this image. CurrBlock and EndBlock are > both 16-bit numbers. > > To get a number from 0 to 25 out of that I figure I have to do the > following: > > CurrBlock * 25 > x = -------------- > EndBlock > > Where x ends up being how many inverse spaces I need to write in the > progress bar. > > Thus I first need to multiply CurrBlock by 25. Since a disk image under > ProDOS 8 could be up to 32767 ($7FFF) blocks, multiplying that by 25 could > give me a number as large as 819175 ($0C7FE7). So I need at least 24 bits > to store that. > > Again the result of that I'll have to divide by EndBlock and that should > give me the 0-25 range integer in the end that I need. Since CurrBlock is increasing by one at a time, and x is increasing by at most a small integer at a time, you need *incremental* multiplication and division, not the full thing. All you have to do is initialize x and a counter to zero, adding 25 to the counter each time CurrBlock increases. Then while the counter is greater(*) than EndBlock, subtract EndBlock and increment x. Since the counter is never greater than 32767+25, 16 bits will suffice. (*) I picked greater instead of greater than or equal to ensure a result between 0 and 24, since there are 25 progress indicators. Scott -- Scott Hemphill hemphill@alumni.caltech.edu "This isn't flying. This is falling, with style." -- Buzz Lightyear Andy McFadden wrote: >This is where I started (Bresenham on the brain?), but it wasn't clear >to me that CurrBlock increased by one at a time. The way my code is, I read 4K (8 blocks) from the image and then write it with 8 x WRITE_BLOCK MLI calls. 4K is 1 track worth on a 5.25" disk and it allows me to do sector rearranging for .dsk/.po translation. It has occurred to me that I don't need to update the progress bar after each 1 block write but I could do it after completing writing my 4K buffer. If I update the progress bar at that point then I can divide CurrBlock and EndBlock by 8 and go from $7FFF to $0FFF maximum blocks. Multiply $0FFF by 25 now gives me $018FE7. Still more than 16 bits but getting closer. Along that line if I update the progress bar after 8K (ever other read) then I can divide by 16 and that gives me a maximum of $C7E7 and finally fits into 16 bits for my divide. The result of doing it this way would be 17 progress bar updates of 25 positions for a 5.25" disk. This would mean that it would update sometimes by 1 position and other times by 2 when creating 5.25" disks. Anything disk bigger than that it would always update by 1. Not perfect but not bad either. Mark R. Percival - RTC Host - Syndicomm Online Apple II Forum "Midweek Madness!" Every Wednesday Night : 7:00 PM - 9:00 PM Pacific Time http://www.syndicomm.com "Mark Percival" wrote in message news:pv9k315vnskp7h3f57vfnhs99h1984kumf@4ax.com... > Andy McFadden wrote: > >>This is where I started (Bresenham on the brain?), but it wasn't clear >>to me that CurrBlock increased by one at a time. > > The way my code is, I read 4K (8 blocks) from the image and then write it > with 8 x WRITE_BLOCK MLI calls. 4K is 1 track worth on a 5.25" disk and > it > allows me to do sector rearranging for .dsk/.po translation. > > It has occurred to me that I don't need to update the progress bar after > each 1 block write but I could do it after completing writing my 4K > buffer. > If I update the progress bar at that point then I can divide CurrBlock and > EndBlock by 8 and go from $7FFF to $0FFF maximum blocks. Multiply $0FFF > by > 25 now gives me $018FE7. Still more than 16 bits but getting closer. > Along that line if I update the progress bar after 8K (ever other read) > then I can divide by 16 and that gives me a maximum of $C7E7 and finally > fits into 16 bits for my divide. > > The result of doing it this way would be 17 progress bar updates of 25 > positions for a 5.25" disk. This would mean that it would update > sometimes > by 1 position and other times by 2 when creating 5.25" disks. Anything > disk bigger than that it would always update by 1. > > Not perfect but not bad either. > > Mark R. Percival - RTC Host - Syndicomm Online Apple II Forum > "Midweek Madness!" Every Wednesday Night : 7:00 PM - 9:00 PM Pacific Time > > http://www.syndicomm.com Before I type up the division let me know if this is in the ballpark of working for you. MPLIER EQU $FA ;FB MCAND EQU $FC ;FD MULTIPLY LDA #MULTIPLIER SBC #0 STA MPLIER+1 LDA #MULTIPLICAND SBC #0 STA MCAND+1 ;COUNT = LENGTH * 8 +1 LDA LENGTH STA COUNT LDA #0 ASL COUNT ;COUNT *2 ROL A ;A WILL BE UPPER BYTE ASL COUNT ;COUNT *4 ROL A ASL COUNT ;COUNT *8 ROL A STA COUNT+1 INC COUNT ;YOUR +1 BNE SCRATCH INC COUNT+1 ;IF LOW BYTE BECOME 0 ;ZERO THE WORK AREA SCRATCH LDX LENGTH LDA #0 SCRLP STA SCRATCHPAD-1,X ;-1 FOR INDEXING FROM 1 BNE SCRLP CLC ;START FRESH DOLOOP LDX LENGTH ROLLLP ROR SCRATCHPAD-1,X DEX BNE ROLLLP ;TILL X = 0 LDY LENGTH SHIFTLP LDA (MPLIER),Y ROR A STA (MPLIER),Y DEY BNE SHIFTLP ;TILL Y=0 BCC DECCNT LDY #1 LDX LENGTH CLC ADDLP LDA (MCAND),Y ADC SCRATCHPAD-1,Y STA SCRATCHPAD-1,Y INY DEX BNE ADDLP DECCNT DEC COUNT BNE DOLOOP LDX COUNT+1 BEQ DONE DEX STX COUNT+1 JMP DOLOOP ;BPL SHOULD WORK DONE RTS ;MULTIPLIER WILL CONTAIN THE RESULTS WHEN FINISHED multiplier DFB $00 ;0 LSB DFB $00 DFB $00 DFB $00 DFB $00 DFB $00 DFB $00 ;7 MSB multiplicand DFB $00 ;0 LSB DFB $00 DFB $00 DFB $00 DFB $00 DFB $00 DFB $00 ;7 MSB COUNT DS 2 ;# OF BITS +1 LENGTH DFB $07 ;number of bytes SCRATCHPAD DS 7 ;MATCH ABOVE ;EXAMPLE $12345 * $1234 = $14B60404 ;MAKE SURE UNUSED BYTES ARE $00 LDA #$45 STA MULTIPLIER LDA #$23 STA MULTIPLIER+1 LDA #$01 STA MULTIPLIER+2 LDA #$34 STA MULTIPLICAND LDA #$12 STA MULTIPLICAND+1 JSR MULTIPLY BRK THE RESULT WILL BE MULTIPLIER = $04 MULTIPLIER+1 = $04 MULTIPLIER+2 = $B6 MULTIPLIER+3 = $14 MULTIPLIER+4 = $00 MULTIPLIER+5 = $00 MULTIPLIER+6 = $00 > SCRLP STA SCRATCHPAD-1,X ;-1 FOR INDEXING FROM 1 > BNE SCRLP > > CLC ;START FRESH SCRLP STA SCRATCHPAD-1,X ;-1 FOR INDEXING FROM 1 DEX missing instruction here BNE SCRLP CLC ;START FRESH On Thu, 17 Mar 2005 16:39:21 -0500, Mark Percival wrote: > I'm writing a utility to write disk images back to real disks. One of the > last features this program needs is a progress bar that advances as the > image is being written back to disk. Hello Mark, It seems wasteful to do so many divisions just to update a status bar. 1) Use a progress indicator with a length of 32, not 25. 2) At the beginning of the process, compute how many file blocks correspond to one progress indicator on the status bar. This is easily done by dividing Endblock by 32 (shift right 5 times). Call this value the "update interval" and save it on page zero. It will be a value between 0 and 1023. 3) Set counter = update interval. 4) Process next file block 5) If end of file reached, return. 6) Decrement counter 7) If counter > 0, go to 4 8) Update your status bar, go to 3. Paul Guertin pg@sff.net Paul Guertin wrote: > 2) At the beginning of the process, compute how many file blocks > correspond to one progress indicator on the status bar. This is > easily done by dividing Endblock by 32 (shift right 5 times). > Call this value the "update interval" and save it on page zero. > It will be a value between 0 and 1023. > > 3) Set counter = update interval. > 4) Process next file block > 5) If end of file reached, return. > 6) Decrement counter > 7) If counter > 0, go to 4 > 8) Update your status bar, go to 3. This isn't *quite* right, because round-off error could leave you hanging. If you have 32768 blocks you end right on time, but with 32767 blocks your status bar never hits the end. The incremental solution in another post is more accurate, and works for non-nice values (i.e. not just 32). I agree with your initial assessment, however: having the status bar be "perfect" isn't necessary. Watch the ProDOS 8 ShrinkIt status bar when it's writing to a 5.25" disk -- it doesn't update for the last few tracks. Dividing values only makes sense if the status bar isn't being updated on every block, or if the way the program was written it's inconvenient to have the status bar function maintain state. Even then, the expected quotient is small enough that iterating subtractions will be fast enough. (Nit: the maximum #of blocks on a ProDOS volume is 65535; 65535/32=2047.) -- Send mail to fadden@fadden.com (Andy McFadden) - http://www.fadden.com/ CD-Recordable FAQ - http://www.cdrfaq.org/ CiderPress Apple II archive utility for Windows - http://www.faddensoft.com/ Fight Internet Spam - http://spam.abuse.net/spam/ & http://spamcop.net/ This is a multi-part message in MIME format. ------=_NextPart_000_0031_01C52C6E.4F2E8280 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable "Mark Percival" wrote in message = news:lmlk31p6td4hvu0bcf5fe88bip9ope7vn9@4ax.com... > Andy McFadden wrote: > Laine, thanks for the source code. I probably won't use it in this = program > but I am going to keep it for future. Multiplication and division is > always a problem in 6502 assembly code. >=20 > Mark R. Percival - RTC Host - Syndicomm Online Apple II Forum > "Midweek Madness!" Every Wednesday Night : 7:00 PM - 9:00 PM Pacific = Time >=20 > http://www.syndicomm.com Mark it is handy. Since I was already that far along I went ahead and assembled and tested = the routines. Just jump down to the bottom and cut them out. LIST OFF KEEP TEST * TEST MULTIPLY AND DIVIDE *************************************** TESTDRIVE START USING COMMON MSB ON PRINTBYTE GEQU $FDDA HOME GEQU $FC58 COUT GEQU $FDED HDVND1 EQU $EB ;EC JSR HOME JSR ZEROALL LDA #$45 STA MULTIPLIER LDA #$23 STA MULTIPLIER+1 LDA #$01 STA MULTIPLIER+2 LDA #$34 STA MULTIPLICAND LDA #$12 STA MULTIPLICAND+1 JSR SAYIT DC C'Multiply $12345 * $1234',H'8D 00' JSR MULTIPLY JSR SAYIT DC C'Result =3D $',H'00' LDX LENGTH PBMLP DEX BMI RETURN LDA MULTIPLIER,X JSR PRINTBYTE CLC BCC PBMLP RETURN JSR SAYIT DC H'8D8D00' JSR ZEROALL JSR SAYIT DC C'Divide 0 / 0 ',H'8D 00' JSR DIVIDE ;TEST DIVISION BY 0 BCC MORE ;NOT!, FALL THROUGH JSR SAYIT DC C'Division by zero error.',H'8D 8D 00' MORE LDA #$04 STA DIVIDEND LDA #$04 STA DIVIDEND+1 LDA #$B6 STA DIVIDEND+2 LDA #$14 STA DIVIDEND+3 LDA #$34 STA DIVISOR LDA #$12 STA DIVISOR+1 JSR SAYIT DC C'Divide $14B60404 / $1234',H'8D 00' JSR DIVIDE BCS ERROR JSR SAYIT DC C' Result =3D $',H'00' LDX LENGTH PBLP DEX BMI RMDR LDA DIVIDEND,X JSR PRINTBYTE CLC BCC PBLP RMDR JSR SAYIT DC H'8D',C'Remainder =3D $',H'00' LDY LENGTH PB1LP DEY BMI PBDONE LDA (HDVND1),Y JSR PRINTBYTE CLC BCC PB1LP PBDONE RTS ERROR BRK ;CRASH AND DIE, SHOULDN'T HAPPEN MSB OFF END *************************************** *ZERO DATA BUFFERS *************************************** ZEROALL START USING COMMON LDA #MULTIPLIER SBC #0 STA MPLIER+1 LDA #MULTIPLICAND SBC #0 STA MCAND+1 ;COUNT =3D LENGTH * 8 +1 LDA LENGTH STA COUNT LDA #0 ASL COUNT ;COUNT *2 ROL A ;A WILL BE UPPER BYTE ASL COUNT ;COUNT *4 ROL A ASL COUNT ;COUNT *8 ROL A STA COUNT+1 INC COUNT ;YOUR +1 BNE ZEROPROD INC COUNT+1 ;IF LOW BYTE BECOMES 0 ;ZERO HIPROD ZEROPROD LDX LENGTH LDA #0 ZROLP STA HIGHPROD-1,X ;-1 FOR INDEXING FROM 1 DEX BNE ZROLP ;MULTIPLY USING SHIFT AND ADD ; ARRAY1 WILL BE THE MULTIPLIER AND ARRAY2 THE MULTIPLICAND CLC ;FIRST TIME THROUGH ;SHIFT CARRY INTO HIPROD AND THE LEAST SIGNIFICANT ; BIT OF HIPROD INTO CARRY LOOP LDX LENGTH ROLLLP ROR HIGHPROD-1,X DEX BNE ROLLLP ;TILL X =3D 0 ;SHIFT CARRY WHICH IS THE NEXT BIT OF THE LOWER PRODUCT INTO THE MOST ; SIGNIFICANT BIT OF ARRAY1. THIS IS NEXT BIT OF THE PRODUCT, ; THIS ALSO SHIFTS THE NEXT BIT OF THE MULTIPLIER TO CARRY LDY LENGTH SHIFTLP LDA (MPLIER),Y ROR A STA (MPLIER),Y DEY BNE SHIFTLP ;TILL Y=3D0 ;IF THE NEXT BIT OF THE MULTIPLIER IS 1 THEN ; ADD ARRAY2 AND HIPROD BCC DECCNT ;BRANCH IF NEXT BIT IS 0 LDY #1 LDX LENGTH CLC ADDLP LDA (MCAND),Y ADC HIGHPROD-1,Y STA HIGHPROD-1,Y INY DEX BNE ADDLP ;DEC BIT COUNT AND EXIT IF DONE ; CARRY UNCHANGED DECCNT DEC COUNT BNE LOOP LDX COUNT+1 BEQ DONE DEX STX COUNT+1 JMP LOOP DONE RTS END *************************************** *DIVIDE ROUTINE *************************************** DIVIDE START USING COMMON DVND EQU $FA ;FB DVSR EQU $FC ;FD HDVND1 EQU $EB ;EC HDVND2 EQU $ED ;EE LDA #DIVISOR STA DVSR+1 LDA #DIVIDEND STA DVND+1 LDA #HIGHDVND1 STA HDVND1+1 LDA #HIGHDVND2 STA HDVND2+1 ;COUNT =3D LENGTH * 8 +1 LDA LENGTH STA COUNT LDA #0 ASL COUNT ;COUNT *2 ROL A ;A WILL BE UPPER BYTE ASL COUNT ;COUNT *4 ROL A ASL COUNT ;COUNT *8 ROL A STA COUNT+1 INC COUNT ;YOUR +1 BNE ZEROHIGH INC COUNT+1 ;IF LOW BYTE BECOME 0 ;ZERO HIGH DIVIDENDS ZEROHIGH LDX LENGTH LDA #0 ZROHI STA HIGHDVND1-1,X ;-1 FOR INDEXING FROM 1 TO LENGTH STA HIGHDVND2-1,X DEX BNE ZROHI ;CHECK IF DIVISION BY 0 LDX LENGTH LDY #0 TYA DB0LP ORA (DVSR),Y INY DEX BNE DB0LP CMP #0 BEQ ERROR ;DIVIDE USING TRIAL SUBTRACTION CLC ;FIRST TIME THROUGH ;SHIFT CARRY INTO LOWER DIVIDEND ARRAY AS THE NEXT BIT OF QUOTIENT ; AND THE MOST SIGNIFICANT BIT OF THE LOWER DIVIDEND TO CARRY LOOP LDX LENGTH LDY #0 SHIFTLP LDA (DVND),Y ROL A STA (DVND),Y INY DEX BNE SHIFTLP DECCNT DEC COUNT BNE MORE LDX COUNT+1 BEQ DONE DEX STX COUNT+1 ;SHIFT THE CARRY INTO THE LEAST SIGNIFICANT BIT OF THE UPPER DIVIDEND MORE LDX LENGTH LDY #0 SHIFT2LP LDA (HDVND1),Y ROL A STA (HDVND1),Y INY DEX BNE SHIFT2LP ;SUBTRACT ARRAY2 FROM HDVND1 PLACING THE DIFFERENCE INTO HDVND2 LDY #0 LDX LENGTH SEC SUBLP LDA (HDVND1),Y SBC (DVSR),Y ;SUBTRACT THE BYTES STA (HDVND2),Y ;STORE THE DIFFERENCE INY DEX BNE SUBLP ;IF NO CARRY IS GENERATED FROM THE SUBTRACTION THEN THE HDVND1 ; IS LESS THAN ARRAY 2 SO THE NEXT BIT OF THE QUOTIENT IS 0. ; IF THE CARRY IS SET THEN THE NEXT BIT OF THE QUOTIENT IS 1 ; AND WE REPLACE THE DIVIDEND WITH REMAINDER BY SWITCHING POINTERS BCC LOOP ;WAS TRIAL SUBTRACTION SUCESSFUL? LDY HDVND1 ;YES, EXCHANGE POINTERS THUS = REPLACING LDX HDVND1+1 ; DIVIDEND WITH REMAINDER LDA HDVND2 STA HDVND1 LDA HDVND2+1 STA HDVND1+1 STY HDVND2 STX HDVND2+1 ;CONTINUE WITH NEXT BIT A 1 (CARRY =3D 1) JMP LOOP DONE CLC BCC EXIT ERROR SEC EXIT RTS ;ARRAY1 IS THE QUOTIENT ;HDVND1 POINTS TO THE REMAINDER END *************************************** ------=_NextPart_000_0031_01C52C6E.4F2E8280 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable
 
"Mark Percival" <mark@syndicomm.com> = wrote in=20 message news:lmlk31p6td4hvu0bcf5fe88bip9ope7vn9@4ax.com...
> Andy McFadden wrote:

> = Laine,=20 thanks for the source code.  I probably won't use it in this=20 program
> but I am going to keep it for future.  = Multiplication and=20 division is
> always a problem in 6502 assembly code.
> =
>=20 Mark R. Percival - RTC Host - Syndicomm Online Apple II Forum
> = "Midweek=20 Madness!" Every Wednesday Night : 7:00 PM - 9:00 PM Pacific Time
> =
>
http://www.syndicomm.com
 
Mark it is handy.
Since I was already that far along I went = ahead and=20 assembled and tested the routines.
 
Just jump down to the bottom and cut them=20 out.
 


          =     =20 LIST=20 OFF
           =    =20 KEEP TEST
 

* TEST MULTIPLY AND=20 DIVIDE
***************************************
TESTDRIVE  = ;   =20 START
 
           &n= bsp;  =20 USING=20 COMMON
          &nb= sp;   =20 MSB  ON
 
PRINTBYTE      GEQU=20 $FDDA
HOME          = GEQU=20 $FC58
COUT          = GEQU=20 $FDED
HDVND1         = EQU =20 $EB            = ;EC
 
           &n= bsp;  =20 JSR =20 HOME
           = ;   =20 JSR  ZEROALL
 
           &n= bsp;  =20 LDA =20 #$45
           = ;   =20 STA =20 MULTIPLIER
          = ;    =20 LDA =20 #$23
           = ;   =20 STA =20 MULTIPLIER+1
         &nb= sp;    =20 LDA =20 #$01
           = ;   =20 STA  MULTIPLIER+2
 
           &n= bsp;  =20 LDA =20 #$34
           = ;   =20 STA =20 MULTIPLICAND
         &nb= sp;    =20 LDA =20 #$12
           = ;   =20 STA  MULTIPLICAND+1
 
           &n= bsp;  =20 JSR =20 SAYIT
          &nbs= p;   =20 DC   C'Multiply $12345 * $1234',H'8D 00'
 
           &n= bsp;  =20 JSR =20 MULTIPLY
          &= nbsp;   =20 JSR =20 SAYIT
          &nbs= p;   =20 DC   C'Result =3D=20 $',H'00'
          &= nbsp;   =20 LDX  = LENGTH
PBMLP         =20 DEX
           =    =20 BMI =20 RETURN
          &nb= sp;   =20 LDA =20 MULTIPLIER,X
         &nb= sp;    =20 JSR =20 PRINTBYTE
          =     =20 CLC
           =    =20 BCC  = PBMLP
RETURN        =20 JSR =20 SAYIT
          &nbs= p;   =20 DC   H'8D8D00'
 
           &n= bsp;  =20 JSR =20 ZEROALL
          &n= bsp;   =20 JSR =20 SAYIT
          &nbs= p;   =20 DC   C'Divide 0 / 0 ',H'8D=20 00'
           =    =20 JSR  DIVIDE         ;TEST = DIVISION=20 BY=20 0
           &n= bsp;  =20 BCC  = MORE          =20 ;NOT!, FALL=20 THROUGH
          &n= bsp;   =20 JSR =20 SAYIT
          &nbs= p;   =20 DC   C'Division by zero error.',H'8D 8D=20 00'
MORE          =20 LDA =20 #$04
           = ;   =20 STA =20 DIVIDEND
          &= nbsp;   =20 LDA =20 #$04
           = ;   =20 STA =20 DIVIDEND+1
          = ;    =20 LDA =20 #$B6
           = ;   =20 STA =20 DIVIDEND+2
          = ;    =20 LDA =20 #$14
           = ;   =20 STA  DIVIDEND+3
 
           &n= bsp;  =20 LDA =20 #$34
           = ;   =20 STA =20 DIVISOR
          &n= bsp;   =20 LDA =20 #$12
           = ;   =20 STA  DIVISOR+1
 
           &n= bsp;  =20 JSR =20 SAYIT
          &nbs= p;   =20 DC   C'Divide $14B60404 / $1234',H'8D=20 00'
           =    =20 JSR =20 DIVIDE
          &nb= sp;   =20 BCS =20 ERROR
          &nbs= p;   =20 JSR =20 SAYIT
          &nbs= p;   =20 DC   C'   Result =3D=20 $',H'00'
          &= nbsp;   =20 LDX =20 LENGTH
PBLP          = ;=20 DEX
           =    =20 BMI =20 RMDR
           = ;   =20 LDA =20 DIVIDEND,X
          = ;    =20 JSR =20 PRINTBYTE
          =     =20 CLC
           =    =20 BCC =20 PBLP
RMDR           = JSR =20 SAYIT
          &nbs= p;   =20 DC   H'8D',C'Remainder =3D=20 $',H'00'
          &= nbsp;   =20 LDY  = LENGTH
PB1LP         =20 DEY
           =    =20 BMI =20 PBDONE
          &nb= sp;   =20 LDA =20 (HDVND1),Y
          = ;    =20 JSR =20 PRINTBYTE
          =     =20 CLC
           =    =20 BCC  PB1LP
 
PBDONE        =20 RTS
ERROR         =20 BRK           &nbs= p;    =20 ;CRASH AND DIE, SHOULDN'T HAPPEN
 
           &n= bsp;  =20 MSB  OFF
 
           &n= bsp;  =20 END
***************************************
 
*ZERO DATA=20 BUFFERS
***************************************
ZEROALL  =      =20 START
 
           &n= bsp;  =20 USING COMMON
 
           &n= bsp;  =20 LDA =20 #<LENGTH
         &nbs= p;    =20 SEC
           =    =20 SBC =20 #<ARRAY1
         &nbs= p;    =20 TAX
           =    =20 DEX
           =    =20 LDA  #0
ZEROLP         = STA =20 ARRAY1,X
          &= nbsp;   =20 DEX
           =    =20 BPL =20 ZEROLP
          &nb= sp;   =20 RTS
 
           &n= bsp;  =20 END
***************************************
 

*TEXT=20 PRINTER
***************************************
SAYIT  &n= bsp;      =20 START
 
RTN           = ;=20 EQU  $06
 
           &n= bsp;  =20 PLA           &nbs= p;    =20 ;GET RTN=20 ADDRESS
          &n= bsp;   =20 CLC
           =    =20 ADC =20 #1            = ;=20 ;CORRECT=20 RTN
           =    =20 STA  = RTN           =20 ;USE AS=20 INDEX
          &nbs= p;   =20 PLA           &nbs= p;    =20 ;TO=20 DATA
           = ;   =20 ADC =20 #0
           &= nbsp;  =20 STA  RTN+1
 
           &n= bsp;  =20 LDX =20 #0
           &= nbsp;  =20 LDY =20 #0            = ; ;=20 PRINT THE=20 MSG
LOOP          =20 LDA =20 (RTN),Y
          &n= bsp;   =20 BEQ =20 DONE
           = ;   =20 JSR =20 COUT
           = ;   =20 INX
           =    =20 INY
           =    =20 BNE =20 LOOP
DONE           = TXA
           =    =20 CLC
           =    =20 ADC =20 RTN
           =    =20 TAX
           =    =20 LDA =20 RTN+1
          &nbs= p;   =20 ADC =20 #0
           &= nbsp;  =20 PHA
           =    =20 TXA
           =    =20 PHA
           =    =20 RTS
 
           &n= bsp;  =20 END
***************************************
 
*DATA=20 BUFFERS
***************************************
COMMON  &= nbsp;     =20 DATA
 
DIVIDEND      =20 ANOP
MULTIPLIER    =20 ANOP
ARRAY1         = DC  =20 H'00'         =20 ;LSByte
          &n= bsp;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC   = H'00'          ;7=20 MSByte
 
DIVISOR       =20 ANOP
MULTIPLICAND  =20 ANOP
ARRAY2         = DC  =20 H'00'         =20 ;LSByte
          &n= bsp;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC  =20 H'00'
          &nbs= p;   =20 DC   = H'00'          ;7=20 MSByte
 

HIGHPROD      =20 ANOP
HIGHDVND1     =20 ANOP
BUFFER1        DS   = 7            =  =20 ;MATCH LENGTH
 
HIGHDVND2     =20 ANOP
BUFFER2        DS   = 7            =  =20 ;MATCH LENGTH
 
COUNT          = DS  =20 2            =  =20 ;# OF BITS +1
 
LENGTH         = DC  =20 H'07'          ;NUMBER OF = BYTES IN=20 ARRAY
 
           &n= bsp;  =20 END
***************************************
 

*MULTIPLY=20 ROUTINE
***************************************
MULTIPLY  = ;    =20 START
 
           &n= bsp;  =20 USING COMMON
 
MPLIER         EQU =20 $FA           =20 ;FB
MCAND          = EQU =20 $FC            = ;FD
 
           &n= bsp;  =20 LDA =20 #<MULTIPLIER
         =      =20 SEC
           =    =20 SBC =20 #1            = ;=20 ;INDEX BY 1 NOT=20 0
           &n= bsp;  =20 STA =20 MPLIER
          &nb= sp;   =20 LDA =20 #>MULTIPLIER
         =      =20 SBC =20 #0
           &= nbsp;  =20 STA  MPLIER+1
 
           &n= bsp;  =20 LDA =20 #<MULTIPLICAND
        &nbs= p;     =20 SEC
           =    =20 SBC =20 #1            = ;=20 ;INDEX BY 1 NOT=20 0
           &n= bsp;  =20 STA =20 MCAND
          &nbs= p;   =20 LDA =20 #>MULTIPLICAND
        &nbs= p;     =20 SBC =20 #0
           &= nbsp;  =20 STA  MCAND+1
 
;COUNT =3D LENGTH * 8=20 +1
           &= nbsp;  =20 LDA =20 LENGTH
          &nb= sp;   =20 STA =20 COUNT
          &nbs= p;   =20 LDA =20 #0
           &= nbsp;  =20 ASL  COUNT          = ;COUNT=20 *2
           &= nbsp;  =20 ROL =20 A            =  =20 ;A WILL BE UPPER=20 BYTE
           = ;   =20 ASL  COUNT          = ;COUNT=20 *4
           &= nbsp;  =20 ROL =20 A
           &n= bsp;  =20 ASL  COUNT          = ;COUNT=20 *8
           &= nbsp;  =20 ROL =20 A
           &n= bsp;  =20 STA =20 COUNT+1
          &n= bsp;   =20 INC  COUNT          = ;YOUR=20 +1
           &= nbsp;  =20 BNE =20 ZEROPROD
          &= nbsp;   =20 INC  COUNT+1        ;IF LOW BYTE = BECOMES=20 0
 
;ZERO HIPROD
ZEROPROD       = LDX =20 LENGTH
          &nb= sp;   =20 LDA  = #0
ZROLP         =20 STA  HIGHPROD-1,X   ;-1 FOR INDEXING FROM=20 1
           &n= bsp;  =20 DEX
           =    =20 BNE  ZROLP
 
;MULTIPLY USING SHIFT AND ADD
; ARRAY1 WILL BE THE MULTIPLIER = AND ARRAY2=20 THE MULTIPLICAND
 
           &n= bsp;  =20 CLC           &nbs= p;    =20 ;FIRST TIME THROUGH
 
;SHIFT CARRY INTO HIPROD AND THE LEAST SIGNIFICANT
; BIT OF = HIPROD INTO=20 CARRY
 
LOOP           = LDX =20 LENGTH
ROLLLP         = ROR =20 HIGHPROD-1,X
         &nb= sp;    =20 DEX
           =    =20 BNE  ROLLLP         ;TILL X = =3D=20 0
 
;SHIFT CARRY WHICH IS THE NEXT BIT OF THE LOWER PRODUCT INTO THE = MOST
;=20 SIGNIFICANT BIT OF ARRAY1. THIS IS NEXT BIT OF THE PRODUCT,
; THIS = ALSO=20 SHIFTS THE NEXT BIT OF THE MULTIPLIER TO CARRY
 
           &n= bsp;  =20 LDY  LENGTH
SHIFTLP        = LDA =20 (MPLIER),Y
          = ;    =20 ROR =20 A
           &n= bsp;  =20 STA =20 (MPLIER),Y
          = ;    =20 DEY
           =    =20 BNE  SHIFTLP        ;TILL = Y=3D0
 
;IF THE NEXT BIT OF THE MULTIPLIER IS 1 THEN
; ADD ARRAY2 AND=20 HIPROD
          &nb= sp;   =20 BCC  DECCNT         ;BRANCH = IF NEXT=20 BIT IS 0
 
           &n= bsp;  =20 LDY =20 #1
           &= nbsp;  =20 LDX =20 LENGTH
          &nb= sp;   =20 CLC
ADDLP          = LDA =20 (MCAND),Y
          =     =20 ADC =20 HIGHPROD-1,Y
         &nb= sp;    =20 STA =20 HIGHPROD-1,Y
         &nb= sp;    =20 INY
           =    =20 DEX
           =    =20 BNE  ADDLP
 
;DEC BIT COUNT AND EXIT IF DONE
; CARRY=20 UNCHANGED
DECCNT         = DEC =20 COUNT
          &nbs= p;   =20 BNE =20 LOOP
           = ;   =20 LDX =20 COUNT+1
          &n= bsp;   =20 BEQ =20 DONE
           = ;   =20 DEX
           =    =20 STX =20 COUNT+1
          &n= bsp;   =20 JMP  LOOP
 
DONE           = RTS
 
           &n= bsp;  =20 END
***************************************
 

*DIVIDE=20 ROUTINE
***************************************
DIVIDE  &= nbsp;     =20 START
 
           &n= bsp;  =20 USING COMMON
 
DVND           = EQU =20 $FA           =20 ;FB
DVSR          =20 EQU  = $FC           =20 ;FD
HDVND1         EQU =20 $EB           =20 ;EC
HDVND2         EQU =20 $ED            = ;EE
 
           &n= bsp;  =20 LDA =20 #<DIVISOR
         &nb= sp;    =20 STA =20 DVSR
           = ;   =20 LDA =20 #>DIVISOR
         &nb= sp;    =20 STA  DVSR+1
 
           &n= bsp;  =20 LDA =20 #<DIVIDEND
         &n= bsp;    =20 STA =20 DVND
           = ;   =20 LDA =20 #>DIVIDEND
         &n= bsp;    =20 STA  DVND+1
 
           &n= bsp;  =20 LDA =20 #<HIGHDVND1
         &= nbsp;    =20 STA =20 HDVND1
          &nb= sp;   =20 LDA =20 #>HIGHDVND1
         &= nbsp;    =20 STA  HDVND1+1
 
           &n= bsp;  =20 LDA =20 #<HIGHDVND2
         &= nbsp;    =20 STA =20 HDVND2
          &nb= sp;   =20 LDA =20 #>HIGHDVND2
         &= nbsp;    =20 STA  HDVND2+1
 
;COUNT =3D LENGTH * 8=20 +1
           &= nbsp;  =20 LDA =20 LENGTH
          &nb= sp;   =20 STA =20 COUNT
          &nbs= p;   =20 LDA =20 #0
           &= nbsp;  =20 ASL  COUNT          = ;COUNT=20 *2
           &= nbsp;  =20 ROL =20 A            =  =20 ;A WILL BE UPPER=20 BYTE
           = ;   =20 ASL  COUNT          = ;COUNT=20 *4
           &= nbsp;  =20 ROL =20 A
           &n= bsp;  =20 ASL  COUNT          = ;COUNT=20 *8
           &= nbsp;  =20 ROL =20 A
           &n= bsp;  =20 STA =20 COUNT+1
          &n= bsp;   =20 INC  COUNT          = ;YOUR=20 +1
           &= nbsp;  =20 BNE =20 ZEROHIGH
          &= nbsp;   =20 INC  COUNT+1        ;IF LOW BYTE = BECOME=20 0
 
;ZERO HIGH = DIVIDENDS
ZEROHIGH      =20 LDX =20 LENGTH
          &nb= sp;   =20 LDA  = #0
ZROHI         =20 STA  HIGHDVND1-1,X  ;-1 FOR INDEXING FROM 1 TO=20 LENGTH
          &nb= sp;   =20 STA =20 HIGHDVND2-1,X
         &n= bsp;    =20 DEX
           =    =20 BNE  ZROHI
 
;CHECK IF DIVISION BY=20 0
           &n= bsp;  =20 LDX =20 LENGTH
          &nb= sp;   =20 LDY =20 #0
           &= nbsp;  =20 TYA
DB0LP          = ORA =20 (DVSR),Y
          &= nbsp;   =20 INY
           =    =20 DEX
           =    =20 BNE =20 DB0LP
          &nbs= p;   =20 CMP =20 #0
           &= nbsp;  =20 BEQ  ERROR
 
;DIVIDE USING TRIAL=20 SUBTRACTION
         &nbs= p;    =20 CLC           &nbs= p;    =20 ;FIRST TIME THROUGH
 
;SHIFT CARRY INTO LOWER DIVIDEND ARRAY AS THE NEXT BIT OF = QUOTIENT
; AND=20 THE MOST SIGNIFICANT BIT OF THE LOWER DIVIDEND TO CARRY
 
LOOP           = LDX =20 LENGTH
          &nb= sp;   =20 LDY  #0
SHIFTLP        = LDA =20 (DVND),Y
          &= nbsp;   =20 ROL =20 A
           &n= bsp;  =20 STA =20 (DVND),Y
          &= nbsp;   =20 INY
           =    =20 DEX
           =    =20 BNE  SHIFTLP
 
DECCNT         DEC =20 COUNT
          &nbs= p;   =20 BNE =20 MORE
           = ;   =20 LDX =20 COUNT+1
          &n= bsp;   =20 BEQ =20 DONE
           = ;   =20 DEX
           =    =20 STX  COUNT+1
 
;SHIFT THE CARRY INTO THE LEAST SIGNIFICANT BIT OF THE UPPER = DIVIDEND
 
MORE           = LDX =20 LENGTH
          &nb= sp;   =20 LDY  #0
SHIFT2LP       LDA =20 (HDVND1),Y
          = ;    =20 ROL =20 A
           &n= bsp;  =20 STA =20 (HDVND1),Y
          = ;    =20 INY
           =    =20 DEX
           =    =20 BNE  SHIFT2LP
 
;SUBTRACT ARRAY2 FROM HDVND1 PLACING THE DIFFERENCE INTO=20 HDVND2
          &nb= sp;   =20 LDY =20 #0
           &= nbsp;  =20 LDX =20 LENGTH
          &nb= sp;   =20 SEC
SUBLP          = LDA =20 (HDVND1),Y
          = ;    =20 SBC  (DVSR),Y       ;SUBTRACT THE=20 BYTES
          &nbs= p;   =20 STA  (HDVND2),Y     ;STORE THE=20 DIFFERENCE
          = ;    =20 INY
           =    =20 DEX
           =    =20 BNE  SUBLP
 

;IF NO CARRY IS GENERATED FROM THE SUBTRACTION THEN THE = HDVND1
; IS=20 LESS THAN ARRAY 2 SO THE NEXT BIT OF THE QUOTIENT IS 0.
; IF THE = CARRY IS SET=20 THEN THE NEXT BIT OF THE QUOTIENT IS 1
; AND WE REPLACE THE DIVIDEND = WITH=20 REMAINDER BY SWITCHING POINTERS
 

          &nbs= p;   =20 BCC  = LOOP           ;WAS=20 TRIAL SUBTRACTION=20 SUCESSFUL?
          = ;    =20 LDY  HDVND1         ;YES, = EXCHANGE=20 POINTERS THUS=20 REPLACING
          =     =20 LDX  HDVND1+1       = ;    =20 DIVIDEND WITH=20 REMAINDER
          =     =20 LDA =20 HDVND2
          &nb= sp;   =20 STA =20 HDVND1
          &nb= sp;   =20 LDA =20 HDVND2+1
          &= nbsp;   =20 STA =20 HDVND1+1
          &= nbsp;   =20 STY =20 HDVND2
          &nb= sp;   =20 STX  HDVND2+1
;CONTINUE WITH NEXT BIT A 1 (CARRY =3D=20 1)
           &= nbsp;  =20 JMP  LOOP
 
DONE          =20 CLC
           =    =20 BCC  = EXIT
ERROR         =20 SEC
EXIT          =20 RTS
 
;ARRAY1 IS THE QUOTIENT
;HDVND1 POINTS TO THE REMAINDER
 
           &n= bsp;  =20 END
***************************************
------=_NextPart_000_0031_01C52C6E.4F2E8280--