Aviator on the BBC Micro

# Dashboard: UpdateIndicator (Part 4 of 15)

```       Name: UpdateIndicator (Part 4 of 15)                          [Show more]
Type: Subroutine
Category: Dashboard
Summary: Calculations for the altimeter's small "hour" hand (indicator 2)
Deep dive: Hard-coded division in the dashboard routines
Context: See this subroutine in context in the source code
References: No direct references to this subroutine in this source file

This section takes the altitude from (yPlaneHi yPlaneLo) and reduces it to
the range 0 to 254, before passing it to the DrawIndicatorHand to update the
small hand of the on-screen altimeter.

It also sets altitudeMinutes to the low byte of the altitude, reduced to the
range 0 to 104, so it can be used in part 5 to update the large hand of the
on-screen altimeter.

.uind4

\ If we get here then the indicator number in X is 2

LDA yPlaneLo           \ Set (A R) = (yPlaneHi yPlaneLo)
STA R
LDA yPlaneHi

LSR A                  \ Set (S R) = (A R) / 4
ROR R                  \           = (yPlaneHi yPlaneLo) / 4
LSR A                  \           = altitude
ROR R                  \
STA S                  \ so (S R) is the altitude in feet, as the value stored
\ in (yPlaneHi yPlaneLo) is the actual altitude x 4

LDA #0                 \ Set T = 0
STA T

\ We now calculate A = R * n / 256 with a hardcoded n,

LDA R                  \ Set A = R

LSR A                  \ Bit 0 of n is 0

LSR A                  \ Bit 1 of n is 0

CLC                    \ Bit 2 of n is 1
ROR A

LSR A                  \ Bit 3 of n is 0

CLC                    \ Bit 4 of n is 1
ROR A

CLC                    \ Bit 5 of n is 1
ROR A

LSR A                  \ Bit 6 of n is 0

\ Bit 7 of n is 0 and the final right shift is missing

\ From the above, n = %000110100 (52), so we just
\ calculated:
\
\   A = (R * n / 256) << 1
\     = (R * 52 / 256) << 1
\     = R * 104 / 256
\
\ which is the low byte of the altitude in (S R),
\ reduced to a range of 0 to 104 to represent the whole
\ dial's range of 0 to 1,000 feet

STA altitudeMinutes    \ Store the result in altitudeMinutes, so we can draw
\ the altimeter's minute hand in indicator 3

\ We now calculate A = S * n / 256 with a hardcoded n,
\ using unrolled shift-and-add multiplication and
\ keeping the overspill from the result

LDA S                  \ Set A = S

LSR A                  \ Bit 0 of n is 0
ROR T

LSR A                  \ Bit 1 of n is 0
ROR T

CLC                    \ Bit 2 of n is 1
ROR A
ROR T

LSR A                  \ Bit 3 of n is 0
ROR T

CLC                    \ Bit 4 of n is 1
ROR A
ROR T

CLC                    \ Bit 5 of n is 1
ROR A
ROR T

LSR A                  \ Bit 6 of n is 0
ROR T

\ Bit 7 of n is 0 and the final right shift is missing

\ From the above, n = %00110100 (52), so we just
\ calculated:
\
\   A = (S * n / 256) << 1
\     = (S * 52 / 256) << 1
\     = S * 104 / 256
\
\ and T contains the overspill from the result

STA U                  \ Set U = S * 104 / 256

LDA T                  \ Set (U A) = (U altitudeMinutes) + (0 T)
CLC                    \

BCC uind5              \ And, if the addition overflowed, incrementing the high
INC U                  \ byte in U

\ So we have just calculated:
\
\   (U A) = (U altitudeMinutes) + (0 T)
\
\ and we already know that:
\
\   U = S * 104 / 256
\
\   altitudeMinutes = R * 104 / 256
\
\ so plugging these into the above, we get:
\
\   (U A) = (U altitudeMinutes) + (0 T)
\         = (S*104 R*104) / 256 + (0 T)
\         = (S R) * 104 / 256

.uind5

LSR U                  \ Set (U A) = (U A) / 16
ROR A                  \           = ((S R) * 104 / 256) / 16
LSR U                  \           = (S R) * 6.5 / 256
ROR A                  \
LSR U
ROR A
LSR U
ROR A

\ So by now, A is in the range 0 to 254 - here's why:
\
\ The maximum altitude that the altimeter can show is
\ 10,000 feet (after which it just wraps around), so the
\ final result of all these calculations is that the
\ altitude in (S R) has been reduced from a range of 0
\ to 10,000 to a range of 0 to 254 in (U A), as:
\
\   10000 * 6.5 / 256 = 254
\
\ and that value is in A alone, as (U A) < 255, so U = 0

JMP DrawIndicatorHand  \ Apply min and max limits to the value in A and update
\ the indicator on-screen, returning from the subroutine
\ using a tail call
```