如何設計高低階混用碼指令?
曾慶潭 Ching-Tang Tseng
ilikeforth@gmail.com
Hamilton, New Zealand
16 March 2026
在某些特殊情況,當我們使用 FORTH 系統提供的所有現成指令設計程式時,會希望高低階指令可以任意混合使用,這種特殊編寫程式的功能稱之為混碼程式(Mixing code)技術。程式語言可以有許許多多的古怪技術,但對 FORTH 而言,只要是你描述得出來的技術, FORTH 沒有設計不出來的,而且強調僅由個人私下就可以解決,這是 FORTH 具有延伸性性能使然。不像其他程式語言,特殊功能通常要等原販售公司將其添加於系統,發行新版後才有可能,因為大多數程式語言均屬封閉性,不容使用者隨意修改系統既定功能。本文介紹如何為 FORTH 系統添加混碼程式功能?它就是一個 FORTH 程式語言與其他程式語言比較時,在眾多性能差異上,特別成為鮮明對比的例子。
1 預備知識
初學 FORTH 之人,可能較難看懂這種指令的設計原理,因為初學者通常不會一開始就直接接觸理論性的『FORTH系統結構』與『FORTH指令基本結構』,更進一步的『FORTH執行原理』,則要等學過 FORTH 後,還有興趣深入探討系統時才會去研究它,而欲設計這種指令時,必須先具備這些基本知識,否則不易透徹了解它們的設計方法。另外,因為要混用高低階指令編寫程式,系統當然要具備 FORTH Assembler 的功能,在使用 FORTH 組合語言時,所有的規矩也都得遵循,要有『CPU內有那些暫存器不可亂用?』的限制觀念。上述的預備知識就成了能看懂本文的基本要素了。屬於系統部份的預備知識,你可以從 1987 年 4 月我們出版過的『FORTH期刊』中獲得。組合語言的部份要自行下功夫實作後才能真正體會了解,要先行標出 CPU 內那些暫存器被 FORTH 系統規劃掉了?必須避開不用,或用前搬開內容,用完再合理恢復,所寫的程式執行時才不會出錯。
這些指令不屬於標準指令,在歷來的標準指令表中找不到他們的蹤跡,甚至於最新的 ANSI 標準中也絕口不提,可是它在 FORTH 發展的早期就已經被經常使用了,很久以前,我們在使用這種性能已經多年之後,才在後來新發行的 C 類程式語言系統中見到它的仿照設計。 FORTH 有許多性能領先別人許久,一直到今天依然如此,我們還可以舉出多項性能是一般程式語言所沒有的,這也是為何學會 FORTH 後便愛用 FORTH 的原因。學會設計混碼程式需用指令的設計方法,將更加強對於 FORTH 系統的深入認識,也將終身受用。看懂本文,將來就能輕易的為任何新出現的 FORTH 系統添加此一性能,這是作者為傳揚 FORTH 的最主要目的。因此,特別挑選了一個原本欠缺此一性能的大眾化系統來驗證它,就以 eForth32 做為設計基礎,為其添加此一性能。如果你手頭上使用中的系統已經有此性能,或者只有一半性能,例如:只能在高階定義指令中混入低階指令編寫程式,而於編寫低階定義指令時,還不能混入高階指令。那麼,你就可以根據本文自行添加此性能,自己磨練系統指令的程式設計能力,並與原已有功能比較,將是毫不遜色,因為不同的設計都將殊途同歸,對於程式執行速度或執行效果毫無影響。
如果你尚未準備好上述背景知識,建議你暫時不用細看本文,留供日後參考便可。通常一般商售的 FORTH 系統都提供了此一性能,它們較常用的指令名稱為 : [C 、 C] 、 C: 、 ;C 之類的名稱。前二者成一對,使用在高階定義中轉入低階再轉回高階。後二者成另一對,使用在低階定義中轉入高階再轉回低階。不用讀通本文,你也可以直接使用這些指令,使用手冊的說明文獻也只能做到這個地步。
留供日後參考的建議係作者個人的贈言,四十幾年前,我們在中山科學研究院內的週五研討會上,討論過此項性能。我記得當時藍瑞賢個人獨衷 Zen-Forth 商售系統,其中只提供了這項功能的半套指令,而當時大家公認使用的推廣標準是無版權問題的 F83-FORTH 系統,已有完整的這項功能。為此問題我們另有 Poly-FORTH 系統,也有完整的這項功能,可以比照參考。陳爽的 FORTH 功力當時最好,他帶頭講解的結果,讓與會者此後便有能力自建此功能於任何系統,我則仔細的做了筆記。三十年前我們移民到了紐西蘭,我隨身攜帶來此的書籍、簿本,只有三樣,一本中英對照的『聖經』,一本精裝大字足本的『四書讀本』,另外就是所有的 FORTH 歷年筆記,這些都是精神糧食,好東西就應該留供日後參考,單純只留在腦袋中,老了是會忘記的。我在 eForth32 中重建此功能時,只花了半天時間,而且一次完成,為什麼?靠的就是筆記。
2 使用時機
我們可以舉出許多例子來強調這項功能非常方便,尤其是對一個想玩進 FORTH 系統內部的人更具有吸引力,因為它涉及了低階程式的可以無所不做能力,以及執行速度可以發揮到系統極限的先天優點,另外配上高階程式的現成與複雜功能,二者組合起來,在許多場合就相當方便。因此,若輕易就能擁有的功能,為何不用?它不是標準指令又有甚麼關係? 舉例來說:如果我有一個程式想測系統性能,必須斤斤計較執行速度到系統的基本時脈週期程度。我曾寫過這種程式,就以讀取電腦中的標準時基計數器內容當標準,要讀得又快又穩又準,當然得用低階組合語言來寫程式,想像中幾乎是一瞬間就得到了參考時基,而且只用幾個低階指令,自己耗了幾個時脈數很容易清算,易於隨後扣除。接下來要處理計算與顯示時,若還只能用低階程式,那就非常痛苦了,這項高低階可以混用的功能就很有用處,讓問題極容易解決。
另外,我們在設計中斷處理程式最後,免不了要用低階程式來安放執行位址(Entry point)於中斷執行向量位置,中斷瞬間想以低階最快速度做一件事,隨後想做的事通常就很複雜,不用高階就不方便,做到關鍵處還有可能又要求用低階設計比較有效,如此又高又低的翻來覆去,這項功能更能提供方便。
還有一些平日設計的高階程式,在某些過程中想穿透系統去做一些沒有指令可用的工作,例如:像除錯工具指令一樣可以取得當時 FORTH 系統高階定義指令的程式計數器(Program counter) 內容,高階指令設計中便可混入幾個低階指令來完成。等同於 FORTH 系統高階指令程式計數器的專有名詞,在 FORTH 領域,則稱之為指令指標暫存器(Interpreter Pointer or Instruction Pointer,IP ),系統一般均不提供操作它的指令,古時候的系統則有此 IP 指令可用,它會直接取得系統執行當時的 IP 內容,有幾個結構化跳躍指令,可以藉助於此指令之存在而容易完成設計,後來有新觀念被發展出來才不用它了。
另外,一個接近終了的程式設計,也許會有強調必須改善執行速度的要求,大家都知道,此時非用低階指令取代設計不可了,如果可修正的指令不想搬離原設計位置,那麼,這項功能理所當然的可以提供服務。
還有無數的例子可以舉出,那怕僅只是玩一玩,當基本教材訓練學生,都是有用的,越用 FORTH 設計程式,就越能發現那些場合?可以讓這項功能盡量發揮。我常用,可是很不喜歡用這種程式來當作寫 FORTH 文章的題材,因為要用組合語言,文章只能在限用時間內有效,我擅長用卻不擅長描述這種程式,痛苦之至,最好不寫。很不幸本文的程式設計就不可或免的得用到一些組合語言,我只好將就一點,勉為其難的在該部份進行簡單說明。
3 基本原理
在解說問題時,必須將問題簡化才方便解釋,我們就以這個方式開始。 FORTH 系統中,強調所有的東西都盡可能為統一的格式,因此,無論是高、低階指令,或變數、常數、或字彙,它們的基本結構都是一致的,至少有名稱欄、連結欄,解碼欄、參數欄,某些系統還多了觀察欄或其他欄,我們暫時別管它們的存在與否,只考慮基本上標準的前四欄。
無論你如何寫程式,能被 FORTH 系統接受的最後結果,其格式仍必須符合標準結構的要求,否則不能被正常的執行。因此,我們現在探討的主題,也不能脫離這個範疇。也就是說,高階定義指令中混用低階的指令,或低階指令中混用了高階指令,這個基本結構規矩仍得遵循,不可以在基本結構中另出一基本結構,我們想解說的問題因此被簡化了一半。
四欄的結構有時又被分成兩個部份,一是頭部,也就是名稱欄與連結欄,另一個就是體部,也就是解碼欄與參數欄。分成兩部份,有時有利,有時有害,利害分析這部份,超出本文探討範圍,擱置不予置評,有許多系統都這樣做, eForth32 、Win32Forth 都是, F83 則不是。高階定義指令中使用低階,其中的低階既然不能也是一個原來的標準結構樣子,那麼,必須是怎樣的結構才能被系統接受呢?根據『FORTH執行原理』來考慮,如果我們能夠去除這個下屬於高階指令的低階指令其頭部,系統的執行機制就可以符合正常的 FORTH 系統執行原理。換句話說,如果我們將這樣的程式設計,搞成包括進來的低階指令沒了頭部,只有體部,那麼整個系統的執行機理就能維持而未被破壞。反之,低階指令中使用了高階,其理亦然,只能留住下屬者的體部,而不能有其頭部。根據這樣的原則,我們就能按照FORTH的執行原理,在邊界位置設計程式,來切換系統執行高階或低階指令時的相關程式計數器內容,以達到目的。
所謂的程式計數器,我們暫時可以將情況比擬想像成, Forth 系統中高階定義指令的程式計數器是 IP 。而低階定義指令的程式計數器是 W ,也就是 Forth 系統中所謂的工作暫存器(Current Word Pointer or Working Register)。一般 CPU 所擁有的程式計數器則仍然稱之為 PC ,如果還想再延伸推理到 FORTH 系統中是否還有其他類似意義的程式計數器?那麼我們也可以說負責多工任務(Multi-task)的另一個指標,使用者系統變數指標暫存器 UP(User Pointer),可以算是多工(Tasks)運轉時的程式計數器,接受這一段描述,很可以加強你了解所謂『FORTH虛電腦』這個專有名詞的意義。
如果你很能融會貫通新學的東西,也很有創意,用心想一想,有一天也許能在 FORTH 領域創作出另一個程式計數器,例如:一種中階定義指令的指標暫存器,名叫 MP(Middle Word Pointer ),或者是比 UP 更高的超級程式計數器,用它供作多人使用時、許多系統相連時、甚或全世界網域互通時的指標暫存器之用,它名叫 Super-P ,因為管得太大了,所以名字比較長。讀者千萬不要認為這些推理不切實際,它蘊涵了 FORTH 一貫的哲理。
將指令結構分成兩部份的系統,常強調最終的應用程式被執行時只有體部才被用到,頭部可以說是多餘的,因此分成兩部份放置後,最後可以一次就丟光系統所有的頭部,只留體部,應用程式仍然照舊執行,省了記憶體,還讓有心人無法以逆行追蹤的方式還原源程式的結構。混用碼的程式技術也就是根據這樣的原則,來將其所下屬的高低不平等指令埋進系統的,我們須要的指令就根據此理而設計,這一部份簡化了剩下來另外一半的問題。
4 程式設計
下列是一套設計完成後經過測試的指令組:
沒有留言:
張貼留言