home *** CD-ROM | disk | FTP | other *** search
- page 78,132
- title Monitor for IBM PC by Tim Paterson
-
- include dos.inc
-
- ;System equates
-
- BreakVect = 1BH
- TermAddr equ word ptr 0AH
- PROMPT = ">"
-
- ExecBlock struc
-
- Environment dw 0 ;Pass on parent's environment
- CommandTail dw 80H
- CommandTailSeg dw 0
- FCB1 dw 5CH
- FCB1Seg dw 0
- FCB2 dw 6CH
- FCB2Seg dw 0
- InitSp dw 0
- InitSs dw 0
- InitIp dw 0
- InitCs dw 0
-
- ExecBlock ends
-
- .model small
- .code
- .data
- Strings segment byte public
- Strings ends
- InitSeg segment public
- InitSeg ends
- LastSeg segment byte
- ret ;End of init code
- LastSeg ends
-
- DGroup group _TEXT,_DATA,Strings,InitSeg,LastSeg
-
- .data
-
- public AxSave,BxSave,SpSave,SsSave,DsSave,CsSave,IpSave,FlSave
- public BpSave,SiSave,DiSave,TestPSP
-
- extrn LineBuf:byte, TCount:word
-
- ExecFile ExecBlock<,DGroup:LineBuf>
- TestPSP dw 0
- NextInt15 dd 0
-
- ALIGN 2
- dw 80H dup(?) ;Working stack area
- STACK label word
- ;Register save area
- AxSave dw ?
- BxSave dw ?
- CxSave dw ?
- DxSave dw ?
- SpSave dw ?
- BpSave dw ?
- SiSave dw ?
- DiSave dw ?
- DsSave dw ?
- EsSave dw ?
- SsSave dw ?
- CsSave dw ?
- IpSave dw ?
- FlSave dw ?
-
- ;Start of Monitor code
-
- .code
- assume cs:DGroup,ds:DGroup,es:DGroup,ss:DGroup
-
- public Monitor, Command, Error, PrintAbort, PErr, ErrMes
-
- extrn InBuf:near, OutCh:near, CrLf:near, PrintMes:near, ScanB:near
- extrn Tab:near, ReEnter:near
-
- org 100H
-
- Monitor:
- cld
-
- IFDEF DEBUG
- ;Copy psp
- xor si,si
- mov di,si
- push cs
- pop es
- mov cx,100H/2
- rep movsw
- push cs
- pop ds
- push cs
- pop ss
- ENDIF ;DEBUG
-
- mov sp,offset DGroup:Stack
- DOS Version,0
- cmp al,3 ;Version OK?
- jae VersionOK
- ;Bad version. Terminate in a DOS 1.0-compatible way
- DOS Print,,<offset DGroup:BadVersionMsg>
- int 20H
-
- VersionOK:
- call Init
- mov si,offset DGroup:Header
- call PrintMes
- ;Load file for debugging
- mov ax,cs
-
- IFDEF DEBUG
- sub ax,10H ;Get to true PSP
- mov es,ax
- ENDIF ;DEBUG
-
- mov bx,[CsSave] ;First segment to free
- sub bx,ax ;Compute paragraphs we're keeping
- DOS ResizeMem
-
- IFDEF DEBUG
- push cs
- pop es
- ENDIF ;DEBUG
-
- mov si,80H ;Point to command line in PSP
- lodsb ;Get length byte
- cbw
- xchg cx,ax ;Put length in cx
- call ParseFile
- mov si,dx
- cmp byte ptr [si],0 ;Was there a file name?
- jz Command
- mov [AxSave],ax
- mov [ExecFile].CommandTailSeg,ds
- mov [ExecFile].FCB1Seg,ds
- mov [ExecFile].FCB2Seg,ds
- mov bx,offset DGroup:ExecFile
- DOS Exec,1 ;Load, don't execute
- jc NoFileLoad
- mov ax,[ExecFile].InitIp
- mov [IpSave],ax
- mov ax,[ExecFile].InitCs
- mov [CsSave],ax
- mov ax,[ExecFile].InitSp
- mov [SpSave],ax
- mov ax,[ExecFile].InitSs
- mov [SsSave],ax
- DOS GetPSP
- mov [DsSave],bx ;DS = ES = PSP
- mov [EsSave],bx
- mov es,bx
- mov es:[TermAddr],offset DGroup:ProgTerminate
- mov es:[TermAddr+2],cs ;Terminate address now set
- mov [TestPSP],bx
- mov bx,cs
-
- IFDEF DEBUG
- sub bx,10H ;True PSP
- ENDIF ;DEBUG
-
- DOS SetPSP ;Change back to our own PSP
- Command:
- ;Re-establish initial conditions
- cld
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,offset DGroup:STACK
- sti
- MOV AL,PROMPT
- CALL OutCh
- CALL INBUF ;Get command line
- ;From now and throughout command line processing, SI points
- ;to next character in command line to be processed.
- CALL SCANB ;Scan off leading blanks
- JZ COMMAND ;Null command?
- LODSB ;AL=first non-blank character
- ;Prepare command letter for table lookup
- SUB AL,"B" ;Low end range check
- JC ERR1
- CMP AL,"U"+1-"B" ;Upper end range check
- JNC ERR1
- SHL AL,1 ;Times two
- CBW ;Now a 16-bit quantity
- XCHG BX,AX ;In BX we can address with it
- CALL [BX+COMTAB] ;Execute command
- jmp Command ;Get next command
-
- NoFileLoad:
- mov si,offset DGroup:FileErrMsg
- jmp PrintAbort
-
- ERR1: JMP PERR
-
- BadVersionMsg db "Invalid DOS--version 3 or later required$"
- Header db 13,10,"IBM-PC Monitor 1.0",13,10+80H
- SYNERR db '^'
- ERRMES db " Error",13,10+80H
- ProgEndMsg db 13,10,"Program terminated",13,10+80H
- FileErrMsg db "Error loading file",13,10+80H
-
- ;Ctrl-BREAK handler. Allows program abort.
- Interrupt:
- MOV AL,20H ;End of interrupt command
- OUT 20H,al ;Send to 8259A
- mov al,0AEH ;Enable keyboard
- out 64H,al ;Send to keyboard
- MOV AL,"^"
- CALL OutCh
- MOV AL,"C"
- CALL OutCh
- call CRLF
- jmp Command
-
- SysReq:
- cmp ax,8500H ;Sys Req key pressed?
- jnz ChainInt15
- mov cs:[TCount],1 ;Stop step mode
- jmp ReEnter
-
- ChainInt15:
- jmp cs:[NextInt15]
-
- ;Command Table. Command letter indexes into table to get
- ;address of command. PERR prints error for no such command.
-
- DwExt Macro lab
- extrn lab:near
- dw offset DGroup:lab
- EndM
-
- COMTAB label word
- DW PERR ;B
- DwExt COMPARE ;C
- DwExt DUMP ;D
- DwExt ENTER ;E
- DwExt FILL ;F
- DwExt GO ;G
- DW PERR ;H
- DwExt INPUT ;I
- DW PERR ;J
- DW PERR ;K
- DW PERR ;L
- DwExt MOVE ;M
- DW PERR ;N
- DwExt OUTPUT ;O
- DW PERR ;P
- DW Quit ;Q
- DwExt REG ;R
- DwExt SEARCH ;S
- DwExt TRACE ;T
- DwExt UnAssemble ;U
-
- ParseFile:
- ;Find start and end of file name
- ;Inputs:
- ; ds:si = pointer to input string
- ; cx = length of string
- ;Outputs:
- ; ax = Starting value for ax (drive validity flags)
- ; dx = File name to execute, zero-terminated
-
- mov bx,si ;Save initial pointer
- call ScanB
- mov dx,si ;Save starting address
- call FindNameEnd
- sub bx,si
- neg bx ;Amount scanned so far
- sub cx,bx ;Amount remaining in string
- mov bx,si ;Save end of name--start of args
- mov di,offset DGroup:LineBuf+1
- mov [di-1],cl ;Put length in first byte
- inc cx ;Copy terminating CR
- rep movsb ;Copy to argument buffer
- mov si,bx ;Restore start of args
- mov di,5CH ;First FCB
- DOS ParseName,1 ;Parse file name, scan off blanks
- cbw ;0FFH if invalid drive
- and al,ah ;Make sure al is zero or one
- xchg cx,ax ;Save return value in cl
- call FindNameEnd ;Skip over any "\" chars
- mov di,6CH ;Second FCB
- DOS ParseName,1 ;Parse file name, scan off blanks
- cbw ;0FFH if invalid drive
- and ah,al ;Make sure ah is zero or one
- mov al,cl
- mov byte ptr [bx],0 ;Zero terminate file name
- ret
-
- FindNameEnd:
- lodsb
- cmp al," " ;Check for blank or control char
- jbe NameEnd
- cmp al,","
- jz NameEnd
- cmp al,";"
- jz NameEnd
- cmp al,"/"
- jnz FindNameEnd
- NameEnd:
- dec si ;Point back at terminator
- ret
-
-
- ;Command error. SI has been incremented beyond the
- ;command letter so it must decremented for the
- ;error pointer to work.
-
- PERR:
- DEC SI
-
- ;Syntax error. SI points to character in the input buffer
- ;which caused error. By subtracting from start of buffer,
- ;we will know how far to tab over to appear directly below
- ;it on the terminal. Then print "^ Error".
-
- ERROR:
- SUB SI,offset DGroup:LINEBUF-1 ;How many char processed so far?
- MOV CX,SI ;Parameter for TAB in CX
- CALL TAB ;Directly below bad char
- MOV SI,offset DGroup:SYNERR ;Error message
-
- ;Print error message and abort to command level
-
- PrintAbort:
- CALL PRINTMES
- JMP COMMAND
-
- ;************************************************************
- ; "Q" - Quit
-
- ProgTerminate:
- ;TestPSP = our own PSP if we are terminating the child in order to quit
- ;Monitor (suppress "program terminated" message).
- push cs
- pop ds
- mov bx,cs
-
- IFDEF DEBUG
- sub bx,10H ;True PSP
- ENDIF ;DEBUG
-
- mov ax,bx
- xchg bx,[TestPSP] ;Set to our own PSP to show no child
- cmp ax,bx ;Do we have a child?
- jz JustExit
- mov si,offset DGroup:ProgEndMsg
- jmp PrintAbort ;Print message, get next command line
-
- Quit:
- ;We must end child first. If no child, TestPSP = our own PSP, so we'll
- ;just terminate directly. If there is a child, set TestPSP to our own PSP
- ;as a flag to ProgTerminate to suppress "program terminated" message.
- mov bx,cs
-
- IFDEF DEBUG
- sub bx,10H ;True PSP
- ENDIF ;DEBUG
-
- xchg bx,[TestPSP]
- DOS SetPSP
- JustExit:
- lds dx,[NextInt15]
- DOS SetVect,15H
- mov ax,76*100H + 0 ;Terminate, no error
- int 21H
-
- ;************************************************************
- ;
- ;Initialization code
- ;
- ;Each module can have its own initialization code. The module simply
- ;puts the code in InitSeg. All InitSegs are combined end-to-end,
- ;thus executing the init code for each module. The RET instruction in
- ;LastSeg, immediately following InitSeg, returns program flow back to
- ;the caller of Init.
- ;
- ;All this code is thrown away when memory is resized.
-
- InitSeg segment
- assume cs:DGroup,ds:Dgroup
-
- Init:
- ;one-time register initialization
- DOS SetVect,BreakVect,<offset DGroup:Interrupt>
- DOS GetVect,15H
- mov word ptr [NextInt15],bx
- mov word ptr [NextInt15+2],es
- push ds
- pop es
- DOS SetVect,15H,<offset DGroup:SysReq>
- mov [TestPSP],cs ;Use our own PSP until program loads
- xor ax,ax
- mov di,offset DGroup:AxSave
- mov cx,8 ;Init all general registers
- rep stosw
- mov ax,cs
- mov bx,offset DGroup:InitSeg
- mov cl,4
- shr bx,cl
- add ax,bx
- rep stosw ;Fill 4 segment registers
- mov ax,100H
- stosw ;Set IP
- mov ah,2
- stosw ;Enable user interrupts
- mov byte ptr [SpSave+1],1 ;Set user SP to 100H
- ;Will now fall into next module's init code
- InitSeg ends
-
- END Monitor
-