📄 mon.asm
字号:
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -