DOS-debug

Форк
0
/
LINEASM.INC 
2343 строки · 55.6 Кб
1

2
;--- A command - tiny assembler.
3

4
;--- todo:
5
;--- 1. fix regression since v1.09: cmp [x], yy  assumes word operand if no size given
6
;--- 2. MS debug accepts call near/far [x], Debug rejects near [x], accepts far [x]
7
;--- 3. MS debug accepts call near/far x (adding current cs as seg if far), Debug rejects both
8

9
;--- macros for asmtbl.inc
10

11
;--- mne macro, used for the assembler mnemonics table
12

13
mne macro val2:REQ, dbytes:VARARG
14
ASMDATA segment
15
CURROFS = $
16
	ifnb <dbytes>
17
	 db dbytes
18
	endif
19
ASMDATA ends
20
	dw CURROFS - asmtab
21
MN_&val2 equ $ - mnlist
22
tmpstr catstr <!">,@SubStr(val2,1,@SizeStr(val2)-1),<!",!'>,@SubStr(val2,@SizeStr(val2)),<!'>,<+80h>
23
	db tmpstr
24
endm
25

26
;--- AGRP: num is the index into agroups, that finally defines the opcode (1 or 2 byte).
27
;--- rfld, bits 0-2 of the final value, define bits 3-5 in ai.regmem.
28

29
AGRP macro num,rfld
30
	exitm <240h + num*8 + rfld>
31
endm
32

33
variant macro opcode:req, key:req, lockb, machine
34
ASMDATA segment
35
	ifnb <lockb>
36
	 db lockb
37
	endif
38
	ifnb <machine>
39
	 db machine
40
	endif
41
ainfo = (opcode) * ASMMOD + key
42
	db HIGH ainfo, LOW ainfo
43
ASMDATA ends
44
endm
45

46
fpvariant macro opcode, key, addb, lockb, machine
47
	variant opcode, key, lockb, machine
48
ASMDATA segment
49
	db addb
50
ASMDATA ends
51
endm
52

53
endvariant macro
54
ASMDATA segment
55
	db -1
56
ASMDATA ends
57
endm
58

59
;--- opl macro, used to define operand list types
60
;--- the macro defines an EQUate, OPLIST_XX, which
61
;--- is refered to by array opindex.
62
;--- v2.50: "terminating" 0 no longer required.
63

64
opl macro index, value:VARARG
65
OPLIST_&index equ $ - oplists
66
	ifnb <value>
67
	  db value
68
	endif
69
endm
70

71
;--- flags for instruction operands.
72
;--- First the sizes.
73

74
OP_ALL	equ 40h		;byte/word/dword operand (could be 30h but ...)
75
OP_1632	equ 50h		;word or dword operand
76
OP_8	equ 60h		;byte operand
77
OP_16	equ 70h		;word operand
78
OP_32	equ 80h		;dword operand
79
OP_64	equ 90h		;qword operand
80

81
OP_SIZE	equ OP_ALL		;the lowest of these
82

83
;--- These operand types need to be combined with a size flag..
84
;--- order must match items in asm_jmp1, bittab and dis_jmp1
85

86
OP_IMM		equ 0		;immediate
87
OP_RM		equ 2		;reg/mem
88
OP_M		equ 4		;mem (but not reg)
89
OP_R_MOD	equ 6		;register, determined from MOD R/M part
90
OP_MOFFS	equ 8		;memory offset; e.g., [1234]
91
OP_R		equ 10		;reg part of reg/mem byte
92
OP_R_ADD	equ 12		;register, determined from instruction byte
93
OP_AX		equ 14		;al or ax or eax
94

95
;--- These don't need a size.
96
;--- order must match items in asm_jmp1, bittab and dis_optab.
97
;--- additionally, order of OP_M64 - OP_FARMEM is used
98
;--- in table asm_siznum
99
;--- v2.50: value 0 was used to terminate an operand list ( macro opl )
100
;---        it's free now.
101

102
OP_M64		equ 2		; 0 qword memory (obsolete?)
103
OP_MFLOAT	equ 4		; 1 float memory
104
OP_MDOUBLE	equ 6		; 2 double-precision floating memory
105
OP_M80		equ 8		; 3 tbyte memory
106
OP_MXX		equ 10		; 4 memory (size unknown)
107
OP_FARMEM	equ 12		; 5 memory far16/far32 pointer 
108
OP_FARIMM	equ 14		; 6 far16/far32 immediate
109
OP_REL8		equ 16		; 7 byte address relative to IP
110
OP_REL1632	equ 18		; 8 word or dword address relative to IP
111
OP_1CHK		equ 20		; 9 check for ST(1)
112
OP_STI		equ 22		;10 ST(I)
113
OP_CR		equ 24		;11 CRx
114
OP_DR		equ 26		;12 DRx
115
OP_TR		equ 28		;13 TRx
116
OP_SEGREG	equ 30		;14 segment register
117
OP_IMMS8	equ 32		;15 sign extended immediate byte
118
OP_IMM8		equ 34		;16 immediate byte (other args may be (d)word)
119
OP_MMX		equ 36		;17 MMx
120
OP_SHOSIZ	equ 38		;18 set flag to always show the size
121

122
OP_1		equ 40		;19 1 (simple "string" ops from here on)
123
OP_3		equ 42		;20 3
124
OP_DX		equ 44		;21 DX
125
OP_CL		equ 46		;22 CL
126
OP_ST		equ 48		;23 ST (top of coprocessor stack)
127
OP_CS		equ 50		;24 CS
128
OP_DS		equ 52		;25 DS
129
OP_ES		equ 54		;26 ES
130
OP_FS		equ 56		;27 FS
131
OP_GS		equ 58		;28 GS
132
OP_SS		equ 60		;29 SS
133

134
OP_STR equ OP_1		;first "string" op
135

136
CONST segment
137

138
;--- Instructions that have an implicit operand subject to a segment override
139
;--- (outsb/w, movsb/w, cmpsb/w, lodsb/w, xlat).
140
;--- also used by disassembler
141

142
prfxtab	db 06eh,06fh, 0a4h,0a5h, 0a6h,0a7h, 0ach,0adh, 0d7h
143
N_PRFXTAB equ $ - prfxtab
144

145
;--- Instructions that can be used with REP/REPE/REPNE.
146
;--- also used by disassembler
147

148
replist	db 06ch,06eh,0a4h,0aah,0ach	;REP (INSB, OUTSB, MOVSB, STOSB, LODSB)
149
N_REPNC  equ $ - replist
150
		db 0a6h,0aeh				;REPE/REPNE (CMPSB, SCASB)
151
N_REPALL equ $ - replist
152

153
	include <ASMTBL.INC>
154

155
;--- opindex array - help array to access operand list items (oplists);
156
;--- needed because the operand list items differ in size.
157

158
opindex label byte
159
	.radix 16t
160
opidx = 0
161
	repeat ASMMOD
162
if opidx lt 10h
163
%	db OPLIST_0&@CatStr(%opidx)
164
else
165
%	db OPLIST_&@CatStr(%opidx)
166
endif
167
opidx = opidx + 1
168
	endm
169
	.radix 10t
170
	db offset agroups - offset oplists	; size of oplists table, required to find end of last operand list
171

172
CONST ends
173

174
_DATA segment
175

176
asm_mn_flags	db 0	;flags for the mnemonic
177

178
AMF_D32		equ 1		;32bit opcode/data operand
179
AMF_WAIT	equ 2
180
AMF_A32		equ 4		;address operand is 32bit
181
AMF_SIB		equ 8		;there's a SIB in the arguments
182
AMF_MSEG	equ 10h		;if a seg prefix was given b4 mnemonic
183
AMF_FSGS	equ 20h		;if FS or GS was encountered
184

185
AMF_D16		equ 40h		;16bit opcode/data operand
186
AMF_ADDR	equ 80h		;address operand is given
187

188
bEndOplItem db 0		;v2.50
189

190
;--- aa_saved_prefix and aa_seg_pre must be consecutive.
191
aa_saved_prefix	db 0	;WAIT or REP... prefix
192
aa_seg_pre	db 0		;segment prefix
193

194
mneminfo	dw 0		;address associated with the mnemonic
195
a_opcode	dw 0		;op code info for this variant
196
a_opcode2	dw 0		;copy of a_opcode for obs-instruction
197

198
;--- dmflags values
199
DM_COPR		equ 1	;math coprocessor
200
DM_MMX		equ 2	;MMX extensions
201

202
;--- varflags values
203
VAR_LOCKABLE	equ 1	;variant is lockable
204
VAR_MODRM		equ 2	;if there's a MOD R/M here
205
VAR_SIZ_GIVN	equ 4	;if a size was given
206
VAR_SIZ_FORCD	equ 8	;if only one size is permitted
207
VAR_SIZ_NEED	equ 10h	;if we need the size
208
VAR_D16			equ 20h	;if operand size is WORD
209
VAR_D32			equ 40h	;if operand size is DWORD
210

211
AINSTR struct
212
rmaddr		dw ?	;address of operand giving the R/M byte (asm only)
213
;--- regmem and sibbyte must be consecutive
214
regmem		db ?	;mod reg r/m part of instruction
215
sibbyte		db ?	;SIB byte
216
immaddr		dw ?	;address of operand giving the immed stf (asm only)
217
xxaddr		dw ?	;address of additional stuff (asm only)
218
;--- dismach and dmflags must be consecutive
219
dismach		db ?	;type of processor needed
220
dmflags		db ?	;flags for extra processor features
221
opcode_or	db ?	;extra bits in the op code (asm only)
222
opsize		db ?	;size of this operation (2 or 4) (asm only)
223
varflags	db ?	;flags for this variant (asm only)
224
reqsize		db ?	;size that this arg should be (asm only)
225
AINSTR ends
226

227
ai	AINSTR <?>		; used by assembler and disassembler
228

229
_DATA ends
230

231
CONST segment
232

233
;--- search for "obsolete" instructions
234
;--- dbe0: FENI
235
;--- dbe1: FDISI
236
;--- dbe4: FSETPM
237
;---  124: MOV TRx, reg
238
;---  126: MOV reg, TRx
239

240
a_obstab	dw 0dbe0h,0dbe1h,0dbe4h,124h,126h	;obs. instruction codes
241
obsmach		db 1,1,2,4,4	;max permissible machine for the above
242

243
modrmtab	db 11,0,13,0,15,0,14,0	;[bx], [bp], [di], [si]
244
			db 15,13,14,13,15,11,14,11	;[bp+di],[bp+si],[bx+di],[bx+si]
245

246
aam_args	db 'a',CR
247

248
;--- Equates for parsed arguments, stored in OPRND.flags
249

250
ARG_DEREF		equ 1	;non-immediate memory reference
251
ARG_MODRM		equ 2	;if we've computed the MOD R/M byte
252
ARG_JUSTREG		equ 4	;a solo register
253
ARG_WEIRDREG	equ 8	;if it's a segment register or CR, etc.
254
ARG_IMMED		equ 10h	;if it's just a number
255
ARG_FARADDR		equ 20h	;if it's of the form xxxx:yyyyyyyy
256

257
;--- For each operand type in the following table, the first byte is
258
;--- the bits, at least one of which must be present; the second is the
259
;--- bits all of which must be absent.
260
;--- the items in bittab must be ordered similiar to asm_jmp1 and dis_jmp1.
261

