-
Notifications
You must be signed in to change notification settings - Fork 2
/
81-232.prn
2110 lines (2110 loc) · 84.4 KB
/
81-232.prn
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
# File 81-232.s
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Analysis of the Kaypro II ROM
0000 ;
0000 ; Based on 81-232.rom
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; NOTES:
0000 ;
0000 ; The code if similar to the 81-149c ROM with the following
0000 ; differences:
0000 ; - The welcome message says "Kaypro" instead of "Kaypro II"
0000 ; - Support for double sided doble density disks (DSDD)
0000 ; - The code goes 144 bytes beyong the 2KB limit and needs a 4KB
0000 ; ROM. All the remaining spce is filled with FF.
0000 ; - The PIO-2A bit 6 is configured as output.
0000 ;
0000 ; To support the DSDD disks, a new disk parameter block is added.
0000 ; This block is not copied to upper RAM as the SSSD and SSDD blocks
0000 ; were. Instead, the upper RAM copy of SSDD is replaced by the disk
0000 ; parameter block for DSDD when needed. Also, the previously unused
0000 ; system bit 2 is used to select single side or double side mode.
0000 ;
0000 ; On the ROM 81.149c, the current track of both drives is stored
0000 ; on two variables. Also, the density detected for the current disk
0000 ; on each drive is stored as an aditional 16th byte of the disk
0000 ; parameter header. On this ROM, there is a need to store also if
0000 ; the disk is double sided. Current track, density and sides are now
0000 ; stored per drive in the variables disk_active_info_drive_a and
0000 ; disk_active_info_drive_b. It is copied back an forth to
0000 ; disk_active_info as A: or B: is selected.
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; CONSTANTS
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; I/O Ports
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 io_00_serial_baud_rate: EQU 0x00
0000 io_04_serial_data: EQU 0x04
0000 io_05_keyboard_data: EQU 0x05
0000 io_06_serial_control: EQU 0x06
0000 io_07_keyboard_control: EQU 0x07
0000 io_08_parallel_data: EQU 0x08
0000 io_09_parallel_control: EQU 0x09
0000 io_0b_parallel_b_control: EQU 0x0b
0000 io_0c_keyboad_baud_rate: EQU 0x0c
0000 io_10_fdc_status: EQU 0x10 ; as IN it is a get status
0000 io_10_fdc_command: EQU 0x10 ; as OUT it is a command
0000 io_11_fdc_track: EQU 0x11
0000 io_12_fdc_sector: EQU 0x12
0000 io_13_fdc_data: EQU 0x13
0000 io_14_scroll_register: EQU 0x14
0000 io_1c_system_bits: EQU 0x1c
0000 io_1d_system_bits_control: EQU 0x1d
0000
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; System bits
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 system_bit_drive_a: EQU 0
0000 system_bit_drive_b: EQU 1
0000 system_bit_side_2: EQU 2
0000 system_bit_centronicsReady: EQU 3
0000 system_bit_centronicsStrobe: EQU 4
0000 system_bit_double_density_neg: EQU 5
0000 system_bit_motors_neg: EQU 6
0000 system_bit_bank: EQU 7
0000
0000 system_bit_drive_a_mask: EQU 0x01
0000 system_bit_drive_b_mask: EQU 0x02
0000 system_bit_side_2_mask: EQU 0x04
0000 system_bit_centronicsReady_mask: EQU 0x08
0000 system_bit_centronicsStrobe_mask: EQU 0x10
0000 system_bit_double_density_neg_mask: EQU 0x20
0000 system_bit_motors_meg_mask: EQU 0x40
0000 system_bit_bank_mask: EQU 0x80
0000
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Console constants
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 address_vram: EQU 0x3000
0000 console_lines: EQU 24
0000 console_columns: EQU 80
0000 console_line_length: EQU 0x80 ; There are 80 cols, but 128 bytes reserved for each line
0000 console_line_mask: EQU 0x7f
0000
0000 address_vram_end: EQU address_vram + console_lines * console_line_length -1 ; 0x3bff
0000 address_vram_start_of_last_line: EQU address_vram_end - console_line_length + 1 ; 0x3b80
0000
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Disk constants
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 logical_sector_size: EQU 128
0000 double_density_block_size: EQU 1024
0000 physical_sectors_per_side: EQU 10
0000 disk_count: EQU 2 ; 0 is A: and 1 is B:
0000
0000 fdc_command_restore: EQU 0x00
0000 fdc_command_read_address: EQU 0xc4
0000 fdc_command_seek: EQU 0x10
0000 fdc_command_read_sector: EQU 0x88
0000 fdc_command_write_sector: EQU 0xac
0000 fdc_command_force_interrupt: EQU 0xd0
0000
0000 rw_mode_single_density: EQU 1 ; We read or write 128 bytes directly to/from DMA
0000 rw_mode_double_density: EQU 4 ; We read or write the full 512 bytes buffer
0000
0000 fdc_status_record_busy_bit: EQU 0
0000 fdc_status_record_not_found_bit: EQU 4
0000 fdc_status_read_error_bitmask: EQU 0x9c ; Not ready, record not found, crc error or lost data
0000 fdc_status_write_error_bitmask: EQU 0xfc ; Not ready, write_protect, write fault, record not found, crc error or lost data
0000
0000 ; RET, used to set the NMI_ISR when the ROM is disabled
0000 RET_opcode: EQU 0xC9
0000
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Info to load CP/M on boot.
0000 ; The first boot sector has the info about how many addtional
0000 ; sectors to read and where to store them.
0000 ; Note that boot only works with double density disks. On DD disks,
0000 ; the OS is on the first track and some more sectors after the
0000 ; directory area.
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 first_sector_load_address: EQU 0xfa00
0000 address_to_load_second_sector: EQU 0xfa02
0000 address_to_exec_boot: EQU 0xfa04
0000 count_of_boot_sectors_needed: EQU 0xfa06
0000
0000 double_density_sectors_per_track: EQU 40
0000 double_density_sectors_for_directory: EQU 16
0000
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Disk related variables
0000 ; Sector address is given by the DTS (Drive, Track and Sector)
0000 ; For double density the sector is divided by 4 to account for 512
0000 ; bytes sector.
0000 ; See "Uninitialized RAM data areas" in Appendix G
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000
0000 ; DTS with the user requested data. Uses losgical sectors of 128 bytes
0000 drive_selected: EQU 0xfc00
0000 track_selected: EQU 0xfc01 ; 2 bytes
0000 sector_selected: EQU 0xfc03
0000
0000 ; DTS as understood by the floppy disk controller. Sectors are 512 bytes
0000 drive_in_fdc: EQU 0xfc04
0000 track_in_fdc: EQU 0xfc05 ; 2 bytes
0000 sector_in_fdc: EQU 0xfc07
0000
0000 dd_sector_selected: EQU 0xfc08 ; the double density sector is sector_selected / 4
0000 fdc_set_flag: EQU 0xfc09 ; 'hstact'
0000 pending_write_flag: EQU 0xfc0a ; 'hstwrt'
0000
0000 pending_count: EQU 0xfc0b
0000 drive_unallocated: EQU 0xfc0c
0000 track_unallocated: EQU 0xfc0d ; 2 bytes
0000 sector_unallocated: EQU 0xfc0f
0000
0000 rw_result: EQU 0xfc10
0000
0000 read_needed_flag: EQU 0xfc11
0000 read_not_needed: EQU 0
0000 read_needed: EQU 1
0000
0000 ; See CP/M 2.2 System alteration guide appendix G
0000 operation_type: EQU 0xfc12 ; 'readop' in appendix G
0000 operation_type_write: EQU 0
0000 operation_type_read: EQU 1
0000
0000 ; See CP/M 2.2 System alteration guide, section 12 and appendix G
0000 rw_type: EQU 0xfc13 ; 'wrtype' in appendix G
0000 rw_type_normal_write: EQU 0 ; write to allocated
0000 rw_type_directory_write: EQU 1
0000 rw_type_read_or_unallocated_write: EQU 2 ; write to unallocated
0000 disk_DMA_address: EQU 0xfc14 ; 2 bytes
0000
0000 ; There are 4 sector buffers. To select the buffer we get the sector modulo 4
0000 sector_buffer_base: EQU 0xfc16
0000 sector_buffer_0: EQU 0xfc16
0000 sector_buffer_1: EQU 0xfc16 + logical_sector_size
0000 sector_buffer_2: EQU 0xfc16 + logical_sector_size * 2
0000 sector_buffer_3: EQU 0xfc16 + logical_sector_size * 3
0000
0000 disk_active_drive: EQU 0xfe16
0000 ; There are three bytes with the disk info: track, density, sides support
0000 disk_active_info: EQU 0xfe17
0000 disk_active_info_undefined: EQU 0xff
0000 disk_active_track: EQU disk_active_info + 0
0000 disk_density: EQU disk_active_info + 1
0000 disk_density_double: EQU 0x00 ; FM encoding
0000 disk_density_single: EQU 0x20 ; MFM encoding
0000 disk_active_has_sides: EQU disk_active_info + 2
0000 disk_active_has_sides_no: EQU 0x00
0000 disk_active_has_sides_yes: EQU 0xff
0000
0000 ; Copy of the disk info for the drive A: (3 bytes)
0000 disk_active_info_drive_a: EQU 0xfe1a ; 3 bytes copy of 0xfe17, 8 and 9
0000 ; Copy of the disk info for the drive B: (3 bytes)
0000 disk_active_info_drive_b: EQU 0xfe1d ; 3 bytes copy of 0xfe17, 8 and 9
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Console related variables
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 console_esc_mode: EQU 0xfe74
0000 console_esc_mode_clear: EQU 0 ; No ESC pending
0000 console_esc_mode_enabled: EQU 1 ; Next char is the ESC command
0000 console_esc_mode_arg_1: EQU 2 ; Next char is the first arg of the = command
0000 console_esc_mode_arg_2: EQU 3 ; Next char is the second arg of the = command
0000 console_esc_equal_first_arg: EQU 0xfe75 ; First arg of the esc= command
0000 console_cursor_position: EQU 0xfe76 ; 2 bytes
0000
0000 ; On greek mode, the char is converted to a control char that is printed as a greek letter
0000 console_alphabet_mask: EQU 0xfe78
0000 console_alphabet_ascii_mask: EQU 0x7f
0000 console_alphabet_greek_mask: EQU 0x1f
0000
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Entry points of code relocated to upper RAM
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 disk_params_destination: EQU 0xfe79
0000 disk_parameter_header_0: EQU 0xfe79
0000 disk_parameter_header_1: EQU 0xfe8a
0000 disk_parameter_block_single_density: EQU 0xfe9b
0000 disk_parameter_block_double_density: EQU 0xfeaa
0000 disk_sector_translation_table: EQU 0xfeb9
0000 disk_parameter_block_size: EQU 15
0000 disk_read_address_buffer: EQU 0xfecb
0000 disk_read_address_sector: EQU 0xfecd
0000 disk_read_address_buffer_size: EQU 6
0000
0000 relocation_destination: EQU 0xfed1
0000 relocation_offset: EQU 0xfed1 - 0x03b ; relocation_destination - block_to_relocate
0000 read_single_density_relocated: EQU 0xfee0 ; reloc_single_density + relocation_offset
0000 move_RAM_relocated: EQU 0xfed1 ; reloc_move_RAM + relocation_offset
0000 read_to_buffer_relocated: EQU 0xfee7 ; reloc_read_to_buffer + relocation_offset
0000 write_from_buffer_relocated: EQU 0xfef8 ; reloc_write_from_buffer + relocation_offset
0000 write_single_density_relocated: EQU 0xfef1 ; reloc_write_single_density + relocation_offset
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Other addresses
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 CSV_0: EQU 0xfe20 ; Scrathpad for change disk check, drive 0
0000 ALV_0: EQU 0xfe30 ; Scrathpad for BDOS disk allocation, drive 0
0000 CSV_1: EQU 0xfe4a ; Scrathpad for change disk check, drive 1
0000 ALV_1: EQU 0xfe5a ; Scrathpad for BDOS disk allocation, drive 1
0000 DIRBUF: EQU 0xff6d ; Address of a 128 byte scratchpad for BDOS dir ops
0000
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; BIOS ENTRY POINTS
0000 ;
0000 ; Description of the entry points adapted from the KayPLUS manual.
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000
0000 ORG 0h
0000 ; COLD: Resets entire computer system and is ALMOST like
0000 ; pressing the RESET button.
0000 ; Corresponds to CP/M BIOS function BOOT
0000 c3 4b 00 JP EP_COLD
0003
0003 ; INITDSK: Resets the disk input/output buffer status to empty.
0003 ; Any pending write is lost. Useful to perform a "soft" disk reset.
0003 c3 95 01 JP EP_INITDSK
0006
0006 ; INITVID: Resets the video system. Video hardware is configured
0006 ; and screen is cleared
0006 c3 98 06 JP EP_INITVID
0009
0009 ; INITDEV: Initializes tall I/O ports.
0009 c3 fb 05 JP EP_INITDEV
000c
000c ; HOME: Sets track number to 0
000c ; Corresponds to CP/M BIOS function HOME
000c c3 e7 01 JP EP_HOME
000f
000f ; SELDSK: Selects logical drive in register C (value of 0 through 1),
000f ; corresponding to drives A or B). SELDSK determines what type of
000f ; disk (density) is present in the drive.
000f ; Corresponds to CP/M BIOS function SELDSK
000f c3 c3 01 JP EP_SELDSK
0012
0012 ; SETTRK: Sets the track number to the value in register BC. No seek
0012 ; is actually performed until a disk read/write occurs.
0012 ; Corresponds to CP/M BIOS function SETTRK
0012 c3 db 01 JP EP_SETTRK
0015
0015 ; SETSEC: Sets the logical sector number to the value in register C.
0015 ; Corresponds to CP/M BIOS function SETSEC
0015 c3 ca 01 JP EP_SETSEC
0018
0018 ; SETDMA: Specifies the DMA address where disk read/write occurs in
0018 ; memory. The address in register pair BC is used until another DMA
0018 ; address is specified.
0018 ; Corresponds to CP/M BIOS function SETDMA
0018 c3 d6 01 JP EP_SETDMA
001b
001b ; READ: Reads the previously-specified logical sector from specified
001b ; track and disk into memory at the DMA address. Note that on
001b ; double-density disks and the hard drive, one physical sector may be
001b ; composed of up to eight logical sectors, so a physical disk read
001b ; may not actually occur. Returns disk status in A with zero
001b ; indicating no error occurred and a non-zero value indicating an
001b ; error.
001b ; Corresponds to CP/M BIOS function READ
001b c3 fb 01 JP EP_READ
001e
001e ; WRITE: Same as above, but writes from memory to disk.
001e ; Corresponds to CP/M BIOS function WRITE
001e c3 16 02 JP EP_WRITE
0021
0021 ; SECTRAN: Translates logical sector number to physical sector number
0021 ; Corresponds to CP/M BIOS function SECTRAN
0021 c3 79 04 JP EP_SECTRAN
0024
0024 ; DISKON: Turns on the disk drive.
0024 c3 a2 04 JP EP_DISKON
0027
0027 ; DISKOFF: Turns off the disk drive.
0027 c3 b1 04 JP EP_DISKOFF
002a
002a ; KBDSTAT: Simply returns status of keyboard queue. Returns 0FFH if
002a ; a key is available, or 00H otherwise.
002a ; Corresponds to CP/M BIOS function CONST
002a c3 08 06 JP EP_KBDSTAT
002d
002d ; KBDIN: Gets character from keyboard buffer or waits for one, if
002d ; none ready.
002d ; Corresponds to CP/M BIOS function CONIN
002d c3 10 06 JP EP_KBDIN
0030
0030 ; KBDOUT: Sends the character in register A to the keyboard port.
0030 c3 1b 06 JP EP_KBDOUT
0033
0033 ; SIOSTI: Returns status of SIO-B input port. Returns 00H if no
0033 ; character is ready, or 0FFH otherwise.
0033 c3 5f 06 JP EP_SIOSTI
0036
0036 ; SIOIN: Gets character from SIO-B input port, or waits for one if
0036 ; none is ready.
0036 c3 65 06 JP EP_SIOIN
0039
0039 ; SIOOUT: Sends character to SIO-B output port.
0039 c3 6d 06 JP EP_SIOOUT
003c
003c ; LISTST: Returns the list status of the Centronics port: 00H is
003c ; returned if the printer is busy, 0FFH if ready.
003c c3 7d 06 JP EP_LISTST
003f
003f ; LIST: Sends the character in register C to the Centronics port.
003f c3 85 06 JP EP_LIST
0042
0042 ; SERSTO: Returns status of SIO-B output port. Returns 0FFH if SIO-B
0042 ; is ready to accept a character for output, and 00H otherwise.
0042 c3 77 06 JP EP_SERSTO
0045
0045 ; VIDOUT: Sends character in register C to video screen. All characters
0045 ; 20H (blank) to 7FH are directly displayed and screen scroll is done,
0045 ; if required. Characters below 20H are defined as control characters.
0045 c3 b1 06 JP EP_VIDOUT
0048
0048 ; DELAY: This entry point performs a "B times 10 mSec" delay. The
0048 ; 10 mSec delay is preset for 4 MHz. "B" is the value in the B-register
0048 ; and ranges from 1 to 256 decimal (0 is treated as 256).
0048 c3 b8 04 JP EP_DELAY
004b
004b ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
004b ; INITIALIZATION AND BOOT FROM DISK
004b ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
004b
004b EP_COLD:
004b f3 DI
004c 31 ff ff LD SP, 0xffff
004f 06 0a LD B, 0xa ; 100ms delay
0051 cd b8 04 CALL EP_DELAY
0054 ; Init the system, io ports, screen and memory
0054 cd fb 05 CALL EP_INITDEV
0057 cd 98 06 CALL EP_INITVID
005a cd 95 01 CALL EP_INITDSK
005d ; Avoid the NMI entry point at 0x0066
005d 18 08 JR EP_COLD_continue
005f 3d c3 3b 2b af 32 13 DB 0x3D, 0xC3, 0x3B, 0x2B, 0xAF, 0x32, 0x13
0066
0066 nmi_isr:
0066 ; Just return from the interrupts generated
0066 ; by the floppy controller
0066 c9 RET
0067
0067 EP_COLD_continue:
0067 ; Show the wellcome message
0067 cd 85 08 CALL console_write_string ; console_write_string uses the zero terminated
006a ; string after the CALL
006a 1b .. 2a 3f DB 1Bh,"=", 0x20 + 0xa, 0x20 + 0x1f ; ESC code, move to line 10, column 31
006e .. DB "* KAYPRO *"
0081 1b .. 2d 34 DB 1Bh,"=", 0x20 + 0xd, 0x20 + 0x14 ; ESC code, move to line 13, column 20
0085 .. DB " Please place your diskette into Drive A"
00ad 08 DB 0x8 ; Cursor
00ae 00 DB 0 ; End NUL terminated string
00af
00af ; Read the first sector of the boot disk
00af 0e 00 LD C,0x0
00b1 cd c3 01 CALL EP_SELDSK
00b4 01 00 00 LD BC,0x0
00b7 cd db 01 CALL EP_SETTRK
00ba 0e 00 LD C,0x0
00bc cd ca 01 CALL EP_SETSEC
00bf 01 00 fa LD BC, first_sector_load_address
00c2 cd d6 01 CALL EP_SETDMA
00c5 cd fb 01 CALL EP_READ
00c8 f3 DI
00c9 ; Verify the result
00c9 b7 OR A
00ca 20 3e JR NZ, error_bad_disk
00cc ; Set the DMA destination as instructed by the info
00cc ; on the first boot sector
00cc ed 4b 02 fa LD BC, (address_to_load_second_sector)
00d0 ed 43 14 fc LD (disk_DMA_address), BC
00d4 ; Store the boot exec addres on the stack. A RET will
00d4 ; use this address and start executionthere
00d4 ed 4b 04 fa LD BC, (address_to_exec_boot)
00d8 c5 PUSH BC
00d9 ; Prepare the loading of the rest of the sectors
00d9 ed 4b 06 fa LD BC, (count_of_boot_sectors_needed)
00dd 41 LD B,C
00de ; Continue reading from sector 1
00de 0e 01 LD C,0x1
00e0 read_another_boot_sector:
00e0 ; B has the count of sectors remaining
00e0 ; C has the current sector number
00e0 c5 PUSH BC
00e1 ; Load sector C
00e1 cd ca 01 CALL EP_SETSEC
00e4 cd fb 01 CALL EP_READ
00e7 f3 DI
00e8 ; Verify the result
00e8 c1 POP BC
00e9 b7 OR A
00ea 20 1e JR NZ, error_bad_disk
00ec ; Increase by 128 the load address (logical sector size is 128 bytes)
00ec 2a 14 fc LD HL, (disk_DMA_address)
00ef 11 80 00 LD DE, logical_sector_size
00f2 19 ADD HL,DE
00f3 22 14 fc LD (disk_DMA_address), HL
00f6 ; Decrease the count of sectors remaining
00f6 05 DEC B
00f7 ; If done , jump to the boot exec address previously pushed to the stack
00f7 c8 RET Z
00f8 ; Not finished, calculate the next sector and track
00f8 0c INC C
00f9 3e 28 LD A, double_density_sectors_per_track
00fb ; Are we on the last sector of the track?
00fb b9 CP C
00fc ; No, continue reading sector + 1
00fc 20 e2 JR NZ,read_another_boot_sector
00fe ; Yes, track 0 completed. Continue with track 1
00fe ; Skip the 16 sectors used for the directory
00fe 0e 10 LD C, double_density_sectors_for_directory
0100 c5 PUSH BC
0101 ; Move to track 1
0101 01 01 00 LD BC,0x0001
0104 cd db 01 CALL EP_SETTRK
0107 c1 POP BC
0108 ; Loop
0108 18 d6 JR read_another_boot_sector
010a
010a error_bad_disk:
010a ; Error, write the error message and stop
010a cd 85 08 CALL console_write_string
010d .. 00 DB "\n\r\n\r\aI cannot read your diskette.",0
012f cd b1 04 CALL EP_DISKOFF
0132 wait_forever:
0132 ; Lock the CPU forever
0132 18 fe JR wait_forever
0134
0134 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0134 ; INIT DISK. COPY CODE AND DISK PARAMS TO UPPER RAM. RESET VARIABLES
0134 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0134 ; See CP/M 2.2 System alteration guide, section 10
0134
0134 ; This data will be copied starting 0xfe79
0134 disk_params:
0134 init_disk_parameter_header_0: ; to 0xfe79
0134 00 00 DW 0x0000 ; XLT, logical translation table
0136 00 00 00 00 00 00 DW 0x0000, 0x0000, 0x0000 ; Scrathpad for BDOS
013c 6d ff DW DIRBUF ; Address of additional scratchpad for BDOS,
013e aa fe DW disk_parameter_block_double_density ; DPB
0140 20 fe DW CSV_0
0142 30 fe DW ALV_0
0144 00 DB 0x00 ; Used by the BIOS to store the disk density
0145
0145 init_disk_parameter_header_1: ; to 0xfe8a
0145 00 00 DW 0x0000 ; XLT, logical translation table
0147 00 00 00 00 00 00 DW 0x0000, 0x0000, 0x0000 ; Scrathpad for BDOS
014d 6d ff DW DIRBUF ; Address of additional scratchpad for BDOS,
014f aa fe DW disk_parameter_block_double_density ; DPB
0151 4a fe DW CSV_1
0153 5a fe DW ALV_1
0155 00 DB 0x00 ; Used by the BIOS to store the disk density
0156
0156 ; Single density disk
0156 ; 18 sectors (of 128 bytes) per track
0156 ; 1024 bytes per allocation block
0156 ; 83 kb total disk space
0156 ; 40 tracks, 3 reserved
0156 init_disk_parameter_block_single_density: ; to 0xfe9b
0156 12 00 DW 18 ; SPT, sectors per track
0158 03 DB 3 ; BSH, data alloc shift factor
0159 07 DB 7 ; BLM
015a ; As BSH=3 and BLM=7, then BLS (data alocation size) is 1024.
015a 00 DB 0 ; EXM, extent mask
015b 52 00 DW 82 ; DSM, total storage in allocation blocks - 1
015d 1f 00 DW 31 ; DRM, number of directory entries - 1
015f 80 DB 0x80 ; AL0
0160 00 DB 0x00 ; AL1
0161 08 00 DW 8 ; CKS, directory check vector size
0163 03 00 DW 3 ; OFF, number of reserved tracks
0165
0165 ; Single density disk
0165 ; 40 sectors (128 bytes) per track
0165 ; 1024 bytes per allocation block
0165 ; 195 kb total disk space
0165 ; 40 tracks, 1 reserved
0165 init_disk_parameter_block_double_density: ; to 0xfeaa
0165 28 00 DW 40 ; SPT, sectors per track
0167 03 DB 3 ; BSH, data alloc shift factor
0168 07 DB 7 ; BLM
0169 ; As BSH=3 and BLM=7, then BLS (data alocation size) is 1024.
0169 00 DB 0 ; EXM, extent mask
016a c2 00 DW 194 ; DSM, total storage in allocation blocks - 1
016c 3f 00 DW 63 ; DRM, number of directory entries - 1
016e f0 DB 0xF0 ; AL0
016f 00 DB 0x00 ; AL1
0170 10 00 DW 16 ; CKS, directory check vector size
0172 01 00 DW 1 ; OFF, number of reserved tracks
0174
0174 init_sector_translation_table: ; 0xfeb9
0174 ; Only used for single density
0174 ; There is translation for 18 sectors.
0174 01 06 0b 10 03 08 0d 12 DB 1, 6, 11, 16, 3, 8, 13, 18
017c 05 0a 0f 02 07 0c 11 04 DB 5, 10, 15, 2, 7, 12, 17, 4
0184 09 0e DB 9, 14
0186 disk_params_end:
0186
0186 init_disk_parameter_block_double_density_double_side:
0186 28 00 DW 40 ; SPT, sectors per track
0188 04 DB 4 ; BSH, data alloc shift factor
0189 0f DB 15 ; BLM
018a ; As BSH=4 and BLM=15, then BLS (data alocation size) is 2048.
018a 01 DB 1 ; EXM, extent mask
018b c4 00 DW 196 ; DSM, total storage in allocation blocks - 1
018d 3f 00 DW 63 ; DRM, number of directory entries - 1
018f c0 DB 0xC0 ; AL0
0190 00 DB 0x00 ; AL1
0191 10 00 DW 16 ; CKS, directory check vector size
0193 01 00 DW 1 ; OFF, number of reserved tracks
0195
0195 EP_INITDSK:
0195 ; Copy relocatable disk access to upper RAM to
0195 ; be accessible even when the ROM is swapped out
0195 21 3b 05 LD HL, block_to_relocate
0198 11 d1 fe LD DE, relocation_destination
019b 01 87 00 LD BC, block_to_relocate_end - block_to_relocate ;0x87
019e ed b0 LDIR
01a0
01a0 ; Copy the disk parameters to upper RAM
01a0 21 34 01 LD HL, disk_params
01a3 11 79 fe LD DE, disk_params_destination
01a6 01 52 00 LD BC, disk_params_end - disk_params ;0x52
01a9 ed b0 LDIR
01ab
01ab ; Init some variables
01ab af XOR A
01ac 32 09 fc LD (fdc_set_flag), A ; = No
01af 32 0b fc LD (pending_count), A ; = 0
01b2 3e 00 LD A, disk_density_double
01b4 32 18 fe LD (disk_density), A
01b7 3e ff LD A, disk_active_info_undefined
01b9 32 16 fe LD (disk_active_drive), A
01bc 32 1a fe LD (disk_active_info_drive_a), A
01bf 32 1d fe LD (disk_active_info_drive_b), A
01c2 c9 RET
01c3
01c3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
01c3 ; FLOPPY DISK ENTRY POINTS
01c3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
01c3
01c3 EP_SELDSK:
01c3 ; C: disk number
01c3 79 LD A,C
01c4 32 00 fc LD (drive_selected), A
01c7 c3 2c 03 JP init_drive
01ca
01ca EP_SETSEC:
01ca ; BC: sector number
01ca 79 LD A,C
01cb 32 03 fc LD (sector_selected), A
01ce ; Is the disk double density?
01ce 3a 18 fe LD A, (disk_density)
01d1 b7 OR A
01d2 ; No, send the sector to the controller
01d2 c2 6d 04 JP NZ, fdc_set_sector
01d5 ; Yes, we just store the sector number
01d5 c9 RET
01d6
01d6 EP_SETDMA:
01d6 ; BC: DMA address
01d6 ed 43 14 fc LD (disk_DMA_address), BC
01da c9 RET
01db
01db EP_SETTRK:
01db ; C: track number
01db ed 43 01 fc LD (track_selected), BC
01df ; Is the disk double density?
01df 3a 18 fe LD A, (disk_density)
01e2 b7 OR A
01e3 ; No, send the track to the controller
01e3 c2 49 04 JP NZ, fdc_seek_track
01e6 ; Yes, we just store the track number
01e6 c9 RET
01e7
01e7 EP_HOME:
01e7 ;Is the disk double density?
01e7 3a 18 fe LD A, (disk_density)
01ea b7 OR A
01eb ; No, go to track 0 and return
01eb c2 36 04 JP NZ, fdc_seek_track_0
01ee ; Yes.
01ee ; Is a write pending?
01ee 3a 0a fc LD A,(pending_write_flag)
01f1 b7 OR A
01f2 ; Yes, skip update
01f2 c2 f8 01 JP NZ, skip_buffer_discard
01f5 ; No, discard the buffer
01f5 32 09 fc LD (fdc_set_flag),A ; = No
01f8 skip_buffer_discard:
01f8 c3 36 04 JP fdc_seek_track_0
01fb
01fb EP_READ:
01fb ; Is disk double density?
01fb 3a 18 fe LD A,(disk_density)
01fe b7 OR A
01ff ; No, go directly to the read routine
01ff c2 e0 fe JP NZ, read_single_density_relocated
0202 ; Yes, some preparation is needed as the calls to EP_SETSEC and
0202 ; EP_SETTRK did not send the info to the fdc for double density.
0202 ; Init variables
0202 af XOR A
0203 32 0b fc LD (pending_count),A ; = 0
0206 ; Starting from here it is equal to read in Appendix G
0206 3e 01 LD A, operation_type_read
0208 32 12 fc LD (operation_type), A; = operation_type_read
020b 32 11 fc LD (read_needed_flag), A ; = read_needed
020e 3e 02 LD A, rw_type_read_or_unallocated_write
0210 32 13 fc LD (rw_type),A
0213 c3 88 02 JP read_write_double_density
0216
0216 EP_WRITE:
0216 ; C indicates the rw_type
0216 ; Is disk double density?
0216 3a 18 fe LD A,(disk_density)
0219 b7 OR A
021a ; No, go directly to the write routine
021a c2 f1 fe JP NZ, write_single_density_relocated
021d ; Yes, some preparation is needed as the calls to EP_SETSEC and
021d ; set_track did not send the info to the fdc on double density.
021d ; Starting from here it is equal to read in Appendix G
021d af XOR A
021e 32 12 fc LD (operation_type), A ; = operation_type_write
0221 79 LD A,C
0222 32 13 fc LD (rw_type),A ; = C
0225 fe 02 CP rw_type_read_or_unallocated_write
0227 ; It's an allocated write, we can skip reset the
0227 ; unallocated params to check if a read is needed.
0227 c2 41 02 JP NZ, write_check_read_needed
022a 3e 08 LD A, double_density_block_size / logical_sector_size ; 8
022c 32 0b fc LD (pending_count),A ; = 8
022f ; Initialize the unallocated params
022f 3a 00 fc LD A, (drive_selected)
0232 32 0c fc LD (drive_unallocated), A
0235 2a 01 fc LD HL, (track_selected)
0238 22 0d fc LD (track_unallocated), HL
023b 3a 03 fc LD A, (sector_selected)
023e 32 0f fc LD (sector_unallocated), A
0241 write_check_read_needed:
0241 ; Do we have pending logical sectors?
0241 3a 0b fc LD A,(pending_count)
0244 b7 OR A
0245 ; No, skip
0245 ca 80 02 JP Z, write_with_read_needed
0248 ; Yes, there are more unallocated records remaining
0248 3d DEC A
0249 32 0b fc LD (pending_count),A ; pending_count-1
024c ; Is drive requested different to the unallocated?
024c 3a 00 fc LD A, (drive_selected)
024f 21 0c fc LD HL, drive_unallocated
0252 be CP (HL)
0253 ; Yes, the drive is different
0253 c2 80 02 JP NZ, write_with_read_needed
0256 ; The drives are the same
0256 ; Is track requested different to the unallocated?
0256 21 0d fc LD HL, track_unallocated
0259 cd 20 03 CALL is_track_equal_to_track_selected
025c ; Yes, the track is different
025c c2 80 02 JP NZ, write_with_read_needed
025f ; The tracks are the same
025f ; Is sector requested different to the unallocated?
025f 3a 03 fc LD A, (sector_selected)
0262 21 0f fc LD HL, sector_unallocated
0265 be CP (HL)
0266 ; Yes, the sector is different
0266 c2 80 02 JP NZ, write_with_read_needed
0269 ; The sectors are the same
0269 ; DTS on the unallocated variables match the requested DTS
0269 ; Advance to the next sector to check if the next write will
0269 ; be of the next sector.
0269 34 INC (HL)
026a ; Are we at the end of the track?
026a 7e LD A,(HL)
026b fe 28 CP double_density_sectors_per_track
026d ; No
026d da 79 02 JP C, write_with_read_not_needed
0270 ; Yes, increase track and set sector to zero
0270 36 00 LD (HL),0x0
0272 2a 0d fc LD HL, (track_unallocated)
0275 23 INC HL
0276 22 0d fc LD (track_unallocated),HL
0279 write_with_read_not_needed:
0279 af XOR A
027a 32 11 fc LD (read_needed_flag),A ; = read_not_needed
027d c3 88 02 JP read_write_double_density
0280 write_with_read_needed:
0280 af XOR A
0281 32 0b fc LD (pending_count),A ; = 0
0284 3c INC A
0285 32 11 fc LD (read_needed_flag),A ; = read_needed
0288
0288 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0288 ; FLOPPY DISK INTERNAL IMPLEMENTATION READ AND WRITE
0288 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0288
0288 read_write_double_density:
0288 ; Reset the result variable
0288 af XOR A
0289 32 10 fc LD (rw_result),A ; = 0
028c ; Translate the sector logical address to the double density
028c ; address. As sector in DD are four times the size of sector
028c ; in SD, we divide by 4 (or shift right twice).
028c ; Sure? Ono some places its 8 times ???
028c 3a 03 fc LD A, (sector_selected)
028f b7 OR A ; Clear carry
0290 1f RRA ; /2
0291 b7 OR A ; Clear carry
0292 1f RRA ; /2
0293 32 08 fc LD (dd_sector_selected),A ; sector_selected / 4
0296 ; Is fcd_position set
0296 21 09 fc LD HL, fdc_set_flag
0299 7e LD A,(HL)
029a 36 01 LD (HL),0x1 ; fdc_set_flag = Yes
029c b7 OR A
029d ; No, continue after updating the DTS_in_fdc variables
029d ca c4 02 JP Z, rw_fdc_not_set
02a0 ; Yes
02a0 ; Are the fdc variables different from the selected?
02a0 3a 00 fc LD A,(drive_selected)
02a3 21 04 fc LD HL, drive_in_fdc
02a6 be CP (HL)
02a7 ; Yes, the drive is different
02a7 c2 bd 02 JP NZ, rw_fdc_mismatch
02aa ; Is track requested different to the xx?
02aa 21 05 fc LD HL, track_in_fdc
02ad cd 20 03 CALL is_track_equal_to_track_selected
02b0 ; Yes, the track is different
02b0 c2 bd 02 JP NZ, rw_fdc_mismatch
02b3 ; Is sector requested equals to the xx?
02b3 3a 08 fc LD A, (dd_sector_selected)
02b6 21 07 fc LD HL, sector_in_fdc
02b9 be CP (HL)
02ba ; Yes, the sector is equal
02ba ca e1 02 JP Z, rw_fdc_set
02bd rw_fdc_mismatch:
02bd ; Is there a pending write on the buffer
02bd 3a 0a fc LD A, (pending_write_flag)
02c0 b7 OR A
02c1 ; Yes, write the buffer before continuing
02c1 c4 cc 04 CALL NZ, write_from_buffer_with_retries
02c4 ; Now we can init the _in_fdc variables
02c4 rw_fdc_not_set:
02c4 ; DTS_in_fdc = DTS_selected
02c4 3a 00 fc LD A, (drive_selected)
02c7 32 04 fc LD (drive_in_fdc),A
02ca 2a 01 fc LD HL, (track_selected)
02cd 22 05 fc LD (track_in_fdc),HL
02d0 3a 08 fc LD A,(dd_sector_selected)
02d3 32 07 fc LD (sector_in_fdc),A
02d6 ; Is a read needed
02d6 3a 11 fc LD A,(read_needed_flag)
02d9 b7 OR A
02da ; Yes, read to fill the buffer
02da c4 0a 05 CALL NZ, read_to_buffer_with_retries
02dd af XOR A
02de 32 0a fc LD (pending_write_flag),A ; = no pending write
02e1 rw_fdc_set:
02e1 ; Calculate the sector buffer to use for this sector
02e1 3a 03 fc LD A, (sector_selected)
02e4 e6 03 AND 0x3 ; mod 4
02e6 6f LD L,A
02e7 26 00 LD H,0x0
02e9 29 ADD HL,HL ; *2
02ea 29 ADD HL,HL ; *2
02eb 29 ADD HL,HL ; *2
02ec 29 ADD HL,HL ; *2
02ed 29 ADD HL,HL ; *2
02ee 29 ADD HL,HL ; *2
02ef 29 ADD HL,HL ; *2. Combined *128
02f0 11 16 fc LD DE, sector_buffer_base
02f3 19 ADD HL,DE
02f4 ; HL = sector_buffer_base + (sector mod 4) * logical_sector_size
02f4 ed 5b 14 fc LD DE,(disk_DMA_address)
02f8 01 80 00 LD BC,logical_sector_size
02fb ;
02fb 3a 12 fc LD A,(operation_type)
02fe b7 OR A
02ff ; Yes, it's a read, skip write related coe
02ff 20 06 JR NZ, copy_block_to_or_from_buffer
0301 3e 01 LD A,0x1
0303 32 0a fc LD (pending_write_flag),A ; = 1
0306 ; Reverse the block copy direction
0306 eb EX DE,HL
0307 copy_block_to_or_from_buffer:
0307 ; Copy a sector from the buffer to the DMA
0307 cd d1 fe CALL move_RAM_relocated
030a 3a 13 fc LD A, (rw_type)
030d fe 01 CP rw_type_directory_write
030f 3a 10 fc LD A, (rw_result)
0312 ; Return if it is a read or a normal write
0312 c0 RET NZ
0313 b7 OR A
0314 ; Return if last read/write had an error
0314 c0 RET NZ
0315 ; It is a directory write. Le's not wait and
0315 ; save to disk now. (to be more reliable?)
0315 af XOR A
0316 32 0a fc LD (pending_write_flag),A ; = 0
0319 cd cc 04 CALL write_from_buffer_with_retries
031c 3a 10 fc LD A,(rw_result)
031f c9 RET
0320
0320 is_track_equal_to_track_selected:
0320 ; HL = address to a variable with the track
0320 ; Returns flag Z set if they are equal.
0320 ; This is not inline as the drive and sector comparison because
0320 ; the track is two bytes.
0320 eb EX DE,HL
0321 21 01 fc LD HL, track_selected
0324 1a LD A,(DE) ; = track
0325 be CP (HL)
0326 c0 RET NZ
0327 13 INC DE
0328 23 INC HL
0329 1a LD A,(DE)
032a be CP (HL)
032b c9 RET
032c
032c ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
032c ; FLOPPY DISK INTERNAL INIT
032c ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
032c
032c init_drive:
032c ; Change current drive, update the disk info and check density
032c ; C: drive number
032c 21 00 00 LD HL,0x0
032f 79 LD A,C
0330 fe 02 CP disk_count
0332 ; Ignore if the drive number is out of range
0332 d0 RET NC
0333 ; Point HL to the disk info for disk A or B
0333 b7 OR A
0334 21 79 fe LD HL, disk_parameter_header_0
0337 28 03 JR Z, disk_params_skip_for_drive_a
0339 21 8a fe LD HL, disk_parameter_header_1
033c disk_params_skip_for_drive_a:
033c ; The current drive is the requested one?
033c 3a 16 fe LD A,(disk_active_drive)
033f b9 CP C
0340 ; Yes, nothing to do
0340 c8 RET Z
0341 ; No, change the drive
0341 ; Store the new drive number
0341 79 LD A,C
0342 32 16 fe LD (disk_active_drive),A
0345 b7 OR A
0346 ; If the disk info for the drive is defined,
0346 ; restore that as the active info
0346 e5 PUSH HL
0347 21 17 fe LD HL, disk_active_info
034a 11 1d fe LD DE, disk_active_info_drive_b
034d 28 03 JR Z, save_previous_disk_info
034f 11 1a fe LD DE, disk_active_info_drive_a
0352 save_previous_disk_info:
0352 1a LD A, (DE)
0353 ; Is the active info undefined?
0353 fe ff CP disk_active_info_undefined
0355 ; Yes, no need to save the info
0355 28 0a JR Z, skip_save_disk_info
0357 c5 PUSH BC
0358 ; Save the current disk info for the drive
0358 01 03 00 LD BC, 0x3
035b ed b0 LDIR
035d c1 POP BC
035e 11 17 fe LD DE, disk_active_info
0361 skip_save_disk_info:
0361 ; C is the disk number
0361 79 LD A,C
0362 b7 OR A
0363 ; Load active info for disk a or b
0363 21 1a fe LD HL, disk_active_info_drive_a
0366 28 03 JR Z, load_previous_info
0368 21 1d fe LD HL, disk_active_info_drive_b
036b load_previous_info:
036b 7e LD A,(HL)
036c ; Is the stored info undefined?
036c fe ff CP disk_active_info_undefined
036e ; Yes, the info is not cached, we need to analyze the disk
036e 28 20 JR Z, analyze_inserted_disk
0370 ; Restore the disk info
0370 01 03 00 LD BC, 0x3
0373 ed b0 LDIR
0375 ; Copy the required disk parameter block DDSD or DDDD
0375 01 0f 00 LD BC, disk_parameter_block_size
0378 11 aa fe LD DE, disk_parameter_block_double_density
037b 21 65 01 LD HL, init_disk_parameter_block_double_density
037e 3a 19 fe LD A, (disk_active_has_sides)
0381 b7 OR A
0382 28 03 JR Z, skip_for_single_side
0384 21 86 01 LD HL, init_disk_parameter_block_double_density_double_side
0387 skip_for_single_side:
0387 ed b0 LDIR ; Copy the parameter block
0389 ; Restore the track position
0389 3a 17 fe LD A, (disk_active_track)
038c d3 11 OUT (io_11_fdc_track), A
038e e1 POP HL
038f c9 RET
0390
0390 analyze_inserted_disk:
0390 e1 POP HL
0391 ; Try reading as double density disk
0391 3e 00 LD A, disk_density_double
0393 32 18 fe LD (disk_density), A
0396 cd 84 04 CALL prepare_drive
0399 cd e7 01 CALL EP_HOME
039c cd 1d 04 CALL fdc_read_address
039f ; If it reads the track, it is a double density disk
039f 28 0e JR Z, set_double_density_disk
03a1 ; No, try reading as single density disk
03a1 3e 20 LD A, disk_density_single
03a3 32 18 fe LD (disk_density), A
03a6 cd 84 04 CALL prepare_drive
03a9 cd 1d 04 CALL fdc_read_address
03ac c0 RET NZ ; Return if it fails as single and double density disk
03ad 18 43 JR set_single_density_disk
03af
03af set_double_density_disk:
03af ; HL is disk_parameter_header
03af e5 PUSH HL
03b0 d5 PUSH DE
03b1 ; Set no sector tran on the disk params $0 and $1
03b1 11 00 00 LD DE,0x0000
03b4 73 LD (HL),E
03b5 23 INC HL
03b6 72 LD (HL),D
03b7 ; Set DPB for double density on the disk params $a and $b
03b7 11 09 00 LD DE,0x0009
03ba 19 ADD HL,DE
03bb 11 aa fe LD DE, disk_parameter_block_double_density
03be 73 LD (HL),E
03bf 23 INC HL
03c0 72 LD (HL),D
03c1 ; Select disk side 2, will be change to side 1 later.
03c1 db 1c IN A,(io_1c_system_bits)
03c3 f6 04 OR system_bit_side_2_mask
03c5 d3 1c OUT (io_1c_system_bits),A
03c7 ; Try reading on the side 2
03c7 cd 1d 04 CALL fdc_read_address
03ca 01 0f 00 LD BC, disk_parameter_block_size
03cd 11 aa fe LD DE, disk_parameter_block_double_density
03d0 21 65 01 LD HL, init_disk_parameter_block_double_density
03d3 3e 00 LD A, disk_active_has_sides_no
03d5 ; If it fails, side 2 is not readable we are for sure on a single side disk
03d5 20 0e JR NZ, second_side_analysis_completed
03d7 ; The previous fdc_read_address has not failed: there is valid
03d7 ; info on the side 2.
03d7 ; We will see if the sector number to check if it is a single side disk