# Driving model: ApplyTyreForces

```       Name: ApplyTyreForces                                         [Show more]
Type: Subroutine
Category: Driving model
Summary: Calculate the tyre forces on the car
Deep dive: The core driving model
Skidding
Matching the code to the driving model
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* ApplyTyresAndSkids calls ApplyTyreForces

Calculate the following:

* If xVelocity is non-zero and xVelocity and xTyreForceNose for tyre X have
the same sign:

* Set the high byte of xTyreForceNose = -xVelocity * 2^5

* Rotate a 1 into bit 7 of tyreSqueal for tyre X and finish

* xTyreForceNose = -xVelocity * 2^5

* Call GetTyreForces to set (A T), H and (NN MM)

* If the throttle is being applied and we are processing the front tyres,
set:

zTyreForceNose = 0

A = |xTyreForceNoseHi|

otherwise:

* If the throttle is being applied, then set:

zTyreForceNose or zTyreForceRear = (A T) * abs(H)

otherwise set:

zTyreForceNose or zTyreForceRear = max((A T), (NN MM)) * abs(H)

* Set the following (as appropriate for tyre X):

A =   max(|xTyreForceNoseHi|, |zTyreForceNoseHi|)
+ min(|xTyreForceNoseHi|, |zTyreForceNoseHi|) / 2

* Rotate a new bit 7 into tyreSqueal for tyre X as follows:

* Clear if A <= wingForce for tyre X

* Set if A > wingForce for tyre X

Arguments:

X                    The set of tyres to process:

* 0 = front tyres

* 1 = rear tyres

.ApplyTyreForces

LDA xVelocityLo        \ Set T = xVelocityLo
STA T

ORA xVelocityHi        \ Set A = xVelocityLo OR xVelocityHi and store the flags
PHP                    \ on the stack, which will be zero if both the high and
\ low bytes of xVelocity are zero, i.e. if xVelocity = 0

LDA xVelocityHi        \ Set (A T) = (xVelocityHi xVelocityLo)

JSR Negate16Bit        \ Set (A T) = -(A T)
\           = -xVelocity

LDY #5                 \ Set Y = 5 to act as a shift counter in the following
\ loop

.tfor1

ASL T                  \ Set (A T) = (A T) << 1
ROL A

DEY                    \ Decrement the shift counter

BNE tfor1              \ Loop back until we have shifted left by five places,
\ so we now have:
\
\   (A T) = (A T) * 2^5
\         = -xVelocity * 2^5

STA xTyreForceNoseHi,X \ Set xTyreForceNoseHi for tyre X to the high byte of
\ the result

PLP                    \ Retrieve the flags that we stored on the stack, which
\ will be zero if xVelocity = 0

BEQ tfor2              \ If xVelocity = 0, jump to tfor2 to set
\ xTyreForceNoseLo to the low byte of the result

\ If we get here then xVelocity is non-zero

EOR xVelocityHi        \ If xVelocityHi and xTyreForceNoseHi for tyre X have
\ the same sign, this will clear bit 7 of A

SEC                    \ Set the C flag

BPL tfor7              \ If bit 7 of A is clear, then xVelocityHi and
\ xTyreForceNoseHi for tyre X have the same sign, so
\ jump to tfor7 with the C flag set to rotate a 1 into
\ bit 7 of tyreSqueal for tyre X

.tfor2

\ If we get here then either xVelocity = 0, or xVelocity
\ is non-zero and xVelocity and xTyreForceNose have
\ different signs

LDA T                  \ Set xTyreForceNoseLo = T, so we now have:
STA xTyreForceNoseLo,X \
\   xTyreForceNose = (A T)
\                  = -xVelocity * 2^5

JSR GetTyreForces      \ Calculate the tyre forces due to the throttle or
\ brakes:
\
\   * (A T) = the force
\
\   * H = the sign of the force
\
\   * G = X + 2, so the call to ApplyLimitThrottle sets
\     zTyreForceNose or zTyreForceRear accordingly
\
\   * If the throttle is not being applied, (NN MM) is
\     a maximum value for the force
\
\ If the throttle is being applied and we are processing
\ the front tyres, only G is calculated and the C flag
\ is set

BCC tfor3              \ If the C flag is clear then GetTyreForces successfully
\ to keep going

LDA #0                 \ Set zTyreForceNose = 0
STA zTyreForceNoseLo
STA zTyreForceNoseHi

LDA xTyreForceNoseHi   \ Set A = xTyreForceNoseHi

JSR Absolute8Bit       \ Set A = |A|
\       = |xTyreForceNoseHi|

.tfor3

JSR ApplyLimitThrottle \ If the throttle is being applied, then set
\ zTyreForceNose or zTyreForceRear to:
\
\   (A T) * abs(H)
\
\ otherwise set it to:
\
\    max((A T), (NN MM)) * abs(H)

LDA zTyreForceNoseHi,X \ Set A = zTyreForceNoseHi for tyre X

JSR Absolute8Bit       \ Set A = |A|
\       = |zTyreForceNoseHi|

STA T                  \ Set T = A
\       = |zTyreForceNoseHi|

LDA xTyreForceNoseHi,X \ Set A = xTyreForceNoseHi for tyre X

JSR Absolute8Bit       \ Set A = |A|
\       = |xTyreForceNoseHi|

CMP T                  \ If A < T then |xTyreForceNoseHi| < |zTyreForceNoseHi|,

\ If we get here then |xTyreForceNoseHi| >=
\ |zTyreForceNoseHi|, so we halve T

LSR T                  \ Set T = T >> 1
\       = |zTyreForceNoseHi| / 2

.tfor4

LSR A                  \ Set A = A >> 1
\       = |xTyreForceNoseHi| / 2

.tfor5

CLC                    \ Set A = A + T
\ So if |zTyreForceNoseHi| > |xTyreForceNoseHi|:
\
\   A = |zTyreForceNoseHi| + |xTyreForceNoseHi| / 2
\
\ or if |xTyreForceNoseHi| >= |zTyreForceNoseHi|:
\
\   A = |xTyreForceNoseHi| + |zTyreForceNoseHi| / 2
\
\ In other words:
\
\   A =  max(|xTyreForceNoseHi|, |zTyreForceNoseHi|)
\      + min(|xTyreForceNoseHi|, |zTyreForceNoseHi|) / 2

.tfor6

CMP wingForce,X        \ If A <> wingForce for tyre X, jump to tfor7 with the C
BNE tfor7              \ flag set as follows:
\
\   * Clear if A < wingForce
\
\   * Set if A > wingForce

CLC                    \ Clear the C flag for when A = wingForce, so in all we
\ have the following for the C flag:
\
\   * Clear if A <= wingForce
\
\   * Set if A > wingForce

.tfor7

ROR tyreSqueal,X       \ Rotate the C flag into bit 7 of tyreSqueal for tyre X

RTS                    \ Return from the subroutine
```