262
bittab label byte
263
	db ARG_IMMED			;+0 OP_IMM
264
	db ARG_DEREF+ARG_JUSTREG;+1 OP_RM
265
	db ARG_DEREF			;+2 OP_M
266
	db ARG_JUSTREG			;+3 OP_R_MOD
267
	db ARG_DEREF			;+4 OP_MOFFS
268
	db ARG_JUSTREG			;+5 OP_R
269
	db ARG_JUSTREG			;+6 OP_R_ADD
270
	db ARG_JUSTREG			;+7 OP_AX
271

272
	db ARG_DEREF			; 0 OP_M64
273
	db ARG_DEREF			; 1 OP_MFLOAT
274
	db ARG_DEREF			; 2 OP_MDOUBLE
275
	db ARG_DEREF			; 3 OP_M80
276
	db ARG_DEREF			; 4 OP_MXX
277
	db ARG_DEREF			; 5 OP_FARMEM
278
	db ARG_FARADDR			; 6 OP_FARIMM
279
	db ARG_IMMED			; 7 OP_REL8
280
	db ARG_IMMED			; 8 OP_REL1632
281
	db ARG_WEIRDREG			; 9 OP_1CHK
282
	db ARG_WEIRDREG			;10 OP_STI
283
	db ARG_WEIRDREG			;11 OP_CR
284
	db ARG_WEIRDREG			;12 OP_DR
285
	db ARG_WEIRDREG			;13 OP_TR
286
	db ARG_WEIRDREG			;14 OP_SEGREG
287
	db ARG_IMMED			;15 OP_IMMS8
288
	db ARG_IMMED			;16 OP_IMM8
289
	db ARG_WEIRDREG			;17 OP_MMX
290
	db 0ffh					;18 OP_SHOSIZ
291

292
	db ARG_IMMED			;OP_1
293
	db ARG_IMMED			;OP_3
294
	db ARG_JUSTREG			;OP_DX
295
	db ARG_JUSTREG			;OP_CL
296
	db ARG_WEIRDREG			;OP_ST
297
	db ARG_WEIRDREG			;OP_CS
298
	db ARG_WEIRDREG			;OP_DS
299
	db ARG_WEIRDREG			;OP_ES
300
	db ARG_WEIRDREG			;OP_FS
301
	db ARG_WEIRDREG			;OP_GS
302
	db ARG_WEIRDREG			;OP_SS
303

304
;--- special ops DX, CL, ST, CS, DS, ES, FS, GS, SS
305
;--- entry required if ao48 is set
306
;--- order of entries matches the last 9 ones in dis_optab
307

308
asm_regnum label byte
309
	db REG_DX, REG_CL, REG_ST, REG_CS, REG_DS, REG_ES, REG_FS, REG_GS, REG_SS
310

311
;--- size qualifier
312
;--- 1  BY=BYTE ptr
313
;--- 2  WO=WORD ptr
314
;--- 3  unused
315
;--- 4  DW=DWORD ptr
316
;--- 5  QW=QWORD ptr
317
;--- 6  FL=FLOAT ptr (REAL4)
318
;--- 7  DO=DOUBLE ptr (REAL8)
319
;--- 8  TB=TBYTE ptr (REAL10)
320
;--- 9  SH=SHORT 
321
;--- 10 LO=LONG
322
;--- 11 NE=NEAR ptr
323
;--- 12 FA=FAR ptr
324

325
SIZ_NONE	equ 0
326
SIZ_BYTE	equ 1
327
SIZ_WORD	equ 2
328
SIZ_DWORD	equ 4
329
SIZ_QWORD	equ 5
330
SIZ_FLOAT	equ 6
331
SIZ_DOUBLE	equ 7
332
SIZ_TBYTE	equ 8
333
SIZ_SHORT	equ 9
334
SIZ_LONG	equ 10
335
SIZ_NEAR	equ 11
336
SIZ_FAR		equ 12
337

338
sizetcnam	db 'BY','WO','WO','DW','QW','FL','DO','TB','SH','LO','NE','FA'
339

340
;--- sizes for OP_M64, OP_MFLOAT, OP_MDOUBLE, OP_M80, OP_MXX, OP_FARMEM
341

342
asm_siznum	db SIZ_QWORD, SIZ_FLOAT, SIZ_DOUBLE, SIZ_TBYTE
343
			db -1, SIZ_FAR			;-1 = none
344

345
CONST ends
346

347
;--- write byte in AL to BX/[E]DX, then increment [E]DX
348

349
writeasm proc
350
	call writemem
351
	sizeprfX	;inc edx
352
	inc dx
353
	ret
354
writeasm endp
355

356
;--- write CX bytes from DS:SI to BX:[E]DX
357

358
writeasmn proc
359
	jcxz nowrite
360
@@:
361
	lodsb
362
	call writeasm
363
	loop @B
364
nowrite:
365
	ret
366
writeasmn endp
367

368
a_cmd proc
369
	mov [errret],offset aa01
370
	cmp al,CR
371
	je aa01x		;if end of line
372
	@movs bx,[regs.rCS]	;default segment to use
373
aa00a:
374
	call getaddr	;get address into bx:(e)dx
375
	call chkeol		;expect end of line here
376
	sizeprfX		;mov [a_addr+0],edx
377
	mov [a_addr+0],dx	;save the address
378
	mov [a_addr+4],bx
379
if ?PM
380
	jmp aa01
381
aa01x:
382
 if ?DPMI
383
	call ispm_dbe
384
	jz aa01
385
;--- v2.0: def seg for a is no longer automatically converted
386
;--- when pm is entered.
387
 endif
388
	test [bFlagsPM], 1	; default for a-cmd already set?
389
	jnz aa01
390
	@movs ax, [regs.rCS]; use current CS:IP as default
391
	mov [a_addr+4], ax 
392
	sizeprfX			; mov eax, [regs.IP]
393
	mov ax, [regs.rIP]    
394
	sizeprfX			; mov [a_addr+0], eax
395
	mov [a_addr+0], ax
396
else
397
aa01x:
398
endif
399

400
;--- Begin loop over input lines.
401

402
aa01:
403
if ?PM
404
	or [bFlagsPM], 1
405
endif
406
	@dprintf "aa01: a_addr=%X:%lX", word ptr [a_addr+4], dword ptr [a_addr+0]
407
if FLATSS
408
	.386
409
	mov esp,[top_sp]	;restore the stack (this implies no "ret")
410
else
411
	mov sp,[top_sp]		;restore the stack (this implies no "ret")
412
endif
413
	mov di,offset line_out
414
	@dispsegm [a_addr+4]
415
	mov al,':'
416
	stosb
417
	mov [asm_mn_flags],0
418
if ?PM
419
	mov bx,[a_addr+4]
420
	call getseldefsize
421
	mov [bCSAttr],al
422
endif
423
	sizeprfX			;mov eax,[a_addr+0]
424
	mov ax,[a_addr+0]
425
	call DispOfs
426
	mov al,' '
427
	stosb
428
	call getline00
429
	cmp al,CR
430
	je aa_exit	;if done
431
	cmp al,';'
432
	je aa01		;if comment
433
	mov word ptr [aa_saved_prefix],0 ;clear aa_saved_prefix and aa_seg_pre
434

435
;--- Get mnemonic and look it up.
436

437
aa02:
438
	mov di,offset line_out	;return here after LOCK/REP/SEG prefix
439
	push si			;save position of mnemonic
440
aa03:
441
	cmp al,'a'
442
	jb @F			;if not lower case letter
443
	cmp al,'z'
444
	ja @F
445
	and al,TOUPPER	;convert to upper case
446
@@:
447
	stosb
448
	lodsb
449
	cmp al,CR
450
	je @F			;if end of mnemonic
451
	cmp al,';'
452
	je @F
453
	cmp al,' '
454
	je @F
455
	cmp al,':'
456
	je @F
457
	cmp al,TAB
458
	jne aa03
459
@@:
460
	or byte ptr [di-1],80h	;set highest bit of last char of mnemonic
461
	call skipwh0	;skip to next field
462
	dec si
463
	push si			;save position in input line
464
;	mov al,0
465
;	stosb
466

467
;--- now search mnemonic in list
468

469
	mov si,offset mnlist
470
aa06:               ;<--- next mnemonic
471
	mov bx,si
472
	add si,2		;skip the 'asmtab' offset 
473
	mov cx,si
474
@@:
475
	lodsb			;skip to end of string
476
	and al,al
477
	jns @B			;if not end of string
478
	xchg cx,si
479
	push cx
480
	sub cx,si		;size of opcode in mnlist
481
	mov di,offset line_out
482
	repe cmpsb
483
	pop si
484
	je aa14			;if found it
485
	cmp si,offset end_mnlist
486
	jc aa06			;next mnemonic
487
	pop si			;skip position in input line
488
aa13a:
489
	pop si			;skip position of mnemonic
490
aa13b:
491
	jmp cmd_error	;complain
492
aa_exit:
493
	jmp cmdloop		;done with this command
494

495
;--- We found the mnemonic.
496

497
aa14:
498
	mov si,[bx]		;get the offset into asmtab
499
	add si,offset asmtab
500

501
;   Now si points to the spot in asmtab corresponding to this mnemonic.
502
;   The format of the assembler table is as follows.
503
;   First, there is optionally one of the following bytes:
504
;       ASM_DB      db mnemonic
505
;       ASM_DW      dw mnemonic
506
;       ASM_DD      dd mnemonic
507
;       ASM_WAIT    the mnemonic should start with a wait
508
;                   instruction.
509
;       ASM_D32     This is a 32 bit instruction variant.
510
;       ASM_D16     This is a 16 bit instruction variant.
511
;       ASM_AAX     Special for AAM and AAD instructions:
512
;                   put 0ah in for a default operand.
513
;       ASM_SEG     This is a segment prefix.
514
;       ASM_LOCKREP This is a LOCK or REP... prefix.
515
;
516
;   Then, in most cases, this is followed by one or more of the following
517
;   sequences, indicating an instruction variant.
518
;   ASM_LOCKABLE (optional) indicates that this instruction can
519
;                follow a LOCK prefix.
520
;   ASM_MACHx    (optional) indicates the first machine on which this
521
;                instruction appeared.
522
;   [word]       This is a 16-bit integer, most significant byte
523
;                first, giving ASMMOD * a + b, where b is an
524
;                index into the array opindex (indicating the
525
;                key, or type of operand list), and a is as
526
;                follows:
527
;                0-255     The (one-byte) instruction.
528
;                256-511   The lower 8 bits give the second byte of
529
;                          a two-byte instruction beginning with 0fh.
530
;                512-575   Bits 2-0 say which floating point instruction
531
;                          this is (0d8h-0dfh), and 5-3 give the /r
532
;                          field.
533
;                576-...   (a-576)/8 is the index in the array agroups
534
;                          (which gives the real value of a), and the
535
;                          low-order 3 bits gives the /r field.
536
;
537
;   [byte]       This gives the second byte of a floating
538
;                instruction if 0d8h <= a <= 0dfh.
539
;
540
;   Following these is an ASM_END byte.
541
;
542
;   Exceptions:
543
;       ASM_SEG and ASM_LOCKREP are followed by just one byte, the
544
;       prefix byte.
545
;       ASM_DB, ASM_DW, and ASM_DD don't need to be followed by
546
;       anything.
547

