home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-08-06 | 159.2 KB | 6,767 lines |
- ; DEBUG.A86 A86 assembler source for a clone of DEBUG.COM
- ; Copyright 1995-1997 Paul Vojta.
-
- ; To do:
- ; help message
- ; /?
- ; x*
- ; *.HEX files
- ; `l' and `w' commands with addresses
- ; < and > and >>
- ; MMX instructions
-
- BS equ 8
- TAB equ 9
- LF equ 10
- CR equ 13
- TOLOWER equ 20h
- TOUPPER equ 0dfh
- TOUPPER_W equ 0dfdfh
-
- LINE_IN_LEN equ 257 ;length of line_in (including header stuff)
-
- jmp initcode
-
- cmdlist dw aa,error,cc,ddd,ee,ff,gg,hh,ii,error,error,ll,mm,nn,oo
- dw pp,qq,rr,sss,tt,uu,error,ww,xx
-
- savesp dw 0 ;save stack pointer
- errret dw 0 ;return here if error
- run_sp dw 0 ;stack pointer when running
- spadjust dw 0 ;adjust sp by this amount for save
- psp dw 0 ;program segment prefix
- blk1 dw 0 ;blocks to free on program termination
- blk2 dw 0
- running db 0 ;if there is a running child process
- run2324 dw 0,0,0,0 ;interrupt vectors 23 and 24 (when running)
- sav2324 dw 0,0,0,0 ;interrupt vectors 23 and 24 (ours)
- hakstat db 0 ;whether we have hacked the vectors or not
- psp22 dw 0,0 ;original terminate address in the PSP
- parent dw 0 ;original PSP of process parent (must be next)
- envlen dw 0 ;length of DEBUG's environment
- machine db 0 ;type of this processor
- has_87 db 0 ;if there is a math coprocessor present
- mach_87 db 0 ;type of coprocessor present
- notatty db LF ;if standard input is from a file
- switchar db 0 ;switch character
- swch1 db ' ' ;switch character if it's a slash
- promptlen dw 0 ;length of prompt
- bufnext dw line_in+2 ;address of next available character
- bufend dw line_in+2 ;address + 1 of last valid character
-
- a_addr dw 0,0 ;address for next 'a' command
- d_addr dw 0,0 ;address of last `d' command; must follow a_addr
- u_addr dw 0,0 ;address of last `u' command; must follow d_addr
- eqflag db 0 ;flag indicating presence of `=' operand
- eqladdr dw 0,0 ;address of `=' operand in G or T command
- run_cs dw 0 ;save original CS when running
- run_int dw 0 ;interrupt type that stopped the running
-
- intsave dw 0,0 ;save area for interrupt vectors 0, 1, and 3
- dw 0,0
- dw 0,0
-
- ; Parameter block for exec call.
-
- execblk dw 0 ;(0) copy the parent's environment
- dw 0,0 ;(2) address of command tail to copy
- dw 5ch,0 ;(6) address of first FCB to copy
- dw 6ch,0 ;(10) address of second FCB to copy
- dw 0,0 ;(14) initial SS:SP
- dw 0,0 ;(18) initial CS:IP
-
- ; Register save area.
-
- regs dw
- reg_ax dw 0 ;ax
- reg_bx dw 0 ;bx
- reg_cx dw 0 ;cx
- reg_dx dw 0 ;dx
- reg_sp dw 0 ;sp
- reg_bp dw 0 ;bp
- reg_si dw 0 ;si
- reg_di dw 0 ;di
- reg_ds dw 0 ;ds
- reg_es dw 0 ;es
- reg_ss dw 0 ;ss
- reg_cs dw 0 ;cs
- reg_ip dw 100h ;ip
- flags dw 200h ;flags (interrupts enabled)
-
- regnames dw 'XA','XB','XC','XD','PS','PB','IS','ID','SD','SE'
- dw 'SS','SC','PI' ;backwards ... because ...
-
- segletrs db 'd','e','s','c'
-
- ; Instruction set information needed for the 'p' command.
-
- ppbytes db 66h,67h,26h,2eh,36h,3eh,64h,65h,0f2h,0f3h ;prefixes
- db 0ach,0adh,0aah,0abh,0a4h,0a5h ;lods,stos,movs
- db 0a6h,0a7h,0aeh,0afh ;cmps,scas
- db 6ch,6dh,6eh,6fh ;ins,outs
- db 0cch,0cdh ;int instructions
- db 0e0h,0e1h,0e2h ;loop instructions
- db 0e8h ;call rel16/32
- db 09ah ;call far seg16:16/32
- ; (This last one is done explicitly by the code.)
- ; db 0ffh ;ff/2 or ff/3: indirect call
-
- ; Info for the above, respectively.
- ; 80h = prefix; 82h = operand size prefix; 81h = address size prefix.
- ; If the high bit is not set, the next highest bit (40h) indicates that
- ; the instruction size depends on whether there is an address size prefix,
- ; and the remaining bits tell the number of additional bytes in the
- ; instruction.
-
- ppinfo db 82h,81h,80h,80h,80h,80h,80h,80h,80h,80h
- db 0,0,0,0,0,0
- db 0,0,0,0
- db 0,0,0,0
- db 0,1
- db 1,1,1
- db 42h
- db 44h
-
- PPLEN equ 31 ;size of the above table
-
- ; Strings.
-
- prompt1 db '=' ;main prompt
- prompt2 db ':' ;prompt for register value
-
- helpmsg db 'This is the help message. I''ll think of something to',CR,LF
- db 'put here sometime.',CR,LF,'$'
-
- notyet db 'The extended memory commands have not been installed yet.'
- db CR,LF,'$'
-
- errcarat db '^ Error',CR,LF,'$'
-
- dskerrs dw dskerr0,dskerr1,dskerr2,dskerr3,dskerr4,dskerr9,dskerr6,dskerr7
- dw dskerr8,dskerr9,dskerra,dskerrb,dskerrc
- dskerr0 db 'Write protect error',0
- dskerr1 db 'Unknown unit error',0
- dskerr2 db 'Drive not ready',0
- dskerr3 db 'Unknown command',0
- dskerr4 db 'Data error (CRC)',0
- dskerr6 db 'Seek error',0
- dskerr7 db 'Unknown media type',0
- dskerr8 db 'Sector not found',0
- dskerr9 db 'Unknown error',0
- dskerra db 'Write fault',0
- dskerrb db 'Read fault',0
- dskerrc db 'General failure',0
- reading db ' read',0
- writing db ' writ',0
- drive db 'ing drive '
- driveno db 'x',0
- msg8088 db '8086/88',0
- msgx86 db 'x86',0
- no_copr db ' without coprocessor',0
- has_copr db ' with coprocessor',0
- has_287 db ' with 287',0
- unused db ' (unused)',0
- needsmsg db '[needs x86]'
- needsmsg_L equ 11
- needsmath db '[needs math coprocessor]'
- needsmath_L equ 24
- obsolete db '[obsolete]'
- obsolete_L equ 10
- int0msg db 'Divide error.',CR,LF,'$'
- int1msg db 'Unexpected single-step interrupt.',CR,LF,'$'
- int3msg db 'Unexpected breakpoint interrupt.',CR,LF,'$'
- progtrm db 'Program terminated normally.',CR,LF,'$'
- nowhexe db 'EXE and HEX files cannot be written.',CR,LF,'$'
- wwmsg1 db 'Writing $'
- wwmsg2 db ' bytes.',CR,LF,'$'
- diskful db 'Disk full.',CR,LF,'$'
- wwerr1 db 'Error $'
- wwerr2 db ' opening file.',CR,LF,'$'
- doserr2 db 'File not found.',CR,LF,'$'
- doserr3 db 'Path not found.',CR,LF,'$'
- doserr5 db 'Access denied.',CR,LF,'$'
- doserr8 db 'Insufficient memory.',CR,LF,'$'
- psperr db 'Error in create-psp call.',CR,LF,'$'
-
- ; Equates for instruction operands.
- ; First the sizes.
-
- OP_ALL equ 40h ;byte/word/dword operand (could be 30h but ...)
- OP_1632 equ 50h ;word or dword operand
- OP_8 equ 60h ;byte operand
- OP_16 equ 70h ;word operand
- OP_32 equ 80h ;dword operand
-
- OP_SIZE equ OP_ALL ;the lowest of these
-
- ; These operand types need to be combined with a size.
-
- OP_IMM equ 0 ;immediate
- OP_RM equ 2 ;reg/mem
- OP_M equ 4 ;mem (but not reg)
- OP_R_MOD equ 6 ;register, determined from MOD R/M part
- OP_MOFFS equ 8 ;memory offset; e.g., [1234]
- OP_R equ 10 ;reg part of reg/mem byte
- OP_R_ADD equ 12 ;register, determined from instruction byte
- OP_AX equ 14 ;al or ax or eax
-
- ; These don't need a size.
-
- OP_M64 equ 2 ;qword memory
- OP_MFLOAT equ 4 ;float memory
- OP_MDOUBLE equ 6 ;double-precision floating memory
- OP_M80 equ 8 ;tbyte memory
- OP_MXX equ 10 ;memory (size unknown)
- OP_FARMEM equ 12 ;far memory
- OP_FARP equ 14 ;far pointer
- OP_REL8 equ 16 ;byte address relative to IP
- OP_REL1632 equ 18 ;word or dword address relative to IP
- OP_1CHK equ 20 ;check for ST(1)
- OP_STI equ 22 ;ST(I)
- OP_CR equ 24 ;CRx
- OP_DR equ 26 ;DRx
- OP_TR equ 28 ;TRx
- OP_SEGREG equ 30 ;segment register
- OP_IMMS8 equ 32 ;sign extended immediate byte
- OP_IMM8 equ 34 ;immediate byte (other args may be (d)word)
- OP_ECX equ 36 ;ECX if 32-bit operands; otherwise nothing
- OP_SHOSIZ equ 38 ;set flag to always show the size
- OP_1 equ 40 ;1 (string ops from here on)
- OP_3 equ 42 ;3
- OP_DX equ 44 ;DX
- OP_CL equ 46 ;CL
- OP_ST equ 48 ;ST (top of coprocessor stack)
- OP_CS equ 50 ;CS
- OP_DS equ 52 ;DS
- OP_ES equ 54 ;ES
- OP_FS equ 56 ;FS
- OP_GS equ 58 ;GS
- OP_SS equ 60 ;SS
-
- ; Instructions that have an implicit operand subject to a segment override
- ; (outs, movs, cmps, lods, xlat).
-
- prfxtab db 06eh,06fh,0a4h,0a5h,0a6h,0a7h,0ach,0adh,0d7h
- P_LEN equ 9
-
- ; Instructions that can be used with REP/REPE/REPNE.
-
- replist db 06ch,06eh,0a4h,0aah,0ach ;REP
- db 0a6h,0aeh ;REPE/REPNE
-
- ;-@@-@@-@@-Do not edit these tables! They have been automatically generated.
-
- ; Main data table for the assembler.
-
- asmtab db 16,139,255,248,64,55,255,248,63,234,255,18,243,255,6,5
- db 245,173,221,245,176,68,245,4,212,5,111,255,1,53,245,173
- db 67,245,175,170,245,0,4,0,159,255,10,213,245,174,119,245
- db 176,222,245,9,164,10,63,255,240,29,205,255,239,29,129,255
- db 241,133,148,255,241,133,225,255,249,242,137,49,255,241,126,17
- db 241,179,79,255,245,241,133,73,245,241,180,54,255,245,241,130
- db 225,245,241,179,233,255,245,241,128,121,245,241,179,156,255,69
- db 212,181,59,181,109,46,95,255,249,45,184,255,74,152,255,75
- db 204,255,75,50,255,240,78,206,255,73,177,255,244,98,99,255
- db 244,97,47,255,244,96,226,255,244,98,22,255,244,96,226,255
- db 244,97,124,255,244,100,203,255,244,100,49,255,244,99,228,255
- db 244,100,126,255,244,98,22,255,244,96,226,255,244,97,47,255
- db 244,98,99,255,244,97,47,255,244,97,201,255,244,100,126,255
- db 244,99,228,255,244,100,49,255,244,100,203,255,244,96,149,255
- db 244,99,151,255,244,98,253,255,244,97,201,255,244,96,72,255
- db 244,99,74,255,244,99,74,255,244,99,151,255,244,98,176,255
- db 244,97,124,255,18,13,175,94,177,197,16,220,17,119,255,49
- db 238,255,249,50,59,255,245,242,129,244,255,243,183,60,255,243
- db 125,186,255,249,46,5,255,11,187,255,14,35,255,254,255,252
- db 255,21,185,245,185,165,245,189,142,255,253,255,239,60,58,255
- db 65,69,240,255,65,69,225,255,154,19,155,72,65,13,192,66
- db 66,192,255,66,221,192,66,198,193,255,154,178,155,231,255,165
- db 213,255,170,165,255,65,69,224,255,250,65,223,226,255,244,65
- db 244,208,255,244,65,244,192,255,244,65,167,192,255,244,65,167
- db 208,255,244,65,167,200,255,244,65,167,208,255,244,65,167,192
- db 255,244,65,244,192,255,244,65,244,208,255,244,65,244,200,255
- db 244,65,244,216,255,244,65,244,200,255,244,65,167,216,255,244
- db 65,167,200,255,158,227,160,24,65,20,208,64,248,209,255,244
- db 65,251,240,244,65,223,241,255,244,67,47,240,244,67,19,241
- db 255,161,75,162,128,65,20,216,64,248,217,255,66,198,217,255
- db 241,65,69,255,255,65,69,246,255,250,65,223,225,255,168,131
- db 169,184,65,13,240,66,66,248,255,66,221,248,66,198,249,255
- db 169,34,170,87,255,170,235,172,32,65,13,248,66,66,240,255
- db 66,221,240,66,198,241,255,171,138,172,191,255,250,65,223,224
- db 255,66,148,192,255,159,130,160,183,255,161,234,163,31,255,154
- db 255,156,52,168,50,255,65,69,247,255,250,65,223,227,255,159
- db 207,161,4,255,162,55,163,108,173,2,255,154,96,155,149,167
- db 9,65,96,192,255,65,69,232,255,65,69,233,255,65,69,234
- db 255,65,69,235,255,65,69,236,255,65,69,237,255,65,69,238
- db 255,250,166,110,255,164,10,255,156,123,157,176,65,13,200,66
- db 66,200,255,66,221,200,66,198,201,255,157,26,158,79,255,65
- db 69,208,255,65,69,243,255,65,69,248,255,241,65,69,245,255
- db 65,69,242,255,65,69,252,255,165,62,255,250,170,14,255,65
- db 69,253,255,250,240,65,223,228,255,241,65,69,254,255,241,65
- db 69,251,255,65,69,250,255,159,48,160,101,66,148,208,255,161
- db 152,162,205,171,217,66,148,216,255,250,171,62,255,250,168,218
- db 255,250,67,49,224,172,114,255,163,179,164,232,65,13,224,66
- db 66,232,255,66,221,232,66,198,233,255,164,82,165,135,255,166
- db 27,167,80,65,13,232,66,66,224,255,66,221,224,66,198,225
- db 255,166,186,167,239,255,65,69,228,255,241,66,149,224,241,66
- db 121,225,255,244,65,251,232,244,65,223,233,255,244,67,47,232
- db 244,67,19,233,255,241,66,149,232,241,66,121,233,255,241,65
- db 146,233,255,46,159,255,65,69,229,255,65,97,200,65,69,201
- db 255,65,69,244,255,65,69,241,255,65,69,249,255,73,100,255
- db 189,219,255,189,65,241,129,171,239,32,78,239,32,79,239,31
- db 182,239,31,183,255,68,183,71,32,255,19,81,245,185,88,245
- db 239,32,124,255,249,239,32,201,255,61,129,61,207,255,61,246
- db 255,242,79,104,255,242,192,80,255,249,62,67,255,35,242,241
- db 117,167,255,34,190,241,116,115,255,34,113,241,116,38,255,35
- db 165,241,117,90,255,34,113,241,116,38,255,249,68,110,255,35
- db 11,241,116,192,255,38,90,241,120,15,255,37,192,241,119,117
- db 255,37,115,241,119,40,255,38,13,241,119,194,255,35,165,241
- db 117,90,255,34,113,241,116,38,255,34,190,241,116,115,255,35
- db 242,241,117,167,255,34,190,241,116,115,255,35,88,241,117,13
- db 255,38,13,241,119,194,255,37,115,241,119,40,255,37,192,241
- db 119,117,255,38,90,241,120,15,255,34,36,241,115,217,255,37
- db 38,241,118,219,255,36,140,241,118,65,255,35,88,241,117,13
- db 255,33,215,241,115,140,255,36,217,241,118,142,255,36,217,241
- db 118,142,255,37,38,241,118,219,255,36,63,241,117,244,255,35
- db 11,241,116,192,255,70,214,70,33,181,213,182,7,70,111,255
- db 47,211,255,240,77,162,255,59,72,255,241,130,145,255,58,251
- db 255,241,131,43,255,241,131,120,255,42,112,255,239,60,117,255
- db 240,190,207,255,240,191,28,255,240,193,68,255,240,192,16,255
- db 246,240,51,188,255,249,52,9,255,68,34,68,33,255,67,213
- db 67,212,255,67,213,67,212,255,67,136,67,135,255,67,136,67
- db 135,255,240,77,239,255,240,193,145,255,48,77,48,232,40,236
- db 41,135,42,71,42,226,53,31,55,136,194,234,241,86,231,241
- db 87,130,241,87,54,241,87,209,241,88,31,241,88,186,255,49
- db 84,255,249,49,161,255,241,134,87,241,134,165,255,241,131,239
- db 241,132,61,255,188,244,255,245,188,167,255,43,80,255,245,188
- db 90,255,3,157,245,173,144,245,175,247,245,2,108,3,7,255
- db 251,255,69,97,71,202,255,239,33,22,255,249,239,33,99,255
- db 197,133,26,137,9,140,2,81,7,35,241,125,167,241,128,16
- db 255,249,239,29,45,255,249,47,57,255,24,33,182,111,239,32
- db 31,239,31,132,4,109,6,214,9,63,2,4,241,125,90,241
- db 127,195,255,249,239,28,224,255,249,46,236,255,200,144,202,249
- db 239,205,98,255,200,221,203,70,239,205,175,255,199,246,202,95
- db 239,204,200,255,200,67,202,172,239,205,21,255,243,92,10,255
- db 246,243,246,243,246,242,58,167,58,155,255,61,15,61,3,255
- db 243,128,34,255,47,134,255,201,42,203,147,239,205,252,255,202
- db 17,204,122,239,206,227,255,11,164,14,13,16,118,18,223,30
- db 78,30,156,255,247,38,247,46,247,54,247,62,247,100,247,101
- db 201,42,203,147,239,205,252,255,201,119,203,224,239,206,73,255
- db 8,109,245,174,42,245,176,145,245,7,60,7,215,255,52,86
- db 255,249,52,163,255,241,122,173,255,241,121,121,255,241,121,44
- db 255,241,122,96,255,241,121,44,255,241,121,198,255,241,125,21
- db 255,241,124,123,255,241,124,46,255,241,124,200,255,241,122,96
- db 255,241,121,44,255,241,121,121,255,241,122,173,255,241,121,121
- db 255,241,122,19,255,241,124,200,255,241,124,46,255,241,124,123
- db 255,241,125,21,255,241,120,223,255,241,123,225,255,241,123,71
- db 255,241,122,19,255,241,120,146,255,241,123,148,255,241,123,148
- db 255,241,123,225,255,241,122,250,255,241,121,198,255,240,190,53
- db 255,240,190,130,255,241,126,151,241,126,229,255,241,128,255,241
- db 129,77,255,240,192,169,255,240,191,118,255,74,229,255,76,25
- db 255,75,127,255,51,34,255,249,51,111,255,240,192,247,255,13
- db 61,245,174,196,245,177,43,245,12,12,12,167,255,50,137,187
- db 178,39,184,39,185,255,240,193,222,255,240,194,43,255,46,159
- db 255,242,79,181,255,243,91,112,255,245,242,134,196,255,43,149
- db 43,150,245,40,82,245,40,83,255,64,171,255,64,171,255,15
- db 165,245,175,17,245,177,120,245,14,116,15,15,255
-
- ; Data on groups (for the assembler).
-
- agroups dw 131,128,442,255,455,254,246,257,256,198,143,208,210,192
-
- ; This is the list of assembler mnemonics.
-
- mnlist db 1,1,"AAA",0,1,4,"AAD",0,1,8,"AAM",0,1,12,"AAS",0
- db 1,15,"ADC",0,1,29,"ADD",0,1,43,"AND",0,1,57,"ARPL",0
- db 1,61,"BOUND",0,1,65,"BSF",0,1,69,"BSR",0
- db 1,73,"BSWAP",0,1,78,"BT",0,1,85,"BTC",0,1,94,"BTR",0
- db 1,103,"BTS",0,1,112,"CALL",0,1,122,"CBW",0,2,37,"CDQ",0
- db 1,125,"CLC",0,1,128,"CLD",0,1,131,"CLI",0,1,134,"CLTS",0
- db 1,138,"CMC",0,1,141,"CMOVA",0,1,145,"CMOVAE",0
- db 1,149,"CMOVB",0,1,153,"CMOVBE",0,1,157,"CMOVC",0
- db 1,161,"CMOVE",0,1,165,"CMOVG",0,1,169,"CMOVGE",0
- db 1,173,"CMOVL",0,1,177,"CMOVLE",0,1,181,"CMOVNA",0
- db 1,185,"CMOVNAE",0,1,189,"CMOVNB",0,1,193,"CMOVNBE",0
- db 1,197,"CMOVNC",0,1,201,"CMOVNE",0,1,205,"CMOVNG",0
- db 1,209,"CMOVNGE",0,1,213,"CMOVNL",0,1,217,"CMOVNLE",0
- db 1,221,"CMOVNO",0,1,225,"CMOVNP",0,1,229,"CMOVNS",0
- db 1,233,"CMOVNZ",0,1,237,"CMOVO",0,1,241,"CMOVP",0
- db 1,245,"CMOVPE",0,1,249,"CMOVPO",0,1,253,"CMOVS",0
- db 2,2,"CMOVZ",0,2,6,"CMP",0,2,17,"CMPSB",0
- db 2,20,"CMPSD",0,2,21,"CMPSW",0,2,24,"CMPXCHG",0
- db 2,29,"CMPXCHG8B",0,2,33,"CPUID",0,6,188,"CS",0
- db 2,38,"CWD",0,1,121,"CWDE",0,2,41,"DAA",0,2,44,"DAS",0
- db 2,47,"DB",0,2,49,"DD",0,2,51,"DEC",0,2,57,"DIV",0
- db 6,192,"DS",0,2,60,"DW",0,2,62,"ENTER",0,6,186,"ES",0
- db 2,66,"F2XM1",0,2,70,"FABS",0,2,74,"FADD",0
- db 2,85,"FADDP",0,2,97,"FBLD",0,2,100,"FBSTP",0
- db 2,103,"FCHS",0,2,107,"FCLEX",0,2,112,"FCMOVA",0
- db 2,117,"FCMOVAE",0,2,122,"FCMOVB",0,2,127,"FCMOVBE",0
- db 2,132,"FCMOVE",0,2,137,"FCMOVNA",0,2,142,"FCMOVNAE",0
- db 2,147,"FCMOVNB",0,2,152,"FCMOVNBE",0,2,157,"FCMOVNE",0
- db 2,162,"FCMOVNU",0,2,167,"FCMOVNZ",0,2,172,"FCMOVU",0
- db 2,177,"FCMOVZ",0,2,182,"FCOM",0,2,193,"FCOMI",0
- db 2,202,"FCOMIP",0,2,211,"FCOMP",0,2,222,"FCOMPP",0
- db 2,226,"FCOS",0,2,231,"FDECSTP",0,2,235,"FDISI",0
- db 2,240,"FDIV",0,2,251,"FDIVP",0,3,8,"FDIVR",0
- db 3,19,"FDIVRP",0,3,31,"FENI",0,3,36,"FFREE",0
- db 2,92,"FIADD",0,3,40,"FICOM",0,3,45,"FICOMP",0
- db 3,3,"FIDIV",0,3,26,"FIDIVR",0,3,50,"FILD",0
- db 3,141,"FIMUL",0,3,57,"FINCSTP",0,3,61,"FINIT",0
- db 3,66,"FIST",0,3,71,"FISTP",0,3,253,"FISUB",0
- db 4,21,"FISUBR",0,3,78,"FLD",0,3,88,"FLD1",0
- db 3,116,"FLDCW",0,3,120,"FLDENV",0,3,96,"FLDL2E",0
- db 3,92,"FLDL2T",0,3,104,"FLDLG2",0,3,108,"FLDLN2",0
- db 3,100,"FLDPI",0,3,112,"FLDZ",0,3,123,"FMUL",0
- db 3,134,"FMULP",0,2,108,"FNCLEX",0,2,236,"FNDISI",0
- db 3,32,"FNENI",0,3,62,"FNINIT",0,3,117,"FNLDCW",0
- db 3,146,"FNOP",0,3,175,"FNSAVE",0,3,183,"FNSETPM",0
- db 3,221,"FNSTCW",0,3,225,"FNSTENV",0,3,229,"FNSTSW",0
- db 3,150,"FPATAN",0,3,154,"FPREM",0,3,158,"FPREM1",0
- db 3,163,"FPTAN",0,3,167,"FRNDINT",0,3,171,"FRSTOR",0
- db 6,194,"FS",0,3,174,"FSAVE",0,3,178,"FSCALE",0
- db 3,182,"FSETPM",0,3,188,"FSIN",0,3,193,"FSINCOS",0
- db 3,198,"FSQRT",0,3,202,"FST",0,3,220,"FSTCW",0
- db 3,224,"FSTENV",0,3,210,"FSTP",0,3,228,"FSTSW",0
- db 3,235,"FSUB",0,3,246,"FSUBP",0,4,3,"FSUBR",0
- db 4,14,"FSUBRP",0,4,26,"FTST",0,4,30,"FUCOM",0
- db 4,39,"FUCOMI",0,4,48,"FUCOMIP",0,4,57,"FUCOMP",0
- db 4,66,"FUCOMPP",0,4,71,"FWAIT",0,4,74,"FXAM",0
- db 4,78,"FXCH",0,4,85,"FXTRACT",0,4,89,"FYL2X",0
- db 4,93,"FYL2XP1",0,6,196,"GS",0,4,97,"HLT",0
- db 4,100,"IDIV",0,4,103,"IMUL",0,4,121,"IN",0,4,126,"INC",0
- db 4,132,"INSB",0,4,136,"INSD",0,4,137,"INSW",0
- db 4,141,"INT",0,4,146,"INTO",0,4,149,"INVD",0
- db 4,153,"INVLPG",0,4,158,"IRET",0,4,157,"IRETD",0
- db 4,161,"JA",0,4,167,"JAE",0,4,173,"JB",0,4,179,"JBE",0
- db 4,185,"JC",0,4,192,"JCXZ",0,4,195,"JE",0,4,191,"JECXZ",0
- db 4,201,"JG",0,4,207,"JGE",0,4,213,"JL",0,4,219,"JLE",0
- db 5,90,"JMP",0,4,225,"JNA",0,4,231,"JNAE",0,4,237,"JNB",0
- db 4,243,"JNBE",0,4,249,"JNC",0,4,255,"JNE",0,5,6,"JNG",0
- db 5,12,"JNGE",0,5,18,"JNL",0,5,24,"JNLE",0
- db 5,30,"JNO",0,5,36,"JNP",0,5,42,"JNS",0,5,48,"JNZ",0
- db 5,54,"JO",0,5,60,"JP",0,5,66,"JPE",0,5,72,"JPO",0
- db 5,78,"JS",0,5,84,"JZ",0,5,101,"LAHF",0,5,104,"LAR",0
- db 5,108,"LDS",0,5,126,"LEA",0,5,129,"LEAVE",0
- db 5,115,"LES",0,5,118,"LFS",0,5,133,"LGDT",0,5,122,"LGS",0
- db 5,137,"LIDT",0,5,141,"LLDT",0,5,145,"LMSW",0
- db 5,149,"LOCK",0,5,151,"LODSB",0,5,154,"LODSD",0
- db 5,155,"LODSW",0,5,158,"LOOP",0,5,163,"LOOPE",0
- db 5,173,"LOOPNE",0,5,178,"LOOPNZ",0,5,168,"LOOPZ",0
- db 5,183,"LSL",0,5,111,"LSS",0,5,187,"LTR",0,5,191,"MOV",0
- db 5,228,"MOVSB",0,5,231,"MOVSD",0,5,232,"MOVSW",0
- db 5,235,"MOVSX",0,5,242,"MOVZX",0,5,249,"MUL",0
- db 5,252,"NEG",0,6,1,"NOP",0,6,4,"NOT",0,6,8,"OR",0
- db 6,22,"ORG",0,6,24,"OUT",0,6,29,"OUTSB",0
- db 6,33,"OUTSD",0,6,34,"OUTSW",0,6,38,"POP",0
- db 6,56,"POPA",0,6,55,"POPAD",0,6,61,"POPF",0
- db 6,60,"POPFD",0,6,64,"PUSH",0,6,90,"PUSHA",0
- db 6,89,"PUSHAD",0,6,95,"PUSHF",0,6,94,"PUSHFD",0
- db 6,98,"RCL",0,6,106,"RCR",0,6,130,"RDMSR",0
- db 6,134,"REP",0,6,136,"REPE",0,6,138,"REPNE",0
- db 6,140,"RET",0,6,145,"RETF",0,6,114,"ROL",0,6,122,"ROR",0
- db 6,150,"RSM",0,6,154,"SAHF",0,6,157,"SAL",0,6,165,"SAR",0
- db 6,214,"SBB",0,6,228,"SCASB",0,6,231,"SCASD",0
- db 6,232,"SCASW",0,6,173,"SEG",0,6,235,"SETA",0
- db 6,239,"SETAE",0,6,243,"SETB",0,6,247,"SETBE",0
- db 6,251,"SETC",0,6,255,"SETE",0,7,4,"SETG",0
- db 7,8,"SETGE",0,7,12,"SETL",0,7,16,"SETLE",0
- db 7,20,"SETNA",0,7,24,"SETNAE",0,7,28,"SETNB",0
- db 7,32,"SETNBE",0,7,36,"SETNC",0,7,40,"SETNE",0
- db 7,44,"SETNG",0,7,48,"SETNGE",0,7,52,"SETNL",0
- db 7,56,"SETNLE",0,7,60,"SETNO",0,7,64,"SETNP",0
- db 7,68,"SETNS",0,7,72,"SETNZ",0,7,76,"SETO",0
- db 7,80,"SETP",0,7,84,"SETPE",0,7,88,"SETPO",0
- db 7,92,"SETS",0,7,96,"SETZ",0,7,100,"SGDT",0
- db 6,198,"SHL",0,7,108,"SHLD",0,6,206,"SHR",0
- db 7,115,"SHRD",0,7,104,"SIDT",0,7,122,"SLDT",0
- db 7,126,"SMSW",0,6,190,"SS",0,7,130,"STC",0,7,133,"STD",0
- db 7,136,"STI",0,7,139,"STOSB",0,7,142,"STOSD",0
- db 7,143,"STOSW",0,7,146,"STR",0,7,150,"SUB",0
- db 7,164,"TEST",0,7,173,"VERR",0,7,177,"VERW",0
- db 7,181,"WAIT",0,7,184,"WBINVD",0,7,188,"WRMSR",0
- db 7,192,"XADD",0,7,197,"XCHG",0,7,208,"XLAT",0
- db 7,211,"XLATB",0,7,214,"XOR",0
- end_mnlist db
-
- ; These are equates to refer to the above mnemonics.
-
- MNEM_BSWAP EQU 71
- MNEM_DB EQU 506
- MNEM_LOCK EQU 1819
- MNEM_REP EQU 2117
- MNEM_REPE EQU 2123
- MNEM_REPNE EQU 2130
- MNEM_SEG EQU 2218
- MNEM_WAIT EQU 2592
-
- ; Number of entries in the following array.
-
- ASMMOD EQU 77
-
- ; This is an array of indices into the oplists array (below).
- ; It is used by the assembler to save space.
-
- opindex db 0,1,4,7,10,13,16,19,22,25,27,30,33,35,37,39,41
- db 43,45,48,50,52,55,58,62,64,66,68,70,73,75,77,81
- db 85,89,93,96,99,101,103,105,108,110,112,115,118,121,124,127
- db 130,134,138,141,144,146,148,150,152,154,156,158,161,164,167,170
- db 173,175,177,181,185,188,191,194,197,200,203,206
-
- ; These are the lists of operands for the various instruction types.
-
- oplists db 0 ;simple instruction
- db OP_ALL+OP_AX, OP_ALL+OP_IMM, 0
- db OP_ALL+OP_RM, OP_ALL+OP_IMM, 0
- db OP_1632+OP_RM, OP_IMMS8, 0
- db OP_ALL+OP_RM, OP_ALL+OP_R, 0
- db OP_ALL+OP_R, OP_ALL+OP_RM, 0
- db OP_16+OP_RM, OP_16+OP_R, 0
- db OP_1632+OP_R, OP_1632+OP_M, 0
- db OP_1632+OP_R, OP_1632+OP_RM, 0
- db OP_32+OP_R_ADD, 0
- db OP_1632+OP_RM, OP_1632+OP_R, 0
- db OP_1632+OP_RM, OP_IMM8, 0
- db OP_REL1632, 0
- db OP_FARP, 0
- db OP_FARMEM, 0
- db OP_M64, 0
- db OP_ALL+OP_RM, 0
- db OP_1632+OP_R_ADD, 0
- db OP_16+OP_IMM, OP_IMM8, 0
- db OP_MFLOAT, 0
- db OP_MDOUBLE, 0
- db OP_ST, OP_STI, 0
- db OP_STI, OP_ST, 0
- db OP_1CHK, OP_STI, OP_ST, 0
- db OP_32+OP_M, 0
- db OP_16+OP_M, 0
- db OP_M80, 0
- db OP_STI, 0
- db OP_1CHK, OP_STI, 0
- db OP_MXX, 0
- db OP_16+OP_AX, 0
- db OP_1632+OP_R, OP_1632+OP_RM, OP_IMMS8, 0
- db OP_1632+OP_R_MOD, OP_1632+OP_R, OP_IMMS8, 0
- db OP_1632+OP_R, OP_1632+OP_RM, OP_1632+OP_IMM, 0
- db OP_1632+OP_R_MOD, OP_1632+OP_R, OP_1632+OP_IMM, 0
- db OP_ALL+OP_AX, OP_IMM8, 0
- db OP_ALL+OP_AX, OP_DX, 0
- db OP_3, 0
- db OP_IMM8, 0
- db OP_REL8, 0
- db OP_ECX, OP_REL8, 0
- db OP_1632+OP_RM, 0
- db OP_16+OP_RM, 0
- db OP_16+OP_RM, OP_SEGREG, 0
- db OP_SEGREG, OP_16+OP_RM, 0
- db OP_ALL+OP_AX, OP_ALL+OP_MOFFS, 0
- db OP_ALL+OP_MOFFS, OP_ALL+OP_AX, 0
- db OP_8+OP_R_ADD, OP_8+OP_IMM, 0
- db OP_1632+OP_R_ADD, OP_1632+OP_IMM, 0
- db OP_1632+OP_R, OP_SHOSIZ, OP_8+OP_RM, 0
- db OP_1632+OP_R, OP_SHOSIZ, OP_16+OP_RM, 0
- db OP_IMM8, OP_ALL+OP_AX, 0
- db OP_DX, OP_ALL+OP_AX, 0
- db OP_1632+OP_M, 0
- db OP_ES, 0
- db OP_CS, 0
- db OP_SS, 0
- db OP_DS, 0
- db OP_FS, 0
- db OP_GS, 0
- db OP_SHOSIZ, OP_1632+OP_IMM, 0
- db OP_SHOSIZ, OP_IMM8, 0
- db OP_ALL+OP_RM, OP_1, 0
- db OP_ALL+OP_RM, OP_CL, 0
- db OP_ALL+OP_RM, OP_IMM8, 0
- db OP_16+OP_IMM, 0
- db OP_8+OP_RM, 0
- db OP_1632+OP_RM, OP_1632+OP_R, OP_IMM8, 0
- db OP_1632+OP_RM, OP_1632+OP_R, OP_CL, 0
- db OP_1632+OP_AX, OP_1632+OP_R_ADD, 0
- db OP_1632+OP_R_ADD, OP_1632+OP_AX, 0
- db OP_32+OP_R_MOD, OP_CR, 0
- db OP_CR, OP_32+OP_R_MOD, 0
- db OP_32+OP_R_MOD, OP_DR, 0
- db OP_DR, OP_32+OP_R_MOD, 0
- db OP_32+OP_R_MOD, OP_TR, 0
- db OP_TR, OP_32+OP_R_MOD, 0
-
- OPTYPES_BASE EQU 12
-
- OPLIST_Z EQU 113
- OPLIST_ES EQU 158
-
- ; Here is the compressed table of the opcode types.
-
- optypes db 22, 22, 25, 25, 13, 13,158,158 ; 00 - 07 (main opcode part)
- db 22, 22, 25, 25, 13, 13,160, 2 ; 08 - 0f
- db 22, 22, 25, 25, 13, 13,162,162 ; 10 - 17
- db 22, 22, 25, 25, 13, 13,164,164 ; 18 - 1f
- db 22, 22, 25, 25, 13, 13, 10, 12 ; 20 - 27
- db 22, 22, 25, 25, 13, 13, 10, 12 ; 28 - 2f
- db 22, 22, 25, 25, 13, 13, 10, 12 ; 30 - 37
- db 22, 22, 25, 25, 13, 13, 10, 12 ; 38 - 3f
- db 55, 55, 55, 55, 55, 55, 55, 55 ; 40 - 47
- db 55, 55, 55, 55, 55, 55, 55, 55 ; 48 - 4f
- db 55, 55, 55, 55, 55, 55, 55, 55 ; 50 - 57
- db 55, 55, 55, 55, 55, 55, 55, 55 ; 58 - 5f
- db 12, 12, 31, 28, 10, 10, 10, 10 ; 60 - 67
- db 170, 97,173, 89, 12, 12, 12, 12 ; 68 - 6f
- db 115,115,115,115,115,115,115,115 ; 70 - 77
- db 115,115,115,115,115,115,115,115 ; 78 - 7f
- db 4, 4, 0, 4, 22, 22, 25, 25 ; 80 - 87
- db 22, 22, 25, 25,124, 31,127, 4 ; 88 - 8f
- db 12,197,197,197,197,197,197,197 ; 90 - 97
- db 12, 12, 47, 12, 12, 12, 12, 12 ; 98 - 9f
- db 130,130,133,133, 12, 12, 12, 12 ; a0 - a7
- db 13, 13, 12, 12, 12, 12, 12, 12 ; a8 - af
- db 136,136,136,136,136,136,136,136 ; b0 - b7
- db 139,139,139,139,139,139,139,139 ; b8 - bf
- db 4, 4,185, 12, 31, 31, 4, 4 ; c0 - c7
- db 57, 12,185, 12,111,113, 12, 12 ; c8 - cf
- db 4, 4, 4, 4,113,113, 0, 12 ; d0 - d7
- db 6, 6, 6, 6, 6, 6, 6, 6 ; d8 - df
- db 117,117,117,115,105,105,150,150 ; e0 - e7
- db 45, 45, 47,115,108,108,153,153 ; e8 - ef
- db 10, 0, 10, 10, 12, 12, 4, 4 ; f0 - f7
- db 12, 12, 12, 12, 12, 12, 4, 4 ; f8 - ff
- db 16, 16, 16, 16, 16, 16, 16, 16 ; 100 - 107 (Intel group 1)
- db 19, 19, 19, 19, 19, 19, 19, 19 ; 108 - 10f
- db 176,176,176,176,176,176, 0,176 ; 110 - 117 (Intel group 2)
- db 179,179,179,179,179,179, 0,179 ; 118 - 11f
- db 182,182,182,182,182,182, 0,182 ; 120 - 127 (Intel group 2a)
- db 16, 0, 53, 53, 53, 53, 53, 53 ; 128 - 12f (Intel group 3)
- db 53, 53,120, 49,120, 49,120, 0 ; 130 - 137 (Intel group 5)
- db 120,122,122,122,122,122, 0, 0 ; 138 - 13f (Intel group 6)
- db 85, 85, 85, 85,122, 0,122, 85 ; 140 - 147 (Intel group 7)
- db 60, 60, 60, 60, 60, 60, 60, 60 ; 148 - 14f (Coprocessor d8)
- db 64, 64, 82, 82, 64, 64, 64, 64 ; 150 - 157
- db 60, 0, 60, 60, 85, 76, 85, 76 ; 158 - 15f (Coprocessor d9)
- db 80, 82, 8, 0, 8, 8, 8, 8 ; 160 - 167
- db 74, 74, 74, 74, 74, 74, 74, 74 ; 168 - 16f (Coprocessor da)
- db 64, 64, 64, 64, 0, 8, 0, 0 ; 170 - 177
- db 74, 0, 74, 74, 0, 78, 0, 78 ; 178 - 17f (Coprocessor db)
- db 64, 64, 64, 64, 8, 82, 82, 0 ; 180 - 187
- db 62, 62, 62, 62, 62, 62, 62, 62 ; 188 - 18f (Coprocessor dc)
- db 67, 67, 0, 0, 67, 67, 67, 67 ; 190 - 197
- db 62, 0, 62, 62, 85, 0, 85, 76 ; 198 - 19f (Coprocessor dd)
- db 80, 0, 80, 80, 82, 82, 0, 0 ; 1a0 - 1a7
- db 76, 76, 76, 76, 76, 76, 76, 76 ; 1a8 - 1af (Coprocessor de)
- db 70, 70, 0, 8, 70, 70, 70, 70 ; 1b0 - 1b7
- db 76, 0, 76, 76, 78, 51, 78, 51 ; 1b8 - 1bf (Coprocessor df)
- db 0, 0, 0, 0, 8, 82, 82, 0 ; 1c0 - 1c7
- db 12, 12, 12, 12, 12, 12, 12, 0 ; 1c8 - 1cf (Coprocessor groups)
- db 12, 12, 12, 12, 12, 12, 12, 12 ; 1d0 - 1d7
- db 12, 12, 12, 12, 12, 12, 12, 12 ; 1d8 - 1df
- ; The rest of these are squeezed.
- db 0, 4, 4, 34, 34, 12, 12, 12
- db 203,209,206,212,215,218, 12, 12
- db 34, 34, 34, 34, 34, 34, 34, 34
- db 34, 34, 34, 34, 34, 34, 34, 34
- db 45, 45, 45, 45, 45, 45, 45, 45
- db 45, 45, 45, 45, 45, 45, 45, 45
- db 187,187,187,187,187,187,187,187
- db 187,187,187,187,187,187,187,187
- db 166,166, 12, 39,189,193,168,168
- db 12, 39,189,193, 34, 22, 22, 31
- db 39, 31, 31,142,146, 4, 39, 34
- db 34,142,146, 22, 22, 4, 37, 37
- db 37, 37, 37, 37, 37, 37, 53, 53
- db 42, 42, 42, 42, 51,156, 16, 12
- db 12, 12, 12, 12, 12, 12, 12, 12
- db 12, 12, 12, 87
-
- ; And here is the compressed table of additional information.
-
- opinfo dw 00020h,00020h,00020h,00020h,00020h,00020h,00808h,007e4h ; 00
- dw 007bbh,007bbh,007bbh,007bbh,007bbh,007bbh,00808h,001e0h ; 08
- dw 0001ah,0001ah,0001ah,0001ah,0001ah,0001ah,00808h,007e4h ; 10
- dw 0088ch,0088ch,0088ch,0088ch,0088ch,0088ch,00808h,007e4h ; 18
- dw 00026h,00026h,00026h,00026h,00026h,00026h,00001h,001eeh ; 20
- dw 00a05h,00a05h,00a05h,00a05h,00a05h,00a05h,00101h,001f4h ; 28
- dw 00a55h,00a55h,00a55h,00a55h,00a55h,00a55h,00201h,00002h ; 30
- dw 001a0h,001a0h,001a0h,001a0h,001a0h,001a0h,00301h,00014h ; 38
- dw 005c2h,005c2h,005c2h,005c2h,005c2h,005c2h,005c2h,005c2h ; 40
- dw 00204h,00204h,00204h,00204h,00204h,00204h,00204h,00204h ; 48
- dw 00808h,00808h,00808h,00808h,00808h,00808h,00808h,00808h ; 50
- dw 007e4h,007e4h,007e4h,007e4h,007e4h,007e4h,007e4h,007e4h ; 58
- dw 0180fh,017eah,01033h,0202ch,03401h,03501h,03008h,03010h ; 60
- dw 01808h,015b6h,01808h,015b6h,015c8h,015d6h,017cch,017dch ; 68
- dw 006ach,00694h,00614h,0060eh,006c7h,006a6h,00619h,00609h ; 70
- dw 006c2h,006a0h,006b6h,006bch,00643h,0063dh,00648h,00638h ; 78
- dw 00100h,00100h,00000h,00108h,00a0bh,00a0bh,00a3fh,00a3fh ; 80
- dw 00775h,00775h,00775h,00775h,00775h,006dfh,00775h,002f8h ; 88
- dw 007afh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh ; 90
- dw 0006dh,001e1h,00066h,00a20h,00820h,007f9h,00879h,006cch ; 98
- dw 00775h,00775h,00775h,00775h,0077bh,0078bh,001a6h,001b6h ; a0
- dw 00a0bh,00a0bh,009e7h,009f7h,00722h,00732h,00892h,008a2h ; a8
- dw 00775h,00775h,00775h,00775h,00775h,00775h,00775h,00775h ; b0
- dw 00775h,00775h,00775h,00775h,00775h,00775h,00775h,00775h ; b8
- dw 00120h,00120h,0085ah,0085ah,006edh,006d9h,00300h,00300h ; c0
- dw 0121ah,016e5h,00860h,00860h,005ddh,005ddh,005e3h,005fah ; c8
- dw 00110h,00110h,00118h,00118h,0000eh,00008h,00000h,00a4dh ; d0
- dw 00148h,00158h,00168h,00178h,00188h,00198h,001a8h,001b8h ; d8
- dw 00752h,0075bh,0073ah,00624h,005bdh,005bdh,007c6h,007c6h ; e0
- dw 00066h,0064eh,0064eh,0064eh,005bdh,005bdh,007c6h,007c6h ; e8
- dw 00004h,00000h,00002h,00002h,005a9h,00092h,00128h,00128h ; f0
- dw 00079h,009d5h,00085h,009e1h,0007fh,009dbh,002e0h,00130h ; f8
- dw 00020h,007bbh,0001ah,0088ch,00026h,00a05h,00a55h,001a0h ; 100
- dw 00020h,007bbh,0001ah,0088ch,00026h,00a05h,00a55h,001a0h ; 108
- dw 00867h,0086dh,00831h,00837h,009a1h,009aeh,00000h,00886h ; 110
- dw 00867h,0086dh,00831h,00837h,009a1h,009aeh,00000h,00886h ; 118
- dw 01867h,0186dh,01831h,01837h,019a1h,019aeh,00000h,01886h ; 120
- dw 00a0bh,00000h,007b5h,007a9h,007a3h,005b6h,0020ah,005afh ; 128
- dw 005c2h,00204h,00066h,00066h,0064eh,0064eh,00808h,00000h ; 130
- dw 029c2h,029ffh,0270dh,0276fh,02a12h,02a19h,00000h,00000h ; 138
- dw 0299ah,029bbh,026f9h,02706h,029c9h,00000h,02714h,045f1h ; 140
- dw 00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh ; 148
- dw 00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh ; 150
- dw 003c8h,00000h,004f7h,0050eh,003ddh,0044bh,00477h,0046eh ; 158
- dw 003c8h,00581h,00308h,00000h,00310h,001c8h,001d0h,001d8h ; 160
- dw 0035dh,0038eh,00365h,0036dh,003b7h,003bfh,00376h,0037eh ; 168
- dw 06276h,06289h,0627fh,062dah,00000h,00318h,00000h,00000h ; 170
- dw 00387h,00000h,003a8h,003afh,00000h,003c8h,00000h,0050eh ; 178
- dw 062a7h,062bch,062b1h,062c6h,00320h,0654ch,062f3h,00000h ; 180
- dw 00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh ; 188
- dw 00236h,00419h,00000h,00000h,0052ch,0051dh,0033dh,0032eh ; 190
- dw 003c8h,00000h,004f7h,0050eh,004b6h,00000h,0045bh,00481h ; 198
- dw 00355h,00000h,004f7h,0050eh,03544h,0355fh,00000h,00000h ; 1a0
- dw 0035dh,0038eh,00365h,0036dh,003b7h,003bfh,00376h,0037eh ; 1a8
- dw 0023dh,00420h,00000h,00328h,00534h,00524h,00345h,00335h ; 1b0
- dw 00387h,00000h,003a8h,003afh,00245h,00387h,0024ch,003afh ; 1b8
- dw 00000h,00000h,00000h,00000h,00330h,06555h,062fbh,00000h ; 1c0
- dw 003ceh,003efh,003e6h,0040ah,003f8h,00401h,00412h,00000h ; 1c8
- dw 00227h,00592h,004a4h,0048ah,00588h,0349bh,0031ch,00396h ; 1d0
- dw 00493h,0059ah,004efh,034e5h,004ach,004cch,034deh,03315h ; 1d8
- ; The rest of these are squeezed.
- dw 0,00138h,00140h,026d3h,02763h,0208bh,045eah,04a27h
- dw 03775h,03775h,03775h,03775h,03775h,03775h,05a30h,0583dh
- dw 0616eh,0614ah,060a9h,060a0h,06198h,06165h,060b1h,06098h
- dw 06190h,0615ch,0617eh,06187h,060dbh,060d2h,060e3h,060cah
- dw 036ach,03694h,03614h,0360eh,036c7h,036a6h,03619h,03609h
- dw 036c2h,036a0h,036b6h,036bch,03643h,0363dh,03648h,03638h
- dw 0396eh,0394eh,038bfh,038b7h,03993h,03966h,038c6h,038b0h
- dw 0398ch,0395eh,0397ch,03984h,038ebh,038e3h,038f2h,038dch
- dw 03808h,037e4h,051d4h,0304fh,039a7h,039a7h,03808h,037e4h
- dw 05873h,03060h,039b4h,039b4h,035b6h,041beh,041beh,03769h
- dw 0305ah,036f3h,03700h,0379bh,0379bh,002e8h,03054h,0303bh
- dw 03041h,03793h,03793h,04a38h,04a38h,002f0h,04047h,04047h
- dw 04047h,04047h,04047h,04047h,04047h,04047h,005c2h,00204h
- dw 0304fh,03060h,0305ah,03054h,051c8h,007e4h,00775h,00454h
- dw 00254h,0022fh,0053dh,0057ah,03568h,0043ah,00431h,00428h
- dw 00442h,02464h,0030ch,00481h
-
- ; This table converts unsqueezed numbers to squeezed.
-
- sqztab db 1, 2, 3, 4, 0, 0, 5, 0
- db 6, 7, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 8, 9, 10, 11, 12, 0, 13, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 14, 0, 15, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 16, 17, 18, 19, 20, 21, 22, 23
- db 24, 25, 26, 27, 28, 29, 30, 31
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 32, 33, 34, 35, 36, 37, 38, 39
- db 40, 41, 42, 43, 44, 45, 46, 47
- db 48, 49, 50, 51, 52, 53, 54, 55
- db 56, 57, 58, 59, 60, 61, 62, 63
- db 64, 65, 66, 67, 68, 69, 0, 0
- db 70, 71, 72, 73, 74, 75, 0, 76
- db 77, 78, 79, 80, 81, 82, 83, 84
- db 0, 0, 85, 86, 87, 88, 89, 90
- db 91, 92, 0, 0, 0, 0, 0, 93
- db 94, 95, 96, 97, 98, 99,100,101
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0, 0, 0, 0, 0
- db 102,103, 0, 0, 0, 0, 0, 0
- db 0, 0, 0, 0,104,105,106,107
- db 0,108, 0, 0, 0, 0, 0, 0
- db 109, 0, 0, 0, 0, 0, 0, 0
- db 110, 0, 0, 0, 0, 0, 0, 0
- db 111, 0, 0, 0, 0, 0, 0, 0
- db 112,113, 0, 0,114,115, 0, 0
- db 0,116, 0, 0, 0, 0, 0, 0
- db 117,118,119,120,121, 0, 0, 0
- db 0,122, 0, 0, 0, 0, 0, 0
- db 123, 0, 0, 0, 0, 0, 0, 0
-
- ; This is the table of mnemonics that change in the presence of a WAIT
- ; instruction.
-
- wtab1 dw 802, 801, 800, 803, 349, 414, 804, 351
- dw 350, 816, 415
- wtab2 dw 603, 806, 846, 928, 981, 1220, 1237, 1277
- dw 1285, 1301, 1301
- N_WTAB equ 11
-
- ; This is the table for operands which have a different mnemonic for
- ; their 32 bit versions.
-
- ltab1 dw 152, 167, 153, 109, 207, 227, 173, 165
- dw 111, 97, 157, 96, 156, 175, 171
- ltab2 dw 487, 430, 115, 1487, 1537, 1584, 1834, 1923
- dw 2004, 2033, 2048, 2071, 2088, 2202, 2543
- N_LTAB equ 15
-
- ; This is the table of lockable instructions
-
- locktab dw 266, 258, 16, 17, 264, 256, 0, 1
- dw 268, 260, 32, 33, 667, 751, 659, 750
- dw 651, 749, 656, 657, 737, 305, 736, 304
- dw 299, 298, 265, 257, 8, 9, 267, 259
- dw 24, 25, 269, 261, 40, 41, 672, 673
- dw 134, 135, 270, 262, 48, 49
- N_LOCK equ 46
-
- ; Equates used in the assembly-language code.
-
- SPARSE_BASE equ 480
-
- SFPGROUP3 equ 800
-
- ;-@@-@@-@@-End of auto-generated tables. You may edit below this point.
-
-
- ; debug22 - INT 22 (Program terminate) interrupt handler.
- ; This is for DEBUG itself: it's a catch-all for the various INT 23
- ; and INT 24 calls that may occur unpredictably at any time.
- ; What we do is pretend to be a command interpreter (which we are,
- ; in a sense, just a different sort of command) by setting the PSP of
- ; our parent equal to our own PSP so that DOS does not free our memory
- ; when we quit. Therefore control ends up here when Control-Break or
- ; an Abort in Abort/Retry/Fail is selected.
-
- debug22:cld ;reestablish things
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
-
- ; Begin main command loop.
-
- cmd3: mov errret,offset cmd3
- mov sp,savesp ;restore stack (this must be first)
- mov dx,offset prompt1
- mov cx,1
- call getline ;prompted input
- cmp al,CR
- je cmd3 ;if blank line
- cmp al,';'
- je cmd3 ;if comment
- cmp al,'?'
- je help ;if request for help
- or al,TOLOWER
- sub al,'a'
- cbw
- cmp al,'x'-'a'
- ja errorj1 ;if not recognized
- xchg bx,ax
- je cmd4 ;if 'x'
- call skipwhite
- cmd4: mov di,offset line_out
- shl bx,1
- call cmdlist[bx]
- jmp cmd3 ;back to the top
-
- help: mov ah,9 ;print string
- mov dx,offset helpmsg
- int 21h
- jmp cmd3 ;done
-
- xx: mov ah,9 ;print string
- mov dx,offset notyet
- int 21h
- ret ;done
-
- errorj1:jmp error
-
- ; A command - tiny assembler.
-
- asm_mn_flags db 0 ;flags for the mnemonic
- AMF_D32 equ 1 ;(order is important for D32/WAIT)
- AMF_WAIT equ 2
- AMF_A32 equ 4 ;if this is 32 bit addressing
- AMF_SIB equ 8 ;there's a SIB in the arguments
- AMF_MSEG equ 10h ;if a seg prefix was given b4 mnemonic
- AMF_FSGS equ 20h ;if FS or GS was encountered
-
- aa_saved_prefix db 0 ;WAIT or REP... prefix
- ; aa_saved_prefix and aa_seg_pre must be consecutive.
- aa_seg_pre db 0 ;segment prefix
-
- mneminfo dw 0 ;address associated with the mnemonic
-
- ; The following (through a_opcode) must all be consecutive.
-
- rmaddr dw 0 ;address of operand giving the R/M byte
- regmem db 0 ;mod reg r/m part of instruction
- ;regmem and sibbyte must be consecutive
- sibbyte db 0 ;SIB byte
- immaddr dw 0 ;address of operand giving the immed stf
- xxaddr dw 0 ;address of additional stuff
- dismach db 0 ;type of processor needed
- dmflags db 0 ;flags for extra processor features
-
- DM_COPR equ 1 ;math coprocessor
- DM_MMX equ 2 ;MMX extensions
-
- opcode_or db 0 ;extra bits in the op code
- opsize db 0 ;size of this operation
- varflags db 0 ;flags for this variant
-
- VAR_LOCKABLE equ 1 ;variant is lockable
- VAR_MODRM equ 2 ;if there's a MOD R/M here
- VAR_SIZ_GIVN equ 4 ;if a size was given
- VAR_SIZ_FORCD equ 8 ;if only one size is permitted
- VAR_SIZ_NEED equ 10h ;if we need the size
- VAR_D32 equ 20h ;if there's a 32 bit operand size prefix
-
- a_opcode dw 0 ;op code info for this variant
- a_reqsize db 0 ;size that this arg should be
-
- a_opcode2 dw 0 ;copy of a_opcode for obs-instruction
- dw 0dbe0h,0dbe1h,0dbe4h,124h,126h ;obs. instruction codes
- ;(the above must follow a_opcode2)
-
- obsmach db 1,1,2,4,4 ;max permissible machine for the above
-
- aadbsiz db 0,4,2,1 ;table for max size of db operand
- aadbsto dw 0,aa28,aa29,aa30;table for routine to store a number
-
- modrmtab db 11,0,13,0,15,0,14,0 ;[bx], [bp], [di], [si]
- db 15,13,14,13,15,11,14,11 ;[bp+di],[bp+si],[bx+di],[bx+si]
-
- aam_args db 'a',CR
-
- ; Equates for parsed arguments.
-
- ARG_DEREF equ 1 ;non-immediate memory reference
- ARG_MODRM equ 2 ;if we've computed the MOD R/M byte
- ARG_JUSTREG equ 4 ;a solo register
- ARG_WEIRDREG equ 8 ;if it's a segment register or CR, etc.
- ARG_IMMED equ 10h ;if it's just a number
- ARG_FARADDR equ 20h ;if it's of the form xxxx:yyyyyyyy
-
- ; For each operand type in the following table, the first byte is
- ; the bits, at least one of which must be present; the second is the
- ; bits all of which must be absent.
-
- bittab db ARG_IMMED ;OP_IMM
- db ARG_DEREF+ARG_JUSTREG ;OP_RM
- db ARG_DEREF ;OP_M
- db ARG_JUSTREG ;OP_R_MOD
- db ARG_DEREF ;OP_MOFFS
- db ARG_JUSTREG ;OP_R
- db ARG_JUSTREG ;OP_R_ADD
- db ARG_JUSTREG ;OP_AX
- db ARG_DEREF ;OP_M64
- db ARG_DEREF ;OP_MFLOAT
- db ARG_DEREF ;OP_MDOUBLE
- db ARG_DEREF ;OP_M80
- db ARG_DEREF ;OP_MXX
- db ARG_DEREF ;OP_FARMEM
- db ARG_FARADDR ;OP_FARP
- db ARG_IMMED ;OP_REL8
- db ARG_IMMED ;OP_REL1632
- db ARG_WEIRDREG ;OP_1CHK
- db ARG_WEIRDREG ;OP_STI
- db ARG_WEIRDREG ;OP_CR
- db ARG_WEIRDREG ;OP_DR
- db ARG_WEIRDREG ;OP_TR
- db ARG_WEIRDREG ;OP_SEGREG
- db ARG_IMMED ;OP_IMMS8
- db ARG_IMMED ;OP_IMM8
- db ARG_JUSTREG ;OP_ECX
- db 0ffh ;OP_SHOSIZ
- db ARG_IMMED ;OP_1
- db ARG_IMMED ;OP_3
- db ARG_JUSTREG ;OP_DX
- db ARG_JUSTREG ;OP_CL
- db ARG_WEIRDREG ;OP_ST
- db ARG_WEIRDREG ;OP_CS
- db ARG_WEIRDREG ;OP_DS
- db ARG_WEIRDREG ;OP_ES
- db ARG_WEIRDREG ;OP_FS
- db ARG_WEIRDREG ;OP_GS
- db ARG_WEIRDREG ;OP_SS
-
- ; Jump table for operand types.
-
- asm_jmp1 dw ao04,ao01,ao01,ao01 ;OP_IMM, OP_RM, OP_M, OP_R_MOD
- dw ao05,ao02,ao03,ao06 ;OP_MOFFS, OP_R, OP_R_ADD, OP_AX
-
- dw ao17,ao17,ao17 ;OP_M64, OP_MFLOAT, OP_MDOUBLE
- dw ao17,ao17,ao17 ;OP_M80, OP_MXX, OP_FARMEM
- dw ao21,ao23,ao25 ;OP_FARP, OP_REL8, OP_REL1632
- dw ao29,ao30,ao31 ;OP_1CHK, OP_STI, OP_CR
- dw ao34,ao35,ao39 ;OP_DR, OP_TR, OP_SEGREG
- dw ao41,ao42,ao43m ;OP_IMMS8, OP_IMM8, OP_ECX
- dw ao44,ao46,ao47 ;OP_SHOSIZ, OP_1, OP_3
- dw ao48,ao48,ao48 ;OP_DX, OP_CL, OP_ST
- dw ao48,ao48,ao48 ;OP_CS, OP_DS, OP_ES
- dw ao48,ao48,ao48 ;OP_FS, OP_GS, OP_SS
-
- asm_regnum db 10,1,30 ;DX, CL, ST
- db 25,27,24,28,29,26 ;CS, DS, ES, FS, GS, SS
-
- asm_siznum db 5, 6, 7, 8 ;qword, float, double, tbyte
- db -1, 12 ;none, far
-
- aa00: jmp cmd3 ;done with this command
-
- aa: mov errret,offset aa01
- cmp al,CR
- je aa01 ;if end of line
- mov bx,reg_cs ;default segment to use
- aa00a: call getaddr ;get address into bx:dx
- call chkeol ;expect end of line here
- mov a_addr,dx ;save the address
- mov a_addr+2,bx
-
- ; Begin loop over input lines.
-
- aa01: mov sp,savesp ;restore the stack (this implies no "ret")
- mov di,offset line_out
- mov ax,a_addr+2
- call hexword
- mov al,':'
- stosb
- mov ax,a_addr
- call hexword
- mov al,' '
- stosb
- call getline00
- cmp al,CR
- je aa00 ;if done
- cmp al,';'
- je aa01 ;if comment
- mov asm_mn_flags,0
- mov word aa_saved_prefix,0 ;clear aa_saved_prefix and aa_seg_pre
-
- ; Get mnemonic and look it up.
-
- aa02: mov di,offset line_out ;return here after LOCK/REP/SEG prefix
- push si ;save position of mnemonic
- aa03: cmp al,'a'
- jb aa04 ;if not lower case letter
- cmp al,'z'
- ja aa04
- and al,TOUPPER ;convert to upper case
- aa04: stosb
- lodsb
- cmp al,CR
- je aa05 ;if end of mnemonic
- cmp al,' '
- je aa05
- cmp al,TAB
- jne aa03
- aa05: call skipwh0 ;skip to next field
- dec si
- push si ;save position in input line
- mov al,0
- stosb
- mov bx,offset mnlist
- mov dx,offset end_mnlist
- aa06: mov si,bx ;begin bisection loop looking for mnemonic
- add si,dx
- rcr si,1
- aa07: lodsb ;skip to end of string
- cmp al,0
- jne aa07 ;if not end of string
- cmp si,dx
- jb aa09 ;if not end of table
- aa08: dec si
- cmp si,bx
- je aa09 ;if beginning of table
- cmp byte [si-1],0
- jne aa08
- aa09: push si ;compare op codes
- inc si ;skip over the data word
- inc si
- push di
- mov cx,offset line_out
- sub di,cx
- xchg cx,di
- repe cmpsb
- pop di
- pop si
- je aa14 ;if found it
- jg aa11 ;if (di) < (si)
- aa10: lodsb
- cmp al,0
- jne aa10 ;skip to end of string
- mov bx,si
- jmp short aa12
- aa11: mov dx,si
- aa12: cmp bx,dx
- jne aa06 ;if more to search
- aa13: pop si ;end of mnemonic
- aa13a: pop si ;beginning of mnemonic
- aa13b: jmp error ;complain
-
- ; We found the mnemonic.
-
- aa14: lodsb ;get significant byte of address
- mov ah,al ;multiply by 255
- neg al
- xchg ax,bx
- lodsb
- mov ah,0
- add bx,ax
- lea si,asmtab[bx-512]
-
- ; Now si points to the spot in asmtab corresponding to this mnemonic.
- ; The format of the assembler table is as follows.
- ; First, there is optionally one of the following bytes:
- ; ASM_DB db mnemonic
- ; ASM_DW dw mnemonic
- ; ASM_DD dd mnemonic
- ; ASM_WAIT the mnemonic should start with a wait
- ; instruction.
- ; ASM_D32 This is a 32 bit instruction.
- ; ASM_AAX Special for AAM and AAD instructions:
- ; put 0ah in for a default operand.
- ; ASM_SEG This is a segment prefix.
- ; ASM_LOCKREP This is a LOCK or REP... prefix.
- ;
- ; Then, in most cases, this is followed by one or more of the following
- ; sequences, indicating an instruction variant.
- ; ASM_LOCKABLE (optional) indicates that this instruction can
- ; follow a LOCK prefix.
- ; ASM_MACHx Indicates the first machine on which this
- ; instruction appeared.
- ; [word] This is a 16-bit integer, most significant byte
- ; first, giving ASMMOD * a + b, where b is an
- ; index into the array opindex (indicating the
- ; key, or type of operand list), and a is as
- ; follows:
- ; 0-255 The (one-byte) instruction.
- ; 256-511 The lower 8 bits give the second byte of
- ; a two-byte instruction beginning with 0fh.
- ; 512-575 Bits 2-0 say which floating point instruction
- ; this is (0d8h-0dfh), and 5-3 give the /r
- ; field.
- ; 576-... (a-576)/8 is the index in the array agroups
- ; (which gives the real value of a), and the
- ; low-order 3 bits gives the /r field.
- ;
- ; [byte] This gives the second byte of a floating
- ; instruction if 0d8h <= a <= 0dfh.
- ;
- ; Following these is an ASM_END byte.
- ;
- ; Exceptions:
- ; ASM_SEG and ASM_LOCKREP are followed by just one byte, the
- ; prefix byte.
- ; ASM_DB, ASM_DW, and ASM_DD don't need to be followed by
- ; anything.
- ;
-
- ASM_END equ 0ffh
- ASM_DB equ 0feh
- ASM_DW equ 0fdh
- ASM_DD equ 0fch
- ASM_ORG equ 0fbh
- ASM_WAIT equ 0fah
- ASM_D32 equ 0f9h
- ASM_AAX equ 0f8h
- ASM_SEG equ 0f7h
- ASM_LOCKREP equ 0f6h
-
- ASM_LOCKABLE equ 0f5h
- ASM_MACH6 equ 0f4h
- ASM_MACH0 equ 0eeh
-
- cmp byte [si],ASM_LOCKREP ;check for mnemonic flag byte
- jb aa15 ;if none
- lodsb ;get the prefix
- sub al,ASM_LOCKREP
- je aa18 ;if LOCK or REP...
- cbw
- dec ax
- jz aa17 ;if segment prefix
- dec ax
- jz aa16 ;if aad or aam
- cmp al,3
- jae aa20 ;if ASM_ORG or ASM_DD or ASM_DW or ASM_DB
- or asm_mn_flags,al ;save AMF_D32 or AMF_WAIT
- aa15: jmp ab01 ;now process the arguments
-
- aa16: jmp ab00
-
- ; segment prefix
-
- aa17: lodsb ;get prefix value
- mov aa_seg_pre,al
- or asm_mn_flags,AMF_MSEG
- pop si
- pop ax
- lodsb
- cmp al,CR
- je aa13a ;if end of line ( ==> error)
- cmp al,';'
- je aa13a ;if end of line (comment) ( ==> error)
- jmp aa02 ;back for more
-
- ; LOCK or REP prefix
-
- aa18: lodsb ;get prefix value
- xchg al,aa_saved_prefix
- cmp al,0
- jnz aa13a ;if there already was a saved prefix
- pop si
- pop ax
- lodsb
- cmp al,CR
- je aa19 ;if end of line
- cmp al,';'
- je aa19 ;if end of line (comment)
- jmp aa02 ;back for more
-
- aa19: mov al,aa_saved_prefix ;just a prefix, nothing else
- mov di,offset line_out
- stosb
- jmp aa31
-
- ; Pseudo ops (org or db/dw/dd).
-
- aa20: cmp word aa_saved_prefix,0
- jnz aa13a ;if there was a prefix or a segment
- pop si ;get position in input line
- sub al,3 ;AX=0 if org, 1 if dd, 2 if dw, 3 if db.
- jnz aa20m ;if not ORG
-
- ; Process ORG pseudo op.
-
- call skipwhite
- cmp al,CR
- je aa20a ;if nothing
- mov bx,a_addr+2 ;default segment
- jmp aa00a ;go to top
- aa20a: jmp aa01 ;get next line
-
- ; Data instructions (DB/DW/DD).
-
- aa20m: mov di,offset line_out ;put the bytes here when we get them
- xchg ax,bx ;mov bx,ax
- mov al,aadbsiz[bx] ;move maximum size
- mov aadbsiz,al
- shl bx,1
- mov ax,aadbsto[bx] ;move address of storage routine
- mov aadbsto,ax
-
- aa21: call skipwhite
- cmp al,CR
- je aa31 ;if end of line
- cmp al,'"'
- je aa22 ;if string
- cmp al,"'"
- je aa22 ;if string
- call aageti ;get a numerical value into dx:bx, size into cl
- cmp cl,aadbsiz
- jg aa27 ;if overflow
- xchg ax,bx
- call [aadbsto] ;store the value
- cmp di,offset real_end
- ja aa27 ;if output line overflow
- xchg ax,bx
- jmp short aa26 ;done with this one
- aa22: mov ah,al
- aa23: lodsb
- cmp al,CR
- je aa27 ;if end of line
- cmp al,ah
- je aa25 ;if end of string
- aa24: stosb
- cmp di,offset real_end
- ja aa27 ;if output line overflow
- jmp aa23
- aa25: lodsb
- cmp al,ah
- je aa24 ;if just a doubled quote character
- aa26: call skipwh0
- cmp al,CR
- je aa31 ;if end of line
- cmp al,','
- je aa21 ;if no error
- aa27: jmp aa13b ;error
-
- aa28: stosw ;store a dword value
- xchg ax,dx
- stosw
- xchg ax,dx
- ret
-
- aa29: stosw ;store a word value
- ret
-
- aa30: stosb ;store a byte value
- ret
-
- ; End of line. Copy it over.
-
- aa31: mov si,offset line_out
- mov cx,di
- sub cx,si
- les di,a_addr
- rep movsb ;copy it
- push ds ;restore es
- pop es
- mov a_addr,di
- jmp aa01
-
- ; Here we process the AAD and AAM instructions. They are special
- ; in that they may take a one-byte argument, or none (in which case
- ; the argument defaults to 0ah = ten).
-
- ab00: mov mneminfo,si ;save this address
- pop si
- lodsb
- cmp al,CR
- je ab00a ;if end of line
- cmp al,';'
- jne ab01b ;if not end of line
- ab00a: mov si,offset aam_args ;fake a 0ah argument
- jmp short ab01a
-
- ; Process normal instructions.
-
- ; First we parse each argument into a 12-byte data block, stored
- ; consecutively at line_out, line_out+12, etc.
- ; This is stored as follows.
-
- ; [di] Flags (ARG_DEREF, etc.)
- ; [di+1] Unused
- ; [di+2] Size argument, if any (1=byte, 2=word, 3=(unused), 4=dword,
- ; 5=qword, 6=float, 7=double, 8=tbyte, 9=short, 10=long, 11=near,
- ; 12=far).
- ; [di+3] Size of MOD R/M displacement
- ; [di+4] First register, or MOD R/M byte
- ; [di+5] Second register or index register or SIB byte
- ; [di+6] Index factor
- ; [di+7] Sizes of numbers are or-ed here
- ; [di+8] (dword) number
-
- ; For arguments of the form xxxx:yyyyyyyy, xxxx is stored in [di+5],
- ; and yyyyyyyy in [di+8]. The number of bytes in yyyyyyyy is stored in
- ; opaddr, 2 is stored in [di+4], and di is stored in xxaddr.
-
- ab01: mov mneminfo,si ;save this address
- pop si ;get position in line
- ab01a: lodsb
- ab01b: mov di,offset line_out
-
- ; Begin loop over operands.
-
- ab02: cmp al,CR
- je ab03 ;if end of line
- cmp al,';'
- jne ab04 ;if not end of line
- ab03: jmp ab99 ;to next phase
-
- ab04: push di ;clear out the next storage area
- mov cx,6
- xor ax,ax
- rep stosw
- pop di
-
- ; Small loop over "BYTE PTR" and segment prefixes.
-
- ab05: dec si
- mov ax,[si]
- and ax,TOUPPER_W
- cmp byte [di+2],0
- jne ab07 ;if already have "BYTE PTR"
- push di
- mov di,offset sizetcnam
- mov cx,12
- repne scasw
- pop di
- jne ab07 ;if not found
- or cx,cx
- jnz ab06 ;if not 'FA'
- mov al,[si+2]
- and al,TOUPPER
- cmp al,'R'
- jne ab09 ;if not 'FAR' (could be hexadecimal)
- ab06: sub cl,12
- neg cl ;convert to 1, ..., 12
- mov [di+2],cl
- call skipalpha
- call skipwh0
- mov ah,[si]
- and ax,TOUPPER_W
- cmp ax,'AF'
- jne ab06a ;if not 'FA'
- mov al,[si+1]
- and al,TOUPPER
- cmp al,'R'
- jne ab05 ;if not 'FAR'
- mov byte [di+2],12 ;set 'FAR'
- or asm_mn_flags,AMF_D32
- call skipalpha
- call skipwh0
- mov ah,[si]
- and ax,TOUPPER_W
- ab06a: cmp ax,'TP'
- jne ab05 ;if not 'PTR'
- call skipalpha
- call skipwh0
- jmp ab05
-
- ab07: cmp aa_seg_pre,0
- jne ab09 ;if we already have a segment prefix
- push di
- mov di,offset segrgnam
- mov cx,6
- repne scasw
- pop di
- jne ab09 ;if not found
- push si ;save si in case there's no colon
- lodsw
- call skipwhite
- cmp al,':'
- jne ab08 ;if not followed by ':'
- pop ax ;discard saved si
- call skipwhite ;skip it
- mov bx,offset prefixlist + 5
- sub bx,cx
- mov al,[bx] ;look up the prefix byte
- mov aa_seg_pre,al ;save it away
- jmp ab05
-
- ab08: pop si
-
- ; Begin parsing main part of argument.
-
- ab09: push di ;check for solo registers
- mov di,offset rgnam816
- mov cx,27
- call aagetreg
- pop di
- jc ab14 ;if not a register
- or byte [di],ARG_JUSTREG
- mov [di+4],bl ;save register number
- cmp bl,24
- jae ab09a ;if it's not a normal register
- xchg ax,bx ;mov al,bl
- mov cl,3
- shr al,cl ;al = size: 0 -> byte, 1 -> word, 2 -> dword
- add al,-2
- adc al,3 ;convert to 1, 2, 4 (respectively)
- jmp short ab13
-
- ab09a: xor byte [di],ARG_JUSTREG + ARG_WEIRDREG
- mov al,2 ;register size
- cmp bl,30
- ja ab11 ;if it's CR, DR, TR, or MM
- je ab09b ;if it's ST
- cmp bl,28
- jb ab13 ;if it's a normal segment register
- or asm_mn_flags,AMF_FSGS ;flag it
- jmp short ab13
-
- ab09b: cmp byte [si],'('
- jne ab12 ;if just plain ST
- lodsb
- lodsb
- sub al,'0'
- cmp al,7
- ja ab10 ;if not 0..7
- mov [di+5],al ;save the number
- lodsb
- cmp al,')'
- je ab12 ;if not error
- ab10: jmp aa13b ;error
-
- ab11: lodsb ;other registers (CR, DR, TR, MM)
- sub al,'0'
- cmp al,7
- ja ab10 ;if error
- mov [di+5],al ;save the number
- mov al,4 ;register size
- cmp bl,31
- jne ab13 ;if not MM register
- ab12: mov al,0
- ab13: cmp al,[di+2] ;compare with stated size
- je ab13a ;if same
- xchg al,[di+2]
- cmp al,0
- jne ab10 ;if wrong size given
- ab13a: jmp ab44 ;done with this operand
-
- ; It's not a register reference. Try for a number.
-
- ab14: lodsb
- call aaifnum
- jc ab17 ;it's not a number
- ab14a: call aageti ;get the number
- mov [di+7],cl
- mov [di+8],bx
- mov [di+10],dx
- call skipwh0
- cmp cl,2
- jg ab17 ;if we can't have a colon here
- cmp al,':'
- jne ab17 ;if not xxxx:yyyy
- call skipwhite
- call aageti
- mov cx,[di+8]
- mov [di+5],cx
- mov [di+8],bx
- mov [di+10],dx
- or byte [di],ARG_FARADDR
- jmp ab43 ;done with this operand
-
- ; Check for [...].
-
- ab15: jmp ab30 ;do post-processing
-
- ab16: call skipwhite
- ab17: cmp al,'[' ;begin loop over sets of []
- jne ab15 ;if not [
- or byte [di],ARG_DEREF ;set the flag
- ab18: call skipwhite
- ab19: cmp al,']' ;begin loop within []
- je ab16 ;if done
-
- ; Check for a register (within []).
-
- dec si
- push di
- mov di,offset rgnam16
- mov cx,8
- call aagetreg
- pop di
- jc ab25 ;if not a register
- cmp bl,16
- jae ab20 ;if 32-bit register
- add bl,8 ;adjust 0..7 to 8..15
- jmp short ab21
- ab20: cmp byte [di+5],0
- jnz ab21 ;if we already have an index
- call skipwhite
- dec si
- cmp al,'*'
- jne ab21 ;if not followed by '*'
- inc si
- mov [di+5],bl ;save index register
- call skipwhite
- call aageti
- call aaconvindex
- jmp short ab28 ;ready for next part
-
- ab21: cmp byte [di+4],0
- jne ab22 ;if there's already a register
- mov byte [di+4],bl
- jmp short ab23
- ab22: cmp byte [di+5],0
- jne ab24 ;if too many registers
- mov byte [di+5],bl
- ab23: call skipwhite
- jmp short ab28 ;ready for next part
-
- ab24: jmp aa13b ;error
-
- ; Try for a number (within []).
-
- ab25: lodsb
- ab26: call aageti ;get a number (or flag an error)
- call skipwh0
- cmp al,'*'
- je ab27 ;if it's an index factor
- or [di+7],cl
- add [di+8],bx
- adc [di+10],dx
- jmp short ab28 ;next part ...
-
- ab27: call aaconvindex
- call skipwhite
- dec si
- push di
- mov di,offset rgnam16
- xor cx,cx
- call aagetreg
- pop di
- jc ab24 ;if error
- cmp byte [di+5],0
- jne ab24 ;if there is already a register
- mov [di+5],bl
- call skipwhite
-
- ; Ready for the next term within [].
-
- ab28: cmp al,'-'
- je ab26 ;if a (negative) number is next
- cmp al,'+'
- jne ab29 ;if no next term (presumably)
- jmp ab18
- ab29: jmp ab19 ;back for more
-
- ; Post-processing for complicated arguments.
-
- ab30: cmp word [di+4],0
- jnz ab32 ;if registers were given ( ==> create MOD R/M)
- cmp byte [di+7],0
- jz ab31 ;if nothing was given ( ==> error)
- cmp byte [di],0
- jnz ab30b ;if it was not immediate
- or byte [di],ARG_IMMED
- ab30a: jmp ab43 ;done with this argument
- ab30b: mov al,2 ;size of the displacement
- test byte [di+7],4
- jz ab30c ;if not 32-bit displacement
- inc ax
- inc ax
- or asm_mn_flags,AMF_A32 ;32-bit addressing
- ab30c: mov byte [di+3],al ;save displacement size
- jmp ab30a ;done with this argument
- ab31: jmp aa13b ;flag an error
-
- ; Create the MOD R/M byte.
- ; (For disp-only or register, this will be done later as needed.)
-
- ab32: or byte [di],ARG_MODRM
- mov al,[di+4]
- or al,[di+5]
- test al,16
- jnz ab34 ;if 32-bit addressing
- test byte [di+7],4
- jnz ab34 ;if 32-bit addressing
- mov ax,[di+4]
- cmp al,ah
- ja ab33 ;make sure al >= ah
- xchg al,ah
- ab33: push di
- mov di,offset modrmtab
- mov cx,8
- repne scasw
- pop di
- jne ab31 ;if not among the possibilities
- mov bx,206h ;max disp = 2 bytes; 6 ==> (non-existent) [bp]
- jmp short ab39 ;done (just about)
-
- ab34: or asm_mn_flags,AMF_A32 ;32-bit addressing
- mov al,[di+4]
- or al,[di+6]
- jnz ab35 ;if we can't optimize [EXX*1] to [EXX]
- mov ax,[di+4]
- xchg al,ah
- mov [di+4],ax
- ab35: mov bx,405h ;max disp = 4 bytes; 5 ==> (non-existent) [bp]
- cmp byte [di+5],0
- jne ab36 ;if there's a SIB
- mov cl,[di+4]
- cmp cl,16
- jl ab31 ;if wrong register type
- and cl,7
- cmp cl,4 ;check for ESP
- jne ab39 ;if not, then we're done (otherwise do SIB)
-
- ab36: or asm_mn_flags,AMF_SIB ;form SIB
- mov ch,[di+6] ;get SS bits
- mov cl,3
- shl ch,cl ;shift them halfway into place
- mov al,[di+5] ;index register
- cmp al,20
- je ab31 ;if ESP ( ==> error)
- cmp al,0
- jne ab37 ;if not zero
- mov al,20 ;set it for index byte 4
- ab37: cmp al,16
- jl ab31 ;if wrong register type
- and al,7
- or ch,al ;put it into the SIB
- shl ch,cl ;shift it into place
- inc cx ;R/M for SIB = 4
- mov al,[di+4] ;now get the low 3 bits
- cmp al,0
- jne ab38 ;if there was a first register
- or ch,5
- jmp short ab42 ;MOD = 0, disp is 4 bytes
-
- ab38: cmp al,16
- jl ab45 ;if wrong register type
- and al,7 ;first register
- or ch,al ;put it into the SIB
- cmp al,5
- je ab40 ;if it's EBP, then we don't recognize disp=0
- ;otherwise bl will be set to 0
-
- ; Find the size of the displacement.
-
- ab39: cmp cl,bl
- je ab40 ;if it's [(E)BP], then disp=0 is still 1 byte
- mov bl,0 ;allow 0-byte disp
-
- ab40: push cx
- mov al,[di+8]
- mov cl,7
- sar al,cl
- pop cx
- mov ah,[di+9]
- cmp al,ah
- jne ab41 ;if it's bigger than 1 byte
- cmp ax,[di+10]
- jne ab41 ;ditto
- mov bh,0 ;no displacement
- or bl,[di+8]
- jz ab42 ;if disp = 0 and it's not (E)BP
- inc bh ;disp = 1 byte
- or cl,40h ;set MOD = 1
- jmp short ab42 ;done
-
- ab41: or cl,80h ;set MOD = 2
-
- ab42: mov [di+3],bh ;store displacement size
- mov [di+4],cx ;store MOD R/M and maybe SIB
-
- ; Finish up with the operand.
-
- ab43: dec si
- ab44: call skipwhite
- add di,12
- cmp al,CR
- je ab99 ;if end of line
- cmp al,';'
- je ab99 ;if comment (ditto)
- cmp al,','
- jne ab45 ;if not comma ( ==> error)
- cmp di,offset line_out+36
- jae ab45 ;if too many operands
- call skipwhite
- jmp ab02
-
- ab45: jmp aa13b ;error jump
-
- ab99: mov byte [di],-1 ;end of parsing phase
- push si ;save the location of the end of the string
-
- ; For the next phase, we match the parsed arguments with the set of
- ; permissible argument lists for the opcode. The first match wins.
- ; Therefore the argument lists should be ordered such that the
- ; cheaper ones come first.
-
- ; There is a tricky issue regarding sizes of memory references.
- ; Here are the rules:
- ; 1. If a memory reference is given with a size, then it's OK.
- ; 2. If a memory reference is given without a size, but some
- ; other argument is a register (which implies a size),
- ; then the memory reference inherits that size.
- ; Exceptions: OP_CL does not imply a size
- ; OP_SHOSIZ
- ; 3. If 1 and 2 do not apply, but this is the last possible argument
- ; list, and if the argument list requires a particular size, then
- ; that size is used.
- ; 4. In all other cases, flag an error.
-
- ac01: xor ax,ax ;zero out rmaddr through varflags or a_opcode
- mov di,offset rmaddr
- mov cx,7
- rep stosw
- mov si,mneminfo ;address of the next argument variant
-
- ; Sort out initial bytes. At this point:
- ; si = address of next argument variant
- ; di = address of next parsed argument table
-
- ac02: lodsb
- sub al,ASM_MACH0
- jb ac05 ;if no more special bytes
- cmp al,ASM_LOCKABLE-ASM_MACH0
- je ac03 ;if ASM_LOCKABLE
- ja ac04 ;if ASM_END ( ==> error)
- mov dismach,al ;save machine type
- jmp ac02 ;back for next byte
- ac03: or varflags,VAR_LOCKABLE
- jmp ac02 ;back for next byte
-
- ac04: jmp aa13a ;error
-
- ; Get and unpack the word.
-
- ac05: dec si
- lodsw
- xchg al,ah ;put into little-endian order
- xor dx,dx
- mov bx,ASMMOD
- div bx ;ax = a_opcode; dx = index into opindex
- mov a_opcode,ax ;save ax
- mov a_opcode2,ax ;save the second copy
- cmp ax,0dfh
- ja ac05a ;if not coprocessor instruction
- cmp al,0d8h
- jb ac05a ;ditto
- or dmflags,DM_COPR ;flag it as an x87 instruction
- mov ah,al ;ah = low order byte of opcode
- lodsb ;get extra byte
- mov regmem,al ;save it in regmem
- mov a_opcode2,ax ;save this for obsolete-instruction detection
- or varflags,VAR_MODRM ;flag its presence
- ac05a: mov mneminfo,si ;save si back again
- mov si,dx
- mov bl,opindex[si]
- lea si,oplists[bx] ;si = the address of our operand list
- mov di,offset line_out
-
- ; Begin loop over operands. At this point si and di are as for ac02.
-
- ac06: lodsb ;get next operand byte
- cmp al,0
- je ac10 ;if end of list
- cmp byte [di],-1
- je ac01 ;if too few operands were given
- cmp al,OP_SIZE
- jb ac07 ;if no size needed
- mov ah,0
- mov cl,4
- shl ax,cl
- shr al,cl
- mov a_reqsize,ah ;save it away
- jmp short ac08
-
- ac07: add al,16-2 ;move these to the end of the previous list
-
- ac08: cbw
- xchg ax,bx ;now bx contains the offset
- mov cx,asm_jmp1[bx] ;subroutine address
- shr bx,1
- mov al,bittab[bx]
- test al,[di]
- jz ac09 ;if no required bits are present
- call cx ;call its specific routine
- cmp word [si-1],(OP_1632+OP_R)*256+(OP_1632+OP_R_MOD)
- je ac06 ;(hack) for IMUL instruction
- add di,12 ;next operand
- jmp ac06 ;back for more
-
- ac09: jmp ac01 ;back to next possibility
-
- ; End of operand list.
-
- ac10: cmp byte [di],-1
- jne ac09 ;if too many operands were given
-
- ; Final check on sizes
-
- mov al,varflags
- test al,VAR_SIZ_NEED
- jz ac12 ;if no size needed
- test al,VAR_SIZ_GIVN
- jnz ac12 ;if a size was given
- test al,VAR_SIZ_FORCD
- jz ac09 ;if the size was not forced ( ==> reject)
- mov si,mneminfo
- cmp byte [si],ASM_END
- je ac12 ;if this is the last one
- ac11: jmp aa13a ;it was not ==> error (not a retry)
-
- ; Check other prefixes.
-
- ac12: mov al,aa_saved_prefix
- cmp al,0
- jz ac14 ;if no saved prefixes to check
- cmp al,0f0h
- jne ac13 ;if it's a rep prefix
- test varflags,VAR_LOCKABLE
- jz ac11 ;if this variant is not lockable ( ==> error)
- jmp short ac14 ;done
-
- ac13: mov ax,a_opcode ;check if opcode is OK for rep{,z,nz}
- and al,not 1 ;clear low order bit
- cmp ax,0ffh
- ja ac11 ;if it's not a 1 byte instruction
- mov di,offset replist ;list of instructions that go with rep
- mov cx,7
- repne scasb
- jnz ac11 ;if it's not among them
-
- ac14: test asm_mn_flags,AMF_MSEG
- jz ac15 ;if no segment prefix before mnemonic
- mov ax,a_opcode ;check if opcode allows this
- cmp ax,0ffh
- ja ac11 ;if it's not a 1 byte instruction
- mov di,offset prfxtab
- mov cx,P_LEN
- repne scasb
- jnz ac11 ;if it's not in the list
-
- ac15: mov bx,immaddr
- or bx,bx
- jz ac16 ;if no immediate data
- mov al,opsize
- neg al
- shl al,1
- test al,[bx+7]
- jnz ac11 ;if the immediate data was too big
-
- ; Put the instruction together
- ; (maybe is this why they call it an assembler)
-
- ; First, the prefixes (including preceding WAIT instruction)
-
- ac16: les di,a_addr
- test asm_mn_flags,AMF_WAIT
- jz ac17 ;if no wait instruction beforehand
- mov al,9bh
- stosb
-
- ac17: mov al,aa_saved_prefix
- cmp al,0
- jz ac18 ;if no LOCK or REP prefix
- stosb
-
- ac18: mov al,67h ;address-size prefix
- test asm_mn_flags,AMF_A32
- jz ac19 ;if none
- stosb
-
- ac19: dec ax ;al = 66h, operand-size prefix
- test asm_mn_flags,AMF_D32
- jnz ac20 ;if flag set for 32-bit operands
- test varflags,VAR_D32
- jz ac21 ;if no flag on instruction variant
- ac20: stosb ;store operand-size prefix
-
- ac21: mov al,aa_seg_pre
- cmp al,0
- jz ac22 ;if no segment prefix
- stosb
- cmp al,64h
- jb ac22 ;if not 64 or 65 (FS or GS)
- or asm_mn_flags,AMF_FSGS ;flag it
-
- ; Now emit the instruction itself.
-
- ac22: mov ax,a_opcode
- mov bx,ax
- sub bx,576
- jae ac23 ;if 576-...
- cmp ax,512
- jb ac24 ;if regular instruction
- or dmflags,DM_COPR ;flag it as an x87 instruction
- and al,038h ;get register part
- or regmem,al
- xchg ax,bx ;mov ax,bx (the low bits of bx are good)
- and al,7
- or al,0d8h
- jmp short ac25 ;on to decoding the instruction
-
- ac23: mov cl,3 ;one instruction of a group
- shr bx,cl
- and al,7
- shl al,cl
- or regmem,al
- shl bx,1
- mov ax,agroups[bx] ;get actual opcode
-
- ac24: cmp ah,0
- jz ac25 ;if no 0fh first
- push ax ;store a 0fh
- mov al,0fh
- stosb
- pop ax
-
- ac25: or al,opcode_or ;put additional bits into the op code
- stosb ;store the op code itself
-
- ; Now store the extra stuff that comes with the instruction.
-
- mov ax,word regmem
- test varflags,VAR_MODRM
- jz ac26 ;if no mod reg/mem
- stosb
- test asm_mn_flags,AMF_SIB
- jz ac26 ;if no SIB
- dec di
- stosw ;store the MOD R/M and SIB, too
-
- ac26: mov bx,rmaddr
- or bx,bx
- jz ac27 ;if no offset associated with the R/M
- mov cl,[bx+3]
- mov ch,0
- lea si,[bx+8]
- rep movsb ;store the R/M offset (or memory offset)
-
- ; Now store immediate data
-
- ac27: mov bx,immaddr
- or bx,bx
- jz ac28 ;if no immediate data
- mov al,opsize
- cbw
- xchg ax,cx ;mov cx,ax
- lea si,[bx+8]
- rep movsb
-
- ; Now store additional bytes (needed for, e.g., enter instruction)
-
- ac28: mov bx,xxaddr
- or bx,bx
- jz ac29 ;if no additional data
- lea si,[bx+4]
- lodsb
- cbw
- xchg ax,cx ;mov cx,ax
- rep movsb
-
- ; Done emitting.
-
- ac29: push cs ;restore ES
- pop es
- mov a_addr,di
-
- ; Compute machine type.
-
- cmp dismach,3
- jae ac31 ;if we already know a 386 is needed
- test asm_mn_flags,AMF_D32 + AMF_A32 + AMF_FSGS
- jnz ac30 ;if 386
- test varflags,VAR_D32
- jz ac31 ;if not 386
- ac30: mov dismach,3
- ac31: mov di,offset a_opcode2 + 2 ; info on this instruction
- call showmach ;get machine message into si, length into cx
- jcxz ac33 ;if no message
-
- ac32: mov di,offset line_out
- rep movsb ;copy the line to line_out
- call putsline
-
- ac33: jmp aa01 ;back for the next input line
-
- ; ||| This is debugging code. It assumes that the original value
- ; of a_addr is on the top of the stack.
-
- ; pop si ;get orig. a_addr
- ; mov ax,a_addr+2
- ; mov u_addr,si
- ; mov u_addr+2,ax
- ; mov bx,a_addr
- ; sub bx,si
- ; mov di,offset line_out
- ; mov cx,10
- ; mov al,' '
- ; rep stosb
- ; mov ds,a_addr+2
-
- ;ax1: lodsb
- ; call hexbyte ;display the bytes generated
- ; dec bx
- ; jnz ax1
- ; push cs
- ; pop ds
- ; call putsline
- ; mov byte disflags,0
- ; call disasm ;disassemble the new instruction
- ; jmp aa01 ;back to next input line
-
- ; Routines to check for specific operand types.
- ; Upon success, the routine returns.
- ; Upon failure, it pops the return address and jumps to ac01.
- ; The routines must preserve si and di.
-
- ; OP_RM and OP_M: form MOD R/M byte.
-
- ao01: call ao90 ;form reg/mem byte
- jmp short ao07 ;go to the size check
-
- ; OP_R: register.
-
- ao02: mov al,[di+4] ;register number
- and al,7
- mov cl,3
- shl al,cl ;shift it into place
- or regmem,al ;put it into the reg/mem byte
- jmp short ao07 ;go to the size check
-
- ; OP_R_ADD: register, added to the instruction.
-
- ao03: mov al,[di+4]
- and al,7
- mov opcode_or,al ;put it there
- jmp short ao07 ;go to the size check
-
- ; OP_IMM: immediate data.
-
- ao04: mov immaddr,di ;save the location of this
- jmp short ao07 ;go to the size check
-
- ; OP_MOFFS: just the memory offset
-
- ao05: test byte [di],ARG_MODRM
- jnz ao11 ;if MOD R/M byte ( ==> reject)
- mov rmaddr,di ;save the pointer
- jmp short ao07 ;go to the size check
-
- ; OP_AX: check for AL/AX/EAX
-
- ao06: test byte [di+4],7
- jnz ao11 ;if wrong register
- ;jmp short ao07 ;go to the size check
-
- ; Size check
-
- ao07: or varflags,VAR_SIZ_NEED
- mov al,a_reqsize
- sub al,5 ;OP_1632 >> 4
- jl ao12 ;if OP_ALL
- jz ao13 ;if OP_1632
- add al,-3
- adc al,3 ;convert 3 --> 4
- ao08: or varflags,VAR_SIZ_FORCD + VAR_SIZ_NEED
- mov bl,[di+2]
- or bl,bl
- jz ao09 ;if no size given
- or varflags,VAR_SIZ_GIVN
- cmp al,bl
- jne ao11 ;if sizes conflict
- ao09: cmp al,opsize
- je ao10 ;if sizes agree
- xchg al,opsize
- cmp al,0
- jnz ao11 ;if sizes disagree
- ao10: ret
-
- ao11: jmp ao50 ;reject
-
- ; OP_ALL - Allow all sizes.
-
- ao12: mov al,[di+2]
- cmp al,1
- je ao15 ;if byte
- jb ao14 ;if unknown
- or opcode_or,1 ;set bit in instruction
- jmp short ao14 ;if size is 16 or 32
-
- ; OP_1632 - word or dword.
-
- ao13: mov al,[di+2]
- ao14: cmp al,0
- je ao16 ;if still unknown
- cmp al,2
- je ao15 ;if word
- cmp al,4
- jne ao11 ;if not dword
- or varflags,VAR_D32;set flag
- ao15: mov opsize,al
- or varflags,VAR_SIZ_GIVN
- ao16: ret
-
- ; OP_M64 - 64-bit memory reference.
- ; OP_MFLOAT - single-precision floating point memory reference.
- ; OP_MDOUBLE - double-precision floating point memory reference.
- ; OP_M80 - 80-bit memory reference.
- ; OP_MXX - memory reference, size unknown.
- ; OP_FARMEM - far memory pointer
-
- ao17: call ao90 ;form reg/mem byte
- mov al,asm_siznum[bx-(OP_M64+16-2)/2]
- jmp ao08 ;check size
-
- ; OP_FARP - far memory address contained in instruction
-
- ao21: mov al,2
- cmp word [di+10],0
- jz ao22 ;if 16 bit address
- or varflags,VAR_D32
- mov al,4
- ao22: mov byte [di+4],2
- mov immaddr,di
- mov opsize,al
- ao22a: mov xxaddr,di
- ret
-
- ; OP_REL8 - relative address
-
- ao23: mov al,9 ;short
- call ao60 ;check the size
- mov ax,a_addr ;offset
- inc ax
- inc ax ;$
- test asm_mn_flags,AMF_D32
- jnz ao23a ;if JECXZ
- test varflags,VAR_D32
- jz ao23b ;if no ECX given in loop instruction
- ao23a: inc ax
- ao23b: xchg ax,bx
- xor cx,cx
- mov ax,[di+8]
- mov dx,[di+10]
- sub ax,bx
- sbb dx,cx
- mov [di+5],al
- mov cl,7
- sar al,cl
- cmp al,ah
- jne ao24 ;if too big
- cmp ax,dx
- jne ao24 ;if too big
- mov byte [di+4],1 ;save the length
- jmp ao22a ;save it away
-
- ao24: jmp ao50 ;reject
-
- ; OP_REL1632: relative jump to a longer address.
-
- ao25: mov bx,a_addr
- inc bx
- inc bx
- inc bx
- cmp a_opcode,100h
- jb ao26
- inc bx
- ao26: mov dx,[di+10]
- mov al,[di+2]
- cmp al,0
- je ao27 ;if no size given
- cmp al,10
- je ao27 ;if "long" given
- cmp al,4
- jne ao24 ;if the size given was not "dword"
- inc bx ;once for the prefix, twice for the longer data
- inc bx
- inc bx
- or varflags,VAR_D32
- jmp short ao28
-
- ao27: or dx,dx
- jnz ao24 ;if operand is too big
- mov al,2
- ao28: mov [di+4],al ;store the size
- mov ax,[di+8]
- xor cx,cx
- sub ax,bx
- sbb dx,cx
- mov [di+5],ax
- mov [di+7],dx
- mov xxaddr,di
- ret
-
- ; OP_1CHK - The assembler can ignore this one.
-
- ao29: pop ax ;discard return address
- jmp ac06 ;next operand
-
- ; OP_STI - ST(I).
-
- ao30: mov al,30 ;code for ST
- mov bl,[di+5]
- jmp short ao38 ;to common code
-
- ; OP_CR
-
- ao31: mov al,[di+5] ;get the index
- cmp al,4
- ja ao24 ;if too big
- jne ao32 ;if not CR4
- mov dismach,5 ;CR4 is new to the 586
- ao32: cmp al,1
- jne ao33
- cmp byte [di+12],-1
- jne ao24 ;if another arg (can't mov CR1,xx)
- ao33: mov al,32 ;code for CR
- jmp short ao37 ;to common code
-
- ; OP_DR
-
- ao34: mov al,33 ;code for DR
- jmp short ao37 ;to common code
-
- ; OP_TR
-
- ao35: mov al,[di+5] ;get the index
- cmp al,3
- jb ao24 ;if too small
- cmp al,6
- jae ao36
- mov dismach,4 ;TR3-5 are new to the 486
- ao36: mov al,34 ;code for TR
-
- ; Common code for these weird registers.
-
- ao37: mov bl,[di+5]
- mov cl,3
- shl bl,cl
- ao38: or regmem,bl
- or varflags,VAR_MODRM
- cmp al,[di+4] ;check for the right numbered register
- je ao40 ;if yes, then return
- ao38a: jmp ao50
-
- ; OP_SEGREG
-
- ao39: mov al,[di+4]
- sub al,24
- cmp al,6
- jae ao38a ;if not a segment register
- mov cl,3
- shl al,cl
- or regmem,al
- ao40: ret
-
- ; OP_IMMS8 - Sign-extended immediate byte
-
- ao41: mov ax,[di+8]
- mov cl,7
- sar al,cl
- jmp short ao43 ;common code
-
- ; OP_IMM8 - Immediate byte
-
- ao42: mov ax,[di+8]
- mov al,0
- ao43: cmp al,ah
- jne ao50 ;if too big
- cmp ax,[di+10]
- jne ao50 ;if too big
- mov al,1
- call ao60 ;check that size == 0 or 1
- mov ah,[di+8] ;store the byte, length 1
- mov [di+4],ax
- mov xxaddr,di
- ao43r: ret
-
- ; OP_ECX - CX or ECX, determining the operand size
-
- ao43m: cmp byte [di+4],9 ;CX
- je ao43r ;if CX (do nothing)
- or varflags,VAR_D32
- mov al,17
- jmp short ao48a ;require ECX
-
- ; OP_SHOSIZ - force the user to declare the size of the next operand
-
- ao44: test varflags,VAR_SIZ_NEED
- jz ao45 ;if no testing needs to be done
- test varflags,VAR_SIZ_GIVN
- jz ao50 ;if size was given ( ==> reject)
- ao45: and varflags,not VAR_SIZ_GIVN ;clear the flag
- cmp byte [si],OP_IMM8
- je ao45a ;if OP_IMM8 is next, then don't set VAR_SIZ_NEED
- or varflags,VAR_SIZ_NEED
- ao45a: mov opsize,0
- pop ax ;discard return address
- jmp ac06 ;next operand
-
- ; OP_1
-
- ao46: cmp word [di+7],101h
- jmp short ao49 ;test it later
-
- ; OP_3
-
- ao47: cmp word [di+7],301h
- jmp short ao49 ;test it later
-
- ; OP_DX, OP_CL, OP_ST, OP_ES, ..., OP_GS
-
- ao48: mov al,asm_regnum[bx-(OP_DX+16-2)/2]
- ao48a: cbw
- cmp ax,[di+4]
-
- ao49: je ao51
-
- ; Reject this operand list.
-
- ao50: pop ax ;discard return address
- jmp ac01 ;go back to try the next alternative
-
- ao51: ret
-
- ; AASIZCHK - Check that the size given is 0 or AL.
-
- ao60: cmp byte [di+2],0
- je ao51
- cmp byte [di+2],al
- je ao51
- pop ax ;discard return address
- jmp ao50
-
- ; Do reg/mem processing.
- ; Uses AX
-
- ao90: test byte [di],ARG_JUSTREG
- jnz ao92 ;if just register
- test byte [di],ARG_MODRM
- jz ao91 ;if no precomputed MOD R/M byte
- mov ax,word [di+4] ;get the precomputed bytes
- jmp short ao93 ;done
-
- ao91: mov al,6 ;convert plain displacement to MOD R/M
- test asm_mn_flags,AMF_A32
- jz ao93 ;if 16 bit addressing
- dec ax
- jmp short ao93 ;done
-
- ao92: mov al,[di+4] ;convert register to MOD R/M
- and al,7 ;get low 3 bits
- or al,0c0h
-
- ao93: or word regmem,ax ;store the MOD R/M and SIB
- or varflags,VAR_MODRM ;flag its presence
- mov rmaddr,di ;save a pointer
- ret ;done
-
- ; AAIFNUM - Determine if there's a number next.
- ; Entry AL First character of number
- ; SI Address of next character of number
- ; Exit CY Clear if there's a number, set otherwise.
- ; Uses None.
-
- aaifnum:
- cmp al,'-'
- je aai2 ;if minus sign (carry is clear)
- push ax
- sub al,'0'
- cmp al,10
- pop ax
- jb aai1 ;if a digit
- push ax
- and al,TOUPPER
- sub al,'A'
- cmp al,6
- pop ax
- aai1: cmc ;carry clear <==> it's a number
- aai2: ret
-
- ; AAGETI - Get a number from the input line.
- ; Entry AL First character of number
- ; SI Address of next character of number
- ; Exit DX:BX Resulting number
- ; CL 1 if it's a byte, 2 if a word, 4 if a dword
- ; AL Next character not in number
- ; SI Address of next character after that
- ; Uses AH, CH
-
- aageti: cmp al,'-'
- je aag1 ;if negative
- call aag4 ;get the bare number
- mov cx,1 ;set up cx
- or dx,dx
- jnz aag2 ;if dword
- or bh,bh
- jnz aag3 ;if word
- ret ;it's a byte
-
- aag1: lodsb
- call aag4 ;get the bare number
- mov cx,bx
- or cx,dx
- mov cx,1
- jz ret ;if -0
- not dx ;negate the answer
- neg bx
- cmc
- adc dx,0
- test dh,80h
- jz aag7 ;if error
- cmp dx,-1
- jne aag2 ;if dword
- test bh,80h
- jz aag2 ;if dword
- cmp bh,-1
- jne aag3 ;if word
- test bl,80h
- jz aag3 ;if word
- ret ;it's a byte
-
- aag2: inc cx ;return: it's a dword
- inc cx
- aag3: inc cx ;return: it's a word
- ret
-
- aag4: xor bx,bx ;get the basic integer
- xor dx,dx
- call getnyb
- jc aag7 ;if not a hex digit
- aag5: or bl,al ;add it to the number
- lodsb
- call getnyb
- jc ret ;if done
- test dh,0f0h
- jnz aag7 ;if overflow
- mov cx,4
- aag6: shl bx,1 ;shift it by 4
- rcl dx,1
- loop aag6
- jmp aag5
-
- aag7: jmp aa13b ;error
-
- ; AACONVINDEX - Convert results from AAGETI and store index value
- ; Entry DX:BX,CL As in exit from AAGETI
- ; DI Points to information record for this arg
- ; Exit SS bits stored in [di+6]
- ; Uses DL
-
- aaconvindex:
- cmp cl,1
- jne aacv1 ;if the number is too large
- cmp bl,1
- je aacv2 ;if 1
- inc dx
- cmp bl,2
- je aacv2 ;if 2
- inc dx
- cmp bl,4
- je aacv2 ;if 4
- inc dx
- cmp bl,8
- je aacv2 ;if 8
- aacv1: jmp aa13b ;error
-
- aacv2: mov [di+6],dl ;save the value
- ret
-
- ; AAGETREG - Get register for the assembler.
- ; Entry DI Start of register table
- ; CX Length of register table
- ; SI Address of first character in register name
- ; Exit SI Updated if a register was found
- ; BX Register number, defined as in the table below.
- ; Uses AX, CX, DI
-
- ; Exit value of BX:
- ; DI = rgnam816, CX = 27 DI = rgnam16, CX = 8
- ; ---------------------- --------------------
- ; 0 .. 7: AL .. BH 0 .. 7: AX .. DI
- ; 8 .. 15: AX .. DI 16 .. 23: EAX..EDI
- ; 16 .. 23: EAX..EDI
- ; 24 .. 29: ES .. GS
- ; 30 .. 34: ST .. MM
-
- aagetreg:
- mov ax,[si]
- and ax,TOUPPER_W ;convert to upper case
- cmp al,'E' ;check for EAX, etc.
- jne aagr1 ;if not
- push ax
- mov al,ah
- mov ah,[si+2]
- and ah,TOUPPER
- push di
- mov di,offset rgnam16
- push cx
- mov cx,8
- repne scasw
- mov bx,cx
- pop cx
- pop di
- pop ax
- jne aagr1 ;if no match
- inc si
- not bx
- add bl,8+16 ;adjust BX
- jmp short aagr2 ;finish up
-
- aagr1: mov bx,cx ;(if cx = 0, this is always reached with
- repne scasw ; ZF clear)
- jne aagr3 ;if no match
- sub bx,cx
- dec bx
- cmp bl,16
- jb aagr2 ;if AL .. BH or AX .. DI
- add bl,8
- aagr2: inc si ;skip the register name
- inc si
- clc
- ret
-
- aagr3: stc ;not found
- ret
-
- ; C command - compare bytes.
-
- cc: call parsecm ;parse arguments
- inc cx
- cc1: push si ;do the interrupt pointer hack
- push di
- push ds
- push es
- push cs ;ds := cs
- pop ds
- call dohack
- pop es
- pop ds
- pop di
- pop si
- repe cmpsb ;start comparing
- lahf
- mov dl,[si-1] ;save the possibly errant characters
- mov dh,es:[di-1]
- push si ;undo the interrupt pointer hack
- push di
- push ds
- push es
- push cs ;ds := cs
- pop ds
- call unhack
- pop es
- pop ds
- pop di
- pop si
- sahf
- je cc2 ;if we're done
- push cx
- push es
- push cs
- pop es
- mov bx,di
- mov di,offset line_out
- mov ax,ds
- call hexword
- mov al,':'
- stosb
- lea ax,[si-1]
- call hexword
- mov ax,' '
- stosw
- mov al,dl
- call hexbyte
- mov ax,' '
- stosw
- mov al,dh
- call hexbyte
- mov ax,' '
- stosw
- pop ax
- push ax
- call hexword
- mov al,':'
- stosb
- lea ax,[bx-1]
- call hexword
- push ds
- push cs
- pop ds
- push bx
- call putsline
- pop di
- pop ds
- pop es
- pop cx
- inc cx
- loop cc1 ;if not done yet
-
- cc2: push cs ;restore segment registers
- pop ds
- push cs
- pop es
- ret
-
- ; D command - hex/ascii dump.
-
- ddd: cmp al,CR
- jne dd1 ;if an address was given
- mov dx,d_addr ;compute range of 80h or until end of segment
- mov si,dx
- add dx,7fh
- jnc dd2 ;if no overflow
- mov dx,0ffffh
- jmp short dd2
-
- dd1: mov cx,80h ;default length
- mov bx,reg_ds
- call getrange ;get address range into dx:bx
- call chkeol ;expect end of line here
- mov d_addr+2,bx ;save segment (offset is saved later)
- mov si,dx
- mov dx,cx ;dx = end address
-
- ; Parsing is done. Print first line.
-
- dd2: mov ax,d_addr+2
- call hexword
- mov al,':'
- stosb
- mov ax,si
- and al,0f0h
- push ax
- call hexword
- mov ax,' '
- stosw
- pop ax
- lea bx,[di+50]
- mov word [bx-2],' '
- push si
- push di
- call prehack ;set up for faking int vectors 23 and 24
- pop di
- pop si
-
- dd3: cmp ax,si ;skip to position in line
- je dd4 ;if we're there yet
- push ax
- mov ax,' '
- stosw
- stosb
- mov es:[bx],al
- inc bx
- pop ax
- inc ax
- jmp dd3
-
- ; Begin main loop over lines of output.
-
- dd4: mov cx,si
- or cl,0fh
- cmp cx,dx ;compare with end address
- jb dd5 ;if we write to the end of the line
- mov cx,dx
- dd5: sub cx,si
- inc cx ;cx = number of bytes to print this line
- push si
- push di
- call dohack ;substitute interrupt vectors
- pop di
- pop si
- mov ds,d_addr+2
-
- dd6: lodsb
- push ax
- push cx
- call hexbyte
- pop cx
- mov al,' '
- stosb
- pop ax
- cmp al,' '
- jb dd7 ;if control character
- cmp al,'~'
- jbe dd8 ;if printable
- dd7: mov al,'.'
- dd8: mov es:[bx],al
- inc bx
- loop dd6
- dd9: test si,0fh ;space out till end of line
- jz dd10
- mov ax,' '
- stosw
- stosb
- inc si
- jmp dd9
-
- dd10: push cs ;restore ds
- pop ds
- mov d_addr,si
- mov byte [di-25],'-'
- push si
- call unhack
- pop si
- mov di,bx
- push dx
- call putsline
- pop dx
- dec si
- cmp si,dx
- jae dd11 ;if we're done
- inc si
- mov di,offset line_out+5 ;set up for next time
- mov ax,si
- call hexword
- inc di
- inc di
- lea bx,[di+50]
- jmp dd4
-
- dd11: inc dx ;set up the address for the next 'D' command.
- mov d_addr,dx
- ret
-
- errorj4:jmp error
-
- ; E command - edit memory.
-
- ee: push si
- push di
- call prehack
- pop di
- pop si
- mov bx,reg_ds
- call getaddr ;get address into bx:dx
- call skipwh0
- cmp al,CR
- je ee1 ;if prompt mode
- push dx
- call getstr ;get data bytes
- mov cx,di
- mov dx,offset line_out
- sub cx,dx ;length of byte string
- pop di
- mov ax,cx
- dec ax
- add ax,di
- jc errorj4 ;if it wraps around
- push di
- call dohack
- pop di
- mov si,dx
- mov es,bx
- rep movsb
-
- ; Restore ds and es and undo the interrupt vector hack.
- ; This code is also used by the `m' command.
-
- ee0a: push cs ;restore es
- pop es
- mov di,offset run2324
- call prehak1 ;copy things back and restore ds
- call unhack
- ret
-
- ; Prompt mode.
-
- ee1: xchg bx,dx
-
- ; Begin loop over lines.
-
- ee2: mov ax,dx ;print out segment and offset
- call hexword
- mov al,':'
- stosb
- mov ax,bx
- call hexword
-
- ; Begin loop over bytes.
-
- ee3: mov ax,' ' ;print old value of byte
- stosw
- push di
- call dohack ;do the INT pointer hack
- mov es,dx
- mov al,es:[bx]
- call unhack ;undo the INT pointer hack and restore es.
- pop di
- call hexbyte
- mov al,'.'
- stosb
- push dx ;save dx
- push bx
- call puts
- pop bx
- mov si,offset line_out+16 ;address of buffer for characters
- xor cx,cx ;number of characters so far
-
- ee4: cmp notatty,0
- jz ee9 ;if it's a tty
- push si
- mov di,offset line_in+2
- mov si,bufnext
- ee5: cmp si,bufend
- jb ee6 ;if there's a character already
- call fillbuf
- mov al,CR
- jc ee8 ;if eof
- ee6: cmp notatty,CR
- jne ee7 ;if no need to compress CR/LF
- cmp byte [si],LF
- jne ee7 ;if not a line feed
- inc si ;skip it
- inc notatty ;avoid repeating this
- jmp ee5 ;next character
-
- ee7: lodsb ;get the character
- mov notatty,al
- ee8: mov bufnext,si
- pop si
- jmp short ee10
-
- ee9: mov ah,8 ;console input without echo
- int 21h
-
- ee10: cmp al,' '
- je ee13 ;if done with this byte
- cmp al,CR
- je ee13 ;ditto
- cmp al,BS
- je ee11 ;if backspace
- cmp cx,2 ;otherwise, it should be a hex character
- jae ee4 ;if we have a full byte already
- mov [si],al
- call getnyb
- jc ee4 ;if it's not a hex character
- inc cx
- lodsb ;get the character back
- jmp short ee12
-
- ee11: jcxz ee4 ;if nothing to backspace over
- dec cx
- dec si
- ee12: xchg ax,dx ;move character into dl
- mov ah,2 ;display output
- int 21h
- jmp ee4 ;back for more
-
- ; We have a byte (if CX != 0).
-
- ee13: jcxz ee14 ;if no change for this byte
- mov [si],al ;terminate the string
- sub si,cx ;point to beginning
- push cx
- lodsb
- call getbyte ;convert byte to binary
- pop cx
- call dohack ;do the INT pointer hack
- pop ds ;get segment register
- mov [bx],dl ;save the byte
- push ds ;segment back on the stack
- mov di,offset run2324
- call prehak1 ;copy things back and restore ds
- call unhack ;undo the INT pointer hack
-
- ; End the loop over bytes.
-
- ee14: inc bx ;next word
- pop dx ;restore dx
- mov di,offset line_out
- cmp al,CR
- je ee16 ;if done
- test bl,7
- jz ee15 ;if new line
- not cx
- add cx,4 ;compute 3 - cx
- mov al,' '
- rep stosb ;store that many spaces
- jmp ee3 ;back for more
-
- ee15: mov ax,LF * 256 + CR;terminate this line
- stosw
- jmp ee2 ;back for a new line
-
- ee16: jmp putsline ;call putsline and return
-
- ; F command - fill memory
-
- ff: xor cx,cx ;get address range (no default length)
- mov bx,reg_ds
- call getrange
- sub cx,dx
- inc cx ;cx = number of bytes
- push cx ;save it
- push dx ;save start address
- call skipwh0
- call getstr ;get string of bytes
- mov cx,di
- sub cx,offset line_out
- pop di
- mov es,bx
- cmp cx,1
- je ff3 ;a common optimization
- pop ax
- xor dx,dx
- div cx ;compute number of whole repetitions
- or ax,ax
- jz ff2 ;if less than one whole rep
- ff1: mov si,offset line_out
- push cx
- rep movsb
- pop cx
- dec ax
- jnz ff1 ;if more to go
- ff2: mov cx,dx
- jcxz ff4 ;if no partial copies
- mov si,offset line_out
- rep movsb
- jmp short ff4 ;done (almost)
-
- ff3: pop cx
- mov al,byte line_out
- rep stosb
-
- ff4: push cs ;restore es
- pop es
- ret
-
- ; G command - go.
-
- gg: xchg ax,bx ;mov bx,ax
- mov ax,reg_cs ;save original CS
- mov run_cs,ax
- mov eqladdr+2,ax
- xchg ax,bx ;mov ax,bx
- call parseql ;process =addr
- mov di,offset line_out+2
- mov [di-2],si ;save si
-
- ; Parse the rest of the line to make sure there are no errors.
-
- gg1: call skipwh0
- cmp al,CR
- je gg2 ;if end of line
- call getaddr
- jmp gg1 ;back for more
-
- ; Store breakpoint bytes in the given locations.
-
- gg2: mov si,[di-2]
- gg3: dec si
- call skipwhite
- cmp al,CR
- je gg4 ;if done
- mov bx,eqladdr+2 ;default segment
- call getaddr ;get address into bx:dx
- mov ds,bx
- mov bx,dx
- mov al,0cch ;INT 3 instruction
- xchg al,[bx] ;put it there
- push cs ;restore DS
- pop ds
- stosb ;save the old contents
- jmp gg3 ;back for more
-
- ; Now run the program.
-
- gg4: call seteq ;make the = operand take effect
- call run
-
- ; Restore breakpoint bytes.
-
- mov di,offset line_out+2
- mov si,[di-2]
- gg5: dec si
- call skipwhite
- cmp al,CR
- je gg6 ;if done
- mov bx,run_cs ;default segment
- call getaddr ;get address into bx:dx
- mov al,[di] ;get old contents
- inc di
- cmp al,0cch ;this is because of possible duplicate values
- je gg5 ;if it was INT 3 originally
- mov ds,bx
- mov bx,dx
- mov [bx],al ;restore value
- push cs ;restore DS
- pop ds
- jmp gg5 ;back for more
-
- ; Finish up. Check if it was one of _our_ breakpoints.
-
- gg6: cmp run_int,offset int3msg
- jne gg9 ;if not CC interrupt
- dec reg_ip
- mov si,[line_out] ;loop over the set breakpoints
- gg7: dec si
- call skipwhite
- cmp al,CR
- je gg8 ;if done
- mov bx,run_cs ;default segment
- call getaddr ;get address into bx:dx
- mov ax,dx
- xor ax,reg_ip
- test al,0fh
- jnz gg7 ;if no match
- mov cl,4
- mov ax,reg_ip
- shr ax,cl
- add ax,reg_cs
- shr dx,cl
- add bx,dx
- cmp ax,bx
- jne gg7 ;if no match
-
- ; It's one of ours.
-
- call dumpregs
- ret
-
- ; It's not.
-
- gg8: inc reg_ip
- gg9: jmp tt2 ;print messages and quit.
-
- ; H command - hex addition and subtraction.
-
- hh: call getword
- push dx
- call skipwh0
- call getword
- call chkeol ;expect end of line here
- pop bx
- mov ax,bx
- add ax,dx
- call hexword
- mov ax,' '
- stosw
- mov ax,bx
- sub ax,dx
- call hexword
- call putsline
- ret
-
- ; I command - input from I/O port.
-
- ii: call getword
- call chkeol ;expect end of line here
- in al,dx
- call hexbyte
- call putsline
- ret
-
- errorj5:jmp error
-
- ; L command - read a program, or disk sectors, from disk.
-
- ll: call parselw ;parse it
- jz ll1 ;if request to read program
- int 25h
- mov dx,offset reading
- jmp ww1
-
- ; Load the program.
-
- ll1: call freemem ;return the previous process's memory
-
- ; Clear registers
-
- ll2: mov di,offset reg_bx
- xor ax,ax
- mov cx,7
- rep stosw
- mov di,offset blk1 ;clear memory of past blocks
- stosw
- stosw
- push si ;restore run2324 area
- mov si,0eh ;address of original INT 23 and 24 (in PSP)
- mov di,offset run2324
- movsw
- movsw
- movsw
- movsw
- pop si ;restore si
-
- ; Check file extension.
-
- mov bx,execblk+2 ;address of end of file name string
- cmp bx,85h
- jb ll3 ;if file name is too short
- cmp word [bx-5],'C.'
- jne ll4 ;if not .COM
- cmp word [bx-3],'MO'
- je ll5 ;if .COM
- ll3: jmp ll11 ;if not .COM
-
- ll4: cmp word [bx-5],'E.'
- jne ll3 ;if not .EXE
- cmp word [bx-3],'EX'
- jne ll3 ;if not .EXE
-
- ; Load .EXE or .COM file, using the DOS interrupt.
- ; First find out the file length and type.
-
- ll5: mov ax,3d00h ;open file for reading
- mov dx,80h
- int 21h
- jnc ll6
- jmp ll9 ;if error
- ll6: push ax
- xchg ax,bx ;mov bx,ax
- mov ah,3fh ;read from file
- mov cx,2
- mov dx,sp
- int 21h
- jc ll7 ;if error
- cmp ax,2
- jne ll7 ;if less than two bytes read
- pop ax
- cmp ax,'ZM'
- jne ll7 ;if not .EXE file header
- ; mov exefile,1 ;set flag |||
- ll7: mov ax,4202h ;lseek
- xor cx,cx
- xor dx,dx
- int 21h
- mov reg_bx,dx
- mov reg_cx,ax
- mov ah,3eh ;close file
- int 21h
-
- ; Actual program loading.
-
- mov ax,4b01h ;load program
- mov dx,80h ;offset of file to load
- mov bx,offset execblk ;parameter block
- int 21h ;load it
- jc ll9 ;if error
- mov ax,sp
- sub ax,[2eh]
- cmp ax,80h
- jb ll8 ;if in range
- mov ax,80h
- ll8: mov spadjust,ax
- mov running,1 ;set flag
- les si,execblk+14
- es lodsw ;recover ax
- mov reg_ax,ax
- mov reg_sp,si
- mov reg_ss,es
- les si,execblk+18
- mov reg_ip,si
- mov reg_cs,es
- push cs
- pop es
- mov ah,51h ;get new PSP
- int 21h
- xchg ax,bx ;mov ax,bx
- mov psp,ax
- mov di,offset reg_ds
- stosw
- stosw ;reg_es
- mov ah,50h ;set PSP back
- mov bx,cs
- int 21h
- jmp ll18
-
- ; Error messages. Do an empty load.
-
- ll9: call ww15 ;print error message
- call ll19 ;set up PSP
- ll10: jmp ll18 ;finish up
-
- ; Load it ourselves.
-
- ll11: call ll19 ;set up PSP
- cmp byte [80h],0
- jz ll10 ;if no file name given
-
- ; Open the file and find its length.
-
- mov ax,3d00h ;open file for reading
- mov dx,80h
- int 21h
- jc ll17 ;if error
- xchg ax,bx ;mov bx,ax
- mov ax,4202h ;lseek from end
- xor cx,cx
- xor dx,dx
- int 21h
- mov reg_bx,dx
- mov reg_cx,ax
-
- ; Check the size against available space.
-
- mov cx,4
- add ax,100h+15
- adc dx,0
- mov cx,4
- ll12: shr dx,1
- rcr ax,1
- loop ll12
- or dx,dx
- jnz ll16 ;if too big
- mov di,run_sp
- cmp ax,di
- ja ll16 ;if too big
- mov ax,4200h ;lseek from beginning
- xor cx,cx ;to zero (dx is already zero)
- int 21h
-
- ; Read in the file. di is still run_sp; dx is still 0.
-
- mov si,psp ;si = segment to use
- add si,10h
- sub di,10h ;di = space left
- ll13: mov ax,0fe0h
- cmp ax,di
- jb ll14 ;if plenty left
- mov ax,di
- ll14: mov ds,si
- add si,ax
- sub di,ax
- mov cl,4
- shl ax,cl ;number of bytes to read
- xchg ax,cx ;mov ax,cx
- mov ah,3fh ;read from file
- int 21h
- cmp ax,cx
- jne ll15 ;if end
- or di,di
- jnz ll13 ;if more room
-
- ; Close the file and finish up.
-
- ll15: mov ah,3eh ;close file
- int 21h
- push cs ;restore ds
- pop ds
- jmp short ll18 ;finish up
-
- ; Errors of various sorts.
-
- ll16: mov ax,8 ;not enough memory
- ll17: call ww15 ;print error message
- xor ax,ax ;clear reg_bx and reg_cx
- mov di,offset reg_bx
- stosw
- stosw
-
- ; Finish up. Set termination address.
-
- ll18: mov ax,2522h ;set interrupt vector 22
- mov dx,offset int22
- int 21h
- mov ds,psp
- mov word [0ah],offset int22
- mov [0ch],cs
- push cs
- pop ds
-
- ; Set up initial addresses for 'a', 'd', and 'u' commands.
-
- mov ax,reg_ip
- mov bx,reg_cs
- mov di,offset a_addr
- stosw
- xchg ax,bx
- stosw
- xchg ax,bx ;d_addr
- stosw
- xchg ax,bx
- stosw
- xchg ax,bx ;u_addr
- stosw
- xchg ax,bx
- stosw
- ret
-
- ; ll19 - Create PSP (subroutine).
-
- ll19:
-
- ; Allocate and fill environment.
-
- mov ax,execblk+2 ;end of file name string
- add ax,envlen ;length of environment
- add ax,-80h+2+15
- mov cl,4
- shr ax,cl
- xchg ax,bx ;mov bx,ax
- mov ah,48h ;allocate memory
- int 21h
- jc ll20 ;if out of memory
- mov blk1,ax
- mov cx,envlen ;copy over parent's environment
- mov ds,[2ch]
- xor si,si
- mov es,ax
- xor di,di
- rep movsb
- mov ax,1 ;store number of extra strings
- stosw
- push cs ;restore ds
- pop ds
- mov si,80h ;copy file name
- mov cx,execblk+2 ;end of file name
- sub cx,si
- rep movsb
- push cs ;restore ES
- pop es
-
- ; Create main program segment.
-
- mov ah,48h ;allocate another block
- mov bx,0ffffh
- int 21h
- cmp bx,11h
- jb ll20 ;if too little memory
- mov ah,48h ;allocate the most we can
- int 21h
- jnc ll21
- ll20: jmp ll24 ;if out of memory
- ll21: mov psp,ax
- mov blk2,ax
- mov run_sp,bx ;save length temporarily
- mov di,offset reg_ds;set up segment registers
- stosw
- stosw
- stosw
- stosw
- xchg ax,dx ;mov dx,ax
- mov ax,100h
- stosw ;set original IP
- mov ah,55h ;create child PSP
- mov si,[2] ;memory size field
- clc ;works around OS/2 bug
- int 21h
- jc ll25 ;if error
-
- ; Set environment pointer in PSP.
-
- mov ax,blk1
- mov ds,dx
- mov [2ch],ax
-
- ; Set up stack.
-
- mov ax,cs:run_sp
- cmp ax,1000h
- jb ll22 ;if smaller than maximum
- xor ax,ax
- ll22: mov cl,4
- shl ax,cl
- dec ax
- dec ax
- mov bx,ax
- mov word [bx],0
- push cs ;restore ds
- pop ds
- mov reg_sp,ax ;set stack pointer
-
- ; Now take care of our own stack.
-
- mov ax,sp
- sub ax,[2eh]
- cmp ax,80h
- jb ll23 ;if in range
- mov ax,80h
- ll23: mov spadjust,ax
- mov running,1 ;set flag
- mov ah,50h ;set PSP
- mov bx,cs
- int 21h
- ret
-
- ; Insufficient memory.
-
- ll24: mov ah,9 ;print string
- mov dx,offset doserr8
- int 21h
- ret
-
- ; Error in PSP creation.
-
- ll25: mov ah,9 ;print string
- mov dx,offset psperr
- int 21h
- ret
-
- ; M command - move from place to place.
-
- mm: push si ;scan for comma or 'l'
- m1: cmp al,','
- je m2 ;if comma found
- cmp al,CR
- je m5 ;if end of string
- or al,TOLOWER
- cmp al,'l'
- je m2 ;if 'l' found
- lodsb
- jmp m1 ;loop back
-
- ; Normal 'm' command (move).
-
- m2: pop si
- dec si
- lodsb
- call parsecm ;parse arguments
- push cx
- mov cl,4
- shr dx,cl
- add dx,bx ;upper 16 bits of destination
- mov ax,si
- shr ax,cl
- mov bx,ds
- add ax,bx
- cmp ax,dx
- jne m3 ;if we know which is larger
- mov ax,si
- and al,0fh
- mov bx,di
- and bl,0fh
- cmp al,bl
- m3: pop cx
- lahf
- push si ;do the interrupt pointer hack
- push di
- push ds
- push es
- push cs ;ds := cs
- pop ds
- call dohack
- pop es
- pop ds
- pop di
- pop si
- sahf
- jae m4 ;if forward copy is OK
- add si,cx
- add di,cx
- std
- m4: rep movsb ;do the move
- movsb ;one more byte
- cld ;restore flag
- jmp ee0a ;restore ds and es and undo the int pointer hack
-
- ; Other 'm' command: set machine type.
-
- m5: pop si
- dec si
- lodsb
- cmp al,CR
- je m10 ;if just an 'm' (query machine type)
- cmp al,'0'
- jb m6 ;if not a digit
- cmp al,'6'
- ja m6 ;ditto
- sub al,'0'
- mov machine,al ;set machine type
- mov mach_87,al ;coprocessor type, too
- ret
-
- m6: or al,TOLOWER
- cmp al,'c'
- je m7 ;if coprocessor declaration
- cmp al,'n'
- jne errorj3 ;if something else
- lodsb
- or al,TOLOWER
- cmp al,'c'
- jne errorj3 ;if not 'c' after that
- lodsb
- call chkeol
- mov has_87,0 ;clear coprocessor flag
- ret ;done
-
- m7: call skipwhite ;get next nonblank character
- mov ah,machine
- cmp ah,3
- jne m9 ;if not a 386
- cmp al,'3'
- je m8 ;if declaring a 387
- cmp al,'2'
- jne m9 ;if not '2'
- mov ah,2
- m8: call skipwhite
- m9: cmp al,CR
- jne errorj3 ;if not end of line
- mov has_87,1 ;set coprocessor flag
- mov mach_87,ah ;set copr. type
- ret
-
- ; Display machine type.
-
- m10: mov si,offset msg8088
- mov al,machine
- cmp al,0
- je m11 ;if 8088
- mov si,offset msgx86
- add al,'0'
- mov [si],al
- m11: call showstring
- mov si,offset no_copr
- cmp has_87,0
- je m12 ;if no coprocessor
- mov si,offset has_copr
- mov al,mach_87
- cmp al,machine
- je m12 ;if has coprocessor same as processor
- mov si,offset has_287
- m12: call showstring ;show string
- jmp putsline ;call puts and quit
-
- errorj3:jmp error
-
- ; N command - change the name of the program being debugged.
-
- nn: mov di,80h
-
- ; Copy and canonicalize file name.
-
- nn1: cmp al,CR
- je nn3 ;if end of line
- call ifsep ;check for separators space, TAB, comma, ;, =
- je nn3 ;if end of file name
- cmp al,swch1
- je nn3 ;if '/' (and '/' is the switch character)
- cmp al,'a'
- jb nn2 ;if not lower case
- cmp al,'z'
- ja nn2 ;ditto
- and al,TOUPPER ;convert to upper case
- nn2: stosb
- lodsb
- jmp nn1 ;back for more
-
- nn3: mov al,0 ;null terminate the file name string
- stosb
- mov execblk+2,di ;save start of command tail
- push di
- mov di,offset line_out
- dec si
- nn4: lodsb ;copy the remainder to line_out
- stosb
- cmp al,CR
- jne nn4
-
- ; Set up FCB's.
-
- mov si,offset line_out
- mov di,5ch
- call nn6 ;do first FCB
- mov byte reg_ax,al
- mov di,6ch
- call nn6 ;second FCB
- mov byte reg_ax+1,al
-
- ; Copy command tail.
-
- mov si,offset line_out
- pop di
- push di
- inc di
- nn5: lodsb
- stosb
- cmp al,CR
- jne nn5 ;if not end of string
- pop ax ;recover old DI
- xchg ax,di
- sub ax,di ;compute length of tail
- dec ax
- dec ax
- stosb
- ret ;done
-
- ; Subroutine to process an FCB.
-
- nn6: lodsb
- cmp al,CR
- je nn7 ;if end
- call ifsep
- je nn6 ;if separator
- cmp al,switchar
- je nn10 ;if switch character
- nn7: dec si
- mov ax,2901h ;parse filename
- int 21h
- push ax ;save AL
- nn8: lodsb ;skip till separator
- cmp al,CR
- je nn9 ;if end
- call ifsep
- je nn9 ;if separator character
- cmp al,swch1
- jne nn8 ;if not switchar (sort of)
- nn9: dec si
- pop ax ;recover AL
- cmp al,1
- jne nn9a ;if not 1
- dec ax
- nn9a: ret
-
- ; Handle a switch (differently).
-
- nn10: lodsb
- cmp al,CR
- je nn7 ;if end of string
- call ifsep
- je nn10 ;if another separator
- mov al,0
- stosb
- dec si
- lodsb
- cmp al,'a'
- jb nn11 ;if not a lower case letter
- cmp al,'z'
- ja nn11
- and al,TOUPPER ;convert to upper case
- nn11: stosb
- mov ax,' '
- stosw
- stosw
- stosw
- stosw
- stosw
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
- ret ;return with AL=0
-
- ; O command - output to I/O port.
-
- oo: call getword
- push dx
- call skipwh0
- call getbyte
- call chkeol ;expect end of line here
- xchg ax,dx ;al = byte
- pop dx ;recover port number
- out dx,al
- ret
-
- ; P command - proceed (i.e., skip over call/int/loop/string instruction).
-
- pp: call parse_pt ;process arguments
-
- ; Do it <count> times. First check the type of instruction.
-
- pp1: push cx ;save cx
- mov si,reg_ip
- mov dx,15 ;DL = number of bytes to go; DH = prefix flags.
-
- pp2: call pp16 ;get next instruction byte into AL
- mov di,offset ppbytes
- mov cx,PPLEN
- repne scasb
- jne pp5 ;if not one of these
- mov al,[di+PPLEN-1] ;get corresponding byte in ppinfo
- test al,80h
- jz pp3 ;if not a prefix
- or dh,al ;set the flags
- dec dl
- jnz pp2 ;if not out of bytes
- jmp pp12
-
- pp3: test al,40h
- jz pp4 ;if no size dependency
- and al,3fh
- and dh,2
- add al,dh
- pp4: cbw
- add si,ax
- jmp short pp11 ;we have a skippable instruction here
-
- pp5: cmp al,0ffh
- jne pp12 ;just an ordinary instruction
- call pp16 ;get MOD REG R/M byte
- and al,not 8 ;clear lowest bit of REG field (/3 --> /2)
- xor al,10h ;/2 --> /0
- test al,38h
- jnz pp12 ;if not ff/2 or ff/3
- cmp al,0c0h
- jae pp11 ;if just a register
- test dh,1
- jnz pp6 ;if 32 bit addressing
- cmp al,6
- je pp9 ;if just plain disp16
- cmp al,40h
- jb pp11 ;if indirect register
- cmp al,80h
- jb pp10 ;if disp8[reg(s)]
- jmp short pp9 ;it's disp16[reg(s)]
-
- pp6: cmp al,5
- je pp8 ;if just plain disp32
- xor al,4
- test al,7
- jnz pp7 ;if no SIB byte
- inc si
- pp7: cmp al,40h
- jb pp11 ;if indirect register
- cmp al,80h
- jb pp10 ;if disp8[reg(s)]
- ;otherwise, it's disp32[reg(s)]
- pp8: inc si
- inc si
- pp9: inc si
- pp10: inc si
-
- ; Special instruction. Set a breakpoint and run until we hit it.
-
- pp11: mov ds,reg_cs
- mov al,0cch
- xchg al,[si]
- push cs
- pop ds
- mov di,offset line_out ;save old byte here
- stosb
- xchg ax,si
- stosw
- mov ax,reg_cs
- stosw
- call run
- mov si,offset line_out
- lodsb ;get old byte
- xchg ax,cx
- lodsw ;old IP
- xchg ax,bx
- lodsw ;old CS
- xchg ax,cx
- mov ds,cx
- mov [bx],al
- push cs
- pop ds
- xor dx,dx ;set flag
- cmp run_int,offset int3msg
- jne pp13 ;if not CC interrupt
- cmp cx,reg_cs
- jne pp13 ;if not same segment
- mov ax,reg_ip
- dec ax
- cmp ax,bx
- jne pp13 ;if not same offset
- mov reg_ip,ax
- mov dx,offset int3msg
- jmp short pp13
-
- ; Ordinary instruction. Just do a trace.
-
- pp12: or flags,100h ;set single-step mode
- call run
- mov dx,offset int1msg
-
- ; Common part to finish up.
-
- pp13: cmp run_int,dx
- jne pp15 ;if some other interrupt
- call dumpregs
- pop cx
- loop pp14 ;back for more
- ret
-
- pp14: jmp pp1 ;back for more
- pp15: jmp tt2 ;print message about unexpected interrupt
- ;and quit
-
- ; PPX - Get next byte in instruction stream.
-
- pp16: mov ds,reg_cs
- lodsb
- push cs
- pop ds
- ret
-
- ; begin loop over instruction bytes.
-
- ; Q command - quit.
-
- qq: call freemem ;free the child process memory
-
- ; Restore interrupt vectors.
-
- mov si,offset intsave
- lodsw
- xchg ax,dx ;mov dx,ax
- lodsw
- mov ds,ax
- mov ax,2500h ;set interrupt vector 0
- int 21h
- push cs
- pop ds
- lodsw
- xchg ax,dx ;mov dx,ax
- lodsw
- mov ds,ax
- mov ax,2501h ;set interrupt vector 1
- int 21h
- push cs
- pop ds
- lodsw
- xchg ax,dx ;mov dx,ax
- lodsw
- mov ds,ax
- mov ax,2503h ;set interrupt vector 3
- int 21h
- push cs
- pop ds
-
- ; Restore termination address.
-
- mov si,offset psp22 ;restore termination address
- mov di,0ah
- movsw
- movsw
- mov di,16h ;restore PSP of parent
- movsw
-
- ; Really done.
-
- int 20h
-
- ; R command - manipulate registers.
-
- rr: cmp al,CR
- jne rr1 ;if there's an argument
- call dumpregs
- ret
-
- rr1: dec si
- lodsw
- and ax,TOUPPER_W
- mov di,offset regnames
- mov cx,13
- repne scasw
- mov bx,di
- mov di,offset line_out
- jne rr2 ;if not found
- stosw ;print register name
- mov al,' '
- stosb
- sub bx,offset regnames+2
- call skipwhite ;skip white spaces
- cmp al,CR
- jne rr1a ;if not end of line
- push bx ;save bx for later
- mov ax,[bx+regs]
- call hexword
- call getline0 ;prompt for new value
- pop bx
- cmp al,CR
- je ret ;if no change required
- rr1a: call getword
- call chkeol ;expect end of line here
- mov [bx+regs],dx ;save new value
- ret
-
- ; Change flags
-
- rr2: cmp al,'F'
- jne rr6 ;if not 'f'
- dec si
- lodsb
- cmp al,CR
- je rr2b ;if end of line
- cmp al,' '
- je rr2a ;if white space
- cmp al,TAB
- jne errorj9 ;if not, then it's an error
- rr2a: call skipwhite
- cmp al,CR
- jne rr3 ;if not end of line
- rr2b: call dmpflags
- call getline0 ;get input line (using line_out as prompt)
- rr3: cmp al,CR
- je ret ;if done
- dec si
- lodsw
- and ax,TOUPPER_W ;here's the mnemonic
- mov di,offset flgnams
- mov cx,16
- repne scasw
- jne rr6 ;if no match
- cmp di,offset flgnons
- ja rr4 ;if we're clearing
- mov ax,[di-16-2]
- not ax
- and flags,ax
- jmp short rr5
-
- rr4: mov ax,[di-32-2]
- or flags,ax
-
- rr5: call skipwhite
- jmp rr3 ;if done
-
- rr6: dec si ;back up one before flagging an error
- errorj9:jmp error
-
- ; S command - search for a string of bytes.
-
- sss: mov bx,reg_ds ;get search range
- xor cx,cx
- call getrange ;get address range into BX:DX..BX:CX
- call skipwh0
- push cx
- push dx
- call getstr ;get string of bytes
- pop dx
- pop cx
- sub cx,dx ;cx = number of bytes in search range minus one
- sub di,offset line_out ;di = number of bytes to look for
- dec di ; minus one
- sub cx,di ;number of possible positions of string minus 1
- jb errorj9 ;if none
- push di
- call prehack ;set up for the interrupt vector hack
- pop di
- inc cx ;cx = number of possible positions of string
- xchg dx,di
- push bx ;push the segment
- sss1: push di
- call dohack ;do the interrupt pointer hack
- pop di
- pop es ;recover the segment
- mov si,offset line_out;si = address of search string
- lodsb ;first character in al
- repne scasb ;look for first byte
- jne sss3 ;if we're done
- push es ;save the segment again
- mov ax,es ;also in ax
- push cx
- push di
- mov cx,dx
- repe cmpsb
- push si
- pushf
- call unhack ;undo the interrupt vector hack and restore es
- popf
- pop si
- pop di
- jne sss2 ;if not equal
- push dx
- xchg si,di ;write address right after search string
- call hexword
- mov al,':'
- stosb
- lea ax,[si-1]
- call hexword
- mov ax,LF * 256 + CR
- stosw
- mov ah,40h ;write to file
- mov bx,1
- mov cx,11
- lea dx,[di-11]
- int 21h
- pop dx
- mov di,si
- sss2: pop cx
- inc cx
- loop sss1 ;go back for more
- pop ax ;remove saved es from the stack
-
- sss3: jmp unhack ;undo the interrupt vector hack, restore es,
- ;and return
-
- ; T command - Trace.
-
- tt: call parse_pt ;process arguments
-
- ; Do it <count> times.
-
- tt1: push cx
- or flags,100h ;set single-step mode
- call run
- cmp run_int,offset int1msg
- jne tt2 ;if some other interrupt
- call dumpregs
- pop cx
- loop tt1
- ret
-
- ; Print message about unexpected interrupt, dump registers, and end
- ; command. This code is also used by the G and P commands.
-
- tt2: mov ah,9 ;print string
- mov dx,run_int
- int 21h
- cmp dx,offset progtrm
- je tt3 ;if it terminated, skip the registers
- call dumpregs
- tt3: jmp cmd3 ;back to the start
-
- ; U command - disassemble.
-
- uu: cmp al,CR
- jne uu1 ;if an address was given
- mov cx,u_addr
- add cx,1fh
- jnc uu2 ;if no overflow
- mov cx,-1
- jmp short uu2
-
- uu1: mov cx,20h ;default length
- mov bx,reg_cs
- call getrange ;get address range into dx:bx
- call chkeol ;expect end of line here
- mov u_addr+2,bx
- mov u_addr,dx
-
- ; At this point, cx holds the last address, and dx the address.
-
- uu2: inc cx ;cx = last address + 1
- uu3: push cx
- push dx
- mov byte disflags,0
- call disasm ;do it
- pop bx
- pop cx
- mov ax,u_addr
- mov dx,ax
- sub ax,cx ;current position - end
- sub bx,cx ;previous position - end
- cmp ax,bx
- jnb uu3 ;if we haven't reached the goal
- uu4: ret
-
- ; W command - write a program, or disk sectors, to disk.
-
- ww: call parselw ;parse it
- jz ww4 ;if request to write program
- int 26h
- mov dx,offset writing
- ww1: mov bx,cs ;restore segment registers
- mov ds,bx
- mov ss,bx
- mov sp,savesp
- mov es,bx
- jnc ww3 ;if no error
- cmp al,0ch
- jbe ww2 ;if in range
- mov al,0ch
- ww2: cbw
- shl ax,1
- xchg si,ax
- mov si,[si+dskerrs]
- mov di,offset line_out
- call showstring
- mov si,dx
- call showstring
- mov si,offset drive
- call showstring
- call putsline
- ww3: jmp cmd3 ;can't ret because stack is wrong
-
- ; Write to file. First check the file extension.
-
- ww4: mov bx,execblk+2 ;address of end of file name string
- cmp bx,85h
- jb ww7 ;if file name is too short
- cmp word [bx-5],'E.'
- jne ww5 ;if not .EXE
- cmp word [bx-3],'EX'
- jne ww7 ;if not .EXE
- jmp short ww6 ;bad
-
- ww5: cmp word [bx-5],'H.'
- jne ww7 ;if not .HEX
- cmp word [bx-3],'XE'
- jne ww7 ;if not .HEX
-
- ww6: mov ah,9 ;print string
- mov dx,offset nowhexe
- int 21h
- ret
-
- ; File extension is OK; write it. First, create the file.
-
- ww7: mov ah,3ch ;create file
- xor cx,cx ;no attributes
- mov dx,80h
- int 21h
- jnc ww8
- jmp ww15 ;if error
- ww8: push ax ;save file handle
-
- ; Print message about writing.
-
- mov ah,9 ;print string
- mov dx,offset wwmsg1
- int 21h
- mov ax,reg_bx
- cmp ax,10h
- jb ww9 ;if not too large
- xor ax,ax ;too large: zero it out
- ww9: mov word line_out+8,ax
- or ax,ax
- jz ww10
- add al,90h ;convert to hex and print
- daa
- adc al,40h
- daa
- stosb
- ww10: mov ax,reg_cx
- mov word line_out+6,ax
- call hexword
- call puts ;print size
- mov ah,9 ;print string
- mov dx,offset wwmsg2
- int 21h
-
- ; Now write the file. Size remaining is in line_out+6.
-
- pop bx ;recover file handle
- mov si,psp
- add si,10h ;si = starting paragraph
- ww11: mov ax,0fe00h
- cmp byte line_out+8,0
- jnz ww12 ;if more than 0fe00h bytes remaining
- cmp ax,word line_out+6
- jb ww12 ;ditto
- mov ax,word line_out+6
- ww12: xchg ax,cx ;mov cx,ax
- mov ah,40h ;write to file
- xor dx,dx
- mov ds,si
- int 21h
- push cs ;restore DS
- pop ds
- cmp ax,cx
- jne ww13 ;if disk full
- add si,0fe0h ;update segment pointer
- sub word line_out+6,cx
- lahf
- sbb byte line_out+8,0
- jnz ww11 ;if more to go
- sahf
- jnz ww11 ;ditto
- jmp short ww14
-
- ww13: mov ah,9 ;print string
- mov dx,offset diskful
- int 21h
- mov ah,41h ;unlink file
- mov dx,80h
- int 21h
-
- ; Close the file.
-
- ww14: mov ah,3eh ;close file
- int 21h
- ret
-
- ; Error opening file. This is also called by the load command.
-
- ww15: cmp ax,2
- mov dx,offset doserr2 ;File not found
- je ww16
- cmp ax,3
- mov dx,offset doserr3 ;Path not found
- je ww16
- cmp ax,5
- mov dx,offset doserr5 ;Access denied
- je ww16
- cmp ax,8
- mov dx,offset doserr8 ;Insufficient memory
- je ww16
- push ax
- mov ah,9 ;print string
- mov dx,offset wwerr1;'Error '
- int 21h
- pop ax
- mov di,offset line_out
- call hexword
- call puts ;print error code
- mov dx,offset wwerr2;' opening file.',CR,LF
- ww16: mov ah,9 ;print string
- int 21h
- ret
-
- ; Error handlers.
-
- error: mov cx,si
- sub cx,offset line_in+4
- add cx,promptlen
- cmp cx,127
- ja err2 ;if we're really messed up
- inc cx ;number of spaces to skip
- mov dl,' '
- err1: mov ah,2 ;display output
- int 21h
- loop err1
- err2: mov ah,9 ;print string
- mov dx,offset errcarat
- int 21h
- jmp [errret]
-
- ; FREEMEM - Free the child process's memory.
-
- freemem:cmp running,0
- jz fmem1 ;if process has already terminated
- mov reg_cs,cs
- mov reg_ip,offset fmem4
- mov reg_ss,ss
- push ax
- mov reg_sp,sp ;save sp-2
- pop ax
- call run
-
- ; Free blocks created when we loaded a program ourselves.
-
- fmem1: mov si,offset blk1
- mov cx,2
- fmem2: lodsw
- cmp ax,0
- je fmem3 ;if nothing needs to be done
- mov es,ax
- mov ah,49h ;free memory
- int 21h
- loop fmem2
-
- fmem3: push cs ;restore ES
- pop es
- ret ;done
-
- fmem4: mov ax,4c00h ;quit
- int 21h
-
- ; This is the routine that starts up the running program.
-
- run: call seteq ;set CS:IP to '=' address
- mov ah,50h ;set PSP
- mov bx,psp
- int 21h
- mov ax,2524h ;set interrupt vector 24h
- lds dx,run2324+4
- int 21h
- mov ax,2523h ;set interrupt vector 23h
- lds dx,cs:run2324
- int 21h
- push cs ;restore ds
- pop ds
- mov run_sp,sp ;save stack position
- sub sp,spadjust
- mov [2eh],sp
- cli
- mov sp,offset regs
- pop ax
- pop bx
- pop cx
- pop dx
- pop bp ;we'll get sp later
- pop bp
- pop si
- pop di
- pop ds
- pop es
- pop ss
- mov sp,cs:reg_sp ;restore program stack
- push cs:flags
- push cs:reg_cs
- push cs:reg_ip
- iret ;jump to program
-
- ; Interrupt 22 (program termination) handler.
-
- int22: cli
- mov cs:run_int,offset progtrm ;remember interrupt type
- mov cs:reg_cs,cs ;put in dummy value for CS:IP
- mov cs:reg_ip,0
- mov cs:flags,200h
- mov cs:running,0
- jmp short intrtn1 ;jump to register saving routine (sort of)
-
- ; Interrupt 0 (divide error) handler.
-
- int0: mov cs:run_int,offset int0msg ;remember interrupt type
- jmp short intrtn ;jump to register saving routine
-
- ; Interrupt 1 (single-step interrupt) handler.
-
- int1: mov cs:run_int,offset int1msg ;remember interrupt type
- jmp short intrtn ;jump to register saving routine
-
- ; Interrupt 3 (breakpoint interrupt) handler.
-
- int3: mov cs:run_int,offset int3msg ;remember interrupt type
-
- ; Common interrupt routine.
-
- ; Housekeeping.
-
- intrtn: cli ;just in case
- pop cs:reg_ip ;recover things from stack
- pop cs:reg_cs
- pop cs:flags
- intrtn1:mov cs:reg_ss,ss ;save stack position
- mov cs:reg_sp,sp
- mov sp,cs ;mov ss,cs
- mov ss,sp
- mov sp,offset reg_ss
- push es
- push ds
- push di
- push si
- push bp
- dec sp ;we already saved sp
- dec sp
- push dx
- push cx
- push bx
- push ax
-
- ; Clean up.
-
- mov sp,cs:run_sp ;restore running stack
- sti ;interrupts back on
- cld ;clear direction flag
- push cs ;reestablish DS
- pop ds
- mov ax,3523h ;get interrupt vector 23h into ES:BX
- int 21h
- mov run2324,bx
- mov run2324+2,es
- mov ax,2523h ;set interrupt vector 23h
- lds dx,[0eh]
- int 21h
- push cs ;reestablish DS
- pop ds
- mov ax,3524h ;get interrupt vector 24h
- int 21h
- mov run2324+4,bx
- mov run2324+6,es
- mov ax,2524h ;set interrupt vector 24h
- lds dx,[12h] ;get original vector from PSP
- int 21h
- mov ah,50h ;set PSP
- mov bx,cs
- int 21h
- mov ds,bx ;reestablish DS and ES
- mov es,bx
- and flags,not 100h ;clear single-step interrupt
-
- ; Return.
-
- ret
-
- ; The next three subroutines concern the handling of INT 23 and 24.
- ; These interrupt vectors are saved and restored when running the
- ; child process, but are not active when DEBUG itself is running.
- ; It is still useful for the programmer to be able to check where INT 23
- ; and 24 point, so these values are copied into the interrupt table
- ; during parts of the c, d, e, m, and s commands, so that they appear
- ; to be in effect. The e command also copies these values back.
- ; Between calls to dohack and unhack, there should be no calls to DOS,
- ; so that there is no possibility of these vectors being used when
- ; the child process is not running.
-
- ; PREHACK - Set up for interrupt vector substitution.
- ; Entry es = cs
- ; Exit ds = cs
- ; Uses si, di.
-
- prehack:cmp hakstat,0
- jnz ph_err ;if hack status error |||
- mov di,offset sav2324
- prehak1:xor si,si
- mov ds,si
- mov si,4*23h
- movsw
- movsw
- movsw
- movsw
- push cs
- pop ds
- ret
-
- ph_err: push ax
- push dx
- mov ah,9 ;print string |||
- mov dx,offset ph_msg
- int 21h
- pop dx
- pop ax
- ret
-
- ph_msg db 'Error in sequence of calls to hack.',CR,LF,'$'
-
- ; DOHACK - Fake the interrupt vectors 23 and 24.
- ; UNHACK - Restore interrupt vectors 23 and 24 to their original values.
- ; It's OK to do either of these twice in a row.
- ; In particular, the `s' command may do unhack twice in a row.
- ; Entry ds = cs
- ; Exit es = cs
- ; Uses si, di.
-
- dohack: mov hakstat,1
- mov si,offset run2324
- jmp short hak1
-
- unhack: mov hakstat,0
- mov si,offset sav2324
- hak1: xor di,di
- mov es,di
- mov di,4*23h
- movsw
- movsw
- movsw
- movsw
- push cs
- pop es
- ret
-
- ; GETLINE - Print a prompt (address in DX, length in CX) and read a line
- ; of input.
- ; GETLINE0 - Same as above, but use the output line (so far), plus two
- ; spaces and a colon, as a prompt.
- ; GETLINE00 - Same as above, but use the output line (so far) as a prompt.
- ; Entry CX Length of prompt (getline only)
- ; DX Address of prompt string (getline only)
- ;
- ; DI Address + 1 of last character in prompt (getline0 and
- ; getline00 only)
- ;
- ; Exit AL First nonwhite character in input line
- ; SI Address of the next character after that
- ; Uses AH,BX,CX,DX,DI
-
- getline0:
- mov ax,' ' ;add two spaces and a colon
- stosw
- mov al,':'
- stosb
- getline00:
- mov dx,offset line_out
- mov cx,di
- sub cx,dx
-
- getline:
- mov promptlen,cx ;save length of prompt
- call bufsetup
- pushf
- mov ah,40h ;write to file
- mov bx,1 ;standard output
- int 21h
- popf
- jc gl5 ;if tty input
-
- ; This part reads the input line from a file (in the case of
- ; `debug < file'). It is necessary to do this by hand because DOS
- ; function 0ah does not handle EOF correctly otherwise. This is
- ; especially important for debug because it traps Control-C.
-
- gl1: mov cx,bufend
- sub cx,si ;cx = number of valid characters
- jz gl3 ;if none
- gl2: lodsb
- cmp al,CR
- je gl4 ;if end of line
- cmp al,LF
- je gl4 ;if eol
- stosb
- loop gl2 ;if there are more valid characters
- gl3: call fillbuf
- jnc gl1 ;if we have more characters
- mov al,LF
- cmp di,offset line_in+LINE_IN_LEN
- jb gl4
- dec si
- dec di
- gl4: mov bufnext,si
- mov notatty,al
- mov al,CR
- stosb
- mov ah,40h ;write to file: print out the received line
- mov bx,1
- mov cx,di
- mov dx,offset line_in + 2
- sub cx,dx
- int 21h
- jmp short gl6 ;done
-
- gl5: mov ah,0ah ;buffered keyboard input
- mov dx,offset line_in
- int 21h
-
- gl6: mov ah,2 ;display output
- mov dl,LF ;print a line feed afterwards
- int 21h
- mov si,offset line_in + 2
- call skipwhite
- ret
-
- ; BUFSETUP - Set up buffer reading. This just means discard an LF
- ; if the last character read (as stored in `notatty') is CR.
- ; Entry DI First available byte in input buffer
- ; Exit SI Address of next character.
- ; If the input is from a tty, then bufsetup returns with carry set.
-
- bufsetup:
- cmp notatty,0
- jnz bs1 ;if not a tty
- stc
- ret
-
- bs1: mov di,offset line_in+2
- mov si,bufnext
- cmp si,bufend
- jb bs2 ;if there's a character already
- call fillbuf
- jc bs4 ;if eof
- bs2: cmp notatty,CR
- jne bs3 ;if nothing more to do
- cmp byte [si],LF
- jne bs3 ;if not a line feed
- inc si ;skip it
- bs3: clc
- ret
-
- bs4: jmp qq ;quit: we've hit an eof
-
- ; FILLBUF - Fill input buffer. Mostly this is an internal routine
- ; for getline.
- ; Entry DI First available byte in input buffer
- ; Exit SI Next readable byte (i.e., equal to DI)
- ; Carry flag is set if and only if there is an error (e.g., eof)
- ; Uses None.
-
- fillbuf:push ax
- push bx
- push cx
- push dx
- mov si,di ;we know this already
- mov ah,3fh ;read from file
- xor bx,bx
- mov cx,offset line_in+LINE_IN_LEN
- mov dx,di
- sub cx,dx
- jz fb1 ;if no more room
- int 21h
- jc fb1 ;if error
- or ax,ax
- jz fb1 ;if eof
- add ax,dx
- clc
- jmp short fb2
-
- fb1: xchg ax,dx ;ax = last valid byte address + 1
- stc
-
- fb2: mov bufend,ax
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-
- ; PARSECM - Parse command line for C and M commands.
- ; Entry AL First nonwhite character of parameters
- ; SI Address of the character after that
- ; Exit DS:SI Address from first parameter
- ; ES:DI Address from second parameter
- ; CX Length of address range minus one
-
- parsecm:push si
- call prehack
- pop si
- mov bx,reg_ds ;get source range
- xor cx,cx
- call getrange
- sub cx,dx ;number of bytes minus one
- push bx
- push dx
- push cx
- call skipwh0
- mov bx,reg_ds
- call getaddr ;get destination address
- pop cx
- mov di,cx
- add di,dx
- jc errorj7 ;if it wrapped around
- call chkeol ;expect end of line
- mov di,dx
- mov es,bx
- pop si
- pop ds
- ret
-
- errorj7:jmp error
-
- ; PARSELW - Parse command line for L and W commands.
- ; Entry AL First nonwhite character of parameters
- ; SI Address of the character after that
- ; Exit If there is at most one argument (program load/write), then the
- ; zero flag is set, and registers are set as follows:
- ; bx:dx Transfer address
- ; If there are more arguments (absolute disk read/write), then the
- ; zero flag is clear, and registers are set as follows:
- ; DOS versions prior to 3.31:
- ; AL Drive number
- ; CX Number of sectors to read
- ; DX Beginning logical sector number
- ; DS:BX Transfer address
- ; Later DOS versions:
- ; AL Drive number
- ; BX Offset of packet
- ; CX 0FFFFh
-
- usepacket db 0 ;if the packet is to be used
-
- packet dw 0,0 ;sector number
- dw 0 ;number of sectors to read
- dw 0,0 ;transfer address
-
- parselw:mov bx,reg_cs ;default segment
- mov dx,100h ;default offset
- cmp al,CR
- je plw2 ;if no arguments
- call getaddr ;get address
- call skipwh0
- cmp al,CR
- je plw2 ;if only one argument
- push dx
- push bx
- mov bx,80h ;max number of sectors to read
- neg dx
- jz plw1 ;if address is zero
- mov cl,9
- shr dx,cl ;max number of sectors which can be read
- mov di,dx
- plw1: call getbyte ;get drive number
- call skipwh0
- push dx
- add dl,'A'
- mov driveno,dl
- call getdbl ;get relative sector number
- call skipwh0
- push dx
- push bx
- push si ;in case we find an error
- call getword ;get sector count
- dec dx
- cmp dx,di
- jae errorj7 ;if too many sectors
- inc dx
- mov cx,dx
- call chkeol ;expect end of line
- cmp usepacket,0
- jnz plw3 ;if new-style packet called for
- pop si ;in case of error
- pop bx ;high bits of sector number
- or bx,bx
- jnz errorj7 ;if too big
- pop dx ;beginning logical sector number
- pop ax ;drive number
- pop ds ;transfer address
- pop bx
- or cx,cx ;set nonzero flag
- plw2: ret
-
- plw3: pop bx ;discard si
- mov bx,offset packet
- pop [bx+2] ;sector number
- pop [bx]
- mov [bx+4],cx ;number of sectors
- pop ax ;drive number
- pop [bx+8] ;transfer address
- pop [bx+6]
- xor cx,cx
- dec cx ;set nonzero flag and make cx = -1
- ret
-
- ; PARSE_PT - Parse 'p' or 't' command.
- ; Entry AL First character of command
- ; SI Address of next character
- ; Exit CX Number of times to repeat
- ; Uses AH,BX,CX,DX.
-
- parse_pt:
- call parseql ;process =addr
- call skipwh0 ;skip any white space
- mov cx,1 ;default count
- cmp al,CR
- je ppt1 ;if no count given
- call getword
- call chkeol ;expect end of line here
- mov cx,dx
- ppt1: call seteq ;make the = operand take effect
- ret
-
- ; PARSEQL - Parse `=' operand for `g' and `t' commands.
- ; Entry AL First character of command
- ; SI Address of next character
- ; Exit AL First character beyond range
- ; SI Address of the character after that
- ; eqflag Nonzero if an `=' operand was present
- ; eqladdr Address, if one was given
- ; Uses AH,BX,CX,DX.
-
- parseql:mov eqflag,0 ;mark `=' as absent
- cmp al,'='
- jne peq1 ;if no `=' operand
- call skipwhite
- mov bx,reg_cs ;default segment
- call getaddr ;get the address into bx:dx
- mov eqladdr,dx
- mov eqladdr+2,bx
- mov eqflag,1
- peq1: ret
-
- ; SETEQ - Copy the = arguments to their place, if appropriate. (This
- ; is not done immediately, because the 'g' command may have a syntax
- ; error.)
- ; Uses AX.
-
- seteq: cmp eqflag,0
- jz seq1 ;if no `=' operand
- mov ax,eqladdr
- mov reg_ip,ax
- mov ax,eqladdr+2
- mov reg_cs,ax
- mov eqflag,0 ;clear the flag
- seq1: ret
-
- ; GETRANGE - Get address range from input line.
- ; Entry AL First character of range
- ; SI Address of next character
- ; BX Default segment to use
- ; CX Default length to use (or 0 if not allowed)
- ; Exit AL First character beyond range
- ; SI Address of the character after that
- ; BX:DX First address in range
- ; BX:CX Last address in range
- ; Uses AH
-
- getrange:
- push cx ;save the default length
- call getaddr
- push si
- call skipwh0
- cmp al,','
- je gr2 ;if an upper bound is given
- or al,TOLOWER
- cmp al,'l'
- je gr3 ;if a range is given
- pop si ;restore si and cx
- pop cx
- jcxz errorj2 ;if a range is mandatory
- dec cx
- add cx,dx
- jnc gr1 ;if no wraparound
- mov cx,0ffffh ;go to end of segment
- gr1: dec si ;restore al
- lodsb
- ret
-
- gr2: call skipwhite ;discard the ','
- push dx
- call getword
- mov cx,dx
- pop dx
- cmp dx,cx
- ja errorj2 ;if empty range
- jmp short gr4
-
- gr3: call skipwhite ;discard the 'l'
- push dx
- call getword
- mov cx,dx
- pop dx
- jcxz errorj2 ;if zero length
- dec cx
- add cx,dx
- jc errorj2 ;if it wraps around
-
- gr4: add sp,4 ;discard saved cx, si
- ret
-
- ; GETADDR - Get address from input line.
- ; Entry AL First character of address
- ; SI Address of next character
- ; BX Default segment to use
- ; Exit AL First character beyond address
- ; SI Address of the character after that
- ; BX:DX Address found
- ; Uses AH,CX
-
- getaddr:mov ah,[si]
- or ah,TOLOWER
- cmp ah,'s'
- jne ga1 ;if not a segment specifier
- push di
- or al,TOLOWER
- mov di,offset segletrs
- mov cx,4
- repne scasb
- jne errorj2 ;if not a valid segment name
- sub di,offset segletrs+1
- shl di,1
- mov bx,[reg_ds+di]
- pop di
- inc si ;skip over 's'
- call skipwhite ;get next character
- cmp al,':'
- jne errorj2 ;expect a colon
- jmp short ga3 ;get colon and lower part of address
-
- ga1: call getword
- push si
- call skipwh0
- cmp al,':'
- je ga2 ;if this is a segment descriptor
- pop si
- dec si
- lodsb
- ret
-
- ga2: pop ax ;throw away saved si
- mov bx,dx
- ga3: call skipwhite ;skip to next word
- call getword
- ret
-
- errorj2:jmp error
-
- ; GETSTR - Get string of bytes. Put the answer in line_out.
- ; Entry AL first character
- ; SI address of next character
- ; Exit [line_out] first byte of string
- ; DI address of last+1 byte of string
- ; Uses AX,CL,DL,SI
-
- getstr: mov di,offset line_out
- cmp al,CR
- je errorj2 ;we don't allow empty byte strings
- gs1: cmp al,"'"
- je gs2 ;if string
- cmp al,'"'
- je gs2 ;ditto
- call getbyte
- mov [di],dl ;store the byte
- inc di
- jmp short gs6
-
- gs2: mov ah,al ;save quote character
- gs3: lodsb
- cmp al,ah
- je gs5 ;if possible end of string
- cmp al,CR
- je errorj2 ;if end of line
- gs4: stosb ;save character and continue
- jmp gs3
-
- gs5: lodsb
- cmp al,ah
- je gs4 ;if doubled quote character
-
- gs6: call skipwh0 ;go back for more
- cmp al,CR
- jne gs1 ;if not done yet
- ret
-
- ; GETDBL - Get (hex) dword from input line.
- ; Entry AL first character
- ; SI address of next character
- ; Exit BX:DX word
- ; AL first character not in the word
- ; SI address of the next character after that
- ; Uses AH,CL
-
- getdbl: call getnyb
- jc errorj2 ;if error
- cbw
- xchg ax,dx
- xor bx,bx ;clear high order word
- gd1: lodsb
- call getnyb
- jc gd3
- test bh,0f0h
- jnz errorj2 ;if too big
- mov cx,4
- gd2: shl dx,1 ;double shift left
- rcl bx,1
- loop gd2
- or dl,al
- jmp gd1
- gd3: ret
-
- ; GETWORD - Get (hex) word from input line.
- ; Entry AL first character
- ; SI address of next character
- ; Exit DX word
- ; AL first character not in the word
- ; SI address of the next character after that
- ; Uses AH,CL
-
- getword:call getnyb
- jc errorj2 ;if error
- cbw
- xchg ax,dx
- mov cl,4
- gw1: lodsb
- call getnyb
- jc gw2
- test dh,0f0h
- jnz errorj2 ;if too big
- shl dx,cl
- or dl,al
- jmp gw1
- gw2: ret
-
- ; GETBYTE - Get (hex) byte from input line.
- ; Entry AL first character
- ; SI address of next character
- ; Exit DL byte
- ; AL first character not in the word
- ; SI address of the next character after that
- ; Uses AH,CL
-
- getbyte:call getnyb
- jc errorj2 ;if error
- mov dl,al
- mov cl,4
- gb1: lodsb
- call getnyb
- jc gb2
- test dl,0f0h
- jnz errorj8 ;if too big
- shl dl,cl
- or dl,al
- jmp gb1
- gb2: ret
-
- ; GETNYB - Convert the hex character in AL into a nybble. Return
- ; carry set in case of error.
-
- getnyb: push ax
- sub al,'0'
- cmp al,9
- jbe gn1 ;if normal digit
- pop ax
- push ax
- or al,TOLOWER
- sub al,'a'
- cmp al,'f'-'a'
- ja gn2 ;if not a-f or A-F
- add al,10
- gn1: inc sp ;normal return (first pop old AX)
- inc sp
- clc
- ret
-
- gn2: pop ax ;error return
- stc
- ret
-
- ; CHKEOL1 - Check for end of line.
-
- chkeol: call skipwh0
- cmp al,CR
- jne errorj8 ;if not found
- ret
-
- errorj8:jmp error
-
- ; SKIPALPHA - Skip alphabetic character, and then white space.
-
- skipalpha:
- lodsb
- and al,TOUPPER
- sub al,'A'
- cmp al,'Z'-'A'
- jbe skipalpha
- dec si
- ; jmp skipwhite ;(control falls through)
-
- ; SKIPWHITE - Skip spaces and tabs.
- ; SKIPWH0 - Same as above, but we already have the character in AL.
-
- skipwhite:
- lodsb
- skipwh0:cmp al,' '
- je skipwhite
- cmp al,TAB
- je skipwhite
- ret
-
- ; IFSEP Compare AL with separators ' ', '\t', ',', ';', '='.
-
- ifsep: cmp al,' '
- je ifs1
- cmp al,TAB
- je ifs1
- cmp al,','
- je ifs1
- cmp al,';'
- je ifs1
- cmp al,'='
- ifs1: ret
-
- ; Here is the start of the disassembly part of the program.
-
- ; Jump table for OP_IMM, OP_RM, OP_M, OP_R_MOD, OP_MOFFS, OP_R, OP_R_ADD,
- ; and OP_AX.
-
- disjmp2 dw dop01,dop04,dop29,dop29a,dop30,dop32,dop36,dop37
-
- optab dw dop38,dop38a,dop38b,dop39,dop42,dop41 ;jump table
- dw dop43,dop46,dop47,dop49,dop51,dop52
- dw dop53,dop54,dop56,dop58,dop59,dop59e,dop60
- db '1',0,'3',0,'DXCLSTCSDSESFSGSSS' ;simple strings
-
- OP_STR equ OP_1 ;first string entry
-
- ; DISASM - Disassemble.
-
- dis_n dw 0 ;number of bytes in instruction so far
- preflags db 0 ;flags for prefixes found so far
- preused db 0 ;flags for prefixes used so far
-
- PRESEG equ 1 ;segment prefix
- PREREP equ 2 ;rep prefixes
- PRELOCK equ 4 ;lock prefix
- PRE32D equ 8 ;flag for 32-bit data
- PRE32A equ 10h ;flag for 32-bit addressing
- PREWAIT equ 20h ;prefix wait (not really a prefix)
- GOTREGM equ 40h ;set if we have the reg/mem part
-
- instr db 0 ;the main instruction byte
- index dw 0 ;index of the instruction (unsqueezed)
- dw SFPGROUP3, SFPGROUP3+1, SFPGROUP3+4
- dw SPARSE_BASE+24h, SPARSE_BASE+26h ;obsolete-instruction values
- rmsize db 0 ;<0 or 0 or >0 means mod r/m is 8 or 16 or 32
- segmnt db 0 ;segment determined by prefix (or otherwise)
- addr dw 0 ;address in mod r/m byte
- savesp2 dw 0 ;save the stack pointer here (used in disasm)
-
- disflags db 0 ;flags for the disassembler
-
- ;equates for disflags:
- DIS_F_REPT equ 1 ;repeat after pop ss, etc.
- DIS_F_SHOW equ 2 ;show memory contents
- DIS_I_SHOW equ 4 ;there are memory contents to show
- DIS_I_UNUSED equ 8 ;(internal) print " (unused)"
- DIS_I_SHOWSIZ equ 10h ;(internal) always show the operand size
- DIS_I_KNOWSIZ equ 20h ;(internal) we know the operand size of instr.
-
- disflags2 db 0 ;another copy of DIS_I_KNOWSIZ
-
- sizeloc dw 0 ;address of size words in output line
-
- ; Jump table for a certain place.
-
- disjmp dw disbad ;illegal instruction
- dw da6 ;two byte instruction
- dw da7 ;instruction group
- dw da8 ;coprocessor instruction
- dw da9 ;coprocessor instruction group
- dw da10 ;instruction prefix
-
- ; Table for 16-bit mod r/m addressing. 8 = BX, 4 = BP, 2 = SI, 1 = DI.
-
- rmtab db 8+2, 8+1, 4+2, 4+1, 2, 1, 4, 8
-
- ; Tables of register names.
- ; rgnam816/rgnam16/segrgnam/xregnam must be consecutive.
-
- rgnam816 dw 'LA','LC','LD','LB','HA','HC','HD','HB'
- rgnam16 dw 'XA','XC','XD','XB','PS','PB','IS','ID'
- segrgnam dw 'SE','SC','SS','SD','SF','SG'
- xregnam dw 'TS','MM','RC','RD','RT'
- sizetcnam dw 'YB','OW','OW','WD','WQ','LF','OD','BT','HS','OL','EN','AF'
- segrgaddr dw reg_es,reg_cs,reg_ss,reg_ds
-
- ; Tables for handling of named prefixes.
-
- prefixlist db 26h,2eh,36h,3eh,64h,65h ;segment prefixes (in order)
- db 9bh,0f0h,0f2h,0f3h ;WAIT,LOCK,REPNE,REPE
- prefixmnem dw MNEM_WAIT,MNEM_LOCK,MNEM_REPNE,MNEM_REPE
-
- disasm: mov savesp2,sp
- mov dis_n,0
- mov word preflags,0 ;clear preflags and preused
- mov segmnt,3 ;initially use DS segment
- mov rmsize,80h ;don't display any memory
- mov word dismach,0 ;no special machine needed, so far
- call disgetbyte ;get a byte of the instruction
- cmp al,9bh ;wait instruction (must be the first prefix)
- jne da2 ;if not
-
- ; The wait instruction is actually a separate instruction as far as
- ; the x86 is concerned, but we treat it as a prefix since there are
- ; some mnemonics that incorporate it. But it has to be treated specially
- ; since you can't do, e.g., seg cs wait ... but must do wait seg cs ...
- ; instead. We'll catch it later if the wait instruction is not going to
- ; be part of a shared mnemonic.
-
- or preflags,PREWAIT
-
- ; If we've found a prefix, we return here for the actual instruction
- ; (or another prefix).
-
- da1: call disgetbyte
- da2: mov instr,al ;save away the instruction
- mov ah,0
-
- ; Now we have the sequence number of the instruction in AX. Look it up.
-
- da3: mov bx,ax
- mov index,ax ;save the compressed index
- cmp ax,SPARSE_BASE
- jb da4 ;if it's not from the squeezed part of the table
- mov bl,sqztab[bx-SPARSE_BASE]
- mov bh,0
- add bx,SPARSE_BASE ;bx = compressed index
-
- da4: mov cl,optypes[bx] ;cx = opcode type
- mov ch,0
- shl bx,1
- mov bx,opinfo[bx] ;bx = other info (usually the mnemonic)
- mov si,cx
- mov ax,bx
- mov cl,12
- shr ax,cl
- cmp al,dismach
- jb da5 ;if a higher machine is already required
- mov dismach,al ;set machine type
- da5: and bx,0fffh ;remove the machine field
- cmp si,OPTYPES_BASE
- jae da13 ;if this is an actual instruction
- call disjmp[si] ;otherwise, do more specific processing
- jmp da3 ;back for more
-
- ; Two-byte instruction.
-
- da6: call disgetbyte
- mov instr,al
- mov ah,0
- add ax,SPARSE_BASE
- ret
-
- ; Instruction group.
-
- da7: call getregmem_r ;get the middle 3 bits of the R/M byte
- cbw
- add ax,bx ;offset
- ret
-
- ; Coprocessor instruction.
-
- da8: or disflags,DIS_I_SHOWSIZ
- or dmflags,DM_COPR
- call getregmem
- cmp al,0c0h
- jb da7 ;range 00-bfh is same as an instruction group
- mov cl,3
- shr al,cl ;C0h --> 18h
- sub al,18h-8 ;18h --> 8
- cbw
- add ax,bx ;offset
- ret
-
- ; Coprocessor instruction group.
-
- da9: mov al,regmem
- and al,7
- cbw
- add ax,bx
- ret
-
- ; Instruction prefix. At this point, bl = prefix bits; bh = segment
-
- da10: test bl,preflags
- jnz da12 ;if there are duplicates
- or preflags,bl
- test bl,PRESEG
- jz da11 ;if not a segment
- mov segmnt,bh ;save the segment
- da11: pop ax ;discard return address
- jmp da1
-
- da12: jmp disbad ;we don't allow duplicate prefixes
-
- ; OK. Here we go. This is an actual instruction.
- ; First print the op mnemonic.
-
- da13: push si
- lea si,mnlist[bx] ;offset of mnemonic
- cmp si,offset mnlist+MNEM_BSWAP
- jne da13a ;if not BSWAP
- call dischk32d
- jz da12 ;if no operand-size prefix
- da13a: call showop ;print out the op code (at line_out+24)
- mov sizeloc,0 ;clear out this flag
- pop si ;recover list of operands
- add si,offset oplists-OPTYPES_BASE
- cmp byte [si],0
- je da21 ;if we're done
-
- ; Loop over operands. [si] = pointer to next operand type.
- ; Fortunately the operands appear in the instruction in the same
- ; order as they appear in the disassembly output.
-
- da14: mov disflags2,0 ;clear out size-related flags
- lodsb ;get the operand type
- cmp al,OP_SIZE
- jb da18 ;if it's not size dependent
- mov disflags2,DIS_I_KNOWSIZ ;set flag to indicate variable size
- cmp al,OP_8
- jae da16 ;if the size is fixed
- cmp al,OP_1632
- jae da15 ;if word or dword
- mov ah,-1
- test instr,1
- jz da17 ;if byte
- da15: or preused,PRE32D ;mark this flag as used
- mov ah,preflags
- and ah,PRE32D ;this will be >0 for dword, =0 for word
- jmp short da17 ;done
-
- da16: mov ah,al ;OP_8 or OP_16 or OP_32 (we know which)
- and ah,0f0h ;this converts ah to <0 for byte, =0 for word,
- sub ah,OP_16 ;and >0 for dword
-
- ; Now we know the size (in ah); branch off to do the operand itself.
-
- da17: mov bl,al
- and bx,0fh
- call disjmp2[bx] ;print out the operand
- jmp short da20 ;done with operand
-
- ; Sizeless operands.
-
- da18: cbw
- xchg ax,bx
- cmp bl,OP_STR
- jb da19 ;if it's not a string
- mov ax,optab[bx-2]
- stosw
- cmp ah,0
- jnz da20 ;if it's two characters
- dec di
- jmp short da20 ;done with operand
-
- da19: call optab[bx-2] ;otherwise, do something else
-
- da20: cmp byte [si],0
- jz da21 ;if we're done
- mov al,','
- stosb
- jmp da14 ;another operand
-
- da21: mov al,preused
- not al
- and al,preflags
- jnz da22 ;if some flags remain unused
- jmp da28 ;if all flags were used
- da22: mov cx,N_WTAB
- mov bx,offset wtab1
- mov dx,2*N_WTAB-2
- mov ah,PREWAIT
- test al,ah
- jnz da23 ;if there's a WAIT prefix hanging
- mov cx,N_LTAB
- mov bx,offset ltab1
- mov dx,2*N_LTAB-2
- mov ah,PRE32D
- test al,ah
- jz da24 ;if it's not a 32-bit prefix that's hanging
- da23: or preused,ah ;mark this prefix as used
- push di
- mov di,bx
- mov ax,index
- repne scasw
- jne disbad2 ;if not found in the list
- add di,dx ;replace the mnemonic with the 32-bit name
- mov si,[di]
- add si,offset mnlist
- call showop ;copy op mnemonic
- pop di
- jmp da21
-
- disbad2:jmp disbad
-
- da24: test al,PRESEG
- jz da25 ;if not because of a segment prefix
- mov ax,index
- cmp ah,0
- jnz disbad2 ;if index > 256
- push di
- mov cx,P_LEN
- mov di,offset prfxtab
- repne scasb
- pop di
- jne disbad2 ;if it's not on the list
- mov cx,3
- call moveover
- push di
- mov di,offset line_out+24
- call showseg
- mov al,' '
- stosb
- pop di
- or preused,PRESEG ;mark it as used
- jmp da21
-
- da25: test al,PREREP
- jz da26 ;if not a REP prefix
- mov ax,index
- cmp ah,0
- jnz disbad2 ;if not in the first 256 bytes
- and al,0feh ;clear the low bit
- or preused,PREREP
- push di
- mov di,offset replist
- mov cx,5
- repne scasb
- mov si,offset mnlist+MNEM_REP
- je da27 ;if one of the REP instructions
- inc cx
- inc cx
- repne scasb
- jne disbad2 ;if not one of the REPE/REPNE instructions
- mov si,offset mnlist+MNEM_REPE
- jz da27 ;if REPE
- mov si,offset mnlist+MNEM_REPNE
- jmp short da27 ;it's REPNE
-
- disbad3:jmp disbad
-
- da26: test al,PRELOCK
- jz disbad3 ;if not a lock prefix, either
- push di
- mov ax,index
- mov di,offset locktab
- mov cx,N_LOCK
- repne scasw
- jne disbad3 ;if not in the approved list
- test preused,PRESEG
- jz disbad3 ;if memory was not accessed
- mov si,offset mnlist+MNEM_LOCK
- or preused,PRELOCK
-
- ; Slip in another mnemonic. SI = offset of mnemonic, what should be
- ; DI is on the stack.
-
- da27: pop di
- mov cx,8
- push si
- call moveover
- pop si
- push di
- call showop
- pop di
- jmp da21
-
- ; Done with instruction. Erase the size indicator, if appropriate.
-
- da28: mov cx,sizeloc
- cmp cx,0
- jz da28b ;if there was no size given
- mov al,disflags
- test al,DIS_I_SHOWSIZ
- jnz da28b ;if we need to show the size
- test al,DIS_I_KNOWSIZ
- jz da28b ;if the size is not known already
- xchg cx,di
- mov si,di ;save old di
- mov al,' '
- da28a: scasb ;skip size name
- jne da28a ;if not done yet
- ;(The above is the same as repne scasb, but
- ;has no effect on cx.)
- add di,4 ;skip 'PTR '
- xchg si,di
- sub cx,si
- rep movsb ;move the line
-
- ; Now we're really done. Print out the bytes on the left.
-
- da28b: push di ;print start of disassembly line
- mov di,offset line_out
- mov ax,u_addr+2 ;print address
- call hexword
- mov al,':'
- stosb
- mov ax,u_addr
- call hexword
- mov al,' '
- stosb
- mov bx,dis_n
- cmp bx,6
- jle da29 ;if it's a short instruction
- mov bx,6
- call disshowbytes
- call puts
- mov di,offset line_out
- mov bx,dis_n
- sub bx,6
- call disshowbytes
- call putsline
- mov di,offset line_out
- jmp short da30 ;done
-
- da29: call disshowbytes
- da30: mov ax,' ' ;pad to op code
- mov cx,offset line_out+24
- sub cx,di
- shr cx,1
- rep stosw
- pop di
- test disflags,DIS_I_UNUSED
- jz da32 ;if we don't print ` (unused)'
- mov si,offset unused
- cmp byte [di-1],' '
- jne da31 ;if there's already a space here
- inc si
- da31: call showstring
-
- ; Print info. on minimal processor needed.
-
- da32: push di
- mov di,offset index+2
- call showmach ;show the machine type, if needed
- pop di
- jcxz da32f ;if no message
-
- ; Print a message on the far right.
-
- mov ax,offset line_out+79
- sub ax,cx
- push cx
- call tab_to ;tab out to the location
- pop cx
- rep movsb ;copy the string
- jmp short da32z ;done
-
- ; Dump referenced memory location.
-
- da32f: mov al,disflags
- xor al,DIS_F_SHOW + DIS_I_SHOW
- test al,DIS_F_SHOW + DIS_I_SHOW
- jnz da32z ;if there is no memory location to show
- cmp segmnt,3
- ja da32z ;if FS or GS
- mov ax,offset line_out+79-10
- cmp rmsize,0
- jl da32h ;if byte
- jz da32g ;if word
- sub ax,4
- da32g: dec ax
- dec ax
- da32h: call tab_to
- call showseg ;show segment name
- mov al,':'
- stosb
- mov ax,addr
- call hexword ;show offset
- mov al,'='
- stosb
- mov al,segmnt ;segment number
- cbw
- shl ax,1
- xchg ax,bx ;mov bx,ax
- mov bx,segrgaddr[bx] ;get address of value
- mov es,[bx]
- mov bx,addr
- mov ax,es:[bx]
- mov dx,es:[bx+2]
- push cs ;restore es
- pop es
- cmp rmsize,0
- jl da32j ;if byte
- jz da32i ;if word
- xchg ax,dx
- call hexword
- xchg ax,dx
- da32i: call hexword
- jmp short da32z ;done
-
- da32j: call hexbyte ;display byte
-
- da32z: call trimputs ;done with operand list
- mov al,disflags
- test al,DIS_F_REPT
- jz da34 ;if we're not allowed to repeat ourselves
- test al,DIS_I_UNUSED
- jnz da33 ;if we printed ` (unused)'
- mov ax,index
- cmp ax,17h
- je da33 ;if it was `pop ss'
- cmp ax,8eh
- je da33 ;if it was `mov ss,--'
- cmp ax,0fbh
- jne da34 ;if it was not `sti'
- da33: mov disflags,0
- jmp disasm
- da34: ret
-
- ; Here are the routines for printing out the operands themselves.
- ; Immediate data (OP_IMM)
-
- dop01: cmp ah,0
- jl dop03 ;if just a byte
- pushf
- test disflags,DIS_I_SHOWSIZ
- jz dop01a ;if we don't need to show the size
- call showsize
- sub di,4 ;erase "PTR "
- dop01a: call disgetword
- popf
- jz dop02 ;if just a word
- push ax
- call disgetword ;print the high order word
- call hexword
- pop ax
- dop02: call hexword
- ret
-
- dop03: call disgetbyte ;print immediate byte
- call hexbyte
- ret
-
- ; MOD R/M (OP_RM)
-
- dop04: call getregmem
- cmp al,0c0h
- jb dop05
- jmp dop33 ;if pure register reference
- dop05: call showsize ;print out size
- dop06: or preused,PRESEG ;must do it even if there's no segment override
- ;because handling of LOCK prefix relies on it
- test preflags,PRESEG
- jz dop07 ;if no segment override
- call showseg ;print segment name
- mov al,':'
- stosb
- dop07: mov al,regmem
- and al,0c7h
- or preused,PRE32A
- test preflags,PRE32A
- jz dop08
- jmp dop18 ;if 32-bit addressing
- dop08: or disflags,DIS_I_SHOW ;we'd like to show this address
- mov addr,0 ;zero out the address initially
- cmp al,6
- xchg ax,bx ;mov bx,ax
- mov al,'['
- stosb
- je dop16 ;if [xxxx]
- and bx,7
- mov bl,rmtab[bx]
- test bl,8
- jnz dop09 ;if BX
- test bl,4
- jz dop11 ;if not BP
- mov ax,'PB'
- mov cx,reg_bp
- test preflags,PRESEG
- jnz dop10 ;if segment override
- dec segmnt ;default is now SS
- jmp short dop10
-
- dop09: mov ax,'XB' ;BX
- mov cx,reg_bx
-
- dop10: mov addr,cx ;print it out, etc.
- stosw
- test bl,2+1
- jz dop13 ;if done
- mov al,'+'
- stosb
- dop11: mov ax,'IS'
- mov cx,reg_si
- test bl,1
- jz dop12 ;if SI
- mov al,'D' ;DI
- mov cx,reg_di
-
- dop12: add addr,cx ;print it out, etc.
- stosw
- dop13: test regmem,0c0h
- jz dop17 ;if no displacement
- test regmem,80h
- jnz dop15 ;if word displacement
- call disgetbyte
- cbw
- add addr,ax
- cmp al,0
- mov ah,'+'
- jge dop14 ;if >= 0
- mov ah,'-'
- neg al
- dop14: mov [di],ah
- inc di
- call hexbyte ;print the byte displacement
- jmp short dop17 ;done
-
- dop15: mov al,'+'
- stosb
- dop16: call disgetword
- add addr,ax
- call hexword
-
- dop17: mov al,']'
- stosb
- ret
-
- ; 32-bit MOD REG R/M addressing.
-
- dop18: cmp al,5
- jne dop19 ;if not just a disp32 address
- mov al,'['
- stosb
- call disp32
- jmp dop27
-
- dop19: push ax
- and al,7
- cmp al,4
- jne dop20 ;if no SIB
- call disgetbyte ;get and save it
- mov sibbyte,al
- dop20: pop ax
- test al,80h
- jnz dop22 ;if disp32
- test al,40h
- jz dop23 ;if no disp8
- call disgetbyte
- cmp al,0
- jge dop21 ;if >= 0
- neg al
- mov byte [di],'-'
- inc di
- dop21: call hexbyte
- jmp short dop23 ;done
-
- dop22: call disp32 ;print disp32
-
- dop23: mov al,regmem
- and al,7
- cmp al,4
- jne dop28 ;if no SIB
- mov al,sibbyte
- and al,7
- cmp al,5
- jne dop24 ;if not [EBP]
- test regmem,0c0h
- jnz dop24 ;if MOD != 0
- call disp32 ;show 32-bit displacement instead of [EBP]
- jmp short dop25
-
- dop24: mov word [di],'E['
- inc di
- inc di
- call showreg16
- mov al,']'
- stosb
-
- dop25: mov al,sibbyte
- shr al,1
- shr al,1
- shr al,1
- and al,7
- cmp al,4
- je disbad1 ;if illegal
- mov word [di],'E['
- inc di
- inc di
- call showreg16
- mov ah,sibbyte
- test ah,0c0h
- jz dop27 ;if SS = 0
- mov al,'*'
- stosb
- mov al,'2'
- test ah,80h
- jz dop26 ;if *2
- mov al,'4'
- test ah,40h
- jz dop26 ;if *4
- mov al,'8'
- dop26: stosb
- dop27: mov al,']'
- stosb
- ret
-
- ; 32-bit addressing without SIB
-
- dop28: mov word [di],'E['
- inc di
- inc di
- call showreg16
- mov al,']'
- stosb
- ret
-
- ; Memory-only reference (OP_M)
-
- dop29: call getregmem
- cmp al,0c0h
- jae disbad1 ;if it's a register reference
- jmp dop05
-
- disbad1:jmp disbad ;this is not supposed to happen
-
- ; Register reference from MOD R/M part (OP_R_MOD)
-
- dop29a: call getregmem
- cmp al,0c0h
- jb disbad1 ;if it's a memory reference
- jmp short dop33
-
- ; Memory offset reference (OP_MOFFS)
-
- dop30: call showsize ;print the size and save various things
- mov al,5
- test preflags,PRE32A
- jnz dop31 ;if 32-bit addressing
- inc ax
- dop31: mov regmem,al
- jmp dop06
-
- ; Pure register reference (OP_R)
-
- dop32: call getregmem_r
-
- dop33: and al,7 ;entry point for regs from MOD R/M, and others
- mov cl,disflags2
- or disflags,cl ;if it was variable size operand, the size
- ;should now be marked as known.
- cmp ah,0
- jl dop35 ;if byte register
- jz dop34 ;if word register
- dop33a: mov byte [di],'E' ;enter here from OP_ECX
- inc di
- dop34: add al,8
- dop35: cbw
- shl ax,1
- xchg ax,bx ;mov bx,ax
- mov ax,rgnam816[bx] ;get the register name
- stosw
- ret
-
- ; Register number embedded in the instruction (OP_R_ADD)
-
- dop36: mov al,instr
- jmp dop33
-
- ; AL or AX or EAX (OP_AX)
-
- dop37: mov al,0
- jmp dop33
-
- ; QWORD mem (OP_M64).
-
- dop38: mov ax,'Q' ;print 'QWORD'
- jmp short dop40
-
- ; FLOAT mem (OP_MFLOAT).
-
- dop38a: mov ax,'LF'
- stosw
- mov al,'O'
- stosb
- mov ax,'TA'
- jmp short dop38c
-
- ; DOUBLE mem (OP_MDOUBLE).
-
- dop38b: mov ax,'OD'
- stosw
- mov ax,'BU'
- stosw
- mov ax,'EL'
- dop38c: stosw
- call showptr
- jmp short dop42a
-
- ; TBYTE mem (OP_M80).
-
- dop39: mov ax,0ff00h+'T' ;print 'tbyte'
- dop40: stosb
- call getregmem
- cmp al,0c0h
- jae disbad1 ;if it's a register reference
- and disflags,not DIS_F_SHOW ;don't show this
- jmp dop05
-
- ; far memory (OP_FARMEM).
-
- dop41: call dischk32d
- jz dop41a ;if not dword far
- call showdwd
- sub di,4 ;erase "PTR "
- dop41a: mov ax,'AF' ;store "FAR "
- stosw
- mov ax,' R'
- stosw
-
- ; mem (OP_MXX).
-
- dop42: and disflags,not DIS_F_SHOW ;don't show this
- dop42a: call getregmem
- cmp al,0c0h
- jae disbad5 ;if it's a register reference
- jmp dop06
-
- disbad5:jmp disbad
-
- ; far pointer (OP_FARP).
-
- dop43: call disgetword
- push ax
- call dischk32d
- jz dop44 ;if not 32-bit address
- call disgetword
- push ax
- dop44: call disgetword
- call hexword
- mov al,':'
- stosb
- call dischk32d
- jz dop45 ;if not 32-bit address
- pop ax
- call hexword
- dop45: pop ax
- call hexword
- ret
-
- ; 8-bit relative jump (OP_REL8)
-
- dop46: call disgetbyte
- cbw
- jmp short dop48
-
- ; 16/32-bit relative jump (OP_REL1632)
-
- dop47: call disgetword
- call dischk32d
- jz dop48 ;if not 32-bit offset
- push ax
- call showdwd
- sub di,4 ;erase "PTR "
- pop dx
- call disgetword
- mov bx,u_addr
- add bx,dis_n
- add dx,bx
- adc ax,0 ;this would normally be the upper word of IP
- call hexword
- xchg ax,dx
- jmp hexword ;call hexword and return
-
- dop48: add ax,u_addr
- add ax,dis_n
- jmp hexword ;call hexword and return
-
- ; Check for ST(1) (OP_1CHK).
-
- dop49: pop ax ;discard return address
- mov al,regmem
- and al,7
- cmp al,1
- je dop50 ;if it's ST(1)
- jmp da14 ;another operand (but no comma)
-
- dop50: jmp da21 ;end of list
-
- ; ST(I) (OP_STI).
-
- dop51: mov al,regmem
- and al,7
- xchg ax,bx ;mov bx,ax
- mov ax,'TS'
- stosw ;store ST(bl)
- mov al,'('
- stosb
- mov ax,')0'
- or al,bl
- stosw
- ret
-
- ; CRx (OP_CR).
-
- dop52: mov bx,'RC'
- call getregmem_r
- cmp al,4
- ja disbad4 ;if too large
- jne dop52a
- mov dismach,5 ;CR4 is new to the 586
- dop52a: cmp index,SPARSE_BASE+22h
- jne dop55 ;if not MOV CRx,xx
- cmp al,1
- jne dop55 ;if not CR1
-
- disbad4:jmp disbad ;can't MOV CR1,xx
-
- ; DRx (OP_DR).
-
- dop53: call getregmem_r
- mov bx,'RD'
- mov cx,-1 ;no max or illegal value
- jmp short dop55
-
- ; TRx (OP_TR).
-
- dop54: call getregmem_r
- cmp al,3
- jb disbad ;if too small
- cmp al,6
- jae dop54a ;if TR6-7
- mov dismach,4 ;TR3-5 are new to the 486
- dop54a: mov bx,'RT'
-
- dop55: xchg ax,bx
- stosw ;store XX
- xchg ax,bx
- or al,'0'
- stosb
- ret
-
- ; Segment register (OP_SEGREG).
-
- dop56: call getregmem_r
- cmp al,6
- jae disbad ;if not a segment register
- cmp al,2
- je dop57 ;if SS
- and disflags,not DIS_F_REPT ;clear flag: don't repeat
- dop57: cmp al,4
- jb dop57a ;if not FS or GS
- mov dismach,3 ;(no new 486-686 instructions involve seg regs)
- dop57a: add al,16
- jmp dop35 ;go print it out
-
- ; Sign-extended immediate byte (OP_IMMS8).
-
- dop58: call disgetbyte
- cmp al,0
- xchg ax,bx ;mov bl,al
- mov al,'+'
- jge dop58a ;if >= 0
- neg bl
- mov al,'-'
- dop58a: stosb
- xchg ax,bx ;mov al,bl
- jmp short dop59a ;call hexbyte and return
-
- ; Immediate byte (OP_IMM8).
-
- dop59: call disgetbyte
- dop59a: jmp hexbyte ;call hexbyte and return
-
- ; Show ECX if it's a 32-bit operand.
-
- dop59e: call dischk32d
- jz dop60a ;if not 32 bit instruction
- mov al,1
- jmp dop33a ;print out register ECX and return
-
- ; Set flag to always show size (OP_SHOSIZ).
-
- dop60: or disflags,DIS_I_SHOWSIZ
- dop60a: pop ax ;discard return address
- jmp da14 ;next...
-
- disbad: mov sp,savesp2 ;pop junk off stack
- mov dis_n,0
- mov word preflags,0 ;clear preflags and preused
- mov rmsize,80h ;don't display any memory
- mov word dismach,0 ;forget about the machine type
- and disflags,not DIS_I_SHOW ;and flags
- call disgetbyte
- mov di,offset prefixlist
- mov cx,10
- repne scasb
- je dbad1 ;if it's a named prefix
- dec dis_n
- mov bx,MNEM_DB ;offset of 'DB' mnemonic
- mov si,OPLIST_Z ;this says OP_8+OP_IMM
- jmp da13
-
- dbad1: or disflags,DIS_I_UNUSED ;print special flag
- mov bx,9
- sub bx,cx
- shl bx,1
- cmp bx,12
- jb dbad2 ;if SEG directive
- mov bx,prefixmnem[bx-12]
- mov si,OPTYPES_BASE
- jmp da13
-
- dbad2: lea si,[bx+OPLIST_ES]
- mov bx,MNEM_SEG
- jmp da13
-
- ; GETREGMEM_R - Get the reg part of the reg/mem part of the instruction
- ; Uses CL
-
- getregmem_r:
- call getregmem
- mov cl,3
- shr al,cl
- and al,7
- ret
-
- ; GETREGMEM - Get the reg/mem part of the instruction
-
- getregmem:
- test preused,GOTREGM
- jnz grm1 ;if we have it already
- or preused,GOTREGM
- call disgetbyte ;get the byte
- mov regmem,al ;save it away
-
- grm1: mov al,regmem
- ret
-
- ; SHOWOP Show the op code
- ; Entry SI Null-terminated string containing the op mnemonic
- ; Exit DI Address of next available byte in output line
- ; (>= offset line_out + 32 due to padding)
- ; Uses AL
-
- showop:
- mov di,offset line_out+24
- call showstring
- mov al,' '
- so1: stosb
- cmp di,offset line_out+32
- jb so1
- ret
-
- ; SHOWSEG - Show the segment descriptor in SEGMNT
- ; Entry DI Where to put it
- ; Exit DI Updated
- ; Uses AX, BX
-
- showseg:
- mov al,segmnt ;segment number
- cbw
- shl ax,1
- xchg ax,bx ;mov bx,ax
- mov ax,segrgnam[bx] ;get register name
- stosw
- ret
-
- ; SHOWSIZE - Print a description of the size
- ; Entry AH >0 for DWORD, =0 for WORD, <0 for BYTE
- ; Uses AX
-
- ; SHOWPTR - Print " PTR "
- ; Uses AX
-
- ; SHOWDWD - Print "DWORD PTR"
- ; Uses AX
-
- showsize:
- mov rmsize,ah ;save r/m size
- mov sizeloc,di ;save where we're putting this
- cmp ah,0
- jge ssz1 ;if word or dword
- mov ax,'YB'
- stosw
- mov ax,'ET'
- jmp short ssz3
-
- ssz1: je ssz2 ;if word
- showdwd:mov al,'D'
- stosb
- ssz2: mov ax,'OW'
- stosw
- mov ax,'DR'
- ssz3: stosw
- showptr:mov ax,'P '
- stosw
- mov ax,'RT'
- stosw
- mov al,' '
- stosb
- ret
-
- ; DISP32 - Print 32-bit displacement for addressing modes.
- ; Entry None
- ; Exit None
- ; Uses AX
-
- disp32: call disgetword
- push ax
- call disgetword
- call hexword
- pop ax
- call hexword
- ret
-
- ; SHOWREG16 - Show 16-bit register name.
- ; Entry AL register number (0-7)
- ; Exit None
- ; Uses AX
-
- showreg16:
- cbw
- shl ax,1
- xchg ax,bx
- push ax
- mov ax,rgnam16[bx]
- stosw
- pop ax
- xchg ax,bx
- ret
-
- ; SHOWMACH - Return string "[needs math coprocessor]", etc.
- ; Exit si Address of string
- ; cx Length of string, or 0 if not needed
- ; Uses al, di
-
- showmach:
- mov si,offset needsmsg ;candidate message
- test dmflags,DM_COPR
- jz sm1 ;if not a coprocessor instruction
- mov byte [si+9],'7' ;change message text
- mov al,mach_87
- cmp has_87,0
- jnz sm2 ;if it has a coprocessor
- mov al,machine
- cmp al,dismach
- jb sm3 ;if we display the message
- mov si,offset needsmath ;print this message instead
- mov cx,needsmath_L
- ret
-
- sm1: mov byte [si+9],'6' ;reset message text
- mov al,machine
- sm2: cmp al,dismach
- jae sm4 ;if no message (so far)
- sm3: mov al,dismach
- add al,'0'
- mov [si+7],al
- mov cx,needsmsg_L ;length of the message
- ret
-
- ; Check for obsolete instruction.
-
- sm4: mov si,offset obsolete ;candidate message
- mov ax,[di-2] ;get info on this instruction
- mov cx,5
- repne scasw
- jne sm5 ;if no matches
- mov di,offset obsmach + 5 - 1
- sub di,cx
- xor cx,cx ;clear CX: no message
- mov al,mach_87
- cmp al,[di]
- jle sm5 ;if this machine is OK
- mov cx,obsolete_L
- sm5: ret
-
- ; DISGETBYTE - Get byte for disassembler.
- ; Entry None
- ; Exit AL Next byte in instruction stream
- ; Uses None
-
- disgetbyte:
- push si ;save si
- lds si,u_addr
- add si,cs:dis_n ;index to the right byte
- lodsb ;get the byte
- pop si ;restore things
- push cs
- pop ds
- inc dis_n ;indicate that we've gotten this byte
- ret
-
- ; DISGETWORD - Get word for disassembler.
- ; Entry None
- ; Exit AX Next word
- ; Uses None
-
- disgetword:
- push si ;save si
- lds si,u_addr
- add si,cs:dis_n ;index to the right byte
- lodsw ;get the byte
- pop si ;restore things
- push cs
- pop ds
- add dis_n,2 ;indicate that we've gotten this byte
- ret
-
- ; DISSHOWBYTES - Show bytes for the disassembler.
- ; Entry BX Number of bytes (must be > 0)
- ; Exit u_addr updated
- ; Uses BX, SI.
-
- disshowbytes:
- lds si,u_addr
- dsb1: lodsb
- call hexbyte
- dec bx
- jnz dsb1
- push cs
- pop ds
- mov u_addr,si
- ret
-
- ; MOVEOVER - Move the line to the right.
- ; Entry DI Last address + 1 of line so far
- ; Exit CX Number of bytes to move
- ; DI Updated
- ; Uses SI
-
- moveover:
- cmp sizeloc,0
- je mo1 ;if sizeloc not saved
- add sizeloc,cx
-
- mo1: mov si,di
- add di,cx
- mov cx,di
- sub cx,offset line_out+24
- push di
- std
- dec si
- dec di
- rep movsb
- pop di
- cld
- ret
-
- ; DISCHK32D - Check for 32 bit operand size prefix.
-
- dischk32d:
- or preused,PRE32D
- test preflags,PRE32D
- ret
-
- ; DUMPREGS - Dump registers.
-
- dumpregs:mov si,offset regs
- mov bx,offset regnames
- mov di,offset line_out
- mov cx,8
- call dmpr1 ;print first row
- push bx
- call trimputs
- pop bx
- mov di,offset line_out
- mov cl,5
- call dmpr1
- mov al,' ' ;add a space
- stosb
- call dmpflags
- call trimputs
- mov ax,reg_ip
- mov di,offset u_addr
- stosw
- mov ax,reg_cs
- stosw
- mov disflags,DIS_F_REPT + DIS_F_SHOW
- call disasm
- mov ax,reg_ip
- mov u_addr,ax
- ret
-
- ; Function to print multiple register entries.
-
- dmpr1: mov ax,[bx]
- inc bx
- inc bx
- stosw
- mov al,'='
- stosb
- lodsw
- push cx
- call hexword
- pop cx
- mov ax,' '
- stosw
- loop dmpr1
- ret
-
- ; DMPFLAGS - Dump flags output.
-
- dmpflags:
- mov bx,flags
- mov si,offset flgbits
- mov cx,8
- dmpf1: mov ax,[si+16]
- test bx,[si]
- jz dmpf2 ;if not asserted
- mov ax,[si+32]
- dmpf2: stosw
- mov al,' '
- stosb
- inc si
- inc si
- loop dmpf1
- ret
-
- flgbits dw 800h,400h,100h,80h,40h,10h,4,1
- flgnams dw 'VN','PU','ID','LP','ZN','AN','OP','CN'
- flgnons dw 'VO','ND','IE','GN','RZ','CA','EP','YC'
-
- ; SHOWSTRING - Print nonempty null-terminated string.
-
- showstring:
- lodsb
- sstr1: stosb
- lodsb
- cmp al,0
- jne sstr1
- ret
-
- ; HEXWORD - Print hex word (in AX).
- ; HEXBYTE - Print hex byte (in AL).
- ; HEXNYB - Print hex digit.
- ; Uses al,cl.
-
- hexword:
- push ax
- mov al,ah
- call hexbyte
- pop ax
-
- hexbyte:
- push ax
- mov cl,4
- shr al,cl
- call hexnyb
- pop ax
-
- hexnyb:
- and al,0fh
- add al,90h ;these four instructions change to ascii hex
- daa
- adc al,40h
- daa
- stosb
- ret
-
- ; TAB_TO - Space fill until reaching the column indicated by AX.
- ; (Print a new line if necessary.)
-
- tab_to: push ax
- sub ax,di
- ja tabto1 ;if there's room on this line
- call trimputs
- mov di,offset line_out
-
- tabto1: pop cx
- sub cx,di
- mov al,' '
- rep stosb ;space fill to the right end
- ret
-
- ; TRIMPUTS - Trim excess blanks from string and print (with CR/LF).
- ; PUTSLINE - Add CR/LF to string and print it.
- ; PUTS - Print string through DI.
-
- trimputs:
- dec di
- cmp byte [di],' '
- je trimputs
- inc di
-
- putsline:
- mov ax,LF * 256 + CR
- stosw
-
- puts: mov ah,40h ;write to file
- mov bx,1
- mov cx,di
- mov dx,offset line_out
- sub cx,dx
- int 21h
- ret
-
- ; I/O buffers. (End of permanently resident part.)
-
- end1 db
-
- line_in db 255,0,CR ;length = 257
- line_out equ end1+258 ;length = 1 + 263
- real_end equ end1+258+264
- staksiz equ 200h
-
- ;lots of bytes follow this
-
- ;---------------------------------------
- ; Initialization second phase.
- ;---------------------------------------
-
- intwo: mov byte line_out-1,'0' ;initialize line_out
-
- ; Shrink DEBUG.
-
- mov bx,offset real_end + staksiz + 15
- and bx,not 15
- mov sp,bx
- xor ax,ax
- push ax ;just in case
- mov savesp,sp ;save SP
- mov ah,4ah ;SETBLOCK
- mov cl,4
- shr bx,cl
- int 21h ;shrink DEBUG now
-
- ; Load the program.
-
- call ll2 ;load the program
- jmp cmd3 ;done
-
- ;---------------------------------------
- ; Debug initialization code.
- ;---------------------------------------
-
- even
- fp_status dw 5a5ah ;FPU status word
-
- inttab dw int0 ;table of interrupt initialization stuff
- db 0
- dw int1
- db 1
- dw int3
- db 3
- dw debug22
- db 22h
-
- initcode:
- cld
-
- mov execblk+4,cs ;set up parameter block for exec command
- mov execblk+8,cs
- mov execblk+12,cs
-
- ; Check for console input vs. input from a file or other device.
-
- mov ax,4400h ;IOCTL--get info
- xor bx,bx
- int 21h
- jc init1 ;if not device
- and dl,81h ;check if console device
- cmp dl,81h
- jne init1 ;if not the console input
- mov notatty,0 ;it _is_ a tty
-
- ; Compute the length of the environment (for future reference).
-
- init1: mov es,[2ch] ;environment segment
- xor di,di
- mov al,0
- mov cx,-1
- init2: scasb
- jz init3 ;if empty string
- repne scasb ;skip string
- jmp init2
-
- init3: mov envlen,di
- push cs
- pop es
-
- mov ax,3000h ;check DOS version
- int 21h
- xchg al,ah
- cmp ax,31fh
- jb init4 ;if early, then don't use new INT 25h method
- inc usepacket
-
- ; Determine the processor type. This is adapted from code in the
- ; Pentium<tm> Family User's Manual, Volume 3: Architecture and
- ; Programming Manual, Intel Corp., 1994, Chapter 5. That code contains
- ; the following comment:
-
- ; This program has been developed by Intel Corporation.
- ; Software developers have Intel's permission to incorporate
- ; this source code into your software royalty free.
-
- ; Intel 8086 CPU check.
- ; Bits 12-15 of the FLAGS register are always set on the 8086 processor.
- ; Probably the 186 as well.
-
- init4: pushf ;get original flags into AX
- pop ax
- mov cx,ax ;save them
- and ax,0fffh ;clear bits 12-15
- push ax ;save new flags value on stack
- popf ;replace current flags value
- pushf ;get new flags
- pop ax ;store new flags in AX
- and ax,0f000h ;check to see whether bits 12-15 are set
- cmp ax,0f000h
- je init6 ;if 8086 or 80186 (can't tell them apart)
-
- ; Intel 286 CPU check.
- ; Bits 12-15 of the flags register are always clear on the
- ; Intel 286 processor in real-address mode.
-
- or cx,0f000h ;try to set bits 12-15
- push cx ;save new flags value on stack
- popf ;replace current flags value
- pushf ;get new flags
- pop ax ;store new flags in AX
- test ax,0f000h ;if bits 12-15 clear, CPU = 80286
- mov machine,2
- jz init6 ;if 80286
-
- ; Intel 386 CPU check.
- ; The AC bit, bit #18, is a new bit introduced in the EFLAGS
- ; register on the Intel486 DX cpu to generate alignment faults.
- ; This bit cannot be set on the Intel386 CPU.
-
- ; It is now safe to use 32-bit opcode/operands.
-
- inc machine
- mov bx,sp ;save current stack pointer to align
- and sp,not 3 ;align stack to avoid AC fault
- db 66h ;32-bit data prefix
- pushf ;push original EFLAGS
- db 66h
- pop ax ;get original EFLAGS
- db 66h
- mov cx,ax ;save original EFLAGS in CX
- db 66h
- db 35h,0,0,4,0 ;flip (XOR) AC bit in EFLAGS
- db 66h
- push ax ;put new EFLAGS value on stack
- db 66h
- popf ;replace EFLAGS value
- db 66h
- pushf ;get new EFLAGS
- db 66h
- pop ax ;store new EFLAGS value in EAX
- db 66h
- cmp ax,cx
- jz init5 ;if 80386 CPU
-
- ; Intel486 DX CPU, Intel487 SX NDP, and Intel486 SX CPU check.
- ; Checking for ability to set/clear ID flag (bit 21) in EFLAGS
- ; which indicates the presence of a processor with the ability
- ; to use the CPUID instruction.
-
- inc machine ;it's a 486
- db 66h
- mov ax,cx ;get original EFLAGS
- db 66h
- db 35h,0,0,20h,0 ;flip (XOR) ID bit in EFLAGS
- db 66h
- push ax ;save new EFLAGS value on stack
- db 66h
- popf ;replace current EFLAGS value
- db 66h
- pushf ;get new EFLAGS
- db 66h
- pop ax ;store new EFLAGS in EAX
- db 66h
- cmp ax,cx ;check if it's changed
- je init5 ;if it's a 486 (can't toggle ID bit)
- db 66h
- push cx
- db 66h
- popf ;restore AC bit in EFLAGS first
- mov sp,bx ;restore original stack pointer
-
- ; Execute CPUID instruction.
-
- db 66h
- xor ax,ax ;set up input for CPUID instruction
- db 0fh,0a2h ;CPUID instruction
- db 66h
- db 83h,0f8h,1 ;cmp eax,1
- jl init6 ;if 1 is not a valid input value for CPUID
- db 66h
- xor ax,ax ;otherwise, run CPUID with ax = 1
- db 66h
- inc ax
- db 0fh,0a2h ;CPUID instruction
- mov al,ah
- and al,0fh ;bits 8-11 are the model number
- mov machine,al ;save it
- jmp short init6 ;don't restore SP
-
- init5: db 66h
- push cx
- db 66h
- popf ;restore AC bit in EFLAGS first
- mov sp,bx ;restore original stack pointer
-
- ; Next determine the type of FPU in a system and set the mach_87
- ; variable with the appropriate value. All registers are used by
- ; this code; none are preserved.
-
- ; Coprocessor check.
- ; The algorithm is to determine whether the floating-point
- ; status and control words can be written to. If not, no
- ; coprocessor exists. If the status and control words can be
- ; written to, the correct coprocessor is then determined
- ; depending on the processor ID. The Intel386 CPU can
- ; work with either an Intel 287 NDP or an Intel387 NDP.
- ; The infinity of the coprocessormust be checked
- ; to determine the correct coprocessor ID.
-
- init6: mov al,machine
- mov mach_87,al ;by default, set mach_87 to machine
-
- fninit ;reset FP status word
- mov fp_status,5a5ah ;restore temp word to nonzero value
- fnstsw fp_status ;save FP status word
- mov ax,fp_status ;check FP status word
- cmp al,0
- jne init7 ;if no FPU present
-
- fnstcw fp_status ;save FP control word
- mov ax,fp_status ;check FP control word
- and ax,103fh ;see if selected parts look OK
- cmp ax,3fh
- jne init7 ;if no FPU present
- inc has_87 ;there's an FPU
-
- ; If we're using a 386, check for 287 vs. 387 by checking whether
- ; +infinity = -infinity.
-
- cmp machine,3
- jne init7 ;if not a 386
- fld1 ;must use default control from FNINIT
- fldz ;form infinity
- fdiv ;1 / 0 = infinity
- fld st ;form negative infinity
- fchs
- fcompp ;see if they are the same and remove them
- fstsw fp_status ;look at status from FCOMPP
- mov ax,fp_status
- sahf
- jnz init7 ;if they are different, then it's a 387
- dec mach_87 ;otherwise, it's a 287
-
- ; ||| Interpret switches and erase them from the command line.
-
- init7: mov ax,3700h ;get switch character
- int 21h
- mov switchar,dl
- cmp dl,'/'
- jne init8
- mov swch1,dl
- init8: mov si,81h
- init9: lodsb
- cmp al,' '
- je init9
- cmp al,TAB
- je init9
-
- ; Feed the remaining command line to the 'n' command.
-
- dec si
- lodsb
- call nn ;process the rest of the line
-
- ; Save some interrupt vectors.
-
- mov cx,2
- mov di,offset intsave
- mov ax,3500h ;get interrupt vector 0
- int 21h
- mov intsave,bx
- mov intsave+2,es
- mov ax,3501h ;get interrupt vector 1
- int 21h
- mov intsave+4,bx
- mov intsave+6,es
- mov ax,3503h ;get interrupt vector 3
- int 21h
- mov intsave+8,bx
- mov intsave+10,es
- push ds
- pop es
-
- ; Set up interrupt vectors.
-
- mov cx,4
- mov si,offset inttab
- init10: lodsw ;get address
- xchg ax,dx ;mov dx,ax
- mov ah,25h ;set interrupt vector
- lodsb ;interrupt number
- int 21h
- loop init10
-
- ; Save and modify termination address and the parent PSP field.
-
- mov si,0ah
- mov di,offset psp22
- movsw
- movsw
- mov word [si-4],offset debug22
- mov [si-2],cs
- mov si,16h
- movsw
- mov [si-2],cs
-
- ; Done with the first phase.
-
- jmp intwo ;jump to second phase
-