├── .gitattributes ├── .gitignore ├── 1-source-files ├── README.md ├── fonts │ ├── P.FONT.bin │ └── README.md ├── images │ ├── P.DIALS2P.bin │ └── README.md └── main-sources │ ├── README.md │ ├── elite-build-options.asm │ ├── elite-data.asm │ ├── elite-disc.asm │ ├── elite-loader.asm │ ├── elite-readme.asm │ └── elite-source.asm ├── 2-build-files ├── README.md ├── crc32.py ├── elite-checksum.py ├── elite-decrypt.py ├── libiconv2.dll ├── libintl3.dll └── make.exe ├── 3-assembled-output ├── BCODE.bin ├── BCODE.unprot.bin ├── BDATA.bin ├── BDATA.unprot.bin ├── M128Elt.bin ├── README.md ├── README.txt └── compile.txt ├── 4-reference-binaries ├── README.md ├── compact │ ├── BCODE.bin │ ├── BCODE.unprot.bin │ ├── BDATA.bin │ ├── BDATA.unprot.bin │ └── M128Elt.bin └── sng47 │ ├── BCODE.bin │ ├── BCODE.unprot.bin │ ├── BDATA.bin │ ├── BDATA.unprot.bin │ └── M128Elt.bin ├── 5-compiled-game-discs ├── README.md ├── elite-master-compact.ssd └── elite-master-sng47.ssd ├── Makefile ├── README.md └── make.bat /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail cache files 2 | Thumbs.db 3 | ehthumbs.db 4 | ehthumbs_vista.db 5 | 6 | # Folder config file 7 | Desktop.ini 8 | 9 | # Recycle Bin used on file shares 10 | $RECYCLE.BIN/ 11 | 12 | # Windows Installer files 13 | *.cab 14 | *.msi 15 | *.msm 16 | *.msp 17 | 18 | # Windows shortcuts 19 | *.lnk 20 | 21 | # IDE files 22 | .vscode/ 23 | *.code-workspace 24 | run.bat 25 | -------------------------------------------------------------------------------- /1-source-files/README.md: -------------------------------------------------------------------------------- 1 | # Source files for the BBC Master version of Elite 2 | 3 | This folder contains the source files for the BBC Master version of Elite. 4 | 5 | * [fonts](fonts) contains the binaries for the game's text font 6 | 7 | * [images](images) contains the image binaries for the title screen and dashboard 8 | 9 | * [main-sources](main-sources) contains the annotated source code 10 | 11 | --- 12 | 13 | Right on, Commanders! 14 | 15 | _Mark Moxon_ -------------------------------------------------------------------------------- /1-source-files/fonts/P.FONT.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/1-source-files/fonts/P.FONT.bin -------------------------------------------------------------------------------- /1-source-files/fonts/README.md: -------------------------------------------------------------------------------- 1 | # Font binaries for the BBC Master version of Elite 2 | 3 | This folder contains the font binaries from the original game disc for the BBC Master version of Elite on Ian Bell's personal website. 4 | 5 | * [P.FONT.bin](P.FONT.bin) is the standard BBC Micro font, extracted from the MOS ROM 6 | 7 | --- 8 | 9 | Right on, Commanders! 10 | 11 | _Mark Moxon_ -------------------------------------------------------------------------------- /1-source-files/images/P.DIALS2P.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/1-source-files/images/P.DIALS2P.bin -------------------------------------------------------------------------------- /1-source-files/images/README.md: -------------------------------------------------------------------------------- 1 | # Image binaries for the BBC Master version of Elite 2 | 3 | This folder contains the image binaries from the original game disc for the BBC Master version of Elite on Ian Bell's personal website. 4 | 5 | * [P.DIALS2P.bin](P.DIALS2P.bin) is the dashboard image 6 | 7 | --- 8 | 9 | Right on, Commanders! 10 | 11 | _Mark Moxon_ -------------------------------------------------------------------------------- /1-source-files/main-sources/README.md: -------------------------------------------------------------------------------- 1 | # Annotated source code for the BBC Master version of Elite 2 | 3 | This folder contains the annotated source code for the BBC Master version of Elite. 4 | 5 | * Main source files: 6 | 7 | * [elite-source.asm](elite-source.asm) contains the main source for the game 8 | 9 | * [elite-data.asm](elite-data.asm) contains source for the game data, including the game text and ship blueprints 10 | 11 | * Other source files: 12 | 13 | * [elite-loader.asm](elite-loader.asm) contains the source for the loader 14 | 15 | * [elite-disc.asm](elite-disc.asm) builds the SSD disc image from the assembled binaries and other source files 16 | 17 | * [elite-readme.asm](elite-readme.asm) generates a README file for inclusion on the SSD disc image 18 | 19 | * Files that are generated during the build process: 20 | 21 | * [elite-build-options.asm](elite-build-options.asm) stores the make options in BeebAsm format so they can be included in the assembly process 22 | 23 | --- 24 | 25 | Right on, Commanders! 26 | 27 | _Mark Moxon_ -------------------------------------------------------------------------------- /1-source-files/main-sources/elite-build-options.asm: -------------------------------------------------------------------------------- 1 | _VERSION=4 2 | _VARIANT=1 3 | _REMOVE_CHECKSUMS=FALSE 4 | _MATCH_ORIGINAL_BINARIES=TRUE 5 | _MAX_COMMANDER=FALSE 6 | -------------------------------------------------------------------------------- /1-source-files/main-sources/elite-disc.asm: -------------------------------------------------------------------------------- 1 | \ ****************************************************************************** 2 | \ 3 | \ BBC MASTER ELITE DISC IMAGE SCRIPT 4 | \ 5 | \ BBC Master Elite was written by Ian Bell and David Braben and is copyright 6 | \ Acornsoft 1986 7 | \ 8 | \ The code in this file has been reconstructed from a disassembly of the version 9 | \ released on Ian Bell's personal website at http://www.elitehomepage.org/ 10 | \ 11 | \ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes 12 | \ in the documentation are entirely my fault 13 | \ 14 | \ The terminology and notations used in this commentary are explained at 15 | \ https://elite.bbcelite.com/terminology 16 | \ 17 | \ The deep dive articles referred to in this commentary can be found at 18 | \ https://elite.bbcelite.com/deep_dives 19 | \ 20 | \ ------------------------------------------------------------------------------ 21 | \ 22 | \ This source file produces an SSD disc image for BBC Master Elite. 23 | \ 24 | \ ------------------------------------------------------------------------------ 25 | \ 26 | \ This source file produces one of the following SSD disc images, depending on 27 | \ which release is being built: 28 | \ 29 | \ * elite-master-sng47.ssd 30 | \ * elite-master-compact.ssd 31 | \ 32 | \ This can be loaded into an emulator or a real BBC Master. 33 | \ 34 | \ ****************************************************************************** 35 | 36 | INCLUDE "1-source-files/main-sources/elite-build-options.asm" 37 | 38 | _SNG47 = (_VARIANT = 1) 39 | _COMPACT = (_VARIANT = 2) 40 | 41 | IF _SNG47 42 | PUTFILE "3-assembled-output/M128Elt.bin", "M128Elt", &FF0E00, &FF0E43 43 | PUTFILE "3-assembled-output/BDATA.bin", "BDATA", &000000, &000000 44 | PUTFILE "3-assembled-output/BCODE.bin", "BCODE", &000000, &000000 45 | ELIF _COMPACT 46 | PUTFILE "3-assembled-output/M128Elt.bin", "!BOOT", &000E00, &000E43 47 | PUTFILE "3-assembled-output/BDATA.bin", "BDATA", &001300, &001300 48 | PUTFILE "3-assembled-output/BCODE.bin", "ELITE", &001300, &002C6C 49 | ENDIF 50 | 51 | PUTFILE "3-assembled-output/README.txt", "README", &FFFFFF, &FFFFFF 52 | -------------------------------------------------------------------------------- /1-source-files/main-sources/elite-loader.asm: -------------------------------------------------------------------------------- 1 | \ ****************************************************************************** 2 | \ 3 | \ BBC MASTER ELITE GAME LOADER SOURCE 4 | \ 5 | \ BBC Master Elite was written by Ian Bell and David Braben and is copyright 6 | \ Acornsoft 1986 7 | \ 8 | \ The code in this file has been reconstructed from a disassembly of the version 9 | \ released on Ian Bell's personal website at http://www.elitehomepage.org/ 10 | \ 11 | \ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes 12 | \ in the documentation are entirely my fault 13 | \ 14 | \ The terminology and notations used in this commentary are explained at 15 | \ https://elite.bbcelite.com/terminology 16 | \ 17 | \ The deep dive articles referred to in this commentary can be found at 18 | \ https://elite.bbcelite.com/deep_dives 19 | \ 20 | \ ------------------------------------------------------------------------------ 21 | \ 22 | \ This source file contains the loader for BBC Master Elite. 23 | \ 24 | \ ------------------------------------------------------------------------------ 25 | \ 26 | \ This source file produces the following binary file: 27 | \ 28 | \ * M128Elt.bin 29 | \ 30 | \ ****************************************************************************** 31 | 32 | INCLUDE "1-source-files/main-sources/elite-build-options.asm" 33 | 34 | CPU 1 \ Switch to 65SC12 assembly, as this code runs on the 35 | \ BBC Master 36 | 37 | _SNG47 = (_VARIANT = 1) 38 | _COMPACT = (_VARIANT = 2) 39 | 40 | GUARD &C000 \ Guard against assembling over MOS memory 41 | 42 | \ ****************************************************************************** 43 | \ 44 | \ Configuration variables 45 | \ 46 | \ ****************************************************************************** 47 | 48 | CODE% = &0E00 \ The address where the code will be run 49 | 50 | LOAD% = &0E00 \ The address where the code will be loaded 51 | 52 | N% = 67 \ N% is set to the number of bytes in the VDU table, so 53 | \ we can loop through them below 54 | 55 | S% = &2C6C \ The address of the main entry point workspace in the 56 | \ main game code 57 | 58 | VIA = &FE00 \ Memory-mapped space for accessing internal hardware, 59 | \ such as the video ULA, 6845 CRTC and 6522 VIAs (also 60 | \ known as SHEILA) 61 | 62 | OSWRCH = &FFEE \ The address for the OSWRCH routine 63 | 64 | OSBYTE = &FFF4 \ The address for the OSBYTE routine 65 | 66 | OSCLI = &FFF7 \ The address for the OSCLI routine 67 | 68 | \ ****************************************************************************** 69 | \ 70 | \ Name: ZP 71 | \ Type: Workspace 72 | \ Address: &0070 to &0075 73 | \ Category: Workspaces 74 | \ Summary: Important variables used by the loader 75 | \ 76 | \ ****************************************************************************** 77 | 78 | ORG &0002 79 | 80 | IF _COMPACT 81 | 82 | .MOS 83 | 84 | SKIP 1 \ Determines whether we are running on a Master Compact 85 | \ 86 | \ * 0 = This is a Master Compact 87 | \ 88 | \ * &FF = This is not a Master Compact 89 | 90 | ENDIF 91 | 92 | ORG &0070 93 | 94 | .ZP 95 | 96 | SKIP 2 \ Stores addresses used for moving content around 97 | 98 | .P 99 | 100 | SKIP 1 \ Temporary storage, used in a number of places 101 | 102 | .Q 103 | 104 | SKIP 1 \ Temporary storage, used in a number of places 105 | 106 | .YY 107 | 108 | SKIP 1 \ Temporary storage, used in a number of places 109 | 110 | .T 111 | 112 | SKIP 1 \ Temporary storage, used in a number of places 113 | 114 | ORG &00F4 115 | 116 | .LATCH 117 | 118 | SKIP 2 \ The RAM copy of the currently selected paged ROM/RAM 119 | \ in SHEILA &30 120 | 121 | \ ****************************************************************************** 122 | \ 123 | \ ELITE LOADER 124 | \ 125 | \ ****************************************************************************** 126 | 127 | ORG CODE% 128 | 129 | \ ****************************************************************************** 130 | \ 131 | \ Name: B% 132 | \ Type: Variable 133 | \ Category: Drawing the screen 134 | \ Summary: VDU commands for setting the square mode 1 screen 135 | \ Deep dive: The split-screen mode in BBC Micro Elite 136 | \ Drawing monochrome pixels on the BBC Micro 137 | \ 138 | \ ------------------------------------------------------------------------------ 139 | \ 140 | \ This block contains the bytes that get written by OSWRCH to set up the screen 141 | \ mode (this is equivalent to using the VDU statement in BASIC). 142 | \ 143 | \ It defines the whole screen using a square, monochrome mode 1 configuration; 144 | \ the mode 2 part for the dashboard is implemented in the IRQ1 routine. 145 | \ 146 | \ The top part of Elite's screen mode is based on mode 1 but with the following 147 | \ differences: 148 | \ 149 | \ * 64 columns, 31 rows (256 x 248 pixels) rather than 80, 32 150 | \ 151 | \ * The horizontal sync position is at character 90 rather than 98, which 152 | \ pushes the screen to the right (which centres it as it's not as wide as 153 | \ the normal screen modes) 154 | \ 155 | \ * Screen memory goes from &4000 to &7EFF 156 | \ 157 | \ * In the Master version of Elite, the screen mode is actually based on mode 158 | \ 129 rather than mode 1, so shadow RAM (known as LYNNE) is used to store 159 | \ the screen memory, though in all other respects the screen mode is the 160 | \ same as if it were based on mode 1 161 | \ 162 | \ * The text window is 1 row high and 13 columns wide, and is at (2, 16) 163 | \ 164 | \ * The cursor is disabled 165 | \ 166 | \ This almost-square mode 1 variant makes life a lot easier when drawing to the 167 | \ screen, as there are 256 pixels on each row (or, to put it in screen memory 168 | \ terms, there are two pages of memory per row of pixels). 169 | \ 170 | \ There is also an interrupt-driven routine that switches the bytes-per-pixel 171 | \ setting from that of mode 1 to that of mode 2, when the raster reaches the 172 | \ split between the space view and the dashboard. 173 | \ 174 | \ ****************************************************************************** 175 | 176 | .B% 177 | 178 | EQUB 22, 129 \ Switch to screen mode 129 179 | 180 | EQUB 28 \ Define a text window as follows: 181 | EQUB 2, 17, 15, 16 \ 182 | \ * Left = 2 183 | \ * Right = 15 184 | \ * Top = 16 185 | \ * Bottom = 17 186 | \ 187 | \ i.e. 1 row high, 13 columns wide at (2, 16) 188 | 189 | EQUB 23, 0, 6, 31 \ Set 6845 register R6 = 31 190 | EQUB 0, 0, 0 \ 191 | EQUB 0, 0, 0 \ This is the "vertical displayed" register, and sets 192 | \ the number of displayed character rows to 31. For 193 | \ comparison, this value is 32 for standard modes 1 and 194 | \ 2, but we claw back the last row for storing code just 195 | \ above the end of screen memory 196 | 197 | EQUB 23, 0, 12, &08 \ Set 6845 register R12 = &08 and R13 = &00 198 | EQUB 0, 0, 0 \ 199 | EQUB 0, 0, 0 \ This sets 6845 registers (R12 R13) = &0800 to point 200 | EQUB 23, 0, 13, &00 \ to the start of screen memory in terms of character 201 | EQUB 0, 0, 0 \ rows. There are 8 pixel lines in each character row, 202 | EQUB 0, 0, 0 \ so to get the actual address of the start of screen 203 | \ memory, we multiply by 8: 204 | \ 205 | \ &0800 * 8 = &4000 206 | \ 207 | \ So this sets the start of screen memory to &4000 208 | 209 | EQUB 23, 0, 1, 64 \ Set 6845 register R1 = 64 210 | EQUB 0, 0, 0 \ 211 | EQUB 0, 0, 0 \ This is the "horizontal displayed" register, which 212 | \ defines the number of character blocks per horizontal 213 | \ character row. For comparison, this value is 80 for 214 | \ modes 1 and 2, but our custom screen is not as wide at 215 | \ only 64 character blocks across 216 | 217 | EQUB 23, 0, 2, 90 \ Set 6845 register R2 = 90 218 | EQUB 0, 0, 0 \ 219 | EQUB 0, 0, 0 \ This is the "horizontal sync position" register, which 220 | \ defines the position of the horizontal sync pulse on 221 | \ the horizontal line in terms of character widths from 222 | \ the left-hand side of the screen. For comparison this 223 | \ is 98 for modes 1 and 2, but needs to be adjusted for 224 | \ our custom screen's width 225 | 226 | EQUB 23, 0, 10, 32 \ Set 6845 register R10 = %00100000 = 32 227 | EQUB 0, 0, 0 \ 228 | EQUB 0, 0, 0 \ This is the "cursor start" register, and bits 5 and 6 229 | \ define the "cursor display mode", as follows: 230 | \ 231 | \ * %00 = steady, non-blinking cursor 232 | \ 233 | \ * %01 = do not display a cursor 234 | \ 235 | \ * %10 = fast blinking cursor (blink at 1/16 of the 236 | \ field rate) 237 | \ 238 | \ * %11 = slow blinking cursor (blink at 1/32 of the 239 | \ field rate) 240 | \ 241 | \ We can therefore turn off the cursor completely by 242 | \ setting cursor display mode %01, with bit 6 of R10 243 | \ clear and bit 5 of R10 set 244 | 245 | \ ****************************************************************************** 246 | \ 247 | \ Name: Elite loader 248 | \ Type: Subroutine 249 | \ Category: Loader 250 | \ Summary: Perform a number of OS calls, check for sideways RAM, load and 251 | \ move the main game data, and load and run the main game code 252 | \ 253 | \ ------------------------------------------------------------------------------ 254 | \ 255 | \ The loader loads and moves the following files. There is no decryption at this 256 | \ stage - that is all done by the main game code. 257 | \ 258 | \ * The BDATA game data file is loaded into main memory at &1300-&54FF, and is 259 | \ then moved as follows: 260 | \ 261 | \ * &1300-&21FF is moved to &7000-&7EFF in screen memory (i.e. shadow RAM) 262 | \ for the dashboard 263 | \ 264 | \ * &2200-&54FF is moved to &7F00-&B1FF in main memory, where the main 265 | \ game code will decrypt it 266 | \ 267 | \ * The main game code file is loaded into main memory at &1300 and the game 268 | \ is started by jumping to &2C6C 269 | \ 270 | \ The main game code file is called BCODE in the Master release and ELITE in the 271 | \ Master Compact release. BCODE loads into &1300-&7F47, while ELITE loads into 272 | \ &1300-&7FEC. 273 | \ 274 | \ The main game code is then responsible for decrypting BDATA (from &8000 to 275 | \ &B1FF) and BCODE/ELITE (from the end of the DEEOR routine to the end of the 276 | \ file). 277 | \ 278 | \ ****************************************************************************** 279 | 280 | .ENTRY 281 | 282 | LDA #16 \ Call OSBYTE with A = 16 and X = 0 to set the ADC to 283 | LDX #0 \ sample no channels from the joystick/Bitstik 284 | JSR OSBYTE 285 | 286 | IF _COMPACT 287 | 288 | LDA #129 \ Call OSBYTE with A = 129, X = 0 and Y = &FF to detect 289 | LDX #0 \ the machine type. This call is undocumented and is not 290 | LDY #&FF \ the recommended way to determine the machine type 291 | JSR OSBYTE \ (OSBYTE 0 is the correct way), but this call returns 292 | \ the following: 293 | \ 294 | \ * X = Y = &F5 if this is a Master Compact with MOS 5 295 | 296 | LDA #&FF \ Set A = &FF, the value we want to store in the MOS 297 | \ flag if this is not a Master Compact 298 | 299 | CPX #&F5 \ If X <> &F5, skip the following instruction as this is 300 | BNE P%+4 \ a Master Compact 301 | 302 | LDA #0 \ This is a Master Compact, so set A = 0 303 | 304 | STA MOS \ Store the value of A in MOS, which will be 0 if this 305 | \ is a Master Compact, or &FF if it isn't 306 | 307 | ENDIF 308 | 309 | LDA #200 \ Call OSBYTE with A = 200, X = 1 and Y = 0 to disable 310 | LDX #1 \ the ESCAPE key and disable memory clearing if the 311 | JSR OSB \ BREAK key is pressed 312 | 313 | LDA #13 \ Call OSBYTE with A = 13, X = 0 and Y = 0 to disable 314 | LDX #0 \ the "output buffer empty" event 315 | JSR OSB 316 | 317 | LDA #144 \ Call OSBYTE with A = 144, X = 255 and Y = 0 to move 318 | LDX #255 \ the screen down one line and turn screen interlace on 319 | LDY #0 320 | JSR OSBYTE 321 | 322 | LDA #144 \ Repeat the above command, which has the effect of 323 | LDX #255 \ setting the interlace to the original value, as the 324 | JSR OSBYTE \ OSBYTE call above returns the original setting in Y 325 | 326 | LDA #225 \ Call OSBYTE with A = 225, X = 128 and Y = 0 to set 327 | LDX #128 \ the function keys to return ASCII codes for SHIFT-fn 328 | JSR OSB \ keys (i.e. add 128) 329 | 330 | LDA #13 \ Call OSBYTE with A = 13, X = 2 and Y = 0 to disable 331 | LDX #2 \ the "character entering buffer" event 332 | JSR OSB 333 | 334 | LDA #LO(B%) \ Set ZP(1 0) to point to the VDU code table at B% 335 | STA ZP 336 | LDA #HI(B%) 337 | STA ZP+1 338 | 339 | LDY #0 \ We are now going to send the N% VDU bytes in the table 340 | \ at B% to OSWRCH to set up the special mode 1 screen 341 | \ that forms the basis for the split-screen mode 342 | 343 | .LOOP 344 | 345 | LDA (ZP),Y \ Pass the Y-th byte of the B% table to OSWRCH 346 | JSR OSWRCH 347 | 348 | INY \ Increment the loop counter 349 | 350 | CPY #N% \ Loop back for the next byte until we have done them 351 | BNE LOOP \ all (the number of bytes was set in N% above) 352 | 353 | LDA #%00001111 \ Set the Access Control latch at SHEILA &34, as 354 | STA VIA+&34 \ follows: 355 | \ 356 | \ * Bit 7 = IRR = 0: Do not IRQ the CPU with this 357 | \ * Bit 6 = TST = 0: Must be set to 0 358 | \ * Bit 5 = IFJ = 0: &FC00-&FDFF maps to the 1Mhz bus 359 | \ * Bit 4 = ITU = 0: CPU can access external co-pro 360 | \ * Bit 3 = Y = 1: &C000-&DFFF set to 8K private RAM 361 | \ * Bit 2 = X = 1: &3000-&7FFF set to 20K shadow RAM 362 | \ * Bit 1 = E = 1: All shadow RAM locations accessible 363 | \ * Bit 0 = D = 1: Display shadow RAM as screen memory 364 | \ 365 | \ In short, this switches the screen memory, which is in 366 | \ shadow RAM, into the memory map at &3000-&7FFF, so now 367 | \ we can poke directly to the screen memory, and it also 368 | \ maps the filing system RAM space into &C000-&DFFF 369 | \ (HAZEL), in place of the MOS VDU workspace 370 | 371 | JSR PLL1 \ Call PLL1 to draw Saturn 372 | 373 | LDA #%00001001 \ Clear bits 1 and 2 of the Access Control latch at 374 | STA VIA+&34 \ SHEILA &34, which changes the following: 375 | \ 376 | \ * Bit 2 = X = 0: &3000-&7FFF set to main RAM 377 | \ * Bit 1 = E = 0: VDU shadow RAM locations accessible 378 | \ 379 | \ In short, this switches the screen memory, which is in 380 | \ shadow RAM, out of the memory map, so &3000-&7FFF is 381 | \ now mapped to main RAM and we can't update the screen 382 | 383 | LDA #4 \ Call OSBYTE with A = 4, X = 1 and Y = 0 to disable 384 | LDX #1 \ cursor editing, so the cursor keys return ASCII values 385 | JSR OSB \ and can therefore be used in-game 386 | 387 | LDA #9 \ Call OSBYTE with A = 9, X = 0 and Y = 0 to disable 388 | LDX #0 \ flashing colours 389 | JSR OSB 390 | 391 | LDX #LO(MESS1) \ Set (Y X) to point to MESS1 ("L.BDATA FFFF1300") 392 | LDY #HI(MESS1) 393 | 394 | JSR OSCLI \ Call OSCLI to run the OS command in MESS1, which 395 | \ loads the BDATA file to address &1300-&54FF, appending 396 | \ &FFFF to the address to make sure it loads in the main 397 | \ BBC Master rather than getting passed across the Tube 398 | \ to the Second Processor, if one is fitted 399 | 400 | LDA #6 \ Set the RAM copy of the currently selected paged ROM 401 | STA LATCH \ to 6, so it matches the paged ROM selection latch at 402 | \ SHEILA &30 that we are about to set 403 | 404 | LDA VIA+&30 \ Set bits 0-3 of the ROM Select latch at SHEILA &30 to 405 | AND #%11110000 \ 6, to switch sideways RAM bank 6 into &8000-&BFFF in 406 | ORA #6 \ main memory 407 | STA VIA+&30 408 | 409 | LDA #%10101010 \ Set A and location &8000 to %10101010 410 | STA &8000 411 | 412 | LSR A \ Shift A and location &8000 right 413 | LSR &8000 414 | 415 | CMP &8000 \ If A matches location &8000 (i.e. both now contain 416 | BEQ OK \ %01010101) then jump to OK, as ROM bank 6 is writable 417 | \ and does indeed contain sideways RAM rather than a 418 | \ paged ROM, which is what we need for running the game 419 | 420 | BRK \ Otherwise we can't run the game, so terminate the 421 | \ loader with the following error message 422 | 423 | EQUB 0 \ Error number 424 | 425 | EQUB 22, 7 \ Switch to mode 7 and clear the screen 426 | 427 | EQUS "ELITE needs RAM in slot #6" 428 | 429 | EQUB 0 \ End of error message 430 | 431 | .OK 432 | 433 | LDA #%00001111 \ Set bits 1 and 2 of the Access Control Register at 434 | STA VIA+&34 \ SHEILA &34 to switch screen memory into &3000-&7FFF 435 | 436 | \ We now want to copy &F pages of memory (&F00 bytes) 437 | \ from &1300-&21FF to &7000-&7EFF in screen memory 438 | 439 | LDX #&F \ Set a page counter in X to copy &F pages 440 | 441 | LDA #&13 \ Set ZP(1 0) = &1300 442 | STA ZP+1 443 | STZ ZP 444 | 445 | STZ P \ Set P(1 0) = &7000 446 | LDA #&70 447 | STA P+1 448 | 449 | LDY #0 \ Set Y = 0 to act as a byte counter within each page 450 | 451 | .MPL1 452 | 453 | LDA (ZP),Y \ Copy the Y-th byte of the memory block at ZP(1 0) to 454 | STA (P),Y \ the Y-th byte of the memory block at P(1 0) 455 | 456 | DEY \ Decrement the byte counter 457 | 458 | BNE MPL1 \ Loop back to copy the next byte until we have copied a 459 | \ whole page of 256 bytes 460 | 461 | INC ZP+1 \ Increment the high bytes of both ZP(1 0) and P(1 0) 462 | INC P+1 \ so we copy the next page in memory 463 | 464 | DEX \ Decrement the page counter 465 | 466 | BNE MPL1 \ Loop back to copy the next page until we have done all 467 | \ &F of them 468 | 469 | LDA #%00001001 \ Clear bits 1 and 2 of the Access Control Register at 470 | STA VIA+&34 \ SHEILA &34 to switch main memory back into &3000-&7FFF 471 | 472 | \ We now want to copy &33 pages of memory (&3300 bytes) 473 | \ from &2200-&54FF to &7F00-&B1FF in main memory 474 | 475 | LDX #&33 \ Set a page counter in X to copy &33 pages 476 | 477 | .MPL2 478 | 479 | LDA (ZP),Y \ Copy the Y-th byte of the memory block at ZP(1 0) to 480 | STA (P),Y \ the Y-th byte of the memory block at P(1 0) 481 | 482 | DEY \ Decrement the byte counter 483 | 484 | BNE MPL2 \ Loop back to copy the next byte until we have copied a 485 | \ whole page of 256 bytes 486 | 487 | INC ZP+1 \ Increment the high bytes of both ZP(1 0) and P(1 0) 488 | INC P+1 \ so we copy the next page in memory 489 | 490 | DEX \ Decrement the page counter 491 | 492 | BNE MPL2 \ Loop back to copy the next page until we have done all 493 | \ &33 of them 494 | 495 | CLI \ Enable interrupts 496 | 497 | LDX #LO(MESS2) \ Set (Y X) to point to MESS2 ("L.BCODE FFFF1300" in the 498 | LDY #HI(MESS2) \ Master release, or "L.ELITE FFFF1300" in the Master 499 | \ Compact release) 500 | 501 | JSR OSCLI \ Call OSCLI to run the OS command in MESS2, which loads 502 | \ the BCODE/ELITE file to address &1300-&7F48, appending 503 | \ &FFFF to the address to make sure it loads in the main 504 | \ BBC Master rather than getting passed across the Tube 505 | \ to the Second Processor, if one is fitted 506 | 507 | LDX #LO(MESS3) \ Set (Y X) to point to MESS3 ("DIR E") 508 | LDY #HI(MESS3) 509 | 510 | JSR OSCLI \ Call OSCLI to run the OS command in MESS3, which 511 | \ changes the disc directory to E 512 | 513 | LDA #6 \ Set the RAM copy of the currently selected paged ROM 514 | STA LATCH \ to 6, so it matches the paged ROM selection latch at 515 | \ SHEILA &30 that we are about to set 516 | 517 | LDA VIA+&30 \ Switch ROM bank 6 into memory by setting bits 0-3 of 518 | AND #%11110000 \ the ROM selection latch at SHEILA &30 to 6 519 | ORA #6 520 | STA VIA+&30 521 | 522 | JMP S% \ Jump to the start of the main game code at S%, which 523 | \ we just loaded in the BCODE/ELITE file 524 | 525 | \ ****************************************************************************** 526 | \ 527 | \ Name: PLL1 (Part 1 of 3) 528 | \ Type: Subroutine 529 | \ Category: Drawing planets 530 | \ Summary: Draw Saturn on the loading screen (draw the planet) 531 | \ Deep dive: Drawing Saturn on the loading screen 532 | \ 533 | \ ****************************************************************************** 534 | 535 | .PLL1 536 | 537 | \ The following loop iterates CNT(1 0) times, i.e. &300 538 | \ or 768 times, and draws the planet part of the 539 | \ loading screen's Saturn 540 | 541 | STA RAND+1 \ Store A in RAND+1 among the hard-coded random seeds 542 | \ in RAND. We set A to %00001111 before calling the PLL1 543 | \ routine, so this sets the random number generator so 544 | \ that it always generates the same numbers every time, 545 | \ which is probably not what was intended (other 546 | \ versions read the 6522 System VIA timer to use as a 547 | \ seed, which is random). As a result, if you look at 548 | \ the Saturn on the Master loading screen, it is always 549 | \ exactly the same, every time you run the game 550 | 551 | JSR DORND \ Set A and X to random numbers, say A = r1 552 | 553 | JSR SQUA2 \ Set (A P) = A * A 554 | \ = r1^2 555 | 556 | STA ZP+1 \ Set ZP(1 0) = (A P) 557 | LDA P \ = r1^2 558 | STA ZP 559 | 560 | JSR DORND \ Set A and X to random numbers, say A = r2 561 | 562 | STA YY \ Set YY = A 563 | \ = r2 564 | 565 | JSR SQUA2 \ Set (A P) = A * A 566 | \ = r2^2 567 | 568 | TAX \ Set (X P) = (A P) 569 | \ = r2^2 570 | 571 | LDA P \ Set (A ZP) = (X P) + ZP(1 0) 572 | ADC ZP \ 573 | STA ZP \ first adding the low bytes 574 | 575 | TXA \ And then adding the high bytes 576 | ADC ZP+1 577 | 578 | BCS PLC1 \ If the addition overflowed, jump down to PLC1 to skip 579 | \ to the next pixel 580 | 581 | STA ZP+1 \ Set ZP(1 0) = (A ZP) 582 | \ = r1^2 + r2^2 583 | 584 | LDA #1 \ Set ZP(1 0) = &4001 - ZP(1 0) - (1 - C) 585 | SBC ZP \ = 128^2 - ZP(1 0) 586 | STA ZP \ 587 | \ (as the C flag is clear), first subtracting the low 588 | \ bytes 589 | 590 | LDA #&40 \ And then subtracting the high bytes 591 | SBC ZP+1 592 | STA ZP+1 593 | 594 | BCC PLC1 \ If the subtraction underflowed, jump down to PLC1 to 595 | \ skip to the next pixel 596 | 597 | \ If we get here, then both calculations fitted into 598 | \ 16 bits, and we have: 599 | \ 600 | \ ZP(1 0) = 128^2 - (r1^2 + r2^2) 601 | \ 602 | \ where ZP(1 0) >= 0 603 | 604 | JSR ROOT \ Set ZP = SQRT(ZP(1 0)) 605 | 606 | LDA ZP \ Set X = ZP >> 1 607 | LSR A \ = SQRT(128^2 - (a^2 + b^2)) / 2 608 | TAX 609 | 610 | LDA YY \ Set A = YY 611 | \ = r2 612 | 613 | CMP #128 \ If YY >= 128, set the C flag (so the C flag is now set 614 | \ to bit 7 of A) 615 | 616 | ROR A \ Rotate A and set the sign bit to the C flag, so bits 617 | \ 6 and 7 are now the same, i.e. A is a random number in 618 | \ one of these ranges: 619 | \ 620 | \ %00000000 - %00111111 = 0 to 63 (r2 = 0 - 127) 621 | \ %11000000 - %11111111 = 192 to 255 (r2 = 128 - 255) 622 | \ 623 | \ The PIX routine flips bit 7 of A before drawing, and 624 | \ that makes -A in these ranges: 625 | \ 626 | \ %10000000 - %10111111 = 128-191 627 | \ %01000000 - %01111111 = 64-127 628 | \ 629 | \ so that's in the range 64 to 191 630 | 631 | JSR PIX \ Draw a pixel at screen coordinate (X, -A), i.e. at 632 | \ 633 | \ (ZP / 2, -A) 634 | \ 635 | \ where ZP = SQRT(128^2 - (r1^2 + r2^2)) 636 | \ 637 | \ So this is the same as plotting at (x, y) where: 638 | \ 639 | \ r1 = random number from 0 to 255 640 | \ r2 = random number from 0 to 255 641 | \ (r1^2 + r2^2) < 128^2 642 | \ 643 | \ y = r2, squished into 64 to 191 by negation 644 | \ 645 | \ x = SQRT(128^2 - (r1^2 + r2^2)) / 2 646 | \ 647 | \ which is what we want 648 | 649 | .PLC1 650 | 651 | DEC CNT \ Decrement the counter in CNT (the low byte) 652 | 653 | BNE PLL1 \ Loop back to PLL1 until CNT = 0 654 | 655 | DEC CNT+1 \ Decrement the counter in CNT+1 (the high byte) 656 | 657 | BNE PLL1 \ Loop back to PLL1 until CNT+1 = 0 658 | 659 | \ ****************************************************************************** 660 | \ 661 | \ Name: PLL1 (Part 2 of 3) 662 | \ Type: Subroutine 663 | \ Category: Drawing planets 664 | \ Summary: Draw Saturn on the loading screen (draw the stars) 665 | \ Deep dive: Drawing Saturn on the loading screen 666 | \ 667 | \ ****************************************************************************** 668 | 669 | \ The following loop iterates CNT2(1 0) times, i.e. &1DD 670 | \ or 477 times, and draws the background stars on the 671 | \ loading screen 672 | 673 | .PLL2 674 | 675 | JSR DORND \ Set A and X to random numbers, say A = r3 676 | 677 | TAX \ Set X = A 678 | \ = r3 679 | 680 | JSR SQUA2 \ Set (A P) = A * A 681 | \ = r3^2 682 | 683 | STA ZP+1 \ Set ZP+1 = A 684 | \ = r3^2 / 256 685 | 686 | JSR DORND \ Set A and X to random numbers, say A = r4 687 | 688 | STA YY \ Set YY = r4 689 | 690 | JSR SQUA2 \ Set (A P) = A * A 691 | \ = r4^2 692 | 693 | ADC ZP+1 \ Set A = A + r3^2 / 256 694 | \ = r4^2 / 256 + r3^2 / 256 695 | \ = (r3^2 + r4^2) / 256 696 | 697 | CMP #&11 \ If A < 17, jump down to PLC2 to skip to the next pixel 698 | BCC PLC2 699 | 700 | LDA YY \ Set A = r4 701 | 702 | JSR PIX \ Draw a pixel at screen coordinate (X, -A), i.e. at 703 | \ (r3, -r4), where (r3^2 + r4^2) / 256 >= 17 704 | \ 705 | \ Negating a random number from 0 to 255 still gives a 706 | \ random number from 0 to 255, so this is the same as 707 | \ plotting at (x, y) where: 708 | \ 709 | \ x = random number from 0 to 255 710 | \ y = random number from 0 to 255 711 | \ HI(x^2 + y^2) >= 17 712 | \ 713 | \ which is what we want 714 | 715 | .PLC2 716 | 717 | DEC CNT2 \ Decrement the counter in CNT2 (the low byte) 718 | 719 | BNE PLL2 \ Loop back to PLL2 until CNT2 = 0 720 | 721 | DEC CNT2+1 \ Decrement the counter in CNT2+1 (the high byte) 722 | 723 | BNE PLL2 \ Loop back to PLL2 until CNT2+1 = 0 724 | 725 | \ ****************************************************************************** 726 | \ 727 | \ Name: PLL1 (Part 3 of 3) 728 | \ Type: Subroutine 729 | \ Category: Drawing planets 730 | \ Summary: Draw Saturn on the loading screen (draw the rings) 731 | \ Deep dive: Drawing Saturn on the loading screen 732 | \ 733 | \ ****************************************************************************** 734 | 735 | \ The following loop iterates CNT3(1 0) times, i.e. &333 736 | \ or 819 times, and draws the rings around the loading 737 | \ screen's Saturn 738 | 739 | .PLL3 740 | 741 | JSR DORND \ Set A and X to random numbers, say A = r5 742 | 743 | STA ZP \ Set ZP = r5 744 | 745 | JSR SQUA2 \ Set (A P) = A * A 746 | \ = r5^2 747 | 748 | STA ZP+1 \ Set ZP+1 = A 749 | \ = r5^2 / 256 750 | 751 | JSR DORND \ Set A and X to random numbers, say A = r6 752 | 753 | STA YY \ Set YY = r6 754 | 755 | JSR SQUA2 \ Set (A P) = A * A 756 | \ = r6^2 757 | 758 | STA T \ Set T = A 759 | \ = r6^2 / 256 760 | 761 | ADC ZP+1 \ Set ZP+1 = A + r5^2 / 256 762 | STA ZP+1 \ = r6^2 / 256 + r5^2 / 256 763 | \ = (r5^2 + r6^2) / 256 764 | 765 | LDA ZP \ Set A = ZP 766 | \ = r5 767 | 768 | CMP #128 \ If A >= 128, set the C flag (so the C flag is now set 769 | \ to bit 7 of ZP, i.e. bit 7 of A) 770 | 771 | ROR A \ Rotate A and set the sign bit to the C flag, so bits 772 | \ 6 and 7 are now the same 773 | 774 | CMP #128 \ If A >= 128, set the C flag (so again, the C flag is 775 | \ set to bit 7 of A) 776 | 777 | ROR A \ Rotate A and set the sign bit to the C flag, so bits 778 | \ 5-7 are now the same, i.e. A is a random number in one 779 | \ of these ranges: 780 | \ 781 | \ %00000000 - %00011111 = 0-31 782 | \ %11100000 - %11111111 = 224-255 783 | \ 784 | \ In terms of signed 8-bit integers, this is a random 785 | \ number from -32 to 31. Let's call it r7 786 | 787 | ADC YY \ Set A = A + YY 788 | \ = r7 + r6 789 | 790 | TAX \ Set X = A 791 | \ = r6 + r7 792 | 793 | JSR SQUA2 \ Set (A P) = A * A 794 | \ = (r6 + r7)^2 795 | 796 | TAY \ Set Y = A 797 | \ = (r6 + r7)^2 / 256 798 | 799 | ADC ZP+1 \ Set A = A + ZP+1 800 | \ = (r6 + r7)^2 / 256 + (r5^2 + r6^2) / 256 801 | \ = ((r6 + r7)^2 + r5^2 + r6^2) / 256 802 | 803 | BCS PLC3 \ If the addition overflowed, jump down to PLC3 to skip 804 | \ to the next pixel 805 | 806 | CMP #80 \ If A >= 80, jump down to PLC3 to skip to the next 807 | BCS PLC3 \ pixel 808 | 809 | CMP #32 \ If A < 32, jump down to PLC3 to skip to the next pixel 810 | BCC PLC3 811 | 812 | TYA \ Set A = Y + T 813 | ADC T \ = (r6 + r7)^2 / 256 + r6^2 / 256 814 | \ = ((r6 + r7)^2 + r6^2) / 256 815 | 816 | CMP #16 \ If A >= 16, skip to PL1 to plot the pixel 817 | BCS PL1 818 | 819 | LDA ZP \ If ZP is positive (i.e. r5 < 128), jump down to PLC3 820 | BPL PLC3 \ to skip to the next pixel 821 | 822 | .PL1 823 | 824 | \ If we get here then the following is true: 825 | \ 826 | \ 32 <= ((r6 + r7)^2 + r5^2 + r6^2) / 256 < 80 827 | \ 828 | \ and either this is true: 829 | \ 830 | \ ((r6 + r7)^2 + r6^2) / 256 >= 16 831 | \ 832 | \ or both these are true: 833 | \ 834 | \ ((r6 + r7)^2 + r6^2) / 256 < 16 835 | \ r5 >= 128 836 | 837 | LDA YY \ Set A = YY 838 | \ = r6 839 | 840 | JSR PIX \ Draw a pixel at screen coordinate (X, -A), where: 841 | \ 842 | \ X = (random -32 to 31) + r6 843 | \ A = r6 844 | \ 845 | \ Negating a random number from 0 to 255 still gives a 846 | \ random number from 0 to 255, so this is the same as 847 | \ plotting at (x, y) where: 848 | \ 849 | \ r5 = random number from 0 to 255 850 | \ r6 = random number from 0 to 255 851 | \ r7 = r5, squashed into -32 to 31 852 | \ 853 | \ x = r6 + r7 854 | \ y = r6 855 | \ 856 | \ 32 <= ((r6 + r7)^2 + r5^2 + r6^2) / 256 < 80 857 | \ 858 | \ Either: ((r6 + r7)^2 + r6^2) / 256 >= 16 859 | \ 860 | \ Or: ((r6 + r7)^2 + r6^2) / 256 < 16 861 | \ r5 >= 128 862 | \ 863 | \ which is what we want 864 | 865 | .PLC3 866 | 867 | DEC CNT3 \ Decrement the counter in CNT3 (the low byte) 868 | 869 | BNE PLL3 \ Loop back to PLL3 until CNT3 = 0 870 | 871 | DEC CNT3+1 \ Decrement the counter in CNT3+1 (the high byte) 872 | 873 | BNE PLL3 \ Loop back to PLL3 until CNT3+1 = 0 874 | 875 | \ ****************************************************************************** 876 | \ 877 | \ Name: DORND 878 | \ Type: Subroutine 879 | \ Category: Maths (Arithmetic) 880 | \ Summary: Generate random numbers 881 | \ Deep dive: Generating random numbers 882 | \ Fixing ship positions 883 | \ 884 | \ ------------------------------------------------------------------------------ 885 | \ 886 | \ Set A and X to random numbers (though note that X is set to the random number 887 | \ that was returned in A the last time DORND was called). 888 | \ 889 | \ The C and V flags are also set randomly. 890 | \ 891 | \ This is a simplified version of the DORND routine in the main game code. It 892 | \ swaps the two calculations around and omits the ROL A instruction, but is 893 | \ otherwise very similar. See the DORND routine in the main game code for more 894 | \ details. 895 | \ 896 | \ ****************************************************************************** 897 | 898 | .DORND 899 | 900 | LDA RAND+1 \ r1´ = r1 + r3 + C 901 | TAX \ r3´ = r1 902 | ADC RAND+3 903 | STA RAND+1 904 | STX RAND+3 905 | 906 | LDA RAND \ X = r2´ = r0 907 | TAX \ A = r0´ = r0 + r2 908 | ADC RAND+2 909 | STA RAND 910 | STX RAND+2 911 | 912 | RTS \ Return from the subroutine 913 | 914 | \ ****************************************************************************** 915 | \ 916 | \ Name: RAND 917 | \ Type: Variable 918 | \ Category: Drawing planets 919 | \ Summary: The random number seed used for drawing Saturn 920 | \ 921 | \ ****************************************************************************** 922 | 923 | .RAND 924 | 925 | EQUD &34785349 926 | 927 | \ ****************************************************************************** 928 | \ 929 | \ Name: SQUA2 930 | \ Type: Subroutine 931 | \ Category: Maths (Arithmetic) 932 | \ Summary: Calculate (A P) = A * A 933 | \ Deep dive: Shift-and-add multiplication 934 | \ 935 | \ ------------------------------------------------------------------------------ 936 | \ 937 | \ Do the following multiplication of signed 8-bit numbers: 938 | \ 939 | \ (A P) = A * A 940 | \ 941 | \ This uses a similar approach to routine SQUA2 in the main game code, which 942 | \ itself uses the MU11 routine to do the multiplication. However, this version 943 | \ first ensures that A is positive, so it can support signed numbers. 944 | \ 945 | \ ****************************************************************************** 946 | 947 | .SQUA2 948 | 949 | BPL SQUA \ If A > 0, jump to SQUA 950 | 951 | EOR #&FF \ Otherwise we need to negate A for the SQUA algorithm 952 | CLC \ to work, so we do this using two's complement, by 953 | ADC #1 \ setting A = ~A + 1 954 | 955 | .SQUA 956 | 957 | STA Q \ Set Q = A and P = A 958 | 959 | STA P \ Set P = A 960 | 961 | LDA #0 \ Set A = 0 so we can start building the answer in A 962 | 963 | LDY #8 \ Set up a counter in Y to count the 8 bits in P 964 | 965 | LSR P \ Set P = P >> 1 966 | \ and C flag = bit 0 of P 967 | 968 | .SQL1 969 | 970 | BCC SQ1 \ If C (i.e. the next bit from P) is set, do the 971 | CLC \ addition for this bit of P: 972 | ADC Q \ 973 | \ A = A + Q 974 | 975 | .SQ1 976 | 977 | ROR A \ Shift A right to catch the next digit of our result, 978 | \ which the next ROR sticks into the left end of P while 979 | \ also extracting the next bit of P 980 | 981 | ROR P \ Add the overspill from shifting A to the right onto 982 | \ the start of P, and shift P right to fetch the next 983 | \ bit for the calculation into the C flag 984 | 985 | DEY \ Decrement the loop counter 986 | 987 | BNE SQL1 \ Loop back for the next bit until P has been rotated 988 | \ all the way 989 | 990 | RTS \ Return from the subroutine 991 | 992 | \ ****************************************************************************** 993 | \ 994 | \ Name: PIX 995 | \ Type: Subroutine 996 | \ Category: Drawing pixels 997 | \ Summary: Draw a single pixel at a specific coordinate 998 | \ 999 | \ ------------------------------------------------------------------------------ 1000 | \ 1001 | \ Draw a pixel at screen coordinate (X, -A). The sign bit of A gets flipped 1002 | \ before drawing, and then the routine uses the same approach as the PIXEL 1003 | \ routine in the main game code, except it plots a single pixel from TWOS 1004 | \ instead of a two pixel dash from TWOS2. This applies to the top part of the 1005 | \ screen (the four-colour mode 1 space view). 1006 | \ 1007 | \ See the PIXEL routine in the main game code for more details. 1008 | \ 1009 | \ ------------------------------------------------------------------------------ 1010 | \ 1011 | \ Arguments: 1012 | \ 1013 | \ X The screen x-coordinate of the pixel to draw 1014 | \ 1015 | \ A The screen y-coordinate of the pixel to draw, negated 1016 | \ 1017 | \ ****************************************************************************** 1018 | 1019 | .PIX 1020 | 1021 | TAY \ Copy A into Y, for use later 1022 | 1023 | EOR #%10000000 \ Flip the sign of A 1024 | 1025 | LSR A \ Set ZP+1 = &40 + 2 * (A >> 3) 1026 | LSR A 1027 | LSR A 1028 | ASL A 1029 | ORA #&40 1030 | STA ZP+1 1031 | 1032 | TXA \ Set (C ZP) = (X >> 2) * 8 1033 | EOR #%10000000 \ 1034 | AND #%11111100 \ i.e. the C flag contains bit 8 of the calculation 1035 | ASL A 1036 | STA ZP 1037 | 1038 | BCC P%+4 \ If the C flag is set, i.e. bit 8 of the above 1039 | INC ZP+1 \ calculation was a 1, increment ZP+1 so that ZP(1 0) 1040 | \ points to the second page in this character row (i.e. 1041 | \ the right half of the row) 1042 | 1043 | TYA \ Set Y = Y mod 8, which is the pixel row within the 1044 | AND #7 \ character block at which we want to draw our pixel 1045 | TAY \ (as each character block has 8 rows) 1046 | 1047 | TXA \ Set X = X mod 8, which is the horizontal pixel number 1048 | AND #7 \ within the character block where the pixel lies (as 1049 | TAX \ each pixel line in the character block is 8 pixels 1050 | \ wide) 1051 | 1052 | LDA TWOS,X \ Fetch a pixel from TWOS and poke it into ZP+Y 1053 | STA (ZP),Y 1054 | 1055 | RTS \ Return from the subroutine 1056 | 1057 | \ ****************************************************************************** 1058 | \ 1059 | \ Name: TWOS 1060 | \ Type: Variable 1061 | \ Category: Drawing pixels 1062 | \ Summary: Ready-made single-pixel character row bytes for mode 1 1063 | \ 1064 | \ ------------------------------------------------------------------------------ 1065 | \ 1066 | \ Ready-made bytes for plotting one-pixel points in mode 1 (the top part of the 1067 | \ split screen). See the PIX routine for details. 1068 | \ 1069 | \ ****************************************************************************** 1070 | 1071 | .TWOS 1072 | 1073 | EQUB %10000000 1074 | EQUB %01000000 1075 | EQUB %00100000 1076 | EQUB %00010000 1077 | EQUB %00001000 1078 | EQUB %00000100 1079 | EQUB %00000010 1080 | EQUB %00000001 1081 | 1082 | \ ****************************************************************************** 1083 | \ 1084 | \ Name: CNT 1085 | \ Type: Variable 1086 | \ Category: Drawing planets 1087 | \ Summary: A counter for use in drawing Saturn's planetary body 1088 | \ 1089 | \ ------------------------------------------------------------------------------ 1090 | \ 1091 | \ Defines the number of iterations of the PLL1 loop, which draws the planet part 1092 | \ of the loading screen's Saturn. 1093 | \ 1094 | \ ****************************************************************************** 1095 | 1096 | .CNT 1097 | 1098 | EQUW &0300 \ The number of iterations of the PLL1 loop (768) 1099 | 1100 | \ ****************************************************************************** 1101 | \ 1102 | \ Name: CNT2 1103 | \ Type: Variable 1104 | \ Category: Drawing planets 1105 | \ Summary: A counter for use in drawing Saturn's background stars 1106 | \ 1107 | \ ------------------------------------------------------------------------------ 1108 | \ 1109 | \ Defines the number of iterations of the PLL2 loop, which draws the background 1110 | \ stars on the loading screen. 1111 | \ 1112 | \ ****************************************************************************** 1113 | 1114 | .CNT2 1115 | 1116 | EQUW &01DD \ The number of iterations of the PLL2 loop (477) 1117 | 1118 | \ ****************************************************************************** 1119 | \ 1120 | \ Name: CNT3 1121 | \ Type: Variable 1122 | \ Category: Drawing planets 1123 | \ Summary: A counter for use in drawing Saturn's rings 1124 | \ 1125 | \ ------------------------------------------------------------------------------ 1126 | \ 1127 | \ Defines the number of iterations of the PLL3 loop, which draws the rings 1128 | \ around the loading screen's Saturn. 1129 | \ 1130 | \ ****************************************************************************** 1131 | 1132 | .CNT3 1133 | 1134 | EQUW &0333 \ The number of iterations of the PLL3 loop (819) 1135 | 1136 | \ ****************************************************************************** 1137 | \ 1138 | \ Name: ROOT 1139 | \ Type: Subroutine 1140 | \ Category: Maths (Arithmetic) 1141 | \ Summary: Calculate ZP = SQRT(ZP(1 0)) 1142 | \ 1143 | \ ------------------------------------------------------------------------------ 1144 | \ 1145 | \ Calculate the following square root: 1146 | \ 1147 | \ ZP = SQRT(ZP(1 0)) 1148 | \ 1149 | \ This routine is identical to LL5 in the main game code - it even has the same 1150 | \ label names. The only difference is that LL5 calculates Q = SQRT(R Q), but 1151 | \ apart from the variables used, the instructions are identical, so see the LL5 1152 | \ routine in the main game code for more details on the algorithm used here. 1153 | \ 1154 | \ ****************************************************************************** 1155 | 1156 | .ROOT 1157 | 1158 | LDY ZP+1 \ Set (Y Q) = ZP(1 0) 1159 | LDA ZP 1160 | STA Q 1161 | 1162 | \ So now to calculate ZP = SQRT(Y Q) 1163 | 1164 | LDX #0 \ Set X = 0, to hold the remainder 1165 | 1166 | STX ZP \ Set ZP = 0, to hold the result 1167 | 1168 | LDA #8 \ Set P = 8, to use as a loop counter 1169 | STA P 1170 | 1171 | .LL6 1172 | 1173 | CPX ZP \ If X < ZP, jump to LL7 1174 | BCC LL7 1175 | 1176 | BNE LL8 \ If X > ZP, jump to LL8 1177 | 1178 | CPY #64 \ If Y < 64, jump to LL7 with the C flag clear, 1179 | BCC LL7 \ otherwise fall through into LL8 with the C flag set 1180 | 1181 | .LL8 1182 | 1183 | TYA \ Set Y = Y - 64 1184 | SBC #64 \ 1185 | TAY \ This subtraction will work as we know C is set from 1186 | \ the BCC above, and the result will not underflow as we 1187 | \ already checked that Y >= 64, so the C flag is also 1188 | \ set for the next subtraction 1189 | 1190 | TXA \ Set X = X - ZP 1191 | SBC ZP 1192 | TAX 1193 | 1194 | .LL7 1195 | 1196 | ROL ZP \ Shift the result in Q to the left, shifting the C flag 1197 | \ into bit 0 and bit 7 into the C flag 1198 | 1199 | ASL Q \ Shift the dividend in (Y S) to the left, inserting 1200 | TYA \ bit 7 from above into bit 0 1201 | ROL A 1202 | TAY 1203 | 1204 | TXA \ Shift the remainder in X to the left 1205 | ROL A 1206 | TAX 1207 | 1208 | ASL Q \ Shift the dividend in (Y S) to the left 1209 | TYA 1210 | ROL A 1211 | TAY 1212 | 1213 | TXA \ Shift the remainder in X to the left 1214 | ROL A 1215 | TAX 1216 | 1217 | DEC P \ Decrement the loop counter 1218 | 1219 | BNE LL6 \ Loop back to LL6 until we have done 8 loops 1220 | 1221 | RTS \ Return from the subroutine 1222 | 1223 | \ ****************************************************************************** 1224 | \ 1225 | \ Name: OSB 1226 | \ Type: Subroutine 1227 | \ Category: Utility routines 1228 | \ Summary: A convenience routine for calling OSBYTE with Y = 0 1229 | \ 1230 | \ ****************************************************************************** 1231 | 1232 | .OSB 1233 | 1234 | LDY #0 \ Call OSBYTE with Y = 0, returning from the subroutine 1235 | JMP OSBYTE \ using a tail call (so we can call OSB to call OSBYTE 1236 | \ for when we know we want Y set to 0) 1237 | 1238 | \ ****************************************************************************** 1239 | \ 1240 | \ Name: MESS1 1241 | \ Type: Variable 1242 | \ Category: Loader 1243 | \ Summary: The OS command string for loading the BDATA binary 1244 | \ 1245 | \ ****************************************************************************** 1246 | 1247 | .MESS1 1248 | 1249 | EQUS "L.BDATA FFFF1300" \ This is short for "*LOAD BDATA FFFF1300" 1250 | EQUB 13 1251 | 1252 | \ ****************************************************************************** 1253 | \ 1254 | \ Name: MESS2 1255 | \ Type: Variable 1256 | \ Category: Loader 1257 | \ Summary: The OS command string for loading the main game code binary 1258 | \ 1259 | \ ****************************************************************************** 1260 | 1261 | .MESS2 1262 | 1263 | IF _SNG47 1264 | 1265 | EQUS "L.BCODE FFFF1300" \ This is short for "*LOAD BCODE FFFF1300" 1266 | EQUB 13 1267 | 1268 | ELIF _COMPACT 1269 | 1270 | EQUS "L.ELITE FFFF1300" \ This is short for "*LOAD ELITE FFFF1300" 1271 | EQUB 13 1272 | 1273 | ENDIF 1274 | 1275 | \ ****************************************************************************** 1276 | \ 1277 | \ Name: MESS3 1278 | \ Type: Variable 1279 | \ Category: Loader 1280 | \ Summary: The OS command string for changing the disc directory to E 1281 | \ 1282 | \ ****************************************************************************** 1283 | 1284 | .MESS3 1285 | 1286 | EQUS "DIR E" 1287 | EQUB 13 1288 | 1289 | \ ****************************************************************************** 1290 | \ 1291 | \ Save M128Elt.bin 1292 | \ 1293 | \ ****************************************************************************** 1294 | 1295 | PRINT "S.M128Elt ", ~CODE%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD% 1296 | SAVE "3-assembled-output/M128Elt.bin", CODE%, P%, LOAD% 1297 | 1298 | -------------------------------------------------------------------------------- /1-source-files/main-sources/elite-readme.asm: -------------------------------------------------------------------------------- 1 | \ ****************************************************************************** 2 | \ 3 | \ BBC MASTER ELITE README SOURCE 4 | \ 5 | \ BBC Master Elite was written by Ian Bell and David Braben and is copyright 6 | \ Acornsoft 1986 7 | \ 8 | \ The code in this file has been reconstructed from a disassembly of the version 9 | \ released on Ian Bell's personal website at http://www.elitehomepage.org/ 10 | \ 11 | \ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes 12 | \ in the documentation are entirely my fault 13 | \ 14 | \ The terminology and notations used in this commentary are explained at 15 | \ https://elite.bbcelite.com/terminology 16 | \ 17 | \ The deep dive articles referred to in this commentary can be found at 18 | \ https://elite.bbcelite.com/deep_dives 19 | \ 20 | \ ------------------------------------------------------------------------------ 21 | \ 22 | \ This source file produces a README file for BBC Master Elite. 23 | \ 24 | \ ------------------------------------------------------------------------------ 25 | \ 26 | \ This source file produces the following binary file: 27 | \ 28 | \ * README.txt 29 | \ 30 | \ ****************************************************************************** 31 | 32 | INCLUDE "1-source-files/main-sources/elite-build-options.asm" 33 | 34 | _SNG47 = (_VARIANT = 1) 35 | _COMPACT = (_VARIANT = 2) 36 | 37 | .readme 38 | 39 | EQUB 10, 13 40 | EQUS "---------------------------------------" 41 | EQUB 10, 13 42 | EQUS "Acornsoft Elite" 43 | EQUB 10, 13 44 | EQUB 10, 13 45 | EQUS "Version: BBC Master" 46 | EQUB 10, 13 47 | 48 | IF _SNG47 49 | 50 | EQUS "Variant: Acornsoft SNG47 release" 51 | EQUB 10, 13 52 | EQUS "Product: Acornsoft SNG47" 53 | EQUB 10, 13 54 | 55 | ELIF _COMPACT 56 | 57 | EQUS "Variant: Master Compact release" 58 | EQUB 10, 13 59 | EQUS "Product: Superior Software" 60 | EQUB 10, 13 61 | 62 | ENDIF 63 | 64 | EQUB 10, 13 65 | EQUS "See www.bbcelite.com for details" 66 | EQUB 10, 13 67 | EQUS "---------------------------------------" 68 | EQUB 10, 13 69 | 70 | SAVE "3-assembled-output/README.txt", readme, P% 71 | 72 | -------------------------------------------------------------------------------- /2-build-files/README.md: -------------------------------------------------------------------------------- 1 | # Build files for the BBC Master version of Elite 2 | 3 | This folder contains support scripts for building the BBC Master version of Elite. 4 | 5 | * [crc32.py](crc32.py) calculates checksums during the verify stage and compares the results with the relevant binaries in the [4-reference-binaries](../4-reference-binaries) folder 6 | 7 | * [elite-checksum.py](elite-checksum.py) adds checksums and encryption to the assembled output 8 | 9 | * [elite-decrypt.py](elite-decrypt.py) decrypts an encrypted game binary by doing the opposite to the elite-checksum.py script (this is not used in the build process, but is useful when trying to decrypt any new releases that might be found) 10 | 11 | It also contains the `make.exe` executable for Windows, plus the required DLL files. 12 | 13 | --- 14 | 15 | Right on, Commanders! 16 | 17 | _Mark Moxon_ -------------------------------------------------------------------------------- /2-build-files/crc32.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # ELITE VERIFICATION SCRIPT 6 | # 7 | # Written by Kieran Connell, extended by Mark Moxon 8 | # 9 | # This script performs checksums on the compiled files from the build process, 10 | # and checks them against the extracted files from the original source disc 11 | # 12 | # ****************************************************************************** 13 | 14 | from __future__ import print_function 15 | import sys 16 | import os 17 | import os.path 18 | import zlib 19 | 20 | 21 | def main(): 22 | if len(sys.argv) <= 2: 23 | # Do CRC on single folder 24 | folder = sys.argv[1] if len(sys.argv) == 2 else "." 25 | names = sorted(os.listdir(folder)) 26 | 27 | print() 28 | print('Checksum Size Filename') 29 | print('------------------------------------------') 30 | 31 | for name in names: 32 | if name.endswith(".bin"): 33 | full_name = os.path.join(folder, name) 34 | if not os.path.isfile(full_name): 35 | continue 36 | with open(full_name, 'rb') as f: 37 | data = f.read() 38 | print('%08x %5d %s' % ( 39 | zlib.crc32(data) & 0xffffffff, 40 | len(data), 41 | full_name) 42 | ) 43 | print() 44 | else: 45 | # Do CRC on two folders 46 | folder1 = sys.argv[1] 47 | names1 = sorted(os.listdir(folder1)) 48 | folder2 = sys.argv[2] 49 | names2 = sorted(os.listdir(folder2)) 50 | names = list(names1) 51 | names.extend(x for x in names2 if x not in names) 52 | 53 | if '4-reference-binaries' in folder1: 54 | src = '[--originals--]' 55 | elif 'output' in folder1: 56 | src = '[---output----]' 57 | else: 58 | src = '[{0: ^13}]'.format(folder1[0:13]).replace(' ', '-') 59 | 60 | if '4-reference-binaries' in folder2: 61 | dest = '[--originals--]' 62 | elif 'output' in folder2: 63 | dest = '[---output----]' 64 | else: 65 | dest = '[{0: ^13}]'.format(folder2[0:13]).replace(' ', '-') 66 | 67 | print('Results for variant: ' + os.path.basename(folder1)) 68 | print(src + ' ' + dest) 69 | print('Checksum Size Checksum Size Match Filename') 70 | print('-----------------------------------------------------------') 71 | 72 | for name in names: 73 | if name.endswith(".bin"): 74 | full_name1 = os.path.join(folder1, name) 75 | full_name2 = os.path.join(folder2, name) 76 | 77 | if name in names1 and name in names2 and os.path.isfile(full_name1) and os.path.isfile(full_name2): 78 | with open(full_name1, 'rb') as f: 79 | data1 = f.read() 80 | with open(full_name2, 'rb') as f: 81 | data2 = f.read() 82 | crc1 = zlib.crc32(data1) & 0xffffffff 83 | crc2 = zlib.crc32(data2) & 0xffffffff 84 | match = ' Yes ' if crc1 == crc2 and len(data1) == len(data2) else ' No ' 85 | print('%08x %5d %08x %5d %s %s' % ( 86 | crc1, 87 | len(data1), 88 | crc2, 89 | len(data2), 90 | match, 91 | name) 92 | ) 93 | elif name in names1 and os.path.isfile(full_name1): 94 | with open(full_name1, 'rb') as f: 95 | data = f.read() 96 | print('%08x %5d %s %s %s %s' % ( 97 | zlib.crc32(data) & 0xffffffff, 98 | len(data), 99 | '- ', 100 | ' -', 101 | ' - ', 102 | name) 103 | ) 104 | elif name in names2 and os.path.isfile(full_name2): 105 | with open(full_name2, 'rb') as f: 106 | data = f.read() 107 | print('%s %s %08x %5d %s %s' % ( 108 | '- ', 109 | ' -', 110 | zlib.crc32(data) & 0xffffffff, 111 | len(data), 112 | ' - ', 113 | name) 114 | ) 115 | print() 116 | 117 | 118 | if __name__ == '__main__': 119 | main() 120 | -------------------------------------------------------------------------------- /2-build-files/elite-checksum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # BBC MASTER ELITE CHECKSUM SCRIPT 6 | # 7 | # Written by Mark Moxon, and inspired by Kieran Connell's version for the 8 | # cassette version of Elite 9 | # 10 | # This script applies encryption and checksums to the compiled binary for the 11 | # main parasite game code. It reads the unencrypted "BCODE.unprot.bin" and 12 | # "BDATA.unprot.bin" binaries and generates encrypted versions as "BCODE.bin" 13 | # and "BDATA.bin" 14 | # 15 | # ****************************************************************************** 16 | 17 | from __future__ import print_function 18 | import sys 19 | 20 | argv = sys.argv 21 | encrypt = True 22 | release = 1 23 | 24 | for arg in argv[1:]: 25 | if arg == "-u": 26 | encrypt = False 27 | if arg == "-rel1": 28 | release = 1 29 | if arg == "-rel2": 30 | release = 2 31 | 32 | print("Master Elite Checksum") 33 | print("Encryption = ", encrypt) 34 | 35 | # Configuration variables for scrambling code and calculating checksums 36 | # 37 | # Values must match those in 3-assembled-output/compile.txt 38 | # 39 | # If you alter the source code, then you should extract the correct values for 40 | # the following variables and plug them into the following, otherwise the game 41 | # will fail the checksum process and will hang on loading 42 | # 43 | # You can find the correct values for these variables by building your updated 44 | # source, and then searching compile.txt for "elite-checksum.py", where the new 45 | # values will be listed 46 | 47 | if release == 1: 48 | # SNG47 49 | f = 0x7F48 # F% 50 | scramble_from = 0x2CC1 # G% 51 | na2_per_cent = 0x34CD # NA2% 52 | elif release == 2: 53 | # Compact 54 | f = 0x7FED # F% 55 | scramble_from = 0x2CC1 # G% 56 | na2_per_cent = 0x34CD # NA2% 57 | 58 | # Configuration variables for BCODE 59 | 60 | load_address = 0x1300 61 | seed = 0x19 62 | 63 | if release == 1: 64 | # SNG47 65 | scramble_to = f - 1 66 | elif release == 2: 67 | # Compact 68 | scramble_to = f - 1 69 | 70 | # Load assembled code file for BCODE 71 | 72 | data_block = bytearray() 73 | 74 | elite_file = open("3-assembled-output/BCODE.unprot.bin", "rb") 75 | data_block.extend(elite_file.read()) 76 | elite_file.close() 77 | 78 | # Commander data checksum 79 | 80 | commander_start = na2_per_cent - load_address 81 | commander_offset = 0x52 82 | CH = 0x4B - 2 83 | CY = 0 84 | for i in range(CH, 0, -1): 85 | CH = CH + CY + data_block[commander_start + i + 7] 86 | CY = (CH > 255) & 1 87 | CH = CH % 256 88 | CH = CH ^ data_block[commander_start + i + 8] 89 | 90 | print("Commander checksum = ", hex(CH)) 91 | 92 | data_block[commander_start + commander_offset] = CH ^ 0xA9 93 | data_block[commander_start + commander_offset + 1] = CH 94 | 95 | # Encrypt game code 96 | 97 | if encrypt: 98 | for n in range(scramble_from, scramble_to): 99 | data_block[n - load_address] = (data_block[n - load_address] + data_block[n + 1 - load_address]) % 256 100 | 101 | data_block[scramble_to - load_address] = (data_block[scramble_to - load_address] + seed) % 256 102 | 103 | # Write output file for BCODE 104 | 105 | output_file = open("3-assembled-output/BCODE.bin", "wb") 106 | output_file.write(data_block) 107 | output_file.close() 108 | 109 | print("3-assembled-output/BCODE.bin file saved") 110 | 111 | # Configuration variables for BDATA 112 | 113 | load_address = 0x1300 + 0x5D00 114 | seed = 0x62 115 | scramble_from = 0x8000 116 | scramble_to = 0xB1FF 117 | 118 | data_block = bytearray() 119 | 120 | # Load assembled code file for BDATA 121 | 122 | elite_file = open("3-assembled-output/BDATA.unprot.bin", "rb") 123 | data_block.extend(elite_file.read()) 124 | elite_file.close() 125 | 126 | if encrypt: 127 | for n in range(scramble_from, scramble_to): 128 | data_block[n - load_address] = (data_block[n - load_address] + data_block[n + 1 - load_address]) % 256 129 | 130 | data_block[scramble_to - load_address] = (data_block[scramble_to - load_address] + seed) % 256 131 | 132 | # Write output file for BDATA 133 | 134 | output_file = open("3-assembled-output/BDATA.bin", "wb") 135 | output_file.write(data_block) 136 | output_file.close() 137 | 138 | print("3-assembled-output/BDATA.bin file saved") 139 | -------------------------------------------------------------------------------- /2-build-files/elite-decrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # BBC MASTER ELITE DECRYPTION SCRIPT 6 | # 7 | # Written by Mark Moxon 8 | # 9 | # This script removes encryption and checksums from the compiled binaries for 10 | # the main game code. It reads the encrypted "BCODE.bin" and "BDATA.bin" 11 | # binaries and generates decrypted versions as "BCODE.decrypt.bin" and 12 | # "BDATA.decrypt.bin 13 | # 14 | # Files are saved using the decrypt.bin suffix so they don't overwrite any 15 | # existing unprot.bin files, so they can be compared if required 16 | # 17 | # Run this script by changing directory to the repository's root folder and 18 | # running the script with "python 2-build-files/elite-decrypt.py" 19 | # 20 | # You can decrypt specific releases by adding the following arguments, as in 21 | # "python 2-build-files/elite-decrypt.py -rel2" for example: 22 | # 23 | # -rel1 Decrypt the SNG47 release 24 | # -rel2 Decrypt the Master Compact release 25 | # 26 | # If unspecified, the default is rel1 27 | # 28 | # ****************************************************************************** 29 | 30 | from __future__ import print_function 31 | import sys 32 | 33 | print() 34 | print("BBC Master Elite decryption") 35 | 36 | argv = sys.argv 37 | release = 1 38 | folder = "sng47" 39 | 40 | for arg in argv[1:]: 41 | if arg == "-rel1": 42 | release = 1 43 | folder = "sng47" 44 | if arg == "-rel2": 45 | release = 2 46 | folder = "compact" 47 | 48 | # Configuration variables for BCODE 49 | 50 | load_address = 0x1300 51 | seed = 0x19 52 | unscramble_to = 0x2CC1 53 | 54 | if release == 1: 55 | # SNG47 56 | unscramble_from = 0x7F47 57 | elif release == 2: 58 | # Compact 59 | unscramble_from = 0x7FEC 60 | 61 | data_block = bytearray() 62 | 63 | # Load assembled code file 64 | 65 | elite_file = open("4-reference-binaries/" + folder + "/BCODE.bin", "rb") 66 | data_block.extend(elite_file.read()) 67 | elite_file.close() 68 | 69 | print() 70 | print("[ Read ] 4-reference-binaries/" + folder + "/BCODE.bin") 71 | 72 | # Do decryption 73 | 74 | for n in range(unscramble_from, unscramble_to - 1, -1): 75 | new = (data_block[n - load_address] - seed) % 256 76 | data_block[n - load_address] = new 77 | seed = new 78 | 79 | print("[ Decrypt ] 4-reference-binaries/" + folder + "/BCODE.bin") 80 | 81 | # Write output file for BCODE.decrypt 82 | 83 | output_file = open("4-reference-binaries/" + folder + "/BCODE.decrypt.bin", "wb") 84 | output_file.write(data_block) 85 | output_file.close() 86 | 87 | print("[ Save ] 4-reference-binaries/" + folder + "/BCODE.decrypt.bin") 88 | 89 | # Configuration variables for BDATA 90 | 91 | load_address = 0x1300 + 0x5D00 92 | seed = 0x62 93 | unscramble_from = 0xB1FF 94 | unscramble_to = 0x8000 95 | 96 | data_block = bytearray() 97 | 98 | # Load assembled code file 99 | 100 | elite_file = open("4-reference-binaries/" + folder + "/BDATA.bin", "rb") 101 | data_block.extend(elite_file.read()) 102 | elite_file.close() 103 | 104 | print() 105 | print("[ Read ] 4-reference-binaries/" + folder + "/BDATA.bin") 106 | 107 | # Do decryption 108 | 109 | for n in range(unscramble_from, unscramble_to - 1, -1): 110 | new = (data_block[n - load_address] - seed) % 256 111 | data_block[n - load_address] = new 112 | seed = new 113 | 114 | print("[ Decrypt ] 4-reference-binaries/" + folder + "/BDATA.bin") 115 | 116 | # Write output file for BDATA.decrypt 117 | 118 | output_file = open("4-reference-binaries/" + folder + "/BDATA.decrypt.bin", "wb") 119 | output_file.write(data_block) 120 | output_file.close() 121 | 122 | print("[ Save ] 4-reference-binaries/" + folder + "/BDATA.decrypt.bin") 123 | print() 124 | -------------------------------------------------------------------------------- /2-build-files/libiconv2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/2-build-files/libiconv2.dll -------------------------------------------------------------------------------- /2-build-files/libintl3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/2-build-files/libintl3.dll -------------------------------------------------------------------------------- /2-build-files/make.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/2-build-files/make.exe -------------------------------------------------------------------------------- /3-assembled-output/BCODE.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/3-assembled-output/BCODE.bin -------------------------------------------------------------------------------- /3-assembled-output/BCODE.unprot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/3-assembled-output/BCODE.unprot.bin -------------------------------------------------------------------------------- /3-assembled-output/BDATA.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/3-assembled-output/BDATA.bin -------------------------------------------------------------------------------- /3-assembled-output/BDATA.unprot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/3-assembled-output/BDATA.unprot.bin -------------------------------------------------------------------------------- /3-assembled-output/M128Elt.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/3-assembled-output/M128Elt.bin -------------------------------------------------------------------------------- /3-assembled-output/README.md: -------------------------------------------------------------------------------- 1 | # Assembled output for the BBC Master version of Elite 2 | 3 | This folder contains the output binaries from the build process for the BBC Master version of Elite. 4 | 5 | It also contains [compile.txt](compile.txt), which contains the output from the assembly process. This is very useful when debugging the build process. 6 | 7 | --- 8 | 9 | Right on, Commanders! 10 | 11 | _Mark Moxon_ -------------------------------------------------------------------------------- /3-assembled-output/README.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------- 3 | Acornsoft Elite 4 | 5 | Version: BBC Master 6 | Variant: Acornsoft SNG47 release 7 | Product: Acornsoft SNG47 8 | 9 | See www.bbcelite.com for details 10 | --------------------------------------- 11 | -------------------------------------------------------------------------------- /4-reference-binaries/README.md: -------------------------------------------------------------------------------- 1 | # Original binaries for the BBC Master version of Elite 2 | 3 | This folder contains the binaries from the game disc for the BBC Master version of Elite on Ian Bell's personal website, as well as reference binaries for the other releases. 4 | 5 | * [compact](compact) contains the binaries from the Superior Software version for the BBC Master Compact 6 | 7 | * [sng47](sng47) contains the binaries from the Acornsoft SNG47 release for the BBC Master 128 8 | 9 | --- 10 | 11 | Right on, Commanders! 12 | 13 | _Mark Moxon_ -------------------------------------------------------------------------------- /4-reference-binaries/compact/BCODE.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/compact/BCODE.bin -------------------------------------------------------------------------------- /4-reference-binaries/compact/BCODE.unprot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/compact/BCODE.unprot.bin -------------------------------------------------------------------------------- /4-reference-binaries/compact/BDATA.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/compact/BDATA.bin -------------------------------------------------------------------------------- /4-reference-binaries/compact/BDATA.unprot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/compact/BDATA.unprot.bin -------------------------------------------------------------------------------- /4-reference-binaries/compact/M128Elt.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/compact/M128Elt.bin -------------------------------------------------------------------------------- /4-reference-binaries/sng47/BCODE.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/sng47/BCODE.bin -------------------------------------------------------------------------------- /4-reference-binaries/sng47/BCODE.unprot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/sng47/BCODE.unprot.bin -------------------------------------------------------------------------------- /4-reference-binaries/sng47/BDATA.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/sng47/BDATA.bin -------------------------------------------------------------------------------- /4-reference-binaries/sng47/BDATA.unprot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/sng47/BDATA.unprot.bin -------------------------------------------------------------------------------- /4-reference-binaries/sng47/M128Elt.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/4-reference-binaries/sng47/M128Elt.bin -------------------------------------------------------------------------------- /5-compiled-game-discs/README.md: -------------------------------------------------------------------------------- 1 | # Compiled game discs for the BBC Master version of Elite 2 | 3 | This folder contains the SSD disc images for the BBC Master version of Elite, as produced by the build process. There is one SSD file for each supported release. These SSD images can be loaded into an emulator like JSBeeb or BeebEm, or into a real BBC Micro using a device like a Gotek. 4 | 5 | --- 6 | 7 | Right on, Commanders! 8 | 9 | _Mark Moxon_ -------------------------------------------------------------------------------- /5-compiled-game-discs/elite-master-compact.ssd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/5-compiled-game-discs/elite-master-compact.ssd -------------------------------------------------------------------------------- /5-compiled-game-discs/elite-master-sng47.ssd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/elite-source-code-bbc-master/96bed390d57471f3aa3b88e6c450233d62344a39/5-compiled-game-discs/elite-master-sng47.ssd -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BEEBASM?=beebasm 2 | PYTHON?=python 3 | 4 | # A make command with no arguments will build the SNG47 variant with 5 | # encrypted binaries, checksums enabled, the standard commander and 6 | # crc32 verification of the game binaries 7 | # 8 | # Optional arguments for the make command are: 9 | # 10 | # variant= Build the specified variant: 11 | # 12 | # sng47 (default) 13 | # compact 14 | # 15 | # commander=max Start with a maxed-out commander 16 | # 17 | # encrypt=no Disable encryption and checksum routines 18 | # 19 | # match=no Do not attempt to match the original game binaries 20 | # (i.e. omit workspace noise) 21 | # 22 | # verify=no Disable crc32 verification of the game binaries 23 | # 24 | # So, for example: 25 | # 26 | # make variant=compact commander=max encrypt=no match=no verify=no 27 | # 28 | # will build an unencrypted Master Compact variant with a maxed-out commander, 29 | # no workspace noise and no crc32 verification 30 | # 31 | # The following variables are written into elite-build-options.asm depending on 32 | # the above arguments, so they can be passed to BeebAsm: 33 | # 34 | # _VERSION 35 | # 4 = BBC Master 36 | # 37 | # _VARIANT 38 | # 1 = SNG47 (default) 39 | # 2 = Master Compact 40 | # 41 | # _MAX_COMMANDER 42 | # TRUE = Maxed-out commander 43 | # FALSE = Standard commander 44 | # 45 | # _REMOVE_CHECKSUMS 46 | # TRUE = Disable checksum routines 47 | # FALSE = Enable checksum routines 48 | # 49 | # _MATCH_ORIGINAL_BINARIES 50 | # TRUE = Match binaries to released version (i.e. fill workspaces with noise) 51 | # FALSE = Zero-fill workspaces 52 | # 53 | # The encrypt and verify arguments are passed to the elite-checksum.py and 54 | # crc32.py scripts, rather than BeebAsm 55 | 56 | ifeq ($(commander), max) 57 | max-commander=TRUE 58 | else 59 | max-commander=FALSE 60 | endif 61 | 62 | ifeq ($(encrypt), no) 63 | unencrypt=-u 64 | remove-checksums=TRUE 65 | else 66 | unencrypt= 67 | remove-checksums=FALSE 68 | endif 69 | 70 | ifeq ($(match), no) 71 | match-original-binaries=FALSE 72 | else 73 | match-original-binaries=TRUE 74 | endif 75 | 76 | ifeq ($(variant), compact) 77 | variant-number=2 78 | folder=compact 79 | suffix=-compact 80 | boot=-opt 2 81 | else 82 | variant-number=1 83 | folder=sng47 84 | suffix=-sng47 85 | boot=-boot M128Elt 86 | endif 87 | 88 | .PHONY:all 89 | all: 90 | echo _VERSION=4 > 1-source-files/main-sources/elite-build-options.asm 91 | echo _VARIANT=$(variant-number) >> 1-source-files/main-sources/elite-build-options.asm 92 | echo _REMOVE_CHECKSUMS=$(remove-checksums) >> 1-source-files/main-sources/elite-build-options.asm 93 | echo _MATCH_ORIGINAL_BINARIES=$(match-original-binaries) >> 1-source-files/main-sources/elite-build-options.asm 94 | echo _MAX_COMMANDER=$(max-commander) >> 1-source-files/main-sources/elite-build-options.asm 95 | $(BEEBASM) -i 1-source-files/main-sources/elite-loader.asm -v > 3-assembled-output/compile.txt 96 | $(BEEBASM) -i 1-source-files/main-sources/elite-source.asm -v >> 3-assembled-output/compile.txt 97 | $(BEEBASM) -i 1-source-files/main-sources/elite-data.asm -v >> 3-assembled-output/compile.txt 98 | $(BEEBASM) -i 1-source-files/main-sources/elite-readme.asm -v >> 3-assembled-output/compile.txt 99 | $(PYTHON) 2-build-files/elite-checksum.py $(unencrypt) -rel$(variant-number) 100 | $(BEEBASM) -i 1-source-files/main-sources/elite-disc.asm $(boot) -do 5-compiled-game-discs/elite-master$(suffix).ssd -title "E L I T E" 101 | ifneq ($(verify), no) 102 | @$(PYTHON) 2-build-files/crc32.py 4-reference-binaries/$(folder) 3-assembled-output 103 | endif 104 | 105 | .PHONY:b2 106 | b2: 107 | curl -G "http://localhost:48075/reset/b2" 108 | curl -H "Content-Type:application/binary" --upload-file "5-compiled-game-discs/elite-master$(suffix).ssd" "http://localhost:48075/run/b2?name=elite-master$(suffix).ssd" 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fully documented source code for Elite on the BBC Master 2 | 3 | [BBC Micro cassette Elite](https://github.com/markmoxon/elite-source-code-bbc-micro-cassette) | [BBC Micro disc Elite](https://github.com/markmoxon/elite-source-code-bbc-micro-disc) | [Acorn Electron Elite](https://github.com/markmoxon/elite-source-code-acorn-electron) | [6502 Second Processor Elite](https://github.com/markmoxon/elite-source-code-6502-second-processor) | [Commodore 64 Elite](https://github.com/markmoxon/elite-source-code-commodore-64) | [Apple II Elite](https://github.com/markmoxon/elite-source-code-apple-ii) | **BBC Master Elite** | [NES Elite](https://github.com/markmoxon/elite-source-code-nes) | [Elite-A](https://github.com/markmoxon/elite-a-source-code-bbc-micro) | [Teletext Elite](https://github.com/markmoxon/teletext-elite) | [Elite Universe Editor](https://github.com/markmoxon/elite-universe-editor) | [Elite Compendium (BBC Master)](https://github.com/markmoxon/elite-compendium-bbc-master) | [Elite Compendium (BBC Micro)](https://github.com/markmoxon/elite-compendium-bbc-micro) | [Elite over Econet](https://github.com/markmoxon/elite-over-econet) | [!EliteNet](https://github.com/markmoxon/elite-over-econet-acorn-archimedes) | [Flicker-free Commodore 64 Elite](https://github.com/markmoxon/c64-elite-flicker-free) | [BBC Micro Aviator](https://github.com/markmoxon/aviator-source-code-bbc-micro) | [BBC Micro Revs](https://github.com/markmoxon/revs-source-code-bbc-micro) | [Archimedes Lander](https://github.com/markmoxon/lander-source-code-acorn-archimedes) 4 | 5 | ![Screenshot of Elite on the BBC Master](https://elite.bbcelite.com/images/github/Elite-Master.png) 6 | 7 | This repository contains source code for Elite on the BBC Master, with every single line documented and (for the most part) explained. It has been reconstructed by hand from a disassembly of the original game binaries. 8 | 9 | It is a companion to the [elite.bbcelite.com website](https://elite.bbcelite.com). 10 | 11 | See the [introduction](#introduction) for more information, or jump straight into the [documented source code](1-source-files/main-sources). 12 | 13 | ## Contents 14 | 15 | * [Introduction](#introduction) 16 | 17 | * [Acknowledgements](#acknowledgements) 18 | 19 | * [A note on licences, copyright etc.](#user-content-a-note-on-licences-copyright-etc) 20 | 21 | * [Browsing the source in an IDE](#browsing-the-source-in-an-ide) 22 | 23 | * [Folder structure](#folder-structure) 24 | 25 | * [Flicker-free Elite](#flicker-free-elite) 26 | 27 | * [BBC Master Elite with music](#bbc-master-elite-with-music) 28 | 29 | * [Elite Compendium](#elite-compendium) 30 | 31 | * [Elite over Econet](#elite-over-econet) 32 | 33 | * [Building BBC Master Elite from the source](#building-bbc-master-elite-from-the-source) 34 | 35 | * [Requirements](#requirements) 36 | * [Windows](#windows) 37 | * [Mac and Linux](#mac-and-linux) 38 | * [Build options](#build-options) 39 | * [Updating the checksum scripts if you change the code](#updating-the-checksum-scripts-if-you-change-the-code) 40 | * [Verifying the output](#verifying-the-output) 41 | * [Log files](#log-files) 42 | * [Auto-deploying to the b2 emulator](#auto-deploying-to-the-b2-emulator) 43 | 44 | * [Building different variants of BBC Master Elite](#building-different-variants-of-bbc-master-elite) 45 | 46 | * [Building the SNG47 variant](#building-the-sng47-variant) 47 | * [Building the Master Compact variant](#building-the-master-compact-variant) 48 | * [Differences between the variants](#differences-between-the-variants) 49 | 50 | * [Notes on the original source files](#notes-on-the-original-source-files) 51 | 52 | * [Producing byte-accurate binaries](#producing-byte-accurate-binaries) 53 | 54 | ## Introduction 55 | 56 | This repository contains source code for Elite on the BBC Master, with every single line documented and (for the most part) explained. 57 | 58 | You can build the fully functioning game from this source. [Two variants](#building-different-variants-of-bbc-master-elite) are currently supported: the Acornsoft SNG47 variant, and the Superior Software variant for the Master Compact. 59 | 60 | This repository is a companion to the [elite.bbcelite.com website](https://elite.bbcelite.com), which contains all the code from this repository, but laid out in a much more human-friendly fashion. The links at the top of this page will take you to repositories for the other versions of Elite that are covered by this project. 61 | 62 | * If you want to browse the source and read about how Elite works under the hood, you will probably find [the website](https://elite.bbcelite.com) a better place to start than this repository. 63 | 64 | * If you would rather explore the source code in your favourite IDE, then the [annotated source](1-source-files/main-sources) is what you're looking for. It contains the exact same content as the website, so you won't be missing out (the website is generated from the source files, so they are guaranteed to be identical). You might also like to read the section on [browsing the source in an IDE](#browsing-the-source-in-an-ide) for some tips. 65 | 66 | * If you want to build BBC Master Elite from the source on a modern computer, to produce a working game disc that can be loaded into a BBC Master or an emulator, then you want the section on [building BBC Master Elite from the source](#building-bbc-master-elite-from-the-source). 67 | 68 | My hope is that this repository and the [accompanying website](https://elite.bbcelite.com) will be useful for those who want to learn more about Elite and what makes it tick. It is provided on an educational and non-profit basis, with the aim of helping people appreciate one of the most iconic games of the 8-bit era. 69 | 70 | ## Acknowledgements 71 | 72 | BBC Master Elite was written by Ian Bell and David Braben and is copyright © Acornsoft 1986. 73 | 74 | The code on this site has been reconstructed from a disassembly of the version released on [Ian Bell's personal website](http://www.elitehomepage.org/). 75 | 76 | The commentary is copyright © Mark Moxon. Any misunderstandings or mistakes in the documentation are entirely my fault. 77 | 78 | Huge thanks are due to the original authors for not only creating such an important piece of my childhood, but also for releasing the source code for us to play with; to Paul Brink for his annotated disassembly; and to Kieran Connell for his [BeebAsm version](https://github.com/kieranhj/elite-beebasm), which I forked as the original basis for this project. You can find more information about this project in the [accompanying website's project page](https://elite.bbcelite.com/about_site/about_this_project.html). 79 | 80 | The following archive from Ian Bell's personal website forms the basis for this project: 81 | 82 | * [BBC Elite, Master version](http://www.elitehomepage.org/archive/a/b8020001.zip) 83 | 84 | ### A note on licences, copyright etc. 85 | 86 | This repository is _not_ provided with a licence, and there is intentionally no `LICENSE` file provided. 87 | 88 | According to [GitHub's licensing documentation](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository), this means that "the default copyright laws apply, meaning that you retain all rights to your source code and no one may reproduce, distribute, or create derivative works from your work". 89 | 90 | The reason for this is that my commentary is intertwined with the original Elite source code, and the original source code is copyright. The whole site is therefore covered by default copyright law, to ensure that this copyright is respected. 91 | 92 | Under GitHub's rules, you have the right to read and fork this repository... but that's it. No other use is permitted, I'm afraid. 93 | 94 | My hope is that the educational and non-profit intentions of this repository will enable it to stay hosted and available, but the original copyright holders do have the right to ask for it to be taken down, in which case I will comply without hesitation. I do hope, though, that along with the various other disassemblies and commentaries of this source, it will remain viable. 95 | 96 | ## Browsing the source in an IDE 97 | 98 | If you want to browse the source in an IDE, you might find the following useful. 99 | 100 | * The most interesting files are in the [main-sources](1-source-files/main-sources) folder: 101 | 102 | * The main game's source code is in the [elite-source.asm](1-source-files/main-sources/elite-source.asm) and [elite-data.asm](1-source-files/main-sources/elite-data.asm) files (containing the game code and game data respectively) - this is the motherlode and probably contains all the stuff you're interested in. 103 | 104 | * The game's loader is in the [elite-loader.asm](1-source-files/main-sources/elite-loader.asm) file - this is mainly concerned with setup and copy protection. 105 | 106 | * It's probably worth skimming through the [notes on terminology and notations](https://elite.bbcelite.com/terminology/) on the accompanying website, as this explains a number of terms used in the commentary, without which it might be a bit tricky to follow at times (in particular, you should understand the terminology I use for multi-byte numbers). 107 | 108 | * The accompanying website contains [a number of "deep dive" articles](https://elite.bbcelite.com/deep_dives/), each of which goes into an aspect of the game in detail. Routines that are explained further in these articles are tagged with the label `Deep dive:` and the relevant article name. 109 | 110 | * There are loads of routines and variables in Elite - literally hundreds. You can find them in the source files by searching for the following: `Type: Subroutine`, `Type: Variable`, `Type: Workspace` and `Type: Macro`. 111 | 112 | * If you know the name of a routine, you can find it by searching for `Name: `, as in `Name: SCAN` (for the 3D scanner routine) or `Name: LL9` (for the ship-drawing routine). 113 | 114 | * The entry point for the [main game code](1-source-files/main-sources/elite-source.asm) is routine `TT170`, which you can find by searching for `Name: TT170`. If you want to follow the program flow all the way from the title screen around the main game loop, then you can find a number of [deep dives on program flow](https://elite.bbcelite.com/deep_dives/) on the accompanying website. 115 | 116 | * The source code is designed to be read at an 80-column width and with a monospaced font, just like in the good old days. 117 | 118 | I hope you enjoy exploring the inner workings of BBC Elite as much as I have. 119 | 120 | ## Folder structure 121 | 122 | There are five main folders in this repository, which reflect the order of the build process. 123 | 124 | * [1-source-files](1-source-files) contains all the different source files, such as the main assembler source files, image binaries, fonts, boot files and so on. 125 | 126 | * [2-build-files](2-build-files) contains build-related scripts, such as the checksum, encryption and crc32 verification scripts. 127 | 128 | * [3-assembled-output](3-assembled-output) contains the output from the assembly process, when the source files are assembled and the results processed by the build files. 129 | 130 | * [4-reference-binaries](4-reference-binaries) contains the correct binaries for each variant, so we can verify that our assembled output matches the reference. 131 | 132 | * [5-compiled-game-discs](5-compiled-game-discs) contains the final output of the build process: an SSD disc image that contains the compiled game and which can be run on real hardware or in an emulator. 133 | 134 | ## Flicker-free Elite 135 | 136 | This repository also includes a flicker-free version, which incorporates a fix for planets so they no longer flicker. The flicker-free code is in a separate branch called `flicker-free`, and apart from the code differences for reducing flicker, this branch is identical to the main branch and the same build process applies. 137 | 138 | The annotated source files in the `flicker-free` branch contain both the original Acornsoft code and all of the modifications for flicker-free Elite, so you can look through the source to see exactly what's changed. Any code that I've removed from the original version is commented out in the source files, so when they are assembled they produce the flicker-free binaries, while still containing details of all the modifications. You can find all the diffs by searching the sources for `Mod:`. 139 | 140 | For more information on flicker-free Elite, see the [hacks section of the accompanying website](https://elite.bbcelite.com/hacks/flicker-free_elite.html). 141 | 142 | ## BBC Master Elite with music 143 | 144 | This repository also includes a version of BBC Master Elite that includes the music from the Commodore 64 version. The music-specific code is in a separate branch called `music`, and apart from the code differences for adding the music, this branch is identical to the main branch and the same build process applies. 145 | 146 | The annotated source files in the `music` branch contain both the original Acornsoft code and all of the modifications for the musical version of Elite, so you can look through the source to see exactly what's changed. Any code that I've removed from the original version is commented out in the source files, so when they are assembled they produce the music-enabled binaries, while still containing details of all the modifications. You can find all the diffs by searching the sources for `Mod:`. 147 | 148 | The music itself is built as a sideways ROM using the code in the [elite-music repository](https://github.com/markmoxon/elite-music/). 149 | 150 | For more information on the music, see the [hacks section of the accompanying website](https://elite.bbcelite.com/hacks/bbc_elite_with_music.html). 151 | 152 | ## Elite Compendium 153 | 154 | This repository also includes a version of BBC Master Elite for the Elite Compendium, which incorporates all the available hacks in one game. The Compendium version is in a separate branch called `elite-compendium`, which is included in the [Elite Compendium (BBC Master)](https://github.com/markmoxon/elite-compendium-bbc-master) repository as a submodule. 155 | 156 | The annotated source files in the `elite-compendium` branch contain both the original Acornsoft code and all of the modifications for the Elite Compendium, so you can look through the source to see exactly what's changed. Any code that I've removed from the original version is commented out in the source files, so when they are assembled they produce the Compendium binaries, while still containing details of all the modifications. You can find all the diffs by searching the sources for `Mod:`. 157 | 158 | For more information on the Elite Compendium, see the [hacks section of the accompanying website](https://elite.bbcelite.com/hacks/elite_compendium.html). 159 | 160 | ## Elite over Econet 161 | 162 | This repository also includes a version of BBC Master Elite that loads over Econet and supports multiplayer scoreboards. The Elite over Econet version is in a separate branch called `econet`, which is included in the [Elite over Econet](https://github.com/markmoxon/elite-over-econet) repository as a submodule. 163 | 164 | The annotated source files in the `econet` branch contain both the original Acornsoft code and all of the modifications for Elite over Econet, so you can look through the source to see exactly what's changed. Any code that I've removed from the original version is commented out in the source files, so when they are assembled they produce the Elite over Econet binaries, while still containing details of all the modifications. You can find all the diffs by searching the sources for `Mod:`. 165 | 166 | For more information on Elite over Econet, see the [hacks section of the accompanying website](https://elite.bbcelite.com/hacks/elite_over_econet.html). 167 | 168 | ## Building BBC Master Elite from the source 169 | 170 | Builds are supported for both Windows and Mac/Linux systems. In all cases the build process is defined in the `Makefile` provided. 171 | 172 | ### Requirements 173 | 174 | You will need the following to build BBC Master Elite from the source: 175 | 176 | * BeebAsm, which can be downloaded from the [BeebAsm repository](https://github.com/stardot/beebasm). Mac and Linux users will have to build their own executable with `make code`, while Windows users can just download the `beebasm.exe` file. 177 | 178 | * Python. The build process has only been tested on 3.x, but 2.7 might work. 179 | 180 | * Mac and Linux users may need to install `make` if it isn't already present (for Windows users, `make.exe` is included in this repository). 181 | 182 | For details of how the build process works, see the [build documentation on bbcelite.com](https://elite.bbcelite.com/about_site/building_elite.html). 183 | 184 | Let's look at how to build BBC Master Elite from the source. 185 | 186 | ### Windows 187 | 188 | For Windows users, there is a batch file called `make.bat` which you can use to build the game. Before this will work, you should edit the batch file and change the values of the `BEEBASM` and `PYTHON` variables to point to the locations of your `beebasm.exe` and `python.exe` executables. You also need to change directory to the repository folder (i.e. the same folder as `make.bat`). 189 | 190 | All being well, entering the following into a command window: 191 | 192 | ``` 193 | make.bat 194 | ``` 195 | 196 | will produce a file called `elite-master-sng47.ssd` in the `5-compiled-game-discs` folder that contains the SNG47 variant, which you can then load into an emulator, or into a real BBC Micro using a device like a Gotek. 197 | 198 | ### Mac and Linux 199 | 200 | The build process uses a standard GNU `Makefile`, so you just need to install `make` if your system doesn't already have it. If BeebAsm or Python are not on your path, then you can either fix this, or you can edit the `Makefile` and change the `BEEBASM` and `PYTHON` variables in the first two lines to point to their locations. You also need to change directory to the repository folder (i.e. the same folder as `Makefile`). 201 | 202 | All being well, entering the following into a terminal window: 203 | 204 | ``` 205 | make 206 | ``` 207 | 208 | will produce a file called `elite-master-sng47.ssd` in the `5-compiled-game-discs` folder that contains the SNG47 variant, which you can then load into an emulator, or into a real BBC Micro using a device like a Gotek. 209 | 210 | ### Build options 211 | 212 | By default the build process will create a typical Elite game disc with a standard commander and verified binaries. There are various arguments you can pass to the build to change how it works. They are: 213 | 214 | * `variant=` - Build the specified variant: 215 | 216 | * `variant=sng47` (default) 217 | * `variant=compact` 218 | 219 | * `commander=max` - Start with a maxed-out commander (specifically, this is the test commander file from the original source, which is almost but not quite maxed-out) 220 | 221 | * `encrypt=no` - Disable encryption and checksum routines 222 | 223 | * `match=no` - Do not attempt to match the original game binaries (i.e. omit workspace noise) 224 | 225 | * `verify=no` - Disable crc32 verification of the game binaries 226 | 227 | So, for example: 228 | 229 | `make variant=compact commander=max encrypt=no match=no verify=no` 230 | 231 | will build an unencrypted Master Compact variant with a maxed-out commander, no workspace noise and no crc32 verification. 232 | 233 | The unencrypted version should be more useful for anyone who wants to make modifications to the game code. As this argument produces unencrypted files, the binaries produced will be quite different to the binaries on the original source disc, which are encrypted. 234 | 235 | See below for more on the verification process. 236 | 237 | ### Updating the checksum scripts if you change the code 238 | 239 | If you change the source code in any way, you may break the game; if so, it will typically hang at the loading screen, though in some versions it may hang when launching from the space station. 240 | 241 | To fix this, you may need to update some of the hard-coded addresses in the checksum script so that they match the new addresses in your changed version of the code. See the comments in the [elite-checksum.py](2-build-files/elite-checksum.py) script for details. 242 | 243 | ### Verifying the output 244 | 245 | The default build process prints out checksums of all the generated files, along with the checksums of the files from the original sources. You can disable verification by passing `verify=no` to the build. 246 | 247 | The Python script `crc32.py` in the `2-build-files` folder does the actual verification, and shows the checksums and file sizes of both sets of files, alongside each other, and with a Match column that flags any discrepancies. If you are building an unencrypted set of files then there will be lots of differences, while the encrypted files should mostly match (see the Differences section below for more on this). 248 | 249 | The binaries in the `4-reference-binaries` folder are those extracted from the released version of the game, while those in the `3-assembled-output` folder are produced by the build process. For example, if you don't make any changes to the code and build the project with `make`, then this is the output of the verification process: 250 | 251 | ``` 252 | Results for variant: sng47 253 | [--originals--] [---output----] 254 | Checksum Size Checksum Size Match Filename 255 | ----------------------------------------------------------- 256 | d52370e7 27720 d52370e7 27720 Yes BCODE.bin 257 | 86e9fa69 27720 86e9fa69 27720 Yes BCODE.unprot.bin 258 | bf10f02b 16896 bf10f02b 16896 Yes BDATA.bin 259 | f7a27087 16896 f7a27087 16896 Yes BDATA.unprot.bin 260 | 6dce29cc 721 6dce29cc 721 Yes M128Elt.bin 261 | ``` 262 | 263 | All the compiled binaries match the originals, so we know we are producing the same final game as the SNG47 variant. 264 | 265 | ### Log files 266 | 267 | During compilation, details of every step are output in a file called `compile.txt` in the `3-assembled-output` folder. If you have problems, it might come in handy, and it's a great reference if you need to know the addresses of labels and variables for debugging (or just snooping around). 268 | 269 | ### Auto-deploying to the b2 emulator 270 | 271 | For users of the excellent [b2 emulator](https://github.com/tom-seddon/b2), you can include the build parameter `b2` to automatically load and boot the assembled disc image in b2. The b2 emulator must be running for this to work. 272 | 273 | For example, to build, verify and load the game into b2, you can do this on Windows: 274 | 275 | ``` 276 | make.bat all b2 277 | ``` 278 | 279 | or this on Mac/Linux: 280 | 281 | ``` 282 | make all b2 283 | ``` 284 | 285 | If you omit the `all` target then b2 will start up with the results of the last successful build. 286 | 287 | Note that you should manually choose the correct platform in b2 (I intentionally haven't automated this part to make it easier to test across multiple platforms). 288 | 289 | ## Building different variants of BBC Master Elite 290 | 291 | This repository contains the source code for two different variants of BBC Master Elite: 292 | 293 | * The Acornsoft SNG47 variant, which was the first appearance of BBC Master Elite, and the one included on all subsequent discs 294 | 295 | * The Superior Software variant for the Master Compact 296 | 297 | By default the build process builds the SNG47 variant, but you can build a specified variant using the `variant=` build parameter. 298 | 299 | ### Building the SNG47 variant 300 | 301 | You can add `variant=sng47` to produce the `elite-master-sng47.ssd` file that contains the SNG47 variant, though that's the default value so it isn't necessary. In other words, you can build it like this: 302 | 303 | ``` 304 | make.bat variant=sng47 305 | ``` 306 | 307 | or this on a Mac or Linux: 308 | 309 | ``` 310 | make variant=sng47 311 | ``` 312 | 313 | This will produce a file called `elite-master-sng47.ssd` in the `5-compiled-game-discs` folder that contains the SNG47 variant. 314 | 315 | The verification checksums for this version are as follows: 316 | 317 | ``` 318 | Results for variant: sng47 319 | [--originals--] [---output----] 320 | Checksum Size Checksum Size Match Filename 321 | ----------------------------------------------------------- 322 | d52370e7 27720 d52370e7 27720 Yes BCODE.bin 323 | 86e9fa69 27720 86e9fa69 27720 Yes BCODE.unprot.bin 324 | bf10f02b 16896 bf10f02b 16896 Yes BDATA.bin 325 | f7a27087 16896 f7a27087 16896 Yes BDATA.unprot.bin 326 | 6dce29cc 721 6dce29cc 721 Yes M128Elt.bin 327 | ``` 328 | 329 | ### Building the Master Compact variant 330 | 331 | You can build the Master Compact variant by appending `variant=compact` to the `make` command, like this on Windows: 332 | 333 | ``` 334 | make.bat variant=compact 335 | ``` 336 | 337 | or this on a Mac or Linux: 338 | 339 | ``` 340 | make variant=compact 341 | ``` 342 | 343 | This will produce a file called `elite-master-compact.ssd` in the `5-compiled-game-discs` folder that contains the Master Compact variant. 344 | 345 | The verification checksums for this version are as follows: 346 | 347 | ``` 348 | Results for variant: compact 349 | [--originals--] [---output----] 350 | Checksum Size Checksum Size Match Filename 351 | ----------------------------------------------------------- 352 | d5cbbba9 27904 d5cbbba9 27904 Yes BCODE.bin 353 | bd689545 27904 bd689545 27904 Yes BCODE.unprot.bin 354 | 8c9d6d1f 16896 8c9d6d1f 16896 Yes BDATA.bin 355 | 5993627f 16896 5993627f 16896 Yes BDATA.unprot.bin 356 | 107b98cc 740 107b98cc 740 Yes M128Elt.bin 357 | ``` 358 | 359 | ### Differences between the variants 360 | 361 | You can see the differences between the variants by searching the source code for `_SNG47` (for features in the SNG47 variant) or `_COMPACT` (for features in the Master Compact variant). The main differences in the Master Compact variant compared to the SNG47 variant are: 362 | 363 | * Support for the Compact's digital joystick. The analogue stick is still supported, but if this variant is run on a Compact, then the digital stick is read instead. 364 | 365 | * Support for ADFS and the single disc drive on the Compact. This essentially replaces the "Which Drive?" prompt in the disc access menu with "Which Directory?", and changes the formatting of the disc catalogue to fit it on-screen. There is also additional code to claim and release the NMI workspace when disc access is required, as ADFS uses zero page differently to DFS. 366 | 367 | See the [accompanying website](https://elite.bbcelite.com/master/releases.html) for a comprehensive list of differences between the variants. 368 | 369 | ## Notes on the original source files 370 | 371 | ### Producing byte-accurate binaries 372 | 373 | Instead of initialising workspaces with null values like BeebAsm, the original BBC Micro source code creates its workspaces by simply incrementing the `P%` and `O%` program counters, which means that the workspaces end up containing whatever contents the allocated memory had at the time. As the source files are broken into multiple BBC BASIC programs that run each other sequentially, this means the workspaces in the source code tend to contain either fragments of these BBC BASIC source programs, or assembled code from an earlier stage. This doesn't make any difference to the game code, which either initialises the workspaces at runtime or just ignores their initial contents, but if we want to be able to produce byte-accurate binaries from the modern BeebAsm assembly process, we need to include this "workspace noise" when building the project. Workspace noise is only loaded by the `encrypt` target; for the `build` target, workspaces are initialised with zeroes. 374 | 375 | You can disable the production of byte-accurate binaries by passing `match=no` to the build. This will omit most workspace noise, leaving workspaces initialised with zeroes instead. 376 | 377 | Here's an example of how workspace noise is included, from the end of the main source in elite-source.asm: 378 | 379 | ``` 380 | IF _MATCH_ORIGINAL_BINARIES 381 | 382 | IF _SNG47 383 | 384 | EQUB &41, &23, &6D, &65, &6D, &3A, &53, &54 \ These bytes appear to be 385 | EQUB &41, &6C, &61, &74, &63, &68, &3A, &52 \ unused and just contain random 386 | EQUB &54, &53, &0D, &13, &74, &09, &5C, &2E \ workspace noise left over from 387 | EQUB &2E, &2E, &2E, &0D, &18, &60, &05, &20 \ the BBC Micro assembly process 388 | EQUB &0D, &1A, &F4, &21, &5C, &2E, &2E, &2E 389 | EQUB &2E, &2E, &2E, &2E, &2E, &2E, &2E, &42 390 | EQUB &61, &79, &20, &56, &69, &65, &77, &2E 391 | EQUB &2E, &2E, &2E, &2E, &2E, &2E, &2E, &2E 392 | EQUB &2E, &0D, &1A, &FE, &05, &20, &0D, &1B 393 | EQUB &08, &11, &2E, &48, &41 394 | 395 | ELIF _COMPACT 396 | 397 | EQUB &2B, &26, &33 \ These bytes appear to be unused and just contain 398 | \ random workspace noise left over from the BBC Micro 399 | \ assembly process 400 | 401 | ENDIF 402 | 403 | ELSE 404 | 405 | IF _SNG47 406 | 407 | SKIP 77 \ These bytes appear to be unused 408 | 409 | ELIF _COMPACT 410 | 411 | SKIP 3 \ These bytes appear to be unused 412 | 413 | ENDIF 414 | 415 | ENDIF 416 | ``` 417 | 418 | --- 419 | 420 | Right on, Commanders! 421 | 422 | _Mark Moxon_ -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SETLOCAL 3 | SET BEEBASM=C:\Users\user\bin\beebasm.exe 4 | SET PYTHON=C:\Users\user\AppData\Local\Microsoft\WindowsApps\python.exe 5 | 2-build-files\make %* 6 | --------------------------------------------------------------------------------