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;

不同速度各 CPU 同步的問題

在不同時脈下工作的 CPU,例如在 pmode=0 的模式 fpp0(/2) fpp1(/8)
假設 fpp0 的 1T=1us、那麼 fpp1 的 1T=4us…

程式碼A:
fpp0:
delay unknown_cycles
set0 signal
goto fpp0
fpp1:
wait0 signal
set1 signal
goto fpp1

問題:fpp1 在 wait 的時候是每 4us 去檢查一次 signal 或者是每 1us 就會檢查一次(或更即時?) 並且往下跑 ? (這影響到 fpp1 頻率固定的問題)

實際測試結果==>

使用 ICE 單步追蹤的結果是 wiat 指令是按當時 CPU 的指令周期來算的,fppa1每 4us 才會檢查一次signal ~(真正的晶片應該也是?)

於是底下程式碼就有可能變成 fpp1 always waitting。(因為每次去檢查都不巧被設為1)

程式碼B:
fpp0Loop:
set0 signal;
set0 signal;
set1 signal;
goto fpp0Loop;

fpp1Loop:
wait0 signal;
// do something
goto fpp1Loop;

再回頭看原來的程式碼A…
程式碼A的 fpp1 有可能在檢查 signal 之前剛好 signal 被設為 0
也可能在檢查 signal 之後的 3us 之內 signal 才被設為 0,於是有了誤差。

相反的,若是快的 cpu 等慢的 cpu 也會有搶到拍子的情況發生。

結論==>
 這應該是屬於 fppa 硬體上的特性,程式設計師自己要小心留意到的一個問題。

2007年7月22日 星期日

簡單的按鈕防彈跳程式碼

 wait1 BTN0;
call Delay;
t1sn BTN0;
goto $-3;
// TODO: button down
wait0 BTN0;
call Delay;
t0sn BTN0;
goto $-3;
// TODO: button release

2007年7月21日 星期六

FPPA 副程式區城變數的問題(結語)

這樣子的結果,感覺還不錯

雖然還不確定在實際應用面能起多大作用

但是,至少在多了一種控制多 cpu 的方式

可以預見,在一些場合,會須要有類似這樣子的(先後)機制

譬如,一個專司 LCM 模組的 cpu,就不能隨機的接受輸出,不然輸出會不成樣…

當然,這些是必須要花一些 cpu 成本的,(大約7-8個指令周期)

而且,可能會有不確定性~(的等待時間)

再者,這也只是自己試的一個方法,還沒有完整的驗證過(包括硬體層面)

說不一定在怎樣的情況下會造成打死結的情況~!?

2007年7月20日 星期五

FPPA 副程式區城變數的問題(正解…?)

延續上一次的架構…
多加了一個鎖,來讓等待中的cpu同步進入要求 share 變數的階段…

現在手邊 ICE 正在跑 8 個 CPU 同步在執行同一段 delay 副程式,執行次數可以說完全一樣。
也試過 8 個 CPU 不同步( 幾乎隨機 ),跑同一段 delay 程式,沒有明顯互相鎖死的情況發生,也確實都有在跑。
再來, 8 個 cpu 不同步,也不同速( mode 0 ),跑同一段 delay 程式,沒有明顯互相鎖死的情況發生,也確實都有在跑。

嘿~看來真的可行~
一個 share 變數( 或一段程式 ) exclusive 執行。
意即~一段程式可以( 安全 )共享執行。


重點在這兩行
inc share_token;
dzsn share_token;
8核同時執行,但是share_token狀態唯一的特性使得只有一個核心得到0的結果。

WaitToken macro // min cost 8 i-cycle
wait0 wait_look;
inc share_token;
dzsn share_token;
goto $-3;
inc share_token;
set1 wait_look;
endm

FreeToken macro
dec share_token;
set0 wait_look;
endm

2007年7月19日 星期四

FPPA 副程式區城變數的問題(意想不到的問題)

// 取得 share 變數使用權:
inc share_token; // 要求取得 share 變數使用權
dzsn share_token; // 由於保證 ram 內容一次只有一個 fppa 能動~所以能保證只有一個 fppa 能過這關
goto $-2; // 其它 fppa 進入等待的循環
inc share_token; // fppa 取得 share 變數使用權

// 釋放 share 變數使用權 :
dec share_token; // fppa 釋放 share 變數使用權

當cpu都同步同速時~幾乎沒有問題~
反之,各cpu就有可能在1-2間打結,造成 share_token 永不為零的狀況,死當。

這個問題很有可能不被發現~要看你這段程式的使用頻率狀況而定~在隨機的情況下,發生的機率應該很大。

2007年7月17日 星期二

FPPA 副程式區城變數的問題(解法)

這個方法~看起來好像很不錯~嘿
簡單好用,稍加修改還可以用 share 作雙迴圈
但是萬萬沒想到有個嚴重的缺點~是什麼?


.ramadr 0x00
word share;
int share_token;

WaitToken macro
inc share_token;
dzsn share_token;
goto $-2;
inc share_token;
endm

FreeToken macro
dec share_token;
endm

Delay:
WaitToken;
mov a, 50;
mov lb@share, a;
DelayLoop:
pushw share;
FreeToken;

delay 200; // do some thing here

WaitToken;
popw share;
dzsn lb@share;
goto DelayLoop;

FreeToken;

ret;

VirtualBox 空間減肥

sdelete64 -z c: VBoxManage  modifymedium  disk  "/Users/fellow/VirtualBox VMs/Win10/Win10.vdi"  --compact *.vdi 路徑可以在 VirtualBox 儲...