548
ASM_END		equ 0ffh
549
ASM_DB		equ 0feh
550
ASM_DW		equ 0fdh
551
ASM_DD		equ 0fch
552
ASM_ORG		equ 0fbh
553
ASM_WAIT	equ 0fah
554
ASM_D32		equ 0f9h
555
ASM_D16		equ 0f8h
556
ASM_AAX		equ 0f7h
557
ASM_SEG		equ 0f6h
558
ASM_LOCKREP	equ 0f5h
559
ASM_LOCKABLE equ 0f4h
560
ASM_MACH6	equ 0f3h
561
ASM_MACH5	equ 0f2h
562
ASM_MACH4	equ 0f1h
563
ASM_MACH3	equ 0f0h
564
ASM_MACH2	equ 0efh
565
ASM_MACH1	equ 0eeh
566
ASM_MACH0	equ 0edh
567

568
	cmp byte ptr [si],ASM_LOCKREP	;check for mnemonic flag byte
569
	jb aa15						;if none
570
	lodsb						;get the prefix
571
	sub al,ASM_LOCKREP			;convert to 0-9
572
	je aa18						;if LOCK or REP...
573
	cbw
574
	dec ax
575
	jz aa17						;if segment prefix (ASM_SEG)
576
	dec ax
577
	jz aa16						;if aad or aam (ASM_AAX)
578
	dec ax
579
	jz aa15_1					;if ASM_D16
580
	cmp al,3
581
	jae aa20					;if ASM_ORG or ASM_DD or ASM_DW or ASM_DB
582
	or [asm_mn_flags],al		;save AMF_D32 or AMF_WAIT (1 or 2)
583
aa15:
584
	jmp ab01					;now process the arguments
585
aa15_1:
586
	or [asm_mn_flags],AMF_D16
587
	inc si						;skip the ASM_D32 byte
588
	jmp ab01					;now process the arguments
589

590
aa16:
591
	jmp ab00
592

593
;--- segment prefix
594

595
aa17:
596
	lodsb			;get prefix value
597
	mov [aa_seg_pre],al
598
	mov cl,al
599
	or [asm_mn_flags],AMF_MSEG
600
	pop si			;get position in input line
601
	pop ax			;skip
602
	lodsb
603
	cmp al,':'
604
	jne aa13b
605
	call skipwhite
606
	cmp al,CR
607
	je @F
608
	cmp al,';'
609
	jne aa13b
610
@@:
611
	mov di,offset line_out
612
	mov al,cl
613
	stosb
614
	jmp aa27		;back for more
615

616
;--- LOCK or REP prefix
617

618
aa18:
619
	lodsb			;get prefix value
620
	xchg al,[aa_saved_prefix]
621
	cmp al,0
622
	jnz aa13a		;if there already was a saved prefix
623
	pop si
624
	pop ax
625
	lodsb
626
	cmp al,CR
627
	je @F			;if end of line
628
	cmp al,';'
629
	je @F			;if end of line (comment)
630
	jmp aa02		;back for more
631
@@:
632
	mov al,[aa_saved_prefix]	;just a prefix, nothing else
633
	mov di,offset line_out
634
	stosb
635
	jmp aa27
636

637
;--- Pseudo ops (org or db/dw/dd).
638

639
aa20:
640
	cmp word ptr [aa_saved_prefix],0
641
	jnz aa13a		;if there was a prefix or a segment: error
642
	pop si			;get position in input line
643
	sub al,3		;AX=0 if org, 1 if dd, 2 if dw, 3 if db.
644
	jnz aa20m		;if not ORG
645

646
;--- Process ORG pseudo op.
647

648
	call skipwhite
649
	cmp al,CR
650
	je @F				;if nothing
651
	mov bx,[a_addr+4]	;default segment
652
	jmp aa00a			;go to top
653
@@:
654
	jmp aa01			;get next line
655

656
;--- Data instructions (DB/DW/DD).
657

658
aa20m:
659
	mov di,offset line_out	;put the bytes here when we get them
660
	xchg ax,bx				;mov bx,ax
661
	shl bx,1
662
	mov bp,[bx+aadbsto-2]	;get address of storage routine
663
	call skipwhite
664
	cmp al,CR
665
	je aa27				;if end of line
666

667
aa21:					;<--- loop
668
	cmp al,'"'
669
	je aa22				;if string
670
	cmp al,"'"
671
	je aa22				;if string
672
	call aageti			;get a numerical value into dx:bx, size into cl
673
	cmp cl,cs:[bp-1]	;compare with size
674
	jg aa24				;if overflow
675
	xchg ax,bx
676
	call bp				;store value in AL/AX/DX:AX
677
	cmp di,offset real_end
678
	ja aa24				;if output line overflow
679
	xchg ax,bx
680
	jmp aa26			;done with this one
681

682
aa22:
683
	mov ah,al
684
aa23:
685
	lodsb
686
	cmp al,CR
687
	je aa24			;if end of line
688
	cmp al,ah
689
	je aa25			;if end of string
690
	stosb
691
	cmp di,offset real_end
692
	jbe aa23		;if output line not overflowing
693
aa24:
694
	jmp aa13b		;error
695
aa25:
696
	lodsb
697
aa26:
698
	call skipcomm0
699
	cmp al,CR
700
	jne aa21		;if not end of line
701

702
;--- End of line.  Copy it to debuggee's memory
703

704
aa27:
705
	mov si,offset line_out
706
	mov bx,[a_addr+4]
707
	sizeprfX	;mov edx, [a_addr+0]
708
	mov dx,[a_addr+0]
709
	mov cx,di
710
	sub cx,si
711
	call writeasmn
712
	sizeprfX	;mov [a_addr+0],edx
713
	mov [a_addr+0],dx
714
	jmp aa01
715

716
CONST segment
717
;--- table for routine to store a number ( index dd=1,dw=2,db=3 )
718
aadbsto dw sto_dd,sto_dw,sto_db
719
CONST ends
720

721
;--- Routines to store a byte/word/dword.
722

723
	db 4            ;size to store
724
sto_dd:
725
	stosw			;store a dword value
726
	xchg ax,dx
727
	stosw
728
	xchg ax,dx
729
	ret
730
	db 2            ;size to store
731
sto_dw:
732
	stosw			;store a word value
733
	ret
734
	db 1            ;size to store
735
sto_db:
736
	stosb			;store a byte value
737
	ret
738

739
;   Here we process the AAD and AAM instructions.  They are special
740
;   in that they may take a one-byte argument, or none (in which case
741
;   the argument defaults to 0ah = ten).
742

743
ab00:
744
	mov [mneminfo],si	;save this address
745
	pop si
746
	lodsb
747
	cmp al,CR
748
	je ab00a		;if end of line
749
	cmp al,';'
750
	jne ab01b		;if not end of line
751
ab00a:
752
	mov si,offset aam_args	;fake a 0ah argument
753
	jmp ab01a
754

755
;--- Process normal instructions.
756

757
;   First we parse each argument into a 12-byte data block (OPRND), stored
758
;   consecutively at line_out, line_out+12, etc.
759
;   This is stored in an OPRND struct:
760

761
;   [di+2]: Size argument, if any (1=byte, 2=word, 3=(unused), 4=dword,
762
;           5=qword, 6=float, 7=double, 8=tbyte, 9=short, 10=long, 11=near,
763
;           12=far), see SIZ_xxx and sizetcnam
764
;   [di+3]  Size of MOD R/M displacement
765
;   [di+4]  First register, or MOD R/M byte, or num of additional bytes
766
;   [di+5]  Second register or index register or SIB byte
767
;   [di+6]  Index factor
768
;   [di+7]  Sizes of numbers are or-ed here
769
;   [di+8]  (dword) number
770

771
;   For arguments of the form xxxx:yyyyyyyy, xxxx is stored in <num2>,
772
;   and yyyyyyyy in <num>.  The number of bytes in yyyyyyyy is stored in
773
;   opaddr, 2 is stored in <numadd>, and di is stored in xxaddr.
774

775
OPRND struc
776
flags	db ?	;+0 ARG_xxx Flags (ARG_DEREF, etc.)
777
		db ?	;+1 unused   
