# uxn 虛擬機 ~共筆~ > 我發現uxn幾乎都沒有什麼中文的資源,於是我打算自己整一個⋯⋯也因我才剛接觸 uxn,目前內容多半以筆記為主,如內容有需改善請不令指教。 > [name=@ljcucc] > 此文件使用 **繁體中文(台灣 🇹🇼 )** ## 目錄 [TOC] ## 什麼是 uxn? * uxn 是一個生態(Ecosystem),而 Varvara 則是他的架構。 > 對了你有發現,uxn是個上下顛倒都一樣的迴文嗎? :3c > TODO ## 我為什麼要學習 uxn uxn相對linux x86_64的assembly來說,uxn更有系統性,而且設計簡約卻不簡單,讓學習assembly的邏輯更容易上手。 從此學習assembly和演算法將是個不錯的學習方法和途徑,就如 xxiivv.co 所說: > Go Slow, and fix things > -- https://100r.co/site/uxn_design.html ## 下載 與 安裝 你可以從100r.co的官網下載到 Windows、Linux、macOS (x86_64)的執行檔和ROM的壓縮檔: * 100r.co官網 https://100r.co/site/uxn.html 如果你是使用ARM64 的 linux 或其他 unix 平台(例如 plan9),官網也有提供原始碼供編譯: * uxn源碼:https://git.sr.ht/~rabbits/uxn # 相關應用 和 參考資源 這份文件有很多資源都是參考自一下資源,希望這些資源也可以幫助你研究和學習: * 官網: * uxn XXIIVV 官網:https://wiki.xxiivv.com/site/uxn.html * uxntal - uxn的程式語言(與基本介紹) (XXIIVV):https://wiki.xxiivv.com/site/uxntal.html * Runtime 和 下載: * 100r.co官網 https://100r.co/site/uxn.html * 網頁瀏覽器 Rumtime(by metasync):https://metasyn.github.io/learn-uxn/ * 參考: * uxntal 參考文件 (XXIIVV):https://wiki.xxiivv.com/site/uxntal_reference.html * uxntal 作弊表 (XXIIVV):https://wiki.xxiivv.com/site/uxntal_cheatsheet.html * varvara 參考文件 (XXIIVV):https://wiki.xxiivv.com/site/varvara.html * 論壇: * uxn 官方論壇:https://llllllll.co/t/uxn-virtual-computer/46103 * 教學: * uxn官方支持教學:https://compudanzas.net/uxn_tutorial.html > TODO # 背景知識 在開始前,雖然uxn設計簡約,但可不簡單。我們可能需要了解過後對於uxn的程式撰寫才能比較容易起步。 ## Stacks & RPN > TODO ## 基礎架構 - Varvara > Varvara 是南瓜發出的聲音 基本上,要理解 Varvara 可能需要知道一些基礎的計算機結構理論,在這裡可能會稍微介紹,但也只會簡單帶過。 Varvara 擁有處理不同長度指令的機制,因為 * Uxn CPU * [因為是VM,內部結構可能因實作設計有所不同] * **PC: Program counter 程式計數器**: Program Counter 會從 `0x0100` 開始計數 * Memory ## 記憶體 - memory 在 Varvara 基礎架構中,memory共分為 4 大區塊,**每個區塊都是一個獨立記憶體空間**。 | 名稱 | 空間 | Pages(單位空間) | | -------- | -------- | ------| | 主記憶體空間 | 64kB | 256 pages | 主工作堆棧 | 256 bytes| 1 page | | 返回堆棧 | 256 bytes| 1 page | | IO 裝置介面 | 256 bytes | 1 page (分為16個分區) | 所以 總共記憶體空間大約會有 13,312 kB (0x0000~0x13000)。 但實際的記憶體佈局還是要依照VM的實際實作方式為主,例如 uxn.py 和 uxn (ANSI C SDL2)的版本就是把Stacks 和 主記憶體分開宣告,而 uxn.js 則是把Stacks、IO Devices和主記憶體宣告在一起,所以Address space可以從0x0000~0x13000,當然的,Stacks的訪問還是會符合規範。 對於撰寫方便和閱讀性,等等有時會個別稱呼這些名詞為: * 主記憶體: Main memory / RAM: * 除了`0x0000~0x00ff` 以外都可以隨意調用 * Program Counter會從`0x0100`開始執行程式,並且向RAM fetch指令。 * 而ROM裡的所有資料將會從`0x0100`為起點,載入所有的內容至RAM中。 * 主工作堆棧: WST (**W**orking **ST**ack) * Working stack(主工作堆棧區)Working stack不如Main memory一樣可以隨意存取,所有記憶體都將以堆棧的原理運作(PUSH、POP、SWAP⋯⋯)。 * 返回堆棧: RST (**R**eturn **ST**ack) * TODO * IO 裝置介面: IO deivce(s) * IO Devices memory 是uxn訪問和操作對外的唯一通道,你可以用他來操作:uxn系統(因為uxn本身並沒有任何暫存器或flag可使用,但是在uxn cpu可能會有,但不開放) * IO Devices memory每個address都會mapping(映射)到不同的裝置和功能,使用DEO、DEI可以特別對address輸出和輸入。 > 你可以在後續或在Varvara的參考圖表中看到相對映的名詞 > TODO ## Display > TODO ## Controller & Keyboard > TODO ## Display icon or sprite > TODO # 進階知識 如果你需要更深入的了解,一下是有關相關部件的詳細內容介紹 ## 主記憶體 - Main memory / RAM 主記憶體分佈於:`0x0000` ~ `0xffff`。 one page = 256 bytes,主記憶體的可被分配的address space可從`0x00~0xff`。 但`0x0000~0x00ff`,為 zero page。在這段記憶體死不可被任意調用。 而其餘記憶體位址可以被任意調用,且可以調用為Working stack和Return stack( 只要利用 IO Device中 System.WST或System.RST 即可 ),詳細可閱「IO Devices - System device」 ## 主工作堆棧: WST (**W**orking **ST**ack) > TODO ## 返回堆棧: RST (**R**eturn **ST**ack) > TODO ## IO 裝置介面: IO deivce(s) > TODO ## Instructions & Execution, Runtime Program counter 會從 `0x0100` 開始算起 > TODO # Programming > Go Slow, and fix things > -- https://100r.co/site/uxn_design.html > 什麼時候這個筆記才可以變成教學? 有關系統性學習的筆記,可以參考這個筆記:[Programming with Uxntal from Zero2Hero](https://hackmd.io/@ljcucc/uxntal-zero2hero) # Uxntal syntax reference ## Comment 和 忽略字 在 uxnasm 組譯器中,有些字是為了方便撰寫而產生的。其源碼對最終的ROM並沒有任何影響,最終也不會被寫入ROM中。 ### ( Comment ) Comment 顧名思義。前後必須有空格,否則會得到錯誤: Malformed comment 語法: ``` ( 前後建議有空格 ) ``` 觸發條件: * comment head: `(` * 內容(忽略,無論是何種編碼 * comment tail: `)` examples: ``` ( valid comment ) ( (((valid comment))) ) ( valid comment))) ) ``` ### `[` & `]` 在許多範例中或許會看到類似的寫法: ``` ( devices ) |10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] ``` 對於字元 `[` 和 `]` 來說(前後要有空格, 連在一起將被視為同一個token),元素會被當成換行被忽略。 > 參考源碼:https://git.sr.ht/~rabbits/uxn/tree/main/item/src/uxnasm.c#L354 ## Runes(符) & Labels(標籤) & Macros(巨集) 剛剛用到了不少runes的技巧來實作我們的第一個hello world,runes是什麼?他有點像是語法糖,是uxnasm的好工具,幫助我們讓我們的程式更加的可讀,同時也可以偷偷幫我們優化最終的machine code。 > 在官方教學中介紹了幾種的rune和labels: ### Pad 所有「pad」就是讓 uxnasm 知道,指令位址是從哪裡開始算、指令在執行過程(Runtime)會被放置於記憶體的那個位置。當搭配label使用時,則會告訴 uxnasm label被調用時該指向何處的記憶體位址。 pad 共可分為兩種: * 相對位址 ( Relative pad rune ) * 絕對位址( Absolute pad rune ) ### 絕對位址( Absolute pad rune ) 在 [zero2hero](https://hackmd.io/@ljcucc/uxntal-zero2hero) 的共筆中也有提到 Absolute pad rune。但是在這裡還是詳細的解釋 Absolute pad rune 到底做了什麼事情⋯⋯ 白話文來說就是:「從此開始後,的所有內容將會被放在 [數字] ,從此往後放」。且 Absolute pad 是 Uxntal 語法的一部分,並不會寫入最終的ROM裡。 對於 Absolute pad rune,以官方文件的說法,有兩種形式: * 4 位數:在RAM中的address(位址) * 2 位數:在zero page或IO devices的address(位址) 至於這兩者的功用有什麼不同,要基於使用情況而定。 #### 4 位數的 padding 在前面我們有提到:「程式將會從 `0x0100` 開始執行」 > TODO #### 2 位數的 padding ### 相對位址 ( Relative pad rune ) > TODO ### Literals rune ### Macro macro的宣告如下: ``` %MACRONAME { instructions... } ``` 觸法條件: 當一下條件被觸發,才會變成 * start (head char):`%` * MACRO_NAME in char[64] *(ANSI C - SDL2 version of uxn)* included head char `'%'` and string terminator `'\0'`. * `{` will be ignored * `[sequence of instructions...]` * end (tail char): `'}'` 行為: > 將會取代 op-code 為 MACRO_NAME 的 token 為`[sequence of instructions...]` example: ``` ( naming ) %STOP { #010f DEO } ( valid ) %stop { #010f DEO } ( valid ) %hey!you!stop!! { #010f DEO } ( valid ) %uwu~stop~ { #010f DEO } ( valid ) %👍 #010f DEO } ( valid ) ( not valid, name is long then 62 will trigger token not found error ) %abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijab { #010f DEO } stop { #010f DEO } ( not valid, macro head char not found ) %stop #010f DEO ( not valid, tial char not found ) ``` 原理: 1. 當 `uxnasm` 偵測到 `%` 符號時,會向後尋找可用關鍵字。 2. 如果關鍵字不可用將會報錯。 3. 如果關鍵字可用,將會尋找到 `}` 時結束 macro。 所以 uxnasm 其實會在 macro 收錄時忽略 `{` > (詳見 https://git.sr.ht/~rabbits/uxn/tree/main/item/src/uxnasm.c#L145 ) 因此你也可以這樣寫: ``` %HALT #010f DEO } ``` or ``` %HALT { { { { #010f DEO } ``` 並不會影響最終結果( 👆 這樣寫會被人錘死),但也請不要惡作劇在code裡不加 `{` 。 # Uxntal 常見寫法彙整表 以下是常見寫法彙整,如果有需要研究其是如何運作的,可以參考 [# Uxntal syntax reference](#Uxntal-syntax-reference) ## Defining all avaiable device ``` ( devices ) |00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1 ] |10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] |20 @Screen [ &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ] |30 @Audio0 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |40 @Audio1 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |50 @Audio2 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |60 @Audio3 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] |80 @Controller [ &vector $2 &button $1 &key $1 ] |90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ] |a0 @File [ &vector $2 &success $2 &stat $2 &delete $1 &append $1 &name $2 &length $2 &read $2 &write $2 ] |c0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ] ``` ## Common variable & struct define ``` ( variables ) |0000 @a-frame &x $2 &y $2 &x2 $2 &y2 $2 @b-frame &x $2 &y $2 &x2 $2 &y2 $2 @input &a $1 &b $1 @pointer &x $2 &y $2 ``` ## Registing Event listener (vector subroutines) ``` ( main program ) |0100 ( assign device vector ) ;on-something .Device/vector DEO2 BRK ( run this when vector got triggered ) @on-something ( -> ) ( code... ) ``` ## Switch-case & subprogram > ref: https://compudanzas.net/uxn_tutorial_day_3.html ``` @on-controller ( do something... ) ( if '1 then case-1 ) .Controller/key DEI LIT '1 EQU ,&case-1 JCN ( if '1 then case-2 ) .Controller/key DEI LIT '2 EQU ,&case-2 JCN ( if '1 then case-3 ) .Controller/key DEI LIT '3 EQU ,&case-3 JCN ,&case-1 ( do case 1 ) BRK ,&case-2 ( do case 2 ) BRK ,&case-3 ( do case 3 ) BRK BRK ``` # 參考與貢獻 ## 貢獻者名單 > 什麼?這裡居然有貢獻者名單?欸?怎麼什麼人都沒有?想要你的名字在上面嗎?趕緊貢獻吧!成為貢獻者的一員! --- ![](https://i.creativecommons.org/l/by-nc/3.0/tw/88x31.png)