-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathzzmon.mac
1681 lines (1505 loc) · 44.9 KB
/
zzmon.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
; 9/18/21 v2.3 by Tony Nicholson
; - CompactFlash disk formatting of drives A:, B:, C: and D: for CP/M
; using the XA, XB, XC and XD commands now clears 80h sectors in case
; a larger number of directory entries is being used.
;
; 9/17/21 v2.2 by Tony Nicholson
; - Detect a zero-length Intel HEX type 0 data record (emitted by various
; CP/M assemblers instead of a end-of-file type 1 record type). This
; prevents a stray zero-length record from incorrectly trying to process
; 256 bytes of data. Loading an Intel HEX input stream will now exit
; when it sees the :00xxxx01yy end-of-file type 1 record, or when an 'X'
; character is entered.
; - Optimise code-size by using relative jumps where possible
;
; 3/11/21 v2.1 by H. Peraza
; - allow 16-bit track number in R command.
;
; 4/3/20 v2.0 by H. Peraza
; - boot RSX280 and UZI280
; - G command calls (instead of jumping to) the user program, so a 'ret'
; instruction can be used to return to ZZmon.
; - Prevent endless loop of D command when end adress is FFFF.
; - Allow ending E command with '.' (dot) in addition to 'X'.
;
; 7/27/18 v0.999 by H. Peraza
; - fix MEMDMP address comparison so e.g. D 0000 01FF works correctly.
; - MEMDMP also dumps memory as ASCII.
; - COUTdone removed (no need to wait for character to be output before
; switching I/O page).
; - CIN calls COUT to echo the character, instead of writing it directly
; to the Tx data port (Tx may be still busy, although unlikely). Also
; uppercases the character.
; - correct conversion of char to uppercase.
; - small code optimizations:
; * stack top set to C000 (word-aligned) and not to BFFF, else the Z280
; will have to do two memory accesses for each push/pop.
; * ex de,hl instead of ld l,e + ld h,d
; * or a instead of cp 0
; * jr xxx instead of jp xxx (where applicable)
; * djnz xxx (where applicable)
; * better/shorter HEXOUT routine
; * HEX file checksum check done by simply 'add b' instead of 'neg a + cp b'
;
; 6/8/18 v0.99
; fix xE command to clear RAMdisk at 0x80000 by writing 0xE5 to the directory
; fill memory from top of program to 0xFFFF and from 0x0 to 0xAFFF
; test memory from top of program to 0xFFFF and from 0x0 to 0xAFFF
;
; 5/19/18 v0.98
; Relocate to 0xB400 so low memory can hold other applications
; memory diagnostic will test 0x0-0xB1FF and then 0xC000-0xFFFF
; Need to modify CFMon, CFMonLdr for different load address
; Combine C0 and C1 command into one C0 command
; C1 command will now copy program from 0x0 to 0x8000 to CF
; B1 will copy program stored in CF to 0x0 to 0x8000 and jump to 0x0
; Scratchpad area is now at 0xC000
; Fill memory and clear memory affect 0x0-0xB1FF and 0xC000-0xFFFF
; modify the xE command so to use page B and C instead of 0 and 1
;
; 4/16/18 v0.9
; Modify the CFMon and CFMonLdr
; Because the cold bootstrap code does not read all 512 bytes of boot
; sector before issue read sector command to get ZZMon code, different
; brand of CF reacts differently to the aborted operation. Correct that by
; read the BSY flag first then read the DRQ flag before prceeding.
;
; 3/25/18 v0.8
; move RAM disk directories to above 512K (0x80000), so the 'XE' command
; needs to change
;
; 3/15/18
; move ZZMon to 0x400 - 0xFFF, all the supporting software:
; CFMon, CFMonLdr, TinyLoad, LoadnGo are changed as well.
;
; 3/10/18 Major revision
; This will be the core monitor to perform all functions related to TinyZ280
; 4 new write commands:
; w0, writes the boot sector with the cold bootstrap code
; w1, writes this program into last 8 sectors of track 0. This program is 2K, but 4K reserved
; w2, writes CP/M 2.2 into track 0, sector 128-146, assuming CPM2.2 is loaded into 0xDC00-0xFFFF
; w3, writes CP/M 3 cpmldr into track 0, sectors after boot sectors, assuming the CP/M
; new boot command:
; b2, boot cpm2.2
; b3, boot cpm3
;
; 2/15/18 Monitor for TinyZZ
; It resides in 4 sectors right after boot sector
; Derived from testCF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZZMon, Copyright (C) 2018 Hui-chien Shen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
UARTconf equ 10h ; UART configuration register
RxData equ 16h ; on-chip UART receive register
TxData equ 18h ; on-chip UART transmit register
RxStat equ 14h ; on-chip UART transmitter status/control register
TxStat equ 12h ; on-chip UART receiver status/control register
CFdata equ 0C0h ; CF data register
CFerr equ 0C2h ; CF error reg
CFsectcnt equ 0C5h ; CF sector count reg
CF07 equ 0C7h ; CF LA0-7
CF815 equ 0C9h ; CF LA8-15
CF1623 equ 0CBh ; CF LA16-23
CF2427 equ 0CDh ; CF LA24-27
CFstat equ 0CFh ; CF status/command reg
CFbootFF equ 0A0h ; CF boot flip flop, initially set to 1
MMUctrl equ 0F0h ; MMU master control reg
MMUptr equ 0F1h ; MMU page descriptor reg pointer
MMUsel equ 0F5h ; MMU descriptor select port
MMUmove equ 0F4h ; MMU block move port
MMUinv equ 0F2h ; MMU invalidation port
DMActrl equ 01Fh ; DMA master control reg
DMA2dstL equ 10h ; DMA chan 2 destination reg low
DMA2dstH equ 11h ; DMA chan 2 destination reg high
DMA2srcL equ 12h ; DMA chan 2 source reg low
DMA2srcH equ 13h ; DMA chan 2 source reg high
DMA2cnt equ 14h ; DMA chan 2 count reg
DMA2td equ 15h ; DMA chan 2 transaction descriptor
DMA3dstL equ 18h ; DMA chan 3 destination reg low
DMA3dstH equ 19h ; DMA chan 3 destination reg high
DMA3srcL equ 1Ah ; DMA chan 3 source reg low
DMA3srcH equ 1Bh ; DMA chan 3 source reg high
DMA3cnt equ 1Ch ; DMA chan 3 count reg
DMA3td equ 1Dh ; DMA chan 3 transaction descriptor
CR equ 0Dh
LF equ 0Ah
FALSE equ 0
TRUE equ NOT FALSE
;TEST equ FALSE
.Z280
IF TEST
cseg
ELSE
aseg
org 0B400h ; when saved to boot track
ENDIF
; Also relocate the stack when testing
jp start
; variable area
refresho: ds 1 ; saved refresh register
refreshn: ds 1
testseed: ds 2 ; RAM test seed value
addr3116: ds 2 ; high address for Intel Hex format 4
; Initialization and sign-on message
start: ld sp,0C000h ; initialize stack
ld c,08h ; reg c points to I/O page register
ld l,0ffh ; set I/O page register to 0xFF
ldctl (c),hl ; write to I/O page register
in a,(0e8h) ; read the original refresh counter value
ld (refresho),a ; save it
ld a,0b0h ; initialize the refresh register to 48 counts
out (0e8h),a ; enable refresh at 16uS
in a,(0e8h) ; read back the counter value
ld (refreshn),a ; save it
ld l,0 ; set I/O page reg to 0
ldctl (c),hl ; write to I/O page register
out (CFbootFF),a ; clear the CFbootFF with any write
call UARTPage ; initialize page I/O reg to UART
ld a,0e2h ; initialize the UART configuration register
out (UARTconf),a
ld a,80h ; enable UART transmit and receive
out (TxStat),a
out (RxStat),a
ld hl,signon$
call strout
ld hl,251 ; initialize RAM test seed value
ld (testseed),hl ; save it
clrRx: in a,(RxStat) ; read on-chip UART receive status
and 10H ; Z data available?
jr z,CMD ; branch if not
in a,(RxData) ; else read to clear the input buffer
jr clrRx
; Main command loop
CMD: ld hl,PROMPT$
call strout
CMDLP1: call CINQ
cp LF ; ignore line feed
jr z,CMDLP1
push CMD ; push return address
cp CR ; carriage return gets a new prompt
ret z
cp ':' ; Is this Intel load file?
jr z,HEXLOAD
call UCASE ; convert to uppercase
call COUT ; echo character
cp 'H' ; Help command
jp z,HELP
cp 'D' ; Dump memory
jp z,MEMDMP
cp 'E' ; Edit memory
jp z,EDMEM
cp 'G' ; Go to address
jp z,GO
cp 'R' ; Read a CF sector
jp z,READCF
cp 'Z' ; Fill memory with zeros
jp z,FILLZ
cp 'F' ; Fill memory with FF
jp z,FILLF
cp 'C' ; Copy to CF
jp z,COPYCF
cp 'T' ; Test RAM
jp z,TESTRAM
cp 'B' ; Boot
jp z,BOOT
cp 'X' ; Clear RAMdisk directory at 0x80000
jp z,FORMAT
what: ld hl,what$
jp STROUT ; Print message and return
abort: ld hl,abort$ ; print command not executed
jp STROUT ; and return to get next command
; Initialize for Intel HEX file load operation
HEXLOAD:
ld hl,0 ; clear the high address in preparation for file load
ld (addr3116),hl ; addr3116 modified with Intel Hex format 4
; continue below
; load Intel file
fileload:
call GETHEXQ ; get two ASCII char (byte count) into hex byte in reg A
ld d,a ; save byte count to reg D
ld c,a ; save copy of byte count to reg C
ld b,a ; initialize the checksum
call GETHEXQ ; get MSB of address
ld h,a ; HL points to memory to be loaded
add a,b ; accumulating checksum
ld b,a ; checksum is kept in reg B
call GETHEXQ ; get LSB of address
ld l,a
add a,b ; accumulating checksum
ld b,a ; checksum is kept in reg B
call GETHEXQ ; get the record type, 0 is data, 1 is end
or a
jr z,filesave
cp 1 ; end of file transfer?
jr z,fileend
cp 4 ; Extended linear address?
jp nz,unknown ; if not, print a 'U'
; Extended linear address for greater than 64K
; this is where addr3116 is modified
add a,b ; accumulating checksum of record type
ld b,a ; checksum is kept in reg B
ld a,d ; byte count should always be 2
cp 2
jp nz,unknown
call GETHEXQ ; get first byte (MSB) of high address
ld (addr3116+1),a ; save to addr3116+1
add a,b ; accumulating checksum
ld b,a ; checksum is kept in reg B
; Little Endian format. MSB in addr3116+1, LSB in addr3116
call GETHEXQ ; get the 2nd byte (LSB) of of high address
ld (addr3116),a ; save to addr3116
add a,b ; accumulating checksum
ld b,a ; checksum is kept in reg B
call GETHEXQ ; get the checksum
add b ; compare to checksum accumulated in reg B
jp nz,badload ; checksum does not match, put '?'
ld a,'E' ; denote a successful Extended linear addr update
jr filesav2
fileend:
; end of the file load
call GETHEXQ ; flush the line, get the last byte
ld a,'X' ; mark the end with 'X'
call COUT
call CRLF ; carriage return and line feed
ret
; The assumption is the data is good and will be saved to the destination
; memory
filesave:
add a,b ; accumulating checksum of record type
ld b,a ; checksum is kept in reg B
ld ix,0c000h ; 0c000h is buffer for incoming data
ld a,d ; count is in reg D
or a ; check for zero length
jr nz,filesavx ; non-zero, get the bytes
call GETHEXQ ; get the checksum
add b ; add the cumulative checksum
jr nz,badload ; result should be zero if ok
ld a,'0' ; log we saw zero-length record
jr filesav2 ; and continue loading
filesavx:
call GETHEXQ ; get a byte
ld (ix),a ; save to buffer
add a,b ; accumulating checksum
ld b,a ; checksum is kept in reg B
inc ix
dec d
jr nz,filesavx
call GETHEXQ ; get the checksum
add b ; compare to checksum accumulated in reg B
jr nz,badload ; checksum not match, put '?'
call DMAPage ; set page I/O reg to DMA
; use DMA to put data from buffer to location pointed by EHL
push hl ; destination RAM in HL, save it for now
ld b,0 ; clear out MSB of reg BC, reg C contains the saved byte count
push bc ; DMA count is in reg BC, save it
; set up DMA master control
ld c,DMActrl ; set up DMA master control
ld hl,0f0e0h ; software ready for dma0&1, no end-of-process, no links
outw (c),hl ; write DMA master control reg
; set up DMA count register
ld c,DMA3cnt ; setup count of 128 byte
pop hl ; transfer what was saved in bc into hl
outw (c),hl ; write DMA3 count reg
; source buffer starts at 0x1000
ld c,DMA3srcH ; source is 0x1000
ld hl,0cfh ; A23..A12 are 0x00c
outw (c),hl ; write DMA3 source high reg
ld c,DMA3srcL ;
ld hl,0f000h ; A11..A0 are 0x0
outw (c),hl ; write DMA3 source low reg
; destination buffer is in E + HL (saved in stack right now)
ld c,DMA3dstH
ld a,(addr3116) ; get A23..A16 value into reg H
ld h,a ;
pop de ; restore saved HL into de
ld l,d ; move A15..A8 value
ld a,0fh ; force lowest nibble of DMA3dstH to 0xF
or l
ld l,a
outw (c),hl ; write DMA3 destination high reg
ld c,DMA3dstL
ld h,d ; reg DE contain A15..A0 value
ld l,e
ld a,0f0h ; force highest nibble of DMA3dstL to 0xF
or h
ld h,a
outw (c),hl ; write DMA3 destination low reg
; write DMA3 transaction description reg and start DMA
ld hl,8080h ; enable DMA3, burst, byte size, flowthrough, no interrupt
; incrementing memory for source & destination
ld c,DMA3td ; setup DMA3 transaction descriptor reg
outw (c),hl ; write DMA3 transaction description reg
; DMA should start now
call UARTPage ; set page I/O reg to default
;filesav1:
; call GETHEXQ ; get a byte
; ld (hl),a ; save to destination
; add a,b ; accumulating checksum
; ld b,a ; checksum is kept in reg B
; inc hl
; dec d
; jp nz,filesav1
; call GETHEXQ ; get the checksum
; add b ; compare to checksum accumulated in reg B
; jp nz,badload ; checksum not match, put '?'
ld a,'.' ; checksum match, put '.'
filesav2:
call COUT
jr flushln ; repeat until record end
badload:
ld a,'?' ; checksum not match, put '?'
jr filesav2
unknown:
ld a,'U' ; put out a 'U' and wait for next record
call COUT
flushln:
call CINQ ; keep on reading until ':' is encountered
cp 'X' ; or an 'X' is typed to abort back
jr z,loadabort ; to the command prompt.
cp 'x'
jr z,loadabort
cp ':'
jr nz,flushln
jp fileload
loadabort:
ld hl,ldabort$ ; put out an abort message and
jp STROUT ; return to the command prompt
; format CF drives directories unless it is RAM disk
; drive A directory is track 1, sectors 0-0x7F (2048 directory entries)
; drive B directory is track 0x40, sectors 0-0x7F " " "
; drive C directory is track 0x80, sectors 0-0x7F " " "
; drive D directory is track 0xC0, sectors 0-0x7F " " "
FORMAT: ld hl,clrdir$ ; command message
call STROUT
call CIN
cp 'A'
jr z,formatA ; fill track 1 sectors 0-0x7F with 0xE5
cp 'B'
jr z,formatB ; fill track 0x40 sectors 0-0x7F with 0xE5
cp 'C'
jr z,formatC ; fill track 0x80 sectors 0-0x7F with 0xE5
cp 'D'
jr z,formatD ; fill track 0xC0 sectors 0-0x7F with 0xE5
cp 'E'
jr z,ClearDir
jp abort ; abort command if not in the list of options
formatA:
ld de,100h ; start with track 1 sector 0
jr doformat
formatB:
ld de,4000h ; start with track 0x40 sector 0
jr doformat
formatC:
ld de,8000h ; start with track 0x80 sector 0
jr doformat
formatD:
ld de,0c000h ; start with track 0xC0 sector 0
doformat:
ld hl,confirm$ ; confirm command execution
call STROUT
call tstCRLF
jp nz,abort ; abort command if not CRLF
call CFPage ; initialize page I/O reg to CF
ld a,40h ; set Logical Address addressing mode
out (CF2427),a
xor a ; clear reg A
out (CF1623),a ; MSB track is 0
ld a,d ; reg D contains the track info
out (CF815),a
ld c,CFdata ; reg C points to CF data reg
ld hl,0e5e5h ; value for empty directories
wrCFf:
ld a,1 ; write 1 sector
out (CFsectcnt),a ; write to sector count with 1
ld a,e ; write CPM sector
cp 80h ; format sector 0-0x7F
jr z,wrCFdonef ; done formatting
out (CF07),a ;
ld a,30h ; write sector command
out (CFstat),a ; issue the write sector command
wrdrqf:
in a,(CFstat) ; check data request bit set before write CF data
and 8 ; bit 3 is DRQ, wait for it to set
jr z,wrdrqf
ld b,0h ; sector has 256 16-bit data
loopf:
outw (c),hl
in a,(CFstat) ; OUTJMP bug fix
djnz loopf
readbsyf:
; spin on CF status busy bit
in a,(CFstat) ; read CF status
and 80h ; mask off all except busy bit
jr nz,readbsyf
inc e ; write next sector
jr wrCFf
wrCFdonef:
call UARTPage ; set page I/O reg to internal UART
ret
; Clear RAM disk directory starting from 0x80000 to 0x90000
; fill memory with 0xE5
; page 0xB is where this program resides
; page 1 is the window to access 16 meg memory space
ClearDir:
; ld hl,clrdir$ ; command message
; call STROUT
ld hl,confirm$ ; confirm command execution
call STROUT
call tstCRLF
jp nz,abort ; abort command if not CRLF
call MMUPage
; initialize two system page descriptors, page 0xB and page 1
ld a,1bh ; start with system page 0xB where this program is located
out (MMUptr),a
ld c,MMUsel ; points to MMU select reg
ld hl,0bah ; system page 0xB descriptor logical=physical, enable cache, valid
outw (c),hl ; write system page 0xB
; 3/25/18 move RAMdisk directory to 0x80000
ld hl,0808h ; system page 1 maps to 0x80000, disable cache, valid
push hl ; will use this value later
ld a,11h ; point to system page 1
out (MMUptr),a ;
outw (c),hl ; write system page 1
ld c,MMUctrl ; point to MMU master control reg
ld hl,03bffh ; enable system translate
outw (c),hl ; turn on MMU
ld d,16 ; reg d is loop counter, do this 16 times
ld a,11h ; point to system page 1
out (MMUptr),a
ld c,MMUsel ; point to MMU select
clrDir1:
; 0x1000-0x1FFF maps to 0x080000-0x080FFF
ld hl,1000h ; start with 0x080000
clrDir:
ld a,0e5h ; fill directory area with 0xE5
ld (hl),a
inc hl
ld a,20h ; hl reaches 0x2000?
cp a,h
jr nz,clrDir
pop hl ; get the previous system page 1 descriptor value
dec d ; decrement loop counter
jr z,clrDir2
ld a,10h ; increment to next 4K page
add a,l ; go thru 16 4K page from 0x080000 to 0x08F000
ld l,a
push hl ; save the new descriptor value for next iteration
outw (c),hl ; write system page 1
jr clrDir1
clrDir2:
ld c,MMUctrl ; point to MMU master control reg
ld hl,33ffh ; turn off MMU,
outw (c),hl ; turn off MMU
nop ; OUTJMP bug fix
nop
nop
nop
call UARTPage ; restore Page I/O reg to default
ret
; print help message
HELP: ld hl,HELP$ ; print help message
jp STROUT ; and return
; Boot OS
BOOT: ld hl,bootcpm$ ; print command message
call STROUT
call CIN ; get input
cp '1' ; '1' is user apps
jp z,bootApps
cp '2' ; '2' is CP/M 2.2
jp z,boot22
cp '3' ; '3' is CP/M 3
jr z,boot3
cp '4' ; '4' is RSX280
jp z,bootrsx
cp '5' ; '5' is UZI280
jp z,bootuzi
jp what
boot3: ; boot CP/M 3
; copy program from LA1-LA15 (7.5K) to 0x1100
; jump to 0x1100 after copy is completed.
ld hl,confirm$ ; CRLF to execute the command
call STROUT
call tstCRLF
jp nz,abort ; abort command if no CRLF
call CFPage ; initialize page I/O reg to CF
ld a,40h ; set Logical Address addressing mode
out (CF2427),a
xor a ; clear reg A
out (CF1623),a ; track 0
out (CF815),a
ld hl,1100h ; CPM3LDR starts from 0x1100
ld c,CFdata ; reg C points to CF data reg
ld d,1h ; read from LA1 to LA15, 7K--much bigger than needed
readCPM3:
ld a,1 ; read 1 sector
out (CFsectcnt),a ; write to sector count with 1
ld a,d ; read CPM sector
cp 10h ; between LA1 and LA15
jr z,goCPM3 ; done copying, execute CPM
out (CF07),a ;
ld a,20h ; read sector command
out (CFstat),a ; issue the read sector command
readdrq3:
in a,(CFstat) ; check data request bit set before read CF data
and 8 ; bit 3 is DRQ, wait for it to set
jr z,readdrq3
ld b,0h ; sector has 256 16-bit data
inirw
inc d ; read next sector
jr readCPM3
goCPM3:
call UARTPage ; set page I/O reg to internal UART
jp 01100h ; BIOS starting address of CP/M
boot22: ; boot CP/M 2.2
; copy program from LA128-LA146 (9K) to 0xDC00
; jump to 0xF200 after copy is completed.
ld hl,confirm$ ; CRLF to execute the command
call STROUT
call tstCRLF
jp nz,abort ; abort command if no CRLF
call CFPage ; initialize page I/O reg to CF
ld a,40h ; set Logical Address addressing mode
out (CF2427),a
xor a ; clear reg A
out (CF1623),a ; track 0
out (CF815),a
ld hl,0dc00h ; CPM starts from 0xDC00 to 0xFFFF
ld c,CFdata ; reg C points to CF data reg
; ld d,9 ; read from LA 9 to LA27
ld d,80h ; read from LA 0x80 to LA 0x92
readCPM1:
ld a,1 ; read 1 sector
out (CFsectcnt),a ; write to sector count with 1
ld a,d ; read CPM sector
; cp 27 ; between LA9 and LA26
cp 92h ; between LA80h and LA91h
jr z,goCPM ; done copying, execute CPM
out (CF07),a ;
ld a,20h ; read sector command
out (CFstat),a ; issue the read sector command
readdrqCPM:
in a,(CFstat) ; check data request bit set before read CF data
and 8 ; bit 3 is DRQ, wait for it to set
jr z,readdrqCPM
ld b,0h ; sector has 256 16-bit data
inirw
inc d ; read next sector
jr readCPM1
goCPM:
call UARTPage ; set page I/O reg to internal UART
jp 0F200h ; BIOS starting address of CP/M
bootrsx:
; boot RSX280
; copy boot loader from LA 010000h to 0000h and execute it
ld ix,rsxpt
jr bootld
bootuzi:
; boot UZI280
; copy boot loader from LA 020000h to 0000h and execute it
ld ix,uzipt
bootld: ld hl,confirm$ ; CRLF to execute the command
call STROUT
call tstCRLF
jp nz,abort ; abort command if no CRLF
call CFPage ; initialize page I/O reg to CF
ld a,40h ; set Logical Address addressing mode
out (CF2427),a
xor a ; clear reg A
out (CF07),a ; sector 0
ld a,(ix+0)
out (CF815),a ; track lo
ld a,(ix+1)
out (CF1623),a ; track hi
ld a,1 ; read 1 sector
out (CFsectcnt),a ; write to sector count with 1
ld hl,0 ; boot loader executes at 0000h
ld c,CFdata ; reg C points to CF data reg
ld a,20h ; read sector command
out (CFstat),a ; issue the read sector command
wtdrq: in a,(CFstat) ; check data request bit set before read CF data
and 8 ; bit 3 is DRQ, wait for it to set
jr z,wtdrq
ld b,0 ; one block is 256 words
inirw
call UARTPage ; set page I/O reg to internal UART
push ix ; setup data area for bootloader
pop hl
ld de,200h
ld bc,4
ldir
ld c,(ix+4) ; partition number (0-based)
jp 0000h ; execute boot loader
rsxpt: dw 0100h ; partition start
db 0D8h,1 ; type and boot flag
db 4 ; partition number
uzipt: dw 0200h ; partition start
db 0D1h,1 ; type and boot flag
db 5 ; partition number
bootApps:
; User applications reside in CF sector 0x40-0x7F.
; Copy it to 0x0-0x7FFF and jump to 0x0
ld hl,confirm$ ; CRLF to execute the command
call STROUT
call tstCRLF
jp nz,abort ; abort command if no CRLF
call CFPage ; initialize page I/O reg to CF
ld a,40h ; set Logical Address addressing mode
out (CF2427),a
xor a ; clear reg A
out (CF1623),a ; track 0
out (CF815),a
ld hl,0 ; user apps starts from 0x0
ld c,CFdata ; reg C points to CF data reg
ld d,40h ; read from LA 0x40 to LA 0x7F
readApp1:
ld a,1 ; read 1 sector
out (CFsectcnt),a ; write to sector count with 1
ld a,d ; read CPM sector
cp 80h ; between LA40h and LA7fh
jr z,goApps ; done copying, execute user apps
out (CF07),a ;
ld a,20h ; read sector command
out (CFstat),a ; issue the read sector command
readdrqApp:
in a,(CFstat) ; check data request bit set before read CF data
and 8 ; bit 3 is DRQ, wait for it to set
jr z,readdrqApp
ld b,0h ; sector has 256 16-bit data
inirw
inc d ; read next sector
jr readApp1
goApps:
call UARTPage ; set page I/O reg to internal UART
jp 0h ; User apps starts at 0x0
; Fill memory from end of program to 0xFFFF with zero or 0xFF
; Also fill memory from 0x0 to 0xB000 with zero or 0xFF
FILLZ: ld hl,fill0$ ; print fill memory with 0 message
call STROUT
ld b,0 ; fill memory with 0
jr dofill
FILLF: ld hl,fillf$ ; print fill memory with F message
call STROUT
ld b,0ffh ; fill memory with ff
dofill: ld hl,confirm$ ; get confirmation before executing
call STROUT
call tstCRLF ; check for carriage return
jp nz,abort
ld hl,PROGEND ; start from end of this program
ld a,0ffh ; end address in reg A
filla: ld (hl),b ; write memory location
inc hl
cp h ; reached 0xFF00?
jr nz,filla ; continue til done
cp l ; reached 0xFFFF?
jr nz,filla
ld hl,0b000h ; fill value from 0xB000 down to 0x0000
fillb: dec hl
ld (hl),b ; write memory location with desired value
ld a,h ; do until h=l=0
or l
jr nz,fillb
ret
; Read CF
; Set page I/O to 0, afterward set it back to 0FEh
READCF:
ld hl,read$ ; put out read command message
call STROUT
ld hl,track$ ; enter track in hex value
call STROUT
call ADRIN ; get a word of hex value as track
push de ; save track value in stack
ld hl,sector$ ; enter sector in hex value
call STROUT
call GETHEX ; get a byte of hex value as sector
ret c
push af ; save sector value in stack
call CFPage ; initialize page I/O reg to CF
ld hl,1000h ; copy previous block to 2000h
ld de,2000h
ld bc,200h ; copy 512 bytes
ldir ; block copy
ld a,40h ; set Logical Address addressing mode
out (CF2427),a
ld a,1 ; read 1 sector
out (CFsectcnt),a ; write to sector count with 1
pop af ; restore the sector value
out (CF07),a ; write sector
pop de ; restore the track value
ld a,e
out (CF815),a ; write low byte of track
ld a,d
out (CF1623),a ; write high byte of track
ld a,20h ; read sector command
out (CFstat),a ; issue the read sector command
readdrq:
in a,(CFstat) ; check data request bit set before read CF data
and 8 ; bit 3 is DRQ, wait for it to set
jr z,readdrq
ld hl,1000h ; store CF data starting from 1000h
ld c,CFdata ; reg C points to CF data reg
ld b,0h ; sector has 256 16-bit data
inirw
ld hl,1000h ; compare with data block in 2000h
ld bc,200h
ld de,2000h
blkcmp:
ld a,(de) ; get a byte from block in 2000h
inc de
cpi ; compare with corresponding data in 1000h
jp po,blkcmp1 ; exit at end of block compare
jr z,blkcmp ; exit if data not compare
call UARTPage
ld hl,notsame$ ; send out message that data not same as previous read
call STROUT
jr dumpdata
blkcmp1:
call UARTPage ; initialize page I/O reg back to UART
ld hl,issame$ ; send out message that data read is same as before
call STROUT
dumpdata:
ld d,32 ; 32 lines of data
ld hl,1000h ; display 512 bytes of data
dmpdata1:
call CRLF ; add a CRLF per line
call DMP16 ; display 16 bytes per line
dec d
jr nz,dmpdata1
;; dec hl ; point hl to the address that caused error
;; ld a,'H' ; display content of HL reg
;; call COUT ; print the HL label
;; ld a,'L'
;; call COUT
;; call SPCOUT
;; call ADROUT ; output the content of HL
ret
; Write CF
; allowable parameters are:
; '0' for boot sector & ZZMon,
; '1' for 32K apps,
; '2' for CPM 2.2,
; '3' for CPM 3
; Set page I/O to 0, afterward set it back to 0FEh
COPYCF:
ld hl,copycf$ ; print copy message
call STROUT
call CIN ; get write parameters
cp '0'
jp z,cpboot
cp '1'
jp z,cpAPPS
cp '2'
jp z,CopyCPM2
cp '3'
jp z,CopyCPM3
jp what ; error, abort command
; Test for CR or LF. Echo back, return 0
tstCRLF:
call CIN ; get a character
cp CR ; if carriage return, output LF
jp z,tstCRLF1
cp LF ; if line feed, output CR
jr z,tstCRLF2
ret
tstCRLF1:
ld a,LF ; put out a LF
call COUT
xor a ; set Z flag
ret
tstCRLF2:
ld a,CR ; put out a CR
call COUT
xor a ; set Z flag
ret
; Write CPM to CF
; Write data from 0xDC00 to 0xFFFF to CF LA128-LA146 (9K)
CopyCPM2:
; call tstCRLF
; ret nz ; abort command if not CR or LF
ld hl,0DC00h ; CPM starts from 0xDC00 to 0xFFFF
ld de,8092h ; reg DE contains beginning sector and end sector values
jr wrCF
CopyCPM3:
ld hl,1100h ; CPMLDR starts from 0x1100
ld de,0110h ; reg DE contains beginning sector and end sector values
jr wrCF
cpboot:
; call tstCRLF
; ret nz ; abort command if not CR or LF
ld hl,confirm$ ; carriage return to execute the program
call STROUT
call tstCRLF
ret nz ; abort command if not CR or LF
ld hl,0B200h ; cold boot loader is included in this program at 0B200h
call wrCFb
;;disable:
;; jp wrCF ; this instruction will be zero-ed (NOP) when ZZMon is copied to CF
;; ld hl,notavail$ ; Do not allow boot sector to be changed
;; call STROUT
;; ret
;;cpZZMon:
; call tstCRLF
; ret nz
;; ld hl,disable ; nop the "jp wrCF" instruction for copying boot sector
; this is because CFMonLdr is not copied into CF
;; ld (hl),0 ; 0 is nop instruction
;; inc hl
;; ld (hl),0
;; inc hl
;; ld (hl),0
ld hl,0B400h ; ZZMon starts from 0xB400 to 0xBFFF
ld de,0F8FEh ; last 8 sectors of track 0 reserved for ZZMon.
jr wrCF1 ; CF is already initialized in wrCFb routine, jump directly
; to sector copy routine
cpAPPS:
ld hl,0 ; Application starts from 0 to 0x7FFF
ld de,407Fh ; reg DE contains beginning sector and end sector values
wrCF: push hl ; save value
ld hl,confirm$ ; carriage return to execute the program
call STROUT
pop hl
call tstCRLF
ret nz ; abort command if not CR or LF
call CFPage ; initialize page I/O reg to CF
ld a,40h ; set Logical Address addressing mode
out (CF2427),a
xor a ; clear reg A
out (CF1623),a ; track 0
out (CF815),a
ld c,CFdata ; reg C points to CF data reg
wrCF1: ld a,1 ; write 1 sector
out (CFsectcnt),a ; write to sector count with 1
ld a,d ; write CPM sector
cp e ; reg E contains end sector value
jr z,wrCFdone ; done copying, execute CPM
out (CF07),a ;
ld a,30h ; write sector command
out (CFstat),a ; issue the write sector command
wrdrq: in a,(CFstat) ; check data request bit set before write CF data
and 8 ; bit 3 is DRQ, wait for it to set
jr z,wrdrq
ld b,0 ; sector has 256 16-bit data
otirw
readbsy:
in a,(CFstat) ; read CF status
and 80h ; mask off all except busy bit
jr nz,readbsy ; loop while busy
inc d ; write next sector
jr wrCF1
wrCFdone:
call UARTPage ; set page I/O reg to internal UART
ret
; This routine is dedicated to write boot sector of CF disk
wrCFb: call CFPage ; initialize page I/O reg to CF