Classic Computer Magazine Archive COMPUTE! ISSUE 46 / MARCH 1984 / PAGE 168

MACHINE LANGUAGE

Jim Butterfield, Associate Editor

FACTORS: A Machine Language Factoring Program

Part 3

This month we conclude the commented listing of our machine language program to find prime factors.

Last month in Part 2, we examined the routines that handle keyboard input and prepare our number for factoring.

Now, here's the division routine. It rolls the dividend left through the joint remainder/quotient area. When we're finished, what's left of the dividend is in the remainder area; the quotient has miraculously appeared on the right.

0615 A9 00     DIVIDE   LDA #0       ;CLEANHOUSE
0617 A2 OB              LDX #11      ;12 BYTES
0619 9D 6C 03  DLP1     STA REMDR,X
061C CA                 DEX
061D 10 FA              BPL DLP1
061F A2 00              LDX #0       ;"FROM" POINTER
0621 A0 00              LDY #0
0623 8E 48 03           STX BCOUNT
0626 BD 50 03  DLP2     LDA NUMBER,X
0629 DO 06              BNE DLP4
062B E8                 INX          ;DROP HIGH BYTES
062C D0 F8              BNE DLP2
062E BD 50 03  DLP3     LDA NUMBER,X
0631 99 70 03  DLP4     STA QUOT,Y
0634 E8                 INX
0635 C8                 INY
0636 EE 48 03           INC BCOUNT
0639 E0 08              CPX #8
063B 90 F1              BCC DLP3
063D 0E 48 03           ASL BCOUNT   ;TIMES 8
0640 0E 48 03           ASL BCOUNT   ;CHANGES BYTES
0643 0E 48 03           ASL BCOUNT   ;TO BITS
0646 18                 CLC
0647 A2 0B     DLP5     LDX #11      ;ROLL ENTIRE
0649 3E 6C 03  DLP6     ROL REMDR,X  ;..WORK AREA
064C CA                 DEX          ;..LEFT
064D 10 FA              BPL DLP6
064F A2 03              LDX #3
0651 38                 SEC          ;COMPARE
0652 BD 6C 03  DLP7     LDA REMDR,X  ;..DIVIDEND TO
0655 FD 68 03           SBC DVSR,X   ;..DIVISOR
0658 CA                 DEX          ;FOUR BYTES
0659 10 F7              BPL DLP7
065B 90 0F              BCC NDIV     ;TOO SMALL
065D A2 03              LDX #3       ;NOT TOO SMALL
065F 38                 SEC          ;SUBTRACT.
0660 BD 6C 03  DLP8     LDA REMDR,X  ;DIVISOR
0663 FD 68 03           SBC DVSR,X
0666 9D 6C 03           STA REMDR,X
0669 CA                 DEX
066A 10 F4              BPL DLP8
066C CE 48 03  NDIV     DEC BCOUNT   ;COUNT BITS
066F D0 D6              BNE DLP5     ;LOOP (CARRY?)
0671 A2 07              LDX #7       ;FINISHED:
0673 3E 70 03  DLP9     ROL REMDR+4,X;TRIM REMAINDER
0676 CA                 DEX
0677 10 FA              BPL DLP9
0679 60                 RTS

This is where we try dividing our number into selected divisors and see if we get an even division (remainder zero)

067A 8D 6B 03 FLOOK  STA DVSR+3  ;PLANT DIVISOR
067D A9 00    FLOOP  LDA #0
067F 8D 49 03        STA EXP     ;ZERO TO START
0682 20 15 06 FPOWER JSR DIVIDE
0685 A9 00           LDA #0      ;CHECK
                                  REMAINDER
0687 A2 03           LDX #3
0689 1D 6C 03 FLP1   ORA REMDR,X ;FOR ZERO
068C CA              DEX
068D 10 FA           BL  FLP1
068F AA              TAX
0690 D0 10           BNE FEXIT    ;NOT ZERO?

Factor Found

We've found a factor. The quotient now becomes our new number; then we can increment the exponent counter and try again.

                   ;MOVE QUOTIENT
0692 EE 49 03          INC  EXP          ;ADD ONE
0695 A2 07             LDX #7
0697 BD 70 03    FLP2  LDA QUOT,X        ;QUOTIENT TO
069A 9D 50 03          STA NUMBER,X      ;..ORIG NUMBER
069D CA                DEX069E 10 F7    BPL FLP2
06A0 30 E0    BMI FPOWR                  ;TRYFOR
                                          ANOTHER

We compare the number to the divisor by subtracting. That way, we'll find out whether or not it's time to wrap it up.

                ;CHECK LIMITS
06A2 A2 07    FEXIT  LDX  #7       ;EIGHT BYTES
06A4 38              SEC
06A5 BD 70 03 FCHEK  LDA  QUOT, X
06A8 FD 64 03        SBC  DVSR-4, X
06AB CA              DEX
06AC 10 F7           BPL  FCHEK

If the exponent is nonzero, we've found a divisor and it's time to report it.

06AE 08             PHP         ;FREEZE STATUS
06AF AE 49 03       LDX EXP
06B2 F0 03          BEQ FPASS
06B4 20 D0 06       JSR SHOW
06B7 28       FPASS PLP         ;UNFREEZE STAT
06B8 60             RTS

Here come the routines for printing numbers SRAP prints the remaining value when we wrap up the line. It's different from printing the other factors, in that the final value might be a very large number.

