-
Notifications
You must be signed in to change notification settings - Fork 2
/
elite-loader3.asm
2884 lines (2229 loc) · 101 KB
/
elite-loader3.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
\ ******************************************************************************
\
\ TELETEXT ELITE LOADER (PART 3) SOURCE
\
\ Elite was written by Ian Bell and David Braben and is copyright Acornsoft 1984
\
\ The code on this site 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 produces the following binary file:
\
\ * ELITE4.bin
\
\ ******************************************************************************
INCLUDE "1-source-files/main-sources/elite-build-options.asm"
_IB_DISC = (_VARIANT = 1)
_STH_DISC = (_VARIANT = 2)
_SRAM_DISC = (_VARIANT = 3)
GUARD &6000 \ Guard against assembling over screen memory
\ --- Mod: Code added for Teletext Elite: ------------->
_DOCKED = TRUE \ Set compilation flag for docked vs flight code
_LOADER = TRUE \ Set compilation flag for loader code
INCLUDE "1-source-files/main-sources/elite-teletext-macros.asm"
\ --- End of added code ------------------------------->
\ ******************************************************************************
\
\ Configuration variables
\
\ ******************************************************************************
CODE% = &1900 \ The address where the code will be run
LOAD% = &1900 \ The address where the code will be loaded
Q% = _MAX_COMMANDER \ Set Q% to TRUE to max out the default commander, FALSE
\ for the standard default commander
\ --- Mod: Code removed for Teletext Elite: ----------->
\N% = 67 \ N% is set to the number of bytes in the VDU table, so
\ \ we can loop through them below
\ --- And replaced by: -------------------------------->
N% = 12 \ N% is set to the number of bytes in the VDU table, so
\ we can loop through them below
\ --- End of replacement ------------------------------>
VSCAN = 57 \ Defines the split position in the split-screen mode
POW = 15 \ Pulse laser power
\ --- Mod: Code removed for Teletext Elite: ----------->
\VEC = &7FFE \ VEC is where we store the original value of the IRQ1
\ \ vector, matching the address in the elite-missile.asm
\ \ source
\ --- And replaced by: -------------------------------->
VEC = &7BFE \ VEC is where we store the original value of the IRQ1
\ vector, matching the address in the elite-missile.asm
\ source
\ --- End of replacement ------------------------------>
BRKV = &0202 \ The break vector that we intercept to enable us to
\ handle and display system errors
IRQ1V = &0204 \ The IRQ1V vector that we intercept to implement the
\ split-screen mode
WRCHV = &020E \ The WRCHV vector that we intercept with our custom
\ text printing routine
NETV = &0224 \ The NETV vector that we intercept as part of the copy
\ protection
LASCT = &0346 \ The laser pulse count for the current laser, matching
\ the address in the main game code
HFX = &0348 \ A flag that toggles the hyperspace colour effect,
\ matching the address in the main game code
ESCP = &0386 \ The flag that determines whether we have an escape pod
\ fitted, matching the address in the main game code
S% = &11E3 \ The address of the main entry point workspace in the
\ main game code
VIA = &FE00 \ Memory-mapped space for accessing internal hardware,
\ such as the video ULA, 6845 CRTC and 6522 VIAs (also
\ known as SHEILA)
OSWRCH = &FFEE \ The address for the OSWRCH routine
OSBYTE = &FFF4 \ The address for the OSBYTE routine
OSWORD = &FFF1 \ The address for the OSWORD routine
OSCLI = &FFF7 \ The address for the OSCLI vector
\ ******************************************************************************
\
\ Name: ZP
\ Type: Workspace
\ Address: &0070 to &008B
\ Category: Workspaces
\ Summary: Important variables used by the loader
\
\ ******************************************************************************
IF _SRAM_DISC
ORG &0004
.TRTB%
SKIP 2 \ Contains the address of the keyboard translation
\ table, which is used to translate internal key
\ numbers to ASCII
ENDIF
ORG &0070
.ZP
SKIP 2 \ Stores addresses used for moving content around
.P
SKIP 1 \ Temporary storage, used in a number of places
.Q
SKIP 1 \ Temporary storage, used in a number of places
.YY
SKIP 1 \ Temporary storage, used in a number of places
.T
SKIP 1 \ Temporary storage, used in a number of places
.SC
SKIP 1 \ Screen address (low byte)
\
\ Elite draws on-screen by poking bytes directly into
\ screen memory, and SC(1 0) is typically set to the
\ address of the character block containing the pixel
\ we want to draw (see the deep dives on "Drawing
\ monochrome pixels in mode 4" and "Drawing colour
\ pixels in mode 5" for more details)
.SCH
SKIP 1 \ Screen address (high byte)
.CHKSM
SKIP 2 \ Used in the copy protection code
\ --- Mod: Code added for Teletext Elite: ------------->
.R
SKIP 2 \ Temporary storage, used in the mode 7 screen routines
\ --- End of added code ------------------------------->
ORG &008B
.DL
SKIP 1 \ Vertical sync flag
\
\ DL gets set to 30 every time we reach vertical sync on
\ the video system, which happens 50 times a second
\ (50Hz). The WSCAN routine uses this to pause until the
\ vertical sync, by setting DL to 0 and then monitoring
\ its value until it changes to 30
\ ******************************************************************************
\
\ ELITE LOADER
\
\ ******************************************************************************
ORG CODE%
\ ******************************************************************************
\
\ Name: B%
\ Type: Variable
\ Category: Drawing the screen
\ Summary: VDU commands for setting the square mode 4 screen
\ Deep dive: The split-screen mode in BBC Micro Elite
\ Drawing monochrome pixels in mode 4
\
\ ------------------------------------------------------------------------------
\
\ This block contains the bytes that get written by OSWRCH to set up the screen
\ mode (this is equivalent to using the VDU statement in BASIC).
\
\ It defines the whole screen using a square, monochrome mode 4 configuration;
\ the mode 5 part for the dashboard is implemented in the IRQ1 routine.
\
\ The top part of Elite's screen mode is based on mode 4 but with the following
\ differences:
\
\ * 32 columns, 31 rows (256 x 248 pixels) rather than 40, 32
\
\ * The horizontal sync position is at character 45 rather than 49, which
\ pushes the screen to the right (which centres it as it's not as wide as
\ the normal screen modes)
\
\ * Screen memory goes from &6000 to &7EFF, which leaves another whole page
\ for code (i.e. 256 bytes) after the end of the screen. This is where the
\ Python ship blueprint slots in
\
\ * The text window is 1 row high and 13 columns wide, and is at (2, 16)
\
\ * The cursor is disabled
\
\ This almost-square mode 4 variant makes life a lot easier when drawing to the
\ screen, as there are 256 pixels on each row (or, to put it in screen memory
\ terms, there's one page of memory per row of pixels). For more details of the
\ screen mode, see the deep dive on "Drawing monochrome pixels in mode 4".
\
\ There is also an interrupt-driven routine that switches the bytes-per-pixel
\ setting from that of mode 4 to that of mode 5, when the raster reaches the
\ split between the space view and the dashboard. See the deep dive on "The
\ split-screen mode" for details.
\
\ ******************************************************************************
.B%
\ --- Mod: Code removed for Teletext Elite: ----------->
\EQUB 22, 4 \ Switch to screen mode 4
\
\EQUB 28 \ Define a text window as follows:
\EQUB 2, 17, 15, 16 \
\ \ * Left = 2
\ \ * Right = 15
\ \ * Top = 16
\ \ * Bottom = 17
\ \
\ \ i.e. 1 row high, 13 columns wide at (2, 16)
\
\EQUB 23, 0, 6, 31 \ Set 6845 register R6 = 31
\EQUB 0, 0, 0 \
\EQUB 0, 0, 0 \ This is the "vertical displayed" register, and sets
\ \ the number of displayed character rows to 31. For
\ \ comparison, this value is 32 for standard modes 4 and
\ \ 5, but we claw back the last row for storing code just
\ \ above the end of screen memory
\
\EQUB 23, 0, 12, &0C \ Set 6845 register R12 = &0C and R13 = &00
\EQUB 0, 0, 0 \
\EQUB 0, 0, 0 \ This sets 6845 registers (R12 R13) = &0C00 to point
\EQUB 23, 0, 13, &00 \ to the start of screen memory in terms of character
\EQUB 0, 0, 0 \ rows. There are 8 pixel lines in each character row,
\EQUB 0, 0, 0 \ so to get the actual address of the start of screen
\ \ memory, we multiply by 8:
\ \
\ \ &0C00 * 8 = &6000
\ \
\ \ So this sets the start of screen memory to &6000
\
\EQUB 23, 0, 1, 32 \ Set 6845 register R1 = 32
\EQUB 0, 0, 0 \
\EQUB 0, 0, 0 \ This is the "horizontal displayed" register, which
\ \ defines the number of character blocks per horizontal
\ \ character row. For comparison, this value is 40 for
\ \ modes 4 and 5, but our custom screen is not as wide at
\ \ only 32 character blocks across
\
\EQUB 23, 0, 2, 45 \ Set 6845 register R2 = 45
\EQUB 0, 0, 0 \
\EQUB 0, 0, 0 \ This is the "horizontal sync position" register, which
\ \ defines the position of the horizontal sync pulse on
\ \ the horizontal line in terms of character widths from
\ \ the left-hand side of the screen. For comparison this
\ \ is 49 for modes 4 and 5, but needs to be adjusted for
\ \ our custom screen's width
\ --- And replaced by: -------------------------------->
EQUB 22, 7 \ Switch to screen mode 7
\ --- End of replacement ------------------------------>
EQUB 23, 0, 10, 32 \ Set 6845 register R10 = %00100000 = 32
EQUB 0, 0, 0 \
EQUB 0, 0, 0 \ This is the "cursor start" register, and bits 5 and 6
\ define the "cursor display mode", as follows:
\
\ * %00 = steady, non-blinking cursor
\
\ * %01 = do not display a cursor
\
\ * %10 = fast blinking cursor (blink at 1/16 of the
\ field rate)
\
\ * %11 = slow blinking cursor (blink at 1/32 of the
\ field rate)
\
\ We can therefore turn off the cursor completely by
\ setting cursor display mode %01, with bit 6 of R10
\ clear and bit 5 of R10 set
\ --- Mod: Code added for Teletext Elite: ------------->
SKIP 55 \ Pad the table out to the same length as in the
\ original
\ --- End of added code ------------------------------->
\ ******************************************************************************
\
\ Name: E%
\ Type: Variable
\ Category: Sound
\ Summary: Sound envelope definitions
\
\ ------------------------------------------------------------------------------
\
\ This table contains the sound envelope data, which is passed to OSWORD by the
\ FNE macro to create the four sound envelopes used in-game. Refer to chapter 30
\ of the BBC Micro User Guide for details of sound envelopes and what all the
\ parameters mean.
\
\ The envelopes are as follows:
\
\ * Envelope 1 is the sound of our own laser firing
\
\ * Envelope 2 is the sound of lasers hitting us, or hyperspace
\
\ * Envelope 3 is the first sound in the two-part sound of us dying, or the
\ second sound in the two-part sound of us hitting or killing an enemy ship
\
\ * Envelope 4 is the sound of E.C.M. firing
\
\ ******************************************************************************
.E%
EQUB 1, 1, 0, 111, -8, 4, 1, 8, 8, -2, 0, -1, 126, 44
EQUB 2, 1, 14, -18, -1, 44, 32, 50, 6, 1, 0, -2, 120, 126
EQUB 3, 1, 1, -1, -3, 17, 32, 128, 1, 0, 0, -1, 1, 1
EQUB 4, 1, 4, -8, 44, 4, 6, 8, 22, 0, 0, -127, 126, 0
\ ******************************************************************************
\
\ Name: FNE
\ Type: Macro
\ Category: Sound
\ Summary: Macro definition for defining a sound envelope
\
\ ------------------------------------------------------------------------------
\
\ The following macro is used to define the four sound envelopes used in the
\ game. It uses OSWORD 8 to create an envelope using the 14 parameters in the
\ I%-th block of 14 bytes at location E%. This OSWORD call is the same as BBC
\ BASIC's ENVELOPE command.
\
\ See variable E% for more details of the envelopes themselves.
\
\ ******************************************************************************
MACRO FNE I%
LDX #LO(E%+I%*14) \ Set (Y X) to point to the I%-th set of envelope data
LDY #HI(E%+I%*14) \ in E%
LDA #8 \ Call OSWORD with A = 8 to set up sound envelope I%
JSR OSWORD
ENDMACRO
\ ******************************************************************************
\
\ Name: Elite loader (Part 1 of 3)
\ Type: Subroutine
\ Category: Loader
\ Summary: Set up the split screen mode, move code around, set up the sound
\ envelopes and configure the system
\
\ ******************************************************************************
.ENTRY
IF _STH_DISC OR _IB_DISC
JSR PROT1 \ Call PROT1 to calculate checksums into CHKSM
ELIF _SRAM_DISC
JSR PROT4 \ Fetch the address of the keyboard translation table
\ before calling PROT1 to calculate checksums into CHKSM
ENDIF
LDA #144 \ Call OSBYTE with A = 144, X = 255 and Y = 0 to move
LDX #255 \ the screen down one line and turn screen interlace on
JSR OSB
LDA #LO(B%) \ Set the low byte of ZP(1 0) to point to the VDU code
STA ZP \ table at B%
LDA #HI(B%) \ Set the high byte of ZP(1 0) to point to the VDU code
STA ZP+1 \ table at B%
LDY #0 \ We are now going to send the N% VDU bytes in the table
\ at B% to OSWRCH to set up the special mode 4 screen
\ that forms the basis for the split-screen mode
.loop1
LDA (ZP),Y \ Pass the Y-th byte of the B% table to OSWRCH
JSR OSWRCH
INY \ Increment the loop counter
CPY #N% \ Loop back for the next byte until we have done them
BNE loop1 \ all (the number of bytes was set in N% above)
\ --- Mod: Code removed for Teletext Elite: ----------->
\JSR PLL1 \ Call PLL1 to draw Saturn
\ --- And replaced by: -------------------------------->
JSR DrawSaturn \ Call DrawSaturn to draw a mode 7 Saturn
\ --- End of replacement ------------------------------>
LDA #16 \ Call OSBYTE with A = 16 and X = 3 to set the ADC to
LDX #3 \ sample 3 channels from the joystick/Bitstik
JSR OSBYTE
LDA #&60 \ Store an RTS instruction in location &0232
STA &0232
LDA #&02 \ Point the NETV vector to &0232, which we just filled
STA NETV+1 \ with an RTS
LDA #&32
STA NETV
LDA #190 \ Call OSBYTE with A = 190, X = 8 and Y = 0 to set the
LDX #8 \ ADC conversion type to 8 bits, for the joystick
JSR OSB
IF _STH_DISC OR _IB_DISC
LDA #200 \ Call OSBYTE with A = 200, X = 0 and Y = 0 to enable
LDX #0 \ the ESCAPE key and disable memory clearing if the
JSR OSB \ BREAK key is pressed
ELIF _SRAM_DISC
LDA #219 \ Store 219 in location &9F. This gets checked by the
STA &9F \ TITLE routine in the main docked code as part of the
\ copy protection (the game hangs if it doesn't match)
\
\ This is normally done in the OSBmod routine, but the
\ sideways RAM variant doesn't call OSBmod as that part
\ of the copy protection is disabled, so we set the
\ value of location &BF here instead
NOP \ Pad out the code so it takes up the same amount of
NOP \ space as in the original version
NOP
ENDIF
LDA #13 \ Call OSBYTE with A = 13, X = 0 and Y = 0 to disable
LDX #0 \ the "output buffer empty" event
JSR OSB
LDA #225 \ Call OSBYTE with A = 225, X = 128 and Y = 0 to set
LDX #128 \ the function keys to return ASCII codes for SHIFT-fn
JSR OSB \ keys (i.e. add 128)
LDA #12 \ Set A = 12 and X = 0 to pretend that this is an
LDX #0 \ innocent call to OSBYTE to reset the keyboard delay
\ and auto-repeat rate to the default, when in reality
\ the OSB address in the next instruction gets modified
\ to point to OSBmod
.OSBjsr
IF _STH_DISC OR _IB_DISC
JSR OSB \ This JSR gets modified by code inserted into PLL1 so
\ that it points to OSBmod instead of OSB, so this
\ actually calls OSBmod to calculate some checksums
ELIF _SRAM_DISC
NOP \ The sideways RAM variant has this part of the copy
NOP \ protection disabled, so pad out the code so it takes
NOP \ up the same amount of space as in the original version
ENDIF
LDA #13 \ Call OSBYTE with A = 13, X = 2 and Y = 0 to disable
LDX #2 \ the "character entering buffer" event
JSR OSB
LDA #4 \ Call OSBYTE with A = 4, X = 1 and Y = 0 to disable
LDX #1 \ cursor editing, so the cursor keys return ASCII values
JSR OSB \ and can therefore be used in-game
LDA #9 \ Call OSBYTE with A = 9, X = 0 and Y = 0 to disable
LDX #0 \ flashing colours
JSR OSB
JSR PROT3 \ Call PROT3 to do more checks on the CHKSM checksum
LDA #&00 \ Set the following:
STA ZP \
LDA #&11 \ ZP(1 0) = &1100
STA ZP+1 \ P(1 0) = TVT1code
LDA #LO(TVT1code)
STA P
LDA #HI(TVT1code)
STA P+1
JSR MVPG \ Call MVPG to move and decrypt a page of memory from
\ TVT1code to &1100-&11FF
\ --- Mod: Code removed for Teletext Elite: ----------->
\LDA #&00 \ Set the following:
\STA ZP \
\LDA #&78 \ ZP(1 0) = &7800
\STA ZP+1 \ P(1 0) = DIALS
\LDA #LO(DIALS) \ X = 8
\STA P
\LDA #HI(DIALS)
\STA P+1
\LDX #8
\
\JSR MVBL \ Call MVBL to move and decrypt 8 pages of memory from
\ \ SHIP_MISSILE to &7B00-&7BFF
\ --- And replaced by: -------------------------------->
LDA #&00 \ Set the following:
STA ZP \
LDA #&7B \ ZP(1 0) = &7B00
STA ZP+1 \ P(1 0) = SHIP_MISSILE
LDA #LO(SHIP_MISSILE) \ X = 1
STA P
LDA #HI(SHIP_MISSILE)
STA P+1
NOP \ Pad the code out to the same length as in the original
NOP
JSR MVPG \ Call MVPG to move and decrypt a page of memory from
\ SHIP_MISSILE to &7B00-&7BFF
\ --- End of replacement ------------------------------>
SEI \ Disable interrupts while we set up our interrupt
\ handler to support the split-screen mode
LDA VIA+&44 \ Read the 6522 System VIA T1C-L timer 1 low-order
STA &0001 \ counter (SHEILA &44), which decrements one million
\ times a second and will therefore be pretty random,
\ and store it in location &0001, which is among the
\ main game code's random seeds (so this seeds the
\ random number generator for the main game)
LDA #%00111001 \ Set 6522 System VIA interrupt enable register IER
STA VIA+&4E \ (SHEILA &4E) bits 0 and 3-5 (i.e. disable the Timer1,
\ CB1, CB2 and CA2 interrupts from the System VIA)
LDA #%01111111 \ Set 6522 User VIA interrupt enable register IER
STA VIA+&6E \ (SHEILA &6E) bits 0-7 (i.e. disable all hardware
\ interrupts from the User VIA)
LDA IRQ1V \ Copy the current IRQ1V vector address into VEC(1 0)
STA VEC
LDA IRQ1V+1
STA VEC+1
LDA #LO(IRQ1) \ Set the IRQ1V vector to IRQ1, so IRQ1 is now the
STA IRQ1V \ interrupt handler
LDA #HI(IRQ1)
STA IRQ1V+1
LDA #VSCAN \ Set 6522 System VIA T1C-L timer 1 high-order counter
STA VIA+&45 \ (SHEILA &45) to VSCAN (57) to start the T1 counter
\ counting down from 14622 at a rate of 1 MHz
CLI \ Re-enable interrupts
LDA #&00 \ Set the following:
STA ZP \
LDA #&61 \ ZP(1 0) = &6100
STA ZP+1 \ P(1 0) = ASOFT
LDA #LO(ASOFT)
STA P
LDA #HI(ASOFT)
STA P+1
\ --- Mod: Code removed for Teletext Elite: ----------->
\JSR MVPG \ Call MVPG to move and decrypt a page of memory from
\ \ ASOFT to &6100-&61FF
\ --- And replaced by: -------------------------------->
NOP \ Pad the code out to the same length as in the original
NOP
NOP
\ --- End of replacement ------------------------------>
LDA #&63 \ Set the following:
STA ZP+1 \
LDA #LO(ELITE) \ ZP(1 0) = &6300
STA P \ P(1 0) = ELITE
LDA #HI(ELITE)
STA P+1
\ --- Mod: Code removed for Teletext Elite: ----------->
\JSR MVPG \ Call MVPG to move and decrypt a page of memory from
\ \ ELITE to &6300-&63FF
\ --- And replaced by: -------------------------------->
NOP \ Pad the code out to the same length as in the original
NOP
NOP
\ --- End of replacement ------------------------------>
LDA #&76 \ Set the following:
STA ZP+1 \
LDA #LO(CpASOFT) \ ZP(1 0) = &7600
STA P \ P(1 0) = CpASOFT
LDA #HI(CpASOFT)
STA P+1
\ --- Mod: Code removed for Teletext Elite: ----------->
\JSR MVPG \ Call MVPG to move and decrypt a page of memory from
\ \ CpASOFT to &7600-&76FF
\ --- And replaced by: -------------------------------->
NOP \ Pad the code out to the same length as in the original
NOP
NOP
\ --- End of replacement ------------------------------>
LDA #&00 \ Set the following:
STA ZP \
LDA #&04 \ ZP(1 0) = &0400
STA ZP+1 \ P(1 0) = WORDS
LDA #LO(WORDS) \ X = 4
STA P
LDA #HI(WORDS)
STA P+1
LDX #4
JSR MVBL \ Call MVBL to move and decrypt 4 pages of memory from
\ WORDS to &0400-&07FF
LDX #35 \ We now want to copy the disc catalogue routine from
\ CATDcode to CATD, so set a counter in X for the 36
\ bytes to copy
.loop2
LDA CATDcode,X \ Copy the X-th byte of CATDcode to the X-th byte of
STA CATD,X \ CATD
DEX \ Decrement the loop counter
BPL loop2 \ Loop back to copy the next byte until they are all
\ done
LDA &76 \ Set the drive number in the CATD routine to the
STA CATBLOCK \ contents of &76, which gets set in ELITE3
FNE 0 \ Set up sound envelopes 0-3 using the FNE macro
FNE 1
FNE 2
FNE 3
LDX #LO(MESS1) \ Set (Y X) to point to MESS1 ("DIR E")
LDY #HI(MESS1)
JSR OSCLI \ Call OSCLI to run the OS command in MESS1, which
\ changes the disc directory to E
LDA #LO(LOAD) \ Set the following:
STA ZP \
LDA #HI(LOAD) \ ZP(1 0) = LOAD
STA ZP+1 \ P(1 0) = LOADcode
LDA #LO(LOADcode)
STA P
LDA #HI(LOADcode)
STA P+1
LDY #0 \ We now want to move and decrypt one page of memory
\ from LOADcode to LOAD, so set Y as a byte counter
.loop3
LDA (P),Y \ Fetch the Y-th byte of the P(1 0) memory block
IF _STH_DISC OR _IB_DISC
EOR #&18 \ Decrypt it by EOR'ing with &18
ELIF _SRAM_DISC
EOR CHKSM \ Decrypt it by EOR'ing with the checksum value
ENDIF
STA (ZP),Y \ Store the decrypted result in the Y-th byte of the
\ ZP(1 0) memory block
DEY \ Decrement the byte counter
BNE loop3 \ Loop back to copy the next byte until we have done a
\ whole page of 256 bytes
JMP LOAD \ Jump to the start of the routine we just decrypted
\ ******************************************************************************
\
\ Name: CHECK
\ Type: Subroutine
\ Category: Copy protection
\ Summary: Calculate a checksum from two 256-byte portions of the loader code
\
\ ******************************************************************************
.CHECK
CLC \ Clear the C flag for the addition below
LDY #0 \ We are going to loop through 256 bytes, so set a byte
\ counter in Y
.p2
ADC PLL1,Y \ Set A = A + Y-th byte of PLL1
EOR ENTRY,Y \ Set A = A EOR Y-th byte of ENTRY
DEY \ Decrement the byte counter
BNE p2 \ Loop back to checksum the next byte
RTS \ Return from the subroutine
\ ******************************************************************************
\
\ Name: LOADcode
\ Type: Subroutine
\ Category: Loader
\ Summary: Encrypted LOAD routine, bundled up in the loader so it can be
\ moved to &0B00 to be run
\
\ ------------------------------------------------------------------------------
\
\ This section is encrypted by EOR'ing with &18. The encryption is done by the
\ elite-checksum.py script, and decryption is done in part 1 above, at the same
\ time as it is moved to &0B00.
\
\ ******************************************************************************
.LOADcode
ORG &0B00
\ ******************************************************************************
\
\ Name: LOAD
\ Type: Subroutine
\ Category: Loader
\ Summary: Load the main docked code, set up various vectors, run a checksum
\ and start the game
\
\ ------------------------------------------------------------------------------
\
\ This routine also contains a hidden message from the authors for potential
\ crackers to enjoy:
\
\ Does your mother know you do this?
\
\ I bet this made quite a few people smile back in the day...
\
\ ******************************************************************************
.LOAD
LDX #LO(LTLI) \ Set (Y X) to point to LTLI ("L.T.CODE")
LDY #HI(LTLI)
JSR OSCLI \ Call OSCLI to run the OS command in LTLI, which loads
\ the T.CODE binary (the main docked code) to its load
\ address of &11E3
LDA #LO(S%+11) \ Point BRKV to the fifth entry in the main docked
STA BRKV \ code's S% workspace, which contains JMP BRBR1
LDA #HI(S%+11)
STA BRKV+1
LDA #LO(S%+6) \ Point WRCHV to the third entry in the main docked
STA WRCHV \ code's S% workspace, which contains JMP CHPR
LDA #HI(S%+6)
STA WRCHV+1
SEC \ Set the C flag so the checksum we calculate in A
\ starts with an initial value of 18 (17 plus carry)
LDY #0 \ Set Y = 0 to act as a byte pointer
STY ZP \ Set the low byte of ZP(1 0) to 0, so ZP(1 0) always
\ points to the start of a page
LDX #&11 \ Set X = &11, so ZP(1 0) will point to &1100 when we
\ stick X in ZP+1 below
TXA \ Set A = &11 = 17, to set the initial value of the
\ checksum to 18 (17 plus carry)
.l1
STX ZP+1 \ Set the high byte of ZP(1 0) to the page number in X
ADC (ZP),Y \ Set A = A + the Y-th byte of ZP(1 0)
DEY \ Decrement the byte pointer
BNE l1 \ Loop back to add the next byte until we have added the
\ whole page
INX \ Increment the page number in X
CPX #&54 \ Loop back to checksum the next page until we have
BCC l1 \ checked up to (but not including) page &54
CMP &55FF \ Compare the checksum with the value in &55FF, which is
\ in the docked file we just loaded, in the byte before
\ the ship hangar blueprints at XX21
IF _REMOVE_CHECKSUMS OR TRUE \ Disable the LOAD checksum for Teletext Elite
NOP \ If we have disabled checksums, then ignore the result
NOP \ of the checksum comparison
ELSE
IF _STH_DISC OR _IB_DISC
BNE P% \ If the checksums don't match then enter an infinite
\ loop, which hangs the computer
ELIF _SRAM_DISC
NOP \ The sideways RAM variant ignores the result of the
NOP \ checksum comparison
ENDIF
ENDIF
JMP S%+3 \ Jump to the second entry in the main docked code's S%
\ workspace to start a new game
.LTLI
EQUS "L.T.CODE" \ This is short for "*LOAD T.CODE"
EQUB 13
EQUS "Does your mother know you do this?"
COPYBLOCK LOAD, P%, LOADcode
ORG LOADcode + P% - LOAD
\ ******************************************************************************
\
\ Name: CATDcode
\ Type: Subroutine
\ Category: Save and load
\ Summary: The CATD routine, bundled up in the loader so it can be moved to
\ &0D7A to be run
\
\ ******************************************************************************
.CATDcode
ORG &0D7A
\ ******************************************************************************
\
\ Name: CATD
\ Type: Subroutine
\ Category: Save and load
\ Summary: Load disc sectors 0 and 1 to &0E00 and &0F00 respectively
\
\ ------------------------------------------------------------------------------
\
\ This routine is copied to &0D7A in part 1 above. It is called by both the main
\ docked code and the main flight code, just before the docked code, flight code
\ or ship blueprint files are loaded.
\
\ ******************************************************************************
.CATD
DEC CATBLOCK+8 \ Decrement sector number from 1 to 0
DEC CATBLOCK+2 \ Decrement load address from &0F00 to &0E00
JSR CATL \ Call CATL to load disc sector 1 to &0E00
INC CATBLOCK+8 \ Increment sector number back to 1
INC CATBLOCK+2 \ Increment load address back to &0F00
.CATL
LDA #127 \ Call OSWORD with A = 127 and (Y X) = CATBLOCK to
LDX #LO(CATBLOCK) \ load disc sector 1 to &0F00
LDY #HI(CATBLOCK)
JMP OSWORD
.CATBLOCK
EQUB 0 \ 0 = Drive = 0
EQUD &00000F00 \ 1 = Data address = &0F00
EQUB 3 \ 5 = Number of parameters = 3
EQUB &53 \ 6 = Command = &53 (read data)
EQUB 0 \ 7 = Track = 0
EQUB 1 \ 8 = Sector = 1
EQUB %00100001 \ 9 = Load 1 sector of 256 bytes
EQUB 0 \ 10 = The result of the OSWORD call is returned here
COPYBLOCK CATD, P%, CATDcode
ORG CATDcode + P% - CATD
\ ******************************************************************************
\
\ Name: PROT1
\ Type: Subroutine
\ Category: Copy protection
\ Summary: Part of the CHKSM copy protection checksum calculation
\
\ ******************************************************************************
.PROT1
LDA #85 \ We start by calculating a checksum in A, with an
\ initial value of 85
LDX #64 \ The checksum calculation in CHECK gets run 65 times,
\ so set a counter in X to count them
.p1a