04 January 2022, 10:54 | #1 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 2,002
|
Casting floats to uint (or rather not) with VBCC
Hi,
What I want to do is to have a single precision float number and endian swap it before I store it in a PCI register. I have something like StorePCI((ULONG)pciaddress, (float)driver->xvalue); and StorePCI being: StorePCI(__reg("a0") ULONG address, __reg("d0") ULONG value)="\trol.w\t#8,d0\n\tswap\td0\n\trol.w\t#8,d0\n\tmove.l\td0,(a0)\n"; What I need is something like: fmove.s #1,fp0 //let's say value stored in driver->xvalue fmove.s fp0,d0 move.l #pciaddress,a0 rol.w #8,d0 swap d0 rol.w #8,d0 move.l d0,(a0) What I end up with is a fmove.d fp0,d0. So the integer value is stored in d0 ($1) instead of the floating point "raw" value ($3f800000) How can I actually byteswap $3f800000 instead of $1 with VBCC. I have tried all different kinds of casting. I am a bit lost. |
04 January 2022, 11:12 | #2 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,233
|
Does vbcc actually support single precision IEEE numbers? I'm asking, because SAS/C does not, it only supports mathffp numbers and double precisoin IEEE numbers.
However, in case it does - and check for the right math options - the following should do it: Code:
union { float u_float; uint32_t u_int; } u; u.u_float = f; /* put the float value into the union */ i = (u.u_int >> 24) | ((u.u_int >> 8) & 0xff00) | ((u.u_int << 8) & 0xff0000) | ((u.u_int << 24)); /* perform endian swap */ |
04 January 2022, 11:20 | #3 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 2,002
|
|
04 January 2022, 11:23 | #4 | |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 2,002
|
Quote:
Now I am trying to compile with VBCC and the result is different. I did not change the source except the asm macro. (Same with PPC where the old compiled program with gcc uses stfs and vbcc uses stfd (single versus double)) or it just get loaded with a lwz. Last edited by Hedeon; 04 January 2022 at 12:51. |
|
04 January 2022, 12:57 | #5 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 2,002
|
So the differences:
If float calculations are done, GCC in the end stores it in d0 using a fmove.s. When the value/parameter is directly used with no calculations it just uses move.l to d0 VBCC after calculations does a fmove.d to store the result in d0. When the value is taken directly, it casts using fmove.d to d0 |
04 January 2022, 13:56 | #6 | |
Registered User
Join Date: Jan 2021
Location: Germany
Posts: 18
|
Quote:
Anyway, why not use one of those: Best for soft-float only: Code:
StorePCI(__reg("a0") ULONG address, __reg("d0") float value)="\trol.w\t#8,d0\n\tswap\td0\n\trol.w\t#8,d0\n\tmove.l\td0,(a0)\n"; Code:
StorePCI(__reg("a0") ULONG address, __reg("fp0") float value)="\tfmove.s\tfp0,d0\n\trol.w\t#8,d0\n\tswap\td0\n\trol.w\t#8,d0\n\tmove.l\td0,(a0)\n"; Code:
StorePCI(__reg("a0") ULONG address, float value)="\tmove.l\t(a7),d0\n\trol.w\t#8,d0\n\tswap\td0\n\trol.w\t#8,d0\n\tmove.l\td0,(a0)\n"; Code:
#if __FPU__>68000 void StorePCI(__reg("a0") ULONG address, __reg("fp0") float value)="\tfmove.s\tfp 0,d0\n\trol.w\t#8,d0\n\tswap\td0\n\trol.w\t#8,d0\n\tmove.l\td0,(a0)\n"; #else void StorePCI(__reg("a0") long address, __reg("d0") float value)="\trol.w\t#8,d0\ n\tswap\td0\n\trol.w\t#8,d0\n\tmove.l\td0,(a0)\n"; #endif |
|
04 January 2022, 14:07 | #7 | ||
Registered User
Join Date: Jan 2021
Location: Germany
Posts: 18
|
Quote:
Quote:
What you can do is using a char * pointer to the float variable and read out the individual bytes. Note that only char * is allowed here without breaking aliasing rules. |
||
04 January 2022, 14:47 | #8 | |||
Registered User
Join Date: Feb 2017
Location: Denmark
Posts: 1,107
|
Quote:
Isn't it explicitly allowed in C99 and later? ยง6.5.2.3.3: Quote:
Quote:
P.S. In C++ reinterpret_cast won't work, you either have to use memcpy or std::bit_cast (from C++20) |
|||
04 January 2022, 14:48 | #9 | ||
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,500
|
Quote:
So, as Thomas correctly pointed out, you have to go over a temporary memory location. In C this is usually done with a union, as shown in his example. If you want it as an assembler inline function, it could look like this: Code:
void StorePCI(__reg("a0") void *addr, __reg("fp0") float val) = "\tfmove.s\tfp0,-(sp)\n" "\tmove.l\t(sp)+,d0\n" "\trol.w\t#8,d0\n" "\tswap\td0\n" "\trol.w\t#8,d0\n" "\tmove.l\td0,(a0)"; Quote:
AFAIK gcc's m68k backend only knows the V.4-ABI, which makes a function always return float results in data registers (d0 for single, d0/d1 for double precision), while the AmigaOS-ABI prefers to use fp0 when compiled with an FPU-option. There is the -no-fp-return option to switch vbcc to V.4-ABI for floating point return values. Last edited by phx; 04 January 2022 at 14:52. Reason: EDIT: My answer was delayed by a 1h phone call. You can safely ignore it and refer to Volker's posting! |
||
04 January 2022, 15:03 | #10 | |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,233
|
Quote:
See, for example: https://stackoverflow.com/questions/...through-unions |
|
04 January 2022, 15:04 | #11 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,233
|
Sure it does. "fmove.s fpx,dy" works nicely. It transfers the bit-pattern of the source fpu register, rounded to 32-bit single precision, to the data register dy. Would be rather bad if this wouldn't work because the processor libraries are full of such code. (-;
|
04 January 2022, 15:21 | #12 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,500
|
|
04 January 2022, 15:35 | #13 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 2,002
|
I made stuff more complicated to try to compile for both ppc and m68k. The ppc does not have direct fpu register to general register modes. So yesterday I ended up with sending the (ULONG*)&driver->xvalue to StorePCI and made value in the asm macro also ULONG* and added a normal load from memory to the data register first. Compiled for at least 68020 and fpu 68881. This also worked for PPC (with -lm).
However, while the speed from the vbcc m68k generated was comparable to gcc (around 5% slower on my 68060), the ppc generated one took a 40% speed hit. I guessed because for 68k the number of opcodes in the macro went from 4 to 5, while the ppc one went from 1 (a single stwbrx) to 2. Also, when looking at the differences in the code where vbcc uses more (double precision) fpu opcodes while gcc uses more general registers directly, I wondered if the mistake was in the casting as I really wanted to ditch those extra opcodes in the asm macros again for speed reasons. This function is used a lot. Hence the post, but focused on m68k while there is more expertise there. Looking at the answers it looks like that for ppc and speed wise I have to revert to gcc2.95 anyway. Sorry for the maybe a bit misleading first post. |
04 January 2022, 16:32 | #14 | |
Registered User
Join Date: Jan 2021
Location: Germany
Posts: 18
|
This footnote is not in my copy of the standard and it was apparently added later through a defect report. While I agree that the wording is somewhat misleading, the defect report suggests that it was intended as clarification, perhaps to allow a trap representation in all cases.
There still is 6.5p7 which lists all allowed types for accessing an lvalue: Quote:
|
|
04 January 2022, 16:52 | #15 | ||
Registered User
Join Date: Jan 2021
Location: Germany
Posts: 18
|
Gesundheit!
Quote:
Quote:
That seems to contain a lot of opinions without any backing. comp.std.c was the place to get decent information on such topics. Unfortunately newsgroups are not much in fashion any more. |
||
04 January 2022, 17:15 | #16 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,233
|
See here for the references: https://stackoverflow.com/questions/...-what-does-not I suggest then to go checking there if you don't believe me. I run into this issue a while ago, this is why I mention it. Storing in memory and going through a pointer cast is indeed not going to work, and had issues with that with, for example, the icc compiler. The "union hack", as you call it, solves that type of problem. |
04 January 2022, 17:56 | #17 | |
Registered User
Join Date: Feb 2017
Location: Denmark
Posts: 1,107
|
Quote:
I have to admit the issue is less clear than I remembered it, and it might be the case that the standard technically doesn't require type-punning through unions to be supported (this stackoverflow answer makes a persuasive argument). You're also right that it was added through a defect report (DR283). Following the linked discussions, I think it's quite clear (from proposal N980) that the intention was to allow it though. It's certainly widely believed to be, as evidences by this thread |
|
04 January 2022, 19:12 | #18 | |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 2,002
|
Quote:
int main(void) { float x; x = 1.0; return int(x); } result is moveq #1,d0 and sadly not move.l #$3f800000,d0 The union approach has me changing a lot of the code. Will take a while. |
|
04 January 2022, 19:49 | #19 | |||
Registered User
Join Date: Jan 2021
Location: Germany
Posts: 18
|
Quote:
Quote:
Quote:
|
|||
04 January 2022, 19:54 | #20 | |
Registered User
Join Date: Feb 2017
Location: Denmark
Posts: 1,107
|
Quote:
Is there any reason why you couldn't just do this? Code:
#ifdef __M68K__ #ifdef __GNUC__ void StorePCIFloat(ULONG address, float f) { union { float f; ULONG u; } u = { .f = f }; *(volatile ULONG*)address = __builtin_bswap32(u.u); } #else void StorePCIFloat(__reg("a0") ULONG address, __reg("fp0") float value)="\tfmove.s\tfp0,d0\n\trol.w\t#8,d0\n\tswap\td0\n\trol.w\t#8,d0\n\tmove.l\td0,(a0)\n"; #endif #else // Insert equivalent PPC magic #endif The above generates very sensible code with both Bebbos GCC and VBCC. GCC even manages to convert StorePCIFloat(0x1234, 1.0f) into move.l #32831,4660.w. |
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
VBCC - What's going on here? | deimos | Coders. C/C++ | 69 | 28 July 2018 16:14 |
Space Hulk (1993) - Question about ray casting & graphics | Cherno | Nostalgia & memories | 0 | 27 August 2017 10:24 |
Integers vs floats (FFP/Sing/Doub) + printf() | guy lateur | Coders. Asm / Hardware | 63 | 18 July 2017 17:57 |
Ray casting | sandruzzo | Coders. General | 14 | 21 June 2017 01:06 |
AmiDevCpp and Floats | AmigaEd | Coders. General | 0 | 18 January 2006 03:16 |
|
|