06B9 AD 4A 03 SRAP LDA CHAR             ;EQUALS OR PLUS
06BC 20 D2 FF      JSR $FFD2            ;..PRINT IT
06BF 20 04 07      JSR SWIPE            ;CLEARWORK
                                         AREA
06C2 A2 07         LDX #7               ;EIGHT BYTES!
06C4 BD 50 03 SRAL LDA NUMBER, X
06C7 9D 70 03      STA REMDR + 4, X
06CA CA            DEX
06CB 10 F7         BPL SRAL
06CD 4C 0F 07      JMP CPR

Our main number printing routine coming up. First, the leading character (equals sign or plus sign). Then we place the binary number into a work area, and call the binary-to-decimal output routine, CPR. We may also need to do this for the exponent if it's greater than one.

06D0 AD 4A 03 SHOW  LDA CHAR        ;EQUALS OR PLUS
06D3 20 D2 FF       JSR $FFD2       ;.PRINT IT
06D6 A9 2A          LDA #$2A        ;NEXT IS PLUS
06D8 8D 4A 03       STA CHAR
06DB 20 04 07       JSR SWIPE       ;CLEAR WORK
                                    AREA
06DE A2 03          LDX #3          ;FOUR BYTES
06E0 BD 68 03 SLP1  LDA DVSR, X     ;.TO WORK AREA
06E3 9D 74 03       STA REMDR + 8, X
06E6 CA             DEX
06E7 10 F7          BPL SLP1
06E9 20 0F 07       JSR CPR
             ;PRINT EXPONENT IF APPR
06EC AE 49 03       LDX EXP
06EF CA             DEX
06F0 F0 11          BEQ SOUT        ;ONE, DON'T
                                   PRINT
06F2 20 04 07       JSR SWIPE
06F5 AE 49 03       LDX EXP
06F8 8E 77 03       STX REMDR+11
06FB A9 5E          LDA #$5E        ;UP ARROW
06FD 20 D2 FF       JSR $FFD2       ;..PRINT IT
0700 20 0F 07       JSR CPR
0703 60       SOUT  RTS
0704 A2 07    SWIPE LDX #7          ;EIGHT BYTE
0706 A9 00          LDA #0          ;CLEAR TO ZERO
0708 9D 70 03 SW1   STA QUOT, X
070B CA DEX
070C 10 FA BPL SW1
070E 60 RTS

Simple, But Curious

CPR, or Character Print, first changes binary into binary coded decimal. To do this, it uses the Decimal mode of the 6502. The method is simple but curious: It shifts the binary bits out of the work area, and shifts them (decimally!) into area DECIML.

070F A2 09    CPR   LDX  #9       ;TEN BYTES.
0711 A9 00          LDA  #0       ;..20 DIGITS
0713 9D 78 03 CLP1  STA  DECIML,X ;..CLEAR
0716 CA             DEX
0717 10 FA          BPL  CLP1
0719 A0 3F          LDY  #63      ;64 BITS
071B A2 07    CLP2  LDX  #7       ;8 BYTES
071D 18             CLC
071E 3E 70 03 CLP3  ROL REMDR+4,X;POP OUT A BIT
0721 CA             DEX           ;..INTO CARRY
0722 10 FA          BPL  CLP3
0724 A2 09          LDX  #9       ;TEN BYTES
0726 78             SEI           ;LOCKOUT IRQ
0727 F8             SED           ;DECIMAL MODE
0728 7D 78 03 CLP4  LDA  DECIML,X ;SHIFT BIT IN
072B 7D 78 03       ADC  DECIML, X
072E 9D 78 03       STA  DECIML, X
0731 CA             DEX
0732 10 F4          BPL  CLP4
0734 D8             CLD           ;BACK TO BINARY
0735 58             CLI           ;RELEASE IRQ
0736 88             DEY
0737 10 E2          BPL  CLP2

Now we print out the decimal digits. They are packed two to a byte, so we must unpack them first. Of course, we remove leading zeros.

0739 A2 00           LDX #0        ;Z SUPPRESS ON
073B 8E 4B 03        STX ZSUP
073E BD 78 03 CLP5   LDA DECIML, X ;HIGH END
0741 48              PHA           ;SAVEIT
0742 4A              LSR A         ;GET HIGH
0743 4A              LSR A         ;..4 BITS
0744 4A              LSR A
0745 4A              LSR A
0746 20 55 07        JSR COUT      ;SEND'EM
0749 68              PLA           ;RECALL IT
074A 29 0F           AND #$0F      ;LOW 4 BITS
074C 20 55 07        JSR COUT      ;SEND'EM
074F E8              INX           ;NEXTBYTE
0750 E0 0A           CPX #10       ;STOP AT 10
0752 90 EA           BCC CLP5
0754 60              RTS

COUT outputs the individual characters, and implements zero suppression.

0755 D0 06 COUT    BNE CFL   ;NOTZERO,
                              PRINT
0757 CD 4B 03      CMP ZSUP  ;ZSUP FLAG ON?
075A D0 01         BNE CFL   ;NO, PRINT
075C 60            RTS       ;ELSE DON'T
075D EE 4B 03 CFL  INC ZSUP  ;KILL ZSUP FLAG
0760 09 30         ORA #$30  ;CHANGETO
                              ASCII
0762 4C D2 FF      JMP $FFD2 ;PRINT & RETURN.

Finally, here's our table of offset values. They are a great timesaver.

0765 01 07 0B 0D TABLE  .BYTE 1, 7, 11, 13
0769 11 13 17 ID        .BYTE 17, 19, 23, 29