pcs/sc.asm

1277 lines
29 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

TITLE CXINIT - Initiate execution of a Lattice C program
SUBTTL Copyright 1982 by Lattice, Inc.
NAME CXINIT
INCLUDE DOS.MAC
.8087
;**** modified to add EGA support 10-20-86 dbs
;**** modified for PROTECTED MODE 7-29-87 tc
; ***** Lattice C v3.0 C.asm file modified for PCS *****
; (None of the original file is altered. Mods done thru conditional assembly.)
scheme equ 1
;**
;
; name CXINIT -- initiate execution of C program
;
; description This is the main module for a C program on the
; MS-DOS implementation. It performs various low-level
; initializations and then calls _main.
;
; This routine is stored as C.OBJ and is included as
; the first object module when linking. It is important
; to include it first so that the segment structure will
; be defined properly.
;
; NOTE: In order for the segment structure to work correctly,
; this module must be assembled with Version 3 or later of the
; Microsoft assembler. Specifically, older assemblers emit
; segments in alphabetical order, while Version 3 and later
; emit them in the order that they appear. The latter is
; required for this module.
;
;**
;**
;
; Assembly parameters
;
TAB EQU 09H ; tab character
;**
;
; External program references (P and L models)
;
IF LPROG
EXTRN _MAIN:FAR
EXTRN RBRK:FAR
ENDIF
;**
;
; Define data group
;
DGROUP GROUP DATA,UDATA,XSTACK
ASSUME DS:DGROUP
;**
;
; Define program segment
;
if scheme ;extra segment for Scheme
XGROUP GROUP PROGX
PROGX SEGMENT BYTE PUBLIC 'PROGX'
PROGX ENDS
endif
IF S8086
IF COM
PGROUP GROUP PROG,TAIL
ENDIF
IFDEF PROMEM ;;; Protected Mode
PROG SEGMENT PARA PUBLIC 'PROG'
ELSE
PROG SEGMENT BYTE PUBLIC 'PROG'
ENDIF
ASSUME CS:PROG
IF COM
ORG 100H
ENDIF
ENDIF
IF D8086
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CODE
ENDIF
IF P8086
_CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:_CODE
ENDIF
IF L8086
_PROG SEGMENT BYTE PUBLIC 'PROG'
ASSUME CS:_PROG
ENDIF
;**
;
; External program references (S and D models)
;
IF LPROG EQ 0
EXTRN _MAIN:NEAR
IFNDEF PROMEM ;;; Protected Mode - IGNORE
EXTRN RBRK:NEAR ; C library function
ENDIF
if scheme
extrn allmem:near ; C library function
extrn rsttimer:near,unfixint:near ; PCS routines
extrn zcuron:near,zclear:near,zputcur:near ; "
extrn xli_term:near ; PCS routine
IFDEF EXPMEM
extrn rlsexp:near ; PCS routine
ENDIF
endif
ENDIF
;**
;
; Execution begins here
;
PUBLIC CXINIT
CXINIT PROC FAR
CLI
IF COM
MOV AX,OFFSET PGROUP:TAIL ; set up DS/SS for .COM file
ADD AX,16
MOV CL,4
SHR AX,CL
MOV BX,CS
ADD AX,BX
MOV DS,AX
MOV SS,AX
MOV SP,OFFSET DGROUP:SBASE+STKRSV
ELSE
MOV AX,DGROUP ; set up DS/SS for .EXE file
MOV DS,AX
IFDEF PROMEM ;;; Protected Mode
mov ss,ax ; ss=ds
mov _ss,ax ; and save in _ss
mov bx, _base ; bx = base of stack (relative to DS)
add bx, _stack ; add # bytes of stack (default = 2048)
mov sp, bx ; and save in sp
mov _top, bx ; top of stack (relative to DS)
mov _sp,bx ; sp reset value
ELSE
MOV AX,XSTACK
MOV SS,AX
MOV SP,STKRSV
ENDIF
ENDIF
STI
if scheme
;
; Save address of our exit routine where C can use it
;
mov ax,offset xcexit
mov _onexit,ax
endif
;
; Compute program size in bytes and save in _PSIZE
;
IFDEF PROMEM ;;; Protected Mode
; _PSIZE actually has limit, should increment....
mov ax, 0ffffh ; Program size will always be 64kb
MOV WORD PTR _PSIZE,AX
xor ax, ax
MOV WORD PTR _PSIZE+2,AX
ELSE
MOV AX,DS
MOV CX,CS
SUB AX,CX
MOV CL,4
ROL AX,CL
MOV WORD PTR _PSIZE,AX
AND WORD PTR _PSIZE,0FFF0H
AND AX,15
MOV WORD PTR _PSIZE+2,AX
ENDIF
;
; Clear the uninitialized data area
;
XOR AX,AX
MOV DI,OFFSET DGROUP:UDATA
MOV CX,OFFSET DGROUP:SBASE
SUB CX,DI
SHR CX,1
JZ M0
PUSH ES
PUSH DS
POP ES
CLD
REP STOSW
POP ES
;
; Get DOS version number
;
M0: MOV AH,30H ; get DOS version number
INT 21H
OR AL,AL
JNZ M00
MOV AX,1 ; assume 1.00 if null return
M00: MOV WORD PTR _DOS,AX
MOV _PSP+2,ES ; set up pointer to prog seg prefix
;
; Examine the environment string area
;
ife scheme ; PCS ignores DOS environment strings
IF MSDOS EQ 1
CMP _DOS,2
JL M01
ENDIF
MOV AX,ES:[2CH]
MOV WORD PTR _ENV+2,AX ; set up pointer to environment
OR AX,AX
JZ M01 ; branch if null
PUSH ES ; determine number of bytes
CLD
LES DI,_ENV
XOR AX,AX
XOR BX,BX
MOV CX,7FFFH
M0A: REPNZ SCASB
JNZ M0C
INC BX
SCASB
JNZ M0A
MOV _ESIZE,DI ; save environment size
MOV _ENVC,BX ; save environment string count
CMP _DOS,3 ; include command name for DOS 3
JL M0B
ADD DI,2
REPNZ SCASB
JNZ M0C
M0B: ADD DI,2 ; make size an even number
AND DI,0FFFEH
MOV _XSIZE,DI
M0C: POP ES
endif
;
; Examine command line
;
M01: MOV SI,80H ; check command line
MOV CL,ES:[SI]
XOR CH,CH ; CX contains length of cmd line
JCXZ M12 ; branch if null
M1: INC SI ; scan for first arg
MOV AL,ES:[SI]
ife scheme ; PCS doesn't scan for special args
IF MSDOS EQ 1
CMP _DOS,2
JGE M10
CMP AL,'<'
JE M2 ; branch if input file name
CMP AL,'>'
JE M3 ; branch if output file name
ENDIF
M10: CMP AL,'='
JE M4 ; branch if stack size
endif
CMP AL,' '
JE M11 ; branch if white space
CMP AL,TAB
JNE M12 ; branch if normal arg
M11: DEC CX
JG M1
XOR CX,CX
M12: JMP M5 ; branch if no args found
ife scheme ; PCS doesn't scan for special args
IF MSDOS EQ 1
;
; Get input file name
;
M2: MOV DI,OFFSET DGROUP:_INAME
JMP M31
;
; Get output file name
;
M3: MOV DI,OFFSET DGROUP:_ONAME
;
; Save file name in data area
;
M31: XOR AH,AH
M32: DEC CX
JZ M33
INC SI
MOV AL,ES:[SI]
CMP AL,' '
JZ M33
CMP AL,TAB
JZ M33
MOV DS:[DI],AL
INC DI
INC AH
CMP AH,32
JE M34
JMP M32
M33: MOV BYTE PTR DS:[DI],0
JMP M11
M34: MOV DX,OFFSET DGROUP:NAMERR
JMP NEAR PTR XCABT
ENDIF
;
; Get stack and heap sizes from command line
;
M4: CALL GETNUM ; get stack size
JC M47 ; branch if error
TEST BX,BX
JZ M42A ; bypass if size is 0
CMP AL,'K'
JE M41
CMP AL,'k'
JNE M42 ; branch if not kilobytes
M41: TEST BX,0FFC0H
JNZ M47 ; error if size > 63
XCHG BH,BL ; multiply by 1024
SHL BH,1
SHL BH,1
DEC CX ; advance to next character
JZ M42
INC SI
MOV AL,ES:[SI]
M42: MOV _STACK,BX ; save stack size
M42A: TEST CX,CX
JZ M5 ; branch if end of command line
CMP AL,' '
JE M46 ; loop if blank
CMP AL,TAB
JE M46 ; loop if tab
CMP AL,'/'
JNE M47 ; branch if not slash
CALL GETNUM ; get heap size
JC M47 ; branch if error
XOR DX,DX ; long result is in DX,BX
TEST BX,BX
JZ M45 ; branch if size is 0
CMP AL,'K'
JE M43
CMP AL,'k'
JNE M44 ; branch if not kilobytes
M43: XCHG BH,BL ; multiply by 1024
ROL BX,1
ROL BX,1
MOV DX,BX
AND BX,0FC00H
AND DX,3FFH
DEC CX ; advance to next character
JZ M44
INC SI
MOV AL,ES:[SI]
M44: MOV WORD PTR _MNEED,BX ; save heap size
MOV WORD PTR _MNEED+2,DX
M45: TEST CX,CX
JZ M5 ; branch if end of command line
CMP AL,' '
JE M46 ; loop if blank
CMP AL,TAB
JNE M47 ; error if not tab
M46: JMP M11
M47: MOV DX,OFFSET DGROUP:STKERR ; abort if stack/heap size error
JMP NEAR PTR XCABT
endif ;matches IFE near M12:
;
; Set up the stack
;
ife scheme ; PCS ignores DOS environment strings
IF LDATA EQ 0
M5: MOV AX,_XSIZE ; reserve space for environment
ADD AX,15
AND AX,0FFFEH
ELSE
M5: XOR AX,AX
ENDIF
else
M5: xor ax,ax
endif
IFDEF PROMEM ;;; Protected Mode
mov bx,_top ; bx = top of stack
jmp M54a
M54: MOV DX,OFFSET DGROUP:MEMERR2 ; abort if error in releasing memory
JMP NEAR PTR XCABT
M54a:
ELSE
MOV BX,_STACK ; get stack size
SHR BX,1 ; make size even
ADD BX,BX
CMP BX,STKMIN
JA M51
MOV BX,STKMIN ; use default if too small
MOV _STACK,BX
M51: ADD BX,AX ; add environment size
JC M54 ; abort if overflow
MOV DX,ES:2 ; compute available paragraphs
if scheme
mov _paras,dx ; save no. paragraphs for Scheme
endif
MOV AX,SS
SUB DX,AX
TEST DX,0F000H
JNZ M52 ; branch if greater than 64Kbytes
SHL DX,1 ; convert to bytes
SHL DX,1
SHL DX,1
SHL DX,1
JMP M53
M52: MOV DX,0FFF0H ; use largest value
IF LDATA
M53: CMP DX,BX ; check if stack will fit
JA M55
ELSE
M53: CMP DX,BX ; check if stack will fit
JB M54
ADD BX,_BASE ; adjust S/P model for statics
JNC M55
ENDIF
M54: MOV DX,OFFSET DGROUP:MEMERR2 ; abort if error in releasing memory
JMP NEAR PTR XCABT
M55: CLI
MOV _TOP,BX ; set top-of-stack
MOV SP,BX ; set stack pointer
IF LDATA EQ 0
MOV AX,DS
MOV SS,AX
ENDIF
MOV _SS,SS
STI
ENDIF ; IFDEF PROMEM
;
; Set up memory allocation pointers
;
PUSH CX ; save command byte count
IFDEF PROMEM ;;; Protected Mode
; Assume small data model
MOV AX,SS ; ax=stack segment
MOV _MBASE+2,AX ; _mbase = top of stack
mov _mbase, bx ;
MOV _MNEXT+2,AX ; _mnext = _mbase
mov _mnext, bx ;
mov bx, 0fff0h ; Protected mode has a full 64K
sub bx, _top ; subtract out top of stack
MOV _MSIZE,BX ; _msize = size of heap pool
xor ax, ax
ELSE
ADD BX,15 ; compute mem pool base segment number
JC M54
MOV CL,4
SHR BX,CL
MOV AX,SS
ADD AX,BX
MOV _MBASE+2,AX
MOV _MNEXT+2,AX
MOV BX,ES:2 ; get top segment number
SUB BX,AX ; compute memory pool size
JBE M54 ; branch if insufficient memory
MOV CL,4 ; compute number of bytes
ROL BX,CL
MOV AX,BX
AND AX,15
AND BX,0FFF0H
MOV _MSIZE,BX
ENDIF
MOV _MSIZE+2,AX
PUSH ES ; reset memory pool
PUSH SI
CALL RBRK
POP SI
POP ES
OR AX,AX
JNZ M54 ; branch if not enough memory
if scheme
IFNDEF PROMEM ;;; Protected Mode - IGNORE
push si
call allmem ; allocate the rest of the data segment
; to C's heap (small model only);
; later, in "initmem", PCS will get the
; rest of MSDOS's memory for itself
pop si
or ax,ax
jnz m54
ENDIF
endif
POP DX ; restore command line length
;
; Put return address at top of stack
;
IF MSDOS EQ 1
PUSH ES ; return is to 1st word of prog prefix
XOR AX,AX
PUSH AX
MOV BP,SP ; BP contains stack linkage
ENDIF
;
; copy command line to stack
;
MOV CX,DX ; get residual command line length
SUB SP,CX ; allocate stack space
DEC SP
MOV DI,SP
MOV DX,SP ; save pointer to end of command
ADD DX,CX
JCXZ M71 ; skip if no bytes to move
PUSH DS ; move them
PUSH ES
POP DS
PUSH SS
POP ES
CLD
REP MOVSB
POP DS
M71: MOV BYTE PTR SS:[DI],0 ; append null byte
MOV WORD PTR _ARG,SP ; save arg array pointer
MOV WORD PTR _ARG+2,SS
;
; Move environment to stack for small data models
;
ife scheme ; PCS ignores DOS environment strings
IF LDATA EQ 0
MOV CX,_XSIZE ; get extended env size
JCXZ M72 ; branch if no environment
SUB SP,CX ; allocate stack space
MOV DI,SP
PUSH DS ; save important regs
PUSH ES
PUSH SI
PUSH SS ; set stack as destination seg
POP ES
MOV SI,WORD PTR _ENV+2
MOV WORD PTR _ENV,DI ; save relocated env pointer
MOV WORD PTR _ENV+2,SS
MOV DS,SI ; set env as source
XOR SI,SI
CLD ; move environment
REP MOVSB
POP SI ; restore regs and continue
POP ES
POP DS
ENDIF
endif
;
; Build argument vector
;
ife scheme ; PCS parses its own command line
M72: AND SP,0FFFEH ; make stack pointer even
MOV SI,DX ; prepare to scan command backwards
XOR CX,CX
PUSH CX ; push null terminator for argv
IF LDATA
PUSH CX
ENDIF
MOV BX,SP ; save this null byte address
M8: CMP SI,WORD PTR _ARG ; skip trailing white space
JNE M80
JMP M83
M80: DEC SI
CMP BYTE PTR SS:[SI],' '
JE M8
CMP BYTE PTR SS:[SI],TAB
JE M8
MOV BYTE PTR SS:[SI+1],0 ; install null terminator byte
MOV AL,0 ; indicate white space scan
CMP BYTE PTR SS:[SI],'"'
JNE M81 ; branch if not quoted arg
CMP SI,WORD PTR _ARG
JE M81
CMP BYTE PTR SS:[SI-1],'\'
JE M810 ; branch if \"
MOV AL,'"' ; indicate quote scan
MOV BYTE PTR SS:[SI],0 ; put null in place of quote
M81: CMP SI,WORD PTR _ARG
JE M82 ; branch if no more chars
DEC SI ; position to next char
CMP BYTE PTR SS:[SI],'"'
JNE M81C ; branch if not quote
CMP SI,WORD PTR _ARG
JE M81C ; branch if no more chars
CMP BYTE PTR SS:[SI-1],'\'
JNE M81C ; branch if not \"
M810: PUSH SI ; squish args to remove \
M81A: DEC SI
CMP SI,WORD PTR _ARG
JE M81B
MOV AH,SS:[SI-1]
MOV SS:[SI],AH
JMP M81A
M81B: INC WORD PTR _ARG
POP SI
JMP M81D
M81C: OR AL,AL
JNZ M82A ; branch if not white space scan
M81D: CMP BYTE PTR SS:[SI],' ' ; find next white space
JE M81E
CMP BYTE PTR SS:[SI],TAB
JNE M81
M81E: INC SI ; position to start of arg
IF LDATA
M82: PUSH SS ; add arg pointer to vector
PUSH SI
ELSE
M82: PUSH SI ; put arg pointer into argv
ENDIF
INC CX ; bump arg count
JMP M8 ; loop till all args done
M82A: CMP BYTE PTR SS:[SI],'"' ; come here to find starting quote
JNE M81 ; branch if not quote
MOV BYTE PTR SS:[SI],' ' ; replace it with white space
JMP M81E ; go save arg pointer
;
; Construct argv[0]
;
M83: CMP _DOS,2
JLE M84
MOV AX,WORD PTR _ENV ; use env trailer for DOS 3
ADD AX,_ESIZE
INC AX
INC AX
IF LDATA
PUSH [WORD PTR _ENV+2]
ENDIF
PUSH AX
JMP M85
IF LDATA
M84: PUSH SS ; use null byte for DOS 2
PUSH BX
ELSE
M84: PUSH BX ; use null byte for DOS 2
ENDIF
;
; Save argv information
;
M85: INC CX ; save arg count
MOV _ARGC,CX
IF LDATA
MOV WORD PTR _ARGV,SP ; save arg vector pointer
MOV WORD PTR _ARGV+2,SS
ELSE
MOV _ARGV,SP ; save arg vector pointer
ENDIF
else ; PCS parses its own command line
; -------------------------------------------------
; The PCS command line parser
; -------------------------------------------------
; The PCS command line can look as follows:
;
; PCS (... ...) atom atom (... ...) "string" atom ...
;
; which parses into PCS-INITIAL-ARGUMENTS as:
;
; ( "(... ...)" "atom" "atom" "(... ...)" "\"string\"" "atom" ... )
;
; Each command line argument is either an atom, list, or string.
; Each is treated as one argument for the argv vector, and each is
; converted to a string which becomes an element of PCS-INITIAL-ARGUMENTS.
;
; The command line parser is not a Scheme reader. It looks for blank-separated
; tokens, where a token can start with a ( and end with the matching ),
; start and end with a ", or just be a sequence of nonblanks. Backslashed
; delimiters are skipped over as you'd expect. We don't bother with | since
; that is a special character to DOS. The blanks between tokens are important
; since the parser replaces them with nulls to get things set up for C's
; argv vector, so situations like ...)(... won't be parsed correctly.
; The parser is implemented as a finite state automaton (FSA).
;
; The first command line argument has special meaning but that is
; handled in "smain.c".
;
; On entry to this section:
; ES = SS (but we don't care)
; SP = ptr to start of cmdline
; DX = ptr to cmdline eos (cmdline on stack with eos at its end)
M72:
push DS ; ES <- DS
pop ES
xor AX,AX ; AH is state, AL is current char
push AX ; push 0 at front of cmdline
; (we're going to parse backwards)
and SP,0FFFEH ; make SP even
mov SI,DX ; SI is index into cmdline
xor DX,DX ; DH is paren counter, DL is argc
cld
M72loop: dec SI ; get the next char from cmdline
cmp byte ptr SS:[SI-1],'\' ; is it singly escaped?
jne M72a ; no, jump
dec SI ; yes, back up to escape char
M72a: mov AL,SS:[SI]
mov CX,scan_size ; look it up in char table
mov DI,offset scan_table
repne scasb ; put into CX the "char class" for
; indexing into state table
mov AL,bytes_per_state ; do 2-D subscript into state table
mul AH ; ... row
shl CX,1 ; ... col
add AX,CX
mov BX,AX ; (BH=0 since subscript small enough)
mov AH,state[BX] ; get next state
mov BL,state+1[BX] ; do action routine
add BX,offset actions
jmp BX
actions label near ; start action routines ---------->
ar_out2: inc SI ; 1 char past token, back up
push SI ; push next argv
dec SI
inc DL ; incr argc
ar_skip: mov byte ptr SS:[SI],0 ; output a null char
ar_decr: jmp short M72loop
ar_lpar: dec DH ; decr paren count
js ar_err ; wrong paren to start with
jnz short M72loop ; on an inner paren, keep looking
mov AH,0 ; override state in table
ar_out1: push SI ; matched delimiter, push next argv
inc DL ; incr argc
jmp short M72loop
ar_rpar: inc DH ; incr paren count
jmp short M72loop
ar_err: mov DX,offset dgroup:parserr ; abort on error in cmdline parsing
jmp near ptr XCABT
ar_out_end: inc SI ; 1 char past token, back up
push SI ; push next argv
dec SI
inc DL ; incr argc
ar_end: ; end action routines <----------
continue: xor AX,AX ; argv[0] = \0
push AX
inc DL ; incr argc
mov _argv,SP ; save address of argv
mov DH,0
push DX
mov _argc,DX ; save argc
endif
;
; Build environment vector
;
ife scheme ; PCS ignores DOS environment strings
XOR AX,AX ; push null terminating pointer
PUSH AX
IF LDATA
PUSH AX
ENDIF
MOV AX,_ENVC ; allocate stack space for vector
ADD AX,AX
JZ M87 ; branch if null environment
SUB SP,AX
IF LDATA
SUB SP,AX
ENDIF
MOV SI,SP ; scan environment
LES DI,_ENV
XOR AX,AX
MOV CX,7FFFH
MOV DX,_ENVC
CLD
M86: MOV SS:[SI],DI
ADD SI,2
IF LDATA
MOV SS:[SI],ES
ADD SI,2
ENDIF
DEC DX
JLE M87
REPNE SCASB
JMP M86
M87: MOV WORD PTR environ,sp
IF LDATA
MOV WORD PTR environ+2,SS
ENDIF
endif
;
; initialize 8087 numeric data processor
;
IFNDEF PROMEM ;;; Protected Mode - IGNORE
FNINIT ; reset
FNSTSW _NDPSW ; get status
MOV AX,100 ; this is just for delay
MOV DX,AX
IMUL DX
TEST _NDPSW,0B8BFH ; 8087 will reset all these
JNZ M9
INC _NDP ; indicate ndp present
ENDIF
;
; set up args for _main and call it
;
M9: MOV _SP,SP ; save stack pointer reset value
PUSH DS ; make ES same as DS
POP ES
CALL _MAIN ; call C main
IF MSDOS EQ 1
CMP _DOS,2
JL M91 ; branch if DOS 1
ENDIF
MOV AX,4C00H ; exit with return code of 0
INT 21H
IF MSDOS EQ 1
M91: MOV SP,BP ;restore ptr to far return
RET ;return to MS-DOS
ENDIF
;**
;
; name GETNUM -- get a number from the command line
;
; description This function is used internally by the start-up routine
; while processing the command line.
;
;**
ife scheme
GETNUM PROC NEAR
XOR BX,BX ; reset accumulator
NUM1: DEC CX ; advance to next character
JZ NUM3 ; branch if end of command line
INC SI
MOV AL,ES:[SI]
CMP AL,'0'
JL NUM3 ; return if not decimal digit
CMP AL,'9'
JG NUM3 ; return if not decimal digit
SUB AL,'0' ; multiply accumulator by 10
ADD BX,BX
JC NUM2
MOV DX,BX
ADD BX,BX
JC NUM2
ADD BX,BX
JC NUM2
ADD BX,DX
JC NUM2
XOR AH,AH ; add this digit
ADD BX,AX
JNC NUM1 ; loop till done
NUM2: RET
NUM3: CLC ; clear carry to indicate no error
RET
GETNUM ENDP
endif
;**
;
; name XCABT -- Ignominious abort
;
; description This area is entered by direct jump with a message
; pointer in DS:DX. It sends the message to the
; console via DOS function 9 and then aborts.
;
ENTRY XCABT
MOV AH,9 ; print error message
INT 21H
MOV ES,_PSP+2
IF MSDOS EQ 1
CMP _DOS,2
JL A1
ENDIF
MOV AX,4C01H
INT 21H
IF MSDOS EQ 1
A1: PUSH ES
XOR AX,AX
PUSH AX
RET
ENDIF
if scheme
;
; Scheme wrapup - the C fn "exit" calls "_exit" which calls this hook routine
;
public xcexit
DOS equ 21h ; MSDOS function request interrupt
xcexit proc near
mov bp,sp ; don't lose our return address to _exit
IFDEF EXPMEM
call rlsexp ; Release Expanded Memory (if any)
ENDIF
call xli_term ; release all external programs
; allocated under XLI
IFNDEF PROMEM
push ES ; return Scheme heap to DOS
mov AH,49h
mov ES,first_dos
int DOS
pop ES
jnc MA
MOV DX,OFFSET DGROUP:MEMERR2 ; abort if error in releasing memory
JMP NEAR PTR XCABT
ENDIF
MA: call rsttimer ; Reset the timer interrupt, if necessary
call unfixint ; Restore the keyboard "patch" (MWH2)
call zcuron ; Turn cursor back on
mov AX,15 ; Load character attribute = white,enable
push AX
mov AX,80 ; 80 Columns
push AX
mov AX,25 ; 25 Rows
push AX
xor AX,AX ; Origin at 0,0
push AX
push AX
call zclear ; Clear the screen
xor AX,AX
push AX
push AX
inc cur_off ; keep cursor off for EGA modes
call zputcur ; Put cursor at 0,0
mov sp,bp ; reestablish the return address to _exit
ret
xcexit endp
endif
CXINIT ENDP
IFDEF PROMEM ;;; Protected Mode
;;; Reset heap break point (unix lingo)
;;;
;;; Set _mbase = _mnext = DS:_top
;;; Set _pool = 0:0, _melt = 0:0
public rbrk
RBRK PROC NEAR
push bp
mov bp,sp
;
; set up memory allocation pointers
;
mov bx, _top
add bx, 0fh ; round up to para
and bx, 0fff0h
mov _tsize, bx ; total size in paras
mov ax,ds
mov _mbase+2,ax ; long ptr to heap base
mov _mbase, bx
mov _mnext+2,ax ; long ptr to heap top
mov _mnext, bx
xor ax,ax
mov [_msize+2],ax ; number of bytes left in pool
mov _msize, ax
; Clear the 2nd level pool
mov [_melt],ax
mov [_pool],ax
mov [_melt+02],ax
mov [_pool+02],ax
pop bp
ret
RBRK ENDP
;
public lsbrk
lsbrk PROC NEAR
push bp
mov bp,sp
mov cx,[bp+6] ; requested size (high)
mov dx,[bp+4] ; requested size (low)
or cx, cx
jnz lsbrk_err1
mov cx, 0FFF0h
sub cx, _mnext ; available bytes
cmp cx, dx
jb lsbrk_err1
mov ax, _mnext ; next location in pool
add _mnext, dx ; bump by requested amount
mov bx, ax
pop bp
ret
lsbrk_err1:
xor ax,ax
mov bx, ax
pop bp
ret
lsbrk ENDP
COMMENT %
;; _RBRK (int desire)
;; desire is initial heap in paras
;; return 0 if OK, ffff otherwise
;;
public _rbrk
;;extrn _model:word
_rbrk proc near
push bp
mov bp,sp
push es
;mov word ptr [_oserr],_model
mov bx, 0 ;; what is really needed here? 128K?
mov [_tsize],bx ;; really total size with heap
mov ax,[_mbase] ;; reset heap allocator ptrs
mov [_mnext],ax
mov ax,[_mbase+02]
mov [_mnext+02] ,ax
xor ax,ax
pop es
pop bp
ret
_rbrk_error1:
mov [_oserr],ax
_rbrk_error:
mov ax,0ffffh
pop es
pop bp
ret
_rbrk endp
%
ENDIF
;**
;
; Dummy segment to establish top of program for small program models
;
IF S8086
IF COM
TAIL SEGMENT WORD 'PROG'
DW -1
TAIL ENDS
ENDIF
ENDIF
IF S8086
PROG ENDS
ENDIF
IF D8086
CODE ENDS
ENDIF
IF P8086
_CODE ENDS
OLDCODE SEGMENT BYTE ; This catches Version 2 code
DW 0CACAH
OLDCODE ENDS
ENDIF
IF L8086
_PROG ENDS
OLDPROG SEGMENT BYTE ; This catches Version 2 code
DW 0CACAH
OLDPROG ENDS
ENDIF
PAGE
;**
;
; DGROUP includes the segments named DATA, UDATA, and XSTACK. The startup
; routine initializes DS to point to this group, and DS must then be pre-
; served throughout the program. The segments within DGROUP are defined
; as follows:
;
; DATA => Contains all static (local and global) initialized items.
; UDATA => Contains all static (local and global) uninitialized items.
; XSTACK => Stack for the startup routine.
;
; During the startup routine, the initial stack (XSTACK) is replaced with
; one that has the correct size for program execution. This size is
; determined by examining the command line and the _STACK global item. Then
; for the S and P memory models, the stack is set up relative to DGROUP (i.e.
; stack items can addressed via DS). For the D and L models, the stack
; segment stands alone and can be up to 64K bytes.
;
; The heap (i.e. the space used by the memory allocator) resides above the
; stack and is also initialized by the startup routine. Any space not
; immediately needed for the heap (as defined by _MNEED) is returned to DOS.
;
; At the end of the startup routine, memory is organized in the following
; sequence:
;
; -- code --
; -- DATA --
; -- UDATA --
; -- stack --
; -- heap --
;
; FOR PROPER OPERATION OF THE STANDARD MEMORY ALLOCATOR, THIS SEQUENCE IS
; EXTREMELY IMPORTANT. IF YOU TAMPER WITH THE STARTUP ROUTINE OR INTRODUCE
; SEGMENTS AND CLASSES THAT DO NOT FOLLOW LATTICE CONVENTIONS, CHECK THE
; LOAD MAP CAREFULLY.
;
;**
;**
;
; Initialized data
;
DATA SEGMENT PARA PUBLIC 'DATA'
EXTRN _STACK:WORD
EXTRN _MNEED:DWORD
IFDEF PROMEM ;;; Protected Mode
EXTRN _POOL:WORD
EXTRN _MELT:WORD
ENDIF
PUBLIC _MODEL,_VER,_TOP,_BASE,_PSP,_MBASE,_MNEXT,_MSIZE,_DSIZE,_PSIZE
PUBLIC _ENV,_DOS,_TSIZE,_ESIZE,_XSIZE,_SS,_SP,_NDP,_NDPSW,_NDPCW
PUBLIC _FPA,_FPERR,_OSERR,_SIGFPE,_ARGV,_ARGC,_ENVC,environ
if scheme
extrn _onexit:word ; our hook into C exit fn
extrn cur_off:byte
public _paras,first_pa,first_dos
endif
IF S8086
_MODEL DW 0
ENDIF
IF P8086
_MODEL DW 1
ENDIF
IF D8086
_MODEL DW 2
ENDIF
IF L8086
_MODEL DW 3
ENDIF
_VER DB "LC 3.00",0
_DOS DB 0 ; DOS major version number
DB 0 ; DOS minor version number
_SS DW 0 ; stack segment number
_SP DW 0 ; SP reset value
_TOP DW 0 ; top of stack (relative to SS)
_BASE DW OFFSET DGROUP:SBASE ; base of stack (relative to DS)
_PSP DW 0 ; program segment prefix pointer
DW 0
_MBASE DW 0 ; base of memory pool
DW 0
_MNEXT DW 0 ; next available memory location
DW 0
_MSIZE DW 0 ; number of bytes left in pool
DW 0
_TSIZE DW 0 ; total size in paragraphs
_PSIZE DD 0 ; size of program in bytes
_DSIZE DW OFFSET DGROUP:SBASE ; size of static data in bytes
DW 0
IF LDATA
_ARGV DD 0 ; argument vector pointer
environ DD 0 ; environment vector pointer
ELSE
DD 0 ; *** DOS 2.00 trashing bug ***
_ARGV DW 0 ; argument vector pointer
environ DW 0 ; environment vector pointer
ENDIF
_ARGC DW 0 ; argument count
_ENVC DW 0 ; environment count
_ARG DD 0 ; far pointer to original arg array
_ENV DD 0 ; far pointer to original env array
_ESIZE DW 0 ; environment size in bytes
_XSIZE DW 0 ; extended env size in bytes
_FPA DQ 0 ; floating point accumulator
_FPERR DW 0 ; floating point error code
_NDP DB 0 ; non-zero if 8087 is installed
_NDPSW DW 0FFFFH ; 8087 status word
_NDPCW DW 0 ; 8087 control word
_OSERR DW 0 ; DOS error code
IF LPROG
_SIGFPE DD 0 ; Floating point error signal
ELSE
_SIGFPE DW 0 ; Floating point error signal
ENDIF
if scheme
_PARAS DW 0 ; # of paragraphs of memory available
FIRST_PA DW 0 ; seg# of first para. actually used for
; Scheme heap
FIRST_DOS DW 0 ; seg# of first para. from DOS for
; Scheme heap
; the characters sought by PCS's scanner
scan_table db 0,' ()"',0
scan_size equ $-scan_table
; the FSA transition table used to parse PCS's command line
; (This once included handling for vertical-bar delimited symbols, but
; DOS's use of | rendered it useless, so it was removed.)
start_state equ 0
list_state equ 1
atom_state equ 2
strg_state equ 3
end_state equ 4
err_state equ 5
state label byte
; initial state
db atom_state,ar_decr-actions ; any char
db strg_state,ar_decr-actions ; "
db list_state,ar_rpar-actions ; )
db err_state,ar_err-actions ; (
db start_state,ar_skip-actions ; blank
db end_state,ar_end-actions ; null
bytes_per_state equ $-state
; in list
db list_state,ar_decr-actions
db list_state,ar_decr-actions
db list_state,ar_rpar-actions
db list_state,ar_lpar-actions ; start_state also possible, see ar_lpar
db list_state,ar_decr-actions
db err_state,ar_err-actions
; in atom
db atom_state,ar_decr-actions
db atom_state,ar_decr-actions
db atom_state,ar_decr-actions
db atom_state,ar_decr-actions
db start_state,ar_out2-actions
db end_state,ar_out_end-actions
; in string
db strg_state,ar_decr-actions
db start_state,ar_out1-actions
db strg_state,ar_decr-actions
db strg_state,ar_decr-actions
db strg_state,ar_decr-actions
db err_state,ar_err-actions
; The exit and error states are not explicitly represented
; in the table, action routines deal with them.
endif
STKERR DB "Invalid stack size",0DH,0AH,"$"
MEMERR DB "Insufficient memory",0DH,0AH,"$"
if scheme
memerr2 db "Error in returning memory to DOS",0dh,0ah,"$"
parserr db "Error in parsing command line",0dh,0ah,"$"
endif
IF MSDOS EQ 1
PUBLIC _INAME,_ONAME
_INAME DB 32 DUP(0) ; input file name
_ONAME DB 32 DUP(0) ; output file name
NAMERR DB "Invalid I/O redirection",0DH,0AH,"$"
ENDIF
DATA ENDS
;**
;
; Uninitialized data
;
UDATA SEGMENT PUBLIC 'DATA'
UDATA ENDS
;**
;
; The stack segment is included to prevent the warning from the
; linker, and also to define the base (lowest address) of the stack.
;
STKRSV EQU 128 ; reserved stack size
STKMIN EQU 512 ; minimum run-time stack size
IF COM
XSTACK SEGMENT 'DATA'
ELSE
XSTACK SEGMENT STACK 'DATA'
ENDIF
SBASE DB STKRSV DUP (?)
XSTACK ENDS
END CXINIT