Skip to navigation

Elite on the BBC Micro and NES

Moving: MVT1

[NES version, Bank 0]

Name: MVT1 [Show more] Type: Subroutine Category: Moving Summary: Calculate (x_sign x_hi x_lo) = (x_sign x_hi x_lo) + (A R)
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * MVEIT (Part 6 of 9) calls MVT1 * SFS2 calls MVT1 * MVEIT (Part 3 of 9) calls via MVT1-2

Add the signed delta (A R) to a ship's coordinate, along the axis given in X. Mathematically speaking, this routine translates the ship along a single axis by a signed delta. Taking the example of X = 0, the x-axis, it does the following: (x_sign x_hi x_lo) = (x_sign x_hi x_lo) + (A R) (In practice, MVT1 is only ever called directly with A = 0 or 128, otherwise it is always called via MVT-2, which clears A apart from the sign bit. The routine is written to cope with a non-zero delta_hi, so it supports a full 16-bit delta, but it appears that delta_hi is only ever used to hold the sign of the delta.) The comments below assume we are adding delta to the x-axis, though the axis is determined by the value of X.
Arguments: (A R) The signed delta, so A = delta_hi and R = delta_lo X Determines which coordinate axis of INWK to change: * X = 0 adds the delta to (x_lo, x_hi, x_sign) * X = 3 adds the delta to (y_lo, y_hi, y_sign) * X = 6 adds the delta to (z_lo, z_hi, z_sign)
Other entry points: MVT1-2 Clear bits 0-6 of A before entering MVT1
AND #%10000000 ; Clear bits 0-6 of A .MVT1 ASL A ; Set the C flag to the sign bit of the delta, leaving ; delta_hi << 1 in A STA S ; Set S = delta_hi << 1 ; ; This also clears bit 0 of S LDA #0 ; Set T = just the sign bit of delta (in bit 7) ROR A STA T LSR S ; Set S = delta_hi >> 1 ; = |delta_hi| ; ; This also clear the C flag, as we know that bit 0 of ; S was clear before the LSR EOR INWK+2,X ; If T EOR x_sign has bit 7 set, then x_sign and delta BMI MV10 ; have different signs, so jump to MV10 ; At this point, we know x_sign and delta have the same ; sign, that sign is in T, and S contains |delta_hi|, ; so now we want to do: ; ; (x_sign x_hi x_lo) = (x_sign x_hi x_lo) + (S R) ; ; and then set the sign of the result to the same sign ; as x_sign and delta LDA R ; First we add the low bytes, so: ADC INWK,X ; STA INWK,X ; x_lo = x_lo + R LDA S ; Then we add the high bytes: ADC INWK+1,X ; STA INWK+1,X ; x_hi = x_hi + S LDA INWK+2,X ; And finally we add any carry into x_sign, and if the ADC #0 ; sign of x_sign and delta in T is negative, make sure ORA T ; the result is negative (by OR'ing with T) STA INWK+2,X RTS ; Return from the subroutine .MV10 ; If we get here, we know x_sign and delta have ; different signs, with delta's sign in T, and ; |delta_hi| in S, so now we want to do: ; ; (x_sign x_hi x_lo) = (x_sign x_hi x_lo) - (S R) ; ; and then set the sign of the result according to ; the signs of x_sign and delta LDA INWK,X ; First we subtract the low bytes, so: SEC ; SBC R ; x_lo = x_lo - R STA INWK,X LDA INWK+1,X ; Then we subtract the high bytes: SBC S ; STA INWK+1,X ; x_hi = x_hi - S LDA INWK+2,X ; And finally we subtract any borrow from bits 0-6 of AND #%01111111 ; x_sign, and give the result the opposite sign bit to T SBC #0 ; (i.e. give it the sign of the original x_sign) ORA #%10000000 EOR T STA INWK+2,X BCS MV11 ; If the C flag is set by the above SBC, then our sum ; above didn't underflow and is correct - to put it ; another way, (x_sign x_hi x_lo) >= (S R) so the result ; should indeed have the same sign as x_sign, so jump to ; MV11 to return from the subroutine ; Otherwise our subtraction underflowed because ; (x_sign x_hi x_lo) < (S R), so we now need to flip the ; subtraction around by using two's complement to this: ; ; (S R) - (x_sign x_hi x_lo) ; ; and then we need to give the result the same sign as ; (S R), the delta, as that's the dominant figure in the ; sum LDA #1 ; First we subtract the low bytes, so: SBC INWK,X ; STA INWK,X ; x_lo = 1 - x_lo LDA #0 ; Then we subtract the high bytes: SBC INWK+1,X ; STA INWK+1,X ; x_hi = 0 - x_hi LDA #0 ; And then we subtract the sign bytes: SBC INWK+2,X ; ; x_sign = 0 - x_sign AND #%01111111 ; Finally, we set the sign bit to the sign in T, the ORA T ; sign of the original delta, as the delta is the STA INWK+2,X ; dominant figure in the sum .MV11 RTS ; Return from the subroutine