-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathdisk_dmcache.asm
1344 lines (1099 loc) · 34.9 KB
/
disk_dmcache.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
;****************************************************************************
;
; Z80 Retro! BIOS
;
; Copyright (C) 2021,2022 John Winans
;
; This library is free software; you can redistribute it and/or
; modify it under the terms of the GNU Lesser General Public
; License as published by the Free Software Foundation; either
; version 2.1 of the License, or (at your option) any later version.
;
; This library 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
; Lesser General Public License for more details.
;
; You should have received a copy of the GNU Lesser General Public
; License along with this library; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
; USA
;
;****************************************************************************
;****************************************************************************
;
; BANK Usage
; 0 SD cache bank 0
; 1 SD cache bank 1
; 2 SD cache bank 2
; 3 SD cache bank 3
; 4
; 5
; 6
; 7
; 8
; 9
; A
; B
; C
; D DM Cache tag table
; E CP/M zero page and low half of the TPA *
; F CP/M high half of the TPA, CCP, BDOS, and BIOS *
;
; * These banks are controlled by the BIOS.
;
; DM cache tag table is used to record the use of each of the 256
; cache slots. The tag table contains 256 entries, each containing
; 8-bits:
;
; VxTTTTTT
;
; Where:
; V = 0 if the entry contains valid data, else it is unused
; x = not used, set to zero
; TTTTTT = CP/M track number bits 8-13 that occupy this slot
;
; Each entry of the tag table are indexed using the cache slot number.
; The slot number is defined as the low 8-bits of the CP/M track
; number that COULD be stored within. Therefore the CP/M track number
; of the data that is stored any given cache slot is the slot-tag bits
; 5-0 followed by the slot number. In binary:
;
; 00TTTTTTSSSSSSSS
;
; Examples of tag values (note that ss is the slot number when used below)
;
; 1xxxxxxx = Slot is not used (filled with garbage)
; 00000000 = Slot contains a copy of CP/M track number 0x00ss
; 00001111 = Slot contains a copy of CP/M track number 0x0Fss
; 00110000 = Slot contains a copy of CP/M track number 0x30ss
;
; Therefore, if entry number 5 (binary 00000101) of the cache tag table
; contains 00110000 then the slot contains a copy of track 0x3005 because:
;
; Tag entry number 5 represents slot number 5.
; The value of entry 5 in this example is binary: 00110000
; The entry is a valid track because the MSB is 0.
; Tag bits 5-0 contain bits 13-8 of the CP/M track number: 110000.
; Combine the tag bits with the slot number to get the CP/M track number:
; 110000 00000101
; Zero-extend the result to get a 16-bit track number:
; 00110000 00000101 = 0x3005
;
; The cache tag table is located in bank 0xD (13) and begins at address 0.
;
;****************************************************************************
.sd_partition_base: equ 0x800
;##########################################################################
; set .dmcache_debug to:
; 0 = no debug output
; 1 = print messages from new code under development
; 2 = print all the above plus the primairy 'normal' debug messages
; 3 = print all the above plus verbose 'noisy' debug messages
;##########################################################################
;.dmcache_debug: equ 3
.dmcache_debug: equ 0
.cache_tag_bank: equ 0xd0 ; defined in terms of the GPIO port bits
;.cache_tag_base: equ 0 ; the first tag table entry MUST be at 0x0000!
.cache_tag_inval: equ 0x80 ; when MSB is set to 0 then the tag is valid
.cache_tag_track: equ 0x3f ; a mask for the tag's track bits
;##########################################################################
; Calc the cache slot number from the CP/M track number
;
; HL = track number
; return: HL=slot number
;##########################################################################
.dm_trk2slt:
ld h,0
ret
;##########################################################################
; Convert a cache slot number in HL to the bank number wherein the slot
; is stored.
;
; L=slot number (H must be zero and is ignored here)
; return: A=blank number
;##########################################################################
.dm_slt2bnk:
ld a,l ; BBxx xxxx
rrca ; xBBx xxxx
rrca ; xxBB xxxx
and 0x30 ; 00BB 0000
ret
;##########################################################################
; Convert a cache slot number in HL to the address the slot is stored.
;
; L = slot number (H must be zero and is ignored here)
; return: HL = slot address
; Clobbers: AF
;##########################################################################
.dm_slt2adr:
ld a,l ; A = xxAA AAAA
rlca ; A = xAAA AAAx
and 0x7e ; A = 0AAA AAA0
ld h,a ; HL = 0AAA AAA0 xxAA AAAA
ld l,0 ; HL = 0AAA AAA0 0000 0000
ret
;##########################################################################
; Return the value of the cache tag for the given slot number
;
; WARNING: This will temporarily change the RAM bank value! If any IRQs
; are possible, either the stack must be in high-memory or the
; IRQs must be disabled before calling this function.
;
; HL = slot number
; return: A = cache tag value
; Clobbers: H
;##########################################################################
.dm_slt2tag:
; select the RAM bank containing the cache tag table
ld a,(gpio_out_cache) ; get current value of the GPIO port
and (~gpio_out_lobank)&0x0ff ; zero the RAM bank bits
or .cache_tag_bank ; set the bank to the tag table
out (gpio_out),a ; select the cache tag bank
if 0
; XXX break the rules for testing is OK because BIOS uses a high-stack
push hl
push bc
push de
ld b,a ; save the bank number
call iputs
db 'bank=\0'
ld a,b ; restore the bank number
call hexdump_a
call puts_crlf
; dump the cache tag table
ld hl,0
ld bc,256
ld e,1
call hexdump
pop de
pop bc
pop hl
endif
; DO NOT USE THE STACK HERE!
; since the cache tag table starts at 0x0000, HL = tag entry address
ld h,(hl) ; H = tag value for the slot
; restore the RAM bank
ld a,(gpio_out_cache)
out (gpio_out),a ; restore the bank to the original value
ld a,h ; A = tag
ret
;##########################################################################
; Return the value of the CP/M track number for a given slot number.
;
; HL = slot address (H must be zero and is ignored here)
; return: HL = CP/M track number (or 0xFFFF if the slot is empty)
; See stack & IRQ warnings in .dm_slt2tag!
; Clobbers: AF
;##########################################################################
.dm_slt2trk:
call .dm_slt2tag ; A = tag, H is clobbered
;and .cache_tag_inval ; this takes longer than..
or a ; check the MSb
jp m,.dm_slt2trkv ; V-bit is set
and .cache_tag_track ; mask off the high bits (should be zero here anyway)
ld h,a ; H = track bits 13-8, L = slot = track bits 7-0
ret
.dm_slt2trkv:
ld hl,0xffff ; tag is invalid
ret
;##########################################################################
; Set the tag for a given slot number to the given value.
;
; WARNING: This will temporarily change the RAM bank value! If any IRQs
; are possible, either the stack must be in high-memory or the
; IRQs must be disabled before calling this function.
;
; H = tag
; L = slot number
; Clobbers: H, A
;##########################################################################
.dm_settag:
; select the RAM bank containing the cache tag table
ld a,(gpio_out_cache) ; get current value of the GPIO port
and (~gpio_out_lobank)&0x0ff ; zero the RAM bank bits
or .cache_tag_bank ; set the bank to the tag table
out (gpio_out),a ; select the cache tag bank
; DO NOT USE THE STACK HERE!
ld a,h ; save the tag value
; Since the cache tag table starts at 0x0000, L = tag entry address
ld h,0 ; HL = tag entry address
ld (hl),a
if 0
; XXX break the rules for testing is OK because BIOS uses a high-stack
push hl
push bc
push de
call iputs
db '\r\ncache tags:\r\n\0'
; dump the cache tag table
ld hl,0
ld bc,256
ld e,1
call hexdump
pop de
pop bc
pop hl
endif
; restore the RAM bank
ld a,(gpio_out_cache)
out (gpio_out),a ; restore the bank to the original value
ret
;************************************************************************
; Convert a CP/M track number & sector to the address of the sector
; in the appropriate cache slot.
;
; HL=CP/M track number
; BC=CP/M sector number
;
; Clobbers everything
;************************************************************************
.dm_trksec2addr:
push bc
call .dm_trk2slt
call .dm_slt2adr
ex de,hl ; DE = target slot buffer address (HL = garbage)
; calculate the CP/M sector offset address (disk_sec*128)
pop hl ; HL=CP/M sector number, must be 0..3
add hl,hl ; HL *= 2
add hl,hl ; HL *= 4
add hl,hl ; HL *= 8
add hl,hl ; HL *= 16
add hl,hl ; HL *= 32
add hl,hl ; HL *= 64
add hl,hl ; HL *= 128
; calculate the address of the CP/M sector in the .bios_sdbuf
add hl,de ; HL = @ of cpm sector in the cache
if .dmcache_debug >= 3
call iputs
db '.dm_trksec2addr sector addr=\0'
ld a,h
call hexdump_a
ld a,l
call hexdump_a
call puts_crlf
endif
ret
if 0 ;not yet
;************************************************************************
; Special case cache 'fill' logic to padd a slot with 0xe5 when CP/M
; wants to write into a sector in an as-yet unused allocation block.
;
; HL=track number
;************************************************************************
.cache_slot_padd:
push hl ; save the track number for repeated use later
call .dm_trk2slt
call .dm_slt2bnk
ld d,a ; D = bank number in high 4-bits
; select the RAM bank with the target cache slot in it
ld a,(gpio_out_cache) ; get current value of the GPIO port
and (~gpio_out_lobank)&0x0ff ; zero the RAM bank bits
or d ; set the bank to that with the desired slot
out (gpio_out),a ; select the cache tag bank
if .dmcache_debug >= 3
push af
call iputs
db '.cache_slot_padd slot bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
; calculate the slot address within the selected bank
pop hl ; HL = the CP/M track number we want
push hl
call .dm_trk2slt
call .dm_slt2adr ; HL = target slot buffer address to read the 512-byte block
ld d,h
ld e,l ; DE = HL
ld (hl),0xe5 ; HL=first slot byte address
inc de ; DE=second slot byte address
ld bc,0x007f ; padd the remaining 127 bytes
ldir
; Update the cache tag for the slot that we just replaced
pop hl ; HL = the CP/M track number we want
call .dm_settag ; set tag=H for slot=L
; restore the proper RAM bank
ld a,(gpio_out_cache)
out (gpio_out),a
ret
endif
;************************************************************************
; Fill a cache slot by reading the CP/M track number in HL into the
; appropriate slot.
;
; This assumes that it is running with a stack over 0x8000
;
; HL = CP/M track number
; return Z flag = 1 = OK
;************************************************************************
.cache_slot_fill:
push hl ; save the track number for repeated use later
call .dm_trk2slt ; HL=slot number
call .dm_slt2trk ; HL=track number currently in the target slot
; Note: The cache slot's track number will be 0xffff if the slot is empty.
; Track 0xffff is impossible when CP/M tracks have more than one sector in them.
pop de ; DE = the CP/M track number we want
or a ; clear the CY flag
sbc hl,de ; HL = got - want
if .dmcache_debug >= 2
jr nz,.dbg_csm ; if we have a cache-miss then don't print here
push af ; save the flags so can decide to return below
call iputs
db ".cache_slot_fill cache hit: \0"
call disk_dump
pop af
.dbg_csm:
endif
ret z ; if HL==DE then return w/Z=1 now
if .dmcache_debug >= 2
call iputs
db ".cache_slot_fill cache miss: \0"
call disk_dump
endif
push de ; put a copy of the CP/M track we want back onto the stack
; calculate the proper RAM bank for the given slot we need to use for the CP/M track
ld h,d
ld l,e
call .dm_trk2slt
call .dm_slt2bnk
ld d,a ; D = bank number in high 4-bits
; select the RAM bank with the target cache slot in it
ld a,(gpio_out_cache) ; get current value of the GPIO port
ld (.save_gpio_out),a ; save the current gpio port value so can restore later
and (~gpio_out_lobank)&0x0ff ; zero the RAM bank bits
or d ; set the bank to that with the desired slot
ld (gpio_out_cache),a ; save it so that the SD/SPI logic uses the right value
out (gpio_out),a ; select the cache tag bank
if .dmcache_debug >= 3
push af
call iputs
db '.cache_slot_fill slot bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
; calculate the slot address within the selected bank
pop hl ; HL = the CP/M track number we want
push hl
call .dm_trk2slt
call .dm_slt2adr ; HL = target slot buffer address to read the 512-byte block
ex de,hl ; DE = target slot buffer address (HL = garbage)
; Calculate the SD physical block number that we want to read
pop hl
push hl ; HL = cp/m track number
if 1
ld bc,.sd_partition_base ; XXX Add the starting partition block number
add hl,bc ; HL = SD physical block number
; Push the 32-bit physical SD block number into the stack in little-endian order
ld bc,0
push bc ; 32-bit SD block number (big end)
push hl ; 32-bit SD block number (little end)
else
; this doesn't work
call .calc_sd_block ; DE,HL = partition_base + HL
; Push the 32-bit physical SD block number into the stack in little-endian order
push de ; 32-bit SD block number (big end)
push hl ; 32-bit SD block number (little end)
endif
if .dmcache_debug >= 3
call iputs
db '.cache_slot_fill slot addr=\0'
ld a,d
call hexdump_a
ld a,e
call hexdump_a
call puts_crlf
endif
call sd_cmd17 ; read the SD block
pop hl ; clean the 4-byte SD block number from the stack
pop bc
or a
jr z,.cache_fill_ok
; Mark the slot as invalid because the read has failed
pop hl ; HL = the CP/M track number we want
call .dm_trk2slt ; overkill, but proper
ld h,.cache_tag_inval ; mark the slot as invalid
call .dm_settag
ld a,(.save_gpio_out)
ld (gpio_out_cache),a
out (gpio_out),a
if .dmcache_debug >= 3
push af ; save the GPIO latch value
call iputs
db '.cache_slot_fill SD read block failed. restore bank=\0'
pop af ; restore the GPIO latch value
call hexdump_a
call puts_crlf
endif
or 1 ; Z = 0 = error
ret
.cache_fill_ok:
if .dmcache_debug >= 3
call iputs
db '.cache_slot_fill update tag=\0'
pop hl ; HL = the CP/M track number we want
push hl
ld a,h
call hexdump_a
call iputs
db ', for slot=\0'
ld a,l
call hexdump_a
call puts_crlf
endif
; Update the cache tag for the slot that we just replaced
pop hl ; HL = the CP/M track number we want
call .dm_settag ; set tag=H for slot=L
; restore the proper RAM bank
ld a,(.save_gpio_out)
ld (gpio_out_cache),a
out (gpio_out),a
if .dmcache_debug >= 3
push af
call iputs
db '.cache_slot_fill restore bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
xor a ; Z = 1 = no errors
ret
;************************************************************************
; Flush a cache slot by writing the CP/M track number in HL out
; to disk.
;
; This assumes that it is running with a stack over 0x8000
;
; HL = CP/M track number
; return Z flag = 1 = OK
;************************************************************************
.cache_slot_flush:
push hl ; save the track number for repeated use later
; calculate the proper RAM bank for the given slot we need to use for the CP/M track
call .dm_trk2slt
call .dm_slt2bnk
ld d,a ; D = bank number in high 4-bits
; select the RAM bank with the target cache slot in it
ld a,(gpio_out_cache) ; get current value of the GPIO port
ld (.save_gpio_out),a ; save the current gpio port value so can restore later
and (~gpio_out_lobank)&0x0ff ; zero the RAM bank bits
or d ; set the bank to that with the desired slot
ld (gpio_out_cache),a ; save it so that the SD/SPI logic uses the right value
out (gpio_out),a ; select the cache tag bank
if .dmcache_debug >= 3
push af
call iputs
db '.cache_slot_flush slot bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
; calculate the slot address within the selected bank
pop hl ; HL = the CP/M track number we want
push hl ; ...and leave a copy on the stack
call .dm_trk2slt
call .dm_slt2adr ; HL = target slot buffer address to read the 512-byte block
ex de,hl ; DE = slot buffer address (and HL = garbage)
; write the cache slot contents to the SD card
pop hl ; HL=CP/M track number
if 1
ld bc,.sd_partition_base ; XXX add the starting partition block number
add hl,bc ; HL = SD physical block number
ld bc,0
push bc ; SD block number to write
push hl
else
; this doesn't work
ld c,e
ld b,d ; BC = DE
call .calc_sd_block ; DE,HL = partition_base + HL
; Push the 32-bit physical SD block number into the stack in little-endian order
push de ; 32-bit SD block number (big end)
push hl ; 32-bit SD block number (little end)
ld e,c
ld d,b ; DE = BC
endif
if .dmcache_debug >= 3
call iputs
db '.cache_slot_flush slot addr=\0'
ld a,d
call hexdump_a
ld a,e
call hexdump_a
call puts_crlf
endif
call sd_cmd24 ; write the SD block
pop hl ; clean the SD block number from the stack
pop bc
or a
jr z,.slot_flush_ret ; write operation succeeded Z=1
call iputs
db ".cache_slot_flush SD CARD WRITE FAILED!\r\n\0"
or 1 ; the write has failed Z=0
.slot_flush_ret:
push af
ld a,(.save_gpio_out)
ld (gpio_out_cache),a
out (gpio_out),a
if .dmcache_debug >= 3
push af ; save the GPIO latch value
call iputs
db '.cache_slot_flush restore bank=\0'
pop af ; restore the GPIO latch value
call hexdump_a
call puts_crlf
endif
pop af
ret
;************************************************************************
; Copy the CP/M sector data from cache into the RAM.
;
; disk_sec = sector in the cache to read from
; disk_track = track in the cache to read from
; disk_dma = where to copy the data into
;
; This assumes that it is running with a stack above 0x8000
;
; Clobbers everything
;************************************************************************
.copy_cache2ram:
; calculate the proper RAM bank for the given slot we need to use for the CP/M track
ld hl,(disk_track)
call .dm_trk2slt
call .dm_slt2bnk
ld d,a ; D = bank number in high 4-bits
; select the RAM bank with the target cache slot in it
ld a,(gpio_out_cache) ; get current value of the GPIO port
ld (.save_gpio_out),a ; save the current gpio port value so can restore later
and (~gpio_out_lobank)&0x0ff ; zero the RAM bank bits
or d ; set the bank to that with the desired slot
ld (gpio_out_cache),a ; save it so that the SD/SPI logic uses the right value
out (gpio_out),a ; select the cache tag bank
if .dmcache_debug >= 3
push af
call iputs
db '.copy_cache2ram slot bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
ld hl,(disk_track)
ld bc,(disk_sec)
call .dm_trksec2addr ; HL = @ of cpm sector in the cache
; Copy the CP/M sector data from the cache slot
ld de,(disk_dma) ; DE = CP/M target buffer address
ld a,0x7f ; is DE > 0x7fff ?
cp d
jp m,.copy_cache2ramd ; yes? then OK
; we need to use a bounce buffer
ld de,.dm_bounce_buffer
if .dmcache_debug >= 3
call iputs
db '.copy_cache2ram bounce dest=\0'
ld a,d
call hexdump_a
ld a,e
call hexdump_a
call puts_crlf
endif
ld bc,0x0080 ; number of bytes to copy
ldir
; restore the original RAM bank
ld a,(.save_gpio_out)
ld (gpio_out_cache),a
out (gpio_out),a
ld hl,.dm_bounce_buffer
ld de,(disk_dma)
if .dmcache_debug >= 3
call iputs
db '.copy_cache2ram bounce src=\0'
ld a,h
call hexdump_a
ld a,l
call hexdump_a
endif
.copy_cache2ramd:
if .dmcache_debug >= 3
call iputs
db ', dest=\0'
ld a,d
call hexdump_a
ld a,e
call hexdump_a
call puts_crlf
endif
ld bc,0x0080 ; number of bytes to copy
ldir
; restore the proper RAM bank (redundant but OK if used a bounce buffer)
ld a,(.save_gpio_out)
ld (gpio_out_cache),a
out (gpio_out),a
if .dmcache_debug >= 3
push af
call iputs
db '.copy_cache2ram restore bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
ret
;************************************************************************
; Copy the CP/M sector data from RAM into the cache.
;
; disk_sec = sector in the cache to write into
; disk_track = track in the cache to write into
; disk_dma = where to copy the data from
;
; This assumes that it is running with a stack above 0x8000
;
; Clobbers everything
;************************************************************************
.copy_ram2cache:
ld hl,(disk_dma) ; HL = CP/M target buffer address
if .dmcache_debug >= 3
call iputs
db '.copy_ram2cache sector src dma addr=\0'
ld a,h
call hexdump_a
ld a,l
call hexdump_a
endif
; Do we need to use a bounce buffer?
ld a,0x7f
cp h ; is HL > 0x7fff ?
jp m,.copy_ram2cached ; if HL > 0x7fff then no bounce
; Need to copy the sector into the bounce buffer
ld de,.dm_bounce_buffer
if .dmcache_debug >= 3
call iputs
db ', bounce dest=\0'
ld a,d
call hexdump_a
ld a,e
call hexdump_a
call puts_crlf
endif
ld bc,0x80
ldir
ld hl,.dm_bounce_buffer
if .dmcache_debug >= 3
call iputs
db '.copy_ram2cache bounce src=\0'
ld a,h
call hexdump_a
ld a,l
call hexdump_a
endif
.copy_ram2cached:
; source address = HL
push hl ; save for later
; calculate the proper RAM bank for the given slot we need to use for the CP/M track
ld hl,(disk_track)
call .dm_trk2slt
call .dm_slt2bnk
ld d,a ; D = bank number in high 4-bits
; select the RAM bank with the target cache slot in it
ld a,(gpio_out_cache) ; get current value of the GPIO port
ld (.save_gpio_out),a ; save the current gpio port value so can restore later
and (~gpio_out_lobank)&0x0ff ; zero the RAM bank bits
or d ; set the bank to that with the desired slot
ld (gpio_out_cache),a ; save it so that the SD/SPI logic uses the right value
out (gpio_out),a ; select the cache tag bank
if .dmcache_debug >= 3
push af
call iputs
db ', dest slot bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
ld hl,(disk_track)
ld bc,(disk_sec)
call .dm_trksec2addr ; HL = @ of cpm sector in the cache
ex de,hl ; DE = @ of target in the cache (and HL = garbage)
pop hl ; HL = @ of source data
ld bc,0x0080 ; number of bytes to copy
ldir
; restore the original RAM bank
ld a,(.save_gpio_out)
ld (gpio_out_cache),a
out (gpio_out),a
if .dmcache_debug >= 3
push af
call iputs
db '.copy_ram2cache restore bank=\0'
pop af
call hexdump_a
call puts_crlf
endif
ret
;##########################################################################
;
; CP/M 2.2 Alteration Guide p19:
; Assuming the drive has been selected, the track has been set, the sector
; has been set, and the DMA address has been specified, the READ subroutine
; attempts to read one sector based upon these parameters, and returns the
; following error codes in register A:
;
; 0 no errors occurred
; 1 non-recoverable error condition occurred
;
; When an error is reported the BDOS will print the message "BDOS ERR ON
; x: BAD SECTOR". The operator then has the option of typing <cr> to ignore
; the error, or ctl-C to abort.
;
;##########################################################################
.dmcache_read:
if .dmcache_debug >= 1
call iputs
db ".dmcache_read entered: \0"
call disk_dump
endif
if .dmcache_debug >= 1
; Test the conversion routines
call iputs
db "DM cache slot=\0"
ld hl,(disk_track)
call .dm_trk2slt
ld a,h
call hexdump_a
ld a,l
call hexdump_a
call iputs
db ", bank=\0"
ld hl,(disk_track)
call .dm_trk2slt
call .dm_slt2bnk
call hexdump_a
call iputs
db ', address=\0'
ld hl,(disk_track)
call .dm_trk2slt
call .dm_slt2adr
ld a,h
call hexdump_a
ld a,l
call hexdump_a
; show the current tag for the slot
call iputs
db ', (tag=\0'
ld hl,(disk_track)
call .dm_trk2slt ; find the slot for the desired track
call .dm_slt2tag ; get the value of the tag for the slot
call hexdump_a
; show the current track number in the slot
call iputs
db ', track=\0'
ld hl,(disk_track)
call .dm_trk2slt ; find the slot for the desired track
call .dm_slt2trk ; ask what track is currently in that slot
ld a,h
call hexdump_a
ld a,l
call hexdump_a
call iputs
db ', hit=\0'
; Does the slot have the track in it that we are looking for?
ex de,hl ; DE = track number/slot (HL = garbage)
ld hl,(disk_track)
or a ; clear the CY flag
sbc hl,de ; HL = got - want
jp nz,.debug_read_miss
call iputs
db 'Y\0'
jp .debug_read_hit
.debug_read_miss:
call iputs
db 'N\0'
.debug_read_hit:
; In a write-through cache this will simply discard what is in the slot if it is
; not what we need.
call iputs
db ', new tag=\0'
ld hl,(disk_track)
ld a,h