It is working now.
But I have problems returning the register values in the C-Code.
I found a way. But I guess it should be possible in an easier way.
At the moment I use extra variables with Protected and
copy the values in C-Code first to this variables and from there
with PB Code the returning Pointer vars!
Does anyone know how to return varibales dirctly in the C-code
without the PokeL(*EAX, a) commands
here the CPUID example
see Procedure CPUID section C-Backend
Code: Select all
Procedure.i CPUID_IsSupported()
; ======================================================================
; NAME: CPUID_IsSupported
; DESC: Checks if CPUID is supported
; DESC: on AMD/Intel x64 Processors CPUID is always supported
; DESC: It was introduced in 1993 with the Pentium CPUs
; DESC: But better to do a check bevor calling !CPUID functions
; VAR(leaf.l): the numerical id of the requested level of information
; RET : #TRUE if supported
; ======================================================================
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x64)
ProcedureReturn #True ; on x64 CPUs CPUID is always supported
CompilerElseIf (#PB_Compiler_Processor = #PB_Processor_x86)
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
!PUSHFD
!POP EAX
!MOV EDX, EAX
!XOR EAX, 0x00200000
!PUSH EAX
!POPFD
!PUSHFD
!POP EAX
!XOR EAX, EDX
!JNE IsCpuid_OK
!XOR EAX, EAX ; ProcedureReturn #False
!RET
!IsCpuid_OK:
!MOV EAX, 1 ; ProcedureReturn #True
!RET
CompilerElseIf #PB_Compiler_Backend = #PB_Backend_C
!asm volatile (".intel_syntax noprefix;"
!"pushfd;"
!"pop EAX;"
!"mov EDX, EAX;"
!"xor EAX, 0x00200000;"
!"push EAX;"
!"popfd;"
!"pushfd;"
!"pop EAX;"
!"xor EAX, EDX;"
!"jne IsCpuid_OK;"
!"mov %[retval], 0;"
!"jmp IsCpuid_EXIT;"
!"IsCpuid_OK:"
!"mov %[retval], 1;"
!"IsCpuid_EXIT:"
!".att_syntax;"
!: [retval] "=r" (r)
!);
!return r ; ProcedureReturn r
CompilerEndIf
CompilerElse
ProcedureReturn #False
CompilerEndIf
EndProcedure
Procedure.i CPUID (Function.l, *EAX, *EBX, *ECX, *EDX)
; ======================================================================
; NAME: CPUID
; DESC: This wraps the CPUID instruction. And copies the return values
; DESC: from CPUID to 4 Variables. CPID returns the values direct in
; DESC: the x86 Registers EAX, EBX, ECX, EDX
; VAR(function.l): the numerical ID of the requested level of information
; VAR(*EAX): Pointer to a 32Bit Long to receive EAX after !CPUID
; VAR(*EBX): Pointer to a 32Bit Long to receive EBX after !CPUID
; VAR(*ECX): Pointer to a 32Bit Long to receive ECX after !CPUID
; VAR(*EDX): Pointer to a 32Bit Long to receive EDX after !CPUID
; RET : TRUE if succseed
; ======================================================================
DisableDebugger
; more informations for the CPUID instruction you can find here:
; https://c9x.me/x86/html/file_module_x86_id_45.html
; https://www.lowlevel.eu/wiki/CPUID
If *EAX And *EBX And *ECX And *EDX
If CPUID_IsSupported()
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
!MOV EAX, DWORD [p.v_Function]
!XOR ECX, ECX ; Subleave = 0
!CPUID
!MOV EBP, DWORD [p.p_EAX]
!MOV DWORD [EBP], EAX
!MOV EBP, DWORD [p.p_EBX]
!MOV DWORD [EBP], EBX
!MOV EBP, DWORD [p.p_ECX]
!MOV DWORD [EBP], ECX
!MOV EBP, DWORD [p.p_EDX]
!MOV DWORD [EBP], EDX
CompilerElse
!XOR RAX, RAX
!MOV EAX, DWORD [p.v_Function]
!XOR ECX, ECX ; Subleave = 0
!CPUID
!MOV RBP, QWORD [p.p_EAX]
!MOV DWORD [RBP], EAX
!MOV RBP, QWORD [p.p_EBX]
!MOV DWORD [RBP], EBX
!MOV RBP, QWORD [p.p_ECX]
!MOV DWORD [RBP], ECX
!MOV RBP, QWORD [p.p_EDX]
!MOV DWORD [RBP], EDX
CompilerEndIf
CompilerElseIf #PB_Compiler_Backend = #PB_Backend_C
Protected.l a, b, c, d
!unsigned int reg_a, reg_b, reg_c, reg_d;
!asm volatile ("cpuid;"
!: "=a" (reg_a), "=b" (reg_b), "=c" (reg_c), "=d" (reg_d)
!: "0" (v_function)
!);
; ---------------------------------------
; thats my way how to return values
!v_a = reg_a;
!v_b = reg_b;
!v_c = reg_c;
!v_d = reg_d;
PokeL(*EAX, a)
PokeL(*EBX, b)
PokeL(*ECX, c)
PokeL(*EDX, d)
; ---------------------------------------
CompilerEndIf
ProcedureReturn #True
Else
*EAX = 0 : *EBX = 0 : *ECX = 0 : *EDX = 0
ProcedureReturn #False
EndIf
Else
ProcedureReturn #False
EndIf
EnableDebugger
EndProcedure
Procedure.s GetCPUVendorID()
; ======================================================================
; NAME: GetCPUVendorID
; DESC: Reads the 12 Character long Vendor ID of the CPU
; RET.s: VendorID String {"AuthenticAMD", "GenuineIntel" ...}
; ======================================================================
; the VendorName contains 12 Chars in ASCII, token from the Registers EBX,EDX,ECX
Protected.l mEAX, mEBX, mECX, mEDX
If CPUID(0, @mEAX, @mEBX, @mECX, @mEDX)
ProcedureReturn PeekS(@mEBX, 4, #PB_Ascii) + PeekS(@mEDX, 4, #PB_Ascii) + PeekS(@mECX, 4, #PB_Ascii)
Else
ProcedureReturn "unknown Vendor"
EndIf
EndProcedure
Define.l mEAX, mEBX, mECX, mEDX
If CPUID(0, @mEAX, @mEBX, @mECX, @mEDX)
Debug "CPU ID is supported"
Debug "EAX = $" + Hex(mEAX)
Debug "EBX = $" + Hex(mEBX)
Debug "ECX = $" + Hex(mECX)
Debug "EDX = $" + Hex(mEDX)
Debug ""
Debug "Vendor ID = " + GetCPUVendorID()
Else
Debug " CPU ID not supported"
EndIf