## 8 bit fractional numbers in GCC

12 posts / 0 new
Author
Message

Is there a way to use 8 bit fractional numbers in GCC?

My goal is to have the the compiler generate a single FMUL instruction when
multiplying two 8 bit fractional numbers.

Thanks

Gabriel

How would you tell the C language that a number is fractional and why would you need to use it? And the FMUL instruction is simply a regular multiply with a 1 bit left shift. And if you are doing fixed point math, you will have to interpret where the decimal point is yourself since C has absolutely no knowledge of fixed point math.

If you really need such a thing, then just use inline assembly.

Regards,
Steve A.

The Board helps those that help themselves.

Where is your binary point? Are you doing signed 8 bit fixed point in the range [-1.0..+0.9997]? (or whatever it works out too... it's been a while since I did fixed point).

Anyway, if you convince the compiler that you really have two signed 8 bit ints, then, the 8x8 multiply will give you a 16 bit result with the binary point off by one. IIRC you can simply shift the result left by one bit position and take the upper byte.

```int8_t a,b,c; // really signed fixed point

c = (a * b) >> 7;
```

What the the compiler generate for this?

I want to use signed and unsigned fractional numbers as described in this application note:

http://www.atmel.com/dyn/resourc...

```Unsigned Fractional, range [0 to 2):
BIT    7    6    5    4    3    2    1    0
value  2^0  2^-1 2^-2 2^-3 2^-4 2^-5 2^-6 2^-7

Signed Fractional, range [-1, 1):
BIT    7    6    5    4    3    2    1    0
value -2^0  2^-1 2^-2 2^-3 2^-4 2^-5 2^-6 2^-7
```

Using fractional numbers is very convinient when doing math, for example, I want to multiply 8 bit numbers by a sinetable, since the sine is in the range [-1, 1], it fits nicely using the FMULSU opcode.

dbc's suggestion:

```int main(void) {
int8_t a,b,c; // really signed fixed point
a=PINA;
b=PINB;
c = (a * b) >> 7;
PORTC = c;
}
```

Generates this assembly:

```+0000005D:   B120        IN      R18,0x00         In from I/O location
+0000005E:   B183        IN      R24,0x03         In from I/O location
+0000005F:   0282        MULS    R24,R18          Multiply signed
+00000060:   01C0        MOVW    R24,R0           Copy register pair
+00000061:   2411        CLR     R1               Clear Register
+00000062:   0F88        LSL     R24              Logical Shift Left
+00000063:   2F89        MOV     R24,R25          Copy register
+00000064:   1F88        ROL     R24              Rotate Left Through Carry
+00000065:   0B99        SBC     R25,R25          Subtract with carry
+00000066:   B988        OUT     0x08,R24         Out to I/O location
```

It works, but those extra shifts could be done automatically if using the FMUL instruction.

If there is no other way I will have to do some inline assembly, as Koshchi is suggesting.

Gabriel

Is there some way to scale your unsigned number to the range [0..1) instead of [0..2)? Because then the upper byte ends up with the binary point in the right place.

I would hope that:

```c = (a * b) >> 8;  // signed = signed * unsigned
```

generates a simple mov, and not a bunch of pointless shifting.

In the end, inline asm might be the simplest solution. To aid readability you could consider using C++ (very carefully!) to get operator overloading to make the code more readable. There was a good post a few weeks back summarizing avr-c++ quirks that is worth digging up if you decide to take that path.

Hello

ganzziani wrote:
Is there a way to use 8 bit fractional numbers in GCC?

My goal is to have the the compiler generate a single FMUL instruction when
multiplying two 8 bit fractional numbers.

My patch adds the '__builtin_avr_fmul*' builtins in avr-gcc.

```extern unsigned int __builtin_avr_fmul(unsigned char __a, unsigned char __b);
extern int __builtin_avr_fmuls(char __a, char __b);
extern int __builtin_avr_fmulsu(char __a, unsigned char __b);```

Re: [avr-gcc-list] Add builtins in avr target:
http://lists.nongnu.org/archive/html/avr-gcc-list/2008-04/msg00171.html

I hope in the future it will be added in GCC.

Anatoly.

Anatoly:

This is just what I am looking for!

But how do I use (or install?) the patch?

Thanks!

Gabriel

Sorry, only one query: is there a way to use GCC, GDB... on Zilog Z80 that is a 8 bit cpu? Awaiting for your reply as soon as possible, GREETINGS, Paul p.s: I am available to use Compilers, Debuggers.... only if they are FREE SOFTWARE, they must be: GPL and LGPL License.

This is a poor choice for a thread! But, NO, at least not AVR-gcc. You should really ask some place that specializes in Z80. I see Zilog Developer Studio on the Zilog web page and it appears to be free. As far as I know, gpl and lgpl licenses apply only to the software, and not what the software creates.

https://www.zilog.com/index.php?...

By the way, there does not appear to be any "pure Z80" chips on the retail market any more, but plenty of later generation derivatives.

Jim

Until Black Lives Matter, we do not have "All Lives Matter"!

Last Edited: Sat. Sep 7, 2019 - 07:11 PM

you can, I believe using fixed-point types

```\$ cat zz.c
#include <stdfix.h>

short fract mul(short fract a, short fract b) {
return a*b;
}

\$ /opt/local/bin/avr-gcc -DF_CPU=3333333 -mmcu=atmega4809 -Os -B/opt/local/avr/packs/1.3.300 -S zz.c -o zz.s

\$ cat zz.s
.file	"zz.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__CCP__ = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
.text
.global	mul
.type	mul, @function
mul:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
mov r18,r24
fmuls r18,r22
dec r1
brvs 0f
inc r1
0:
mov r24,r1
clr __zero_reg__
/* epilogue start */
ret
.size	mul, .-mul
.ident	"GCC: (GNU) 8.3.0"```

The earlier part of this thread is over 11 years old!  I have no clue why pavelz attached his question to this ancient thread.

Jim

Until Black Lives Matter, we do not have "All Lives Matter"!