-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcpmutil.z80
989 lines (989 loc) · 24.3 KB
/
cpmutil.z80
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
; -*- tab-width: 8;-*-
;; .z80
.xlist
;==============================================================================
;Boolean constants:
;==============================================================================
false equ 0
true equ not false
;==============================================================================
;ASCII Characters
;==============================================================================
NULL equ 00h ;null
ACK equ 'F'-'@' ;acknowledge
BEL equ 'G'-'@' ;bell
BS equ 'H'-'@' ;backspace
TAB equ 'I'-'@' ;horzontial tab
LF equ 'J'-'@' ;line feed
FF equ 'L'-'@' ;form feed
CR equ 'M'-'@' ;carriage return
XOFF equ 'S'-'@' ;transmitt off
NAK equ 'U'-'@' ;negative acknowledge
EOF equ 'Z'-'@' ;end-of-file
ESC equ '['-'@' ;escape
DEL equ 7Fh ;delete
;==============================================================================
;CP/M Plus entry points
;==============================================================================
wboot equ 00000h ;warm boot
reboot equ 00000h ;system reboot
bdos equ 00005h ;bdos entry point
fcb equ 0005Ch ;file control block
fcb1 equ 0006Ch ;alternate file control block
tail equ 00080h ;command tail
tpa equ 00100h ;temporary program area
;==============================================================================
;CP/M Plus BDOS function codes
;==============================================================================
$coninp equ 1 ;console input function
$conout equ 2 ;console output function
$print equ 9 ;print string until '$'
$conips equ 11 ;console input status
$vers equ 12 ;get cp/m version
$openf equ 15 ;open file
$readf equ 20 ;read file
$scb equ 49 ;get/set scb info
$stime equ 104 ;get/set system time
$parse equ 152 ;parse filename
;==============================================================================
;utility subroutines for console i/o
;==============================================================================
;
;##############################################################################
;dump bc bytes @hl
;==============================================================================
;
dump: call pushall ;save all registers (and popall as return address)
xor a ;no headers
ld d,h ;copy dump address to offset
ld e,l
jr dump05
;
dumpoff:call pushall ;save all registers (and popall as return address)
;
dump05: or a ;headers?
jr z,dump10 ;(no)
;
PRINT$ 1,' +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F',1
;
dump10: ld a,b ;is count zero?
or c
jp z,dump99 ;(yes)
;
push bc ;save byte count
push hl ;save address
;
xor a ;clear carry flag
ld hl,16 ;is byte count less than 16?
sbc hl,bc
jr nc,dump15 ;(yes)
;
ld bc,16 ;set byte count to 16 max
;
dump15: ld b,c ;copy byte count to b
;
ex de,hl ;offset to hl
call hex_w ;output hex word (offset hl) to console
ld a,':'
call putchr
ex de,hl ;offset back to de
;
pop hl ;restore address
push hl ;save address
;
dump20: ld a,' '
call putchr
;
ld a,(hl) ;get byte from memory
call hex_b ;output hex byte (a) to console
;
inc hl ;bump pointer
;
djnz dump20 ;(loop till byte count-- is zero)
;
PRINT$ 0,' |',0
;
pop hl ;restore address
;
ld b,c ;count to b
;
dump40: ld a,(hl) ;get byte from memory
res 7,a ;clear msbit
cp 07Fh ;delete character?
jr z,dump48 ;(yes)
cp ' ' ;valid character?
jr nc,dump50 ;(yes)
dump48: ld a,'.' ;load invalid character
dump50: call putchr ;output character to console
;
inc hl ;bump pointer
inc de ;bump offset
djnz dump40 ;(loop till byte count-- is zero)
;
PRINT$ 0,'|',1
;
ex (sp),hl ;swap byte count & dump address
xor a ;clear carry
sbc hl,bc
ex (sp),hl ;swap dump address & byte count
;
pop bc ;restore byte count
;
call constat ;any input from console?
or a,a ;test Acc zero
jp z,dump10 ;(no)
;
call getchr ;get input from console
jp wboot ;go warm boot
;
dump99: ret
;
;##############################################################################
;dump registers (for debugging)
;==============================================================================
;
DumpRegs:
push hl ;save hl
;
push af ;copy AF...
pop hl ;...to HL
PRINT$ 0,"AF: ",0 ;print it...
call hex_w ;...in hex
;
push bc ;copy bc...
pop hl ;...to hl
PRINT$ 0,", BC: ",0 ;print it...
call hex_w ;...in hex
;
push de ;copy de...
pop hl ;...to hl
PRINT$ 0,", DE: ",0 ;print it...
call hex_w ;...in hex
;
pop hl ;restore hl
PRINT$ 0,", HL: ",0 ;print it...
call hex_w ;...in hex
;
jp crlf ;go print cr/lf
;
DumpAltRegs:
exx ;swap main/alt registers
call DumpRegs
exx ;swap main/alt registers
ret
;
DumpAllRegs:
call DumpRegs ;dump main registers
call DumpAltRegs ;dump alt registers
;
push hl ;save hl
;
push ix ;copy IX...
pop hl ;...to HL
PRINT$ 0,"IX: ",0 ;print it...
call hex_w ;...in hex
;
push iy ;copy bc...
pop hl ;...to hl
PRINT$ 0,", IY: ",0 ;print it...
call hex_w ;...in hex
;
ld hl,4 ;get offset to return address on stack
add hl,sp
PRINT$ 0,", SP: ",0 ;print it...
call hex_w ;...in hex
;
ld a,(hl) ;get return address
inc hl
ld h,(hl)
ld l,a
PRINT$ 0,", PC: ",0 ;print it...
call hex_w ;...in hex
;
pop hl ;restore hl
jp crlf ;go print cr/lf
;
;##############################################################################
;dump file control block
;==============================================================================
;
dump_fcb:
call pushall ;save all registers (and popall as return address)
;
ld a,(hl) ;drive
inc hl ;bump pointer
;
or a ;zero?
jr z,dfcb_09 ;(yes)
;
add 'A'-1
call putchr ;output character to console
;
ld a,':' ;output drive delimiter
call putchr ;output character to console
;
dfcb_09:ld b,8 ;output 8 characters for filename
dfcb_10:ld a,(hl) ;get filename character
and 07Fh ;clear high bit
inc hl ;bump pointer
cp ' ' ;space?
call nz,putchr ;(no)output character to console
djnz dfcb_10 ;(loop till --b is zero)
;
ld a,'.' ;output filename / extension delimiter
call putchr ;output character to console
;
ld b,3 ;output 3 characters for extension
dfcb_20:ld a,(hl) ;get extension character
inc hl ;bump pointer
and 07Fh ;clear high bit
cp ' ' ;space?
call nz,putchr ;(no)output character to console
djnz dfcb_20 ;(loop till --b is zero)
;
PRINT$ 0,", ex: ",0
ld a,(hl) ;get extent
call dec_b ;output decimal byte
;
inc hl ;bump to record count
inc hl
inc hl
;
PRINT$ 0,", rc: ",0
ld a,(hl) ;get extent
call dec_b ;output decimal byte
;
ld de,17 ;add offset to current record
add hl,de
;
PRINT$ 0,", cr: ",0
ld a,(hl) ;get current record
inc hl ;bump pointer
call dec_b ;output decimal byte
;
PRINT$ 0,", r0-3: ",0
ld a,(hl) ;get r0
inc hl ;bump pointer
ld e,(hl) ;get r1
inc hl ;bump pointer
ld d,(hl) ;get r2
ex de,hl ;move r1-2 to hl
call hex_w ;output hexadecimal word
jp hex_b ;output hexadecimal byte
;
;##############################################################################
;
;datehl converts the value in HL to BCD year, month, day
;
;Inputs: HL contains hex days since December 31, 1977
;
;Outputs: H contains BCD 20th century year
; L contains BCD month
; A contains BCD day
;
; Zero flag set (Z) and A=0 if invalid date (zero) detected,
; Zero flag reset (NZ) and A=0ffh otherwise.
;
;==============================================================================
;
datehl: ld a,h
or l ;test blank date (zero)
ret z ;return z and a=0 if so
;
push bc ;save these registers
push de
;
ld (days),hl ;save initial value
ld b,78 ;set years counter
;
dhl10: call ckleap
ld de,-365 ;set up for subtract
jr nz,dhl20 ;skip if no leap year
;
dec de ;set for leap year
;
dhl20: add hl,de ;subtract
jr nc,dhl30 ;continue if years done
;
ld a,h
or l
jr z,dhl30
;
ld (days),hl ;else save days count
inc b ;increment years count
jr dhl10 ;and do again
;
;the years are now finished, the years count is in 'b' (hl is invalid)
;
dhl30: ld a,b
call binbcd
ld (years),a ;save bcd year
;
call ckleap ;check if leap year
ld a,-28
jr nz,dhl40 ;february not 29 days
;
ld a,-29 ;leap year
;
dhl40: ld (feb),a ;set february
;
ld hl,(days) ;get days count
ld de,mtable ;point to months table
ld b,0ffh ;set up 'b' for subtract
ld a,0 ;set a for # of months
;
dhl50: ex de,hl ;swap
ld c,(hl) ;get month
ex de,hl
;
ld (days),hl ;save days count
add hl,bc ;subtract
;
inc de ;increment months counter
inc a
jr c,dhl50 ;loop for next month
;
;the months are finished, days count is on stack. first, calculate
;the month.
;
ld b,a ;save months
;
ld hl,(days)
ld a,h
or l
jr nz,dhl60
;
dec de ;backup two months
dec de
;
ld a,(de)
cpl
inc a
ld l,a
dec b
;
dhl60: ld a,l ;retrieve binary day of month
call binbcd ;convert to bcd
;
push af ;save day
;
ld a,b ;retrieve the binary month
call binbcd ;convert binary month to bcd
ld l,a ;return month in l
;
ld a,(years)
ld h,a ;return year in h
;
pop af ;restore day
or a ;set nz flag
;
pop de ;restore these registers
pop bc
;
ret
;
;support routines:
;
;check for leap years.
;
ckleap: ld a,b
and 0fch
cp b
ret
;
;convert a to bcd & store back in a
;
binbcd: or a
ret z
push bc
ld b,a
xor a
;
binbcd1:add a,1
daa
dec b
jp nz,binbcd1
pop bc
ret
;
;months table
;
mtable: defb -31 ;january
feb: defb -28 ;february
defb -31,-30,-31,-30 ;mar-jun
defb -31,-31,-30 ;jul-sep
defb -31,-30,-31 ;oct-dec
;
days: defs 2 ;days
years: defs 1 ;years
;
;##############################################################################
;dump time stamp [@hl]
;==============================================================================
;
dump_ts:call pushall ;save all registers (and popall as return address)
;
ld e,(hl) ;get lsbyte of days since 1977
inc hl ;bump pointer
ld d,(hl) ;get msbyte of days since 1977
inc hl ;bump pointer
;
push de ;save # of days since 1977
push hl ;save pointer
;
ex de,hl ;move days since 1977 to hl
call datehl ;convert days since 1977 (hl) to BCD day (a), month (l) & year(h)
jr z,dts010 ;(bad date)
;
call hex_b ;output day
;
ld a,'/' ;output date seperator
call putchr ;to console
;
ld a,l ;get month
call hex_b ;output it
;
ld a,'/' ;output date seperator
call putchr ;to console
;
ld a,h ;get year
;
cp 078h ;before 1978?
ld a,019h ;assume century 19
jr nc,dts005 ;(no)
;
ld a,020h ;century 20
;
dts005: call hex_b ;output century to console
ld a,h ;get year
call hex_b ;output year to console
;
pop hl ;restore pointer
pop de ;restore # of days since 1977
jr dts020
;
dts010: pop de ;restore pointer
pop hl ;restore # of days since 1977
call dec_w ;output decimal word [in hl] to console
ex de,hl ;swap pointer & # of days since 1977
;
dts020: ld a,' ' ;output space...
call putchr ;... to console
;
ld a,(hl) ;get hours
inc hl ;bump pointer
;
call dec_b ;output decimal byte [in a] to console
;
ld a,':' ;output colan seperator...
call putchr ;... to console
;
ld a,(hl) ;get minutes
cp 10 ;greater than or equal to 10?
jr nc,skip_lz ;(yes)
;
ld a,'0' ;output leading zero...
call putchr ;... to console
;
ld a,(hl) ;get minutes (again)
;
skip_lz:jp dec_b ;output decimal byte [in a] to console
;
;output byte (a) as decimal
;
dec_b: call pushall ;save all registers (and popall as return address)
ld l,a
ld h,0
jr dec_wI
;
;##############################################################################
;output word (hl) as decimal
;==============================================================================
;
dec_w: call pushall ;save all registers (and popall as return address)
;
dec_wI: ld b,h ;dividend to bc
ld c,l
;
ld de,10 ;divisor to de
;
call Div16 ;bc=bc/de;hl=bc%de (remainder)
;
ld a,l ;get lsb remainder
add '0' ;convert to ASCII '0'-'9'
push af ;save ASCII
;
ld h,b ;result to hl
ld l,c
;
ld a,h ;is result zero?
or a,l
call nz,dec_wI ;(no) recurse
;
pop af ;restore ASCII
jp putchr ;output to console
;
;##############################################################################
;output boolean ('0'/'1') not zero (flag)
;==============================================================================
;
bool_nz:push af ;save a
ld a,'0' ;assume zero
jr z,bool_z0 ;(yes)
inc a ;change to '1'
bool_z0:call putchr ;output to console
pop af ;restore a
ret
;
;##############################################################################
;output boolean ('0'/'1') carry (flag)
;==============================================================================
;
bool_c: push af ;save a
ld a,'0' ;assume zero
adc a,0 ;add carry
call putchr ;output to console
pop af ;restore a
ret
;
;##############################################################################
;output binary word (hl)
;==============================================================================
;
bin_w: call pushall ;save all registers (and popall as return address)
ld a,h ;output h in binary
call bin_b
ld a,l ;output l in binary
;note: fall thru to bin_b
;##############################################################################
;output binary byte (a)
;==============================================================================
;
bin_b: push af ;save registers
push bc
;
ld b,8 ;do 8 bits
ld c,a ;value to c
bin_b0: sla c ;shift bits up and out into carry
call bool_c ;output boolen carry
djnz bin_b0 ;(loop till --b is zero)
;
pop bc ;restore registers
pop af
ret
;
;##############################################################################
;output binary nibble
;==============================================================================
;
bin_n: push af ;save registers
push bc
;
ld c,a ;move to c
sla c ;shift low nibble to high
sla c
sla c
sla c
;
ld b,4 ;4-bits
jr bin_b0
;
;##############################################################################
;output hex word (@hl)
;==============================================================================
;
hex_w: push af ;save registers
ld a,h
call hex_b ;MSB of word
ld a,l ;LSB of word
call hex_b ;MSB of word
pop af
ret
;
;##############################################################################
;output hex byte (in a)
;==============================================================================
;
hex_b: push af ;save acc
;
srl a
srl a
srl a
srl a
;
call hex_n
;
pop af ;restore acc and fall thru to hex_n
;note: fall thru to bin_b
;##############################################################################
;output hex nibble (in a)
;==============================================================================
;
hex_n: push af ;save register
;
or 0f0h ;convert to ASCII
daa
add a,0A0h
adc a,040h
;
call putchr
;
pop af ;restore register
ret
;
;##############################################################################
;convert to upper case
;==============================================================================
;
toupper:cp 'a' ;< 'a'?
ret c ;(yes)
cp 'z'+1 ;> 'z'?
ret nc ;(yes)
;
and 05Fh ;make it upper case
ret
;
;##############################################################################
;convert to lower case
;==============================================================================
;
tolower:cp 'A' ;< 'A'?
ret c ;(yes)
cp 'Z'+1 ;> 'Z'?
ret nc ;(yes)
;
or 020h ;make it lower case
ret
;
;##############################################################################
;write character to console from a
;==============================================================================
;
conout: ;alternative function name
putchr: call pushall ;save all registers (and popall as return address)
putchr1:ld e,a ;character to send
ld c,$conout
jp bdos ;send character
;
;##############################################################################
;return A not zero if console character ready
;==============================================================================
;
constat:call pushpair ;save all register pairs (and poppair return address)
ld c,$conips
jp bdos
;
;##############################################################################
;read console character to a
;==============================================================================
;
conin: ;alternative function name
getchr: call pushpair ;save all register pairs (and poppair return address)
ld c,$coninp
jp bdos
;
;##############################################################################
;output carriage return and line feed
;==============================================================================
;
crlf: call pushall ;save all registers (and popall as return address)
ld a,cr
call putchr1
ld a,lf
jp putchr1
;
;##############################################################################
;output space to console
;==============================================================================
;
space: call pushall ;save all registers (and popall as return address)
ld a,' '
jp putchr1
;
;##############################################################################
;output tab to console
;==============================================================================
;
puttab: call pushall ;save all registers (and popall as return address)
ld a,TAB
jp putchr1
;
;##############################################################################
;output the buffer addressed by de until $
;==============================================================================
;
lprint: call crlf ;new line
print: call pushall ;save all registers (and popall as return address)
ld c,$print
jp bdos ;print the string
;
;##############################################################################
;output the buffer addressed by hl until null
;==============================================================================
;
print2NullSafe:
call pushpair ;save all register pairs (and poppair return address)
print2Null:
ld a,(hl) ;load character
or a ;is it NULL?
ret z ;(yes)
;
call putchr ;output a to console
inc hl ;bump pointer
jr print2Null ;loop till NULL
;
;##############################################################################
;concatinate null terminated string @de to destination string @hl
;==============================================================================
;
strcat: call pushpair ;save all register pairs (and poppair return address)
call scanNULL ;move hl to end of destination string
ex de,hl ;swap cat & end of destination string pointers
jr scpylp ;go copy cat string to end of destination string
;
;##############################################################################
;copy null terminated string from @hl to @de
;==============================================================================
;
strcpy: call pushpair ;save all register pairs (and poppair return address)
;
scpylp: ld a,(hl) ;get source character
inc hl ;bump source pointer
;
ld (de),a ;store destination character
inc de ;bump destination character
;
or a ;is it null?
ret z ;(yes)
;
jr scpylp ;loop till null source character
;
;##############################################################################
;compare NULL terminated strings (@de & hl)
;==============================================================================
;
strcmp: call pushpair ;save all register pairs (and poppair return address)
sc_lp: xor a ;NULL character to acc
cp (hl) ;is NULL?
ret z ;(yes)
;
ex de,hl ;swap string pointers
cp (hl) ;is NULL?
ret z ;(yes)
;
ld a,(hl) ;get character from string
ex de,hl ;swap string pointers
cp (hl) ;same?
ret nz ;(no)
;
inc hl ;bump string pointers
inc de
;
jr sc_lp ;loop till NULL or not equal
;
;##############################################################################
;calculate the length of the string (@hl)
;return result in bc
;==============================================================================
;
strlen: xor a ;null terminator
strlenA:call pushpair ;save all register pairs (and poppair as return address)
ld bc,0 ;zero count
l2t_lp: cp a,(hl) ;term character?
jr z,l2p_end ;(yes)
;
inc bc
inc hl
jr l2t_lp ;loop till term
;
l2p_end:
IFZ280
ldw (sp+2),bc ;replace bc on poppair stack
ELSE
ld hl,2 ;computer address of bc on poppair stack
add hl,sp
;
ld (hl),c ;replace bc on poppair stack
inc hl
ld (hl),b
ENDIF
ret
;
;##############################################################################
;compare memory @hl to @de for bc bytes
;==============================================================================
;
memcmp:call pushpair ;save all register pairs (and poppair return address)
;
mcLP: ld a,b ;get count
or c ;zero?
ret z ;(yes)
;
ld a,(hl) ;get 1st byte
inc hl ;bump pointer
;
ex de,hl ;swap pointers
cp (hl) ;compare to 2nd byte
inc hl ;bump pointer
ex de,hl ;swap pointers
;
ret nz ;(not equal)
;
dec bc ;unbump count
jr mcLP ;loop till not equal or count is zero
;
;##############################################################################
;insert string @de before string @hl (both NULL terminated)
;==============================================================================
;
strIns: call pushall ;push all registers (and popall return address)
;
ex de,hl ;swap insert & destination string pointers
call strlen ;get length of (insert) string (@hl) to bc
ex de,hl ;swap them back
;
ld a,b ;length zero?
or c
ret z ;(yes) nothing to insert
;
push hl ;save destination string address
;
call scanNULL ;scan forward to end of string terminator
;
;pad destination string with strlen(insert string) spaces
;
push bc ;save length
;
iss010: ld (hl),' ' ;add a space
inc hl ;bump pointer
;
dec bc ;decrease count
ld a,b ;zero?
or c
jr nz,iss010 ;(no)
;
ld (hl),NULL ;terminate new string
;
pop bc ;restore length
pop hl ;restore destination string address
;
call padRight ;shift destination string to the right
;
ex de,hl ;swap insert & destination strin pointers
ldir ;copy bc bytes from @hl++ to @de++
ret
;
;##############################################################################
;copy memory from @hl to @de for bc bytes
;==============================================================================
;
memcpy: call pushpair ;save all register pairs (and poppair return address)
ldir
ret
;
;##############################################################################
;pad string (@hl) to the right
;==============================================================================
;
padRight:
call pushall ;save all registers (and popall return address)
;
call strlen ;get length of string to bc
;
add hl,bc ;add offset to end of string
;
dec hl ;backup to last character of string (before terminator)
;
ld d,h ;copy to de
ld e,l
;
;backup to last non-space character
;
pR0010: ld a,b ;length zero?
or c
ret z ;(yes)no non-space characters
;
ld a,(hl) ;get character from end-of-string
cp ' ' ;space?
jr nz,pR0025 ;(no) jump into copy loop
;
dec hl ;unbunp pointer
dec bc ;unbump length
;
jr pR0010 ;loop till bc is zero or non-space character
;
;found last non-space character, copy string to end-of-string
;
pR0020: ld a,(hl) ;get character from end-of-non-space pointer
pR0025: ld (de),a ;store it
;
dec de ;unbump end-of-string pointer
dec hl ;unbump end-of-non-space pointer
;
dec bc ;unbump length
;
ld a,b ;length zero?
or c
jr nz,pR0020 ;(loop till --length is zero)
;
;now while --hl != de add padding
;
ex de,hl ;swap pointers
;
pR0030: ld (hl),' ' ;store a space
dec hl ;unbump pointer
cphlde ;cpw hl,de
jr nz,pR0030 ;(loop till hl==de)
;
ret ;return (to popall)
;
;##############################################################################
;scan string @hl for null (or a)
;==============================================================================
;
scanNULL:
xor a ;get null
;
scanA: cp (hl) ;same character?
ret z ;(yes)
;
inc hl ;bump pointer
jr scanA ;loop till same
;
;##############################################################################
;parse decimal string @hl
;==============================================================================
;
parsedec:
ex de,hl ;move string pointer to de
or a ;clear carry
sbc hl,hl ;zero result
pd_lp: ld a,(de) ;get character
;
cp a,'0'
ret c ;(less than 0)
;
cp a,'9'+1
ret nc ;(greater than 9)
;
sub a,'0' ;convert ASCII to binary
;
ld b,h ;copy result to bc
ld c,l
;
add hl,hl ;+ x1 = x2
add hl,hl ;+ x2 = x4
add hl,bc ;+ x1 = x5
add hl,hl ;+ x5 = x10
;
ld c,a ;new digit to bc
ld b,0
add hl,bc ;add in new digit
;
inc de ;bump string pointer
jr pd_lp ;loop till invalid character
;##############################################################################
; z80 utility code
;==============================================================================
include z80util.z80
;