778
sizearg	db ?	;+2
779
sizedis	db ?	;+3 Size of MOD R/M displacement
780
union
781
reg1	db ?	;+4 First register, or MOD R/M byte
782
numadd	db ?	;+4 (additional bytes, stored at num2 (up to 4)
783
ends
784
union
785
struct
786
reg2	db ?	;+5 Second register or index register or SIB byte
787
index	db ?	;+6 Index factor
788
ends
789
num2	dw ?	;+5
790
ends
791
orednum	db ?	;+7
792
num		dd ?	;+8
793
OPRND ends
794

795
ab01:
796
	mov [mneminfo],si	;save this address
797
	pop si				;get position in line
798
ab01a:
799
	lodsb
800
ab01b:
801
	mov di,offset line_out
802

803
;--- Begin loop over operands.
804

805
ab02:               ;<--- next operand
806
	cmp al,CR
807
	je ab03			;if end of line
808
	cmp al,';'
809
	jne ab04		;if not end of line
810
ab03:
811
	jmp ab99		;to next phase
812

813
ab04:
814
	push di			;clear out the current OPRND storage area
815
	mov cx,sizeof OPRND / 2
816
	xor ax,ax
817
	rep stosw
818
	pop di
819

820
;--- Small loop over "BYTE PTR" and segment prefixes.
821

822
ab05:
823
	dec si
824
	mov ax,[si]
825
	and ax,TOUPPER_W
826
	cmp [di].OPRND.sizearg,SIZ_NONE
827
	jne ab07		;if already have a size qualifier ("BYTE PTR",...)
828
	push di
829
	mov di,offset sizetcnam
830
	mov cx,sizeof sizetcnam / 2
831
	repne scasw
832
	pop di
833
	jne ab07		;if not found
834
	or cx,cx
835
	jnz @F			;if not 'FA'
836
	mov al,[si+2]
837
	and al,TOUPPER
838
	cmp al,'R'
839
	jne ab09		;if not 'FAR' (could be hexadecimal)
840
@@:
841
	sub cl,sizeof sizetcnam / 2
842
	neg cl			;convert to 1, ..., 12
843
	mov [di].OPRND.sizearg,cl
844
	call skipalpha	;go to next token
845
	mov ah,[si]
846
	and ax,TOUPPER_W
847
	cmp ax,'TP'
848
	jne ab05		;if not 'PTR'
849
	call skipalpha	;go to next token
850
	jmp ab05
851

852
ab07:
853
	cmp [aa_seg_pre],0
854
	jne ab09		;if we already have a segment prefix
855
	push di
856
	mov di,offset segrgnam
857
	mov cx,N_SEGREGS
858
	repne scasw
859
	pop di
860
	jne ab09		;if not found
861
	push si			;save si in case there's no colon
862
	lodsw
863
	call skipwhite
864
	cmp al,':'
865
	jne ab08		;if not followed by ':'
866
	pop ax			;discard saved si
867
	call skipwhite	;skip it
868
	mov bx,offset prefixlist + 5
869
	sub bx,cx
870
	mov al,[bx]		;look up the prefix byte
871
	mov [aa_seg_pre],al	;save it away
872
	jmp ab05
873
ab08:
874
	pop si
875

876
;--- Begin parsing main part of argument.
877

878
;--- first check registers
879

880
ab09:
881
	push di			;check for solo registers
882
	mov di,offset rgnam816
883
	mov cx,N_ALLREGS;8+16bit regs, segment regs, special regs
884
	call aagetreg
885
	pop di
886
	jc ab14			;if not a register
887
	or [di].OPRND.flags, ARG_JUSTREG
888
	mov [di].OPRND.reg1,bl	;save register number
889
	cmp bl,24		;0-23 = AL-DH, AX-DI, EAX-EDI (REG_NO_GPR)
890
	jae @F			;if it's not a normal register
891
	xchg ax,bx		;mov al,bl
892
	mov cl,3
893
	shr al,cl		;al = size:  0 -> byte, 1 -> word, 2 -> dword
894
	add al,-2
895
	adc al,3		;convert to 1, 2, 4 (respectively)
896
	jmp ab13
897
@@:
898
	xor [di].OPRND.flags, ARG_JUSTREG + ARG_WEIRDREG
899
	mov al,SIZ_WORD	;register size
900
	cmp bl,REG_ST
901
	ja ab11			;if it's MM, CR, DR or TR
902
	je @F			;if it's ST
903
	cmp bl,28		;24-27 are ES,CS,SS,DS (segrgnam)
904
	jb ab13			;if it's a normal segment register
905
	or [asm_mn_flags],AMF_FSGS	;flag it
906
	jmp ab13
907
@@:
908
	cmp byte ptr [si],'('
909
	jne ab12		;if just plain ST
910
	lodsb
911
	lodsb
912
	sub al,'0'
913
	cmp al,7
914
	ja ab10			;if not 0..7
915
	mov [di].OPRND.reg2,al	;save the number
916
	lodsb
917
	cmp al,')'
918
	je ab12			;if not error
919
ab10:
920
	jmp aa13b		;error
921

922
;--- other registers 31-34 (MM, CR, DR, TR)
923

924
ab11:
925
	lodsb
926
	sub al,'0'
927
	cmp al,7
928
	ja ab10			;if error
929
	mov [di].OPRND.reg2,al	;save the number
930
	mov al,SIZ_DWORD;register size
931
	cmp bl,REG_MM
932
	jne ab13		;if not MM register
933
	or [di].OPRND.flags, ARG_JUSTREG
934
	mov al,SIZ_QWORD
935
	jmp ab13
936
ab12:
937
	mov al,0		;size for ST regs
938
ab13:
939
	cmp al,[di].OPRND.sizearg	;compare with stated size
940
	je @F			;if same
941
	xchg al,[di].OPRND.sizearg
942
	cmp al,0
943
	jne ab10		;if wrong size given - error
944
@@:
945
	jmp ab44		;done with this operand
946

947
;--- It's not a register reference.  Try for a number.
948

949
ab14:
950
	lodsb
951
	call aaifnum
952
	jc ab17			;it's not a number
953
	call aageti		;get the number
954
	mov [di].OPRND.orednum,cl
955
	mov word ptr [di].OPRND.num+0,bx
956
	mov word ptr [di].OPRND.num+2,dx
957
	call skipwh0
958
	cmp cl,2
959
	jg ab17			;if we can't have a colon here
960
	cmp al,':'
961
	jne ab17		;if not xxxx:yyyy
962
if 1	;v2.50: size for ssss:oooo must be none or far
963
	cmp [di].OPRND.sizearg, SIZ_NONE
964
	jz @F
965
	cmp [di].OPRND.sizearg, SIZ_FAR
966
	jnz ab24
967
@@:
968
endif
969
	call skipwhite
970
	call aageti
971
	mov cx,word ptr [di].OPRND.num+0
972
	mov [di].OPRND.num2,cx
973
	mov word ptr [di].OPRND.num+0,bx
974
	mov word ptr [di].OPRND.num+2,dx
975
	or [di].OPRND.flags, ARG_FARADDR
976
	jmp ab43		;done with this operand
977

978
;--- Check for [...].
979

980
ab15:
981
	jmp ab30		;do post-processing
982

983
ab16:
984
	call skipwhite
985
ab17:
986
	cmp al,'['		;begin loop over sets of []
987
	jne ab15		;if not [
988
	or [di].OPRND.flags, ARG_DEREF ;set the flag
989
ab18:
990
	call skipwhite
991
ab19:
992
	cmp al,']'		;begin loop within []
993
	je ab16			;if done
994

995
;--- Check for a register (within []).
996

997
	dec si
998
	push di
999
	mov di,offset rgnam16
1000
	mov cx,N_REGS16
1001
	call aagetreg
1002
	pop di
1003
	jc ab25			;if not a register
1004
	cmp bl,16
1005
	jae @F			;if 32-bit register
1006
	add bl,8		;adjust 0..7 to 8..15
1007
	jmp ab21
1008
@@:
1009
	cmp [di].OPRND.reg2, 0
1010
	jnz ab21		;if we already have an index
1011
	call skipwhite
1012
	dec si
1013
	cmp al,'*'
1014
	jne ab21		;if not followed by '*'
1015
	inc si
1016
	mov [di].OPRND.reg2,bl	;save index register
1017
	call skipwhite
1018
	call aageti
1019
	call aaconvindex
1020
	jmp ab28		;ready for next part
1021

1022
ab21:
1023
	cmp [di].OPRND.reg1,0
1024
	jne @F			;if there's already a register
1025
	mov [di].OPRND.reg1,bl
1026
	jmp ab23
1027
@@:
1028
	cmp [di].OPRND.reg2, 0
1029
	jne ab24		;if too many registers
1030
	mov [di].OPRND.reg2,bl
1031
ab23:
1032
	call skipwhite
1033
	jmp ab28		;ready for next part
1034
ab24:
1035
	jmp aa13b		;error
1036

1037
;--- Try for a number (within []).
1038

1039
ab25:
1040
	lodsb
1041
ab26:
1042
	call aageti		;get a number (or flag an error)
1043
	call skipwh0
1044
	cmp al,'*'
1045
	je ab27			;if it's an index factor
1046
	or [di].OPRND.orednum,cl
1047
	add word ptr [di].OPRND.num+0,bx
1048
	adc word ptr [di].OPRND.num+2,dx
1049
	jmp ab28		;next part ...
1050

1051
ab27:
1052
	call aaconvindex
1053
	call skipwhite
1054
	dec si
1055
	push di
1056
	mov di,offset rgnam16
1057
	xor cx,cx
1058
	call aagetreg
1059
	pop di
1060
	jc ab24			;if error
1061
	cmp [di].OPRND.reg2, 0
1062
	jne ab24		;if there is already a register
1063
	mov [di].OPRND.reg2, bl
1064
	call skipwhite
1065

1066
;--- Ready for the next term within [].
1067

1068
ab28:
1069
	cmp al,'-'
1070
	je ab26			;if a (negative) number is next
1071
	cmp al,'+'
1072
	jne @F			;if no next term (presumably)
1073
	jmp ab18
1074
@@:
1075
	jmp ab19		;back for more
1076

1077
;--- Post-processing for complicated arguments.
1078

1079
ab30:
1080
	cmp word ptr [di].OPRND.reg1,0	;check both reg1+reg2
1081
	jnz ab32		;if registers were given ( ==> create MOD R/M)
1082
	cmp [di].OPRND.orednum,0
1083
	jz ab31			;if nothing was given ( ==> error)
1084
	cmp [di].OPRND.flags,0
1085
	jnz ab30b		;if it was not immediate
1086
	or [di].OPRND.flags,ARG_IMMED
1087
ab30a:
1088
	jmp ab43		;done with this argument
1089
ab30b:
1090
	or [asm_mn_flags],AMF_ADDR
1091
	mov al,2		;size of the displacement
1092
	test [di].OPRND.orednum,4
1093
	jz @F			;if not 32-bit displacement
1094
	inc ax
1095
	inc ax
1096
	or [asm_mn_flags],AMF_A32	;32-bit addressing
1097
@@:
1098
	mov [di].OPRND.sizedis,al	;save displacement size
1099
	jmp ab30a		;done with this argument
1100
ab31:
1101
	jmp aa13b		;flag an error
1102

1103
;   Create the MOD R/M byte.
1104
;   (For disp-only or register, this will be done later as needed.)
1105

1106
ab32:
1107
	or [di].OPRND.flags, ARG_MODRM
1108
	mov al,[di].OPRND.reg1
1109
	or al,[di].OPRND.reg2
1110
	test al,16
1111
	jnz ab34		;if 32-bit addressing
1112
	test [di].OPRND.orednum,4
1113
	jnz ab34		;if 32-bit addressing
1114
;	or [asm_mn_flags], AMF_ADDR | AMF_A32
1115
	or [asm_mn_flags], AMF_ADDR
1116
	mov ax,word ptr [di].OPRND.reg1	;get reg1+reg2
1117
	cmp al,ah
1118
	ja @F			;make sure al >= ah
1119
	xchg al,ah
1120
@@:
1121
	push di
1122
	mov di,offset modrmtab
1123
	mov cx,8
1124
	repne scasw
1125
	pop di
1126
	jne ab31		;if not among the possibilities
1127
	mov bx,206h		;max disp = 2 bytes; 6 ==> (non-existent) [bp]
1128
	jmp ab39		;done (just about)
1129

1130
;--- 32-bit addressing
1131

1132
ab34:
1133
	or [asm_mn_flags],AMF_A32 + AMF_ADDR
1134
	mov al,[di].OPRND.reg1
1135
	or al,[di].OPRND.index
1136
	jnz @F			;if we can't optimize [EXX*1] to [EXX]
1137
	mov ax,word ptr [di].OPRND.reg1	;get reg1+reg2
1138
	xchg al,ah
1139
	mov word ptr [di].OPRND.reg1,ax
1140
@@:
1141
	mov bx,405h		;max disp = 4 bytes; 5 ==> (non-existent) [bp]
1142
	cmp [di].OPRND.reg2,0
1143
	jne @F			;if there's a SIB
1144
	mov cl,[di].OPRND.reg1
1145
	cmp cl,16
1146
	jl ab31			;if wrong register type
1147
	and cl,7
1148
	cmp cl,4		;check for ESP
1149
	jne ab39		;if not, then we're done (otherwise do SIB)
1150
@@:
1151
	or [asm_mn_flags],AMF_SIB	;form SIB
1152
	mov ch,[di].OPRND.index		;get SS bits
1153
	mov cl,3
1154
	shl ch,cl				;shift them halfway into place
1155
	mov al,[di].OPRND.reg2	;index register
1156
	cmp al,20
1157
	je ab31			;if ESP ( ==> error)
1158
	cmp al,0
1159
	jne @F			;if not zero
1160
	mov al,20		;set it for index byte 4
1161
@@:
1162
	cmp al,16
1163
	jl ab31			;if wrong register type
1164
	and al,7
1165
	or ch,al		;put it into the SIB
1166
	shl ch,cl		;shift it into place
1167
	inc cx			;R/M for SIB = 4
1168
	mov al,[di].OPRND.reg1	;now get the low 3 bits
1169
	cmp al,0
1170
	jne @F			;if there was a first register
1171
	or ch,5
1172
	jmp ab42		;MOD = 0, disp is 4 bytes
1173
@@:
1174
	cmp al,16
1175
	jl ab45			;if wrong register type
1176
	and al,7		;first register
1177
	or ch,al		;put it into the SIB
1178
	cmp al,5
1179
	je ab40			;if it's EBP, then we don't recognize disp=0
1180
					;otherwise bl will be set to 0
1181

1182
;--- Find the size of the displacement.
1183

1184
ab39:
1185
	cmp cl,bl
1186
	je ab40			;if it's [(E)BP], then disp=0 is still 1 byte
1187
	mov bl,0		;allow 0-byte disp
1188

1189
ab40:
1190
	push cx
1191
	mov al,byte ptr [di].OPRND.num+0
1192
	mov cl,7
1193
	sar al,cl
1194
	pop cx
1195
	mov ah,byte ptr [di].OPRND.num+1
1196
	cmp al,ah
1197
	jne @F			;if it's bigger than 1 byte
1198
	cmp ax,word ptr [di].OPRND.num+2
1199
	jne @F			;ditto
1200
	mov bh,0		;no displacement
1201
	or bl,byte ptr [di].OPRND.num+0
1202
	jz ab42			;if disp = 0 and it's not (E)BP
1203
	inc bh			;disp = 1 byte
1204
	or cl,40h		;set MOD = 1
1205
	jmp ab42		;done
1206
@@:
1207
	or cl,80h		;set MOD = 2
1208
ab42:
1209
	mov [di].OPRND.sizedis,bh	;store displacement size
1210
	mov word ptr [di].OPRND.reg1, cx	;store MOD R/M and maybe SIB
1211

1212
;--- Finish up with the operand.
1213

1214
ab43:
1215
	dec si
1216
ab44:
1217
	call skipwhite
1218
	add di,sizeof OPRND
1219
	cmp al,CR
1220
	je ab99			;if end of line
1221
	cmp al,';'
1222
	je ab99			;if comment (ditto)
1223
	cmp al,','
1224
	jne ab45		;if not comma ( ==> error)
1225
	cmp di,offset line_out+ 3 * sizeof OPRND
1226
	jae ab45		;if too many operands
1227
	call skipwhite
1228
	jmp ab02
1229

1230
ab45:
1231
	jmp aa13b		;error jump
1232

1233
ab99:
1234
	mov [di].OPRND.flags,-1;end of parsing phase
1235
	push si			;save the location of the end of the string
1236

1237
;   For the next phase, we match the parsed arguments with the set of
1238
;   permissible argument lists for the opcode.  The first match wins.
1239
;   Therefore the argument lists should be ordered such that the
1240
;   cheaper ones come first.
1241

1242
;   There is a tricky issue regarding sizes of memory references.
1243
;   Here are the rules:
1244
;      1.   If a memory reference is given with a size, then it's OK.
1245
;      2.   If a memory reference is given without a size, but some
1246
;       other argument is a register (which implies a size),
1247
;       then the memory reference inherits that size.
1248
;           Exceptions: OP_CL does not imply a size
1249
;                   OP_SHOSIZ
1250
;      3.   If 1 and 2 do not apply, but this is the last possible argument
1251
;       list, and if the argument list requires a particular size, then
1252
;       that size is used.
1253
;      4.   In all other cases, flag an error.
1254

1255
ac01:				;<--- next possible argument list
1256
	xor ax,ax
1257
	mov di,offset ai
1258
	mov cx,sizeof ai/2
1259
	rep stosw
1260
	mov si,[mneminfo]	;address of the argument variant
1261

1262
;--- Sort out initial bytes.  At this point:
1263
;--- si = address of argument variant
1264

1265
ac02:               ;<--- next byte of argument variant
1266
	lodsb
1267
	sub al,ASM_MACH0
1268
	jb ac05			;if no more special bytes
1269
	cmp al,ASM_LOCKABLE - ASM_MACH0
1270
	je @F			;if ASM_LOCKABLE
1271
	ja ac04			;if ASM_END ( ==> error)
1272
	mov [ai.dismach],al;save machine type
1273
	jmp ac02		;back for next byte
1274
@@:
1275
	or [ai.varflags],VAR_LOCKABLE
1276
	jmp ac02		;back for next byte
1277

1278
ac04:
1279
	jmp aa13a		;error
1280

1281
;--- Get and unpack the word.
1282

1283
ac05:
1284
	dec si
1285
	lodsw
1286
	xchg al,ah			;put into little-endian order
1287
	xor dx,dx
1288
	mov bx,ASMMOD
1289
	div bx				;ax = a_opcode; dx = index into opindex
1290
	mov [a_opcode],ax	;save ax
1291
	mov [a_opcode2],ax	;save the second copy
1292
	cmp ax,0dfh
1293
	ja @F				;if not coprocessor instruction
1294
	cmp al,0d8h
1295
	jb @F				;ditto
1296
	or [ai.dmflags],DM_COPR;flag it as an x87 instruction
1297
	mov ah,al			;ah = low order byte of opcode
1298
	lodsb				;get extra byte
1299
	mov [ai.regmem],al		;save it in regmem
1300
	mov [a_opcode2],ax	;save this for obsolete-instruction detection
1301
	or [ai.varflags],VAR_MODRM	;flag its presence
1302
@@:
1303
	mov [mneminfo],si	;save si back again
1304
	mov si,dx
1305
	@dprintf "ac05: opindex=%X", si
1306
	mov ax,word ptr [opindex+si]
1307
	mov bl,al
1308
	mov [bEndOplItem], ah	; end of oplist item
1309

1310
	lea si,[oplists+bx]		;si = the address of our operand list
1311
	mov di,offset line_out	;di = array of OPRNDs
1312

1313
;--- Begin loop over operands.
1314

1315
ac06:               ;<--- next operand
1316
	mov ax, si
1317
	sub ax, offset oplists
1318
	cmp al, [bEndOplItem]
1319
	jae ac10
1320
	lodsb			;get next operand byte
1321
;	cmp al,0
1322
;	je ac10			;if end of list
1323
	cmp [di].OPRND.flags,-1
1324
	je ac01			;if too few operands were given
1325
	cmp al,OP_SIZE
1326
	jb @F			;if no size needed
1327
;	mov ah,0
1328
;	mov cl,4
1329
;	shl ax,cl		;move bits 4-7 (size) to ah (OP_1632=5,OP_8=6,OP_16=7,...)
1330
;	shr al,cl		;move bits 0-3 back
1331
	db 0d4h,10h		;=aam 10h (AX=00XY -> AX=0X0Y)
1332
	mov [ai.reqsize],ah	;save size away
1333
	@dprintf "ac08: di=%X size requested, AH in AX=%X", di, ax
1334
	jmp ac08
1335
@@:					;AL = OP_M64 - ...
1336
	add al,ASM_OPOFF - OP_M64	;adjust for the start entries im asm_jmp1
1337
ac08:
1338
	cbw
1339
	xchg ax,bx		;now bx contains the offset
1340
	mov cx,[asm_jmp1+bx] ;subroutine address
1341
	shr bx,1
1342
	mov al,[bittab+bx]
1343
	@dprintf "ac08: di=%X si=%X, offset=%X, func=%X, al=%X", di, si, bx, cx, ax
1344
	test al,[di].OPRND.flags
1345
	jz ac09			;if no required bits are present
1346
	call cx			;call its specific routine
1347
	cmp word ptr [si-1], (OP_1632 + OP_R) * 256 + (OP_1632 + OP_R_MOD)
1348
	je ac06			;(hack) for IMUL instruction
1349
	add di,sizeof OPRND	;next operand
1350
	jmp ac06		;back for more
1351

1352
ac09:
1353
	jmp ac01		;back to next possibility
1354

1355
;--- End of operand list.
1356

1357
ac10:
1358
	cmp [di].OPRND.flags,-1
1359
	jne ac09		;if too many operands were given
1360

1361
;--- Final check on sizes
1362

1363
	mov al,[ai.varflags]
1364
	test al,VAR_SIZ_NEED
1365
	jz ac12			;if no size needed
1366
	test al,VAR_SIZ_GIVN
1367
	jnz ac12		;if a size was given
1368
	test al,VAR_SIZ_FORCD
1369
	jz ac09			;if the size was not forced ( ==> reject)
1370
	mov si,[mneminfo]
1371
	cmp byte ptr [si],ASM_END
1372
	je ac12			;if this is the last one
1373
ac11:
1374
	jmp aa13a		;it was not ==> error (not a retry)
1375

1376
;--- Check other prefixes.
1377

1378
ac12:
1379
	mov al,[aa_saved_prefix]
1380
	cmp al,0
1381
	jz ac14			;if no saved prefixes to check
1382
	cmp al,0f0h
1383
	jne @F			;if it's a rep prefix
1384
	test [ai.varflags],VAR_LOCKABLE
1385
	jz ac11			;if this variant is not lockable - error
1386
	jmp ac14		;done
1387
@@:
1388
	mov ax,[a_opcode]	;check if opcode is OK for rep{,z,nz}
1389
	and al,not 1		;clear low order bit (MOVSW -> MOVSB)
1390
	cmp ax,0ffh
1391
	ja ac11				;if it's not a 1 byte instruction - error
1392
	mov di,offset replist	;list of instructions that go with rep
1393
	mov cx,N_REPALL			;scan all (REP + REPxx)
1394
	repne scasb
1395
	jnz ac11			;if it's not among them - error
1396

1397
ac14:
1398
	test [asm_mn_flags],AMF_MSEG
1399
	jz @F				;if no segment prefix before mnemonic
1400
	mov ax,[a_opcode]	;check if opcode allows this
1401
	cmp ax,0ffh
1402
	ja ac11				;if it's not a 1 byte instruction - error
1403
	mov di,offset prfxtab
1404
	mov cx,N_PRFXTAB
1405
	repne scasb
1406
	jnz ac11			;if it's not in the list - error
1407
@@:
1408
	mov bx,[ai.immaddr]
1409
	or bx,bx
1410
	jz ac16			;if no immediate data
1411
	mov al,[ai.opsize]
1412
	neg al
1413
	shl al,1
1414
	test al,[bx+7]
1415
	jnz ac11		;if the immediate data was too big - error
1416

1417
;   Put the instruction together
1418
;   (maybe is this why they call it an assembler)
1419

1420
;   First, the prefixes (including preceding WAIT instruction)
1421

1422
ac16:
1423
	sizeprfX	;mov edx,[a_addr]
1424
	mov dx,[a_addr+0]
1425
	mov bx,[a_addr+4]
1426
	test [asm_mn_flags],AMF_WAIT
1427
	jz @F			;if no wait instruction beforehand
1428
	mov al,9bh
1429
	call writeasm
1430
@@:
1431
	mov al,[aa_saved_prefix]
1432
	cmp al,0
1433
	jz @F			;if no LOCK or REP prefix
1434
	call writeasm
1435
@@:
1436

1437
;--- a 67h address size prefix is needed
1438
;--- 1. for CS32: if AMF_ADDR=1 and AMF_A32=1
1439
;--- 2. for CS16: if AMF_ADDR=1 and AMF_A32=0
1440

1441
	mov al,[asm_mn_flags]
1442
	test al,AMF_ADDR
1443
	jz @F
1444
	and al,AMF_A32
1445
if ?PM
1446
	mov ah,[bCSAttr]
1447
	and ah,40h
1448
	or al,ah
1449
endif
1450
	and al,AMF_A32 + 40h
1451
	jz @F
1452
	cmp al,AMF_A32 + 40h
1453
	jz @F
1454
	@dprintf "ac20: 67h prefix"
1455
	mov al,67h
1456
	call writeasm
1457
@@:
1458

1459
;--- a 66h data size prefix is needed
1460
;--- for CS16: if VAR_D32 == 1 or AMF_D32 == 1
1461
;--- for CS32: if VAR_D16 == 1 or AMF_D16 == 1
1462

1463
	mov ah,[asm_mn_flags]
1464
	mov al,[ai.varflags]
1465
if ?PM
1466
	test [bCSAttr],40h
1467
	jz @F
1468
	test al, VAR_D16
1469
	jnz ac20_1
1470
	test ah, AMF_D16
1471
	jnz ac20_1
1472
	jmp ac21
1473
@@:
1474
endif
1475
	test al,VAR_D32
1476
	jnz ac20_1
1477
	test ah,AMF_D32
1478
	jz ac21
1479
ac20_1:
1480
	@dprintf "ac20: 66h prefix"
1481
	mov al,66h
1482
	call writeasm		;store operand-size prefix
1483
ac21:
1484
	mov al,[aa_seg_pre]
1485
	cmp al,0
1486
	jz @F			;if no segment prefix
1487
	call writeasm
1488
	cmp al,64h
1489
	jb @F			;if not 64 or 65 (FS or GS)
1490
	or [asm_mn_flags],AMF_FSGS	;flag it
1491
@@:
1492

1493
;--- Now emit the instruction itself.
1494

1495
	mov ax,[a_opcode]
1496
	mov di,ax
1497
	sub di,240h
1498
	jae @F			;if 576-...
1499
	cmp ax,200h
1500
	jb ac24			;if regular instruction
1501
	or [ai.dmflags],DM_COPR	;flag it as an x87 instruction
1502
	and al,038h		;get register part
1503
	@dprintf "ac21: fpu instr (>200h), update ai.regmem with AL=%X", ax
1504
	or [ai.regmem],al
1505
	xchg ax,di		;mov ax,di (the low bits of di are good)
1506
	and al,7
1507
	or al,0d8h
1508
	jmp ac25		;on to decoding the instruction
1509
@@:
1510
	mov cl,3		;one instruction of a group
1511
	shr di,cl
1512
	and al,7
1513
	shl al,cl
1514
	@dprintf "ac21: grp-instr (%X), update ai.regmem with AL=%X", a_opcode, ax
1515
	or [ai.regmem],al
1516
	shl di,1
1517
	mov ax,[agroups+di]	;get actual opcode
1518

1519
ac24:
1520
	cmp ah,0
1521
	jz ac25			;if no 0fh first
1522
	push ax			;store a 0fh
1523
	@dprintf "ac24: 0F prefix"
1524
	mov al,0fh
1525
	call writeasm
1526
	pop ax
1527

1528
ac25:
1529
	@dprintf "ac25: instruction byte: %X", ax
1530
	or al,[ai.opcode_or]	;put additional bits into the op code
1531
	call writeasm		;store the op code itself
1532

1533
;--- Now store the extra stuff that comes with the instruction.
1534

1535
	mov ax,word ptr [ai.regmem]
1536
	test [ai.varflags],VAR_MODRM
1537
	jz @F			;if no mod reg/mem
1538
	@dprintf "ac25: modrm %X (ai.regmem)", ax
1539
	push ax
1540
	call writeasm
1541
	pop ax
1542
	test [asm_mn_flags],AMF_SIB
1543
	jz @F			;if no SIB
1544
	mov al,ah
1545
	@dprintf "ac25: sib in AL %X", ax
1546
	call writeasm	;store the MOD R/M and SIB, too
1547
@@:
1548

1549
	mov di,[ai.rmaddr]
1550
	or di,di
1551
	jz @F			;if no offset associated with the R/M
1552
	mov cl,[di].OPRND.sizedis
1553
	mov ch,0
1554
	lea si,[di].OPRND.num	;store the R/M offset (or memory offset)
1555
	@dprintf "ac25: mem offs, size=%X ofs=%X", cx, word ptr [di].OPRND.num
1556
	call writeasmn
1557
@@:
1558

1559
;--- Now store immediate data
1560

1561
	mov di,[ai.immaddr]
1562
	or di,di
1563
	jz @F			;if no immediate data
1564
	mov al,[ai.opsize]
1565
	cbw
1566
	xchg ax,cx		;mov cx,ax
1567
	@dprintf "ac25: imm data, size=%X data=%X", cx, word ptr [di].OPRND.num
1568
	lea si,[di].OPRND.num
1569
	call writeasmn
1570
@@:
1571

1572
;--- Now store additional bytes (needed for, e.g., enter instruction)
1573
;--- also for FAR memory address
1574

1575
	mov di,[ai.xxaddr]
1576
	or di,di
1577
	jz @F			;if no additional data
1578
	lea si,[di].OPRND.numadd	;number of bytes (2 for FAR, size of segment)
1579
	lodsb
1580
	cbw
1581
	xchg ax,cx		;mov cx,ax
1582
	@dprintf "ac25: additional data=%X", cx
1583
	call writeasmn
1584
@@:
1585

1586
;--- Done emitting. Update asm address offset.
1587

1588
	sizeprfX	;mov [a_addr],edx
1589
	mov [a_addr],dx
1590

1591
;--- Compute machine type.
1592

1593
	cmp [ai.dismach],3
1594
	jae ac31		;if we already know a 386 is needed
1595
	test [asm_mn_flags], AMF_D32 or AMF_A32 or AMF_FSGS
1596
	jnz ac30		;if 386
1597
	test [ai.varflags],VAR_D32
1598
	jz ac31			;if not 386
1599
ac30:
1600
	mov [ai.dismach],3
1601
ac31:
1602
	mov di,offset a_obstab	;obsolete instruction table
1603
	mov cx,[a_opcode2]
1604
	call showmach		;get machine message into si, length into cx
1605
	jcxz ac33			;if no message
1606

1607
ac32:
1608
	mov di,offset line_out
1609
	rep movsb		;copy the line to line_out
1610
	call putsline
1611

1612
ac33:
1613
	jmp aa01		;back for the next input line
1614

1615
if 0
1616
;--- This is debugging code.  It assumes that the original value
1617
;--- of a_addr is on the top of the stack.
1618

1619
	pop si		;get orig. a_addr
1620
	mov ax,[a_addr+4]
1621
	mov [u_addr+0],si
1622
	mov [u_addr+4],ax
1623
	mov bx,[a_addr]
1624
	sub bx,si
1625
	mov di,offset line_out
1626
	mov cx,10
1627
	mov al,' '
1628
	rep stosb
1629
	mov ds,[a_addr+4]
1630
@@:
1631
	lodsb
1632
	call hexbyte	;display the bytes generated
1633
	dec bx
1634
	jnz @B
1635
	push ss
1636
	pop ds
1637
	call putsline
1638
	call disasm1	;disassemble the new instruction
1639
	jmp aa01		;back to next input line
1640
endif
1641

1642
CONST segment
1643

1644
	align 2
1645

1646
;--- Jump table for operand types.
1647
;--- order of entries in asm_jmp1 must match 
1648
;--- the one in dis_jmp1 / dis_optab.
1649

1650
asm_jmp1 label word
1651
	dw aop_imm, aop_rm, aop_m, aop_r_mod	;OP_IMM, OP_RM, OP_M, OP_R_MOD
1652
	dw aop_moffs, aop_r, aop_r_add, aop_ax	;OP_MOFFS, OP_R, OP_R_ADD, OP_AX
1653
ASM_OPOFF equ $ - asm_jmp1
1654

1655
;--- order must match the one in dis_optab
1656
	dw ao17, ao17, ao17		;OP_M64, OP_MFLOAT, OP_MDOUBLE
1657
	dw ao17, ao17, ao17		;OP_M80, OP_MXX, OP_FARMEM
1658
	dw aop_farimm, aop_rel8, aop_rel1632;OP_FARIMM, OP_REL8, OP_REL1632
1659
	dw ao29, aop_sti, aop_cr	;OP_1CHK, OP_STI, OP_CR
1660
	dw ao34, ao35, ao39		;OP_DR, OP_TR, OP_SEGREG
1661
	dw ao41, ao42, aop_mmx	;OP_IMMS8, OP_IMM8, OP_MMX
1662
	dw ao44, ao46, ao47		;OP_SHOSIZ, OP_1, OP_3
1663
	dw ao48, ao48, ao48		;OP_DX, OP_CL, OP_ST
1664
	dw ao48, ao48, ao48		;OP_CS, OP_DS, OP_ES
1665
	dw ao48, ao48, ao48		;OP_FS, OP_GS, OP_SS
1666

1667
CONST ends
1668

1669
;   Routines to check for specific operand types.
1670
;   Upon success, the routine returns.
1671
;   Upon failure, it pops the return address and jumps to ac01.
1672
;   The routines must preserve si and di.
1673

1674
;--- OP_RM, OP_M, OP_R_MOD:  form MOD R/M byte.
1675

1676
aop_rm:
1677
aop_m:
1678
aop_r_mod:
1679
	call ao90		;form reg/mem byte
1680
	jmp ao07		;go to the size check
1681

1682
;--- OP_R:  register.
1683

1684
aop_r:
1685
	mov al,[di].OPRND.reg1	;register number
1686
	and al,7
1687
	mov cl,3
1688
	shl al,cl		;shift it into place
1689
	or [ai.regmem],al	;put it into the reg/mem byte
1690
	jmp ao07		;go to the size check
1691

1692
;--- OP_R_ADD:  register, added to the instruction.
1693

1694
aop_r_add:
1695
	mov al,[di].OPRND.reg1
1696
	and al,7
1697
	mov [ai.opcode_or],al	;put it there
1698
	jmp ao07		;go to the size check
1699

1700
;--- OP_IMM:  immediate data.
1701

1702
aop_imm:
1703
	mov [ai.immaddr],di	;save the location of this
1704
	jmp ao07		;go to the size check
1705

1706
;--- OP_MOFFS:  just the memory offset
1707

1708
aop_moffs:
1709
	test [di].OPRND.flags,ARG_MODRM
1710
	jnz ao11		;if MOD R/M byte ( ==> reject)
1711
	mov [ai.rmaddr],di	;save the operand pointer
1712
	jmp ao07		;go to the size check
1713

1714
;--- OP_AX:  check for AL/AX/EAX
1715

1716
aop_ax:
1717
	test [di].OPRND.reg1,7
1718
	jnz ao11		;if wrong register
1719
	;jmp ao07		;go to the size check
1720

1721
;--- Size check
1722

1723
ao07:               ;<--- entry for OP_RM, OP_M, OP_R_MOD, OP_R, OP_R_ADD...
1724
	or [ai.varflags],VAR_SIZ_NEED
1725
	@dprintf "ao07: size check, reqsizeB=%X, sizeargB=%X", word ptr ai.reqsize, word ptr [di].OPRND.sizearg
1726
	mov al,[ai.reqsize]	;4 OP_ALL, 5 OP_1632, 6 OP_8, 7 OP_16, 8 OP_32, 9 OP_64
1727
	sub al,5
1728
	jl ao12			;if OP_ALL
1729
	jz ao13			;if OP_1632
1730
;--- OP_8=1, OP_16=2, OP_32=3, OP_64=4
1731
	add al,-3
1732
	adc al,3		;convert 3 --> 4 and 4 --> 5
1733

1734
ao08:               ;<--- entry for OP_M64 ... OP_FARMEM
1735
	or [ai.varflags],VAR_SIZ_FORCD + VAR_SIZ_NEED
1736
ao08_1:
1737
	mov bl,[di].OPRND.sizearg
1738
	@dprintf "ao08_1: BL=%X AL=%X ai.opsize=%X", bx, ax, word ptr ai.opsize
1739
	or bl,bl
1740
	jz @F			;if no size given
1741
	or [ai.varflags],VAR_SIZ_GIVN
1742
	cmp al,bl
1743
	jne ao11		;if sizes conflict
1744
@@:
1745
	cmp al,[ai.opsize]
1746
	je @F			;if sizes agree
1747
	xchg al,[ai.opsize]
1748
	cmp al,0
1749
	jnz ao11		;if sizes disagree
1750
;--- v2.50: the next line caused - as a side effect - a regression for "call [xxxx]"
1751
;--- which has been fixed at ao13.
1752
	or [ai.varflags],VAR_SIZ_GIVN	;v1.18 added!!!
1753
@@:
1754
	ret
1755

1756
ao11:
1757
	jmp ao50		;reject
1758

1759
;--- OP_ALL - Allow all sizes.
1760

1761
ao12:
1762
	mov al,[di].OPRND.sizearg
1763
	cmp al,SIZ_BYTE
1764
	je ao15			;if byte
1765
	jb ao14			;if unknown
1766
	or [ai.opcode_or],1;set bit in instruction
1767
	jmp ao14		;if size is 16 or 32
1768

1769
ao13:				;<--- OP_1632 - word or dword.
1770
	mov al,[di].OPRND.sizearg
1771
	@dprintf "ao13: OP_1632, AL=sizearg=%X, dx=%X", ax, dx
1772
if 1	;v2.50: set default size for call/jmp/push [mem] (hackish fix)
1773
	cmp al,SIZ_NONE
1774
	jnz @F
1775
	cmp dx, 40		;just opindex 40 ( call/jmp/push [memref] )   
1776
	jnz @F
1777
	mov al,SIZ_WORD
1778
 if ?PM
1779
	test [bCSAttr],40h
1780
	jz @F
1781
	mov al,SIZ_DWORD
1782
 endif
1783
@@:
1784
endif
1785
ao14:
1786
	cmp al,SIZ_NONE
1787
	je ao16			;if still unknown
1788
	cmp al,SIZ_WORD
1789
	jne @F			;if word
1790
	or [ai.varflags],VAR_D16
1791
	jmp ao15
1792
@@:
1793
	cmp al,SIZ_DWORD
1794
	jne ao11		;if not dword
1795
	or [ai.varflags],VAR_D32
1796
ao15:
1797
	mov [ai.opsize],al
1798
	or [ai.varflags],VAR_SIZ_GIVN
1799
ao16:
1800
	ret
1801

1802
;   OP_M64 - 64-bit memory reference.
1803
;   OP_MFLOAT - single-precision floating point memory reference.
1804
;   OP_MDOUBLE - double-precision floating point memory reference.
1805
;   OP_M80 - 80-bit memory reference.
1806
;   OP_MXX - memory reference, size unknown.
1807
;   OP_FARMEM - far memory pointer
1808

1809
;--- bx contains byte index for bittab
1810
ao17:
1811
	call ao90		;form reg/mem byte
1812
	mov al,[asm_siznum + bx - ASM_OPOFF/2]
1813
	@dprintf "ao17: bx=%X al=%X ai.opsiz=%X [di].sizearg=%X", bx, ax, word ptr ai.opsize, word ptr [di].OPRND.sizearg
1814
	jmp ao08		;check size
1815

1816
;--- OP_FARIMM - far address contained in instruction
1817

1818
aop_farimm:
1819
if ?PM
1820
	test [bCSAttr],40h
1821
	jnz @F
1822
endif
1823
	mov al,2
1824
	cmp word ptr [di].OPRND.num+2,0
1825
	jz ao22			;if 16 bit address
1826
@@:
1827
	or [ai.varflags],VAR_D32
1828
	mov al,4
1829
ao22:
1830
	mov [di].OPRND.numadd,2	;2 additional bytes (segment part)
1831
	mov [ai.immaddr],di
1832
	mov [ai.opsize],al			;2/4, size of offset
1833
ao22_1:
1834
	mov [ai.xxaddr],di
1835
	ret
1836

1837
;--- OP_REL8 - relative address
1838
;--- Jcc, LOOPx, JxCXZ
1839

1840
aop_rel8:
1841
	mov al,SIZ_SHORT
1842
	call aasizchk	;check the size
1843
	mov cx,2		;size of instruction
1844
	mov al,[asm_mn_flags]
1845

1846
	test al,AMF_D32 or AMF_D16
1847
	jz ao23_1		;if not JxCXZ, LOOPx
1848
	test al,AMF_D32
1849
	jz @F
1850
	or al,AMF_A32	; JxCXZ and LOOPx need a 67h, not a 66h prefix
1851
@@:
1852
	and al,not (AMF_D32 or AMF_D16)
1853
	or al, AMF_ADDR
1854
	mov [asm_mn_flags],al
1855
if ?PM
1856
	mov ah,[bCSAttr]
1857
	and ah,40h
1858
else
1859
	mov ah,0
1860
endif
1861
	and al,AMF_A32
1862
	or al,ah
1863
	jz ao23_1
1864
	cmp al,AMF_A32+40h
1865
	jz ao23_1
1866
	inc cx        ;instruction size = 3
1867
ao23_1:
1868
	mov bx,[a_addr+0]
1869
	add bx,cx
1870
	mov cx,[a_addr+2];v1.22: handle HiWord(EIP) properly
1871
	adc cx,0
1872
	mov ax,word ptr [di].OPRND.num+0
1873
	mov dx,word ptr [di].OPRND.num+2
1874
;--- CX:BX holds E/IP (=src), DX:AX holds dst
1875
	sub ax,bx
1876
	sbb dx,cx
1877
	mov byte ptr [di].OPRND.num2,al
1878
	mov cl,7        ;range must be ffffff80 <= x <= 0000007f
1879
	sar al,cl       ;1xxxxxxxb -> FF, 0xxxxxxxb -> 00
1880
	cmp al,ah
1881
	jne ao_err1		;if too big
1882
	cmp ax,dx
1883
	jne ao_err1		;if too big
1884
	mov [di].OPRND.numadd,1	;save the length
1885
	jmp ao22_1		;save it away
1886

1887
;--- OP_REL1632:  relative jump/call to a longer address.
1888
;--- size of instruction is
1889
;--- a) CS 16-bit:
1890
;---  3 (xx xxxx, jmp/call) or
1891
;---  4 (0F xx xxxx)
1892
;---  6 (66 xx xxxxxxxx)
1893
;---  7 (66 0F xx xxxxxxxx)
1894
;---
1895
;--- b) CS 32-bit:
1896
;---  5 (xx xxxxxxxx, jmp/call) or
1897
;---  6 (0F xx xxxxxxxx)
1898

