summaryrefslogtreecommitdiff
path: root/v2.0/source/DEBCOM2.ASM
blob: a800d4b93d91e306724f4f03682fe85c5c2a776e (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
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
TITLE   PART2 DEBUGGER COMMANDS

; Routines to perform debugger commands except ASSEMble and UASSEMble

.xlist
.xcref
        INCLUDE DEBEQU.ASM
        INCLUDE DOSSYM.ASM
.cref
.list

CODE    SEGMENT PUBLIC BYTE 'CODE'
CODE    ENDS

CONST   SEGMENT PUBLIC BYTE

        EXTRN   NOTFND:BYTE,NOROOM:BYTE,DRVLET:BYTE,NOSPACE:BYTE,NAMBAD:BYTE
        EXTRN   TOOBIG:BYTE,ERRMES:BYTE
        EXTRN   EXEBAD:BYTE,HEXERR:BYTE,EXEWRT:BYTE,HEXWRT:BYTE
        EXTRN   EXECEMES:BYTE,WRTMES1:BYTE,WRTMES2:BYTE,ACCMES:BYTE

        EXTRN   FLAGTAB:WORD,EXEC_BLOCK:BYTE,COM_LINE:DWORD,COM_FCB1:DWORD
        EXTRN   COM_FCB2:DWORD,COM_SSSP:DWORD,COM_CSIP:DWORD,RETSAVE:WORD
        EXTRN   NEWEXEC:BYTE,HEADSAVE:WORD
        EXTRN   REGTAB:BYTE,TOTREG:BYTE,NOREGL:BYTE
        EXTRN   USER_PROC_PDB:WORD,STACK:BYTE,RSTACK:WORD,AXSAVE:WORD
        EXTRN   BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD
        EXTRN   SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FSAVE:WORD
        EXTRN   SREG:BYTE,SEGTAB:WORD,REGDIF:WORD,RDFLG:BYTE

CONST   ENDS

DATA    SEGMENT PUBLIC BYTE

        EXTRN   DEFDUMP:BYTE,TRANSADD:DWORD,INDEX:WORD,BUFFER:BYTE
        EXTRN   ASMADD:BYTE,DISADD:BYTE,NSEG:WORD,BPTAB:BYTE
        EXTRN   BRKCNT:WORD,TCOUNT:WORD,SWITCHAR:BYTE,XNXCMD:BYTE,XNXOPT:BYTE
        EXTRN   AWORD:BYTE,EXTPTR:WORD,HANDLE:WORD,PARSERR:BYTE

DATA    ENDS

DG      GROUP   CODE,CONST,DATA


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

        PUBLIC  DEFIO,SKIP_FILE,PREPNAME,DEBUG_FOUND
        PUBLIC  REG,COMPARE,GO,INPUT,LOAD
        PUBLIC  NAME,OUTPUT,TRACE,ZTRACE,DWRITE
        if  sysver
        PUBLIC  DISPREG
        endif

        EXTRN   GETHEX:NEAR,GETEOL:NEAR
        EXTRN   CRLF:NEAR,BLANK:NEAR,OUT:NEAR
        EXTRN   OUTSI:NEAR,OUTDI:NEAR,INBUF:NEAR,SCANB:NEAR,SCANP:NEAR
        EXTRN   RPRBUF:NEAR,HEX:NEAR,OUT16:NEAR,DIGIT:NEAR
        EXTRN   COMMAND:NEAR,DISASLN:NEAR,SET_TERMINATE_VECTOR:NEAR
        EXTRN   RESTART:NEAR,DABORT:NEAR,TERMINATE:NEAR,DRVERR:NEAR
        EXTRN   FIND_DEBUG:NEAR,NMIInt:NEAR,NMIIntEnd:NEAR
        EXTRN   HEXCHK:NEAR,GETHEX1:NEAR,PRINT:NEAR,DSRANGE:NEAR
        EXTRN   ADDRESS:NEAR,HEXIN:NEAR,PERROR:NEAR


DEBCOM2:
DISPREG:
        MOV     SI,OFFSET DG:REGTAB
        MOV     BX,OFFSET DG:AXSAVE
        MOV     BYTE PTR TOTREG,13
        MOV     CH,0
        MOV     CL,NOREGL
REPDISP:
        SUB     TOTREG,CL
        CALL    DISPREGLINE
        CALL    CRLF
        MOV     CH,0
        MOV     CL,NOREGL
        CMP     CL,TOTREG
        JL      REPDISP
        MOV     CL,TOTREG
        CALL    DISPREGLINE
        CALL    BLANK
        CALL    DISPFLAGS
        CALL    CRLF
        MOV     AX,[IPSAVE]
        MOV     WORD PTR [DISADD],AX
        PUSH    AX
        MOV     AX,[CSSAVE]
        MOV     WORD PTR [DISADD+2],AX
        PUSH    AX
        MOV     [NSEG],-1
        CALL    DISASLN
        POP     WORD PTR DISADD+2
        POP     WORD PTR DISADD
        MOV     AX,[NSEG]
        CMP     AL,-1
        JZ      CRLFJ
        CMP     AH,-1
        JZ      NOOVER
        XCHG    AL,AH
NOOVER:
        CBW
        MOV     BX,AX
        SHL     BX,1
        MOV     AX,WORD PTR [BX+SREG]
        CALL    OUT
        XCHG    AL,AH
        CALL    OUT
        MOV     AL,":"
        CALL    OUT
        MOV     DX,[INDEX]
        CALL    OUT16
        MOV     AL,"="
        CALL    OUT
        MOV     BX,[BX+SEGTAB]
        PUSH    DS
        MOV     DS,[BX]
        MOV     BX,DX
        MOV     DX,[BX]
        POP     DS
        TEST    BYTE PTR [AWORD],-1
        JZ      OUT8
        CALL    OUT16
CRLFJ:
        JMP     CRLF
OUT8:
        MOV     AL,DL
        CALL    HEX
        JMP     CRLF

DISPREGJ:JMP    DISPREG

; Perform register dump if no parameters or set register if a
; register designation is a parameter.

REG:
        CALL    SCANP
        JZ      DISPREGJ
        MOV     DL,[SI]
        INC     SI
        MOV     DH,[SI]
        CMP     DH,13
        JZ      FLAG
        INC     SI
        CALL    GETEOL
        CMP     DH," "
        JZ      FLAG
        MOV     DI,OFFSET DG:REGTAB
        XCHG    AX,DX
        PUSH    CS
        POP     ES
        MOV     CX,REGTABLEN
        REPNZ   SCASW
        JNZ     BADREG
        OR      CX,CX
        JNZ     NOTPC
        DEC     DI
        DEC     DI
        MOV     AX,CS:[DI-2]
NOTPC:
        CALL    OUT
        MOV     AL,AH
        CALL    OUT
        CALL    BLANK
        PUSH    DS
        POP     ES
        LEA     BX,[DI+REGDIF-2]
        MOV     DX,[BX]
        CALL    OUT16
        CALL    CRLF
        MOV     AL,":"
        CALL    OUT
        CALL    INBUF
        CALL    SCANB
        JZ      RET4
        MOV     CX,4
        CALL    GETHEX1
        CALL    GETEOL
        MOV     [BX],DX
RET4:   RET
BADREG:
        MOV     AX,5200H+"B"            ; BR ERROR
        JMP     ERR
FLAG:
        CMP     DL,"F"
        JNZ     BADREG
        CALL    DISPFLAGS
        MOV     AL,"-"
        CALL    OUT
        CALL    INBUF
        CALL    SCANB
        XOR     BX,BX
        MOV     DX,[FSAVE]
GETFLG:
        LODSW
        CMP     AL,13
        JZ      SAVCHG
        CMP     AH,13
        JZ      FLGERR
        MOV     DI,OFFSET DG:FLAGTAB
        MOV     CX,32
        PUSH    CS
        POP     ES
        REPNE   SCASW
        JNZ     FLGERR
        MOV     CH,CL
        AND     CL,0FH
        MOV     AX,1
        ROL     AX,CL
        TEST    AX,BX
        JNZ     REPFLG
        OR      BX,AX
        OR      DX,AX
        TEST    CH,16
        JNZ     NEXFLG
        XOR     DX,AX
NEXFLG:
        CALL    SCANP
        JMP     SHORT GETFLG
DISPREGLINE:
        LODS    CS:WORD PTR [SI]
        CALL    OUT
        MOV     AL,AH
        CALL    OUT
        MOV     AL,"="
        CALL    OUT
        MOV     DX,[BX]
        INC     BX
        INC     BX
        CALL    OUT16
        CALL    BLANK
        CALL    BLANK
        LOOP    DISPREGLINE
        RET
REPFLG:
        MOV     AX,4600H+"D"            ; DF ERROR
FERR:
        CALL    SAVCHG
ERR:
        CALL    OUT
        MOV     AL,AH
        CALL    OUT
        MOV     SI,OFFSET DG:ERRMES
        JMP     PRINT
SAVCHG:
        MOV     [FSAVE],DX
        RET
FLGERR:
        MOV     AX,4600H+"B"            ; BF ERROR
        JMP     SHORT FERR
DISPFLAGS:
        MOV     SI,OFFSET DG:FLAGTAB
        MOV     CX,16
        MOV     DX,[FSAVE]
DFLAGS:
        LODS    CS:WORD PTR [SI]
        SHL     DX,1
        JC      FLAGSET
        MOV     AX,CS:[SI+30]
FLAGSET:
        OR      AX,AX
        JZ      NEXTFLG
        CALL    OUT
        MOV     AL,AH
        CALL    OUT
        CALL    BLANK
NEXTFLG:
        LOOP    DFLAGS
        RET

; Input from the specified port and display result

INPUT:
        MOV     CX,4                    ; Port may have 4 digits
        CALL    GETHEX                  ; Get port number in DX
        CALL    GETEOL
        IN      AL,DX                   ; Variable port input
        CALL    HEX                     ; And display
        JMP     CRLF

; Output a value to specified port.

OUTPUT:
        MOV     CX,4                    ; Port may have 4 digits
        CALL    GETHEX                  ; Get port number
        PUSH    DX                      ; Save while we get data
        MOV     CX,2                    ; Byte output only
        CALL    GETHEX                  ; Get data to output
        CALL    GETEOL
        XCHG    AX,DX                   ; Output data in AL
        POP     DX                      ; Port in DX
        OUT     DX,AL                   ; Variable port output
RET5:   RET
COMPARE:
        CALL    DSRANGE
        PUSH    CX
        PUSH    AX
        PUSH    DX
        CALL    ADDRESS                 ; Same segment
        CALL    GETEOL
        POP     SI
        MOV     DI,DX
        MOV     ES,AX
        POP     DS
        POP     CX                      ; Length
        DEC     CX
        CALL    COMP                    ; Do one less than total
        INC     CX                      ; CX=1 (do last one)
COMP:
        REPE    CMPSB
        JZ      RET5
; Compare error. Print address, value; value, address.
        DEC     SI
        CALL    OUTSI
        CALL    BLANK
        CALL    BLANK
        LODSB
        CALL    HEX
        CALL    BLANK
        CALL    BLANK
        DEC     DI
        MOV     AL,ES:[DI]
        CALL    HEX
        CALL    BLANK
        CALL    BLANK
        CALL    OUTDI
        INC     DI
        CALL    CRLF
        XOR     AL,AL
        JMP     SHORT COMP

ZTRACE:
IF ZIBO
; just like trace except skips OVER next INT or CALL.
        CALL    SETADD                  ; get potential starting point
        CALL    GETEOL                  ; check for end of line
        MOV     [TCOUNT],1              ; only a single go at it
        MOV     ES,[CSSAVE]             ; point to instruction to execute
        MOV     DI,[IPSAVE]             ; include offset in segment
        XOR     DX,DX                   ; where to place breakpoint
        MOV     AL,ES:[DI]              ; get the opcode
        CMP     AL,11101000B            ; direct intra call
        JZ      ZTrace3                 ; yes, 3 bytes
        CMP     AL,10011010B            ; direct inter call
        JZ      ZTrace5                 ; yes, 5 bytes
        CMP     AL,11111111B            ; indirect?
        JZ      ZTraceModRM             ; yes, go figure length
        CMP     AL,11001100B            ; short interrupt?
        JZ      ZTrace1                 ; yes, 1 byte
        CMP     AL,11001101B            ; long interrupt?
        JZ      ZTrace2                 ; yes, 2 bytes
        CMP     AL,11100010B            ; loop
        JZ      ZTrace2                 ; 2 byter
        CMP     AL,11100001B            ; loopz/loope
        JZ      ZTrace2                 ; 2 byter
        CMP     AL,11100000B            ; loopnz/loopne
        JZ      ZTrace2                 ; 2 byter
        AND     AL,11111110B            ; check for rep
        CMP     AL,11110010B            ; perhaps?
        JNZ     Step                    ; can't do anything special, step
        MOV     AL,ES:[DI+1]            ; next instruction
        AND     AL,11111110B            ; ignore w bit
        CMP     AL,10100100B            ; MOVS
        JZ      ZTrace2                 ; two byte
        CMP     AL,10100110B            ; CMPS
        JZ      ZTrace2                 ; two byte
        CMP     AL,10101110B            ; SCAS
        JZ      ZTrace2                 ; two byte
        CMP     AL,10101100B            ; LODS
        JZ      ZTrace2                 ; two byte
        CMP     AL,10101010B            ; STOS
        JZ      ZTrace2                 ; two byte
        JMP     Step                    ; bogus, do single step

ZTraceModRM:
        MOV     AL,ES:[DI+1]            ; get next byte
        AND     AL,11111000B            ; get mod and type
        CMP     AL,01010000B            ; indirect intra 8 bit offset?
        JZ      ZTrace3                 ; yes, three byte whammy
        CMP     AL,01011000B            ; indirect inter 8 bit offset
        JZ      ZTrace3                 ; yes, three byte guy
        CMP     AL,10010000B            ; indirect intra 16 bit offset?
        JZ      ZTrace4                 ; four byte offset
        CMP     AL,10011000B            ; indirect inter 16 bit offset?
        JZ      ZTrace4                 ; four bytes
        JMP     Step                    ; can't figger out what this is!
ZTrace5:INC     DX
ZTrace4:INC     DX
ZTrace3:INC     DX
ZTrace2:INC     DX
ZTrace1:INC     DX
        ADD     DI,DX                   ; offset to breakpoint instruction
        MOV     WORD PTR [BPTab],DI     ; save offset
        MOV     WORD PTR [BPTab+2],ES   ; save segment
        MOV     AL,ES:[DI]              ; get next opcode byte
        MOV     BYTE PTR [BPTab+4],AL   ; save it
        MOV     BYTE PTR ES:[DI],0CCh   ; break point it
        MOV     [BrkCnt],1              ; only this breakpoint
        JMP     DExit                   ; start the operation!
        ENDIF

; Trace 1 instruction or the number of instruction specified
; by the parameter using 8086 trace mode. Registers are all
; set according to values in save area

TRACE:
        CALL    SETADD
        CALL    SCANP
        CALL    HEXIN
        MOV     DX,1
        JC      STOCNT
        MOV     CX,4
        CALL    GETHEX
STOCNT:
        MOV     [TCOUNT],DX
        CALL    GETEOL
STEP:
        MOV     [BRKCNT],0
        OR      BYTE PTR [FSAVE+1],1
DEXIT:
IF  NOT SYSVER
        MOV     BX,[USER_PROC_PDB]
        MOV     AH,SET_CURRENT_PDB
        INT     21H
ENDIF
        PUSH    DS
        XOR     AX,AX
        MOV     DS,AX
        MOV     WORD PTR DS:[12],OFFSET DG:BREAKFIX ; Set vector 3--breakpoint instruction
        MOV     WORD PTR DS:[14],CS
        MOV     WORD PTR DS:[4],OFFSET DG:REENTER   ; Set vector 1--Single step
        MOV     WORD PTR DS:[6],CS
        CLI

        IF      SETCNTC
        MOV     WORD PTR DS:[8CH],OFFSET DG:CONTC   ; Set vector 23H (CTRL-C)
        MOV     WORD PTR DS:[8EH],CS
        ENDIF

        POP     DS
        MOV     SP,OFFSET DG:STACK
        POP     AX
        POP     BX
        POP     CX
        POP     DX
        POP     BP
        POP     BP
        POP     SI
        POP     DI
        POP     ES
        POP     ES
        POP     SS
        MOV     SP,[SPSAVE]
        PUSH    [FSAVE]
        PUSH    [CSSAVE]
        PUSH    [IPSAVE]
        MOV     DS,[DSSAVE]
        IRET
STEP1:
        CALL    CRLF
        CALL    DISPREG
        JMP     SHORT STEP

; Re-entry point from CTRL-C. Top of stack has address in 86-DOS for
; continuing, so we must pop that off.

CONTC:
        ADD     SP,6
        JMP     SHORT ReEnterReal

; Re-entry point from breakpoint. Need to decrement instruction
; pointer so it points to location where breakpoint actually
; occured.

BREAKFIX:
        PUSH    BP
        MOV     BP,SP
        DEC     WORD PTR [BP].OldIP
        POP     BP
        JMP     ReenterReal

; Re-entry point from trace mode or interrupt during
; execution. All registers are saved so they can be
; displayed or modified.

Interrupt_Frame STRUC
OldBP   DW  ?
OldIP   DW  ?
OldCS   DW  ?
OldF    DW  ?
OlderIP DW  ?
OlderCS DW  ?
OlderF  DW  ?
Interrupt_Frame ENDS

REENTER:
        PUSH    BP
        MOV     BP,SP                   ; get a frame to address from
        PUSH    AX
        MOV     AX,CS
        CMP     AX,[BP].OldCS           ; Did we interrupt ourselves?
        JNZ     GoReEnter               ; no, go reenter
        MOV     AX,[BP].OldIP
        CMP     AX,OFFSET DG:NMIInt     ; interrupt below NMI interrupt?
        JB      GoReEnter               ; yes, go reenter
        CMP     [BP].OLDIP,OFFSET DG:NMIIntEnd
        JAE     GoReEnter               ; interrupt above NMI interrupt?
        POP     AX                      ; restore state
        POP     BP
        SUB     SP,6                    ; switch TRACE and NMI stack frames
        PUSH    BP
        MOV     BP,SP                   ; set up frame
        PUSH    AX                      ; get temp variable
        MOV     AX,[BP].OlderIP         ; get NMI Vector
        MOV     [BP].OldIP,AX           ; stuff in new NMI vector
        MOV     AX,[BP].OlderCS         ; get NMI Vector
        MOV     [BP].OldCS,AX           ; stuff in new NMI vector
        MOV     AX,[BP].OlderF          ; get NMI Vector
        AND     AH,0FEh                 ; turn off Trace if present
        MOV     [BP].OldF,AX            ; stuff in new NMI vector
        MOV     [BP].OlderF,AX
        MOV     [BP].OlderIP,OFFSET DG:ReEnter  ; offset of routine
        MOV     [BP].OlderCS,CS         ; and CS
        POP     AX
        POP     BP
        IRET                            ; go try again
GoReEnter:
        POP     AX
        POP     BP
ReEnterReal:
        MOV     CS:[SPSAVE+SEGDIF],SP
        MOV     CS:[SSSAVE+SEGDIF],SS
        MOV     CS:[FSAVE],CS
        MOV     SS,CS:[FSAVE]
        MOV     SP,OFFSET DG:RSTACK
        PUSH    ES
        PUSH    DS
        PUSH    DI
        PUSH    SI
        PUSH    BP
        DEC     SP
        DEC     SP
        PUSH    DX
        PUSH    CX
        PUSH    BX
        PUSH    AX
        PUSH    SS
        POP     DS
        MOV     SS,[SSSAVE]
        MOV     SP,[SPSAVE]
        POP     [IPSAVE]
        POP     [CSSAVE]
        POP     AX
        AND     AH,0FEH                 ; turn off trace mode bit
        MOV     [FSAVE],AX
        MOV     [SPSAVE],SP
        PUSH    DS
        POP     ES
        PUSH    DS
        POP     SS
        MOV     SP,OFFSET DG:STACK
        PUSH    DS
        XOR     AX,AX
        MOV     DS,AX

        IF      SETCNTC
        MOV     WORD PTR DS:[8CH],OFFSET DG:DABORT  ; Set Ctrl-C vector
        MOV     WORD PTR DS:[8EH],CS
        ENDIF

        POP     DS
        STI
        CLD
IF  NOT SYSVER
        MOV     AH,GET_CURRENT_PDB
        INT     21H
        MOV     [USER_PROC_PDB],BX
        MOV     BX,DS
        MOV     AH,SET_CURRENT_PDB
        INT     21H
ENDIF
        DEC     [TCOUNT]
        JZ      CheckDisp
        JMP     Step1
CheckDisp:
        MOV     SI,OFFSET DG:BPTAB
        MOV     CX,[BRKCNT]
        JCXZ    SHOREG
        PUSH    ES
CLEARBP:
        LES     DI,DWORD PTR [SI]
        ADD     SI,4
        MOVSB
        LOOP    CLEARBP
        POP     ES
SHOREG:
        CALL    CRLF
        CALL    DISPREG
        JMP     COMMAND

SETADD:
        MOV     BP,[CSSAVE]
        CALL    SCANP
        CMP     BYTE PTR [SI],"="
        JNZ     RET$5
        INC     SI
        CALL    ADDRESS
        MOV     [CSSAVE],AX
        MOV     [IPSAVE],DX
RET$5:  RET

; Jump to program, setting up registers according to the
; save area. up to 10 breakpoint addresses may be specified.

GO:
        CALL    SETADD
        XOR     BX,BX
        MOV     DI,OFFSET DG:BPTAB
GO1:
        CALL    SCANP
        JZ      DEXEC
        MOV     BP,[CSSAVE]
        CALL    ADDRESS
        MOV     [DI],DX                 ; Save offset
        MOV     [DI+2],AX               ; Save segment
        ADD     DI,5                    ; Leave a little room
        INC     BX
        CMP     BX,1+BPMAX
        JNZ     GO1
        MOV     AX,5000H+"B"            ; BP ERROR
        JMP     ERR
DEXEC:
        MOV     [BRKCNT],BX
        MOV     CX,BX
        JCXZ    NOBP
        MOV     DI,OFFSET DG:BPTAB
        PUSH    DS
SETBP:
        LDS     SI,ES:DWORD PTR [DI]
        ADD     DI,4
        MOVSB
        MOV     BYTE PTR [SI-1],0CCH
        LOOP    SETBP
        POP     DS
NOBP:
        MOV     [TCOUNT],1
        JMP     DEXIT

SKIP_FILE:
        MOV     AH,CHAR_OPER
        INT     21H
        MOV     [SWITCHAR],DL           ; GET THE CURRENT SWITCH CHARACTER
FIND_DELIM:
        LODSB
        CALL    DELIM1
        JZ      GOTDELIM
        CALL    DELIM2
        JNZ     FIND_DELIM
GOTDELIM:
        DEC     SI
        RET

PREPNAME:
        MOV     ES,DSSAVE
        PUSH    SI
        MOV     DI,81H
COMTAIL:
        LODSB
        STOSB
        CMP     AL,13
        JNZ     COMTAIL
        SUB     DI,82H
        XCHG    AX,DI
        MOV     ES:(BYTE PTR [80H]),AL
        POP     SI
        MOV     DI,FCB
        MOV     AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
        INT     21H
        MOV     BYTE PTR [AXSAVE],AL    ; Indicate analysis of first parm
        CALL    SKIP_FILE
        MOV     DI,6CH
        MOV     AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
        INT     21H
        MOV     BYTE PTR [AXSAVE+1],AL  ; Indicate analysis of second parm
RET23:  RET


;  OPENS A XENIX PATHNAME SPECIFIED IN THE UNFORMATTED PARAMETERS
;  VARIABLE [XNXCMD] SPECIFIES WHICH COMMAND TO OPEN IT WITH
;
;  VARIABLE [HANDLE] CONTAINS THE HANDLE
;  VARIABLE [EXTPTR] POINTS TO THE FILES EXTENSION

DELETE_A_FILE:
        MOV     BYTE PTR [XNXCMD],UNLINK
        JMP     SHORT OC_FILE

PARSE_A_FILE:
        MOV     BYTE PTR [XNXCMD],0
        JMP     SHORT OC_FILE

EXEC_A_FILE:
        MOV     BYTE PTR [XNXCMD],EXEC
        MOV     BYTE PTR [XNXOPT],1
        JMP     SHORT OC_FILE

OPEN_A_FILE:
        MOV     BYTE PTR [XNXCMD],OPEN
        MOV     BYTE PTR [XNXOPT],2     ; Try read write
        CALL    OC_FILE
        JNC     RET23
        MOV     BYTE PTR [XNXCMD],OPEN
        MOV     BYTE PTR [XNXOPT],0     ; Try read only
        JMP     SHORT OC_FILE

CREATE_A_FILE:
        MOV     BYTE PTR [XNXCMD],CREAT

OC_FILE:
        PUSH    DS
        PUSH    ES
        PUSH    AX
        PUSH    BX
        PUSH    CX
        PUSH    DX
        PUSH    SI
        XOR     AX,AX
        MOV     [EXTPTR],AX             ; INITIALIZE POINTER TO EXTENSIONS
        MOV     AH,CHAR_OPER
        INT     21H
        MOV     [SWITCHAR],DL           ; GET THE CURRENT SWITCH CHARACTER

        MOV     SI,81H

OPEN1:  CALL    GETCHRUP
        CALL    DELIM2                  ; END OF LINE?
        JZ      OPEN4
        CALL    DELIM1                  ; SKIP LEADING DELIMITERS
        JZ      OPEN1

        MOV     DX,SI                   ; SAVE POINTER TO BEGINNING
        DEC     DX
OPEN2:  CMP     AL,"."                  ; LAST CHAR A "."?
        JNZ     OPEN3
        MOV     [EXTPTR],SI             ; SAVE POINTER TO THE EXTENSION
OPEN3:  CALL    GETCHRUP
        CALL    DELIM1                  ; LOOK FOR END OF PATHNAME
        JZ      OPEN4
        CALL    DELIM2
        JNZ     OPEN2

OPEN4:  DEC     SI                      ; POINT BACK TO LAST CHAR
        PUSH    [SI]                    ; SAVE TERMINATION CHAR
        MOV     BYTE PTR [SI],0         ; NULL TERMINATE THE STRING

        MOV     AL,[XNXOPT]
        MOV     AH,[XNXCMD]             ; OPEN OR CREATE FILE
        OR      AH,AH
        JZ      OPNRET
        MOV     BX,OFFSET DG:EXEC_BLOCK
        XOR     CX,CX
        INT     21H
        MOV     CS:[HANDLE],AX          ; SAVE ERROR CODE OR HANDLE

OPNRET: POP     [SI]

        POP     SI
        POP     DX
        POP     CX
        POP     BX
        POP     AX
        POP     ES
        POP     DS
        RET

GETCHRUP:
        LODSB
        CMP     AL,"a"
        JB      GCUR
        CMP     AL,"z"
        JA      GCUR
        SUB     AL,32
        MOV     [SI-1],AL
GCUR:   RET

DELIM0: CMP     AL,"["
        JZ      LIMRET
DELIM1: CMP     AL," "                  ; SKIP THESE GUYS
        JZ      LIMRET
        CMP     AL,";"
        JZ      LIMRET
        CMP     AL,"="
        JZ      LIMRET
        CMP     AL,9
        JZ      LIMRET
        CMP     AL,","
        JMP     SHORT LIMRET

DELIM2: CMP     AL,[SWITCHAR]           ; STOP ON THESE GUYS
        JZ      LIMRET
        CMP     AL,13
LIMRET: RET

NAME:
        CALL    PREPNAME
        MOV     AL,BYTE PTR AXSAVE
        MOV     PARSERR,AL
        PUSH    ES
        POP     DS
        PUSH    CS
        POP     ES
        MOV     SI,FCB                  ; DS:SI points to user FCB
        MOV     DI,SI                   ; ES:DI points to DEBUG FCB
        MOV     CX,82
        REP     MOVSW
RET6:   RET

BADNAM:
        MOV     DX,OFFSET DG:NAMBAD
        JMP     RESTART

IFHEX:
        CMP     BYTE PTR [PARSERR],-1   ; Invalid drive specification?
        JZ      BADNAM
        CALL    PARSE_A_FILE
        MOV     BX,[EXTPTR]
        CMP     WORD PTR DS:[BX],"EH"   ; "HE"
        JNZ     RET6
        CMP     BYTE PTR DS:[BX+2],"X"
        RET

IFEXE:
        PUSH    BX
        MOV     BX,[EXTPTR]
        CMP     WORD PTR DS:[BX],"XE"   ; "EX"
        JNZ     RETIF
        CMP     BYTE PTR DS:[BX+2],"E"
RETIF:  POP     BX
        RET

LOAD:
        MOV     BYTE PTR [RDFLG],READ
        JMP     SHORT DSKIO

DWRITE:
        MOV     BYTE PTR [RDFLG],WRITE
DSKIO:
        MOV     BP,[CSSAVE]
        CALL    SCANB
        JNZ     PRIMIO
        JMP     DEFIO
PRIMIO: CALL    ADDRESS
        CALL    SCANB
        JNZ     PRMIO
        JMP     FILEIO
PRMIO:  PUSH    AX                      ; Save segment
        MOV     BX,DX                   ; Put displacement in proper register
        MOV     CX,1
        CALL    GETHEX                  ; Drive number must be 1 digit
        PUSH    DX
        MOV     CX,4
        CALL    GETHEX                  ; Logical record number
        PUSH    DX
        MOV     CX,3
        CALL    GETHEX                  ; Number of records
        CALL    GETEOL
        MOV     CX,DX
        POP     DX                      ; Logical record number
        POP     AX                      ; Drive number
        CBW                             ; Turn off verify after write
        MOV     BYTE PTR DRVLET,AL      ; Save drive in case of error
        PUSH    AX
        PUSH    BX
        PUSH    DX
        MOV     DL,AL
        INC     DL
        MOV     AH,GET_DPB
        INT     21H
        POP     DX
        POP     BX
        OR      AL,AL
        POP     AX
        POP     DS                      ; Segment of transfer
        JNZ     DRVERRJ
        CMP     CS:BYTE PTR [RDFLG],WRITE
        JZ      ABSWRT
        INT     25H                     ; Primitive disk read
        JMP     SHORT ENDABS

ABSWRT:
        INT     26H                     ; Primitive disk write
ENDABS:
        JNC     RET0
DRVERRJ: JMP    DRVERR

RET0:
        POPF
        RET

DEFIO:
        MOV     AX,[CSSAVE]             ; Default segment
        MOV     DX,100H                 ; Default file I/O offset
        CALL    IFHEX
        JNZ     EXECHK
        XOR     DX,DX                   ; If HEX file, default OFFSET is zero
HEX2BINJ:JMP    HEX2BIN

FILEIO:
; AX and DX have segment and offset of transfer, respectively
        CALL    IFHEX
        JZ      HEX2BINJ
EXECHK:
        CALL    IFEXE
        JNZ     BINFIL
        CMP     BYTE PTR [RDFLG],READ
        JZ      EXELJ
        MOV     DX,OFFSET DG:EXEWRT
        JMP     RESTART                 ; Can't write .EXE files

BINFIL:
        CMP     BYTE PTR [RDFLG],WRITE
        JZ      BINLOAD
        CMP     WORD PTR DS:[BX],4F00H + "C"    ; "CO"
        JNZ     BINLOAD
        CMP     BYTE PTR DS:[BX+2],"M"
        JNZ     BINLOAD
EXELJ:
        DEC     SI
        CMP     DX,100H
        JNZ     PRER
        CMP     AX,[CSSAVE]
        JZ      OAF
PRER:   JMP     PERROR
OAF:    CALL    OPEN_A_FILE
        JNC     GDOPEN
        MOV     AX,exec_file_not_found
        JMP     EXECERR

GDOPEN: XOR     DX,DX
        XOR     CX,CX
        MOV     BX,[HANDLE]
        MOV     AL,2
        MOV     AH,LSEEK
        INT     21H
        CALL    IFEXE                   ; SUBTRACT 512 BYTES FOR EXE
        JNZ     BIN2                    ; FILE LENGTH BECAUSE OF
        SUB     AX,512                  ; THE HEADER
BIN2:   MOV     [BXSAVE],DX             ; SET UP FILE SIZE IN DX:AX
        MOV     [CXSAVE],AX
        MOV     AH,CLOSE
        INT     21H
        JMP     EXELOAD

NO_MEM_ERR:
        MOV     DX,OFFSET DG:TOOBIG
        MOV     AH,STD_CON_STRING_OUTPUT
        INT     21H
        JMP     COMMAND

WRTFILEJ: JMP   WRTFILE
NOFILEJ: JMP    NOFILE

BINLOAD:
        PUSH    AX
        PUSH    DX
        CMP     BYTE PTR [RDFLG],WRITE
        JZ      WRTFILEJ
        CALL    OPEN_A_FILE
        JC      NOFILEJ
        MOV     BX,[HANDLE]
        MOV     AX,(LSEEK SHL 8) OR 2
        XOR     DX,DX
        MOV     CX,DX
        INT     21H                     ; GET SIZE OF FILE
        MOV     SI,DX
        MOV     DI,AX                   ; SIZE TO SI:DI
        MOV     AX,(LSEEK SHL 8) OR 0
        XOR     DX,DX
        MOV     CX,DX
        INT     21H                     ; RESET POINTER BACK TO BEGINNING
        POP     AX
        POP     BX
        PUSH    BX
        PUSH    AX                      ; TRANS ADDR TO BX:AX
        ADD     AX,15
        MOV     CL,4
        SHR     AX,CL
        ADD     BX,AX                   ; Start of transfer rounded up to seg
        MOV     DX,SI
        MOV     AX,DI                   ; DX:AX is size
        MOV     CX,16
        DIV     CX
        OR      DX,DX
        JZ      NOREM
        INC     AX
NOREM:                                  ; AX is number of paras in transfer
        ADD     AX,BX                   ; AX is first seg that need not exist
        CMP     AX,CS:[PDB_block_len]
        JA      NO_MEM_ERR
        MOV     CXSAVE,DI
        MOV     BXSAVE,SI
        POP     DX
        POP     AX

RDWR:
; AX:DX is disk transfer address (segment:offset)
; SI:DI is length (32-bit number)

RDWRLOOP:
        MOV     BX,DX                   ; Make a copy of the offset
        AND     DX,000FH                ; Establish the offset in 0H-FH range
        MOV     CL,4
        SHR     BX,CL                   ; Shift offset and
        ADD     AX,BX                   ; Add to segment register to get new Seg:offset
        PUSH    AX
        PUSH    DX                      ; Save AX,DX register pair
        MOV     WORD PTR [TRANSADD],DX
        MOV     WORD PTR [TRANSADD+2],AX
        MOV     CX,0FFF0H               ; Keep request in segment
        OR      SI,SI                   ; Need > 64K?
        JNZ     BIGRDWR
        MOV     CX,DI                   ; Limit to amount requested
BIGRDWR:
        PUSH    DS
        PUSH    BX
        MOV     BX,[HANDLE]
        MOV     AH,[RDFLG]
        LDS     DX,[TRANSADD]
        INT     21H                     ; Perform read or write
        POP     BX
        POP     DS
        JC      BADWR
        CMP     BYTE PTR [RDFLG],WRITE
        JNZ     GOODR
        CMP     CX,AX
        JZ      GOODR
BADWR:  MOV     CX,AX
        STC
        POP     DX                      ; READ OR WRITE BOMBED OUT
        POP     AX
        RET

GOODR:
        MOV     CX,AX
        SUB     DI,CX                   ; Request minus amount transferred
        SBB     SI,0                    ; Ripple carry
        OR      CX,CX                   ; End-of-file?
        POP     DX                      ; Restore DMA address
        POP     AX
        JZ      RET8
        ADD     DX,CX                   ; Bump DMA address by transfer length
        MOV     BX,SI
        OR      BX,DI                   ; Finished with request
        JNZ     RDWRLOOP
RET8:   CLC                             ; End-of-file not reached
        RET

NOFILE:
        MOV     DX,OFFSET DG:NOTFND
RESTARTJMP:
        JMP     RESTART

WRTFILE:
        CALL    CREATE_A_FILE           ; Create file we want to write to
        MOV     DX,OFFSET DG:NOROOM     ; Creation error - report error
        JC      RESTARTJMP
        MOV     SI,BXSAVE               ; Get high order number of bytes to transfer
        CMP     SI,000FH
        JLE     WRTSIZE                 ; Is bx less than or equal to FH
        XOR     SI,SI                   ; Ignore BX if greater than FH - set to zero
WRTSIZE:
        MOV     DX,OFFSET DG:WRTMES1    ; Print number bytes we are writing
        CALL    RPRBUF
        OR      SI,SI
        JZ      NXTBYT
        MOV     AX,SI
        CALL    DIGIT
NXTBYT:
        MOV     DX,CXSAVE
        MOV     DI,DX
        CALL    OUT16                   ; Amount to write is SI:DI
        MOV     DX,OFFSET DG:WRTMES2
        CALL    RPRBUF
        POP     DX
        POP     AX
        CALL    RDWR
        JNC     CLSFLE
        CALL    CLSFLE
        CALL    DELETE_A_FILE
        MOV     DX,OFFSET DG:NOSPACE
        JMP     RESTARTJMP
        CALL    CLSFLE
        JMP     COMMAND

CLSFLE:
        MOV     AH,CLOSE
        MOV     BX,[HANDLE]
        INT     21H
        RET

EXELOAD:
        POP     [RETSAVE]               ; Suck up return addr
        INC     BYTE PTR [NEWEXEC]
        MOV     BX,[USER_PROC_PDB]
        MOV     AX,DS
        CMP     AX,BX
        JZ      DEBUG_CURRENT
        JMP     FIND_DEBUG

DEBUG_CURRENT:
        MOV     AX,[DSSAVE]
DEBUG_FOUND:
        MOV     BYTE PTR [NEWEXEC],0
        MOV     [HEADSAVE],AX
        PUSH    [RETSAVE]               ; Get the return address back
        PUSH    AX
        MOV     BX,CS
        SUB     AX,BX
        PUSH    CS
        POP     ES
        MOV     BX,AX
        ADD     BX,10H                  ; RESERVE HEADER
        MOV     AH,SETBLOCK
        INT     21H
        POP     AX
        MOV     WORD PTR [COM_LINE+2],AX
        MOV     WORD PTR [COM_FCB1+2],AX
        MOV     WORD PTR [COM_FCB2+2],AX

        CALL    EXEC_A_FILE
        JC      EXECERR
        CALL    SET_TERMINATE_VECTOR    ; Reset int 22
        MOV     AH,GET_CURRENT_PDB
        INT     21H
        MOV     [USER_PROC_PDB],BX
        MOV     [DSSAVE],BX
        MOV     [ESSAVE],BX
        MOV     ES,BX
        MOV     WORD PTR ES:[PDB_exit],OFFSET DG:TERMINATE
        MOV     WORD PTR ES:[PDB_exit+2],DS
        LES     DI,[COM_CSIP]
        MOV     [CSSAVE],ES
        MOV     [IPSAVE],DI
        MOV     WORD PTR [DISADD+2],ES
        MOV     WORD PTR [DISADD],DI
        MOV     WORD PTR [ASMADD+2],ES
        MOV     WORD PTR [ASMADD],DI
        MOV     WORD PTR [DEFDUMP+2],ES
        MOV     WORD PTR [DEFDUMP],DI
        MOV     BX,DS
        MOV     AH,SET_CURRENT_PDB
        INT     21H
        LES     DI,[COM_SSSP]
        MOV     AX,ES:[DI]
        INC     DI
        INC     DI
        MOV     [AXSAVE],AX
        MOV     [SSSAVE],ES
        MOV     [SPSAVE],DI
        RET

EXECERR:
        MOV     DX,OFFSET DG:NOTFND
        CMP     AX,exec_file_not_found
        JZ      GOTEXECEMES
        MOV     DX,OFFSET DG:ACCMES
        CMP     AX,error_access_denied
        JZ      GOTEXECEMES
        MOV     DX,OFFSET DG:TOOBIG
        CMP     AX,exec_not_enough_memory
        JZ      GOTEXECEMES
        MOV     DX,OFFSET DG:EXEBAD
        CMP     AX,exec_bad_format
        JZ      GOTEXECEMES
        MOV     DX,OFFSET DG:EXECEMES
GOTEXECEMES:
        MOV     AH,STD_CON_STRING_OUTPUT
        INT     21H
        JMP     COMMAND

HEX2BIN:
        MOV     [INDEX],DX
        MOV     DX,OFFSET DG:HEXWRT
        CMP     BYTE PTR [RDFLG],WRITE
        JNZ     RDHEX
        JMP     RESTARTJ2
RDHEX:
        MOV     ES,AX
        CALL    OPEN_A_FILE
        MOV     DX,OFFSET DG:NOTFND
        JNC     HEXFND
        JMP     RESTART
HEXFND:
        XOR     BP,BP
        MOV     SI,OFFSET DG:(BUFFER+BUFSIZ)    ; Flag input buffer as empty
READHEX:
        CALL    GETCH
        CMP     AL,":"                  ; Search for : to start line
        JNZ     READHEX
        CALL    GETBYT                  ; Get byte count
        MOV     CL,AL
        MOV     CH,0
        JCXZ    HEXDONE
        CALL    GETBYT                  ; Get high byte of load address
        MOV     BH,AL
        CALL    GETBYT                  ; Get low byte of load address
        MOV     BL,AL
        ADD     BX,[INDEX]              ; Add in offset
        MOV     DI,BX
        CALL    GETBYT                  ; Throw away type byte
READLN:
        CALL    GETBYT                  ; Get data byte
        STOSB
        CMP     DI,BP                   ; Check if this is the largest address so far
        JBE     HAVBIG
        MOV     BP,DI                   ; Save new largest
HAVBIG:
        LOOP    READLN
        JMP     SHORT READHEX

GETCH:
        CMP     SI,OFFSET DG:(BUFFER+BUFSIZ)
        JNZ     NOREAD
        MOV     DX,OFFSET DG:BUFFER
        MOV     SI,DX
        MOV     AH,READ
        PUSH    BX
        PUSH    CX
        MOV     CX,BUFSIZ
        MOV     BX,[HANDLE]
        INT     21H
        POP     CX
        POP     BX
        OR      AX,AX
        JZ      HEXDONE
NOREAD:
        LODSB
        CMP     AL,1AH
        JZ      HEXDONE
        OR      AL,AL
        JNZ     RET7
HEXDONE:
        MOV     [CXSAVE],BP
        MOV     BXSAVE,0
        RET

HEXDIG:
        CALL    GETCH
        CALL    HEXCHK
        JNC     RET7
        MOV     DX,OFFSET DG:HEXERR
RESTARTJ2:
        JMP     RESTART

GETBYT:
        CALL    HEXDIG
        MOV     BL,AL
        CALL    HEXDIG
        SHL     BL,1
        SHL     BL,1
        SHL     BL,1
        SHL     BL,1
        OR      AL,BL
RET7:   RET


CODE    ENDS
        END     DEBCOM2