; ; CALL.A Small-C version 2 arithmetic and logical library ; ; (RMAC Version 05/10/88, Dave Johnson) ; (ASM Version 07/28/83, Bill Randle) ; LINK EQU 1 ; IF LINK PUBLIC CCDDGC PUBLIC CCDSGC PUBLIC CCGCHAR PUBLIC CCARGC PUBLIC CCSXT PUBLIC CCDDGI PUBLIC CCDSGI PUBLIC CCGINT PUBLIC CCDECC PUBLIC CCINCC PUBLIC CCPDPC PUBLIC CCPCHAR PUBLIC CCDECI PUBLIC CCINCI PUBLIC CCPDPI PUBLIC CCPINT PUBLIC CCOR PUBLIC CCXOR PUBLIC CCAND PUBLIC CCEQ PUBLIC CCNE PUBLIC CCGT PUBLIC CCLE PUBLIC CCGE PUBLIC CCLT PUBLIC CCUGE PUBLIC CCULT PUBLIC CCUGT PUBLIC CCULE PUBLIC CCASR PUBLIC CCASL PUBLIC CCSUB PUBLIC CCNEG PUBLIC CCCOM PUBLIC CCMULT PUBLIC CCDIV PUBLIC CCLNEG PUBLIC CCSWITCH ENDIF ; ; Compiler compiled with #define M80, to generate short names (unique in ; 6 chars). Set to 0 if compiler NOT compiled with M80 switch. ; M80 EQU 0 ; CCDDGC: DAD D JMP CCGCHAR ; CCDSGC: INX H INX H DAD SP ; ; Get a single byte from the address in HL and sign extent into HL ; CCGCHAR:MOV A,M ; ; Put the accumulator into HL and sign extend through H. ; CCARGC: CCSXT: MOV L,A RLC SBB A MOV H,A RET ; CCDDGI: DAD D JMP CCGINT ; CCDSGI: INX H INX H DAD SP ; ; Get a full 16-bit integer from the address in HL into HL ; CCGINT: MOV A,M INX H MOV H,M MOV L,A RET ; CCDECC: INX H INX H DAD SP MOV D,H MOV E,L CALL CCGCHAR DCX H MOV A,L STAX D RET ; CCINCC: INX H INX H DAD SP MOV D,H MOV E,L CALL CCGCHAR INX H MOV A,L STAX D RET ; ; ; ; Use short symbol name ; IF M80 CCDDPC: ENDIF ; ; Use full length name ; IF NOT M80 CCDDPDPC: ENDIF ; DAD D ; CCPDPC: POP B ; Return address POP D PUSH B ; ; Store a single byte from HL at the address in DE ; CCPCHAR: PCHAR: MOV A,L STAX D RET ; CCDECI: INX H INX H DAD SP MOV D,H MOV E,L CALL CCGINT DCX H JMP CCPINT ; CCINCI: INX H INX H DAD SP MOV D,H MOV E,L CALL CCGINT INX H JMP CCPINT ; ; Use short symbol name ; IF M80 CCDDPI: ENDIF ; ; Use full length name ; IF NOT M80 CCDDPDPI: ENDIF ; DAD D ; CCPDPI: POP B ; Return address POP D PUSH B ; ; Store a 16-bit integer in HL at the address in DE ; CCPINT: PINT: MOV A,L STAX D INX D MOV A,H STAX D RET ; ; Inclusive "OR" HL and DE into HL ; CCOR: MOV A,L ORA E MOV L,A MOV A,H ORA D MOV H,A RET ; ; Exclusive "OR" HL and DE into HL ; CCXOR: MOV A,L XRA E MOV L,A MOV A,H XRA D MOV H,A RET ; ; "AND" HL and DE into HL ; CCAND: MOV A,L ANA E MOV L,A MOV A,H ANA D MOV H,A RET ; ; In all the followin compare routines, HL is set to 1 if the condition ; is YES, otherwise it is set to 0 (Zero). ; ; Test if HL = DE ; CCEQ: CALL CCCMP RZ DCX H RET ; ; Test if DE <> HL ; CCNE: CALL CCCMP RNZ DCX H RET ; ; Test if DE > HL (signed) ; CCGT: XCHG CALL CCCMP RC DCX H RET ; ; Test if DE <= HL (signed) ; CCLE: CALL CCCMP RZ RC DCX H RET ; ; Test if DE >= HL (signed) ; CCGE: CALL CCCMP RNC DCX H RET ; ; Test if DE < HL (signed) ; CCLT: CALL CCCMP RC DCX H RET ; ; Common routine to perform a signed compare of DE and HL. THis routine ; performs DE-HL and sets the contidions: ; ; Carry reflects sign of difference (set means DE < HL) ; Zero/non-Zero set according to equality. ; CCCMP: MOV A,H ; Invert sign of HL XRI 80H MOV H,A MOV A,D ; Invert sign of DE XRI 80H CMP H ; Compare most significant bytes JNZ CCCMP1 ; Done if not equal MOV A,E ; Compare least significant bytes CMP L ; CCCMP1: LXI H,1 ; Preset YES condition RET ; ; Test if DE >= HL (unsigned) ; CCUGE: CALL CCUCMP RNC DCX H RET ; ; Test if DE < HL (unsigned) ; CCULT: CALL CCUCMP RC DCX H RET ; ; Test if DE > HL (unsigned) ; CCUGT: XCHG CALL CCUCMP RC DCX H RET ; ; Test if DE <= HL (unsigned) ; CCULE: CALL CCUCMP RZ RC DCX H RET ; ; Common routine to perform unsigned compare. Carry set if DE < HL ; Zero/non-Zero set accordingly ; CCUCMP: MOV A,D CMP H JNZ CCUCP1 MOV A,E CMP L ; CCUCP1: LXI H,1 RET ; ; Shift DE arithmetically right by HL and return in HL ; CCASR: XCHG DCR E RM MOV A,H RAL MOV A,H RAR MOV H,A MOV A,L RAR MOV L,A JMP CCASR+1 ; ; Shift DE arithmetically left by HL and return in HL ; CCASL: XCHG DCR E RM DAD H JMP CCASL+1 ; ; Subtract HL from DE and return in HL ; CCSUB: MOV A,E SUB L MOV L,A MOV A,D SBB H MOV H,A RET ; ; Form the two's complement of HL ; CCNEG: CALL CCCOM INX H RET ; ; Form the one's complement of HL ; CCCOM: MOV A,H CMA MOV H,A MOV A,L CMA MOV L,A RET ; ; Multiply DE by HL and return in HL. (Signed multiply) ; CCMULT: MULT: MOV B,H MOV C,L LXI H,0 ; CCMLT1: MOV A,C RRC JNC CCMLT2 DAD D ; CCMLT2: XRA A MOV A,B RAR MOV B,A MOV A,C RAR MOV C,A ORA B RZ XRA A MOV A,E RAL MOV E,A MOV A,D RAL MOV D,A ORA E RZ JMP CCMLT1 ; ; Divide DE by HL and return quotient in HL, remainder in DE ; (Signed divide) ; CCDIV: DIV: MOV B,H MOV C,L MOV A,D XRA B PUSH PSW MOV A,D ORA A CM CCDENEG MOV A,B ORA A CM CCBCNEG MVI A,16 PUSH PSW XCHG LXI D,0 ; CCDIV1: DAD H CALL CCRDEL JZ CCDIV2 CALL CCCMPBCDE JM CCDIV2 MOV A,L ORI 1 MOV L,A MOV A,E SUB C MOV E,A MOV A,D SBB B MOV D,A ; CCDIV2: POP PSW DCR A JZ CCDIV3 PUSH PSW JMP CCDIV1 ; CCDIV3: POP PSW RP CALL CCDENEG XCHG CALL CCDENEG XCHG RET ; ; Negate the integer in DE (internal routine) ; CCDENEG:MOV A,D CMA MOV D,A MOV A,E CMA MOV E,A INX D RET ; ; Negate the integer in BC (internal routine) ; CCBCNEG:MOV A,B CMA MOV B,A MOV A,C CMA MOV C,A INX B RET ; ; Rotate DE left one bit (internal routine) ; CCRDEL: MOV A,E RAL MOV E,A MOV A,D RAL MOV D,A ORA E RET ; ; Compare BC to DE (internal routine) ; CCCMPBCDE: MOV A,E SUB C MOV A,D SBB B RET ; ; Logical negation ; CCLNEG: MOV A,H ORA L JNZ $+6 MVI L,1 RET LXI H,0 RET ; ; Execute "switch" statement ; ; HL = switch value ; (SP) -> switch table ; DW ADDR1, VALUE1 ; DW ADDR2, VALUE2 ; ; DW 0 ; [JMP default] ; Continuation ; CCSWITCH: XCHG ; ;DE = switch value POP H ; ;HL -> switch table ; SWLOOP: MOV C,M INX H MOV B,M ; BC -> case ADDR, else 0 INX H MOV A,B ORA C JZ SWEND ; Default or continuation code MOV A,M INX H CMP E MOV A,M INX H JNZ SWLOOP CMP D JNZ SWLOOP MOV H,B ; Case matched MOV L,C ; SWEND: PCHL ;