pcs/sc.asm

1277 lines
29 KiB
NASM
Raw Permalink Normal View History

2023-05-20 05:57:06 -04:00
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