/* ********************************************************************************************************* * uC/CPU * CPU CONFIGURATION & PORT LAYER * * Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com * * SPDX-License-Identifier: APACHE-2.0 * * This software is subject to an open source license and is distributed by * Silicon Laboratories Inc. pursuant to the terms of the Apache License, * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. * ********************************************************************************************************* */ /* ********************************************************************************************************* * * CPU PORT FILE * * Win32 * Microsoft Visual Studio * * Filename : cpu_c.c * Version : v1.32.00 ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #define MICRIUM_SOURCE #include #include #define _WIN32_WINNT 0x0600 #define WIN32_LEAN_AND_MEAN #include #include #ifdef _MSC_VER #include #pragma intrinsic(_BitScanForward) #pragma intrinsic(_BitScanReverse) #endif #ifdef __cplusplus extern "C" { #endif /* ********************************************************************************************************* * LOCAL VARIABLES ********************************************************************************************************* */ #if (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_CRITICAL_SECTION) static CRITICAL_SECTION CriticalSection; #elif (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_MUTEX) static HANDLE CriticalSection; #endif /* ********************************************************************************************************* * LOCAL FUNCTION PROTOTYPES ********************************************************************************************************* */ #ifdef CPU_CFG_MSG_TRACE_EN static int CPU_Printf(char *p_str, ...); #endif /* ********************************************************************************************************* * CPU_IntInit() * * Description : This function initializes the critical section. * * Argument(s) : none. * * Return(s) : none. * * Note(s) : 1) CPU_IntInit() MUST be called prior to use any of the CPU_IntEn(), and CPU_IntDis() * functions. ********************************************************************************************************* */ void CPU_IntInit (void) { #if (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_MUTEX) #ifdef CPU_CFG_MSG_TRACE_EN DWORD last_err; LPTSTR p_msg; #endif CriticalSection = CreateMutex(NULL, FALSE, NULL); if (CriticalSection == NULL) { #ifdef CPU_CFG_MSG_TRACE_EN last_err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&p_msg, 0, NULL); CPU_Printf("Error: Initialize Critical Section failed: %s.\n", p_msg); LocalFree(p_msg); #endif return; } #elif (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_CRITICAL_SECTION) InitializeCriticalSection(&CriticalSection); #endif } /* ********************************************************************************************************* * CPU_IntEnd() * * Description : This function terminates the critical section. * * Argument(s) : none. * * Return(s) : none. * * Note(s) : 1) . ********************************************************************************************************* */ void CPU_IntEnd (void) { #if (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_MUTEX) CloseHandle(CriticalSection); #elif (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_CRITICAL_SECTION) DeleteCriticalSection(&CriticalSection); #endif } /* ********************************************************************************************************* * CPU_IntDis() * * Description : This function disables interrupts for critical sections of code. * * Argument(s) : none. * * Return(s) : none. * * Note(s) : none. ********************************************************************************************************* */ void CPU_IntDis (void) { #if (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_MUTEX) DWORD ret; #ifdef CPU_CFG_MSG_TRACE_EN DWORD last_err; LPTSTR p_msg; #endif ret = WaitForSingleObject(CriticalSection, INFINITE); switch (ret) { case WAIT_OBJECT_0: default: break; #ifdef CPU_CFG_MSG_TRACE_EN case WAIT_ABANDONED: CPU_Printf("cpu_c.c: Enter Critical Section failed: Mutex abandoned by owning thread.\n"); break; case WAIT_TIMEOUT: CPU_Printf("cpu_c.c: Enter Critical Section failed: Time-out interval elapsed.\n"); break; case WAIT_FAILED: last_err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&p_msg, 0, NULL); CPU_Printf("cpu_c.c: Enter Critical Section failed: %s.\n", p_msg); LocalFree(p_msg); break; #endif } #elif (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_CRITICAL_SECTION) EnterCriticalSection(&CriticalSection); #endif } /* ********************************************************************************************************* * CPU_IntEn() * * Description : This function enables interrupts after critical sections of code. * * Argument(s) : none. * * Return(s) : none. * * Note(s) : none. ********************************************************************************************************* */ void CPU_IntEn (void) { #if (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_MUTEX) #ifdef CPU_CFG_MSG_TRACE_EN DWORD last_err; LPTSTR p_msg; #endif if (ReleaseMutex(CriticalSection) == 0u) { #ifdef CPU_CFG_MSG_TRACE_EN last_err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&p_msg, 0, NULL); CPU_Printf("cpu_c.c: Exit Critical Section failed: %s.\n", p_msg); LocalFree(p_msg); #endif } #elif (CPU_CFG_CRITICAL_METHOD_WIN32 == WIN32_CRITICAL_SECTION) LeaveCriticalSection(&CriticalSection); #endif } /* ********************************************************************************************************* * CPU_Printf() * * Description: This function is analog of printf. * * Arguments : p_str Pointer to format string output. * * Returns : Number of characters written. ********************************************************************************************************* */ #ifdef CPU_CFG_MSG_TRACE_EN static int CPU_Printf (char *p_str, ...) { va_list param; int ret; va_start(param, p_str); ret = vprintf_s(p_str, param); va_end(param); return (ret); } #endif /* ********************************************************************************************************* * CPU_CntLeadZeros() * * Description : Count the number of contiguous, most-significant, leading zero bits in a data value. * * Argument(s) : val Data value to count leading zero bits. * * Return(s) : Number of contiguous, most-significant, leading zero bits in 'val', if NO error(s). * * 0, otherwise. * * Note(s) : (1) (a) Supports the following data value sizes : * * (1) 8-bits * (2) 16-bits * (3) 32-bits * * See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. * * (b) (1) For 8-bit values : * * b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros * --- --- --- --- --- --- --- --- --------------- * 1 x x x x x x x 0 * 0 1 x x x x x x 1 * 0 0 1 x x x x x 2 * 0 0 0 1 x x x x 3 * 0 0 0 0 1 x x x 4 * 0 0 0 0 0 1 x x 5 * 0 0 0 0 0 0 1 x 6 * 0 0 0 0 0 0 0 1 7 * 0 0 0 0 0 0 0 0 8 * * * (2) For 16-bit values : * * b15 b14 b13 ... b04 b03 b02 b01 b00 # Leading Zeros * --- --- --- --- --- --- --- --- --------------- * 1 x x x x x x x 0 * 0 1 x x x x x x 1 * 0 0 1 x x x x x 2 * : : : : : : : : : * : : : : : : : : : * 0 0 0 1 x x x x 11 * 0 0 0 0 1 x x x 12 * 0 0 0 0 0 1 x x 13 * 0 0 0 0 0 0 1 x 14 * 0 0 0 0 0 0 0 1 15 * 0 0 0 0 0 0 0 0 16 * * * (3) For 32-bit values : * * b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros * --- --- --- --- --- --- --- --- --------------- * 1 x x x x x x x 0 * 0 1 x x x x x x 1 * 0 0 1 x x x x x 2 * : : : : : : : : : * : : : : : : : : : * 0 0 0 1 x x x x 27 * 0 0 0 0 1 x x x 28 * 0 0 0 0 0 1 x x 29 * 0 0 0 0 0 0 1 x 30 * 0 0 0 0 0 0 0 1 31 * 0 0 0 0 0 0 0 0 32 * * * See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. * * (2) MUST be implemented in cpu_a.asm if and only if CPU_CFG_LEAD_ZEROS_ASM_PRESENT * is #define'd in 'cpu_cfg.h' or 'cpu.h'. ********************************************************************************************************* */ #ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT #ifdef _MSC_VER CPU_DATA CPU_CntLeadZeros (CPU_DATA val) { DWORD clz; if (val == 0u) { return (32u); } _BitScanReverse(&clz, (DWORD)val); return (31u - (CPU_DATA)clz); } #endif #endif /* ********************************************************************************************************* * CPU_CntTrailZeros() * * Description : Count the number of contiguous, least-significant, trailing zero bits in a data value. * * Argument(s) : val Data value to count trailing zero bits. * * Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. * * Note(s) : (1) (a) Supports the following data value sizes : * * (1) 8-bits * (2) 16-bits * (3) 32-bits * (4) 64-bits * * See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. * * (b) (1) For 8-bit values : * * b07 b06 b05 b04 b03 b02 b01 b00 # Trailing Zeros * --- --- --- --- --- --- --- --- ---------------- * x x x x x x x 1 0 * x x x x x x 1 0 1 * x x x x x 1 0 0 2 * x x x x 1 0 0 0 3 * x x x 1 0 0 0 0 4 * x x 1 0 0 0 0 0 5 * x 1 0 0 0 0 0 0 6 * 1 0 0 0 0 0 0 0 7 * 0 0 0 0 0 0 0 0 8 * * * (2) For 16-bit values : * * b15 b14 b13 b12 b11 ... b02 b01 b00 # Trailing Zeros * --- --- --- --- --- --- --- --- ---------------- * x x x x x x x 1 0 * x x x x x x 1 0 1 * x x x x x 1 0 0 2 * : : : : : : : : : * : : : : : : : : : * x x x x 1 0 0 0 11 * x x x 1 0 0 0 0 12 * x x 1 0 0 0 0 0 13 * x 1 0 0 0 0 0 0 14 * 1 0 0 0 0 0 0 0 15 * 0 0 0 0 0 0 0 0 16 * * * (3) For 32-bit values : * * b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros * --- --- --- --- --- --- --- --- ---------------- * x x x x x x x 1 0 * x x x x x x 1 0 1 * x x x x x 1 0 0 2 * : : : : : : : : : * : : : : : : : : : * x x x x 1 0 0 0 27 * x x x 1 0 0 0 0 28 * x x 1 0 0 0 0 0 29 * x 1 0 0 0 0 0 0 30 * 1 0 0 0 0 0 0 0 31 * 0 0 0 0 0 0 0 0 32 * * * (4) For 64-bit values : * * b63 b62 b61 b60 b59 ... b02 b01 b00 # Trailing Zeros * --- --- --- --- --- --- --- --- ---------------- * x x x x x x x 1 0 * x x x x x x 1 0 1 * x x x x x 1 0 0 2 * : : : : : : : : : * : : : : : : : : : * x x x x 1 0 0 0 59 * x x x 1 0 0 0 0 60 * x x 1 0 0 0 0 0 61 * x 1 0 0 0 0 0 0 62 * 1 0 0 0 0 0 0 0 63 * 0 0 0 0 0 0 0 0 64 * * (2) For non-zero values, the returned number of contiguous, least-significant, trailing * zero bits is also equivalent to the bit position of the least-significant set bit. * * (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : * * (a) CPU_CntTrailZeros()'s final conditional statement calculates 'val's number of * trailing zeros based on its return data size, 'CPU_CFG_DATA_SIZE', & 'val's * calculated number of lead zeros ONLY if the initial 'val' is non-'0' : * * if (val != 0u) { * nbr_trail_zeros = ((CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; * } else { * nbr_trail_zeros = nbr_lead_zeros; * } * * Therefore, initially validating all non-'0' values avoids having to conditionally * execute the final statement. ********************************************************************************************************* */ #ifdef CPU_CFG_TRAIL_ZEROS_ASM_PRESENT #ifdef _MSC_VER CPU_DATA CPU_CntTrailZeros (CPU_DATA val) { DWORD ctz; if (val == 0u) { return (32u); } _BitScanForward(&ctz, (DWORD)val); return ((CPU_DATA)ctz); } #endif #endif #ifdef __cplusplus } #endif