# 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
```
# 參考與貢獻
## 貢獻者名單
> 什麼?這裡居然有貢獻者名單?欸?怎麼什麼人都沒有?想要你的名字在上面嗎?趕緊貢獻吧!成為貢獻者的一員!
---
