keep obj/cc mcopy cc.macros **************************************************************** * * CC - C Specific Run Time Libraries * * October 1988 * Mike Westerfield * * Copyright 1988 * Byte Works, Inc. * **************************************************************** * CC start dummy routine end **************************************************************** * * ~CopyBF - Copy a bit field * ~SaveBF - Save a bit field * * Inputs: * addr - address to copy to * bitDisp - displacement past the address * bitNum - number of bits * val - value to copy * **************************************************************** * ~CopyBF start ret equ 2 return address val equ 5 value to copy bitNum equ 9 number of bits bitDisp equ 11 displacement past the address addr equ 13 address to copy to lda #0 set the call type bra lb1 ~SaveBF entry lda #1 lb1 phb phk plb sta isSave tsc set up the stack frame phd tcd move4 val,lval save the value (for copybf only) stz mask+2 set up the and mask ldx bitNum lda #0 lb2 sec rol A rol mask+2 dex bne lb2 sta mask and val and out extra bits in the mask sta val lda mask+2 and val+2 sta val+2 ldx bitDisp shift the mask and value beq lb4 lda mask lb3 asl A rol mask+2 asl val rol val+2 dex bne lb3 sta mask lb4 ldy #2 place the bits in memory lda mask eor #$FFFF and [addr] ora val sta [addr] lda mask+2 eor #$FFFF and [addr],Y ora val+2 sta [addr],Y lda isSave branch based on call type beq lb5 lda ret+1 return from save sta addr+2 lda ret sta addr+1 pld plb tsc clc adc #12 tcs rtl lb5 move4 lval,addr place the value back on the stack lda ret+1 return from copy sta bitDisp lda ret sta bitDisp-1 pld plb tsc clc adc #8 tcs rtl ; ; local data ; mask ds 4 bit mask isSave ds 2 is the call a save? (or copy?) lval ds 4 temp storage for val end **************************************************************** * * ~C_ShutDown - do shut down peculiar to the C language * * Inputs: * A - shell return code * **************************************************************** * ~C_ShutDown start pha save the return code jsr ~Exit do exit processing pla quit jml ~Quit end **************************************************************** * * ~C_ShutDown2 - do shut down peculiar to the C language * * Inputs: * A - shell return code * **************************************************************** * ~C_ShutDown2 start pha save the return code jsr ~Exit do exit processing pla quit jml ~RTL end **************************************************************** * * ~C_StartUp - do startup peculiar to the C language * **************************************************************** * ~C_StartUp start argv equ 11 argument vector argc equ 9 argument count cLine equ 1 command line address TAB equ 9 TAB key code phb remove our return address phk plb plx ply pea targv|-16 make room for argc, argv per targv (default argv = ptr to targv) pea 0 phy put the return addr back on the stack phx ph4 ~CommandLine create some work space tsc set up our stack frame phd tcd stz ~ExitList no exit routines, yet stz ~ExitList+2 stz ~QuickExitList stz ~QuickExitList+2 case on stz __useTimeTool do not use Time Tool jsl ~InitIO reset standard I/O case off lda cLine if cLine == 0 then ora cLine+2 bne lb0 stz targv argv[0] = NULL stz targv+2 brl rtl exit lb0 add4 cLine,#8 skip the shell identifier ldx #0 count the arguments txy short M * skip over white space lb1 lda [cLine],Y beq lb6 iny cmp #' ' beq lb1 cmp #TAB beq lb1 inx cmp #'"' beq lb3 * skip to next white space lb2 anop lda [cLine],y beq lb6 iny cmp #' ' beq lb1 cmp #TAB beq lb1 bra lb2 * skip to next " lb3 anop lda [cLine],y beq lb6 iny cmp #'"' beq lb1 bra lb3 lb6 long M txa we need (X+1)*4 + strlen(cLine)+1 bytes inc A asl A asl A sta start phy sec adc 1,S pha pea 0 pha ph2 >~User_ID ph2 #$C008 ph4 #0 _NewHandle bcc lb7 puts #'Out of memory',cr=t,errout=t lda #-1 jml ~Quit lb7 pl4 argv get the pointer to the area ldy #2 lda [argv],Y tax lda [argv] sta targv stx targv+2 ; clc (already clear) adc start get a pointer to the command line string bcc lb8 inx lb8 sta argv stx argv+2 short M move the command line string ldy #-1 lb9 iny lda [cLine],Y sta [argv],Y bne lb9 long M move4 argv,cLine save the pointer move4 targv,argv set up the pointer to argv av1 lda [cLine] skip leading spaces and #$00FF beq av8 cmp #' ' beq av2 cmp #TAB bne av3 av2 inc4 cLine bra av1 av3 tax save the argument cmp #'"' if the argument is quoted then bne av4 inc4 cLine skip the quote av4 ldy #2 save the address in argv lda cLine sta [argv] lda cLine+2 sta [argv],Y add4 argv,#4 inc argc inc the # of arguments cpx #'"' if the string is quoted then bne av6 av5 lda [cLine] skip to the next quote and #$00FF beq av8 cmp #'"' beq av7 inc4 cLine bra av5 else av6 lda [cLine] skip to the next whitespace char and #$00FF beq av8 cmp #' ' beq av7 cmp #TAB beq av7 inc4 cLine bra av6 av7 short M null terminate the parameter lda #0 sta [cLine] long M bra av2 get the next parameter av8 lda #0 null terminate the arg list sta [argv] ldy #2 sta [argv],Y move4 targv,argv set up the pointer to argv rtl pld return pla pla plb rtl targv ds 4 start ds 2 start of the command line string end **************************************************************** * * ~C_StartUp2 - do C startup for RTL pragma programs * **************************************************************** * ~C_StartUp2 start phb remove our return address phk plb plx ply pea targv|-16 set argc = 0, argv to point to targv per targv pea 0 phy put the return addr back on the stack phx stz ~ExitList no exit routines, yet stz ~ExitList+2 stz ~QuickExitList stz ~QuickExitList+2 case on stz __useTimeTool do not use Time Tool case off lda #~RTL set up so exit(), etc. call ~RTL sta ~C_Quit+1 stz targv argv[0] = NULL stz targv+2 plb return rtl targv ds 4 end **************************************************************** * * ~CDevCleanup - cleanup code run after a CDev call * * Inputs: * A+X - CDev result value * 1,S - Original data bank to restore * 2,S - Return address * 5,S - Message code passed to CDev * 7,S - Old user ID from before the call (0 if none) * * Notes: * This routine handles cases where the CDev is going * away and so the user ID allocated for it needs to be * disposed of to avoid being leaked. * **************************************************************** * ~CDevCleanup start MachineCDEV equ 1 BootCDEV equ 2 CloseCDEV equ 5 AboutCDEV equ 8 tay stash low word of result lda 5,s if message == CloseCDEV cmp #CloseCDEV beq cleanup cmp #BootCDEV or message == BootCDEV beq cleanup cmp #AboutCDEV or message == AboutCDEV bne lb1 lda 7,s and original user ID was 0 beq cleanup (i.e. CDev window was not open) bra ret lb1 cmp #MachineCDEV or message == MachineCDEV bne ret tya and return value is 0 bne ret txa bne ret cleanup pea 0 ...then dispose of user ID jsl >~DAID ret tya store return value in result space sta 5,s txa sta 7,s plb restore data bank rtl return to original caller end **************************************************************** * * ~CheckPtrC - check a pointer to insure it is not null * * Inputs: * 1,S - return address * 4,S - pointer * **************************************************************** * ~CheckPtrC start lda 4,S ora 5,S bne lb1 error #1 subrange exceeded lb1 rtl end **************************************************************** * * ~CUMul2 - unsigned multiply * * Inputs: * X,A - operands * * Outputs: * A - result * * Notes: * This routine is used for array index calculations and * for unsigned multiplies. It returns the low-order * 16 bits of the true result in case of overflow. * **************************************************************** * ~CUMul2 start n1 equ 3 n2 equ 5 ; ; Initialization ; phx save the operands pha phd set up our DP tsc tcd cpx n1 make sure n1 is the smaller argument bge in1 lda n1 stx n1 sta n2 in1 anop ; ; Do the multiply ; lda #0 lsr n1 lb0 bcc lb1 clc adc n2 lb1 asl n2 lsr n1 bne lb0 bcc aa1 clc adc n2 aa1 pld return the result plx plx rtl end **************************************************************** * * ~Exit - call exit routines and clean up open files * * Inputs: * ~ExitList - list of exit routines * **************************************************************** * ~Exit start ptr equ 3 pointer to exit routines ; ; Set up our stack frame ; ph4 >~ExitList set up our stack frame phd tsc tcd ; ; Call the exit functions ; lb1 lda ptr if the pointer is non-nil then ora ptr+2 beq lb3 pea +(lb2-1)|-8 call the function pea +(lb2-1)|8 phb pla ldy #5 lda [ptr],Y pha dey dey lda [ptr],Y pha phb pla rtl lb2 ldy #2 dereference the pointer lda [ptr],Y tax lda [ptr] sta ptr stx ptr+2 bra lb1 ; ; Close (and flush) any open files ; case on lb3 lda >stderr+6 while there is a next file ora >stderr+4 beq lb4 ph4 >stderr+4 close it dc h'22' (jsl fclose, soft reference) dc s3'fclose' bra lb3 case off ; ; return ; lb4 pld return pla pla rts end **************************************************************** * * ~QuickExit - call quick exit routines * * Inputs: * ~QuickExitList - list of quick exit routines * **************************************************************** * ~QuickExit start ptr equ 3 pointer to exit routines ; ; Set up our stack frame ; ph4 >~QuickExitList set up our stack frame phd tsc tcd ; ; Call the quick exit functions ; lb1 lda ptr if the pointer is non-nil then ora ptr+2 beq lb3 pea +(lb2-1)|-8 call the function pea +(lb2-1)|8 phb pla ldy #5 lda [ptr],Y pha dey dey lda [ptr],Y pha phb pla rtl lb2 ldy #2 dereference the pointer lda [ptr],Y tax lda [ptr] sta ptr stx ptr+2 bra lb1 ; ; return ; lb3 pld return pla pla rts end **************************************************************** * * ~ExitList - list of exit routines * ~QuickExitList - list of quick exit routines * ~C_Quit - call to quit (may be changed to call ~RTL) * **************************************************************** * ~ExitList start ds 4 ~QuickExitList entry ds 4 ~C_Quit entry jmp ~QUIT end **************************************************************** * * ~IntChkC - check for integer math error * * Inputs: * V - set for error * **************************************************************** * ~IntChkC start bvc lb1 branch if no error php pha phx phy error #9 integer math error ply plx pla plp lb1 rtl end **************************************************************** * * ~LoadBF - load a bit field * * Inputs: * addr - address to load from * bitDisp - displacement past the address * bitNum - number of bits * **************************************************************** * ~LoadBF start mask equ 1 bit mask sign equ 5 sign mask csubroutine (2:bitNum,2:bitDisp,4:addr),8 ldy #2 get the value lda [addr],Y tax lda [addr] sta addr stx addr+2 ldx bitDisp normalize the value beq lb2 lb1 lsr addr+2 ror addr dex bne lb1 lb2 stz mask form the bit and sign mask lda #-1 sta sign sta sign+2 lda #0 ldx bitNum lb3 sec rol A rol mask asl sign rol sign+2 dex bne lb3 sec adjust the sign flag ror sign+2 ror sign and addr and out the extra bits sta addr lda mask and addr+2 sta addr+2 lda addr if the value is negative then and sign bne lb4 lda addr+2 and sign+2 beq lb5 lb4 lda addr or in the sign bits ora sign sta addr lda addr+2 ora sign+2 sta addr+2 lb5 creturn 4:addr end **************************************************************** * * ~LoadStruct - load a long value onto the stack * * Inputs: * addr - address of the structure to load * size - size of the structure * **************************************************************** * ~LoadStruct start phb save the caller's data bank pl4 >ret get the return address plx get the transfer size pla get the absolute save addr sta >ad1+1 sta >ad2+1 plb set the data bank phb remove the data bank & extra addr byte pla txa quit if there are no bytes to move beq lb3 lsr a branch if the # of bytes is even bcc lb1 dex move one byte short M ad1 lda ad1,X pha long M txa beq lb3 lb1 dex move the words dex bmi lb3 ad2 lda ad2,X pha bra lb1 lb3 ph4 >ret return to the caller plb rtl ; ; Local data ; ret ds 4 end **************************************************************** * * ~LoadUBF - load an unsigned bit field * * Inputs: * addr - address to load from * bitDisp - displacement past the address * bitNum - number of bits * **************************************************************** * ~LoadUBF start mask equ 1 msw of bit mask csubroutine (2:bitNum,2:bitDisp,4:addr),2 ldy #2 get the value lda [addr],Y tax lda [addr] sta addr stx addr+2 ldx bitDisp normalize the value beq lb2 lb1 lsr addr+2 ror addr dex bne lb1 lb2 stz mask form the bit mask lda #0 ldx bitNum lb3 sec rol A rol mask dex bne lb3 and addr and out the extra bits sta addr lda mask and addr+2 sta addr+2 creturn 4:addr end **************************************************************** * * ~LongMove2 - move some bytes * * Inputs: * source - pointer to source bytes * dest - pointer to destination bytes * len - number of bytes to move * * Notes: * This subroutine leaves the destination address on the * stack. It is used by C for multiple assignment of * arrays and structures. It differs from ~Move2 in that * it can move 64K or more. * **************************************************************** * ~LongMove2 start csubroutine (4:len,4:source),0 dest equ source+4 pei dest+2 save original dest value pei dest ldx len+2 move whole banks beq lm2 ldy #0 lm1 lda [source],Y sta [dest],Y dey dey bne lm1 inc source+2 inc dest+2 dex bne lm1 lm2 lda len move one byte if the move length is odd lsr a bcc lb1 short M lda [source] sta [dest] long M inc4 source inc4 dest dec len lb1 ldy len move the bytes beq lb4 dey dey beq lb3 lb2 lda [source],Y sta [dest],Y dey dey bne lb2 lb3 lda [source] sta [dest] lb4 pla restore original dest value sta dest pla sta dest+2 creturn end **************************************************************** * * ~LShr4 - Shift an unsigned long value right * * Inputs: * A - value to shift * X - # bits to shift by * * Outputs: * A - result * **************************************************************** * ~LShr4 start num1 equ 8 number to shift num2 equ 4 # bits to shift by tsc set up DP phd tcd lda num2+2 if num2 < 0 then bpl lb2 cmp #$FFFF shift left bne zero ldx num2 cpx #-34 blt zero lb1 asl num1 rol num1+2 inx bne lb1 bra lb4 zero stz num1 (result is zero) stz num1+2 bra lb4 lb2 bne zero else shift right ldx num2 beq lb4 cpx #33 bge zero lb3 lsr num1+2 ror num1 dex bne lb3 lb4 lda 0 fix stack and return sta num2 lda 2 sta num2+2 pld pla pla rtl end **************************************************************** * * ~Move2 - move some bytes * * Inputs: * source - pointer to source bytes * dest - pointer to destination bytes * len - number of bytes to move * * Notes: * This subroutine leaves the destination address on the * stack. It is used by C for multiple assignment of * arrays and structures. * **************************************************************** * ~Move2 start csubroutine (2:len,4:source),0 dest equ source+4 lda len move one byte if the move length is odd lsr a bcc lb1 short M lda [source] sta [dest] long M inc4 source inc4 dest dec len lb1 ldy len move the bytes beq lb4 dey dey beq lb3 lb2 lda [source],Y sta [dest],Y dey dey bne lb2 lb3 lda [source] sta [dest] lb4 bcc lb5 if the move length was odd dec4 dest restore original dest value lb5 creturn end **************************************************************** * * extern pascal PDosInt(int callNum, void *parm) * * Make a ProDOS or shell call * * Inputs: * callNum - ProDOS call number * parm - address of the parameter block * **************************************************************** * PDOSINT start ProDOS equ $E100A8 csubroutine (4:parm,2:callNum),0 lda callNum sta >lb1 lda parm sta >lb2 lda parm+2 sta >lb2+2 jsl ProDOS lb1 ds 2 lb2 ds 4 sta >~TOOLERROR creturn end **************************************************************** * * ~UDiv4 - Four byte unsigned integer divide * * Inputs: * num1 - numerator * X-A - denominator * * Outputs: * ans - result * **************************************************************** * ~UDiv4 start num1 equ 12 arguments ans equ 1 answer rem equ 5 remainder return equ 9 ; ; Initialize ; tay place the values in the correct spot pea 0 on the stack frame pea 0 lda 10,S pha lda 10,S pha tsc set up DP phd tcd sty num1 stx num1+2 tya check for division by zero ora num1+2 beq dv10 lda num1+2 do 16 bit divides separately ora ans+2 beq dv5 ; ; 32 bit divide ; ldy #32 32 bits to go dv3 asl ans roll up the next number rol ans+2 rol ans+4 rol ans+6 sec subtract for this digit lda ans+4 sbc num1 tax lda ans+6 sbc num1+2 bcc dv4 branch if minus stx ans+4 turn the bit on sta ans+6 inc ans dv4 dey next bit bne dv3 bra dv9 go do the sign ; ; 16 bit divide ; dv5 lda #0 initialize the remainder ldy #16 16 bits to go dv6 asl ans roll up the next number rol a sec subtract the digit sbc num1 bcs dv7 adc num1 digit is 0 dey bne dv6 bra dv8 dv7 inc ans digit is 1 dey bne dv6 dv8 sta ans+4 save the remainder ; ; Return the result ; dv9 move4 ans,num1 move answer dv10 pld return tsc clc adc #8 tcs rtl end **************************************************************** * * ~UMod4 - Four byte unsigned integer remainder * * Inputs: * num1 - numerator * X-A - denominator * * Outputs: * ans - result * **************************************************************** * ~UMod4 start num1 equ 12 arguments ans equ 1 answer rem equ 5 remainder return equ 9 ; ; Initialize ; tay place the values in the correct spot pea 0 on the stack frame pea 0 lda 10,S pha lda 10,S pha tsc set up DP phd tcd sty num1 stx num1+2 tya check for division by zero ora num1+2 beq dv10 lda num1+2 do 16 bit divides separately ora ans+2 beq dv5 ; ; 32 bit divide ; ldy #32 32 bits to go dv3 asl ans roll up the next number rol ans+2 rol ans+4 rol ans+6 sec subtract for this digit lda ans+4 sbc num1 tax lda ans+6 sbc num1+2 bcc dv4 branch if minus stx ans+4 turn the bit on sta ans+6 inc ans dv4 dey next bit bne dv3 bra dv9 go do the sign ; ; 16 bit divide ; dv5 lda #0 initialize the remainder ldy #16 16 bits to go dv6 asl ans roll up the next number rol a sec subtract the digit sbc num1 bcs dv7 adc num1 digit is 0 dey bne dv6 bra dv8 dv7 inc ans digit is 1 dey bne dv6 dv8 sta ans+4 save the remainder ; ; Return the result ; dv9 move4 ans+4,num1 move answer dv10 pld return tsc clc adc #8 tcs rtl end **************************************************************** * * ~Zero - zero an area of direct page memory * * Inputs: * addr - address of the memory * size - number of bytes to zero (must be > 1) * **************************************************************** * ~Zero start csubroutine (2:size,4:addr),0 lda #0 sta [addr] ldx addr txy iny lda size dea dea phb mvn 0,0 plb creturn end