Here is my version for x86 and x64:
function GetCPUID: TCPUID; asm {$IF Defined(CPUX86)} push ebx push edi mov edi, eax mov eax, 1 xor ecx,ecx cpuid mov [edi+$0], eax mov [edi+$4], ebx mov [edi+$8], ecx mov [edi+$c], edx pop edi pop ebx {$ELSEIF Defined(CPUX64)} mov r8, rbx mov r9, rcx mov eax, 1 cpuid mov [r9+$0], eax mov [r9+$4], ebx mov [r9+$8], ecx mov [r9+$c], edx mov rbx, r8 {$IFEND} end;
One of the nice things about x64 is that there are much more registers available, many of which are unstable. Therefore, we can use this space for scratches and not touch the main memory at all. Well, obviously, we need to touch the main memory in order to return the result.
Since RBX is non-volatile , we retain its value. All other registers that we modify are volatile, so we do not need to save them. I can think of no way to simplify this further.
This can be easily extended to skip CPUID input as an argument:
function GetCPUID(ID: Integer): TCPUID; asm {$IF Defined(CPUX86)} push ebx push edi mov edi, edx xor ecx,ecx cpuid mov [edi+$0], eax mov [edi+$4], ebx mov [edi+$8], ecx mov [edi+$c], edx pop edi pop ebx {$ELSEIF Defined(CPUX64)} mov r8, rbx mov r9, rcx mov eax, edx cpuid mov [r9+$0], eax mov [r9+$4], ebx mov [r9+$8], ecx mov [r9+$c], edx mov rbx, r8 {$ELSE} {$Message Fatal 'GetCPUID has not been implemented for this architecture.'} {$IFEND} end;
This assumes that the sublist value is 0, which is passed to ECX. Again, if you want to convey this, it's simple enough:
function GetCPUID(Leaf, Subleaf: Integer): TCPUID; asm {$IF Defined(CPUX86)} push ebx push edi mov edi, ecx mov ecx, edx cpuid mov [edi+$0], eax mov [edi+$4], ebx mov [edi+$8], ecx mov [edi+$c], edx pop edi pop ebx {$ELSEIF Defined(CPUX64)} mov r9,rcx mov ecx,r8d mov r8,rbx mov eax,edx cpuid mov [r9+$0], eax mov [r9+$4], ebx mov [r9+$8], ecx mov [r9+$c], edx mov rbx, r8 {$ELSE} {$Message Fatal 'GetCPUID has not been implemented for this architecture.'} {$IFEND} end;