; FTPUtila.asm -- assembly routines for Pup FTP ; Copyright Xerox Corporation 1979, 1980 ; Last modified December 3, 1980 3:08 PM by Boggs .ent DataIsBinary .ent MulPlus32x16 .ent Divide32x16 .ent DblUsc .srel DataIsBinary: .DataIsBinary MulPlus32x16: .MulPlus32x16 Divide32x16: .Divide32x16 DblUsc: .DblUsc .nrel ; DataIsBinary(address, count) = true or false ; Returns true if the "count" bytes of data starting at "address" ; have any high-order bits on. .DataIsBinary: sta 3 1,2 mov 0 3 ; Address to ac3 lda 0 c17 ; Compute count mod 16 and 1 0 sta 0 2,2 ; Save for later lda 0 c100200 ; Load mask movzr 1 1 ; Compute count/16 movzr 1 1 movzr 1 1 movzr 1 1 snr jmp datib2 ; Less than 16 bytes sta 1 3,2 ; Store loop count ; Fast loop -- scans 16 bytes per iteration datib1: lda 1 0,3 and# 0 1 snr lda 1 1,3 and# 0 1 snr lda 1 2,3 and# 0 1 snr lda 1 3,3 and# 0 1 snr lda 1 4,3 and# 0 1 snr lda 1 5,3 and# 0 1 snr lda 1 6,3 and# 0 1 snr lda 1 7,3 and# 0 1 szr jmp truret ; Return true if saw a high bit on lda 1 c10 ; Advance address add 1 3 dsz 3,2 ; Decrement and test count jmp datib1 ; Slow loop to handle leftover words datib2: lda 1 2,2 ; Get leftover byte count movzr 1 1 snr ; Compute word count (remainder to carry) jmp datib4 ; No full words left sta 1 2,2 ; Store loop count datib3: lda 1 0,3 ; Look at a word and# 0 1 szr jmp truret ; Return true if saw a high bit on inc 3 3 ; Advance address dsz 2,2 ; Decrement and test count jmp datib3 ; Handle leftover byte if any datib4: lda 1 0,3 ; Get the word mov# 0 0 szc ; Is there a leftover byte? movl# 1 1 snc ; Yes, skip if it has high bit set mkzero 0 0 skp ; Return false -- data is not binary truret: mkminusone 0 0 ; Return true -- data is binary lda 3 1,2 jmp 1,3 c10: 10 c17: 17 c100200: 100200 ; MulPlus32x16(addend, multiplier, lvMultiplicand) ; lvMultiplicand = lvMultiplicand*multiplier + addend ; lvMultiplicand is 32 bits, multiplier and addend are 16 bits. ; returns the overflow .MulPlus32x16: sta 3 1,2 ; save return in frame mov 2 3 ; vacate AC2. AC3_ frame sta 1 2,3 ; save multiplier in frame lda 2 3,3 ; AC2_ lvMultiplicand lda 2 1,2 ; AC2_ lvMultiplicand!low mul lda 2 3,3 ; AC2_ lvMultiplicand sta 1 1,2 ; store low result lda 2 0,2 ; AC2_ lvMultiplicand!high lda 1 2,3 ; AC1_ multiplier mul sta 1 @3,3 ; store high result mov 3 2 ; restore frame lda 3 1,2 ; return jmp 1,3 ; overflow in AC0 ; Divide32x16(lvNumber, divisor) = ; unsigned divide the 32-bit number at @lvNumber, ; put the quotient back in @lvNumber, and return the remainder .Divide32x16: sta 3 1,2 ; return mov 2 3 ; save stack pointer sta 0 2,3 ; lvNumber sta 1 3,3 ; divisor mkzero 0 0 lda 1 @2,3 ; get high dividend lda 2 3,3 ; get divisor div ; ac0 _ remainder, ac1 _ quotient nop sta 1 @2,3 ; store high quotient isz 2,3 lda 1 @2,3 ; get low dividend div ; ac0 _ remainder, ac1 _ quotient nop sta 1 @2,3 ; store low quotient mov 3 2 ; restore stack pointer lda 3 1,2 jmp 1,3 ; DblUsc(lvA, lvB, nWords) = -1|0|1 ; Returns: -1 if A < B ; 0 if A = B ; 1 if A > B ; lvA and lvB are the addresses of the nWords-word operands. ; nWords defaults to 2. .DblUsc: sta 0 1,2 ; lvA sta 1 2,2 ; lvB lda 0 0,3 ; numArgs lda 1 c2 sne 0 1 sta 1 3,2 ; default nWords to 2 uscLp: lda 0 @1,2 ; A word lda 1 @2,2 ; B word sleu 0 1 jmp gr ; A > B sub 1 0 szr jmp ls ; A < B isz 1,2 ; lvA isz 2,2 ; lvB dsz 3,2 ; nWords jmp uscLp jmp 1,3 ; all words equal; return zero. gr: mkone 0 0 skp ls: mkminusone 0 0 jmp 1,3 c2: 2 .end (2116)