Browse Source

add libcpu/sim/win32 to support the win32 bsp (compiled by visual studio)

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2359 bbd45198-f89e-11dd-88c7-29a3b14d5316
goprife@gmail.com 12 years ago
parent
commit
20352571e2
2 changed files with 691 additions and 0 deletions
  1. 658 0
      libcpu/sim/win32/cpu_port.c
  2. 33 0
      libcpu/sim/win32/cpu_port.h

+ 658 - 0
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  <rtthread.h>
+#include  <windows.h>
+#include  <mmsystem.h>
+#include  <stdio.h>
+#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 ***/

+ 33 - 0
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_ */