# Uxntal Programming Zero2Hero ~共筆~ 一起來學Uxntal吧! 什麼是Uxntal呢?Uxn是什麼?如果你還不知道,你應該參考這篇共筆: * https://hackmd.io/@ljcucc/uxn 這篇筆記有很大一部分是參考自:https://compudanzas.net/uxn_tutorial.html 如果你有能力閱讀原文,那我很建議你去讀原本,再來看這篇筆記,因為這篇筆記會稍微加油添醋,會跟原本的教學有差異。 ## 🗂 目錄 [TOC] ## 🎒 行前參考資料 * 🌐 官網 : * 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 > 💡 小小的建議:因為內容複雜度比較高,我的作法是會把大部分的參考資料印下來,之後有利於快速的翻閱。 ## 1. Hello world > 參考教學:https://compudanzas.net/uxn_tutorial_day_1.html ### 第一個程式 - Hello A file: `hello.tal` ``` |0100 LIT 41 LIT 18 DEO ``` ### 組譯並執行 執行 `uxnasm` 來組譯我們的uxntal程式,接著使用uxn模擬器 `uxnemu` 來執行我們組譯好的 rom: ```shell $ uxnasm hello.tal -o hello.rom ; uxnemu hello.rom ``` 如果不意外的話,你應該會看到一下畫面: ``` [一個全黑的視窗會彈出] Assembled hello.rom in 5 bytes(0.01% used), 0 labels, 0 macros. Loaded hello.rom A ``` 然後按下 `Ctrl+C` 停止目前執行的程式,因為目前程式不會終止。 ### 解釋 先讓我們仔細看看程式中發生了什麼事情: 1. `|0100`:`0100` 是 Program Counter 的起始數值:`0x0100`。這意味著從這裡往後的所有程式都會被放在RAM(主記憶體)中的`0x0100`位置以後。 這個符號我們稱之為 {[`Absolute pad rune`](https://hackmd.io/@ljcucc/uxn#Absolute-pad-rune)}(之後會提到詳細運作原理)。 2. `LIT`: 當程式讀到 `LIT` 後,將會把下一個讀到的值 `push` 到 Working stack 中。 3. `41`: 當`41` 在ASCII code中代表著16進位的字母 `A`,而因為上一個是指令 `LIT`,所以 `41` 會被 `push` 到 Working stack。 4. `LIT`: 又讀到一次 5. `18`: `18`會被 push 到 Working stack 中。 6. `DEO`: 當遇到DEO指令時,DEO會從Working stack取(Pop)最後兩個數值,當作DEO的參數。 * 第一個參數是:Device ID * 第二個參數是:要傳遞的 Value * 也就是說目前 uxn machine會對裝置 0x18 輸出數值41 * 對於 uxn machine 來說 0x18 是 Console 輸出裝置,或者是Standard Output(device)(相對於C的fputc對STDIN) 一下是當執行完當前指令後,每一個Working Stack的狀態 | 當前指令 | 0x00 | 0x01 | 0x02 | | -------- | -------- | -------- | -------- | | 1 :`\|0100` | | 2 :`LIT` | | 3 :`41` | ***0x41*** | | 4 :`LIT` | ***0x41*** | | 5 :`18` | ***0x41*** | ***0x18*** | | 6 :`DEO` | ### Hello ABC with Literal rune 對於剛剛的hello A,我們可以寫出這個簡寫: ``` |0100 #41 #18 DEO ``` `#41` 是 `LIT 41`的一個簡寫,對於 `#41 #18` 我們也可以簡寫成 `#4118`(至於有什麼不同呢,我們等等會提到) 以此類推,我們可以用這個方式寫出 hello ABC: ``` |0100 #4118 DEO #4218 DEO #4318 DEO ``` output: ``` ABC[END] ``` ### Hello world with raw character rune 對於char,uxntal有一個raw character rune,可以讓我們直接讓uxnasm幫我們轉換成ASCII hex的value(注意喔,是value不是literal): ``` |0100 LIT 'A #18 DEO LIT 'B #18 DEO LIT 'C #18 DEO ``` output: ``` ABC[END] ``` 因此我們就可以寫出hello 「World」: ``` |0100 LIT 'H #18 DEO LIT 'E #18 DEO LIT 'L #18 DEO LIT 'L #18 DEO LIT 'O #18 DEO #2018 DEO (whitespace) LIT 'W #18 DEO LIT 'O #18 DEO LIT 'R #18 DEO LIT 'L #18 DEO LIT 'D #18 DEO ``` output: ``` HELLO WORLD[END] ``` ### 用 label 增加可讀性 接下來讓我們 label 來增加我們程式的可讀性: ``` |10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1] |0100 LIT 'H .Console/write DEO LIT 'E .Console/write DEO LIT 'L .Console/write DEO LIT 'L .Console/write DEO LIT 'O .Console/write DEO ``` 中間發生了什麼事情呢?對於assembler來說一切都是合理的,讓我們來看看吧: * 首先,我們可以看到`|10 @Console`,`@`是用來宣告 `Label` 的符號,他可以讓我們取代一個數字,什麼數字呢?就是當前我們跟程式說:「位於位置10的地方後要寫⋯⋯⋯⋯」 * 然後 `[` 會被忽略( {[詳細資料](https://hackmd.io/@ljcucc/uxn#-amp-)} ) --- Contributed by: ![](https://i.creativecommons.org/l/by-nc/3.0/tw/88x31.png)