diff --git a/libcpu/sim/win32/cpu_port.c b/libcpu/sim/win32/cpu_port.c new file mode 100644 index 0000000000000000000000000000000000000000..f4e3f771e678cd6bcd0d05e3c17e310f285c2d67 --- /dev/null +++ b/libcpu/sim/win32/cpu_port.c @@ -0,0 +1,658 @@ +/* +************************************************************************************************************************ +* File : cpu_port.c +* By : xyou +* Version : V1.00.00 +* +* By : prife +* Version : V1.00.01 +************************************************************************************************************************ +*/ + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ +#include +#include +#include +#include +#include "cpu_port.h" + +/* +********************************************************************************************************* +* WinThread STRUCTURE +* Windows runs each task in a thread. +* The context switch is managed by the threads.So the task stack does not have to be managed directly, +* although the stack stack is still used to hold an WinThreadState structure this is the only thing it +* will be ever hold. +* the structure indirectly maps the task handle to a thread handle +********************************************************************************************************* +*/ +typedef struct +{ + void *Param; //Thread param + void (*Entry)(void *); //Thread entry + void (*Exit)(void); //Thread exit + HANDLE ThreadHandle; + DWORD ThreadID; +}win_thread_t; + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ +#define MAX_INTERRUPT_NUM ((rt_uint32_t)sizeof(rt_uint32_t) * 8) + +/* + * Simulated interrupt waiting to be processed.this is a bit mask where each bit represent one interrupt + * so a maximum of 32 interrupts can be simulated + */ +static volatile rt_uint32_t CpuPendingInterrupts = 0; + +/* + * An event used to inform the simulated interrupt processing thread (a high priority thread + * that simulated interrupt processing) that an interrupt is pending + */ +static HANDLE hInterruptEventHandle = NULL; + +/* + * Mutex used to protect all the simulated interrupt variables that are accessed by multiple threads + */ +static HANDLE hInterruptEventMutex = NULL; + +/* + * Handler for all the simulate software interrupts. + * The first two positions are used the Yield and Tick interrupt so are handled slightly differently + * all the other interrupts can be user defined +*/ +static rt_uint32_t (*CpuIsrHandler[MAX_INTERRUPT_NUM])(void) = {0}; + +/* + * Handler for OSTick Thread + */ +static HANDLE OSTick_Thread; +static DWORD OSTick_ThreadID; +static HANDLE OSTick_SignalPtr; +static TIMECAPS OSTick_TimerCap; +static MMRESULT OSTick_TimerID; + +/* + * flag in interrupt handling + */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/* +********************************************************************************************************* +* PRIVATE FUNCTION PROTOTYPES +********************************************************************************************************* +*/ +//static void WinThreadScheduler(void); +void WinThreadScheduler(void); +rt_uint32_t YieldInterruptHandle(void); +rt_uint32_t SysTickInterruptHandle(void); +static DWORD WINAPI ThreadforSysTickTimer(LPVOID lpParam); +static DWORD WINAPI ThreadforKeyGet(LPVOID lpParam); +/* +********************************************************************************************************* +* CPU Port Function for RT-Thread +********************************************************************************************************* +*/ + +//void rt_hw_console_output(const char *str) +//{ +// printf("%s",str); +//} + +/* +********************************************************************************************************* +* rt_hw_stack_init() +* Description : Initialize stack of thread +* Argument(s) : void *pvEntry,void *pvParam,rt_uint8_t *pStackAddr,void *pvExit +* Return(s) : rt_uint8_t* +* Caller(s) : rt_thread_init or rt_thread_create +* Note(s) : none +********************************************************************************************************* +*/ + +static DWORD WINAPI thread_run( LPVOID lpThreadParameter ) +{ + win_thread_t *pWinThread = (win_thread_t *)lpThreadParameter; + pWinThread->Entry(pWinThread->Param); + + printf("thread %x exit\n", pWinThread->ThreadID); + pWinThread->Exit(); + return 0; +} + +rt_uint8_t* rt_hw_stack_init(void *pEntry,void *pParam,rt_uint8_t *pStackAddr,void *pExit) +{ + win_thread_t *pWinThread = NULL; + + /* + * In this simulated case a stack is not initialized + * The thread handles the context switching itself. The WinThreadState object is placed onto the stack + * that was created for the task + * so the stack buffer is still used,just not in the conventional way. + */ + pWinThread = (win_thread_t *)(pStackAddr - sizeof(win_thread_t)); + + pWinThread->Entry = pEntry; + pWinThread->Param = pParam; + pWinThread->Exit = pExit; + + pWinThread->ThreadHandle = NULL; + pWinThread->ThreadID = 0; + + /* Create the winthread */ + pWinThread->ThreadHandle = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE) thread_run, + pWinThread, + CREATE_SUSPENDED, + &(pWinThread->ThreadID)); + SetThreadAffinityMask(pWinThread->ThreadHandle, + 0x01); + SetThreadPriorityBoost(pWinThread->ThreadHandle, + TRUE); + SetThreadPriority(pWinThread->ThreadHandle, + THREAD_PRIORITY_IDLE); + + return (rt_uint8_t*)pWinThread; +} /*** rt_hw_stack_init ***/ + + + + +/* +********************************************************************************************************* +* rt_hw_interrupt_disable() +* Description : disable cpu interrupts +* Argument(s) : void +* Return(s) : rt_base_t +* Caller(s) : Applicatios or os_kernel +* Note(s) : none +********************************************************************************************************* +*/ +rt_base_t rt_hw_interrupt_disable(void) +{ + if(hInterruptEventMutex != NULL) + { + WaitForSingleObject(hInterruptEventMutex,INFINITE); + } + + return 0; +} /*** rt_hw_interrupt_disable ***/ + + +/* +********************************************************************************************************* +* rt_hw_interrupt_enable() +* Description : enable cpu interrupts +* Argument(s) : rt_base_t level +* Return(s) : void +* Caller(s) : Applications or os_kernel +* Note(s) : none +********************************************************************************************************* +*/ +void rt_hw_interrupt_enable(rt_base_t level) +{ + level = level; + + if (hInterruptEventMutex != NULL) + { + ReleaseMutex(hInterruptEventMutex); + } + +} /*** rt_hw_interrupt_enable ***/ + +/* +********************************************************************************************************* +* rt_hw_context_switch_interrupt() +* Description : switch thread's contex +* Argument(s) : void +* Return(s) : void +* Caller(s) : os kernel +* Note(s) : none +********************************************************************************************************* +*/ +void rt_hw_context_switch_interrupt(rt_uint32_t from, + rt_uint32_t to) +{ + if(rt_thread_switch_interrupt_flag != 1) + { + rt_thread_switch_interrupt_flag = 1; + + // set rt_interrupt_from_thread + rt_interrupt_from_thread = *((rt_uint32_t *)(from)); + } + + rt_interrupt_to_thread = *((rt_uint32_t *)(to)); + + //trigger YIELD exception(cause contex switch) + TriggerSimulateInterrupt(CPU_INTERRUPT_YIELD); +} /*** rt_hw_context_switch_interrupt ***/ + + + +void rt_hw_context_switch(rt_uint32_t from, + rt_uint32_t to) +{ + if(rt_thread_switch_interrupt_flag != 1) + { + rt_thread_switch_interrupt_flag = 1; + + // set rt_interrupt_from_thread + rt_interrupt_from_thread = *((rt_uint32_t *)(from)); + + } + + // set rt_interrupt_to_thread + rt_interrupt_to_thread = *((rt_uint32_t *)(to)); + + //trigger YIELD exception(cause contex switch) + TriggerSimulateInterrupt(CPU_INTERRUPT_YIELD); + +} /*** rt_hw_context_switch ***/ + +/* +********************************************************************************************************* +* rt_hw_context_switch_to() +* Description : switch to new thread +* Argument(s) : rt_uint32_t to //the stack address of the thread which will switch to +* Return(s) : void +* Caller(s) : rt_thread schecale +* Note(s) : this function is used to perform the first thread switch +********************************************************************************************************* +*/ +void rt_hw_context_switch_to(rt_uint32_t to) +{ + //set to thread + rt_interrupt_to_thread = *((rt_uint32_t *)(to)); + + //clear from thread + rt_interrupt_from_thread = 0; + + //set interrupt to 1 + rt_thread_switch_interrupt_flag = 1; + + //start WinThreadScheduler + WinThreadScheduler(); + + //never reach here! + return; + +} /*** rt_hw_context_switch_to ***/ + + + +/* +********************************************************************************************************* +* TriggerSimulateInterrupt() +* Description : Trigger a simulated interrupts handle +* Argument(s) : t_uint32_t IntIndex +* Return(s) : void +* Caller(s) : Applications +* Note(s) : none +********************************************************************************************************* +*/ +void TriggerSimulateInterrupt(rt_uint32_t IntIndex) +{ + if((IntIndex < MAX_INTERRUPT_NUM) && (hInterruptEventMutex != NULL)) + { + /* Yield interrupts are processed even when critical nesting is non-zero */ + WaitForSingleObject(hInterruptEventMutex, + INFINITE); + + CpuPendingInterrupts |= (1 << IntIndex); + + SetEvent(hInterruptEventHandle); + + ReleaseMutex(hInterruptEventMutex); + } +} /*** TriggerSimulateInterrupt ***/ + +/* +********************************************************************************************************* +* RegisterSimulateInterrupt() +* Description : Register a interrupt handle to simulate paltform +* Argument(s) : rt_uint32_t IntIndex,rt_uint32_t (*IntHandler)(void) +* Return(s) : void +* Caller(s) : Applications +* Note(s) : none +********************************************************************************************************* +*/ +void RegisterSimulateInterrupt(rt_uint32_t IntIndex,rt_uint32_t (*IntHandler)(void)) +{ + if(IntIndex < MAX_INTERRUPT_NUM) + { + if (hInterruptEventMutex != NULL) + { + WaitForSingleObject(hInterruptEventMutex, + INFINITE); + + CpuIsrHandler[IntIndex] = IntHandler; + + ReleaseMutex(hInterruptEventMutex); + } + else + { + CpuIsrHandler[IntIndex] = IntHandler; + } + } + +} /*** RegisterSimulateInterrupt ***/ + + + +/* +********************************************************************************************************* +* PRIVATE FUNCTION +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* WinThreadScheduler() +* Description : Handle all simulate interrupts +* Argument(s) : void +* Return(s) : static void +* Caller(s) : os scachle +* Note(s) : none +********************************************************************************************************* +*/ +#define WIN_WM_MIN_RES (1) + void WinThreadScheduler(void) +{ + HANDLE hInterruptObjectList[2]; + HANDLE hThreadHandle; + rt_uint32_t SwitchRequiredMask; + rt_uint32_t i; + + win_thread_t *WinThreadFrom; + win_thread_t *WinThreadTo; + + /* + * Install the interrupt handlers used bye scheduler itself + */ + RegisterSimulateInterrupt(CPU_INTERRUPT_YIELD, + YieldInterruptHandle); + RegisterSimulateInterrupt(CPU_INTERRUPT_TICK, + SysTickInterruptHandle); + + /* + * Create the events and mutex that are used to synchronise all the WinThreads + */ + hInterruptEventMutex = CreateMutex(NULL, + FALSE, + NULL); + hInterruptEventHandle = CreateEvent(NULL, + FALSE, + FALSE, + NULL); + + if((hInterruptEventMutex == NULL) || (hInterruptEventHandle == NULL)) + { + return; + } + + /* + * Set the priority of this WinThread such that it is above the priority of the WinThreads + * that run rt-threads. + * This is higher priority is required to ensure simulate interrupts take priority over rt-threads + */ + hThreadHandle = GetCurrentThread(); + if(hThreadHandle == NULL) + { + return; + } + + if (SetThreadPriority(hThreadHandle, + THREAD_PRIORITY_HIGHEST) == 0) + { + return; + } + SetThreadPriorityBoost(hThreadHandle, + TRUE); + SetThreadAffinityMask(hThreadHandle, + 0x01); + + /* + * Start the thread that simulates the timer peripheral to generate tick interrupts. + */ + OSTick_Thread = CreateThread(NULL, + 0, + ThreadforSysTickTimer, + 0, + CREATE_SUSPENDED, + &OSTick_ThreadID); + if(OSTick_Thread == NULL) + { + //Display Error Message + + + return; + } + SetThreadPriority(OSTick_Thread, + THREAD_PRIORITY_NORMAL); + SetThreadPriorityBoost(OSTick_Thread, + TRUE); + SetThreadAffinityMask(OSTick_Thread, + 0x01); + + /* + * Set timer Caps + */ + if (timeGetDevCaps(&OSTick_TimerCap, + sizeof(OSTick_TimerCap)) != TIMERR_NOERROR) + { + + CloseHandle(OSTick_Thread); + + return; + } + if (OSTick_TimerCap.wPeriodMin < WIN_WM_MIN_RES) + { + OSTick_TimerCap.wPeriodMin = WIN_WM_MIN_RES; + } + + if(timeBeginPeriod(OSTick_TimerCap.wPeriodMin) != TIMERR_NOERROR) + { + CloseHandle(OSTick_Thread); + + return; + } + + OSTick_SignalPtr = CreateEvent(NULL,TRUE,FALSE,NULL); + if(OSTick_SignalPtr == NULL) + { + // disp error message + + timeEndPeriod(OSTick_TimerCap.wPeriodMin); + CloseHandle(OSTick_Thread); + + return; + } + + OSTick_TimerID = timeSetEvent((UINT ) (1000 / RT_TICK_PER_SECOND) , + (UINT ) OSTick_TimerCap.wPeriodMin, + (LPTIMECALLBACK ) OSTick_SignalPtr, + (DWORD_PTR ) NULL, + (UINT ) (TIME_PERIODIC | TIME_CALLBACK_EVENT_SET)); + + if(OSTick_TimerID == 0) + { + //disp + + CloseHandle(OSTick_SignalPtr); + timeEndPeriod(OSTick_TimerCap.wPeriodMin); + CloseHandle(OSTick_Thread); + + return; + } + + /* + * Start OS Tick Thread an release Interrupt Mutex + */ + ResumeThread(OSTick_Thread); + ReleaseMutex( hInterruptEventMutex ); + + //trigger YEILD INTERRUPT + TriggerSimulateInterrupt(CPU_INTERRUPT_YIELD); + + /* + * block on the mutex that ensure exclusive access to the simulated interrupt objects + * and the events that signals that a simulated interrupt should be processed. + */ + + hInterruptObjectList[0] = hInterruptEventHandle; + hInterruptObjectList[1] = hInterruptEventMutex; + + + while (1) + { + WaitForMultipleObjects(sizeof(hInterruptObjectList) / sizeof(HANDLE), + hInterruptObjectList, + TRUE, + INFINITE); + + /* + * Used to indicate whether the simulate interrupt processing has necessitated a contex + * switch to another thread + */ + SwitchRequiredMask = 0; + + /* + * For each interrupt we are interested in processing ,each of which is represented + * by a bit in the 32bit CpuPendingInterrupts variable. + */ + for (i = 0; i < MAX_INTERRUPT_NUM; ++i) + { + /* is the simulated interrupt pending ? */ + if (CpuPendingInterrupts & (1UL << i)) + { + /* Is a handler installed ?*/ + if (CpuIsrHandler[i] != NULL) + { + /* Run the actual handler */ + if (CpuIsrHandler[i]() != 0) + { + SwitchRequiredMask |= (1UL << i); + } + } + + /* Clear the interrupt pending bit */ + CpuPendingInterrupts &= ~(1UL << i); + } + } + + if(SwitchRequiredMask != 0) + { + WinThreadFrom = (win_thread_t *)rt_interrupt_from_thread; + WinThreadTo = (win_thread_t *)rt_interrupt_to_thread; + + if ((WinThreadFrom != NULL) && (WinThreadFrom->ThreadHandle != NULL)) + { + SuspendThread(WinThreadFrom->ThreadHandle); + } + + ResumeThread(WinThreadTo->ThreadHandle); + + } + + ReleaseMutex(hInterruptEventMutex); + } +} /*** WinThreadScheduler ***/ + + + +/* +********************************************************************************************************* +* ThreadforSysTickTimer() +* Description : win thread to simulate a systick timer +* Argument(s) : LPVOID lpParam +* Return(s) : static DWORD WINAPI +* Caller(s) : none +* Note(s) : This is not a real time way of generating tick events as the next wake time should be relative +* to the previous wake time,not the time Sleep() is called. +* It is done this way to prevent overruns in this very non real time simulated/emulated environment +********************************************************************************************************* +*/ +static DWORD WINAPI ThreadforSysTickTimer(LPVOID lpParam) +{ + + (void)lpParam; //prevent compiler warnings + + for(;;) + { + /* + * Wait until the timer expires and we can access the simulated interrupt variables. + */ + WaitForSingleObject(OSTick_SignalPtr,INFINITE); + + ResetEvent(OSTick_SignalPtr); + + /* + * Trigger a systick interrupt + */ + TriggerSimulateInterrupt(CPU_INTERRUPT_TICK); + + } + + return 0; + +} /*** prvThreadforSysTickTimer ***/ + +/* +********************************************************************************************************* +* SysTickInterruptHandle() +* Description : Interrupt handle for systick +* Argument(s) : void +* Return(s) : rt_uint32_t +* Caller(s) : none +* Note(s) : none +********************************************************************************************************* +*/ +rt_uint32_t SysTickInterruptHandle(void) +{ + + /* enter interrupt */ + rt_interrupt_enter(); + + rt_tick_increase(); + + /* leave interrupt */ + rt_interrupt_leave(); + + return 0; +} /*** SysTickInterruptHandle ***/ + +/* +********************************************************************************************************* +* YieldInterruptHandle() +* Description : Interrupt handle for Yield +* Argument(s) : void +* Return(s) : rt_uint32_t +* Caller(s) : none +* Note(s) : none +********************************************************************************************************* +*/ +rt_uint32_t YieldInterruptHandle(void) +{ + + /* + * if rt_thread_switch_interrupt_flag = 1 yield already handled + */ + if(rt_thread_switch_interrupt_flag != 0) + { + rt_thread_switch_interrupt_flag = 0; + + /* return thread switch request = 1 */ + return 1; + } + + return 0; +} /*** YieldInterruptHandle ***/ diff --git a/libcpu/sim/win32/cpu_port.h b/libcpu/sim/win32/cpu_port.h new file mode 100644 index 0000000000000000000000000000000000000000..9d43d61c6d4b029e770d1ad3f428efde91be29db --- /dev/null +++ b/libcpu/sim/win32/cpu_port.h @@ -0,0 +1,33 @@ +/* +************************************************************************************************************************ +* File : cpu_port.h +* By : xyou +* Version : V1.00.00 +************************************************************************************************************************ +*/ + + + +#ifndef _CPU_PORT_H_ +#define _CPU_PORT_H_ + + +/* +********************************************************************************************************* +* CPU INTERRUPT PRIORITY +********************************************************************************************************* +*/ +#define CPU_INTERRUPT_YIELD 0x00 +#define CPU_INTERRUPT_TICK 0x01 + + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ +void TriggerSimulateInterrupt(rt_uint32_t IntIndex); + +void WinThreadScheduler(void); +#endif /* _CPU_PORT_H_ */