1899
aop_rel1632:
1900
	mov bx,[a_addr+0]
1901
	mov cx,3
1902
	mov dx,word ptr [di].OPRND.num+2
1903
	mov al,[di].OPRND.sizearg
1904
	cmp [a_opcode],100h	;is a 0F xx opcode?
1905
	jb @F
1906
	inc cx
1907
@@:
1908
	cmp al,SIZ_NONE
1909
	je @F			;if no size given
1910
	cmp al,SIZ_DWORD
1911
	je ao27			;if size "dword"
1912
	cmp al,SIZ_LONG
1913
	jne ao_err1		;if not size "long"
1914
@@:
1915
if ?PM
1916
	test [bCSAttr],40h
1917
	jnz ao27
1918
endif
1919
	or dx,dx
1920
	jnz ao_err1		;if operand is too big
1921
	mov al,2        ;displacement size 2
1922
	jmp ao28
1923
ao27:
1924
	mov al,4        ;displacement size 4
1925
	or [ai.varflags],VAR_D32
1926
	add cx,3		;add 3 to instr size (+2 for displ, +1 for 66h)
1927
if ?PM
1928
	test [bCSAttr],40h
1929
	jz @F
1930
	dec cx			;no 66h prefix byte in 32-bit code
1931
@@:
1932
endif
1933
ao28:
1934
	add bx,cx
