📄 input.asm
字号:
;
; GRDB
;
; Copyright(c) LADsoft
;
; David Lindauer, camille@bluegrass.net
;
;
; Input.asm
;
; Function: Handle input
;
; Handles numbers
; Handles segments
; Handles trapping page faults
; Handles command input
;
;MASM MODE
.model small
.386
include edispatc.inc
include eprints.inc
include emtrap.inc
include eregs.inc
include edump.inc
include eentry.inc
include eexec.inc
include ebreaks.inc
include edis.inc
include einout.inc
include eoptions.inc
include ehistory.inc
extrn _exit : PROC,domath : PROC, drive : PROC, fill : PROC
extrn logging : PROC, help : PROC, pci : PROC
extrn DoFileRead : PROC, DoFileWrite : PROC, search : PROC
extrn fpcommand : PROC, move : proc, compare : proc, asm : PROC
PUBLIC qerr, ReadNumber, ReadAddress, Inputhandler
PUBLIC wadeSpace, GetInputLine, WadeSpaceOnly, inputbuffer
PUBLIC defDS,defCS
IBSIZE = 80 ;max size of iinput buffer for a line=width of screen
.data
inputbuffer db IBSIZE DUP (?) ;Allocate Input buffer
Commands db "abcdefghilmnopqrstuwxy@?" ; List of commands
comlen = $ - Commands ; Length of list
inquote db 0
.code
;
; load defaults if dx is zero
; INPUT: EDX contains segment to use if not 0, OR if big real with offset 0
; OUTPUT: DX contains segment to use, could be default DX from bucket
;
defDS PROC
or edx,edx ;if edx has a value
jnz ddsx ;then use it
sub dx,dx ; waste one instruction
test [optflat0],1 ;see if default seg is 0
jnz ddsx ;if so, use EDX=0
mov dx,[RegdumpDS] ;else use default DS
ddsx:
ret
defDS ENDP
;
; for now we just default CS to the active CS, since it is only
; used on U and A commands and since we can't do linear addressing
; with those anyway right now. ???is this true???
; If EDX <> 0, we are starting from a specified segment location,
; so use that instead of CS. (EDX contains the segment).
;
defCS PROC
or edx,edx
jnz dcsx
mov dx,[RegdumpCS]
dcsx:
ret
defCS ENDP
;
; Print an error if command wrong
; Apparently, SI points to some location in the input buffer. We
; need to determine how many spaces to print before we found the actual
; error to point to from the line below. I guess if the error is in the
; first or second positions, we print the character right at the start of
; the line, else we space over to where the error is found.
;
qerr PROC
call crlf ;new line for this
sub si,offset inputbuffer-2 ; Calculate error pos
mov cx,si ;
jcxz short qestart ;
dec cx ;
jcxz short qestart ;
qelp:
call printspace ; Space over to error pos
loop qelp
qestart:
mov dl,'^' ; Display error
call PutChar
stc ; Did an error
ret
qerr ENDP
;
; Read in a number.
; In at least some cases, we have ALREADY called ReadReg to find a register,
;and failed so we are looking for a number anyway.
; SI points to the input line from the user.
; OUTPUT: CY if we found 0 digits and did NOT find a register by name
; EAX contains number found if NC
;
ReadNumber PROC
push ebx
push cx
push dx
call ReadReg ;find a non-number (mnemonic)
clc ;ignore which type or reg found
jz gotnum ;if 0, we have value of this reg
;We reach here if we found no mnemonic in our lookup table
sub ebx,ebx ; Number = 0
sub cx,cx ; digits = 0
mov al,[si] ;get next user character
cmp al,"'" ;if single or double quotes
jz getstring ;get a string input
cmp al,'"'
jz getstring
cmp al,'-' ;if a hyphen
pushf ;save result of compare
jnz rnlp ;not a hyphen, so SI is ok
inc si ;else skip the hyphen
rnlp:
lodsb ; Get char & convert to uppercase
cmp al,60h
jc notlower
and al,NOT 20h
notlower:
sub al,'0' ; Convert to binary
jc short rn_done ; < '0' is an error
cmp al,10 ; See if is a digit
jc short gotdigit ; Yes, got it
sub al,7 ; Convert letters to binary
cmp al,16 ; Make sure is < 'G'
jnc short rn_done ; Quit if not
cmp al,10 ; MAke sure not < 'A'
jc short rn_done
gotdigit:
shl ebx,4 ; It is a hex digit, add in
or bl,al ; OR in the digit
inc cx ; Set flag to indicate we got digits
jmp rnlp ; go get the next digit
;We have snagged all entered digits here, and in the process SI got bumped
;past the non-digit by lodsb, so back up to look at the first non-digit
;character. the Zero flag contains the result of our hyphen compare, ZF if
;we found a hyphen, NZ if we didn't.
; NOTE also that if we found a string, EBX has up to 4 ASCII codes in it,
;NOT a value. Don't offhand see any way the caller can know this, though.
rn_done:
dec si ; Point at first non-digit
popf ;did we find a hyphen?
jnz rm_done2 ; check for negation
neg ebx ;yes, negative, so negate value
rm_done2:
mov eax,ebx ;final result into EAX
test cl,-1 ; See if got any CX=digit count
jnz gotnum ;if non-0, we got at least one
stc ; No, error
gotnum:
pop dx
pop cx
pop ebx
ret ;return number/string in EAX
;We found a quote character at [SI], so we move past the quote to try to
;snag a quoted string. We keep sticking ASCII codes into EBX, shifting it
;left as we go, and losing all but the last 4 ASCII codes.
getstring:
inc si ;bump past quote character
getstringl:
lodsb ;get next char
cmp al,13 ;if CR, end of input
jz rm_done2 ;so leave SI alone?
cmp al,"'" ;find end of quotes already?
jz rm_done2 ;if so, check if null string
cmp al,'"'
jz rm_done2
inc cl ;else we got a char
shl ebx,8 ;stick in BL
mov bl,al
jmp getstringl ;and get the next one
ReadNumber ENDP
;
; Read an address, composed of a number and a possible selector
; INPUT: SI points at the input line just following the U (for unassemble).
; OUTPUT: EBX contains the address, which came either from a current
; register bucket or from a string or number
;
ReadAddress PROC
sub edx,edx ;EDX used for segment if found
call ReadReg ;chk for seg or non-seg register
; mnemonic (like 'AX')
;ReadReg returns two flags: if NZ, we found nothing. if ZF, we found either
;a segment register or a non-segment register, so we examine the carry flag.
;CY means it was a non-segment register, and NC means we found a segment
;register.
; If we found a register at all, the value returned is what was in the
;Regdump bucket for that register, and is returned in EAX unless it was not a
;32-bit register, in which case the low word is returned in AX and the high
;word of AX is zero. (undefined for segments)
jnc gotseg ;if NC, we snagged a segment reg
mov ebx,eax ;else, get value into ebx
jz gotaddr ;ZF if non-segment reg found
;We fall through here if we failed to find a register. The syntax from the
;user permits either REG:number, REG:REG, number:REG, number:number, or just
;number. At this point, no register was asked for by name, so we check for a
;number.
readseg:
call ReadNumber ; Read a number or string
jc short raerr ; Quit if error - no input
mov ebx,eax ;move number/string to EBX
call WadeSpace ;find next input
jz gotaddr ;if no more, we're done
cmp al,':' ;if not a colon
jnz gotaddr ;we are also done
inc si ;else move past colon
; We fell through above because the user did NOT ask for any
;register by name, then fell through to here because we found a colon after
;a number or quoted string.
;EBX now contains a number of up to the last 8 digits entered, or a string
;of up to the last 4 ASCII characters entered. We take the low 4 digits or
;two characters and put them in DX, then set bit 16 of EDX
mov dx,bx ;low order num/string to DX
or edx,10000H ;set bit 16 for segment
jmp readofs ;and go read an offset
;EAX contains the value read out of the RegdumpREG bucket, with the high
;order word zeroed out.
gotseg:
sub ebx,ebx ;assume seg only, so offset is 0
mov dx,ax ;get segment value into DX
or edx,10000H ;set bit 16 for segment
call WadeSpace ;look for more input
jz gotaddr ;if no more, segment given only
cmp al,':' ;else see if colon for offset
jnz gotaddr ;if not, that's it
inc si ;else move past colon
;We get here if the input contained a colon, indicating that there might
;be an offset following. If nothing follows the colon, assume an offset
;of 0.
readofs:
call WadeSpace ;any further input
jz gotaddr ;ZF means we found a CR
call ReadNumber ; Read in offset
jc short raerr ; Quit if error - no number or
; quoted string with endquotes
mov ebx,eax ;else set offset into EBX
gotaddr:
clc ; OK, exit
ret
raerr:
stc ; Error on number input
ret
ReadAddress ENDP
;
; Get an input line
; OUTPUT: SI points to the line of input.
;
GetInputLine PROC
mov [inquote],0 ;say input not in quotes
mov di,offset InputBuffer ;point to input buffer
mov si,di ;Return buffer pointer
mov cx,IBSIZE ; Size of buffer=80 bytes
moreinput:
call GetKey ;wait, return keystroke
call CheckHistory ;check for history substitutions
jc MoreInput ;and go for more input if so
or al,al ; ignore function keys
jz moreinput ;
cmp al,9 ; is tab?
jz dotab
cmp al,8 ; Is delete or rubout?
jz short bkspc ; Yes - go do it
cmp al,7fh ;not on PC?
jz short bkspc ; yes - go do it
cmp al,'"' ;is it double quotes
jz doquote ;if so, set flag
cmp al,"'" ;is it single quotes
jnz dochar ;no, must be valid char
doquote:
xor [inquote],1 ;invert quote flag
dochar:
push ax ;save keystroke
test [inquote],1 ;was it quotes
jnz nolc ;if so, OK
cmp al,'A' ;see if below A
jc nolc
cmp al,'Z' ;or above Z
ja nolc
or al,20h ;if A-Z, force lowercase
nolc:
stosb
pop ax
cmp al,13 ; Is CR
jz short endinput ; Yes, return
mov dl,al ; Echo character
call PutChar
loop moreinput ; Loop till buffer full
endinput:
call EnterHistory
ret
bkspc:
cmp di,offset InputBuffer ; Quit if nothing in buffer
jz moreinput ; And get more input
mov dl,8 ; Erase last echoed char
call PutChar
mov dl,' ' ;
call PutChar
mov dl,8 ; Reset pointer
call PutChar
dec di ; Point at last char
cmp byte ptr [di],' ' ; check for multiple spaces
jnz moreinput
cmp byte ptr [di-1],' ' ;
jz bkspc
jmp moreinput ; Get more input
dotab:
push cx
mov cx,di ; cx = current pos
sub cx,si ; Minus start pos
add cl,7 ; now it equals number of
and cx,7 ; spaces per tab
xor cx,7
inc cl ; spaces = 1 to 8
tablp:
mov al,' '
stosb
mov dl,' '
call PutChar
loop tablp
pop cx
jmp moreinput
GetInputLine ENDP
;
; Wade past spaces
; Whoa! By subtle implication, the carry accidentally gets set if the non-
; space of comma character was less than 13 in ASCII sequence. This means
; if we hit a tab (8), the carry gets returned set.
; Turns out this is NO ACCIDENT, and callers rely on this somehow.
;
WadeSpace PROC
lodsb ; Get char
cmp al,' ' ; if ' ' or ',' go again
je short wadeSpace ;
cmp al,',' ;
je short WadeSpace ;
cmp al,9 ;ignore tab also
je WadeSpace
dec si ; Point at last space char
cmp al,13
ret
WadeSpace ENDP
;
; Wade through spaces only
;
WadeSpaceOnly PROC
lodsb ; Get a char
cmp al,' ' ; Is space
je WadeSpaceOnly ; Loop if so
cmp al,9 ; ignore tab also
je WadeSpaceOnly
dec si ; Else point at char
cmp al,13
ret
WadeSpaceOnly ENDP
;
; Main Input routine
;
InputHandler PROC
call LoadHistory
PRINT_MESSAGE <13,10,"->"> ; MONITOR prompt
call GetInputLine ; Get an input line
call WadeSpace ; Wade through spaces
jz InputHandler ; blank line, so try again
inc si ; Point at first non-space char
mov di,offset commands ; Get command list
mov cx,comlen ; Length of list
repne scasb ; search for command in list
jnz ierr ; Error if not in list
mov ax,comlen-1 ; Calculate position
sub ax,cx ;
;Dangerous practice - the list of commands is tightly coupled to the string
;of command characters. Some day, I should convert this to an array of
;structures, each containing the command and a pointer to its handler.
;Then we search through the structure list to find the command, and if found
;call the associated handler.
push 0 ; Command arg = 0
call TableDispatch ; Dispatch command
dw comlen-1
dw asm ;A command
dw breaks ;B command
dw compare ;C command
dw Dump ;D command
dw entry ;E command
dw fill ;F command
dw go ;G command
dw domath ;H command
dw doin ;I command
dw DoFileRead ;L command
dw move ;M command
dw fpcommand ;N command
dw doout ;O command
dw proceed ;P command
dw _exit ;Q command
dw ModifyRegisters ;R command
dw search ;S command
dw trap ;T command
dw diss ;U command
dw DoFileWrite ;W command
dw drive ;X command
dw pci ;Y command
dw logging ;@ command
dw help ;? command
jnc InputHandler ; Get more input if no err
ierr:
call qerr ; Display error
jmp InputHandler ; Get more input
InputHandler ENDP
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -