2018年12月21日 星期五

如何在Flash ROM上實現直譯語言4: MCU需求修改

原先的LbForth是在DOS-Box上執行,在RAM上執行且記憶體空間完全獨立。
有數個功能要修改:
1 . 記憶體從矩陣改成指標,這樣才能做MCU內的配置。包括生成字典的地方才可以控制。
2 . 記憶體空間管理,因為寫回的記憶體若是Flash區,要轉去Flash燒寫函式去執行。其他讀寫一樣。
3 . 屬性標記修改,因為NOR Flash清空時是0xFF,一般RAM清空是0,且Flash只能單向設定(1轉0),所以內容要反過來,判定程式也要反過來。

實作時前二項修改很容易。
再來是屬性,它有二個flag在用,各佔一個bit,剩下的bit則是數值,標示名字字串長度,用於尋找字。
一個flag是immediate,它是編譯模式下特權標記,標記設定後的字在編譯模式下是執行,而非媥譯,用來形成控制結構用的。
一個flag是hide,它是將此字標記為廢字,不執行也不會進查找。這個設計很奇怪的和Flash寫入程序很合。因為編譯時沒有做全文章分析,有可能會出現程式中有錯,但寫了一大堆的字進入Flash內,但它不完全,所以不可以執行及查找,故需要這個flag去標記。用在Flash上面可以先留下1(設定),在新字確定完成時再回來清除(設成0)。
又剛好STM32L系列及STM32F系列其Flash動作相反。故要修改成可以設定反相又可以運作的程式。

改完後放入MCU,不會動。因為Flash Erase是有規則的,可以Erase大塊,不能Erase單元,但Write可以寫入一個單元。變成又要加入Flash邊界檢知,在字典長到下一個sector時,發動Erase。
然後,還是不行。發現Flash不能只改一個bit,這個和個人認知有出入。測試一下動作,發現對Flash寫入單元可以做的只有二個動作: 寫入資料,寫入0(全清)。
這下頭大了,屬性欄位要改,若是要可以用,immediate及hide要分出來不能和字串長度放一起。
這下動到字典管理了。要符合,變成用資料的值來做為flag應用。變成Erase後的值是hide,若是沒改,新字就是廢字。若要是有用字就要寫入值(非清除),若是為immediate設定,則再加寫0(只能加寫成全清)。

改完後,還有一些Flash上小問題,再以程式解決。然後總算看到去執行字典生成的高階字編譯。又出問題了。
高階字的空值預設是0,但Nor-Flash不是,所以要去改高階指令。這下又要去理解Forth編譯的細節,硬著頭皮上了。
改完後,真的弄清楚了整個Forth語言系統。
總算在STM32F系列上執行了。不過事情沒有完,移去STM32L系列又掛掉。因為它的Flash除了是0寫成0xFF外,又不能亂寫有ECC在,二次寫入是不行的。看來只能改用在QSPI Flash上看可不可以。

如何在Flash ROM上實現直譯語言3: Forth系統分析

LBForth和一般Forth不同,因為它不用從CPU指令來建造,所以沒有基本指令再堆積成高階功能的問題。
因為由C建造,所以它只要專心應付語言實現問題。這使得系統簡單不少。

所以只要看幾個大的函式,弄清其功能,就可以知道如何動作。
但在解析前,有一個必須解決的問題,它的字典資料結構要先弄清楚。
因為這個是Forth運行最重要的結構。

字典的主要內容:
1.字名(函式名): 輸入的文字代表
2.內容(執行欄): op code或是指標,op code是基本執行功能。高階字以指標表代,遇到指標會跳去對應的記憶體內容再解析,直到執行op code。
3 .結構串接: 以link-list串起來
4. 屬性及標記,後面用到時再分析
實際排列:有固定長度的放在前面,所以link-list為第一個word,第二個是屬性,和名字共用32個byte(佔4個word),接下來是執行欄,長度不定。

字典在程式碼內是看不到的,因為它是在執行才生成,這個動作有利於Flash的寫入,也是可以利用未用的程式Flash的原因。個人覺得這個設計解決MCU上可以動態增加函式的方法。

再來是Forth的執行結構,它和CPU設計有相關,所以很像硬體的方式。
主要有二個堆疊,一個是資料堆,所以資料及參數全部放在此運算。
另外是一個返回堆,主要是呼叫返回堆疊及一些控制結構變數也放在內。
二個堆疊各有一個管理指標暫存器。
另外在執行上,有一個指令指標暫存器(IP)用來標記目前執行位址。

使用二個堆疊原因:
資料處理全部在資料堆疊上,故使用者要去做堆疊內容管理,這個在高階電腦語言是沒有的。因為此動作沒有執行效果,但可以限定RAM的使用只在資料堆疊上。這也是為何Forth使用RAM很少就可以運作。
MCU一向RAM就是不多,其他語言都有RAM需求問題,若是RAM大,MCU就不用寫得辛苦了。

實際上執行,有分成直譯模式及編譯模式。
平時在直譯模式下,輸入一個字串結束(空白字元出現),就去字典查找這個字,有找到,就依執行欄內容再進一步查找或是執行。
若是直譯失敗,再來是進行數字解析,因為這個字串有可能是數字字串,解析成功,就放入資料堆。
若再次直譯失敗,就沒法了,就執行錯誤處理(顯示輸入錯誤)。
有多字輸入下,會一個一個去執行,直到沒有新的輸入。
但有個直譯指令是不一樣的,它會進入編譯模式。
編譯模式下一樣有找字和轉換數字字串的動作,但再下去的動作不同,它不執行而是寫入Flash,生成新的字進入字典內。
在編譯模式下,一樣找字,找到字就將其執行欄位址寫入新字的內容,然後找下一個字。遇到數字時有點不一樣,會先寫入一個lit指令碼再寫入資料值。執行到lit指令碼會將下一欄的內容吐回資料堆疊。這樣就完成固定值的編譯。

了解Forth的運作後,才能做下一步的修改。

2018年12月13日 星期四

如何在Flash ROM上實現直譯語言2: 規劃及找材料

MCU上實現一個語言,在8位元時代就有,8051 Forth是我第一個看到的作品。
全部組合語言寫出來,以機器碼寫回。但有條件,RAM也是Code space,這個要在硬體上動手腳。
有興趣的人可以看一下CamelForth51,因為實用性不好,程式碼看了沒在用。

不過CamelForth的作者有另一個作品MSP430 Forth,它可以寫回Flash,無需佔用RAM做程式儲存。
可惜沒有用到大一點的MSP430,沒有機會用,也沒有機會看原始碼。但粗看和8051一樣用組合語言寫的。

二個Forth看完原始碼,皆打破我對Compile的觀念,原來字彙分析就可以集成語言。但它有一些基本模型在。
像是雙堆疊,有一個資料堆以及一個返迴堆。一般語言像C,只有一個堆疊,資料及返迴一起堆進Stack。
這個相當"硬體"的設計。
另外一個是直譯,沒有main函式。輸入字全部都可以執行。

再來是32位元時代,Forth仍用組合語言寫出來,這個完全沒有引起我的興趣。
因為這個時代,原廠都是給C函式庫,像USB如此複雜的裝置,要用別的語言再寫一次,那有時間?
要用,也用C寫的,但eLua有點大,它可以拆分將VM放入MCU內。用起來還是有點麻煩。

然後找到STM32Forth,看來可以了。且證明可以完全在Flash ROM上作業。不過它也有點問題。
加功能進去不是很容易,因為C的語法限制,不像組合語言一樣好寫,維護肯定不好用。先放著。

再來有一天找到LBForth,一看就是我要的。它有幾個特性:
  1. 它不使用機器碼,改用OP Code為基本單元。這個可以避免執行平台問題。
       2. 指令實現的C Source Code是集成的,不是分散的,這個易維護。但看來是動用到一些巨集技巧。

不過它在X86上執行,且為區域變數空間上。要在STM32上執行仍要改,順便修改時看看它是如何實作一個Forth。



2018年11月29日 星期四

如何在Flash ROM上實現直譯語言:草稿1

Q: 為何compile不能在Flash ROM上?
A: Compile有三個程序,Lex,Parser,Assembly。其中parser會使用大量RAM做堆疊搜尋,會使用大量RAM。這個程序產生出來的資料結構也不合適Flash寫入特性。

Q: 若是跳過Parser,能否成為一套語言?
A: 有可能,但有可能是採用機器類似的語法。可能有些怪。

Q: 若有些怪不是問題,它會有什麼好處?
A: 可以動態改變MCU程式,在不關機下進行程式變更。此特性對多變化的通信環境比較合適。

Q: 若MCU可用程式空間變大下,此功能是否會變得有用?
A: 會。因為程式更新開始變得痛苦,程式不管改大改小,都要進行脫機燒錄升級,若可以不重開下進行變更,在使用者觀感上會有很大的好處。因為IOT大部分不會給予太大的變動,使用動態編程式可以解決很多問題。且沒有程式空間用完的問題下,新加函式就算沒有用,也不會有浪費空間問題。

以上問題全部解決,於是找出可以用的語言來做。可以用的小型語言就是Forth。
先不看Forth是什麼。先看如何解決問題。

1. 不經由Compile程序做編程,又要在Flash上編程式,程式生成就是直述法。除去基本運算函式,程式會由基本運算組合起來的程式集所組成。只要經由查表,就生成,這個特性就符合Flash上的編程。但高階程式(也就是函式)要執行後可以返回,在執行時一定要有一個呼叫堆疊。這是很硬體的特性。

2. 資料操作,程式運行時需求區域變數去處理,函式呼叫也要有參數區。可以設置一個資料堆疊來完成。又多了一個硬體特性。

3. 函式如何運行:字典的結構
  以編譯語言來說,有二個狀態要解決:執行及編譯
  先做執行時期的功能:
  若是有找到字詞,就執行。又要如何結構一個可以查的又可以動態成長的表?
 串列鍵結可以解決此問題。將所有可以查的字用串列方式鍵結成一個"字典"。
 這個字典有三個部分,第一欄是Link-List。第二欄是名字,因為長度不定,第一格變成要給一個長度,因為過此長度,就是第三欄,第三欄是執行內容,這也是不定長度,但不用記長度,因為接下去又回到第一欄,由Link-list就可以知道結尾。

4. 常數
  對於只有純的字解析語言來說,會先查表,看看是否輸入字詞有函式符合,有則執行。但常數不是固定的字。
  所 以等於可以在查字詞失敗時,有可能是常數,可以在此進行常數解析及轉換,都失敗,就等於都不是。

5. 語法結構  
  這裏要決定第一個語法結構,這個語言要用前敘式、中敘式還是用後敘式語法?
  最省RAM的是後敘式,這個最符合MCU的ROM多RAM少結構。但此結構有另一個問題,後面再說明。
  分字,使用空白字,這是唯一的關鍵字。或許有人會覺得不足,實際上還是要加一點特性就有機會像一套語言。
  1. 試寫並模擬
 直譯動作原理。目前因為字典第三欄未定,為省空間,先放一個函式指標進去。找到字,就用指標執行。
需要的程式動作有:
取字,遇到空白,才取出一個待解的詞。
找字,比對輸入詞是否在字典內。
執行,比對成功就依內容指標跳去執行。
數值,有些是定數輸入,會再取用下一欄的資料,轉成數值。但這有跳過一欄問題,顯然要去調整"執行標記"指標。

  1. 編譯
也就是新加入一個字到字典內。
有二個狀態,第一個是新名字取出,寫入Flash。
再來第二個字就是執行字,取出後要找字。
新加入doLit功能,它是取值,同時調整 "執行標記"指標。
執行標記名為IP

8. 函式呼數堆疊
新加入doColon功能, IP暫存及返回堆疊,仿CPU,類似函式呼叫。IP會堆在堆疊上,再載入新一層函式指標。
也有類Return功能退回上一層函式。

  1. 組合編譯及執行
":"指令及";"指令。":" 是進入編譯模式,";"是編譯結束,回到直譯模式。 

10. 進階編譯問題
  immediate旗標及tick指令。
因為編譯下有一些計算問題,所以變成要有一些指令要編譯下仍可以執行。故設置immediate旗標,執行字被標記為immediate就進入直接執行。
"'" tick指令,用來解除immediate字的狀況,直接編譯入字典。

11. 控制結構
沒有if/else就不能算是一套語言,所以要有。但可以利用高階字寫出來。
因為是後敘式函式,變成順序有點相反。形成IF  ELSE THEN結構。

12. 廻圈
利用返回堆做計數,使用者就不會看到廻圈計數器,又可以做到控制次數。

13. 其他函式
  需要多少基本指令? 函式編碼,形成token threading,也就是類VM設計又保有指標數值的方法。
  除錯指令,堆疊內容印出,才能知道執行狀況。
  廢字問題,Flash要如何處理編譯失敗形成的廢字。新增Hide旗標,進入編譯時設定,編譯成功時解除。
在語法出錯時,己寫入Flash的指令就變成廢字不會使用到,也不會進入找字程序。

  1. 全部組合及模擬測試
C的語法限制。變成有些動作要去執行時才進行。
  
  1. 使用RAM/ROM資源大小
在STM32上實現結果:程式大約6KB,但自定義字原始碼約4KB。


執行時生成字典6KB,RAM使用在2KB就可以了。

2018年11月16日 星期五

Emscripten試用及心得

本來是想多一個C的平台可以玩。但也是對IOT的預備。順便想一下有什麼題目可以玩。
架起來後,可以編譯C,但沒有好的目標可以執行。因為Chrome開起來怪怪的,只好先用Node.js執行。
然後就去找一下我心中想要做的應用:RTOS轉成javascript後在Browser上執行。
因為想要將MCU全系統拉去新平台做個模擬。
找著找著,發現人家已做完了....
因為這個題目我才放上line討論,就有人問這題目有用?
然後找到別人已做完,還Open Source。
這個大計劃很多人都不看好,為何已做完?
已做完,就是指下個階段已啟動,後面再分析。

完成品是 mbed OS 5 Simulator。
它有一個off-line版本,就是用emscripten所建造的。
on-line compiler不奇怪,但除錯還是要回MCU,個人試用率也不高。
所以我才會想說用emscripten做為利用C往PC走的路。
因為這樣就可以連上機器學習相關的程式,利用機器學習和MCU同時開發程式系統。
中間產品自然是MCU模擬器。
這樣說,有些人無法理解,換個方法說明。

有些C函式庫已存在很久了,但沒有進MCU內,主因是程式容量。但近來這個限制解除了。
所以open source的套件可以進入MCU內。
於是我就想將openCV這樣的函式庫移入MCU。
但openCV實在太大,一定要分解出來。這也是大工程。
另一個想法是,openCV在手機上,MCU仍做它的,只是MCU是輸出元件。
要放在一起寫又要分開平台,就是問題。
Emscripten有機會解決問題,可在PC上執行,又保有C可移回MCU。

然後看到mbed simulator開放off-line版本。
心想MCU最難的工作已做完,ARM差不多是IOT的領導人了。
因為MCU工程師就是不會AI,要MCU和機器學習放在一起,沒人知道要如何除錯。
IOT這個問題會卡住很久MCU工程師要花很多時間才能慢慢解。
現在工具出現,會用的必然前進的很快,其他MCU工程一定跟不上來。
所以會用simulator的工程師,可以很方便寫模擬的MCU,同時看機器學習是否可以放在伺服器上運用。
模擬過了,才轉回MCU上,看看實際執行的資料跑得是否順。
那其他MCU廠商不就被simulator給擠出IOT市場?這個答案是肯定的。

IOT時代的程式開發,一定是一種分散式系統。分散式系統難以除錯。
拉回PC上做模擬及開發是一定要走的路,問題是使用何種語言及工具。
現在看來都完備了。利用emscripten就可以連接MCU及網路世界。
在大家仍在各自想方法解決時,已有人端出套件來,看來規格必然會傾向出套件的廠商。
所以我才說下一步已經啟動了。

2018年10月5日 星期五

富碼時代

重新移植Forth,但為何要新的語言,以及語言應會如何發展,我有疑惑。
因為已進入資訊時代,我發現程式開發行為也變得不同。
以前人要去了解原理,再轉成程式。但現在不是,都是網路上找原始碼,再加以拼裝。
這樣的行為在年輕及老工程師之間變成很大的行為不同。
為何行為不同?
個人發現,因為資料取得的方式不同,造成行為不同。

這個差異,我分成二個時代,貧碼時代及富碼時代。
貧碼時代,因為原始碼取得不易,大部分程式碼要自己寫,工具也不是很好,除錯方法有限。
所以工程師要對原理很清楚,不然程式跑不對,就無法從其他儀器或是除錯器上來看。
工程師會要求別人很仔細的看別人的程式,或是很追求程式效率。因為以前CPU跑很慢,效率加速是很明顯的。
再來網際網路出現,開始進入富碼時代。年輕一輩因為可以找到原始碼,且工具進化,有程式產生器。
程式設計變成富碼的設計方式。程式可以很容易下載到函式庫,很容易安裝,有各式各樣的函式庫取用。
利用別人的函式庫,很容易達成基礎建設,所以心力轉去應用架構上的設計。

那一個新起來的語言,變成別人不會在乎它是不是真的有效率,而是在乎它有沒有龐大的應用函式庫。
富碼時代,語言會傾向使用解譯式,因為效率不重要,反而是大型架構下,能不能重態修改程式。這種想法是受到網路程式javascript的設計style影響。
已不是說使用在MCU或是什麼領域上,而是新生代工程師認為那是理所當然。

個人是MCU工程師,這個領域在變。之前的貧碼時代已經很久了。
最近MCU開始支援Quad SPI Flash XIP模式。程式空間爆增。
於是正式要進入富碼時代,已不會因為程式空間太小,限定了程式的發展。
程式空間一大,各式工具程式就會開始使用。
MCU在富碼時代應如何開發,是新的議題了。

2018年7月7日 星期六

HTML Forth Test

Forth開啟
會花一點時間下載。

2018/07/08補
實驗能否用google driver做為靜態網頁。照書做,弄不起來。
查到2016年底就不支援。
轉成由第三方轉址。
https://drv.tw/
就可以了。所以放在blog中。