Created
January 10, 2021 07:02
-
-
Save fesh0r/0bfc8b14fe97c54637a0bebe944df561 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\ ****************************************************************************** | |
\ | |
\ ELITE LOADER SOURCE | |
\ | |
\ Elite was written by Ian Bell and David Braben and is copyright Acornsoft 1984 | |
\ | |
\ The code on this site is identical to the version released on Ian Bell's | |
\ personal website at http://www.elitehomepage.org/ | |
\ | |
\ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes | |
\ in the documentation are entirely my fault | |
\ | |
\ The terminology and notations used in this commentary are explained at | |
\ https://www.bbcelite.com/about_site/terminology_used_in_this_commentary.html | |
\ | |
\ ****************************************************************************** | |
\ ****************************************************************************** | |
\ | |
\ Configuration variables | |
\ | |
\ ****************************************************************************** | |
OSWRCH = &FFEE \ The address for the OSWRCH routine | |
ZP = &70 \ Temporary storage, used all over the place | |
P = &72 \ Temporary storage, used all over the place | |
Q = &73 \ Temporary storage, used all over the place | |
YY = &74 \ Temporary storage, used when drawing Saturn | |
T = &75 \ Temporary storage, used all over the place | |
ORG &1C05 | |
.start | |
INC fix+1 \ fix 0D byte in PIX | |
LDX #2 | |
.crtc_loop | |
LDA crtc_reg, X | |
STA &FE00 | |
LDA crtc_val, X | |
STA &FE01 | |
DEX | |
BPL crtc_loop | |
\ ****************************************************************************** | |
\ | |
\ Name: PLL1 | |
\ Summary: Draw Saturn on the loading screen | |
\ | |
\ ****************************************************************************** | |
.PLL1 | |
\ The following loop iterates CNT(1 0) times, i.e. &500 | |
\ or 1280 times, and draws the planet part of the | |
\ loading screen's Saturn | |
JSR DORND \ Set A and X to random numbers, say A = r1 | |
JSR SQUA2 \ Set (A P) = A * A | |
\ = r1^2 | |
STA ZP+1 \ Set ZP(1 0) = (A P) | |
LDA P \ = r1^2 | |
STA ZP | |
JSR DORND \ Set A and X to random numbers, say A = r2 | |
STA YY \ Set YY = A | |
\ = r2 | |
JSR SQUA2 \ Set (A P) = A * A | |
\ = r2^2 | |
TAX \ Set (X P) = (A P) | |
\ = r2^2 | |
LDA P \ Set (A ZP) = (X P) + ZP(1 0) | |
ADC ZP \ | |
STA ZP \ first adding the low bytes | |
TXA \ And then adding the high bytes | |
ADC ZP+1 | |
BCS PLC1 \ If the addition overflowed, jump down to PLC1 to skip | |
\ to the next pixel | |
STA ZP+1 \ Set ZP(1 0) = (A ZP) | |
\ = r1^2 + r2^2 | |
LDA #1 \ Set ZP(1 0) = &4001 - ZP(1 0) - (1 - C) | |
SBC ZP \ = 128^2 - ZP(1 0) | |
STA ZP \ | |
\ (as the C flag is clear), first subtracting the low | |
\ bytes | |
LDA #&40 \ And then subtracting the high bytes | |
SBC ZP+1 | |
STA ZP+1 | |
BCC PLC1 \ If the subtraction underflowed, jump down to PLC1 to | |
\ skip to the next pixel | |
\ If we get here, then both calculations fitted into | |
\ 16 bits, and we have: | |
\ | |
\ ZP(1 0) = 128^2 - (r1^2 + r2^2) | |
\ | |
\ where ZP(1 0) >= 0 | |
JSR ROOT \ Set ZP = SQRT(ZP(1 0)) | |
LDA ZP \ Set X = ZP >> 1 | |
LSR A \ = SQRT(128^2 - (a^2 + b^2)) / 2 | |
TAX | |
LDA YY \ Set A = YY | |
\ = r2 | |
CMP #128 \ If YY >= 128, set the C flag (so the C flag is now set | |
\ to bit 7 of A) | |
ROR A \ Rotate A and set the sign bit to the C flag, so bits | |
\ 6 and 7 are now the same, i.e. A is a random number in | |
\ one of these ranges: | |
\ | |
\ %00000000 - %00111111 = 0 to 63 (r2 = 0 - 127) | |
\ %11000000 - %11111111 = 192 to 255 (r2 = 128 - 255) | |
\ | |
\ The PIX routine flips bit 7 of A before drawing, and | |
\ that makes -A in these ranges: | |
\ | |
\ %10000000 - %10111111 = 128-191 | |
\ %01000000 - %01111111 = 64-127 | |
\ | |
\ so that's in the range 64 to 191 | |
JSR PIX \ Draw a pixel at screen coordinate (X, -A), i.e. at | |
\ | |
\ (ZP / 2, -A) | |
\ | |
\ where ZP = SQRT(128^2 - (r1^2 + r2^2)) | |
\ | |
\ So this is the same as plotting at (x, y) where: | |
\ | |
\ r1 = random number from 0 to 255 | |
\ r1 = random number from 0 to 255 | |
\ (r1^2 + r1^2) < 128^2 | |
\ | |
\ y = r2, squished into 64 to 191 by negation | |
\ | |
\ x = SQRT(128^2 - (r1^2 + r1^2)) / 2 | |
\ | |
\ which is what we want | |
.PLC1 | |
DEC CNT \ Decrement the counter in CNT (the low byte) | |
BNE PLL1 \ Loop back to PLL1 until CNT = 0 | |
DEC CNT+1 \ Decrement the counter in CNT+1 (the high byte) | |
BNE PLL1 \ Loop back to PLL1 until CNT+1 = 0 | |
\ The following loop iterates CNT2(1 0) times, i.e. &1DD | |
\ or 477 times, and draws the background stars on the | |
\ loading screen | |
.PLL2 | |
JSR DORND \ Set A and X to random numbers, say A = r3 | |
TAX \ Set X = A | |
\ = r3 | |
JSR SQUA2 \ Set (A P) = A * A | |
\ = r3^2 | |
STA ZP+1 \ Set ZP+1 = A | |
\ = r3^2 / 256 | |
JSR DORND \ Set A and X to random numbers, say A = r4 | |
STA YY \ Set YY = r4 | |
JSR SQUA2 \ Set (A P) = A * A | |
\ = r4^2 | |
ADC ZP+1 \ Set A = A + r3^2 / 256 | |
\ = r4^2 / 256 + r3^2 / 256 | |
\ = (r3^2 + r4^2) / 256 | |
CMP #&11 \ If A < 17, jump down to PLC2 to skip to the next pixel | |
BCC PLC2 | |
LDA YY \ Set A = r4 | |
JSR PIX \ Draw a pixel at screen coordinate (X, -A), i.e. at | |
\ (r3, -r4), where (r3^2 + r4^2) / 256 >= 17 | |
\ | |
\ Negating a random number from 0 to 255 still gives a | |
\ random number from 0 to 255, so this is the same as | |
\ plotting at (x, y) where: | |
\ | |
\ x = random number from 0 to 255 | |
\ y = random number from 0 to 255 | |
\ (x^2 + y^2) div 256 >= 17 | |
\ | |
\ which is what we want | |
.PLC2 | |
DEC CNT2 \ Decrement the counter in CNT2 (the low byte) | |
BNE PLL2 \ Loop back to PLL2 until CNT2 = 0 | |
DEC CNT2+1 \ Decrement the counter in CNT2+1 (the high byte) | |
BNE PLL2 \ Loop back to PLL2 until CNT2+1 = 0 | |
\ The following loop iterates CNT3(1 0) times, i.e. &500 | |
\ or 1280 times, and draws the rings around the loading | |
\ screen's Saturn | |
.PLL3 | |
JSR DORND \ Set A and X to random numbers, say A = r5 | |
STA ZP \ Set ZP = r5 | |
JSR SQUA2 \ Set (A P) = A * A | |
\ = r5^2 | |
STA ZP+1 \ Set ZP+1 = A | |
\ = r5^2 / 256 | |
JSR DORND \ Set A and X to random numbers, say A = r6 | |
STA YY \ Set YY = r6 | |
JSR SQUA2 \ Set (A P) = A * A | |
\ = r6^2 | |
STA T \ Set T = A | |
\ = r6^2 / 256 | |
ADC ZP+1 \ Set ZP+1 = A + r5^2 / 256 | |
STA ZP+1 \ = r6^2 / 256 + r5^2 / 256 | |
\ = (r5^2 + r6^2) / 256 | |
LDA ZP \ Set A = ZP | |
\ = r5 | |
CMP #128 \ If A >= 128, set the C flag (so the C flag is now set | |
\ to bit 7 of ZP, i.e. bit 7 of A) | |
ROR A \ Rotate A and set the sign bit to the C flag, so bits | |
\ 6 and 7 are now the same | |
CMP #128 \ If A >= 128, set the C flag (so again, the C flag is | |
\ set to bit 7 of A) | |
ROR A \ Rotate A and set the sign bit to the C flag, so bits | |
\ 5-7 are now the same, i.e. A is a random number in one | |
\ of these ranges: | |
\ | |
\ %00000000 - %00011111 = 0-31 | |
\ %11100000 - %11111111 = 224-255 | |
\ | |
\ In terms of signed 8-bit integers, this is a random | |
\ number from -32 to 31. Let's call it r7 | |
ADC YY \ Set X = A + YY | |
TAX \ = r7 + r6 | |
JSR SQUA2 \ Set (A P) = r7 * r7 | |
TAY \ Set Y = A | |
\ = r7 * r7 / 256 | |
ADC ZP+1 \ Set A = A + ZP+1 | |
\ = r7^2 / 256 + (r5^2 + r6^2) / 256 | |
\ = (r5^2 + r6^2 + r7^2) / 256 | |
BCS PLC3 \ If the addition overflowed, jump down to PLC3 to skip | |
\ to the next pixel | |
CMP #80 \ If A >= 80, jump down to PLC3 to skip to the next | |
BCS PLC3 \ pixel | |
CMP #32 \ If A < 32, jump down to PLC3 to skip to the next pixel | |
BCC PLC3 | |
TYA \ Set A = Y + T | |
ADC T \ = r7^2 / 256 + r6^2 / 256 | |
\ = (r6^2 + r7^2) / 256 | |
CMP #16 \ If A > 16, skip to PL1 to plot the pixel | |
BCS PL1 | |
LDA ZP \ If ZP is positive (50% chance), jump down to PLC3 to | |
BPL PLC3 \ skip to the next pixel | |
.PL1 | |
LDA YY \ Set A = YY | |
\ = r6 | |
JSR PIX \ Draw a pixel at screen coordinate (X, -A), where: | |
\ | |
\ X = (random -32 to 31) + r6 | |
\ A = r6 | |
\ | |
\ Negating a random number from 0 to 255 still gives a | |
\ random number from 0 to 255, so this is the same as | |
\ plotting at (x, y) where: | |
\ | |
\ r5 = random number from 0 to 255 | |
\ r6 = random number from 0 to 255 | |
\ r7 = r5, squashed into -32 to 31 | |
\ | |
\ x = r5 + r7 | |
\ y = r5 | |
\ | |
\ 32 <= (r5^2 + r6^2 + r7^2) / 256 <= 79 | |
\ Draw 50% fewer pixels when (r6^2 + r7^2) / 256 <= 16 | |
\ | |
\ which is what we want | |
.PLC3 | |
DEC CNT3 \ Decrement the counter in CNT3 (the low byte) | |
BNE PLL3 \ Loop back to PLL3 until CNT3 = 0 | |
DEC CNT3+1 \ Decrement the counter in CNT3+1 (the high byte) | |
BNE PLL3 \ Loop back to PLL3 until CNT3+1 = 0 | |
\ ****************************************************************************** | |
\ | |
\ Name: DORND | |
\ Summary: Generate random numbers | |
\ | |
\ ****************************************************************************** | |
.DORND | |
LDA RAND+1 \ r1´ = r1 + r3 + C | |
TAX \ r3´ = r1 | |
ADC RAND+3 | |
STA RAND+1 | |
STX RAND+3 | |
LDA RAND \ X = r2´ = r0 | |
TAX \ A = r0´ = r0 + r2 | |
ADC RAND+2 | |
STA RAND | |
STX RAND+2 | |
RTS | |
.RAND | |
EQUD &6C785349 \ The random number seed used for drawing Saturn | |
\--------------------------------------------- BREAK FOR NEXT LINE | |
NOP:NOP:NOP:NOP:NOP | |
\--------------------------------------------- BREAK FOR NEXT LINE | |
\ ****************************************************************************** | |
\ | |
\ Name: SQUA2 | |
\ Summary: Calculate (A P) = A * A | |
\ | |
\ ****************************************************************************** | |
.SQUA2 | |
BPL SQUA \ If A > 0, jump to SQUA | |
EOR #&FF \ Otherwise we need to negate A for the SQUA algorithm | |
CLC \ to work, so we do this using two's complement, by | |
ADC #1 \ setting A = ~A + 1 | |
.SQUA | |
STA Q \ Set Q = A and P = A | |
STA P \ Set P = A | |
LDA #0 \ Set A = 0 so we can start building the answer in A | |
LDY #8 \ Set up a counter in Y to count the 8 bits in P | |
LSR P \ Set P = P >> 1 | |
\ and C flag = bit 0 of P | |
.SQL1 | |
BCC SQ1 \ If C (i.e. the next bit from P) is set, do the | |
CLC \ addition for this bit of P: | |
ADC Q \ | |
\ A = A + Q | |
.SQ1 | |
ROR A \ Shift A right to catch the next digit of our result, | |
\ which the next ROR sticks into the left end of P while | |
\ also extracting the next bit of P | |
ROR P \ Add the overspill from shifting A to the right onto | |
\ the start of P, and shift P right to fetch the next | |
\ bit for the calculation into the C flag | |
DEY \ Decrement the loop counter | |
BNE SQL1 \ Loop back for the next bit until P has been rotated | |
\ all the way | |
RTS | |
\ ****************************************************************************** | |
\ | |
\ Name: ROOT | |
\ Summary: Calculate ZP = SQRT(ZP(1 0)) | |
\ | |
\ ****************************************************************************** | |
.ROOT | |
LDY ZP+1 \ Set (Y Q) = ZP(1 0) | |
LDA ZP | |
STA Q | |
\ So now to calculate ZP = SQRT(Y Q) | |
LDX #0 \ Set X = 0, to hold the remainder | |
STX ZP \ Set ZP = 0, to hold the result | |
LDA #8 \ Set P = 8, to use as a loop counter | |
STA P | |
.LL6 | |
CPX ZP \ If X < ZP, jump to LL7 | |
BCC LL7 | |
BNE LL8 \ If X > ZP, jump to LL8 | |
CPY #64 \ If Y < 64, jump to LL7 with the C flag clear, | |
BCC LL7 \ otherwise fall through into LL8 with the C flag set | |
.LL8 | |
TYA \ Set Y = Y - 64 | |
SBC #64 \ | |
TAY \ This subtraction will work as we know C is set from | |
\ the BCC above, and the result will not underflow as we | |
\ already checked that Y >= 64, so the C flag is also | |
\ set for the next subtraction | |
TXA \ Set X = X - ZP | |
SBC ZP | |
TAX | |
.LL7 | |
ROL ZP \ Shift the result in Q to the left, shifting the C flag | |
\ into bit 0 and bit 7 into the C flag | |
ASL Q \ Shift the dividend in (Y S) to the left, inserting | |
TYA \ bit 7 from above into bit 0 | |
ROL A | |
TAY | |
TXA \ Shift the remainder in X to the left | |
ROL A | |
TAX | |
ASL Q \ Shift the dividend in (Y S) to the left | |
TYA | |
ROL A | |
TAY | |
TXA \ Shift the remainder in X to the left | |
ROL A | |
TAX | |
DEC P \ Decrement the loop counter | |
BNE LL6 \ Loop back to LL6 until we have done 8 loops | |
RTS | |
\ ****************************************************************************** | |
\ | |
\ Name: PIX | |
\ Summary: Draw a single pixel at a specific coordinate | |
\ | |
\ ****************************************************************************** | |
.PIX | |
TAY \ Copy A into Y, for use later | |
EOR #%10000000 \ Flip the sign of A | |
LSR A \ Set ZP+1 = &60 + A >> 3 | |
LSR A | |
LSR A | |
ORA #&60 | |
STA ZP+1 | |
TXA \ Set ZP = (X >> 3) * 8 | |
EOR #%10000000 | |
AND #%11111000 | |
STA ZP | |
TYA \ Set Y = Y AND %111 | |
AND #%00000111 | |
TAY | |
TXA \ Set X = X AND %111 | |
AND #%00000111 | |
TAX | |
.fix | |
LDA &C40C,X \ Otherwise fetch a pixel from TWOS and OR it into ZP+Y | |
ORA (ZP),Y | |
STA (ZP),Y | |
RTS \ Return from the subroutine | |
\ ****************************************************************************** | |
\ | |
\ Name: CNT | |
\ Summary: A counter for use in drawing Saturn's planetary body | |
\ | |
\ ****************************************************************************** | |
.CNT | |
EQUW &0500 \ The number of iterations of the PLL1 loop (1280) | |
\ ****************************************************************************** | |
\ | |
\ Name: CNT2 | |
\ Summary: A counter for use in drawing Saturn's background stars | |
\ | |
\ ****************************************************************************** | |
.CNT2 | |
EQUW &01DD \ The number of iterations of the PLL2 loop (477) | |
\ ****************************************************************************** | |
\ | |
\ Name: CNT3 | |
\ Summary: A counter for use in drawing Saturn's rings | |
\ | |
\ ****************************************************************************** | |
.CNT3 | |
EQUW &0500 \ The number of iterations of the PLL3 loop (1280) | |
\ values to poke at 6845 | |
.crtc_val | |
EQUB 32 | |
EQUB &0C | |
EQUB &00 | |
\ register to poke at 6845 | |
.crtc_reg | |
EQUB 1 | |
EQUB 12 | |
EQUB 13 | |
.end | |
SAVE "saturn", start, end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment