cpu_port.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*
  2. ************************************************************************************************************************
  3. * File : cpu_port.c
  4. * By : xyou
  5. * Version : V1.00.00
  6. *
  7. * By : prife
  8. * Version : V1.00.01
  9. ************************************************************************************************************************
  10. */
  11. /*
  12. *********************************************************************************************************
  13. * INCLUDE FILES
  14. *********************************************************************************************************
  15. */
  16. #include <rtthread.h>
  17. #include <windows.h>
  18. #include <mmsystem.h>
  19. #include <stdio.h>
  20. #include "cpu_port.h"
  21. /*
  22. *********************************************************************************************************
  23. * WinThread STRUCTURE
  24. * Windows runs each task in a thread.
  25. * The context switch is managed by the threads.So the task stack does not have to be managed directly,
  26. * although the stack stack is still used to hold an WinThreadState structure this is the only thing it
  27. * will be ever hold.
  28. * the structure indirectly maps the task handle to a thread handle
  29. *********************************************************************************************************
  30. */
  31. typedef struct
  32. {
  33. void *Param; //Thread param
  34. void (*Entry)(void *); //Thread entry
  35. void (*Exit)(void); //Thread exit
  36. HANDLE ThreadHandle;
  37. DWORD ThreadID;
  38. }win_thread_t;
  39. /*
  40. *********************************************************************************************************
  41. * LOCAL DEFINES
  42. *********************************************************************************************************
  43. */
  44. #define MAX_INTERRUPT_NUM ((rt_uint32_t)sizeof(rt_uint32_t) * 8)
  45. /*
  46. * Simulated interrupt waiting to be processed.this is a bit mask where each bit represent one interrupt
  47. * so a maximum of 32 interrupts can be simulated
  48. */
  49. static volatile rt_uint32_t CpuPendingInterrupts = 0;
  50. /*
  51. * An event used to inform the simulated interrupt processing thread (a high priority thread
  52. * that simulated interrupt processing) that an interrupt is pending
  53. */
  54. static HANDLE hInterruptEventHandle = NULL;
  55. /*
  56. * Mutex used to protect all the simulated interrupt variables that are accessed by multiple threads
  57. */
  58. static HANDLE hInterruptEventMutex = NULL;
  59. /*
  60. * Handler for all the simulate software interrupts.
  61. * The first two positions are used the Yield and Tick interrupt so are handled slightly differently
  62. * all the other interrupts can be user defined
  63. */
  64. static rt_uint32_t (*CpuIsrHandler[MAX_INTERRUPT_NUM])(void) = {0};
  65. /*
  66. * Handler for OSTick Thread
  67. */
  68. static HANDLE OSTick_Thread;
  69. static DWORD OSTick_ThreadID;
  70. static HANDLE OSTick_SignalPtr;
  71. static TIMECAPS OSTick_TimerCap;
  72. static MMRESULT OSTick_TimerID;
  73. /*
  74. * flag in interrupt handling
  75. */
  76. rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
  77. rt_uint32_t rt_thread_switch_interrupt_flag;
  78. /*
  79. *********************************************************************************************************
  80. * PRIVATE FUNCTION PROTOTYPES
  81. *********************************************************************************************************
  82. */
  83. //static void WinThreadScheduler(void);
  84. void WinThreadScheduler(void);
  85. rt_uint32_t YieldInterruptHandle(void);
  86. rt_uint32_t SysTickInterruptHandle(void);
  87. static DWORD WINAPI ThreadforSysTickTimer(LPVOID lpParam);
  88. static DWORD WINAPI ThreadforKeyGet(LPVOID lpParam);
  89. /*
  90. *********************************************************************************************************
  91. * CPU Port Function for RT-Thread
  92. *********************************************************************************************************
  93. */
  94. //void rt_hw_console_output(const char *str)
  95. //{
  96. // printf("%s",str);
  97. //}
  98. /*
  99. *********************************************************************************************************
  100. * rt_hw_stack_init()
  101. * Description : Initialize stack of thread
  102. * Argument(s) : void *pvEntry,void *pvParam,rt_uint8_t *pStackAddr,void *pvExit
  103. * Return(s) : rt_uint8_t*
  104. * Caller(s) : rt_thread_init or rt_thread_create
  105. * Note(s) : none
  106. *********************************************************************************************************
  107. */
  108. static DWORD WINAPI thread_run( LPVOID lpThreadParameter )
  109. {
  110. win_thread_t *pWinThread = (win_thread_t *)lpThreadParameter;
  111. pWinThread->Entry(pWinThread->Param);
  112. printf("thread %x exit\n", pWinThread->ThreadID);
  113. pWinThread->Exit();
  114. return 0;
  115. }
  116. rt_uint8_t* rt_hw_stack_init(void *pEntry,void *pParam,rt_uint8_t *pStackAddr,void *pExit)
  117. {
  118. win_thread_t *pWinThread = NULL;
  119. /*
  120. * In this simulated case a stack is not initialized
  121. * The thread handles the context switching itself. The WinThreadState object is placed onto the stack
  122. * that was created for the task
  123. * so the stack buffer is still used,just not in the conventional way.
  124. */
  125. pWinThread = (win_thread_t *)(pStackAddr - sizeof(win_thread_t));
  126. pWinThread->Entry = pEntry;
  127. pWinThread->Param = pParam;
  128. pWinThread->Exit = pExit;
  129. pWinThread->ThreadHandle = NULL;
  130. pWinThread->ThreadID = 0;
  131. /* Create the winthread */
  132. pWinThread->ThreadHandle = CreateThread(NULL,
  133. 0,
  134. (LPTHREAD_START_ROUTINE) thread_run,
  135. pWinThread,
  136. CREATE_SUSPENDED,
  137. &(pWinThread->ThreadID));
  138. SetThreadAffinityMask(pWinThread->ThreadHandle,
  139. 0x01);
  140. SetThreadPriorityBoost(pWinThread->ThreadHandle,
  141. TRUE);
  142. SetThreadPriority(pWinThread->ThreadHandle,
  143. THREAD_PRIORITY_IDLE);
  144. return (rt_uint8_t*)pWinThread;
  145. } /*** rt_hw_stack_init ***/
  146. /*
  147. *********************************************************************************************************
  148. * rt_hw_interrupt_disable()
  149. * Description : disable cpu interrupts
  150. * Argument(s) : void
  151. * Return(s) : rt_base_t
  152. * Caller(s) : Applicatios or os_kernel
  153. * Note(s) : none
  154. *********************************************************************************************************
  155. */
  156. rt_base_t rt_hw_interrupt_disable(void)
  157. {
  158. if(hInterruptEventMutex != NULL)
  159. {
  160. WaitForSingleObject(hInterruptEventMutex,INFINITE);
  161. }
  162. return 0;
  163. } /*** rt_hw_interrupt_disable ***/
  164. /*
  165. *********************************************************************************************************
  166. * rt_hw_interrupt_enable()
  167. * Description : enable cpu interrupts
  168. * Argument(s) : rt_base_t level
  169. * Return(s) : void
  170. * Caller(s) : Applications or os_kernel
  171. * Note(s) : none
  172. *********************************************************************************************************
  173. */
  174. void rt_hw_interrupt_enable(rt_base_t level)
  175. {
  176. level = level;
  177. if (hInterruptEventMutex != NULL)
  178. {
  179. ReleaseMutex(hInterruptEventMutex);
  180. }
  181. } /*** rt_hw_interrupt_enable ***/
  182. /*
  183. *********************************************************************************************************
  184. * rt_hw_context_switch_interrupt()
  185. * Description : switch thread's contex
  186. * Argument(s) : void
  187. * Return(s) : void
  188. * Caller(s) : os kernel
  189. * Note(s) : none
  190. *********************************************************************************************************
  191. */
  192. void rt_hw_context_switch_interrupt(rt_uint32_t from,
  193. rt_uint32_t to)
  194. {
  195. if(rt_thread_switch_interrupt_flag != 1)
  196. {
  197. rt_thread_switch_interrupt_flag = 1;
  198. // set rt_interrupt_from_thread
  199. rt_interrupt_from_thread = *((rt_uint32_t *)(from));
  200. }
  201. rt_interrupt_to_thread = *((rt_uint32_t *)(to));
  202. //trigger YIELD exception(cause contex switch)
  203. TriggerSimulateInterrupt(CPU_INTERRUPT_YIELD);
  204. } /*** rt_hw_context_switch_interrupt ***/
  205. void rt_hw_context_switch(rt_uint32_t from,
  206. rt_uint32_t to)
  207. {
  208. if(rt_thread_switch_interrupt_flag != 1)
  209. {
  210. rt_thread_switch_interrupt_flag = 1;
  211. // set rt_interrupt_from_thread
  212. rt_interrupt_from_thread = *((rt_uint32_t *)(from));
  213. }
  214. // set rt_interrupt_to_thread
  215. rt_interrupt_to_thread = *((rt_uint32_t *)(to));
  216. //trigger YIELD exception(cause contex switch)
  217. TriggerSimulateInterrupt(CPU_INTERRUPT_YIELD);
  218. } /*** rt_hw_context_switch ***/
  219. /*
  220. *********************************************************************************************************
  221. * rt_hw_context_switch_to()
  222. * Description : switch to new thread
  223. * Argument(s) : rt_uint32_t to //the stack address of the thread which will switch to
  224. * Return(s) : void
  225. * Caller(s) : rt_thread schecale
  226. * Note(s) : this function is used to perform the first thread switch
  227. *********************************************************************************************************
  228. */
  229. void rt_hw_context_switch_to(rt_uint32_t to)
  230. {
  231. //set to thread
  232. rt_interrupt_to_thread = *((rt_uint32_t *)(to));
  233. //clear from thread
  234. rt_interrupt_from_thread = 0;
  235. //set interrupt to 1
  236. rt_thread_switch_interrupt_flag = 1;
  237. //start WinThreadScheduler
  238. WinThreadScheduler();
  239. //never reach here!
  240. return;
  241. } /*** rt_hw_context_switch_to ***/
  242. /*
  243. *********************************************************************************************************
  244. * TriggerSimulateInterrupt()
  245. * Description : Trigger a simulated interrupts handle
  246. * Argument(s) : t_uint32_t IntIndex
  247. * Return(s) : void
  248. * Caller(s) : Applications
  249. * Note(s) : none
  250. *********************************************************************************************************
  251. */
  252. void TriggerSimulateInterrupt(rt_uint32_t IntIndex)
  253. {
  254. if((IntIndex < MAX_INTERRUPT_NUM) && (hInterruptEventMutex != NULL))
  255. {
  256. /* Yield interrupts are processed even when critical nesting is non-zero */
  257. WaitForSingleObject(hInterruptEventMutex,
  258. INFINITE);
  259. CpuPendingInterrupts |= (1 << IntIndex);
  260. SetEvent(hInterruptEventHandle);
  261. ReleaseMutex(hInterruptEventMutex);
  262. }
  263. } /*** TriggerSimulateInterrupt ***/
  264. /*
  265. *********************************************************************************************************
  266. * RegisterSimulateInterrupt()
  267. * Description : Register a interrupt handle to simulate paltform
  268. * Argument(s) : rt_uint32_t IntIndex,rt_uint32_t (*IntHandler)(void)
  269. * Return(s) : void
  270. * Caller(s) : Applications
  271. * Note(s) : none
  272. *********************************************************************************************************
  273. */
  274. void RegisterSimulateInterrupt(rt_uint32_t IntIndex,rt_uint32_t (*IntHandler)(void))
  275. {
  276. if(IntIndex < MAX_INTERRUPT_NUM)
  277. {
  278. if (hInterruptEventMutex != NULL)
  279. {
  280. WaitForSingleObject(hInterruptEventMutex,
  281. INFINITE);
  282. CpuIsrHandler[IntIndex] = IntHandler;
  283. ReleaseMutex(hInterruptEventMutex);
  284. }
  285. else
  286. {
  287. CpuIsrHandler[IntIndex] = IntHandler;
  288. }
  289. }
  290. } /*** RegisterSimulateInterrupt ***/
  291. /*
  292. *********************************************************************************************************
  293. * PRIVATE FUNCTION
  294. *********************************************************************************************************
  295. */
  296. /*
  297. *********************************************************************************************************
  298. * WinThreadScheduler()
  299. * Description : Handle all simulate interrupts
  300. * Argument(s) : void
  301. * Return(s) : static void
  302. * Caller(s) : os scachle
  303. * Note(s) : none
  304. *********************************************************************************************************
  305. */
  306. #define WIN_WM_MIN_RES (1)
  307. void WinThreadScheduler(void)
  308. {
  309. HANDLE hInterruptObjectList[2];
  310. HANDLE hThreadHandle;
  311. rt_uint32_t SwitchRequiredMask;
  312. rt_uint32_t i;
  313. win_thread_t *WinThreadFrom;
  314. win_thread_t *WinThreadTo;
  315. /*
  316. * Install the interrupt handlers used bye scheduler itself
  317. */
  318. RegisterSimulateInterrupt(CPU_INTERRUPT_YIELD,
  319. YieldInterruptHandle);
  320. RegisterSimulateInterrupt(CPU_INTERRUPT_TICK,
  321. SysTickInterruptHandle);
  322. /*
  323. * Create the events and mutex that are used to synchronise all the WinThreads
  324. */
  325. hInterruptEventMutex = CreateMutex(NULL,
  326. FALSE,
  327. NULL);
  328. hInterruptEventHandle = CreateEvent(NULL,
  329. FALSE,
  330. FALSE,
  331. NULL);
  332. if((hInterruptEventMutex == NULL) || (hInterruptEventHandle == NULL))
  333. {
  334. return;
  335. }
  336. /*
  337. * Set the priority of this WinThread such that it is above the priority of the WinThreads
  338. * that run rt-threads.
  339. * This is higher priority is required to ensure simulate interrupts take priority over rt-threads
  340. */
  341. hThreadHandle = GetCurrentThread();
  342. if(hThreadHandle == NULL)
  343. {
  344. return;
  345. }
  346. if (SetThreadPriority(hThreadHandle,
  347. THREAD_PRIORITY_HIGHEST) == 0)
  348. {
  349. return;
  350. }
  351. SetThreadPriorityBoost(hThreadHandle,
  352. TRUE);
  353. SetThreadAffinityMask(hThreadHandle,
  354. 0x01);
  355. /*
  356. * Start the thread that simulates the timer peripheral to generate tick interrupts.
  357. */
  358. OSTick_Thread = CreateThread(NULL,
  359. 0,
  360. ThreadforSysTickTimer,
  361. 0,
  362. CREATE_SUSPENDED,
  363. &OSTick_ThreadID);
  364. if(OSTick_Thread == NULL)
  365. {
  366. //Display Error Message
  367. return;
  368. }
  369. SetThreadPriority(OSTick_Thread,
  370. THREAD_PRIORITY_NORMAL);
  371. SetThreadPriorityBoost(OSTick_Thread,
  372. TRUE);
  373. SetThreadAffinityMask(OSTick_Thread,
  374. 0x01);
  375. /*
  376. * Set timer Caps
  377. */
  378. if (timeGetDevCaps(&OSTick_TimerCap,
  379. sizeof(OSTick_TimerCap)) != TIMERR_NOERROR)
  380. {
  381. CloseHandle(OSTick_Thread);
  382. return;
  383. }
  384. if (OSTick_TimerCap.wPeriodMin < WIN_WM_MIN_RES)
  385. {
  386. OSTick_TimerCap.wPeriodMin = WIN_WM_MIN_RES;
  387. }
  388. if(timeBeginPeriod(OSTick_TimerCap.wPeriodMin) != TIMERR_NOERROR)
  389. {
  390. CloseHandle(OSTick_Thread);
  391. return;
  392. }
  393. OSTick_SignalPtr = CreateEvent(NULL,TRUE,FALSE,NULL);
  394. if(OSTick_SignalPtr == NULL)
  395. {
  396. // disp error message
  397. timeEndPeriod(OSTick_TimerCap.wPeriodMin);
  398. CloseHandle(OSTick_Thread);
  399. return;
  400. }
  401. OSTick_TimerID = timeSetEvent((UINT ) (1000 / RT_TICK_PER_SECOND) ,
  402. (UINT ) OSTick_TimerCap.wPeriodMin,
  403. (LPTIMECALLBACK ) OSTick_SignalPtr,
  404. (DWORD_PTR ) NULL,
  405. (UINT ) (TIME_PERIODIC | TIME_CALLBACK_EVENT_SET));
  406. if(OSTick_TimerID == 0)
  407. {
  408. //disp
  409. CloseHandle(OSTick_SignalPtr);
  410. timeEndPeriod(OSTick_TimerCap.wPeriodMin);
  411. CloseHandle(OSTick_Thread);
  412. return;
  413. }
  414. /*
  415. * Start OS Tick Thread an release Interrupt Mutex
  416. */
  417. ResumeThread(OSTick_Thread);
  418. ReleaseMutex( hInterruptEventMutex );
  419. //trigger YEILD INTERRUPT
  420. TriggerSimulateInterrupt(CPU_INTERRUPT_YIELD);
  421. /*
  422. * block on the mutex that ensure exclusive access to the simulated interrupt objects
  423. * and the events that signals that a simulated interrupt should be processed.
  424. */
  425. hInterruptObjectList[0] = hInterruptEventHandle;
  426. hInterruptObjectList[1] = hInterruptEventMutex;
  427. while (1)
  428. {
  429. WaitForMultipleObjects(sizeof(hInterruptObjectList) / sizeof(HANDLE),
  430. hInterruptObjectList,
  431. TRUE,
  432. INFINITE);
  433. /*
  434. * Used to indicate whether the simulate interrupt processing has necessitated a contex
  435. * switch to another thread
  436. */
  437. SwitchRequiredMask = 0;
  438. /*
  439. * For each interrupt we are interested in processing ,each of which is represented
  440. * by a bit in the 32bit CpuPendingInterrupts variable.
  441. */
  442. for (i = 0; i < MAX_INTERRUPT_NUM; ++i)
  443. {
  444. /* is the simulated interrupt pending ? */
  445. if (CpuPendingInterrupts & (1UL << i))
  446. {
  447. /* Is a handler installed ?*/
  448. if (CpuIsrHandler[i] != NULL)
  449. {
  450. /* Run the actual handler */
  451. if (CpuIsrHandler[i]() != 0)
  452. {
  453. SwitchRequiredMask |= (1UL << i);
  454. }
  455. }
  456. /* Clear the interrupt pending bit */
  457. CpuPendingInterrupts &= ~(1UL << i);
  458. }
  459. }
  460. if(SwitchRequiredMask != 0)
  461. {
  462. WinThreadFrom = (win_thread_t *)rt_interrupt_from_thread;
  463. WinThreadTo = (win_thread_t *)rt_interrupt_to_thread;
  464. if ((WinThreadFrom != NULL) && (WinThreadFrom->ThreadHandle != NULL))
  465. {
  466. SuspendThread(WinThreadFrom->ThreadHandle);
  467. }
  468. ResumeThread(WinThreadTo->ThreadHandle);
  469. }
  470. ReleaseMutex(hInterruptEventMutex);
  471. }
  472. } /*** WinThreadScheduler ***/
  473. /*
  474. *********************************************************************************************************
  475. * ThreadforSysTickTimer()
  476. * Description : win thread to simulate a systick timer
  477. * Argument(s) : LPVOID lpParam
  478. * Return(s) : static DWORD WINAPI
  479. * Caller(s) : none
  480. * Note(s) : This is not a real time way of generating tick events as the next wake time should be relative
  481. * to the previous wake time,not the time Sleep() is called.
  482. * It is done this way to prevent overruns in this very non real time simulated/emulated environment
  483. *********************************************************************************************************
  484. */
  485. static DWORD WINAPI ThreadforSysTickTimer(LPVOID lpParam)
  486. {
  487. (void)lpParam; //prevent compiler warnings
  488. for(;;)
  489. {
  490. /*
  491. * Wait until the timer expires and we can access the simulated interrupt variables.
  492. */
  493. WaitForSingleObject(OSTick_SignalPtr,INFINITE);
  494. ResetEvent(OSTick_SignalPtr);
  495. /*
  496. * Trigger a systick interrupt
  497. */
  498. TriggerSimulateInterrupt(CPU_INTERRUPT_TICK);
  499. }
  500. return 0;
  501. } /*** prvThreadforSysTickTimer ***/
  502. /*
  503. *********************************************************************************************************
  504. * SysTickInterruptHandle()
  505. * Description : Interrupt handle for systick
  506. * Argument(s) : void
  507. * Return(s) : rt_uint32_t
  508. * Caller(s) : none
  509. * Note(s) : none
  510. *********************************************************************************************************
  511. */
  512. rt_uint32_t SysTickInterruptHandle(void)
  513. {
  514. /* enter interrupt */
  515. rt_interrupt_enter();
  516. rt_tick_increase();
  517. /* leave interrupt */
  518. rt_interrupt_leave();
  519. return 0;
  520. } /*** SysTickInterruptHandle ***/
  521. /*
  522. *********************************************************************************************************
  523. * YieldInterruptHandle()
  524. * Description : Interrupt handle for Yield
  525. * Argument(s) : void
  526. * Return(s) : rt_uint32_t
  527. * Caller(s) : none
  528. * Note(s) : none
  529. *********************************************************************************************************
  530. */
  531. rt_uint32_t YieldInterruptHandle(void)
  532. {
  533. /*
  534. * if rt_thread_switch_interrupt_flag = 1 yield already handled
  535. */
  536. if(rt_thread_switch_interrupt_flag != 0)
  537. {
  538. rt_thread_switch_interrupt_flag = 0;
  539. /* return thread switch request = 1 */
  540. return 1;
  541. }
  542. return 0;
  543. } /*** YieldInterruptHandle ***/