Skip to navigation

Aviator on the BBC Micro

Maths: ScaleSigned

Name: ScaleSigned [Show more] Type: Subroutine Category: Maths Summary: Scale an indicator value by 4 or 16, retaining the sign and adding sensitivity for smaller values
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * UpdateIndicator (Part 13 of 15) calls ScaleSigned * UpdateIndicator (Part 14 of 15) calls ScaleSigned

This routine is used to scale the values for the following indicators: * The joystick position display (indicator 8 or 10), where the x-coordinate is scaled by 16 and the y-coordinate by 4, as the display is taller than it is wide * Rudder (indicator 9), which is divided by 16 When scaling down by a factor of 16, some smaller values scale to 1 instead of 0 (specifically, 4 to 7), and in all cases the final scaling is rounded up, so this routine shows small deviations on the rudder and joystick indicators that otherwise wouldn't register.
Arguments: A The value to scale C flag Determines the scale factor: * C flag set = divide A by 16 * C flag clear = divide A by 4
.ScaleSigned PHP \ Store the flags on the stack, so we can check later \ what their values were on entry BPL scsi1 \ If A is positive, jump to scsi1 to skip the following \ three instructions EOR #&FF \ Set A = -A using two's complement, so A is positive CLC ADC #1 .scsi1 \ By this point, A = |A| LSR A \ Set A = |A| / 2 PLP \ Restore the flags from the stack, leaving them on the PHP \ stack for later BCC scsi3 \ If the C flag is clear, jump to scsi3 so we only \ divide the original value by 4 \ If we get here then the C flag was set on entry, so we \ want to divide A by 16 using four shifts in total LSR A \ Set A = A / 2 \ = |A| / 4 CMP #1 \ If A <> 1, skip the following instruction BNE scsi2 LDA #2 \ A = 1 (so the original |A| was in the range 4 to 7), \ so set A = 2, which will give us an end result of 1 \ \ In other words, this scales smaller values to 1 that \ would otherwise scale to 0, like this: \ \ * 0 to 3 scale down to 0 \ * 4 to 23 scale down to 1 \ * 24 to 39 scale down to 2 \ * 40 to 55 scale down to 3 \ \ and so on .scsi2 LSR A \ Set A = A / 2 \ = |A| / 8 .scsi3 LSR A \ Set A = A / 2 \ \ so this is: \ \ * |A| / 16 if the C flag was set on entry \ * |A| / 4 if the C flag was clear on entry ADC #0 \ Increment A if the value of A before the LSR was odd \ (so the result of the last division gets rounded up) \ \ This works because the LSR will set the C flag if bit \ 0 of A was set before the shift, so A gets bumped up \ by 1 by the ADC PLP \ Restore the flags from the stack BPL scsi4 \ If the N flag is clear, then the result already has \ the correct sign (positive), so jump to scsi4 to \ return from the subroutine EOR #&FF \ Set A = -A using two's complement, so A is now CLC \ negative and the sign matches the original value of A ADC #1 \ on entry into the subroutine .scsi4 RTS \ Return from the subroutine