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