-
Notifications
You must be signed in to change notification settings - Fork 3
/
debug.asm
2536 lines (2423 loc) · 63.9 KB
/
debug.asm
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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DEBUG - Bare bones debugger for real mode x86 ;;
;; ;;
;; Copyright 2019 Michael Rasmussen ;;
;; See LICENSE.md for details ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Tries to support roughly what old-school debug.com
;; for DOS does.
;;
;; The disassembly functions assumes ES points to DisSeg
;;
;; TODO: Implement missing commands
;; TODO: Unify range handling (and allow for ffff as end..)
;; TODO: Allow starting without file
;;
org 0x100
cpu 8086
STACK_SIZE equ 512
DEFAULT_DIS_SIZE equ 0x20 ; Note: ranges are inclusive, so atleast this many bytes are unassembled
PSP_OLDINT22 equ 0x0A ; DWORD Old Int22 (Termination handler)
BP_OFF equ 0 ; WORD Breakpoint offset
BP_SEG equ 2 ; WORD Breakpoint segment
BP_OLDVAL equ 4 ; BYTE Previous byte at breakpoint position
BP_SIZE equ 5 ; Size of break point structure
BP_MAX equ 10 ; Maximum number of breakpoints
PREFIX_LOCK equ 0x01
PREFIX_F2 equ 0x02 ; REPNE/REPNZ
PREFIX_F3 equ 0x04 ; REPE/REPZ
PREFIX_ES equ 0x08
PREFIX_CS equ 0x10
PREFIX_SS equ 0x20
PREFIX_DS equ 0x40
OTYPE_AL equ 0x00
OTYPE_CL equ 0x01
OTYPE_DL equ 0x02
OTYPE_BL equ 0x03
OTYPE_AH equ 0x04
OTYPE_CH equ 0x05
OTYPE_DH equ 0x06
OTYPE_BH equ 0x07
OTYPE_AX equ 0x08
OTYPE_CX equ 0x09
OTYPE_DX equ 0x0A
OTYPE_BX equ 0x0B
OTYPE_SP equ 0x0C
OTYPE_BP equ 0x0D
OTYPE_SI equ 0x0E
OTYPE_DI equ 0x0F
OTYPE_ES equ 0x10
OTYPE_CS equ 0x11
OTYPE_SS equ 0x12
OTYPE_DS equ 0x13
OTYPE_1 equ 0x14 ; Constant 1
OTYPE_IMM8 equ 0x20
OTYPE_IMM16 equ 0x21
OTYPE_REL8 equ 0x22
OTYPE_REL16 equ 0x23
OTYPE_RM8 equ 0x40 ; r/m part of ModRM
OTYPE_RM16 equ 0x41
OTYPE_R8 equ 0x42 ; /r part of ModRM
OTYPE_R16 equ 0x43
OTYPE_SREG equ 0x44
OTYPE_RTAB equ 0x45 ; /r selects opcode from table
OTYPE_MOFF equ 0x80
OTYPE_PTR32 equ 0x81
OTYPE_NONE equ 0xFF
OTYPE_MASK_IMM equ 0x20
OTYPE_MASK_MODRM equ 0x40
Start:
; Clear BSS
mov di, BssStart
mov cx, ProgramEnd
sub cx, di
xor ax, ax
rep stosb
cli
mov bx, ProgramEnd
add bx, 15
and bx, 0xFFF0
add bx, STACK_SIZE
mov sp, bx
mov [DbgSP], sp
mov cl, 4
shr bx, cl
mov ax, ds
add bx, ax
sti
; Free remaining memory
mov ah, 0x4a
int 0x21
; Install single step handler
mov ax, SingleStep
mov dx, cs
mov bl, 1
call SetIntVec
mov [OldInt1], ax
mov [OldInt1+2], dx
; And breakpoint handler
mov ax, Breakpoint
mov dx, cs
mov bl, 3
call SetIntVec
mov [OldInt3], ax
mov [OldInt3+2], dx
;
; Handle command line
;
; Command line arguments always need DS
mov [PB_ArgPtr+2], ds
push ds
pop es
mov si, 0x81
.SkipSpace:
lodsb
cmp al, 0x0D
jne .NotDone
;.Usage:
mov dx, MsgErrUsage
jmp Fatal
.NotDone:
cmp al, ' '
jbe .SkipSpace
; Copy filename
mov di, FileName
stosb
; TODO: Limit to 12...
.CopyFname:
lodsb
cmp al, ' '
jbe .CopyDone
stosb
jmp .CopyFname
.CopyDone:
mov ah, al
xor al, al
stosb ; Ensure NUL terimnated
cmp ah, 0x0D
jne .ProcessArgs
; No additional arguments
mov si, EmptyArgsLen
jmp short .GotArgs
.ProcessArgs:
; Adjust length
mov bx, si
sub bx, 0x81
xor ah, ah
mov al, [0x80]
sub ax, bx
dec si
mov [si], al
.GotArgs:
mov [PB_ArgPtr], si
push ds
pop es
mov dx, FileName
mov bx, ParameterBlock
mov ax, 0x4B01
int 0x21
jnc .LoadOK
call PutHexWord
mov dx, MsgErrLoad
jmp Fatal
.LoadOK:
; Get current PSP address
mov ah, 0x62
int 0x21
mov [CodeSeg], bx
; Set termination handler
mov es, bx
mov word [es:PSP_OLDINT22], TerminateHandler
mov [es:PSP_OLDINT22+2], cs
; Initialize program registers etc.
mov ax, [PB_ChildCSIP]
mov bx, [PB_ChildCSIP+2]
mov [DisOff], ax
mov [DisSeg], bx
mov [DumpOff], ax
mov [DumpSeg], bx
mov [Prog_SI], ax ; SI=0x0100
mov [Prog_DX], bx ; DX=CS
mov [Prog_IP], ax ; IP=0x0100
mov [Prog_ES], bx ; ES=CS
mov [Prog_CS], bx
mov [Prog_DS], bx ; DS=CS
mov es, [PB_ChildSSSP+2]
mov [Prog_SS], es ; SS
xor ax, ax
mov [Prog_BX], ax ; BX=0x0000 (TODO: DOS DEBUG.COM stores file size in BX:CX)
mov word [Prog_CX], 0x00FF ; CX=0x00FF
mov bx, [PB_ChildSSSP]
; DOS pushes initial AX onto stack when using AX=4E01
mov ax, [es:bx]
mov [Prog_AX], ax
add bx, 2 ; Pop it off
mov [Prog_DI], bx ; DI=SP
mov [Prog_SP], bx ; SP=0xFFFE (usually)
mov word [Prog_F], 0x0202 ; Interrupts enabled
CommandLoop:
xor ax, ax
mov [TraceCount], ax
mov [ProceedCount], ax
mov [BPCount], al
mov [LastCause], al
; Print prompt
mov al, '-'
call PutChar
call ReadCommand
jc CommandLoop ; Blank line
call CommandDispatch
jmp CommandLoop
PutChar:
push ax
push dx
mov dl, al
mov ah, 2
int 0x21
pop dx
pop ax
ret
PutSpace:
push ax
mov al, ' '
call PutChar
pop ax
ret
PutCrLf:
push ax
mov al, 13
call PutChar
mov al, 10
call PutChar
pop ax
ret
; Print dword in DX:AX
PutHexDword:
push ax
mov ax, dx
call PutHexWord
mov al, ':'
call PutChar
pop ax
; Print word in AX
PutHexWord:
push ax
mov al, ah
call PutHexByte
pop ax
PutHexByte:
push ax
shr al, 1
shr al, 1
shr al, 1
shr al, 1
call PutHexDigit
pop ax
PutHexDigit:
push ax
and al, 0x0f
add al, '0'
cmp al, '9'
jbe .Pr
add al, 7
.Pr:
call PutChar
pop ax
ret
; Print '$'-terminated string in DS:DX
PutString:
push ax
mov ah, 9
int 0x21
pop ax
ret
Fatal:
push cs
pop ds
call PutString
mov al, 0xFF
Exit:
push ax
; Restore old Int1 handler
mov dx, [OldInt1]
mov ax, [OldInt1+2]
mov bl, 1
call SetIntVec
; Restore old Int3 handler
mov dx, [OldInt3]
mov ax, [OldInt3+2]
mov bl, 3
call SetIntVec
pop ax
mov ah, 0x4C
int 0x21
; Set interrupt vector BL to DX:AX, return old vector in DX:AX
SetIntVec:
xor bh, bh
shl bx, 1
shl bx, 1
xor cx, cx
mov es, cx
xchg ax, [es:bx]
xchg dx, [es:bx+2]
ret
TerminateHandler:
cli
; Take care to ensure a valid stack
; Even when exiting
mov ax, cs
mov ds, ax
mov ss, ax
mov sp, [DbgSP]
sti
cmp byte [LastCause], 'Q'
jne .NotQuit
mov ax, 0x4c00
int 0x21
.NotQuit:
mov dx, MsgProgramExit
call PutString
mov ah, 0x4d
int 0x21
push ax
call PutHexWord
call PutCrLf
pop ax
jmp Exit ; Exit for now..
Breakpoint:
mov byte [cs:LastCause], 3
jmp short IntCommon
SingleStep:
mov byte [cs:LastCause], 1
; Fall through
IntCommon:
cld
mov [cs:Prog_DS], ds
push cs
pop ds
mov [Prog_SS], ss
mov [Prog_AX], ax
mov [Prog_CX], cx
mov [Prog_DX], dx
mov [Prog_BX], bx
mov [Prog_BP], bp
mov [Prog_SI], si
mov [Prog_DI], di
mov [Prog_ES], es
pop ax
mov [Prog_IP], ax
pop ax
mov [Prog_CS], ax
pop ax
and ah, 0xFE ; Clear trap flag
mov [Prog_F], ax
mov [Prog_SP], sp ; We'll push flags/cs/ip again
mov ax, cs
mov ss, ax
mov sp, [DbgSP]
sti
; Remove all breakpoints
; And adjust CS/IP if caused by breakpoint
xor ch, ch
call RemBreakpoints
; Print registers/next instruction
mov si, EmptyArgs
call Regs
; Are we doing Proceed with a count?
cmp word [ProceedCount], 0
je .CheckTrace
dec word [ProceedCount]
jmp StartProceed
.CheckTrace:
; Is trace with count in progress?
cmp word [TraceCount], 0
je .Done
dec word [TraceCount]
jmp StartTrace
.Done:
jmp CommandLoop
; CH=0 = Adjust CS/IP if matching BP found
RemBreakpoints:
mov cl, [BPCount]
and cl, cl
jz .Done
mov si, BreakPoints
mov dx, [Prog_IP]
.L:
mov di, [si+BP_OFF]
mov es, [si+BP_SEG]
mov al, [si+BP_OLDVAL]
stosb
and ch, ch
jnz .N ; Already found breakpoint
cmp di, dx
jne .N
mov ax, es
cmp ax, [Prog_CS]
jne .N
dec word [Prog_IP]
inc ch
.N:
add si, BP_SIZE
dec cl
jnz .L
mov [BPCount], cl
.Done:
ret
; Read line to CmdBuffer, returns SI pointing to first non-blank char
; Returns carry clear if non-empty
ReadCommand:
; Read command line
mov bx, CmdBuffer
mov word [bx], 0x7F
mov dx, bx
mov ah, 0x0a
int 0x21
call PutCrLf
mov si, CmdBuffer+2
; Convert to upper case
mov cl, [si-1]
and cl, cl
jz .Blank
xor bx, bx
xor ch, ch
.ToUpper:
mov al, [si+bx]
cmp al, ch
jne .NotEndQ
xor ch, ch
jmp short .Next
.NotEndQ:
cmp al, 0x27 ; quote character
je .Q
cmp al, '"'
jne .NotQ
.Q:
mov ch, al
jmp short .Next
.NotQ:
and ch, ch ; In quoted string? Then don't modify
jnz .Next
cmp al, 'a'
jb .Next
cmp al, 'z'
ja .Next
and al, 0xDF
mov [si+bx], al
.Next:
inc bx
cmp bl, cl
jne .ToUpper
; Unterminated string?
and ch, ch
jz .NotInString
jmp InvalidCommmand
.NotInString:
call CSkipSpaces
cmp byte [si], ' '
jbe .Blank
clc
ret
.Blank:
stc
ret
; SI=Command line
CommandDispatch:
lodsb
push ax
call CSkipSpaces
pop ax
cmp al, 'C'
je .CmdC
cmp al, 'D'
je .CmdD
cmp al, 'E'
je .CmdE
cmp al, 'F'
je .CmdF
cmp al, 'G'
je .CmdG
cmp al, 'H'
je .CmdH
cmp al, 'I'
je .CmdI
cmp al, 'M'
je .CmdM
cmp al, 'O'
je .CmdO
cmp al, 'P'
je .CmdP
cmp al, 'R'
je .CmdR
cmp al, 'S'
je .CmdS
cmp al, 'T'
je .CmdT
cmp al, 'U'
je .CmdU
cmp al, 'Q'
je .CmdQ
jmp short InvalidCommmand
; TODO: A(ssemble)
.CmdC: jmp Compare
.CmdD: jmp Dump
.CmdE: jmp Enter
.CmdF: jmp Fill
.CmdG: jmp Go
.CmdH: jmp Hex
.CmdI: jmp InPort
; TODO: L(oad)
.CmdM: jmp Move
; TODO: N(ame)
.CmdO: jmp OutPort
.CmdP: jmp Proceed
.CmdQ: jmp short Quit
.CmdR: jmp Regs
.CmdS: jmp Search
.CmdT: jmp Trace
.CmdU: jmp Unassemble
;TODO: W(rite)
; Q(uit)
Quit:
mov byte [LastCause], 'Q'
xor al, al
jmp Exit
InvalidCommmand:
mov dx, MsgErrInvCmd
call PutString
call PutCrLf
mov sp, [DbgSP] ; Long jump..
jmp CommandLoop
CSkipSpaces:
lodsb
cmp al, 0x0D
je .Done
cmp al, ' '
jbe CSkipSpaces
.Done:
dec si
ret
; Get number from command line (and update SI) to AX
; Returns carry clear on success
CGetNum:
cmp byte [si], ' '
ja .NotEmpty
stc
ret
.NotEmpty:
push cx
push dx
xor dx, dx
xor ch, ch
mov cl, 4
.L:
lodsb
cmp al, '0'
jb .Done
cmp al, '9'
jbe .OK
cmp al, 'A'
jb .Done
cmp al, 'F'
ja .Done
.OK:
shl dx, cl
sub al, '0'
cmp al, 9
jbe .D
sub al, 7
.D:
or dl, al
inc ch
jmp .L
.Done:
and ch, ch
jnz .CntOK
jmp InvalidCommmand
.CntOK:
dec si
mov ax, dx
pop dx
pop cx
clc
ret
; Get address from command line to DX:AX
; returns carry clear on success
CGetAddress:
cmp word [si+1], 'S:'
jne .NotReg
lodsb
inc si ; Point to ':'
cmp al, 'C'
jne .NotCS
mov ax, [Prog_CS]
jmp short .GetOffset
.NotCS:
cmp al, 'D'
jne .NotDS
mov ax, [Prog_DS]
jmp short .GetOffset
.NotDS:
cmp al, 'E'
jne .NotES
mov ax, [Prog_ES]
jmp short .GetOffset
.NotES:
cmp al, 'S'
jne .Invalid
mov ax, [Prog_SS]
jmp short .GetOffset
.NotReg:
call CGetNum
jc .Done
cmp byte [si], ':'
je .GetOffset
mov dx, [Prog_CS] ; No segment means use current CS
clc
.Done:
ret
.GetOffset:
inc si
mov dx, ax
call CGetNum
jnc .Done
.Invalid:
jmp InvalidCommmand
CGetStartAddress:
cmp byte [si], '='
je .GetAddr
ret
.GetAddr:
inc si
call CGetAddress
jnc .OK
jmp InvalidCommmand
.OK:
mov [Prog_CS], dx
mov [Prog_IP], ax
call CSkipSpaces
ret
; H(ex) value value
Hex:
call CGetNum
jc .Err
push ax
call CSkipSpaces
call CGetNum
pop dx
jc .Err
mov bx, dx
sub bx, ax
add ax, dx
call PutHexWord
call PutSpace
mov ax, bx
call PutHexWord
jmp PutCrLf
.Err:
jmp InvalidCommmand
; I(n) port (Only byte input supported)
InPort:
call CGetNum
jnc .PortOK
jmp InvalidCommmand
.PortOK:
mov dx, ax
in al, dx
call PutHexByte
jmp PutCrLf
; O(ut) port val (Only byte output supported)
OutPort:
call CGetNum
jc .Invalid
push ax
call CSkipSpaces
call CGetNum
jc .Invalid
and ah, ah
jnz .Invalid
pop dx
out dx, al
ret
.Invalid:
jmp InvalidCommmand
; (hex)D(ump) [range] / [address] [length]
Dump:
call .GetDefaultRange
call CGetAddress
jc .DoDump
mov [DumpSeg], dx
mov [DumpOff], ax
call .GetDefaultRange
call CSkipSpaces
mov al, [si]
cmp al, ' '
jbe .DoDump
cmp al, 'L'
jne .CheckRange
inc si
call CGetNum
jc .Err
and ax, ax
jc .Err
mov bp, ax
jmp short .DoDump
.Err:
jmp InvalidCommmand
.GetDefaultRange:
mov bp, [DumpOff]
neg bp
and bp, 0x0F
add bp, 0x80 ; Default length (round up to get paragraph aligned)
ret
.CheckRange:
call CGetNum
jc .DoDump
mov bp, ax
inc bp ; Range is inclusive
sub bp, [DumpOff]
jc .Err
.DoDump:
mov dx, [DumpSeg]
mov es, dx
mov ax, [DumpOff]
add [DumpOff], bp
push ax
and al, 0xF0
call PutHexDword
call PutSpace
pop si
mov di, DumpBuf
mov cx, si
call .Align
.Main:
mov al, [es:si]
mov [di], al
inc di
call PutHexByte
mov bx, si
and bl, 0x0f
mov al, ' '
cmp bl, 7
jne .PrintSep
mov al, '-' ; Hypen between position 8 and 9
.PrintSep:
call PutChar
inc si
dec bp
jz .Done
test si, 0x0f
jnz .Main
call PutSpace
call .PutDumpBuf
mov di, DumpBuf
mov dx, es
mov ax, si
call PutHexDword
call PutSpace
jmp .Main
.Done:
mov cx, si
and cl, 0x0f
jz .NoEndAlign
neg cl
call .Align
.NoEndAlign:
call PutSpace
jmp short .PutDumpBuf
.Align:
and cl, 0x0f
jz .AlignDone
.DoAlign:
call PutSpace
call PutSpace
call PutSpace
mov byte [di], ' '
inc di
dec cl
jnz .DoAlign
.AlignDone:
ret
.PutDumpBuf:
mov di, DumpBuf
mov cl, 16
.Pr:
mov al, [di]
cmp al, ' '
jae .Pr2
mov al, '.'
.Pr2:
call PutChar
inc di
dec cl
jnz .Pr
jmp PutCrLf
; E(nter) address [list]
Enter:
call CGetAddress
jnc .AddrOK
jmp InvalidCommmand
.AddrOK:
mov es, dx
mov di, ax
; Fall through
; Copy list from command line in DS:SI to ES:DI
CopyListFromCmd:
call CSkipSpaces
lodsb
cmp al, 0x0D
jne .NotDone
ret
.NotDone:
cmp al, 0x27
je .CopyLit
cmp al, '"'
je .CopyLit
dec si
call CGetNum
jc .Invalid
and ah, ah
jnz .Invalid
stosb
jmp CopyListFromCmd
.CopyLit:
mov ah, al ; Save opening quote char
.CopyLoop:
lodsb
cmp al, ah
je CopyListFromCmd
stosb
jmp .CopyLoop
.Invalid:
jmp InvalidCommmand
; F(ill) range list
Fill:
call CGetAddress
jnc .AddrOK
.Invalid:
jmp InvalidCommmand
.AddrOK:
; Store address for later
push dx
push ax
mov di, ax
call CSkipSpaces
call CGetNum
jc .Invalid
inc ax
sub ax, di
jbe .Invalid
push ax ; Push length to fill
; Copy list to CmdBuffer (we'll never catch up to SI)
push ds
pop es
mov di, CmdBuffer
call CopyListFromCmd
; How many bytes is the pattern?
mov bx, di
sub bx, CmdBuffer
pop dx
pop di
pop es
.F:
; BX: Bytes in pattern
; DX: Bytes to fill
mov si, CmdBuffer
mov cx, dx
cmp cx, bx
jbe .DoFill
mov cx, bx
.DoFill:
sub dx, cx
rep movsb
and dx, dx
jnz .F
ret
; M(ove) range address
Move:
call CGetAddress
jc .Invalid
push dx
push ax
mov di, ax
call CSkipSpaces
call CGetNum
jc .Invalid
inc ax
sub ax, di
jbe .Invalid
push ax ; Push length
call CSkipSpaces
call CGetAddress
jc .Invalid
mov es, dx
mov di, ax
pop cx
pop si
pop ds
; TODO: Check for overlap...
rep movsb
push cs
pop ds
ret
.Invalid:
jmp InvalidCommmand
; S(earch) range list
Search:
call CGetAddress
jc .Invalid
push dx
push ax
mov di, ax
call CSkipSpaces
call CGetNum
jc .Invalid
inc ax
sub ax, di
jbe .Invalid
push ax ; Push length
; Copy list to CmdBuffer (we'll never catch up to SI)
push ds
pop es
mov di, CmdBuffer
call CopyListFromCmd
mov bx, di
sub bx, CmdBuffer
pop dx
pop di
pop es
xchg bx, bx
.Search:
; BX=Pattern length
; DX=Range length
cmp dx, bx
jb .Done ; Can't match
; Search for first byte in pattern
mov si, CmdBuffer
mov cx, dx
sub cx, bx
push cx
lodsb
repne scasb
pop ax
je .CheckMatch
.Done:
push cs
pop ds
ret