Skip to navigation


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 \ returned a set of calculated values, so jump to tfor3 \ to keep going LDA #0 \ Set zTyreForceNose = 0 STA zTyreForceNoseLo STA zTyreForceNoseHi LDA xTyreForceNoseHi \ Set A = xTyreForceNoseHi JSR Absolute8Bit \ Set A = |A| \ = |xTyreForceNoseHi| JMP tfor6 \ Jump to tfor6 .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|, BCC tfor4 \ so jump to tfor4 to halve A \ If we get here then |xTyreForceNoseHi| >= \ |zTyreForceNoseHi|, so we halve T LSR T \ Set T = T >> 1 \ = |zTyreForceNoseHi| / 2 JMP tfor5 \ Jump to tfor5 .tfor4 LSR A \ Set A = A >> 1 \ = |xTyreForceNoseHi| / 2 .tfor5 CLC \ Set A = A + T ADC 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