Page 1 of 2
Simple Big Endian / Little Endian byte order swap function.
Posted: Thu Mar 24, 2005 8:30 am
by Rescator
Ever needed to swap the byte order when working with LittleEndian and BigEndian values?
Here is a quick solution.
32bit value swap
Code: Select all
Procedure.l Endian(val.l)
!MOV Eax,dword[p.v_val]
!BSWAP Eax
ProcedureReturn
EndProcedure
Example:
64bit value swap (PS! the ordering (pairing) of instructions is in an attempt to support hyper threading and similar)
Code: Select all
CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
Procedure.q EndianQ(val.q)
!MOV rax,qword[p.v_val]
!BSWAP rax
ProcedureReturn
EndProcedure
CompilerElse
Procedure.q EndianQ(val.q)
!MOV Eax,dword[p.v_val]
!MOV Edx,dword[p.v_val+4]
!BSWAP Eax
!BSWAP Edx
!MOV dword[p.v_val+4],Eax
!MOV dword[p.v_val],Edx
ProcedureReturn val
EndProcedure
CompilerEndIf
Example:
Now you can just do things like color=Endian(color)
if you need to convert to/from RGB,BGR or RGBA and ABGR etc.
Or when dealing with network order/Motorola (big endian) values.
EDIT: PB 4.x implementations instead, the older PB 3.x functions moved to the 2nd post.
Sidenote to Fred: Endian() and EndianQ() really need to be native PB commands
Have fun!
Posted: Thu Mar 24, 2005 9:17 am
by Rescator
***Older PB 3.x functions***
Code: Select all
Procedure.l Endian(dummy.l)
!BSWAP Eax
ProcedureReturn
EndProcedure
And here is how to do Little/Big Endian byte swapping with 64bit values.
Code: Select all
Procedure.l Endian64(*val.LARGE_INTEGER)
h.l=Endian(*val\HighPart)
l.l=Endian(*val\LowPart)
*val\HighPart=l
*val\LowPart=h
ProcedureReturn *val
EndProcedure
Example of use:
Code: Select all
b.LARGE_INTEGER
b\HighPart=$BB0220
b\LowPart=$AA0110
Debug Hex(b\HighPart)
Debug Hex(b\LowPart)
Endian64(b)
Debug Hex(b\HighPart)
Debug Hex(b\LowPart)
Here is a assembler implementation of Endian64()
Code: Select all
Procedure.l Endian64(*dummy)
!MOV Ebx,[Eax]
!MOV Edx,[Eax+4]
!BSWAP Ebx
!BSWAP Edx
!MOV [Eax+4],Ebx
!MOV [Eax],Edx
ProcedureReturn
EndProcedure
Have fun
Code: Select all
b.LARGE_INTEGER
b\HighPart=$BB0220
b\LowPart=$AA0110
Debug Hex(b\HighPart)
Debug Hex(b\LowPart)
Endian64(b)
Debug Hex(b\HighPart)
Debug Hex(b\LowPart)
Re: Simple Big Endian / Little Endian byte order swap function.
Posted: Sun Nov 22, 2009 6:30 am
by Rescator
Updated first post, x64 support and speedup.
Re: Simple Big Endian / Little Endian byte order swap function.
Posted: Sun Nov 22, 2009 12:07 pm
by Thorium
Yes, bswap is pretty usefull. But the ordering of instructions have nothing to do with hyperthreading. The CPU can execute up to 3 instructions in parallel because it have 3 instruction pipelines (2 on older CPU's). That have nothing to do with threads. You can use threads in addition to the instruction ordering.
In fact there are 3 distinct parallelization layers. First you can parallelize by using SIMD instructions, which can process 4 doublewords or 8 words or 16 bytes in parallel. Second you can order the instructions, you even can order SIMD instructions so a maximum of 3 SIMD instructions is executed in parallel. And third you can use threads.
Re: Simple Big Endian / Little Endian byte order swap function.
Posted: Mon Nov 23, 2009 8:27 am
by Rescator
That's an old comment, I think what I meant at the time was dual pipelining, I think it was Intel Pentium 4 (!) that added some stuff for that while at the time AMD had not yet.
Shame phhpBB3 doesn't have a strike through tag or I'd use that to strike out that comment.
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Sat May 07, 2011 12:32 am
by skywalk
Thanks Rescator!
I agree this should be a native command.
So, I needed to swap a 16 bit word...
I am ashamed to say how much reading/fumbling along to come up with this...
But now I have a whole bunch of ASM urls for next time...
Code: Select all
Procedure.w EndianW(val.w)
!MOV ax, word[p.v_val]
!XCHG al, ah ; Swap Lo byte <-> Hi byte
!MOV word[p.v_val], ax
ProcedureReturn val
EndProcedure
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Mon Sep 19, 2011 3:48 pm
by ABBKlaus
Thanks Rescator / skywalk for this very usefull Tip.
I am currently using it in PurePDF.
I hope its working on all three Platforms ? (Win / Linux / MacOS)
BR Klaus
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Mon Sep 19, 2011 4:40 pm
by wilbert
ABBKlaus wrote:I hope its working on all three Platforms ? (Win / Linux / MacOS)
No, that won't work on OS X.
There's a bug on OS X with labels of local variables like [p.v_val].
What should work on all three platforms is using EnableASM.
Here's two alternatives
Code: Select all
Procedure.w EndianW(val.w)
EnableASM
ROL val, 8
DisableASM
ProcedureReturn val
EndProcedure
Code: Select all
Procedure.w EndianW(val.w)
EnableASM
MOV ax, val
XCHG al, ah
DisableASM
ProcedureReturn
EndProcedure
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Mon Sep 19, 2011 5:51 pm
by ABBKlaus
Thanks wilbert,
i have changed the above procedures for EndianW() and EndianL() :
Code: Select all
Procedure.w ipf_EndianW(value.w)
EnableASM
ROL value, 8
DisableASM
ProcedureReturn value
EndProcedure
Code: Select all
Procedure.l ipf_EndianL(value.l)
EnableASM
MOV Eax,value
BSWAP Eax
DisableASM
ProcedureReturn
EndProcedure
but what about EndianQ() ?
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Mon Sep 19, 2011 6:54 pm
by wilbert
EndianQ is a bit more complicated but here are two ways.
Code: Select all
Procedure.q EndianQ(val.q)
EnableASM
MOVQ mm0, val
MOVD edx, mm0
BSWAP edx
PSRLQ mm0, 32
MOVD eax, mm0
BSWAP eax
EMMS
DisableASM
ProcedureReturn
EndProcedure
Code: Select all
Procedure.q EndianQ(val.q)
Protected addr.l = @val
EnableASM
MOV edx, addr
MOV eax, [edx + 4]
MOV edx, [edx]
BSWAP eax
BSWAP edx
DisableASM
ProcedureReturn
EndProcedure
The first one doesn't need an extra variable but uses a mmx register, the second one is plain asm but requires an extra protected variable.
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Mon Sep 19, 2011 10:10 pm
by skywalk
Thanks wilbert.
I don't have a Mac. Is this what you are saying does not work?
http://www.purebasic.com/documentation/reference/inlinedasm.html wrote:- It's possible to pass directly an assembly line to the assembler without being processed by the compiler by using the '!' character at the line start. This allow to have a full access to the assembler directives. When using this, it's possible to
reference the local variables using the notation 'p.v_variablename' for a regular variable or 'p.p_variablename' for a pointer
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Tue Sep 20, 2011 5:31 am
by wilbert
When you enable asm with EnableASM, you can use a variable name directly otherwise you have to use the p.v_variablename .
I would prefer the p.v_variablename since it's more versatile but there's a bug with that on OS X.
It's kind of a nightmare at the moment on OS X to use variables with inline ASM.
The p.v_variablename isn't working and using the stack pointer directly like esp+4 also isn't reliable since the offset from the stack pointer where the variable is located is different from that on windows because of some extra code the PB compiler adds.
I mentioned the bug with the p.v_variablename syntax in the OS X bugs forum but unfortunately it hasn't been fixed yet.
It probably only would be a matter of one minute. If you look at the ASM source, it currently says
instead of
so the only problem is that the space character is on the wrong place.
But it's not something I can fix
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Tue Sep 20, 2011 11:53 am
by ABBKlaus
Thanks wilbert, i have taken your second approach for PurePDF
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Tue Sep 20, 2011 3:53 pm
by skywalk
wilbert wrote:If you look at the ASM source, it currently says
instead of
so the only problem is that the space character is on the wrong place.
Thanks for the details.
I bet Fred wishes all his bugs were this easy
Re: Simple Big Endian / Little Endian byte order swap functi
Posted: Thu Sep 22, 2011 2:52 pm
by El_Choni
I would use macros instead of procedures for speed's sake.