-
Notifications
You must be signed in to change notification settings - Fork 3
/
cpmio.mac
1286 lines (1121 loc) · 22.9 KB
/
cpmio.mac
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
;**********************************************************************;
; ;
; This file is part of ZSM4, a Z80/Z180/Z280 relocatable macro- ;
; assembler written in Z80 assembly. ;
; Copyright (C) 2017-2021, Hector Peraza. ;
; ;
; This work is derived from Z80ASM, originally written by Michael ;
; G. Lehman (1977) and with modifications by Ray Halls (1992) and ;
; Neil Harrison (1983). ;
; ;
; This program is free software; you can redistribute it and/or ;
; modify it under the terms of the GNU General Public License as ;
; published by the Free Software Foundation; either version 2 of ;
; the License, or (at your option) any later version. ;
; ;
; This program is distributed in the hope that it will be useful, ;
; but WITHOUT ANY WARRANTY; without even the implied warranty of ;
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;
; GNU General Public License for more details. ;
; ;
; You should have received a copy of the GNU General Public License ;
; along with this program; if not, write to the Free Software ;
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;
; ;
;**********************************************************************;
TITLE Z80/Z180/Z280 Macro-Assembler
SUBTTL System-dependent routines - CP/M version
; Command syntax is similar to Microsoft's M80:
;
; ZSM [relfile],[prnfile]=srcfile[/option][/option...]
;
; where option can be:
;
; /L force generation of listing file
; /Sn set max length of symbols in REL file (default = 6)
; /U assume all Undefined symbols are External
; /M initialize DEFS data areas to zero
; /Zn set initial processor type to Z80, Z180 or Z280
; (n=0, 1 or 2 respectively; defaults to 0 = Z80)
; /Dsym[=val] define symbol and optionally assign a value to it
;
; in addition, prnfile can be a device specification:
;
; TTY: or CON: send listing output to console
; LST: or LPT: send listing output to printer
.Z80
include ZSM.INC
public UCASE,GNB,WNB,WNB2,CLINE,WLINE,REWIND,INCMEM
public CLSINP,CLOSE1,CLOSE2,OPNLIB,CLSLIB,INCLVL
extrn Z80ASM,HOFNAM,HOFDAT,HOFTIM,LFLAG,OFLAG,QFLAG
extrn ERRFLG,CMPHD,MAXMEM,SYMTBL,VALID,MALLOC,MFREE
extrn FNDREC,CNV2HX,NAMLEN,UMODE,ZERODS,DEFCPU,RADIX
extrn CMNPTR
BDOS equ 5 ; BDOS entry point
BOOT equ 0 ; warm boot
CPMFCB equ 5Ch ; default CP/M FCB
CPMBUF equ 80h
IBUFSZ equ 512 ; input buffer size
OBUFSZ equ 256 ; object buffer size
LBUFSZ equ 512 ; listing buffer size
cseg
VSNMSG: db 'Z80/Z180/Z280 Macro-Assembler V',VER1,'.',VER2
db 0
SUBTTL Initializations and command loop
;
; System-dependent initializations
;
START: ld sp,STACK ; setup local stack
ld hl,(BDOS+1) ; get top of memory
ld l,0 ; trim to page boundary
dec hl
ld (MAXMEM),hl ; save max memory address
ld hl,($MEMRY)
ld (SYMTBL),hl ; save start of symbol table
ld hl,VSNMSG ; sign on message
call CLINE ; display on console
ld hl,CPMBUF
ld a,(hl) ; command tail present?
ld (MODE),a
or a
jr nz,S2 ; branch if yes
S1: call CRLF
ld e,'*'
ld c,2
call ENTRY ; display prompt
call GETLN ; get command line
S2: call PROCESS ; parse and process the command
ld a,(MODE)
or a
jr z,S1 ; loop if in interactive mode
jp BOOT ; else exit program
;
; Parse the command line, open/create files and call the assembler
;
PROCESS:
ld hl,(SYMTBL)
ld (SYMPTR##),hl
ld (hl),0 ; reset symbol table
ld hl,(MAXMEM)
ld (DSPTR##),hl
ld (hl),0 ; reset dynamic memory storage
ld a,'Z' ; setup default options
ld (OFLAG),a ; no output file specified yet
ld (LFLAG),a ; no listing file either
xor a
ld (UMODE),a ; Undefined symbols do not default to External
ld (ZERODS),a ; no DS zeroing
ld (DEFCPU),a ; CPU is Z80
ld a,6
ld (NAMLEN),a ; REL symbol length = 6
ld hl,10
ld (RADIX),hl ; default radix = 10 (for /D option)
ld hl,0
ld (CMNPTR),hl ; clear COMMON pointer (for /D option)
ld hl,CPMBUF
ld e,(hl)
ld d,0
inc hl
push hl
add hl,de
ld (hl),0 ; terminate command line with a null
pop hl
call SKIPB ; skip blanks
or a
ret z ; ignore empty command line
; REL file
ld de,FCB2 ; set up REL file FCB
call MKFCB
jp c,CMDERR
call GETOPT
call TSTFCB
jp c,CMDERR
cp 'Z'
jr nz,PR1
ld a,'=' ; special case of implicit REL
PR1: ld (OFLAG),a
push hl
ld hl,RELEXT
call ADDEXT ; set up extension
pop hl
; PRN file
call SKIPB ; skip blanks
cp ','
jr nz,PR3
ld a,(OFLAG)
cp '='
jr nz,PR2
ld a,'Z' ; explicit null REL
ld (OFLAG),a
PR2: inc hl ; skip delimiter
call SKIPB
ld de,FCB3 ; set up PRN file FCB
call MKFCB
jp c,CMDERR
call GETOPT
call TSTFCB
jp c,CMDERR
ld (LFLAG),a
push hl
ld hl,PRNEXT
call ADDEXT ; set up extension
pop hl
call SKIPB
; MAC file
PR3: cp '='
jp nz,CMDERR
inc hl
call SKIPB
ld de,FCB1 ; set up source FCB
call MKFCB
jp c,CMDERR
call GETOPT
call TSTFCB
jp c,CMDERR
cp 'Y'
ld hl,SM5
jp z,CLINE ; input device can't be LPT:
ld (IFLAG),a
ld hl,ASMEXT
call ADDEXT ; set up extension
ld a,(OFLAG)
cp '='
jr nz,PR5
ld hl,FCB1
ld de,FCB2 ; setup implicit REL output file
ld bc,36
ldir
ld hl,RELEXT
ld de,FCB2+9
ld bc,3
ldir
ld a,'@'
ld (OFLAG),a
PR5: ld a,(LFLAG)
cp '='
jr nz,PR5A
ld hl,FCB1
ld de,FCB3
ld bc,36
ldir
ld hl,PRNEXT
ld de,FCB3+9
ld bc,3
ldir
ld a,'@'
ld (LFLAG),a
; Header line message
PR5A: ld hl,FCB1+1
ld de,HOFNAM
ld bc,8
ldir ; set file name
; Date and time
ld c,12
call BDOS ; get system version
dec h
ld c,155
jr z,PR6 ; branch if MP/M
ld a,l
cp 30h
jp c,PR7 ; skip if not CP/M 3
ld c,105
PR6: ld de,TOD
call BDOS
ld (SEC),a ; seconds are returned in A
ld hl,(DAYS)
call CVTDAT ; convert date
ld de,HOFDAT ; address to store date
ld hl,(DAY)
ld h,0
call BINBCD ; convert days to BCD
ex de,hl
ld a,e
call CNV2HX ; store BCD pair
ld a,(MONTH)
add a,a
add a,a ; *4
ld c,a
ld b,0
ex de,hl
ld hl,MLIST
add hl,bc
ld bc,5
ldir
ld hl,(YEAR)
call BINBCD ; convert year to BCD
ld a,h
add a,19h
daa ; add century
ld h,a
ex de,hl
ld a,d
call CNV2HX ; store BCD pair
ld a,e
call CNV2HX ; store BCD pair
ld hl,HOFTIM ; address to store time
ld a,(HRS)
call CNV2HX ; store BCD pair
ld (hl),':'
inc hl
ld a,(MIN)
call CNV2HX
ld (hl),':'
inc hl
ld a,(SEC)
call CNV2HX
; Open/create files
PR7: ld a,(IFLAG)
cp 'X'
jr z,PR71
ld de,FCB1
call OPNFIL ; open source file
ld hl,SM1 ; source file not found
jp z,CLINE ; on error, msg and return
PR71: ld de,FCB3
ld a,(LFLAG)
cp '@'
jr nz,PR8
call CREFIL ; create listing file
ld hl,SM3 ; can't create listing file
jp z,CLINE ; on error, msg and return
PR8: ld de,FCB2
ld a,(OFLAG)
cp '@'
jr nz,PR9
call CREFIL ; create object file
ld hl,SM2 ; can't create object file
jp z,CLINE ; on error, msg and return
PR9: ld hl,0
ld (IBCNT),hl ; init char counters
ld (IBLEN),hl
ld (IOB2+BUFCNT),hl
ld (IOB3+BUFCNT),hl
xor a
ld (INCLVL),a
ld (QFLAG),a
ld (EFLAG),a
call Z80ASM ; assemble file
ld hl,ENDMSG ; sign off
jp CLINE ; msg and return
ENDMSG: db 'Finished.',0
CMDERR: ld hl,SM4 ; command syntax error
jp CLINE ; output message and return
SM1: db 'Source file not found',0
SM2: db 'Unable to create object file',0
SM3: db 'Unable to create listing file',0
SM4: db 'Command syntax error',0
SM5: db 'Illegal input device',0
ASMEXT: db 'MAC'
RELEXT: db 'REL'
PRNEXT: db 'PRN'
; Get next non-blank char from command line
SKP: inc hl
SKIPB: ld a,(hl)
or a
ret z
cp ' '
jr z,SKP
cp TAB
jr z,SKP
ret
; Test FCB and return code in reg A:
; 'Z' if FCB is empty
; '@' if FCB specifies a valid disk file
; 'X' if console device
; 'Y' if printer device
; CY set on error (invalid device name)
TSTFCB: inc de
ld a,(de)
dec de
cp ' '
ld a,'Z'
ret z ; empty FCB
ld a,(hl)
cp ':'
jr z,T1
ld a,'@' ; disk file
or a
ret
T1: inc hl
push hl
call TSTDEV
pop hl
ret
TSTDEV: ld hl,DEVNAM
TEST1: ld a,(hl)
or a ; end of table?
scf
ret z
push de
inc de
ld b,3
TEST2: ld a,(de)
cp (hl)
jr nz,TEST3
inc hl
inc de
djnz TEST2
pop de
ld a,(hl)
add a,40h
ret ; note CY clear
TEST3: inc hl
djnz TEST3
inc hl
pop de
jr TEST1
DEVNAM: db 'CON',18h
db 'TTY',18h
db 'LST',10h
db 'LPT',10h
db 0
; Get command line options, if present
GETOPT: call SKIPB ; skip blanks
cp '/' ; option switch?
ret nz ; return if not
ld bc,GETOPT
push bc
inc hl
ld a,(hl) ; else process it
call UCASE
cp 'D'
jr z,DEFSYM
cp 'S'
jr z,SETLEN
cp 'L'
jr z,SETPRN
cp 'U'
jr z,SETUFL
cp 'M'
jr z,SETMFL
cp 'Z'
jr z,SETCPU
OPTERR: call CMDERR
pop bc ; drop return address
pop bc ; return one level higher
ret
SETLEN: inc hl
ld a,(hl)
cp '5'
jr c,OPTERR
cp '8'+1
jr nc,OPTERR
sub '0'
ld (NAMLEN),a ; set symbol length
inc hl
ret
SETPRN: inc hl
ld a,(LFLAG)
cp 'Z'
ret nz
ld a,'='
ld (LFLAG),a ; set listing flag, using name of input file
ret
SETUFL: inc hl
ld a,1
ld (UMODE),a ; Undefined symbols are External
ret
SETMFL: inc hl
ld a,1
ld (ZERODS),a ; initialize DS to all zeros
ret
SETCPU: inc hl
ld a,(hl)
sub '0'
jr c,OPTERR
cp 2+1
jr nc,OPTERR
ld (DEFCPU),a ; set CPU type
inc hl
ret
DEFSYM: inc hl
ld (PTR1##),hl
call ID##
ld a,(IDLEN##)
or a
jp z,OPTERR ; symbol name required
ld hl,(PTR1)
call SKIPB
cp '='
ld bc,0 ; if no value specified, assume 0
jr nz,DEF1
inc hl
ld (PTR1),hl
push de
call INT## ; convert value
pop de
ld bc,(INTBUF##)
DEF1: ld (VAL##),bc
ld a,GBLSYM ; /D symbol is Global
ld (SYMMOD##),a
push de
call ADDSYM## ; enter symbol
pop de
; jp c,... ; error - can't enter symbol (unlikely)
; jp z,... ; error - multiple defined (ignore/redefine)
ld hl,(IDADR##)
ld a,(hl)
and 0Fh
add a,EQUNAME
ld (hl),a ; treat like EQU
ld hl,(PTR1)
ret
; Convert binary number in HL to BCD number in AHL.
BINBCD: push bc
push de
ld e,16+1
call BD1
ld c,a
ld e,16+1
call BD1
ld h,a
ld a,l
ld l,c
pop de
pop bc
ret
BD1: xor a
BD2: dec e
ret z
add hl,hl
adc a,a
daa
jr nc,BD2
inc hl
jr BD2
; Convert BDOS date (num of days) to day-month-year
; HL = number of days (1 = Jan 1, 1978)
CVTDAT: call CYEAR
ld (YEAR),bc
; year has been set, HL has remaining days
ld e,0 ; leap$bias
ld a,c
and 3
jr nz,CVD1 ; year & 3 == 0 ?
ld a,l
sub 59+1 ; and remaining days > 59 ?
ld a,h
sbc a,0
jr c,CVD1
; after feb 29 on leap year
inc e ; then leap$bias = 1
CVD1: ld c,e
call CMONTH
ld a,e
ld (MONTH),a
; day = remaining_days - (month_days[month] + leap_bias);
push hl
ld hl,MDAYS
add hl,de
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ; HL = month_days[month]
ld b,0
add hl,bc ; + leap_bias
ex de,hl
pop hl
or a
sbc hl,de ; day = remaining_days - HL
ld a,l
ld (DAY),a
ret
; Compute year from number of days in HL, returns year in BC
CYEAR: ld bc,78 ; year = 78 (base year)
CY1: ld de,365 ; year length
ld a,c
and 3 ; leap year?
jr nz,CY2
inc de ; year length = 366
CY2: push hl
inc de
sbc hl,de ; remaining days - year length (note CY was clear)
jr c,CY3 ; return if <= 0
pop af
inc hl
inc bc ; ++year
jr CY1
CY3: pop hl
ret
; Compute month from remaining days in HL, C = leap bias.
; Returns month in DE, C = leap bias
CMONTH: ld de,11 ; E = month, D = 0
push hl
ld b,d ; B = 0
CM1: ld a,e
cp 2 ; jan or feb?
jr nc,CM2
ld c,b ; if yes, leap bias = 0
CM2: ld hl,MDAYS
add hl,de
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ; HL = month$days[month]
add hl,bc ; + leap bias
ex de,hl
ex (sp),hl ; HL = rem days
ld a,e
sub l
ld a,d
sbc a,h
ex (sp),hl
ex de,hl
jr c,CM3
dec e
jr nz,cm1
CM3: pop hl
ret
MDAYS: ; jan feb mar apr may jun jul aug sep oct nov dec
dw 0, 31, 59, 90,120,151,181,212,243,273,304,334
MLIST: db '-Jan-Feb-Mar-Apr-May-Jun-Jul-Aug-Sep-Oct-Nov-Dec-'
SUBTTL Console, Printer and File I/O
; ENTRY - Used to call BDOS - Saves and restores registers
ENTRY: push bc
push de
push hl
push ix
call BDOS
pop ix
pop hl
pop de
pop bc
ret
; WLINE - Write line to list device and append newline
; HL -> buffer, term = null
WLINE: ld a,(hl)
or a
jr z,WCRLF
ld e,a
ld c,5
call ENTRY
inc hl
jr WLINE
WCRLF: ld e,CR
ld c,5
call ENTRY
ld e,LF
ld c,5
jp ENTRY
; CLINE - Write line to console and append newline
; HL -> buffer, term = null
CLINE: ld a,(hl)
or a
jr z,CRLF
ld e,a
ld c,2
call ENTRY
inc hl
jr CLINE
CRLF: ld e,CR
ld c,2
call ENTRY
ld e,LF
ld c,2
jp ENTRY
; OPNFIL - Open file
; DE -> FCB
; Z=0 success, Z=1 failure
OPNFIL: ld c,15
call ENTRY
inc a ; test for 255
ret
; CLSFIL - Close file
; DE -> FCB
; Z=0 success, Z=1 error
CLSFIL: ld c,16
call ENTRY
inc a
ret
; DREAD - Read disk sector
; DE -> FCB
; Z=0 error or EOF, Z=1 normal
DREAD: ld c,33 ; note: read random record
call ENTRY
or a
ret
; DWRITE - Write disk sector
; DE -> FCB
; Z=0 error, Z=1 normal
DWRITE: ld c,21
call ENTRY
or a
ret
; CREFIL - Create file
; Reel # assummed to be set
; DE -> FCB
; Z=0 normal, Z=1 error
CREFIL: push de
ld c,19 ; delete file
call ENTRY
pop de
ld c,22
call ENTRY
inc a
ret
; DMASET - Set DMA address
; Buffer address in DE
DMASET: ld c,26
jp ENTRY
; Convert character in A to uppercase
UCASE: cp 'a'
ret c
cp 'z'+1
ret nc
and 5Fh
ret
; GNB - Get next byte (FCB1)
GNB: push hl
push de
ld hl,(IBLEN)
ld de,(IBCNT)
call CMPHD ; see if end of buffer
call z,REFILL ; refill buffer if necessary
ld hl,INBUF
add hl,de
ld a,(hl) ; get byte
and 7Fh ; strip parity bit
inc de
ld (IBCNT),de
pop de
pop hl
ret
; REFILL - (Re)fill input buffer
REFILL: push bc
ld a,(IFLAG)
cp 'X'
jr z,RE4
ld hl,(FCB1+33)
ld (IRECNO),hl
ld de,INBUF ; set up pointer for DMASET
ld hl,IBUFSZ ; input buffer size
RE1: push hl
push de
call DMASET ; set up DMA address
ld de,FCB1
call DREAD ; go read a sector
ld hl,(FCB1+33)
inc hl
ld (FCB1+33),hl ; point to next record
pop de
pop hl
jr z,RE2
ld a,EOF
ld (de),a
jr RE3
RE2: ex de,hl
ld bc,128
add hl,bc
ex de,hl ; update pointer
or a
sbc hl,bc
ld a,h
or l
jr nz,RE1 ; branch back if more to do
RE3: ex de,hl
ld hl,IBUFSZ
or a
sbc hl,de
ld (IBLEN),hl
RE6: ld de,0
ld (IBCNT),de ; set up next data pointer
pop bc ; note: returns DE = 0
ret
RE4: call GETLN
ld hl,CPMBUF
ld de,INBUF
ld c,(hl)
ld b,0
push bc
inc hl
ld a,b
or c
jr z,RE5
ldir
RE5: ex de,hl
ld (hl),CR
inc hl
ld (hl),LF
inc hl
ld (hl),0
pop bc
inc bc
inc bc
ld (IBLEN),bc
jr RE6
GETLN: ld hl,CPMBUF-1
ld (hl),126
ex de,hl
ld c,10
call ENTRY ; get command line
jp CRLF
; REWIND - Rewind input file
REWIND: ld a,(INCLVL)
or a
jr z,REW1
call CLSLIB ; close any open INCLUDE files
jr REWIND
REW1: ld hl,0
ld (FCB1+33),hl ; reset r0,r1
ld hl,0
ld (IBCNT),hl ; reset char pointer
ld (IBLEN),hl
ret
; CLSINP - Close input file
CLSINP: ld a,(IFLAG)
sub 'X'
ret z
ld de,FCB1
jp CLSFIL ; !!!TODO: close include files?
; (are there any still open?)
; WNB - Write next byte (PRN)
; Byte in A reg
WNB: ld iy,EFLAG
bit 2,(iy)
scf
ret nz
push ix
and 7Fh ; strip parity bit
ld ix,IOB3
call FWRITE
pop ix
ret nc
set 2,(iy)
ret
; WNB2 - Write next byte (REL)
WNB2: ld iy,EFLAG
bit 1,(iy)
scf
ret nz
push ix
ld ix,IOB2
call FWRITE
pop ix
ret nc
set 1,(iy)
ret
; FWRITE - Write byte to file
; Byte in reg A
; I/O block address in reg IX
FWRITE: push hl
push de
push bc
ld e,(ix+BUFCNT)
ld d,(ix+BUFCNT+1)
ld l,(ix+BUFADR)
ld h,(ix+BUFADR+1)
push hl
add hl,de
ld (hl),a ; store byte
inc de
ld l,(ix+BUFSZ)
ld h,(ix+BUFSZ+1)
call CMPHD ; at end of buffer?
pop bc
jr nz,WNB1 ; branch if not
ld e,c ; buffer address in DE, size in HL
ld d,b
WNB0: push de
call DMASET
ld e,(ix+FCBADR)
ld d,(ix+FCBADR+1)
call DWRITE
pop de
jr nz,WRERR ; on error, print message and return
ld bc,128
ex de,hl
add hl,bc
ex de,hl
or a
sbc hl,bc
ld a,h
or l
jr nz,WNB0
ld de,0
WNB1: ld (ix+BUFCNT),e
ld (ix+BUFCNT+1),d
pop bc
pop de
pop hl
or a
ret
WRERR: ld hl,SM6 ; file write error
call CLINE ; msg and return
pop bc
pop de
pop hl
scf
ret
SM6: db 'Output file write error',0
; CLOSE1 - Close PRN file
CLOSE1: push ix
ld ix,IOB3
call CLOSE
pop ix
ret
; CLOSE2 - Close REL file
CLOSE2: push ix
ld ix,IOB2
call CLOSE
pop ix
ret
CLOSE: ld a,(ix+BUFCNT)
or (ix+BUFCNT+1)
jr z,CLS1
ld a,EOF
call FWRITE
jr CLOSE
CLS1: ld e,(ix+FCBADR)
ld d,(ix+FCBADR+1)
jp CLSFIL
; OPNLIB - Open MACLIB or INCLUDE file
; HL points to file name
;
; Input file structure as saved in high memory:
;