-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathZmon.asm
1404 lines (1314 loc) · 38.6 KB
/
Zmon.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
; Basic monitor for Z80SBC based on ProtoRC rev 1
; 10/25/18 fork from ZZ80Mon
; L ist memory in Intel Hex format
; I in from port # in I/O page 0
; O out to port # in I/O page 0
; Display the ASCII characters along with HEX value
; show the correct memory address with 'R' command
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZMon, Copyright (C) 2018 Hui-chien Shen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RxData equ 0f9h ; CPLD UART receive register
TxData equ 0f9h ; CPLD UART transmit register
RxStat equ 0f8h ; CPLD UART transmitter status/control register
TxStat equ 0f8h ; CPLD UART receiver status/control register
CFdata equ 0C0h ;CF data register
CFerr equ 0C1h ;CF error reg
CFsectcnt equ 0C2h ;CF sector count reg
CF07 equ 0C3h ;CF LA0-7
CF815 equ 0C4h ;CF LA8-15
CF1623 equ 0C5h ;CF LA16-23
CF2427 equ 0C6h ;CF LA24-27
CFstat equ 0C7h ;CF status/command reg
ORG 0b000h
ld hl,400h ; ZMon is stored in 0x400 to 0xFFF
ld de,0b400h ; destination where ZMon will run
ld bc,0c00h ; copy 3K of program
ldir
jp 0b400h ; jump into ZMon
ORG 0b400H
; This part of the program will be relocated to 0x400 post process
jr start
; variable area
testseed: ds 2 ; RAM test seed value
addr3116 ds 2 ; high address for Intel Hex format 4
RDsector ds 1 ; current RAM disk sector
RDtrack ds 1 ; current RAM disk track
RDaddr ds 2 ; current RAM disk address
;Initialization and sign-on message
start:
ld sp,0bfffh ; initialize stack
LD HL,signon$
CALL strout
call readbsy ;;8 wait until busy flag is cleared
ld a,0e0h ;;8 set up LBA mode
out (CF2427),a ;;8
ld a,1 ;;8 set feature to 8-bit interface
out (CFerr),a ;;8
ld a,0efh ;;8 set feature command
out (CFstat),a ;;8
call readbsy ;;8 wait until busy flag is cleared
ld hl,251 ; initialize RAM test seed value
ld (testseed),hl ; save it
clrRx:
IN A,(RxStat) ; read on-chip UART receive status
AND 2 ; data available?
jp z,CMD
IN A,(RxData) ; read clear the input buffer
jr clrRx
;Main command loop
CMD: LD HL, PROMPT$
CALL strout
CMDLP1:
CALL cinq
cp ':' ; Is this Intel load file?
jp z,initload
cp 0ah ; ignore line feed
jp z,CMDLP1
cp 0dh ; carriage return get a new prompt
jp z,CMD
CALL cout ; echo character
AND 5Fh
cp 'H' ; help command
jp z,HELP
CP A,'D'
JP Z,MEMDMP
CP A,'E'
JP Z,EDMEM
cp a,'I' ; read data from specified I/O port in page 0
jp z,INPORT
cp a,'O' ; write data to specified I/O port in page 0
jp z,OUTPORT
cp a,'L' ; list memory as Intel Hex format
jp z,LISTHEX
CP A,'G'
JP Z,go
cp a,'R' ; read a CF sector
jp z,READRD
cp a,'Z' ; fill memory with zeros
jp z,fillZ
cp a,'F' ; fill memory with ff
jp z,fillF
cp a,'C' ; Copy to CF
jp z,COPYCF
cp a,'T' ; testing RAM
jp z,TESTRAM
cp 'B' ; boot CPM
jp z,BootCPM
cp 'X' ; clear RAMdisk directory at 0x80000
jp z,format
what:
LD HL, what$
CALL strout
JP CMD
abort:
ld hl,abort$ ; print command not executed
call strout
jp CMD
; initialize for file load operation
initload:
ld hl,0 ; clear the high address in preparation for file load
ld (addr3116),hl ; addr3116 modified with Intel Hex format 4
; 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
cp 0
jp z,filesave
cp 1 ; end of file transfer?
jp 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
neg a ; 2's complement
cp b ; compare to checksum accumulated in reg B
jp nz,badload ; checksum not match, put '?'
ld a,'E' ; denote a successful Extended linear addr update
jp filesav2
; end of the file load
fileend:
call GETHEXQ ; flush the line, get the last byte
ld a,'X' ; mark the end with 'X'
call cout
ld a,10 ; carriage return and line feed
call cout
ld a,13
call cout
jp CMD
; 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
filesavx:
call GETHEXQ ; get a byte
;Z80SBC ld (ix),a ; save to buffer
ld (hl),a ;Z80SBC save data to destination
add a,b ; accumulating checksum
ld b,a ; checksum is kept in reg B
inc ix
inc hl ;Z80SBC
dec d
jp nz,filesavx
call GETHEXQ ; get the checksum
neg a ; 2's complement
cp b ; compare to checksum accumulated in reg B
jp 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
; db 0edh,0bfh ; op code for OUTW (C),HL
; 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
; db 0edh,0bfh ; op code for OUTW (C),HL
; source buffer starts at 0xc000
; ld c,DMA3srcH ; source is 0x1000
; ld hl,0cfh ; A23..A12 are 0x00c
; outw (c),hl ; write DMA3 source high reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; ld c,DMA3srcL ;
; ld hl,0f000h ; A11..A0 are 0x0
; outw (c),hl ; write DMA3 source low reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; 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
;lines marked with ;;mmu comment are added to check for physical page 0
; insert a test for physical page 0 (addr3116 equal 0 & upper nibble of reg D also zero)
; or a ;;mmu reg A contains (addr3116)
; jp nz,notpage0 ;;mmu not physical page 0
; ld a,d ;;mmu A31..A16 is zero, now examine A15..A12
; and 0f0h ;;mmu mask off A11..A8
; jp nz,notpage0 ;;mmu not physical page 0
; the destination is physical page 0, substitue 0x3C000 instead
; put 3C000 in HL and jump to write dma3destination
; ld l,0cfh ;;mmu
; ld h,03h ;;mmu
; jp do_dma3hi ;;mmu
;notpage0:
; ld l,d ; move A15..A8 value
; ld a,0fh ; force lowest nibble of DMA3dstH to 0xF
; or l
;do_dma3hi:
; outw (c),hl ; write DMA3 destination high reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; 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
; outw (c),hl ; write DMA3 destination low reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; 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
; db 0edh,0bfh ; op code for OUTW (C),HL
; DMA should start now
ld a,'.' ; checksum match, put '.'
filesav2:
call cout
jp flushln ; repeat until record end
badload:
ld a,'?' ; checksum not match, put '?'
jp 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 ':'
jp nz,flushln
jp fileload
; format CF drives directories unless it is RAM disk
; drive A directory is track 1, sectors 0-0x1F
; drive B directory is track 0x40, sectors 0-0x1F
; drive C directory is track 0x80, sectors 0-0x1F
; drive D directory is track 0xC0, sectors 0-0x1F
format:
ld hl,clrdir$ ; command message
call strout
call cin
cp 'A'
jp z,formatA ; fill track 1 sectors 0-0x1F with 0xE5
cp 'B'
jp z,formatB ; fill track 0x40 sectors 0-0x1F with 0xE5
cp 'C'
jp z,formatC ; fill track 0x80 sectors 0-0x1F with 0xE5
cp 'D'
jp z,formatD ; fill track 0xC0 sectors 0-0x1F with 0xE5
; cp 'E'
; jp z,ClearDir
jp abort ; abort command if not in the list of options
formatA:
ld de,100h ; start with track 1 sector 0
jp doformat
formatB:
ld de,4000h ; start with track 0x40 sector 0
jp doformat
formatC:
ld de,8000h ; start with track 0x80 sector 0
jp 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
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 20h ; format sector 0-0x1F
jp 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
jp z,wrdrqf
ld b,0h ; sector has 256 16-bit data
loopf:
;z80 db 0edh,0bfh ; op code for OUT[W] (C),HL
; outw (c),hl
out (c),h ;z80 writes 2 bytes to CF
out (c),h
inc b
jp nz,loopf
readbsyf:
; spin on CF status busy bit
in a,(CFstat) ; read CF status
and 80h ; mask off all except busy bit
jp nz,readbsyf
inc e ; write next sector
jp wrCFf
wrCFdonef:
jp CMD
INPORT:
; read data from specified I/O port in page 0
; command format is "I port#"
;
ld hl,inport$ ; print command 'I' prompt
call strout
call GETHEX ; get port # into reg A
push bc ; save register
ld c,a ; load port # in reg C
; call ZeroPage ; The I/O port resides in page 0
in b,(c) ; get data from port # into reg B
; call UARTPage
ld hl,invalue$
call strout
ld a,b
call HEXOUT
pop bc ; restore reg
jp CMD
OUTPORT:
; write data to specified I/O port in page 0
; command format is "O value port#"
ld hl,outport$ ; print command 'O' prompt
call strout
call GETHEX ; get value to be output
push bc ; save register
ld b,a ; load value in reg B
ld hl,outport2$ ; print additional prompt for command 'O'
call strout
call GETHEX ; get port number into reg A
ld c,a
; call ZeroPage ; The I/O port resides in page 0
out (c),b ; output data in regB to port in reg C
; call UARTPage
pop bc
jp CMD
LISTHEX:
; list memory as Intel Hex format
; the purpose of command is to save memory as Intel Hex format to console
ld hl,listhex$ ; print command 'L' prompt
call strout
call ADRIN ; get address word into reg DE
push de ; save for later use
ld hl,listhex1$ ; print second part of 'L' command prompt
call strout
call ADRIN ; get end address into reg DE
listhex1:
ld hl,CRLF$ ; put out a CR, LF
call strout
ld c,10h ; each line contains 16 bytes
ld b,c ; reg B is the running checksum
ld a,':' ; start of Intel Hex record
call cout
ld a,c ; byte count
call HEXOUT
pop hl ; start address in HL
call ADROUT ; output start address
ld a,b ; get the checksum
add a,h ; accumulate checksum
add a,l ; accumulate checksum
ld b,a ; checksum is kept in reg B
xor a
call HEXOUT ; record type is 00 (data)
listhex2:
ld a,(hl) ; get memory pointed by hl
call HEXOUT ; output the memory value in hex
ld a,(hl) ; get memory again
add a,b ; accumulate checksum
ld b,a ; checksum is kept in reg B
inc hl
dec c
jp nz,listhex2
ld a,b ; get the checksum
neg a
call HEXOUT ; output the checksum
; output 16 memory location, check if reached the end address (saved in reg DE)
; unsign compare: if reg A < reg N, C flag set, if reg A > reg N, C flag clear
push hl ; save current address pointer
ld a,h ; get MSB of current address
cp d ; reg DE contain the end address
jp nc,hexend ; if greater, output end-of-file record
jp c,listhex1 ; if less, output more record
; if equal, compare the LSB value of the current address pointer
ld a,l ; now compare the LSB of current address
cp e
jp c,listhex1 ; if less, output another line of Intel Hex
hexend:
; end-of-record is :00000001FF
ld hl,CRLF$
call strout
ld a,':' ; start of Intel Hex record
call cout
xor a
call HEXOUT ; output "00"
xor a
call HEXOUT ; output "00"
xor a
call HEXOUT ; output "00"
ld a,1
call HEXOUT ; output "01"
ld a,0ffh
call HEXOUT ; output "FF"
pop hl ; clear up the stack
jp CMD
; print help message
HELP:
ld hl,HELP$ ; print help message
call strout
jp CMD
; boot CPM
; copy program from LA9-LA26 (9K) to 0xDC00
; jump to 0xF200 after copy is completed.
BootCPM:
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 cpm2.2
jp z,boot22
; cp '3' ; '3' is cpm3, not implemented
; jp z,boot3
jp what
boot22:
ld hl,confirm$ ; CRLF to execute the command
call strout
call tstCRLF
jp nz,abort ; abort command if no CRLF
; call COUTdone ; wait for transmit done before switch page i/o reg
ld a,0e0h ; 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
jp 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
jp z,readdrqCPM
ld b,0h ; sector has 256 16-bit data
inir ;z80 read 256 bytes
ld b,0h ;z80
inir ;z80 read 256 bytes
;z80 db 0edh,92h ; op code for inirw input word and increment
; inirw
inc d ; read next sector
jp readCPM1
goCPM:
jp 0f200h ; BIOS starting address of CP/M
fillZ:
ld hl,fill0$ ; print fill memory with 0 message
call strout
ld b,0 ; fill memory with 0
jp 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?
jp nz,filla ; continue til done
cp l ; reached 0xFFFF?
jp 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
jp nz,fillb
jp CMD
; Read RAMdisk
; start from 0x1000 as track 0 sector 0
; each track is 128k, so there are total of 4 tracks
; each sector is 512 bytes, this is holdover from a CF sector
; use DMA to read a sector to 0x1000
READRD:
ld hl,read$ ; put out read command message
call strout
ld hl,track$ ; enter track in hex value
call strout
call GETHEX ; get a byte of hex value as track
ld (RDtrack),a ; save it
;; push af ; 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
ld (RDsector),a ; save it
;; push af ; save sector value in stack
READRD1:
ld hl,1000h ; copy previous block to 2000h
ld de,2000h
ld bc,200h ; copy 512 bytes
ldir ; block copy
; track 0 is 0x10000 base address plus 0x200*sector
; track 1 is 0x30000 base address plus 0x200*sector
; track 2 is 0x50000 base address plus 0x200*sector
; track 3 is 0x70000 base address plus 0x200*sector
; call DMAPage ; set page i/o reg to DMA
; 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
; db 0edh,0bfh ; op code for OUTW (C),HL
; set up DMA count register
; ld c,DMA3cnt ; setup count of 512 bytes
; ld hl,200h
; outw (c),hl ; write DMA3 count reg
; db 0edh,0bfh ; op code for OUTW (C),HL
;; pop af ; get sector value from stack
;; push af ; save for later use
; ld a,(RDsector) ; get sector value
; add a ; 2*n, no need to worry about carry for this part of operation
; or 0f0h ; set high nibble to all 1's
; ld h,a ; forming source low address
; ld l,0
; ld c,DMA3srcL ;
; outw (c),hl ; write DMA3 source low reg
; db 0edh,0bfh ; op code for OUTW (C),HL
;; pop af ; restore, now calculate the high 12-bit of source address
; ld a,(RDsector)
; ld h,0
; ld l,a ; get the sector value into reg L
; add hl,hl ; 16-bit add, carry bit goes into reg H
; ld a,0fh ; force lowest nibble to all 1's
; or l ;
; ld l,a ; reg L has the low address value
; now get the high address value into reg H:
;; pop af ; get track number
; ld a,(RDtrack)
; add a ; track 0 ->0x10000, track 1 -> 0x30000, track 2 -> 0x50000, etc
; add 1 ; add the track offset
; add h ; h may be 1 due to carry from hl+hl operation
; ld h,a ; reg H has the high address value
; ld c,DMA3srcH ; point to source high register
; outw (c),hl ; write DMA3 source high reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; destination is 0x1000
; ld c,DMA3dstH
; ld hl,01fh ; A23..A12 are 0x001, low nibble is all 1's
; outw (c),hl ; write DMA3 destination high reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; ld c,DMA3dstL
; ld hl,0f000h ; A11..A0 are 0x000, high nibble is all 1's
; outw (c),hl ; write DMA3 destination low reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; 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
; db 0edh,0bfh ; op code for OUTW (C),HL
; DMA should start now
;dumpdata:
; ld d,32 ; 32 lines of data
; ld hl,1000h ; display 512 bytes of data
;dmpdata1:
; push hl ; save hl
; ld hl,CRLF$ ; add a CRLF per line
; call strout
; pop hl ; hl is the next address to display
; call DMP16TS ; display 16 bytes per line
; dec d
; jp nz,dmpdata1
; 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
; jp z,blkcmp ; exit if data not compare
; ld hl,notsame$ ; send out message that data not same as previous read
; call strout
; jp chkRDmore
;blkcmp1:
; ld hl,issame$ ; send out message that data read is same as before
; call strout
;chkRDmore:
; ld hl,RDmore$ ; carriage return for next sector of data
; call strout
; call tstCRLF ; look for CRLF
; jp nz,CMD ;
; ld hl,(RDsector) ; load track & sector as 16-bit value
; inc hl ; increment by 1
; ld (RDsector),hl ; save updated values
; ld hl,track$ ; print track & sector value
; call strout
; ld a,(RDtrack)
; call HEXOUT
; ld hl,sector$
; call strout
; ld a,(RDsector)
; call HEXOUT
; jp READRD1
;********************** CF read**************
ld a,0e0h ; set Logical Address addressing mode
out (CF2427),a
ld a,1 ; read 1 sector
out (CFsectcnt),a ; write to sector count with 1
ld a,0 ; read first sector
out (CF1623),a ; high byte of track is always 0
;Z80SBC pop af ; restore the sector value
ld a,(RDsector) ;Z80SBC get sector value
out (CF07),a ; write sector
;Z80SBC pop af ; restore the track value
ld a,(RDtrack)
out (CF815),a
; ld a,0 ; LA sector 0
; out (CF07),a ;
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
jp 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
inir ;Z80SBC
ld b,0h ;Z80SBC 2nd half of 512-byte sector
inir
;Z80SBC db 0edh,92h ; op code for inirw input word and increment
; 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
jp z,blkcmp ; exit if data not compare
; call UARTPage
ld hl,notsame$ ; send out message that data not same as previous read
call strout
jp 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:
push hl ; save hl
ld hl,CRLF$ ; add a CRLF per line
call strout
pop hl ; hl is the next address to display
call DMP16 ; display 16 bytes per line
dec d
jp nz,dmpdata1
jp CMD
readbsy:
; spin on CF status busy bit
in a,(CFstat) ; read CF status
and 80h ; mask off all except busy bit
jp nz,readbsy
ret
;****************CF read*************
; Write CF
; allowable parameters are '0' for boot sector & ZZMon, '1' for 32K apps,
; '2' for CPM2.2, '3' for CPM3
; 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
jp CMD
; test for CR or LF. Echo back. return 0
tstCRLF:
call cin ; get a character
cp 0dh ; if carriage return, output LF
jp z,tstCRLF1
cp 0ah ; if line feed, output CR
jp z,tstCRLF2
ret
tstCRLF1:
ld a,0ah ; put out a LF
call cout
xor a ; set Z flag
ret
tstCRLF2:
ld a,0dh ; 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:
ld hl,0dc00h ; CPM starts from 0xDC00 to 0xFFFF
ld de,8092h ; reg DE contains beginning sector and end sector values
jp wrCF
cpboot:
; use DMA to copy itself into physical page 0
; the reason DMA is used is because physical page 0 is invisible due to MMU mapping
; but DMA transfer between physical addresses bypassing the MMU
; ld hl,confirm$ ; carriage return to execute the program
; call strout
; call tstCRLF
; jp nz,CMD ; abort command if not CR or LF
; Source is at 0xb000
; call DMAPage ; set page i/o reg to DMA
; 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
; db 0edh,0bfh ; op code for OUTW (C),HL
; set up DMA count register
; ld c,DMA3cnt ; setup count of 4096 byte
; ld hl,1000h
; outw (c),hl ; write DMA3 count reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; source buffer starts at 0xb000
; ld c,DMA3srcH ; source is 0xb000
; ld hl,0bfh ; A23..A12 are 0x00b, low nibble is all 1's
; outw (c),hl ; write DMA3 source high reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; ld c,DMA3srcL ;
; ld hl,0f000h ; A11..A0 are 0x0, high nibble is all 1's
; outw (c),hl ; write DMA3 source low reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; destination is 0x0
; ld c,DMA3dstH
; ld hl,0fh ; A23..A12 are 0x000, low nibble is all 1's
; outw (c),hl ; write DMA3 destination high reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; ld c,DMA3dstL
; ld hl,0f000h ; A11..A0 are 0x0, high nibble is all 1's
; outw (c),hl ; write DMA3 destination low reg
; db 0edh,0bfh ; op code for OUTW (C),HL
; 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
; db 0edh,0bfh ; op code for OUTW (C),HL
; DMA should start now
jp CMD
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
jp nz,CMD ; abort command if not CR or LF
ld a,0e0h ; 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
jp 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
jp z,wrdrq
ld b,0h ; sector has 256 16-bit data
otir ;z80 write 256 bytes
ld b,0h ;z80
otir ;z80 wrute 256 bytes
;Z80
;Z80 db 0edh,93h ; op code for otirw output word and increment
; otirw
readbsyc:
; spin on CF status busy bit
in a,(CFstat) ; read CF status
and 80h ; mask off all except busy bit
jp nz,readbsyc
inc d ; write next sector
jp wrCF1
wrCFdone:
jp CMD
TESTRAM:
; test memory from top of this program to 0xFFFE
ld hl,testram$ ; print test ram message
call strout
ld hl,confirm$ ; get confirmation before executing
call strout
call tstCRLF ; check for carriage return
jp nz,abort
ld iy,(testseed) ; a prime number seed, another good prime number is 211
TRagain:
ld hl,PROGEND ; start testing from the end of this program
ld de,137 ; increment by prime number
TRLOOP:
push iy ; bounce off stack
pop bc
ld (hl),c ; write a pattern to memory
inc hl
ld (hl),b
inc hl
add iy,de ; add a prime number
ld a,0ffh ; compare h to 0xff
cp h
jp nz,TRLOOP ; continue until reaching 0xFFFE
ld a,0feh ; compare l to 0xFE
cp l
jp nz,TRLOOP
ld hl,0b000h ; test memory from 0xAFFF down to 0x0000
TR1LOOP:
push iy
pop bc ; bounce off stack
dec hl
ld (hl),b ; write MSB
dec hl
ld (hl),c ; write LSB
add iy,de ; add a prime number
ld a,h ; check h=l=0
or l
jp nz,TR1LOOP
ld hl,PROGEND ; verify starting from the end of this program
ld iy,(testseed) ; starting seed value
TRVER:
push iy ; bounce off stack
pop bc
ld a,(hl) ; get LSB
cp c ; verify
jp nz,TRERROR
inc hl
ld a,(hl) ; get MSB
cp b
jp nz,TRERROR
inc hl
add iy,de ; next reference value
ld a,0ffh ; compare h to 0xff
cp h
jp nz,TRVER ; continue verifying til end of memory
ld a,0feh ; compare l to 0xFE
cp l
jp nz,TRVER
ld hl,0b000h ; verify memory from 0xB000 down to 0x0000
TR1VER:
push iy ; bounce off stack
pop bc
dec hl
ld a,(hl) ; get MSB from memory
cp b ; verify
jp nz,TRERROR
dec hl
ld a,(hl) ; get LSB from memory
cp c
jp nz,TRERROR
add iy,de
ld a,h ; check h=l=0
or l
jp nz,TR1VER
call SPCOUT ; a space delimiter
ld a,'O' ; put out 'OK' message
call cout
ld a,'K'
call cout
ld (testseed),iy ; save seed value
IN A,(RxStat) ; read on-chip UART receive status
AND 2 ;;Z data available?
JP Z,TRagain ; no char, do another iteration of memory test
IN A,(RxData) ; save to reg A
OUT (TxData),A ; echo back
; cp 'X' ; if 'X' or 'x', exit memory test
; jp z,CMD
; cp 'x'
; jp nz,TRagain
jp CMD
TRERROR: