-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path81-149c.prn
1980 lines (1980 loc) · 78 KB
/
81-149c.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-149c.s
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Analysis of the Kaypro II ROM
0000 ;
0000 ; Based on 81-149c.rom
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_unused: 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_unused_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 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 disk_density: EQU 0xfe17
0000 disk_density_double: EQU 0x00 ; FM encoding
0000 disk_density_single: EQU 0x20 ; MFM encoding
0000 disk_active_track_drive_a: EQU 0xfe18
0000 disk_active_track_drive_b: EQU 0xfe19
0000 disk_active_track_undefined: EQU 0xff
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Console related variables
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 console_esc_mode: EQU 0xfe6c
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 0xfe6d ; First arg of the esc= command
0000 console_cursor_position: EQU 0xfe6e ; 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 0xfe70
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 0xfe71
0000 disk_parameter_header_0: EQU 0xfe71
0000 disk_parameter_header_1: EQU 0xfe82
0000 disk_parameter_block_single_density: EQU 0xfe93
0000 disk_parameter_block_double_density: EQU 0xfea2
0000 disk_sector_translation_table: EQU 0xfeb1
0000
0000 relocation_destination: EQU 0xfecd
0000 relocation_offset: EQU 0xfecd - 0x04a8 ; relocation_destination - block_to_relocate
0000 read_single_density_relocated: EQU 0xfedc ; reloc_single_density + relocation_offset
0000 move_RAM_relocated: EQU 0xfecd ; reloc_move_RAM + relocation_offset
0000 read_to_buffer_relocated: EQU 0xfee3 ; reloc_read_to_buffer + relocation_offset
0000 write_from_buffer_relocated: EQU 0xfef4 ; reloc_write_from_buffer + relocation_offset
0000 write_single_density_relocated: EQU 0xfeed ; reloc_write_single_density + relocation_offset
0000
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 ; Other addresses
0000 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000 CSV_0: EQU 0xfe1a ; Scrathpad for change disk check, drive 0
0000 ALV_0: EQU 0xfe2a ; Scrathpad for BDOS disk allocation, drive 0
0000 CSV_1: EQU 0xfe43 ; Scrathpad for change disk check, drive 1
0000 ALV_1: EQU 0xfe53 ; Scrathpad for BDOS disk allocation, drive 1
0000 DIRBUF: EQU 0xff73 ; 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 86 01 JP EP_INITDSK
0006
0006 ; INITVID: Resets the video system. Video hardware is configured
0006 ; and screen is cleared
0006 c3 05 06 JP EP_INITVID
0009
0009 ; INITDEV: Initializes tall I/O ports.
0009 c3 68 05 JP EP_INITDEV
000c
000c ; HOME: Sets track number to 0
000c ; Corresponds to CP/M BIOS function HOME
000c c3 d8 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 b4 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 cc 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 bb 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 c7 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 ec 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 07 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 e4 03 JP EP_SECTRAN
0024
0024 ; DISKON: Turns on the disk drive.
0024 c3 0f 04 JP EP_DISKON
0027
0027 ; DISKOFF: Turns off the disk drive.
0027 c3 1e 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 75 05 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 7d 05 JP EP_KBDIN
0030
0030 ; KBDOUT: Sends the character in register A to the keyboard port.
0030 c3 88 05 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 cc 05 JP EP_SIOSTI
0036
0036 ; SIOIN: Gets character from SIO-B input port, or waits for one if
0036 ; none is ready.
0036 c3 d2 05 JP EP_SIOIN
0039
0039 ; SIOOUT: Sends character to SIO-B output port.
0039 c3 da 05 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 ea 05 JP EP_LISTST
003f
003f ; LIST: Sends the character in register C to the Centronics port.
003f c3 f2 05 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 e4 05 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 1e 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 25 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 25 04 CALL EP_DELAY
0054 ; Init the system, io ports, screen and memory
0054 cd 68 05 CALL EP_INITDEV
0057 cd 05 06 CALL EP_INITVID
005a cd 86 01 CALL EP_INITDSK
005d ; Avoid the NMI entry point at 0x0066
005d 18 08 JR EP_COLD_continue
005f 3d 00 00 00 00 00 00 DB 0x3D, 0, 0, 0, 0, 0, 0
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 f2 07 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 II *"
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 b4 01 CALL EP_SELDSK
00b4 01 00 00 LD BC,0x0
00b7 cd cc 01 CALL EP_SETTRK
00ba 0e 00 LD C,0x0
00bc cd bb 01 CALL EP_SETSEC
00bf 01 00 fa LD BC, first_sector_load_address
00c2 cd c7 01 CALL EP_SETDMA
00c5 cd ec 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 bb 01 CALL EP_SETSEC
00e4 cd ec 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 cc 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 f2 07 CALL console_write_string
010d .. 00 DB "\n\r\n\r\aI cannot read your diskette.",0
012f cd 1e 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 0xfe71
0134 disk_params:
0134 init_disk_parameter_header_0: ; to 0xfe71
0134 00 00 DW 0x0000 ; XLT, logical translation table
0136 00 00 00 00 00 00 DW 0x0000, 0x0000, 0x0000 ; Scrathpad for BDOS
013c 73 ff DW DIRBUF ; Address of additional scratchpad for BDOS,
013e a2 fe DW disk_parameter_block_double_density ; DPB
0140 1a fe DW CSV_0
0142 2a 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 0xfe82
0145 00 00 DW 0x0000 ; XLT, logical translation table
0147 00 00 00 00 00 00 DW 0x0000, 0x0000, 0x0000 ; Scrathpad for BDOS
014d 73 ff DW DIRBUF ; Address of additional scratchpad for BDOS,
014f a2 fe DW disk_parameter_block_double_density ; DPB
0151 43 fe DW CSV_1
0153 53 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 0xfe93
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 0xfea2
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: ; 0xfeb1
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 EP_INITDSK:
0186 ; Copy relocatable disk access to upper RAM to
0186 ; be accessible even when the ROM is swapped out
0186 21 a8 04 LD HL, block_to_relocate
0189 11 cd fe LD DE, relocation_destination
018c 01 87 00 LD BC, block_to_relocate_end - block_to_relocate ;0x87
018f ed b0 LDIR
0191
0191 ; Copy the disk parameters to upper RAM
0191 21 34 01 LD HL, disk_params
0194 11 71 fe LD DE, disk_params_destination
0197 01 52 00 LD BC, disk_params_end - disk_params ;0x52
019a ed b0 LDIR
019c
019c ; Init some variables
019c af XOR A
019d 32 09 fc LD (fdc_set_flag), A ; = No
01a0 32 0b fc LD (pending_count), A ; = 0
01a3 3e 00 LD A, disk_density_double
01a5 32 17 fe LD (disk_density), A
01a8 3e ff LD A, disk_active_track_undefined
01aa 32 16 fe LD (disk_active_drive), A
01ad 32 18 fe LD (disk_active_track_drive_a), A
01b0 32 19 fe LD (disk_active_track_drive_b), A
01b3 c9 RET
01b4
01b4 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
01b4 ; FLOPPY DISK ENTRY POINTS
01b4 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
01b4
01b4 EP_SELDSK:
01b4 ; C: disk number
01b4 79 LD A,C
01b5 32 00 fc LD (drive_selected), A
01b8 c3 1d 03 JP init_drive
01bb
01bb EP_SETSEC:
01bb ; BC: sector number
01bb 79 LD A,C
01bc 32 03 fc LD (sector_selected), A
01bf ; Is the disk double density?
01bf 3a 17 fe LD A, (disk_density)
01c2 b7 OR A
01c3 ; No, send the sector to the controller
01c3 c2 e0 03 JP NZ, fdc_set_sector
01c6 ; Yes, we just store the sector number
01c6 c9 RET
01c7
01c7 EP_SETDMA:
01c7 ; BC: DMA address
01c7 ed 43 14 fc LD (disk_DMA_address), BC
01cb c9 RET
01cc
01cc EP_SETTRK:
01cc ; C: track number
01cc ed 43 01 fc LD (track_selected), BC
01d0 ; Is the disk double density?
01d0 3a 17 fe LD A, (disk_density)
01d3 b7 OR A
01d4 ; No, send the track to the controller
01d4 c2 d4 03 JP NZ, fdc_seek_track
01d7 ; Yes, we just store the track number
01d7 c9 RET
01d8
01d8 EP_HOME:
01d8 ;Is the disk double density?
01d8 3a 17 fe LD A, (disk_density)
01db b7 OR A
01dc ; No, go to track 0 and return
01dc c2 cb 03 JP NZ, fdc_seek_track_0
01df ; Yes.
01df ; Is a write pending?
01df 3a 0a fc LD A,(pending_write_flag)
01e2 b7 OR A
01e3 ; Yes, skip update
01e3 c2 e9 01 JP NZ, skip_buffer_discard
01e6 ; No, discard the buffer
01e6 32 09 fc LD (fdc_set_flag),A ; = No
01e9 skip_buffer_discard:
01e9 c3 cb 03 JP fdc_seek_track_0
01ec
01ec EP_READ:
01ec ; Is disk double density?
01ec 3a 17 fe LD A,(disk_density)
01ef b7 OR A
01f0 ; No, go directly to the read routine
01f0 c2 dc fe JP NZ, read_single_density_relocated
01f3 ; Yes, some preparation is needed as the calls to EP_SETSEC and
01f3 ; EP_SETTRK did not send the info to the fdc for double density.
01f3 ; Init variables
01f3 af XOR A
01f4 32 0b fc LD (pending_count),A ; = 0
01f7 ; Starting from here it is equal to read in Appendix G
01f7 3e 01 LD A, operation_type_read
01f9 32 12 fc LD (operation_type), A; = operation_type_read
01fc 32 11 fc LD (read_needed_flag), A ; = read_needed
01ff 3e 02 LD A, rw_type_read_or_unallocated_write
0201 32 13 fc LD (rw_type),A
0204 c3 79 02 JP read_write_double_density
0207
0207 EP_WRITE:
0207 ; C indicates the rw_type
0207 ; Is disk double density?
0207 3a 17 fe LD A,(disk_density)
020a b7 OR A
020b ; No, go directly to the write routine
020b c2 ed fe JP NZ, write_single_density_relocated
020e ; Yes, some preparation is needed as the calls to EP_SETSEC and
020e ; set_track did not send the info to the fdc on double density.
020e ; Starting from here it is equal to read in Appendix G
020e af XOR A
020f 32 12 fc LD (operation_type), A ; = operation_type_write
0212 79 LD A,C
0213 32 13 fc LD (rw_type),A ; = C
0216 fe 02 CP rw_type_read_or_unallocated_write
0218 ; It's an allocated write, we can skip reset the
0218 ; unallocated params to check if a read is needed.
0218 c2 32 02 JP NZ, write_check_read_needed
021b 3e 08 LD A, double_density_block_size / logical_sector_size ; 8
021d 32 0b fc LD (pending_count),A ; = 8
0220 ; Initialize the unallocated params
0220 3a 00 fc LD A, (drive_selected)
0223 32 0c fc LD (drive_unallocated), A
0226 2a 01 fc LD HL, (track_selected)
0229 22 0d fc LD (track_unallocated), HL
022c 3a 03 fc LD A, (sector_selected)
022f 32 0f fc LD (sector_unallocated), A
0232 write_check_read_needed:
0232 ; Do we have pending logical sectors?
0232 3a 0b fc LD A,(pending_count)
0235 b7 OR A
0236 ; No, skip
0236 ca 71 02 JP Z, write_with_read_needed
0239 ; Yes, there are more unallocated records remaining
0239 3d DEC A
023a 32 0b fc LD (pending_count),A ; pending_count-1
023d ; Is drive requested different to the unallocated?
023d 3a 00 fc LD A, (drive_selected)
0240 21 0c fc LD HL, drive_unallocated
0243 be CP (HL)
0244 ; Yes, the drive is different
0244 c2 71 02 JP NZ, write_with_read_needed
0247 ; The drives are the same
0247 ; Is track requested different to the unallocated?
0247 21 0d fc LD HL, track_unallocated
024a cd 11 03 CALL is_track_equal_to_track_selected
024d ; Yes, the track is different
024d c2 71 02 JP NZ, write_with_read_needed
0250 ; The tracks are the same
0250 ; Is sector requested different to the unallocated?
0250 3a 03 fc LD A, (sector_selected)
0253 21 0f fc LD HL, sector_unallocated
0256 be CP (HL)
0257 ; Yes, the sector is different
0257 c2 71 02 JP NZ, write_with_read_needed
025a ; The sectors are the same
025a ; DTS on the unallocated variables match the requested DTS
025a ; Advance to the next sector to check if the next write will
025a ; be of the next sector.
025a 34 INC (HL)
025b ; Are we at the end of the track?
025b 7e LD A,(HL)
025c fe 28 CP double_density_sectors_per_track
025e ; No
025e da 6a 02 JP C, write_with_read_not_needed
0261 ; Yes, increase track and set sector to zero
0261 36 00 LD (HL),0x0
0263 2a 0d fc LD HL, (track_unallocated)
0266 23 INC HL
0267 22 0d fc LD (track_unallocated),HL
026a write_with_read_not_needed:
026a af XOR A
026b 32 11 fc LD (read_needed_flag),A ; = read_not_needed
026e c3 79 02 JP read_write_double_density
0271 write_with_read_needed:
0271 af XOR A
0272 32 0b fc LD (pending_count),A ; = 0
0275 3c INC A
0276 32 11 fc LD (read_needed_flag),A ; = read_needed
0279
0279 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0279 ; FLOPPY DISK INTERNAL IMPLEMENTATION READ AND WRITE
0279 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0279
0279 read_write_double_density:
0279 ; Reset the result variable
0279 af XOR A
027a 32 10 fc LD (rw_result),A ; = 0
027d ; Translate the sector logical address to the double density
027d ; address. As sector in DD are four times the size of sector
027d ; in SD, we divide by 4 (or shift right twice).
027d ; Sure? Ono some places its 8 times ???
027d 3a 03 fc LD A, (sector_selected)
0280 b7 OR A ; Clear carry
0281 1f RRA ; /2
0282 b7 OR A ; Clear carry
0283 1f RRA ; /2
0284 32 08 fc LD (dd_sector_selected),A ; sector_selected / 4
0287 ; Is fcd_position set
0287 21 09 fc LD HL, fdc_set_flag
028a 7e LD A,(HL)
028b 36 01 LD (HL),0x1 ; fdc_set_flag = Yes
028d b7 OR A
028e ; No, continue after updating the DTS_in_fdc variables
028e ca b5 02 JP Z, rw_fdc_not_set
0291 ; Yes
0291 ; Are the fdc variables different from the selected?
0291 3a 00 fc LD A,(drive_selected)
0294 21 04 fc LD HL, drive_in_fdc
0297 be CP (HL)
0298 ; Yes, the drive is different
0298 c2 ae 02 JP NZ, rw_fdc_mismatch
029b ; Is track requested different to the xx?
029b 21 05 fc LD HL, track_in_fdc
029e cd 11 03 CALL is_track_equal_to_track_selected
02a1 ; Yes, the track is different
02a1 c2 ae 02 JP NZ, rw_fdc_mismatch
02a4 ; Is sector requested equals to the xx?
02a4 3a 08 fc LD A, (dd_sector_selected)
02a7 21 07 fc LD HL, sector_in_fdc
02aa be CP (HL)
02ab ; Yes, the sector is equal
02ab ca d2 02 JP Z, rw_fdc_set
02ae rw_fdc_mismatch:
02ae ; Is there a pending write on the buffer
02ae 3a 0a fc LD A, (pending_write_flag)
02b1 b7 OR A
02b2 ; Yes, write the buffer before continuing
02b2 c4 39 04 CALL NZ, write_from_buffer_with_retries
02b5 ; Now we can init the _in_fdc variables
02b5 rw_fdc_not_set:
02b5 ; DTS_in_fdc = DTS_selected
02b5 3a 00 fc LD A, (drive_selected)
02b8 32 04 fc LD (drive_in_fdc),A
02bb 2a 01 fc LD HL, (track_selected)
02be 22 05 fc LD (track_in_fdc),HL
02c1 3a 08 fc LD A,(dd_sector_selected)
02c4 32 07 fc LD (sector_in_fdc),A
02c7 ; Is a read needed
02c7 3a 11 fc LD A,(read_needed_flag)
02ca b7 OR A
02cb ; Yes, read to fill the buffer
02cb c4 77 04 CALL NZ, read_to_buffer_with_retries
02ce af XOR A
02cf 32 0a fc LD (pending_write_flag),A ; = no pending write
02d2 rw_fdc_set:
02d2 ; Calculate the sector buffer to use for this sector
02d2 3a 03 fc LD A, (sector_selected)
02d5 e6 03 AND 0x3 ; mod 4
02d7 6f LD L,A
02d8 26 00 LD H,0x0
02da 29 ADD HL,HL ; *2
02db 29 ADD HL,HL ; *2
02dc 29 ADD HL,HL ; *2
02dd 29 ADD HL,HL ; *2
02de 29 ADD HL,HL ; *2
02df 29 ADD HL,HL ; *2
02e0 29 ADD HL,HL ; *2. Combined *128
02e1 11 16 fc LD DE, sector_buffer_base
02e4 19 ADD HL,DE
02e5 ; HL = sector_buffer_base + (sector mod 4) * logical_sector_size
02e5 ed 5b 14 fc LD DE,(disk_DMA_address)
02e9 01 80 00 LD BC,logical_sector_size
02ec ;
02ec 3a 12 fc LD A,(operation_type)
02ef b7 OR A
02f0 ; Yes, it's a read, skip write related coe
02f0 20 06 JR NZ, copy_block_to_or_from_buffer
02f2 3e 01 LD A,0x1
02f4 32 0a fc LD (pending_write_flag),A ; = 1
02f7 ; Reverse the block copy direction
02f7 eb EX DE,HL
02f8 copy_block_to_or_from_buffer:
02f8 ; Copy a sector from the buffer to the DMA
02f8 cd cd fe CALL move_RAM_relocated
02fb 3a 13 fc LD A, (rw_type)
02fe fe 01 CP rw_type_directory_write
0300 3a 10 fc LD A, (rw_result)
0303 ; Return if it is a read or a normal write
0303 c0 RET NZ
0304 b7 OR A
0305 ; Return if last read/write had an error
0305 c0 RET NZ
0306 ; It is a directory write. Le's not wait and
0306 ; save to disk now. (to be more reliable?)
0306 af XOR A
0307 32 0a fc LD (pending_write_flag),A ; = 0
030a cd 39 04 CALL write_from_buffer_with_retries
030d 3a 10 fc LD A,(rw_result)
0310 c9 RET
0311
0311 is_track_equal_to_track_selected:
0311 ; HL = address to a variable with the track
0311 ; Returns flag Z set if they are equal.
0311 ; This is not inline as the drive and sector comparison because
0311 ; the track is two bytes.
0311 eb EX DE,HL
0312 21 01 fc LD HL, track_selected
0315 1a LD A,(DE) ; = track
0316 be CP (HL)
0317 c0 RET NZ
0318 13 INC DE
0319 23 INC HL
031a 1a LD A,(DE)
031b be CP (HL)
031c c9 RET
031d
031d ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
031d ; FLOPPY DISK INTERNAL INIT
031d ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
031d
031d init_drive:
031d ; Change current drive, update the disk info and check density
031d ; C: drive number
031d 21 00 00 LD HL,0x0
0320 79 LD A,C
0321 fe 02 CP disk_count
0323 ; Ignore if the drive number is out of range
0323 d0 RET NC
0324 ; Point HL to the disk info for disk A or B
0324 b7 OR A
0325 21 71 fe LD HL, disk_parameter_header_0
0328 28 03 JR Z, disk_params_skip_for_drive_a
032a 21 82 fe LD HL, disk_parameter_header_1
032d disk_params_skip_for_drive_a:
032d ; The current drive is the requested one?
032d 3a 16 fe LD A,(disk_active_drive)
0330 b9 CP C
0331 ; Yes, nothing to do
0331 c8 RET Z
0332 ; No, change the drive
0332 ; Store the new drive number
0332 79 LD A,C
0333 32 16 fe LD (disk_active_drive),A
0336 b7 OR A
0337 ; Set the read_address_state to the disk param $10
0337 ; The param default is disk_density_double
0337 e5 PUSH HL
0338 11 10 00 LD DE,0x10
033b 19 ADD HL,DE
033c 7e LD A,(HL)
033d 32 17 fe LD (disk_density),A
0340 ; Load active track for disk a or b
0340 21 19 fe LD HL,disk_active_track_drive_b
0343 28 01 JR Z, skip_for_drive_b
0345 2b DEC HL ; HL is disk_active_track_drive_a
0346 skip_for_drive_b:
0346 7e LD A,(HL)
0347 ; Is the active track undefined?
0347 fe ff CP disk_active_track_undefined
0349 ; Yes, skip. Why????
0349 28 03 JR Z, skip_get_track_number
034b ; No, get track number from the controller
034b db 11 IN A,(io_11_fdc_track)
034d 77 LD (HL),A; HL is disk_active_track_drive_x
034e skip_get_track_number:
034e ; C is the disk number
034e 79 LD A,C
034f b7 OR A
0350 ; Load active track for disk a or b
0350 21 18 fe LD HL, disk_active_track_drive_a
0353 28 01 JR Z, skip_for_drive_a
0355 23 INC HL; HL is disk_active_track_drive_b
0356 skip_for_drive_a:
0356 7e LD A,(HL)
0357 ; Send the requested track to the controller
0357 d3 11 OUT (io_11_fdc_track),A
0359 eb EX DE,HL
035a e1 POP HL
035b ; Is the active track undefined?
035b fe ff CP disk_active_track_undefined
035d ; No, we are done
035d c0 RET NZ
035e ; Yes
035e cd ef 03 CALL prepare_drive
0361 cd d8 01 CALL EP_HOME
0364 ; Enable double density
0364 db 1c IN A,(io_1c_system_bits)
0366 e6 df AND ~system_bit_double_density_neg_mask
0368 f6 00 OR 0x0
036a d3 1c OUT (io_1c_system_bits),A
036c ; Can we read the address in double density?
036c cd c1 03 CALL fdc_read_address
036f ; Yes
036f 28 0e JR Z, set_double_density_disk
0371 ; No, retry with single density
0371 ; Disbable double density
0371 db 1c IN A,(io_1c_system_bits)
0373 e6 df AND ~system_bit_double_density_neg_mask
0375 f6 20 OR system_bit_double_density_neg_mask
0377 d3 1c OUT (io_1c_system_bits),A
0379 ; Can we read the address?
0379 cd c1 03 CALL fdc_read_address
037c ; No, there is nothing we can do
037c c0 RET NZ
037d ; Yes
037d 18 1e JR set_single_density_disk
037f
037f set_double_density_disk:
037f ; HL is disk_parameter_header
037f e5 PUSH HL
0380 d5 PUSH DE
0381 ; Set no sector tran on the disk params $0 and $1
0381 11 00 00 LD DE,0x0000
0384 73 LD (HL),E
0385 23 INC HL
0386 72 LD (HL),D
0387 ; Set DPB for double density on the disk params $a and $b
0387 11 09 00 LD DE,0x0009
038a 19 ADD HL,DE
038b 11 a2 fe LD DE, disk_parameter_block_double_density
038e 73 LD (HL),E
038f 23 INC HL
0390 72 LD (HL),D
0391 ; Set disk_density_double in the disk param $10
0391 11 05 00 LD DE,0x0005
0394 19 ADD HL,DE
0395 3e 00 LD A, disk_density_double
0397 77 LD (HL),A
0398 ; Store the current disk density
0398 32 17 fe LD (disk_density),A
039b 18 1c JR fdc_init_drive
039d
039d set_single_density_disk:
039d ; HL is disk_parameter_header
039d e5 PUSH HL
039e d5 PUSH DE
039f ; Set the sector translation table on the disk params $0 and $1
039f 11 b1 fe LD DE, disk_sector_translation_table
03a2 73 LD (HL),E
03a3 23 INC HL
03a4 72 LD (HL),D
03a5 ; Set the DPB on the disk params $a and $b
03a5 11 09 00 LD DE,0x0009
03a8 19 ADD HL,DE
03a9 11 93 fe LD DE, disk_parameter_block_single_density
03ac 73 LD (HL),E
03ad 23 INC HL
03ae 72 LD (HL),D
03af ; Set disk_density_single in the disk param $10
03af 11 05 00 LD DE,0x0005
03b2 19 ADD HL,DE
03b3 3e 20 LD A, disk_density_single
03b5 77 LD (HL),A
03b6 ; Store the current disk density
03b6 32 17 fe LD (disk_density),A
03b9
03b9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
03b9 ; FLOPPY DISK CONTROLLER ACCESS
03b9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
03b9
03b9 fdc_init_drive:
03b9 d1 POP DE ; DE is disk_active_track_drive_x
03ba e1 POP HL ; HL is disk_parameter_header
03bb ; Why set track with the sector value????
03bb db 12 IN A,(io_12_fdc_sector)
03bd d3 11 OUT (io_11_fdc_track),A
03bf ; Update disk_active_track_drive_x
03bf 12 LD (DE),A
03c0 c9 RET
03c1
03c1 fdc_read_address:
03c1 ; FDC read address command
03c1 3e c4 LD A, fdc_command_read_address
03c3 d3 10 OUT (io_10_fdc_command), A
03c5 cd 31 04 CALL wait_for_result
03c8 ; Is record not found?
03c8 cb 67 BIT fdc_status_record_not_found_bit, A
03ca c9 RET
03cb
03cb fdc_seek_track_0:
03cb cd ef 03 CALL prepare_drive
03ce ; Restore controller
03ce 3e 00 LD A, fdc_command_restore
03d0 d3 10 OUT (io_10_fdc_command), A
03d2 18 5d JR wait_for_result
03d4
03d4 fdc_seek_track:
03d4 ; C: track number
03d4 cd ef 03 CALL prepare_drive
03d7 79 LD A,C
03d8 ; Request seek track C
03d8 d3 13 OUT (io_13_fdc_data),A
03da 3e 10 LD A, fdc_command_seek
03dc d3 10 OUT (io_10_fdc_command),A
03de 18 51 JR wait_for_result
03e0
03e0 fdc_set_sector:
03e0 ; C = sector
03e0 79 LD A,C