home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / DEBUG095.ZIP / debug.a86 next >
Encoding:
Text File  |  1997-08-06  |  159.2 KB  |  6,767 lines

  1. ;    DEBUG.A86    A86 assembler source for a clone of DEBUG.COM
  2. ;            Copyright 1995-1997 Paul Vojta.
  3.  
  4. ;    To do:
  5. ;        help message
  6. ;        /?
  7. ;        x*
  8. ;        *.HEX files
  9. ;        `l' and `w' commands with addresses
  10. ;        < and > and >>
  11. ;        MMX instructions
  12.  
  13. BS    equ    8
  14. TAB    equ    9
  15. LF    equ    10
  16. CR    equ    13
  17. TOLOWER    equ    20h
  18. TOUPPER    equ    0dfh
  19. TOUPPER_W equ    0dfdfh
  20.  
  21. LINE_IN_LEN equ    257        ;length of line_in (including header stuff)
  22.  
  23.     jmp    initcode
  24.  
  25. cmdlist    dw    aa,error,cc,ddd,ee,ff,gg,hh,ii,error,error,ll,mm,nn,oo
  26.     dw    pp,qq,rr,sss,tt,uu,error,ww,xx
  27.  
  28. savesp    dw    0        ;save stack pointer
  29. errret    dw    0        ;return here if error
  30. run_sp    dw    0        ;stack pointer when running
  31. spadjust dw    0        ;adjust sp by this amount for save
  32. psp    dw    0        ;program segment prefix
  33. blk1    dw    0        ;blocks to free on program termination
  34. blk2    dw    0
  35. running    db    0        ;if there is a running child process
  36. run2324    dw    0,0,0,0        ;interrupt vectors 23 and 24 (when running)
  37. sav2324    dw    0,0,0,0        ;interrupt vectors 23 and 24 (ours)
  38. hakstat    db    0        ;whether we have hacked the vectors or not
  39. psp22    dw    0,0        ;original terminate address in the PSP
  40. parent    dw    0        ;original PSP of process parent (must be next)
  41. envlen    dw    0        ;length of DEBUG's environment
  42. machine    db    0        ;type of this processor
  43. has_87    db    0        ;if there is a math coprocessor present
  44. mach_87    db    0        ;type of coprocessor present
  45. notatty    db    LF        ;if standard input is from a file
  46. switchar db    0        ;switch character
  47. swch1    db    ' '        ;switch character if it's a slash
  48. promptlen dw    0        ;length of prompt
  49. bufnext    dw    line_in+2    ;address of next available character
  50. bufend    dw    line_in+2    ;address + 1 of last valid character
  51.  
  52. a_addr    dw    0,0        ;address for next 'a' command
  53. d_addr    dw    0,0        ;address of last `d' command; must follow a_addr
  54. u_addr    dw    0,0        ;address of last `u' command; must follow d_addr
  55. eqflag    db    0        ;flag indicating presence of `=' operand
  56. eqladdr    dw    0,0        ;address of `=' operand in G or T command
  57. run_cs    dw    0        ;save original CS when running
  58. run_int    dw    0        ;interrupt type that stopped the running
  59.  
  60. intsave    dw    0,0        ;save area for interrupt vectors 0, 1, and 3
  61.     dw    0,0
  62.     dw    0,0
  63.  
  64. ;    Parameter block for exec call.
  65.  
  66. execblk    dw    0        ;(0) copy the parent's environment
  67.     dw    0,0        ;(2) address of command tail to copy
  68.     dw    5ch,0        ;(6) address of first FCB to copy
  69.     dw    6ch,0        ;(10) address of second FCB to copy
  70.     dw    0,0        ;(14) initial SS:SP
  71.     dw    0,0        ;(18) initial CS:IP
  72.  
  73. ;    Register save area.
  74.  
  75. regs    dw
  76. reg_ax    dw    0        ;ax
  77. reg_bx    dw    0        ;bx
  78. reg_cx    dw    0        ;cx
  79. reg_dx    dw    0        ;dx
  80. reg_sp    dw    0        ;sp
  81. reg_bp    dw    0        ;bp
  82. reg_si    dw    0        ;si
  83. reg_di    dw    0        ;di
  84. reg_ds    dw    0        ;ds
  85. reg_es    dw    0        ;es
  86. reg_ss    dw    0        ;ss
  87. reg_cs    dw    0        ;cs
  88. reg_ip    dw    100h        ;ip
  89. flags    dw    200h        ;flags (interrupts enabled)
  90.  
  91. regnames dw    'XA','XB','XC','XD','PS','PB','IS','ID','SD','SE'
  92.     dw    'SS','SC','PI'    ;backwards ... because ...
  93.  
  94. segletrs db    'd','e','s','c'
  95.  
  96. ;    Instruction set information needed for the 'p' command.
  97.  
  98. ppbytes    db    66h,67h,26h,2eh,36h,3eh,64h,65h,0f2h,0f3h    ;prefixes
  99.     db    0ach,0adh,0aah,0abh,0a4h,0a5h    ;lods,stos,movs
  100.     db    0a6h,0a7h,0aeh,0afh        ;cmps,scas
  101.     db    6ch,6dh,6eh,6fh            ;ins,outs
  102.     db    0cch,0cdh            ;int instructions
  103.     db    0e0h,0e1h,0e2h        ;loop instructions
  104.     db    0e8h            ;call rel16/32
  105.     db    09ah            ;call far seg16:16/32
  106. ;    (This last one is done explicitly by the code.)
  107. ;    db    0ffh            ;ff/2 or ff/3:  indirect call
  108.  
  109. ;    Info for the above, respectively.
  110. ;    80h = prefix; 82h = operand size prefix; 81h = address size prefix.
  111. ;    If the high bit is not set, the next highest bit (40h) indicates that
  112. ;    the instruction size depends on whether there is an address size prefix,
  113. ;    and the remaining bits tell the number of additional bytes in the
  114. ;    instruction.
  115.  
  116. ppinfo    db    82h,81h,80h,80h,80h,80h,80h,80h,80h,80h
  117.     db    0,0,0,0,0,0
  118.     db    0,0,0,0
  119.     db    0,0,0,0
  120.     db    0,1
  121.     db    1,1,1
  122.     db    42h
  123.     db    44h
  124.  
  125. PPLEN    equ    31        ;size of the above table
  126.  
  127. ;    Strings.
  128.  
  129. prompt1    db    '='        ;main prompt
  130. prompt2    db    ':'        ;prompt for register value
  131.  
  132. helpmsg    db    'This is the help message.  I''ll think of something to',CR,LF
  133.     db    'put here sometime.',CR,LF,'$'
  134.  
  135. notyet    db    'The extended memory commands have not been installed yet.'
  136.     db    CR,LF,'$'
  137.  
  138. errcarat db    '^ Error',CR,LF,'$'
  139.  
  140. dskerrs dw    dskerr0,dskerr1,dskerr2,dskerr3,dskerr4,dskerr9,dskerr6,dskerr7
  141.     dw    dskerr8,dskerr9,dskerra,dskerrb,dskerrc
  142. dskerr0    db    'Write protect error',0
  143. dskerr1    db    'Unknown unit error',0
  144. dskerr2    db    'Drive not ready',0
  145. dskerr3    db    'Unknown command',0
  146. dskerr4    db    'Data error (CRC)',0
  147. dskerr6    db    'Seek error',0
  148. dskerr7    db    'Unknown media type',0
  149. dskerr8    db    'Sector not found',0
  150. dskerr9    db    'Unknown error',0
  151. dskerra    db    'Write fault',0
  152. dskerrb    db    'Read fault',0
  153. dskerrc    db    'General failure',0
  154. reading    db    ' read',0
  155. writing    db    ' writ',0
  156. drive    db    'ing drive '
  157. driveno    db    'x',0
  158. msg8088    db    '8086/88',0
  159. msgx86    db    'x86',0
  160. no_copr    db    ' without coprocessor',0
  161. has_copr db    ' with coprocessor',0
  162. has_287    db    ' with 287',0
  163. unused    db    ' (unused)',0
  164. needsmsg db    '[needs x86]'
  165. needsmsg_L equ    11
  166. needsmath db    '[needs math coprocessor]'
  167. needsmath_L equ    24
  168. obsolete db    '[obsolete]'
  169. obsolete_L equ    10
  170. int0msg    db    'Divide error.',CR,LF,'$'
  171. int1msg    db    'Unexpected single-step interrupt.',CR,LF,'$'
  172. int3msg    db    'Unexpected breakpoint interrupt.',CR,LF,'$'
  173. progtrm    db    'Program terminated normally.',CR,LF,'$'
  174. nowhexe    db    'EXE and HEX files cannot be written.',CR,LF,'$'
  175. wwmsg1    db    'Writing $'
  176. wwmsg2    db    ' bytes.',CR,LF,'$'
  177. diskful    db    'Disk full.',CR,LF,'$'
  178. wwerr1    db    'Error $'
  179. wwerr2    db    ' opening file.',CR,LF,'$'
  180. doserr2    db    'File not found.',CR,LF,'$'
  181. doserr3    db    'Path not found.',CR,LF,'$'
  182. doserr5    db    'Access denied.',CR,LF,'$'
  183. doserr8    db    'Insufficient memory.',CR,LF,'$'
  184. psperr    db    'Error in create-psp call.',CR,LF,'$'
  185.  
  186. ;    Equates for instruction operands.
  187. ;    First the sizes.
  188.  
  189. OP_ALL    equ    40h        ;byte/word/dword operand (could be 30h but ...)
  190. OP_1632    equ    50h        ;word or dword operand
  191. OP_8    equ    60h        ;byte operand
  192. OP_16    equ    70h        ;word operand
  193. OP_32    equ    80h        ;dword operand
  194.  
  195. OP_SIZE    equ    OP_ALL        ;the lowest of these
  196.  
  197. ;    These operand types need to be combined with a size.
  198.  
  199. OP_IMM    equ    0        ;immediate
  200. OP_RM    equ    2        ;reg/mem
  201. OP_M    equ    4        ;mem (but not reg)
  202. OP_R_MOD equ    6        ;register, determined from MOD R/M part
  203. OP_MOFFS equ    8        ;memory offset; e.g., [1234]
  204. OP_R    equ    10        ;reg part of reg/mem byte
  205. OP_R_ADD equ    12        ;register, determined from instruction byte
  206. OP_AX    equ    14        ;al or ax or eax
  207.  
  208. ;    These don't need a size.
  209.  
  210. OP_M64    equ    2        ;qword memory
  211. OP_MFLOAT equ    4        ;float memory
  212. OP_MDOUBLE equ    6        ;double-precision floating memory
  213. OP_M80    equ    8        ;tbyte memory
  214. OP_MXX    equ    10        ;memory (size unknown)
  215. OP_FARMEM equ    12        ;far memory
  216. OP_FARP    equ    14        ;far pointer
  217. OP_REL8    equ    16        ;byte address relative to IP
  218. OP_REL1632 equ    18        ;word or dword address relative to IP
  219. OP_1CHK    equ    20        ;check for ST(1)
  220. OP_STI    equ    22        ;ST(I)
  221. OP_CR    equ    24        ;CRx
  222. OP_DR    equ    26        ;DRx
  223. OP_TR    equ    28        ;TRx
  224. OP_SEGREG equ    30        ;segment register
  225. OP_IMMS8 equ    32        ;sign extended immediate byte
  226. OP_IMM8    equ    34        ;immediate byte (other args may be (d)word)
  227. OP_ECX    equ    36        ;ECX if 32-bit operands; otherwise nothing
  228. OP_SHOSIZ equ    38        ;set flag to always show the size
  229. OP_1    equ    40        ;1 (string ops from here on)
  230. OP_3    equ    42        ;3
  231. OP_DX    equ    44        ;DX
  232. OP_CL    equ    46        ;CL
  233. OP_ST    equ    48        ;ST (top of coprocessor stack)
  234. OP_CS    equ    50        ;CS
  235. OP_DS    equ    52        ;DS
  236. OP_ES    equ    54        ;ES
  237. OP_FS    equ    56        ;FS
  238. OP_GS    equ    58        ;GS
  239. OP_SS    equ    60        ;SS
  240.  
  241. ;    Instructions that have an implicit operand subject to a segment override
  242. ;    (outs, movs, cmps, lods, xlat).
  243.  
  244. prfxtab    db    06eh,06fh,0a4h,0a5h,0a6h,0a7h,0ach,0adh,0d7h
  245. P_LEN    equ    9
  246.  
  247. ;    Instructions that can be used with REP/REPE/REPNE.
  248.  
  249. replist    db    06ch,06eh,0a4h,0aah,0ach        ;REP
  250.     db    0a6h,0aeh                ;REPE/REPNE
  251.  
  252. ;-@@-@@-@@-Do not edit these tables!  They have been automatically generated.
  253.  
  254. ;    Main data table for the assembler.
  255.  
  256. asmtab    db    16,139,255,248,64,55,255,248,63,234,255,18,243,255,6,5
  257.     db    245,173,221,245,176,68,245,4,212,5,111,255,1,53,245,173
  258.     db    67,245,175,170,245,0,4,0,159,255,10,213,245,174,119,245
  259.     db    176,222,245,9,164,10,63,255,240,29,205,255,239,29,129,255
  260.     db    241,133,148,255,241,133,225,255,249,242,137,49,255,241,126,17
  261.     db    241,179,79,255,245,241,133,73,245,241,180,54,255,245,241,130
  262.     db    225,245,241,179,233,255,245,241,128,121,245,241,179,156,255,69
  263.     db    212,181,59,181,109,46,95,255,249,45,184,255,74,152,255,75
  264.     db    204,255,75,50,255,240,78,206,255,73,177,255,244,98,99,255
  265.     db    244,97,47,255,244,96,226,255,244,98,22,255,244,96,226,255
  266.     db    244,97,124,255,244,100,203,255,244,100,49,255,244,99,228,255
  267.     db    244,100,126,255,244,98,22,255,244,96,226,255,244,97,47,255
  268.     db    244,98,99,255,244,97,47,255,244,97,201,255,244,100,126,255
  269.     db    244,99,228,255,244,100,49,255,244,100,203,255,244,96,149,255
  270.     db    244,99,151,255,244,98,253,255,244,97,201,255,244,96,72,255
  271.     db    244,99,74,255,244,99,74,255,244,99,151,255,244,98,176,255
  272.     db    244,97,124,255,18,13,175,94,177,197,16,220,17,119,255,49
  273.     db    238,255,249,50,59,255,245,242,129,244,255,243,183,60,255,243
  274.     db    125,186,255,249,46,5,255,11,187,255,14,35,255,254,255,252
  275.     db    255,21,185,245,185,165,245,189,142,255,253,255,239,60,58,255
  276.     db    65,69,240,255,65,69,225,255,154,19,155,72,65,13,192,66
  277.     db    66,192,255,66,221,192,66,198,193,255,154,178,155,231,255,165
  278.     db    213,255,170,165,255,65,69,224,255,250,65,223,226,255,244,65
  279.     db    244,208,255,244,65,244,192,255,244,65,167,192,255,244,65,167
  280.     db    208,255,244,65,167,200,255,244,65,167,208,255,244,65,167,192
  281.     db    255,244,65,244,192,255,244,65,244,208,255,244,65,244,200,255
  282.     db    244,65,244,216,255,244,65,244,200,255,244,65,167,216,255,244
  283.     db    65,167,200,255,158,227,160,24,65,20,208,64,248,209,255,244
  284.     db    65,251,240,244,65,223,241,255,244,67,47,240,244,67,19,241
  285.     db    255,161,75,162,128,65,20,216,64,248,217,255,66,198,217,255
  286.     db    241,65,69,255,255,65,69,246,255,250,65,223,225,255,168,131
  287.     db    169,184,65,13,240,66,66,248,255,66,221,248,66,198,249,255
  288.     db    169,34,170,87,255,170,235,172,32,65,13,248,66,66,240,255
  289.     db    66,221,240,66,198,241,255,171,138,172,191,255,250,65,223,224
  290.     db    255,66,148,192,255,159,130,160,183,255,161,234,163,31,255,154
  291.     db    255,156,52,168,50,255,65,69,247,255,250,65,223,227,255,159
  292.     db    207,161,4,255,162,55,163,108,173,2,255,154,96,155,149,167
  293.     db    9,65,96,192,255,65,69,232,255,65,69,233,255,65,69,234
  294.     db    255,65,69,235,255,65,69,236,255,65,69,237,255,65,69,238
  295.     db    255,250,166,110,255,164,10,255,156,123,157,176,65,13,200,66
  296.     db    66,200,255,66,221,200,66,198,201,255,157,26,158,79,255,65
  297.     db    69,208,255,65,69,243,255,65,69,248,255,241,65,69,245,255
  298.     db    65,69,242,255,65,69,252,255,165,62,255,250,170,14,255,65
  299.     db    69,253,255,250,240,65,223,228,255,241,65,69,254,255,241,65
  300.     db    69,251,255,65,69,250,255,159,48,160,101,66,148,208,255,161
  301.     db    152,162,205,171,217,66,148,216,255,250,171,62,255,250,168,218
  302.     db    255,250,67,49,224,172,114,255,163,179,164,232,65,13,224,66
  303.     db    66,232,255,66,221,232,66,198,233,255,164,82,165,135,255,166
  304.     db    27,167,80,65,13,232,66,66,224,255,66,221,224,66,198,225
  305.     db    255,166,186,167,239,255,65,69,228,255,241,66,149,224,241,66
  306.     db    121,225,255,244,65,251,232,244,65,223,233,255,244,67,47,232
  307.     db    244,67,19,233,255,241,66,149,232,241,66,121,233,255,241,65
  308.     db    146,233,255,46,159,255,65,69,229,255,65,97,200,65,69,201
  309.     db    255,65,69,244,255,65,69,241,255,65,69,249,255,73,100,255
  310.     db    189,219,255,189,65,241,129,171,239,32,78,239,32,79,239,31
  311.     db    182,239,31,183,255,68,183,71,32,255,19,81,245,185,88,245
  312.     db    239,32,124,255,249,239,32,201,255,61,129,61,207,255,61,246
  313.     db    255,242,79,104,255,242,192,80,255,249,62,67,255,35,242,241
  314.     db    117,167,255,34,190,241,116,115,255,34,113,241,116,38,255,35
  315.     db    165,241,117,90,255,34,113,241,116,38,255,249,68,110,255,35
  316.     db    11,241,116,192,255,38,90,241,120,15,255,37,192,241,119,117
  317.     db    255,37,115,241,119,40,255,38,13,241,119,194,255,35,165,241
  318.     db    117,90,255,34,113,241,116,38,255,34,190,241,116,115,255,35
  319.     db    242,241,117,167,255,34,190,241,116,115,255,35,88,241,117,13
  320.     db    255,38,13,241,119,194,255,37,115,241,119,40,255,37,192,241
  321.     db    119,117,255,38,90,241,120,15,255,34,36,241,115,217,255,37
  322.     db    38,241,118,219,255,36,140,241,118,65,255,35,88,241,117,13
  323.     db    255,33,215,241,115,140,255,36,217,241,118,142,255,36,217,241
  324.     db    118,142,255,37,38,241,118,219,255,36,63,241,117,244,255,35
  325.     db    11,241,116,192,255,70,214,70,33,181,213,182,7,70,111,255
  326.     db    47,211,255,240,77,162,255,59,72,255,241,130,145,255,58,251
  327.     db    255,241,131,43,255,241,131,120,255,42,112,255,239,60,117,255
  328.     db    240,190,207,255,240,191,28,255,240,193,68,255,240,192,16,255
  329.     db    246,240,51,188,255,249,52,9,255,68,34,68,33,255,67,213
  330.     db    67,212,255,67,213,67,212,255,67,136,67,135,255,67,136,67
  331.     db    135,255,240,77,239,255,240,193,145,255,48,77,48,232,40,236
  332.     db    41,135,42,71,42,226,53,31,55,136,194,234,241,86,231,241
  333.     db    87,130,241,87,54,241,87,209,241,88,31,241,88,186,255,49
  334.     db    84,255,249,49,161,255,241,134,87,241,134,165,255,241,131,239
  335.     db    241,132,61,255,188,244,255,245,188,167,255,43,80,255,245,188
  336.     db    90,255,3,157,245,173,144,245,175,247,245,2,108,3,7,255
  337.     db    251,255,69,97,71,202,255,239,33,22,255,249,239,33,99,255
  338.     db    197,133,26,137,9,140,2,81,7,35,241,125,167,241,128,16
  339.     db    255,249,239,29,45,255,249,47,57,255,24,33,182,111,239,32
  340.     db    31,239,31,132,4,109,6,214,9,63,2,4,241,125,90,241
  341.     db    127,195,255,249,239,28,224,255,249,46,236,255,200,144,202,249
  342.     db    239,205,98,255,200,221,203,70,239,205,175,255,199,246,202,95
  343.     db    239,204,200,255,200,67,202,172,239,205,21,255,243,92,10,255
  344.     db    246,243,246,243,246,242,58,167,58,155,255,61,15,61,3,255
  345.     db    243,128,34,255,47,134,255,201,42,203,147,239,205,252,255,202
  346.     db    17,204,122,239,206,227,255,11,164,14,13,16,118,18,223,30
  347.     db    78,30,156,255,247,38,247,46,247,54,247,62,247,100,247,101
  348.     db    201,42,203,147,239,205,252,255,201,119,203,224,239,206,73,255
  349.     db    8,109,245,174,42,245,176,145,245,7,60,7,215,255,52,86
  350.     db    255,249,52,163,255,241,122,173,255,241,121,121,255,241,121,44
  351.     db    255,241,122,96,255,241,121,44,255,241,121,198,255,241,125,21
  352.     db    255,241,124,123,255,241,124,46,255,241,124,200,255,241,122,96
  353.     db    255,241,121,44,255,241,121,121,255,241,122,173,255,241,121,121
  354.     db    255,241,122,19,255,241,124,200,255,241,124,46,255,241,124,123
  355.     db    255,241,125,21,255,241,120,223,255,241,123,225,255,241,123,71
  356.     db    255,241,122,19,255,241,120,146,255,241,123,148,255,241,123,148
  357.     db    255,241,123,225,255,241,122,250,255,241,121,198,255,240,190,53
  358.     db    255,240,190,130,255,241,126,151,241,126,229,255,241,128,255,241
  359.     db    129,77,255,240,192,169,255,240,191,118,255,74,229,255,76,25
  360.     db    255,75,127,255,51,34,255,249,51,111,255,240,192,247,255,13
  361.     db    61,245,174,196,245,177,43,245,12,12,12,167,255,50,137,187
  362.     db    178,39,184,39,185,255,240,193,222,255,240,194,43,255,46,159
  363.     db    255,242,79,181,255,243,91,112,255,245,242,134,196,255,43,149
  364.     db    43,150,245,40,82,245,40,83,255,64,171,255,64,171,255,15
  365.     db    165,245,175,17,245,177,120,245,14,116,15,15,255
  366.  
  367. ;    Data on groups (for the assembler).
  368.  
  369. agroups    dw    131,128,442,255,455,254,246,257,256,198,143,208,210,192
  370.  
  371. ;    This is the list of assembler mnemonics.
  372.  
  373. mnlist    db    1,1,"AAA",0,1,4,"AAD",0,1,8,"AAM",0,1,12,"AAS",0
  374.     db    1,15,"ADC",0,1,29,"ADD",0,1,43,"AND",0,1,57,"ARPL",0
  375.     db    1,61,"BOUND",0,1,65,"BSF",0,1,69,"BSR",0
  376.     db    1,73,"BSWAP",0,1,78,"BT",0,1,85,"BTC",0,1,94,"BTR",0
  377.     db    1,103,"BTS",0,1,112,"CALL",0,1,122,"CBW",0,2,37,"CDQ",0
  378.     db    1,125,"CLC",0,1,128,"CLD",0,1,131,"CLI",0,1,134,"CLTS",0
  379.     db    1,138,"CMC",0,1,141,"CMOVA",0,1,145,"CMOVAE",0
  380.     db    1,149,"CMOVB",0,1,153,"CMOVBE",0,1,157,"CMOVC",0
  381.     db    1,161,"CMOVE",0,1,165,"CMOVG",0,1,169,"CMOVGE",0
  382.     db    1,173,"CMOVL",0,1,177,"CMOVLE",0,1,181,"CMOVNA",0
  383.     db    1,185,"CMOVNAE",0,1,189,"CMOVNB",0,1,193,"CMOVNBE",0
  384.     db    1,197,"CMOVNC",0,1,201,"CMOVNE",0,1,205,"CMOVNG",0
  385.     db    1,209,"CMOVNGE",0,1,213,"CMOVNL",0,1,217,"CMOVNLE",0
  386.     db    1,221,"CMOVNO",0,1,225,"CMOVNP",0,1,229,"CMOVNS",0
  387.     db    1,233,"CMOVNZ",0,1,237,"CMOVO",0,1,241,"CMOVP",0
  388.     db    1,245,"CMOVPE",0,1,249,"CMOVPO",0,1,253,"CMOVS",0
  389.     db    2,2,"CMOVZ",0,2,6,"CMP",0,2,17,"CMPSB",0
  390.     db    2,20,"CMPSD",0,2,21,"CMPSW",0,2,24,"CMPXCHG",0
  391.     db    2,29,"CMPXCHG8B",0,2,33,"CPUID",0,6,188,"CS",0
  392.     db    2,38,"CWD",0,1,121,"CWDE",0,2,41,"DAA",0,2,44,"DAS",0
  393.     db    2,47,"DB",0,2,49,"DD",0,2,51,"DEC",0,2,57,"DIV",0
  394.     db    6,192,"DS",0,2,60,"DW",0,2,62,"ENTER",0,6,186,"ES",0
  395.     db    2,66,"F2XM1",0,2,70,"FABS",0,2,74,"FADD",0
  396.     db    2,85,"FADDP",0,2,97,"FBLD",0,2,100,"FBSTP",0
  397.     db    2,103,"FCHS",0,2,107,"FCLEX",0,2,112,"FCMOVA",0
  398.     db    2,117,"FCMOVAE",0,2,122,"FCMOVB",0,2,127,"FCMOVBE",0
  399.     db    2,132,"FCMOVE",0,2,137,"FCMOVNA",0,2,142,"FCMOVNAE",0
  400.     db    2,147,"FCMOVNB",0,2,152,"FCMOVNBE",0,2,157,"FCMOVNE",0
  401.     db    2,162,"FCMOVNU",0,2,167,"FCMOVNZ",0,2,172,"FCMOVU",0
  402.     db    2,177,"FCMOVZ",0,2,182,"FCOM",0,2,193,"FCOMI",0
  403.     db    2,202,"FCOMIP",0,2,211,"FCOMP",0,2,222,"FCOMPP",0
  404.     db    2,226,"FCOS",0,2,231,"FDECSTP",0,2,235,"FDISI",0
  405.     db    2,240,"FDIV",0,2,251,"FDIVP",0,3,8,"FDIVR",0
  406.     db    3,19,"FDIVRP",0,3,31,"FENI",0,3,36,"FFREE",0
  407.     db    2,92,"FIADD",0,3,40,"FICOM",0,3,45,"FICOMP",0
  408.     db    3,3,"FIDIV",0,3,26,"FIDIVR",0,3,50,"FILD",0
  409.     db    3,141,"FIMUL",0,3,57,"FINCSTP",0,3,61,"FINIT",0
  410.     db    3,66,"FIST",0,3,71,"FISTP",0,3,253,"FISUB",0
  411.     db    4,21,"FISUBR",0,3,78,"FLD",0,3,88,"FLD1",0
  412.     db    3,116,"FLDCW",0,3,120,"FLDENV",0,3,96,"FLDL2E",0
  413.     db    3,92,"FLDL2T",0,3,104,"FLDLG2",0,3,108,"FLDLN2",0
  414.     db    3,100,"FLDPI",0,3,112,"FLDZ",0,3,123,"FMUL",0
  415.     db    3,134,"FMULP",0,2,108,"FNCLEX",0,2,236,"FNDISI",0
  416.     db    3,32,"FNENI",0,3,62,"FNINIT",0,3,117,"FNLDCW",0
  417.     db    3,146,"FNOP",0,3,175,"FNSAVE",0,3,183,"FNSETPM",0
  418.     db    3,221,"FNSTCW",0,3,225,"FNSTENV",0,3,229,"FNSTSW",0
  419.     db    3,150,"FPATAN",0,3,154,"FPREM",0,3,158,"FPREM1",0
  420.     db    3,163,"FPTAN",0,3,167,"FRNDINT",0,3,171,"FRSTOR",0
  421.     db    6,194,"FS",0,3,174,"FSAVE",0,3,178,"FSCALE",0
  422.     db    3,182,"FSETPM",0,3,188,"FSIN",0,3,193,"FSINCOS",0
  423.     db    3,198,"FSQRT",0,3,202,"FST",0,3,220,"FSTCW",0
  424.     db    3,224,"FSTENV",0,3,210,"FSTP",0,3,228,"FSTSW",0
  425.     db    3,235,"FSUB",0,3,246,"FSUBP",0,4,3,"FSUBR",0
  426.     db    4,14,"FSUBRP",0,4,26,"FTST",0,4,30,"FUCOM",0
  427.     db    4,39,"FUCOMI",0,4,48,"FUCOMIP",0,4,57,"FUCOMP",0
  428.     db    4,66,"FUCOMPP",0,4,71,"FWAIT",0,4,74,"FXAM",0
  429.     db    4,78,"FXCH",0,4,85,"FXTRACT",0,4,89,"FYL2X",0
  430.     db    4,93,"FYL2XP1",0,6,196,"GS",0,4,97,"HLT",0
  431.     db    4,100,"IDIV",0,4,103,"IMUL",0,4,121,"IN",0,4,126,"INC",0
  432.     db    4,132,"INSB",0,4,136,"INSD",0,4,137,"INSW",0
  433.     db    4,141,"INT",0,4,146,"INTO",0,4,149,"INVD",0
  434.     db    4,153,"INVLPG",0,4,158,"IRET",0,4,157,"IRETD",0
  435.     db    4,161,"JA",0,4,167,"JAE",0,4,173,"JB",0,4,179,"JBE",0
  436.     db    4,185,"JC",0,4,192,"JCXZ",0,4,195,"JE",0,4,191,"JECXZ",0
  437.     db    4,201,"JG",0,4,207,"JGE",0,4,213,"JL",0,4,219,"JLE",0
  438.     db    5,90,"JMP",0,4,225,"JNA",0,4,231,"JNAE",0,4,237,"JNB",0
  439.     db    4,243,"JNBE",0,4,249,"JNC",0,4,255,"JNE",0,5,6,"JNG",0
  440.     db    5,12,"JNGE",0,5,18,"JNL",0,5,24,"JNLE",0
  441.     db    5,30,"JNO",0,5,36,"JNP",0,5,42,"JNS",0,5,48,"JNZ",0
  442.     db    5,54,"JO",0,5,60,"JP",0,5,66,"JPE",0,5,72,"JPO",0
  443.     db    5,78,"JS",0,5,84,"JZ",0,5,101,"LAHF",0,5,104,"LAR",0
  444.     db    5,108,"LDS",0,5,126,"LEA",0,5,129,"LEAVE",0
  445.     db    5,115,"LES",0,5,118,"LFS",0,5,133,"LGDT",0,5,122,"LGS",0
  446.     db    5,137,"LIDT",0,5,141,"LLDT",0,5,145,"LMSW",0
  447.     db    5,149,"LOCK",0,5,151,"LODSB",0,5,154,"LODSD",0
  448.     db    5,155,"LODSW",0,5,158,"LOOP",0,5,163,"LOOPE",0
  449.     db    5,173,"LOOPNE",0,5,178,"LOOPNZ",0,5,168,"LOOPZ",0
  450.     db    5,183,"LSL",0,5,111,"LSS",0,5,187,"LTR",0,5,191,"MOV",0
  451.     db    5,228,"MOVSB",0,5,231,"MOVSD",0,5,232,"MOVSW",0
  452.     db    5,235,"MOVSX",0,5,242,"MOVZX",0,5,249,"MUL",0
  453.     db    5,252,"NEG",0,6,1,"NOP",0,6,4,"NOT",0,6,8,"OR",0
  454.     db    6,22,"ORG",0,6,24,"OUT",0,6,29,"OUTSB",0
  455.     db    6,33,"OUTSD",0,6,34,"OUTSW",0,6,38,"POP",0
  456.     db    6,56,"POPA",0,6,55,"POPAD",0,6,61,"POPF",0
  457.     db    6,60,"POPFD",0,6,64,"PUSH",0,6,90,"PUSHA",0
  458.     db    6,89,"PUSHAD",0,6,95,"PUSHF",0,6,94,"PUSHFD",0
  459.     db    6,98,"RCL",0,6,106,"RCR",0,6,130,"RDMSR",0
  460.     db    6,134,"REP",0,6,136,"REPE",0,6,138,"REPNE",0
  461.     db    6,140,"RET",0,6,145,"RETF",0,6,114,"ROL",0,6,122,"ROR",0
  462.     db    6,150,"RSM",0,6,154,"SAHF",0,6,157,"SAL",0,6,165,"SAR",0
  463.     db    6,214,"SBB",0,6,228,"SCASB",0,6,231,"SCASD",0
  464.     db    6,232,"SCASW",0,6,173,"SEG",0,6,235,"SETA",0
  465.     db    6,239,"SETAE",0,6,243,"SETB",0,6,247,"SETBE",0
  466.     db    6,251,"SETC",0,6,255,"SETE",0,7,4,"SETG",0
  467.     db    7,8,"SETGE",0,7,12,"SETL",0,7,16,"SETLE",0
  468.     db    7,20,"SETNA",0,7,24,"SETNAE",0,7,28,"SETNB",0
  469.     db    7,32,"SETNBE",0,7,36,"SETNC",0,7,40,"SETNE",0
  470.     db    7,44,"SETNG",0,7,48,"SETNGE",0,7,52,"SETNL",0
  471.     db    7,56,"SETNLE",0,7,60,"SETNO",0,7,64,"SETNP",0
  472.     db    7,68,"SETNS",0,7,72,"SETNZ",0,7,76,"SETO",0
  473.     db    7,80,"SETP",0,7,84,"SETPE",0,7,88,"SETPO",0
  474.     db    7,92,"SETS",0,7,96,"SETZ",0,7,100,"SGDT",0
  475.     db    6,198,"SHL",0,7,108,"SHLD",0,6,206,"SHR",0
  476.     db    7,115,"SHRD",0,7,104,"SIDT",0,7,122,"SLDT",0
  477.     db    7,126,"SMSW",0,6,190,"SS",0,7,130,"STC",0,7,133,"STD",0
  478.     db    7,136,"STI",0,7,139,"STOSB",0,7,142,"STOSD",0
  479.     db    7,143,"STOSW",0,7,146,"STR",0,7,150,"SUB",0
  480.     db    7,164,"TEST",0,7,173,"VERR",0,7,177,"VERW",0
  481.     db    7,181,"WAIT",0,7,184,"WBINVD",0,7,188,"WRMSR",0
  482.     db    7,192,"XADD",0,7,197,"XCHG",0,7,208,"XLAT",0
  483.     db    7,211,"XLATB",0,7,214,"XOR",0
  484. end_mnlist db
  485.  
  486. ;    These are equates to refer to the above mnemonics.
  487.  
  488. MNEM_BSWAP    EQU    71
  489. MNEM_DB    EQU    506
  490. MNEM_LOCK    EQU    1819
  491. MNEM_REP    EQU    2117
  492. MNEM_REPE    EQU    2123
  493. MNEM_REPNE    EQU    2130
  494. MNEM_SEG    EQU    2218
  495. MNEM_WAIT    EQU    2592
  496.  
  497. ;    Number of entries in the following array.
  498.  
  499. ASMMOD    EQU    77
  500.  
  501. ;    This is an array of indices into the oplists array (below).
  502. ;    It is used by the assembler to save space.
  503.  
  504. opindex    db    0,1,4,7,10,13,16,19,22,25,27,30,33,35,37,39,41
  505.     db    43,45,48,50,52,55,58,62,64,66,68,70,73,75,77,81
  506.     db    85,89,93,96,99,101,103,105,108,110,112,115,118,121,124,127
  507.     db    130,134,138,141,144,146,148,150,152,154,156,158,161,164,167,170
  508.     db    173,175,177,181,185,188,191,194,197,200,203,206
  509.  
  510. ;    These are the lists of operands for the various instruction types.
  511.  
  512. oplists    db    0    ;simple instruction
  513.     db    OP_ALL+OP_AX, OP_ALL+OP_IMM, 0
  514.     db    OP_ALL+OP_RM, OP_ALL+OP_IMM, 0
  515.     db    OP_1632+OP_RM, OP_IMMS8, 0
  516.     db    OP_ALL+OP_RM, OP_ALL+OP_R, 0
  517.     db    OP_ALL+OP_R, OP_ALL+OP_RM, 0
  518.     db    OP_16+OP_RM, OP_16+OP_R, 0
  519.     db    OP_1632+OP_R, OP_1632+OP_M, 0
  520.     db    OP_1632+OP_R, OP_1632+OP_RM, 0
  521.     db    OP_32+OP_R_ADD, 0
  522.     db    OP_1632+OP_RM, OP_1632+OP_R, 0
  523.     db    OP_1632+OP_RM, OP_IMM8, 0
  524.     db    OP_REL1632, 0
  525.     db    OP_FARP, 0
  526.     db    OP_FARMEM, 0
  527.     db    OP_M64, 0
  528.     db    OP_ALL+OP_RM, 0
  529.     db    OP_1632+OP_R_ADD, 0
  530.     db    OP_16+OP_IMM, OP_IMM8, 0
  531.     db    OP_MFLOAT, 0
  532.     db    OP_MDOUBLE, 0
  533.     db    OP_ST, OP_STI, 0
  534.     db    OP_STI, OP_ST, 0
  535.     db    OP_1CHK, OP_STI, OP_ST, 0
  536.     db    OP_32+OP_M, 0
  537.     db    OP_16+OP_M, 0
  538.     db    OP_M80, 0
  539.     db    OP_STI, 0
  540.     db    OP_1CHK, OP_STI, 0
  541.     db    OP_MXX, 0
  542.     db    OP_16+OP_AX, 0
  543.     db    OP_1632+OP_R, OP_1632+OP_RM, OP_IMMS8, 0
  544.     db    OP_1632+OP_R_MOD, OP_1632+OP_R, OP_IMMS8, 0
  545.     db    OP_1632+OP_R, OP_1632+OP_RM, OP_1632+OP_IMM, 0
  546.     db    OP_1632+OP_R_MOD, OP_1632+OP_R, OP_1632+OP_IMM, 0
  547.     db    OP_ALL+OP_AX, OP_IMM8, 0
  548.     db    OP_ALL+OP_AX, OP_DX, 0
  549.     db    OP_3, 0
  550.     db    OP_IMM8, 0
  551.     db    OP_REL8, 0
  552.     db    OP_ECX, OP_REL8, 0
  553.     db    OP_1632+OP_RM, 0
  554.     db    OP_16+OP_RM, 0
  555.     db    OP_16+OP_RM, OP_SEGREG, 0
  556.     db    OP_SEGREG, OP_16+OP_RM, 0
  557.     db    OP_ALL+OP_AX, OP_ALL+OP_MOFFS, 0
  558.     db    OP_ALL+OP_MOFFS, OP_ALL+OP_AX, 0
  559.     db    OP_8+OP_R_ADD, OP_8+OP_IMM, 0
  560.     db    OP_1632+OP_R_ADD, OP_1632+OP_IMM, 0
  561.     db    OP_1632+OP_R, OP_SHOSIZ, OP_8+OP_RM, 0
  562.     db    OP_1632+OP_R, OP_SHOSIZ, OP_16+OP_RM, 0
  563.     db    OP_IMM8, OP_ALL+OP_AX, 0
  564.     db    OP_DX, OP_ALL+OP_AX, 0
  565.     db    OP_1632+OP_M, 0
  566.     db    OP_ES, 0
  567.     db    OP_CS, 0
  568.     db    OP_SS, 0
  569.     db    OP_DS, 0
  570.     db    OP_FS, 0
  571.     db    OP_GS, 0
  572.     db    OP_SHOSIZ, OP_1632+OP_IMM, 0
  573.     db    OP_SHOSIZ, OP_IMM8, 0
  574.     db    OP_ALL+OP_RM, OP_1, 0
  575.     db    OP_ALL+OP_RM, OP_CL, 0
  576.     db    OP_ALL+OP_RM, OP_IMM8, 0
  577.     db    OP_16+OP_IMM, 0
  578.     db    OP_8+OP_RM, 0
  579.     db    OP_1632+OP_RM, OP_1632+OP_R, OP_IMM8, 0
  580.     db    OP_1632+OP_RM, OP_1632+OP_R, OP_CL, 0
  581.     db    OP_1632+OP_AX, OP_1632+OP_R_ADD, 0
  582.     db    OP_1632+OP_R_ADD, OP_1632+OP_AX, 0
  583.     db    OP_32+OP_R_MOD, OP_CR, 0
  584.     db    OP_CR, OP_32+OP_R_MOD, 0
  585.     db    OP_32+OP_R_MOD, OP_DR, 0
  586.     db    OP_DR, OP_32+OP_R_MOD, 0
  587.     db    OP_32+OP_R_MOD, OP_TR, 0
  588.     db    OP_TR, OP_32+OP_R_MOD, 0
  589.  
  590. OPTYPES_BASE    EQU    12
  591.  
  592. OPLIST_Z    EQU    113
  593. OPLIST_ES    EQU    158
  594.  
  595. ;    Here is the compressed table of the opcode types.
  596.  
  597. optypes    db     22, 22, 25, 25, 13, 13,158,158    ; 00 - 07 (main opcode part)
  598.     db     22, 22, 25, 25, 13, 13,160,  2    ; 08 - 0f
  599.     db     22, 22, 25, 25, 13, 13,162,162    ; 10 - 17
  600.     db     22, 22, 25, 25, 13, 13,164,164    ; 18 - 1f
  601.     db     22, 22, 25, 25, 13, 13, 10, 12    ; 20 - 27
  602.     db     22, 22, 25, 25, 13, 13, 10, 12    ; 28 - 2f
  603.     db     22, 22, 25, 25, 13, 13, 10, 12    ; 30 - 37
  604.     db     22, 22, 25, 25, 13, 13, 10, 12    ; 38 - 3f
  605.     db     55, 55, 55, 55, 55, 55, 55, 55    ; 40 - 47
  606.     db     55, 55, 55, 55, 55, 55, 55, 55    ; 48 - 4f
  607.     db     55, 55, 55, 55, 55, 55, 55, 55    ; 50 - 57
  608.     db     55, 55, 55, 55, 55, 55, 55, 55    ; 58 - 5f
  609.     db     12, 12, 31, 28, 10, 10, 10, 10    ; 60 - 67
  610.     db    170, 97,173, 89, 12, 12, 12, 12    ; 68 - 6f
  611.     db    115,115,115,115,115,115,115,115    ; 70 - 77
  612.     db    115,115,115,115,115,115,115,115    ; 78 - 7f
  613.     db      4,  4,  0,  4, 22, 22, 25, 25    ; 80 - 87
  614.     db     22, 22, 25, 25,124, 31,127,  4    ; 88 - 8f
  615.     db     12,197,197,197,197,197,197,197    ; 90 - 97
  616.     db     12, 12, 47, 12, 12, 12, 12, 12    ; 98 - 9f
  617.     db    130,130,133,133, 12, 12, 12, 12    ; a0 - a7
  618.     db     13, 13, 12, 12, 12, 12, 12, 12    ; a8 - af
  619.     db    136,136,136,136,136,136,136,136    ; b0 - b7
  620.     db    139,139,139,139,139,139,139,139    ; b8 - bf
  621.     db      4,  4,185, 12, 31, 31,  4,  4    ; c0 - c7
  622.     db     57, 12,185, 12,111,113, 12, 12    ; c8 - cf
  623.     db      4,  4,  4,  4,113,113,  0, 12    ; d0 - d7
  624.     db      6,  6,  6,  6,  6,  6,  6,  6    ; d8 - df
  625.     db    117,117,117,115,105,105,150,150    ; e0 - e7
  626.     db     45, 45, 47,115,108,108,153,153    ; e8 - ef
  627.     db     10,  0, 10, 10, 12, 12,  4,  4    ; f0 - f7
  628.     db     12, 12, 12, 12, 12, 12,  4,  4    ; f8 - ff
  629.     db     16, 16, 16, 16, 16, 16, 16, 16    ; 100 - 107 (Intel group 1)
  630.     db     19, 19, 19, 19, 19, 19, 19, 19    ; 108 - 10f
  631.     db    176,176,176,176,176,176,  0,176    ; 110 - 117 (Intel group 2)
  632.     db    179,179,179,179,179,179,  0,179    ; 118 - 11f
  633.     db    182,182,182,182,182,182,  0,182    ; 120 - 127 (Intel group 2a)
  634.     db     16,  0, 53, 53, 53, 53, 53, 53    ; 128 - 12f (Intel group 3)
  635.     db     53, 53,120, 49,120, 49,120,  0    ; 130 - 137 (Intel group 5)
  636.     db    120,122,122,122,122,122,  0,  0    ; 138 - 13f (Intel group 6)
  637.     db     85, 85, 85, 85,122,  0,122, 85    ; 140 - 147 (Intel group 7)
  638.     db     60, 60, 60, 60, 60, 60, 60, 60    ; 148 - 14f (Coprocessor d8)
  639.     db     64, 64, 82, 82, 64, 64, 64, 64    ; 150 - 157
  640.     db     60,  0, 60, 60, 85, 76, 85, 76    ; 158 - 15f (Coprocessor d9)
  641.     db     80, 82,  8,  0,  8,  8,  8,  8    ; 160 - 167
  642.     db     74, 74, 74, 74, 74, 74, 74, 74    ; 168 - 16f (Coprocessor da)
  643.     db     64, 64, 64, 64,  0,  8,  0,  0    ; 170 - 177
  644.     db     74,  0, 74, 74,  0, 78,  0, 78    ; 178 - 17f (Coprocessor db)
  645.     db     64, 64, 64, 64,  8, 82, 82,  0    ; 180 - 187
  646.     db     62, 62, 62, 62, 62, 62, 62, 62    ; 188 - 18f (Coprocessor dc)
  647.     db     67, 67,  0,  0, 67, 67, 67, 67    ; 190 - 197
  648.     db     62,  0, 62, 62, 85,  0, 85, 76    ; 198 - 19f (Coprocessor dd)
  649.     db     80,  0, 80, 80, 82, 82,  0,  0    ; 1a0 - 1a7
  650.     db     76, 76, 76, 76, 76, 76, 76, 76    ; 1a8 - 1af (Coprocessor de)
  651.     db     70, 70,  0,  8, 70, 70, 70, 70    ; 1b0 - 1b7
  652.     db     76,  0, 76, 76, 78, 51, 78, 51    ; 1b8 - 1bf (Coprocessor df)
  653.     db      0,  0,  0,  0,  8, 82, 82,  0    ; 1c0 - 1c7
  654.     db     12, 12, 12, 12, 12, 12, 12,  0    ; 1c8 - 1cf (Coprocessor groups)
  655.     db     12, 12, 12, 12, 12, 12, 12, 12    ; 1d0 - 1d7
  656.     db     12, 12, 12, 12, 12, 12, 12, 12    ; 1d8 - 1df
  657. ;    The rest of these are squeezed.
  658.     db     0,  4,  4, 34, 34, 12, 12, 12
  659.     db    203,209,206,212,215,218, 12, 12
  660.     db     34, 34, 34, 34, 34, 34, 34, 34
  661.     db     34, 34, 34, 34, 34, 34, 34, 34
  662.     db     45, 45, 45, 45, 45, 45, 45, 45
  663.     db     45, 45, 45, 45, 45, 45, 45, 45
  664.     db    187,187,187,187,187,187,187,187
  665.     db    187,187,187,187,187,187,187,187
  666.     db    166,166, 12, 39,189,193,168,168
  667.     db     12, 39,189,193, 34, 22, 22, 31
  668.     db     39, 31, 31,142,146,  4, 39, 34
  669.     db     34,142,146, 22, 22,  4, 37, 37
  670.     db     37, 37, 37, 37, 37, 37, 53, 53
  671.     db     42, 42, 42, 42, 51,156, 16, 12
  672.     db     12, 12, 12, 12, 12, 12, 12, 12
  673.     db     12, 12, 12, 87
  674.  
  675. ;    And here is the compressed table of additional information.
  676.  
  677. opinfo    dw    00020h,00020h,00020h,00020h,00020h,00020h,00808h,007e4h    ; 00
  678.     dw    007bbh,007bbh,007bbh,007bbh,007bbh,007bbh,00808h,001e0h    ; 08
  679.     dw    0001ah,0001ah,0001ah,0001ah,0001ah,0001ah,00808h,007e4h    ; 10
  680.     dw    0088ch,0088ch,0088ch,0088ch,0088ch,0088ch,00808h,007e4h    ; 18
  681.     dw    00026h,00026h,00026h,00026h,00026h,00026h,00001h,001eeh    ; 20
  682.     dw    00a05h,00a05h,00a05h,00a05h,00a05h,00a05h,00101h,001f4h    ; 28
  683.     dw    00a55h,00a55h,00a55h,00a55h,00a55h,00a55h,00201h,00002h    ; 30
  684.     dw    001a0h,001a0h,001a0h,001a0h,001a0h,001a0h,00301h,00014h    ; 38
  685.     dw    005c2h,005c2h,005c2h,005c2h,005c2h,005c2h,005c2h,005c2h    ; 40
  686.     dw    00204h,00204h,00204h,00204h,00204h,00204h,00204h,00204h    ; 48
  687.     dw    00808h,00808h,00808h,00808h,00808h,00808h,00808h,00808h    ; 50
  688.     dw    007e4h,007e4h,007e4h,007e4h,007e4h,007e4h,007e4h,007e4h    ; 58
  689.     dw    0180fh,017eah,01033h,0202ch,03401h,03501h,03008h,03010h    ; 60
  690.     dw    01808h,015b6h,01808h,015b6h,015c8h,015d6h,017cch,017dch    ; 68
  691.     dw    006ach,00694h,00614h,0060eh,006c7h,006a6h,00619h,00609h    ; 70
  692.     dw    006c2h,006a0h,006b6h,006bch,00643h,0063dh,00648h,00638h    ; 78
  693.     dw    00100h,00100h,00000h,00108h,00a0bh,00a0bh,00a3fh,00a3fh    ; 80
  694.     dw    00775h,00775h,00775h,00775h,00775h,006dfh,00775h,002f8h    ; 88
  695.     dw    007afh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh    ; 90
  696.     dw    0006dh,001e1h,00066h,00a20h,00820h,007f9h,00879h,006cch    ; 98
  697.     dw    00775h,00775h,00775h,00775h,0077bh,0078bh,001a6h,001b6h    ; a0
  698.     dw    00a0bh,00a0bh,009e7h,009f7h,00722h,00732h,00892h,008a2h    ; a8
  699.     dw    00775h,00775h,00775h,00775h,00775h,00775h,00775h,00775h    ; b0
  700.     dw    00775h,00775h,00775h,00775h,00775h,00775h,00775h,00775h    ; b8
  701.     dw    00120h,00120h,0085ah,0085ah,006edh,006d9h,00300h,00300h    ; c0
  702.     dw    0121ah,016e5h,00860h,00860h,005ddh,005ddh,005e3h,005fah    ; c8
  703.     dw    00110h,00110h,00118h,00118h,0000eh,00008h,00000h,00a4dh    ; d0
  704.     dw    00148h,00158h,00168h,00178h,00188h,00198h,001a8h,001b8h    ; d8
  705.     dw    00752h,0075bh,0073ah,00624h,005bdh,005bdh,007c6h,007c6h    ; e0
  706.     dw    00066h,0064eh,0064eh,0064eh,005bdh,005bdh,007c6h,007c6h    ; e8
  707.     dw    00004h,00000h,00002h,00002h,005a9h,00092h,00128h,00128h    ; f0
  708.     dw    00079h,009d5h,00085h,009e1h,0007fh,009dbh,002e0h,00130h    ; f8
  709.     dw    00020h,007bbh,0001ah,0088ch,00026h,00a05h,00a55h,001a0h    ; 100
  710.     dw    00020h,007bbh,0001ah,0088ch,00026h,00a05h,00a55h,001a0h    ; 108
  711.     dw    00867h,0086dh,00831h,00837h,009a1h,009aeh,00000h,00886h    ; 110
  712.     dw    00867h,0086dh,00831h,00837h,009a1h,009aeh,00000h,00886h    ; 118
  713.     dw    01867h,0186dh,01831h,01837h,019a1h,019aeh,00000h,01886h    ; 120
  714.     dw    00a0bh,00000h,007b5h,007a9h,007a3h,005b6h,0020ah,005afh    ; 128
  715.     dw    005c2h,00204h,00066h,00066h,0064eh,0064eh,00808h,00000h    ; 130
  716.     dw    029c2h,029ffh,0270dh,0276fh,02a12h,02a19h,00000h,00000h    ; 138
  717.     dw    0299ah,029bbh,026f9h,02706h,029c9h,00000h,02714h,045f1h    ; 140
  718.     dw    00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh    ; 148
  719.     dw    00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh    ; 150
  720.     dw    003c8h,00000h,004f7h,0050eh,003ddh,0044bh,00477h,0046eh    ; 158
  721.     dw    003c8h,00581h,00308h,00000h,00310h,001c8h,001d0h,001d8h    ; 160
  722.     dw    0035dh,0038eh,00365h,0036dh,003b7h,003bfh,00376h,0037eh    ; 168
  723.     dw    06276h,06289h,0627fh,062dah,00000h,00318h,00000h,00000h    ; 170
  724.     dw    00387h,00000h,003a8h,003afh,00000h,003c8h,00000h,0050eh    ; 178
  725.     dw    062a7h,062bch,062b1h,062c6h,00320h,0654ch,062f3h,00000h    ; 180
  726.     dw    00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh    ; 188
  727.     dw    00236h,00419h,00000h,00000h,0052ch,0051dh,0033dh,0032eh    ; 190
  728.     dw    003c8h,00000h,004f7h,0050eh,004b6h,00000h,0045bh,00481h    ; 198
  729.     dw    00355h,00000h,004f7h,0050eh,03544h,0355fh,00000h,00000h    ; 1a0
  730.     dw    0035dh,0038eh,00365h,0036dh,003b7h,003bfh,00376h,0037eh    ; 1a8
  731.     dw    0023dh,00420h,00000h,00328h,00534h,00524h,00345h,00335h    ; 1b0
  732.     dw    00387h,00000h,003a8h,003afh,00245h,00387h,0024ch,003afh    ; 1b8
  733.     dw    00000h,00000h,00000h,00000h,00330h,06555h,062fbh,00000h    ; 1c0
  734.     dw    003ceh,003efh,003e6h,0040ah,003f8h,00401h,00412h,00000h    ; 1c8
  735.     dw    00227h,00592h,004a4h,0048ah,00588h,0349bh,0031ch,00396h    ; 1d0
  736.     dw    00493h,0059ah,004efh,034e5h,004ach,004cch,034deh,03315h    ; 1d8
  737. ;    The rest of these are squeezed.
  738.     dw         0,00138h,00140h,026d3h,02763h,0208bh,045eah,04a27h
  739.     dw    03775h,03775h,03775h,03775h,03775h,03775h,05a30h,0583dh
  740.     dw    0616eh,0614ah,060a9h,060a0h,06198h,06165h,060b1h,06098h
  741.     dw    06190h,0615ch,0617eh,06187h,060dbh,060d2h,060e3h,060cah
  742.     dw    036ach,03694h,03614h,0360eh,036c7h,036a6h,03619h,03609h
  743.     dw    036c2h,036a0h,036b6h,036bch,03643h,0363dh,03648h,03638h
  744.     dw    0396eh,0394eh,038bfh,038b7h,03993h,03966h,038c6h,038b0h
  745.     dw    0398ch,0395eh,0397ch,03984h,038ebh,038e3h,038f2h,038dch
  746.     dw    03808h,037e4h,051d4h,0304fh,039a7h,039a7h,03808h,037e4h
  747.     dw    05873h,03060h,039b4h,039b4h,035b6h,041beh,041beh,03769h
  748.     dw    0305ah,036f3h,03700h,0379bh,0379bh,002e8h,03054h,0303bh
  749.     dw    03041h,03793h,03793h,04a38h,04a38h,002f0h,04047h,04047h
  750.     dw    04047h,04047h,04047h,04047h,04047h,04047h,005c2h,00204h
  751.     dw    0304fh,03060h,0305ah,03054h,051c8h,007e4h,00775h,00454h
  752.     dw    00254h,0022fh,0053dh,0057ah,03568h,0043ah,00431h,00428h
  753.     dw    00442h,02464h,0030ch,00481h
  754.  
  755. ;    This table converts unsqueezed numbers to squeezed.
  756.  
  757. sqztab    db      1,  2,  3,  4,  0,  0,  5,  0
  758.     db      6,  7,  0,  0,  0,  0,  0,  0
  759.     db      0,  0,  0,  0,  0,  0,  0,  0
  760.     db      0,  0,  0,  0,  0,  0,  0,  0
  761.     db      8,  9, 10, 11, 12,  0, 13,  0
  762.     db      0,  0,  0,  0,  0,  0,  0,  0
  763.     db     14,  0, 15,  0,  0,  0,  0,  0
  764.     db      0,  0,  0,  0,  0,  0,  0,  0
  765.     db     16, 17, 18, 19, 20, 21, 22, 23
  766.     db     24, 25, 26, 27, 28, 29, 30, 31
  767.     db      0,  0,  0,  0,  0,  0,  0,  0
  768.     db      0,  0,  0,  0,  0,  0,  0,  0
  769.     db      0,  0,  0,  0,  0,  0,  0,  0
  770.     db      0,  0,  0,  0,  0,  0,  0,  0
  771.     db      0,  0,  0,  0,  0,  0,  0,  0
  772.     db      0,  0,  0,  0,  0,  0,  0,  0
  773.     db     32, 33, 34, 35, 36, 37, 38, 39
  774.     db     40, 41, 42, 43, 44, 45, 46, 47
  775.     db     48, 49, 50, 51, 52, 53, 54, 55
  776.     db     56, 57, 58, 59, 60, 61, 62, 63
  777.     db     64, 65, 66, 67, 68, 69,  0,  0
  778.     db     70, 71, 72, 73, 74, 75,  0, 76
  779.     db     77, 78, 79, 80, 81, 82, 83, 84
  780.     db      0,  0, 85, 86, 87, 88, 89, 90
  781.     db     91, 92,  0,  0,  0,  0,  0, 93
  782.     db     94, 95, 96, 97, 98, 99,100,101
  783.     db      0,  0,  0,  0,  0,  0,  0,  0
  784.     db      0,  0,  0,  0,  0,  0,  0,  0
  785.     db      0,  0,  0,  0,  0,  0,  0,  0
  786.     db      0,  0,  0,  0,  0,  0,  0,  0
  787.     db      0,  0,  0,  0,  0,  0,  0,  0
  788.     db      0,  0,  0,  0,  0,  0,  0,  0
  789.     db    102,103,  0,  0,  0,  0,  0,  0
  790.     db      0,  0,  0,  0,104,105,106,107
  791.     db      0,108,  0,  0,  0,  0,  0,  0
  792.     db    109,  0,  0,  0,  0,  0,  0,  0
  793.     db    110,  0,  0,  0,  0,  0,  0,  0
  794.     db    111,  0,  0,  0,  0,  0,  0,  0
  795.     db    112,113,  0,  0,114,115,  0,  0
  796.     db      0,116,  0,  0,  0,  0,  0,  0
  797.     db    117,118,119,120,121,  0,  0,  0
  798.     db      0,122,  0,  0,  0,  0,  0,  0
  799.     db    123,  0,  0,  0,  0,  0,  0,  0
  800.  
  801. ;    This is the table of mnemonics that change in the presence of a WAIT
  802. ;    instruction.
  803.  
  804. wtab1    dw      802,  801,  800,  803,  349,  414,  804,  351
  805.     dw      350,  816,  415
  806. wtab2    dw      603,  806,  846,  928,  981, 1220, 1237, 1277
  807.     dw     1285, 1301, 1301
  808. N_WTAB    equ    11
  809.  
  810. ;    This is the table for operands which have a different mnemonic for
  811. ;    their 32 bit versions.
  812.  
  813. ltab1    dw      152,  167,  153,  109,  207,  227,  173,  165
  814.     dw      111,   97,  157,   96,  156,  175,  171
  815. ltab2    dw      487,  430,  115, 1487, 1537, 1584, 1834, 1923
  816.     dw     2004, 2033, 2048, 2071, 2088, 2202, 2543
  817. N_LTAB    equ    15
  818.  
  819. ;    This is the table of lockable instructions
  820.  
  821. locktab    dw      266,  258,   16,   17,  264,  256,    0,    1
  822.     dw      268,  260,   32,   33,  667,  751,  659,  750
  823.     dw      651,  749,  656,  657,  737,  305,  736,  304
  824.     dw      299,  298,  265,  257,    8,    9,  267,  259
  825.     dw       24,   25,  269,  261,   40,   41,  672,  673
  826.     dw      134,  135,  270,  262,   48,   49
  827. N_LOCK    equ    46
  828.  
  829. ;    Equates used in the assembly-language code.
  830.  
  831. SPARSE_BASE    equ    480
  832.  
  833. SFPGROUP3    equ    800
  834.  
  835. ;-@@-@@-@@-End of auto-generated tables.  You may edit below this point.
  836.  
  837.  
  838. ;    debug22 - INT 22 (Program terminate) interrupt handler.
  839. ;    This is for DEBUG itself:  it's a catch-all for the various INT 23
  840. ;    and INT 24 calls that may occur unpredictably at any time.
  841. ;    What we do is pretend to be a command interpreter (which we are,
  842. ;    in a sense, just a different sort of command) by setting the PSP of
  843. ;    our parent equal to our own PSP so that DOS does not free our memory
  844. ;    when we quit.  Therefore control ends up here when Control-Break or
  845. ;    an Abort in Abort/Retry/Fail is selected.
  846.  
  847. debug22:cld            ;reestablish things
  848.     mov    ax,cs
  849.     mov    ds,ax
  850.     mov    es,ax
  851.     mov    ss,ax
  852.  
  853. ;    Begin main command loop.
  854.  
  855. cmd3:    mov    errret,offset cmd3
  856.     mov    sp,savesp    ;restore stack (this must be first)
  857.     mov    dx,offset prompt1
  858.     mov    cx,1
  859.     call    getline        ;prompted input
  860.     cmp    al,CR
  861.     je    cmd3        ;if blank line
  862.     cmp    al,';'
  863.     je    cmd3        ;if comment
  864.     cmp    al,'?'
  865.     je    help        ;if request for help
  866.     or    al,TOLOWER
  867.     sub    al,'a'
  868.     cbw
  869.     cmp    al,'x'-'a'
  870.     ja    errorj1        ;if not recognized
  871.     xchg    bx,ax
  872.     je    cmd4        ;if 'x'
  873.     call    skipwhite
  874. cmd4:    mov    di,offset line_out
  875.     shl    bx,1
  876.     call    cmdlist[bx]
  877.     jmp    cmd3        ;back to the top
  878.  
  879. help:    mov    ah,9        ;print string
  880.     mov    dx,offset helpmsg
  881.     int    21h
  882.     jmp    cmd3        ;done
  883.  
  884. xx:    mov    ah,9        ;print string
  885.     mov    dx,offset notyet
  886.     int    21h
  887.     ret            ;done
  888.  
  889. errorj1:jmp    error
  890.  
  891. ;    A command - tiny assembler.
  892.  
  893. asm_mn_flags    db    0        ;flags for the mnemonic
  894. AMF_D32        equ    1        ;(order is important for D32/WAIT)
  895. AMF_WAIT    equ    2
  896. AMF_A32        equ    4        ;if this is 32 bit addressing
  897. AMF_SIB        equ    8        ;there's a SIB in the arguments
  898. AMF_MSEG    equ    10h        ;if a seg prefix was given b4 mnemonic
  899. AMF_FSGS    equ    20h        ;if FS or GS was encountered
  900.  
  901. aa_saved_prefix    db    0        ;WAIT or REP... prefix
  902. ;        aa_saved_prefix and aa_seg_pre must be consecutive.
  903. aa_seg_pre    db    0        ;segment prefix
  904.  
  905. mneminfo    dw    0        ;address associated with the mnemonic
  906.  
  907. ;    The following (through a_opcode) must all be consecutive.
  908.  
  909. rmaddr        dw    0        ;address of operand giving the R/M byte
  910. regmem        db    0        ;mod reg r/m part of instruction
  911.                     ;regmem and sibbyte must be consecutive
  912. sibbyte        db    0        ;SIB byte
  913. immaddr        dw    0        ;address of operand giving the immed stf
  914. xxaddr        dw    0        ;address of additional stuff
  915. dismach        db    0        ;type of processor needed
  916. dmflags        db    0        ;flags for extra processor features
  917.  
  918.     DM_COPR    equ    1        ;math coprocessor
  919.     DM_MMX    equ    2        ;MMX extensions
  920.  
  921. opcode_or    db    0        ;extra bits in the op code
  922. opsize        db    0        ;size of this operation
  923. varflags    db    0        ;flags for this variant
  924.  
  925. VAR_LOCKABLE    equ    1        ;variant is lockable
  926. VAR_MODRM    equ    2        ;if there's a MOD R/M here
  927. VAR_SIZ_GIVN    equ    4        ;if a size was given
  928. VAR_SIZ_FORCD    equ    8        ;if only one size is permitted
  929. VAR_SIZ_NEED    equ    10h        ;if we need the size
  930. VAR_D32        equ    20h        ;if there's a 32 bit operand size prefix
  931.  
  932. a_opcode    dw    0        ;op code info for this variant
  933. a_reqsize    db    0        ;size that this arg should be
  934.  
  935. a_opcode2    dw    0        ;copy of a_opcode for obs-instruction
  936.         dw    0dbe0h,0dbe1h,0dbe4h,124h,126h    ;obs. instruction codes
  937.                     ;(the above must follow a_opcode2)
  938.  
  939. obsmach        db    1,1,2,4,4    ;max permissible machine for the above
  940.  
  941. aadbsiz        db    0,4,2,1        ;table for max size of db operand
  942. aadbsto        dw    0,aa28,aa29,aa30;table for routine to store a number
  943.  
  944. modrmtab    db    11,0,13,0,15,0,14,0    ;[bx], [bp], [di], [si]
  945.         db    15,13,14,13,15,11,14,11    ;[bp+di],[bp+si],[bx+di],[bx+si]
  946.  
  947. aam_args    db    'a',CR
  948.  
  949. ;    Equates for parsed arguments.
  950.  
  951. ARG_DEREF    equ    1    ;non-immediate memory reference
  952. ARG_MODRM    equ    2    ;if we've computed the MOD R/M byte
  953. ARG_JUSTREG    equ    4    ;a solo register
  954. ARG_WEIRDREG    equ    8    ;if it's a segment register or CR, etc.
  955. ARG_IMMED    equ    10h    ;if it's just a number
  956. ARG_FARADDR    equ    20h    ;if it's of the form xxxx:yyyyyyyy
  957.  
  958. ;    For each operand type in the following table, the first byte is
  959. ;    the bits, at least one of which must be present; the second is the
  960. ;    bits all of which must be absent.
  961.  
  962. bittab        db    ARG_IMMED                ;OP_IMM
  963.         db    ARG_DEREF+ARG_JUSTREG            ;OP_RM
  964.         db    ARG_DEREF                ;OP_M
  965.         db    ARG_JUSTREG                ;OP_R_MOD
  966.         db    ARG_DEREF                ;OP_MOFFS
  967.         db    ARG_JUSTREG                ;OP_R
  968.         db    ARG_JUSTREG                ;OP_R_ADD
  969.         db    ARG_JUSTREG                ;OP_AX
  970.         db    ARG_DEREF                ;OP_M64
  971.         db    ARG_DEREF                ;OP_MFLOAT
  972.         db    ARG_DEREF                ;OP_MDOUBLE
  973.         db    ARG_DEREF                ;OP_M80
  974.         db    ARG_DEREF                ;OP_MXX
  975.         db    ARG_DEREF                ;OP_FARMEM
  976.         db    ARG_FARADDR                ;OP_FARP
  977.         db    ARG_IMMED                ;OP_REL8
  978.         db    ARG_IMMED                ;OP_REL1632
  979.         db    ARG_WEIRDREG                ;OP_1CHK
  980.         db    ARG_WEIRDREG                ;OP_STI
  981.         db    ARG_WEIRDREG                ;OP_CR
  982.         db    ARG_WEIRDREG                ;OP_DR
  983.         db    ARG_WEIRDREG                ;OP_TR
  984.         db    ARG_WEIRDREG                ;OP_SEGREG
  985.         db    ARG_IMMED                ;OP_IMMS8
  986.         db    ARG_IMMED                ;OP_IMM8
  987.         db    ARG_JUSTREG                ;OP_ECX
  988.         db    0ffh                    ;OP_SHOSIZ
  989.         db    ARG_IMMED                ;OP_1
  990.         db    ARG_IMMED                ;OP_3
  991.         db    ARG_JUSTREG                ;OP_DX
  992.         db    ARG_JUSTREG                ;OP_CL
  993.         db    ARG_WEIRDREG                ;OP_ST
  994.         db    ARG_WEIRDREG                ;OP_CS
  995.         db    ARG_WEIRDREG                ;OP_DS
  996.         db    ARG_WEIRDREG                ;OP_ES
  997.         db    ARG_WEIRDREG                ;OP_FS
  998.         db    ARG_WEIRDREG                ;OP_GS
  999.         db    ARG_WEIRDREG                ;OP_SS
  1000.  
  1001. ;    Jump table for operand types.
  1002.  
  1003. asm_jmp1    dw    ao04,ao01,ao01,ao01    ;OP_IMM, OP_RM, OP_M, OP_R_MOD
  1004.         dw    ao05,ao02,ao03,ao06    ;OP_MOFFS, OP_R, OP_R_ADD, OP_AX
  1005.  
  1006.         dw    ao17,ao17,ao17        ;OP_M64, OP_MFLOAT, OP_MDOUBLE
  1007.         dw    ao17,ao17,ao17        ;OP_M80, OP_MXX, OP_FARMEM
  1008.         dw    ao21,ao23,ao25        ;OP_FARP, OP_REL8, OP_REL1632
  1009.         dw    ao29,ao30,ao31        ;OP_1CHK, OP_STI, OP_CR
  1010.         dw    ao34,ao35,ao39        ;OP_DR, OP_TR, OP_SEGREG
  1011.         dw    ao41,ao42,ao43m        ;OP_IMMS8, OP_IMM8, OP_ECX
  1012.         dw    ao44,ao46,ao47        ;OP_SHOSIZ, OP_1, OP_3
  1013.         dw    ao48,ao48,ao48        ;OP_DX, OP_CL, OP_ST
  1014.         dw    ao48,ao48,ao48        ;OP_CS, OP_DS, OP_ES
  1015.         dw    ao48,ao48,ao48        ;OP_FS, OP_GS, OP_SS
  1016.  
  1017. asm_regnum    db    10,1,30            ;DX, CL, ST
  1018.         db    25,27,24,28,29,26    ;CS, DS, ES, FS, GS, SS
  1019.  
  1020. asm_siznum    db    5, 6, 7, 8        ;qword, float, double, tbyte
  1021.         db    -1, 12            ;none, far
  1022.  
  1023. aa00:    jmp    cmd3        ;done with this command
  1024.  
  1025. aa:    mov    errret,offset aa01
  1026.     cmp    al,CR
  1027.     je    aa01        ;if end of line
  1028.     mov    bx,reg_cs    ;default segment to use
  1029. aa00a:    call    getaddr        ;get address into bx:dx
  1030.     call    chkeol        ;expect end of line here
  1031.     mov    a_addr,dx    ;save the address
  1032.     mov    a_addr+2,bx
  1033.  
  1034. ;    Begin loop over input lines.
  1035.  
  1036. aa01:    mov    sp,savesp    ;restore the stack (this implies no "ret")
  1037.     mov    di,offset line_out
  1038.     mov    ax,a_addr+2
  1039.     call    hexword
  1040.     mov    al,':'
  1041.     stosb
  1042.     mov    ax,a_addr
  1043.     call    hexword
  1044.     mov    al,' '
  1045.     stosb
  1046.     call    getline00
  1047.     cmp    al,CR
  1048.     je    aa00        ;if done
  1049.     cmp    al,';'
  1050.     je    aa01        ;if comment
  1051.     mov    asm_mn_flags,0
  1052.     mov    word aa_saved_prefix,0    ;clear aa_saved_prefix and aa_seg_pre
  1053.  
  1054. ;    Get mnemonic and look it up.
  1055.  
  1056. aa02:    mov    di,offset line_out    ;return here after LOCK/REP/SEG prefix
  1057.     push    si        ;save position of mnemonic
  1058. aa03:    cmp    al,'a'
  1059.     jb    aa04        ;if not lower case letter
  1060.     cmp    al,'z'
  1061.     ja    aa04
  1062.     and    al,TOUPPER    ;convert to upper case
  1063. aa04:    stosb
  1064.     lodsb
  1065.     cmp    al,CR
  1066.     je    aa05        ;if end of mnemonic
  1067.     cmp    al,' '
  1068.     je    aa05
  1069.     cmp    al,TAB
  1070.     jne    aa03
  1071. aa05:    call    skipwh0        ;skip to next field
  1072.     dec    si
  1073.     push    si        ;save position in input line
  1074.     mov    al,0
  1075.     stosb
  1076.     mov    bx,offset mnlist
  1077.     mov    dx,offset end_mnlist
  1078. aa06:    mov    si,bx        ;begin bisection loop looking for mnemonic
  1079.     add    si,dx
  1080.     rcr    si,1
  1081. aa07:    lodsb            ;skip to end of string
  1082.     cmp    al,0
  1083.     jne    aa07        ;if not end of string
  1084.     cmp    si,dx
  1085.     jb    aa09        ;if not end of table
  1086. aa08:    dec    si
  1087.     cmp    si,bx
  1088.     je    aa09        ;if beginning of table
  1089.     cmp    byte [si-1],0
  1090.     jne    aa08
  1091. aa09:    push    si        ;compare op codes
  1092.     inc    si        ;skip over the data word
  1093.     inc    si
  1094.     push    di
  1095.     mov    cx,offset line_out
  1096.     sub    di,cx
  1097.     xchg    cx,di
  1098.     repe    cmpsb
  1099.     pop    di
  1100.     pop    si
  1101.     je    aa14        ;if found it
  1102.     jg    aa11        ;if (di) < (si)
  1103. aa10:    lodsb
  1104.     cmp    al,0
  1105.     jne    aa10        ;skip to end of string
  1106.     mov    bx,si
  1107.     jmp    short aa12
  1108. aa11:    mov    dx,si
  1109. aa12:    cmp    bx,dx
  1110.     jne    aa06        ;if more to search
  1111. aa13:    pop    si        ;end of mnemonic
  1112. aa13a:    pop    si        ;beginning of mnemonic
  1113. aa13b:    jmp    error        ;complain
  1114.  
  1115. ;    We found the mnemonic.
  1116.  
  1117. aa14:    lodsb            ;get significant byte of address
  1118.     mov    ah,al        ;multiply by 255
  1119.     neg    al
  1120.     xchg    ax,bx
  1121.     lodsb
  1122.     mov    ah,0
  1123.     add    bx,ax
  1124.     lea    si,asmtab[bx-512]
  1125.  
  1126. ;    Now si points to the spot in asmtab corresponding to this mnemonic.
  1127. ;    The format of the assembler table is as follows.
  1128. ;    First, there is optionally one of the following bytes:
  1129. ;        ASM_DB        db mnemonic
  1130. ;        ASM_DW        dw mnemonic
  1131. ;        ASM_DD        dd mnemonic
  1132. ;        ASM_WAIT    the mnemonic should start with a wait
  1133. ;                instruction.
  1134. ;        ASM_D32        This is a 32 bit instruction.
  1135. ;        ASM_AAX        Special for AAM and AAD instructions:
  1136. ;                put 0ah in for a default operand.
  1137. ;        ASM_SEG        This is a segment prefix.
  1138. ;        ASM_LOCKREP    This is a LOCK or REP... prefix.
  1139. ;
  1140. ;    Then, in most cases, this is followed by one or more of the following
  1141. ;    sequences, indicating an instruction variant.
  1142. ;        ASM_LOCKABLE    (optional) indicates that this instruction can
  1143. ;                follow a LOCK prefix.
  1144. ;        ASM_MACHx    Indicates the first machine on which this
  1145. ;                instruction appeared.
  1146. ;        [word]        This is a 16-bit integer, most significant byte
  1147. ;                first, giving ASMMOD * a + b, where b is an
  1148. ;                index into the array opindex (indicating the
  1149. ;                key, or type of operand list), and a is as
  1150. ;                follows:
  1151. ;            0-255      The (one-byte) instruction.
  1152. ;            256-511      The lower 8 bits give the second byte of
  1153. ;                  a two-byte instruction beginning with 0fh.
  1154. ;            512-575      Bits 2-0 say which floating point instruction
  1155. ;                  this is (0d8h-0dfh), and 5-3 give the /r
  1156. ;                  field.
  1157. ;            576-...      (a-576)/8 is the index in the array agroups
  1158. ;                  (which gives the real value of a), and the
  1159. ;                  low-order 3 bits gives the /r field.
  1160. ;
  1161. ;        [byte]        This gives the second byte of a floating
  1162. ;                instruction if 0d8h <= a <= 0dfh.
  1163. ;
  1164. ;    Following these is an ASM_END byte.
  1165. ;
  1166. ;    Exceptions:
  1167. ;        ASM_SEG and ASM_LOCKREP are followed by just one byte, the
  1168. ;        prefix byte.
  1169. ;        ASM_DB, ASM_DW, and ASM_DD don't need to be followed by
  1170. ;        anything.
  1171. ;
  1172.  
  1173. ASM_END        equ    0ffh
  1174. ASM_DB        equ    0feh
  1175. ASM_DW        equ    0fdh
  1176. ASM_DD        equ    0fch
  1177. ASM_ORG        equ    0fbh
  1178. ASM_WAIT     equ    0fah
  1179. ASM_D32        equ    0f9h
  1180. ASM_AAX        equ    0f8h
  1181. ASM_SEG        equ    0f7h
  1182. ASM_LOCKREP    equ    0f6h
  1183.  
  1184. ASM_LOCKABLE    equ    0f5h
  1185. ASM_MACH6    equ    0f4h
  1186. ASM_MACH0    equ    0eeh
  1187.  
  1188.     cmp    byte [si],ASM_LOCKREP    ;check for mnemonic flag byte
  1189.     jb    aa15        ;if none
  1190.     lodsb            ;get the prefix
  1191.     sub    al,ASM_LOCKREP
  1192.     je    aa18        ;if LOCK or REP...
  1193.     cbw
  1194.     dec    ax
  1195.     jz    aa17        ;if segment prefix
  1196.     dec    ax
  1197.     jz    aa16        ;if aad or aam
  1198.     cmp    al,3
  1199.     jae    aa20        ;if ASM_ORG or ASM_DD or ASM_DW or ASM_DB
  1200.     or    asm_mn_flags,al    ;save AMF_D32 or AMF_WAIT
  1201. aa15:    jmp    ab01        ;now process the arguments
  1202.  
  1203. aa16:    jmp    ab00
  1204.  
  1205. ;    segment prefix
  1206.  
  1207. aa17:    lodsb            ;get prefix value
  1208.     mov    aa_seg_pre,al
  1209.     or    asm_mn_flags,AMF_MSEG
  1210.     pop    si
  1211.     pop    ax
  1212.     lodsb
  1213.     cmp    al,CR
  1214.     je    aa13a        ;if end of line ( ==> error)
  1215.     cmp    al,';'
  1216.     je    aa13a        ;if end of line (comment) ( ==> error)
  1217.     jmp    aa02        ;back for more
  1218.  
  1219. ;    LOCK or REP prefix
  1220.  
  1221. aa18:    lodsb            ;get prefix value
  1222.     xchg    al,aa_saved_prefix
  1223.     cmp    al,0
  1224.     jnz    aa13a        ;if there already was a saved prefix
  1225.     pop    si
  1226.     pop    ax
  1227.     lodsb
  1228.     cmp    al,CR
  1229.     je    aa19        ;if end of line
  1230.     cmp    al,';'
  1231.     je    aa19        ;if end of line (comment)
  1232.     jmp    aa02        ;back for more
  1233.  
  1234. aa19:    mov    al,aa_saved_prefix    ;just a prefix, nothing else
  1235.     mov    di,offset line_out
  1236.     stosb
  1237.     jmp    aa31
  1238.  
  1239. ;    Pseudo ops (org or db/dw/dd).
  1240.  
  1241. aa20:    cmp    word aa_saved_prefix,0
  1242.     jnz    aa13a        ;if there was a prefix or a segment
  1243.     pop    si        ;get position in input line
  1244.     sub    al,3        ;AX=0 if org, 1 if dd, 2 if dw, 3 if db.
  1245.     jnz    aa20m        ;if not ORG
  1246.  
  1247. ;    Process ORG pseudo op.
  1248.  
  1249.     call    skipwhite
  1250.     cmp    al,CR
  1251.     je    aa20a        ;if nothing
  1252.     mov    bx,a_addr+2    ;default segment
  1253.     jmp    aa00a        ;go to top
  1254. aa20a:    jmp    aa01        ;get next line
  1255.  
  1256. ;    Data instructions (DB/DW/DD).
  1257.  
  1258. aa20m:    mov    di,offset line_out    ;put the bytes here when we get them
  1259.     xchg    ax,bx        ;mov bx,ax
  1260.     mov    al,aadbsiz[bx]    ;move maximum size
  1261.     mov    aadbsiz,al
  1262.     shl    bx,1
  1263.     mov    ax,aadbsto[bx]    ;move address of storage routine
  1264.     mov    aadbsto,ax
  1265.  
  1266. aa21:    call    skipwhite
  1267.     cmp    al,CR
  1268.     je    aa31        ;if end of line
  1269.     cmp    al,'"'
  1270.     je    aa22        ;if string
  1271.     cmp    al,"'"
  1272.     je    aa22        ;if string
  1273.     call    aageti        ;get a numerical value into dx:bx, size into cl
  1274.     cmp    cl,aadbsiz
  1275.     jg    aa27        ;if overflow
  1276.     xchg    ax,bx
  1277.     call    [aadbsto]    ;store the value
  1278.     cmp    di,offset real_end
  1279.     ja    aa27        ;if output line overflow
  1280.     xchg    ax,bx
  1281.     jmp    short aa26    ;done with this one
  1282. aa22:    mov    ah,al
  1283. aa23:    lodsb
  1284.     cmp    al,CR
  1285.     je    aa27        ;if end of line
  1286.     cmp    al,ah
  1287.     je    aa25        ;if end of string
  1288. aa24:    stosb
  1289.     cmp    di,offset real_end
  1290.     ja    aa27        ;if output line overflow
  1291.     jmp    aa23
  1292. aa25:    lodsb
  1293.     cmp    al,ah
  1294.     je    aa24        ;if just a doubled quote character
  1295. aa26:    call    skipwh0
  1296.     cmp    al,CR
  1297.     je    aa31        ;if end of line
  1298.     cmp    al,','
  1299.     je    aa21        ;if no error
  1300. aa27:    jmp    aa13b        ;error
  1301.  
  1302. aa28:    stosw            ;store a dword value
  1303.     xchg    ax,dx
  1304.     stosw
  1305.     xchg    ax,dx
  1306.     ret
  1307.  
  1308. aa29:    stosw            ;store a word value
  1309.     ret
  1310.  
  1311. aa30:    stosb            ;store a byte value
  1312.     ret
  1313.  
  1314. ;    End of line.  Copy it over.
  1315.  
  1316. aa31:    mov    si,offset line_out
  1317.     mov    cx,di
  1318.     sub    cx,si
  1319.     les    di,a_addr
  1320.     rep    movsb        ;copy it
  1321.     push    ds        ;restore es
  1322.     pop    es
  1323.     mov    a_addr,di
  1324.     jmp    aa01
  1325.  
  1326. ;    Here we process the AAD and AAM instructions.  They are special
  1327. ;    in that they may take a one-byte argument, or none (in which case
  1328. ;    the argument defaults to 0ah = ten).
  1329.  
  1330. ab00:    mov    mneminfo,si    ;save this address
  1331.     pop    si
  1332.     lodsb
  1333.     cmp    al,CR
  1334.     je    ab00a        ;if end of line
  1335.     cmp    al,';'
  1336.     jne    ab01b        ;if not end of line
  1337. ab00a:    mov    si,offset aam_args    ;fake a 0ah argument
  1338.     jmp    short ab01a
  1339.  
  1340. ;    Process normal instructions.
  1341.  
  1342. ;    First we parse each argument into a 12-byte data block, stored
  1343. ;    consecutively at line_out, line_out+12, etc.
  1344. ;    This is stored as follows.
  1345.  
  1346. ;    [di]    Flags (ARG_DEREF, etc.)
  1347. ;    [di+1]    Unused
  1348. ;    [di+2]    Size argument, if any (1=byte, 2=word, 3=(unused), 4=dword,
  1349. ;        5=qword, 6=float, 7=double, 8=tbyte, 9=short, 10=long, 11=near,
  1350. ;        12=far).
  1351. ;    [di+3]    Size of MOD R/M displacement
  1352. ;    [di+4]    First register, or MOD R/M byte
  1353. ;    [di+5]    Second register or index register or SIB byte
  1354. ;    [di+6]    Index factor
  1355. ;    [di+7]    Sizes of numbers are or-ed here
  1356. ;    [di+8]    (dword) number
  1357.  
  1358. ;    For arguments of the form xxxx:yyyyyyyy, xxxx is stored in [di+5],
  1359. ;    and yyyyyyyy in [di+8].  The number of bytes in yyyyyyyy is stored in
  1360. ;    opaddr, 2 is stored in [di+4], and di is stored in xxaddr.
  1361.  
  1362. ab01:    mov    mneminfo,si    ;save this address
  1363.     pop    si        ;get position in line
  1364. ab01a:    lodsb
  1365. ab01b:    mov    di,offset line_out
  1366.  
  1367. ;    Begin loop over operands.
  1368.  
  1369. ab02:    cmp    al,CR
  1370.     je    ab03        ;if end of line
  1371.     cmp    al,';'
  1372.     jne    ab04        ;if not end of line
  1373. ab03:    jmp    ab99        ;to next phase
  1374.  
  1375. ab04:    push    di        ;clear out the next storage area
  1376.     mov    cx,6
  1377.     xor    ax,ax
  1378.     rep    stosw
  1379.     pop    di
  1380.  
  1381. ;    Small loop over "BYTE PTR" and segment prefixes.
  1382.  
  1383. ab05:    dec    si
  1384.     mov    ax,[si]
  1385.     and    ax,TOUPPER_W
  1386.     cmp    byte [di+2],0
  1387.     jne    ab07        ;if already have "BYTE PTR"
  1388.     push    di
  1389.     mov    di,offset sizetcnam
  1390.     mov    cx,12
  1391.     repne    scasw
  1392.     pop    di
  1393.     jne    ab07        ;if not found
  1394.     or    cx,cx
  1395.     jnz    ab06        ;if not 'FA'
  1396.     mov    al,[si+2]
  1397.     and    al,TOUPPER
  1398.     cmp    al,'R'
  1399.     jne    ab09        ;if not 'FAR' (could be hexadecimal)
  1400. ab06:    sub    cl,12
  1401.     neg    cl        ;convert to 1, ..., 12
  1402.     mov    [di+2],cl
  1403.     call    skipalpha
  1404.     call    skipwh0
  1405.     mov    ah,[si]
  1406.     and    ax,TOUPPER_W
  1407.     cmp    ax,'AF'
  1408.     jne    ab06a        ;if not 'FA'
  1409.     mov    al,[si+1]
  1410.     and    al,TOUPPER
  1411.     cmp    al,'R'
  1412.     jne    ab05        ;if not 'FAR'
  1413.     mov    byte [di+2],12    ;set 'FAR'
  1414.     or    asm_mn_flags,AMF_D32
  1415.     call    skipalpha
  1416.     call    skipwh0
  1417.     mov    ah,[si]
  1418.     and    ax,TOUPPER_W
  1419. ab06a:    cmp    ax,'TP'
  1420.     jne    ab05        ;if not 'PTR'
  1421.     call    skipalpha
  1422.     call    skipwh0
  1423.     jmp    ab05
  1424.  
  1425. ab07:    cmp    aa_seg_pre,0
  1426.     jne    ab09        ;if we already have a segment prefix
  1427.     push    di
  1428.     mov    di,offset segrgnam
  1429.     mov    cx,6
  1430.     repne    scasw
  1431.     pop    di
  1432.     jne    ab09        ;if not found
  1433.     push    si        ;save si in case there's no colon
  1434.     lodsw
  1435.     call    skipwhite
  1436.     cmp    al,':'
  1437.     jne    ab08        ;if not followed by ':'
  1438.     pop    ax        ;discard saved si
  1439.     call    skipwhite    ;skip it
  1440.     mov    bx,offset prefixlist + 5
  1441.     sub    bx,cx
  1442.     mov    al,[bx]        ;look up the prefix byte
  1443.     mov    aa_seg_pre,al    ;save it away
  1444.     jmp    ab05
  1445.  
  1446. ab08:    pop    si
  1447.  
  1448. ;    Begin parsing main part of argument.
  1449.  
  1450. ab09:    push    di        ;check for solo registers
  1451.     mov    di,offset rgnam816
  1452.     mov    cx,27
  1453.     call    aagetreg
  1454.     pop    di
  1455.     jc    ab14        ;if not a register
  1456.     or    byte [di],ARG_JUSTREG
  1457.     mov    [di+4],bl    ;save register number
  1458.     cmp    bl,24
  1459.     jae    ab09a        ;if it's not a normal register
  1460.     xchg    ax,bx        ;mov al,bl
  1461.     mov    cl,3
  1462.     shr    al,cl        ;al = size:  0 -> byte, 1 -> word, 2 -> dword
  1463.     add    al,-2
  1464.     adc    al,3        ;convert to 1, 2, 4 (respectively)
  1465.     jmp    short ab13
  1466.  
  1467. ab09a:    xor    byte [di],ARG_JUSTREG + ARG_WEIRDREG
  1468.     mov    al,2        ;register size
  1469.     cmp    bl,30
  1470.     ja    ab11        ;if it's CR, DR, TR, or MM
  1471.     je    ab09b        ;if it's ST
  1472.     cmp    bl,28
  1473.     jb    ab13        ;if it's a normal segment register
  1474.     or    asm_mn_flags,AMF_FSGS    ;flag it
  1475.     jmp    short ab13
  1476.  
  1477. ab09b:    cmp    byte [si],'('
  1478.     jne    ab12        ;if just plain ST
  1479.     lodsb
  1480.     lodsb
  1481.     sub    al,'0'
  1482.     cmp    al,7
  1483.     ja    ab10        ;if not 0..7
  1484.     mov    [di+5],al    ;save the number
  1485.     lodsb
  1486.     cmp    al,')'
  1487.     je    ab12        ;if not error
  1488. ab10:    jmp    aa13b        ;error
  1489.  
  1490. ab11:    lodsb            ;other registers (CR, DR, TR, MM)
  1491.     sub    al,'0'
  1492.     cmp    al,7
  1493.     ja    ab10        ;if error
  1494.     mov    [di+5],al    ;save the number
  1495.     mov    al,4        ;register size
  1496.     cmp    bl,31
  1497.     jne    ab13        ;if not MM register
  1498. ab12:    mov    al,0
  1499. ab13:    cmp    al,[di+2]    ;compare with stated size
  1500.     je    ab13a        ;if same
  1501.     xchg    al,[di+2]
  1502.     cmp    al,0
  1503.     jne    ab10        ;if wrong size given
  1504. ab13a:    jmp    ab44        ;done with this operand
  1505.  
  1506. ;    It's not a register reference.  Try for a number.
  1507.  
  1508. ab14:    lodsb
  1509.     call    aaifnum
  1510.     jc    ab17        ;it's not a number
  1511. ab14a:    call    aageti        ;get the number
  1512.     mov    [di+7],cl
  1513.     mov    [di+8],bx
  1514.     mov    [di+10],dx
  1515.     call    skipwh0
  1516.     cmp    cl,2
  1517.     jg    ab17        ;if we can't have a colon here
  1518.     cmp    al,':'
  1519.     jne    ab17        ;if not xxxx:yyyy
  1520.     call    skipwhite
  1521.     call    aageti
  1522.     mov    cx,[di+8]
  1523.     mov    [di+5],cx
  1524.     mov    [di+8],bx
  1525.     mov    [di+10],dx
  1526.     or    byte [di],ARG_FARADDR
  1527.     jmp    ab43        ;done with this operand
  1528.  
  1529. ;    Check for [...].
  1530.  
  1531. ab15:    jmp    ab30        ;do post-processing
  1532.  
  1533. ab16:    call    skipwhite
  1534. ab17:    cmp    al,'['        ;begin loop over sets of []
  1535.     jne    ab15        ;if not [
  1536.     or    byte [di],ARG_DEREF ;set the flag
  1537. ab18:    call    skipwhite
  1538. ab19:    cmp    al,']'        ;begin loop within []
  1539.     je    ab16        ;if done
  1540.  
  1541. ;    Check for a register (within []).
  1542.  
  1543.     dec    si
  1544.     push    di
  1545.     mov    di,offset rgnam16
  1546.     mov    cx,8
  1547.     call    aagetreg
  1548.     pop    di
  1549.     jc    ab25        ;if not a register
  1550.     cmp    bl,16
  1551.     jae    ab20        ;if 32-bit register
  1552.     add    bl,8        ;adjust 0..7 to 8..15
  1553.     jmp    short ab21
  1554. ab20:    cmp    byte [di+5],0
  1555.     jnz    ab21        ;if we already have an index
  1556.     call    skipwhite
  1557.     dec    si
  1558.     cmp    al,'*'
  1559.     jne    ab21        ;if not followed by '*'
  1560.     inc    si
  1561.     mov    [di+5],bl    ;save index register
  1562.     call    skipwhite
  1563.     call    aageti
  1564.     call    aaconvindex
  1565.     jmp    short ab28    ;ready for next part
  1566.     
  1567. ab21:    cmp    byte [di+4],0
  1568.     jne    ab22        ;if there's already a register
  1569.     mov    byte [di+4],bl
  1570.     jmp    short ab23
  1571. ab22:    cmp    byte [di+5],0
  1572.     jne    ab24        ;if too many registers
  1573.     mov    byte [di+5],bl
  1574. ab23:    call    skipwhite
  1575.     jmp    short ab28    ;ready for next part
  1576.  
  1577. ab24:    jmp    aa13b        ;error
  1578.  
  1579. ;    Try for a number (within []).
  1580.  
  1581. ab25:    lodsb
  1582. ab26:    call    aageti        ;get a number (or flag an error)
  1583.     call    skipwh0
  1584.     cmp    al,'*'
  1585.     je    ab27        ;if it's an index factor
  1586.     or    [di+7],cl
  1587.     add    [di+8],bx
  1588.     adc    [di+10],dx
  1589.     jmp    short ab28    ;next part ...
  1590.  
  1591. ab27:    call    aaconvindex
  1592.     call    skipwhite
  1593.     dec    si
  1594.     push    di
  1595.     mov    di,offset rgnam16
  1596.     xor    cx,cx
  1597.     call    aagetreg
  1598.     pop    di
  1599.     jc    ab24        ;if error
  1600.     cmp    byte [di+5],0
  1601.     jne    ab24        ;if there is already a register
  1602.     mov    [di+5],bl
  1603.     call    skipwhite
  1604.  
  1605. ;    Ready for the next term within [].
  1606.  
  1607. ab28:    cmp    al,'-'
  1608.     je    ab26        ;if a (negative) number is next
  1609.     cmp    al,'+'
  1610.     jne    ab29        ;if no next term (presumably)
  1611.     jmp    ab18
  1612. ab29:    jmp    ab19        ;back for more
  1613.     
  1614. ;    Post-processing for complicated arguments.
  1615.  
  1616. ab30:    cmp    word [di+4],0
  1617.     jnz    ab32        ;if registers were given ( ==> create MOD R/M)
  1618.     cmp    byte [di+7],0
  1619.     jz    ab31        ;if nothing was given ( ==> error)
  1620.     cmp    byte [di],0
  1621.     jnz    ab30b        ;if it was not immediate
  1622.     or    byte [di],ARG_IMMED
  1623. ab30a:    jmp    ab43        ;done with this argument
  1624. ab30b:    mov    al,2        ;size of the displacement
  1625.     test    byte [di+7],4
  1626.     jz    ab30c        ;if not 32-bit displacement
  1627.     inc    ax
  1628.     inc    ax
  1629.     or    asm_mn_flags,AMF_A32    ;32-bit addressing
  1630. ab30c:    mov    byte [di+3],al    ;save displacement size
  1631.     jmp    ab30a        ;done with this argument
  1632. ab31:    jmp    aa13b        ;flag an error
  1633.  
  1634. ;    Create the MOD R/M byte.
  1635. ;    (For disp-only or register, this will be done later as needed.)
  1636.  
  1637. ab32:    or    byte [di],ARG_MODRM
  1638.     mov    al,[di+4]
  1639.     or    al,[di+5]
  1640.     test    al,16
  1641.     jnz    ab34        ;if 32-bit addressing
  1642.     test    byte [di+7],4
  1643.     jnz    ab34        ;if 32-bit addressing
  1644.     mov    ax,[di+4]
  1645.     cmp    al,ah
  1646.     ja    ab33        ;make sure al >= ah
  1647.     xchg    al,ah
  1648. ab33:    push    di
  1649.     mov    di,offset modrmtab
  1650.     mov    cx,8
  1651.     repne    scasw
  1652.     pop    di
  1653.     jne    ab31        ;if not among the possibilities
  1654.     mov    bx,206h        ;max disp = 2 bytes; 6 ==> (non-existent) [bp]
  1655.     jmp    short ab39    ;done (just about)
  1656.  
  1657. ab34:    or    asm_mn_flags,AMF_A32    ;32-bit addressing
  1658.     mov    al,[di+4]
  1659.     or    al,[di+6]
  1660.     jnz    ab35        ;if we can't optimize [EXX*1] to [EXX]
  1661.     mov    ax,[di+4]
  1662.     xchg    al,ah
  1663.     mov    [di+4],ax
  1664. ab35:    mov    bx,405h        ;max disp = 4 bytes; 5 ==> (non-existent) [bp]
  1665.     cmp    byte [di+5],0
  1666.     jne    ab36        ;if there's a SIB
  1667.     mov    cl,[di+4]
  1668.     cmp    cl,16
  1669.     jl    ab31        ;if wrong register type
  1670.     and    cl,7
  1671.     cmp    cl,4        ;check for ESP
  1672.     jne    ab39        ;if not, then we're done (otherwise do SIB)
  1673.  
  1674. ab36:    or    asm_mn_flags,AMF_SIB    ;form SIB
  1675.     mov    ch,[di+6]    ;get SS bits
  1676.     mov    cl,3
  1677.     shl    ch,cl        ;shift them halfway into place
  1678.     mov    al,[di+5]    ;index register
  1679.     cmp    al,20
  1680.     je    ab31        ;if ESP ( ==> error)
  1681.     cmp    al,0
  1682.     jne    ab37        ;if not zero
  1683.     mov    al,20        ;set it for index byte 4
  1684. ab37:    cmp    al,16
  1685.     jl    ab31        ;if wrong register type
  1686.     and    al,7
  1687.     or    ch,al        ;put it into the SIB
  1688.     shl    ch,cl        ;shift it into place
  1689.     inc    cx        ;R/M for SIB = 4
  1690.     mov    al,[di+4]    ;now get the low 3 bits
  1691.     cmp    al,0
  1692.     jne    ab38        ;if there was a first register
  1693.     or    ch,5
  1694.     jmp    short ab42    ;MOD = 0, disp is 4 bytes
  1695.  
  1696. ab38:    cmp    al,16
  1697.     jl    ab45        ;if wrong register type
  1698.     and    al,7        ;first register
  1699.     or    ch,al        ;put it into the SIB
  1700.     cmp    al,5
  1701.     je    ab40        ;if it's EBP, then we don't recognize disp=0
  1702.                 ;otherwise bl will be set to 0
  1703.  
  1704. ;    Find the size of the displacement.
  1705.  
  1706. ab39:    cmp    cl,bl
  1707.     je    ab40        ;if it's [(E)BP], then disp=0 is still 1 byte
  1708.     mov    bl,0        ;allow 0-byte disp
  1709.  
  1710. ab40:    push    cx
  1711.     mov    al,[di+8]
  1712.     mov    cl,7
  1713.     sar    al,cl
  1714.     pop    cx
  1715.     mov    ah,[di+9]
  1716.     cmp    al,ah
  1717.     jne    ab41        ;if it's bigger than 1 byte
  1718.     cmp    ax,[di+10]
  1719.     jne    ab41        ;ditto
  1720.     mov    bh,0        ;no displacement
  1721.     or    bl,[di+8]
  1722.     jz    ab42        ;if disp = 0 and it's not (E)BP
  1723.     inc    bh        ;disp = 1 byte
  1724.     or    cl,40h        ;set MOD = 1
  1725.     jmp    short ab42    ;done
  1726.  
  1727. ab41:    or    cl,80h        ;set MOD = 2
  1728.  
  1729. ab42:    mov    [di+3],bh    ;store displacement size
  1730.     mov    [di+4],cx    ;store MOD R/M and maybe SIB
  1731.  
  1732. ;    Finish up with the operand.
  1733.  
  1734. ab43:    dec    si
  1735. ab44:    call    skipwhite
  1736.     add    di,12
  1737.     cmp    al,CR
  1738.     je    ab99        ;if end of line
  1739.     cmp    al,';'
  1740.     je    ab99        ;if comment (ditto)
  1741.     cmp    al,','
  1742.     jne    ab45        ;if not comma ( ==> error)
  1743.     cmp    di,offset line_out+36
  1744.     jae    ab45        ;if too many operands
  1745.     call    skipwhite
  1746.     jmp    ab02
  1747.  
  1748. ab45:    jmp    aa13b        ;error jump
  1749.  
  1750. ab99:    mov    byte [di],-1    ;end of parsing phase
  1751.     push    si        ;save the location of the end of the string
  1752.  
  1753. ;    For the next phase, we match the parsed arguments with the set of
  1754. ;    permissible argument lists for the opcode.  The first match wins.
  1755. ;    Therefore the argument lists should be ordered such that the
  1756. ;    cheaper ones come first.
  1757.  
  1758. ;    There is a tricky issue regarding sizes of memory references.
  1759. ;    Here are the rules:
  1760. ;       1.    If a memory reference is given with a size, then it's OK.
  1761. ;       2.    If a memory reference is given without a size, but some
  1762. ;        other argument is a register (which implies a size),
  1763. ;        then the memory reference inherits that size.
  1764. ;            Exceptions:    OP_CL does not imply a size
  1765. ;                    OP_SHOSIZ
  1766. ;       3.    If 1 and 2 do not apply, but this is the last possible argument
  1767. ;        list, and if the argument list requires a particular size, then
  1768. ;        that size is used.
  1769. ;       4.    In all other cases, flag an error.
  1770.  
  1771. ac01:    xor    ax,ax        ;zero out rmaddr through varflags or a_opcode
  1772.     mov    di,offset rmaddr
  1773.     mov    cx,7
  1774.     rep    stosw
  1775.     mov    si,mneminfo    ;address of the next argument variant
  1776.  
  1777. ;    Sort out initial bytes.  At this point:
  1778. ;    si = address of next argument variant
  1779. ;    di = address of next parsed argument table
  1780.  
  1781. ac02:    lodsb
  1782.     sub    al,ASM_MACH0
  1783.     jb    ac05        ;if no more special bytes
  1784.     cmp    al,ASM_LOCKABLE-ASM_MACH0
  1785.     je    ac03        ;if ASM_LOCKABLE
  1786.     ja    ac04        ;if ASM_END ( ==> error)
  1787.     mov    dismach,al    ;save machine type
  1788.     jmp    ac02        ;back for next byte
  1789. ac03:    or    varflags,VAR_LOCKABLE
  1790.     jmp    ac02        ;back for next byte
  1791.  
  1792. ac04:    jmp    aa13a        ;error
  1793.  
  1794. ;    Get and unpack the word.
  1795.  
  1796. ac05:    dec    si
  1797.     lodsw
  1798.     xchg    al,ah        ;put into little-endian order
  1799.     xor    dx,dx
  1800.     mov    bx,ASMMOD
  1801.     div    bx        ;ax = a_opcode; dx = index into opindex
  1802.     mov    a_opcode,ax    ;save ax
  1803.     mov    a_opcode2,ax    ;save the second copy
  1804.     cmp    ax,0dfh
  1805.     ja    ac05a        ;if not coprocessor instruction
  1806.     cmp    al,0d8h
  1807.     jb    ac05a        ;ditto
  1808.     or    dmflags,DM_COPR    ;flag it as an x87 instruction
  1809.     mov    ah,al        ;ah = low order byte of opcode
  1810.     lodsb            ;get extra byte
  1811.     mov    regmem,al    ;save it in regmem
  1812.     mov    a_opcode2,ax    ;save this for obsolete-instruction detection
  1813.     or    varflags,VAR_MODRM    ;flag its presence
  1814. ac05a:    mov    mneminfo,si    ;save si back again
  1815.     mov    si,dx
  1816.     mov    bl,opindex[si]
  1817.     lea    si,oplists[bx]    ;si = the address of our operand list
  1818.     mov    di,offset line_out
  1819.  
  1820. ;    Begin loop over operands.  At this point si and di are as for ac02.
  1821.  
  1822. ac06:    lodsb            ;get next operand byte
  1823.     cmp    al,0
  1824.     je    ac10        ;if end of list
  1825.     cmp    byte [di],-1
  1826.     je    ac01        ;if too few operands were given
  1827.     cmp    al,OP_SIZE
  1828.     jb    ac07        ;if no size needed
  1829.     mov    ah,0
  1830.     mov    cl,4
  1831.     shl    ax,cl
  1832.     shr    al,cl
  1833.     mov    a_reqsize,ah    ;save it away
  1834.     jmp    short ac08
  1835.  
  1836. ac07:    add    al,16-2        ;move these to the end of the previous list
  1837.  
  1838. ac08:    cbw
  1839.     xchg    ax,bx        ;now bx contains the offset
  1840.     mov    cx,asm_jmp1[bx]    ;subroutine address
  1841.     shr    bx,1
  1842.     mov    al,bittab[bx]
  1843.     test    al,[di]
  1844.     jz    ac09        ;if no required bits are present
  1845.     call    cx        ;call its specific routine
  1846.     cmp    word [si-1],(OP_1632+OP_R)*256+(OP_1632+OP_R_MOD)
  1847.     je    ac06        ;(hack) for IMUL instruction
  1848.     add    di,12        ;next operand
  1849.     jmp    ac06        ;back for more
  1850.  
  1851. ac09:    jmp    ac01        ;back to next possibility
  1852.  
  1853. ;    End of operand list.
  1854.  
  1855. ac10:    cmp    byte [di],-1
  1856.     jne    ac09        ;if too many operands were given
  1857.  
  1858. ;    Final check on sizes
  1859.  
  1860.     mov    al,varflags
  1861.     test    al,VAR_SIZ_NEED
  1862.     jz    ac12        ;if no size needed
  1863.     test    al,VAR_SIZ_GIVN
  1864.     jnz    ac12        ;if a size was given
  1865.     test    al,VAR_SIZ_FORCD
  1866.     jz    ac09        ;if the size was not forced ( ==> reject)
  1867.     mov    si,mneminfo
  1868.     cmp    byte [si],ASM_END
  1869.     je    ac12        ;if this is the last one
  1870. ac11:    jmp    aa13a        ;it was not ==> error (not a retry)
  1871.  
  1872. ;    Check other prefixes.
  1873.  
  1874. ac12:    mov    al,aa_saved_prefix
  1875.     cmp    al,0
  1876.     jz    ac14        ;if no saved prefixes to check
  1877.     cmp    al,0f0h
  1878.     jne    ac13        ;if it's a rep prefix
  1879.     test    varflags,VAR_LOCKABLE
  1880.     jz    ac11        ;if this variant is not lockable ( ==> error)
  1881.     jmp    short ac14    ;done
  1882.  
  1883. ac13:    mov    ax,a_opcode    ;check if opcode is OK for rep{,z,nz}
  1884.     and    al,not 1    ;clear low order bit
  1885.     cmp    ax,0ffh
  1886.     ja    ac11        ;if it's not a 1 byte instruction
  1887.     mov    di,offset replist ;list of instructions that go with rep
  1888.     mov    cx,7
  1889.     repne    scasb
  1890.     jnz    ac11        ;if it's not among them
  1891.  
  1892. ac14:    test    asm_mn_flags,AMF_MSEG
  1893.     jz    ac15        ;if no segment prefix before mnemonic
  1894.     mov    ax,a_opcode    ;check if opcode allows this
  1895.     cmp    ax,0ffh
  1896.     ja    ac11        ;if it's not a 1 byte instruction
  1897.     mov    di,offset prfxtab
  1898.     mov    cx,P_LEN
  1899.     repne    scasb
  1900.     jnz    ac11        ;if it's not in the list
  1901.  
  1902. ac15:    mov    bx,immaddr
  1903.     or    bx,bx
  1904.     jz    ac16        ;if no immediate data
  1905.     mov    al,opsize
  1906.     neg    al
  1907.     shl    al,1
  1908.     test    al,[bx+7]
  1909.     jnz    ac11        ;if the immediate data was too big
  1910.  
  1911. ;    Put the instruction together
  1912. ;    (maybe is this why they call it an assembler)
  1913.  
  1914. ;    First, the prefixes (including preceding WAIT instruction)
  1915.  
  1916. ac16:    les    di,a_addr
  1917.     test    asm_mn_flags,AMF_WAIT
  1918.     jz    ac17        ;if no wait instruction beforehand
  1919.     mov    al,9bh
  1920.     stosb
  1921.  
  1922. ac17:    mov    al,aa_saved_prefix
  1923.     cmp    al,0
  1924.     jz    ac18        ;if no LOCK or REP prefix
  1925.     stosb
  1926.  
  1927. ac18:    mov    al,67h        ;address-size prefix
  1928.     test    asm_mn_flags,AMF_A32
  1929.     jz    ac19        ;if none
  1930.     stosb
  1931.  
  1932. ac19:    dec    ax        ;al = 66h, operand-size prefix
  1933.     test    asm_mn_flags,AMF_D32
  1934.     jnz    ac20        ;if flag set for 32-bit operands
  1935.     test    varflags,VAR_D32
  1936.     jz    ac21        ;if no flag on instruction variant
  1937. ac20:    stosb            ;store operand-size prefix
  1938.  
  1939. ac21:    mov    al,aa_seg_pre
  1940.     cmp    al,0
  1941.     jz    ac22        ;if no segment prefix
  1942.     stosb
  1943.     cmp    al,64h
  1944.     jb    ac22        ;if not 64 or 65 (FS or GS)
  1945.     or    asm_mn_flags,AMF_FSGS    ;flag it
  1946.  
  1947. ;    Now emit the instruction itself.
  1948.  
  1949. ac22:    mov    ax,a_opcode
  1950.     mov    bx,ax
  1951.     sub    bx,576
  1952.     jae    ac23        ;if 576-...
  1953.     cmp    ax,512
  1954.     jb    ac24        ;if regular instruction
  1955.     or    dmflags,DM_COPR    ;flag it as an x87 instruction
  1956.     and    al,038h        ;get register part
  1957.     or    regmem,al
  1958.     xchg    ax,bx        ;mov ax,bx (the low bits of bx are good)
  1959.     and    al,7
  1960.     or    al,0d8h
  1961.     jmp    short ac25    ;on to decoding the instruction
  1962.     
  1963. ac23:    mov    cl,3        ;one instruction of a group
  1964.     shr    bx,cl
  1965.     and    al,7
  1966.     shl    al,cl
  1967.     or    regmem,al
  1968.     shl    bx,1
  1969.     mov    ax,agroups[bx]    ;get actual opcode
  1970.  
  1971. ac24:    cmp    ah,0
  1972.     jz    ac25        ;if no 0fh first
  1973.     push    ax        ;store a 0fh
  1974.     mov    al,0fh
  1975.     stosb
  1976.     pop    ax
  1977.  
  1978. ac25:    or    al,opcode_or    ;put additional bits into the op code
  1979.     stosb            ;store the op code itself
  1980.  
  1981. ;    Now store the extra stuff that comes with the instruction.
  1982.  
  1983.     mov    ax,word regmem
  1984.     test    varflags,VAR_MODRM
  1985.     jz    ac26        ;if no mod reg/mem
  1986.     stosb
  1987.     test    asm_mn_flags,AMF_SIB
  1988.     jz    ac26        ;if no SIB
  1989.     dec    di
  1990.     stosw            ;store the MOD R/M and SIB, too
  1991.  
  1992. ac26:    mov    bx,rmaddr
  1993.     or    bx,bx
  1994.     jz    ac27        ;if no offset associated with the R/M
  1995.     mov    cl,[bx+3]
  1996.     mov    ch,0
  1997.     lea    si,[bx+8]
  1998.     rep    movsb        ;store the R/M offset (or memory offset)
  1999.  
  2000. ;    Now store immediate data
  2001.  
  2002. ac27:    mov    bx,immaddr
  2003.     or    bx,bx
  2004.     jz    ac28        ;if no immediate data
  2005.     mov    al,opsize
  2006.     cbw
  2007.     xchg    ax,cx        ;mov cx,ax
  2008.     lea    si,[bx+8]
  2009.     rep    movsb
  2010.  
  2011. ;    Now store additional bytes (needed for, e.g., enter instruction)
  2012.  
  2013. ac28:    mov    bx,xxaddr
  2014.     or    bx,bx
  2015.     jz    ac29        ;if no additional data
  2016.     lea    si,[bx+4]
  2017.     lodsb
  2018.     cbw
  2019.     xchg    ax,cx        ;mov cx,ax
  2020.     rep    movsb
  2021.  
  2022. ;    Done emitting.
  2023.  
  2024. ac29:    push    cs        ;restore ES
  2025.     pop    es
  2026.     mov    a_addr,di
  2027.  
  2028. ;    Compute machine type.
  2029.  
  2030.     cmp    dismach,3
  2031.     jae    ac31        ;if we already know a 386 is needed
  2032.     test    asm_mn_flags,AMF_D32 + AMF_A32 + AMF_FSGS
  2033.     jnz    ac30        ;if 386
  2034.     test    varflags,VAR_D32
  2035.     jz    ac31        ;if not 386
  2036. ac30:    mov    dismach,3
  2037. ac31:    mov    di,offset a_opcode2 + 2 ; info on this instruction
  2038.     call    showmach    ;get machine message into si, length into cx
  2039.     jcxz    ac33        ;if no message
  2040.  
  2041. ac32:    mov    di,offset line_out
  2042.     rep    movsb        ;copy the line to line_out
  2043.     call    putsline
  2044.  
  2045. ac33:    jmp    aa01        ;back for the next input line
  2046.  
  2047. ;    ||| This is debugging code.  It assumes that the original value
  2048. ;    of a_addr is on the top of the stack.
  2049.  
  2050. ;    pop    si        ;get orig. a_addr
  2051. ;    mov    ax,a_addr+2
  2052. ;    mov    u_addr,si
  2053. ;    mov    u_addr+2,ax
  2054. ;    mov    bx,a_addr
  2055. ;    sub    bx,si
  2056. ;    mov    di,offset line_out
  2057. ;    mov    cx,10
  2058. ;    mov    al,' '
  2059. ;    rep    stosb
  2060. ;    mov    ds,a_addr+2
  2061.  
  2062. ;ax1:    lodsb
  2063. ;    call    hexbyte        ;display the bytes generated
  2064. ;    dec    bx
  2065. ;    jnz    ax1
  2066. ;    push    cs
  2067. ;    pop    ds
  2068. ;    call    putsline
  2069. ;    mov    byte disflags,0
  2070. ;    call    disasm        ;disassemble the new instruction
  2071. ;    jmp    aa01        ;back to next input line
  2072.  
  2073. ;    Routines to check for specific operand types.
  2074. ;    Upon success, the routine returns.
  2075. ;    Upon failure, it pops the return address and jumps to ac01.
  2076. ;    The routines must preserve si and di.
  2077.  
  2078. ;    OP_RM and OP_M:  form MOD R/M byte.
  2079.  
  2080. ao01:    call    ao90        ;form reg/mem byte
  2081.     jmp    short ao07    ;go to the size check
  2082.  
  2083. ;    OP_R:  register.
  2084.  
  2085. ao02:    mov    al,[di+4]    ;register number
  2086.     and    al,7
  2087.     mov    cl,3
  2088.     shl    al,cl        ;shift it into place
  2089.     or    regmem,al    ;put it into the reg/mem byte
  2090.     jmp    short ao07    ;go to the size check
  2091.  
  2092. ;    OP_R_ADD:  register, added to the instruction.
  2093.  
  2094. ao03:    mov    al,[di+4]
  2095.     and    al,7
  2096.     mov    opcode_or,al    ;put it there
  2097.     jmp    short ao07    ;go to the size check
  2098.  
  2099. ;    OP_IMM:  immediate data.
  2100.  
  2101. ao04:    mov    immaddr,di    ;save the location of this
  2102.     jmp    short ao07    ;go to the size check
  2103.  
  2104. ;    OP_MOFFS:  just the memory offset
  2105.  
  2106. ao05:    test    byte [di],ARG_MODRM
  2107.     jnz    ao11        ;if MOD R/M byte ( ==> reject)
  2108.     mov    rmaddr,di    ;save the pointer
  2109.     jmp    short ao07    ;go to the size check
  2110.  
  2111. ;    OP_AX:  check for AL/AX/EAX
  2112.  
  2113. ao06:    test    byte [di+4],7
  2114.     jnz    ao11        ;if wrong register
  2115.     ;jmp    short ao07    ;go to the size check
  2116.  
  2117. ;    Size check
  2118.  
  2119. ao07:    or    varflags,VAR_SIZ_NEED
  2120.     mov    al,a_reqsize
  2121.     sub    al,5        ;OP_1632 >> 4
  2122.     jl    ao12        ;if OP_ALL
  2123.     jz    ao13        ;if OP_1632
  2124.     add    al,-3
  2125.     adc    al,3        ;convert 3 --> 4
  2126. ao08:    or    varflags,VAR_SIZ_FORCD + VAR_SIZ_NEED
  2127.     mov    bl,[di+2]
  2128.     or    bl,bl
  2129.     jz    ao09        ;if no size given
  2130.     or    varflags,VAR_SIZ_GIVN
  2131.     cmp    al,bl
  2132.     jne    ao11        ;if sizes conflict
  2133. ao09:    cmp    al,opsize
  2134.     je    ao10        ;if sizes agree
  2135.     xchg    al,opsize
  2136.     cmp    al,0
  2137.     jnz    ao11        ;if sizes disagree
  2138. ao10:    ret
  2139.  
  2140. ao11:    jmp    ao50        ;reject
  2141.  
  2142. ;    OP_ALL - Allow all sizes.
  2143.  
  2144. ao12:    mov    al,[di+2]
  2145.     cmp    al,1
  2146.     je    ao15        ;if byte
  2147.     jb    ao14        ;if unknown
  2148.     or    opcode_or,1    ;set bit in instruction
  2149.     jmp    short ao14    ;if size is 16 or 32
  2150.  
  2151. ;    OP_1632 - word or dword.
  2152.  
  2153. ao13:    mov    al,[di+2]
  2154. ao14:    cmp    al,0
  2155.     je    ao16        ;if still unknown
  2156.     cmp    al,2
  2157.     je    ao15        ;if word
  2158.     cmp    al,4
  2159.     jne    ao11        ;if not dword
  2160.     or    varflags,VAR_D32;set flag
  2161. ao15:    mov    opsize,al
  2162.     or    varflags,VAR_SIZ_GIVN
  2163. ao16:    ret
  2164.  
  2165. ;    OP_M64 - 64-bit memory reference.
  2166. ;    OP_MFLOAT - single-precision floating point memory reference.
  2167. ;    OP_MDOUBLE - double-precision floating point memory reference.
  2168. ;    OP_M80 - 80-bit memory reference.
  2169. ;    OP_MXX - memory reference, size unknown.
  2170. ;    OP_FARMEM - far memory pointer
  2171.  
  2172. ao17:    call    ao90        ;form reg/mem byte
  2173.     mov    al,asm_siznum[bx-(OP_M64+16-2)/2]
  2174.     jmp    ao08        ;check size
  2175.  
  2176. ;    OP_FARP - far memory address contained in instruction
  2177.  
  2178. ao21:    mov    al,2
  2179.     cmp    word [di+10],0
  2180.     jz    ao22        ;if 16 bit address
  2181.     or    varflags,VAR_D32
  2182.     mov    al,4
  2183. ao22:    mov    byte [di+4],2
  2184.     mov    immaddr,di
  2185.     mov    opsize,al
  2186. ao22a:    mov    xxaddr,di
  2187.     ret
  2188.  
  2189. ;    OP_REL8 - relative address
  2190.  
  2191. ao23:    mov    al,9        ;short
  2192.     call    ao60        ;check the size
  2193.     mov    ax,a_addr    ;offset
  2194.     inc    ax
  2195.     inc    ax        ;$
  2196.     test    asm_mn_flags,AMF_D32
  2197.     jnz    ao23a        ;if JECXZ
  2198.     test    varflags,VAR_D32
  2199.     jz    ao23b        ;if no ECX given in loop instruction
  2200. ao23a:    inc    ax
  2201. ao23b:    xchg    ax,bx
  2202.     xor    cx,cx
  2203.     mov    ax,[di+8]
  2204.     mov    dx,[di+10]
  2205.     sub    ax,bx
  2206.     sbb    dx,cx
  2207.     mov    [di+5],al
  2208.     mov    cl,7
  2209.     sar    al,cl
  2210.     cmp    al,ah
  2211.     jne    ao24        ;if too big
  2212.     cmp    ax,dx
  2213.     jne    ao24        ;if too big
  2214.     mov    byte [di+4],1    ;save the length
  2215.     jmp    ao22a        ;save it away
  2216.  
  2217. ao24:    jmp    ao50        ;reject
  2218.  
  2219. ;    OP_REL1632:  relative jump to a longer address.
  2220.  
  2221. ao25:    mov    bx,a_addr
  2222.     inc    bx
  2223.     inc    bx
  2224.     inc    bx
  2225.     cmp    a_opcode,100h
  2226.     jb    ao26
  2227.     inc    bx
  2228. ao26:    mov    dx,[di+10]
  2229.     mov    al,[di+2]
  2230.     cmp    al,0
  2231.     je    ao27        ;if no size given
  2232.     cmp    al,10
  2233.     je    ao27        ;if "long" given
  2234.     cmp    al,4
  2235.     jne    ao24        ;if the size given was not "dword"
  2236.     inc    bx        ;once for the prefix, twice for the longer data
  2237.     inc    bx
  2238.     inc    bx
  2239.     or    varflags,VAR_D32
  2240.     jmp    short ao28
  2241.  
  2242. ao27:    or    dx,dx
  2243.     jnz    ao24        ;if operand is too big
  2244.     mov    al,2
  2245. ao28:    mov    [di+4],al    ;store the size
  2246.     mov    ax,[di+8]
  2247.     xor    cx,cx
  2248.     sub    ax,bx
  2249.     sbb    dx,cx
  2250.     mov    [di+5],ax
  2251.     mov    [di+7],dx
  2252.     mov    xxaddr,di
  2253.     ret
  2254.  
  2255. ;    OP_1CHK - The assembler can ignore this one.
  2256.  
  2257. ao29:    pop    ax        ;discard return address
  2258.     jmp    ac06        ;next operand
  2259.  
  2260. ;    OP_STI - ST(I).
  2261.  
  2262. ao30:    mov    al,30        ;code for ST
  2263.     mov    bl,[di+5]
  2264.     jmp    short ao38    ;to common code
  2265.  
  2266. ;    OP_CR
  2267.  
  2268. ao31:    mov    al,[di+5]    ;get the index
  2269.     cmp    al,4
  2270.     ja    ao24        ;if too big
  2271.     jne    ao32        ;if not CR4
  2272.     mov    dismach,5    ;CR4 is new to the 586
  2273. ao32:    cmp    al,1
  2274.     jne    ao33
  2275.     cmp    byte [di+12],-1
  2276.     jne    ao24        ;if another arg (can't mov CR1,xx)
  2277. ao33:    mov    al,32        ;code for CR
  2278.     jmp    short ao37    ;to common code
  2279.  
  2280. ;    OP_DR
  2281.  
  2282. ao34:    mov    al,33        ;code for DR
  2283.     jmp    short ao37    ;to common code
  2284.  
  2285. ;    OP_TR
  2286.  
  2287. ao35:    mov    al,[di+5]    ;get the index
  2288.     cmp    al,3
  2289.     jb    ao24        ;if too small
  2290.     cmp    al,6
  2291.     jae    ao36
  2292.     mov    dismach,4    ;TR3-5 are new to the 486
  2293. ao36:    mov    al,34        ;code for TR
  2294.  
  2295. ;    Common code for these weird registers.
  2296.  
  2297. ao37:    mov    bl,[di+5]
  2298.     mov    cl,3
  2299.     shl    bl,cl
  2300. ao38:    or    regmem,bl
  2301.     or    varflags,VAR_MODRM
  2302.     cmp    al,[di+4]    ;check for the right numbered register
  2303.     je    ao40        ;if yes, then return
  2304. ao38a:    jmp    ao50
  2305.  
  2306. ;    OP_SEGREG
  2307.  
  2308. ao39:    mov    al,[di+4]
  2309.     sub    al,24
  2310.     cmp    al,6
  2311.     jae    ao38a        ;if not a segment register
  2312.     mov    cl,3
  2313.     shl    al,cl
  2314.     or    regmem,al
  2315. ao40:    ret
  2316.  
  2317. ;    OP_IMMS8 - Sign-extended immediate byte
  2318.  
  2319. ao41:    mov    ax,[di+8]
  2320.     mov    cl,7
  2321.     sar    al,cl
  2322.     jmp    short ao43    ;common code
  2323.  
  2324. ;    OP_IMM8 - Immediate byte
  2325.  
  2326. ao42:    mov    ax,[di+8]
  2327.     mov    al,0
  2328. ao43:    cmp    al,ah
  2329.     jne    ao50        ;if too big
  2330.     cmp    ax,[di+10]
  2331.     jne    ao50        ;if too big
  2332.     mov    al,1
  2333.     call    ao60        ;check that size == 0 or 1
  2334.     mov    ah,[di+8]    ;store the byte, length 1
  2335.     mov    [di+4],ax
  2336.     mov    xxaddr,di
  2337. ao43r:    ret
  2338.  
  2339. ;    OP_ECX - CX or ECX, determining the operand size
  2340.  
  2341. ao43m:    cmp    byte [di+4],9    ;CX
  2342.     je    ao43r        ;if CX (do nothing)
  2343.     or    varflags,VAR_D32
  2344.     mov    al,17
  2345.     jmp    short ao48a    ;require ECX
  2346.  
  2347. ;    OP_SHOSIZ - force the user to declare the size of the next operand
  2348.  
  2349. ao44:    test    varflags,VAR_SIZ_NEED
  2350.     jz    ao45        ;if no testing needs to be done
  2351.     test    varflags,VAR_SIZ_GIVN
  2352.     jz    ao50        ;if size was given ( ==> reject)
  2353. ao45:    and    varflags,not VAR_SIZ_GIVN    ;clear the flag
  2354.     cmp    byte [si],OP_IMM8
  2355.     je    ao45a        ;if OP_IMM8 is next, then don't set VAR_SIZ_NEED
  2356.     or    varflags,VAR_SIZ_NEED
  2357. ao45a:    mov    opsize,0
  2358.     pop    ax        ;discard return address
  2359.     jmp    ac06        ;next operand
  2360.  
  2361. ;    OP_1
  2362.  
  2363. ao46:    cmp    word [di+7],101h
  2364.     jmp    short ao49    ;test it later
  2365.  
  2366. ;    OP_3
  2367.  
  2368. ao47:    cmp    word [di+7],301h
  2369.     jmp    short ao49    ;test it later
  2370.  
  2371. ;    OP_DX, OP_CL, OP_ST, OP_ES, ..., OP_GS
  2372.  
  2373. ao48:    mov    al,asm_regnum[bx-(OP_DX+16-2)/2]
  2374. ao48a:    cbw
  2375.     cmp    ax,[di+4]
  2376.  
  2377. ao49:    je    ao51
  2378.  
  2379. ;    Reject this operand list.
  2380.  
  2381. ao50:    pop    ax        ;discard return address
  2382.     jmp    ac01        ;go back to try the next alternative
  2383.  
  2384. ao51:    ret
  2385.  
  2386. ;    AASIZCHK - Check that the size given is 0 or AL.
  2387.  
  2388. ao60:    cmp    byte [di+2],0
  2389.     je    ao51
  2390.     cmp    byte [di+2],al
  2391.     je    ao51
  2392.     pop    ax        ;discard return address
  2393.     jmp    ao50
  2394.  
  2395. ;    Do reg/mem processing.
  2396. ;    Uses    AX
  2397.  
  2398. ao90:    test    byte [di],ARG_JUSTREG
  2399.     jnz    ao92        ;if just register
  2400.     test    byte [di],ARG_MODRM
  2401.     jz    ao91        ;if no precomputed MOD R/M byte
  2402.     mov    ax,word [di+4]    ;get the precomputed bytes
  2403.     jmp    short ao93    ;done
  2404.  
  2405. ao91:    mov    al,6        ;convert plain displacement to MOD R/M
  2406.     test    asm_mn_flags,AMF_A32
  2407.     jz    ao93        ;if 16 bit addressing
  2408.     dec    ax
  2409.     jmp    short ao93    ;done
  2410.  
  2411. ao92:    mov    al,[di+4]    ;convert register to MOD R/M
  2412.     and    al,7        ;get low 3 bits
  2413.     or    al,0c0h
  2414.  
  2415. ao93:    or    word regmem,ax    ;store the MOD R/M and SIB
  2416.     or    varflags,VAR_MODRM    ;flag its presence
  2417.     mov    rmaddr,di    ;save a pointer
  2418.     ret            ;done
  2419.  
  2420. ;    AAIFNUM - Determine if there's a number next.
  2421. ;    Entry    AL    First character of number
  2422. ;        SI    Address of next character of number
  2423. ;    Exit    CY    Clear if there's a number, set otherwise.
  2424. ;    Uses    None.
  2425.  
  2426. aaifnum:
  2427.     cmp    al,'-'
  2428.     je    aai2        ;if minus sign (carry is clear)
  2429.     push    ax
  2430.     sub    al,'0'
  2431.     cmp    al,10
  2432.     pop    ax
  2433.     jb    aai1        ;if a digit
  2434.     push    ax
  2435.     and    al,TOUPPER
  2436.     sub    al,'A'
  2437.     cmp    al,6
  2438.     pop    ax
  2439. aai1:    cmc            ;carry clear <==> it's a number
  2440. aai2:    ret
  2441.  
  2442. ;    AAGETI - Get a number from the input line.
  2443. ;    Entry    AL    First character of number
  2444. ;        SI    Address of next character of number
  2445. ;    Exit    DX:BX    Resulting number
  2446. ;        CL    1 if it's a byte, 2 if a word, 4 if a dword
  2447. ;        AL    Next character not in number
  2448. ;        SI    Address of next character after that
  2449. ;    Uses    AH, CH
  2450.  
  2451. aageti:    cmp    al,'-'
  2452.     je    aag1        ;if negative
  2453.     call    aag4        ;get the bare number
  2454.     mov    cx,1        ;set up cx
  2455.     or    dx,dx
  2456.     jnz    aag2        ;if dword
  2457.     or    bh,bh
  2458.     jnz    aag3        ;if word
  2459.     ret            ;it's a byte
  2460.  
  2461. aag1:    lodsb
  2462.     call    aag4        ;get the bare number
  2463.     mov    cx,bx
  2464.     or    cx,dx
  2465.     mov    cx,1
  2466.     jz    ret        ;if -0
  2467.     not    dx        ;negate the answer
  2468.     neg    bx
  2469.     cmc
  2470.     adc    dx,0
  2471.     test    dh,80h
  2472.     jz    aag7        ;if error
  2473.     cmp    dx,-1
  2474.     jne    aag2        ;if dword
  2475.     test    bh,80h
  2476.     jz    aag2        ;if dword
  2477.     cmp    bh,-1
  2478.     jne    aag3        ;if word
  2479.     test    bl,80h
  2480.     jz    aag3        ;if word
  2481.     ret            ;it's a byte
  2482.  
  2483. aag2:    inc    cx        ;return:  it's a dword
  2484.     inc    cx
  2485. aag3:    inc    cx        ;return:  it's a word
  2486.     ret
  2487.  
  2488. aag4:    xor    bx,bx        ;get the basic integer
  2489.     xor    dx,dx
  2490.     call    getnyb
  2491.     jc    aag7        ;if not a hex digit
  2492. aag5:    or    bl,al        ;add it to the number
  2493.     lodsb
  2494.     call    getnyb
  2495.     jc    ret        ;if done
  2496.     test    dh,0f0h
  2497.     jnz    aag7        ;if overflow
  2498.     mov    cx,4
  2499. aag6:    shl    bx,1        ;shift it by 4
  2500.     rcl    dx,1
  2501.     loop    aag6
  2502.     jmp    aag5
  2503.  
  2504. aag7:    jmp    aa13b        ;error
  2505.  
  2506. ;    AACONVINDEX - Convert results from AAGETI and store index value
  2507. ;    Entry    DX:BX,CL As in exit from AAGETI
  2508. ;        DI    Points to information record for this arg
  2509. ;    Exit    SS bits stored in [di+6]
  2510. ;    Uses    DL
  2511.  
  2512. aaconvindex:
  2513.     cmp    cl,1
  2514.     jne    aacv1        ;if the number is too large
  2515.     cmp    bl,1
  2516.     je    aacv2        ;if 1
  2517.     inc    dx
  2518.     cmp    bl,2
  2519.     je    aacv2        ;if 2
  2520.     inc    dx
  2521.     cmp    bl,4
  2522.     je    aacv2        ;if 4
  2523.     inc    dx
  2524.     cmp    bl,8
  2525.     je    aacv2        ;if 8
  2526. aacv1:    jmp    aa13b        ;error
  2527.  
  2528. aacv2:    mov    [di+6],dl    ;save the value
  2529.     ret
  2530.  
  2531. ;    AAGETREG - Get register for the assembler.
  2532. ;    Entry    DI    Start of register table
  2533. ;        CX    Length of register table
  2534. ;        SI    Address of first character in register name
  2535. ;    Exit    SI    Updated if a register was found
  2536. ;        BX    Register number, defined as in the table below.
  2537. ;    Uses    AX, CX, DI
  2538.  
  2539. ;    Exit value of BX:
  2540. ;        DI = rgnam816, CX = 27    DI = rgnam16, CX = 8
  2541. ;        ----------------------    --------------------
  2542. ;        0  ..  7:  AL .. BH    0  ..  7:  AX .. DI
  2543. ;        8  .. 15:  AX .. DI    16 .. 23:  EAX..EDI
  2544. ;        16 .. 23:  EAX..EDI
  2545. ;        24 .. 29:  ES .. GS
  2546. ;        30 .. 34:  ST .. MM
  2547.  
  2548. aagetreg:
  2549.     mov    ax,[si]
  2550.     and    ax,TOUPPER_W    ;convert to upper case
  2551.     cmp    al,'E'        ;check for EAX, etc.
  2552.     jne    aagr1        ;if not
  2553.     push    ax
  2554.     mov    al,ah
  2555.     mov    ah,[si+2]
  2556.     and    ah,TOUPPER
  2557.     push    di
  2558.     mov    di,offset rgnam16
  2559.     push    cx
  2560.     mov    cx,8
  2561.     repne    scasw
  2562.     mov    bx,cx
  2563.     pop    cx
  2564.     pop    di
  2565.     pop    ax
  2566.     jne    aagr1        ;if no match
  2567.     inc    si
  2568.     not    bx
  2569.     add    bl,8+16        ;adjust BX
  2570.     jmp    short aagr2    ;finish up
  2571.  
  2572. aagr1:    mov    bx,cx        ;(if cx = 0, this is always reached with
  2573.     repne    scasw        ; ZF clear)
  2574.     jne    aagr3        ;if no match
  2575.     sub    bx,cx
  2576.     dec    bx
  2577.     cmp    bl,16
  2578.     jb    aagr2        ;if AL .. BH or AX .. DI
  2579.     add    bl,8
  2580. aagr2:    inc    si        ;skip the register name
  2581.     inc    si
  2582.     clc
  2583.     ret
  2584.  
  2585. aagr3:    stc            ;not found
  2586.     ret
  2587.  
  2588. ;    C command - compare bytes.
  2589.  
  2590. cc:    call    parsecm        ;parse arguments
  2591.     inc    cx
  2592. cc1:    push    si        ;do the interrupt pointer hack
  2593.     push    di
  2594.     push    ds
  2595.     push    es
  2596.     push    cs        ;ds := cs
  2597.     pop    ds
  2598.     call    dohack
  2599.     pop    es
  2600.     pop    ds
  2601.     pop    di
  2602.     pop    si
  2603.     repe    cmpsb        ;start comparing
  2604.     lahf
  2605.     mov    dl,[si-1]    ;save the possibly errant characters
  2606.     mov    dh,es:[di-1]
  2607.     push    si        ;undo the interrupt pointer hack
  2608.     push    di
  2609.     push    ds
  2610.     push    es
  2611.     push    cs        ;ds := cs
  2612.     pop    ds
  2613.     call    unhack
  2614.     pop    es
  2615.     pop    ds
  2616.     pop    di
  2617.     pop    si
  2618.     sahf
  2619.     je    cc2        ;if we're done
  2620.     push    cx
  2621.     push    es
  2622.     push    cs
  2623.     pop    es
  2624.     mov    bx,di
  2625.     mov    di,offset line_out
  2626.     mov    ax,ds
  2627.     call    hexword
  2628.     mov    al,':'
  2629.     stosb
  2630.     lea    ax,[si-1]
  2631.     call    hexword
  2632.     mov    ax,'  '
  2633.     stosw
  2634.     mov    al,dl
  2635.     call    hexbyte
  2636.     mov    ax,'  '
  2637.     stosw
  2638.     mov    al,dh
  2639.     call    hexbyte
  2640.     mov    ax,'  '
  2641.     stosw
  2642.     pop    ax
  2643.     push    ax
  2644.     call    hexword
  2645.     mov    al,':'
  2646.     stosb
  2647.     lea    ax,[bx-1]
  2648.     call    hexword
  2649.     push    ds
  2650.     push    cs
  2651.     pop    ds
  2652.     push    bx
  2653.     call    putsline
  2654.     pop    di
  2655.     pop    ds
  2656.     pop    es
  2657.     pop    cx
  2658.     inc    cx
  2659.     loop    cc1        ;if not done yet
  2660.  
  2661. cc2:    push    cs        ;restore segment registers
  2662.     pop    ds
  2663.     push    cs
  2664.     pop    es
  2665.     ret
  2666.  
  2667. ;    D command - hex/ascii dump.
  2668.  
  2669. ddd:    cmp    al,CR
  2670.     jne    dd1        ;if an address was given
  2671.     mov    dx,d_addr    ;compute range of 80h or until end of segment
  2672.     mov    si,dx
  2673.     add    dx,7fh
  2674.     jnc    dd2        ;if no overflow
  2675.     mov    dx,0ffffh
  2676.     jmp    short dd2
  2677.  
  2678. dd1:    mov    cx,80h        ;default length
  2679.     mov    bx,reg_ds
  2680.     call    getrange    ;get address range into dx:bx
  2681.     call    chkeol        ;expect end of line here
  2682.     mov    d_addr+2,bx    ;save segment (offset is saved later)
  2683.     mov    si,dx
  2684.     mov    dx,cx        ;dx = end address
  2685.  
  2686. ;    Parsing is done.  Print first line.
  2687.  
  2688. dd2:    mov    ax,d_addr+2
  2689.     call    hexword
  2690.     mov    al,':'
  2691.     stosb
  2692.     mov    ax,si
  2693.     and    al,0f0h
  2694.     push    ax
  2695.     call    hexword
  2696.     mov    ax,'  '
  2697.     stosw
  2698.     pop    ax
  2699.     lea    bx,[di+50]
  2700.     mov    word [bx-2],'  '
  2701.     push    si
  2702.     push    di
  2703.     call    prehack        ;set up for faking int vectors 23 and 24
  2704.     pop    di
  2705.     pop    si
  2706.  
  2707. dd3:    cmp    ax,si        ;skip to position in line
  2708.     je    dd4        ;if we're there yet
  2709.     push    ax
  2710.     mov    ax,'  '
  2711.     stosw
  2712.     stosb
  2713.     mov    es:[bx],al
  2714.     inc    bx
  2715.     pop    ax
  2716.     inc    ax
  2717.     jmp    dd3
  2718.  
  2719. ;    Begin main loop over lines of output.
  2720.  
  2721. dd4:    mov    cx,si
  2722.     or    cl,0fh
  2723.     cmp    cx,dx        ;compare with end address
  2724.     jb    dd5        ;if we write to the end of the line
  2725.     mov    cx,dx
  2726. dd5:    sub    cx,si
  2727.     inc    cx        ;cx = number of bytes to print this line
  2728.     push    si
  2729.     push    di
  2730.     call    dohack        ;substitute interrupt vectors
  2731.     pop    di
  2732.     pop    si
  2733.     mov    ds,d_addr+2
  2734.  
  2735. dd6:    lodsb
  2736.     push    ax
  2737.     push    cx
  2738.     call    hexbyte
  2739.     pop    cx
  2740.     mov    al,' '
  2741.     stosb
  2742.     pop    ax
  2743.     cmp    al,' '
  2744.     jb    dd7        ;if control character
  2745.     cmp    al,'~'
  2746.     jbe    dd8        ;if printable
  2747. dd7:    mov    al,'.'
  2748. dd8:    mov    es:[bx],al
  2749.     inc    bx
  2750.     loop    dd6
  2751. dd9:    test    si,0fh        ;space out till end of line
  2752.     jz    dd10
  2753.     mov    ax,'  '
  2754.     stosw
  2755.     stosb
  2756.     inc    si
  2757.     jmp    dd9
  2758.  
  2759. dd10:    push    cs        ;restore ds
  2760.     pop    ds
  2761.     mov    d_addr,si
  2762.     mov    byte [di-25],'-'
  2763.     push    si
  2764.     call    unhack
  2765.     pop    si
  2766.     mov    di,bx
  2767.     push    dx
  2768.     call    putsline
  2769.     pop    dx
  2770.     dec    si
  2771.     cmp    si,dx
  2772.     jae    dd11        ;if we're done
  2773.     inc    si
  2774.     mov    di,offset line_out+5    ;set up for next time
  2775.     mov    ax,si
  2776.     call    hexword
  2777.     inc    di
  2778.     inc    di
  2779.     lea    bx,[di+50]
  2780.     jmp    dd4
  2781.  
  2782. dd11:    inc    dx        ;set up the address for the next 'D' command.
  2783.     mov    d_addr,dx
  2784.     ret
  2785.  
  2786. errorj4:jmp    error
  2787.  
  2788. ;    E command - edit memory.
  2789.  
  2790. ee:    push    si
  2791.     push    di
  2792.     call    prehack
  2793.     pop    di
  2794.     pop    si
  2795.     mov    bx,reg_ds
  2796.     call    getaddr        ;get address into bx:dx
  2797.     call    skipwh0
  2798.     cmp    al,CR
  2799.     je    ee1        ;if prompt mode
  2800.     push    dx
  2801.     call    getstr        ;get data bytes
  2802.     mov    cx,di
  2803.     mov    dx,offset line_out
  2804.     sub    cx,dx        ;length of byte string
  2805.     pop    di
  2806.     mov    ax,cx
  2807.     dec    ax
  2808.     add    ax,di
  2809.     jc    errorj4        ;if it wraps around
  2810.     push    di
  2811.     call    dohack
  2812.     pop    di
  2813.     mov    si,dx
  2814.     mov    es,bx
  2815.     rep    movsb
  2816.  
  2817. ;    Restore ds and es and undo the interrupt vector hack.
  2818. ;    This code is also used by the `m' command.
  2819.  
  2820. ee0a:    push    cs        ;restore es
  2821.     pop    es
  2822.     mov    di,offset run2324
  2823.     call    prehak1        ;copy things back and restore ds
  2824.     call    unhack
  2825.     ret
  2826.  
  2827. ;    Prompt mode.
  2828.  
  2829. ee1:    xchg    bx,dx
  2830.  
  2831. ;    Begin loop over lines.
  2832.  
  2833. ee2:    mov    ax,dx        ;print out segment and offset
  2834.     call    hexword
  2835.     mov    al,':'
  2836.     stosb
  2837.     mov    ax,bx
  2838.     call    hexword
  2839.  
  2840. ;    Begin loop over bytes.
  2841.  
  2842. ee3:    mov    ax,'  '        ;print old value of byte
  2843.     stosw
  2844.     push    di
  2845.     call    dohack        ;do the INT pointer hack
  2846.     mov    es,dx
  2847.     mov    al,es:[bx]
  2848.     call    unhack        ;undo the INT pointer hack and restore es.
  2849.     pop    di
  2850.     call    hexbyte
  2851.     mov    al,'.'
  2852.     stosb
  2853.     push    dx        ;save dx
  2854.     push    bx
  2855.     call    puts
  2856.     pop    bx
  2857.     mov    si,offset line_out+16    ;address of buffer for characters
  2858.     xor    cx,cx        ;number of characters so far 
  2859.  
  2860. ee4:    cmp    notatty,0
  2861.     jz    ee9        ;if it's a tty
  2862.     push    si
  2863.     mov    di,offset line_in+2
  2864.     mov    si,bufnext
  2865. ee5:    cmp    si,bufend
  2866.     jb    ee6        ;if there's a character already
  2867.     call    fillbuf
  2868.     mov    al,CR
  2869.     jc    ee8        ;if eof
  2870. ee6:    cmp    notatty,CR
  2871.     jne    ee7        ;if no need to compress CR/LF
  2872.     cmp    byte [si],LF
  2873.     jne    ee7        ;if not a line feed
  2874.     inc    si        ;skip it
  2875.     inc    notatty        ;avoid repeating this
  2876.     jmp    ee5        ;next character
  2877.  
  2878. ee7:    lodsb            ;get the character
  2879.     mov    notatty,al
  2880. ee8:    mov    bufnext,si
  2881.     pop    si
  2882.     jmp    short ee10
  2883.  
  2884. ee9:    mov    ah,8        ;console input without echo
  2885.     int    21h
  2886.  
  2887. ee10:    cmp    al,' '
  2888.     je    ee13        ;if done with this byte
  2889.     cmp    al,CR
  2890.     je    ee13        ;ditto
  2891.     cmp    al,BS
  2892.     je    ee11        ;if backspace
  2893.     cmp    cx,2        ;otherwise, it should be a hex character
  2894.     jae    ee4        ;if we have a full byte already
  2895.     mov    [si],al
  2896.     call    getnyb
  2897.     jc    ee4        ;if it's not a hex character
  2898.     inc    cx
  2899.     lodsb            ;get the character back
  2900.     jmp    short ee12
  2901.  
  2902. ee11:    jcxz    ee4        ;if nothing to backspace over
  2903.     dec    cx
  2904.     dec    si
  2905. ee12:    xchg    ax,dx        ;move character into dl
  2906.     mov    ah,2        ;display output
  2907.     int    21h
  2908.     jmp    ee4        ;back for more
  2909.  
  2910. ;    We have a byte (if CX != 0).
  2911.  
  2912. ee13:    jcxz    ee14        ;if no change for this byte
  2913.     mov    [si],al        ;terminate the string
  2914.     sub    si,cx        ;point to beginning
  2915.     push    cx
  2916.     lodsb
  2917.     call    getbyte        ;convert byte to binary
  2918.     pop    cx
  2919.     call    dohack        ;do the INT pointer hack
  2920.     pop    ds        ;get segment register
  2921.     mov    [bx],dl        ;save the byte
  2922.     push    ds        ;segment back on the stack
  2923.     mov    di,offset run2324
  2924.     call    prehak1        ;copy things back and restore ds
  2925.     call    unhack        ;undo the INT pointer hack
  2926.  
  2927. ;    End the loop over bytes.
  2928.  
  2929. ee14:    inc    bx        ;next word
  2930.     pop    dx        ;restore dx
  2931.     mov    di,offset line_out
  2932.     cmp    al,CR
  2933.     je    ee16        ;if done
  2934.     test    bl,7
  2935.     jz    ee15        ;if new line
  2936.     not    cx
  2937.     add    cx,4        ;compute 3 - cx
  2938.     mov    al,' '
  2939.     rep    stosb        ;store that many spaces
  2940.     jmp    ee3        ;back for more
  2941.  
  2942. ee15:    mov    ax,LF * 256 + CR;terminate this line
  2943.     stosw
  2944.     jmp    ee2        ;back for a new line
  2945.  
  2946. ee16:    jmp    putsline    ;call putsline and return
  2947.  
  2948. ;    F command - fill memory
  2949.  
  2950. ff:    xor    cx,cx        ;get address range (no default length)
  2951.     mov    bx,reg_ds
  2952.     call    getrange
  2953.     sub    cx,dx
  2954.     inc    cx        ;cx = number of bytes
  2955.     push    cx        ;save it
  2956.     push    dx        ;save start address
  2957.     call    skipwh0
  2958.     call    getstr        ;get string of bytes
  2959.     mov    cx,di
  2960.     sub    cx,offset line_out
  2961.     pop    di
  2962.     mov    es,bx
  2963.     cmp    cx,1
  2964.     je    ff3        ;a common optimization
  2965.     pop    ax
  2966.     xor    dx,dx
  2967.     div    cx        ;compute number of whole repetitions
  2968.     or    ax,ax
  2969.     jz    ff2        ;if less than one whole rep
  2970. ff1:    mov    si,offset line_out
  2971.     push    cx
  2972.     rep    movsb
  2973.     pop    cx
  2974.     dec    ax
  2975.     jnz    ff1        ;if more to go
  2976. ff2:    mov    cx,dx
  2977.     jcxz    ff4        ;if no partial copies
  2978.     mov    si,offset line_out
  2979.     rep    movsb
  2980.     jmp    short ff4    ;done (almost)
  2981.  
  2982. ff3:    pop    cx
  2983.     mov    al,byte line_out
  2984.     rep    stosb
  2985.  
  2986. ff4:    push    cs        ;restore es
  2987.     pop    es
  2988.     ret
  2989.  
  2990. ;    G command - go.
  2991.  
  2992. gg:    xchg    ax,bx        ;mov bx,ax
  2993.     mov    ax,reg_cs    ;save original CS
  2994.     mov    run_cs,ax
  2995.     mov    eqladdr+2,ax
  2996.     xchg    ax,bx        ;mov ax,bx
  2997.     call    parseql        ;process =addr
  2998.     mov    di,offset line_out+2
  2999.     mov    [di-2],si    ;save si
  3000.  
  3001. ;    Parse the rest of the line to make sure there are no errors.
  3002.  
  3003. gg1:    call    skipwh0
  3004.     cmp    al,CR
  3005.     je    gg2        ;if end of line
  3006.     call    getaddr
  3007.     jmp    gg1        ;back for more
  3008.  
  3009. ;    Store breakpoint bytes in the given locations.
  3010.  
  3011. gg2:    mov    si,[di-2]
  3012. gg3:    dec    si
  3013.     call    skipwhite
  3014.     cmp    al,CR
  3015.     je    gg4        ;if done
  3016.     mov    bx,eqladdr+2    ;default segment
  3017.     call    getaddr        ;get address into bx:dx
  3018.     mov    ds,bx
  3019.     mov    bx,dx
  3020.     mov    al,0cch        ;INT 3 instruction
  3021.     xchg    al,[bx]        ;put it there
  3022.     push    cs        ;restore DS
  3023.     pop    ds
  3024.     stosb            ;save the old contents
  3025.     jmp    gg3        ;back for more
  3026.  
  3027. ;    Now run the program.
  3028.  
  3029. gg4:    call    seteq        ;make the = operand take effect
  3030.     call    run
  3031.  
  3032. ;    Restore breakpoint bytes.
  3033.  
  3034.     mov    di,offset line_out+2
  3035.     mov    si,[di-2]
  3036. gg5:    dec    si
  3037.     call    skipwhite
  3038.     cmp    al,CR
  3039.     je    gg6        ;if done
  3040.     mov    bx,run_cs    ;default segment
  3041.     call    getaddr        ;get address into bx:dx
  3042.     mov    al,[di]        ;get old contents
  3043.     inc    di
  3044.     cmp    al,0cch        ;this is because of possible duplicate values
  3045.     je    gg5        ;if it was INT 3 originally
  3046.     mov    ds,bx
  3047.     mov    bx,dx
  3048.     mov    [bx],al        ;restore value
  3049.     push    cs        ;restore DS
  3050.     pop    ds
  3051.     jmp    gg5        ;back for more
  3052.  
  3053. ;    Finish up.  Check if it was one of _our_ breakpoints.
  3054.  
  3055. gg6:    cmp    run_int,offset int3msg
  3056.     jne    gg9        ;if not CC interrupt
  3057.     dec    reg_ip
  3058.     mov    si,[line_out]    ;loop over the set breakpoints
  3059. gg7:    dec    si
  3060.     call    skipwhite
  3061.     cmp    al,CR
  3062.     je    gg8        ;if done
  3063.     mov    bx,run_cs    ;default segment
  3064.     call    getaddr        ;get address into bx:dx
  3065.     mov    ax,dx
  3066.     xor    ax,reg_ip
  3067.     test    al,0fh
  3068.     jnz    gg7        ;if no match
  3069.     mov    cl,4
  3070.     mov    ax,reg_ip
  3071.     shr    ax,cl
  3072.     add    ax,reg_cs
  3073.     shr    dx,cl
  3074.     add    bx,dx
  3075.     cmp    ax,bx
  3076.     jne    gg7        ;if no match
  3077.  
  3078. ;    It's one of ours.
  3079.  
  3080.     call    dumpregs
  3081.     ret
  3082.  
  3083. ;    It's not.
  3084.  
  3085. gg8:    inc    reg_ip
  3086. gg9:    jmp    tt2        ;print messages and quit.
  3087.  
  3088. ;    H command - hex addition and subtraction.
  3089.  
  3090. hh:    call    getword
  3091.     push    dx
  3092.     call    skipwh0
  3093.     call    getword
  3094.     call    chkeol        ;expect end of line here
  3095.     pop    bx
  3096.     mov    ax,bx
  3097.     add    ax,dx
  3098.     call    hexword
  3099.     mov    ax,'  '
  3100.     stosw
  3101.     mov    ax,bx
  3102.     sub    ax,dx
  3103.     call    hexword
  3104.     call    putsline
  3105.     ret
  3106.  
  3107. ;    I command - input from I/O port.
  3108.  
  3109. ii:    call    getword
  3110.     call    chkeol        ;expect end of line here
  3111.     in    al,dx
  3112.     call    hexbyte
  3113.     call    putsline
  3114.     ret
  3115.  
  3116. errorj5:jmp    error
  3117.  
  3118. ;    L command - read a program, or disk sectors, from disk.
  3119.  
  3120. ll:    call    parselw        ;parse it
  3121.     jz    ll1        ;if request to read program
  3122.     int    25h
  3123.     mov    dx,offset reading
  3124.     jmp    ww1
  3125.  
  3126. ;    Load the program.
  3127.  
  3128. ll1:    call    freemem        ;return the previous process's memory
  3129.  
  3130. ;    Clear registers
  3131.  
  3132. ll2:    mov    di,offset reg_bx
  3133.     xor    ax,ax
  3134.     mov    cx,7
  3135.     rep    stosw
  3136.     mov    di,offset blk1    ;clear memory of past blocks
  3137.     stosw
  3138.     stosw
  3139.     push    si        ;restore run2324 area
  3140.     mov    si,0eh        ;address of original INT 23 and 24 (in PSP)
  3141.     mov    di,offset run2324
  3142.     movsw
  3143.     movsw
  3144.     movsw
  3145.     movsw
  3146.     pop    si        ;restore si
  3147.  
  3148. ;    Check file extension.
  3149.  
  3150.     mov    bx,execblk+2    ;address of end of file name string
  3151.     cmp    bx,85h
  3152.     jb    ll3        ;if file name is too short
  3153.     cmp    word [bx-5],'C.'
  3154.     jne    ll4        ;if not .COM
  3155.     cmp    word [bx-3],'MO'
  3156.     je    ll5        ;if .COM
  3157. ll3:    jmp    ll11        ;if not .COM
  3158.  
  3159. ll4:    cmp    word [bx-5],'E.'
  3160.     jne    ll3        ;if not .EXE
  3161.     cmp    word [bx-3],'EX'
  3162.     jne    ll3        ;if not .EXE
  3163.  
  3164. ;    Load .EXE or .COM file, using the DOS interrupt.
  3165. ;    First find out the file length and type.
  3166.  
  3167. ll5:    mov    ax,3d00h    ;open file for reading
  3168.     mov    dx,80h
  3169.     int    21h
  3170.     jnc    ll6
  3171.     jmp    ll9        ;if error
  3172. ll6:    push    ax
  3173.     xchg    ax,bx        ;mov bx,ax
  3174.     mov    ah,3fh        ;read from file
  3175.     mov    cx,2
  3176.     mov    dx,sp
  3177.     int    21h
  3178.     jc    ll7        ;if error
  3179.     cmp    ax,2
  3180.     jne    ll7        ;if less than two bytes read
  3181.     pop    ax
  3182.     cmp    ax,'ZM'
  3183.     jne    ll7        ;if not .EXE file header
  3184. ;    mov    exefile,1    ;set flag |||
  3185. ll7:    mov    ax,4202h    ;lseek
  3186.     xor    cx,cx
  3187.     xor    dx,dx
  3188.     int    21h
  3189.     mov    reg_bx,dx
  3190.     mov    reg_cx,ax
  3191.     mov    ah,3eh        ;close file
  3192.     int    21h
  3193.  
  3194. ;    Actual program loading.
  3195.  
  3196.     mov    ax,4b01h    ;load program
  3197.     mov    dx,80h        ;offset of file to load
  3198.     mov    bx,offset execblk ;parameter block
  3199.     int    21h        ;load it
  3200.     jc    ll9        ;if error
  3201.     mov    ax,sp
  3202.     sub    ax,[2eh]
  3203.     cmp    ax,80h
  3204.     jb    ll8        ;if in range
  3205.     mov    ax,80h
  3206. ll8:    mov    spadjust,ax
  3207.     mov    running,1    ;set flag
  3208.     les    si,execblk+14
  3209.     es lodsw        ;recover ax
  3210.     mov    reg_ax,ax
  3211.     mov    reg_sp,si
  3212.     mov    reg_ss,es
  3213.     les    si,execblk+18
  3214.     mov    reg_ip,si
  3215.     mov    reg_cs,es
  3216.     push    cs
  3217.     pop    es
  3218.     mov    ah,51h        ;get new PSP
  3219.     int    21h
  3220.     xchg    ax,bx        ;mov ax,bx
  3221.     mov    psp,ax
  3222.     mov    di,offset reg_ds
  3223.     stosw
  3224.     stosw            ;reg_es
  3225.     mov    ah,50h        ;set PSP back
  3226.     mov    bx,cs
  3227.     int    21h
  3228.     jmp    ll18
  3229.  
  3230. ;    Error messages.  Do an empty load.
  3231.  
  3232. ll9:    call    ww15        ;print error message
  3233.     call    ll19        ;set up PSP
  3234. ll10:    jmp    ll18        ;finish up
  3235.  
  3236. ;    Load it ourselves.
  3237.  
  3238. ll11:    call    ll19        ;set up PSP
  3239.     cmp    byte [80h],0
  3240.     jz    ll10        ;if no file name given
  3241.  
  3242. ;    Open the file and find its length.
  3243.  
  3244.     mov    ax,3d00h    ;open file for reading
  3245.     mov    dx,80h
  3246.     int    21h
  3247.     jc    ll17        ;if error
  3248.     xchg    ax,bx        ;mov bx,ax
  3249.     mov    ax,4202h    ;lseek from end
  3250.     xor    cx,cx
  3251.     xor    dx,dx
  3252.     int    21h
  3253.     mov    reg_bx,dx
  3254.     mov    reg_cx,ax
  3255.  
  3256. ;    Check the size against available space.
  3257.  
  3258.     mov    cx,4
  3259.     add    ax,100h+15
  3260.     adc    dx,0
  3261.     mov    cx,4
  3262. ll12:    shr    dx,1
  3263.     rcr    ax,1
  3264.     loop    ll12
  3265.     or    dx,dx
  3266.     jnz    ll16        ;if too big
  3267.     mov    di,run_sp
  3268.     cmp    ax,di
  3269.     ja    ll16        ;if too big
  3270.     mov    ax,4200h    ;lseek from beginning
  3271.     xor    cx,cx        ;to zero (dx is already zero)
  3272.     int    21h
  3273.  
  3274. ;    Read in the file.  di is still run_sp; dx is still 0.
  3275.  
  3276.     mov    si,psp        ;si = segment to use
  3277.     add    si,10h
  3278.     sub    di,10h        ;di = space left
  3279. ll13:    mov    ax,0fe0h
  3280.     cmp    ax,di
  3281.     jb    ll14        ;if plenty left
  3282.     mov    ax,di
  3283. ll14:    mov    ds,si
  3284.     add    si,ax
  3285.     sub    di,ax
  3286.     mov    cl,4
  3287.     shl    ax,cl        ;number of bytes to read
  3288.     xchg    ax,cx        ;mov ax,cx
  3289.     mov    ah,3fh        ;read from file
  3290.     int    21h
  3291.     cmp    ax,cx
  3292.     jne    ll15        ;if end
  3293.     or    di,di
  3294.     jnz    ll13        ;if more room
  3295.  
  3296. ;    Close the file and finish up.
  3297.  
  3298. ll15:    mov    ah,3eh        ;close file
  3299.     int    21h
  3300.     push    cs        ;restore ds
  3301.     pop    ds
  3302.     jmp    short ll18    ;finish up
  3303.  
  3304. ;    Errors of various sorts.
  3305.  
  3306. ll16:    mov    ax,8        ;not enough memory
  3307. ll17:    call    ww15        ;print error message
  3308.     xor    ax,ax        ;clear reg_bx and reg_cx
  3309.     mov    di,offset reg_bx
  3310.     stosw
  3311.     stosw
  3312.  
  3313. ;    Finish up.  Set termination address.
  3314.  
  3315. ll18:    mov    ax,2522h    ;set interrupt vector 22
  3316.     mov    dx,offset int22
  3317.     int    21h
  3318.     mov    ds,psp
  3319.     mov    word [0ah],offset int22
  3320.     mov    [0ch],cs
  3321.     push    cs
  3322.     pop    ds
  3323.  
  3324. ;    Set up initial addresses for 'a', 'd', and 'u' commands.
  3325.  
  3326.     mov    ax,reg_ip
  3327.     mov    bx,reg_cs
  3328.     mov    di,offset a_addr
  3329.     stosw
  3330.     xchg    ax,bx
  3331.     stosw
  3332.     xchg    ax,bx        ;d_addr
  3333.     stosw
  3334.     xchg    ax,bx
  3335.     stosw
  3336.     xchg    ax,bx        ;u_addr
  3337.     stosw
  3338.     xchg    ax,bx
  3339.     stosw
  3340.     ret
  3341.  
  3342. ;    ll19 - Create PSP (subroutine).
  3343.  
  3344. ll19:
  3345.  
  3346. ;    Allocate and fill environment.
  3347.  
  3348.     mov    ax,execblk+2    ;end of file name string
  3349.     add    ax,envlen    ;length of environment
  3350.     add    ax,-80h+2+15
  3351.     mov    cl,4
  3352.     shr    ax,cl
  3353.     xchg    ax,bx        ;mov bx,ax
  3354.     mov    ah,48h        ;allocate memory
  3355.     int    21h
  3356.     jc    ll20        ;if out of memory
  3357.     mov    blk1,ax
  3358.     mov    cx,envlen    ;copy over parent's environment
  3359.     mov    ds,[2ch]
  3360.     xor    si,si
  3361.     mov    es,ax
  3362.     xor    di,di
  3363.     rep    movsb
  3364.     mov    ax,1        ;store number of extra strings
  3365.     stosw
  3366.     push    cs        ;restore ds
  3367.     pop    ds
  3368.     mov    si,80h        ;copy file name
  3369.     mov    cx,execblk+2    ;end of file name
  3370.     sub    cx,si
  3371.     rep    movsb
  3372.     push    cs        ;restore ES
  3373.     pop    es
  3374.  
  3375. ;    Create main program segment.
  3376.  
  3377.     mov    ah,48h        ;allocate another block
  3378.     mov    bx,0ffffh
  3379.     int    21h
  3380.     cmp    bx,11h
  3381.     jb    ll20        ;if too little memory
  3382.     mov    ah,48h        ;allocate the most we can
  3383.     int    21h
  3384.     jnc    ll21
  3385. ll20:    jmp    ll24        ;if out of memory
  3386. ll21:    mov    psp,ax
  3387.     mov    blk2,ax
  3388.     mov    run_sp,bx    ;save length temporarily
  3389.     mov    di,offset reg_ds;set up segment registers
  3390.     stosw
  3391.     stosw
  3392.     stosw
  3393.     stosw
  3394.     xchg    ax,dx        ;mov dx,ax
  3395.     mov    ax,100h
  3396.     stosw            ;set original IP
  3397.     mov    ah,55h        ;create child PSP
  3398.     mov    si,[2]        ;memory size field
  3399.     clc            ;works around OS/2 bug
  3400.     int    21h
  3401.     jc    ll25        ;if error
  3402.  
  3403. ;    Set environment pointer in PSP.
  3404.  
  3405.     mov    ax,blk1
  3406.     mov    ds,dx
  3407.     mov    [2ch],ax
  3408.  
  3409. ;    Set up stack.
  3410.  
  3411.     mov    ax,cs:run_sp
  3412.     cmp    ax,1000h
  3413.     jb    ll22        ;if smaller than maximum
  3414.     xor    ax,ax
  3415. ll22:    mov    cl,4
  3416.     shl    ax,cl
  3417.     dec    ax
  3418.     dec    ax
  3419.     mov    bx,ax
  3420.     mov    word [bx],0
  3421.     push    cs        ;restore ds
  3422.     pop    ds
  3423.     mov    reg_sp,ax    ;set stack pointer
  3424.  
  3425. ;    Now take care of our own stack.
  3426.  
  3427.     mov    ax,sp
  3428.     sub    ax,[2eh]
  3429.     cmp    ax,80h
  3430.     jb    ll23        ;if in range
  3431.     mov    ax,80h
  3432. ll23:    mov    spadjust,ax
  3433.     mov    running,1    ;set flag
  3434.     mov    ah,50h        ;set PSP
  3435.     mov    bx,cs
  3436.     int    21h
  3437.     ret
  3438.  
  3439. ;    Insufficient memory.
  3440.  
  3441. ll24:    mov    ah,9        ;print string
  3442.     mov    dx,offset doserr8
  3443.     int    21h
  3444.     ret
  3445.  
  3446. ;    Error in PSP creation.
  3447.  
  3448. ll25:    mov    ah,9        ;print string
  3449.     mov    dx,offset psperr
  3450.     int    21h
  3451.     ret
  3452.  
  3453. ;    M command - move from place to place.
  3454.  
  3455. mm:    push    si        ;scan for comma or 'l'
  3456. m1:    cmp    al,','
  3457.     je    m2        ;if comma found
  3458.     cmp    al,CR
  3459.     je    m5        ;if end of string
  3460.     or    al,TOLOWER
  3461.     cmp    al,'l'
  3462.     je    m2        ;if 'l' found
  3463.     lodsb
  3464.     jmp    m1        ;loop back
  3465.  
  3466. ;    Normal 'm' command (move).
  3467.  
  3468. m2:    pop    si
  3469.     dec    si
  3470.     lodsb
  3471.     call    parsecm        ;parse arguments
  3472.     push    cx
  3473.     mov    cl,4
  3474.     shr    dx,cl
  3475.     add    dx,bx        ;upper 16 bits of destination
  3476.     mov    ax,si
  3477.     shr    ax,cl
  3478.     mov    bx,ds
  3479.     add    ax,bx
  3480.     cmp    ax,dx
  3481.     jne    m3        ;if we know which is larger
  3482.     mov    ax,si
  3483.     and    al,0fh
  3484.     mov    bx,di
  3485.     and    bl,0fh
  3486.     cmp    al,bl
  3487. m3:    pop    cx
  3488.     lahf
  3489.     push    si        ;do the interrupt pointer hack
  3490.     push    di
  3491.     push    ds
  3492.     push    es
  3493.     push    cs        ;ds := cs
  3494.     pop    ds
  3495.     call    dohack
  3496.     pop    es
  3497.     pop    ds
  3498.     pop    di
  3499.     pop    si
  3500.     sahf
  3501.     jae    m4        ;if forward copy is OK
  3502.     add    si,cx
  3503.     add    di,cx
  3504.     std
  3505. m4:    rep    movsb        ;do the move
  3506.     movsb            ;one more byte
  3507.     cld            ;restore flag
  3508.     jmp    ee0a        ;restore ds and es and undo the int pointer hack
  3509.  
  3510. ;    Other 'm' command:  set machine type.
  3511.  
  3512. m5:    pop    si
  3513.     dec    si
  3514.     lodsb
  3515.     cmp    al,CR
  3516.     je    m10        ;if just an 'm' (query machine type)
  3517.     cmp    al,'0'
  3518.     jb    m6        ;if not a digit
  3519.     cmp    al,'6'
  3520.     ja    m6        ;ditto
  3521.     sub    al,'0'
  3522.     mov    machine,al    ;set machine type
  3523.     mov    mach_87,al    ;coprocessor type, too
  3524.     ret
  3525.  
  3526. m6:    or    al,TOLOWER
  3527.     cmp    al,'c'
  3528.     je    m7        ;if coprocessor declaration
  3529.     cmp    al,'n'
  3530.     jne    errorj3        ;if something else
  3531.     lodsb
  3532.     or    al,TOLOWER
  3533.     cmp    al,'c'
  3534.     jne    errorj3        ;if not 'c' after that
  3535.     lodsb
  3536.     call    chkeol
  3537.     mov    has_87,0    ;clear coprocessor flag
  3538.     ret            ;done
  3539.  
  3540. m7:    call    skipwhite    ;get next nonblank character
  3541.     mov    ah,machine
  3542.     cmp    ah,3
  3543.     jne    m9        ;if not a 386
  3544.     cmp    al,'3'
  3545.     je    m8        ;if declaring a 387
  3546.     cmp    al,'2'
  3547.     jne    m9        ;if not '2'
  3548.     mov    ah,2
  3549. m8:    call    skipwhite
  3550. m9:    cmp    al,CR
  3551.     jne    errorj3        ;if not end of line
  3552.     mov    has_87,1    ;set coprocessor flag
  3553.     mov    mach_87,ah    ;set copr. type
  3554.     ret
  3555.  
  3556. ;    Display machine type.
  3557.  
  3558. m10:    mov    si,offset msg8088
  3559.     mov    al,machine
  3560.     cmp    al,0
  3561.     je    m11        ;if 8088
  3562.     mov    si,offset msgx86
  3563.     add    al,'0'
  3564.     mov    [si],al
  3565. m11:    call    showstring
  3566.     mov    si,offset no_copr
  3567.     cmp    has_87,0
  3568.     je    m12        ;if no coprocessor
  3569.     mov    si,offset has_copr
  3570.     mov    al,mach_87
  3571.     cmp    al,machine
  3572.     je    m12        ;if has coprocessor same as processor
  3573.     mov    si,offset has_287
  3574. m12:    call    showstring    ;show string
  3575.     jmp    putsline    ;call puts and quit
  3576.  
  3577. errorj3:jmp    error
  3578.  
  3579. ;    N command - change the name of the program being debugged.
  3580.  
  3581. nn:    mov    di,80h
  3582.  
  3583. ;    Copy and canonicalize file name.
  3584.  
  3585. nn1:    cmp    al,CR
  3586.     je    nn3        ;if end of line
  3587.     call    ifsep        ;check for separators space, TAB, comma, ;, =
  3588.     je    nn3        ;if end of file name
  3589.     cmp    al,swch1
  3590.     je    nn3        ;if '/' (and '/' is the switch character)
  3591.     cmp    al,'a'
  3592.     jb    nn2        ;if not lower case
  3593.     cmp    al,'z'
  3594.     ja    nn2        ;ditto
  3595.     and    al,TOUPPER    ;convert to upper case
  3596. nn2:    stosb
  3597.     lodsb
  3598.     jmp    nn1        ;back for more
  3599.  
  3600. nn3:    mov    al,0        ;null terminate the file name string
  3601.     stosb
  3602.     mov    execblk+2,di    ;save start of command tail
  3603.     push    di
  3604.     mov    di,offset line_out
  3605.     dec    si
  3606. nn4:    lodsb            ;copy the remainder to line_out
  3607.     stosb
  3608.     cmp    al,CR
  3609.     jne    nn4
  3610.  
  3611. ;    Set up FCB's.
  3612.  
  3613.     mov    si,offset line_out
  3614.     mov    di,5ch
  3615.     call    nn6        ;do first FCB
  3616.     mov    byte reg_ax,al
  3617.     mov    di,6ch
  3618.     call    nn6        ;second FCB
  3619.     mov    byte reg_ax+1,al
  3620.  
  3621. ;    Copy command tail.
  3622.  
  3623.     mov    si,offset line_out
  3624.     pop    di
  3625.     push    di
  3626.     inc    di
  3627. nn5:    lodsb
  3628.     stosb
  3629.     cmp    al,CR
  3630.     jne    nn5        ;if not end of string
  3631.     pop    ax        ;recover old DI
  3632.     xchg    ax,di
  3633.     sub    ax,di        ;compute length of tail
  3634.     dec    ax
  3635.     dec    ax
  3636.     stosb
  3637.     ret            ;done
  3638.  
  3639. ;    Subroutine to process an FCB.
  3640.  
  3641. nn6:    lodsb
  3642.     cmp    al,CR
  3643.     je    nn7        ;if end
  3644.     call    ifsep
  3645.     je    nn6        ;if separator
  3646.     cmp    al,switchar
  3647.     je    nn10        ;if switch character
  3648. nn7:    dec    si
  3649.     mov    ax,2901h    ;parse filename
  3650.     int    21h
  3651.     push    ax        ;save AL
  3652. nn8:    lodsb            ;skip till separator
  3653.     cmp    al,CR
  3654.     je    nn9        ;if end
  3655.     call    ifsep
  3656.     je    nn9        ;if separator character
  3657.     cmp    al,swch1
  3658.     jne    nn8        ;if not switchar (sort of)
  3659. nn9:    dec    si
  3660.     pop    ax        ;recover AL
  3661.     cmp    al,1
  3662.     jne    nn9a        ;if not 1
  3663.     dec    ax
  3664. nn9a:    ret
  3665.  
  3666. ;    Handle a switch (differently).
  3667.  
  3668. nn10:    lodsb
  3669.     cmp    al,CR
  3670.     je    nn7        ;if end of string
  3671.     call    ifsep
  3672.     je    nn10        ;if another separator
  3673.     mov    al,0
  3674.     stosb
  3675.     dec    si
  3676.     lodsb
  3677.     cmp    al,'a'
  3678.     jb    nn11        ;if not a lower case letter
  3679.     cmp    al,'z'
  3680.     ja    nn11
  3681.     and    al,TOUPPER    ;convert to upper case
  3682. nn11:    stosb
  3683.     mov    ax,'  '
  3684.     stosw
  3685.     stosw
  3686.     stosw
  3687.     stosw
  3688.     stosw
  3689.     xor    ax,ax
  3690.     stosw
  3691.     stosw
  3692.     stosw
  3693.     stosw
  3694.     ret            ;return with AL=0
  3695.  
  3696. ;    O command - output to I/O port.
  3697.  
  3698. oo:    call    getword
  3699.     push    dx
  3700.     call    skipwh0
  3701.     call    getbyte
  3702.     call    chkeol        ;expect end of line here
  3703.     xchg    ax,dx        ;al = byte
  3704.     pop    dx        ;recover port number
  3705.     out    dx,al
  3706.     ret
  3707.  
  3708. ;    P command - proceed (i.e., skip over call/int/loop/string instruction).
  3709.  
  3710. pp:    call    parse_pt    ;process arguments
  3711.  
  3712. ;    Do it <count> times.  First check the type of instruction.
  3713.  
  3714. pp1:    push    cx        ;save cx
  3715.     mov    si,reg_ip
  3716.     mov    dx,15        ;DL = number of bytes to go; DH = prefix flags.
  3717.  
  3718. pp2:    call    pp16        ;get next instruction byte into AL
  3719.     mov    di,offset ppbytes
  3720.     mov    cx,PPLEN
  3721.     repne    scasb
  3722.     jne    pp5        ;if not one of these
  3723.     mov    al,[di+PPLEN-1]    ;get corresponding byte in ppinfo
  3724.     test    al,80h
  3725.     jz    pp3        ;if not a prefix
  3726.     or    dh,al        ;set the flags
  3727.     dec    dl
  3728.     jnz    pp2        ;if not out of bytes
  3729.     jmp    pp12
  3730.  
  3731. pp3:    test    al,40h
  3732.     jz    pp4        ;if no size dependency
  3733.     and    al,3fh
  3734.     and    dh,2
  3735.     add    al,dh
  3736. pp4:    cbw
  3737.     add    si,ax
  3738.     jmp    short pp11    ;we have a skippable instruction here
  3739.  
  3740. pp5:    cmp    al,0ffh
  3741.     jne    pp12        ;just an ordinary instruction
  3742.     call    pp16        ;get MOD REG R/M byte
  3743.     and    al,not 8    ;clear lowest bit of REG field (/3 --> /2)
  3744.     xor    al,10h        ;/2 --> /0
  3745.     test    al,38h
  3746.     jnz    pp12        ;if not ff/2 or ff/3
  3747.     cmp    al,0c0h
  3748.     jae    pp11        ;if just a register
  3749.     test    dh,1
  3750.     jnz    pp6        ;if 32 bit addressing
  3751.     cmp    al,6
  3752.     je    pp9        ;if just plain disp16
  3753.     cmp    al,40h
  3754.     jb    pp11        ;if indirect register
  3755.     cmp    al,80h
  3756.     jb    pp10        ;if disp8[reg(s)]
  3757.     jmp    short pp9    ;it's disp16[reg(s)]
  3758.  
  3759. pp6:    cmp    al,5
  3760.     je    pp8        ;if just plain disp32
  3761.     xor    al,4
  3762.     test    al,7
  3763.     jnz    pp7        ;if no SIB byte
  3764.     inc    si
  3765. pp7:    cmp    al,40h
  3766.     jb    pp11        ;if indirect register
  3767.     cmp    al,80h
  3768.     jb    pp10        ;if disp8[reg(s)]
  3769.                 ;otherwise, it's disp32[reg(s)]
  3770. pp8:    inc    si
  3771.     inc    si
  3772. pp9:    inc    si
  3773. pp10:    inc    si
  3774.  
  3775. ;    Special instruction.  Set a breakpoint and run until we hit it.
  3776.  
  3777. pp11:    mov    ds,reg_cs
  3778.     mov    al,0cch
  3779.     xchg    al,[si]
  3780.     push    cs
  3781.     pop    ds
  3782.     mov    di,offset line_out    ;save old byte here
  3783.     stosb
  3784.     xchg    ax,si
  3785.     stosw
  3786.     mov    ax,reg_cs
  3787.     stosw
  3788.     call    run
  3789.     mov    si,offset line_out
  3790.     lodsb            ;get old byte
  3791.     xchg    ax,cx
  3792.     lodsw            ;old IP
  3793.     xchg    ax,bx
  3794.     lodsw            ;old CS
  3795.     xchg    ax,cx
  3796.     mov    ds,cx
  3797.     mov    [bx],al
  3798.     push    cs
  3799.     pop    ds
  3800.     xor    dx,dx        ;set flag
  3801.     cmp    run_int,offset int3msg
  3802.     jne    pp13        ;if not CC interrupt
  3803.     cmp    cx,reg_cs
  3804.     jne    pp13        ;if not same segment
  3805.     mov    ax,reg_ip
  3806.     dec    ax
  3807.     cmp    ax,bx
  3808.     jne    pp13        ;if not same offset
  3809.     mov    reg_ip,ax
  3810.     mov    dx,offset int3msg
  3811.     jmp    short pp13
  3812.  
  3813. ;    Ordinary instruction.  Just do a trace.
  3814.  
  3815. pp12:    or    flags,100h    ;set single-step mode
  3816.     call    run
  3817.     mov    dx,offset int1msg
  3818.  
  3819. ;    Common part to finish up.
  3820.  
  3821. pp13:    cmp    run_int,dx
  3822.     jne    pp15        ;if some other interrupt
  3823.     call    dumpregs
  3824.     pop    cx
  3825.     loop    pp14        ;back for more
  3826.     ret
  3827.  
  3828. pp14:    jmp    pp1        ;back for more
  3829. pp15:    jmp    tt2        ;print message about unexpected interrupt
  3830.                 ;and quit
  3831.  
  3832. ;    PPX - Get next byte in instruction stream.
  3833.  
  3834. pp16:    mov    ds,reg_cs
  3835.     lodsb
  3836.     push    cs
  3837.     pop    ds
  3838.     ret
  3839.  
  3840. ;    begin loop over instruction bytes.
  3841.  
  3842. ;    Q command - quit.
  3843.  
  3844. qq:    call    freemem        ;free the child process memory
  3845.  
  3846. ;    Restore interrupt vectors.
  3847.  
  3848.     mov    si,offset intsave
  3849.     lodsw
  3850.     xchg    ax,dx        ;mov    dx,ax
  3851.     lodsw
  3852.     mov    ds,ax
  3853.     mov    ax,2500h    ;set interrupt vector 0
  3854.     int    21h
  3855.     push    cs
  3856.     pop    ds
  3857.     lodsw
  3858.     xchg    ax,dx        ;mov    dx,ax
  3859.     lodsw
  3860.     mov    ds,ax
  3861.     mov    ax,2501h    ;set interrupt vector 1
  3862.     int    21h
  3863.     push    cs
  3864.     pop    ds
  3865.     lodsw
  3866.     xchg    ax,dx        ;mov    dx,ax
  3867.     lodsw
  3868.     mov    ds,ax
  3869.     mov    ax,2503h    ;set interrupt vector 3
  3870.     int    21h
  3871.     push    cs
  3872.     pop    ds
  3873.  
  3874. ;    Restore termination address.
  3875.  
  3876.     mov    si,offset psp22    ;restore termination address
  3877.     mov    di,0ah
  3878.     movsw
  3879.     movsw
  3880.     mov    di,16h        ;restore PSP of parent
  3881.     movsw
  3882.  
  3883. ;    Really done.
  3884.  
  3885.     int    20h
  3886.  
  3887. ;    R command - manipulate registers.
  3888.  
  3889. rr:    cmp    al,CR
  3890.     jne    rr1        ;if there's an argument
  3891.     call    dumpregs
  3892.     ret
  3893.  
  3894. rr1:    dec    si
  3895.     lodsw
  3896.     and    ax,TOUPPER_W
  3897.     mov    di,offset regnames
  3898.     mov    cx,13
  3899.     repne    scasw
  3900.     mov    bx,di
  3901.     mov    di,offset line_out
  3902.     jne    rr2        ;if not found
  3903.     stosw            ;print register name
  3904.     mov    al,' '
  3905.     stosb
  3906.     sub    bx,offset regnames+2
  3907.     call    skipwhite    ;skip white spaces
  3908.     cmp    al,CR
  3909.     jne    rr1a        ;if not end of line
  3910.     push    bx        ;save bx for later
  3911.     mov    ax,[bx+regs]
  3912.     call    hexword
  3913.     call    getline0    ;prompt for new value
  3914.     pop    bx
  3915.     cmp    al,CR
  3916.     je    ret        ;if no change required
  3917. rr1a:    call    getword
  3918.     call    chkeol        ;expect end of line here
  3919.     mov    [bx+regs],dx    ;save new value
  3920.     ret
  3921.  
  3922. ;    Change flags
  3923.  
  3924. rr2:    cmp    al,'F'
  3925.     jne    rr6        ;if not 'f'
  3926.     dec    si
  3927.     lodsb
  3928.     cmp    al,CR
  3929.     je    rr2b        ;if end of line
  3930.     cmp    al,' '
  3931.     je    rr2a        ;if white space
  3932.     cmp    al,TAB
  3933.     jne    errorj9        ;if not, then it's an error
  3934. rr2a:    call    skipwhite
  3935.     cmp    al,CR
  3936.     jne    rr3        ;if not end of line
  3937. rr2b:    call    dmpflags
  3938.     call    getline0    ;get input line (using line_out as prompt)
  3939. rr3:    cmp    al,CR
  3940.     je    ret        ;if done
  3941.     dec    si
  3942.     lodsw
  3943.     and    ax,TOUPPER_W    ;here's the mnemonic
  3944.     mov    di,offset flgnams
  3945.     mov    cx,16
  3946.     repne    scasw
  3947.     jne    rr6        ;if no match
  3948.     cmp    di,offset flgnons
  3949.     ja    rr4        ;if we're clearing
  3950.     mov    ax,[di-16-2]
  3951.     not    ax
  3952.     and    flags,ax
  3953.     jmp    short rr5
  3954.  
  3955. rr4:    mov    ax,[di-32-2]
  3956.     or    flags,ax
  3957.  
  3958. rr5:    call    skipwhite
  3959.     jmp    rr3        ;if done
  3960.  
  3961. rr6:    dec    si        ;back up one before flagging an error
  3962. errorj9:jmp    error
  3963.  
  3964. ;    S command - search for a string of bytes.
  3965.  
  3966. sss:    mov    bx,reg_ds    ;get search range
  3967.     xor    cx,cx
  3968.     call    getrange    ;get address range into BX:DX..BX:CX
  3969.     call    skipwh0
  3970.     push    cx
  3971.     push    dx
  3972.     call    getstr        ;get string of bytes
  3973.     pop    dx
  3974.     pop    cx
  3975.     sub    cx,dx        ;cx = number of bytes in search range minus one
  3976.     sub    di,offset line_out ;di = number of bytes to look for
  3977.     dec    di        ;        minus one
  3978.     sub    cx,di        ;number of possible positions of string minus 1
  3979.     jb    errorj9        ;if none
  3980.     push    di
  3981.     call    prehack        ;set up for the interrupt vector hack
  3982.     pop    di
  3983.     inc    cx        ;cx = number of possible positions of string
  3984.     xchg    dx,di
  3985.     push    bx        ;push the segment
  3986. sss1:    push    di
  3987.     call    dohack        ;do the interrupt pointer hack
  3988.     pop    di
  3989.     pop    es        ;recover the segment
  3990.     mov    si,offset line_out;si = address of search string
  3991.     lodsb            ;first character in al
  3992.     repne    scasb        ;look for first byte
  3993.     jne    sss3        ;if we're done
  3994.     push    es        ;save the segment again
  3995.     mov    ax,es        ;also in ax
  3996.     push    cx
  3997.     push    di
  3998.     mov    cx,dx
  3999.     repe    cmpsb
  4000.     push    si
  4001.     pushf
  4002.     call    unhack        ;undo the interrupt vector hack and restore es
  4003.     popf
  4004.     pop    si
  4005.     pop    di
  4006.     jne    sss2        ;if not equal
  4007.     push    dx
  4008.     xchg    si,di        ;write address right after search string
  4009.     call    hexword
  4010.     mov    al,':'
  4011.     stosb
  4012.     lea    ax,[si-1]
  4013.     call    hexword
  4014.     mov    ax,LF * 256 + CR
  4015.     stosw
  4016.     mov    ah,40h        ;write to file
  4017.     mov    bx,1
  4018.     mov    cx,11
  4019.     lea    dx,[di-11]
  4020.     int    21h
  4021.     pop    dx
  4022.     mov    di,si
  4023. sss2:    pop    cx
  4024.     inc    cx
  4025.     loop    sss1        ;go back for more
  4026.     pop    ax        ;remove saved es from the stack
  4027.  
  4028. sss3:    jmp    unhack        ;undo the interrupt vector hack, restore es,
  4029.                 ;and return
  4030.  
  4031. ;    T command - Trace.
  4032.  
  4033. tt:    call    parse_pt    ;process arguments
  4034.  
  4035. ;    Do it <count> times.
  4036.  
  4037. tt1:    push    cx
  4038.     or    flags,100h    ;set single-step mode
  4039.     call    run
  4040.     cmp    run_int,offset int1msg
  4041.     jne    tt2        ;if some other interrupt
  4042.     call    dumpregs
  4043.     pop    cx
  4044.     loop    tt1
  4045.     ret
  4046.  
  4047. ;    Print message about unexpected interrupt, dump registers, and end
  4048. ;    command.  This code is also used by the G and P commands.
  4049.  
  4050. tt2:    mov    ah,9        ;print string
  4051.     mov    dx,run_int
  4052.     int    21h
  4053.     cmp    dx,offset progtrm
  4054.     je    tt3        ;if it terminated, skip the registers
  4055.     call    dumpregs
  4056. tt3:    jmp    cmd3        ;back to the start
  4057.  
  4058. ;    U command - disassemble.
  4059.  
  4060. uu:    cmp    al,CR
  4061.     jne    uu1        ;if an address was given
  4062.     mov    cx,u_addr
  4063.     add    cx,1fh
  4064.     jnc    uu2        ;if no overflow
  4065.     mov    cx,-1
  4066.     jmp    short uu2
  4067.  
  4068. uu1:    mov    cx,20h        ;default length
  4069.     mov    bx,reg_cs
  4070.     call    getrange    ;get address range into dx:bx
  4071.     call    chkeol        ;expect end of line here
  4072.     mov    u_addr+2,bx
  4073.     mov    u_addr,dx
  4074.  
  4075. ;    At this point, cx holds the last address, and dx the address.
  4076.  
  4077. uu2:    inc    cx        ;cx = last address + 1
  4078. uu3:    push    cx
  4079.     push    dx
  4080.     mov    byte disflags,0
  4081.     call    disasm        ;do it
  4082.     pop    bx
  4083.     pop    cx
  4084.     mov    ax,u_addr
  4085.     mov    dx,ax
  4086.     sub    ax,cx        ;current position - end
  4087.     sub    bx,cx        ;previous position - end
  4088.     cmp    ax,bx
  4089.     jnb    uu3        ;if we haven't reached the goal
  4090. uu4:    ret
  4091.  
  4092. ;    W command - write a program, or disk sectors, to disk.
  4093.  
  4094. ww:    call    parselw        ;parse it
  4095.     jz    ww4        ;if request to write program
  4096.     int    26h
  4097.     mov    dx,offset writing
  4098. ww1:    mov    bx,cs        ;restore segment registers
  4099.     mov    ds,bx
  4100.     mov    ss,bx
  4101.     mov    sp,savesp
  4102.     mov    es,bx
  4103.     jnc    ww3        ;if no error
  4104.     cmp    al,0ch
  4105.     jbe    ww2        ;if in range
  4106.     mov    al,0ch
  4107. ww2:    cbw
  4108.     shl    ax,1
  4109.     xchg    si,ax
  4110.     mov    si,[si+dskerrs]
  4111.     mov    di,offset line_out
  4112.     call    showstring
  4113.     mov    si,dx
  4114.     call    showstring
  4115.     mov    si,offset drive
  4116.     call    showstring
  4117.     call    putsline
  4118. ww3:    jmp    cmd3        ;can't ret because stack is wrong
  4119.  
  4120. ;    Write to file.  First check the file extension.
  4121.  
  4122. ww4:    mov    bx,execblk+2    ;address of end of file name string
  4123.     cmp    bx,85h
  4124.     jb    ww7        ;if file name is too short
  4125.     cmp    word [bx-5],'E.'
  4126.     jne    ww5        ;if not .EXE
  4127.     cmp    word [bx-3],'EX'
  4128.     jne    ww7        ;if not .EXE
  4129.     jmp    short ww6    ;bad
  4130.  
  4131. ww5:    cmp    word [bx-5],'H.'
  4132.     jne    ww7        ;if not .HEX
  4133.     cmp    word [bx-3],'XE'
  4134.     jne    ww7        ;if not .HEX
  4135.  
  4136. ww6:    mov    ah,9        ;print string
  4137.     mov    dx,offset nowhexe
  4138.     int    21h
  4139.     ret
  4140.  
  4141. ;    File extension is OK; write it.  First, create the file.
  4142.  
  4143. ww7:    mov    ah,3ch        ;create file
  4144.     xor    cx,cx        ;no attributes
  4145.     mov    dx,80h
  4146.     int    21h
  4147.     jnc    ww8
  4148.     jmp    ww15        ;if error
  4149. ww8:    push    ax        ;save file handle
  4150.  
  4151. ;    Print message about writing.
  4152.  
  4153.     mov    ah,9        ;print string
  4154.     mov    dx,offset wwmsg1
  4155.     int    21h
  4156.     mov    ax,reg_bx
  4157.     cmp    ax,10h
  4158.     jb    ww9        ;if not too large
  4159.     xor    ax,ax        ;too large:  zero it out
  4160. ww9:    mov    word line_out+8,ax
  4161.     or    ax,ax
  4162.     jz    ww10
  4163.     add    al,90h        ;convert to hex and print
  4164.     daa
  4165.     adc    al,40h
  4166.     daa
  4167.     stosb
  4168. ww10:    mov    ax,reg_cx
  4169.     mov    word line_out+6,ax
  4170.     call    hexword
  4171.     call    puts        ;print size
  4172.     mov    ah,9        ;print string
  4173.     mov    dx,offset wwmsg2
  4174.     int    21h
  4175.  
  4176. ;    Now write the file.  Size remaining is in line_out+6.
  4177.  
  4178.     pop    bx        ;recover file handle
  4179.     mov    si,psp
  4180.     add    si,10h        ;si = starting paragraph
  4181. ww11:    mov    ax,0fe00h
  4182.     cmp    byte line_out+8,0
  4183.     jnz    ww12        ;if more than 0fe00h bytes remaining
  4184.     cmp    ax,word line_out+6
  4185.     jb    ww12        ;ditto
  4186.     mov    ax,word line_out+6
  4187. ww12:    xchg    ax,cx        ;mov cx,ax
  4188.     mov    ah,40h        ;write to file
  4189.     xor    dx,dx
  4190.     mov    ds,si
  4191.     int    21h
  4192.     push    cs        ;restore DS
  4193.     pop    ds
  4194.     cmp    ax,cx
  4195.     jne    ww13        ;if disk full
  4196.     add    si,0fe0h    ;update segment pointer
  4197.     sub    word line_out+6,cx
  4198.     lahf
  4199.     sbb    byte line_out+8,0
  4200.     jnz    ww11        ;if more to go
  4201.     sahf
  4202.     jnz    ww11        ;ditto
  4203.     jmp    short ww14
  4204.  
  4205. ww13:    mov    ah,9        ;print string
  4206.     mov    dx,offset diskful
  4207.     int    21h
  4208.     mov    ah,41h        ;unlink file
  4209.     mov    dx,80h
  4210.     int    21h
  4211.  
  4212. ;    Close the file.
  4213.  
  4214. ww14:    mov    ah,3eh        ;close file
  4215.     int    21h
  4216.     ret
  4217.  
  4218. ;    Error opening file.  This is also called by the load command.
  4219.  
  4220. ww15:    cmp    ax,2
  4221.     mov    dx,offset doserr2 ;File not found
  4222.     je    ww16
  4223.     cmp    ax,3
  4224.     mov    dx,offset doserr3 ;Path not found
  4225.     je    ww16
  4226.     cmp    ax,5
  4227.     mov    dx,offset doserr5 ;Access denied
  4228.     je    ww16
  4229.     cmp    ax,8
  4230.     mov    dx,offset doserr8 ;Insufficient memory
  4231.     je    ww16
  4232.     push    ax
  4233.     mov    ah,9        ;print string
  4234.     mov    dx,offset wwerr1;'Error '
  4235.     int    21h
  4236.     pop    ax
  4237.     mov    di,offset line_out
  4238.     call    hexword
  4239.     call    puts        ;print error code
  4240.     mov    dx,offset wwerr2;' opening file.',CR,LF
  4241. ww16:    mov    ah,9        ;print string
  4242.     int    21h
  4243.     ret
  4244.  
  4245. ;    Error handlers.
  4246.  
  4247. error:    mov    cx,si
  4248.     sub    cx,offset line_in+4
  4249.     add    cx,promptlen
  4250.     cmp    cx,127
  4251.     ja    err2        ;if we're really messed up
  4252.     inc    cx        ;number of spaces to skip
  4253.     mov    dl,' '
  4254. err1:    mov    ah,2        ;display output
  4255.     int    21h
  4256.     loop    err1
  4257. err2:    mov    ah,9        ;print string
  4258.     mov    dx,offset errcarat
  4259.     int    21h
  4260.     jmp    [errret]
  4261.  
  4262. ;    FREEMEM - Free the child process's memory.
  4263.  
  4264. freemem:cmp    running,0
  4265.     jz    fmem1        ;if process has already terminated
  4266.     mov    reg_cs,cs
  4267.     mov    reg_ip,offset fmem4
  4268.     mov    reg_ss,ss
  4269.     push    ax
  4270.     mov    reg_sp,sp    ;save sp-2
  4271.     pop    ax
  4272.     call    run
  4273.  
  4274. ;    Free blocks created when we loaded a program ourselves.
  4275.  
  4276. fmem1:    mov    si,offset blk1
  4277.     mov    cx,2
  4278. fmem2:    lodsw
  4279.     cmp    ax,0
  4280.     je    fmem3        ;if nothing needs to be done
  4281.     mov    es,ax
  4282.     mov    ah,49h        ;free memory
  4283.     int    21h
  4284.     loop    fmem2
  4285.  
  4286. fmem3:    push    cs        ;restore ES
  4287.     pop    es
  4288.     ret            ;done
  4289.  
  4290. fmem4:    mov    ax,4c00h    ;quit
  4291.     int    21h
  4292.  
  4293. ;    This is the routine that starts up the running program.
  4294.  
  4295. run:    call    seteq        ;set CS:IP to '=' address
  4296.     mov    ah,50h        ;set PSP
  4297.     mov    bx,psp
  4298.     int    21h
  4299.     mov    ax,2524h    ;set interrupt vector 24h
  4300.     lds    dx,run2324+4
  4301.     int    21h
  4302.     mov    ax,2523h    ;set interrupt vector 23h
  4303.     lds    dx,cs:run2324
  4304.     int    21h
  4305.     push    cs        ;restore ds
  4306.     pop    ds
  4307.     mov    run_sp,sp    ;save stack position
  4308.     sub    sp,spadjust
  4309.     mov    [2eh],sp
  4310.     cli
  4311.     mov    sp,offset regs
  4312.     pop    ax
  4313.     pop    bx
  4314.     pop    cx
  4315.     pop    dx
  4316.     pop    bp        ;we'll get sp later
  4317.     pop    bp
  4318.     pop    si
  4319.     pop    di
  4320.     pop    ds
  4321.     pop    es
  4322.     pop    ss
  4323.     mov    sp,cs:reg_sp    ;restore program stack
  4324.     push    cs:flags
  4325.     push    cs:reg_cs
  4326.     push    cs:reg_ip
  4327.     iret            ;jump to program
  4328.  
  4329. ;    Interrupt 22 (program termination) handler.
  4330.  
  4331. int22:    cli
  4332.     mov    cs:run_int,offset progtrm    ;remember interrupt type
  4333.     mov    cs:reg_cs,cs        ;put in dummy value for CS:IP
  4334.     mov    cs:reg_ip,0
  4335.     mov    cs:flags,200h
  4336.     mov    cs:running,0
  4337.     jmp    short intrtn1    ;jump to register saving routine (sort of)
  4338.  
  4339. ;    Interrupt 0 (divide error) handler.
  4340.  
  4341. int0:    mov    cs:run_int,offset int0msg    ;remember interrupt type
  4342.     jmp    short intrtn    ;jump to register saving routine
  4343.  
  4344. ;    Interrupt 1 (single-step interrupt) handler.
  4345.  
  4346. int1:    mov    cs:run_int,offset int1msg    ;remember interrupt type
  4347.     jmp    short intrtn    ;jump to register saving routine
  4348.  
  4349. ;    Interrupt 3 (breakpoint interrupt) handler.
  4350.  
  4351. int3:    mov    cs:run_int,offset int3msg    ;remember interrupt type
  4352.  
  4353. ;    Common interrupt routine.
  4354.  
  4355. ;    Housekeeping.
  4356.  
  4357. intrtn:    cli            ;just in case
  4358.     pop    cs:reg_ip    ;recover things from stack
  4359.     pop    cs:reg_cs
  4360.     pop    cs:flags
  4361. intrtn1:mov    cs:reg_ss,ss    ;save stack position
  4362.     mov    cs:reg_sp,sp
  4363.     mov    sp,cs        ;mov ss,cs
  4364.     mov    ss,sp
  4365.     mov    sp,offset reg_ss
  4366.     push    es
  4367.     push    ds
  4368.     push    di
  4369.     push    si
  4370.     push    bp
  4371.     dec    sp        ;we already saved sp
  4372.     dec    sp
  4373.     push    dx
  4374.     push    cx
  4375.     push    bx
  4376.     push    ax
  4377.  
  4378. ;    Clean up.
  4379.  
  4380.     mov    sp,cs:run_sp    ;restore running stack
  4381.     sti            ;interrupts back on
  4382.     cld            ;clear direction flag
  4383.     push    cs        ;reestablish DS
  4384.     pop    ds
  4385.     mov    ax,3523h    ;get interrupt vector 23h into ES:BX
  4386.     int    21h
  4387.     mov    run2324,bx
  4388.     mov    run2324+2,es
  4389.     mov    ax,2523h    ;set interrupt vector 23h
  4390.     lds    dx,[0eh]
  4391.     int    21h
  4392.     push    cs        ;reestablish DS
  4393.     pop    ds
  4394.     mov    ax,3524h    ;get interrupt vector 24h
  4395.     int    21h
  4396.     mov    run2324+4,bx
  4397.     mov    run2324+6,es
  4398.     mov    ax,2524h    ;set interrupt vector 24h
  4399.     lds    dx,[12h]    ;get original vector from PSP
  4400.     int    21h
  4401.     mov    ah,50h        ;set PSP
  4402.     mov    bx,cs
  4403.     int    21h
  4404.     mov    ds,bx        ;reestablish DS and ES
  4405.     mov    es,bx
  4406.     and    flags,not 100h    ;clear single-step interrupt
  4407.  
  4408. ;    Return.
  4409.  
  4410.     ret
  4411.  
  4412. ;    The next three subroutines concern the handling of INT 23 and 24.
  4413. ;    These interrupt vectors are saved and restored when running the
  4414. ;    child process, but are not active when DEBUG itself is running.
  4415. ;    It is still useful for the programmer to be able to check where INT 23
  4416. ;    and 24 point, so these values are copied into the interrupt table
  4417. ;    during parts of the c, d, e, m, and s commands, so that they appear
  4418. ;    to be in effect.  The e command also copies these values back.
  4419. ;    Between calls to dohack and unhack, there should be no calls to DOS,
  4420. ;    so that there is no possibility of these vectors being used when
  4421. ;    the child process is not running.
  4422.  
  4423. ;    PREHACK - Set up for interrupt vector substitution.
  4424. ;    Entry    es = cs
  4425. ;    Exit    ds = cs
  4426. ;    Uses    si, di.
  4427.  
  4428. prehack:cmp    hakstat,0
  4429.     jnz    ph_err        ;if hack status error |||
  4430.     mov    di,offset sav2324
  4431. prehak1:xor    si,si
  4432.     mov    ds,si
  4433.     mov    si,4*23h
  4434.     movsw
  4435.     movsw
  4436.     movsw
  4437.     movsw
  4438.     push    cs
  4439.     pop    ds
  4440.     ret
  4441.  
  4442. ph_err:    push    ax
  4443.     push    dx
  4444.     mov    ah,9        ;print string |||
  4445.     mov    dx,offset ph_msg
  4446.     int    21h
  4447.     pop    dx
  4448.     pop    ax
  4449.     ret
  4450.  
  4451. ph_msg    db    'Error in sequence of calls to hack.',CR,LF,'$'
  4452.  
  4453. ;    DOHACK - Fake the interrupt vectors 23 and 24.
  4454. ;    UNHACK - Restore interrupt vectors 23 and 24 to their original values.
  4455. ;        It's OK to do either of these twice in a row.
  4456. ;        In particular, the `s' command may do unhack twice in a row.
  4457. ;    Entry    ds = cs
  4458. ;    Exit    es = cs
  4459. ;    Uses    si, di.
  4460.  
  4461. dohack:    mov    hakstat,1
  4462.     mov    si,offset run2324
  4463.     jmp    short hak1
  4464.  
  4465. unhack:    mov    hakstat,0
  4466.     mov    si,offset sav2324
  4467. hak1:    xor    di,di
  4468.     mov    es,di
  4469.     mov    di,4*23h
  4470.     movsw
  4471.     movsw
  4472.     movsw
  4473.     movsw
  4474.     push    cs
  4475.     pop    es
  4476.     ret
  4477.  
  4478. ;    GETLINE - Print a prompt (address in DX, length in CX) and read a line
  4479. ;    of input.
  4480. ;    GETLINE0 - Same as above, but use the output line (so far), plus two
  4481. ;    spaces and a colon, as a prompt.
  4482. ;    GETLINE00 - Same as above, but use the output line (so far) as a prompt.
  4483. ;    Entry    CX    Length of prompt (getline only)
  4484. ;        DX    Address of prompt string (getline only)
  4485. ;
  4486. ;        DI    Address + 1 of last character in prompt (getline0 and
  4487. ;            getline00 only)
  4488. ;
  4489. ;    Exit    AL    First nonwhite character in input line
  4490. ;        SI    Address of the next character after that
  4491. ;    Uses    AH,BX,CX,DX,DI
  4492.  
  4493. getline0:
  4494.     mov    ax,'  '        ;add two spaces and a colon
  4495.     stosw
  4496.     mov    al,':'
  4497.     stosb
  4498. getline00:
  4499.     mov    dx,offset line_out
  4500.     mov    cx,di
  4501.     sub    cx,dx
  4502.  
  4503. getline:
  4504.     mov    promptlen,cx    ;save length of prompt
  4505.     call    bufsetup
  4506.     pushf
  4507.     mov    ah,40h        ;write to file
  4508.     mov    bx,1        ;standard output
  4509.     int    21h
  4510.     popf
  4511.     jc    gl5        ;if tty input
  4512.  
  4513. ;    This part reads the input line from a file (in the case of
  4514. ;    `debug < file').  It is necessary to do this by hand because DOS
  4515. ;    function 0ah does not handle EOF correctly otherwise.  This is
  4516. ;    especially important for debug because it traps Control-C.
  4517.  
  4518. gl1:    mov    cx,bufend
  4519.     sub    cx,si        ;cx = number of valid characters
  4520.     jz    gl3        ;if none
  4521. gl2:    lodsb
  4522.     cmp    al,CR
  4523.     je    gl4        ;if end of line
  4524.     cmp    al,LF
  4525.     je    gl4        ;if eol
  4526.     stosb
  4527.     loop    gl2        ;if there are more valid characters
  4528. gl3:    call    fillbuf
  4529.     jnc    gl1        ;if we have more characters
  4530.     mov    al,LF
  4531.     cmp    di,offset line_in+LINE_IN_LEN
  4532.     jb    gl4
  4533.     dec    si
  4534.     dec    di
  4535. gl4:    mov    bufnext,si
  4536.     mov    notatty,al
  4537.     mov    al,CR
  4538.     stosb
  4539.     mov    ah,40h        ;write to file:  print out the received line
  4540.     mov    bx,1
  4541.     mov    cx,di
  4542.     mov    dx,offset line_in + 2
  4543.     sub    cx,dx
  4544.     int    21h
  4545.     jmp    short gl6    ;done
  4546.  
  4547. gl5:    mov    ah,0ah        ;buffered keyboard input
  4548.     mov    dx,offset line_in
  4549.     int    21h
  4550.  
  4551. gl6:    mov    ah,2        ;display output
  4552.     mov    dl,LF        ;print a line feed afterwards
  4553.     int    21h
  4554.     mov    si,offset line_in + 2
  4555.     call    skipwhite
  4556.     ret
  4557.  
  4558. ;    BUFSETUP - Set up buffer reading.  This just means discard an LF
  4559. ;    if the last character read (as stored in `notatty') is CR.
  4560. ;    Entry    DI    First available byte in input buffer
  4561. ;    Exit    SI    Address of next character.
  4562. ;    If the input is from a tty, then bufsetup returns with carry set.
  4563.  
  4564. bufsetup:
  4565.     cmp    notatty,0
  4566.     jnz    bs1        ;if not a tty
  4567.     stc
  4568.     ret
  4569.  
  4570. bs1:    mov    di,offset line_in+2
  4571.     mov    si,bufnext
  4572.     cmp    si,bufend
  4573.     jb    bs2        ;if there's a character already
  4574.     call    fillbuf
  4575.     jc    bs4        ;if eof
  4576. bs2:    cmp    notatty,CR
  4577.     jne    bs3        ;if nothing more to do
  4578.     cmp    byte [si],LF
  4579.     jne    bs3        ;if not a line feed
  4580.     inc    si        ;skip it
  4581. bs3:    clc
  4582.     ret
  4583.  
  4584. bs4:    jmp    qq        ;quit:  we've hit an eof
  4585.  
  4586. ;    FILLBUF - Fill input buffer.  Mostly this is an internal routine
  4587. ;    for getline.
  4588. ;    Entry    DI    First available byte in input buffer
  4589. ;    Exit    SI    Next readable byte (i.e., equal to DI)
  4590. ;        Carry flag is set if and only if there is an error (e.g., eof)
  4591. ;    Uses    None.
  4592.  
  4593. fillbuf:push    ax
  4594.     push    bx
  4595.     push    cx
  4596.     push    dx
  4597.     mov    si,di        ;we know this already
  4598.     mov    ah,3fh        ;read from file
  4599.     xor    bx,bx
  4600.     mov    cx,offset line_in+LINE_IN_LEN
  4601.     mov    dx,di
  4602.     sub    cx,dx
  4603.     jz    fb1        ;if no more room
  4604.     int    21h
  4605.     jc    fb1        ;if error
  4606.     or    ax,ax
  4607.     jz    fb1        ;if eof
  4608.     add    ax,dx
  4609.     clc
  4610.     jmp    short fb2
  4611.  
  4612. fb1:    xchg    ax,dx        ;ax = last valid byte address + 1
  4613.     stc
  4614.  
  4615. fb2:    mov    bufend,ax
  4616.     pop    dx
  4617.     pop    cx
  4618.     pop    bx
  4619.     pop    ax
  4620.     ret
  4621.  
  4622. ;    PARSECM - Parse command line for C and M commands.
  4623. ;    Entry    AL    First nonwhite character of parameters
  4624. ;        SI    Address of the character after that
  4625. ;    Exit    DS:SI    Address from first parameter
  4626. ;        ES:DI    Address from second parameter
  4627. ;        CX    Length of address range minus one
  4628.  
  4629. parsecm:push    si
  4630.     call    prehack
  4631.     pop    si
  4632.     mov    bx,reg_ds    ;get source range
  4633.     xor    cx,cx
  4634.     call    getrange
  4635.     sub    cx,dx        ;number of bytes minus one
  4636.     push    bx
  4637.     push    dx
  4638.     push    cx
  4639.     call    skipwh0
  4640.     mov    bx,reg_ds
  4641.     call    getaddr        ;get destination address
  4642.     pop    cx
  4643.     mov    di,cx
  4644.     add    di,dx
  4645.     jc    errorj7        ;if it wrapped around
  4646.     call    chkeol        ;expect end of line
  4647.     mov    di,dx
  4648.     mov    es,bx
  4649.     pop    si
  4650.     pop    ds
  4651.     ret
  4652.  
  4653. errorj7:jmp    error
  4654.  
  4655. ;    PARSELW - Parse command line for L and W commands.
  4656. ;    Entry    AL    First nonwhite character of parameters
  4657. ;        SI    Address of the character after that
  4658. ;    Exit    If there is at most one argument (program load/write), then the
  4659. ;        zero flag is set, and registers are set as follows:
  4660. ;        bx:dx    Transfer address
  4661. ;        If there are more arguments (absolute disk read/write), then the
  4662. ;        zero flag is clear, and registers are set as follows:
  4663. ;        DOS versions prior to 3.31:
  4664. ;        AL    Drive number
  4665. ;        CX    Number of sectors to read
  4666. ;        DX    Beginning logical sector number
  4667. ;        DS:BX    Transfer address
  4668. ;        Later DOS versions:
  4669. ;        AL    Drive number
  4670. ;        BX    Offset of packet
  4671. ;        CX    0FFFFh
  4672.  
  4673. usepacket db    0        ;if the packet is to be used
  4674.  
  4675. packet    dw    0,0        ;sector number
  4676.     dw    0        ;number of sectors to read
  4677.     dw    0,0        ;transfer address
  4678.  
  4679. parselw:mov    bx,reg_cs    ;default segment
  4680.     mov    dx,100h        ;default offset
  4681.     cmp    al,CR
  4682.     je    plw2        ;if no arguments
  4683.     call    getaddr        ;get address
  4684.     call    skipwh0
  4685.     cmp    al,CR
  4686.     je    plw2        ;if only one argument
  4687.     push    dx
  4688.     push    bx
  4689.     mov    bx,80h        ;max number of sectors to read
  4690.     neg    dx
  4691.     jz    plw1        ;if address is zero
  4692.     mov    cl,9
  4693.     shr    dx,cl        ;max number of sectors which can be read
  4694.     mov    di,dx
  4695. plw1:    call    getbyte        ;get drive number
  4696.     call    skipwh0
  4697.     push    dx
  4698.     add    dl,'A'
  4699.     mov    driveno,dl
  4700.     call    getdbl        ;get relative sector number
  4701.     call    skipwh0
  4702.     push    dx
  4703.     push    bx
  4704.     push    si        ;in case we find an error
  4705.     call    getword        ;get sector count
  4706.     dec    dx
  4707.     cmp    dx,di
  4708.     jae    errorj7        ;if too many sectors
  4709.     inc    dx
  4710.     mov    cx,dx
  4711.     call    chkeol        ;expect end of line
  4712.     cmp    usepacket,0
  4713.     jnz    plw3        ;if new-style packet called for
  4714.     pop    si        ;in case of error
  4715.     pop    bx        ;high bits of sector number
  4716.     or    bx,bx
  4717.     jnz    errorj7        ;if too big
  4718.     pop    dx        ;beginning logical sector number
  4719.     pop    ax        ;drive number
  4720.     pop    ds        ;transfer address
  4721.     pop    bx
  4722.     or    cx,cx        ;set nonzero flag
  4723. plw2:    ret
  4724.  
  4725. plw3:    pop    bx        ;discard si
  4726.     mov    bx,offset packet
  4727.     pop    [bx+2]        ;sector number
  4728.     pop    [bx]
  4729.     mov    [bx+4],cx    ;number of sectors
  4730.     pop    ax        ;drive number
  4731.     pop    [bx+8]        ;transfer address
  4732.     pop    [bx+6]
  4733.     xor    cx,cx
  4734.     dec    cx        ;set nonzero flag and make cx = -1
  4735.     ret
  4736.  
  4737. ;    PARSE_PT - Parse 'p' or 't' command.
  4738. ;    Entry    AL    First character of command
  4739. ;        SI    Address of next character
  4740. ;    Exit    CX    Number of times to repeat
  4741. ;    Uses    AH,BX,CX,DX.
  4742.  
  4743. parse_pt:
  4744.     call    parseql        ;process =addr
  4745.     call    skipwh0        ;skip any white space
  4746.     mov    cx,1        ;default count
  4747.     cmp    al,CR
  4748.     je    ppt1        ;if no count given
  4749.     call    getword
  4750.     call    chkeol        ;expect end of line here
  4751.     mov    cx,dx
  4752. ppt1:    call    seteq        ;make the = operand take effect
  4753.     ret
  4754.  
  4755. ;    PARSEQL - Parse `=' operand for `g' and `t' commands.
  4756. ;    Entry    AL    First character of command
  4757. ;        SI    Address of next character
  4758. ;    Exit    AL    First character beyond range
  4759. ;        SI    Address of the character after that
  4760. ;        eqflag    Nonzero if an `=' operand was present
  4761. ;        eqladdr    Address, if one was given
  4762. ;    Uses    AH,BX,CX,DX.
  4763.  
  4764. parseql:mov    eqflag,0    ;mark `=' as absent
  4765.     cmp    al,'='
  4766.     jne    peq1        ;if no `=' operand
  4767.     call    skipwhite
  4768.     mov    bx,reg_cs    ;default segment
  4769.     call    getaddr        ;get the address into bx:dx
  4770.     mov    eqladdr,dx
  4771.     mov    eqladdr+2,bx
  4772.     mov    eqflag,1
  4773. peq1:    ret
  4774.  
  4775. ;    SETEQ - Copy the = arguments to their place, if appropriate.  (This
  4776. ;    is not done immediately, because the 'g' command may have a syntax
  4777. ;    error.)
  4778. ;    Uses    AX.
  4779.  
  4780. seteq:    cmp    eqflag,0
  4781.     jz    seq1        ;if no `=' operand
  4782.     mov    ax,eqladdr
  4783.     mov    reg_ip,ax
  4784.     mov    ax,eqladdr+2
  4785.     mov    reg_cs,ax
  4786.     mov    eqflag,0    ;clear the flag
  4787. seq1:    ret
  4788.  
  4789. ;    GETRANGE - Get address range from input line.
  4790. ;    Entry    AL    First character of range
  4791. ;        SI    Address of next character
  4792. ;        BX    Default segment to use
  4793. ;        CX    Default length to use (or 0 if not allowed)
  4794. ;    Exit    AL    First character beyond range
  4795. ;        SI    Address of the character after that
  4796. ;        BX:DX    First address in range
  4797. ;        BX:CX    Last address in range
  4798. ;    Uses    AH
  4799.  
  4800. getrange:
  4801.     push    cx        ;save the default length
  4802.     call    getaddr
  4803.     push    si
  4804.     call    skipwh0
  4805.     cmp    al,','
  4806.     je    gr2        ;if an upper bound is given
  4807.     or    al,TOLOWER
  4808.     cmp    al,'l'
  4809.     je    gr3        ;if a range is given
  4810.     pop    si        ;restore si and cx
  4811.     pop    cx
  4812.     jcxz    errorj2        ;if a range is mandatory
  4813.     dec    cx
  4814.     add    cx,dx
  4815.     jnc    gr1        ;if no wraparound
  4816.     mov    cx,0ffffh    ;go to end of segment
  4817. gr1:    dec    si        ;restore al
  4818.     lodsb
  4819.     ret
  4820.  
  4821. gr2:    call    skipwhite    ;discard the ','
  4822.     push    dx
  4823.     call    getword
  4824.     mov    cx,dx
  4825.     pop    dx
  4826.     cmp    dx,cx
  4827.     ja    errorj2        ;if empty range
  4828.     jmp    short gr4
  4829.  
  4830. gr3:    call    skipwhite    ;discard the 'l'
  4831.     push    dx
  4832.     call    getword
  4833.     mov    cx,dx
  4834.     pop    dx
  4835.     jcxz    errorj2        ;if zero length
  4836.     dec    cx
  4837.     add    cx,dx
  4838.     jc    errorj2        ;if it wraps around
  4839.  
  4840. gr4:    add    sp,4        ;discard saved cx, si
  4841.     ret
  4842.  
  4843. ;    GETADDR - Get address from input line.
  4844. ;    Entry    AL    First character of address
  4845. ;        SI    Address of next character
  4846. ;        BX    Default segment to use
  4847. ;    Exit    AL    First character beyond address
  4848. ;        SI    Address of the character after that
  4849. ;        BX:DX    Address found
  4850. ;    Uses    AH,CX
  4851.  
  4852. getaddr:mov    ah,[si]
  4853.     or    ah,TOLOWER
  4854.     cmp    ah,'s'
  4855.     jne    ga1        ;if not a segment specifier
  4856.     push    di
  4857.     or    al,TOLOWER
  4858.     mov    di,offset segletrs
  4859.     mov    cx,4
  4860.     repne    scasb
  4861.     jne    errorj2        ;if not a valid segment name
  4862.     sub    di,offset segletrs+1
  4863.     shl    di,1
  4864.     mov    bx,[reg_ds+di]
  4865.     pop    di
  4866.     inc    si        ;skip over 's'
  4867.     call    skipwhite    ;get next character
  4868.     cmp    al,':'
  4869.     jne    errorj2        ;expect a colon
  4870.     jmp    short ga3    ;get colon and lower part of address
  4871.  
  4872. ga1:    call    getword
  4873.     push    si
  4874.     call    skipwh0
  4875.     cmp    al,':'
  4876.     je    ga2        ;if this is a segment descriptor
  4877.     pop    si
  4878.     dec    si
  4879.     lodsb
  4880.     ret
  4881.  
  4882. ga2:    pop    ax        ;throw away saved si
  4883.     mov    bx,dx
  4884. ga3:    call    skipwhite    ;skip to next word
  4885.     call    getword
  4886.     ret
  4887.  
  4888. errorj2:jmp    error
  4889.  
  4890. ;    GETSTR - Get string of bytes.  Put the answer in line_out.
  4891. ;        Entry    AL    first character
  4892. ;            SI    address of next character
  4893. ;        Exit    [line_out] first byte of string
  4894. ;            DI    address of last+1 byte of string
  4895. ;        Uses    AX,CL,DL,SI
  4896.  
  4897. getstr:    mov    di,offset line_out
  4898.     cmp    al,CR
  4899.     je    errorj2        ;we don't allow empty byte strings
  4900. gs1:    cmp    al,"'"
  4901.     je    gs2        ;if string
  4902.     cmp    al,'"'
  4903.     je    gs2        ;ditto
  4904.     call    getbyte
  4905.     mov    [di],dl        ;store the byte
  4906.     inc    di
  4907.     jmp    short gs6
  4908.  
  4909. gs2:    mov    ah,al        ;save quote character
  4910. gs3:    lodsb
  4911.     cmp    al,ah
  4912.     je    gs5        ;if possible end of string
  4913.     cmp    al,CR
  4914.     je    errorj2        ;if end of line
  4915. gs4:    stosb            ;save character and continue
  4916.     jmp    gs3
  4917.  
  4918. gs5:    lodsb
  4919.     cmp    al,ah
  4920.     je    gs4        ;if doubled quote character
  4921.  
  4922. gs6:    call    skipwh0        ;go back for more
  4923.     cmp    al,CR
  4924.     jne    gs1        ;if not done yet
  4925.     ret
  4926.  
  4927. ;    GETDBL - Get (hex) dword from input line.
  4928. ;        Entry    AL    first character
  4929. ;            SI    address of next character
  4930. ;        Exit    BX:DX    word
  4931. ;            AL    first character not in the word
  4932. ;            SI    address of the next character after that
  4933. ;        Uses    AH,CL
  4934.  
  4935. getdbl:    call    getnyb
  4936.     jc    errorj2        ;if error
  4937.     cbw
  4938.     xchg    ax,dx
  4939.     xor    bx,bx        ;clear high order word
  4940. gd1:    lodsb
  4941.     call    getnyb
  4942.     jc    gd3
  4943.     test    bh,0f0h
  4944.     jnz    errorj2        ;if too big
  4945.     mov    cx,4
  4946. gd2:    shl    dx,1        ;double shift left
  4947.     rcl    bx,1
  4948.     loop    gd2
  4949.     or    dl,al
  4950.     jmp    gd1
  4951. gd3:    ret
  4952.  
  4953. ;    GETWORD - Get (hex) word from input line.
  4954. ;        Entry    AL    first character
  4955. ;            SI    address of next character
  4956. ;        Exit    DX    word
  4957. ;            AL    first character not in the word
  4958. ;            SI    address of the next character after that
  4959. ;        Uses    AH,CL
  4960.  
  4961. getword:call    getnyb
  4962.     jc    errorj2        ;if error
  4963.     cbw
  4964.     xchg    ax,dx
  4965.     mov    cl,4
  4966. gw1:    lodsb
  4967.     call    getnyb
  4968.     jc    gw2
  4969.     test    dh,0f0h
  4970.     jnz    errorj2        ;if too big
  4971.     shl    dx,cl
  4972.     or    dl,al
  4973.     jmp    gw1
  4974. gw2:    ret
  4975.  
  4976. ;    GETBYTE - Get (hex) byte from input line.
  4977. ;        Entry    AL    first character
  4978. ;            SI    address of next character
  4979. ;        Exit    DL    byte
  4980. ;            AL    first character not in the word
  4981. ;            SI    address of the next character after that
  4982. ;        Uses    AH,CL
  4983.  
  4984. getbyte:call    getnyb
  4985.     jc    errorj2        ;if error
  4986.     mov    dl,al
  4987.     mov    cl,4
  4988. gb1:    lodsb
  4989.     call    getnyb
  4990.     jc    gb2
  4991.     test    dl,0f0h
  4992.     jnz    errorj8        ;if too big
  4993.     shl    dl,cl
  4994.     or    dl,al
  4995.     jmp    gb1
  4996. gb2:    ret
  4997.  
  4998. ;    GETNYB - Convert the hex character in AL into a nybble.  Return
  4999. ;    carry set in case of error.
  5000.  
  5001. getnyb:    push    ax
  5002.     sub    al,'0'
  5003.     cmp    al,9
  5004.     jbe    gn1        ;if normal digit
  5005.     pop    ax
  5006.     push    ax
  5007.     or    al,TOLOWER
  5008.     sub    al,'a'
  5009.     cmp    al,'f'-'a'
  5010.     ja    gn2        ;if not a-f or A-F
  5011.     add    al,10
  5012. gn1:    inc    sp        ;normal return (first pop old AX)
  5013.     inc    sp
  5014.     clc
  5015.     ret
  5016.  
  5017. gn2:    pop    ax        ;error return
  5018.     stc
  5019.     ret
  5020.  
  5021. ;    CHKEOL1 - Check for end of line.
  5022.  
  5023. chkeol:    call    skipwh0
  5024.     cmp    al,CR
  5025.     jne    errorj8        ;if not found
  5026.     ret
  5027.  
  5028. errorj8:jmp    error
  5029.  
  5030. ;    SKIPALPHA - Skip alphabetic character, and then white space.
  5031.  
  5032. skipalpha:
  5033.     lodsb
  5034.     and    al,TOUPPER
  5035.     sub    al,'A'
  5036.     cmp    al,'Z'-'A'
  5037.     jbe    skipalpha
  5038.     dec    si
  5039. ;    jmp    skipwhite    ;(control falls through)
  5040.  
  5041. ;    SKIPWHITE - Skip spaces and tabs.
  5042. ;    SKIPWH0 - Same as above, but we already have the character in AL.
  5043.  
  5044. skipwhite:
  5045.     lodsb
  5046. skipwh0:cmp    al,' '
  5047.     je    skipwhite
  5048.     cmp    al,TAB
  5049.     je    skipwhite
  5050.     ret
  5051.  
  5052. ;    IFSEP    Compare AL with separators ' ', '\t', ',', ';', '='.
  5053.  
  5054. ifsep:    cmp    al,' '
  5055.     je    ifs1
  5056.     cmp    al,TAB
  5057.     je    ifs1
  5058.     cmp    al,','
  5059.     je    ifs1
  5060.     cmp    al,';'
  5061.     je    ifs1
  5062.     cmp    al,'='
  5063. ifs1:    ret
  5064.  
  5065. ;    Here is the start of the disassembly part of the program.
  5066.  
  5067. ;    Jump table for OP_IMM, OP_RM, OP_M, OP_R_MOD, OP_MOFFS, OP_R, OP_R_ADD,
  5068. ;    and OP_AX.
  5069.  
  5070. disjmp2    dw    dop01,dop04,dop29,dop29a,dop30,dop32,dop36,dop37
  5071.  
  5072. optab    dw    dop38,dop38a,dop38b,dop39,dop42,dop41    ;jump table
  5073.     dw    dop43,dop46,dop47,dop49,dop51,dop52
  5074.     dw    dop53,dop54,dop56,dop58,dop59,dop59e,dop60
  5075.     db    '1',0,'3',0,'DXCLSTCSDSESFSGSSS'    ;simple strings
  5076.  
  5077. OP_STR    equ    OP_1        ;first string entry
  5078.  
  5079. ;    DISASM - Disassemble.
  5080.  
  5081. dis_n    dw    0        ;number of bytes in instruction so far
  5082. preflags db    0        ;flags for prefixes found so far
  5083. preused    db    0        ;flags for prefixes used so far
  5084.  
  5085. PRESEG    equ    1        ;segment prefix
  5086. PREREP    equ    2        ;rep prefixes
  5087. PRELOCK    equ    4        ;lock prefix
  5088. PRE32D    equ    8        ;flag for 32-bit data
  5089. PRE32A    equ    10h        ;flag for 32-bit addressing
  5090. PREWAIT    equ    20h        ;prefix wait (not really a prefix)
  5091. GOTREGM    equ    40h        ;set if we have the reg/mem part
  5092.  
  5093. instr    db    0        ;the main instruction byte
  5094. index    dw    0        ;index of the instruction (unsqueezed)
  5095.     dw    SFPGROUP3, SFPGROUP3+1, SFPGROUP3+4
  5096.     dw    SPARSE_BASE+24h, SPARSE_BASE+26h ;obsolete-instruction values
  5097. rmsize    db    0        ;<0 or 0 or >0 means mod r/m is 8 or 16 or 32
  5098. segmnt    db    0        ;segment determined by prefix (or otherwise)
  5099. addr    dw    0        ;address in mod r/m byte
  5100. savesp2    dw    0        ;save the stack pointer here (used in disasm)
  5101.  
  5102. disflags db    0        ;flags for the disassembler
  5103.  
  5104.                 ;equates for disflags:
  5105. DIS_F_REPT    equ    1    ;repeat after pop ss, etc.
  5106. DIS_F_SHOW    equ    2    ;show memory contents
  5107. DIS_I_SHOW    equ    4    ;there are memory contents to show
  5108. DIS_I_UNUSED    equ    8    ;(internal) print " (unused)"
  5109. DIS_I_SHOWSIZ    equ    10h    ;(internal) always show the operand size
  5110. DIS_I_KNOWSIZ    equ    20h    ;(internal) we know the operand size of instr.
  5111.  
  5112. disflags2 db    0        ;another copy of DIS_I_KNOWSIZ
  5113.  
  5114. sizeloc    dw    0        ;address of size words in output line
  5115.  
  5116. ;    Jump table for a certain place.
  5117.  
  5118. disjmp    dw    disbad        ;illegal instruction
  5119.     dw    da6        ;two byte instruction
  5120.     dw    da7        ;instruction group
  5121.     dw    da8        ;coprocessor instruction
  5122.     dw    da9        ;coprocessor instruction group
  5123.     dw    da10        ;instruction prefix
  5124.  
  5125. ;    Table for 16-bit mod r/m addressing.  8 = BX, 4 = BP, 2 = SI, 1 = DI.
  5126.  
  5127. rmtab    db    8+2, 8+1, 4+2, 4+1, 2, 1, 4, 8
  5128.  
  5129. ;    Tables of register names.
  5130. ;    rgnam816/rgnam16/segrgnam/xregnam must be consecutive.
  5131.  
  5132. rgnam816 dw    'LA','LC','LD','LB','HA','HC','HD','HB'
  5133. rgnam16    dw    'XA','XC','XD','XB','PS','PB','IS','ID'
  5134. segrgnam dw    'SE','SC','SS','SD','SF','SG'
  5135. xregnam    dw    'TS','MM','RC','RD','RT'
  5136. sizetcnam dw    'YB','OW','OW','WD','WQ','LF','OD','BT','HS','OL','EN','AF'
  5137. segrgaddr dw    reg_es,reg_cs,reg_ss,reg_ds
  5138.  
  5139. ;    Tables for handling of named prefixes.
  5140.  
  5141. prefixlist    db    26h,2eh,36h,3eh,64h,65h    ;segment prefixes (in order)
  5142.         db    9bh,0f0h,0f2h,0f3h    ;WAIT,LOCK,REPNE,REPE
  5143. prefixmnem    dw    MNEM_WAIT,MNEM_LOCK,MNEM_REPNE,MNEM_REPE
  5144.  
  5145. disasm:    mov    savesp2,sp
  5146.     mov    dis_n,0
  5147.     mov    word preflags,0    ;clear preflags and preused
  5148.     mov    segmnt,3    ;initially use DS segment
  5149.     mov    rmsize,80h    ;don't display any memory
  5150.     mov    word dismach,0    ;no special machine needed, so far
  5151.     call    disgetbyte    ;get a byte of the instruction
  5152.     cmp    al,9bh        ;wait instruction (must be the first prefix)
  5153.     jne    da2        ;if not
  5154.  
  5155. ;    The wait instruction is actually a separate instruction as far as
  5156. ;    the x86 is concerned, but we treat it as a prefix since there are
  5157. ;    some mnemonics that incorporate it.  But it has to be treated specially
  5158. ;    since you can't do, e.g., seg cs wait ... but must do wait seg cs ...
  5159. ;    instead.  We'll catch it later if the wait instruction is not going to
  5160. ;    be part of a shared mnemonic.
  5161.  
  5162.     or    preflags,PREWAIT
  5163.  
  5164. ;    If we've found a prefix, we return here for the actual instruction
  5165. ;    (or another prefix).
  5166.  
  5167. da1:    call    disgetbyte
  5168. da2:    mov    instr,al    ;save away the instruction
  5169.     mov    ah,0
  5170.  
  5171. ;    Now we have the sequence number of the instruction in AX.  Look it up.
  5172.  
  5173. da3:    mov    bx,ax
  5174.     mov    index,ax    ;save the compressed index
  5175.     cmp    ax,SPARSE_BASE
  5176.     jb    da4        ;if it's not from the squeezed part of the table
  5177.     mov    bl,sqztab[bx-SPARSE_BASE]
  5178.     mov    bh,0
  5179.     add    bx,SPARSE_BASE    ;bx = compressed index
  5180.  
  5181. da4:    mov    cl,optypes[bx]    ;cx = opcode type
  5182.     mov    ch,0
  5183.     shl    bx,1
  5184.     mov    bx,opinfo[bx]    ;bx = other info (usually the mnemonic)
  5185.     mov    si,cx
  5186.     mov    ax,bx
  5187.     mov    cl,12
  5188.     shr    ax,cl
  5189.     cmp    al,dismach
  5190.     jb    da5        ;if a higher machine is already required
  5191.     mov    dismach,al    ;set machine type
  5192. da5:    and    bx,0fffh    ;remove the machine field
  5193.     cmp    si,OPTYPES_BASE
  5194.     jae    da13        ;if this is an actual instruction
  5195.     call    disjmp[si]    ;otherwise, do more specific processing
  5196.     jmp    da3        ;back for more
  5197.  
  5198. ;    Two-byte instruction.
  5199.  
  5200. da6:    call    disgetbyte
  5201.     mov    instr,al
  5202.     mov    ah,0
  5203.     add    ax,SPARSE_BASE
  5204.     ret
  5205.  
  5206. ;    Instruction group.
  5207.  
  5208. da7:    call    getregmem_r    ;get the middle 3 bits of the R/M byte
  5209.     cbw
  5210.     add    ax,bx        ;offset
  5211.     ret
  5212.  
  5213. ;    Coprocessor instruction.
  5214.  
  5215. da8:    or    disflags,DIS_I_SHOWSIZ
  5216.     or    dmflags,DM_COPR
  5217.     call    getregmem
  5218.     cmp    al,0c0h
  5219.     jb    da7        ;range 00-bfh is same as an instruction group
  5220.     mov    cl,3
  5221.     shr    al,cl        ;C0h --> 18h
  5222.     sub    al,18h-8    ;18h --> 8
  5223.     cbw
  5224.     add    ax,bx        ;offset
  5225.     ret
  5226.  
  5227. ;    Coprocessor instruction group.
  5228.  
  5229. da9:    mov    al,regmem
  5230.     and    al,7
  5231.     cbw
  5232.     add    ax,bx
  5233.     ret
  5234.  
  5235. ;    Instruction prefix.  At this point, bl = prefix bits; bh = segment
  5236.  
  5237. da10:    test    bl,preflags
  5238.     jnz    da12        ;if there are duplicates
  5239.     or    preflags,bl
  5240.     test    bl,PRESEG
  5241.     jz    da11        ;if not a segment
  5242.     mov    segmnt,bh    ;save the segment
  5243. da11:    pop    ax        ;discard return address
  5244.     jmp    da1
  5245.  
  5246. da12:    jmp    disbad        ;we don't allow duplicate prefixes
  5247.  
  5248. ;    OK.  Here we go.  This is an actual instruction.
  5249. ;    First print the op mnemonic.
  5250.  
  5251. da13:    push    si
  5252.     lea    si,mnlist[bx]    ;offset of mnemonic
  5253.     cmp    si,offset mnlist+MNEM_BSWAP
  5254.     jne    da13a        ;if not BSWAP
  5255.     call    dischk32d
  5256.     jz    da12        ;if no operand-size prefix
  5257. da13a:    call    showop        ;print out the op code (at line_out+24)
  5258.     mov    sizeloc,0    ;clear out this flag
  5259.     pop    si        ;recover list of operands
  5260.     add    si,offset oplists-OPTYPES_BASE
  5261.     cmp    byte [si],0
  5262.     je    da21        ;if we're done
  5263.  
  5264. ;    Loop over operands.  [si] = pointer to next operand type.
  5265. ;    Fortunately the operands appear in the instruction in the same
  5266. ;    order as they appear in the disassembly output.
  5267.  
  5268. da14:    mov    disflags2,0    ;clear out size-related flags
  5269.     lodsb            ;get the operand type
  5270.     cmp    al,OP_SIZE
  5271.     jb    da18        ;if it's not size dependent
  5272.     mov    disflags2,DIS_I_KNOWSIZ    ;set flag to indicate variable size
  5273.     cmp    al,OP_8
  5274.     jae    da16        ;if the size is fixed
  5275.     cmp    al,OP_1632
  5276.     jae    da15        ;if word or dword
  5277.     mov    ah,-1
  5278.     test    instr,1
  5279.     jz    da17        ;if byte
  5280. da15:    or    preused,PRE32D    ;mark this flag as used
  5281.     mov    ah,preflags
  5282.     and    ah,PRE32D    ;this will be >0 for dword, =0 for word
  5283.     jmp    short da17    ;done
  5284.  
  5285. da16:    mov    ah,al        ;OP_8 or OP_16 or OP_32 (we know which)
  5286.     and    ah,0f0h        ;this converts ah to <0 for byte, =0 for word,
  5287.     sub    ah,OP_16    ;and >0 for dword
  5288.  
  5289. ;    Now we know the size (in ah); branch off to do the operand itself.
  5290.  
  5291. da17:    mov    bl,al
  5292.     and    bx,0fh
  5293.     call    disjmp2[bx]    ;print out the operand
  5294.     jmp    short da20    ;done with operand
  5295.  
  5296. ;    Sizeless operands.
  5297.  
  5298. da18:    cbw
  5299.     xchg    ax,bx
  5300.     cmp    bl,OP_STR
  5301.     jb    da19        ;if it's not a string
  5302.     mov    ax,optab[bx-2]
  5303.     stosw
  5304.     cmp    ah,0
  5305.     jnz    da20        ;if it's two characters
  5306.     dec    di
  5307.     jmp    short da20    ;done with operand
  5308.  
  5309. da19:    call    optab[bx-2]    ;otherwise, do something else
  5310.  
  5311. da20:    cmp    byte [si],0
  5312.     jz    da21        ;if we're done
  5313.     mov    al,','
  5314.     stosb
  5315.     jmp    da14        ;another operand
  5316.  
  5317. da21:    mov    al,preused
  5318.     not    al
  5319.     and    al,preflags
  5320.     jnz    da22        ;if some flags remain unused
  5321.     jmp    da28        ;if all flags were used
  5322. da22:    mov    cx,N_WTAB
  5323.     mov    bx,offset wtab1
  5324.     mov    dx,2*N_WTAB-2
  5325.     mov    ah,PREWAIT
  5326.     test    al,ah
  5327.     jnz    da23        ;if there's a WAIT prefix hanging
  5328.     mov    cx,N_LTAB
  5329.     mov    bx,offset ltab1
  5330.     mov    dx,2*N_LTAB-2
  5331.     mov    ah,PRE32D
  5332.     test    al,ah
  5333.     jz    da24        ;if it's not a 32-bit prefix that's hanging
  5334. da23:    or    preused,ah    ;mark this prefix as used
  5335.     push    di
  5336.     mov    di,bx
  5337.     mov    ax,index
  5338.     repne    scasw
  5339.     jne    disbad2        ;if not found in the list
  5340.     add    di,dx        ;replace the mnemonic with the 32-bit name
  5341.     mov    si,[di]
  5342.     add    si,offset mnlist
  5343.     call    showop        ;copy op mnemonic
  5344.     pop    di
  5345.     jmp    da21
  5346.  
  5347. disbad2:jmp    disbad
  5348.  
  5349. da24:    test    al,PRESEG
  5350.     jz    da25        ;if not because of a segment prefix
  5351.     mov    ax,index
  5352.     cmp    ah,0
  5353.     jnz    disbad2        ;if index > 256
  5354.     push    di
  5355.     mov    cx,P_LEN
  5356.     mov    di,offset prfxtab
  5357.     repne    scasb
  5358.     pop    di
  5359.     jne    disbad2        ;if it's not on the list
  5360.     mov    cx,3
  5361.     call    moveover
  5362.     push    di
  5363.     mov    di,offset line_out+24
  5364.     call    showseg
  5365.     mov    al,' '
  5366.     stosb
  5367.     pop    di
  5368.     or    preused,PRESEG    ;mark it as used
  5369.     jmp    da21
  5370.  
  5371. da25:    test    al,PREREP
  5372.     jz    da26        ;if not a REP prefix
  5373.     mov    ax,index
  5374.     cmp    ah,0
  5375.     jnz    disbad2        ;if not in the first 256 bytes
  5376.     and    al,0feh        ;clear the low bit
  5377.     or    preused,PREREP
  5378.     push    di
  5379.     mov    di,offset replist
  5380.     mov    cx,5
  5381.     repne    scasb
  5382.     mov    si,offset mnlist+MNEM_REP
  5383.     je    da27        ;if one of the REP instructions
  5384.     inc    cx
  5385.     inc    cx
  5386.     repne    scasb
  5387.     jne    disbad2        ;if not one of the REPE/REPNE instructions
  5388.     mov    si,offset mnlist+MNEM_REPE
  5389.     jz    da27        ;if REPE
  5390.     mov    si,offset mnlist+MNEM_REPNE
  5391.     jmp    short da27    ;it's REPNE
  5392.  
  5393. disbad3:jmp    disbad
  5394.  
  5395. da26:    test    al,PRELOCK
  5396.     jz    disbad3        ;if not a lock prefix, either
  5397.     push    di
  5398.     mov    ax,index
  5399.     mov    di,offset locktab
  5400.     mov    cx,N_LOCK
  5401.     repne    scasw
  5402.     jne    disbad3        ;if not in the approved list
  5403.     test    preused,PRESEG
  5404.     jz    disbad3        ;if memory was not accessed
  5405.     mov    si,offset mnlist+MNEM_LOCK
  5406.     or    preused,PRELOCK
  5407.  
  5408. ;    Slip in another mnemonic.  SI = offset of mnemonic, what should be
  5409. ;    DI is on the stack.
  5410.  
  5411. da27:    pop    di
  5412.     mov    cx,8
  5413.     push    si
  5414.     call    moveover
  5415.     pop    si
  5416.     push    di
  5417.     call    showop
  5418.     pop    di
  5419.     jmp    da21
  5420.  
  5421. ;    Done with instruction.  Erase the size indicator, if appropriate.
  5422.  
  5423. da28:    mov    cx,sizeloc
  5424.     cmp    cx,0
  5425.     jz    da28b        ;if there was no size given
  5426.     mov    al,disflags
  5427.     test    al,DIS_I_SHOWSIZ
  5428.     jnz    da28b        ;if we need to show the size
  5429.     test    al,DIS_I_KNOWSIZ
  5430.     jz    da28b        ;if the size is not known already
  5431.     xchg    cx,di
  5432.     mov    si,di        ;save old di
  5433.     mov    al,' '
  5434. da28a:    scasb            ;skip size name
  5435.     jne    da28a        ;if not done yet
  5436.                 ;(The above is the same as repne scasb, but
  5437.                 ;has no effect on cx.)
  5438.     add    di,4        ;skip 'PTR '
  5439.     xchg    si,di
  5440.     sub    cx,si
  5441.     rep    movsb        ;move the line
  5442.  
  5443. ;    Now we're really done.  Print out the bytes on the left.
  5444.  
  5445. da28b:    push    di        ;print start of disassembly line
  5446.     mov    di,offset line_out
  5447.     mov    ax,u_addr+2    ;print address
  5448.     call    hexword
  5449.     mov    al,':'
  5450.     stosb
  5451.     mov    ax,u_addr
  5452.     call    hexword
  5453.     mov    al,' '
  5454.     stosb
  5455.     mov    bx,dis_n
  5456.     cmp    bx,6
  5457.     jle    da29        ;if it's a short instruction
  5458.     mov    bx,6
  5459.     call    disshowbytes
  5460.     call    puts
  5461.     mov    di,offset line_out
  5462.     mov    bx,dis_n
  5463.     sub    bx,6
  5464.     call    disshowbytes
  5465.     call    putsline
  5466.     mov    di,offset line_out
  5467.     jmp    short da30    ;done
  5468.  
  5469. da29:    call    disshowbytes
  5470. da30:    mov    ax,'  '        ;pad to op code
  5471.     mov    cx,offset line_out+24
  5472.     sub    cx,di
  5473.     shr    cx,1
  5474.     rep    stosw
  5475.     pop    di
  5476.     test    disflags,DIS_I_UNUSED
  5477.     jz    da32        ;if we don't print ` (unused)'
  5478.     mov    si,offset unused
  5479.     cmp    byte [di-1],' '
  5480.     jne    da31        ;if there's already a space here
  5481.     inc    si
  5482. da31:    call    showstring
  5483.  
  5484. ;    Print info. on minimal processor needed.
  5485.  
  5486. da32:    push    di
  5487.     mov    di,offset index+2
  5488.     call    showmach    ;show the machine type, if needed
  5489.     pop    di
  5490.     jcxz    da32f        ;if no message
  5491.  
  5492. ;    Print a message on the far right.
  5493.  
  5494.     mov    ax,offset line_out+79
  5495.     sub    ax,cx
  5496.     push    cx
  5497.     call    tab_to        ;tab out to the location
  5498.     pop    cx
  5499.     rep    movsb        ;copy the string
  5500.     jmp    short da32z    ;done
  5501.  
  5502. ;    Dump referenced memory location.
  5503.  
  5504. da32f:    mov    al,disflags
  5505.     xor    al,DIS_F_SHOW + DIS_I_SHOW
  5506.     test    al,DIS_F_SHOW + DIS_I_SHOW
  5507.     jnz    da32z        ;if there is no memory location to show
  5508.     cmp    segmnt,3
  5509.     ja    da32z        ;if FS or GS
  5510.     mov    ax,offset line_out+79-10
  5511.     cmp    rmsize,0
  5512.     jl    da32h        ;if byte
  5513.     jz    da32g        ;if word
  5514.     sub    ax,4
  5515. da32g:    dec    ax
  5516.     dec    ax
  5517. da32h:    call    tab_to
  5518.     call    showseg        ;show segment name
  5519.     mov    al,':'
  5520.     stosb
  5521.     mov    ax,addr
  5522.     call    hexword        ;show offset
  5523.     mov    al,'='
  5524.     stosb
  5525.     mov    al,segmnt    ;segment number
  5526.     cbw
  5527.     shl    ax,1
  5528.     xchg    ax,bx        ;mov bx,ax
  5529.     mov    bx,segrgaddr[bx] ;get address of value
  5530.     mov    es,[bx]
  5531.     mov    bx,addr
  5532.     mov    ax,es:[bx]
  5533.     mov    dx,es:[bx+2]
  5534.     push    cs        ;restore es
  5535.     pop    es
  5536.     cmp    rmsize,0
  5537.     jl    da32j        ;if byte
  5538.     jz    da32i        ;if word
  5539.     xchg    ax,dx
  5540.     call    hexword
  5541.     xchg    ax,dx
  5542. da32i:    call    hexword
  5543.     jmp    short da32z    ;done
  5544.  
  5545. da32j:    call    hexbyte        ;display byte
  5546.  
  5547. da32z:    call    trimputs    ;done with operand list
  5548.     mov    al,disflags
  5549.     test    al,DIS_F_REPT
  5550.     jz    da34        ;if we're not allowed to repeat ourselves
  5551.     test    al,DIS_I_UNUSED
  5552.     jnz    da33        ;if we printed ` (unused)'
  5553.     mov    ax,index
  5554.     cmp    ax,17h
  5555.     je    da33        ;if it was `pop ss'
  5556.     cmp    ax,8eh
  5557.     je    da33        ;if it was `mov ss,--'
  5558.     cmp    ax,0fbh
  5559.     jne    da34        ;if it was not `sti'
  5560. da33:    mov    disflags,0
  5561.     jmp    disasm
  5562. da34:    ret
  5563.  
  5564. ;    Here are the routines for printing out the operands themselves.
  5565. ;    Immediate data (OP_IMM)
  5566.  
  5567. dop01:    cmp    ah,0
  5568.     jl    dop03        ;if just a byte
  5569.     pushf
  5570.     test    disflags,DIS_I_SHOWSIZ
  5571.     jz    dop01a        ;if we don't need to show the size
  5572.     call    showsize
  5573.     sub    di,4        ;erase "PTR "
  5574. dop01a:    call    disgetword
  5575.     popf
  5576.     jz    dop02        ;if just a word
  5577.     push    ax
  5578.     call    disgetword    ;print the high order word
  5579.     call    hexword
  5580.     pop    ax
  5581. dop02:    call    hexword
  5582.     ret
  5583.  
  5584. dop03:    call    disgetbyte    ;print immediate byte
  5585.     call    hexbyte
  5586.     ret
  5587.  
  5588. ;    MOD R/M (OP_RM)
  5589.  
  5590. dop04:    call    getregmem
  5591.     cmp    al,0c0h
  5592.     jb    dop05
  5593.     jmp    dop33        ;if pure register reference
  5594. dop05:    call    showsize    ;print out size
  5595. dop06:    or    preused,PRESEG    ;must do it even if there's no segment override
  5596.                 ;because handling of LOCK prefix relies on it
  5597.     test    preflags,PRESEG
  5598.     jz    dop07        ;if no segment override
  5599.     call    showseg        ;print segment name
  5600.     mov    al,':'
  5601.     stosb
  5602. dop07:    mov    al,regmem
  5603.     and    al,0c7h
  5604.     or    preused,PRE32A
  5605.     test    preflags,PRE32A
  5606.     jz    dop08
  5607.     jmp    dop18        ;if 32-bit addressing
  5608. dop08:    or    disflags,DIS_I_SHOW    ;we'd like to show this address
  5609.     mov    addr,0        ;zero out the address initially
  5610.     cmp    al,6
  5611.     xchg    ax,bx        ;mov bx,ax
  5612.     mov    al,'['
  5613.     stosb
  5614.     je    dop16        ;if [xxxx]
  5615.     and    bx,7
  5616.     mov    bl,rmtab[bx]
  5617.     test    bl,8
  5618.     jnz    dop09        ;if BX
  5619.     test    bl,4
  5620.     jz    dop11        ;if not BP
  5621.     mov    ax,'PB'
  5622.     mov    cx,reg_bp
  5623.     test    preflags,PRESEG
  5624.     jnz    dop10        ;if segment override
  5625.     dec    segmnt        ;default is now SS
  5626.     jmp    short dop10
  5627.  
  5628. dop09:    mov    ax,'XB'        ;BX
  5629.     mov    cx,reg_bx
  5630.  
  5631. dop10:    mov    addr,cx        ;print it out, etc.
  5632.     stosw
  5633.     test    bl,2+1
  5634.     jz    dop13        ;if done
  5635.     mov    al,'+'
  5636.     stosb
  5637. dop11:    mov    ax,'IS'
  5638.     mov    cx,reg_si
  5639.     test    bl,1
  5640.     jz    dop12        ;if SI
  5641.     mov    al,'D'        ;DI
  5642.     mov    cx,reg_di
  5643.  
  5644. dop12:    add    addr,cx        ;print it out, etc.
  5645.     stosw
  5646. dop13:    test    regmem,0c0h
  5647.     jz    dop17        ;if no displacement
  5648.     test    regmem,80h
  5649.     jnz    dop15        ;if word displacement
  5650.     call    disgetbyte
  5651.     cbw
  5652.     add    addr,ax
  5653.     cmp    al,0
  5654.     mov    ah,'+'
  5655.     jge    dop14        ;if >= 0
  5656.     mov    ah,'-'
  5657.     neg    al
  5658. dop14:    mov    [di],ah
  5659.     inc    di
  5660.     call    hexbyte        ;print the byte displacement
  5661.     jmp    short dop17    ;done
  5662.  
  5663. dop15:    mov    al,'+'
  5664.     stosb
  5665. dop16:    call    disgetword
  5666.     add    addr,ax
  5667.     call    hexword
  5668.  
  5669. dop17:    mov    al,']'
  5670.     stosb
  5671.     ret
  5672.  
  5673. ;    32-bit MOD REG R/M addressing.
  5674.  
  5675. dop18:    cmp    al,5
  5676.     jne    dop19        ;if not just a disp32 address
  5677.     mov    al,'['
  5678.     stosb
  5679.     call    disp32
  5680.     jmp    dop27
  5681.  
  5682. dop19:    push    ax
  5683.     and    al,7
  5684.     cmp    al,4
  5685.     jne    dop20        ;if no SIB
  5686.     call    disgetbyte    ;get and save it
  5687.     mov    sibbyte,al
  5688. dop20:    pop    ax
  5689.     test    al,80h
  5690.     jnz    dop22        ;if disp32
  5691.     test    al,40h
  5692.     jz    dop23        ;if no disp8
  5693.     call    disgetbyte
  5694.     cmp    al,0
  5695.     jge    dop21        ;if >= 0
  5696.     neg    al
  5697.     mov    byte [di],'-'
  5698.     inc    di
  5699. dop21:    call    hexbyte
  5700.     jmp    short dop23    ;done
  5701.  
  5702. dop22:    call    disp32        ;print disp32
  5703.  
  5704. dop23:    mov    al,regmem
  5705.     and    al,7
  5706.     cmp    al,4
  5707.     jne    dop28        ;if no SIB
  5708.     mov    al,sibbyte
  5709.     and    al,7
  5710.     cmp    al,5
  5711.     jne    dop24        ;if not [EBP]
  5712.     test    regmem,0c0h
  5713.     jnz    dop24        ;if MOD != 0
  5714.     call    disp32        ;show 32-bit displacement instead of [EBP]
  5715.     jmp    short dop25
  5716.  
  5717. dop24:    mov    word [di],'E['
  5718.     inc    di
  5719.     inc    di
  5720.     call    showreg16
  5721.     mov    al,']'
  5722.     stosb
  5723.  
  5724. dop25:    mov    al,sibbyte
  5725.     shr    al,1
  5726.     shr    al,1
  5727.     shr    al,1
  5728.     and    al,7
  5729.     cmp    al,4
  5730.     je    disbad1        ;if illegal
  5731.     mov    word [di],'E['
  5732.     inc    di
  5733.     inc    di
  5734.     call    showreg16
  5735.     mov    ah,sibbyte
  5736.     test    ah,0c0h
  5737.     jz    dop27        ;if SS = 0
  5738.     mov    al,'*'
  5739.     stosb
  5740.     mov    al,'2'
  5741.     test    ah,80h
  5742.     jz    dop26        ;if *2
  5743.     mov    al,'4'
  5744.     test    ah,40h
  5745.     jz    dop26        ;if *4
  5746.     mov    al,'8'
  5747. dop26:    stosb
  5748. dop27:    mov    al,']'
  5749.     stosb
  5750.     ret
  5751.  
  5752. ;    32-bit addressing without SIB
  5753.  
  5754. dop28:    mov    word [di],'E['
  5755.     inc    di
  5756.     inc    di
  5757.     call    showreg16
  5758.     mov    al,']'
  5759.     stosb
  5760.     ret
  5761.  
  5762. ;    Memory-only reference (OP_M)
  5763.  
  5764. dop29:    call    getregmem
  5765.     cmp    al,0c0h
  5766.     jae    disbad1        ;if it's a register reference
  5767.     jmp    dop05
  5768.  
  5769. disbad1:jmp    disbad        ;this is not supposed to happen
  5770.  
  5771. ;    Register reference from MOD R/M part (OP_R_MOD)
  5772.  
  5773. dop29a:    call    getregmem
  5774.     cmp    al,0c0h
  5775.     jb    disbad1        ;if it's a memory reference
  5776.     jmp    short dop33
  5777.  
  5778. ;    Memory offset reference (OP_MOFFS)
  5779.  
  5780. dop30:    call    showsize    ;print the size and save various things
  5781.     mov    al,5
  5782.     test    preflags,PRE32A
  5783.     jnz    dop31        ;if 32-bit addressing
  5784.     inc    ax
  5785. dop31:    mov    regmem,al
  5786.     jmp    dop06
  5787.  
  5788. ;    Pure register reference (OP_R)
  5789.  
  5790. dop32:    call    getregmem_r
  5791.  
  5792. dop33:    and    al,7        ;entry point for regs from MOD R/M, and others
  5793.     mov    cl,disflags2
  5794.     or    disflags,cl    ;if it was variable size operand, the size
  5795.                 ;should now be marked as known.
  5796.     cmp    ah,0
  5797.     jl    dop35        ;if byte register
  5798.     jz    dop34        ;if word register
  5799. dop33a:    mov    byte [di],'E'    ;enter here from OP_ECX
  5800.     inc    di
  5801. dop34:    add    al,8
  5802. dop35:    cbw
  5803.     shl    ax,1
  5804.     xchg    ax,bx        ;mov bx,ax
  5805.     mov    ax,rgnam816[bx]    ;get the register name
  5806.     stosw
  5807.     ret
  5808.  
  5809. ;    Register number embedded in the instruction (OP_R_ADD)
  5810.  
  5811. dop36:    mov    al,instr
  5812.     jmp    dop33
  5813.  
  5814. ;    AL or AX or EAX (OP_AX)
  5815.  
  5816. dop37:    mov    al,0
  5817.     jmp    dop33
  5818.  
  5819. ;    QWORD mem (OP_M64).
  5820.  
  5821. dop38:    mov    ax,'Q'        ;print 'QWORD'
  5822.     jmp    short dop40
  5823.  
  5824. ;    FLOAT mem (OP_MFLOAT).
  5825.  
  5826. dop38a:    mov    ax,'LF'
  5827.     stosw
  5828.     mov    al,'O'
  5829.     stosb
  5830.     mov    ax,'TA'
  5831.     jmp    short dop38c
  5832.  
  5833. ;    DOUBLE mem (OP_MDOUBLE).
  5834.  
  5835. dop38b:    mov    ax,'OD'
  5836.     stosw
  5837.     mov    ax,'BU'
  5838.     stosw
  5839.     mov    ax,'EL'
  5840. dop38c:    stosw
  5841.     call    showptr
  5842.     jmp    short dop42a
  5843.  
  5844. ;    TBYTE mem (OP_M80).
  5845.  
  5846. dop39:    mov    ax,0ff00h+'T'    ;print 'tbyte'
  5847. dop40:    stosb
  5848.     call    getregmem
  5849.     cmp    al,0c0h
  5850.     jae    disbad1        ;if it's a register reference
  5851.     and    disflags,not DIS_F_SHOW    ;don't show this
  5852.     jmp    dop05
  5853.  
  5854. ;    far memory (OP_FARMEM).
  5855.  
  5856. dop41:    call    dischk32d
  5857.     jz    dop41a        ;if not dword far
  5858.     call    showdwd
  5859.     sub    di,4        ;erase "PTR "
  5860. dop41a:    mov    ax,'AF'        ;store "FAR "
  5861.     stosw
  5862.     mov    ax,' R'
  5863.     stosw
  5864.  
  5865. ;    mem (OP_MXX).
  5866.  
  5867. dop42:    and    disflags,not DIS_F_SHOW    ;don't show this
  5868. dop42a:    call    getregmem
  5869.     cmp    al,0c0h
  5870.     jae    disbad5        ;if it's a register reference
  5871.     jmp    dop06
  5872.  
  5873. disbad5:jmp    disbad
  5874.  
  5875. ;    far pointer (OP_FARP).
  5876.  
  5877. dop43:    call    disgetword
  5878.     push    ax
  5879.     call    dischk32d
  5880.     jz    dop44        ;if not 32-bit address
  5881.     call    disgetword
  5882.     push    ax
  5883. dop44:    call    disgetword
  5884.     call    hexword
  5885.     mov    al,':'
  5886.     stosb
  5887.     call    dischk32d
  5888.     jz    dop45        ;if not 32-bit address
  5889.     pop    ax
  5890.     call    hexword
  5891. dop45:    pop    ax
  5892.     call    hexword
  5893.     ret
  5894.  
  5895. ;    8-bit relative jump (OP_REL8)
  5896.  
  5897. dop46:    call    disgetbyte
  5898.     cbw
  5899.     jmp    short dop48
  5900.  
  5901. ;    16/32-bit relative jump (OP_REL1632)
  5902.  
  5903. dop47:    call    disgetword
  5904.     call    dischk32d
  5905.     jz    dop48        ;if not 32-bit offset
  5906.     push    ax
  5907.     call    showdwd
  5908.     sub    di,4        ;erase "PTR "
  5909.     pop    dx
  5910.     call    disgetword
  5911.     mov    bx,u_addr
  5912.     add    bx,dis_n
  5913.     add    dx,bx
  5914.     adc    ax,0        ;this would normally be the upper word of IP
  5915.     call    hexword
  5916.     xchg    ax,dx
  5917.     jmp    hexword        ;call hexword and return
  5918.  
  5919. dop48:    add    ax,u_addr
  5920.     add    ax,dis_n
  5921.     jmp    hexword        ;call hexword and return
  5922.  
  5923. ;    Check for ST(1) (OP_1CHK).
  5924.  
  5925. dop49:    pop    ax        ;discard return address
  5926.     mov    al,regmem
  5927.     and    al,7
  5928.     cmp    al,1
  5929.     je    dop50        ;if it's ST(1)
  5930.     jmp    da14        ;another operand (but no comma)
  5931.  
  5932. dop50:    jmp    da21        ;end of list
  5933.  
  5934. ;    ST(I) (OP_STI).
  5935.  
  5936. dop51:    mov    al,regmem
  5937.     and    al,7
  5938.     xchg    ax,bx        ;mov bx,ax
  5939.     mov    ax,'TS'
  5940.     stosw            ;store ST(bl)
  5941.     mov    al,'('
  5942.     stosb
  5943.     mov    ax,')0'
  5944.     or    al,bl
  5945.     stosw
  5946.     ret
  5947.  
  5948. ;    CRx (OP_CR).
  5949.  
  5950. dop52:    mov    bx,'RC'
  5951.     call    getregmem_r
  5952.     cmp    al,4
  5953.     ja    disbad4        ;if too large
  5954.     jne    dop52a
  5955.     mov    dismach,5    ;CR4 is new to the 586
  5956. dop52a:    cmp    index,SPARSE_BASE+22h
  5957.     jne    dop55        ;if not MOV CRx,xx
  5958.     cmp    al,1
  5959.     jne    dop55        ;if not CR1
  5960.  
  5961. disbad4:jmp    disbad        ;can't MOV CR1,xx
  5962.  
  5963. ;    DRx (OP_DR).
  5964.  
  5965. dop53:    call    getregmem_r
  5966.     mov    bx,'RD'
  5967.     mov    cx,-1        ;no max or illegal value
  5968.     jmp    short dop55
  5969.  
  5970. ;    TRx (OP_TR).
  5971.  
  5972. dop54:    call    getregmem_r
  5973.     cmp    al,3
  5974.     jb    disbad        ;if too small
  5975.     cmp    al,6
  5976.     jae    dop54a        ;if TR6-7
  5977.     mov    dismach,4    ;TR3-5 are new to the 486
  5978. dop54a:    mov    bx,'RT'
  5979.  
  5980. dop55:    xchg    ax,bx
  5981.     stosw            ;store XX
  5982.     xchg    ax,bx
  5983.     or    al,'0'
  5984.     stosb
  5985.     ret
  5986.  
  5987. ;    Segment register (OP_SEGREG).
  5988.  
  5989. dop56:    call    getregmem_r
  5990.     cmp    al,6
  5991.     jae    disbad        ;if not a segment register
  5992.     cmp    al,2
  5993.     je    dop57        ;if SS
  5994.     and    disflags,not DIS_F_REPT    ;clear flag:  don't repeat
  5995. dop57:    cmp    al,4
  5996.     jb    dop57a        ;if not FS or GS
  5997.     mov    dismach,3    ;(no new 486-686 instructions involve seg regs)
  5998. dop57a:    add    al,16
  5999.     jmp    dop35        ;go print it out
  6000.  
  6001. ;    Sign-extended immediate byte (OP_IMMS8).
  6002.  
  6003. dop58:    call    disgetbyte
  6004.     cmp    al,0
  6005.     xchg    ax,bx        ;mov bl,al
  6006.     mov    al,'+'
  6007.     jge    dop58a        ;if >= 0
  6008.     neg    bl
  6009.     mov    al,'-'
  6010. dop58a:    stosb
  6011.     xchg    ax,bx        ;mov al,bl
  6012.     jmp    short dop59a    ;call hexbyte and return
  6013.  
  6014. ;    Immediate byte (OP_IMM8).
  6015.  
  6016. dop59:    call    disgetbyte
  6017. dop59a:    jmp    hexbyte        ;call hexbyte and return
  6018.  
  6019. ;    Show ECX if it's a 32-bit operand.
  6020.  
  6021. dop59e:    call    dischk32d
  6022.     jz    dop60a        ;if not 32 bit instruction
  6023.     mov    al,1
  6024.     jmp    dop33a        ;print out register ECX and return
  6025.  
  6026. ;    Set flag to always show size (OP_SHOSIZ).
  6027.  
  6028. dop60:    or    disflags,DIS_I_SHOWSIZ
  6029. dop60a:    pop    ax        ;discard return address
  6030.     jmp    da14        ;next...
  6031.  
  6032. disbad:    mov    sp,savesp2    ;pop junk off stack
  6033.     mov    dis_n,0
  6034.     mov    word preflags,0    ;clear preflags and preused
  6035.     mov    rmsize,80h    ;don't display any memory
  6036.     mov    word dismach,0    ;forget about the machine type
  6037.     and    disflags,not DIS_I_SHOW    ;and flags
  6038.     call    disgetbyte
  6039.     mov    di,offset prefixlist
  6040.     mov    cx,10
  6041.     repne    scasb
  6042.     je    dbad1        ;if it's a named prefix
  6043.     dec    dis_n
  6044.     mov    bx,MNEM_DB    ;offset of 'DB' mnemonic
  6045.     mov    si,OPLIST_Z    ;this says OP_8+OP_IMM
  6046.     jmp    da13
  6047.  
  6048. dbad1:    or    disflags,DIS_I_UNUSED    ;print special flag
  6049.     mov    bx,9
  6050.     sub    bx,cx
  6051.     shl    bx,1
  6052.     cmp    bx,12
  6053.     jb    dbad2        ;if SEG directive
  6054.     mov    bx,prefixmnem[bx-12]
  6055.     mov    si,OPTYPES_BASE
  6056.     jmp    da13
  6057.  
  6058. dbad2:    lea    si,[bx+OPLIST_ES]
  6059.     mov    bx,MNEM_SEG
  6060.     jmp    da13
  6061.  
  6062. ;    GETREGMEM_R - Get the reg part of the reg/mem part of the instruction
  6063. ;    Uses    CL
  6064.  
  6065. getregmem_r:
  6066.     call    getregmem
  6067.     mov    cl,3
  6068.     shr    al,cl
  6069.     and    al,7
  6070.     ret
  6071.  
  6072. ;    GETREGMEM - Get the reg/mem part of the instruction
  6073.  
  6074. getregmem:
  6075.     test    preused,GOTREGM
  6076.     jnz    grm1        ;if we have it already
  6077.     or    preused,GOTREGM
  6078.     call    disgetbyte    ;get the byte
  6079.     mov    regmem,al    ;save it away
  6080.  
  6081. grm1:    mov    al,regmem
  6082.     ret
  6083.  
  6084. ;    SHOWOP    Show the op code
  6085. ;    Entry    SI    Null-terminated string containing the op mnemonic
  6086. ;    Exit    DI    Address of next available byte in output line
  6087. ;            (>= offset line_out + 32 due to padding)
  6088. ;    Uses    AL
  6089.  
  6090. showop:
  6091.     mov    di,offset line_out+24
  6092.     call    showstring
  6093.     mov    al,' '
  6094. so1:    stosb
  6095.     cmp    di,offset line_out+32
  6096.     jb    so1
  6097.     ret
  6098.  
  6099. ;    SHOWSEG - Show the segment descriptor in SEGMNT
  6100. ;    Entry    DI    Where to put it
  6101. ;    Exit    DI    Updated
  6102. ;    Uses    AX, BX
  6103.  
  6104. showseg:
  6105.     mov    al,segmnt    ;segment number
  6106.     cbw
  6107.     shl    ax,1
  6108.     xchg    ax,bx        ;mov bx,ax
  6109.     mov    ax,segrgnam[bx]    ;get register name
  6110.     stosw
  6111.     ret
  6112.  
  6113. ;    SHOWSIZE - Print a description of the size
  6114. ;    Entry    AH    >0 for DWORD, =0 for WORD, <0 for BYTE
  6115. ;    Uses    AX
  6116.  
  6117. ;    SHOWPTR - Print " PTR "
  6118. ;    Uses    AX
  6119.  
  6120. ;    SHOWDWD - Print "DWORD PTR"
  6121. ;    Uses    AX
  6122.  
  6123. showsize:
  6124.     mov    rmsize,ah    ;save r/m size
  6125.     mov    sizeloc,di    ;save where we're putting this
  6126.     cmp    ah,0
  6127.     jge    ssz1        ;if word or dword
  6128.     mov    ax,'YB'
  6129.     stosw
  6130.     mov    ax,'ET'
  6131.     jmp    short ssz3
  6132.  
  6133. ssz1:    je    ssz2        ;if word
  6134. showdwd:mov    al,'D'
  6135.     stosb
  6136. ssz2:    mov    ax,'OW'
  6137.     stosw
  6138.     mov    ax,'DR'
  6139. ssz3:    stosw
  6140. showptr:mov    ax,'P '
  6141.     stosw
  6142.     mov    ax,'RT'
  6143.     stosw
  6144.     mov    al,' '
  6145.     stosb
  6146.     ret
  6147.  
  6148. ;    DISP32 - Print 32-bit displacement for addressing modes.
  6149. ;    Entry    None
  6150. ;    Exit    None
  6151. ;    Uses    AX
  6152.  
  6153. disp32:    call    disgetword
  6154.     push    ax
  6155.     call    disgetword
  6156.     call    hexword
  6157.     pop    ax
  6158.     call    hexword
  6159.     ret
  6160.  
  6161. ;    SHOWREG16 - Show 16-bit register name.
  6162. ;    Entry    AL    register number (0-7)
  6163. ;    Exit    None
  6164. ;    Uses    AX
  6165.  
  6166. showreg16:
  6167.     cbw
  6168.     shl    ax,1
  6169.     xchg    ax,bx
  6170.     push    ax
  6171.     mov    ax,rgnam16[bx]
  6172.     stosw
  6173.     pop    ax
  6174.     xchg    ax,bx
  6175.     ret
  6176.  
  6177. ;    SHOWMACH - Return string "[needs math coprocessor]", etc.
  6178. ;    Exit    si    Address of string
  6179. ;        cx    Length of string, or 0 if not needed
  6180. ;    Uses    al, di
  6181.  
  6182. showmach:
  6183.     mov    si,offset needsmsg ;candidate message
  6184.     test    dmflags,DM_COPR
  6185.     jz    sm1        ;if not a coprocessor instruction
  6186.     mov    byte [si+9],'7'    ;change message text
  6187.     mov    al,mach_87
  6188.     cmp    has_87,0
  6189.     jnz    sm2        ;if it has a coprocessor
  6190.     mov    al,machine
  6191.     cmp    al,dismach
  6192.     jb    sm3        ;if we display the message
  6193.     mov    si,offset needsmath    ;print this message instead
  6194.     mov    cx,needsmath_L
  6195.     ret
  6196.  
  6197. sm1:    mov    byte [si+9],'6'    ;reset message text
  6198.     mov    al,machine
  6199. sm2:    cmp    al,dismach
  6200.     jae    sm4        ;if no message (so far)
  6201. sm3:    mov    al,dismach
  6202.     add    al,'0'
  6203.     mov    [si+7],al
  6204.     mov    cx,needsmsg_L    ;length of the message
  6205.     ret
  6206.  
  6207. ;    Check for obsolete instruction.
  6208.  
  6209. sm4:    mov    si,offset obsolete    ;candidate message
  6210.     mov    ax,[di-2]        ;get info on this instruction
  6211.     mov    cx,5
  6212.     repne    scasw
  6213.     jne    sm5        ;if no matches
  6214.     mov    di,offset obsmach + 5 - 1
  6215.     sub    di,cx
  6216.     xor    cx,cx        ;clear CX:  no message
  6217.     mov    al,mach_87
  6218.     cmp    al,[di]
  6219.     jle    sm5        ;if this machine is OK
  6220.     mov    cx,obsolete_L
  6221. sm5:    ret
  6222.  
  6223. ;    DISGETBYTE - Get byte for disassembler.
  6224. ;    Entry    None
  6225. ;    Exit    AL    Next byte in instruction stream
  6226. ;    Uses    None
  6227.  
  6228. disgetbyte:
  6229.     push    si        ;save si
  6230.     lds    si,u_addr
  6231.     add    si,cs:dis_n    ;index to the right byte
  6232.     lodsb            ;get the byte
  6233.     pop    si        ;restore things
  6234.     push    cs
  6235.     pop    ds
  6236.     inc    dis_n        ;indicate that we've gotten this byte
  6237.     ret
  6238.  
  6239. ;    DISGETWORD - Get word for disassembler.
  6240. ;    Entry    None
  6241. ;    Exit    AX    Next word
  6242. ;    Uses    None
  6243.  
  6244. disgetword:
  6245.     push    si        ;save si
  6246.     lds    si,u_addr
  6247.     add    si,cs:dis_n    ;index to the right byte
  6248.     lodsw            ;get the byte
  6249.     pop    si        ;restore things
  6250.     push    cs
  6251.     pop    ds
  6252.     add    dis_n,2        ;indicate that we've gotten this byte
  6253.     ret
  6254.  
  6255. ;    DISSHOWBYTES - Show bytes for the disassembler.
  6256. ;    Entry    BX    Number of bytes (must be > 0)
  6257. ;    Exit        u_addr updated
  6258. ;    Uses    BX, SI.
  6259.  
  6260. disshowbytes:
  6261.     lds    si,u_addr
  6262. dsb1:    lodsb
  6263.     call    hexbyte
  6264.     dec    bx
  6265.     jnz    dsb1
  6266.     push    cs
  6267.     pop    ds
  6268.     mov    u_addr,si
  6269.     ret
  6270.  
  6271. ;    MOVEOVER - Move the line to the right.
  6272. ;    Entry    DI    Last address + 1 of line so far
  6273. ;    Exit    CX    Number of bytes to move
  6274. ;        DI    Updated
  6275. ;    Uses    SI
  6276.  
  6277. moveover:
  6278.     cmp    sizeloc,0
  6279.     je    mo1        ;if sizeloc not saved
  6280.     add    sizeloc,cx
  6281.  
  6282. mo1:    mov    si,di
  6283.     add    di,cx
  6284.     mov    cx,di
  6285.     sub    cx,offset line_out+24
  6286.     push    di
  6287.     std
  6288.     dec    si
  6289.     dec    di
  6290.     rep    movsb
  6291.     pop    di
  6292.     cld
  6293.     ret
  6294.  
  6295. ;    DISCHK32D - Check for 32 bit operand size prefix.
  6296.  
  6297. dischk32d:
  6298.     or    preused,PRE32D
  6299.     test    preflags,PRE32D
  6300.     ret
  6301.  
  6302. ;    DUMPREGS - Dump registers.
  6303.  
  6304. dumpregs:mov    si,offset regs
  6305.     mov    bx,offset regnames
  6306.     mov    di,offset line_out
  6307.     mov    cx,8
  6308.     call    dmpr1        ;print first row
  6309.     push    bx
  6310.     call    trimputs
  6311.     pop    bx
  6312.     mov    di,offset line_out
  6313.     mov    cl,5
  6314.     call    dmpr1
  6315.     mov    al,' '        ;add a space
  6316.     stosb
  6317.     call    dmpflags
  6318.     call    trimputs
  6319.     mov    ax,reg_ip
  6320.     mov    di,offset u_addr
  6321.     stosw
  6322.     mov    ax,reg_cs
  6323.     stosw
  6324.     mov    disflags,DIS_F_REPT + DIS_F_SHOW
  6325.     call    disasm
  6326.     mov    ax,reg_ip
  6327.     mov    u_addr,ax
  6328.     ret
  6329.  
  6330. ;    Function to print multiple register entries.
  6331.  
  6332. dmpr1:    mov    ax,[bx]
  6333.     inc    bx
  6334.     inc    bx
  6335.     stosw
  6336.     mov    al,'='
  6337.     stosb
  6338.     lodsw
  6339.     push    cx
  6340.     call    hexword
  6341.     pop    cx
  6342.     mov    ax,'  '
  6343.     stosw
  6344.     loop    dmpr1
  6345.     ret
  6346.  
  6347. ;    DMPFLAGS - Dump flags output.
  6348.  
  6349. dmpflags:
  6350.     mov    bx,flags
  6351.     mov    si,offset flgbits
  6352.     mov    cx,8
  6353. dmpf1:    mov    ax,[si+16]
  6354.     test    bx,[si]
  6355.     jz    dmpf2        ;if not asserted
  6356.     mov    ax,[si+32]
  6357. dmpf2:    stosw
  6358.     mov    al,' '
  6359.     stosb
  6360.     inc    si
  6361.     inc    si
  6362.     loop    dmpf1
  6363.     ret
  6364.  
  6365. flgbits    dw    800h,400h,100h,80h,40h,10h,4,1
  6366. flgnams    dw    'VN','PU','ID','LP','ZN','AN','OP','CN'
  6367. flgnons    dw    'VO','ND','IE','GN','RZ','CA','EP','YC'
  6368.  
  6369. ;    SHOWSTRING - Print nonempty null-terminated string.
  6370.  
  6371. showstring:
  6372.     lodsb
  6373. sstr1:    stosb
  6374.     lodsb
  6375.     cmp    al,0
  6376.     jne    sstr1
  6377.     ret
  6378.  
  6379. ;    HEXWORD - Print hex word (in AX).
  6380. ;    HEXBYTE - Print hex byte (in AL).
  6381. ;    HEXNYB - Print hex digit.
  6382. ;    Uses    al,cl.
  6383.  
  6384. hexword:
  6385.     push    ax
  6386.     mov    al,ah
  6387.     call    hexbyte
  6388.     pop    ax
  6389.     
  6390. hexbyte:
  6391.     push    ax
  6392.     mov    cl,4
  6393.     shr    al,cl
  6394.     call    hexnyb
  6395.     pop    ax
  6396.  
  6397. hexnyb:
  6398.     and    al,0fh
  6399.     add    al,90h        ;these four instructions change to ascii hex
  6400.     daa
  6401.     adc    al,40h
  6402.     daa
  6403.     stosb
  6404.     ret
  6405.  
  6406. ;    TAB_TO - Space fill until reaching the column indicated by AX.
  6407. ;    (Print a new line if necessary.)
  6408.  
  6409. tab_to:    push    ax
  6410.     sub    ax,di
  6411.     ja    tabto1        ;if there's room on this line
  6412.     call    trimputs
  6413.     mov    di,offset line_out
  6414.  
  6415. tabto1:    pop    cx
  6416.     sub    cx,di
  6417.     mov    al,' '
  6418.     rep    stosb        ;space fill to the right end
  6419.     ret
  6420.  
  6421. ;    TRIMPUTS - Trim excess blanks from string and print (with CR/LF).
  6422. ;    PUTSLINE - Add CR/LF to string and print it.
  6423. ;    PUTS - Print string through DI.
  6424.  
  6425. trimputs:
  6426.     dec    di
  6427.     cmp    byte [di],' '
  6428.     je    trimputs
  6429.     inc    di
  6430.  
  6431. putsline:
  6432.     mov    ax,LF * 256 + CR
  6433.     stosw
  6434.  
  6435. puts:    mov    ah,40h        ;write to file
  6436.     mov    bx,1
  6437.     mov    cx,di
  6438.     mov    dx,offset line_out
  6439.     sub    cx,dx
  6440.     int    21h
  6441.     ret
  6442.  
  6443. ;    I/O buffers.  (End of permanently resident part.)
  6444.  
  6445. end1    db
  6446.  
  6447. line_in    db    255,0,CR    ;length = 257
  6448. line_out equ    end1+258    ;length = 1 + 263
  6449. real_end equ    end1+258+264
  6450. staksiz    equ    200h
  6451.  
  6452.                 ;lots of bytes follow this
  6453.  
  6454. ;---------------------------------------
  6455. ;    Initialization second phase.
  6456. ;---------------------------------------
  6457.  
  6458. intwo:    mov    byte line_out-1,'0'    ;initialize line_out
  6459.  
  6460. ;    Shrink DEBUG.
  6461.  
  6462.     mov    bx,offset real_end + staksiz + 15
  6463.     and    bx,not 15
  6464.     mov    sp,bx
  6465.     xor    ax,ax
  6466.     push    ax        ;just in case
  6467.     mov    savesp,sp    ;save SP
  6468.     mov    ah,4ah        ;SETBLOCK
  6469.     mov    cl,4
  6470.     shr    bx,cl
  6471.     int    21h        ;shrink DEBUG now
  6472.  
  6473. ;    Load the program.
  6474.  
  6475.     call    ll2        ;load the program
  6476.     jmp    cmd3        ;done
  6477.  
  6478. ;---------------------------------------
  6479. ;    Debug initialization code.
  6480. ;---------------------------------------
  6481.  
  6482.     even
  6483. fp_status dw    5a5ah        ;FPU status word
  6484.  
  6485. inttab    dw    int0        ;table of interrupt initialization stuff
  6486.     db    0
  6487.     dw    int1
  6488.     db    1
  6489.     dw    int3
  6490.     db    3
  6491.     dw    debug22
  6492.     db    22h
  6493.  
  6494. initcode:
  6495.     cld
  6496.  
  6497.     mov    execblk+4,cs    ;set up parameter block for exec command
  6498.     mov    execblk+8,cs
  6499.     mov    execblk+12,cs
  6500.  
  6501. ;    Check for console input vs. input from a file or other device.
  6502.  
  6503.     mov    ax,4400h    ;IOCTL--get info
  6504.     xor    bx,bx
  6505.     int    21h
  6506.     jc    init1        ;if not device
  6507.     and    dl,81h        ;check if console device
  6508.     cmp    dl,81h
  6509.     jne    init1        ;if not the console input
  6510.     mov    notatty,0    ;it _is_ a tty
  6511.  
  6512. ;    Compute the length of the environment (for future reference).
  6513.  
  6514. init1:    mov    es,[2ch]    ;environment segment
  6515.     xor    di,di
  6516.     mov    al,0
  6517.     mov    cx,-1
  6518. init2:    scasb
  6519.     jz    init3        ;if empty string
  6520.     repne    scasb        ;skip string
  6521.     jmp    init2
  6522.  
  6523. init3:    mov    envlen,di
  6524.     push    cs
  6525.     pop    es
  6526.  
  6527.     mov    ax,3000h    ;check DOS version
  6528.     int    21h
  6529.     xchg    al,ah
  6530.     cmp    ax,31fh
  6531.     jb    init4        ;if early, then don't use new INT 25h method
  6532.     inc    usepacket
  6533.  
  6534. ;    Determine the processor type.  This is adapted from code in the
  6535. ;    Pentium<tm> Family User's Manual, Volume 3:  Architecture and
  6536. ;    Programming Manual, Intel Corp., 1994, Chapter 5.  That code contains
  6537. ;    the following comment:
  6538.  
  6539. ;    This program has been developed by Intel Corporation.
  6540. ;    Software developers have Intel's permission to incorporate
  6541. ;    this source code into your software royalty free.
  6542.  
  6543. ;    Intel 8086 CPU check.
  6544. ;    Bits 12-15 of the FLAGS register are always set on the 8086 processor.
  6545. ;    Probably the 186 as well.
  6546.  
  6547. init4:    pushf            ;get original flags into AX
  6548.     pop    ax
  6549.     mov    cx,ax        ;save them
  6550.     and    ax,0fffh    ;clear bits 12-15
  6551.     push    ax        ;save new flags value on stack
  6552.     popf            ;replace current flags value
  6553.     pushf            ;get new flags
  6554.     pop    ax        ;store new flags in AX
  6555.     and    ax,0f000h    ;check to see whether bits 12-15 are set
  6556.     cmp    ax,0f000h
  6557.     je    init6        ;if 8086 or 80186 (can't tell them apart)
  6558.  
  6559. ;    Intel 286 CPU check.
  6560. ;    Bits 12-15 of the flags register are always clear on the
  6561. ;    Intel 286 processor in real-address mode.
  6562.  
  6563.     or    cx,0f000h    ;try to set bits 12-15
  6564.     push    cx        ;save new flags value on stack
  6565.     popf            ;replace current flags value
  6566.     pushf            ;get new flags
  6567.     pop    ax        ;store new flags in AX
  6568.     test    ax,0f000h    ;if bits 12-15 clear, CPU = 80286
  6569.     mov    machine,2
  6570.     jz    init6        ;if 80286
  6571.  
  6572. ;    Intel 386 CPU check.
  6573. ;    The AC bit, bit #18, is a new bit introduced in the EFLAGS
  6574. ;    register on the Intel486 DX cpu to generate alignment faults.
  6575. ;    This bit cannot be set on the Intel386 CPU.
  6576.  
  6577. ;    It is now safe to use 32-bit opcode/operands.
  6578.  
  6579.     inc    machine
  6580.     mov    bx,sp        ;save current stack pointer to align
  6581.     and    sp,not 3    ;align stack to avoid AC fault
  6582.     db 66h            ;32-bit data prefix
  6583.     pushf            ;push original EFLAGS
  6584.     db 66h
  6585.     pop    ax        ;get original EFLAGS
  6586.     db 66h
  6587.     mov    cx,ax        ;save original EFLAGS in CX
  6588.     db 66h
  6589.     db    35h,0,0,4,0    ;flip (XOR) AC bit in EFLAGS
  6590.     db 66h
  6591.     push    ax        ;put new EFLAGS value on stack
  6592.     db 66h
  6593.     popf            ;replace EFLAGS value
  6594.     db 66h
  6595.     pushf            ;get new EFLAGS
  6596.     db 66h
  6597.     pop    ax        ;store new EFLAGS value in EAX
  6598.     db 66h
  6599.     cmp    ax,cx
  6600.     jz    init5        ;if 80386 CPU
  6601.  
  6602. ;    Intel486 DX CPU, Intel487 SX NDP, and Intel486 SX CPU check.
  6603. ;    Checking for ability to set/clear ID flag (bit 21) in EFLAGS
  6604. ;    which indicates the presence of a processor with the ability
  6605. ;    to use the CPUID instruction.
  6606.  
  6607.     inc    machine        ;it's a 486
  6608.     db 66h
  6609.     mov    ax,cx        ;get original EFLAGS
  6610.     db 66h
  6611.     db    35h,0,0,20h,0    ;flip (XOR) ID bit in EFLAGS
  6612.     db 66h
  6613.     push    ax        ;save new EFLAGS value on stack
  6614.     db 66h
  6615.     popf            ;replace current EFLAGS value
  6616.     db 66h
  6617.     pushf            ;get new EFLAGS
  6618.     db 66h
  6619.     pop    ax        ;store new EFLAGS in EAX
  6620.     db 66h
  6621.     cmp    ax,cx        ;check if it's changed
  6622.     je    init5        ;if it's a 486 (can't toggle ID bit)
  6623.     db 66h
  6624.     push    cx
  6625.     db 66h
  6626.     popf            ;restore AC bit in EFLAGS first
  6627.     mov    sp,bx        ;restore original stack pointer
  6628.  
  6629. ;    Execute CPUID instruction.
  6630.  
  6631.     db 66h
  6632.     xor    ax,ax        ;set up input for CPUID instruction
  6633.     db    0fh,0a2h    ;CPUID instruction
  6634.     db 66h
  6635.     db    83h,0f8h,1    ;cmp eax,1
  6636.     jl    init6        ;if 1 is not a valid input value for CPUID
  6637.     db 66h
  6638.     xor    ax,ax        ;otherwise, run CPUID with ax = 1
  6639.     db 66h
  6640.     inc    ax
  6641.     db    0fh,0a2h    ;CPUID instruction
  6642.     mov    al,ah
  6643.     and    al,0fh        ;bits 8-11 are the model number
  6644.     mov    machine,al    ;save it
  6645.     jmp    short init6    ;don't restore SP
  6646.  
  6647. init5:    db 66h
  6648.     push    cx
  6649.     db 66h
  6650.     popf            ;restore AC bit in EFLAGS first
  6651.     mov    sp,bx        ;restore original stack pointer
  6652.  
  6653. ;    Next determine the type of FPU in a system and set the mach_87
  6654. ;    variable with the appropriate value.  All registers are used by
  6655. ;    this code; none are preserved.
  6656.  
  6657. ;    Coprocessor check.
  6658. ;    The algorithm is to determine whether the floating-point
  6659. ;    status and control words can be written to.  If not, no
  6660. ;    coprocessor exists.  If the status and control words can be
  6661. ;    written to, the correct coprocessor is then determined
  6662. ;    depending on the processor ID.  The Intel386 CPU can
  6663. ;    work with either an Intel 287 NDP or an Intel387 NDP.
  6664. ;    The infinity of the coprocessormust be checked
  6665. ;    to determine the correct coprocessor ID.
  6666.  
  6667. init6:    mov    al,machine
  6668.     mov    mach_87,al    ;by default, set mach_87 to machine
  6669.  
  6670.     fninit            ;reset FP status word
  6671.     mov    fp_status,5a5ah    ;restore temp word to nonzero value
  6672.     fnstsw    fp_status    ;save FP status word
  6673.     mov    ax,fp_status    ;check FP status word
  6674.     cmp    al,0
  6675.     jne    init7        ;if no FPU present
  6676.  
  6677.     fnstcw    fp_status    ;save FP control word
  6678.     mov    ax,fp_status    ;check FP control word
  6679.     and    ax,103fh    ;see if selected parts look OK
  6680.     cmp    ax,3fh
  6681.     jne    init7        ;if no FPU present
  6682.     inc    has_87        ;there's an FPU
  6683.  
  6684. ;    If we're using a 386, check for 287 vs. 387 by checking whether
  6685. ;    +infinity = -infinity.
  6686.  
  6687.     cmp    machine,3
  6688.     jne    init7        ;if not a 386
  6689.     fld1            ;must use default control from FNINIT
  6690.     fldz            ;form infinity
  6691.     fdiv            ;1 / 0 = infinity
  6692.     fld    st        ;form negative infinity
  6693.     fchs
  6694.     fcompp            ;see if they are the same and remove them
  6695.     fstsw    fp_status    ;look at status from FCOMPP
  6696.     mov    ax,fp_status
  6697.     sahf
  6698.     jnz    init7        ;if they are different, then it's a 387
  6699.     dec    mach_87        ;otherwise, it's a 287
  6700.  
  6701. ;    ||| Interpret switches and erase them from the command line.
  6702.  
  6703. init7:    mov    ax,3700h    ;get switch character
  6704.     int    21h
  6705.     mov    switchar,dl
  6706.     cmp    dl,'/'
  6707.     jne    init8
  6708.     mov    swch1,dl
  6709. init8:    mov    si,81h
  6710. init9:    lodsb
  6711.     cmp    al,' '
  6712.     je    init9
  6713.     cmp    al,TAB
  6714.     je    init9
  6715.  
  6716. ;    Feed the remaining command line to the 'n' command.
  6717.  
  6718.     dec    si
  6719.     lodsb
  6720.     call    nn        ;process the rest of the line
  6721.  
  6722. ;    Save some interrupt vectors.
  6723.  
  6724.     mov    cx,2
  6725.     mov    di,offset intsave
  6726.     mov    ax,3500h    ;get interrupt vector 0
  6727.     int    21h
  6728.     mov    intsave,bx
  6729.     mov    intsave+2,es
  6730.     mov    ax,3501h    ;get interrupt vector 1
  6731.     int    21h
  6732.     mov    intsave+4,bx
  6733.     mov    intsave+6,es
  6734.     mov    ax,3503h    ;get interrupt vector 3
  6735.     int    21h
  6736.     mov    intsave+8,bx
  6737.     mov    intsave+10,es
  6738.     push    ds
  6739.     pop    es
  6740.  
  6741. ;    Set up interrupt vectors.
  6742.  
  6743.     mov    cx,4
  6744.     mov    si,offset inttab
  6745. init10:    lodsw            ;get address
  6746.     xchg    ax,dx        ;mov dx,ax
  6747.     mov    ah,25h        ;set interrupt vector
  6748.     lodsb            ;interrupt number
  6749.     int    21h
  6750.     loop    init10
  6751.  
  6752. ;    Save and modify termination address and the parent PSP field.
  6753.  
  6754.     mov    si,0ah
  6755.     mov    di,offset psp22
  6756.     movsw
  6757.     movsw
  6758.     mov    word [si-4],offset debug22
  6759.     mov    [si-2],cs
  6760.     mov    si,16h
  6761.     movsw
  6762.     mov    [si-2],cs
  6763.  
  6764. ;    Done with the first phase.
  6765.  
  6766.     jmp    intwo        ;jump to second phase
  6767.