1935
	mov cx,[a_addr+2]
1936
	adc cx,0
1937
	mov [di].OPRND.numadd,al	;store size of displacement (2 or 4)
1938
	mov ax,word ptr [di].OPRND.num+0
1939
	sub ax,bx		;compute DX:AX - CX:BX
1940
	sbb dx,cx
1941
	mov [di].OPRND.num2,ax
1942
	mov [di].OPRND.num2+2,dx
1943
	mov [ai.xxaddr],di
1944
	ret
1945
ao_err1:
1946
	jmp ao50		;reject
1947

1948
;--- OP_1CHK - The assembler can ignore this one.
1949

1950
ao29:
1951
	pop ax			;discard return address
1952
	jmp ac06		;next operand
1953

1954
;--- OP_STI - ST(I).
1955

1956
aop_sti:
1957
	mov al,REG_ST	;code for ST
1958
	mov bl,[di].OPRND.reg2
1959
	jmp ao38		;to common code
1960

1961
;--- OP_MMX [previously was OP_ECX (used for LOOPx)]
1962

1963
aop_mmx:
1964
	mov al,REG_MM
1965
	jmp ao37		;to common code
1966

1967
;--- OP_CR
1968

1969
aop_cr:
1970
	mov al,[di].OPRND.reg2	;get the index
