Skip to navigation

Elite on the BBC Micro and NES

Moving: MV40

[NES version, Bank 0]

Name: MV40 [Show more] Type: Subroutine Category: Moving Summary: Rotate the planet or sun's location in space by the amount of pitch and roll of our ship
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * MVEIT (Part 2 of 9) calls MV40

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.
.MV40 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 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+1 ; We then do the middle bytes, which go into y_lo ADC K2+1 STA INWK+3 LDA K+2 ; And then the high bytes, which go into y_hi ADC K2+2 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 ; didn't underflow and the result is correct, so jump to ; 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 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