I like your use of macros. I made a feeble attempt at using a macro to replace eax/rax (etc.), but it did not work, either in pb or fasm. I was trying to just replace the register name, though. Since it was just for fun to retrofit sample code, I did not put much focus on it. Replacing the whole line is a neat idea.
This seems to work with a quick test outputting to a text file. You could duplicate Xdx for Xax, etc, and eliminate all of the conditional compilation from within the procs.
You can carry it a step further, and just do the whole 3-word instruction, so you only need one macro for all instructions, plus one for each e/r register pair:
Code: Select all
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
Macro UTF8_MovFromMem_(offset, reg)
!mov reg, [rdx + offset]
EndMacro
Macro UTF8_MovToMem_(offset, reg)
!mov [rdx + offset], reg
EndMacro
Macro UTF8_MovToChar_()
!mov [rax], ecx
EndMacro
CompilerElse
Macro UTF8_MovFromMem_(offset, reg)
!mov reg, [edx + offset]
EndMacro
Macro UTF8_MovToMem_(offset, reg)
!mov [edx + offset], reg
EndMacro
Macro UTF8_MovToChar_()
!mov [eax], ecx
EndMacro
CompilerEndIf
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
Macro Xdx
rdx
EndMacro
Macro Xax
rax
EndMacro
CompilerElse
Macro Xdx
edx
EndMacro
Macro Xax
eax
EndMacro
CompilerEndIf
Macro asm(instruction, arg1, arg2)
!instruction arg1, arg2
EndMacro
Procedure.i UTF8_Size(FirstByte.a)
!movzx eax, byte [p.v_FirstByte]
!shr al, 3
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!lea r8, [utf8size0]
!mov al, [r8 + rax]
CompilerElse
!mov al, [utf8size0 + eax]
CompilerEndIf
ProcedureReturn
!utf8size0:
!db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
!db 0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,0
EndProcedure
Procedure.i UTF8_PeekC(*MemoryBuffer, *Character.Long)
asm(MOV, xdx, [p.p_MemoryBuffer])
asm(MOV, xax, [p.p_Character])
UTF8_MovFromMem_(0, cl)
!cmp cl, 0xc0
!jl utf8peekc3
!jnb utf8peekc0
!and ecx, 0x7f
UTF8_MovToChar_()
ProcedureReturn 1
!utf8peekc0:
!cmp cl, 0xe0
!jnb utf8peekc1
UTF8_MovFromMem_(1, ch)
!cmp ch, 0xc0
!jge utf8peekc3
!shl ch, 2
!rol cx, 6
!and ecx, 0x7ff
UTF8_MovToChar_()
ProcedureReturn 2
!utf8peekc1:
!cmp cl, 0xf0
!jnb utf8peekc2
!shl ecx, 16
UTF8_MovFromMem_(1, cx)
!cmp cl, 0xc0
!jge utf8peekc3
!cmp ch, 0xc0
!jge utf8peekc3
!xchg ch, cl
!shl cl, 2
!shl cx, 2
!shr ecx, 4
!and ecx, 0xffff
UTF8_MovToChar_()
ProcedureReturn 3
!utf8peekc2:
!cmp cl, 0xf4
!ja utf8peekc3
UTF8_MovFromMem_(0, ecx)
!cmp ch, 0xc0
!jge utf8peekc3
!shl ch, 2
!bswap ecx
!cmp cl, 0xc0
!jge utf8peekc3
!cmp ch, 0xc0
!jge utf8peekc3
!shl cl, 2
!shr ecx, 2
!shl cx, 4
!shr ecx, 4
!and ecx, 0x1ffff
UTF8_MovToChar_()
ProcedureReturn 4
!utf8peekc3:
ProcedureReturn 0
EndProcedure
Procedure.i UTF8_PokeC(*MemoryBuffer, Character.l)
asm(MOV, xdx, [p.p_MemoryBuffer])
!mov ecx, [p.v_Character]
!cmp ecx, 0x7f
!ja utf8pokec0
UTF8_MovToMem_(0, cl)
ProcedureReturn 1
!utf8pokec0:
!cmp ecx, 0x7ff
!ja utf8pokec1
!shl cx, 2
!shr cl, 2
!or cx, 1100000010000000b
!xchg ch, cl
UTF8_MovToMem_(0, cx)
ProcedureReturn 2
!utf8pokec1:
!cmp ecx, 0xffff
!ja utf8pokec2
!shl ecx, 4
!shr cx, 2
!shr cl, 2
!or ecx, 111000001000000010000000b
!bswap ecx
UTF8_MovToMem_(0, ch)
!shr ecx, 16
UTF8_MovToMem_(1, cx)
ProcedureReturn 3
!utf8pokec2:
!cmp ecx, 0x10ffff
!ja utf8pokec3
!ror ecx, 10
!shl ch, 2
!rol ecx, 14
!shr cx, 2
!shr cl, 2
!or ecx, 11110000100000001000000010000000b
!bswap ecx
UTF8_MovToMem_(0, ecx)
ProcedureReturn 4
!utf8pokec3:
ProcedureReturn 0
EndProcedure
Procedure.i ReadUTF8Character(File.i)
Protected.i c, size, l = $80808080
ReadData(File, @l, 1)
size = UTF8_PeekC(@l, @c)
If size = 1
ProcedureReturn c
ElseIf size > 1
ReadData(File, @l + 1, size - 1)
If UTF8_PeekC(@l, @c)
ProcedureReturn c
EndIf
EndIf
ProcedureReturn -1
EndProcedure
Procedure.i WriteUTF8Character(File.i, Character.l)
ProcedureReturn WriteData(File, @Character, UTF8_PokeC(@Character, Character))
EndProcedure
*Mem = AllocateMemory(1024)
PokeS(*Mem, "€1,- €2,- €3,50", -1, #PB_UTF8)
Repeat
cnt.l = UTF8_PeekC(*Mem, @c.l)
Debug Hex(c) + " " + Chr(c)
*Mem + cnt
Until cnt = 0 Or c = 0
The one place it still requires the conditional compilation is when there are two x64 instructions, and only one x86. (I am not familiar enough with x86 & x64 asm to know why it is not 1:1.)