summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/DEBUG/DEBUASM.ASM
blob: 6dffb33638f02a59e61ddfabe5bc22a79f666606 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
	   PAGE    80,132 ;
	   TITLE DEBUASM.ASM
; Code for the UASSEMble command in the debugger

	    IF1
		%OUT COMPONENT=DEBUG, MODULE=DEBUASM
	    ENDIF
.XLIST
.XCREF
	   INCLUDE DOSSYM.INC
	   INCLUDE DEBEQU.ASM
.CREF
.LIST
CODE	   SEGMENT PUBLIC BYTE
CODE	   ENDS

CONST	   SEGMENT PUBLIC BYTE
	   EXTRN SYNERR_PTR:BYTE,UNASSEM_LN_PTR:WORD
	   EXTRN NSEG:WORD,SISAVE:WORD,BPSAVE:WORD,DISAVE:WORD
	   EXTRN BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD
	   EXTRN SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FLSAVE:WORD
	   EXTRN DISTAB:WORD,SHFTAB:WORD,IMMTAB:WORD,GRP1TAB:WORD,GRP2TAB:WORD
	   EXTRN DBMN:BYTE,ESCMN:BYTE,DISPB:WORD,STACK:BYTE,REG8:BYTE
	   EXTRN REG16:BYTE,SREG:BYTE,SIZ8:BYTE,SEGTAB:WORD,M8087_TAB:BYTE
	   EXTRN FI_TAB:BYTE,SIZE_TAB:BYTE,MD9_TAB:BYTE,MD9_TAB2:BYTE
	   EXTRN MDB_TAB:BYTE,MDB_TAB2:BYTE,MDD_TAB:BYTE,MDD_TAB2:BYTE
	   EXTRN MDF_TAB:BYTE
CONST	   ENDS

CSTACK	   SEGMENT STACK
CSTACK	   ENDS

DATA	   SEGMENT PUBLIC BYTE
	   EXTRN DISADD:BYTE,DISCNT:WORD,BYTCNT:BYTE,TEMP:BYTE,AWORD:BYTE
	   EXTRN MIDFLD:BYTE,MODE:BYTE,REGMEM:BYTE,OPCODE:WORD,OPBUF:BYTE
	   EXTRN INDEX:WORD,ARG_BUF:BYTE,ARG_BUF_PTR:BYTE,ARG_BUF_INDEX:WORD
	   EXTRN OPBUF:BYTE,OPCODE:WORD
DATA	   ENDS

DG	   GROUP CODE,CONST,CSTACK,DATA

CODE	   SEGMENT PUBLIC BYTE
	   ASSUME CS:DG,DS:DG,ES:DG,SS:DG

	   PUBLIC UNASSEM
	   PUBLIC DISASLN,MEMIMM,JMPCALL,SIGNIMM,ALUFROMREG,WORDTOALU
	   PUBLIC GRP2,PREFIX,OUTVARW,GRP1,SSPRE,MOVSEGTO,DSPRE,SHIFT
	   PUBLIC ESPRE,IMMED,CSPRE,OUTVARB,CHK10,ACCIMM,INT3,INVARB
	   PUBLIC MOVSEGFROM,LOADACC,OUTFIXB,XCHGAX,REGIMMW,SHORTJMP
	   PUBLIC SAV8,M8087,M8087_DB,M8087_DF,M8087_D9,M8087_DD
	   PUBLIC SAV16,SAVHEX,INFIXW,REGIMMB,OUTFIXW,SHIFTV,LONGJMP
	   PUBLIC INVARW,STOREACC,INFIXB,NOOPERANDS,ALUTOREG
	   PUBLIC SEGOP,REGOP,GETADDR

	   EXTRN CRLF:NEAR,BLANK:NEAR,TAB:NEAR,STD_PRINTF:NEAR
	   EXTRN HEX:NEAR,DEFAULT:NEAR,OUTSI:NEAR,OUTDI:NEAR
	   EXTRN HEX_ADDRESS_ONLY:NEAR

UNASSEM:
	   MOV	BP,[CSSAVE]		; Default code segment
	   MOV	DI,OFFSET DG:DISADD	; Default address
	   MOV	CX,DISPB		; Default length
	   SHR	CX,1
	   SHR	CX,1
	   CALL DEFAULT
	   MOV	WORD PTR [DISADD],DX	; Displacement of disassembly
	   MOV	WORD PTR [DISADD+2],AX	; Segment
	   MOV	WORD PTR [DISCNT],CX	; No. of bytes (but whole instructions)
DISLP:
	   CALL DISASLN 		; Disassemble one line
	   CALL CRLF
	   TEST [DISCNT],-1		; See if we've used up the range
	   JNZ	DISLP
	   RET

GOTDIS:
	   PUSH DS			; RE-GET LAST BYTE
	   PUSH SI
	   LDS	SI,DWORD PTR [DISADD]
	   MOV	AL,[SI-1]
	   POP	SI
	   POP	DS
	   RET

GETDIS:
	   PUSH DS
	   LDS	SI,DWORD PTR [DISADD]
	   LODSB			; Get the next byte of code
	   POP	DS
	   MOV	WORD PTR [DISADD],SI	; Update pointer
	   PUSH AX
	   PUSH DI
	   MOV	DI,[ARG_BUF_INDEX]
	   CALL HEX			; Display each code byte
	   MOV	[ARG_BUF_INDEX],DI
	   POP	DI
	   MOV	SI,[DISCNT]
	   OR	SI,SI			; Check if range exhausted
	   JZ	ENDRNG			; If so, don't wrap around
	   DEC	SI			; Count off the bytes
	   MOV	[DISCNT],SI
ENDRNG:
	   INC	BYTE PTR[BYTCNT]	; Keep track of no. of bytes per line
	   POP	AX
	   RET

DSPRE:
	   INC	BYTE PTR [NSEG+1]
SSPRE:
	   INC	BYTE PTR [NSEG+1]
CSPRE:
	   INC	BYTE PTR [NSEG+1]
ESPRE:
	   INC	BYTE PTR [NSEG+1]

PREFIX:
	   POP	BX			; Dump off return address
	   CALL FINLN
	   CALL CRLF
DISASLN:
	   PUSH DS
	   LDS	SI,DWORD PTR [DISADD]
	   CALL OUTSI			; Show disassembly address
	   POP	DS
	   CALL HEX_ADDRESS_ONLY
DISASLN1:
	   MOV	BYTE PTR [BYTCNT],0	; Count of code bytes per line
; Fill overflow area with zeros
	   MOV	DI,OFFSET DG:OPBUF
	   MOV	CX,50
	   MOV	AL,0
	   REP	STOSB
; fill buffer with spaces
	   MOV	DI,OFFSET DG:OPBUF
	   MOV	CX,OPBUFLEN
	   MOV	AL," "
	   REP	STOSB
	   MOV	DI,OFFSET DG:ARG_BUF
	   MOV	[ARG_BUF_INDEX],DI
	   CALL GETDIS			; Get opcode
	   MOV	DI,[ARG_BUF_INDEX]
	   MOV	AH,0
	   MOV	BX,AX
	   AND	AL,1			; Mask to "W" bit
	   MOV	[AWORD],AL
	   MOV	AL,BL			; Restore opcode
	   SHL	BX,1
	   SHL	BX,1			; Multiply opcode by 4
	   ADD	BX,OFFSET DG:DISTAB
	   MOV	DX,[BX] 		; Get pointer to mnemonic from table
	   MOV	[OPCODE],DX
	   MOV	[ARG_BUF_INDEX],DI
	   MOV	DI,OFFSET DG:OPBUF
	   CALL WORD PTR [BX+2]
FINLN:
	   MOV	AH,[BYTCNT]		; See how many bytes in this instruction
	   ADD	AH,AH			; Each uses two characters
	   MOV	AL,14			; Amount of space we want to use
	   SUB	AL,AH			; See how many fill characters needed
	   CBW
	   XCHG CX,AX			; Parameter for TAB needed in CX
	   MOV	DI,[ARG_BUF_INDEX]
	   CALL TAB
	   MOV	SI,[OPCODE]
	   OR	SI,SI
	   JZ	GET_TAB
GET_OPCODE:
	   LODSB
	   OR	AL,AL
	   JZ	GET_TAB
	   STOSB
	   JMP	GET_OPCODE

GET_TAB:
	   MOV	AL,9
	   STOSB
	   MOV	BYTE PTR [DI],0 	; nul terminate address buffer
	   MOV	DX,OFFSET DG:UNASSEM_LN_PTR
	   CALL STD_PRINTF
	   RET

GETMODE:
	   CALL GETDIS			; Get the address mode byte
	   MOV	AH,AL
	   AND	AL,7			; Mask to "r/m" field
	   MOV	[REGMEM],AL
	   SHR	AH,1
	   SHR	AH,1
	   SHR	AH,1
	   MOV	AL,AH
	   AND	AL,7			; Mask to center 3-bit field
	   MOV	[MIDFLD],AL
	   SHR	AH,1
	   SHR	AH,1
	   SHR	AH,1
	   MOV	[MODE],AH		; Leaving 2-bit "MOD" field
	   RET

IMMED:
	   MOV	BX,OFFSET DG:IMMTAB
	   CALL GETMNE
FINIMM:
	   CALL TESTREG
	   JMP	SHORT IMM

MEMIMM:
	   CALL GETMODE
	   JMP	SHORT FINIMM

ACCIMM:
	   XOR	AL,AL
IMM1:
	   CALL SAVREG
IMM:
	   MOV	AL,","
	   STOSB
	   TEST BYTE PTR [AWORD],-1
	   JNZ	SAV16
SAV8:
	   CALL GETDIS
	   JMP	SHORT SAVHEX

LONGJMP:
	   PUSH DI
	   MOV	DI,OFFSET DG:TEMP
	   CALL SAV16
	   POP	DI
	   CALL SAV16
	   MOV	AL,":"
	   STOSB
	   MOV	SI,OFFSET DG:TEMP
	   MOV	CX,4
MOVDIG:
	   LODSB
	   STOSB
	   LOOP MOVDIG
	   RET

SAV16:
	   CALL GETDIS			; Get low byte
	   MOV	DL,AL
	   CALL GETDIS			; Get high byte
	   MOV	DH,AL
	   CALL SAVHEX			; Convert and store high byte
	   MOV	AL,DL
SAVHEX:
	   MOV	AH,AL
	   SHR	AL,1
	   SHR	AL,1
	   SHR	AL,1
	   SHR	AL,1
	   CALL SAVDIG
	   MOV	AL,AH
SAVDIG:
	   AND	AL,0FH
	   ADD	AL,90H
	   DAA
	   ADC	AL,40H
	   DAA
	   STOSB
	   RET

CHK10:
	   CALL GETDIS
	   CMP	AL,10
	   JNZ	SAVHEX
	   RET

SIGNIMM:
	   MOV	BX,OFFSET DG:IMMTAB
	   CALL GETMNE
	   CALL TESTREG
	   MOV	AL,","
	   STOSB
SAVD8:
	   CALL GETDIS			; Get signed 8-bit number
	   CBW
	   MOV	DX,AX			; Save true 16-bit value in DX
	   MOV	AH,AL
	   MOV	AL,"+"
	   OR	AH,AH
;	JZ	NOSIGN
	   JNS	POSITIV 		; OK if positive
	   MOV	AL,"-"
	   NEG	AH			; Get magnitude if negative
POSITIV:
	   STOSB
; NOSIGN:
	   MOV	AL,AH
	   JMP	SHORT SAVHEX

ALUFROMREG:
	   CALL GETADDR
	   MOV	AL,","
	   STOSB
REGFLD:
	   MOV	AL,[MIDFLD]
SAVREG:
	   MOV	SI,OFFSET DG:REG8
	   CMP	BYTE PTR [AWORD],1
	   JNE	FNDREG
SAVREG16:
	   MOV	SI,OFFSET DG:REG16
FNDREG:
	   CBW
	   ADD	SI,AX
	   ADD	SI,AX
	   MOVSW
	   RET

SEGOP:
	   SHR	AL,1
	   SHR	AL,1
	   SHR	AL,1
SAVSEG:
	   AND	AL,3
	   MOV	SI,OFFSET DG:SREG
	   JMP	SHORT FNDREG

REGOP:
	   AND	AL,7
	   JMP	SHORT SAVREG16

MOVSEGTO:
	   MOV	BYTE PTR [AWORD],1
	   CALL GETADDR
	   MOV	AL,","
	   STOSB
	   MOV	AL,[MIDFLD]
	   JMP	SHORT SAVSEG

MOVSEGFROM:
	   CALL GETMODE
	   CALL SAVSEG
	   MOV	BYTE PTR [AWORD],1
	   JMP	SHORT MEMOP2

GETADDR:
	   CALL GETMODE
	   JMP	SHORT ADDRMOD

WORDTOALU:
	   MOV	BYTE PTR [AWORD],1
ALUTOREG:
	   CALL GETMODE
	   CALL REGFLD
MEMOP2:
	   MOV	AL,","
	   STOSB
ADDRMOD:
	   CMP	BYTE PTR [MODE],3
	   MOV	AL,[REGMEM]
	   JE	SAVREG
	   XOR	BX,BX
	   MOV	BYTE PTR [NSEG],3
	   MOV	BYTE PTR [DI],"["
	   INC	DI
	   CMP	AL,6
	   JNE	NODRCT
	   CMP	BYTE PTR [MODE],0
	   JE	DIRECT			; Mode=0 and R/M=6 means direct addr.
NODRCT:
	   MOV	DL,AL
	   CMP	AL,1
	   JBE	USEBX
	   CMP	AL,7
	   JE	USEBX
	   CMP	AL,3
	   JBE	USEBP
	   CMP	AL,6
	   JNE	CHKPLS
USEBP:
	   MOV	BX,[BPSAVE]
	   MOV	BYTE PTR [NSEG],2	; Change default to Stack Segment
	   MOV	AX,BPREG
SAVBASE:
	   STOSW
CHKPLS:
	   CMP	DL,4
	   JAE	NOPLUS
	   MOV	AL,"+"
	   STOSB
NOPLUS:
	   CMP	DL,6
	   JAE	DOMODE			; No index register
	   AND	DL,1			; Even for SI, odd for DI
	   JZ	USESI
	   ADD	BX,[DISAVE]
	   MOV	AX,DIREG
SAVINDX:
	   STOSW
DOMODE:
	   MOV	AL,[MODE]
	   OR	AL,AL
	   JZ	CLOSADD 		; If no displacement, then done
	   CMP	AL,2
	   JZ	ADDDIR
	   CALL SAVD8			; Signed 8-bit displacement
ADDCLOS:
	   ADD	BX,DX
CLOSADD:
	   MOV	AL,"]"
	   STOSB
	   MOV	[INDEX],BX
NOOPERANDS:
	   RET

ADDDIR:
	   MOV	AL,"+"
	   STOSB
DIRECT:
	   CALL SAV16
	   JMP	SHORT ADDCLOS

USEBX:
	   MOV	BX,[BXSAVE]
	   MOV	AX,BXREG
	   JMP	SHORT SAVBASE

USESI:
	   ADD	BX,[SISAVE]
	   MOV	AX,SIREG
	   JMP	SHORT SAVINDX

SHORTJMP:
	   CALL GETDIS
	   CBW
	   ADD	AX,WORD PTR [DISADD]
	   XCHG DX,AX
SAVJMP:
	   MOV	AL,DH
	   CALL SAVHEX
	   MOV	AL,DL
	   JMP	SAVHEX

JMPCALL:
	   CALL GETDIS
	   MOV	DL,AL
	   CALL GETDIS
	   MOV	DH,AL
	   ADD	DX,WORD PTR [DISADD]
	   JMP	SHORT SAVJMP

XCHGAX:
	   AND	AL,7
	   CALL SAVREG16
	   MOV	AL,","
	   STOSB
	   XOR	AL,AL
	   JMP	SAVREG16

LOADACC:
	   XOR	AL,AL
	   CALL SAVREG
	   MOV	AL,","
	   STOSB
MEMDIR:
	   MOV	AL,"["
	   STOSB
	   XOR	BX,BX
	   MOV	BYTE PTR [NSEG],3
	   JMP	DIRECT

STOREACC:
	   CALL MEMDIR
	   MOV	AL,","
	   STOSB
	   XOR	AL,AL
	   JMP	SAVREG

REGIMMB:
	   MOV	BYTE PTR [AWORD],0
	   JMP	SHORT REGIMM

REGIMMW:
	   MOV	BYTE PTR [AWORD],1
REGIMM:
	   AND	AL,7
	   JMP	IMM1

INT3:
	   MOV	BYTE PTR [DI],"3"
	   INC	DI
	   RET

;  8087 instructions whose first byte is 0dfh
M8087_DF:
	   CALL GET64F
	   JZ	ISDD3
	   MOV	SI,OFFSET DG:MDF_TAB
	   JMP	NODB3

;  8087 instructions whose first byte is 0ddh
M8087_DD:
	   CALL GET64F
	   JZ	ISDD3
	   MOV	SI,OFFSET DG:MDD_TAB
	   JMP	NOD93

ISDD3:
	   MOV	AL,DL
	   TEST AL,100B
	   JZ	ISSTI
	   JMP	ESC0

ISSTI:
	   AND	AL,11B
	   MOV	SI,OFFSET DG:MDD_TAB2
	   MOV	CL,AL
	   CALL MOVBYT
	   JMP	PUTRST

;  8087 instructions whose first byte is 0dbh
M8087_DB:
	   CALL GET64F
	   JZ	ISDB3
	   MOV	SI,OFFSET DG:MDB_TAB
NODB3:
	   CALL PUTOP
	   CALL PUTSIZE
	   JMP	ADDRMOD

ISDB3:
	   MOV	AL,DL
	   TEST AL,100B
	   JNZ	ISDBIG
ESC0V:
	   JMP	ESC0

ISDBIG:
	   CALL GOTDIS
	   AND	AL,11111B
	   CMP	AL,4
	   JAE	ESC0V
	   MOV	SI,OFFSET DG:MDB_TAB2
	   JMP	DOBIG

;  8087 instructions whose first byte is 0d9h
M8087_D9:
	   CALL GET64F
	   JZ	ISD93

	   MOV	SI,OFFSET DG:MD9_TAB
NOD93:
	   CALL PUTOP
	   AND	AL,111B
	   CMP	AL,3
	   JA	NOSHO
	   MOV	AL,DL
	   CALL PUTSIZE
NOSHO:
	   JMP	ADDRMOD

ISD93:
	   MOV	AL,DL
	   TEST AL,100B
	   JNZ	ISD9BIG
	   AND	AL,111B
	   OR	AL,AL
	   JNZ	NOTFLD
	   MOV	AX,"DL"
	   STOSW
	   JMP	SHORT PUTRST

NOTFLD:
	   CMP	AL,1
	   JNZ	NOTFXCH
	   MOV	AX,"CX"
	   STOSW
	   MOV	AL,"H"
	   JMP	SHORT PUTRST1

NOTFXCH:
	   CMP	AL,3
	   JNZ	NOTFSTP
	   MOV	AX,"TS"
	   STOSW
	   MOV	AL,"P"
PUTRST1:
	   STOSB
PUTRST:
	   MOV	AL,9
	   STOSB
	   JMP	PUTST0

NOTFSTP:
	   CALL GOTDIS
	   CMP	AL,11010000B		; CHECK FOR FNOP
	   JZ	GOTFNOP
	   JMP	ESC0

GOTFNOP:
	   MOV	AX,"ON"
	   STOSW
	   MOV	AL,"P"
	   STOSB
	   RET

ISD9BIG:
	   CALL GOTDIS			; GET THE MODE BYTE
	   MOV	SI,OFFSET DG:MD9_TAB2
DOBIG:
	   AND	AL,11111B
	   MOV	CL,AL
	   JMP	MOVBYT

; entry point for the remaining 8087 instructions
M8087:
	   CALL GET64
	   CALL PUTFI			; PUT FIRST PART OF OPCODE
	   MOV	AL,DL
	   CMP	BYTE PTR [MODE],11B	; CHECK FOR REGISTER MODE
	   JZ	MODEIS3
	   CALL PUTMN			; PUT MIDDLE PART OF OPCODE
NO3:
	   MOV	AL,9			; OUTPUT A TAB
	   STOSB
	   MOV	AL,DL
	   CALL PUTSIZE 		; OUTPUT THE OPERAND SIZE
	   JMP	ADDRMOD

MODEIS3:
	   TEST AL,100000B		; D BIT SET?
	   JZ	MPUT			; NOPE...
	   TEST AL,000100B		; FDIV OR FSUB?
	   JZ	MPUT			; NOPE...
	   XOR	AL,1			; REVERSE SENSE OF R
	   MOV	DL,AL			; SAVE CHANGE
MPUT:
	   CALL PUTMN			; PUT MIDDLE PART OF OPCODE
	   MOV	AL,DL
	   TEST AL,010000B
	   JZ	NOPSH
	   MOV	AL,"P"
	   STOSB
NOPSH:
	   MOV	AL,9
	   STOSB
	   MOV	AL,DL
	   AND	AL,00000111B
	   CMP	AL,2			; FCOM
	   JZ	PUTST0
	   CMP	AL,3			; FCOMP
	   JZ	PUTST0
	   MOV	AL,DL
	   TEST AL,100000B
	   JZ	PUTSTST0

; output 8087 registers in the form st(n),st
PUTST0ST:
	   CALL PUTST0
	   MOV	AL,','
ISCOMP:
	   STOSB

PUTST:
	   MOV	AX,"TS"
	   STOSW
	   RET

; output 8087 registers in the form st,st(n)
PUTSTST0:
	   CALL PUTST
	   MOV	AL,','
	   STOSB

PUTST0:
	   CALL PUTST
	   MOV	AL,"("
	   STOSB
	   MOV	AL,[REGMEM]
	   ADD	AL,"0"
	   STOSB
	   MOV	AL,")"
	   STOSB
	   RET

; output an 8087 mnemonic
PUTMN:
	   MOV	SI,OFFSET DG:M8087_TAB
	   MOV	CL,AL
	   AND	CL,00000111B
	   JMP	SHORT MOVBYT

; output either 'FI' or 'F' for first byte of opcode
PUTFI:
	   MOV	SI,OFFSET DG:FI_TAB
	   JMP	SHORT PUTFI2

; output size (dword, tbyte, etc.)
PUTSIZE:
	   MOV	SI,OFFSET DG:SIZE_TAB
PUTFI2:
	   CMP	BYTE PTR [MODE],11B	; check if 8087 register
	   JNZ	PUTFI3
	   AND	AL,111000B		; LOOK FOR INVALID FORM OF 0DAH OPERANDS
	   CMP	AL,010000B
	   JZ	ESC0PJ
	   MOV	AL,DL
	   CMP	AL,110011B		; FCOMPP
	   JNZ	GOFI
	   CMP	BYTE PTR [REGMEM],1
	   JZ	GOFI
ESC0PJ:
	   JMP	ESC0P

GOFI:
	   XOR	CL,CL
	   JMP	SHORT MOVBYT

;  Look for qword
PUTFI3:
	   CMP	AL,111101B
	   JZ	GOTQU
	   CMP	AL,111111B
	   JNZ	NOTQU
GOTQU:
	   MOV	CL,2
	   JMP	SHORT MOVBYT

;  look for tbyte
NOTQU:
	   CMP	AL,011101B
	   JZ	GOTTB
	   CMP	AL,111100B
	   JZ	GOTTB
	   CMP	AL,111110B
	   JZ	GOTTB
	   CMP	AL,011111B
	   JNZ	NOTTB
GOTTB:
	   MOV	CL,5
	   JMP	SHORT MOVBYT

NOTTB:
	   MOV	CL,4
	   SHR	AL,CL
	   MOV	CL,AL
; SI POINTS TO A TABLE OF TEXT SEPARATED BY "$"
; CL = WHICH ELEMENT IN THE TABLE YOU WISH TO COPY TO [DI]
MOVBYT:
	   PUSH AX
	   INC	CL
MOVBYT1:
	   DEC	CL
	   JZ	MOVBYT3
MOVBYT2:
	   LODSB
	   CMP	AL,"$"
	   JZ	MOVBYT1
	   JMP	MOVBYT2

MOVBYT3:
	   LODSB
	   CMP	AL,'$'
	   JZ	MOVBYT5
	   CMP	AL,'@'                  ; THIS MEANS RESVERED OP-CODE
	   JNZ	MOVBYT4
	   POP	AX
	   JMP	SHORT ESC0P		; GO DO AN ESCAPE COMMAND

MOVBYT4:
	   STOSB
	   JMP	MOVBYT3

MOVBYT5:
	   POP	AX
	   RET

PUTOP:
	   AND	AL,111B
	   MOV	CL,AL
	   CALL MOVBYT
	   MOV	AL,9
	   STOSB
	   MOV	AL,DL
	   RET

GET64F:
	   CALL GET64
	   MOV	AL,"F"
	   STOSB
	   CMP	BYTE PTR [MODE],3
	   MOV	AL,DL
	   RET

GET64:
	   AND	AL,7
	   MOV	DL,AL
	   CALL GETMODE
	   SHL	DL,1
	   SHL	DL,1
	   SHL	DL,1
	   OR	AL,DL
	   MOV	DL,AL			; SAVE RESULT
	   RET

ESC0P:
	   POP	DI			; CLEAN UP STACK
ESC0:
	   MOV	WORD PTR [OPCODE],OFFSET DG:ESCMN
	   MOV	AL,DL
	   MOV	DI,OFFSET DG:OPBUF
	   JMP	SHORT ESC1

ESCP:
	   CALL GET64
ESC1:
	   CALL SAVHEX
	   CMP	BYTE PTR [MODE],3
	   JZ	SHRTESC
	   MOV	BYTE PTR  [AWORD],1
	   JMP	MEMOP2

SHRTESC:
	   MOV	AL,","
	   STOSB
	   MOV	AL,[REGMEM]
	   AND	AL,7
	   JMP	SAVREG

INVARW:
	   CALL PUTAX
	   JMP	SHORT INVAR

INVARB:
	   CALL PUTAL
INVAR:
	   MOV	AL,','
	   STOSB
	   JMP	PUTDX

INFIXW:
	   CALL PUTAX
	   JMP	SHORT INFIX

INFIXB:
	   CALL PUTAL
INFIX:
	   MOV	AL,','
	   STOSB
	   JMP	SAV8

	   STOSW			;IS THIS DEAD CODE? EMK
	   RET

OUTVARB:
	   MOV	BX,"LA"
	   JMP	SHORT OUTVAR

OUTVARW:
	   MOV	BX,"XA"
OUTVAR:
	   CALL PUTDX
OUTFV:
	   MOV	AL,','
	   STOSB
	   MOV	AX,BX
	   STOSW
	   RET

OUTFIXB:
	   MOV	BX,"LA"
	   JMP	SHORT OUTFIX

OUTFIXW:
	   MOV	BX,"XA"
OUTFIX:
	   CALL SAV8
	   JMP	OUTFV

PUTAL:
	   MOV	AX,"A"+4C00H            ; "AL"
	   JMP	SHORT PUTX

PUTAX:
	   MOV	AX,"A"+5800H            ; "AX"
	   JMP	SHORT PUTX

PUTDX:
	   MOV	AX,"D"+5800H            ; "DX"
PUTX:
	   STOSW
	   RET

SHFT:
	   MOV	BX,OFFSET DG:SHFTAB
	   CALL GETMNE
TESTREG:
	   CMP	BYTE PTR [MODE],3
	   JZ	NOFLG
	   MOV	SI,OFFSET DG:SIZE_TAB
	   MOV	CL,3
	   TEST BYTE PTR [AWORD],-1
	   JNZ	TEST_1
	   INC	CL
TEST_1:
	   CALL MOVBYT
NOFLG:
	   JMP	ADDRMOD

SHIFTV:
	   CALL SHFT
	   MOV	AL,","
	   STOSB
	   MOV	WORD PTR [DI],"C"+4C00H ; "CL"
	   ADD	DI,2
	   RET

SHIFT:
	   CALL SHFT
	   MOV	AX,"1,"
	   STOSW
	   RET

GETMNE:
	   CALL GETMODE
	   MOV	DL,AL
	   CBW
	   SHL	AX,1
	   ADD	BX,AX
	   MOV	AX,[BX]
	   MOV	[OPCODE],AX
	   MOV	AL,DL
	   RET

GRP1:
	   MOV	BX,OFFSET DG:GRP1TAB
	   CALL GETMNE
	   OR	AL,AL
	   JZ	FINIMMJ
	   JMP	TESTREG
FINIMMJ:
	   JMP	FINIMM

GRP2:
	   MOV	BX,OFFSET DG:GRP2TAB
	   CALL GETMNE
	   CMP	AL,2
	   JB	TESTREG
	   CMP	AL,6
	   JAE	INDIRECT
	   TEST AL,1
	   JZ	INDIRECT
	   MOV	AX,"AF"                 ; "FAR"
	   STOSW
	   MOV	AX," R"
	   STOSW
INDIRECT:
	   JMP	ADDRMOD

CODE	   ENDS
	   END	UNASSEM