Simple Big Endian / Little Endian byte order swap function.

Share your advanced PureBasic knowledge/code with the community.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Simple Big Endian / Little Endian byte order swap function.

Post 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:

Code: Select all

Debug Hex(Endian($112233))
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:

Code: Select all

Debug Hex(EndianQ($112233))
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 :P

Have fun!
Last edited by Rescator on Sun Nov 22, 2009 6:33 am, edited 10 times in total.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post 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) 
Last edited by Rescator on Thu Aug 17, 2006 4:43 pm, edited 3 times in total.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Simple Big Endian / Little Endian byte order swap function.

Post by Rescator »

Updated first post, x64 support and speedup.
Thorium
Addict
Addict
Posts: 1271
Joined: Sat Aug 15, 2009 6:59 pm

Re: Simple Big Endian / Little Endian byte order swap function.

Post 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.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Simple Big Endian / Little Endian byte order swap function.

Post 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. :)
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Simple Big Endian / Little Endian byte order swap functi

Post by skywalk »

Thanks Rescator!
I agree this should be a native command. :idea:

So, I needed to swap a 16 bit word...
I am ashamed to say how much reading/fumbling along to come up with this... :oops:
But now I have a whole bunch of ASM urls for next time... :lol:

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
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Re: Simple Big Endian / Little Endian byte order swap functi

Post 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
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Simple Big Endian / Little Endian byte order swap functi

Post 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
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Re: Simple Big Endian / Little Endian byte order swap functi

Post 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() ?
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Simple Big Endian / Little Endian byte order swap functi

Post 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.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Simple Big Endian / Little Endian byte order swap functi

Post 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
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Simple Big Endian / Little Endian byte order swap functi

Post 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

Code: Select all

%define p. v_valesp+PS0+0
instead of

Code: Select all

%define p.v_val esp+PS0+0
so the only problem is that the space character is on the wrong place.
But it's not something I can fix :(
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Re: Simple Big Endian / Little Endian byte order swap functi

Post by ABBKlaus »

Thanks wilbert, i have taken your second approach for PurePDF :wink:
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Simple Big Endian / Little Endian byte order swap functi

Post by skywalk »

wilbert wrote:If you look at the ASM source, it currently says

Code: Select all

%define p. v_valesp+PS0+0
instead of

Code: Select all

%define p.v_val esp+PS0+0
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 :D
El_Choni
TailBite Expert
TailBite Expert
Posts: 1007
Joined: Fri Apr 25, 2003 6:09 pm
Location: Spain

Re: Simple Big Endian / Little Endian byte order swap functi

Post by El_Choni »

I would use macros instead of procedures for speed's sake.
El_Choni
Post Reply