-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathelite-loader.asm
2568 lines (2039 loc) · 96.2 KB
/
elite-loader.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
; ******************************************************************************
;
; APPLE II ELITE LOADER SOURCE
;
; Apple II Elite was written by Ian Bell and David Braben and is copyright
; D. Braben and I. Bell 1986
;
; The code in this file has been reconstructed from a disassembly of the version
; released on Ian Bell's personal website at http://www.elitehomepage.org/
;
; The commentary is copyright Mark Moxon, and any misunderstandings or mistakes
; in the documentation are entirely my fault
;
; The terminology and notations used in this commentary are explained at
; https://elite.bbcelite.com/terminology
;
; The deep dive articles referred to in this commentary can be found at
; https://elite.bbcelite.com/deep_dives
;
; ------------------------------------------------------------------------------
;
; This source file contains code to move binaries in memory during the loading
; process.
;
; ------------------------------------------------------------------------------
;
; This source file produces the following binary file:
;
; * SEC3.bin
;
; ******************************************************************************
INCLUDE "1-source-files/main-sources/elite-build-options.asm"
_IB_DISK = (_VARIANT = 1)
_SOURCE_DISK_BUILD = (_VARIANT = 2)
_SOURCE_DISK_CODE_FILES = (_VARIANT = 3)
_SOURCE_DISK_ELT_FILES = (_VARIANT = 4)
_4AM_CRACK = (_VARIANT = 5)
_SOURCE_DISK = (_VARIANT = 2) OR (_VARIANT = 3) OR (_VARIANT = 4)
; ******************************************************************************
;
; Configuration variables
;
; ******************************************************************************
CODE% = $2000 ; The address where the code will be run
LOAD% = $2000 ; The address where the code will be loaded
startGame = $4000 ; The entry point for the main game binary
fireButtonMask = $4562 ; The address of the variable that controls the
; joystick selection on the title screen
phsoff = $C080 ; Disk controller I/O soft switch for turning the
; stepper motor phase 0 off (PHASEOFF)
mtroff = $C088 ; Disk controller I/O soft switch for turning the motor
; off (MOTOROFF)
mtron = $C089 ; Disk controller I/O soft switch for turning the motor
; on (MOTORON)
drv1en = $C08A ; Disk controller I/O soft switch for enabling drive 1
; (DRV0EN)
drv2en = $C08B ; Disk controller I/O soft switch for enabling drive 2
; (DRV1EN)
Q6L = $C08C ; Disk controller I/O soft switch for strobing the data
; latch for I/O (Q6L)
Q6H = $C08D ; Disk controller I/O soft switch for loading the data
; latch (Q6H)
Q7L = $C08E ; Disk controller I/O soft switch for preparing the
; latch for input (Q7L)
Q7H = $C08F ; Disk controller I/O soft switch for preparing the
; latch for output (Q7H)
; ******************************************************************************
;
; Name: ZP
; Type: Workspace
; Address: $00F0 to $00F7
; Category: Workspaces
; Summary: Important variables used by the loader
;
; ******************************************************************************
ORG $00F0
.ztemp0
SKIP 1 ; Temporary storage used by the disk routines
.ztemp1
SKIP 1 ; Temporary storage used by the disk routines
.ztemp2
SKIP 1 ; Temporary storage used by the disk routines
.ztemp3
SKIP 1 ; Temporary storage used by the disk routines
.fromAddr
SKIP 2 ; The address to copy from in the CopyMemory routine
.toAddr
SKIP 2 ; The address to copy to in the CopyMemory routine
; ******************************************************************************
;
; Name: Disk operations workspace 1
; Type: Workspace
; Address: $0300 to $0310
; Category: Workspaces
; Summary: Variables used by the disk operations and DOS 3.3 RWTS routines
;
; ******************************************************************************
ORG $0300
.track
SKIP 1 ; Storage for a track number in the RWTS code
.sector
SKIP 1 ; Storage for a sector number in the RWTS code
.curtrk
SKIP 1 ; The current track before performing a seek in the RWTS
; code
.tsltrk
SKIP 1 ; The track for the commander file's track/sector list
.tslsct
SKIP 1 ; The sector for the commander file's track/sector list
.filtrk
SKIP 1 ; The track for the commander file's contents
.filsct
SKIP 1 ; The sector for the commander file's contents
.mtimel
SKIP 1 ; The motor on time (low byte)
.mtimeh
SKIP 1 ; The motor on time (high byte)
.seeks
SKIP 1 ; The maximum number of seeks
.recals
SKIP 1 ; The maximum number of arm recalibrations to 2
.slot16
SKIP 1 ; The slot number containing the disk controller card,
; multiplied by 16 to move the slot number into the top
; nibble (so the value is $x0 for slot x)
;
; This can then be used as an offset to add to the soft
; switch addresses for the disk controller, to ensure we
; access the addresses for the correct slot
.atemp0
SKIP 1 ; Temporary storage for the read/write status bit
.idfld
SKIP 4 ; Storage for four bytes used in the RDADR16 routine:
;
; * Checksum
; * Sector
; * Track
; * Volume
PRINT "Disk operations workspace 1 from ", ~track, "to ", ~P%-1, "inclusive"
; ******************************************************************************
;
; Name: Disk operations workspace 2
; Type: Workspace
; Address: $25D6 to $287B
; Category: Workspaces
; Summary: Variables used by the disk operations and DOS 3.3 RWTS routines
;
; ******************************************************************************
ORG $25D6
.buffer
SKIP 48 ; A 256-byte sector buffer, where we can load sectors
; from the disk, such as the track/sector list, or the
; commander file contents
;
; For file data, this is where we store the data that
; we want to save, before it is pre-nibblized into
; 6-bit nibbles in buff2 by the prenib routine
;
; It is also where file data is stored after being
; post-nibblized, in which case the 6-bit nibbles in
; buffr2 are converted into 8-bit bytes and stored here
.fretrk
SKIP 1 ; The number of the last track that we checked for a
; free sector in the getsct routine
.dirtrk
SKIP 3 ; The direction in which we are searching tracks for
; free sectors in the getsct routine (+1 or -1)
.tracks
SKIP 1 ; The number of tracks per disk
SKIP 3 ; Padding to ensure the bitmap variable lines up with
; byte #56 ($38) for the bitmap of free sectors
.bitmap
SKIP 200 ; Bit map of free sectors in track 0, at byte #56 ($38)
; in the buffer
SKIP 72 ; These bytes appear to be unused
.buffr2
SKIP 350 ; A 342-byte buffer for storing data in the 6-bit nibble
; format
;
; This is where we load file data from the disk in the
; 6-bit nibble format, so it can be post-nibblized into
; 8-bit bytes and stored in buffer
;
; It is also where we store nibblized data that is ready
; to be saved to the disk
PRINT "Disk operations workspace 2 from ", ~buffer, "to ", ~P%-1, "inclusive"
; ******************************************************************************
;
; ELITE LOADER
;
; ******************************************************************************
ORG CODE%
; ******************************************************************************
;
; Name: Elite loader
; Type: Subroutine
; Category: Loader
; Summary: Load the SCRN and ELB1 binaries and run the game
;
; ------------------------------------------------------------------------------
;
; This game loader is only used by the official Firebird release (i.e. the 4am
; crack variant).
;
; The loader's aim is to load the game code and data into memory as follows:
;
; * The game's data is from $0B60 to $1C99.
;
; * The loading screen (including the dashboard) is from $2000 to $3FFF.
;
; * The first block of the main game binary (CODE1) is $4000 to $8FFF.
;
; * The second block of the main game binary (CODE2) is from $9000 to $BFFF.
;
; These blocks of code and data are packaged up into two large files - ELA and
; ELB - by the elite-transfer.asm source. Note that the ELB file is called ELB1
; on the 4am crack disk, but the source files refer to it as ELB, so I'll stick
; with that name here.
;
; For the Firebird release, the loading process is as follows:
;
; * The ELITE BASIC file is run. This does BRUN ELA, followed by BRUN SEC3.
; Let's see what those commands do.
;
; * ELA (which includes this routine) is run first with a load address of
; $0A00, so that loads the game data at $0B60, the loading screen at $2000
; and CODE2 at $4000 to $8FFF. This means that the game data and dashboard
; are now in the correct places for running the game (though the latter will
; soon get corrupted, see below).
;
; * Because the ELA file is run with a BRUN command, it calls its own ENTRY
; routine after loading, which switches to the high-resolution screen mode.
; It also copies some data into bank-switched RAM, but this has no effect in
; the released game; it's a remnant of the transfer process used by the
; source disk variant, as described in the elite-transfer.asm source.
;
; * The game loader in SEC3 is then run, which starts by copying CODE2 from
; $4000-$8FFF to $9000-$BFFF. This means that CODE2 is now in the correct
; place for running the game. SEC3 itself loads at $2000, which means it
; corrupts the loading screen (as $2000 is the start of screen memory).
;
; * SEC3 then loads ELB (called ELB1 on disk) with a load address of $4000,
; which loads CODE1 from $4000 to $8FFF. This means that CODE1 is now in
; the correct place for running the game.
;
; * Finally, we start the game by calling the main game's S% routine at $4000,
; which starts by restoring the loading screen (in particular the dashboard,
; which is needed for the game to work), and then the game itself starts.
;
; So this loads the complete game binary into memory, and it's ready to run.
;
; ******************************************************************************
.ENTRY
JSR CopyCode2 ; The ELITE BASIC program has already run by this point,
; so the following step has already been done:
;
; * ELA has been loaded and run, so CODE2 is in memory
; from $4000 to $8FFF
;
; The first step is therefore to copy the CODE2 block
; from $4000-$6FFF to $9000-$BFFF
JSR SetLoadVariables1 ; Configure the file load variables as follows:
;
; * skipBytes = 4
;
; * fileSize(1 0) = $0880
;
; * trackSector = 0
;
; * loadAddr = STA $0200,X
JSR LoadFile ; Load the SCRN file of size $0880 at $0200 (though this
; isn't actually used)
JSR SetFilename ; Set the filename in comnam to ELB1
JSR SetLoadVariables2 ; Configure the file load variables as follows:
;
; * skipBytes = 4
;
; * fileSize(1 0) = $4FFF
;
; * trackSector = 0
;
; * loadAddr = STA $4000,X
JSR LoadFile ; Load the ELB1 file of size $4FFF at $4000, so that's
; from $4000 to $8FFF
;
; ELB1 contains the CODE1 block of the main game binary,
; so the end result of all this loading is:
;
; * CODE1 from $4000 to $8FFF
;
; * CODE2 from $9000 to $BFFF
;
; In other words the game binary is now loaded and in
; the correct location for the game to run
JMP startGame ; Jump to startGame to start the game
; ******************************************************************************
;
; Name: filename
; Type: Variable
; Category: Save and load
; Summary: The filename of the second file to load
;
; ******************************************************************************
.filename
EQUS "ELB1"
; ******************************************************************************
;
; Name: comnam
; Type: Variable
; Category: Save and load
; Summary: The filename of the first file to load, padded out with spaces to
; a fixed size of 30 characters for the rfile routine
;
; ******************************************************************************
.comnam
EQUS "SCRN "
; ******************************************************************************
;
; Name: findf
; Type: Subroutine
; Category: Save and load
; Summary: Search the disk catalog for an existing file
; Deep dive: File operations with embedded Apple DOS
;
; ------------------------------------------------------------------------------
;
; Returns:
;
; C flag The result of the search:
;
; * Clear = file found
;
; * Set = file not found
;
; ******************************************************************************
.findf
CLC ; Clear the C flag to pass to rentry to indicate that we
; should search the disk catalog for an existing file
BCC rentry ; Jump to rentry to find the file (this BCC is
; effectively a JMP as we just cleared the C flag
; ******************************************************************************
;
; Name: rentry
; Type: Subroutine
; Category: Save and load
; Summary: Search the disk catalog for an existing file or an empty file
; entry
; Deep dive: File operations with embedded Apple DOS
;
; ------------------------------------------------------------------------------
;
; For a detailed look at how DOS works, see the book "Beneath Apple DOS" by Don
; Worth and Pieter Lechner. In particular, see chapter 4 for the layout of the
; VTOC, catalog sector, file entry and track/sector list.
;
; ------------------------------------------------------------------------------
;
; Arguments:
;
; C flag The type of search:
;
; * Clear = search the catalog for an existing file
;
; * Set = search the catalog for an empty file entry
;
; ------------------------------------------------------------------------------
;
; Returns:
;
; C flag The result of the search:
;
; * Clear = file/entry found
;
; * Set = file/entry not found
;
; Y The offset to the file entry in the catalog sector
;
; ******************************************************************************
.rentry
ROR atemp0 ; Store the C flag in bit 7 of atemp0, so we can check
; it later
JSR rvtoc ; Read the VTOC sector into the buffer
; We now work through the catalog sectors to look for
; the existing file entry (if bit 7 of atemp0 is clear)
; or an empty file empty (if bit 7 of atemp0 is set)
.rentr2
LDA buffer+1 ; Set track to the track number of the next catalog
STA track ; sector from byte #1 of the VTOC
LDA buffer+2 ; Set sector to the sector number of the next catalog
STA sector ; sector from byte #2 of the VTOC
JSR rsect ; Read the catalog sector into the buffer
LDY #$B ; Set Y to use as an index to the first file entry in
; the catalog sector (as the file entries start at
; offset $B in the catalog, with each entry taking up
; 35 bytes)
.rentr3
LDA buffer,Y ; Set A to the first byte from the file entry, which
; will either be the track number of the file, or 0 to
; indicate an empty file entry, or $FF to indicate a
; deleted file
BIT atemp0 ; If bit 7 of atemp0 is clear then we are searching the
BPL rentr4 ; catalog for an existing file entry, so jump to rentr4
; to do this
; If we get here then we are searching for an empty file
; entry
TAX ; If A = 0 then we have just found an empty file entry,
BEQ rentr6 ; so jump to rentr6 to return from the subroutine with a
; successful result
CMP #$FF ; If A = $FF then we have just found a deleted file
BEQ rentr6 ; entry, so jump to rentr6 to return from the subroutine
; with a successful result
BNE rentr8 ; This file entry doesn't match our requirements, so
; jump to rentr8 to try the next file entry in this
; catalog sector
.rentr4
; If we get here then we are searching for an existing
; file entry
TAX ; If A = 0 then we have just found an empty file entry,
BEQ rentr9 ; which means we have not found a match for our file, so
; jump to rentr9 to return from the subroutine with the
; C flag set to indicate that we can't find the file
CMP #$FF ; If A = $FF then we have just found a deleted file
BEQ rentr8 ; entry, which is not a match for our file, so jump to
; rentr8 to try the next file entry in this catalog
; sector
TYA ; Store the file entry index in Y on the stack, so we
PHA ; can retrieve it after the following loop
; We now check the file entry to see if it matches the
; filename in comnam
LDX #0 ; Set X = 0 to use as a character index for the filename
; in the file entry
.rentr5
LDA buffer+3,Y ; Set A to the Y-th character from the filename in the
AND #%01111111 ; file entry we are checking (the filename in a file
; entry starts at byte #3)
CMP comnam,X ; If the character does not match the X-th character of
BNE rentr7 ; comnam then the names don't match, to jump to rentr7
; to try the next file entry in this catalog sector
INY ; Increment the character index for the file entry
INX ; Increment the character index for the filename we are
; searching for
CPX #30 ; Loop back until we have checked all 30 characters
BNE rentr5
; If we get here then all 30 characters of the filename
; in the file entry match the filename in comnam, so we
; have found the file entry we are looking for
PLA ; Set Y to the file entry index that we stored on the
TAY ; stack above, so it once again points to the entry we
; are checking
.rentr6
CLC ; Clear the C flag to indicate that we have found the
; file entry we are looking for
RTS ; Return from the subroutine
.rentr7
PLA ; Set Y to the file entry index that we stored on the
TAY ; stack above, so it once again points to the entry we
; are checking
.rentr8
TYA ; Set Y = Y + 35
CLC ;
ADC #35 ; Each file entry in the catalog consists of 35 bytes,
TAY ; so this increments Y to point to the next entry
BNE rentr3 ; Loop back until we have reached the last file entry
LDA buffer+1 ; Set track to the track number of the next catalog
; sector from byte #1 of the VTOC
BNE rentr2 ; If the next catalog sector is non-zero then loop back
; to load and search this sector
; Otherwise we have searched every catalog sector and we
; haven't found what we're looking for, so fall through
; into rentr9 to return from the subroutine with the C
; flag set to indicate that the catalog is full
.rentr9
SEC ; Clear the C flag to indicate that we have not found
; the file entry we are looking for
RTS ; Return from the subroutine
; ******************************************************************************
;
; Name: getsct
; Type: Subroutine
; Category: Save and load
; Summary: Analyse the VTOC sector to allocate one free sector
; Deep dive: File operations with embedded Apple DOS
;
; ------------------------------------------------------------------------------
;
; For a detailed look at how DOS works, see the book "Beneath Apple DOS" by Don
; Worth and Pieter Lechner. In particular, see chapter 4 for the layout of the
; VTOC, catalog sector, file entry and track/sector list.
;
; ------------------------------------------------------------------------------
;
; Arguments:
;
; buffer The VTOC sector for this disk
;
; ------------------------------------------------------------------------------
;
; Returns:
;
; C flag The result of the check:
;
; * Clear = free sector found
;
; * Set = no free sectors found (i.e. the disk is full)
;
; X The track number containing the free sector
;
; Y The free sector number
;
; ******************************************************************************
.getsct
LDA #0 ; Set ztemp0 = 0 to denote that we are starting this
STA ztemp0 ; search in the outer half of the disk from track 16
; down to track 0
BEQ getsc4 ; Jump into the loop below at getsc4 with A = 0, so we
; start the search at the last track number that we
; checked, which is in fretrk
.getsc3
LDA dirtrk ; Set A to the direction we are moving in our search for
; a free sector (-1 or +1)
.getsc4
CLC ; Add the direction in A to the last allocated track so
ADC fretrk ; we move in the direction in A
;
; Or, if we just started searching with A = 0, we check
; the last allocated track, as it might not have been
; used last time and might still be free
;
; In either case, A now contains the next track to check
; for a free sector
BEQ getsc5 ; If we have reached track 0, jump to getsc5
CMP tracks ; If A is less than the number of tracks on the disc
BCC getsc7 ; then we haven't reached the highest numbered track
; yet, so jump to getsc7 to check this track for a free
; sector
LDA #$FF ; Otherwise we have reached the highest numbered track,
; so set A = -1 so we start searching from track 16 down
; to track 0
BNE getsc6 ; Jump to getsc6 to set the direction to -1 and start
; searching from track 16 down to track 0 (this BNE is
; effectively a JMP as A is always non-zero)
.getsc5
LDA ztemp0 ; If ztemp0 is non-zero then we have already searched
BNE getscB ; the disk from track 18 up to track 34, and we jumped
; here when we finished searching track 16 down to track
; 0, so we have searched the whole disk and haven't
; found a free sector, so jump to getscB to return from
; the subroutine with a disk full error
LDA #1 ; Otherwise we have not already searched from track 18
; up to track 34, so set A = +1 so we start searching
; from track 18 up to track 34
STA ztemp0 ; Set ztemp0 = 1 to record that we are now searching the
; half of the disk track 18 up to track 34
.getsc6
STA dirtrk ; Set the search direction to A, so it's now -1 or +1
CLC ; Set A = A + 17, so A is now the track next to the VTOC
ADC #17 ; track in the direction we want to search (the VTOC is
; always in track 17)
;
; So this is the track to start searching from, heading
; in the new direction in dirtrk
.getsc7
STA fretrk ; Store the number of the track we are checking for a
; free sector in fretrk
; We now search the bitmap of free sectors for the track
; in A, which is part of the VTOC and is therefore in
; buffer
;
; The bitmaps for each track are stored at byte $38 (for
; track 0) onwards, with four bitmap bytes per track,
; though only the first two bytes contain bitmap data
;
; The bitmap variable points to byte #56 ($38) of the
; buffer where we loaded the VTOC, so it points to the
; first bitmap for track 0
ASL A ; Set Y = A * 4
ASL A ;
TAY ; So we can use Y as an index into the bitmap of free
; sectors in the buffer, so the bitmap for track Y is
; at bitmap + Y
LDX #16 ; Set X = 16 to denote that we are searching the first
; byte of the bitmap
LDA bitmap,Y ; Set A to the first byte of the bitmap for the track
; we are checking
BNE getsc8 ; If A is non-zero then there is a non-zero bit in the
; bitmap, which indicates a free sector, so jump to
; getsc8 to convert this into a sector number
INY ; Increment Y to point to the next byte in the bitmap
; of free sectors
LDX #8 ; Set X = 8 to denote that we are searching the second
; byte of the bitmap
LDA bitmap,Y ; Set A to the second byte of the bitmap for the track
; we are checking
BEQ getsc3 ; If A is zero then every sector is occupied in the
; bitmap, so loop back getsc3 to move on to the next
; track, as there are no free sectors in this one
.getsc8
; If we get here then we have found a free sector in
; the bitmap for this track, so we need to convert this
; into a sector number
;
; We do this by looping through the bitmap byte in A
; until we find a set bit to indicate a free sector
STX ztemp0 ; Store X in ztemp0, so it is 16 if we found a free
; sector in the first bitmap byte, or 8 if we found a
; free sector in the second bitmap byte
;
; So ztemp0 is the sector number that corresponds to
; bit 7 in the relevant byte, as the first byte covers
; sectors 8 to 15 (bit 0 to 7), and the second byte
; covers sectors 0 to 7 (bit 0 to 7)
LDX #0 ; Set a counter in X to keep track of the position of
; the bit we are currently checking
.getsc9
INX ; Increment the bit position in X
DEC ztemp0 ; Decrement the sector number in ztemp0
ROL A ; Set the C flag to the next bit from the bitmap byte
BCC getsc9 ; Loop back to getsc9 until we shift a 1 out of the
; bitmap byte, which indicates a free sector
; We now change this 1 to a 0 and shift all the other
; bits in the bitmap back to their original positions
CLC ; Clear the C flag so the first rotation in the
; following loop will replace the 1 we just found with a
; 0, to indicate that it is no longer free
.getscA
ROR A ; Rotate the bits back into A again
DEX ; Decrement the position counter in X
BNE getscA ; Loop back until we have rotated all the bits back into
; the bitmap, with the 1 changed to a 0
STA bitmap,Y ; update VTOC
LDX fretrk ; Set X to the track number where we found the free
; sector, which we stored in fretrk, so we can return it
; from the subroutine
LDY ztemp0 ; Set X to the number of the free sector in ztemp0, so
; we can return it from the subroutine
CLC ; Clear the C flag to indicate that we have successfully
; found a free sector
RTS ; Return from the subroutine
.getscB
SEC ; Clear the C flag to indicate that we have not found
; a free sector and the disk is full
RTS ; Return from the subroutine
; ******************************************************************************
;
; Name: gettsl
; Type: Subroutine
; Category: Save and load
; Summary: Read a file's track/sector list
; Deep dive: File operations with embedded Apple DOS
;
; ------------------------------------------------------------------------------
;
; For a detailed look at how DOS works, see the book "Beneath Apple DOS" by Don
; Worth and Pieter Lechner. In particular, see chapter 4 for the layout of the
; VTOC, catalog sector, file entry and track/sector list.
;
; ------------------------------------------------------------------------------
;
; Arguments:
;
; buffer The catalog sector for this file
;
; Y The offset within the catalog sector for the relevant
; file entry
;
; ------------------------------------------------------------------------------
;
; Returns:
;
; buffer The track/sector list for the file
;
; track The track number of the file's data
;
; sector The sector number of the file's data
;
; ******************************************************************************
.gettsl
LDA buffer,Y ; Set track to the track containing the track/sector
STA track ; list
LDA buffer+1,Y ; Set sector to the sector containing the track/sector
STA sector ; list
JSR rsect ; Read the track/sector list into the buffer
LDY #$C ; Set Y to offset $C, so it points to the track and
; sector of first data sector in the track/sector list
; we just loaded
LDA buffer,Y ; Set track to the track containing the file data
STA track
LDA buffer+1,Y ; Set sector to the sector containing the file data
STA sector
RTS ; Return from the subroutine
; ******************************************************************************
;
; Name: rvtoc
; Type: Subroutine
; Category: Save and load
; Summary: Read the VTOC sector into the buffer
; Deep dive: File operations with embedded Apple DOS
;
; ------------------------------------------------------------------------------
;
; For a detailed look at how DOS works, see the book "Beneath Apple DOS" by Don
; Worth and Pieter Lechner. In particular, see chapter 4 for the layout of the
; VTOC, catalog sector, file entry and track/sector list.
;
; ------------------------------------------------------------------------------
;
; Returns:
;
; buffer Contains the VTOC sector
;
; ******************************************************************************
.rvtoc
LDA #17 ; Set the track number to 17, which is where the VTOC is
STA track ; stored on the disk
LDA #0 ; Set the sector number to 0, which is where the VTOC is
STA sector ; stored on the disk
; Fall through into rsect to read sector 0 in track 17,
; so we read the VTOC sector from the disk into the
; buffer
; ******************************************************************************
;
; Name: rsect
; Type: Subroutine
; Category: Save and load
; Summary: Read a specific sector from disk into the buffer
; Deep dive: File operations with embedded Apple DOS
;
; ------------------------------------------------------------------------------
;
; For a detailed look at how DOS works, see the book "Beneath Apple DOS" by Don
; Worth and Pieter Lechner. In particular, see chapter 4 for the layout of the
; VTOC, catalog sector, file entry and track/sector list.
;
; ------------------------------------------------------------------------------
;
; Arguments:
;
; track The track number
;
; sector The sector number
;
; ------------------------------------------------------------------------------
;
; Returns:
;
; buffer Contains the sector
;
; ******************************************************************************
.rsect
CLC ; Clear the C flag to denote that this is a read
; operation (this value will be read throughout the
; RWTS code that follows)
BCC wsect2 ; Jump to wsect2 to read the specified sector
; ******************************************************************************
;
; Name: wsect
; Type: Subroutine
; Category: Save and load
; Summary: Write a specific sector from the buffer to disk
; Deep dive: File operations with embedded Apple DOS
;
; ------------------------------------------------------------------------------
;
; For a detailed look at how DOS works, see the book "Beneath Apple DOS" by Don
; Worth and Pieter Lechner. In particular, see chapter 4 for the layout of the
; VTOC, catalog sector, file entry and track/sector list.
;
; ------------------------------------------------------------------------------
;
; Arguments:
;
; track The track number
;
; sector The sector number
;
; buffer Contains the data to write
;
; ------------------------------------------------------------------------------
;
; Other entry points:
;
; wsect2 Read or write a sector, depending on the value of the
; C flag (clear = read, set = write)