Category : Assembly Language Source Code
Archive   : RE-SOURC.ZIP
Filename : RE-SOURC.ASM

 
Output of file : RE-SOURC.ASM contained in archive : RE-SOURC.ZIP

;®LM0¯RE-SOURCE DISASSEMBLER - modified by JIR 7/87 - 11/88

;Disassembly starts ÷ page 43.
;Commands, file handling in first half, except Symbol stuff at ÷ page 67.

;All label addrs stored per pcntr, displayed as pcntr + curorg.
;Hard-coded addrs found in B cmd stored at coded addr - curorg.

PAGE 192,132
CSEG segment byte public 'CODE'
assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG

DB 256 DUP(?)

bel equ 7
tab equ 9
cr equ 0Dh
lf equ 0Ah
initlcnt equ 20 ;lines displayed initially
DefaultDTA equ 80h ;in PSP, used as buffer for disk read/writes
symbas equ offset ctlbas + 3072 ;base of 16K symbol (label) table
rembas equ symbas + 16384 ;base of 24K remark table

;The scheme above makes the .COM file shorter. MEMCHK routine makes sure
; there's enough room for these.

start proc near
jmp memchk

banner db 'RE-SOURCE by C.Derouen, revised by J. Rebold '
db 'Dec 88',cr,lf,'$'

;CHECK FOR DOS V2.0+
memchk: mov ah,30h ;get DOS version
int 21h
cmp al,2
jae good_vers
mov dx,offset bad_vers
mov ah,9
int 21h
int 20h ; Exit

bad_vers db cr,lf,7,'DOS 2.0+ required. Sorry.$'

good_vers:
;ALLOCATE RAM FOR BUFFERS & TARGET PGM
mov ax,cs
mov es,ax ;seg addr of block to change
mov bx,2000h ;allocate 128K
mov ah,4Ah ;modify allocated memory block
int 21h
jc L001
jmp goodmem
L001: cmp al,8
jz notnuf
cmp al,7
jnz invalid
mov dx,offset destro
jmp short prtmsg

invalid: mov dx,offset invmsg
jmp short prtmsg

notnuf: mov dx,offset nomem ;location of string to print
prtmsg: mov ah,9 ;print string
int 21h
mov ah,4Ch ;set Errorlevel & exit
mov al,08h ;Errorlevel=8, failure
int 21h

nomem db cr,lf,7,'Not enough memory - program aborted$'
destro db cr,lf,7,'DOS mem ctl blocks destroyed - cannot allocate RAM$'
invmsg db cr,lf,7,'Invalid MCB addr or other screwup - pgm aborted$'

goodmem:
cli
mov ax,ds
mov ss,ax ;SS=DS
mov sp,offset stak ;machine stack now in buffer @ end pgm
sti
mov bx,rembas ;EQU symbas + 16K
mov remtbl,bx ;used from now on - start of REM table
mov dx,offset banner ;addr of intro message
mov ah,9 ;print string
int 21h
call ClearTables
mov al,cs:byte ptr [80h] ;length of cmd line incl the CR
or al,al
jz fstcmd
;There is something on the command line
call prtstr
db cr,lf,'Reading All Files of ',0
mov di,offset FileString
mov bx,81h ;point to 1st char of cmd line
BlnkLoop:
mov al,[bx]
cmp al,' '
jnz FirstChar
inc bx
jmp short BlnkLoop
FirstChar:
call MoveField
mov DotPtr,di
mov byte ptr [di],'.'
mov bx,offset FileString
ZLoop: mov al,[bx]
or al,al
jz ZLoopDone
call typech
inc bx
jmp short ZLoop

ZLoopDone:
call LoadAll
jmp short fstcmd

Restart:
call ClearTables
fstcmd: call prtstr
db cr,lf,'Enter ? for Stats, H for Help (or hit F1)',cr,lf,cr,lf,0

nxcmd: mov hlpflg,0 ;cursor keys not to show help
hlpcmd: mov wfiflg,0 ;don't write to file
; mov segflg,0 ;clear segment use flag (not now used)
mov sp,offset stak ;for errors in CALLs that jmp to NXCMD
call gtcmd
mov bx, offset cmdbuf+2 ;first char of command
; cmp word ptr [bx+1],':S' ;'S:' in reverse order
; jz segonl ;just change segment
mov al,[bx] ;get 1st char of command
mov bx,offset CmdVectorTable
mov ch,(offset VectorTblEnd-offset CmdVectorTable)/3 ;no. of entries
FuncLoop:
cmp al,cs:[bx] ;test char match
jz fndfun
inc bx
inc bx
inc bx
dec ch
jnz FuncLoop
jmp cmerr

fndfun: inc bx
mov dx,cs:[bx] ;address of function
jmp dx ;no, NOT jmp [dx] !!

;segonl: inc bx ;pre-adj BX to point to S: in cmdbuf
; call updseg
; jmp short nxcmd

CmdVectorTable db cr
dw offset hlpcmd
db ';'
dw offset cmrem ;enter Remark
db 'A'
dw offset cmatmt ;Attempt to find DB's
db 'B'
dw offset cmbld ;Build symbol table
db 'C'
dw offset cmctl ;enter Control (BEHISW) or dump table
db 'D'
dw offset cmdump ;hex Dump, also Dump Symbol table
db 'E'
dw offset cmentr ;Enter a label
db 'H'
dw offset cmhelp
db 'K'
dw offset cmkill ;Kill a label
db 'L'
dw offset cmload ;load files
db 'N'
dw offset cmpurg ;clear .CTL, .SMB, .REM tables
db 'O'
dw offset cmorg ;set ORG addr
db 'P'
dw offset CmPath ;change D:\path\ to save to
db 'Q'
dw offset cmexit ;enter Q to quit
db 'R'
dw offset CmRAMpara ;unassemble anywhere in RAM
db 'S'
dw offset CmSearch
db 'T'
dw offset cmtrim ;toggle Trim (prints addrs w/labels)
db 'U'
dw offset CmUnasm ;do Unassembly
db 'W'
dw offset CmWriteRSM ;write .RSM file
db 'Z'
dw offset cmeof ;write EOF to .ASM file & close
db '?'
dw offset CmStats
VectorTblEnd db 0

;--------------------------------
cmerr: mov wfiflg,0 ;clear 'write to file' flag
call prtstr
db 'Command Error at ',bel,0
pop bx ;addr called from
call Print00BX_ ; for debugging
call prtstr
db cr,lf,0
cli
mov sp,offset stak
sti
jmp nxcmd

;--------------------------------
delim: cmp al,' '
jz deliok
cmp al,','
jz deliok
call cmerr ;expected delimiter missing
deliok: ret

;--------------------------------
; Exit program here
cmexit: cmp ChgFlag,0
jz ByeBye
call prtstr
db cr,lf,'Unsaved changes - '
db cr,lf,'hit U to update & exit, E to just exit.',0
Gotta: mov ah,0 ;read next kbd char into AL
int 16h
or al,al ;check for non-ASCII key
jz Gotta
and al,5Fh ;make upper-case
cmp al,'E'
jz ByeBye
cmp al,'U'
jnz Gotta
call sav_em
ByeBye: mov ax,4C00h ;exit w/errorlevel = 0
int 21h

;--------------------------------
;HELP SCREENS

cmhelp: mov hlpflg,1 ;signal cursor keys - see gtcmd
xor ah,ah
mov bx,offset helptr
mov al,helpno ;get which help screen
add al,al
add bx,ax
mov dx,[bx] ;make dx point to desired screen
mov ah,9 ;print string
int 21h
jmp hlpcmd

;line 0
help db ' COMMAND SUMMARY - all numbers are HEX!'
;line 1 & 2
db cr,lf,cr,lf,';NNNN,[;]Remark enter Remark at NNNN'
db ' ;=append \ starts new line'
;line 3
db cr,lf,';[NNNN] list Remarks Table [from NNNN] '
db ';NNNN, delete remark at NNNN'
;line 4
db cr,lf,'A (See U) attempt to find DBs '
db 'B (See U) build Symbol Table'
;line 5
db cr,lf,'C dump CTL table '
db 'CSSSS dump CTL from SSSS on'
;line 6
db cr,lf,'CNNNN,X set CTL (X=BEHISW or K) '
db 'DSSSS dump bytes from SSSS on'
;line 7
db cr,lf,'DSSSS,EEEE dump bytes over range '
db 'D,EEEE dump thru EEEE'
;line 8
db cr,lf,'D dump a page more '
db 'D=NN bytes (not lines)/dump (HEX)'
;line 9
db cr,lf,'DS dump the Symbol Table '
db 'DS.Label dump SMB from Label on'
;line 10
db cr,lf,'ENNNN,.Label enter Label at NNNN '
db 'DSssss dump SMB from ssss on'
;line 11
db cr,lf,'K.Label kill Label from Table '
db 'U Unassemble entire pgm'
;line 12
db cr,lf,'USSSS,EEEE Unasm over range '
db 'U,EEEE Unasm to EEEE'
;line 13
db cr,lf,'USSSS Unasm 20 lns from SSSS '
db 'U=NN Set no. lines to Unasm'
;line 14
db cr,lf,'O display Current ORG '
db 'ONNNN Set new ORG'

;line 15
db cr,lf
;line 16
db cr,lf,'RNNNN sets, R shows para in RAM to unassemble if '
db 'no file is loaded'
;line 17
db cr,lf,'L[d:][\path\]name.COM .CTL .SMB .REM .ALL'
db ' Load files (no .ext same as .ALL)'
;line 18
db cr,lf,'F9 save .CTL, .SMB, .REM files '
db 'N trash .CTL, .SMB, .REM files'
;line 19
db cr,lf,'W enables saving as you '
db 'Unassemble. Stops at END or Z closes'
;line 20
db cr,lf,'Z close .RSM file '
db '? print Statistics'
;line 21
db cr,lf
;line 22
db cr,lf,'enter Q or hit ESC, Q to exit to DOS'
;line 23 & 24
db cr,lf,tab,tab,tab,196,196,196,'PgDn for next help page'
db 196,196,196,cr,lf,'$'

extnd_help db ' Commands Continued'
db cr,lf,cr,lf,'T toggle display of label addresses as comments'
db cr,lf
db cr,lf,'SWWWW search for WWWW'
db cr,lf,'S continue search for WWWW '
db 'SWWWW,SSSS search WWWW after SSSS'
db cr,lf,'ANY KEY stops search. WWWW is in reverse order in RAM!'
db cr,lf,cr,lf,'P lets you edit path to save/load.'
db cr,lf,cr,lf,'Control meanings:',cr,lf
db ' B=Bytes in ASCII H=Bytes in hex E=END (ends Unassembly)'
db cr,lf,' I=Instructions S=Same [DB n DUP (x)] W=Words'
db cr,lf,' K=Kill CTL at this addr'
db cr,lf,cr,lf,'You can enter .YourLabel in place of any address'
db cr,lf,cr,lf,cr,lf
db 'Run RE-SOURC [d:][\path\]filename to load filename.COM (or '
db '.EXE or .SYS),'
db cr,lf,' .REM, .CTL, and .SMB'
db ' automatically. Files must all be in same directory.'
db cr,lf,cr,lf,'PGDN works, CTRL-PGUP goes to start, '
db 'down arrow does 1 more line',cr,lf
db cr,lf,196,196,196,'PgUp for previous help page'
db 22 dup (196)
db 'PgDn for next help page',196,196,196
db cr,lf,'$'

instrs db tab,tab,tab,tab,'INSTRUCTIONS',cr,lf,cr,lf
db 'Lfilename (or .ALL) loads target program and .SMB, .REM, .CTL'
db cr,lf,cr,lf,'Load any file with Lfilename.ext '
db cr,lf,cr,lf,'For unusual programs, use O to set ORG as desired.'
db cr,lf,cr,lf,'A finds approx location of DBs.'
db cr,lf,cr,lf,'Build .SMB (label) table with B. Some'
db ' labels will not show until next U.'
db cr,lf,cr,lf,'Enter or change labels with ENNNN,.Label',cr,lf
db 'Add remarks with ;NNNN,inserted remark or '
db ';NNNN,;appended remark'
db cr,lf,cr,lf,'F9 saves the .SMB, .CTL, and .REM files.'
db cr,lf,cr,lf,'To write a .RSM "source" file,'
db ' hit W and then U.'
db cr,lf,cr,lf,cr,lf
db 'RE-SOURCE works only on the first 64K of a program...'
db cr,lf,' use ? to find and R to set seg of next 64K.'
db cr,lf
db cr,lf,tab,tab,tab,196,196,196,'PgUp for previous help page'
db 196,196,196,cr,lf,'$'
;--------------------------------
cmtrim: mov al,trmflg
not al
mov trmflg,al
or al,al
jz LblAdrsOn
call prtstr
db 'Label Addresses Off',cr,lf,0
jmp nxcmd
LblAdrsOn:
call prtstr
db 'Label Addresses On',cr,lf,0
jmp nxcmd

;--------------------------------
cmpurg: call prtstr
db 'purge .SMB (labels), .REM, & .CTL tables? (Y/N)',0
call gtcmd
mov al,byte ptr cmdbuf+2
cmp al,'Y'
jnz NoPurge
call erstbl ;empty the segment tables
mov segsho,205 ;replace seg char in prompt arrow
mov PgmParas,0 ;size of loaded pgm
jmp Restart

NoPurge:
jmp nxcmd

;--------------------------------
;all calls commented out
sgreqs: mov bx,offset cmdbuf+4 ;check for segment prefix, e.g. UDS:1234
mov ax,[bx] ; (remember,1st char of cmd @ cmdbuf+2)
cmp ax,word ptr lblS ;is xS: there?
jz updseg ;yes, find which and set
ret ;else do nothing
lblS db ':S' ;backwards since lo-hi in RAM

updseg: dec bx
mov al,[bx] ;first seg char, C or D or E or S
sub ah,ah ;start at 0
cmp al,'C'
jz segmch
inc ah
cmp al,'D'
jz segmch
inc ah
cmp al,'E'
jz segmch
inc ah
cmp al,'S'
jz segmch
ret ;ignore any others
;segmch used only in this routine
segmch: mov segsho,al ;for cmd. prompt display
mov segflg,al ;seg req given
mov al,ah ;count value
sub ah,ah
mov bx,ax ;in a base reg
add bx,offset segmtb
mov cl,cs:[bx] ;get bit pattern
mov OprndType,cl ;init symbol select
mov bl,12 ;size of segment record
mul bl ;index segment records
mov bx,offset cofset ;segment para word base
add bx,ax ;index to right seg.
mov ax,[bx] ;get this para value
mov curpar,ax ;to active para holder
mov ax,-8[bx] ;get segment length
mov cl,4
shl ax,cl ;convert to bytes
mov segsiz,ax ;for ctl table limits
mov dx,offset cmdbuf[3] ;dest
mov bx,offset cmdbuf[6] ;source
;squeeze out segment chars
l03b2: mov al,[bx] ;move cmd line
xchg bx,dx
mov [bx],al ;down a notch
xchg bx,dx
inc bx
inc dx
cmp al,cr
jnz l03b2
ret

segmtb db 0Ch,04h,08h,0

;--------------------------------
cmdump: ;call sgreqs
mov dx,DumpStart
mov bx,dmpcnt
add bx,dx
mov DumpEnd,bx
mov bx,offset cmdbuf+3
mov al,[bx] ;2nd cmd char
cmp al,cr
jz dmphdr ;continue last dump
cmp al,'S' ;DS command, dump symbol table
jnz l0411
mov al,[bx+1] ;next char
cmp al,':' ;segment req coming?
jz l0411 ;looks like it, not DS command
jmp DumpSym

l0411: cmp al,'=' ;is this a dump length change ?
jnz l0418
jmp SetDumpCt

l0418: cmp al,',' ;Dump to end addr only
jz dump1
;Dump from DumpStart (user input DNNNN)
dump0: call gtval ;rets w/bx>char past number, dx=addr less curorg
jnc notneg ; and carry if DX<0
xor dx,dx ;If Dump addr before ORG, start at ORG
notneg: push bx
mov bx,dmpcnt
add bx,dx
mov DumpEnd,bx
pop bx
dump1: cmp al,cr
jz dump3
call delim
inc bx
push dx
call gtval
xchg bx,dx
mov DumpEnd,bx
pop dx
dump3: mov DumpStart,dx
cmp al,cr
jz dmphdr
call cmerr

dmphdr: call prtstr
db 'Addr +0+1 +2+3 +4+5 +6+7 +8+9 +A+B +C+D +E+F'
db tab,196,196,196,'ASCII',196,196,196,cr,lf,0
cntdmp: mov bx,DumpStart
mov es,curpar
dump4: call BreakChk
push bx ;BX is pointer to code wrt start of target pgm
add bx,curorg
call Print00BX_
pop bx
push bx
call prspc
dmpln: mov es,curpar
mov al,es:[bx]
call xo
inc bx
mov al,bl

and al,1
jnz wdspc1
call prspc
wdspc1: mov al,bl
and al,3
jnz wdspc2
call prspc
wdspc2: mov al,bl
and al,7
jnz wdspc3
call prspc
wdspc3: mov al,bl
and al,0fh
jnz dmpln
call prspc
pop bx
dmpasc: mov es,curpar
mov al,es:[bx]
cmp al,' ' ;20h
jb period
cmp al,7Fh
jb chrctr
period: mov al,'.' ;2eh
chrctr: call typech
inc bx
mov al,bl
and al,0Fh
jz lcmplt
and al,7
jnz wdspc4
call prspc
wdspc4: jmp dmpasc

lcmplt: call prspc
call pstg
db cr,lf,0
mov DumpStart,bx
mov ax,DumpEnd
sub ax,bx
jnb dump4
jmp nxcmd

;set no of bytes per dump (dmpcnt)
SetDumpCt:
inc bx
call gtval
add dx,curorg ;gtval subtracts curorg!
inc bx
dec dx
xchg bx,dx
mov dmpcnt,bx
xchg bx,dx
l04e8: cmp al,cr
jnz l04ef
jmp nxcmd

l04ef: call delim
jmp dump0

;--------------end of Dump command-------------

;DUMP THE SYMBOL TABLE
; Table is 2 byte addr, 1 byte Seg/Type, 1 byte length, n bytes string

DumpSym:
mov EntriesLeft,4 ;init items/line
mov bx,offset cmdbuf+4 ;1st past the DS
mov al,[bx]
cmp al,cr
jz frmbgn
call gtval
call symluk
mov bx,NxtSymPtr ;> this or next higher label
jmp frmsym