1971
	cmp al,4
1972
	ja ao_err1		;if too big
1973
	jne @F			;if not CR4
1974
	mov [ai.dismach],5	;CR4 is new to the 586
1975
@@:
1976
	cmp al,1
1977
	jne @F
1978
	cmp [di+sizeof OPRND].OPRND.flags,-1
1979
	jne ao_err1		;if another arg (can't mov CR1,xx)
1980
@@:
1981
	mov al,REG_CR	;code for CR
1982
	jmp ao37		;to common code
1983

1984
;--- OP_DR
1985

1986
ao34:
1987
	mov al,REG_DR	;code for DR
1988
	jmp ao37		;to common code
1989

1990
;--- OP_TR
1991

1992
ao35:
1993
	mov al,[di].OPRND.reg2	;get the index
1994
	cmp al,3
1995
	jb ao_err1		;if too small
1996
	cmp al,6
1997
	jae @F
1998
	mov [ai.dismach],4	;TR3-5 are new to the 486
1999
@@:
2000
	mov al,REG_TR	;code for TR
2001

2002
;--- Common code for these weird registers.
2003

2004
ao37:
2005
	mov bl,[di].OPRND.reg2
2006
	mov cl,3
2007
	shl bl,cl
2008
ao38:
2009
	or [ai.regmem],bl
2010
	or [ai.varflags],VAR_MODRM
2011
	cmp al,[di].OPRND.reg1	;check for the right numbered register
2012
	je ao40			;if yes, then return
2013
ao38a:
2014
	jmp ao50		;reject
2015

2016
;--- OP_SEGREG
2017

2018
ao39:
2019
	mov al,[di].OPRND.reg1
2020
	sub al,24
2021
	cmp al,6
2022
	jae ao38a		;if not a segment register
2023
	mov cl,3
2024
	shl al,cl
2025
	or [ai.regmem],al
2026
;--- v1.26: don't force size for MOV sreg,mxx / MOV mxx, sreg
2027
	or [ai.varflags], VAR_SIZ_GIVN
2028
ao40:
2029
	ret
2030

2031
;--- OP_IMMS8 - Sign-extended immediate byte (PUSH xx)
2032

2033
ao41:
2034
	and [ai.varflags],not VAR_SIZ_NEED	;added for v1.09. Ok?
2035
	mov ax,word ptr [di].OPRND.num+0
2036
	mov cl,7
2037
	sar al,cl
2038
	jmp ao43		;common code
2039

2040
;--- OP_IMM8 - Immediate byte
2041

2042
ao42:
2043
	mov ax,word ptr [di].OPRND.num+0
2044
	mov al,0
2045
ao43:
2046
	cmp al,ah
2047
	jne ao50		;if too big
2048
	cmp ax,word ptr [di].OPRND.num+2
2049
	jne ao50		;if too big
2050
	mov al,SIZ_BYTE
2051
	call aasizchk	;check that size == 0 or 1
2052
	mov ah,byte ptr [di].OPRND.num+0
2053
	mov word ptr [di].OPRND.numadd,ax	;store length (0/1) + the byte
2054
	mov [ai.xxaddr],di
2055
ao43r:
2056
	ret
2057

2058
;--- OP_SHOSIZ - force the user to declare the size of the next operand
2059

2060
ao44:
2061
	test [ai.varflags],VAR_SIZ_NEED
2062
	jz ao45			;if no testing needs to be done
2063
	test [ai.varflags],VAR_SIZ_GIVN
2064
	jz ao50			;if size was given ( ==> reject)
2065
ao45:
2066
	and [ai.varflags],not VAR_SIZ_GIVN	;clear the flag
2067
	cmp byte ptr [si],OP_IMM8
2068
	je ao45a		;if OP_IMM8 is next, then don't set VAR_SIZ_NEED
2069
	or [ai.varflags],VAR_SIZ_NEED
2070
ao45a:
2071
	mov byte ptr [ai.opsize],0
2072
	pop ax			;discard return address
2073
	jmp ac06		;next operand
2074

2075
;--- OP_1
2076

2077
ao46:
2078
	cmp word ptr [di+7],101h	;check both size and value
2079
	jmp ao49		;test it later
2080

2081
;--- OP_3
2082

2083
ao47:
2084
	cmp word ptr [di+7],301h	;check both size and value
2085
	jmp ao49		;test it later
2086

2087
;--- OP_DX, OP_CL, OP_ST, OP_CS/DS/ES/FS/GS/SS
2088
;--- bx contains index for bittab
2089

2090
ao48:
2091
	mov al,[asm_regnum+bx-(ASM_OPOFF + OP_DX - OP_M64)/2]
2092
	cbw
2093
	cmp ax,word ptr [di].OPRND.reg1
2094

2095
ao49:
2096
	je ao51
2097

2098
;--- Reject this operand list.
2099

2100
ao50:
2101
	pop ax			;discard return address
2102
	jmp ac01		;go back to try the next alternative
2103

2104
ao51:
2105
	ret
2106

2107
;--- AASIZCHK - Check that the size given is 0 or AL.
2108

2109
aasizchk:
2110
	cmp [di].OPRND.sizearg,SIZ_NONE
2111
	je ao51
2112
	cmp [di].OPRND.sizearg,al
2113
	je ao51
2114
	pop ax		;discard return address
2115
	jmp ao50
2116

2117
a_cmd endp
2118

2119
;--- Do reg/mem processing.
2120
;--- in: DI->OPRND
2121
;--- Uses AX
2122

2123
ao90 proc
2124
	@dprintf "ao90: reg/mem processing [di].flags=%X", word ptr [di].OPRND.flags
2125
	test [di].OPRND.flags, ARG_JUSTREG
2126
	jnz ao92		;if just register
2127
	test [di].OPRND.flags, ARG_MODRM
2128
	jz @F			;if no precomputed MOD R/M byte
2129
	mov ax,word ptr [di].OPRND.reg1	;get the precomputed bytes
2130
	jmp ao93		;done
2131
@@:
2132
	mov al,6		;convert plain displacement to MOD R/M
2133
	test [asm_mn_flags],AMF_A32
2134
	jz ao93			;if 16 bit addressing
2135
	dec ax
2136
	jmp ao93		;done
2137

2138
ao92:
2139
	mov al,[di].OPRND.reg1	;convert register to MOD R/M
2140
if 1
2141
	cmp al,REG_MM
2142
	jnz @F
2143
	mov al,[di].OPRND.reg2
2144
@@:
2145
endif
2146
	and al,7		;get low 3 bits
2147
	or al,0c0h
2148

2149
ao93:
2150
	@dprintf "ao90: modrm, ai.regmem=%X, ax=%X", word ptr ai.regmem, ax
2151
	or word ptr [ai.regmem],ax	;store the MOD R/M and SIB
2152
	or [ai.varflags],VAR_MODRM	;flag its presence
2153
	mov [ai.rmaddr],di			;save a pointer
2154
	ret						;done
2155
ao90 endp
2156

2157
;   AAIFNUM - Determine if there's a number next.
2158
;   Entry   AL First character of number
2159
;           SI Address of next character of number
2160
;   Exit    CY Clear if there's a number, set otherwise.
2161
;   Uses    None.
2162

2163
aaifnum proc
2164
	cmp al,'-'
2165
	je aai2			;if minus sign (carry is clear)
2166
	push ax
2167
	sub al,'0'
2168
	cmp al,10
2169
	pop ax
2170
	jb aai1			;if a digit
2171
	push ax
2172
	and al,TOUPPER
2173
	sub al,'A'
2174
	cmp al,6
2175
	pop ax
2176
aai1:
2177
	cmc				;carry clear <==> it's a number
2178
aai2:
2179
	ret
2180
aaifnum endp
2181

2182
;   AAGETI - Get a number from the input line.
2183
;   Entry   AL First character of number
2184
;           SI Address of next character of number
2185
;   Exit    DX:BX Resulting number
2186
;           CL 1 if it's a byte ptr, 2 if a word, 4 if a dword
2187
;           AL Next character not in number
2188
;           SI Address of next character after that
2189
;   Uses    AH, CH
2190

2191
aageti proc
2192
	cmp al,'-'
2193
	je aag1			;if negative
2194
	call aag4		;get the bare number
2195
	mov cx,1		;set up cx
2196
	or dx,dx
2197
	jnz aag2		;if dword
2198
	or bh,bh
2199
	jnz aag3		;if word
2200
	ret				;it's a byte
2201

2202
aag1:
2203
	lodsb
2204
	call aag4		;get the bare number
2205
	mov cx,bx
2206
	or cx,dx
2207
	mov cx,1
2208
	jz aag1a		;if -0
2209
	not dx		;negate the answer
2210
	neg bx
2211
	cmc
2212
	adc dx,0
2213
	test dh,80h
2214
	jz aag7			;if error
2215
	cmp dx,-1
2216
	jne aag2		;if dword
2217
	test bh,80h
2218
	jz aag2			;if dword
2219
	cmp bh,-1
2220
	jne aag3		;if word
2221
	test bl,80h
2222
	jz aag3			;if word
2223
aag1a:
2224
	ret				;it's a byte
2225

2226
aag2:
2227
	inc cx		;return:  it's a dword
2228
	inc cx
2229
aag3:
2230
	inc cx		;return:  it's a word
2231
	ret
2232

2233
aag4:
2234
	xor bx,bx		;get the basic integer
2235
	xor dx,dx
2236
	call getnyb
2237
	jc aag7			;if not a hex digit
2238
aag5:
2239
	or bl,al		;add it to the number
2240
	lodsb
2241
	call getnyb
2242
	jc aag1a		;if done
2243
	test dh,0f0h
2244
	jnz aag7		;if overflow
2245
	mov cx,4
2246
aag6:
2247
	shl bx,1		;shift it by 4
2248
	rcl dx,1
2249
	loop aag6
2250
	jmp aag5
2251

2252
aag7:
2253
	jmp cmd_error	;error
2254

2255
aageti endp
2256

2257
;   AACONVINDEX - Convert results from AAGETI and store index value
2258
;   Entry   DX:BX,CL As in exit from AAGETI
2259
;           DI Points to information record for this arg
2260
;   Exit    SS bits stored in [di].OPRND.index
2261
;   Uses    DL
2262

2263
aaconvindex proc
2264
	cmp cl,1
2265
	jne aacv1		;if the number is too large
2266
	cmp bl,1
2267
	je aacv2		;if 1
2268
	inc dx
2269
	cmp bl,2
2270
	je aacv2		;if 2
2271
	inc dx
2272
	cmp bl,4
2273
	je aacv2		;if 4
2274
	inc dx
2275
	cmp bl,8
2276
	je aacv2		;if 8
2277
aacv1:
2278
	jmp cmd_error	;error
2279

2280
aacv2:
2281
	mov [di].OPRND.index,dl	;save the value
2282
	ret
2283
aaconvindex endp
2284

2285
;   AAGETREG - Get register for the assembler.
2286
;   Entry   DI Start of register table
2287
;           CX Length of register table ( or 0 )
2288
;           SI Address of first character in register name
2289
;   Exit    NC if a register was found
2290
;           SI Updated if a register was found
2291
;           BX Register number, defined as in the table below.
2292
;   Uses    AX, CX, DI
2293

2294
;   Exit value of BX:
2295
;       DI = rgnam816, CX = 27  DI = rgnam16, CX = 8
2296
;       ----------------------  --------------------
2297
;       0  ..  7:  AL .. BH     0  ..  7:  AX .. DI
2298
;       8  .. 15:  AX .. DI     16 .. 23:  EAX..EDI
2299
;       16 .. 23:  EAX..EDI
2300
;       24 .. 29:  ES .. GS
2301
;       30 .. 34:  ST .. TR
2302

2303
aagetreg proc
2304
	mov ax,[si]
2305
	and ax,TOUPPER_W	;convert to upper case
2306
	cmp al,'E'			;check for EAX, etc.
2307
	jne aagr1			;if not
2308
	push ax
2309
	mov al,ah
2310
	mov ah,[si+2]
2311
	and ah,TOUPPER
2312
	push di
2313
	mov di,offset rgnam16
2314
	push cx
2315
	mov cx,N_REGS16
2316
	repne scasw
2317
	mov bx,cx
2318
	pop cx
2319
	pop di
2320
	pop ax
2321
	jne aagr1		;if no match
2322
	inc si
2323
	not bx
2324
	add bl,8+16		;adjust BX
2325
	jmp aagr2		;finish up
2326

2327
aagr1:
2328
	mov bx,cx		;(if cx = 0, this is always reached with
2329
	repne scasw		; ZF clear)
2330
	jne aagr3		;if no match
2331
	sub bx,cx
2332
	dec bx
2333
	cmp bl,16
2334
	jb aagr2		;if AL .. BH or AX .. DI
2335
	add bl,8
2336
aagr2:
2337
	inc si			;skip the register name
2338
	inc si
2339
	clc
2340
	ret
2341
aagr3:
2342
	stc				;not found
2343
	ret
2344
aagetreg endp
2345

2346

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.