home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource3
/
115_01
/
c80lib
< prev
next >
Wrap
Text File
|
1979-12-31
|
19KB
|
1,241 lines
#asm
;
;
;------------------------------------------------------------------
; Small-C Run-time Library
;
;
; V3b As of June 9, 1980 12pm (rj)
; corrected cp to chp in @gets
; changed lower case to hex constants in @fopen and fcb
; V4 As of June 26, 1980 12:15pm (gtf)
; Changed all @'s and ?'s to "QZ" for ASM compatibility
; V4b As of July 7, 1980 3:00 pm (gtf)
; Changed putc() to test code returned by cput()
; V4c As of July 9, 1980 9:15 pm (gtf)
; Fixed bug in CPMIO which returned wrong error status.
; Added PUTS() function
; Un-hardwired I/O buffer count.
; Made GETCHAR() print LF after reading CR.
; Made GETCHAR() return -1 on EOF (=CTRL-Z)
; Added EOL and LF equates, instead of magic numbers
; V4d As of July 16, 1980 9:00 pm (gtf)
; Added EXIT() function
;------------------------------------------------------------------
;
; Runtime library initialization. Set up default drive for CP/M.
CCGO: MVI C,QUERY ;get logged-in disk
CALL BDOS
INR A ;make it so it will work in fcb
STA DFLTDSK
RET
;Fetch a single byte from the address in HL and
; sign extend into HL
CCGCHAR: MOV A,M
CCSXT: MOV L,A
RLC
SBB A
MOV H,A
RET
;Fetch a full 16-bit integer from the address in HL
CCGINT: MOV A,M
INX H
MOV H,M
MOV L,A
RET
;Store a single byte from HL at the address in DE
CCPCHAR: MOV A,L
STAX D
RET
;Store a 16-bit integer in HL at the address in DE
CCPINT: 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
;Test if HL = DE and set HL = 1 if true else 0
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 conditions:
; Carry reflects sign of difference (set means DE < HL)
; Zero/non-zero set according to equality.
CCCMP: MOV A,E
SUB L
MOV E,A
MOV A,D
SBB H
LXI H,1 ;preset true condition
JM CCCMP1
ORA E ;"OR" resets carry
RET
CCCMP1: ORA E
STC ;set carry to signal minus
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/nonzero set accordingly
CCUCMP: MOV A,D
CMP H
JNZ $+5
MOV A,E
CMP L
LXI H,1
RET
;
;Shift DE arithmetically right by HL and return in HL
CCASR: XCHG
MOV A,H
RAL
MOV A,H
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
DCR E
JNZ CCASR+1
RET
;Shift DE arithmetically left by HL and return in HL
CCASL: XCHG
DAD H
DCR E
JNZ CCASL+1
RET
;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
CCMULT: MOV B,H
MOV C,L
LXI H,0
CCMULT1: MOV A,C
RRC
JNC $+4
DAD D
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 CCMULT1
;Divide DE by HL and return quotient in HL, remainder in DE
CCDIV: 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
CCDENEG: MOV A,D
CMA
MOV D,A
MOV A,E
CMA
MOV E,A
INX D
RET
CCBCNEG: MOV A,B
CMA
MOV B,A
MOV A,C
CMA
MOV C,A
INX B
RET
CCRDEL: MOV A,E
RAL
MOV E,A
MOV A,D
RAL
MOV D,A
ORA E
RET
CCCMPBCDE: MOV A,E
SUB C
MOV A,D
SBB B
RET
;
; ========================================
; I/O subroutines for CP/M
; By Glen Fisher
; The Code Works(tm)
; ========================================
;
NULL EQU 0 ;pointer to nothing
FCBSIZE EQU 36 ;size, in bytes, of an FCB
NEXTP EQU 0 ;offset to next-character pointer in I/O structure
UNUSED EQU 2 ;offset to unused-positions-count in I/O structure
BUFFER EQU 4 ;offset to disk sector buffer in I/O structure
FLAG EQU 33 ;file-type flag byte (in unused part of FCB)
FREEFLG EQU 128 ;This I/O structure is available for the taking
EOFFLG EQU 2 ;The end of this file has been hit
WRTFLG EQU 1 ;This file open for writing
BUFSIZ EQU 128 ;how long the sector buffer is
NBUFS EQU 4 ;number of I/O buffers (change buffer declarations, too)
; CP/M system call codes
CLOSE EQU 16 ;close a file
CREATE EQU 22 ;make a file
DMA EQU 26 ;set DMA (I/O address)
DELETE EQU 19 ;delete a file
GETCH EQU 1 ;read character from console
GETSTR EQU 10 ;read string from console
OPEN EQU 15 ;open a file
PUTCH EQU 2 ;write character to console
QUERY EQU 25 ;get logged-in drive id
READ EQU 20 ;read a sector
SELECT EQU 14 ;log-in a drive
WRITE EQU 21 ;write a sector
LF EQU 10 ;line feed
EOL EQU 13 ;end-of-line character (=carriage return)
CTRLZ EQU 26 ;end-of-file mark for text files
TBUFF EQU 80H ;address of default I/O address
DFLTDSK DS 1 ;drive to use if no drive is named
UNIT DS 2 ;I/O structure address to act on
IP DS 2 ;int *ip;
CHP DS 2 ;char *chp;
DP DS 2 ;char *dp;
FILE DS 2 ;file name
MODE DS 2 ;char *mode;(read or write)
ZCH DS 2 ;char ch;
ZT DS 2 ;int t;
FN DS 2 ;int fn; i/o function (for cpmio)
;
; exit()
;
; Stop execution of the program,
; restore the logged-in drive,
; and re-boot CP/M
;
QZEXIT:
LDA DFLTDSK ; Grab orig. logged-in disk
MOV E,A
DCR E ; (cvt. back to 0-n)
MVI C,SELECT ; and log it in again
CALL BDOS
JMP 0 ; Our work is complete.
;
; cpm(bc,de)
;
; fill BC and DE, and then call CP/M
;
; return whatever is in A
;
BDOS EQU 5
QZCPM:
POP H ;grab the arguments
POP D
POP B
PUSH B ;restore the size of the stack
PUSH D
PUSH H
CALL BDOS ;go to daddy
JMP CCSXT ;hand the answer back
;
; grabio()
;
; find an input buffer, and return its address.
; if there isn't one, return a NULL.
;
GRABIO: ;6 May 80 rj
MVI B,NBUFS
LXI H,IOBUFS+FLAG
LXI D,FCBSIZE+BUFFER+BUFSIZ
MVI A,FREEFLG
GRAB2: CMP M ;flag byte == freeflg?
JZ GRAB3 ;if so, found a free buffer
DAD D ;on to next buffer
DCR B
JNZ GRAB2 ;if there is one...
LXI H,NULL ;there ain't
RET ;give up
GRAB3: MVI M,0 ;mark buffer as taken
LXI D,-FLAG ;back up to buffer start
DAD D
RET ;and hand it back
;
; freeio(unit)
;
; mark a buffer as free.
;
FREEIO: ;Mod 6 May 80 rj
POP B ;save rtn addr
POP H ;get buffer addr
PUSH H ;put the stack back together
PUSH B
LXI D,FLAG ;find flag byte
DAD D
MVI M,FREEFLG ;mark buffer as 'free'
LXI H,NULL ;return something
RET
IOBUFS:
DS FCBSIZE-3
DB FREEFLG,0,0
DS BUFFER+BUFSIZ
DS FCBSIZE-3
DB FREEFLG,0,0
DS BUFFER+BUFSIZ
DS FCBSIZE-3
DB FREEFLG,0,0
DS BUFFER+BUFSIZ
DS FCBSIZE-3 ;mod 4 May 80 rj
DB FREEFLG,0,0
DS BUFFER+BUFSIZ
;
; fopen(name,mode)
;
QZFOPEN:
POP B ;get args
POP H ;mode
SHLD MODE
POP D
XCHG
SHLD FILE
PUSH H
PUSH D
PUSH B
CALL GRABIO ; unit = grabio();
SHLD UNIT
MOV A,H