Need an inline PASM function — Parallax Forums

# Need an inline PASM function

edited 2023-04-07 11:42

Can I get one of you PASM experts to create an inline function out of this equation?
`
{to clarify: x is the Var that changes each pass}
result=(x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;}

`
all of the inputs and outputs are integers with the largest being 3300 and the smallest 0. Out min is 0 and out max is 200 in min lowest is 0 highest is 3300. X is automatically constrained by the environment and will never fall outside the the in_min and in_Max.
Jim

• edited 2023-04-07 01:04

I'm not a PASM expert, but do dabble a bit.

It sounds like you want to constrain an input between 0..3300 and scale it to 0..200.

```pub scale(x) : result

x := 0 #> x <# 3300

return x * 200 / 3300

pub scale_pasm(x) : result

org
fges      x, #0
fles      x, ##3300
mul       x, #200
qdiv      x, ##3300
getqx     result
end
```

In a timing test of both passing a variable to the method the first ran in 3.64us, the inline PASM version in 3.36us. If you need it to go faster you can install the PASM in the top part of the interpreter so you don't have the overhead of loading it every time.

Update: I tried the technique of installing the PASM code in the interpreter cog. It still requires a Spin interface, and is faster than native Spin, but not quite as fast as the inline version of the code.

• edited 2023-04-07 01:36

Forget all that -- this is fastest (by 2x) since you're doing a simple mx equation.

```  scaled := (0 #> raw <# 3300) sca 260_301_049
```

The value for sca is 200 / 3300 * (2^32)

It's even faster (by 2x again) if your input value doesn't need to be constrained.

• Thanks jon,
I have to think about about this for a while. What I see you doing is letting the compiler do some of the calculations on the numbers and only calculating on the fly the changing var.
Jim

• @RS_Jim : It's worth mentioning here that @JonnyMac is using the standard PNut / PropTool Spin2 interpreter. If you use a different compiler or interpreter your results will vary -- for example, in flexspin the inline PASM is actually slower than the regular method, because flexspin is compiling the code to PASM anyway. Even in flexspin the SCA operator method that Jon posted seems to be the fastest approach, so that's probably the best way to go.

• @ersmith,
Thanks for the input Eric. Yes I work in Linux and use only flexprop. I will see what happens when I use Jon's method.
Jim

• edited 2023-04-07 12:59

What Eric didn't mention: On FlexSpin, you generally want to use the ASM/ENDASM style inline assembly rather than ORG/END. The former is processable by the optimizer and can thus be inlined...

You can go even faster if you use a somewhat lower precision approximation that can run on the fast multiplier

```pub scale_inline(x) : result

asm
fges      x, #0
fles      x, ##3300
mul       x, #round((220.0 / 3300.0) 65536.0)
shr       x, #16
mov       result,x
endasm
```

or with slightly different rounding:

```pub scale_inline(x) : result

asm
fges      x, #0
fles      x, ##3300
mul       x, #round((220.0 / 3300.0) 65536.0)
shr       x, #16    wc
mov       result,x
endasm
```
• Yes I work in Linux and use only flexprop

Why, then, would you ask for PASM when you're using a tool that already outputs PASM?

What I see you doing is letting the compiler do some of the calculations on the numbers and only calculating on the fly the changing var.

I just simplified the expression. From your description, it would have been:

```  scaled := (raw - 0) * (200 - 0) / (3300 - 0) + 0
```

Internally, the sca instruction is identical to what Ada suggested. The constant used in that version represents 200/3300 but for 32 bits (Ada is using 16, which is probably fine for such a small output range).

• @JonnyMac said:

Yes I work in Linux and use only flexprop

Why, then, would you ask for PASM when you're using a tool that already outputs PASM?

Well, flexspin can very rarely choose MUL(S) over QMUL, so explicitly spelling things like that out in ASM is actual helpful. (In particular, both sides of a multiply need to either be a small constant, a word/byte sized variable or a zerox/signx sub-expression for flexspin to generate a MUL or MULS)