ORCALib/cc.asm

1111 lines
27 KiB
NASM

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
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
ply
pha
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 get a pointer to the command line string
adc start
bcc lb8
inx
lb8 sta argv
stx argv+2
short M move the command line string
ldy #0
lb9 lda [cLine],Y
sta [argv],Y
beq lb10
iny
bra lb9
lb10 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
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
****************************************************************
*
* ~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
;
phb
phk
plb
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
plb
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
;
phb
phk
plb
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
plb
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
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 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 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