2007年7月26日 星期四

FPPA 多執行緒?

這兩天看到這篇文章 Coroutine in FPPA,寫有關於用同一顆 CPU 來跑不同 TASK 的問題。
突然也靈機一動,想來試試這樣子的機制可以用在哪邊~

答案是~多執行緒~Time Sharing

把一個CPU當成四個來用,靠TIMER中斷來控制PC頁的切換~
可惜由於中斷只有FPP0能產生,所以只能作用在FPP0~
不過,要切成幾個分時的TASK基本上都沒有問題~嘿~有趣了。

測試的中間也發現一個有趣的問題,delay 這個指令由於不是一個指令周期就能完成(同時 acc 遞減),導致有可能delay到一半被 swap out,再回來時 PC 又重回到了delay上(acc又重置),結果就是 delay 不完。
解決的方法目前想到的就是暫時把中斷關掉嘍。(安全起見)

另一個問題,萬一 time slice 小於一個指令周期的話,會造成類似上面的情形,指令尚未完成,PC還沒來的及往後加,就被 swap out,再回來又回到了原點,結果就是一個指令永遠也跑不完。

這樣子的狀況代表的意義很值得深入去探討,也就是關係到 fppa 核心硬體設計上的特性~
於是會不會有一種可能,太快的 timer interrupt 或 time slice 的大小~造成「不正常的」swap out?

解決的方式可能還有待進行各種不同的試驗才會知道,應當是可以調整到切出固定的 time slice 出來(正確來講是分配到同樣多的指令周期),當然如果你的要求不是很嚴苛的話,那只要確保能往下跑也就ok了。

另外一種解決方式,就是用 internal interrupt 的方式來由各 task 控制把自己的執行權讓出來,這也是可行,不過好像就少了那種味道了。

至於是不是還有其它更多問題? 我想要實際拿來用才知道了。

不過話說回來,也蠻懷疑這樣大費周張的效益倒底有多大,因為畢竟八核己經很夠用了,而且除非要寫的程式要控制的事項非常的煩多,才會突顯出它的便利性吧?


// ======== START RAM Define ========
.ramadr 0x00
word nousePC;
word task0PC;
word task1PC;
word task2PC;
word task3PC;
word t16index;
int taskno;
// ======== END RAM Define ========

// ======== START FPPA ========
.romadr 0x0000
goto fpp0Boot;
goto fpp1Boot;
goto fpp2Boot;
goto fpp3Boot;
goto fpp4Boot;
goto fpp5Boot;
goto fpp6Boot;
goto fpp7Boot;
// ======== END FPPA ========

// ======== START Interrpt Service Routine ========
.romadr 0x0010
mov a, 0xFF; /// 第一次產生中斷,stack裡的pc是無用的
ceqsn taskno, a;
goto switch01;
popw nousePC;
pushw task0PC; /// 準備切到task0 pc
goto switchOk;
switch01:
mov a, 0;
ceqsn taskno, a;
goto switch12;
popw task0PC; /// 保存好task0 PC
pushw task1PC; /// 準備切到task1
goto switchOk;
switch12:
mov a, 1;
ceqsn taskno, a;
goto switch23;
popw task1PC; /// 保存好task1 PC
pushw task2PC; /// 準備切到task2
goto switchOk;
switch23:
mov a, 2;
ceqsn taskno, a;
goto switch30;
popw task2PC; /// 保存好task2 PC
pushw task3PC; /// 準備切到task3
goto switchOk;
switch30:
mov a, 3;
ceqsn taskno, a;
goto switchOk;
popw task3PC; /// 保存好task3 PC
pushw task0PC; // /準備切到task0
switchOk:
inc taskno; /// 記錄目前task編號-遞增循環
mov a, 0b00000011;
and taskno, a;
stt16 t16index ; /// 重置 Time Slice
set0 intrq.2;
reti;
// ======== END Interrpt Service Routine ========
fpp0boot:
// -------- START FPPA Boot Setting --------
///...略
// -------- END FPPA Boot Setting --------
// -------- START Interrupt initial setup --------
mov a, 0x00;
mov intrq, a; /// clear interrpt reqest register
mov a, 0b00000100;
mov inten, a; /// enable Timer16 interrupt
// -------- END Interrupt initial setup --------

// -------- START Timer16 initial setup --------
mov a, 0x00; /// timer 16 is up-count
mov lb@t16index, a ; ///Time Slice
mov a, 0x00;
mov hb@t16index, a ;

mov a, 0b10010000 ;
mov t16m, a ; /// Set OSC/Prescale
// -------- END Timer16 initial setup --------

// -------- START variables initialize --------
mov a, la@Task0;
mov lb@task0PC, a;
mov a, ha@Task0;
mov hb@task0PC, a;

mov a, la@Task1;
mov lb@task1PC, a;
mov a, ha@Task1;
mov hb@task1PC, a;

mov a, la@Task2;
mov lb@task2PC, a;
mov a, ha@Task2;
mov hb@task2PC, a;

mov a, la@Task3;
mov lb@task3PC, a;
mov a, ha@Task3;
mov hb@task3PC, a;

mov a, 0xFF;
mov taskno, a;
// -------- END variables initialize --------

/// Enable ALL FPP !!
mov a, 0b11111111;
mov fppen, a ;

/// Stack Pointer Setting for fpp0
mov a, 0x60;
mov sp, a;

stt16 t16index ;
engint;
goto $; /// Idle... waitting first interrupt
Task0:
tog LED0;
goto Task0;
Task1:
tog LED1;
goto Task1;
Task2:
tog LED2;
goto Task2;
Task3:
tog LED3;
goto Task3;

沒有留言:

更高效處理 micro second 的方式

更高效處理 micro second 的方式…  以 STM32 為例… __IO unsigned long sys_tick = 0; void SysTick_Handler(void) {     HAL_IncTick();     sys_tick += (SysTi...