517 lines
20 KiB
C
517 lines
20 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* 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 <cpu.h>
|
|
#include <cpu_core.h>
|
|
|
|
|
|
#define _WIN32_WINNT 0x0600
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
|
|
#ifdef _MSC_VER
|
|
#include <intrin.h>
|
|
|
|
#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
|