frmbgn: mov bx,symbas
frmsym: call prtstr
db 'KEY: 1st char = CS, DS, ES, SS '
db '2nd char = Byte, Word, Dword, Undefined',cr,lf,cr,lf,0
NxtSym: mov dx,[bx] ;start of a SMB entry, the addr
inc bx
inc bx
inc bx
mov al,[bx] ;string length
or al,al
jz DSdone ;end of table reached
l051a: push dx ;addr
push bx ;pointer to string length
dec bx
add dx,curorg ;correct all addrs for ORG
xchg bx,dx ;must be in BX to print
call Print00BX_ ;print address in BX, + space
pop bx ;pointer to length byte
pop dx ;addr
dec bx
mov al,[bx] ;OprndType byte
inc bx ;back to length byte
xor ah,ah
push ax ;save type byte
mov bp,offset ltable
and al,00110000b ;get bits 4 & 5
mov cl,4
shr al,cl ;into bits 0 & 1
mov si,ax
mov al,[bp+si]
call typech ;print seg char, S D E or C
pop ax
and al,3 ;get bits 0 & 1
mov si,ax
mov al,[bp+si+4]
call typech ;print Type char, U B W or D
mov al,' '
call typech ;print a space
mov cl,[bx] ;length of label
xor ch,ch
inc cx ;length + 1 to
add cx,bx ; point to next label field
mov NxLblPtr,cx ;save pointer
mov cl,10 ;always print 10d bytes
inc bx ;to 1st char of label
;print the label, truncated or padded out to 10d characters
spit: mov al,[bx]
call typech
inc bx
dec cl ;keep count of bytes printed
jz EntryDone
cmp bx,NxLblPtr
jnz spit
PadLoop:
call prspc
dec cl
jnz PadLoop
EntryDone:
call ChkEntryCt
call BreakChk
mov bx,NxLblPtr
jmp NxtSym

ltable db 'SDECUBWD'

DSdone: call prtstr
db cr,lf,0
jmp nxcmd

;after printing entry, see if line is finished (for CTL and SYM dump)
ChkEntryCt:
dec EntriesLeft
jz NotherLine
call prspc
call prspc
ret

;new line of 4 entries
NotherLine:
call CrLf
mov EntriesLeft,4
ret
;--------------------------------

;SET ORG ADDRESS
cmorg: ;call sgreqs ;any segment data?
mov bx,offset cmdbuf+3 ;1st char after the O
mov al,[bx]
cmp al,cr
jz prntos ;just show curr value
call gtval ;new ORG (less old ORG) from user to DX
add dx,curorg ;correct it for old curorg
cmp al,cr ;end of entry ?
jz l0557
call cmerr

l0557: mov curorg,dx ;this is the ORG for display
prntos: call prtstr
db 'ORG = ',0
mov bx,curorg
call Print00BX_
call CrLf
jmp nxcmd

;--------------------------------
;ATTEMPT TO FIND DBs
cmatmt: mov AmodeFlag,1
mov BmodeFlag,0
jmp short list1
;BUILD SYMBOL TABLE
cmbld: mov BmodeFlag,1
mov AmodeFlag,0
jmp short list1

;UNASSEMBLE at [pcntr] but show addr [pcntr+curorg], & A or B if reqd
CmUnasm:
mov BmodeFlag,0
mov AmodeFlag,0
list1: mov wfiflg,0 ;write to display only
mov al,LnsPerScreen ;no. of lines to show
mov LinesToGo,al
mov LCountFlag,al ;show specific no of lines
; call sgreqs ;check cmdbuf for segment spec.
mov bx,offset cmdbuf+3 ;1st char after the U, A, or B
mov al,[bx]
cmp al,cr
jz ToTheEnd
cmp al,','
jz list3 ;no starting location
cmp al,' '
jz list3 ;no starting location
cmp al,'='
jnz list2
jmp SetLineCount ;change default no of lines

ToTheEnd:
mov pcntr,0
mov dx,0FFFFh
jmp short list4

;U B or A from given location
list2: call gtval ;get start pcntr=input-curorg
mov pcntr,dx ;where to start
cmp al,cr
jz TwentyLines ;only start given
call delim
list3: inc bx ;past delimiter
call gtval ;get ending location
list4: mov lastwd,dx
mov LCountFlag,0 ;not specific line count

;--------------------------------
;U B or A default no. of lines - always entered w/wfiflg=0

TwentyLines:
call BreakChk ;check for Ctrl-Break w/DOS func 01
cmp LCountFlag,0
jz contl ;end addr was input, do reqd no lines
mov al,LinesToGo
dec al
jns flagck ;another line if screen not full
jmp nxcmd

contl: mov es,curpar ;para of target pgm
mov ax,pcntr
sub ax,lastwd
jb flagck ;not at end
jmp nxcmd

flagck: cmp AmodeFlag,0
jnz Attempt
jmp morel ;not in 'Attempt find DBs' mode

;ATTEMPT TO FIND DB's WHILE UNASSEMBLING, insert CTL where found
;first, search for DUPs
Attempt:
mov di,pcntr
mov es,curpar
mov al,es:[di] ;get 1st byte of line
mov cx,17 ;to find 16 DUPs
repz scasb
or cx,cx
jnz ChkASCII
;16 DUPs in a row have been found, CX is 0
dec cx ;to FFFFh
dec di ;back to 1st un-scanned byte
repz scasb
mov bx,di
mov Control,'S'
call SetControl
jmp morel

ChkASCII:
mov bx,pcntr
mov cx,8 ;no. of ASCII chars to call it a DB line
mov es,curpar
loop8: mov al,es:[bx]
call IfASCII ;test one byte for DB
jc morel ;not a DB line
inc bx
loop loop8 ;must find 8 ASCII chars in a row
;8 ASCII chars in a row have been found
follow: mov al,es:[bx]
inc bx
call IfASCII ;keep looking for ASCII
jnc follow
mov Control,'B'
call SetControl
jmp morel
; . . . . . . . . . . . . . . . .
SetControl: ;insert Control if none here
dec bx ;to 1st non-ASCII/non-DUP byte
push bx
mov dx,pcntr ;start addr of line
call ctlook
jc okchg ;if no ctl at this location
cmp byte ptr [bx+3],'E' ;if ctl exists
pop bx
jz morel ;don't overwrite END ctl
push bx
okchg: mov dx,pcntr
mov al,Control
call EnterCTL ;make entry in CTL table
;insert I ctl where ASCII bytes/DUPs end
pop dx ;was BX, last byte + 1
cmp word ptr PgmBytes+2,0
jnz NoENDp ;there is no END ctl if >64K
cmp dx,PgmBytes
jc NoENDp ;if not past end
push dx
mov dx,PgmBytes
call ctlook ;is there a ctl at end locn ?
pop dx
jc NoENDp
;under 64K, past end, there is a ctl at end
cmp byte ptr [bx+3],'E' ;is the ctl at end really END ?
jz morel ;if so, no ctl past END
NoENDp: call ctlook
jc okchg2 ;no ctl at this location
cmp byte ptr [bx+3],'E'
jz morel ;don't overwrite END ctl
okchg2: mov al,'I' ;back to 'I' at end
jmp EnterCTL
; . . . . . . . . . . . . . . . .

;Jump here if not in A mode
morel: mov bx,remtbl
cmp bx,remend
jz ncmt ;remark table is empty
mov dx,pcntr
call RemChk ;test for poss. remark at [DX]
jc ncmt ;if none
;remark exists, BX points to its matching addr
inc bx
inc bx ;skip addr field
mov ch,[bx] ;byte count of remark
mov al,[bx+1] ;first remark character
cmp al,';' ;append it?
jnz morel1
mov AppendPtr,bx
jmp ncmt

morel1: call DoRemark ;print the remark
call CrLf
jmp ncmt
; . . . . . . . . . . . . . . . .
;print remark like this on separate line(s)
DoRemark:
mov wfiflg,1
call semic ;start lines with a semicolon
or ch,ch ;check for zero-length remark
jnz RemContinues
ret

RemContinues:
inc bx
mov al,[bx]
cmp al,'\' ;multi-line remark ?
jnz NoBkslash
call CrLf ;break remark here
dec ch
jmp DoRemark

NoBkslash:
call typech
dec ch
jnz RemContinues
ret
; . . . . . . . . . . . . . . . .
;Line is not remark, or remark is done. Every line goes thru here.
ncmt: mov RelFlag,1 ;line labels not corrected for Org
mov dx,pcntr ;get address of line
call ctlook ;CTL entry for this addr?
; (rets w/BX>ctlbas+0, 4, etc)
jc SameMode ;carry=not matched addr, use old mode
add bx,4 ;use mode of matched addr
SameMode:
dec bx ;to mode byte (prev mode if no change)
mov al,[bx] ;mode char, is at ctlbas-1, +3, +7, etc
cmp al,'I'
jnz not_i
mov ColonFlag,0 ;put colon after label
call AddrOrSmb ;print any label, or addr=pcntr+curorg
mov RelFlag,0 ;default not relative JMP, CALL, etc
mov SegOvrdPfx,0 ;just in case
call dline ;disassemble one line as instruction
mov wfiflg,0 ;write to screen only
jmp TwentyLines ;and go to the next line.

not_i: mov ColonFlag,1 ;no colon after label
call AddrOrSmb ;print any label, or addr=pcntr+curorg
;RelFlag stays = 1 so symluk looks for lbls w/o correction
cmp al,'E' ;is it the END ?
jnz notend
jmp cmeof ;show end & stop

notend: inc bx ;to next CTL record
mov dx,[bx+1] ;address
mov nxtctl,dx ;save to end Hex, Byte & Space lines
mov wfiflg,0
cmp al,'S' ;space mode ?
jnz ckbmd
jmp Smode

ckbmd: cmp al,'B' ;byte ASCII mode ?
jnz ckhmd
jmp bmode

ckhmd: cmp al,'H' ;hex mode ?
jnz ckwmd
jmp hmode

ckwmd: cmp al,'W' ;word mode ?
jnz badmd
jmp wmode

badmd: call typech
call prtstr
db ' INVALID CTL ENTRY - check .CTL file at this location.',cr,lf,0
jmp nxcmd
;--------------------------------
;SET NO OF LINES TO UNASSEMBLE
SetLineCount:
inc bx
call gtval ;input less curorg to DX
add dx,curorg ;correct it
or dh,dh ;now check for more than a screen full
jnz toerr ; and zero lines
mov al,dl
or al,al ;test if more than 0
jz toerr
cmp al,24
jc linesok ;23d lines max
toerr: call cmerr

linesok:
mov LnsPerScreen,al
mov LinesToGo,al
mov al,[bx] ;char in cmdbuf after input no.
inc bx
l0776: cmp al,cr ;just set no. of lines?
jnz l077d
jmp nxcmd

l077d: call delim
jmp list2
;--------------------------------
;S(ame) control, n DUP (x).
Smode: mov wfiflg,1
call pstg
db 'DB',tab,0
mov ax,NxtSymAddr
or ax,ax ;note: * problem if >64K file *
jz UseNxtctl ;if no next label; always is an E ctl
mov EndSameAddr,ax
cmp ax,nxtctl ;ESAddr - nxtctl
jc FindNxtDif
UseNxtctl:
mov ax,nxtctl
mov EndSameAddr,ax
FindNxtDif:
mov di,pcntr
mov es,curpar
mov al,es:[di] ;get 1st byte of DUPs
xor cx,cx
dec cx ;limit 64K REPs
repz scasb ;1st NZ will still INC DI
dec di ;to 1st byte past match
cmp di,EndSameAddr ;1st different - next ctl or smb
jnc PrintDUP
mov EndSameAddr,di
PrintDUP:
push ax ;save the DUP char
mov dx,EndSameAddr
sub dx,pcntr ;ESAddr - pcntr, * NFG over 64K *
call PrintDXh
call pstg
db ' DUP (',0
pop ax ;the DUP char
call PrtALasDB
call pstg
db ')',0
mov dx,EndSameAddr
mov pcntr,dx
jmp StopLine
;--------------------------------
;'W' control, words ***** needs to chk for SMB/CTL at 2nd byte, chg to DB.
wmode: mov wfiflg,1
call pstg
db 'DW',tab,0
mov bx,pcntr
mov es,curpar
mov dx,es:[bx]
call PrintDXh
inc pcntr
inc pcntr
StopLine:
call NewLine
jmp TwentyLines
;--------------------------------
;Byte-ASCII & Hex byte modes
hmode: mov BytesFlag,0
jmp short bmode1

bmode: mov BytesFlag,1 ;flag Bytes ASCII, not HEX
bmode1: mov wfiflg,1 ;write to file, too
call pstg
db 'DB',tab,0
mov strcnt,0 ;chars on this line, any print bumps
mov CrLfFlag,0 ;for Bytes ASCII
mov bx,pcntr
mov es,curpar
cmp BytesFlag,0
jz PrtAsHex ;jump for sure if Hex mode
;CTL is Byte mode, but use Hex routine if unprintable:
ChkHex: mov al,es:[bx]
call ChkSpl
jz ToDoASCII
cmp al,' '
jb ChkComma ;no print other ctrl codes in Byte mode
cmp al,7Fh
jnb ChkComma ;7Fh and over also unprintable
ToDoASCII:
jmp DoASCII

ChkComma:
cmp strcnt,0
jz PrtAsHex
call comma
PrtAsHex:
mov al,es:[bx]
call PrintALh
inc bx
inc pcntr
;end Hex line if up to a CTL change
cmp bx,nxtctl
jnz trysym
jmp StopLine

;end Hex line if up to a label
trysym: cmp bx,NxtSymAddr ;set by symluk when line addr printed
jnz NoHexSmb
jmp StopLine

;end Hex line if up to 31d chars
NoHexSmb:
cmp strcnt,31
jb NotHexMax
jmp StopLine

NotHexMax:
cmp BytesFlag,0
jz ChkComma ;if in Hex mode
jmp ChkHex ;if in Bytes ASCII mode

ChkSpl: xor ah,ah
cmp al,cr
jz CRet
add ah,3
cmp al,lf
jz CRet
add ah,3
cmp al,tab
jz CRet
add ah,3
cmp al,bel
jz CRet
add ah,3
or al,al
CRet: ret ;w/Z if match

XpandTbl db 'cr.lf.tabbel0..'

;ASCII byte printing loop
MoreASCII:
call ChkSpl
jnz NoXpand
;print expanded special characters
cmp strcnt,0
jz PrtSpl
cmp byte ptr es:[bx-1],' '
jb JusComma
cmp byte ptr es:[bx-1],7Fh
jnb JusComma
call apostrophe ; ' if prev char was ASCII, not special
JusComma:
call comma ;comma before special chars
PrtSpl: mov al,ah
push bx
mov bx,offset XpandTbl
call Prt3FromTabl
pop bx
;a Zero after anything else ends the line
cmp ah,12d ;did we just print a '0' ?
jnz SameByte
cmp strcnt,1
jz SameByte ;if it was 1st on the line
cmp byte ptr es:[bx-1],0
jz SameByte
inc pcntr
jmp StopLine ;end the line unless prev char also '0'

NoXpand:
cmp strcnt,0
jz Apost
cmp byte ptr es:[bx-1],' '
jb Cmma
cmp byte ptr es:[bx-1],7Fh
jnb Cmma
jmp short PrtIt
Cmma: call comma ;if prev spl or Hex & this is not 1st
Apost: call apostrophe ;if 1st or prev was special or Hex
PrtIt: call typech ;print to screen and/or file buffer
SameByte:
mov al,es:[bx] ;get byte just printed
cmp al,'''' ;27h, single quote
jnz NotQuote
call typech ;for special case of quote char only
NotQuote:
inc pcntr ;bump character pointer
mov bx,pcntr
;end ASCII line if up to a Control location
cmp bx,nxtctl
jnz NoEnd
ToEndQ: jmp EndQuote
;end ASCII line with any '$'
NoEnd: cmp al,'$'
jz ToEndQ
;end ASCII line if up to a label
mov dx,pcntr
cmp dx,NxtSymAddr ;set by symluk when line addr printed
jz ToEndQ
;end ASCII line if up to 50d chars
cmp strcnt,49
jnb ToEndQ
;end the line after a space if line is 40-49 chars long
cmp strcnt,40
jb DoASCII
mov bx,pcntr
cmp byte ptr es:[bx-1],' ' ;was just-printed char a space ?
jz ToEndQ
;Entry point for Byte Mode, printable codes only.
DoASCII:
mov bx,pcntr
mov al,es:[bx] ;get next char
cmp al,cr
jz CRorLF
cmp al,lf
jnz ChkPrn
CRorLF:
cmp CrLfFlag,1
jnz SetCL
jmp MoreASCII ;just printed a cr or lf

SetCL: mov CrLfFlag,1
cmp strcnt,0
jnz EndQuote ;1st CR/LF after others => new line
jmp MoreASCII ;cr or lf is 1st on the line

;Check if next char is printable. It is not a cr or lf.
ChkPrn: call ChkSpl
jz ToMoreASCII
cmp al,' ' ;20h
jb EndQuote
cmp al,7Fh
jnb EndQuote
mov CrLfFlag,0
ToMoreASCII:
jmp MoreASCII ;go print the char & keep going

EndQuote:
mov al,es:[bx-1]
call ChkSpl
jz ToStop ;no closing ' if just printed special
call apostrophe
ToStop: jmp StopLine
;--------------------------------

CmStats:
call prtstr
db cr,lf,'RE-SOURC PSP at Segment. ',0
mov bx,cs
call Print00BX_
call prtstr
db cr,lf,'Target Pgm at Segment... ',0
mov bx,curpar
call Print00BX_
call prtstr
db cr,lf,'Loc in Pgm Now-Last+1.. ',0
mov bx,pcntr
add bx,curorg
call Print00BX_
mov bx,PgmBytes ;**64K max**
add bx,curorg
call Print00BX_
call prtstr
db cr,lf,cr,lf,'Offsets into RE-SOURCE segment:'
db cr,lf,'CTL Table Start-End.... ',0
mov bx,offset ctlbas
call Print00BX_
l0984: mov ax,1[bx]
and al,ah
add bx,4
inc al
jnz l0984
sub bx,4
call Print00BX_
call prtstr
db cr,lf,'SMB (labels) Start-End.. ',0
mov bx,symbas
call Print00BX_
mov bx,symtp
call Print00BX_
call prtstr
db cr,lf,'REM Table Start-End..... ',0
mov bx,remtbl
call Print00BX_
mov bx,remend
call Print00BX_
call prtstr
; db cr,lf,cr,lf,'SEG. LGTH BASE SMIN SMAX PARA',0
db cr,lf,cr,lf,0
; mov bx,offset cstbl

;sgplp: mov al,[bx]
; or al,al
; jz sgpends ;found end flag
; cmp al,' ' ;used entry?

; jnz usdseg
; add bx,12
; jmp short sgplp
;usdseg: mov ch,2 ;print 2 chars
; call PrtCHbytesPerBX ;(seg label & order no)
; call prtstr
; db ': ',0
; call prwval
; call prwval
; call prwval
; call prwval
; call prwval
; call CrLf
; jmp short sgplp
;sgpends:
jmp nxcmd

prwval: mov dx,[bx]
xchg bx,dx
call Print00BX_
xchg bx,dx
inc bx
inc bx
ret
;--------------------------------
;SEARCH FOR HEX WORD
CmSearch:
;call sgreqs
mov bx,offset cmdbuf+3 ;1st char after the S
mov al,[bx]
cmp al,cr
jz ContinueSearch
call gtval ;word to search for to DX (less curorg)
add dx,curorg ;correct it
mov fndadd,dx
mov SearchPointer,0
xor dx,dx
cmp al,cr
jz ContinueSearch
call delim
l09c6: inc bx
call gtval ;start addr of search to DX (w.r.t. ORG)
cmp al,cr
jz StartSearch
call cmerr

StartSearch:
mov es,curpar
mov SearchPointer,dx
ContinueSearch:
call prtstr
db 'Lo-Hi word found at ',0
mov bx,fndadd
xchg bx,dx
;this is the step-&-compare loop
nyet: call BreakChk
;check for end of pgm
mov ax,PgmBytes ;end of pgm **64K max**
mov bx,SearchPointer
cmp bx,ax
jng NotPast
call prtstr
db cr,lf,'End of program reached',cr,lf,0
jmp nxcmd
NotPast:
mov es,curpar
mov al,es:[bx] ;get byte in target pgm
inc bx
mov SearchPointer,bx
cmp al,dl ;match?
jnz nyet
mov es,curpar
mov al,es:[bx] ;get next byte
cmp al,dh ;match too?
jnz nyet
;the word matches
push bx
push dx
dec bx
add bx,curorg ;correct the find addr for ORG
call Print00BX_
pop dx
pop bx
call prspc
jmp nyet ;continue searching

;--------------------------------
;The 'Z' command, also used when Control E found while Unassembling.
cmeof: mov al,ASMopenFlag
or al,al
jnz CloseRSM
call pstg
db 'END',cr,lf,0 ;to screen only
jmp nxcmd

CloseRSM:
mov wfiflg,1 ;print to file, too
call pstg
db cr,lf,'CSEG',tab,'ends'
db cr,lf,tab,'END',0
cmp EXTflag,'C'
jz DoStart
cmp EXTflag,'E'
jnz StartFin
DoStart:
call pstg

db tab,'Start',cr,lf,0
StartFin:
call WriteNclose ;add 1Ah, flush buffer to disk
mov wfiflg,0 ;no more printing to file
mov ASMopenFlag,0
call prtstr
db cr,lf,'.RSM file is closed',cr,lf,0
jmp nxcmd

;--------------------------------
EXTtoSpec:
mov di,DotPtr
inc di
;put \path\name or .ext [BX] in FileString [DI] - stops at a '.' w/C set
MoveField:
mov al,[bx]
cmp al,cr
jz MovDone
mov [di],al
cmp al,'.'
jz DotFound
or al,al
jz MovDone
inc di
inc bx
jmp short MoveField

MovDone:
clc
ret

DotFound:
stc
ret

;--------------------------------
cmload: mov al,ASMopenFlag
or al,al
jz OKtoLoad
jmp ASMstillOpenErr

OKtoLoad:
mov bx,offset cmdbuf+3 ;BX > 1st char after the 'L'
mov al,byte ptr cmdbuf+4 ;2nd char after the 'L'
cmp al,' ' ;2nd char blank?
jnz NameEntered
call cmerr

NameEntered:
mov di,offset FileString
cmp al,':' ;drive specified ?
jnz nodriv
mov al,byte ptr cmdbuf+3
inc bx
inc bx ;to 1st char after the colon
mov byte ptr [di],al
inc di
mov byte ptr [di],':'
inc di ;to area for \path\name
nodriv: call MoveField ;get \path\name, stops at a '.'
mov DotPtr,di ;save pointer to the '.'
mov byte ptr [di],'.' ;in case no '.' found
jnc SpecDone
inc di ;to byte after the dot
inc bx
call MoveField ;get .EXT
mov byte ptr [di],0 ;mark end of ASCIIZ string
stc
SpecDone:
jnc wntall ;if no .EXT entered
mov dx,offset LitALL
mov cl,3 ;bytes to compare at [BX]
call cmpstr
jz wntall ;want .ALL files
jmp ntlall ;if .EXT other than .ALL entered
wntall: call LoadAll
jmp nxcmd

LoadAll:
mov EXTflag,0
;try to load any file with name.COM, .EXE, or .SYS
call prtstr
db cr,lf,'Loading target file..',0
mov EXTflag,'C' ;in case a .COM is found
mov bx,offset LitCOM
call EXTtoSpec ;'COM',0 to filespec
call LoadPGM
jnc TargetLoadDone ;if successful
mov EXTflag,'E'
mov bx,offset LitEXE
call EXTtoSpec
call LoadPGM
jnc TargetLoadDone
mov EXTflag,0
mov bx,offset LitSYS
call EXTtoSpec
call LoadPGM
jnc TargetLoadDone
call prtstr
db tab,tab,tab,'.COM, .EXE, or .SYS FILE NOT FOUND',0
TargetLoadDone:
mov bx,offset LitREM
call EXTtoSpec
call prtstr
db cr,lf,'Loading .REM file..',0
call LoadREM
mov bx,offset LitCTL
call EXTtoSpec
call prtstr
db cr,lf,'Loading .CTL file..',0
call LoadCTL
mov bx,offset LitSMB
call EXTtoSpec
call prtstr
db cr,lf,'Loading .SMB file..',0
call LoadSMB
call crlf
ret

ntlall: mov bx,DotPtr
inc bx
mov cl,3
mov dx,offset LitSMB ;LitSMB holds 'SMB'
call cmpstr
jnz AintSMB
call LoadSMB
call crlf
jmp nxcmd

AintSMB:
mov dx,offset LitCTL
call cmpstr
jnz AintCTL
call LoadCTL
call crlf
jmp nxcmd

AintCTL:
mov dx,offset LitREM
call cmpstr
jnz AintREM
call LoadREM
call crlf
jmp nxcmd

AintREM:
mov dx,offset LitALL
call cmpstr
jnz AsTarget
call LoadALL
jmp nxcmd

;load any other .ext as target pgm
AsTarget:
mov EXTflag,0
mov dx,offset LitCOM
call cmpstr
jnz TryEXE
mov EXTflag,'C'
jmp short NowLd
TryEXE: mov dx,offset LitEXE
call cmpstr
jnz NowLd
mov EXTflag,'E'
NowLd: call LoadPGM
jnc TgtMsg
call OpenError
call crlf
jmp nxcmd

TgtMsg: call prtstr
db 'Loaded specified file as target program.',cr,lf,0
jmp nxcmd

;--------------------------------
;LOAD pgm at curpar (end of RE-SOURC + buffers) & set pcntr to 0

LoadPGM:
call fopen ; open file. Saves BX.
jnc cmdlds ; opened successfully
ret
;this is approx 1A70 in code
cmdlds: call erstbl ; erase seg table (presently unused)
mov segsho,205 ; reset cmd line arrow
call ClearTables ; reset ctl, rem, smb tables
mov ah,42h ; move pointer, returns size in DX:AX
mov al,2 ; move to EOF + CX:DX
xor cx,cx
xor dx,dx
mov bx,Handle
int 21h
mov PgmBytes,ax
mov PgmBytes+2,dx
;convert Pgmbytes to paras
mov cx,4
llll: shr dx,1
rcr ax,1
loop llll
or dx,dx ;over 1 meg ?
jnz pppp
cmp ax,0FFFEh ;just at 1 meg ?
jna oooo
pppp: mov ax,0FFFEh ;1 meg max, ALLOC MEM below is more limiting
oooo: inc ax ; for round-off
mov PgmParas,ax ; size of Target Pgm in paragraphs
;reset file pointer to start of file
mov ah,42h ;move file pointer
xor al,al ;move to CX:DX
xor cx,cx
xor dx,dx
mov bx,Handle
int 21h
;Store locn of end of RE-SOURCE
mov bx,rembas ; length of RE-SOURC program
mov cl,4
shr bx,cl
add bx,600h ; 24K in paras, for remark table
mov ax,cs
add ax,bx ; seg of end of RE-SOURC w/buffers,
mov curpar,ax ; = current para of target pgm
;change size of allocated memory
mov bx,cs ;no math on seg registers !
sub ax,bx ;length of RE-SOURCE in paras
add ax,PgmParas
jnc nnnn
mov ax,0FFFFh ;crude trap for over 1 Meg
nnnn: mov bx,ax ;paras requested
push cs
pop es ;seg of block to change
push ax
mov ah,4Ah ;change allocated block
int 21h
pop ax ;paras requested
jnc ReadFile
;insufficient RAM for target program
sub ax,bx ;shortfall
mov bx,ax
call prtstr ;saves BX
db cr,lf,'Not enough memory, you need ',0
call Print00BX_
call prtstr
db ' paras more...',cr,lf,0
clc ;no '.COM, etc NOT FOUND' message
ret
;Read a file with 32-bit length
;(this might be simpler if you can read 0 bytes)
ReadFile:
mov ParasRead,0
mov cx,PgmBytes ;bytes to load, lo word
mov dx,word ptr PgmBytes+2 ;hi word
ReadMore:
or dx,dx ;over 64K left ?
jnz Read64 ;yes, read 64K bytes
push dx ;will pop as CX so CX:DX=0 => done
jmp short ReadSome ;read CX bytes

Read64: sub cx,0FFFFh
sbb dx,0 ;DX:CX = DX:CX - 64K
push cx
mov cx,0FFFFh ;read 1st 64K
ReadSome:
push dx
mov bx,Handle
push ds
mov ax,curpar ;end of RE-SOURCE and its buffers
add ax,ParasRead
mov ds,ax ; is seg of target buffer
xor dx,dx ;start target buffer on para boundary
mov ah,3Fh ;read w/handle, 64K bytes max
int 21h
pop ds
pop dx
pop cx
jc ReadErr
;are we done reading ?
add ParasRead,1000h
or cx,cx
jnz ReadMore
or dx,dx
jnz ReadMore
call prtstr
db 'Size of loaded file in paragraphs = ',0
mov bx,PgmParas
call Print00BX_
call CrLf
call fclose ;reads use fclose, writes use WriteNclose
mov pcntr,0 ;'real' addr to unassemble
mov DumpStart,0 ;Dump command's start addr
;set END & ORG
cmp word ptr PgmBytes+2,0
jnz CantEnd
mov dx,PgmBytes ;lo word of file length***MAX 64K !!
mov al,'E'
call ALtoCTLatDX
CantEnd:
mov curorg,0
cmp EXTflag,'C'
jnz OrgZero
;It's a .COM file, set ORG
mov curorg,100h
OrgZero:
mov ChgFlag,0 ;for 'Update/Exit'
clc ;no '.COM, .EXE, etc NOT FOUND'
ret

ReadErr:
push ax
call prtstr
db cr,lf,'Error reading file: Func 3Fh, AX returned ',0
pop bx
call Print00BX_
call prtstr
db 'hex',cr,lf,0
ret

;--------------------------------
LoadSMB:
mov bx,symbas ;table start
mov REMflag,0 ;do SMB, not REM file
call LoadREMorSMB
jc gggg
mov symtp,bx
mov byte ptr [bx+3],0 ;zero count = end flag
clc
gggg: ret ;w/C set if not found

LoadREM:
mov bx,remtbl
mov REMflag,1
call LoadREMorSMB
jnc MarkRemEnd
ret

MarkRemEnd:
mov remend,bx
mov word ptr [bx],0FFFFh
ret

LoadREMorSMB:
call fopen ;C set if file not found
jnc RemSmbCharLoop
call OpenError ;print 'File Not Found'
ret

RemSmbCharLoop:
call GetByte ;get 1 byte from buffer, read if req'd
cmp al,1Ah
jnz l0b6c
call fclose
ret

l0b6c: cmp al,' '
jb RemSmbCharLoop ;eat CR, LF, ctrl chars
call hexbin ;hex to binary, variable, space ends
mov [bx],dx
inc bx
inc bx
test byte ptr REMflag,1 ;DAMN MASM requires BYTE PTR
jnz drdsk1
;for SMB file only:
call GetByte
mov [bx],al ;OprndType byte
inc bx
call GetByte ;eat delim space
drdsk1: push bx ;save locn for count
inc bx
xor ch,ch
lpasld: call GetByte
cmp al,tab
jz FoundDelim
cmp al,cr
jz FoundDelim
mov [bx],al
inc bx
inc ch ;char count
jmp lpasld

FoundDelim:
pop si
xchg bx,si
push si
mov [bx],ch ;store byte count
pop bx
jmp RemSmbCharLoop

hexbin: xor dx,dx
l0ba3: cmp al,' '
jnz l0ba8
ret

l0ba8: cmp al,1Ah
jnz l0baf
jmp UnexpEOF

l0baf: call DigitToDX
call GetByte
cmp al,1Ah
jnz l0ba3
jmp UnexpEOF

DigitToDX:
cmp al,'9'+1 ;can it be decimal digit ?
jb l0bb5
sub al,7 ;alpha to hex
l0bb5: sub al,'0' ;30h, to binary
add dx,dx
add dx,dx
add dx,dx
add dx,dx ;now DX times 16d
add al,dl
mov dl,al
ret

;--------------------------------
;put d:\path\name entered in GTCMD into FileString
CmPath: mov bx,offset cmdbuf+3 ;1st byte past the 'P'
mov di,offset FileString
call MoveField ;stops at CR or '.'
mov byte ptr [di],'.'
mov DotPtr,di
jmp nxcmd
;--------------------------------
CmRAMpara:
mov bx,offset cmdbuf+3 ;1st char after the R
mov al,[bx]
cmp al,cr
jnz NewPara
call ShowAddr ;just show curr value
jmp nxcmd
NewPara:
mov EXTflag,0 ;in case a .SMB file is to be loaded
call gtval ;hex no. entered - curorg to DX
add dx,curorg
cmp al,cr ;end of entry ?
jz RAMparaOK
call cmerr
RAMparaOK:
mov curpar,dx
mov DotPtr,0 ;to flag .RSM header routine
mov curorg,0 ;ORG = 0 for RAM unassemblies
call ShowAddr
jmp cmpurg ;Dump .REM, .CTL, .SMB tables ?

ShowAddr:
call prtstr
db 'ORG = 0 at ',0
mov bx,curpar
call Print00BX_
call prtstr
db ': 0000',0
call CrLf
ret

;--------------------------------

;erase the seg tables - called by Load .COM file, cmpurg
erstbl: mov bx,offset cstbl
mov nrsegs,0
mov ch,8
etlp1: mov cl,5
mov ax,' '
etlp2: mov [bx],ax
xor ax,ax
inc bx
inc bx
dec cl
jnz etlp2
inc bx
inc bx
dec ch
jnz etlp1
ret

;--------------------------------
SaveAll:
mov ChgFlag,0 ;for 'Update/Exit' in CmExit
mov dx,remend
mov bx,remtbl
cmp bx,dx
jz nosrem
mov bx,offset LitREM
call EXTtoSpec
call prtstr
db cr,lf,'Saving .REM file..',0
call SaveREM
nosrem: mov dx,symtp
mov bx,symbas
cmp bx,dx
jz nossym
mov bx,offset LitSMB
call EXTtoSpec
call prtstr
db cr,lf,'Saving .SMB file..',0
call SaveSMB
nossym: mov dx,ctltop
mov bx,offset ctlbas
cmp bx,dx
jnz havctl
jmp nxcmd
havctl: mov bx,offset LitCTL
call EXTtoSpec
call prtstr
db cr,lf,'Saving .CTL file..',0
call prtstr
db cr,lf,0
jmp SaveCTL

;--------------------------------
;save labels (routine at l0bf4 also used to save remark table)
SaveSMB:
mov bx,symbas
mov REMflag,0 ;saving .SMB, not .REM

l0bf4: call creatf
l0bf7: mov dx,[bx] ;address in rem or smb table
inc bx ;to 2nd addr byte
test byte ptr REMflag,1
jnz sdskp1 ;if .REM, no type byte
inc bx
mov ah,[bx] ;OprndType byte
sdskp1: inc bx
mov al,[bx] ;string length
inc bx ;to 1st byte of string
mov ch,al
or al,al
jz oufend ;end of table found
push ax ;save OprndType byte
call outadr ;convert to hex & write 4 char number
mov al,' '
call WriteChar
pop ax
test byte ptr REMflag,1
jnz StringLoop ;if doing REM, not SMB
mov al,ah ;get OprndType byte
call WriteChar
mov al,' '
call WriteChar

StringLoop:
mov al,[bx]
call WriteChar
inc bx
dec ch
jnz StringLoop
mov al,cr
call WriteChar
mov al,lf
call WriteChar
jmp l0bf7

oufend: call WriteNclose ;flush buffer to disk
ret

outadr: mov al,dh
call hexl
call WriteChar
mov al,dh
call hexr
call WriteChar
mov al,dl
call hexl
call WriteChar
mov al,dl
call hexr
jmp WriteChar

;--------------------------------
ChkNoFSpec:
cmp DotPtr,0 ;any filespec been entered ?
jz PutRAMaddr
ret
;R command has been used, or no file has been loaded
PutRAMaddr:
mov di,offset FileString
mov bx,offset SEG_string
call MoveField
mov bx,di
mov ax,curpar
xchg al,ah
call StoreHex ;AL to 2 hex bytes [BX] & inc BX
xchg al,ah
call StoreHex
mov byte ptr [bx],'.'
mov DotPtr,bx
ret

;Enable saving .RSM file as you Unasm
CmWriteRSM:
mov ASMopenFlag,1
mov wfiflg,0 ;don't write message to file
call ChkNoFSpec ;save as 'SEG_nnnn.RSM' if doing RAM
mov bx,offset LitRSM
call EXTtoSpec
call creatf
call prtstr
db ' Writing .RSM is enabled... '
db 'use Z command to close file before END',cr,lf,cr,lf,0
;create .RSM header (title, org addr, equ's for labels outside the pgm)
mov wfiflg,1 ;write to both screen & file
call pstg
db ';Re-Source Disassembly of ',0
mov bx,offset FileString
FileNameLoop:
mov al,[bx]
cmp al,'.' ;don't print '.RSM'
jz PrintHeader
or al,al ;end of string ?
jz PrintHeader
call typech
inc bx
jmp short FileNameLoop

PrintHeader:
test Direc286Flag,1
jz NoDirec
call pstg
db cr,lf,'.286P',0 ;file has '186+ instr's
;note: .386P calls MOV wr,OFFSET H001234 "illegal size for operand"
NoDirec:
call pstg
db cr,lf,cr,lf,'cr',tab,'EQU',tab,'0Dh'
db cr,lf,'lf',tab,'EQU',tab,'0Ah'
db cr,lf,'tab',tab,'EQU',tab,'9'
db cr,lf,'bel',tab,'EQU',tab,'7'
db cr,lf,cr,lf,'CSEG',tab,'segment',tab,'byte public',0
cmp EXTflag,'E'
jz SegsDone
call pstg
db cr,lf,tab,'assume',tab,'CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG',0
SegsDone:
mov OutsideFlag,0 ;don't print header if none outside
xor cx,cx ;start at beginning of pgm
mov bx,symbas
FarLabelLoop:
inc bx
inc bx
inc bx ;>length byte
mov al,[bx]
or al,al ;0 marks end of table
jnz l032c ;not table end, check for more labels
cmp EXTflag,'E'
jz OrgDone
call pstg
db cr,lf,cr,lf,tab,'ORG',tab,0
mov dx,curorg
call PrintDXh
OrgDone:
call CrLf
call CrLf
jmp nxcmd

l032c: dec bx
dec bx
dec bx ;>addr @ 1st of entry
push bx
push cx ;pointer to code
inc bx
inc bx
inc bx
;only print labels outside the pgm
push bx ;>length byte
dec bx
dec bx
dec bx
mov dx,[bx] ;label's addr
cmp dx,PgmBytes ;1st after pgm, locn of END**64K max**
jb nodisp
pop bx
;print the label
cmp OutsideFlag,0
jnz NoOutsideHdr
call pstg
db cr,lf,cr,lf,';Labels outside the program:',cr,lf,0
mov OutsideFlag,1 ;flag it's been printed
NoOutsideHdr:
mov ch,[bx] ;length of label
l0362: inc bx
mov al,[bx]
call typech
dec ch
jnz l0362
call pstg
db tab,'EQU',tab,'$+',0
pop cx ;pointer to code
pop bx ;>addr @ 1st of entry
push bx
mov dx,[bx]
inc bx
inc bx ;to type byte
add dx,curorg ;correct all addrs for ORG
mov al,dh
call xo0
mov al,dl
call xo
call pstg
db 'h',cr,lf,0
pop bx ;>addr @ 1st of entry
l0394: inc bx
inc bx
inc bx ;to 4th (length) byte
mov al,[bx]
xor ah,ah
add bx,ax
inc bx ;to 1st of next label entry
call BreakChk ;test for Ctrl-Break
jmp FarLabelLoop ;loop to next entry in symbol table

nodisp: pop bx
pop cx
pop bx
jmp l0394
;--------------------------------

SaveREM:
mov REMflag,1
mov bx,remend
inc bx
inc bx ;2 bytes past end
mov byte ptr [bx],0 ;mark length byte so end will be found
mov bx,remtbl
jmp l0bf4

;--------------------------------
ASMstillOpenErr:
call prtstr
db 'NO FILE ACCESSES UNTIL .RSM CLOSED',cr,lf,0
jmp nxcmd

;an EOF has been found in the middle of a number, jumped to 2 places
UnexpEOF:
call prtstr
db 'Unexpected EOF',cr,lf,0
jmp nxcmd
;--------------------------------
;SET CONTROL or dump CTL table

;control table structure:
; cfence is ctltbl-1, holds mode char for 1st line
; each entry 4 bytes: 1 byte segment char,
; 2 byte address, 1 byte mode char (BEHISW).
; Table terminated by 0FFFFh in address bytes

cmctl: ;call sgreqs
mov bx,offset cmdbuf+3 ;1st byte after the C in the command
mov al,[bx]
cmp al,cr ;C alone ?
jnz ChkNnList ;command has more than C
jmp ShowCTLtable

ChkNnList:
call gtval
cmp al,cr ;C and just a no.
jnz setctl ;more follows the number
jmp ListCtl ;list .CTL from NNNN

setctl: call delim
l0d5a: inc bx
mov al,[bx] ;BEHISW to use
call ALtoCTLatDX ;make a manual entry in .CTL table
jmp nxcmd

;called by A command only. Enter w/new char in AL, DX=locn
EnterCTL:
push bx
push dx ;pcntr
push ax ;save CTL char in AL
call ctlook ;search ctl table
jc OldEntry ;if table end or past right addr
add bx,4 ;point to curr entry
OldEntry:
pop ax ;the CTL char
pop dx ; and pcntr location
dec bx ;to mode char at this or last locn
cmp al,[bx] ;compare to current mode char
pop bx
jnz ALtoCTLatDX ;if different from CTL at this or last
ret

;make manual entry in .CTL table - AL=ctl char, DX=addr
ALtoCTLatDX:
mov typndx,al ;save CTL char (BEHIS or W)
call ctlook ;if found, BX points to entry in ctltbl
jnc ChgExist ;if matches an existing entry
jmp NewCtl ;make a new entry

ChgExist:
mov al,typndx ;recover the char
call cltrck ;test all legal values
mov ChgFlag,1 ;for 'Update/Exit'
cmp al,'K'
jz KillIt
jmp ChgCtl ;modify existing entry

KillIt: mov ax,[bx+1] ;addr field of entry
cmp ax,0FFFFh
jz l0bf5 ;if at table end
mov cx,4 ;entry length
KillLoop:
mov al,[bx+4] ;move from higher rec
mov [bx],al ;down to lower rec
inc bx
loop KillLoop
jmp KillIt ;repeat for rest of recs

;entries past kill are all moved down
l0bf5: sub bx,4 ;base of last valid entry
jmp nxcmd

cltrck: cmp al,'K'
jz cltrrt
ChkValidCtl:
cmp al,'E'
jz cltrrt
cmp al,'B'
jz cltrrt
cmp al,'H'
jz cltrrt
cmp al,'W'
jz cltrrt
cmp al,'I'
jz cltrrt
cmp al,'S'
jz cltrrt
call cmerr
cltrrt: ret

;make a new entry in the .CTL table - AL=type, DX=addr.
; ctlook returned C set, BX > entry for next higher addr.
NewCtl: mov al,typndx ;the BEHIS or W
call ChkValidCtl ;to cmerr if not valid
mov ChgFlag,1 ;for 'Update/Exit'
push dx ;addr of the entered control
push bx ;location for new entry
mov bx,offset ctlbas
FindEndLoop:
mov ax,[bx+1] ;addr of this entry
add bx,4 ;to start next entry
cmp ax,0FFFFh ;end of table ?
jnz FindEndLoop
;now BX points to the end-marker 0FFFFh entry
mov dx,bx
add dx,4 ;make space for new FFFF entry
pop cx ;was BX, > next higher entry
entrc8: dec bx ;to seg (1st) char first
dec dx ;dest
mov al,[bx] ;old entry byte
xchg bx,dx
mov [bx],al ;to new place higher
xchg bx,dx
cmp dx,cx ;at insert location yet?

jnz entrc8 ;no, loop
;make the entry
mov bx,cx ;restore table pointer
pop dx ;pcntr value to store
mov ch,segsho ;segment char (now always 205d)
mov [bx],ch
mov [bx+1],dx ;store address
mov al,typndx
mov [bx+3],al ;store CTL code
add bx,4
ret

;modify existing entry
ChgCtl: mov ah,segsho ;segment char (now always 205d)
mov [bx],ah
mov [bx+3],al ;modify existing entry (the BEHIS or W)
ret

;--------------------------------
;Check the .CTL table for entry @DX. 4 bytes/entry. Rets w/BX pointing
;to ctlbas+0, +4 etc of entry for addr just past DX. Uses AX, BX, CX; saves DX

ctlook: mov bx,offset ctlbas ;point BX at table's start
mov ch,segsho ;(presently always 205d)
LookLoop:
mov ax,[bx+1] ;addr value
cmp ax,0FFFFh ;end of table ?
stc
jnz l0e4s ;wasn't the end
ret ;w/carry set if no match below end

l0e4s: cmp ch,[bx] ;(presently always 205d)
jz l0e48 ; in right segment
l0e5c: jnb ctlk4 ;still too low in table
ret ;too far, stop w/carry set

l0e48: cmp dx,[bx+1]
jnz l0e5c
ret ;found exact match

ctlk4: add bx,4 ;to next entry
jmp short LookLoop
;--------------------------------

ListCtl:
mov EntriesLeft,4
call ctlook ;find starting entry
jmp clist
;--------------------------------
;display the .CTL table in 4 columns
ShowCTLtable:
mov EntriesLeft,4
mov bx,offset ctlbas ;start with first CTL entry
clist: call BreakChk ;test for user break
mov dx,1[bx] ;addr of entry
add bx,3 ;last of this entry, the BESHI or W
cmp dx,0FFFFh
jnz clist2 ;not at table end
call CrLf
jmp nxcmd

clist2: mov al,-3[bx] ;1st of this entry, the seg char
cmp al,segsho ;is special seg char showing?
jnz skclis ;if so, skip this entry
push bx
mov bx,dx
add bx,curorg ;correct for ORG
call Print00BX_ ;print location
call prtstr
db '= ',0
pop bx
mov al,[bx]
call typech ;ctl char from table (BEHIS or W)
call prspc
push dx
push bx
call symluk ;symbol at this address?
jc NoLblCtl
;locn has label, CH is length, BX points to start ot text
mov EntriesLeft,1 ;signal no more entries on this line
call prtstr
db '= ',0
call PrtCHbytesPerBX
NoLblCtl:
pop bx
pop dx
call prspc
call prspc
call ChkEntryCt
skclis: inc bx
jmp clist

;--------------------------------
SaveCTL:
call creatf ;make a new file
mov bx,offset ctlbas ;start of CTL table
NxtEntry:
mov dx,1[bx] ;address value
cmp dx,0FFFFh
jz HitEnd ;0FFFFh is flag for end of table
mov al,[bx] ;seg char
call WriteChar
call outadr ;convert to hex & write 4 chars
mov al,','
call WriteChar
mov al,3[bx]
call WriteChar
mov al,cr
call WriteChar
mov al,lf
call WriteChar
add bx,4
jmp NxtEntry

HitEnd: jmp WriteNclose

;--------------------------------
;.CTL file format: 1 line/entry, seg byte, variable length hex address
; (always 4 chars now), a comma, and the Ctl byte (BEHISW). E.g., Í0123,B

LoadCTL:
call fopen ;C set if file not found
jnc FoundCTL
call OpenError
ret

FoundCTL:
mov bx,offset ctlbas
CtlLineLoop:
call GetByte ;get byte from buffer, read another 128 if empty
cmp al,1Ah
jz IsEOF
cmp al,' '+1
jb CtlLineLoop ;eat space, CR, LF, ctrl chars
mov [bx],al ;segment char (now always 205d)
call GetByte ;1st byte of hex address
xor dx,dx ;clear addr accumulator
CtlDigitLoop:
cmp al,1Ah
jz IsEOF
cmp al,',' ;comma marks end of addr field
jz ItsComma
call DigitToDX
call GetByte
jmp CtlDigitLoop

ItsComma:
mov 1[bx],dx
call GetByte
mov 3[bx],al
add bx,4
jmp CtlLineLoop

IsEOF: mov word ptr 1[bx],0FFFFh
add bx,4
call fclose
ret
;--------------------------------
; ADD REMARKS

; remark table structure, variable length records:
; 2 byte address, 1 byte string count, n byte string
; table terminated by 0ffffh in address field
; if 1st char = ; remark appended to instruction
; else remark on separate line before instruction

cmrem: ;call sgreqs
mov bx,offset cmdbuf+3 ;1st char after the ';'
mov al,[bx]
cmp al,cr
jnz cmnt1
jmp DumpRem ;dump the remark table

cmnt1: call gtval ;addr of remark to DX, corrected for ORG
inc bx
cmp al,cr
jnz l0f52
jmp adr_dmp ;user entered ;NNNN (dump remarks from NNNN)

l0f52: call delim
push bx
;at this point, a Rem will be added or deleted
mov ChgFlag,1 ;for 'Update/Exit'
call RemChk ;point BX at entry for addr user has input
jc AddRem ;jump if at end of table, no remark here
call delrem ;delete any existing remark
pop bx ;pointer to cmdbuf
push bx
mov al,[bx]
cmp al,cr ;input was ;NNNN, (delete remark at NNNN)
jnz AddRem
jmp nxcmd
;make new entry at end of table
AddRem: mov bx,remend
mov [bx],dx ;addr for the new last entry
inc bx
inc bx ;to String Count byte
pop si ;points in cmdbuf
xor ch,ch ;clear string count
mov di,bx ;bx still holds pointer to String Count
inc di ;point to first char for remark string
push cs
pop es ;just to be sure
RemCharCopy:
lodsb ;get char from cmdbuf & inc SI
cmp al,cr ;is it CR ?
jz EndRemStr
stosb ;put it in rem table & inc DI
inc ch
jmp short RemCharCopy
EndRemStr:
mov remend,di
mov word ptr [di],0FFFFh
mov [bx],ch ;string count
jmp nxcmd

;--------------------------------
;point BX to entry at addr in DX. C set if not found.
RemChk: mov bx,remtbl ;points to rembas
NxtRem: cmp word ptr [bx],0FFFFh ;check for end-of-table
jnz RemsGoOn
stc
ret ;w/carry if at end of table

RemsGoOn:
cmp dx,[bx]
jnz l0fc3
ret ;w/BX > matching addr and no carry

l0fc3: inc bx
inc bx
mov al,[bx] ;length of remark
call AddALtoBX
inc bx
jmp NxtRem
;--------------------------------
adr_dmp:
call RemChk ;point BX at entry user has input
jmp l0fd8

;dump the remarks table to the screen
DumpRem:
mov bx,remtbl ;point BX at start of table
l0fd8: call BreakChk ;check for CTRL-BREAK
mov dl,[bx]
inc bx
mov dh,[bx]
inc bx
mov al,dh
and al,dl
inc al
jnz l0fec
jmp nxcmd

l0fec: xchg bx,dx
push bx
add bx,curorg ;correct printed address for ORG
call Print00BX_
pop bx
xchg bx,dx
mov al,';'
call typech
mov ch,[bx] ;length of remark
l0ffa: inc bx
mov al,[bx]
call typech
dec ch
jnz l0ffa
call CrLf
inc bx
jmp l0fd8
;--------------------------------
;enter w/BX > entry for addr in DX that user has input. Saves DX.
delrem: cmp word ptr [bx],0FFFFh
jnz l1015
ret ;if at end of table

l1015: push dx
mov dx,bx ;now DX > start of entry to overwrite
inc bx
inc bx
mov al,[bx]
call AddALtoBX
inc bx ;to start of next entry's string
xor ch,ch
l1023: mov al,[bx]
xchg bx,dx
mov [bx],al
xchg bx,dx
inc bx
inc dx
mov cl,al ;char just moved
and al,ch ;AND previous char moved
inc al ;if both were 0FFh, gives Z
mov ch,cl ;save char just moved
jnz l1023 ;loop if not at end of table
xchg bx,dx
dec bx
dec bx
mov remend,bx
pop dx
ret

;==============================================================================
;Start of actual disassembly routines.


LitStart db 'Start'

;Print any label to screen and file, space & addr at start of line to scrn only
AddrOrSmb:
push ax
push dx
push bx
mov wfiflg,1 ;print to output file, too
mov dx,pcntr
;insert 'Start' in B mode if .COM file at 100h, for MASM
cmp BmodeFlag,0
jz NoStart
or dx,dx
jnz NoStart
cmp EXTflag,'C'
jnz NoStart
mov bx,offset LitStart
mov ch,5 ;length of 'Start'. DX is already 0000.
call symtch ;inserts sym if not already present
NoStart:
mov dx,pcntr
call symluk ;BX>label, CH=label length, carry if no label
jc NoLblHere
;print the label
push cx ;save label's length
call PrtCHbytesPerBX
pop cx
;check for non-Instruction
cmp ColonFlag,0
jz ItsAnInstr
;no addr as comment for DB, DW, DS lines, MASM req label on SAME LINE !
cmp ch,7
jna TabExit
mov wfiflg,1 ;now print to file, too
call prspc
jmp JusExit

ItsAnInstr:
mov al,':'
call typech ;saves CX
inc ch ;length of label determines no. of Tabs
cmp trmflg,0
jz AddrAsComment
;trim is on, check for label over 7 chars long
cmp ch,7
jna TabExit
call CrLf
jmp TabExit

AddrAsComment:
call PrtTab
call PrtTab
cmp ch,8
jae NoMoreTab
call PrtTab ;extra tab to keep label addr's aligned
NoMoreTab:
call semic ;print a semicolon
mov bx,pcntr
add bx,curorg ;correct for ORG
call Print00BX_ ;print address
call CrLf
jmp TabExit

;line has no label, just print address
NoLblHere:
mov wfiflg,0 ;don't print to .RSM file, just screen
call prspc ;print the space at start of line
mov bx,pcntr
add bx,curorg ;correct for ORG
call Print00BX_ ;print address
TabExit:
mov wfiflg,1 ;now print to file, too
call PrtTab
JusExit:
pop bx
pop dx
pop ax
ret

;--------------------------------
;UNASSEMBLE A LINE OF CODE at [curpar:pcntr] - always called w/wfiflg=0

dline: mov es,curpar
mov OprndType,10h ;DS unless changed, do correct for ORG
mov bx,pcntr
mov curadr,bx
inc pcntr
;Find Op Code in opct table
mov ch,es:[bx] ;first byte of code for this line
mov CurInstr,ch ;also signals blank line if req'd
mov bx,offset opct-7
mov dx,7 ;size of table entry -1

OpLineLoop:
add bx,dx
mov al,cs:[bx] ;starts at beginning of opct table
or al,al
jnz KeepLooking
jmp PrtDBandByte ;end of table

KeepLooking:
and al,ch
mov cl,al ;masked opcode
inc bx
mov al,cs:[bx]
cmp al,cl ;nxt byte in opct match masked opcode?
jnz OpLineLoop
inc bx ;to 3rd byte of line in opct,
mov al,cs:[bx] ; the instr's Kind no.
mov typndx,al ;typndx also holds the BEHISW later

;PRINT THE OP CODE (the instruction)
mov ch,5 ;every entry is 5 bytes incl the ...
OpLoop: inc bx
mov al,cs:[bx]
cmp al,'.' ;dot is ignored
jz nodot
call typech ;print opcode char
nodot: dec ch
jnz OpLoop

mov dl, typndx
and dl,3Fh
xor dh,dh
mov bx,offset jmptbl
add bx,dx
add bx,dx
mov dx,cs:[bx]
mov bx,curadr
mov al,es:[bx]
;pick out the '186+ op codes. 0F, C0 and C1 done in kindXX routines.
;The codes are 60-63, 68-6F, C8 and C9
cmp al,0C8h
jz Is186
cmp al,0C9h
jz Is186
cmp al,60h
jb GoJmp
cmp al,6Fh
ja GoJmp
cmp al,68h
ja Is186
cmp al,64h
ja GoJmp
Is186: mov Direc286Flag,1 ;this is a '186+ instr
GoJmp: jmp dx ;with AL, CurInstr, BX and curadr set

;Jump table is indexed by typndx.
;See list of which codes are which KIND at opct table.

jmptbl dw offset kind00
dw offset kind01
dw offset kind02
dw offset kind03
dw offset kind04
dw offset kind05
dw offset kind06
dw offset kind07
dw offset kind08
dw offset kind09
dw offset kind10 ;'186 PUSH nnnn
dw offset kind11
dw offset kind12
dw offset kind13
dw 0 ;kind14 unused
dw offset kind15
dw offset kind16
dw offset kind17
dw offset kind18
dw offset kind19
dw offset kind20
dw offset kind21
dw offset kind22 ;'286 protected mode instrs
dw offset kind23
dw offset kind24
dw offset kind25
dw offset kind26
dw offset kind27
dw offset kind28
dw offset kind29
dw offset kind30
dw offset kind31
dw offset kind32
dw offset kind33
dw offset kind34
dw offset kind35
dw offset kind36
dw offset kind37
dw offset kind38
; - - - - - - - - - - - - - - - -
;Routines to print the operands. On entry:
;BX = curadr, points to the 1st op code byte. CurInstr holds op code.

kind00: jmp NewLine
; - - - - - - - - - - - - - - - -
kind01: call PrtTab ;IN AL or AX,DX and OUT DX,AL or AX
mov al,es:[bx]
test al,2
jnz k01out
test al,1
jnz k01iw
call pstg
db 'AL,DX',0
jmp NewLine

k01iw: call pstg
db 'AX,DX',0
jmp NewLine

k01out: test al,1
jnz k01ow
call pstg
db 'DX,AL',0
jmp NewLine

k01ow: call pstg
db 'DX,AX',0
jmp NewLine
; - - - - - - - - - - - - - - - -
kind02: ;IN AX,nn and OUT nn,AX
mov al,es:[bx+1]
mov CurModRegRM,al ;use for immed data
inc pcntr
inc curadr
call PrtTab
test byte ptr CurInstr,2 ; AND it w/2 to check bit 1
jnz OutnnAX
call pstg
db 'AX,',0
mov al,CurModRegRM
call PrintALh
jmp NewLine

OutnnAX:
mov al,CurModRegRM
call PrintALh ;print port no.
call pstg
db ',AX',0
jmp NewLine

; - - - - - - - - - - - - - - - -
kind37: ;IN AL,nn and OUT nn,AL
;same as kind02 above, except AL
mov al,es:[bx+1]
mov CurModRegRM,al ;use for immed data
inc pcntr
inc curadr
call PrtTab
test byte ptr CurInstr,2 ; AND it w/2 to check bit 1
jnz OutnnAL
call pstg
db 'AL,',0
mov al,CurModRegRM
call PrintALh
jmp NewLine

OutnnAL:
mov al,CurModRegRM
call PrintALh ;print port no.
call pstg
db ',AL',0
jmp NewLine

; - - - - - - - - - - - - - - - -
kind03: call PrtTab ;MOV immed data to reg
mov al,es:[bx] ;get the op code
inc pcntr
inc curadr
test al,8
jnz k03Word
and al,7
call namrg8
call comma
call bytopd
jmp NewLine

k03Word:
inc pcntr
and al,7
call namr16
call comma
jmp ImmedWord

; - - - - - - - - - - - - - - - -
kind04: ;byte arith, logic, CMP, TEST to AL
inc pcntr
call PrtTab
call pstg
db 'AL,',0
mov al,CurInstr
inc curadr
jmp OldArith
; - - - - - - - - - - - - - - - -

;ONE-BYTE operand shown as ASCII if so
bytopd: mov bx,curadr ;has been inc'd
mov al,es:[bx] ;get data byte
push ax
call PrtALasDB ;C set => don't show comment hex
pop ax
jnc ShAsCm
ret

ShAsCm: push ax
call PrtTab
call PrtTab
call semic ;print semicolon
pop ax
jmp PrintALh ;print actual code byte

PrtALasDB:
cmp al,cr
jnz cccc
call pstg
db 'cr',0
clc ;show as comment hex
ret

cccc: cmp al,lf
jnz dddd
call pstg
db 'lf',0
clc
ret

dddd: cmp al,' '
jb JustPrtNumber
cmp al,'z'+1
jnb JustPrtNumber
;print AL in quotes
call apostrophe
cmp al,''''
jnz Normal
call apostrophe ;print an extra '
Normal: call typech
call apostrophe ;print ending quote
clc ;show as comment hex
ret

