-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathelite-loader2.asm
1516 lines (1091 loc) · 39.5 KB
/
elite-loader2.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 2) 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:
\
\ * ELITE3.bin
\
\ ******************************************************************************
INCLUDE "1-source-files/main-sources/elite-build-options.asm"
_IB_DISC = (_VARIANT = 1)
_STH_DISC = (_VARIANT = 2)
_SRAM_DISC = (_VARIANT = 3)
GUARD &7C00 \ Guard against assembling over screen memory
\ ******************************************************************************
\
\ Configuration variables
\
\ ******************************************************************************
CODE% = &5700 \ The address where the code will be run
LOAD% = &5700 \ The address where the code will be loaded
OSNEWL = &FFE7 \ The address for the OSNEWL routine
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: &0004 to &0005 and &0070 to &0082
\ Category: Workspaces
\ Summary: Important variables used by the loader
\
\ ******************************************************************************
ORG &0004
.TRTB%
SKIP 2 \ Contains the address of the keyboard translation
\ table, which is used to translate internal key
\ numbers to ASCII
ORG &0070
.S
SKIP 1 \ Temporary storage, used in a number of places
.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
.R
SKIP 1 \ Temporary storage, used in a number of places
.T
SKIP 1 \ Temporary storage, used in a number of places
ORG &0081
.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)
\ ******************************************************************************
\
\ ELITE LOADER
\
\ ******************************************************************************
ORG CODE%
\ ******************************************************************************
\
\ Name: Elite loader (Part 1 of 2)
\ Type: Subroutine
\ Category: Loader
\ Summary: Various copy protection checks, and make sure there is no Tube
\
\ ******************************************************************************
.ENTRY
LDA #0 \ We start by deleting the first loader from memory, so
\ it doesn't leave any clues for the crackers, so set A
\ to 0 so we can zero the memory
TAY \ Set Y to 0 to act as an index in the following loop
.LOOP1
STA &2F00,Y \ Zero the Y-th byte of &2F00, which is where the first
\ loader was running before it loaded this one
INY \ Increment the loop counter
BNE LOOP1 \ Loop back until we have zeroed all 256 bytes from
\ &2F00 to &2FFF, leaving Y = 0
LDA #0 \ Set &3FFF = 0
STA &3FFF
LDA #64 \ Set &7FFF = 64
STA &7FFF
EOR &3FFF \ Set A = 64 EOR &3FFF
\ = 64 EOR 0
\ = 64
CLC \ Set A = A + 64
ADC #64 \ = 64 + 64
\ = 128
PHA \ Push 128 on the stack
TAX \ Set X = 128
LDA #254 \ Call OSBYTE with A = 254, X = 128 and Y = 0 to set
LDY #0 \ the available RAM to 32K
JSR OSBYTE
PLA \ Pull 128 from the stack into A
AND &5973 \ &5973 contains 128, so set A = 128 AND 128 = 128
IF _REMOVE_CHECKSUMS
NOP \ If we have disabled checksums, ignore the result in A
NOP
ELSE
BEQ P% \ If A = 0 then enter an infinite loop, which hangs the
\ computer
ENDIF
JSR PROT1 \ Call PROT1 to display the mode 7 loading screen and
\ perform lots of copy protection
LDA #172 \ Call OSBYTE 172 to read the address of the MOS
LDX #0 \ keyboard translation table into (Y X)
LDY #&FF
JSR OSBYTE
STX TRTB% \ Store the address of the keyboard translation table in
STY TRTB%+1 \ TRTB%(1 0)
LDA #234 \ Call OSBYTE with A = 234, X = 0 and Y = &FF, which
LDX #0 \ detects whether Tube hardware is present, returning
LDY #&FF \ X = 0 (not present) or X = &FF (present)
JSR OSBYTE
CPX #&FF \ If X is not &FF, i.e. we are not running this over the
BNE notube \ Tube, then jump to notube
LDA &5A00 \ &5A00 contains 0, so set A = 0
BEQ P% \ If A = 0 then enter an infinite loop, which hangs the
\ computer
JMP &5A00 \ Otherwise we jump to &5A00, though I have no idea why,
\ as we will only get here if the code has been altered
\ in some way
.notube
LDA MPL \ Set A = &A0, as MPL contains an LDY #0 instruction
NOP \ These bytes appear to be unused
NOP
NOP
JMP MPL \ Jump to MPL to copy 512 bytes to &0400 and jump to
\ ENTRY2
SKIP 8 \ These bytes appear to be unused
NOP
NOP
\ ******************************************************************************
\
\ Name: Elite loader (Part 2 of 2)
\ Type: Subroutine
\ Category: Loader
\ Summary: Load and run the ELITE4 loader
\
\ ------------------------------------------------------------------------------
\
\ Other entry points:
\
\ ENTRY2 Re-entry point to continue the loading process from the
\ MPL routine
\
\ ******************************************************************************
.ENTRY2
LDA #15 \ Call OSBYTE with A = 15 and Y = 0 to flush the input
LDY #0 \ buffer
JSR OSBYTE
LDX #LO(MESS1) \ Set (Y X) to point to MESS1 ("LOAD Elite4")
LDY #HI(MESS1)
JSR OSCLI \ Call OSCLI to run the OS command in MESS1, which loads
\ the ELITE4 binary to its load address of &1900
LDA #21 \ Call OSBYTE with A = 21 and X = 0 to flush the
LDX #0 \ keyboard buffer
JSR OSBYTE
LDA #201 \ Call OSBYTE with A = 201, X = 1 and Y = 1 to re-enable
LDX #1 \ the keyboard, which we disabled in the first loader
LDY #1
JSR OSBYTE
JMP &197B \ Jump to the start of the ELITE4 loader code at &197B
SKIP 15 \ These bytes appear to be unused
\ ******************************************************************************
\
\ Name: MESS1
\ Type: Variable
\ Category: Loader
\ Summary: The OS command string for loading the ELITE4 loader
\
\ ******************************************************************************
.MESS1
EQUS "LOAD Elite4"
EQUB 13
SKIP 86 \ These bytes appear to be unused
EQUB &32
SKIP 13
\ ******************************************************************************
\
\ Name: MPL
\ Type: Subroutine
\ Category: Utility routines
\ Summary: Move two pages of memory from LOADcode to LOAD and jump to ENTRY2
\
\ ******************************************************************************
.MPL
LDY #0 \ Set Y = 0 to act as a byte counter
LDX #2 \ Set X = 2 to act as a page counter
.MVBL
LDA LOADcode,Y \ Copy the Y-th byte of LOADcode to the Y-th byte of
STA LOAD,Y \ LOAD (this instruction gets modified below, so this is
\ a single-use, self-modifying routine)
INY \ Increment the byte counter
BNE MVBL \ Loop back to MVBL to copy the next byte until we have
\ copied a whole page
INC MVBL+2 \ Increment the high byte of the LDA instruction above,
\ so it now points to the next page
INC MVBL+5 \ Increment the high byte of the STA instruction above,
\ so it now points to the next page
DEX \ Decrement the page counter in X
BNE MVBL \ Loop back to MVBL to copy the next page until we have
\ copied X pages
JMP ENTRY2 \ Jump to ENTRY2 to continue the loading process
\ ******************************************************************************
\
\ Name: LOADcode
\ Type: Subroutine
\ Category: Copy protection
\ Summary: LOAD routine, bundled up in the loader so it can be moved to &0400
\ to be run
\
\ ******************************************************************************
.LOADcode
ORG &0400
\ ******************************************************************************
\
\ Name: LOAD
\ Type: Subroutine
\ Category: Copy protection
\ Summary: This code accesses the disc directly (not used in this version as
\ disc protection is disabled)
\
\ ******************************************************************************
.LOAD
JSR LOAD10
PLA
STA L0509
PLA
STA L050A
PLA
CLC
ADC L0551
STA L0557
PLA
STA L0559
PLA
STA L0558
BEQ LOAD2
.LOAD1
JSR LOAD7
DEC L0558
BNE LOAD1
.LOAD2
LDA L0559
BEQ LOAD3
ORA #&20
STA L0511
JSR LOAD7
.LOAD3
LDA L051A
BEQ LOAD5
LDY #&00
.LOAD4
LDA &0700,Y
STA &1000,Y
INY
BNE LOAD4
.LOAD5
LDX L055B
BEQ LOAD6
LDX #&52
LDY #&05
JSR OSCLI
LDX #&02
.LOAD6
STX &76 \ Store the drive number in &76 for retrieval in ELITE4
LDA #&15
LDX #&00
JSR OSBYTE
LDA #&C9
LDX #&01
LDY #&01
JMP OSBYTE
.LOAD7
JSR LOAD11
LDA #&28
SEC
SBC L0557
STA L0545
STA L050F
LDA #&01
JSR LOAD13
LDA L050A
CMP #&0E
BNE LOAD8
LDA L050F
STA L051A
STA L0525
STA L0530
LDA #&04
JSR LOAD13
LDA #&05
JSR LOAD13
LDA #&06
JSR LOAD13
JMP LOAD9
.LOAD8
LDA #&03
JSR LOAD13
.LOAD9
LDA L053B
STA L0545
LDA #&01
JSR LOAD13
LDA L050A
CLC
ADC #&0A
STA L050A
INC L0557
RTS
.LOAD10
JSR LOAD11
LDA L053B
STA L054E
LDA #&02
JSR LOAD13
RTS
.LOAD11
LDA L0557
LDX L055B
BEQ LOAD12
ASL A
.LOAD12
STA L053B
LDA #&00
.LOAD13
STA R
.LOAD14
LDA R
ASL A
TAX
LDA L04FA,X
LDY L04FA+1,X
TAX
STX P
STY P+1
LDA #127
JSR OSWORD
LDA R
CMP #&03
BCC LOAD15
LDY #&0A
LDA (P),Y
AND #&DF
BNE LOAD14
.LOAD15
RTS
.L04FA
EQUB &34
EQUB &05, &3D, &05, &47, &05, &08, &05, &13
EQUB &05, &1E, &05, &29, &05, &FF
.L0509
EQUB &00
.L050A
EQUB &0A
EQUB &FF, &FF, &03, &57
.L050F
EQUB &00, &F6
.L0511
EQUB &2A, &00
EQUB &FF, &00, &0E, &FF, &FF, &03, &57
.L051A
EQUB &00
EQUB &F6, &22, &00, &FF, &00, &07, &FF, &FF
EQUB &03, &57
.L0525
EQUB &00, &F8, &21, &00, &FF, &00
EQUB &11, &FF, &FF, &03, &57
.L0530
EQUB &00, &F9, &27
EQUB &00, &FF, &FF, &FF, &FF, &FF, &01, &69
.L053B
EQUB &00, &00, &FF, &FF, &FF, &FF, &FF, &02
EQUB &7A, &12
.L0545
EQUB &00, &00, &FF, &00, &07, &FF
EQUB &FF, &03, &5B
.L054E
EQUB &00, &00, &0A
.L0551
EQUB &00, &44
EQUB &52, &2E, &32, &0D
.L0557
EQUB &03
.L0558
EQUB &00
.L0559
EQUB &00
EQUB &80 \ This is location &5973, as referenced by part 1
.L055B
EQUB &FF, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00 \ This is location &5A00, as referenced by part 1
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &00, &00
COPYBLOCK LOAD, P%, LOADcode
ORG LOADcode + P% - LOAD
SKIP 487 \ These bytes appear to be unused
\ ******************************************************************************
\
\ Name: ECHAR
\ Type: Variable
\ Category: Loader
\ Summary: Character definitions for the Electron to mimic the graphics
\ characters of the BBC Micro's mode 7 teletext screen
\
\ ******************************************************************************
.ECHAR
EQUB &00, &00, &00, &00, &00, &00, &00, &00
EQUB &E0, &E0, &00, &00, &00, &00, &00, &00
EQUB &0E, &0E, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &0E, &0E
EQUB &E0, &E0, &00, &E0, &E0, &00, &00, &00
EQUB &EE, &EE, &00, &E0, &E0, &00, &00, &00
EQUB &EE, &EE, &00, &0E, &0E, &00, &00, &00
EQUB &00, &00, &00, &00, &00, &00, &E0, &E0
EQUB &E0, &E0, &00, &00, &00, &00, &E0, &E0
EQUB &00, &00, &00, &E0, &E0, &00, &E0, &E0
EQUB &E0, &E0, &00, &E0, &E0, &00, &E0, &E0
EQUB &EE, &EE, &00, &E0, &E0, &00, &E0, &E0
EQUB &EE, &EE, &00, &EE, &EE, &00, &E0, &E0
EQUB &EE, &EE, &00, &00, &00, &00, &00, &00
EQUB &00, &00, &00, &0E, &0E, &00, &0E, &0E
EQUB &0E, &0E, &00, &0E, &0E, &00, &0E, &0E
EQUB &EE, &EE, &00, &0E, &0E, &00, &0E, &0E
EQUB &EE, &EE, &00, &EE, &EE, &00, &0E, &0E
EQUB &00, &00, &00, &00, &00, &00, &EE, &EE
EQUB &EE, &EE, &00, &00, &00, &00, &EE, &EE
EQUB &00, &00, &00, &E0, &E0, &00, &EE, &EE
EQUB &E0, &E0, &00, &E0, &E0, &00, &EE, &EE
EQUB &00, &00, &00, &0E, &0E, &00, &EE, &EE
EQUB &0E, &0E, &00, &0E, &0E, &00, &EE, &EE
EQUB &00, &00, &00, &EE, &EE, &00, &EE, &EE
EQUB &E0, &E0, &00, &EE, &EE, &00, &EE, &EE
EQUB &0E, &0E, &00, &EE, &EE, &00, &EE, &EE
EQUB &EE, &EE, &00, &EE, &EE, &00, &EE, &EE
\ ******************************************************************************
\
\ Name: LOGO
\ Type: Variable
\ Category: Loader
\ Summary: Tables containing the Acornsoft logo for the BBC Micro and Acorn
\ Electron
\
\ ******************************************************************************
.LOGO
EQUB &A0, &A1 \ For the BBC Micro, the tables below consist of offsets
EQUB &A2, &E0 \ into this top table, so the first three characters of
EQUB &A5, &A7 \ the Acornsoft logo are &A0 (the &00-th entry in this
EQUB &AB, &B0 \ table), then &FC (the &18-th entry in this table),
EQUB &B1, &B4 \ then &B4 (the &09-th entry in this table) and so on
EQUB &B5, &B7 \
EQUB &BF, &A3 \ The Electron ignores this top table and just uses the
EQUB &E8, &EA \ values below, adding &E0 to get the number of the
EQUB &EB, &EF \ relevant user-defined character (so the first three
EQUB &F0, &F3 \ characters are &E0, then &F8, then &E9 and so on)
EQUB &F4, &F5 \
EQUB &F8, &FA \ The Acornsoft logo is made up of 5 rows with 38
EQUB &FC, &FD \ graphics characters on each row, which corresponds
EQUB &FE, &FF \ with the tables below
EQUB &00, &00, &00, &18, &09, &03, &18, &18
EQUB &07, &00, &16, &18, &14, &00, &18, &18
EQUB &18, &07, &0E, &14, &00, &0E, &09, &16
EQUB &18, &18, &07, &00, &1A, &1B, &09, &00
EQUB &18, &18, &18, &18, &18, &18
EQUB &00, &00, &17, &1B, &0A, &1B, &05, &06
EQUB &1B, &0F, &0C, &0D, &11, &0A, &1B, &0D
EQUB &10, &0A, &0F, &1B, &09, &0F, &0A, &1B
EQUB &08, &06, &04, &0F, &1B, &1B, &1B, &00
EQUB &1B, &0D, &0D, &0D, &1B, &0D
EQUB &00, &0E, &0C, &10, &0A, &1B, &00, &00
EQUB &00, &0F, &0A, &00, &0F, &0A, &1B, &18
EQUB &1A, &04, &0F, &0C, &1B, &17, &0A, &06
EQUB &1B, &19, &07, &1B, &1B, &1B, &1B, &0A
EQUB &1B, &1B, &1B, &00, &1B, &00
EQUB &03, &1B, &19, &1A, &0A, &1B, &07, &03
EQUB &18, &0F, &15, &00, &17, &0A, &1B, &06
EQUB &19, &00, &0F, &0A, &10, &1B, &0A, &12
EQUB &00, &10, &1B, &13, &13, &13, &13, &08
EQUB &1B, &00, &00, &00, &1B, &00
EQUB &1A, &0B, &00, &0F, &0A, &06, &1B, &1B
EQUB &05, &02, &11, &1B, &0C, &01, &1B, &00
EQUB &10, &15, &0F, &0A, &00, &11, &0A, &11
EQUB &1B, &1B, &04, &11, &1B, &1B, &1B, &04
EQUB &1B, &00, &00, &00, &1B, &00
SKIP 28 \ These bytes appear to be unused
EQUB &02, &0D
SKIP 8
\ ******************************************************************************
\
\ Name: PROT1
\ Type: Subroutine
\ Category: Loader
\ Summary: Various copy protection shenanigans in preparation for showing
\ the Acornsoft loading screen
\
\ ******************************************************************************
.PROT1
LDA #&68 \ Poke the following routine into &0100 to &0108:
STA &0100 \
STA &0103 \ 0100 : &68 PLA
LDA #&85 \ 0101 : &85 &71 STA ZP
STA &0101 \ 0103 : &68 PLA
STA &0104 \ 0104 : &85 &72 STA ZP+1
LDX #&71 \ 0106 : &6C &71 &00 JMP (ZP)
STX &0107 \
STX &0102 \ This routine pulls an address off the stack into a
INX \ location in zero page, and then jumps to that address
STX &0105
LDA #&6C
STA &0106
LDA #&00
STA &0108
.do
JSR &0100 \ Call the subroutine at &0100, which does the
EQUB 0 \ following:
\
\ * The JSR puts the address of the last byte of the
\ JSR instruction on the stack (i.e. the address of
\ the &01), pushing the high byte first
\
\ * It then jumps to &0100, which pulls the address
\ off the stack and puts it in ZP(1 0)
\
\ * The final instruction of the routine at &0100
\ jumps to the address in ZP(1 0), i.e. it jumps to
\ the &01 of the JSR instruction. The &01 byte is
\ followed by a &00 byte, and &01 &00 is the opcode
\ for ORA (&00,X), which doesn't do anything apart
\ from affect the value of the accumulator
\
\ In other words, this whole routine is a complicated
\ way of pointing ZP(1 0) to the &01 byte in the JSR
\ instruction above, i.e. to do + 2
LDA ZP \ Set ZP(1 0) = ZP(1 0) - (2 + do - PROT1)
SEC \ = do + 2 - 2 - do + PROT1
SBC #(2 + do - PROT1) \ = PROT1
STA ZP
LDA ZP+1
SBC #&00
STA ZP+1
LDY #(TABLE - PROT1) \ We're now going to loop through the words in TABLE, so
\ set Y as an index we can add to PROT1 (i.e. ZP) to
\ reach TABLE
.PROT1a
LDA (ZP),Y \ Set SC(1 0) = ZP(1 0) + Y-th word from TABLE
CLC \
ADC ZP \ so, for example, the first entry in TABLE does this:
STA SC \
INY \ SC(1 0) = ZP + first word from TABLE
LDA (ZP),Y \ = PROT1 + jsr1 + 1 - PROT1
ADC ZP+1 \ = jsr1 + 1
STA SC+1 \
\ which is the address of the destination address in the
\ JSR instruction at jsr1
LDX #0 \ Add ZP(1 0), i.e. PROT1, to the word at SC(1 0),
LDA (SC,X) \ starting with the low bytes
CLC
ADC ZP
STA (SC,X)
INC SC \ And then adding the high bytes
BNE P%+4 \
INC SC+1 \ So, for example, the first entry in TABLE modifies the
LDA (SC,X) \ destination address of the JSR at jsr1 by adding PROT1
ADC ZP+1 \ to it, so the address now points to prstr
STA (SC,X)
INY \ Increment Y to point to the next word in TABLE
CPY #&7D \ Loop until we have done them all
BNE PROT1a
BEQ LOADSCR \ Jump to LOADSCR (this BEQ is effectively a JMP as we
\ didn't take the BNE branch)
.TABLE
EQUW jsr1 + 1 - PROT1 \ Offsets within PROT1 of JSR destination addresses that
EQUW jsr2 + 1 - PROT1 \ we modify with the code above
EQUW jsr3 + 1 - PROT1
EQUW jsr4 + 1 - PROT1
EQUW jsr5 + 1 - PROT1
EQUW jsr6 + 1 - PROT1
SKIP 14 \ These bytes appear to be unused
\ ******************************************************************************
\
\ Name: LOADSCR
\ Type: Subroutine
\ Category: Loader
\ Summary: Show the mode 7 Acornsoft loading screen
\
\ ******************************************************************************
.LOADSCR
LDA ZP \ Set ZP(1 0) = ZP(1 0) - (PROT1 - ECHAR)
SEC \ = PROT1 - PROT1 + ECHAR
SBC #LO(PROT1 - ECHAR) \ = ECHAR
STA ZP
LDA ZP+1
SBC #HI(PROT1 - ECHAR)
STA ZP+1
LDX #0 \ Set S = 0, to use as a flag denoting whether this is a
STX S \ BBC Micro (0) or an Electron (&FF)
LDY #&FF \ Call OSBYTE with A = 129, X = 0 and Y = &FF to detect
LDA #129 \ the machine type. This call is undocumented and is not
JSR OSBYTE \ the recommended way to determine the machine type
\ (OSBYTE 0 is the correct way), but this call returns
\ the following:
\
\ * X = Y = 0 if this is a BBC Micro with MOS 0.1
\ * X = Y = 1 if this is an Electron
\ * X = Y = &FF if this is a BBC Micro with MOS 1.20
CPX #1 \ If X is not 1, then this is not an Electron, so jump
BNE bbc \ to bbc
DEC S \ Decrement S to &FF, to denote that this is an Acorn
\ Electron
\ We now define a character set consisting of "fake"
\ mode 7 graphics characters so the Electron can print
\ its own version of the Acornsoft loading screen
\ despite not having the BBC Micro's teletext mode 7
\
\ The command to define a character is as follows:
\
\ VDU 23, n, b0, b1, b2, b3, b4, b5, b6, b7
\
\ where n is the character number and b0 through b7 are
\ the bytes for each pixel row in the character (there
\ are 8 rows of 8 pixels in a character)
\
\ So in the following, we perform the above command
\ for each character using the values from the ECHAR
\ table
LDY #0 \ Set Y to act as an index into the table at ECHAR
.eloop
LDX #7 \ Set a counter in X for the 8 bytes we need to print
\ from the table for each character definition (one byte
\ per pixel row)
LDA #23 \ Print character 23 (i.e. VDU 23)
JSR OSWRCH
TYA \ We will increase Y by 8 for each character, so this
LSR A \ sets A = Y / 8 to give the character number, starting
LSR A \ from 0 and counting up by 1 for each new character
LSR A
ORA #&E0 \ This adds &E0 to A, so our new character set starts
\ with character number &E0, then character number &E1,
\ and so on
JSR OSWRCH \ Print the character number (so we have now done the
\ VDU 23, n part of the command)
.vloop
LDA (ZP),Y \ Print the Y-th byte from the ECHAR table (we set ZP to
JSR OSWRCH \ point to ECHAR above)
INY \ Increment the index to point to the next byte in the
\ table
DEX \ Decrement the byte counter
BPL vloop \ Loop back until we have printed 8 characters
CPY #224 \ Loop back to do the next VDU 23 command until we have
BNE eloop \ printed out the whole table
.bbc
\ We now print the Acornsoft loading screen background
\ using mode 7 graphics (for the BBC Micro) or the
\ "fake" characters we just defined (for the Electron
\ version)
LDA ZP \ Set ZP(1 0) = ZP(1 0) + LOGO - ECHAR
CLC \ = ECHAR + LOGO - ECHAR
ADC #(LOGO - ECHAR) \ = LOGO
STA ZP
BCC P%+4
INC ZP+1
LDA #22 \ Switch to mode 7 using a VDU 22, 7 command
JSR OSWRCH
LDA #7
JSR OSWRCH
.jsr1
JSR prstr - PROT1 \ Call prstr to print the following characters,
\ restarting from the NOP instruction (this destination
\ address is modified by the code above that adds PROT1
\ to the address)
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
NOP \ Marks the end of the VDU block
LDA #145 \ Set T to teletext control code 145 (Red graphics) to
STA T \ specify that the first Acornsoft is red
.jsr2
JSR jsr5 - PROT1 \ Call jsr5, which calls jsr6, which calls LOGOS (this
\ destination address is modified by the code above that
\ adds PROT1 to the address)
BIT S \ If bit 7 of S is set (this is an Electron), jump to
BMI jsr4 \ jsr4
.jsr3