|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 52480 (0xcd00) Types: TextFile Names: »STARTUP.A86«
└─⟦93c4d868c⟧ Bits:30005869 SW1609 Digital Research C v. 1.11 - May 84 └─ ⟦this⟧ »STARTUP.A86« └─⟦b85731168⟧ Bits:30002664 Digital Research C - CCP/M - May 84 └─ ⟦this⟧ »STARTUP.A86«
Name 'STARTUP' Title 'STARTUP for DRC V1.11' Pagesize 75 ; ; This startup file is actually several files edited together: ; clear.a86, minit.a86, minitrel.a86, minitsta.a86, minithea.a86, minitcmd.a86, ; miniterr.a86, minitos.a86. The include statements and public/extrn ; statements that connect the separate files have been commented out. ; Each such comment has the initials ACF on it. ; ; Notes to the user. ; ; Only the most sophisticated user, with a thorough knowledge of the 8086, ; CP/M, RASM86, LINK86, the .CMD file format, and the C calling conventions, ; should attempt to write a startup routine. These notes will explain how ; this one was written, and why certain things are done in certain ways. ; ; First of all, DRI has a new policy for assembly language routines: public ; names in them should not conflict with user public names, whether from a ; high level language or assembly language. This is accomplished by having ; a special in-house version of RASM86 which permits '.' (period) in an ; identifier as any but the first character. This startup routine uses that ; convention. When CLEAR, the Common Language Environment And Runtime, is ; extended to all DRI languages, all internal (compiler referenced) runtime ; routines will contain a period, to avoid any conflict with a user name. ; ; This being the case, if you try to assemble this startup routine, you will ; get assembly errors. So you must alter your RASM86 by patching it. This ; is our way to insure that you really are a sophisticated user who knows what ; you are doing, otherwise you would not go to all this trouble. Using SID86, ; read in RASM86.CMD. The, using the SR (search) command, search for "$_?@". ; The byte before these four characters should be a hex 04, and the byte after ; should be a hex 00. Change the hex 04 to a hex 05. Change the hex 00 to a ; hex 2E (ASCII period). Now write RASM86.CMD back out to the disk. Period is ; now valid for the second and subsequent characters of an identifier. ; ; Now you can assemble this routine, or modify it. ; You MUST use the $nc (no case conversion) switch with RASM86. ; ; Note that the cseg is named 'cinit.' in lower case with a period in it. ; LINK86 puts this particular cseg FIRST in the .CMD file. This means that ; if the compiler does not emit a MOD END (module end) record with a starting ; address, and if no assembly routine contains END START, where START is a ; label, then LINK86 will NOT put five bytes of JMPF (or JMP/NOP/NOP) in the ; file to jump to the START address, and control will come to the initializer. ; LINK86 also puts the dseg 'dinit.' first in the data area of the .CMD file. ; You must use the RASM86 $nc option to assemble; otherwise the names will be ; CINIT. and DINIT., which LINK86 does not treat as special. ; ; This startup routine has been made modular for easy modification. ; There are basically six calls: perform the segment relocation (omitted in ; small model), initialize the stack, initialize the heap, initialize the .CMD ; drive, initialize the zerodivide handler, and call _main which ; parses the command line passed to it, opens the standard files (performing ; I/O redirection), and calls main. ; ; This one startup routine is the common source for all memory models. For ; example, 'retc' assembles to 'ret' in small model and to 'retf' in large model. ; ; The first file, clear.a86, provides the definitions that make model ; independent coding possible. ; nolist ; ; This is a file of definitions written by Craig Franklin and ; Bill Haygood and used throughout CLEAR. ; C32 equ 0 ; Small code model (use 1 for big model) D32 equ 0 ; Small data model (use 1 for big model) CPM equ 1 ; Operating system PCDOS equ 0 ; ; Memory model determined by C32 and D32 defined above. ; Operating System determined by CPM and PCDOS, defined there also. ; ; Model C32 D32 ; ----- --- --- ; Small 0 0 ; Small code, small data ; Compact 0 1 ; Small code, large data ; Medium 1 0 ; Large code, small data ; Large 1 1 ; Large code, large data ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * s t a c k f r a m e o f f s e t s * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; if C32 ;-------------------------------------------------------------- if D32 ;------------------------------------------------------------ ; ARG1 equ 8 ; Offset from ÆBPÅ of caller argument #1 ; ; RAseg equ 6 ; Offset from ÆBPÅ of caller return address segment ; ; RAoff equ 4 ; Offset from ÆBPÅ of caller return address offset ; ; SAVEDS equ 2 ; Offset from ÆBPÅ of caller DS slot ; ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ; ARG1 equ 6 ; Offset from ÆBPÅ of caller argument #1 ; ; RAseg equ 4 ; Offset from ÆBPÅ of caller return address segment ; ; RAoff equ 2 ; Offset from ÆBPÅ of caller return address offset ; ; endif ;------------------------------------------------------------ ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; if D32 ;------------------------------------------------------------ ; ARG1 equ 6 ; Offset from ÆBPÅ of caller argument #1 ; ; RAoff equ 4 ; Offset from ÆBPÅ of caller return address offset ; ; SAVEDS equ 2 ; Offset from ÆBPÅ of caller DS slot ; ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ; ARG1 equ 4 ; Offset from ÆBPÅ of caller argument #1 ; ; RAoff equ 2 ; Offset from ÆBPÅ of caller return address offset ; ; endif ;-----------------------------------------------------------; ; endif ;-------------------------------------------------------------- SAVEBP equ 0 ; Offset from ÆBPÅ of caller BP slot SAVESP equ -2 ; Offset from ÆBPÅ of my own SP slot OVRAseg equ -4 ; Offset from ÆBPÅ of my own true return address segment OVRAoff equ -6 ; Offset from ÆBPÅ of my own true return address offset OVIDoff equ -8 ; Offset from ÆBPÅ of my own overlay index DISPLAY equ -10 ; Offset from ÆBPÅ of my lexical father frame ONLINK equ -12 ; Offset from ÆBPÅ of the previous on-frame ONHEAD equ -14 ; Offset from ÆBPÅ of the first on-unit for this frame ; ; O/S Capability Definitions ; multiuser equ 8000h ; Multi-user capability bit multitasking equ 4000h ; Multi-tasking capability bit. multisector equ 2000h ; Multi-sector I/O capability bit. date..time equ 1000h ; Date/time capability bit. networking equ 0800h ; Networking capability bit. cmdname equ 0400h ; Capability to find .CMD file name is8087 equ 0200h ; 8087 chip is present. em8087 equ 0100h ; 8087 emulator is present and used. ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * m o v e b y t e s * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; MOVEBYTES is a codemacro which generates code to move a string. ; MOVEBYTES logically replaces REP MOVSB except for altering the flags. ; MOVEBYTES takes 5 more bytes and is much faster for large CX. ; Breakeven is about CX = 3, depending on the particular chip. ; ; MOVEBYTES first moves an integral number of words and then moves the ; (odd) last byte, if there is one. Thus MOVEBYTES will run even faster ; if either or both the source and target start on a word boundary. ; ; Assumptions: ; ; CX = number of bytes to be moved ; DS:SI -> source text address ; ES:DI -> destination text address ; codemacro MOVEBYTES db 0d1h ; shr cx,1 db 0e9h db 0f3h ; rep movsw db 0a5h db 073h ; jnc even db 001h db 0a4h ; movsb endm ; even: ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * p a d b y t e s * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; PADBYTES stores the contents of the AX register into the destination. ; PADBYTES exactly replaces REP STOSB except for altering the flags, ; under the assumption that register AH = register AL. ; PADBYTES takes 5 more bytes, and is much faster for large CX. ; Breakeven is about CX = 3, depending on the particular chip. ; ; PADBYTES first stores an integral number of words, and then stores ; the (odd) last byte, if there is one. Thus PADBYTES will run even ; faster if the target is on a word boundary. ; ; Assumptions: ; ; CX = number of copies of (AL) to store. ; ES:DI -> destination text address ; codemacro PADBYTES db 0d1h ; shr cx,1 db 0e9h db 0f3h ; rep stosw db 0abh db 073h ; jnc even db 001h db 0aah ; stosb endm ; even: ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * n i l * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; The NIL macro generates no code and accepts any argument types. ; codemacro NIL src:Db endm codemacro NIL src:Dw endm codemacro NIL src:Eb endm codemacro NIL src:Ew endm codemacro NIL src:S endm ; codemacro NIL dst:Eb,src:Db endm codemacro NIL dst:Eb,src:Rb endm ; codemacro NIL dst:Ew,src:Dw endm codemacro NIL dst:Ew,src:Rw endm codemacro NIL dst:Ew,src:S endm ; codemacro NIL dst:Rw,src:Ew endm ; codemacro NIL dst:S,src:Ew endm ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * c o d e m o d e l d e f i n i t i o n s * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; For large code model (C32 = 1), POPC and PUSHC generate POP and PUSH. ; For small code model (C32 = 0), they generate nothing. ; ; For large code model (C32 = 1), (CALLC,JMPC,RETC) generate (CALLF,JMPF,RETF). ; For small code model (C32 = 0), (CALLC,JMPC,RETC) generate (CALL,JMP,RET). ; if C32 ;-------------------------------------------------------------- CALLC equ CALLF ; For medium and large models. ; JMPC equ JMPF ; POPC equ POP ; PUSHC equ PUSH ; RETC equ RETF ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; CALLC equ CALL ; For small and compact models. ; JMPC equ JMP ; POPC equ NIL ; PUSHC equ NIL ; RETC equ RET ; endif ;-------------------------------------------------------------- ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * d a t a m o d e l d e f i n i t i o n s * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; For large data model (D32 = 1), LDX and LEX generate LDS and LES. ; For small data model (D32 = 0), LDX and LEX generate MOV. ; ; For large data model (D32 = 1), (MOVD,POPD,PUSHD) generate (MOV,POP,PUSH). ; For small data model (D32 = 0), (MOVD,POPD,PUSHD) generate nothing. ; if D32 ;-------------------------------------------------------------- LDX equ LDS ; For compact and large models. ; LEX equ LES ; MOVD equ MOV ; POPD equ POP ; PUSHD equ PUSH ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; LDX equ MOV ; For small and medium models. ; LEX equ MOV ; MOVD equ NIL ; POPD equ NIL ; PUSHD equ NIL ; endif ;-------------------------------------------------------------- ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * f r a m e * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; FRAME creates a stack frame in accordance with the memory model in use. ; For small data model (D32 = 0), it does not "PUSH DS". ; For large data model (D32 = 1), it does. ; If immediate data is specified, it must be less than 128 bytes. ; codemacro FRAME if D32 ;-------------------------------------------------------------- db 01eh ; push ds ; endif ;-------------------------------------------------------------- db 055h ; push bp db 08bh ; mov bp,sp db 0ech endm ; codemacro FRAME imm.data:Db if D32 ;-------------------------------------------------------------- db 01eh ; pushd ds ; endif ;-------------------------------------------------------------- db 055h ; push bp dw 0ec83h ; sub sp,imm.data db imm.data dw 0ec8bh ; mov bp,sp endm ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * u n f r a m e * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; UNFRAME release the stack frame created by FRAME above. ; For small data model (D32 = 0), it does not do a POP DS; ; for large data model (D32 = 1), it does a POP DS before it returns. ; For large code (C32=1) it does a RETF instead of RET. ; codemacro UNFRAME db 05dh ; pop bp if D32 ;-------------------------------------------------------------- db 01fh ; pop ds ; endif ;-------------------------------------------------------------- if C32 ;-------------------------------------------------------------- db 0cbh ; retf ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; db 0c3h ; ret ; endif ;-------------------------------------------------------------- endm ; codemacro UNFRAME imm.data:Db dw 0668dh ; lea sp,imm.dataÆbpÅ db imm.data db 05dh ; pop bp if D32 ;-------------------------------------------------------------- db 01fh ; pop ds ; endif ;-------------------------------------------------------------- if C32 ;-------------------------------------------------------------- db 0cbh ; retf ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; db 0c3h ; ret ; endif ;-------------------------------------------------------------- endm ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * s y s * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; SYS loads the CL register (for CP/M) or AH register (for PCDOS) with ; the system call number specified as an argument and generates a call ; to the operating system. The argument may be an immediate byte value, ; a byte register, or a byte memory address. The ES register is ; preserved for small data model under CP/M. (PCDOS does not alter it.) ; codemacro SYS src:Db if CPM ;-------------------------------------------------------------- db 0b1h ; mov cl,--- ; db src ; if D32 eq 0;-------------------------------------------------------- ; db 06 ; push es ; ; endif ;-------------------------------------------------------- ; db 0cdh ; call cpm ; db 0e0h ; if D32 eq 0;-------------------------------------------------------- ; db 07 ; pop es ; ; endif ;-------------------------------------------------------- ; endif ;-------------------------------------------------------------- if PCDOS ;-------------------------------------------------------------- db 0b4h ; mov ah,--- ; db src ; db 0cdh ; call pcdos ; db 021h ; endif ;-------------------------------------------------------------- endm ; codemacro SYS src:Rb db 08ah ; mov Æah/clÅ,R if CPM ;-------------------------------------------------------------- dbit 5(19h),3(src(0)) ; mov cl,R ; if D32 eq 0;-------------------------------------------------------- ; db 06h ; push es ; ; endif ;-------------------------------------------------------- ; db 0cdh ; call cpm ; db 0e0h ; if D32 eq 0;-------------------------------------------------------- ; db 07h ; pop es ; ; endif ;-------------------------------------------------------- ; endif ;-------------------------------------------------------------- if PCDOS ;-------------------------------------------------------------- dbit 5(1ch),3(src(0)) ; mov ah,R ; db 0cdh ; call pcdos ; db 021h ; endif ;-------------------------------------------------------------- endm ; codemacro SYS src:Eb segfix src db 8ah ; mov ---,qÆbpÅ if CPM ;-------------------------------------------------------------- modrm 1,src ; mov cl,qÆbpÅ ; if D32 eq 0;-------------------------------------------------------- ; db 06h ; push es ; ; endif ;-------------------------------------------------------- ; db 0cdh ; call cpm ; db 0e0h ; if D32 eq 0;-------------------------------------------------------- ; db 07h ; pop es ; ; endif ;-------------------------------------------------------- ; endif ;-------------------------------------------------------------- if PCDOS ;-------------------------------------------------------------- modrm 4,src ; mov ah,qÆbpÅ ; db 0cdh ; call pcdos ; db 021h ; endif ;-------------------------------------------------------------- endm list ;ACF Name 'MINIT' ;ACF Title 'MINIT for DRC V1.11' ;ACF Pagesize 75 ; ; File name: MINIT.A86 ; ; Module name: MINIT ; ; Entry parameters: None. ; ; Return value: None. ; ; Entry point Arguments Function ; ----------- --------- -------- ; m.init None. Initialize the Common Lanugage ; Environment And Runtime (CLEAR). ; Algorithm: ; Relocate the segment references if O/S has not ; (not for small model). ; Initialize the stack. ; Initialize the heap. ; Initialize the command name drive. ; Initialize the 8087 or 8087 emulator (not for DRC). ; Address the command tail and call _main. ; eject ;ACF include CLEAR ; Include CLEAR definitions. ; if C32 eq 0;-------------------------------------------------------------- CGROUP GROUP cinit. ; endif ;-------------------------------------------------------------- ; cinit. cseg ; ;ACF extrn m.init.stack: near ;ACF extrn m.init.heap: near ;ACF extrn m.init.cmd: near ;ACF extrn m.init.hardware.error:near ;ACF extrn m.init.os: near extrn osattr: far extrn _main: far extrn main: far ; public m.init public _exit public m.init.error public m.error ; m.init: if D32 or C32 ;----------------------------------------------------- ;ACF extrn m.init.reloc:near call m.init.reloc ; Eliminate the R command. endif ;----------------------------------------------------- call m.init.stack ; Initialize the stack. call m.init.heap ; Initialize the heap. call m.init.cmd ; Find .CMD drive for overlay manager. call m.init.hardware.error ; Initialize the zero divide handler. call m.init.os ; Find out which version of the operating system. ; ; The following call is for Fortran 77 only, not for DRC. ; if 0 ;-------------------------------------------------------------- extrn m.init.8087: near call m.init.8087 ; Initialize the 8087 or 8087 emulator. endif ;-------------------------------------------------------------- ; Note: above calls can be short because all ; call targets use cinit. cseg in them. callc osattr ; Find O/S attributes. ; mov si,80h ; Offset of command line lodsb ; AL = length of command line. xor ah,ah push ax pushd ds ; Push DS if D32 (large data model) push si callc _main ; _exit: ; if CPM ;---------------------------------------------------------------------- SYS 0 ; Exit to O/S. endif ;---------------------------------------------------------------------- ; if PCDOS;---------------------------------------------------------------------- mov ds,ss:.9 ; DS = original DS from O/S. push word ptr .40h ; Push CS for INT 20 sub ax,ax push ax ; Push IP (= 0) for INT 20 retf ; Return to PCDOS INT 20 instruction ; endif ;---------------------------------------------------------------------- jmpc main ; For debugging. ; m.init.error: ; Near call followed by fatal error message. popd dx pushd cs pushd dx ; m.error: ; Far call followed by fatal error message. pop dx ; DS:DX -> error message text. if D32 eq 0 push cs endif pop ds SYS 9 ; BDOS function 9 prints the error message. jmps _exit ; Return to O/S. ; ; Dummy out _v_reloc_8087 for overlay manager ; public _v_reloc_8087 _v_reloc_8087: retc ; Return ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * D A T A * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; DGROUP GROUP DATA,dinit. ; dinit. dseg ; public offset.8087 ; offset.8087 dw 0 ; Offset from SS: of 8087 reentrant data area. ; MUST BE FIRST IN DATA AREA FOR 8087 EMULATOR. ; dseg ; ;ACF end ;ACF Name 'MINITRELOC' ;ACF Title 'M.INIT.RELOC' ;ACF Pagesize 75 ; ; File name: MINITREL.A86 ; ; Module name: MINITRELOC ; ; Entry parameters: Stack exists. DS:0 -> base page. ; ; Return value: None. ; ; Errors: Must use R command or LINK86 V1.2 with this O/S ; ; Entry point Arguments ; ----------- --------- ; m.init.reloc None. ; ; m.init.reloc.buffer Pointer to null terminated relocation buffer. ; ; _v_reloc_segs Pointer to null terminated relocation buffer. ; Pointer to array of 8 overlay segment bases. ; Byte containing valid target relocation groups. ; ; Function: Relocate segment references in a program/overlay. ; WARNING: program must be linked by LINK86 V1.2. ; eject ;ACF include clear ; Get CLEAR definitions. ; cinit. cseg ; ;ACF public m.init.reloc ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * O F F S E T S F R O M B P * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; OSDS equ 2 ; Original DS from OS -> base page. ; equ 0 ; Caller BP SIDI equ -4 ; Space to save SI and DI. loadsegs equ SIDI-2 ; Mask of segments to relocate. overbases equ loadsegs -16 ; 8 group bases from overlay header. reloc.return equ overbases-2 ; Return address for reloc.buffer rootbases equ reloc.return-16 ; 8 group bases from program base page. ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * m . i n i t . r e l o c * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ;ACF extrn m.init.error: near ; m.init.reloc: mov cx,seg m.init.reloc ; Get a relocatable segment reference. jcxz need_relocation ; Relocation done already ? ret ; Yes, return to caller. ; need_relocation: mov cx,.45 ; CX = Aux Group 4 base address. jcxz old_LINK86 ; If 0, must be LINK86 before V1.2 ; ; Relocate the root using Aux Group 4 ; push es ; Save caller ES. push ds ; Save caller DS. push bp ; Save caller BP. mov bp,sp ; Create new stack frame. mov ax,-1 ; AX = ffffh = LOADSEGS = relocate all segments. push ax ; Pretend to save SI and DI push ax ; to synchronize with _v_reloc_segs. push ax ; Push LOADSEGS = ffffh call pushbase ; Push the group start addresses. mov ds,cx ; DS:SI-> AUX GROUP 4 sub si,si call reloc.buffer ; Do it all in only one call. mov sp,bp ; Reset SP. pop bp ; Restore caller BP. pop ds ; Restore caller DS. pop es ; Restore caller ES. ret ; Return to caller. ; old_LINK86: call m.init.error db 'You must link with LINK86 V1.2 or later.',0dh,0ah,'$' ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * _ v_ r e l o c * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; ; +2 below for PUSH SS:.9 BUFFER equ ARG1+2 ; Offset from ÆBPÅ of buffer address. OVERBASE equ BUFFER +2+2*D32; Offset from ÆBPÅ of overlay bases. LOADSEGS equ OVERBASE+2+2*D32; Offset from ÆBPÅ of valid targets. ; public _v_reloc_segs ; _v_reloc_segs: pushd ds ; Save caller DS push ss:word ptr .9 ; Push original DS from O/S. push bp ; Save caller BP mov bp,sp ; Address argument. push si ; Save caller SI. push di ; Save caller DI. push word ptr LOADSEGSÆbpÅ ; Push loadsegs for reloc.buffer. ; ; Push the overlay group start addresses ; ldx si,OVERBASEÆbpÅ ; DS:SI -> overlay bases from caller. ; TEMPORARY -- must always do this for large model. Must TEMPORARILY do it ; for small model until ES is always = SS. Uncomment if/endif when true. ;if D32 ;-------------------------------------------------------------- push ss ; ES:DI -> stack frame overlay bases. pop es ;endif ;-------------------------------------------------------------- lea di,overbasesÆbpÅ mov sp,di ; Allocate space mov cx,8 ; 8 groups rep movsw ; ; Relocate the buffer ; ldx si,BUFFERÆbpÅ ; DS:SI -> relocation buffer call reloc.buffer ; Process the relocation buffer lea sp,0-4ÆbpÅ ; Reset SP. pop di ; Restore caller DI. pop si ; Restore caller SI. pop bp ; Restore caller BP. pop cx ; Pop off original DS from O/S. popd ds ; Restore caller DS. retc eject ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * Subroutine to push the base page group start addresses * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; pushbase: pop bx ; BX = return address. mov dx,ds ; DX = caller DS. mov ds,OSDSÆbpÅ ; DS from O/S, points to base page. push word ptr .45 push word ptr .39 push word ptr .33 push word ptr .27 push word ptr .21 push word ptr .15 push word ptr .09 push word ptr .03 ; mov ds,dx ; DS = caller DS. push bx ret ; Return eject ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * P R O C E S S O N E R E L O C A T I O N B U F F E R * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; Register usage: ; ; (AX) Temporary. ; (BX) Byte offset in paragraph. ; (CX) Shift count. ; (DX) Segment base to add to memory. ; (DI) Temporary. ; (BP) Frame pointer to address loadsegs byte and two base tables ; (DS:SI) Relocation buffer entry. ; (ES:BX) Memory word to relocate. ; reloc.buffer: call pushbase ; Push the root base addresses. push si ; Save caller SI. sub ax,ax ; AX = 0 (for first LODSB). sub cx,cx ; CX = 0. jmps reloc.element.into ; Jump into loop. ; reloc.element.loop: ; ; Set DX = source group base ; sub al,11h ; Convert 1-8/1-8 to 0-7/0-7. mov di,ax ; DI = AX. and di,0007h ; DI = source group number (0-7). add di,di ; DI = source group number * 2. mov dx,rootbasesÆdi+bpÅ ; DX = source group base. ; ; Set DI = target group base ; and al,70h ; AX = target group number * 16. shr al,1 ; AX = target group number * 8. shr al,1 ; AX = target group number * 4. shr al,1 ; AX = target group number * 2. mov di,ax ; DI = target group number * 2. mov di,overbasesÆdi+bpÅ ; DI = target group base. ; ; Set BL = byte with a 1 bit in it for the target group ; shr al,1 ; AX = target group number * 1. mov cl,al ; CX = target group number. mov bl,1 ; BL = 1 for shift shl bl,cl ; BL = mask with 1 for target segment ; ; Compute address of memory word to add DX to ; lodsw ; AX = paragraph offset of memory word add di,ax ; DI = segment base of memory word mov es,di ; ES = DI sub ax,ax ; Clear AX for LODSB. lodsb ; AL = byte offset of memory word test bl,loadsegsÆbpÅ ; OK to relocate target segment? jz reloc.element.into ; No. mov bx,ax ; BX = byte offset add es:ÆbxÅ,dx ; Relocate memory word. ; reloc.element.into: lodsb ; AL = group number test al,0f0h ; End of buffer or fixup list ? jnz reloc.element.loop ; No. ; sub ax,ax ; Assume return false (done). pop bx ; BX = input SI sub si,bx ; SI = number of bytes processed. sub si,129 ; Full buffer processed? jnz reloc.element.return ; No, return 0 (last buffer). inc ax ; Yes, return 1 (more to come). ; reloc.element.return: if D32 eq 0;-------------------------------------------------------------- push ss ; Reset ES = SS for small model. pop es endif ;-------------------------------------------------------------- lea sp,reloc.returnÆbpÅ ; Prepare to return. ret ; Return. ; ;ACF end ;ACF Name 'MINITSTACK' ;ACF Title 'M.INIT.STACK' ;ACF Pagesize 75 ; ; File name: MINITSTA.A86 ; ; Module name: M.INIT.STACK ; ; Entry parameters: None. ; ; Return value: None. ; ; Entry point Arguments Function ; ----------- --------- -------- ; ; m.init.stack None. Initialize the CLEAR stack. ; ; _salloc int n Allocate n bytes on the stack. ; ; Algorithm: With interrupts disabled (to allow for the ; defective versions of the 8088), set SS:SP, SL. ; ; Small model: Set SS = DS. Set SP from .6, ; the top of the DGROUP. ; SL. = HP. in minithea.a86. ; ; Large model: Set SS:SP from the base page. ; SL. is assembled in. ; eject ;ACF include clear ; Get CLEAR definitions. ; if C32 eq 0;-------------------------------------------------------------- CGROUP GROUP cinit. ; endif ;-------------------------------------------------------------- ; cinit. cseg ; ;ACF extrn m.init.error: near ; public m.init.stack, _salloc ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * M . I N I T . S T A C K * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; m.init.stack: pop ax ; Pop m.init return address. pop cx ; Pop system return address (this is a pop dx ; 32-bit address even in small model!). ; ; Disable interrupts to set SS:SP. ; sub bx,bx ; BX = 0 if D32 ;-------------------------------------------------------------- pushf pop si ; Save current status and flags. cli ; Disable interrupts. mov ss,15hÆbxÅ ; Setup stack segment register. mov sp,12hÆbxÅ ; Set stack offset. ; SL. is already set by assembly. push si popf ; Restore status and flags else push ds ; SS = DS pushf pop si ; Save current status and flags. cli ; Disable interrupts. pop ss mov sp,6ÆbxÅ ; Initialize SP from base page. ; SL. is defined equ HP. (minithea.a86) push si popf ; Restore status and flags endif ;-------------------------------------------------------------- inc sp ; Use all available allocated memory. and sp,0fffeh ; Align for iAPX-286 speed. eject ; ; Now construct the first stack frame. ; push dx ; Push system return address (this is a push cx ; 32-bit address even in small model!). push bx ; No previous stack frame. mov bp,sp ; Establish the first stack frame. lea dx,-8ÆbpÅ ; First stack frame is 8 words long. push dx ; Set SAVESP push bx ; Set ENLINK = 0 (no previous environment) push bx ; Set ONLINK = 0 (no previous on frame) push bx ; Set ONFRAME = 0 (no on units in frame) push ax ; Push m.init return address if D32 ;-------------------------------------------------------------- mov ss:.0,ds ; For large model to load for big model endif ;-------------------------------------------------------------- mov ss:.9,ds ; All memory models can now use ss:.9! ret ; Return. ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * _ s a l l o c * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; _salloc: ; Allocate N bytes on the stack. pop bx ; Pop return address. popc cx pop dx ; Pop N. inc dx ; Round N to even. and dl,0feh if D32 ;-------------------------------------------------------------- mov ax,seg SL. mov es,ax mov ax,dx ; AX = N. add ax,es:SL. ; AX = SL. + N else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; mov ax,dx ; AX = N. add ax,SL. ; AX = SL. + N endif ;-------------------------------------------------------------- cmp ax,sp ; Would stack overflow? jbe stackok ; No. call m.init.error ; Yes, fatal error. db 'Stack overflow$' ; stackok: sub sp,dx ; Allocate N bytes. mov ax,sp ; SS:AX -> N bytes on stack. push dx ; Push N. pushc cx ; Push return address push bx if D32 ;-------------------------------------------------------------- mov bx,ss ; BX = SS for large model return value. endif ;-------------------------------------------------------------- retc ; Return BX:AX -> N bytes on stack. eject if D32 ;-------------------------------------------------------------- ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * D A T A * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; DGROUP GROUP dinit. ; dinit. dseg ; public SL. ; SL. dw 14 ; Stack limit. Bias of 14 is for string routines. ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * S T A C K S T O R A G E A L L O C A T I O N * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; sinit. sseg word ; ; ; dw 0 ; Old OSDS -- TEMPORARY. ; rb 7 ; DSOS dw 0 ; DS value from O/S. ; ; Large model -- ss:.9 is here. ; ; Small model -- ss:.9 is base page ; ; stack. sseg word ; ; ; public ONFRAME ; Wait for PL/I to implement this. ; ; ; ;ONFRAME dw 0 ; ; dw seg ONFRAME ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ;ACFDGROUP GROUP dinit. ;ACFdinit. dseg ;ACF extrn SL.:word endif ;-------------------------------------------------------------- ; ;ACF end ;ACF Name 'MINITHEAP' ;ACF Title 'M.INIT.HEAP' ;ACF Pagesize 75 ; ; File name: MINITHEA.A86 ; ; Module name: MINITHEAP ; ; Entry point Arguments Function ; ----------- --------- -------- ; ; m.init.heap None. Initialize the heap. ; ; nbrk None Return the remaining ; heap size in bytes. ; Return (long)(HL.-HP.) ; ; sbrk int n Extend the heap n bytes. ; If HP. + n <= HL., ; set HP. = HP. + n ; ; brk char *p If HP. <= p <= HL., ; set HP. = p ; ; Algorithm: ; ; m.init.heap: ; ; Large: Set HP. to point to ESEG. ; Set HL. to point to HP. + size of ESEG. ; ; Small: Set HP. to point to the heap at the bottom of ; the free area. The stack is located at the top of the ; free area. Equivalence HL. and SL., the stack limit. ; ; nbrk: Set R = HP. - HL., if D32 set R *= 16, return R. ; ; sbrk: Round request r to bytes or paragraphs, set R = P = HP., ; set P = P+r, if P <= HL., set HP. = R and return R. ; ; brk: Compare pointer argument P to HP. and HL. ; If P >= HP. and P <= HL., set HP. = P, and ; return 0 (success), else return -1 (failure). ; ; In all of the above routines, HP. and HL. are one word ; pointers into the heap whose units are paragraphs. ; When sbrk returns the old HP., it is converted to a ; pointer with offset 0 in the large model. ; This is so the caller can use a full 64K byte offset with it. ; eject ;ACF include clear ; Get CLEAR definitions. ; if D32 eq 0;-------------------------------------------------------------- slack equ 256 ; Allow for additional stack. endif ;-------------------------------------------------------------- ; cinit. cseg ; public m.init.heap, nbrk, sbrk, brk ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * m . i n i t . h e a p * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; m.init.heap: if D32 ;-------------------------------------------------------------- mov HP.,es ; Initialize HP. (LINK86 bug). mov ax,.0ch ; AX = low word of Extra Segment size. mov dh,.0eh ; DH = high byte of Extra Segment size. add ax,15 ; Convert offset to paragraphs. jnc m.init.heap.nc ; Jump if not 64K boundary. inc dh ; 64K boundary. Increment high order. ; m.init.heap.nc: and al,0f0h ; Round bytes to paragraphs. mov cl,4 ; CL = 4 shr ax,cl ; Convert to paragraph number. shl dh,cl ; Convert to paragraph number. add ah,dh ; AX = paragraph number of heap size add ax,HP. ; AX = paragraph number of heap limit mov HL.,ax ; Set heap limit else push ds ; ES = DS pop es mov ax,?MEMRY ; Set up heap for brk(). add ax,15 and ax,0fff0h ; Paragraph align. mov HP.,ax endif ;-------------------------------------------------------------- ret eject ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * n b r k * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ;LONG nbrk() /* CLEAR FUNCTION ***********/ nbrk: if D32 ;-------------------------------------------------------------- mov ax,seg HP. ; AX = seg HP. mov es,ax ; Set ES = seg HP. mov ax,es:HL. ; AX = heap limit. sub ax,es:HP. ; AX = heap size = heap limit - heap base. mov bx,16 mul bx ; Convert paragraphs to long int bytes. mov bx,dx ; In AX/BX. retc ; Return. else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; mov ax,sp ; AX = heap limit. sub ax,slack ; Allow for additional stack. sub ax,HP. sub bx,bx ; Return long int bytes. retc ; Return. endif ;-------------------------------------------------------------- ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * s b r k * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ;BYTE * sbrk(Num) /* CLEAR FUNCTION ***********/ sbrk: if D32 ;-------------------------------------------------------------- mov bx,sp ; Address argument mov dx,ss:2+2*C32ÆbxÅ ; Get allocation size in bytes. add dx,15 ; Round up to next paragraph. and dl,0f0h mov cl,4 ; CL = 4 shr dx,cl ; Convert bytes to paragraphs push ds ; Save caller DS (large model) mov bx,seg HP. ; BX = DS of HP. mov ds,bx ; Set DS mov bx,HP. ; BX = old heap pointer (in paragraphs) sub ax,ax ; BX:AX = old HP.:0 = pointer to area add dx,bx ; DX = new heap pointer (in paragraphs) cmp dx,HL. ; Will it fit ? ja xbrk.fail ; No. Fail. mov HP.,dx ; Update HP. pop ds ; Restore original DS. retc ; Return BX:AX = old HP.:0. ; xbrk.fail: ; Set AX = -1 (failure) and return. mov ax,-1 ; AX = -1 mov bx,ax pop ds ; Restore original DS. retc ; Return. ; else mov bx,sp ; BX = SP mov bx,ss:2+2*C32ÆbxÅ ; Get argument. inc bx ; Round up to even byte boundary. and bl,0feh mov ax,HP. ; Get current heap pointer. add bx,ax ; Did wrap around occur ? jc xbrk.fail ; Yes. jmps xbrk ; xbrk.fail: ; Set AX = -1 (failure) and return. mov ax,-1 ; AX = -1 ret ; Return. endif ;-------------------------------------------------------------- eject ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * b r k * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ;BYTE * brk(HeapPtr) /* CLEAR FUNCTION ***********/ brk: if D32 ;-------------------------------------------------------------- mov bx,sp ; BX = SP push ds ; Save caller DS (large model) mov ax,ss:2+2*C32ÆbxÅ ; AX = pointer offset mov bx,ss:4+2*C32ÆbxÅ ; BX = pointer segment add ax,15 ; Round AX from bytes to paragraphs jnc brk.ok ; Carry ? add bx,1000h ; Yes, add 64K bytes to segment. ; brk.ok: mov cl,4 ; CL = 4 shr ax,cl add ax,bx ; And add in segment cmp ax,HP. ; Below current heap pointer? jb xbrk.fail ; Yes. Fail. cmp ax,HL. ; Above heap limit? ja xbrk.fail ; Yes. Fail. mov HP.,ax ; Reset heap pointer sub ax,ax ; Succeed. pop ds ; Restore caller DS else mov bx,sp mov bx,ss:2+2*C32ÆbxÅ ; Get parameter - brk address. sub ax,ax ; AX = 0 for success ; xbrk: mov cx,sp ; CX = SP sub cx,slack ; Allow for additional stack. cmp bx,cx ; Below stack pointer ? jae xbrk.fail ; No. cmp bx,HP. ; Above heap pointer ? jb xbrk.fail ; No. mov HP.,bx ; Set new heap pointer. endif ;-------------------------------------------------------------- retc ; Return. eject ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * D A T A * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; DGROUP GROUP dinit. dinit. dseg ; if D32 ;-------------------------------------------------------------- HP. dw 0 ; Heap pointer in paragraphs. ; HL. dw 0 ; Heap limit in paragraphs. ; ; ; (Set by m.init.heap.) ; heap. eseg ; ; ; ES. rw 0 ; else ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; public ?MEMRY, HP., SL. ; ?MEMRY rw 1 ; Initialized by LINK86. ; HP. rw 1 ; Heap pointer in bytes. ; SL. equ HP. ; Is also stack limit in bytes. ; endif ;-------------------------------------------------------------- ; ;ACF end ;ACF Name 'MINITCMD' ;ACF Title 'M.INIT.CMD' ;ACF Pagesize 75 ; ; File name: MINITCMD.A86 ; ; Module name: MINITCMD ; ; Arguments: None. ; ; Return value: _cmd_drive_bin .CMD drive in binary ; _cmd_drive_asc .CMD drive in ASCII ; ; Function: To determine the .CMD file drive. ; ; Algorithm: Look at location 50h in the base page. ; If it is non-zero, it is the binary .CMD drive. ; If it is zero, get the current drive from BDOS. ; In either case, add 'A' to get the ASCII drive. ; eject ;ACF include clear ; Get CLEAR definitions. ; curdrive equ 25 ; BDOS call to return current drive. ; if C32 eq 0;-------------------------------------------------------------- CGROUP GROUP cinit. ; endif ;-------------------------------------------------------------- ; cinit. cseg ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * m . i n i t . c m d * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; public m.init.cmd ; m.init.cmd: ; if CPM ;-------------------------------------------------------------- SYS 12 ; get O.S. version number cmp ah,11h ; MPM-86? jne m.aft.os.check ; nope inc byte ptr .50h ; fix for MPM m.aft.os.check: ; mov al,.50h ; AL = CMD drive number (1 to 16 or 0) test al,al ; Special CMD drive = 0 case? jz m.init.cmd.current.drive; Yes. dec al ; AL = 0 to 15. cmp al,15 ; 1 <= CMD drive <= 16 case? jbe m.init.cmd.drive ; Yes, trust it. endif ;-------------------------------------------------------------- m.init.cmd.current.drive: ; Use system current drive: SYS curdrive ; AL = 0 to 15 for A to P. ; m.init.cmd.drive: mov _cmd_drive_bin,al ; Store drive in binary. add al,'A' ; Convert it to ASCII. mov _cmd_drive_asc,al ; Store drive in ASCII. ret ; Return. ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * D A T A * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; DGROUP GROUP _CMD_DRIVE_BIN,_CMD_DRIVE_ASC ; _CMD_DRIVE_BIN dseg common public _cmd_drive_bin _cmd_drive_bin db 0 ; _CMD_DRIVE_ASC dseg common public _cmd_drive_asc _cmd_drive_asc db 0 ; ;ACF end ;ACF Name 'MINITERROR' ;ACF Title 'M.INIT.ERROR' ;ACF Pagesize 75 ; ; File name: MINITER.A86 ; ; Module name: MINITERROR ; ; Entry parameters: None. ; ; Return value: None. ; ; Entry point Arguments ; ----------- --------- ; ; m.init.hardware.error None. ; ; Function: To initialize the runtime system integer zero ; divide error handler. ; ; Algorithm: Place the vector to the integer zero divide ; handler in absolute location 0:0. ; eject ;ACF include clear ; Get CLEAR definitions. ; if C32 eq 0;-------------------------------------------------------------- CGROUP GROUP cinit. ; endif ;-------------------------------------------------------------- ; cinit. cseg ; ;ACF extrn m.init.error: near ; public m.init.hardware.error ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * m . i n i t . h a r d w a r e . e r r o r * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; Initialize the zero divide vector. ; m.init.hardware.error: push ds ; Save original DS. sub bx,bx ; BX -> offset 0 mov ds,bx ; DS = 0 mov ÆbxÅ,offset zerodiv ; Store the zero divide handler pointer mov 2ÆbxÅ,cs ; at hardware locations 0 and 2. pop ds ; Restore original DS. ret ; Return. ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * z e r o d i v * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; Integer zero divide handler. ; zerodiv: call m.init.error ; Fatal error db 'Zero divide error$' ; ;ACF end ;ACF Name 'M.INIT.OS' ;ACF Title 'M.INIT.OS' ;ACF Pagesize 75 ; ; File name: MINITOS.A86 ; ; Module name: M.INIT.OS ; ; Arguments: None. ; ; Return value: _os_version = 0 (unrecognized OS) ; = 1 - 21h (non-CP/M OS's) ; = 22h (CP/M-86 v. 2.2) ; = 23h (MP/M-86 v. 3.0) ; = 24h (CCP/M-86 v. 3.0) ; ; _os_ability = inclusive OR of: ; 8000h (multi-user) ; 4000h (multi-tasking) ; 2000h (multi-sect I/O) ; 1000h (date/time) ; 0800h (networking) ; 0400h (cmd name available) ; 0200h (8087 is present) ; ; Entry Point Arguments ; ----------- --------- ; m.init.os None ; ; Function: To determine the OS version and capabilities. ; ; Algorithm: Call the operating to obtain the OS ; type/version and the date/time, if present. ; ; Attributes: OSIF (O/S interface routine) ; eject ;ACF include clear ; Get CLEAR definitions. ; version equ 12 ; BDOS call to return version. date.time equ 105 ; BDOS call to return date/time. ; if C32 eq 0;-------------------------------------------------------------- CGROUP GROUP cinit. ; endif ;-------------------------------------------------------------- ; cinit. cseg ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * m . i n i t . o s * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; public m.init.os ; m.init.os: if PCDOS;-------------------------------------------------------------- ret ; Proper attributes are assembled in. ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * D A T A * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; DGROUP GROUP _OS_ABILITY,_OS_VERSION ; _OS_ABILITY dseg common public _os_ability _os_ability dw multisector+date..time ; _OS_VERSION dseg common public _os_version _os_version db 0 ; endif ;-------------------------------------------------------------- ; if CPM ;-------------------------------------------------------------- ; ; Determine whether the operating system supports date/time. ; pushd ds ; Save caller DS. pushd ss popd ds sub sp,4 ; Allocate space for date/time. mov dx,sp SYS date.time add sp,4 ; Free date/time space. popd ds ; Restore caller DS. inc ax ; AX = -1? (No date/time). jz m.init.os.notime ; Yes. sub ax,ax ; AX = 0. or ax,date..time ; Set the date/time capability bit. ; m.init.os.notime: ; ; Get the O/S version ; push ax SYS version ; Get the O/S version in BX pop ax cmp bx,22h ; Is the version less than 22h ? jb m.init.os.found ; Yes. ; ; Determine whether the operating system supports networking. ; test bh,2 ; Is networking available ? jz m.init.os.nonet ; No. or ax,networking ; Yes, set its capability bit. xor bh,2 ; Turn networking bit off. ; m.init.os.nonet: mov cx,0022h ; Start with CP/M-86 BDOS version 2.2 or ax,cmdname ; CP/M has cmdname capability test bh,bh ; CP/M-86 ? jz m.init.os.found ; Yes. xor ax,cmdname ; But MP/M and CCP/M do not. inc cl ; No, try for MP/M-86. or ax,multiuser+multitasking+multisector ; Yes, set MP/M-86 capabilities. cmp bh,1 ; MP/M-86 ? je m.init.os.found ; Yes. inc cl ; Try for CCP/M-86 (CX = 24h). xor ax,multiuser ; CCP/M-86 lacks multiuser of MP/M. cmp bh,14h ; CCP/M-86 ? je m.init.os.found ; Yes. sub cx,cx ; Unrecognized operating system. ; jmps m.init.os.found ; Join common code. ; m.init.os.found: mov _os_version,cl ; Store O/S version byte. mov _os_ability,ax ; Store O/S ability word. ret ; Return. ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * D A T A * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; DGROUP GROUP _OS_ABILITY,_OS_VERSION ; _OS_ABILITY dseg common public _os_ability _os_ability dw 0 ; _OS_VERSION dseg common public _os_version _os_version db 0 ; endif ;-------------------------------------------------------------- end «eof»