JustPrtNumber:
call PrintALh
stc ;don't show as comment hex
ret

; - - - - - - - - - - - - - - - -
kind05: call PrtTab ;CALL/long JMP to relative address - word displ
inc pcntr
inc pcntr
inc bx
mov dx,es:[bx] ;displacement from 1st byte past instr
inc bx
inc bx ;to 1st byte past instr
add bx,dx
mov dx,bx ;now DX = pcntr + displ
mov RelFlag,1
or OprndType,2 ; word
call PrtNoOrSmb ;print DX + org, and ;ADDR if label, add SMB if in B
jmp NewLine
; - - - - - - - - - - - - - - - -
kind06: call PrtTab ;16-bit immediate data arith to AX
inc pcntr
inc pcntr
inc curadr
call pstg
db 'AX,',0
ImmedWord: ;used by kind10, PUSH immed & kind03, MOV immed
mov bx,curadr ;has been inc'd
mov dx,es:[bx]
ImSE: call symluk ;saves DX
jnc hvsym3 ;jmp if label
call PrintDXh ;print word in DX, followed by 'h'
jmp NewLine

hvsym3: call pstg
db 'OFFSET ',0
call HaveSmb
jmp NewLine

; - - - - - - - - - - - - - - - -
;print operand words following 'WORD PTR' (AddrOrSmb does line addrs)
; and Rel JMPs and CALLs. Adds symbols if in B mode.
PrtNoOrSmb:
mov al,OprndType
and al,00110000b ;look at seg override for this line
cmp al,10h ;is it DS:, the default set at Dline ?
jnz NoDS
cmp RelFlag,0
jnz NoDS ;no 'DS:' for JZ, LOOP, etc.
call pstg
db 'DS:',0 ;req'd by dumb MASM for [addr] !
NoDS: push dx ;holds the addr or data to print
call symluk ;check for symbol
pop dx
jnc HaveSmb ;print it
mkopds: cmp BmodeFlag,0 ;building symbols?
jz PrtAdr ;just print addr if not
push dx
call addsym ;this is the only call to addsym
pop dx
jmp PrtAdr ;it's too late to print new label (is it ??)

