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

 
Output of file : RE-SOURC.ASM contained in archive : RESORC93.ZIP
;®RM80¯®LM0¯RE-SOURCE DISASSEMBLER - modified by JIR 7/87 - 11/93

;Disassembly starts ÷ page 46
;Commands, file handling in first half, except Symbol stuff at ÷ page 67.
;The keyboard is read at gtcmd:

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

.386p
PAGE 192,132
CSEG segment byte USE16 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+6144 ;base of 32K symbol (label) table
rembas equ symbas+(32*1024) ;base of 48K remark table

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

;Remarks are loaded after symbols at RemSeg, always uses FS
;The target program is loaded after the remarks at PgmSeg, always uses ES

start: jmp AllocRAM

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

AllocRAM:
;ALLOCATE RAM FOR BUFFERS & TARGET PGM
mov ax,cs
mov es,ax ;seg addr of block to change
mov bx,3000h ;allocate 192K
mov ah,4Ah ;modify allocated memory block
int 21h
jnc goodmem
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
;set RemSeg
mov bx,rembas ;EQU symbas + 32K
shr bx,4 ;divide by 16, now paras past CS
push cs
pop dx
add bx,dx
mov RemSeg,bx
push bx
pop fs ;set FS to RemSeg. It is never changed.
mov dx,offset banner
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 PrtScrn
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 PrtScrn
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 ;point to 1st 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
db '3'
dw offset Cm32bit
VectorTblEnd db 0

;--------------------------------
cmerr: mov wfiflg,0 ;clear 'write to file' flag
call PrtScrn
db 'Command Error at ',bel,0
pop bx ;addr called from
call Print00BX_ ; for debugging
call PrtScrn
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 PrtScrn
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'
;line 1 & 2
db cr,lf,cr,lf,'T toggle display of label addresses as comments'
;line 3 & 4
db cr,lf
db cr,lf,'SWWWW search for WWWW'
;line 5
db cr,lf,'S continue search for WWWW '
db 'SWWWW,SSSS search WWWW after SSSS'
;line 6
db cr,lf,'ANY KEY stops search. WWWW is in reverse order in RAM!'
;line 7 & 8
db cr,lf,cr,lf,'P lets you edit path to save/load'
;line 9 & 10
db cr,lf,cr,lf,'3 toggles ''386 32-bit code'
db cr,lf,cr,lf,'Controls:'
db ' B=Bytes in ASCII H=Bytes in hex E=END (ends Unassembly)'
db cr,lf,' I=Instructions S=Same [DB n DUP (x)] '
db 'W=Words D=DWords'
db cr,lf,' K=Kill CTL at this addr'
;line 15 & 16
db cr,lf,cr,lf,'You can enter .YourLabel in place of any address'
;line 17 & 18
db 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.'
;line 20 & 21
db cr,lf,cr,lf,'PGDN works, CTRL-PGUP goes to start, '
db 'down arrow does 1 more line',cr,lf
;line 22
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,'$'
;--------------------------------
Cm32bit:xor Flag386,00000011b ;toggle bits 0 & 1
cmp Flag386,00000011b
jz On32bit
call PrtScrn
db '32-bit is OFF',cr,lf,0
jmp nxcmd

On32bit:call PrtScrn
db '32-bit enabled',cr,lf,0
jmp nxcmd
;--------------------------------
cmtrim: mov al,trmflg
not al
mov trmflg,al
or al,al
jz LblAdrsOn
call PrtScrn
db 'Label Addresses Off',cr,lf,0
jmp nxcmd

LblAdrsOn:
call PrtScrn
db 'Label Addresses On',cr,lf,0
jmp nxcmd

;--------------------------------
cmpurg: call PrtScrn
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 (not used)
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 PgmSeg,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 ?
jz 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 PrtScrn
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,PgmSeg
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,PgmSeg
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,PgmSeg
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
jz nxcmd
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 PrtScrn
db '1st char = CS, DS, ES, SS, FS, GS '
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 PrtScrn
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 PrtScrn
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,PgmSeg ;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,PgmSeg
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,PgmSeg
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: xor bx,bx
cmp bx,RemEndAddr
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,fs:[bx] ;byte count of remark
mov al,fs:[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,fs:[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 & String lines
mov wfiflg,0
cmp al,'S' ;string 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 ckdmd
jmp wmode

ckdmd: cmp al,'D' ;double word mode ?
jnz badmd
jmp dmode

badmd: call typech
call PrtScrn
db ' INVALID 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,PgmSeg
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
mov bx,pcntr
mov es,PgmSeg
mov cx,1
call CtlInWord
jc bmode ;use B mode if Ctl or Rem exists
call pstg
db 'DW',tab,0
mov dx,es:[bx]
call PrintDXh
inc pcntr
inc pcntr
StopLine:
call NewLine
jmp TwentyLines
;--------------------------------
;'D' control, dword ***** needs to chk for SMB/CTL at 2-4th byte, chg to DB.
dmode: mov wfiflg,1
mov bx,pcntr
mov es,PgmSeg
mov cx,3
call CtlInWord
jc bmode ;use B mode if Ctl or Rem exists
call pstg
db 'DD',tab,0
mov edx,es:[bx]
call PrintEDXh
add pcntr,4
jmp short StopLine
;--------------------------------
;chk for SMB or CTL at 2-4th byte, show as DB if so. CX=bytes to check
CtlInWord:
mov dx,bx
InWordLoop:
inc dx
cmp dx,nxtctl
jz UseDB
cmp dx,NxtSymAddr
jz UseDB
loop InWordLoop
clc
ret

UseDB: stc
ret

;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,PgmSeg
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 PrtScrn
db cr,lf,'RE-SOURC PSP at Segment. ',0
mov bx,cs
call Print00BX_
call PrtScrn
db cr,lf,'Target Pgm at Segment... ',0
mov bx,PgmSeg
call Print00BX_
call PrtScrn
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 PrtScrn
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 PrtScrn
db cr,lf,'SMB (labels) Start-End.. ',0
mov bx,symbas
call Print00BX_
mov bx,symtp
call Print00BX_
call PrtScrn
db cr,lf,'REM Table Seg:End..... ',0
mov bx,RemSeg
call Print00BX_
call colon
mov bx,RemEndAddr
call Print00BX_
call PrtScrn
; 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 PrtScrn
; 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,PgmSeg
mov SearchPointer,dx
ContinueSearch:
call PrtScrn
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 PrtScrn
db cr,lf,'End of program reached',cr,lf,0
jmp nxcmd
NotPast:
mov es,PgmSeg
mov al,es:[bx] ;get byte in target pgm
inc bx
mov SearchPointer,bx
cmp al,dl ;match?
jnz nyet
mov es,PgmSeg
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 PrtScrn
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 PrtScrn
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 PrtScrn
db tab,tab,tab,'.COM, .EXE, or .SYS FILE NOT FOUND',0
TargetLoadDone:
mov bx,offset LitREM
call EXTtoSpec
call PrtScrn
db cr,lf,'Loading .REM file..',0
call LoadREM
mov bx,offset LitCTL
call EXTtoSpec
call PrtScrn
db cr,lf,'Loading .CTL file..',0
call LoadCTL
mov bx,offset LitSMB
call EXTtoSpec
call PrtScrn
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 PrtScrn
db 'Loaded specified file as target program.',cr,lf,0
jmp nxcmd

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

LoadPGM:
call fopen ; open file. Saves BX.
jnc cmdlds ; opened successfully
ret

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
shr bx,4
add bx,0C00h ; 48K in paras, for remark table
mov ax,cs
add ax,bx ; seg of end of RE-SOURC w/buffers,
mov PgmSeg,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 PrtScrn ;saves BX
db cr,lf,'Not enough memory, you need ',0
call Print00BX_
call PrtScrn
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,PgmSeg ;end of RE-SOURCE and its buffers
add ax,ParasRead
mov ds,ax ;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 PrtScrn
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 PrtScrn
db cr,lf,'Error reading file: Func 3Fh, AX returned ',0
pop bx
call Print00BX_
call PrtScrn
db 'hex',cr,lf,0
ret

;--------------------------------
LoadSMB:push es
push ds
pop es
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: pop es
ret ;w/C set if not found

LoadREM:push es
push fs
pop es
xor bx,bx
mov REMflag,1
call LoadREMorSMB
jnc MarkRemEnd
pop es
ret

MarkRemEnd:
mov RemEndAddr,bx
mov word ptr fs:[bx],0FFFFh
pop es
ret

LoadREMorSMB:
call fopen ;C set if file not found
mov al,0 ;so it's never 1Ah the first time
jnc RemSmbCharLoop
call OpenError ;print 'File Not Found'
ret

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

l0b6c: cmp al,' '
jb RemSmbCharLoop ;eat CR, LF, ctrl chars
call hexbin ;hex to binary, variable, space ends
mov es:[bx],dx
add bx,2
test byte ptr REMflag,1
jnz drdsk1
;for SMB file only:
call GetByte
mov es:[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
cmp al,1Ah ;in case EOF char is at end of line
jz FoundDelim
mov es:[bx],al
inc bx
inc ch ;char count
jmp lpasld

FoundDelim:
pop si
xchg bx,si
push si ;save BX in SI
mov es:[bx],ch ;store byte count
pop bx ;restore pointer to next byte in tbl
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
shl dx,4 ;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 PgmSeg,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 PrtScrn
db 'ORG = 0 at ',0
mov bx,PgmSeg
call Print00BX_
call PrtScrn
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,RemEndAddr
or dx,dx
jz nosrem
mov bx,offset LitREM
call EXTtoSpec
call PrtScrn
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 PrtScrn
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 PrtScrn
db cr,lf,'Saving .CTL file..',cr,lf,0
jmp SaveCTL

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

SavRemSym:
call creatf
l0bf7: mov dx,es:[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,es:[bx] ;OprndType byte
sdskp1: inc bx
mov al,es:[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 DX 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,es:[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
pop es
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,PgmSeg
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 PrtScrn
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 Flag386,1
jz TryIf286
call pstg
db cr,lf,'.386P',0 ;file has '386+ instr's
jmp short Just86
;note: .386P calls MOV wr, OFFSET H001234 "illegal size for operand"
;unless you USE16 in the SEGMENT AT line
TryIf286:
test Flag286,1
jz Just86
call pstg
db cr,lf,'.286P',0 ;file has '186+ instr's
Just86: 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 ',0
test Flag386,1
jz NoUSE
call pstg
db 'use16 ' ;assume (permit?) 16-bit registers
NoUSE: call pstg
db '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:push es
push fs
pop es
mov REMflag,1
mov bx,RemEndAddr
inc bx
inc bx ;2 bytes past end
mov byte ptr fs:[bx],0 ;mark length byte so end will be found
xor bx,bx
jmp SavRemSym

;--------------------------------
ASMstillOpenErr:
call PrtScrn
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 PrtScrn
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
cmp al,'D'
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 BEHISW or D)
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 BESHIW or D
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 PrtScrn
db '= ',0
pop bx
mov al,[bx]
call typech ;ctl char from table (BEHISW or D)
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 PrtScrn
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 al,'O'
call WriteChar
mov al,'R'
call WriteChar
mov al,'G'
call WriteChar
mov al,' '
call WriteChar
mov dx,curorg
call outadr
mov al,cr
call WriteChar
mov al,lf
call WriteChar
test Flag386,1
jz Write16bit
mov al,'3'
call WriteChar
mov al,'2'
call WriteChar
jmp short SizeWritten

Write16bit:
mov al,'1'
call WriteChar
mov al,'6'
call WriteChar
SizeWritten:
mov al,cr
call WriteChar
mov al,lf
call WriteChar
mov bx,offset ctlbas ;start of CTL table
NxtEntry:
mov dx,[bx+1] ;address value
cmp dx,0FFFFh
jz HitEnd ;0FFFFh is flag for end of table
mov al,[bx] ;seg char
call WriteChar
call outadr ;convert DX 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:
; 1st char of 1st line is 'O' else skip to CTL's, number at end is ORG
; 1st char of 2nd line is 1(6 bit) or 3(2 bit)
; 1 line/entry, seg byte, variable length hex address
; (always 4 chars now), a comma, and the Ctl byte (BEHISWD). E.g., Í0123,B

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

FoundCTL:
mov bx,offset ctlbas
;check for ORG & 16/32 bit
call getbyte
cmp al,'O'
jnz LoadTheCTLs
LoadORG:
call GetByte ;get byte from buffer, read another 128 if empty
cmp al,'0'
jb LoadORG
cmp al,'F'
ja LoadORG
xor dx,dx
call DigitToDX
mov cx,3
GetORGloop:
call GetByte
call DigitToDX
loop GetORGloop

mov curorg,dx
GetSizeLoop:
call GetByte
cmp al,' '+1
jb GetSizeLoop ;eat space, CR, LF, ctrl chars
;check for 32-bit
cmp al,'3'
jnz LineEndLoop
mov Flag386,3
LineEndLoop:
call GetByte
cmp al,1Ah
jz IsEOF
cmp al,cr
jnz LineEndLoop
CtlLineLoop:
call GetByte
LoadTheCTLs:
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,RemEndAddr
mov fs:[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 fs
pop es ;dest seg for STOSB
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:
push cs
pop es
mov RemEndAddr,di
mov word ptr fs:[di],0FFFFh
mov fs:[bx],ch ;string count
jmp nxcmd

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

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

l0fc3: inc bx
inc bx
mov al,fs:[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:xor bx,bx ;point BX at start of table
l0fd8: call BreakChk ;check for CTRL-BREAK
mov dl,fs:[bx]
inc bx
mov dh,fs:[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,fs:[bx] ;length of remark
l0ffa: inc bx
mov al,fs:[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 fs:[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,fs:[bx]
call AddALtoBX
inc bx ;to start of next entry's string
xor ch,ch
l1023: mov al,fs:[bx]
xchg bx,dx
mov fs:[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 RemEndAddr,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 [PgmSeg:pcntr] - always called w/wfiflg=0

dline: mov es,PgmSeg
mov OprndType,10h ;DS unless changed, do correct for ORG
SzDet: mov bx,pcntr
mov curadr,bx
inc pcntr
mov ch,es:[bx] ;first byte of code for this line
;check for '386 size overrides
cmp ch,66h ;is operand 32-bit ?
jnz Chk67
or SzOvrdFlag,1 ;set bit 0
jmp short SzDet

Chk67: cmp ch,67h ;is adress 32-bit ?
jnz StartLn
or SzOvrdFlag,2 ;set bit 1
jmp short SzDet

StartLn:mov CurInstr,ch ;also signals blank line if req'd
;Find Op Code in opct table
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 D-bit codes (GxEx, register 1st)
mov RegFirstFlag,0
cmp al,3Fh
ja TryHi
test al,2
jnz SetRegFirst
TryHi: mov ah,al
and ah,11111100b
cmp ah,84h ;op codes 84, 85, 86, 87h
jz SetRegFirst
cmp al,62h
jz SetRegFirst
cmp al,69h
jz SetRegFirst
cmp al,6Bh
jz SetRegFirst
cmp al,8Ah
jz SetRegFirst
cmp al,8Bh
jz SetRegFirst
cmp al,0C4h ;LES
jz SetRegFirst
cmp al,0C5h ;LDS
jnz ChkFor186
SetRegFirst:
mov RegFirstFlag,1
;pick out the '186+ op codes. 0F, C0 and C1 done in kindXX routines.
;The codes are 60-63, 68-6F, C8 and C9
;'386 prefixes are 66h=operand 32-bit and 67h=effective addr 32-bit
ChkFor186:
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 Flag286,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
; - - - - - - - - - - - - - - - -
Chk32opd:
push ax
mov al,Flag386 ;=11b for 32 bits default
xor al,SzOvrdFlag ;=x1b for override default operand size,
test al,1 ;operand size 32-bit ?
pop ax
ret ;w/Z set if NOT 32-bit oprnd

Chk32adr:
push ax
mov al,Flag386 ;=11b for 32 bits default
xor al,SzOvrdFlag ;=1xb for override default addr size
test al,2
pop ax
ret ;w/Z set if NOT 32-bit addr

Chk32andPrintE:
call Chk32opd
jz done32
call pstg
db 'E',0
done32: ret
; - - - - - - - - - - - - - - - -
;Routines to print the operands. On entry:
;BX = curadr, points to the 1st op code byte. CurInstr holds op code.
;If Word, then Flag386 XOR SzOvrdFlag determines if 16- or 32-bit (Dword) size

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 Chk32andPrintE
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,',0
call Chk32andPrintE
call pstg
db '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 ;check bit 1
jnz OutnnAX
call Chk32andPrintE
call pstg
db 'AX,',0
mov al,CurModRegRM
call PrintALh
jmp NewLine

OutnnAX:mov al,CurModRegRM
call PrintALh ;print port no.
call comma
call Chk32andPrintE
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 byte, word, dword to reg
mov al,es:[bx] ;get the op code
inc curadr
test al,8
jnz k03Word
inc pcntr
and al,7
call namrg8
call comma
call bytopd
jmp NewLine

k03Word:
and al,7
call namr16or32
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 - full displ
inc bx
mov edx,es:[bx] ;displacement from 1st byte past instr
call Chk32opd
jz K0516
add bx,2
K0516: add bx,2 ;to 1st byte past instr
add bx,dx
movzx edx,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 curadr
call Chk32andPrintE
call pstg
db 'AX,',0
ImmedWord: ;used by kind10, PUSH immed & kind03, MOV immed
mov bx,curadr ;has been inc'd
mov edx,es:[bx]
ImSE: add pcntr,2
call Chk32opd
jz ImNo32
add pcntr,2
ImNo32: call symluk ;saves DX
jnc hvsym3 ;jmp if label
call Chk32opd
jz OneWord
call PrintEDXh
jmp NewLine

OneWord:call PrintDXh ;print word in DX, followed by 'h'
jmp NewLine

hvsym3: call pstg
db 'OFFSET ',0
call HaveSmb ;does NOT adjust pcntr
jmp NewLine

; - - - - - - - - - - - - - - - -
;print operand words following 'WORD PTR' (AddrOrSmb does line addrs)
; and Rel JMPs and CALLs. Adds symbols if in B mode.
PrtNoOrSmb:
add pcntr,2
call Chk32adr
jz SymSz
add pcntr,2 ;must handle first so can skip by call SymSz
SymSz: 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 edx ;holds the addr or data to print
call symluk ;check for symbol
pop edx
jnc HaveSmb ;print it
mkopds: cmp BmodeFlag,0 ;building symbols?
jz PrtAdr ;just print addr if not
push edx
call addsym ; only call
pop edx
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 (line addrs done by Print00BX_)
PrtAdr: cmp RelFlag,0
jz PrintCorrected
add dx,curorg ;correct relative addrs for ORG
PrintCorrected:
cmp ShortFlag,1
jz PrintDXh
call Chk32adr
jnz PrintEDXh
PrintDXh: ;leading zeros only where MASM requires,
; EXCEPT, e.g., 400h shows as 0400h
mov al,'0'
or dx,dx
jz ToTypch
mov al,dh
or al,al
jz PrintDLh
call xo0
mov al,dl
call xo
PhSfx: mov al,'h'
ToTypch:jmp typech

PrintEDXh:
mov al,'0'
or edx,edx
jz ToTypch
push edx
shr edx,16 ;hi word to DX
or dx,dx
jz PopAndPrintDXh
mov al,dh
call xo0
mov al,dl
call xo
pop edx
mov al,dh
call xo
mov al,dl
call xo
jmp short PhSfx

PopAndPrintDXh:
pop edx
jmp short PrintDXh

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

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 curadr ;used by ImmedWord
cmp al,6Ah ;is the Sign-Extend bit set ?
jz SExt
jmp ImmedWord ;print 2 or 4 byte no. or 'OFFSET label'

SExt: mov bx,curadr ;sign extended always 1 byte data
mov dl,es:[bx]
movsx edx,dl
inc pcntr
ExDone: jmp ImNo32 ;in ImmedWord routine, past pcntr stuff

; - - - - - - - - - - - - - - - -
kind11: call pcndop ;conditional jumps. 'J' has been printed.
jmp short JopDone

kind21: ;JCXZ, JMP SHORT - always byte displ
mov al,CurInstr ;get op code byte again
cmp al,0EBh ;was it JMP SHORT, not JCXZ ?
jnz ItsJCXZ
call PrtTab
call pstg
db 'SHORT ',0
jmp short ShortDone

ItsJCXZ:call Chk32opd
jz ItsNotE
call pstg
db 'JECXZ',0
jmp short JopDone

ItsNotE:
call pstg
db 'JCXZ',0
JopDone:call PrtTab
ShortDone:
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: movzx edx,bx
mov ShortFlag,1 ;flag displ is always 1 byte
mov RelFlag,1 ;flag rel-displ for
call SymSz ;print (E)DX + curorg, add SMB if in B mode
jmp NewLine ; (=PrtNoOrSmb but past inc pcntr)
; - - - - - - - - - - - - - - - -
kind12: ;movs, cmps, lods, stos, scas
mov al,CurInstr
and al,1
jnz k12wrd
call pstg
db 'B',0
jmp NewLine

k12wrd: call Chk32opd
jz k12one
call pstg
db 'D',0
jmp NewLine

k12one: call pstg
db 'W',0
jmp NewLine
; - - - - - - - - - - - - - - - -
kind13: call PrtTab ;XCHG (E)AX,
call Chk32andPrintE
call pstg
db 'AX,',0
mov al,CurInstr
and al,7
call namr16or32
jmp NewLine
; - - - - - - - - - - - - - - - -
kind15: call PrtTab ;PUSH, POP, INC, DEC one register
mov al,CurInstr
and al,7
call namr16or32
jmp NewLine
; - - - - - - - - - - - - - - - -
PrtRMasReg:
mov al,CurModRegRM
and al,00000111b ;look at R/M field only
jmp l156d

PrtReg: mov al,CurModRegRM
and al,38h ;look at reg field only
shr al,1
shr al,1
shr al,1
l156d: push ax
mov al,CurInstr
;MOVSX & -ZX take 16/32-bit reg for opd, then as if 16-bit for eff addr
test MOVxXflag,2
jz CkWd
;we are doing a MOVxX instruction
test MOVxXflag,4 ;have we done the 1st part ?
jnz Res3 ;jmp if so
or MOVxXflag,4
jmp short WordReg ;1st pass, oprnd is W or DW

Res3: test al,1 ;word size ?
pop ax
jnz namr16 ;no 'E' before reg
jmp namrg8

;LES, LDS, '286 LAR, etc are WORD reg's, must filter out
CkWd: cmp WordFlag,0
jnz WordReg
test al,1
jnz WordReg
pop ax
jmp namrg8

WordReg:pop ax
jmp namr16or32

;used for TEST, MOV, XCHG, kind18 arith, and '286+ ARPL, LSL, LAR
;At least some TEST and XCHG assemble the same regardless of operand order
ModRegRM:
inc pcntr
mov bx,curadr
mov al,es:[bx+1] ;get modregr/m byte
mov CurModRegRM,al
and al,11000000b ;the MOD field
or al,al
jz ChkQuirk ;mod=00, no displacement unless [BP]
cmp al,11000000b
jnz Displacement
RMisReg: ;MOD = 11
cmp RegFirstFlag,1
jz RegFirst
call PrtRMasReg
call comma
jmp PrtReg

RegFirst:
call PrtReg
call comma
jmp PrtRMasReg

ChkQuirk: ;MOD = 00
cmp RegFirstFlag,1
jz QuirkReg1st
call PrtEffAddr
call comma
jmp PrtReg

QuirkReg1st:
call PrtReg
call comma
jmp PrtEffAddr

Displacement: ;MOD = 01 or 10, [XX+YY+disp]
cmp RegFirstFlag,1
jz DisplLast
call PrtPTRandDisplPerReg ;print XS:XXXX PTR nn[XX+YY]
call comma
jmp PrtReg

DisplLast:
call PrtReg
call comma
jmp PrtPTRandDisplPerReg

PrtSize: ;for MOD = 00, 01, 10 in ModRegRM
and MOVxXflag,3 ;now 2nd part, clear reg flag (bit 2)
cmp MOVxXflag,3
jz DWis1
cmp MOVxXflag,2
jz DoByte
cmp DwordFlag,0
jnz SoDoDword
cmp WordFlag,0
jnz DoWORD ;'286 0Fh-prefix instrs are WORD
cmp ShortFlag,0
jnz DoByte ;'386 SETcc are BYTE
mov al,CurInstr
test al,1
jnz DoWORD
DoByte: call pstg
db 'BYTE PTR ',0
or OprndType,1 ;byte size
ret

DoWORD: cmp FwordFlag,1
jnz Is16or32
call pstg
db 'F',0
jmp short DWis1

Is16or32:
call Chk32opd
jz DWis1
mov al,CurInstr
cmp al,62h ;BOUND ?
jnz SoDoDWord
call pstg
db 'Q',0
jmp short DWis1

SoDoDWord:
call pstg
db 'D',0
DWis1: call pstg
db 'WORD PTR ',0
or OprndType,2 ;word size
ret

;Called from above ModRegRM routine and PrtWhatsShifted. MOD is 00.
PrtEffAddr:
call PrtSize
l1630: call psgprf ;show segment override prefix if any
mov bx,curadr
inc bx
mov al,CurModRegRM
call Chk32adr
jz Mod0016
;We are in 32-bit adr mode, MOD=00 and AL has the MODREGR/M byte
and al,7 ;the r/m field
cmp al,4
jz TwoByteMODRM
cmp al,5
jnz PrtBrkt32regBrkt
;RM=101, print 32 -bit displ addr
mov NoCommentAddr,1 ;no addr as comment, we're not at end of line
inc bx
mov edx,es:[bx] ;get the 32-bit displ
jmp PrtNoOrSmb

PrtBrkt32regBrkt: ;AL has R/M
call PrtBrkt32reg
call pstg
db ']',0
ret

PrtBrkt32reg:
call pstg
db '[',0
call Prt32reg
ret

Prt32reg:
push ax
push cx
mov bx,offset Reg32tbl
mov cl,al
add al,al
add al,cl ;multiplied by 3
call Prt3FromTabl
pop cx
pop ax
ret

TwoByteMODRM:
inc pcntr
call psgprf
call pstg
db '[',0
mov bx,curadr
mov al,es:[bx+2] ;the ssIndexBase byte
mov CurSsIB,al
mov cl,CurModRegRM
mov ch,cl
mov ah,al
and ch,11000000b ;Mod field
and ah,00000111b ;Base field
or ch,ah
cmp ch,00000101b ;MOD BASE = just Scaled Index + d32 ?
jz ScaledIndex
mov al,ah
call Prt32reg ;print the Base register
ScaledIndex:
mov al,CurSsIB
and al,00111000b ;Index field
cmp al,00100000b ;no index (SS must be 00, not checked)
jz Displ32
cmp ch,00000101b ;just Scaled Index + d32 ?
jz SIplusDone ;skip the '+'
call pstg
db '+',0
SIplusDone:
shr al,3
call Prt32reg
mov al,CurSsIB
and al,11000000b ;the SS field
or al,al
jz Displ32
call pstg
db '*',0
shr al,6 ;SS field to low bits of AL
mov cl,al
mov dl,1
shl dl,cl
add dl,'0' ;make ASCII
mov al,dl
call typech
Displ32:mov bx,pcntr ;can't use curadr, used for 1 & 2-byte
mov edx,es:[bx] ; ModRegRM instr's
mov al,CurModRegRM
and al,11000000b ;MOD field
or al,al
jnz NotDone
;MOD is 00
mov cl,CurSsIB
and cl,00000111b ;BASE field
cmp cl,00000101b ;DS:[d32 + scaled index] ?
jz DisplIs32bit
jmp short TwoByteDone

NotDone:cmp al,10000000b
jz DisplIs32bit
;8-bit displ
inc pcntr
test dl,80h
jnz NegSign
call pstg
db '+',0
jmp short SignSet

NegSign:call pstg
db '-',0
neg dl
SignSet:call PrintDLh
TwoByteDone:
call pstg
db ']',0
ret

DisplIs32bit:
add pcntr,4
or edx,edx
jz TwoByteDone
bt edx,15
jc NegWSign
call pstg
db '+',0
jmp short WSignSet

NegWSign:
call pstg
db '-',0
neg edx
WSignSet:
call PrintEDXh
jmp short TwoByteDone

;In 16-bit addr mode, if mod=00, and r/m=110 then displ addr word follows
Mod0016: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 bx
mov edx,es:[bx] ;the 'displ' word
mov NoCommentAddr,1 ;don't show addr as a comment
call PrtNoOrSmb ;adds SMB if in B mode
ret

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

PrtPTRandDisplPerReg: ;call from ModRegRM. MOD is 01 or 10
call PrtSize ;print BYTE or (D|F|Q)WORD PTR
PrtDisplPerReg: ;16-bit reg or reg+displ (e.g., 3[BP+SI])
call psgprf

;at this point, the line looks like 0123 MOV WORD PTR CS:
mov bx,curadr
inc bx
mov al,es:[bx] ;the modregr/m byte
call Chk32adr
jz Mod0110_16
;We are in 32-bit adr mode, MOD=01 or 10 and AL has the MODREGR/M byte
and al,7 ;the r/m field
cmp al,4
jz TwoByteMODRM
call PrtBrkt32reg
jmp Displ32

Mod0110_16:
inc pcntr
inc bx ;points DISP byte
and al,11000000b
cmp al,01000000b ;is DISP 1 byte ?
jnz WordDispl
mov al,es:[bx] ;get 1-byte disp
;Convert neg nos to -nn form
test al,80h ;is disp negative ?
jz PosNo
call pstg
db '-',0
neg al
PosNo: call PrintALh
call PrtIndxedOprd ;print 16-bit [BP+SI], etc
ret

WordDispl:
inc pcntr
mov dx,es:[bx] ;get displ word, just past modregr/m
;Convert neg nos to -nn form
test dh,80h ;is disp negative ?
jz PosWd
call pstg
db '-',0
neg dx
PosWd: call PrintDXh
call PrtIndxedOprd ;print 16-bit [BP+SI], etc
ret
;--------------------------------
psgprf: push ax
mov al,SegOvrdPfx
or al,al
jz NoPrefix
test al,40h ;hi nibble=6 for FS and GS prefix
jz Old1s
and al,00000111b
shl al,1
call ALset
jmp short FinishSegPfx

Old1s: and al,00011000b
shr al,2
call ALset ;in PrtaSegReg, after bit manip
FinishSegPfx:
call colon
mov al,SegOvrdPfx
test al,40h ;hi nibble=6 for FS and GS prefix
jz OldOpdType
and al,00000111b
shl al,3
OldOpdType:
shl al,1 ;get the REG bits into the hi nibble
;There are many, many references to OprndType
and al,00110000b ;look at only lo 2 of those bits
xor al,00100000b ;invert hi bit, now S D E C - why??
mov OprndType,al
mov SegOvrdPfx,0
NoPrefix:
pop ax
ret

namr16or32:
call Chk32andPrintE ;checks for 32-bit oprnd
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: ;1st byte is 0Fh
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
;check for 0F-prefix register-first codes
mov RegFirstFlag,0
cmp al,2
jz Set1st
cmp al,3
jz Set1st
cmp al,0AFh
jz Set1st
mov ah,al
and ah,11110000b
cmp ah,0B0h
jnz RegSet
;instr is 0F Bx
cmp al,0B5h
jb RegSet
cmp al,0B7h
jbe Set1st
cmp al,0BCh
jb RegSet
Set1st: mov RegFirstFlag,1
RegSet: test Flag386,1
jz Try286
;'386 instrs, we are in 32-bit mode
and al,11110000b ;look at hi nibble
cmp al,80h ;32-bit displ conditional jmp ?
jz Fpfx8x
cmp al,90h
jz Fpfx9x
cmp al,20h ;MOV control, debug, test reg's w/EEE field
jz TestReg
cmp al,0A0h
jz PPShiftBT
cmp al,0B0h
jz BitsAndX
jmp Try286 ;handle 0F 00 (incl Group 6 & 7)

BitsAndX: ;opcode 0F Bx
mov al,CurInstr
and al,00001111b ;look at lo nibble
cmp al,0Ah ;Bit Tests ?
jz Group8
mov ah,al
and ah,00000110b ;0,1,8,9 are invalid
jz NotAny
cmp ah,00000110b ;6,7,E,F are MOVxX
jz ExtdMov
test al,8
jnz MoreBitTests
cmp al,3
jz MoreBitTests
;it's LSS, LFS, or LGS
sub al,2 ;now AL = 0, 2, or 3
mov bx,offset LxStbl
call Prt3inALfromTbl
mov bx,curadr
jmp kind38

LxStbl db 'LSS','...','LFS','LGS'

MoreBitTests: ;AL is 3, B, C, or D
cmp al,3
jnz BTindexSet
dec al
BTindexSet:
and al,00000111b ;now AL is 2, 3, 4, or 5
sub al,2
mov bx,offset BitEvGvTbl
call Prt3inALfromTbl
jmp JustMRM

BitEvGvTbl db 'BTR','BTC','BSF','BSR'

ExtdMov:test al,8
jnz MovSignExt
call pstg
db 'MOVZX',0
jmp short MovXprinted

MovSignExt:
call pstg
db 'MOVSX',0
MovXprinted:
call PrtTab
mov MOVxXflag,2
mov al,CurInstr
and al,1 ;get W bit
or MOVxXflag,al
call ModRegRM ;bit 0 of instr: Dword <- word, else w <- byte
jmp NewLine ;NOTE: TASM refuses, but possible word <- word

Group8: mov al,CurModRegRM ;sim Group 2 (SHR, RCL, etc), but no by CL, 286
test al,00100000b ;make sure 1st opcode bit is 1
jz NotAny
and al,00011000b ;get 2nd & 3rd bits of opcode (REG) field
mov bx,offset BitTbl
call PrtTTTopds
call PrtTab
mov WordFlag,1
call PrtWhatsShifted
call comma
mov bx,pcntr
mov al,es:[bx]
call PrintALh
inc pcntr
jmp NewLine

BitTbl db 'BT.','BTS','BTR','BTC'

PPShiftBT: ;opcode 0F Ax
mov al,CurInstr
and al,00001111b ;look at lo nibble
cmp al,9
jz PopSeg
cmp al,8
jz PushSeg
cmp al,1
jz PopSeg
or al,al
jz PushSeg
mov WordFlag,1 ;flag ModRegRM all below are WORD, not BYTE
cmp al,3
jz BitTestRMR
cmp al,0Bh
jz BitTSRMR
cmp al,0Fh
jz AnyRegIMUL
;Shift Double's
cmp al,4
jnz TryA5
call pstg
db 'SHLD',0
call PrtTab
jmp short WithImmed

TryA5: cmp al,5
jnz TryAC
call pstg
db 'SHLD',0
call PrtTab
jmp short NoImmed

TryAC: cmp al,0Ch
jnz TryAD
call pstg
db 'SHRD',0
call PrtTab
WithImmed:
call ModRegRM
call comma
mov bx,pcntr
mov al,es:[bx]
call PrintALh
inc pcntr
jmp NewLine

TryAD: CMP al,0Dh
jnz NotAny
call pstg
db 'SHRD',0
call PrtTab
NoImmed:call ModRegRM
call pstg
db ',CL',0
jmp NewLine

BitTestRMR:
call pstg
db 'BT',0
JustMRM:call PrtTab
call ModRegRM
jmp NewLine

BitTSRMR:
call pstg
db 'BTS',0
jmp short JustMRM

AnyRegIMUL:
call pstg
db 'IMUL',0
jmp short JustMRM

PopSeg: call pstg ;AL = 1 or 9
db 'POP',0
jmp short PrtGSorFS

PushSeg:call pstg ;AL = 0 or 8
db 'PUSH',0
PrtGSorFS:
call PrtTab
and al,8 ;now AL is 0 or 8, make it 8 or 0Ah
shr al,2
or al,8
call ALset
jmp NewLine

TestReg:mov al,CurInstr ;opcode 0F 2x
cmp al,26h
ja NotAny
cmp al,25h
jz NotAny
inc pcntr
mov cl,CurModRegRM ;get 11EEEreg byte
and cl,00000111b ;get the REG field into CL
call pstg
db 'MOV',0
call PrtTab
cmp al,22h
jnz Try20
;it's 22h
call PrtCRs
Reg32last:
call comma
mov al,cl
call Prt32reg
jmp NewLine

Try20: cmp al,20h
jnz Try23
mov al,cl
call Prt32reg
call comma
call PrtCRs
jmp NewLine

Try23: cmp al,23h
jnz try21
call PrtDRs
jmp short Reg32last

Try21: cmp al,21h
jnz Try26
mov al,cl
call Prt32reg
call comma
call PrtDRs
jmp NewLine

Try26: cmp al,26h
jnz Its24
call PrtTRs
jmp short Reg32last

Its24: mov al,cl
call Prt32reg
call comma
call PrtTRs
jmp NewLine

PrtCRs: call pstg
db 'CR',0
mov al,CurModRegRM
and al,00111000b ;get the EEE field
shr al,3
cmp al,3
ja nfgEEE
add al,30h ;make ASCII
call typech
ret

PrtDRs: call pstg
db 'DR',0
mov al,CurModRegRM
and al,00111000b ;get the EEE field
shr al,3
cmp al,4
jz nfgEEE
cmp al,5
jz nfgEEE
add al,30h ;make ASCII
call typech
ret

PrtTRs: call pstg
db 'TR',0
mov al,CurModRegRM
and al,00111000b ;get the EEE field
shr al,3
cmp al,6
jb nfgEEE
add al,30h ;make ASCII
call typech
ret

nfgEEE: call pstg
db '*invalid*',0
ret

Fpfx9x: ;SETcc's
mov ShortFlag,1 ;flag PrtWhatsShifted they set a byte to 01
mov bx,curadr
mov al,CurModRegRM
and al,00111000b ;check the REG field, must be 000
jnz NotAny ;invalid instr
call pstg
db 'SET',0
call pcndop
call PrtTab
call PrtWhatsShifted
jmp NewLine

Fpfx8x: call pstg
db 'J',0
call pcndop
call PrtTab
;calculate 32-bit address
mov bx,curadr
mov eax,es:[bx+1] ;get displ
add bx,4 ;point to 1st byte past this instr
test eax,80000000h ;sign bit
jnz Rel32neg
inc bx
movzx ebx,bx
add ebx,eax
jmp short Rel32end

Rel32neg:
inc bx
not eax
inc eax
movzx ebx,bx ;fill upper 16 bits w/0's
sub ebx,eax
Rel32end:
test ebx,0FFFF0000h ;is BX >64K ?
jz CanAddr ;jmp if in same seg
mov edx,ebx ;just print the dword addr ***temporary
call PrintEDXh ; until full 32-bit seg's in PrtNoOrSmb
add pcntr,4
jmp NewLine

CanAddr:movzx edx,bx
mov RelFlag,1 ;flag rel-displ for
call PrtNoOrSmb ; print (E)DX + curorg, add SMB if in B mode
jmp NewLine

;'286+ Protected mode instrs
Try286: ror Flag286,1 ;move present status to hi bit
or Flag286,1 ;and set flag (invalid codes will restore)
mov WordFlag,1 ;'long' 2-byte op codes with ModRegR/M ex CLTS
mov al,CurInstr
test al,11111100b ;look at all but lo 2 bits of instr
jnz BetterBeCLTS
cmp al,3
jz ItsLSL
cmp al,2
jnz TryLTV
jmp ItsLAR

TryLTV: 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 Flag286,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 old seg reg, 'sreg2' field
mov al,CurInstr
and al,00011000b
shr al,2
call ALset ;in PrtaSegReg after bit manip
jmp NewLine
; - - - - - - - - - - - - - - - -
kind25: call PrtTab ;MOV AL or AX <-> mem, codes A0h - A3h
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 Chk32andPrintE
call pstg
db 'AX',0
ret

PrtMemory: ;called only by knd25, A0-A3 MOV<->accum
mov al,CurInstr
test al,1
jnz TisWord
call pstg
db 'BYTE PTR ',0
or OprndType,1 ;byte size
jmp l17b3

TisWord:
call Chk32opd
jz TisOne
call pstg
db 'D',0
TisOne: call pstg
db 'WORD PTR ',0
or OprndType,2 ;word size
l17b3: call psgprf
mov bx,curadr
inc bx
mov edx,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 Flag286,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 PrtRMasReg ;MOD is 11
or al,al
jz PrtEffAddr ;MOD is 00
jmp PrtPTRandDisplPerReg

; - - - - - - - - - - - - - - - -
kind27: inc bx ;POP to memory
mov al,es:[bx]
mov CurModRegRM,al
and al,38h
jnz PrtDBandByte
call pstg
db 'POP',0
call PrtTab
call PrtWhatsShifted
jmp NewLine
; - - - - - - - - - - - - - - - -
kind28: ;8C & 8E, MOV to or from segment reg
mov al,es:[bx+1]
mov CurModRegRM,al
call PrtTab
mov al,CurInstr
test al,2
jnz SegRegFirst
call l187d
call comma
mov al,CurModRegRM
call PrtaSegReg
jmp NewLine

SegRegFirst:
mov al,CurModRegRM
call PrtAsegReg
call comma
call l187d
jmp NewLine

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

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

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 ModRegRM2
; - - - - - - - - - - - - - - - -
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 namr16or32 ;print register (AX, EBX, etc)
call comma
call PrtMoprnd
jmp NewLine

PrtMoprnd:
inc pcntr
mov al,CurModRegRM
and al,11000000b ;the mod field
or al,al
jnz l18ba ;print 'WORD PTR' and addr
call DoWORD ;MOD is 00
jmp l1630
; - - - - - - - - - - - - - - - -
kind31: ;F6 & F7h: TEST, MOV, MUL, DIV, etc
inc bx ; ('Group 3')
mov al,es:[bx]
mov CurModRegRM,al
and al,38h
cmp al,8
jz PrtDBandByte
call PrtMiscInstr ;only call
call PrtTab
mov al,CurModRegRM
and al,00111000b
jz ModRegRM2 ;jmp if nnn=000, TEST
call PrtWhatsShifted
jmp NewLine

; - - - - - - - - - - - - - - - -
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 ;not a 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 LDS & LES
and al,11000000b ;the MOD 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
call Chk32opd
jz GetSeg
add pcntr,2
add bx,2
GetSeg: mov dx,es:[bx+3] ;get segment, always 16-bit
call PrintDXh
CJcolon:call colon
mov bx,curadr
mov edx,es:[bx+1] ;get offset
call Chk32opd
jz OfsIs16
call PrintEDXh
jmp NewLine

OfsIs16: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 ;LOOP, LOOPZ and LOOPNZ
and al,3
cmp al,0
jnz ItsLOOPZ
call pstg
db 'NZ',0
jmp JopDone

ItsLOOPZ:
cmp al,1
jnz JustLOOP
call pstg
db 'Z',0
JustLOOP:
jmp JopDone
; - - - - - - - - - - - - - - - -
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
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 edx,es:[bx]
inc pcntr
call PrintDXh
jmp NewLine

; - - - - - - - - - - - - - - - -
;LDS, LES, BOUND - enter w/BX=curadr, points 1st byte of op code
;all take DWORD if 16-bit; BOUND is QWORD, LxS is FWORD if 32-bit
kind38: call PrtTab ;the instr has just been printed
call Chk32opd
jnz ChkForQ
;the oprnd is 16-bit
mov DwordFlag,1
jmp short NoFword

;the oprnd (reg) is 32-bit, QWORD for BOUND picked up in PrtSize
ChkForQ:mov al,CurInstr
cmp al,62h
jz NoFword
mov FwordFlag,1 ;an FWORD is 48 bits, not an obscenity
NoFword:mov WordFlag,1 ;so reg will never be byte
call ModRegRM
jmp NewLine
; - - - - - - - - - - - - - - - -
kind20: ;Arith immed to reg/mem, code 80,1,2,3h
mov al,CurInstr ;NOTE: Intel books WRONG, uses s bit
L1c0c: inc bx ;to ModRegRM, has actual instr
call PrtArithInstr
call PrtTab
;print the ModRegR/M and immed data for arith, MOV immed, TEST immed w/r/m.
; ModRegRM does similar, but no immed data or sign-extend, & this does no sym
ModRegRM2:
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
add bx,3
test al,80h ;word disp ?
jz bbbb
inc bx ;curadr + 3 or 4 to get past DISP
call Chk32adr
jz bbbb
add bx,2
bbbb: inc pcntr
jmp PrtImmedData

ModIs11:
inc pcntr
call PrtRMasReg ;no use BX
call comma
inc pcntr
mov al,CurInstr
mov bx,curadr
inc 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
call Chk32opd
jz WD1
mov edx,es:[bx]
call PrintEDXh
add pcntr,2
jmp NewLine

WD1: mov dx,es:[bx]
call PrintDXh
jmp NewLine

SignExtend:
mov dl,es:[bx]
movsx edx,dl
call Chk32opd
jz SE16
call PrintEDXh
jmp NewLine

SE16: call PrintDXh
jmp NewLine

ModIsZero:
inc pcntr
call PrtEffAddr
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
call Chk32adr
jz SixteenBit
cmp al,5 ;MODRM = 00 101 (displ32, byte data) ?
jnz l1c93
add bx,4
jmp short l1c93

SixteenBit:
cmp al,6 ;check the 16-bit [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: push ax
mov al,tab
call typech
pop ax
ret

semic: mov al,';'
jmp typech

colon: mov al,':'
jmp typech

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

;--------------------------------
PrtaSegReg: ;the xxSreg3xxx ones
and al,00111000b
shr al,2
ALset: ;psgprf enters here
cmp al,0Ah ;AL must be 0, 2, 4, 6, 8, or 0Ah
jbe ALvalid
call pstg
db '*invalid*',0
jmp NewLine

ALvalid:mov bx,offset segtbl ;only ref
mov ch,2 ;length of each entry
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

PrtMiscInstr:
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
mov al,es:[bx+1] ;get ModTTTRM byte
mov bx,offset shftbl
PrtTTTopds:
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
jmp Prt3FromTabl

PrtArithInstr:
mov al,es:[bx]
mov bx,offset ArithTbl
jmp short PrtTTTopds

pcndop: mov bx,curadr ;print Conditional ops (JC, JNZ, etc)
mov al,es:[bx] ;get op code
mov bx,offset cndtbl ;only ref
and al,0Fh ;just look at low nibble
Prt3inALfromTbl:
mov ch,al
add al,al
add al,ch ;lo nibble X 3
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','FS','GS'

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'

ArithTbl 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'

Reg32tbl db 'EAX','ECX','EDX','EBX','ESP','EBP','ESI','EDI'
;--------------------------------
; 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 byte, word, dword 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 15h 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 or JECXZ [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 0fch,088h,19,'MOV..' ;MOV reg <-> reg/mem
db 0feh,084h,19,'TEST.' ;ModRegR/M
db 0feh,086h,19,'XCHG.' ;except with AX
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, 386
db 0ffh,026h,23,'.....' ;Kind23 is seg override prefix only
db 0ffh,02eh,23,'.....' ;CS
db 0ffh,036h,23,'.....' ;SS
db 0ffh,03eh,23,'.....' ;DS
db 0ffh,064h,23,'.....' ;FS
db 0ffh,065h,23,'.....' ;GS
db 0ffh,006h,24,'PUSH.' ;Kind24 are push/pop old 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 to memory
db 0fdh,08ch,28,'MOV..' ;MOV, mem-or-reg <-> seg reg
db 0feh,0c6h,29,'.....' ;MOV immed to reg/mem
db 0ffh,08dh,30,'.....' ;LEA ModRegR/M, but no Reg
db 0feh,0f6h,31,'.....' ;TEST, NOT immed w/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 or OOOOOOOO:SSSS
db 0ffh,0eah,34,'JMP..' ;OOOO:SSSS or OOOOOOOO: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 edx
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 from table
add bx,3 ;point 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 edx
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 PrtScrn
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 PrtScrn
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 PrtScrn
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 PrtScrn
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 PrtScrn
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 PrtScrn
db cr,lf,'Error creating file: Func 3Ch, AX returned ',0
pop bx
call Print00BX_
call PrtScrn
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 PrtScrn
db 'ERROR closing file (DOS func 3Eh)',cr,lf,0
jmp nxcmd

DiskFull:
call PrtScrn
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 PrtScrn
db cr,lf,'Error writing file: Func 40h, AX returned ',0
pop bx
call Print00BX_
call PrtScrn
db 'hex',cr,lf,0
jmp nxcmd

;--------------------------------
;called after every line. RegFirstFlag is reset at dline and kind22
NewLine:xor al,al
mov SzOvrdFlag,al
mov WordFlag,al
mov DwordFlag,al
mov ShortFlag,al
mov FwordFlag,al
mov MOVxXflag,al
mov bx,AppendPtr ;check for remark
or bx,bx
jz NewLine2
call PrtTab
mov ch,fs:[bx]
or ch,ch ;zero-length remark ?
jz NewLine2 ;if so, do nothing
PrtAppendedRem:
inc bx
mov al,fs:[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' ;set new d:\path\name to save to ?
jnz NotP
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 PrtScrn
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 PrtScrn ;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 PrtScrn
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 PrtScrn
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 PrtScrn

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.
PrtScrn: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
xor bx,bx
mov RemEndAddr,bx ;end = start
mov word ptr fs:[bx],0FFFFh ;end marker
mov Flag286,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 PrtScrn
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
PgmSeg dw 0 ;seg of target pgm loaded, use ES
RemSeg dw 0 ;seg of Remark table, use FS
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 (BEHISW or D) 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

;this table not now used
segnam dw 'SC' ; for CS, etc
dw 'SD'
dw 'SE'
dw 'SS'
dw 'SF'
dw 'SG'
dw 'X1'
dw 'X2'
dw 'X3'
dw '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 F G = 0 1 2 3 4 5,
; lower = Undefined, Byte, Word, Dword(Qword, Spaces)
RelFlag db 0 ;line addr or rel disp instr, don't correct for CurOrg
Flag286 db 0 ;1 = put '.286P' in .RSM, '186+ instrs in file
Flag386 db 0 ;code is 32-bit default (D flag in CS Descriptor is set)
SzOvrdFlag db 0 ;bit 0=operand, bit 1=eff adr size is opposite of D flag
MOVxXflag db 0 ;reg is 16/32 bit but 2 => opd is 8, 3 => 16 bit
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
CurSsIB db 0 ;current ssIndexBase (2nd modregrm byte) for 32-bit adr
DwordFlag db 0
FwordFlag db 0 ;current instr is 6-byte = 48-bit LxS in 32-bit mode
WordFlag db 0 ;current instr is a long '286
ShortFlag db 0 ;flag SETcc '386, addr is Byte, or rel displ is Byte
RegFirstFlag db 0
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 ;allow for 336 byte stack
stak dw 0 ;stack top
RemEndAddr dw 0 ;end addr or REM table
cfence db 0 ;this is ctlbas-1, holds BEHISWD for 1st line
ctlbas db 0 ;start of enough room for 1536 items, 4 bytes each

cseg ends
end start


  3 Responses to “Category : Assembly Language Source Code
Archive   : RESORC93.ZIP
Filename : RE-SOURC.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/