Elite on the BBC Micro and NES

# Version analysis of MV40

This code appears in the following versions (click to see it in the source code):

Code variations between these versions are shown below.

Name: MV40 Type: Subroutine Category: Moving

Code variation 1 of 5A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

Summary: Rotate the planet or sun's location in space by the amount of pitch and roll of our ship
Summary: Rotate the planet's location in space by the amount of pitch and roll of our ship

We implement this using the same equations as in part 5 of MVEIT, where we rotated the current ship's location by our pitch and roll. Specifically, the calculation is as follows: 1. K2 = y - alpha * x 2. z = z + beta * K2 3. y = K2 - beta * z 4. x = x + alpha * y See the deep dive on "Rotating the universe" for more details on the above.

Code variation 2 of 5A variation in the comments only

This variation is blank in the Cassette, Disc (flight), 6502 Second Processor and Master versions.

Arguments: X The type of the planet Other entry points: MV40-1 Contains an RTS
.MV40

Code variation 3 of 5Related to the Electron version

As the Electron only has planets and no suns, the MV40 routine only moves the planet by our pitch and roll, and does nothing if asked to move the sun.

This variation is blank in the Cassette, Disc (flight), 6502 Second Processor and Master versions.

TXA \ If bit 0 of X is set, then this is 129, which is the LSR A \ placeholder used to denote that there is no space BCS MV40-1 \ station, so return from the subroutine (as MV40-1 \ contains an RTS)
LDA ALPHA              \ Set Q = -ALPHA, so Q contains the angle we want to
EOR #%10000000         \ roll the planet through (i.e. in the opposite
STA Q                  \ direction to our ship's roll angle alpha)

LDA INWK               \ Set P(1 0) = (x_hi x_lo)
STA P
LDA INWK+1
STA P+1

LDA INWK+2             \ Set A = x_sign

JSR MULT3              \ Set K(3 2 1 0) = (A P+1 P) * Q
\
\ which also means:
\
\   K(3 2 1) = (A P+1 P) * Q / 256
\            = x * -alpha / 256
\            = - alpha * x / 256

LDX #3                 \ Set K(3 2 1) = (y_sign y_hi y_lo) + K(3 2 1)
JSR MVT3               \              = y - alpha * x / 256

LDA K+1                \ Set K2(2 1) = P(1 0) = K(2 1)
STA K2+1
STA P

LDA K+2                \ Set K2+2 = K+2
STA K2+2

STA P+1                \ Set P+1 = K+2

LDA BETA               \ Set Q = beta, the pitch angle of our ship
STA Q

LDA K+3                \ Set K+3 to K2+3, so now we have result 1 above:
STA K2+3               \
\   K2(3 2 1) = K(3 2 1)
\             = y - alpha * x / 256

\ We also have:
\
\   A = K+3
\
\   P(1 0) = K(2 1)
\
\ so combined, these mean:
\
\   (A P+1 P) = K(3 2 1)
\             = K2(3 2 1)

JSR MULT3              \ Set K(3 2 1 0) = (A P+1 P) * Q
\
\ which also means:
\
\   K(3 2 1) = (A P+1 P) * Q / 256
\            = K2(3 2 1) * beta / 256
\            = beta * K2 / 256

LDX #6                 \ K(3 2 1) = (z_sign z_hi z_lo) + K(3 2 1)
JSR MVT3               \          = z + beta * K2 / 256

LDA K+1                \ Set P = K+1
STA P

STA INWK+6             \ Set z_lo = K+1

LDA K+2                \ Set P+1 = K+2
STA P+1

STA INWK+7             \ Set z_hi = K+2

LDA K+3                \ Set A = z_sign = K+3, so now we have:
STA INWK+8             \
\   (z_sign z_hi z_lo) = K(3 2 1)
\                      = z + beta * K2 / 256

\ So we now have result 2 above:
\
\   z = z + beta * K2

EOR #%10000000         \ Flip the sign bit of A to give A = -z_sign

JSR MULT3              \ Set K(3 2 1 0) = (A P+1 P) * Q
\                = (-z_sign z_hi z_lo) * beta
\                = -z * beta

LDA K+3                \ Set T to the sign bit of K(3 2 1 0), i.e. to the sign
AND #%10000000         \ bit of -z * beta
STA T

EOR K2+3               \ If K2(3 2 1 0) has a different sign to K(3 2 1 0),
BMI MV1                \ then EOR'ing them will produce a 1 in bit 7, so jump
\ to MV1 to take this into account

\ If we get here, K and K2 have the same sign, so we can
\ add them together to get the result we're after, and
\ then set the sign afterwards

Code variation 4 of 5Other (e.g. bug fix, optimisation)

A CLC instruction is omitted from the cassette version in the rotation routine in MV40; it isn't needed, so this claws back one precious byte.