HaveSmb:
call PrtCHbytesPerBX
cmp NoCommentAddr,1
jz JustLabel
test byte ptr trmflg,0FFh
jnz JustLabel
call PrtTab
call semic
mov bx,dx ;the address
cmp RelFlag,0
jz NoCorr
add bx,curorg ;correct for ORG
NoCorr: jmp Print00BX_

JustLabel:
mov NoCommentAddr,0
ret

;print operand addr pushed on stack (line addrs done by Print00BX_)
;called only by mkopds
PrtAdr: cmp RelFlag,0
jz PrintDXh ;Jump for hard-coded addrs
add dx,curorg ;correct relative addrs for ORG,
PrintDXh: ;leading zeros only where MASM requires,
; EXCEPT, e.g., 400h shows as 0400h
mov al,'0'
or dx,dx
jz l147d
mov al,dh
or al,al
jz PrintDLh
call xo0
mov al,dl
call xo
phxsfx: mov al,'h'
l147d: jmp typech

PrintDLh:
mov al,dl
PrintALh:
cmp al,0Ah
jb padigt
call xo0
jmp phxsfx

padigt: add al,'0' ;30h
jmp typech
; - - - - - - - - - - - - - - - -
kind07: call PrtTab ;INT is the only kind07 opcode
inc pcntr
mov al,es:[bx+1]
call PrintALh
jmp NewLine
; - - - - - - - - - - - - - - - -
kind08: inc pcntr ;AAM, AAD. Doesn't check 2nd byte (0Ah)
jmp NewLine
; - - - - - - - - - - - - - - - -
kind09: call PrtTab ;lock/rep/repnz prefixes
jmp dline ;to continue instr
; - - - - - - - - - - - - - - - -
kind10: call PrtTab ;'186 PUSH nnnn
mov al,CurInstr
inc pcntr
inc curadr
cmp al,6Ah ;is the Sign-Extend bit set ?
jz SExt
inc pcntr
jmp ImmedWord ;print no. or 'OFFSET label'

SExt: xor dh,dh
mov bx,curadr
mov dl,es:[bx]
or dl,dl
jns ExDone
dec dh ;to 0FFh
ExDone: jmp ImSE ;last part of ImmedWord routine

; - - - - - - - - - - - - - - - -
kind11: call pcndop ;conditional jumps. 'J' has been printed.
kind21: call PrtTab ;JCXZ, JMP SHORT
mov al,CurInstr ;get op code byte again
cmp al,0EBh ;was it JMP SHORT, not JCXZ ?
jnz NoShort
call pstg
db 'SHORT ',0
NoShort:
inc pcntr
mov bx,curadr
inc bx
mov al,es:[bx] ;get displacement byte
test al,80h ;get sign
jnz k21neg
inc bx
call AddALtoBX
jmp k21add

k21neg: inc bx
not al
inc al
xor ah,ah
sub bx,ax
k21add: mov dx,bx
mov RelFlag,1 ;flag rel-displ for
call PrtNoOrSmb ; print DX + curorg, add SMB if in B mode
jmp NewLine
; - - - - - - - - - - - - - - - -
kind12: ;movs, cmps, lods, stos, scas
mov al,CurInstr
and al,1
jnz k12wrd
call pstg
db 'B',0
jmp NewLine

k12wrd: call pstg
db 'W',0
jmp NewLine
; - - - - - - - - - - - - - - - -
kind13: call pstg ;xchg ax,
db tab,'AX,',0
mov al,CurInstr
and al,7
call namr16
jmp NewLine
; - - - - - - - - - - - - - - - -
kind15: call PrtTab ;PUSH, POP, INC, DEC one 16 bit register
mov al,CurInstr
and al,7
call namr16
jmp NewLine
; - - - - - - - - - - - - - - - -
PrtRegOfRM:
mov bx,curadr
inc bx
mov al,es:[bx] ;get ModRegR/M byte
and al,00000111b ;look at R/M field only
jmp l156d

PrtReg: mov bx,curadr
inc bx
mov al,es:[bx]
and al,38h ;look at reg field only
shr al,1
shr al,1
shr al,1
l156d: push ax
;'286 LAR, etc are WORD reg's, must filter out
cmp LongFlag,0
jnz WordReg
mov bx,curadr
mov al,es:[bx] ;get current op code
test al,1
jnz WordReg
pop ax
jmp namrg8
WordReg:
pop ax
jmp namr16

;used for TEST, MOV, XCHG, kind18 arith, and '286 ARPL, LSL, LAR
ModRegRM:
mov bx,curadr
inc bx
mov al,es:[bx] ;get modregr/m byte
and al,11000000b ;the MOD field
or al,al
jz ChkQuirk ;no displacement unless [BP]
cmp al,11000000b
jz RMisReg
jmp Displacement

RMisReg: ;mod = 11
inc pcntr
mov bx,curadr
mov al,es:[bx] ;get op code again
cmp al,63h ;ARPL ?
jz RegLast
cmp al,69h ;'186 IMUL immed ?
jz RegFirst
test al,2 ;the D bit. Never set for TEST
; **** ignored for '286 long instrs ??
jnz RegFirst
RegLast:
call PrtRegOfRM
call comma
jmp PrtReg

RegFirst:
call PrtReg
call comma
jmp PrtRegOfRM

ChkQuirk: ; the MOD field is 00
inc pcntr
mov bx,curadr
mov al,es:[bx] ;get the op code again
cmp al,63h ;ARPL ?
jz QuirkRegLast
test al,2
jnz QuirkReg1st
QuirkRegLast:
call l1606
call comma
jmp PrtReg

QuirkReg1st:
call PrtReg
call comma
jmp l1606

Displacement: ;mod = 01 or 10, [XX+YY+disp]
inc pcntr
mov bx,curadr
mov al,es:[bx] ;get op code again
cmp al,63h ;ARPL ?
jz DisplFirst
cmp al,69h ;'186 IMUL ?
jz DisplLast
test al,2 ;set, 1st operand is displ, 2nd is reg
jnz DisplLast
DisplFirst:
call PrtPTRandDisplPerReg ;print XS:XXXX PTR nn[XX+YY]
call comma
jmp PrtReg

DisplLast:
call PrtReg
call comma
jmp PrtPTRandDisplPerReg

;This is a CALL from above ModRegRM routine - - - - -
l1606: cmp LongFlag,0
jnz DoWORD ;'286 0F-prefix instrs are WORD
mov bx,curadr
mov al,es:[bx]
test al,1
jnz DoWORD
call pstg
db 'BYTE PTR ',0
or OprndType,1 ;byte size
jmp l1630

DoWORD: call pstg
db 'WORD PTR ',0
or OprndType,2 ;word size
l1630: call psgprf ;show segment override prefix if any
;if mod=00, and r/m=110 then addr word is present
mov bx,curadr
inc bx
mov al,es:[bx] ;the modregr/m byte of the instr
and al,7 ;bits 0, 1, 2 only, the r/m field
cmp al,6 ;r/m = [BP]+disp ?
jnz NotDoingBP
;it's addr word, not [BP]
inc pcntr
inc pcntr
inc bx
mov dx,es:[bx] ;the 'displ' word
mov NoCommentAddr,1 ;don't show addr as a comment
call PrtNoOrSmb ;add SMB if in B mode
ret

NotDoingBP:
call PrtIndxedOprd ;print [BP+SI], etc
ret

PrtPTRandDisplPerReg:
cmp LongFlag,0
jnz PrtWordPtr ;'286 0F-prefix instrs are WORD
mov bx,curadr
mov al,es:[bx]
test al,1 ;check the W bit
jnz PrtWordPtr
call pstg
db 'BYTE PTR ',0
or OprndType,1 ;byte size
jmp PrtDisplPerReg

PrtWordPtr:
call pstg
db 'WORD PTR ',0
or OprndType,2 ;word size
;print reg or reg+displ (like 3[BP+SI], etc)
PrtDisplPerReg:
call psgprf
;at this point, the line looks like 0123 MOV WORD PTR CS:
inc pcntr
mov bx,curadr
inc bx
mov al,es:[bx] ;the modregr/m byte
inc bx ;points DISP byte
and al,11000000b
cmp al,01000000b ;is DISP 1 byte ?
jnz Not1ByteDisp
mov al,es:[bx] ;get 1-byte disp
;CONVERT NEG NOS TO -nn form
test al,80h ;is disp negative ?
jz PosNo
push ax
call pstg
db '-',0
pop ax
neg al
PosNo: call PrintALh
call PrtIndxedOprd ;print [BP+SI], etc
ret

Not1ByteDisp:
inc pcntr
mov dx,es:[bx] ;get disp word, just past modregr/m
call PrintDXh
call PrtIndxedOprd ;print [BP+SI], etc
ret
;--------------------------------
psgprf: push ax
mov al,SegOvrdPfx
or al,al
jz NoPrefix
and al,18h
call PrtaSegReg
call colon
mov al,SegOvrdPfx
shl al,1 ;get the 2 REG bits into the hi nibble
and al,00110000b ;look at only those bits
xor al,00100000b ;invert hi bit, now S D E C - why??
mov OprndType,al
mov SegOvrdPfx,0
NoPrefix:
pop ax
ret

namr16: mov bx,offset rtb16
add al,al
call AddALtoBX
mov al,cs:[bx]
call typech
inc bx
mov al,cs:[bx]
jmp typech

rtb16 db 'AX','CX','DX','BX','SP','BP','SI','DI'

namrg8: mov bx,offset rtb08
add al,al
call AddALtoBX
mov al,cs:[bx]
call typech
inc bx
mov al,cs:[bx]
jmp typech

rtb08 db 'AL','CL','DL','BL','AH','CH','DH','BH'
; - - - - - - - - - - - - - - - -
kind22: ;80286, 386 Protected mode instrs begin w/0Fh
ror Direc286Flag,1 ;move present status to hi bit
or Direc286Flag,1 ;and set flag (invalid codes will restore)
mov LongFlag,1 ;'long' 2-byte op codes with ModRegR/M ex CLTS
inc curadr
inc pcntr
mov bx,curadr ;to 2nd byte of opcode, now curadr
mov al,es:[bx+1]
mov CurModRegRM,al
mov al,es:[bx]
mov CurInstr,al
test al,11111100b ;look at all but lo 2 bits of instr
jnz BetterBeCLTS
cmp al,3
jz ItsLSL
cmp al,2
jnz xxyy
jmp ItsLAR
xxyy: or al,al ;AL has lo 2 bits of opcode
jz ItsLD_TR_VER
;2nd byte is 01, instr is LGDT, SGDT, LIDT, SIDT, LMSW, or SMSW
mov bl,CurModRegRM
and bl,00111000b
cmp bl,00111000b
jz NotAny
cmp bl,00101000b
jz NotAny
mov bx,offset DTandSWtbl
call PrtLongInstrs
call PrtTab
mov al,CurModRegRM
and al,00111000b
cmp al,00100000b
jae ItsMSW
call pstg
db 'F',0 ;MASM 5.0 bug requires Q here
call PrtMoprnd
jmp NewLine

;2nd byte is 00, instr is LLDT, SLDT, LTR, STR, VERR, or VERW
ItsLD_TR_VER:
mov bl,CurModRegRM
and bl,00111000b
cmp bl,00110000b
jae NotAny
mov bx,offset LongZeroTbl
call PrtLongInstrs
call PrtTab
ItsMSW: call PrtWhatsShifted
jmp NewLine

BetterBeCLTS:
cmp al,6
jnz NotAny
call pstg
db 'CLTS',0
jmp NewLine

NotAny: call pstg
db 'DB',tab,'0Fh,',0
mov al,CurInstr
call PrintALh
rol Direc286Flag,1 ;restore bit 0 to previous status
jmp NewLine

ItsLSL: call pstg
db 'LSL',tab,0
call ModRegRM
jmp NewLine

ItsLAR: call pstg
db 'LAR',tab,0
call ModRegRM
jmp NewLine

; - - - - - - - - - - - - - - - -
kind23: mov al,CurInstr ;segment override prefix
mov SegOvrdPfx,al
jmp dline ;to continue instr
; - - - - - - - - - - - - - - - -
kind24: call PrtTab ;push/pop seg regs
mov al,CurInstr
and al,18h
call PrtaSegReg
jmp NewLine
; - - - - - - - - - - - - - - - -
kind25: call PrtTab ;MOV AL or AX <-> mem, codes A0h - A3h
inc pcntr
inc pcntr
mov al,CurInstr
test al,2
jz MemToAccum
call PrtMemory
call comma
call paccum
jmp NewLine

MemToAccum:
call paccum
call comma
call PrtMemory
jmp NewLine

paccum: mov al,CurInstr
test al,1 ;the W bit
jnz acc16b
call pstg
db 'AL',0
ret

acc16b: call pstg
db 'AX',0
ret

PrtMemory:
mov al,CurInstr
test al,1
jnz TisWord
call pstg
db 'BYTE PTR ',0
or OprndType,1 ;byte size
jmp l17b3

TisWord:
call pstg

db 'WORD PTR ',0
or OprndType,2 ;word size
l17b3: call psgprf
mov bx,curadr
inc bx
mov dx,es:[bx]
mov NoCommentAddr,1 ;don't show addr as a comment
call PrtNoOrSmb
ret
; - - - - - - - - - - - - - - - -
kind26: ;shift/rotate instr's
mov al,es:[bx+1] ;get byte after op code, modTTTr/m
mov CurModRegRM,al
and al,00111000b ;get the TTT field
cmp al,00110000b ;TTT=110 ?
jnz ValidTTT
jmp PrtDBandByte ;it's not a valid Op code

ValidTTT:
call PrtShiftOpds
call PrtTab
call PrtWhatsShifted ;does single-operand Extnd Addrs
call comma
mov al,CurInstr ;get the Op code again
and al,0FEh ;look at all but last bit
cmp al,0C0h ;is it '286 sh/rotate by count ?
jnz NotByCount
mov Direc286Flag,1
mov bx,pcntr ;because length of instr is variable
mov al,es:[bx] ;the count byte
call PrintALh
inc pcntr ;these are 1 byte longer
jmp NewLine

NotByCount:
and al,2 ;bit 1 signals 'by CL'
jz Shift1
call pstg
db 'CL',0
jmp NewLine

Shift1: mov al,'1'
call typech
jmp NewLine

PrtWhatsShifted:
inc pcntr
mov al,CurModRegRM
and al,11000000b ;look at 'mod' field
cmp al,11000000b
jz ItsaReg
or al,al
jz NoDispl
jmp PrtPTRandDisplPerReg

ItsaReg:
jmp PrtRegOfRM

NoDispl:
jmp l1606

; - - - - - - - - - - - - - - - -
kind27: inc bx ;POP to memory
mov al,es:[bx]
mov CurModRegRM,al
and al,38h
jz YesPOPmem
jmp PrtDBandByte

YesPOPmem:
call pstg
db 'POP',0
call PrtTab
call PrtWhatsShifted
jmp NewLine
; - - - - - - - - - - - - - - - -
kind28: ;MOV to or from segment reg
mov al,es:[bx+1] ;get 2nd byte of instr
mov CurModRegRM,al
test al,20h ;nondest AND AL, 0010000
jz YesMOVsegreg
jmp PrtDBandByte

YesMOVsegreg:
call pstg
db 'MOV',0
call PrtTab
mov al,CurInstr
test al,2
jnz l1865
call l187d
call comma
call l1871
jmp NewLine

l1865: call l1871
call comma
call l187d
jmp NewLine

l1871: mov al,CurModRegRM
and al,18h
jmp PrtaSegReg

l187d: inc pcntr
mov al,CurModRegRM
and al,11000000b
cmp al,11000000b
jz RMisaReg
or al,al
jnz l18ba
jmp DoWORD

RMisaReg:
mov al,CurModRegRM
and al,7
jmp namr16

l18ba: call pstg
db 'WORD PTR ',0
or OprndType,2 ;word type
jmp PrtDisplPerReg ;prints Seg Ovrd Pfx, if any
; - - - - - - - - - - - - - - - -
kind29: ;MOV immed to r/m
inc bx
mov al,es:[bx] ;modregr/m byte
mov CurModRegRM,al
and al,38h
jz ItsMov
jmp PrtDBandByte ;not a valid code

ItsMov: call pstg
db 'MOV',0
call PrtTab
jmp l1c19
; - - - - - - - - - - - - - - - -
kind30: ;LEA, ModRegR/M, but no Reg
;MASM always assumes DS:, but old code may have Seg Ovrd Pfx
mov al,SegOvrdPfx
or al,al
jz NoLEApfx
and al,18h
cmp al,00011000b ;DS:
jz NoLEApfx
call pstg
db 'DB',tab,0
mov al,SegOvrdPfx
call PrintALh
call PrtTab
call semic
call pstg
db 'Seg Prefix for code length, MASM will use DS:',cr,lf,tab,0
NoLEApfx:
call pstg
db 'LEA',0
call PrtTab
mov al,es:[bx+1]
mov CurModRegRM,al
and al,38h
shr al,1
shr al,1
shr al,1 ;which register in list
call namr16 ;print register (AX, BX, etc)
call comma
call PrtMoprnd
jmp NewLine

PrtMoprnd:
inc pcntr
mov al,CurModRegRM
and al,0C0h ;the mod field
or al,al
jnz Tol18ba ;print 'WORD PTR' and addr
jmp DoWORD
Tol18ba:
jmp l18ba ;print 'WORD PTR' and [XX+nn]

; - - - - - - - - - - - - - - - -
kind31: ;NOT r/m
inc bx
mov al,es:[bx]
mov CurModRegRM,al
and al,38h
cmp al,8
jnz YesNOT
jmp PrtDBandByte

YesNOT: call pmisci
call PrtTab
mov al,CurModRegRM
and al,38h
jz Tol1c19
call PrtWhatsShifted
jmp NewLine

Tol1c19:
jmp l1c19
; - - - - - - - - - - - - - - - -
kind32: inc bx ;INC, DEC reg/mem
mov al,es:[bx]
mov CurModRegRM,al
and al,38h
or al,al
jz l1971
cmp al,8
jz l197f
jmp PrtDBandByte

l1971: call pstg
db 'INC',0
jmp l1986

l197f: call pstg
db 'DEC',0
l1986: call PrtTab
call PrtWhatsShifted
jmp NewLine
; - - - - - - - - - - - - - - - -
kind33: inc bx ;code FFh. Many: INC, DEC, CALLs, JMP, PUSH mem
mov al,es:[bx] ;2nd byte, mod sub-opcode r/m
mov CurModRegRM,al
and al,38h ;sub-opcode
cmp al,38h
jnz OK33
jmp PrtDBandByte ;db, not valid instr

OK33: or al,al ;inc reg/mem word
jz ItsINC
cmp al,8 ;dec reg/mem word
jz ItsDEC
cmp al,30h ;push reg/mem
jz ItsPUSHrm
cmp al,00011000b ;indir interseg call
jz ItsCallDword
cmp al,00101000b ;indir interseg jmp
jz ItsJmpDword
cmp al,00010000b ;reg/mem indir intraseg call
jz ItsCallPER
jmp ItsJmpPER ;reg/mem indir intraseg jmp (AL must be 20h)

ItsINC: call pstg
db 'INC',0
jmp l19d1

ItsDEC: call pstg
db 'DEC',0
l19d1: call PrtTab
call PrtMoprnd
jmp NewLine

ItsPUSHrm:
call pstg
db 'PUSH',0
jmp l19d1

ItsCallPER:
call pstg
db 'CALL',tab,0
call PrtWhatsShifted
jmp NewLine

ItsJmpPER:
call pstg
db 'JMP',tab,0
call PrtWhatsShifted
mov CurInstr,0E9h ;signal to put blank line after this
jmp NewLine

ItsCallDword:
call pstg
db 'CALL',tab,0
jmp DoDWORD

ItsJmpDword:
call pstg
db 'JMP',tab,0
mov CurInstr,0E9h ;signal to put blank line after this
DoDWORD:
call pstg
db 'DWORD PTR ',0
or OprndType,3 ;dword type
inc pcntr
mov al,CurModRegRM ;for BOUND, LDS & LES
and al,11000000b ;the Mode field
or al,al
jz NoDis
;register or reg+displ
call PrtDisplPerReg
jmp NewLine

;Mod = 0, no displacement unless R/M = 110 then is word addr
NoDis: call l1630
jmp NewLine

; - - - - - - - - - - - - - - - -
kind34: ;call far ptr, 9Ah & jmp far ptr, EAh
;MASM req SEGMENT AT to generate these
call PrtTab
add pcntr,4
mov dx,es:[bx+3] ;get segment
call PrintDXh
call colon
mov dx,es:[bx+1] ;get offset
call PrintDXh
jmp NewLine
; - - - - - - - - - - - - - - - -
kind35: ;'186 ENTER nnnn,nn
call PrtTab
mov dx,es:[bx+1]
call PrintDXh
call comma
mov al,es:[bx+3]
call PrintALh
add pcntr,3
jmp NewLine

; - - - - - - - - - - - - - - - -
kind36: ;RET nnnn, RET FAR nnnn
call PrtTab
mov dx,es:[bx+1]
call PrintDXh
inc pcntr
inc pcntr
jmp NewLine
; - - - - - - - - - - - - - - - -
kind16: call PrtTab ;ESC nn,reg for 80x87
; *** not right, do the FLoating instr's ***
mov al,CurInstr
and al,7 ;get the TTT field
mov cl,3
shl al,cl
mov ah,al
mov al,es:[bx+1]
mov CurModRegRM,al
and al,38h ;the LLL field
mov cl,3
shr al,cl
add al,ah ;now AL = 00 TTT LLL
call PrintALh
call comma
call l187d
jmp NewLine
; - - - - - - - - - - - - - - - -
kind17: mov al,CurInstr ;LOOPZ and LOOPNZ
and al,3
cmp al,0
jnz ItsLOOPZ
call pstg
db 'NZ',0
jmp kind21

ItsLOOPZ:
cmp al,1
jnz l1b55
call pstg
db 'Z',0
l1b55: jmp kind21
; - - - - - - - - - - - - - - - -
kind18: ;arith, r/m & reg to either
call PrtArithInstr ; (opcode bits 00111011 only)
kind19: call PrtTab ;TEST, XCHG, MOV, IMUL186, ARPL reg w/reg/mem
mov bx,curadr
mov al,CurInstr
call ModRegRM
mov al,CurInstr
cmp al,69h ;is it '186 IMUL immed word ?
jz ItsIMUL
cmp al,6Bh ;is it IMUL immed Sign-Ext byte ?
jz ItsIMUL
jmp NewLine

ItsIMUL:
mov bx,pcntr ;ModRegRM routine has variable bytes
inc pcntr
call comma
mov al,CurInstr
cmp al,6Bh
jnz IMULword
jmp SignExtend

IMULword:
mov dx,es:[bx]
inc pcntr
call PrintDXh
jmp NewLine

; - - - - - - - - - - - - - - - -
;LES, LDS, BOUND. Enter w/BX=curadr, points 1st byte of op code
kind38: call PrtTab ;the instr has just been printed
mov al,es:[bx+1] ;get modregr/m byte
mov CurModRegRM,al
and al,00111000b ;the Reg field
shr al,1
shr al,1
shr al,1 ;AL=which register in list
call namr16 ;print the register
call comma
jmp DoDWORD
; - - - - - - - - - - - - - - - -
kind20: ;Arith immed to reg/mem, code 80,1,2,3h
mov al,CurInstr ;NOTE: Intel book is WRONG, uses d bit
L1c0c: inc bx ;to ModRegRM, has actual instr
call PrtArithInstr
call PrtTab
;print the ModRegR/M and immed data for arith & mov immed.
; PrtModRegRM does similar, but no immed data
l1c19: mov bx,curadr
inc bx
mov al,es:[bx] ;get the modregr/m byte
mov CurModRegRM,al
and al,0C0h ;look at the mod field
or al,al
jnz ModNotZero
jmp ModIsZero
ModNotZero:
cmp al,0C0h
jz ModIs11
;mod is 01 or 10, disp is present
inc pcntr
call PrtPTRandDisplPerReg ;no use BX
call comma
mov al,CurModRegRM
mov bx,curadr
inc bx
inc bx
inc bx
test al,80h ;word disp ?
jz bbbb
inc bx ;curadr + 3 or 4 to get past DISP
bbbb: inc pcntr
jmp PrtImmedData

ModIs11:
inc pcntr
call PrtRegOfRM ;no use BX
call comma
inc pcntr
mov al,CurInstr
mov bx,curadr
inc bx ;ought to use Curadr, not BX
inc bx
PrtImmedData:
push bx ;must save BX, locn diff if DISP present
mov bx,curadr
mov al,es:[bx]
cmp al,83h ;is the sign-extend bit set ?
pop bx
jz SignExtend ;doesn't use AX, DOES use BX
test al,1
jnz WordData
;it is Byte Data
mov curadr,bx
cmp al,0C6h ;is it MOV ea,ib ?
jz OKtoShowASCII
mov al,CurModRegRM
OldArith: ;used by kind04, arith/logic to AL
; - the 3 bits in the op code are same as REG
and al,00111000b ;get the sub-opcode field
cmp al,00111000b ;is it CMP ?
jnz ChkLogic
OKtoShowASCII:
call bytopd ;print [curadr] as ASCII if so
jmp NewLine

ChkLogic:
cmp al,00100000b ;AND
jz ItsLogic
cmp al,00001000b ;OR
jz ItsLogic
cmp al,00110000b ;XOR
jz ItsLogic
mov bx,curadr
mov al,es:[bx]
ForZero:
call PrintALh
jmp NewLine

ItsLogic: ;print the byte as Binary
mov bx,curadr
mov al,es:[bx]
or al,al
jz ForZero
mov dl,al
push es
push cs
pop es
mov di,offset Bits
mov cx,8
BitLoop:
mov al,'0'
shl dl,1
jnc StoreBit
inc al
StoreBit:
stosb
loop BitLoop

pop es
call pstg
Bits db 8 dup('0'),'b',0
jmp NewLine

WordData:
inc pcntr
mov dx,es:[bx]
call PrintDXh
jmp NewLine

SignExtend:
xor dh,dh
mov dl,es:[bx]
or dl,dl
jns PosExtend
dec dh ;to 0FFh
PosExtend:
call PrintDXh
jmp NewLine

ModIsZero:
inc pcntr
call l1606
call comma
mov bx,curadr
inc bx
mov al,es:[bx] ;get the modregr/m byte
and al,7 ;look at the r/m field
cmp al,6 ;check the [BP] quirk
jnz l1c93
;mod=00 and r/m=110, so word disp, not [BP]
inc bx
inc bx
l1c93: inc bx
inc pcntr
jmp PrtImmedData
;--------------------------------
comma: push ax
mov al,','
call typech
pop ax
ret

apostrophe:
push ax
mov al,''''
call typech
pop ax
ret

PrtTab: mov al,tab
jmp typech

semic: mov al,';'
jmp typech

colon: mov al,':'
jmp typech

PrtDBandByte:
call pstg
db 'DB',tab,0
call bytopd
jmp NewLine

;--------------------------------
PrtaSegReg:
shr al,1
shr al,1
mov bx,offset segtbl
mov ch,2
call AddALtoBX
jmp PrtFromTabl

PrtIndxedOprd:
mov bx,offset indtbl ;holds [BP+SI][BX]...[BX+SI], etc
push bx ; (only ref to indtbl)
mov bx,curadr
inc bx
mov al,es:[bx] ;get the modregr/m byte
and al,7 ;the r/m field, it's a reg
shl al,1
shl al,1
shl al,1 ;multiply by eight
pop bx
mov ch,8 ;each entry is 8 bytes
call AddALtoBX
jmp PrtFromTabl ;print the entry in the table

PrtLongInstrs:
push bx
jmp Prt4ByteTbl

pmisci: mov bx,offset msctbl
push bx
Prt4ByteTbl:
mov bx,curadr
inc bx
mov al,es:[bx] ;get the ModREgR/M byte
and al,38h
shr al,1
pop bx
mov ch,4 ;each entry is 4 bytes
call AddALtoBX
jmp PrtFromTabl ;print the entry in msctbl

PrtShiftOpds:
mov bx,curadr
inc bx
mov al,es:[bx]
and al,38h ;00111000b, just look at the TTT field
shr al,1
shr al,1
mov ah,al
shr al,1
add al,ah
mov bx,offset shftbl
jmp Prt3FromTabl

PrtArithInstr:
mov al,es:[bx]
and al,38h
shr al,1
shr al,1
mov ah,al
shr al,1
add al,ah
mov bx,offset aritbl
jmp Prt3FromTabl

pcndop: mov bx,curadr ;print Conditional ops (JC, JNZ, etc)
mov al,es:[bx] ;get op code
and al,0Fh ;just look at low nibble
mov ch,al
add al,al
add al,ch ;lo nibble X 3
mov bx,offset cndtbl
Prt3FromTabl:
mov ch,3
call AddALtoBX
PrtFromTabl:
mov al,cs:[bx]
cmp al,'.'
jz PrtSkip
call typech
PrtSkip:
inc bx
dec ch
jnz PrtFromTabl
ret

AddALtoBX:
push ax
xor ah,ah
add bx,ax
pop ax
ret
;--------------------------------
;PRINT [BX] until CH=0
PrtCHbytesPerBX:
mov al,[bx]
call typech
inc bx
dec ch
jnz PrtCHbytesPerBX
ret
;--------------------------------
segtbl db 'ES','CS','SS','DS'

cndtbl db 'O..','NO.','C..','NC.'
db 'Z..','NZ.','NA.','A..'
db 'S..','NS.','PE.','PO.'
db 'NGE','GE.','NG.','G..'

shftbl db 'ROL','ROR','RCL','RCR'
db 'SHL','SHR','...','SAR'

msctbl db 'TEST','....','NOT.','NEG.'
db 'MUL.','IMUL','DIV.','IDIV'

aritbl db 'ADD','OR.','ADC','SBB'
db 'AND','SUB','XOR','CMP'

;this table entries 8 char for ease of math
indtbl db '[BX+SI].','[BX+DI].','[BP+SI].','[BP+DI].'
db '[SI]....','[DI]....','[BP]....','[BX]....'

DTandSWtbl db 'SGDT','SIDT','LGDT','LIDT','SMSW','....','LMSW'

LongZeroTbl db 'SLDT','STR.','LLDT','LTR.','VERR','VERW'

;--------------------------------
; Opcode mask, Opcode pattern, Kind, Literal
; Each line is 8 bytes. Opcode ANDED 1st byte must=2nd byte
; 3rd byte is Kind - see 'kindNN:' routines
; Most of these lines can be in any order, see last line.
; Don't print instr if do additional chk for valid instr first.

opct db 0ffh,098h,00,'CBW..' ;Kind00 have no operands
db 0ffh,027h,00,'DAA..'
db 0ffh,02fh,00,'DAS..'
db 0ffh,037h,00,'AAA..'
db 0ffh,0c3h,00,'RET..'
db 0ffh,0cbh,00,'RETF.' ;MASM 5.0+ takes this
db 0ffh,099h,00,'CWD..'
db 0ffh,09bh,00,'FWAIT'
db 0ffh,09ch,00,'PUSHF'
db 0ffh,09dh,00,'POPF.'
db 0ffh,09eh,00,'SAHF.'
db 0ffh,09fh,00,'LAHF.'
db 0ffh,0ceh,00,'INTO.'
db 0ffh,0cfh,00,'IRET.'
db 0ffh,0f4h,00,'HLT..'
db 0ffh,0f5h,00,'CMC..'
db 0ffh,0f8h,00,'CLC..'
db 0ffh,0f9h,00,'STC..'
db 0ffh,0fah,00,'CLI..'
db 0ffh,0fbh,00,'STI..'
db 0ffh,0fch,00,'CLD..'
db 0ffh,0fdh,00,'STD..'
db 0ffh,090h,00,'NOP..'
db 0ffh,03fh,00,'AAS..'
db 0ffh,0d7h,00,'XLAT.'
db 0ffh,060h,00,'PUSHA' ;186
db 0ffh,061h,00,'POPA.' ;186
db 0ffh,0c9h,00,'LEAVE' ;186
db 0ffh,0cch,00,'INT 3'
db 0feh,0ech,01,'IN...' ;AL or AX,DX
db 0feh,0eeh,01,'OUT..' ;DX, AL or AX
db 0ffh,0e5h,02,'IN...' ;AX,nn
db 0ffh,0e7h,02,'OUT..' ;nn,AX
db 0f0h,0b0h,03,'MOV..' ;immed to reg
db 0ffh,004h,04,'ADD..' ; Kind 4 are arith & logic to AL
db 0ffh,00ch,04,'OR...'
db 0ffh,014h,04,'ADC..'
db 0ffh,01ch,04,'SBB..'
db 0ffh,024h,04,'AND..'
db 0ffh,02ch,04,'SUB..'
db 0ffh,034h,04,'XOR..'
db 0ffh,03ch,04,'CMP..' ;immed w/AL, byte
db 0ffh,0a8h,04,'TEST.'
db 0ffh,005h,06,'ADD..' ;Kind 6 are arith & logic to AX
db 0ffh,00dh,06,'OR...'
db 0ffh,015h,06,'ADC..'
db 0ffh,01dh,06,'SBB..'
db 0ffh,025h,06,'AND..'
db 0ffh,02dh,06,'SUB..'
db 0ffh,035h,06,'XOR..'
db 0ffh,03dh,06,'CMP..' ;immed w/AX, word
db 0ffh,0a9h,06,'TEST.'
db 0ffh,0cdh,07,'INT..'
db 0ffh,0d4h,08,'AAM..'
db 0ffh,0d5h,08,'AAD..' ;Kind 08 are 2-bytes, 2nd is 0Ah
db 0ffh,0f3h,09,'REP..' ;Kind 09 are prefix instrs...
db 0ffh,0f2h,09,'REPNZ' ; REPZ, REPE same as REP
db 0ffh,0f0h,09,'LOCK.'
db 0fdh,068h,10,'PUSH.' ;186 PUSH nnnn
db 0feh,0a4h,12,'MOVS.' ;Kind 12 are String instructions
db 0feh,0a6h,12,'CMPS.'
db 0feh,0aah,12,'STOS.'
db 0feh,0ach,12,'LODS.'
db 0feh,0aeh,12,'SCAS.'
db 0feh,06ch,12,'INS..' ;186 ins [dx]
db 0feh,06eh,12,'OUTS.' ;186 outs [dx]
db 0f8h,090h,13,'XCHG.' ;with AX
db 0f8h,040h,15,'INC..' ;Kind 15 are one 16 bit reg
db 0f8h,048h,15,'DEC..'
db 0f8h,050h,15,'PUSH.'
db 0f8h,058h,15,'POP..' ;non-seg register
db 0f8h,0d8h,16,'Fxxxx' ;80x87 codes, not done yet
db 0f0h,070h,11,'J....' ;Jxx are 70h-7Fh [DISPL]
db 0ffh,0e3h,21,'JCXZ.' ; [DISPL]
db 0ffh,0ebh,21,'JMP..' ;(SHORT jump) [DISPL]
db 0ffh,0e8h,05,'CALL.' ; [DISPL]
db 0ffh,0e9h,05,'JMP..' ;word relative [DISPL]
db 0feh,0e0h,17,'LOOP.' ;LOOPNZ (E0h) and LOOPZ (E1h) [DISPL]
db 0ffh,0e2h,17,'LOOP.' ;plain LOOP short-label [DISPL]
db 0c4h,000h,18,'.....' ;arith, r/m & r to ModRegR/M
db 0feh,084h,19,'TEST.' ;ModRegR/M
db 0feh,086h,19,'XCHG.' ;except with AX
db 0fch,088h,19,'MOV..' ;MOV reg <-> reg/mem
db 0fdh,069h,19,'IMUL.' ;186 ModRegR/M,nnnn
db 0ffh,063h,19,'ARPL.' ;286
db 0fch,080h,20,'.....' ;arith & logic immed to reg/mem
db 0ffh,00fh,22,'.....' ;286 prot control & CLTS prefix
db 0ffh,026h,23,'.....' ;Kind23 is seg override prefix only
db 0ffh,02eh,23,'.....'
db 0ffh,036h,23,'.....'
db 0ffh,03eh,23,'.....'
db 0ffh,006h,24,'PUSH.' ;Kind24 are push/pop SEG REG
db 0ffh,00eh,24,'PUSH.'
db 0ffh,016h,24,'PUSH.'
db 0ffh,01eh,24,'PUSH.'
db 0ffh,007h,24,'POP..' ;ES
db 0ffh,017h,24,'POP..' ;SS
db 0ffh,01Fh,24,'POP..' ;DS
;note: POP CS (0Fh) works on 8088,6 only, used as prefix on '186+ !
db 0fch,0a0h,25,'MOV..' ;MOV AL or AX <-> mem
db 0fch,0d0h,26,'.....' ;shift/rotate
db 0feh,0C0h,26,'.....' ;186 shift by count
db 0ffh,08fh,27,'.....' ;POP memory
db 0ffh,08ch,28,'.....' ;MOV mem-or-reg, seg reg
db 0ffh,08eh,28,'.....' ;MOV seg reg, mem-or-reg
db 0feh,0c6h,29,'.....' ;MOV immed to reg/mem
db 0ffh,08dh,30,'.....' ;LEA ModRegR/M, but no Reg
db 0feh,0f6h,31,'.....' ;NOT reg/mem
db 0ffh,0feh,32,'.....' ;INC, DEC ModRegR/M
db 0ffh,0ffh,33,'.....' ;many: call/jmp DWORD PTR, PUSH mem. etc
db 0ffh,09ah,34,'CALL.' ;OOOO:SSSS
db 0ffh,0eah,34,'JMP..' ;OOOO:SSSS
db 0ffh,0C8h,35,'ENTER' ;'186 ENTER nnnn,nn
db 0ffh,0c2h,36,'RET..' ;RET nnnn
db 0ffh,0cah,36,'RETF.' ;RETF nnnn
db 0ffh,0e4h,37,'IN...' ;IN AL,nn
db 0ffh,0e6h,37,'OUT..' ;OUT nn,AL
db 0ffh,062h,38,'BOUND' ;'186 BOUND wr,dw[nnnn]
db 0ffh,0c4h,38,'LES..' ;ModRegR/M mod not 11
db 0ffh,0c5h,38,'LDS..' ;ModRegR/M mod not 11
db 0
;--------------------------------

; .SMB (label) table structure, variable length records:

; 2 bytes address, 1 byte seg/type, 1 byte string length, n bytes string
; table end defined by length byte = 0
; first byte past end pointed to by symtp
; type bits 1-0: 0=instr, 1=byte, 2=word, 3=dword
; type bits 5-4: 0=ss, 1=ds, 2=es, 3=cs (bit 3 inverted from REG code)

;ADDSYM called only in B cmd, creates H0[DX] (or [DX-ORG] for hard coded).
;Generates text of H0NNNN (same form as DASM).
addsym: mov bx,offset lblbuf ;use to build up label string
mov byte ptr [bx],'H'
inc bx
mov byte ptr [bx],'0'
inc bx
push dx ;label's pcntr addr
cmp RelFlag,0
jz hardcod
add dx,curorg ;correct text for ORG, rel-displ only
hardcod:
mov al,dh ;put DX into string
call StoreHex ;AL to 2 hex bytes [BX] & inc bx
mov al,dl
call StoreHex
pop dx ;restore pcntr addr of label
mov bx,offset lblbuf ;point beginning of string
mov ch,6 ;string length of H0nnnn
;SYMTCH also used by E command & to enter 'Start:'.
symtch: push cx
push bx
call symluk ;is there a label for addr=DX ?
pop bx
pop cx
jc entsym ;jump if no label at addr
ret

;first, open up space for new entry
entsym: mov ChgFlag,1 ;for 'Update/Exit'
push bx ;pointer to string to insert
push cx ;CH = string length
mov bx,symtp
mov si,bx ;save old symtp
mov al,ch ;length of label
xor ah,ah
add al,4
add si,ax
mov symtp,si ;new '1-past-end' pointer
mov byte ptr [si+3],0 ;zero length byte marks end

;now SI = new symtp, BX = old symtp (used SI not DI so no change to ES)
l22a5: cmp bx,NxtSymPtr ;set by symluk
jz inssym
dec bx
dec si
mov al,[bx] ;start w/1st byte below old symtp
mov [si],al ;move to 1st below new sympt
jmp l22a5

;put new entry in hole just made, DX = addr of label
inssym: pop cx ;CH is length byte
cmp RelFlag,0 ;rel-displ ?
jnz notchg
cmp byte ptr cmdbuf+2,'E' ;in E command? [BYTE PTR reqd]
jz notchg
sub dx,curorg ;hard-coded oprnds in B command only
notchg: mov [bx],dx
inc bx
inc bx
mov al,OprndType
mov [bx],al
inc bx
mov [bx],ch ;length of label
pop si ;was BX, pointer to string to insert
l22cb: inc bx
mov al,[si]
mov [bx],al
inc si
dec ch
jnz l22cb
ret

;--------------------------------
;locate symbol. BX > start of string to match, CH = length of string.
; Returns w/C set and BX unchanged if not found.
locsym: push dx
push bx ;string start
mov bx,symbas
NxSym: pop dx
push dx ;string start
inc bx
inc bx
inc bx
push bx
mov al,[bx] ;entry's length
or al,al
jz NotFoundExit ;table end
inc bx
cmp al,ch ;entry length - string length
jnz PointNext
;length matches
mov cl,al ;bytes to compare
call cmpstr
jz symfnd ;found right entry
PointNext:
pop bx ;points length byte of same entry
mov al,[bx]
inc bx ;string start
call AddALtoBX
jmp NxSym

symfnd: pop bx ;points length byte of same entry
dec bx
dec bx
dec bx ;back to entry start
pop dx ;adj stack
pop dx
clc
ret

NotFoundExit:
pop bx
pop bx
pop dx
stc ;not found flag
ret

;--------------------------------
;Check for symbol/label at [DX] (or [DX-ORG] for hard coded addrs)
;Struc: 2 bytes address, 1 byte Oprndtype, 1 byte string length, n bytes string
;saves DX, BX lost - no carry & BX > start of string, CH=length if found.
symluk: mov bx,symbas
mov NxtSymAddr,0 ;changed if exist lbl at or past DX addr
push dx
cmp RelFlag,0 ;rel-displ instr ?
jnz SymlookLoop ;yes, jump
cmp byte ptr cmdbuf+2,'E' ;are we entering a label?
jz SymlookLoop
cmp word ptr cmdbuf+2,'SD' ;are we Dumping Symbol table ?
jz SymlookLoop
cmp word ptr cmdbuf+2,0D43h ;cr,'C' - are we dumping the CTL table ?
jz SymlookLoop
sub dx,curorg
SymlookLoop:
mov ax,[bx] ;get address
add bx,3 ;to length byte
cmp ax,dx ;this lbl's addr - one we want
jz SmbFound
jc ChkForEnd
;this is 1st label is for addr higher than DX
sub bx,3 ;back to addr
mov NxtSymPtr,bx
mov dx,[bx]
mov NxtSymAddr,dx
stc ;signal not found
jmp EndSymLook

;this label addr is less than the one we're looking for
ChkForEnd:
mov al,[bx]
or al,al ;end of table ?
stc
jnz l2348 ;not end
mov bx,symtp
mov NxtSymPtr,bx
jmp EndSymlook ;addr past highest in table, ret w/C

l2348: inc bx ;to 1st of string
call AddALtoBX ;adj for string length
jmp short SymlookLoop

SmbFound: ;(segment scheme req chk seg here)
mov ch,[bx] ;string length to return
mov NxtSymPtr,bx
sub NxtSymPtr,3 ;point to start of entry, the addr
inc bx ;string pointer to return
or ch,ch ;clears carry flag, too
jz EOT ;ret w/carry if end of table
push bx
mov al,ch
call AddALtoBX ;point to next label's address
mov dx,[bx]
mov NxtSymAddr,dx
pop bx
clc
jmp short EndSymlook

EOT: stc
EndSymlook:
pop dx
ret ;with carry if end of table
;--------------------------------

;ENTER A LABEL (SYMBOL)
cmentr: mov bx,offset cmdbuf+3 ;1st byte after the E
call gtval ;label (pcntr, not ORG) address to DX
mov al,[bx]
call delim ;comma or space must exist
inc bx
mov al,[bx]
cmp al,'.'
jz DotIsThere ;dot must prefix label text
call cmerr

DotIsThere:
push dx ;label pcntr address
push bx ;cmdbuf pointer to '.'
call LblChk ;checks permissible characters
;be sure label doesn't exist
call locsym
jb nohit
call prtstr
db 'Label already exists...',cr,lf,0
jmp nxcmd

nohit: mov ChgFlag,1 ;for 'Update/Exit'
pop bx ;cmdbuf pointer to '.'
pop dx ;label pcntr address
push dx
push bx
call symluk ;is there a label at this addr?
jc symnf ;jmp if not
push bx
call CrLf
call PrtCHbytesPerBX
call prtstr
db ' was killed',7,cr,lf,0
pop bx ;from symluk, >1st of text
dec bx
dec bx
mov al,[bx] ;type byte of found label
mov OprndType,al ;to be same for replacement label
dec bx
dec bx
call lkill
symnf: pop bx ;orig cmdbuf pointer
call LblChk ;BX > 1st char in label, CH = chars
pop dx ;label address
call symtch ;puts label in table at DX
jmp nxcmd
;--------------------------------

cmkill: mov bx,offset cmdbuf+3 ;1st byte after the K in command
mov al,[bx]
cmp al,'.'
jz l2396
call cmerr

l2396: call LblChk
call locsym
jnc l23a1 ;found it
call cmerr

l23a1: call lkill
jmp nxcmd

lkill: mov cx,bx
inc bx
inc bx
inc bx
mov al,[bx]
sub ah,ah
add bx,ax
inc bx
xchg bx,dx ;hold in dx
mov bx,symtp
l23b8: cmp dx,bx ;at top yet?
jz l23d5
xchg bx,dx
mov al,[bx] ;from [dx]
xchg bx,dx
xchg bx,cx
mov [bx],al ;to [cx]
xchg bx,cx
inc cx
inc dx
jmp l23b8

l23d5: mov bx,cx
mov symtp,bx ;new top
mov byte ptr [bx+3],0
ret
;--------------------------------
;enter with BX > dot before label. Exit CH = chars in label
;returns BX > 1st char of label, DX > 1st char after label
LblChk: inc bx ;skip dot symbol flag
xor ch,ch ;clear length counter
push bx ;save string start pntr
mov al,[bx] ;get first char
;for 1st char only:
cmp al,cr
jz LblErr
cmp al,'.' ;period allowed only as 1st char
jz nxtcnt
cmp al,'$' ;weed
jz nxtcnt ; out
cmp al,'9'+1 ; digits in 1st char
jc LblErr
nxtcnt: inc bx ;starts with 2nd char
inc ch ;bump the count
mov al,[bx]
cmp al,cr ;label ends at a CR,
jz endcnt
cmp al,',' ; or a comma
jz endcnt
cmp al,'$'
jz nxtcnt
cmp al,'_'
jz nxtcnt
cmp al,'0'
jb LblErr
cmp al,'9'+1
jb nxtcnt
cmp al,'?'
jae nxtcnt
cmp al,'Z'+1
jb nxtcnt
LblErr: call prtstr
db 7,cr,lf,'Period only as 1st character'
db cr,lf,'0-9 must not be 1st character'
db cr,lf,'Also allowed are $ ? _ @',cr,lf,0
jmp nxcmd

endcnt: mov dx,bx ;delimiter ptr to DX
pop bx ;string start pointer
ret
;--------------------------------
StoreHex:
push ax ;AL to 2 hex chars [BX]
call hexl
mov [bx],al
inc bx
pop ax
call hexr
mov [bx],al
inc bx
ret

hexl: shr al,1 ;move hi nibble to lo nibble
shr al,1
shr al,1
shr al,1
hexr: and al,0Fh
cmp al,0Ah
jb hexrn
add al,7
hexrn: add al,'0' ;30h, make ASCII
ret

;print AL with leading zero if 0Ah or above
xo0: cmp al,0A0h
jnb Leading0
jmp xo

Leading0:
push ax
mov al,'0'
call typech
pop ax
xo: push ax
call hexl
call typech
pop ax
call hexr
jmp typech

Print00BX_: ;with leading zeros and trailing space
mov al,bh
call xo
mov al,bl
call xo
prspc: mov al,' '
jmp typech

;--------------------------------
;GET USER INPUT NUMBERS (or no. equiv of label) from cmdbuf to DX
gtval: mov al,[bx]
cmp al,'.'
jz GetSmbAddr
mov dx,0
hexbi: mov al,[bx]
cmp al,'0' ;30h
jnb NumContinues
;it's a punctuation mark, the no. has ended
sub dx,curorg ;correct address for ORG (pcntr always wrt 0)
ret ;w/carry set if DX less than 0

NumContinues:
cmp al,'9'+1 ;3ah
jb cvnum
cmp al,'A' ;41h
jnb l2468
ret

l2468: cmp al,'G'
jb l246d ;thru F it's a Hex character
ret

l246d: sub al,7
cvnum: sub al,'0' ;30h
xchg bx,dx
add bx,bx
add bx,bx
add bx,bx
add bx,bx
add al,bl
mov bl,al
xchg bx,dx
inc bx ;point to next char
jmp hexbi ;back near start of this routine

GetSmbAddr: ;now BX > the dot before the label
call LblChk ;rets w/DX > delimiter (CR or comma after lbl),
push dx ; BX > 1st char of label and CH = bytes in lbl
call locsym
jnc l2491 ;it exists
pop dx
call prtstr
db cr,lf,'Label not found',7,cr,lf,0
jmp nxcmd

l2491: mov dx,[bx] ;symbol value
pop bx ;was DX
mov al,[bx] ;string terminator
ret
;--------------------------------
fopen: push bx
mov ah,3Dh ;open file w/handle to AX
mov al,2 ;read/write
mov dx,offset FileString
int 21h
mov Handle,ax
mov DTAptr,100h ;so GetByte will first fill buffer
pop bx
ret ;w/no carry if successful

OpenError:
call prtstr
db tab,tab,tab,'FILE NOT FOUND',0
stc
ret
;--------------------------------
;read a byte from the buffer at old DTA, read in 128 bytes if empty
GetByte:
push bx
mov bx,DTAptr ;was set to 100h at fopen
test bh,1 ;AND, tests bit 0, so NZ 1st pass
jz StillGotSome ;DTAptr has NOT passed 0100h, end of buffer
;refill the 'DTA'
push cx
push dx
mov cx,128 ;bytes to read
mov bx,Handle
mov dx,DefaultDTA ;equ 80h, in the PSP
mov ah,3Fh ;read w/handle
int 21h
jnc CtuXX
jmp ReadErr
CtuXX: or ax,ax
jz mrkeof ;EOF has been read
pop dx
pop cx
mov bx,DefaultDTA ;equ 80h

StillGotSome:
mov al,[bx]
inc bx
mov DTAptr,bx
pop bx
ret

mrkeof: mov bx,DefaultDTA
mov al,1Ah
mov [bx],al
jmp StillGotSome ;now will RET w/AL=1Ah

;--------------------------------
creatf: push bx
mov ah,3Ch ;create file w/handle
push cs
pop ds ;just to be sure
mov dx,offset FileString ;DS:DX points to ASCIIZ string
xor cx,cx ;attribute = normal file
int 21h
jc CreateErr
mov Handle,ax
mov DTAptr,DefaultDTA ;equ 80h
pop bx
ret

CreateErr:
push ax
call prtstr
db cr,lf,'Error creating file: Func 3Ch, AX returned ',0
pop bx
call Print00BX_
call prtstr
db 'hex',cr,lf,0
jmp nxcmd

;--------------------------------
WriteNclose:
mov al,1Ah
call WriteChar ;add EOF to file
mov cx,DTAptr ;points 1 past the EOF char
sub cx,DefaultDTA ;now cx = bytes to write
call DumpDTA
fclose: push bx
mov ah,3Eh ;close file w/handle
mov bx,Handle
int 21h
pop bx
ret

CloseErr:
call prtstr
db 'ERROR closing file (DOS func 3Eh)',cr,lf,0
jmp nxcmd

DiskFull:
call prtstr
db 'Oh, phooey the disk is full !!',cr,lf,0
jmp nxcmd

WriteChar:
push cx
push bx
mov bx,DTAptr
mov [bx],al
inc bl
mov DTAptr,bx
pop bx
mov cx,128 ;bytes to write
jnz WrChRet
call DumpDTA ;DTAptr just rolled past 0FFh
WrChRet:
pop cx
ret

DumpDTA: ;called by WriteNclose, too
push dx
push bx
mov bx,Handle
mov dx,DefaultDTA ;equ 80h, in the PSP
mov ah,40h ;write to file w/handle
int 21h
jc WriteErr ;stack is reset by NXCMD, don't worry
cmp ax,cx ;bytes written - bytes requested
jnz DiskFull
mov bx,DefaultDTA ;equ 80h
mov DTAptr,bx ;reset pointer to start of DTA
pop bx
pop dx
ret

WriteErr:
push ax
call prtstr
db cr,lf,'Error writing file: Func 40h, AX returned ',0
pop bx
call Print00BX_
call prtstr
db 'hex',cr,lf,0
jmp nxcmd

;--------------------------------
;called after every line
NewLine:
mov LongFlag,0
mov bx,AppendPtr
or bx,bx
jz NewLine2
call PrtTab
mov ch,[bx]
or ch,ch ;zero-length remark ?
jz NewLine2 ;if so, do nothing
PrtAppendedRem:
inc bx
mov al,[bx]
call typech
dec ch
jnz PrtAppendedRem
NewLine2:
mov AppendPtr,0
UnasmCrLf:
mov al,CurInstr ;check opcode for JMP, RET, etc for blank line
cmp al,0C3h
jz SkipAline
cmp al,0E9h ;2-byte jmp in segment, also used by
; CALL, etc to force blank line.
jz SkipAline
cmp al,0EBh ;jmp short
jz SkipAline
cmp al,0C2h ;ret in seg, add immed to SP
jz SkipAline
cmp al,0CAh ;ret far, add immed to SP
jz SkipAline
cmp al,0CBh ;ret far
jz SkipAline
cmp al,0CFh ;iret
jz SkipAline
cmp al,0EAh ;jmp far
jz SkipAline
cmp al,0E2h ;LOOP
jz SkipAline
CrLf: mov al,cr
call typech
mov al,lf
jmp typech

SkipAline:
call CrLf
mov al,' '
mov CurInstr,al ;why ??
jmp CrLf

;--------------------------------
;GET COMMAND from the keyboard
gtcmd: mov UpCaseFlag,1 ;assume command is not ; or E
mov bx,offset segsho ;prompt string
mov ch,3 ;no. of characters
call PrtCHbytesPerBX
xor dh,dh ;clear the byte count
mov bx, offset cmdbuf
inc bx
inc bx ;for compatibility, start @ cmdbuf+2
nexkey: mov ah,0 ;read next kbd char into AL
int 16h
or al,al ;check for non-ASCII key
jnz NoSpl
jmp splkey
;now change lower to upper-case if reqd. First, check for ';', comma, or '.'
NoSpl: cmp al,','
jz LoCaseOK
cmp al,'e'
jz LoCaseOK
cmp al,'E'
jz LoCaseOK
cmp al,';'
jz LoCaseOK
UpCaseIt:
cmp UpCaseFlag,0
jz uc2cmd
call CapitalizeAL
uc2cmd: cmp al,' '
jnz NotSpace
cmp byte ptr cmdbuf+2,';'
jz NotSpace
jmp BeepBeep ;space allowed only in Remarks
NotSpace:
mov [bx],al ;put char in cmdbuf
mov ah,0Eh ;show on screen and move cursor
int 10h
cmp al,cr ;ENTER hit?
jnz noentr
mov byte ptr ds:[cmdbuf+1],dh ;like func 0A, byte count to 2nd byte
jmp CrLf ;vector to command routines

CapitalizeAL:
cmp al,'a'
jb Nope
cmp al,'z'+1
jnb Nope
and al,5Fh ;converts to Upper-case
Nope: ret

LoCaseOK: ;char is ; or e or E or comma
cmp al,','
jz DoComma
or dh,dh ;first char E or ; ?
jnz UpCaseIt
mov UpCaseFlag,2 ;flag next comma turn off upper case
jmp short UpCaseIt

DoComma:
cmp UpCaseFlag,2
jnz UpCaseIt
mov UpCaseFlag,0
jmp short UpCaseIt

noentr: cmp al,8 ;check for backspace
jnz nobksp
or dh,dh ;is cursor at left end of field?
jnz goback
mov al,segsho[2] ;bksp put cursor on last of arrow
mov ah,0Eh ;so replace it & move cursor back up
int 10h
jmp nexkey

goback: dec dh
jnz NotTheFirst
mov UpCaseFlag,1 ;must have erased 1st char
NotTheFirst:
dec bx
mov al,' '
mov ah,9 ;write char at cursor, no move cursor
mov cx,1 ;no of reps
push bx ;must save BX
mov bx,7 ;page=0, attrib=normal wht on blk
int 10h
pop bx
jmp nexkey

nobksp: cmp al,'Q' ;Quit ?
jnz NotQ
cmp byte ptr [bx-1],1Bh ;was previous char ESC ?
jnz NotQ
jmp cmexit ;Update/Exit w/Errorlevel 0
NotQ: or dh,dh ;is this the 1st char entered ?
jnz NotP
cmp al,'P'
jnz NotP
;set new d:\path\name to save to
mov si,offset FileString
PathLoop:
inc dh
inc bx
lodsb
cmp al,'.'
jz ToNexKey
or al,al
jz ToNexKey
mov [bx],al
mov ah,0Eh
int 10h ;show on screen and move cursor
jmp short PathLoop

ToNexKey:
jmp nexkey

NotP: cmp al,'='
jnz NotEqSign
cmp byte ptr [bx-1],'U' ;doing U= (set lines to Unasm) ?
jnz NotEqSign
call prtstr
db '(hex)',0
NotEqSign:
inc dh ;bump byte counter
inc bx ;bump cmdbuf pointer
jmp nexkey

;key was non-ASCII (AL was 0, so AH holds special scan code)
splkey: cmp ah,51h
jz PgDn
cmp ah,50h ;down arrow
jnz nodnar
jmp downar
nodnar: cmp ah,49h
jz PgUp
cmp ah,84h ;ctrl-pgup
jz ctlpup
cmp ah,43h ;F9 key
jnz notF9
call sav_em
jmp nxcmd

notF9: cmp ah,3Bh ;F1 key
jnz ToNexKey
jmp cmhelp

PgDn: cmp hlpflg,0 ;are we in Help?
jnz yeshlp
;what did we do last ?
cmp byte ptr cmdbuf+2,'D' ;are we in Dump or DS ?
jnz to_Udown
cmp byte ptr cmdbuf+3,'S' ;did we just dump sym table ?
jz to_Udown
mov byte ptr cmdbuf+3,cr ;set up cmdump to continue last dump
call prtstr ;start header at beginning of line!
db cr,0
jmp cmdump

to_Udown:
jmp Udown

yeshlp: mov al,helpno
inc al
cmp al,3 ;3 screens, no 2 is last
hlpend: jz BeepBeep
mov helpno,al
call CrLf ;keeps cmd line off display
jmp cmhelp

BeepBeep:
call prtstr
db 7,0 ;BEL, makes a beep
ToNexKey2:
jmp nexkey

PgUp: cmp hlpflg,0
jnz helpup
jmp nexkey

helpup: mov al,helpno
dec al
cmp al,0FFh ;AL was 0
jmp short hlpend

ctlpup: cmp byte ptr cmdbuf+2,'D' ;are we in Dump?
jnz Ustart
cmp byte ptr cmdbuf+3,'S' ;did we just DS (dump sym table) ?
jz Ustart
mov bx,dmpcnt
mov DumpEnd,bx ;dump a full page
mov DumpStart,0 ;start at 0 + ORG
jmp dmphdr

downar: mov ah,byte ptr cmdbuf+2 ;find out what we last did
cmp ah,'A'
jz onelin
cmp ah,'B'
jz onelin
cmp ah,'U'
jz onelin
cmp ah,'D'
jnz ToNexKey2
cmp byte ptr cmdbuf+3,'S'
jz ToNexKey2
;cmdbuf holds D but not DS, so Dump one more line of hex code
add DumpEnd,16
call prtstr
db cr,0
jmp cntdmp

onelin: mov al,1
jmp short DoALlines

Ustart: call CrLf
mov pcntr,0
mov AmodeFlag,0 ;turn off A and
mov BmodeFlag,0 ; B mode
Udown: mov byte ptr cmdbuf+2,'U' ;for down arrow
mov al,LnsPerScreen
DoALlines:
mov wfiflg,0 ;no write file, default for TwentyLines
mov LinesToGo,al
mov LCountFlag,al ;do specific line count
call prtstr
db cr,0 ;so will overwrite the 'ÍÍ'
jmp TwentyLines

;F9 has been hit, save the .REM, .SMB, and .CTL files
sav_em: call ChkNoFSpec ;save as 'SEG_nnnn.xxx' if doing RAM
cmp ASMopenFlag,0
jz ok2sav
jmp ASMstillOpenErr
ok2sav: jmp SaveAll ;resets ChgFlag

;--------------------------------
;Print ASCIIZ string (ends in 0) following call, to screen/both. Saves AX,BX,DX.
prtstr: mov wfiflg,0 ;output to screen only, not file
pstg: pop si ;get RET addr (of byte past call)
xchg bx,si
push si ;now BX points to byte after call
push ax
ostrlp: mov al,cs:[bx]
call typech ;print at least one char - saves DX
inc bx
mov al,cs:[bx]
or al,al
jnz ostrlp ;loop if not 0
pop ax
inc bx
pop si
xchg bx,si ;BX & DX saved
push si ;make RET addr the byte after the 0
ret

;--------------------------------
;Print [AL] to screen and/or output file buffer as req'd

typech: inc strcnt ;for ASCII lines
push ax
push cx
push dx
push bx
mov dl,al ;the character to print
push dx
push es
mov ah,2 ;display the character in DL
int 21h
pop es
pop dx
mov al,ASMopenFlag
and al,wfiflg
mov al,dl
jz l25d8 ;jump if both wfiflg and ASMopenFlag are 0
call WriteChar ;write to file buffer
l25d8: mov al,dl
cmp al,lf
jnz notlf
;character was Line Feed
cmp LCountFlag,0
jz notlf
dec LinesToGo
notlf: pop bx
pop dx
pop cx
pop ax
ret
;--------------------------------

ClearTables:
mov bx,symbas
mov byte ptr [bx+3],0 ;zero size byte
mov symtp,bx ;top = bottom
mov byte ptr cmdbuf+3,0Dh ;null command [shouldn't this be +2 ???]
mov cfence,'I' ;initial mode=Instrs (cfence=ctlbas-1)
mov al,segsho
mov byte ptr ctlbas,al ;1st byte of prompt arrow initially
mov word ptr ctlbas+1,0FFFFh ;end flag for addr's in .CTL table
mov bx,offset ctlbas+0C00h
mov ctltop,bx ;max length of ctl table 3K bytes
mov bx,remtbl ;set at start of pgm to REMBAS
mov remend,bx ;end = start
mov word ptr [bx],0FFFFh ;end marker
mov Direc286Flag,0
ret

;--------------------------------
;case-INsensitive string compare, [BX] & [DX], CL=length. Z set => match.
cmpstr: push bx
push cx
CmpStrLoop:
xchg bx,dx
mov al,[bx] ;get [DX] byte
call CapitalizeAL
mov ah,al
xchg bx,dx
mov al,[bx]
call CapitalizeAL
cmp al,ah ;compare w/[BX] byte
jz Match
jmp short CmpEnd ;w/NZ

Match: inc dx
inc bx
dec cl ;bytes to compare
jnz CmpStrLoop
CmpEnd: pop cx
pop bx
ret ;w/Z set if match

;--------------------------------
BreakChk:
push cx
push dx
push bx
mov ah,0Bh ;check for kbd input
int 21h
or al,al
jz NeverMind ;if no character is available, ret
mov ah,1 ;kbd input w/echo to screen
int 21h
cmp al,3 ;ctrl-C
jz abort
call CrLf
jmp nxcmd

abort: call prtstr
db cr,lf,'ABORT Y/N ',0
mov ah,1 ;kbd input w/echo to screen
int 21h
and al,5Fh ;make Upper-Case
cmp al,'Y'
jnz NotExit
mov ah,4Ch
mov al,1 ;Errorlevel = 1
int 21h ;normal terminate

NotExit:
jmp nxcmd

NeverMind:
pop bx
pop dx
pop cx
ret
;--------------------------------
;test for DB (cr, lf, 0, tab, bel, space thru 7Fh) - no carry if ASCII
;called twice, with al=es:[bx]
IfASCII:
cmp al,cr
jnz Not0Da
ret

Not0Da: cmp al,lf
jnz Not0Aa
ret

Not0Aa: or al,al
jnz Not0a
ret

Not0a: cmp al,tab
jnz NotTa
ret

NotTa: cmp al,bel
jnz NotBel
ret

NotBel: cmp al,' ' ;20h
jnb SpaceOrAbove
ret

SpaceOrAbove:
cmp al,3Ch ;code for CMP AL
jnz NotCMP
mov ah,es:[bx+2]
cmp ah,70h ;Jxx lowest code
jb NotCMP
cmp ah,7Ah ;Jxx highest code
ja NotCMP
;char is 3Ch and 2nd char following is a Jxx instr
stc
ret

NotCMP: push di
mov ah,al
and ah,11110000b
cmp ah,01010000b
jnz NotPushOrPop
;are next 4 chars also PUSH or also POP ?
mov ah,al
and ah,11111000b ;mask for all PUSH and POP instr's
mov di,4
PPloop: push ax
mov al,es:[bx+di]
and al,11111000b
cmp ah,al
pop ax
jnz NotPushOrPop
dec di
jnz PPloop
stc
pop di
ret

NotPushOrPop:
cmp al,7Fh ;thru 7Eh is ASCII
cmc
pop di
ret
;--------------------------------

curorg dw 0 ;ORG address
curpar dw 0 ;para (segment) of target pgm loaded
segsiz dw 0 ;bytes in current segment (not used now)
DumpStart dw 0 ;dump start addr
DumpEnd dw 0100h ;dump end addr
symtbl dw symbas ;addr of symbol table start
symtp dw symbas ;addr of symbol table end+1 (ie, 1st free byte)
pcntr dw 0 ;true program counter for Unassemble, etc.
lastwd dw 0100h ;end addr for U, input by user
curadr dw 0 ;pgm pointer during disassy
ctltbl dw offset ctlbas ;control (BEHIS or W) table start addr
ctltop dw 0 ; and end addr
SearchPointer dw 0
fndadd dw 0
dmpcnt dw 0FFh
lblbuf db 'H0XXXX' ;used to build up label in Build Symbol Table
PgmParas dw 0 ;size of loaded pgm in paras
PgmBytes dw 0,0 ;doubleword, lo-hi
ParasRead dw 0 ;for loading files > 64K, points buffer para

;This table erased by erstbl in LoadPGM (load .COM file)
cstbl db ' '
dw 0,0,0,0
cofset dw 0 ;default
db ' '
dw 0,0,0,0
dw 0 ;default
db ' '
dw 0,0,0,0
dw 0 ;default
db ' '
dw 0,0,0,0
dw 0 ;default
db ' '
dw 0,0,0,0
dw 0
db ' '
dw 0,0,0,0
dw 0
db ' '
dw 0,0,0,0
dw 0
db ' '
dw 0,0,0,0
dw 0
db 0 ;table end flag
;end of table erased by erstbl

segnam dw 5343h ; 'SC' for CS, etc
dw 5344h ; 'SD'
dw 5345h ; 'SE'
dw 5353h ; 'SS'
dw 5831h ; 'X1'
dw 5832h ; 'X2'
dw 5833h ; 'X3'
dw 5834h ; 'X4'

FileString db 'D:'
db 81 dup(0)
DotPtr dw 0 ;pointer to the . before the EXT
Handle dw 0 ;File Handle for load & save routines
LitRSM db 'RSM',0 ;literals for file types
LitCOM db 'COM',0
LitEXE db 'EXE',0
LitSYS db 'SYS',0
LitCTL db 'CTL',0
LitSMB db 'SMB',0
LitREM db 'REM',0
LitALL db 'ALL',0
SEG_string db 'SEG_',cr ;for name of saved files doing RAM

EXTflag db 0 ;.EXT of loaded file, C=.COM, E=.EXE
hlpflg db 0
helptr dw offset help
dw offset extnd_help
dw offset instrs
helpno db 0 ;which help screen to display
NxLblPtr dw 0 ;stores BX in Dump Symbol table
AppendPtr dw 0 ;temp pointer to Appended remark while Unasm'ing line
Control db 0 ;temp CTL char to insert when Attempting to find DB's
nxtctl dw 0 ;addr of next CTL change, to end Byte & Hex lines
NxtSymAddr dw 0 ;when not at end of table, addr of next label and
NxtSymPtr dw 0 ; pointer to 1st byte of next entry in SYM table
EndSameAddr dw 0 ;in S mode, next non-Same or CTL or SMB addr
DTAptr dw 0 ;pointer in buffer for disk read/writes
segsho db 205,205,16 ;command prompt string 'ÍÍ'
UpCaseFlag db 1 ;zero permits lower-case for remarks & labels
nrsegs db 0 ;number of segments loaded
trmflg db 0 ;trim flag, 1= don't show ;addrs for labels
SegOvrdPfx db 0 ;segment override prefix

segflg db 0 ;segment req in current command (not now used)

OprndType db 0 ;upper nibble = seg type, S D E C = 0 1 2 3,
; lower = Undefined, Byte, Word, Dword(Qword, Spaces)
RelFlag db 0 ;line addr or rel disp instr, don't correct for CurOrg
Direc286Flag db 0 ;1 = put '.386P' in .RSM, '186+ instrs in file
LnsPerScreen db 22 ;lines per screen of Unassembly
LinesToGo db 10 ;lines left to Unassemble on this screen
LCountFlag db 1 ;0 for U B or A,EEEE to end addr, not line count
wfiflg db 0 ;0 means don't print to file, just screen
ASMopenFlag db 0 ;.RSM file still open, close it before writes
REMflag db 0 ;1 => doing REM, not SMB file operation
CurInstr db 0 ;current op code during unassembly
CurModRegRM db 0 ;current Extended Address byte of instr
LongFlag db 0 ;current instr is a long '286
strcnt db 0 ;no of chars on ASCII Byte or Hex lines
EntriesLeft db 0 ;count of displayed labels in DS and Ctl list
BytesFlag db 0 ;flag line is Bytes ASCII, not Hex
ChgFlag db 0 ;flag change made for 'Update/Exit' in CmExit
OutsideFlag db 0 ;in .RSM hdr, flag 'Labels Outside Pgm' printed
CrLfFlag db 0 ;in ASCII strings, last byte was cr, lf, or 0
ColonFlag db 0 ;flag for colon after labels
NoCommentAddr db 0 ;flag no ;0123 after label in oprnd
AmodeFlag db 0 ; 1 => Attempt find DB's mode
BmodeFlag db 0 ; 1 => Build symbol table mode
typndx db 0,0,0
cmdbuf: org offset $+336
stak dw 0 ;machine stack top
remtbl dw 0 ;loaded w/remark table start addr
remend dw 0 ; and end addr
cfence db 0 ;this is ctlbas-1, holds BEHISW for 1st line
ctlbas db 0 ;start of enough room for 768 items, 4 bytes each

start endp
cseg ends
end start