; ISETUP.A - Setup for C program execution on IBM PC. ; jumped to by first instruction to do C initilization. ; DS:0 is program segment prefix. ; SS is program DS. ; SS:0 is size of C initilized memory. ; SS:2 is size of uninitilized memory. ; EQUs define fields. IBM EQU 21H ;IBM DOS INTERRUPT NUMBER CI_CODE EQU 1 CO_CODE EQU 2 DIRECT_CODE EQU 6 DIRECT_INPUT EQU 7 VERSION EQU 30H READ EQU 3FH SETBLK EQU 4AH TERMINATE EQU 4CH BS EQU 8 TAB EQU 9 LF EQU 0AH CR EQU 0DH CONTS EQU 19 CONTX EQU 24 DSEG PUBLIC _PCB_,_MSDOS2_ ;USED BY CHAIN NE_MSG DB 'not enough memory',10 MEMFROM DW 0 ;FIRSE FREE BYTE IN DS _PCB_ DW 0 ;_PCB_ SEGMENT REGISTER _ORIGSP_ DW 0 ;STARTING SP. CAUTION: MUST FOLLOW ;_PCB_ _MSDOS2_ DB 0 ;1 IF VERSION 2.0 OR ABOVE LASTCH DB 0 CURCH DB 0 PUBLIC ERRNO_ ERRNO_ RW 1 ;ERROR NUMBER CSEG PUBLIC _CSETUP,EXIT_,PUTCHAR_,GETCHAR_,PUTS_,MAIN_ ; this is the actual entry point for a C88 program. ; the following initilization must take place before a program ; is actually called. ; 1) set SP to highest available byte. ; 2) set uninitilized storage to zero. ; 3) calculate argc and argv. ; 4) set DS to users data area. ; 5) call main(argc,argv). ; if program returns then goto exit. ; SET SP. _CSETUP: MOV SS:_PCB_,DS ;SAVE _PCB_ FOR EXIT CALL MOV AX,[2] ;IBM PUTS TOTAL SYSTEM PARAGRAPHS HERE MOV BX,SS ;CURRENT SS:SP MUST BE WITHIN AVAILABLE SUB AX,BX ;PARAGRAPHS AVAILABLE FOR DATA JBE NOT_ENOUGH DEC AX ;PLAY IT SAFE CMP AX,1000H ;IF OVER 64K THEN SET SP TO 64K JC UNDER_64 MOV AX,0FFFH ;MAXIMUM STACK WITHOUT WRAP UNDER_64: MOV CL,4 ;TURN PARAGRAPH INTO BYTE SHL AX,CL CMP AX,SP ;SEE IF BIG ENOUGH JC NOT_ENOUGH MOV BX,SS:[0] ;IF SP IS INIT DATA+RESDATA+127 THEN MAKE MAX. ADD BX,SS:[2] ADD BX,127 CMP SP,BX ;WANT MAXIMUM ? JNZ HAVE_SP ;NO, MUST HAVE HAS A -Snn OPTION OF BIND MOV SP,AX ;HAVE A GOOD STACK HAVE_SP:MOV SS:_ORIGSP_,SP ;REMEMBER STACK FOR EXEC ; REMEMBER VERSION NUMBER MOV AH,VERSION ;CODE TO ASK FOR VERSION INT IBM CMP AL,2 ;IS IT 2 OR ABOVE ? JB OLDVER MOV SS:_MSDOS2_,1 ;TRUE IF VERSION 2 OR ABOVE OLDVER: ; CALCULATE ARGC AND ARGV. THE COMMAND TAIL IS BETWEEN 129 AND ; 255. COMMNAD TAIL IN COPIED TO TOP OF STACK AND ARGV VECTOR ; IS PLACED UNDER IT. THE COMMAND NAME IS LAMENTABLY NULL. MOV BYTE [255],CR ;DONT FALL OFF END IF INVALID MOV BYTE [128],' ' ;DONT FALL OFF START EITHER (REPLACES LENGTH) MOV CX,1 ;NUMBER OF ARGUMENTS. ALWAYS (NULL) COMMAND MOV SI,-1 ;LENGTH OF ARGUMENTS. ; FIND SIZE OF TAIL CMD_COUNT: INC SI MOV AL,[SI+129] ;NEXT COMMAND CHAR CMP AL,CR ;CR OR LF IS END OF LINE JZ END_COUNT CMP AL,LF JNZ CMD_COUNT END_COUNT: MOV AX,0 ;NEED ZERO AT END PUSH AX TEST SI,1 ;NEED WORD ALLIGNED STACK JZ WORD_A INC SP ;ODD NOW SO EVEN LATER WORD_A: MOV DI,SP ;REMEMBER LOC OF ZERO SUB SP,SI ;MAKE ROOM FOR TAIL MOV BP,SP ;BP CAN ADDRESS NEW TAIL NTAIL: DEC SI CMP SI,-1 ;-1 WHEN DONE JZ SAVE_ARGS ; A NON WHITE SPACE PRECEEDED BY WHITE MEANS ANOTHER ARGUMENT MOV AL,[SI+129] CMP AL,' ' ;SEE IF WHITE JZ WHITE CMP AL,TAB JNZ NOT_WHITE WHITE: MOV AL,0 ;SET WHITE TO NULL FOR END OF STRING JMP STUFF ; IS PRECEEDING A WHITE? NOT_WHITE: CMP BYTE [SI+128],' ' JZ NEW_ARG CMP BYTE [SI+128],TAB JNZ STUFF NEW_ARG:LEA BX,[BP+SI] ;STORE ARGV ELEMENT PUSH BX INC CX ;INCREMENT ARGC STUFF: MOV [BP+SI],AL ;PUT TAIL CHAR ON STACK JMP NTAIL ; SAVE A POINTER TO A ZERO FOR ARGV[0] SAVE_ARGS: PUSH DI ; SAVE ARGV AND ARGC MOV BP,SP ;DONT PUSH SP AS 286 IS DIFFERENT PUSH BP ;*ARGV[] PUSH CX ;ARGC ; SET DS TO CORRECT VALUE MOV AX,SS MOV DS,AX ; INITILIZE UNINITILIZED MEMORY TO ZERO MOV DI,[0] ;LENGTH OF INITILIZED MEMORY IS HERE MOV CX,[2] ;LENGTH OF UNINITILIZED IS HERE MOV ES,AX ;ES=DS MOV AL,0 ;THE ZERO CLD REP STOSB ; REMEMBER LOW ADDRESS OF FREE MEMORY ADD DI,2 ;MAKE WORD ALLIGNED AND DI,0FFFEH MOV MEMFROM,DI ;PUT AWAY FOR MEMORY CALL ; NOW READY FOR MAIN CALL MAIN_ ;AND DO THE PROGRAM ; FALL INTO EXIT IF RETURN MOV AL,0 ;SET RETURN CODE TO ZERO JMP DOEXIT ; exit(); EXIT_: POP AX ;RETRIEVE RETURN CODE POP AX DOEXIT: ;IN DOS 2.0 USE CODE 4C TO TERMINATE ;AS THIS ALLOWS AN ERROR CODE CMP _MSDOS2_,0 ;DOS 1.0 ? JZ OLDEND MOV AH,TERMINATE ;DOC 2.0 TERMINATE CODE INT IBM OLDEND: PUSH _PCB_ ;CREATE A LONG RETURN TO _PCB_:0 MOV AX,0 PUSH AX LRET NOT_ENOUGH: MOV AX,&NE_MSG PUSH AX CALL PUTS_ ADD SP,2 MOV AL,2 ;ERROR EXIT JMP DOEXIT ; charactor = getchar(); GETCHAR_: CMP LASTCH,0 ;SAVED CHAR JZ DOGC GLAST: MOV AL,LASTCH ;RETURN LAST CHAR MOV LASTCH,0 JMP GOTIN DOGC: MOV AH,CI_CODE ;CODE FOR ECHOED INPUT INT IBM ;DO THE CONSOLE READ GOTIN: MOV AH,0 ;RETURN A WORD CMP AL,26 ;CONTROL z ? JZ READNFG RET ;CHARACTER IS IN AL READNFG:MOV AX,-1 ;-1 IF EOF RET ; putchar(character); PUTCHAR_:POP AX ;RETURN ADDRESS POP DX ;DL IS CHARACTER PUSH DX PUSH AX CMP DL,LF ;MUST CHANGE LF TO CR,LF JNZ XCO MOV DL,CR ;PRINT THE CR FIRST CALL XCO MOV DL,LF ;PUT THE LF BACK XCO: MOV AH,CO_CODE INT IBM ;DO THE WRITE RET ; puts(string address); PUTS_: POP AX ;RETURN ADDRESS POP BX ;STRING ADDRESS PUSH BX PUSH AX PS_LP: MOV AL,[BX] ;NEXT CHAR OR AL,AL JZ PS_END ;ZERO AT END OF STRING PUSH BX PUSH AX ;CHAR CALL PUTCHAR_ ;LET PUTCHAR TURN LF INTO CR,LF ADD SP,2 POP BX INC BX ;STRING POINTER JMP PS_LP PS_END: RET PUBLIC CI_, CO_, CSTS_ ; charactor = ci(); CI_: CMP LASTCH,0 ;SAVED CHAR JZ DOCI MOV AL,LASTCH ;RETURN LAST CHAR MOV LASTCH,0 MOV AH,0 RET DOCI: MOV AH,DIRECT_INPUT ;CODE FOR DIRECT CONSOLE INPUT INT IBM MOV AH,0 ;MAKE AN INT RET ; charactor or zero = csts(); CSTS_: MOV AH,DIRECT_CODE ;CODE FOR DIRECT CONSOLE IO MOV DL,0FFH ;WANT A CHAR INT IBM MOV LASTCH,AL ;SAVE CHARACTER MOV AH,0 ;MAKE AN INT RET ; co(character); CO_: POP AX ;RETURN ADDRESS POP DX PUSH DX PUSH AX MOV AH,DIRECT_CODE ;WANT A DIRECT CONSOLE OUTPUT INT IBM RET ; MEMORY MANAGEMENT FUNCTIONS: _MEMORY, _SHOWSP, _SETSP PUBLIC _MEMORY_,_SETSP_,_SHOWSP_ _MEMORY_:MOV AX,MEMFROM ;ADDRESS OF FIRST FREE BYTE OF MEMORY RET _SHOWSP_:POP DX ;RETURN ADDRESS MOV AX,SP ;RETURN SP VALUE TO USER JMP DX _SETSP_: POP DX ;CHOP THE STACK - DANGEROUS OPERATION POP BX ;NEW SP VALUE CMP BP,SP ;ANY LOCALS JNZ NOC MOV BP,BX ;MUST MOVE THE BP TOO NOC: MOV SP,BX PUSH BX JMP DX ; SEGMENT REGISTER FUNCTIONS: _SHOWDS, _SHOWCS, _SETDS PUBLIC _SHOWDS_,_SHOWCS_,_SETDS_ _SHOWDS_:MOV AX,DS ;DS (AND SS) VALUE RET _SHOWCS_:MOV AX,CS ;CS VALUE RET _SETDS_:POP DX ;RETURN VALUE POP DS ;NEW DS PUSH DS JMP DX ;RETURN ; OS CALL USED BY OPEN, CREAT ETC. ; VALUE=_OS(CODE,ARGUMENT); PUBLIC _OS_ _OS_: PUSH BP MOV BP,SP MOV AH,[BP+4] ;IBM CODE MOV DX,[BP+6] ;ARGUMENT POINTER INT IBM MOV AH,0 ;MAKE RETURN AN INTEGER POP BP RET