Tap on a block to expand it, and tap it again to revert.

LDA K \ We now do the following sum: \CLC \ ADC K2 \ (A y_hi y_lo -) = K(3 2 1 0) + K2(3 2 1 0) \ \ starting with the low bytes (which we don't keep) \ \ The CLC instruction is commented out in the original \ source. It isn't needed because MULT3 clears the C \ flag, so this is an example of the authors finding \ one more precious byte to save
LDA K \ We now do the following sum: CLC \ ADC K2 \ (A y_hi y_lo -) = K(3 2 1 0) + K2(3 2 1 0) \ \ starting with the low bytes (which we don't keep) \ \ The CLC has no effect because MULT3 clears the C \ flag, so this instruction could be removed (as it is \ in the cassette version, for example)
LDA K \ We now do the following sum: ADC K2 \ \ (A y_hi y_lo -) = K(3 2 1 0) + K2(3 2 1 0) \ \ starting with the low bytes (which we don't keep) \ \ The addition works because MULT3 clears the C flag
LDA K+1                \ We then do the middle bytes, which go into y_lo
STA INWK+3

LDA K+2                \ And then the high bytes, which go into y_hi
STA INWK+4

LDA K+3                \ And then the sign bytes into A, so overall we have the
ADC K2+3               \ following, if we drop the low bytes from the result:
\
\   (A y_hi y_lo) = (K + K2) / 256

JMP MV2                \ Jump to MV2 to skip the calculation for when K and K2
\ have different signs

.MV1

LDA K                  \ If we get here then K2 and K have different signs, so
SEC                    \ instead of adding, we need to subtract to get the
SBC K2                 \ result we want, like this:
\
\   (A y_hi y_lo -) = K(3 2 1 0) - K2(3 2 1 0)
\
\ starting with the low bytes (which we don't keep)

LDA K+1                \ We then do the middle bytes, which go into y_lo
SBC K2+1
STA INWK+3

LDA K+2                \ And then the high bytes, which go into y_hi
SBC K2+2
STA INWK+4

LDA K2+3               \ Now for the sign bytes, so first we extract the sign
AND #%01111111         \ byte from K2 without the sign bit, so P = |K2+3|
STA P

LDA K+3                \ And then we extract the sign byte from K without the
AND #%01111111         \ sign bit, so A = |K+3|

SBC P                  \ And finally we subtract the sign bytes, so P = A - P
STA P

\ By now we have the following, if we drop the low bytes
\ from the result:
\
\   (A y_hi y_lo) = (K - K2) / 256
\
\ so now we just need to make sure the sign of the
\ result is correct

BCS MV2                \ If the C flag is set, then the last subtraction above
\ MV2 as we are done with this particular stage

LDA #1                 \ Otherwise the subtraction above underflowed, as K2 is
SBC INWK+3             \ the dominant part of the subtraction, so we need to
STA INWK+3             \ negate the result using two's complement, starting
\ with the low bytes:
\
\   y_lo = 1 - y_lo

LDA #0                 \ And then the high bytes:
SBC INWK+4             \
STA INWK+4             \   y_hi = 0 - y_hi

LDA #0                 \ And finally the sign bytes:
SBC P                  \
\   A = 0 - P

ORA #%10000000         \ We now force the sign bit to be negative, so that the
\ final result below gets the opposite sign to K, which
\ we want as K2 is the dominant part of the sum

.MV2

EOR T                  \ T contains the sign bit of K, so if K is negative,
\ this flips the sign of A

STA INWK+5             \ Store A in y_sign

\ So we now have result 3 above:
\
\   y = K2 + K
\     = K2 - beta * z

LDA ALPHA              \ Set A = alpha
STA Q

LDA INWK+3             \ Set P(1 0) = (y_hi y_lo)
STA P
LDA INWK+4
STA P+1

LDA INWK+5             \ Set A = y_sign

JSR MULT3              \ Set K(3 2 1 0) = (A P+1 P) * Q
\                = (y_sign y_hi y_lo) * alpha
\                = y * alpha

LDX #0                 \ Set K(3 2 1) = (x_sign x_hi x_lo) + K(3 2 1)
JSR MVT3               \              = x + y * alpha / 256

LDA K+1                \ Set (x_sign x_hi x_lo) = K(3 2 1)
STA INWK               \                        = x + y * alpha / 256
LDA K+2
STA INWK+1
LDA K+3
STA INWK+2

\ So we now have result 4 above:
\
\   x = x + y * alpha

Code variation 5 of 5A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

JMP MV45 \ We have now finished rotating the planet or sun by \ our pitch and roll, so jump back into the MVEIT \ routine at MV45 to apply all the other movements
JMP MV45 \ We have now finished rotating the planet by our pitch \ and roll, so jump back into the MVEIT routine at MV45 \ to apply all the other movements