從零開始的 Gameboy 模擬器開發 -- Step 5

Gameboy 的輸入系統

接著要來做有關輸入系統的部分,也就是搖桿,其實不會太困難,甚至這是整系列最簡單的一部分,作法就是我們要想辦法從 sdl2 那邊收到外部的輸入後,再模擬成 z80 收到外部輸入的樣子即可

從 sdl2 接收輸入很簡單,他已經幫我們弄好了 void process_events() 算是定番了,照著打就對了,最後會轉一手傳入到 key_down_event() or key_up_event() 裡面

Read More

從零開始的 Gameboy 模擬器開發 -- Step 4

Gameboy 的 tile 系統與繪圖

接著要來做有關繪圖的部分,這部分說簡單也不簡單,說難也不會難,難的部分是因為我們沒有碰過 tile 系統,所以要花點時間去理解,當理解後,實作部分其實很簡單一點也不難,如果你還沒去看最前面介紹的影片,我建議你趕快去看,因為看完之後會比較好理解

首先我再幫大家整理一下概念

  • 一個 tile 由 8*8 個 pixel 所組成
  • GB 整個顯示的部分是 256 * 256 個 pixel ,換算成 tile 就是 32 * 32 個 tile, 在code 裡面我們會以 scroll_px_x, scroll_px_y 來表示
    • 好像有人稱作虛擬螢幕
  • 但是  GB 能顯示的螢幕(screen)卻只有 160 * 144 個 pixel ,也就是說他只會顯示上述畫面的一部分
    • 他的用意在於,他可以利用這種窗口,去實現類似鏡頭平移的的功能,這邊的 demo 你可以在影片中看到
    • 對於螢幕的 x, y ,在code 裡面會以 screen_px_x 與 screen_px_y 來表示
  • 總結就是,cpu 內設計的螢幕結構是 256256 的,但是你只能看到這 256256  的 160*144 ,
    • 這樣設計的原因就是他可以做出一些視覺的效果
    • 例如網球比賽的鏡頭,馬力歐跳躍時的畫面移動,或是橫向捲軸遊戲的效果

像我對於這東西就困擾很久,想說這什麼鬼東西,為什麼任天堂的螢幕不弄得跟他內部一樣都是  256*256 等等, 反正你不要想得太複雜,以下做個比喻

  • 地上有個由 32 *32 個巧拼所組成的正方形背景拚圖,每個巧拼為 8 * 8 cm,所以整個拼背景圖大小為 256 cm * 256 cm
  • 然後你手上有個 160 cm * 144 cm 的白色方框,這個代表你所能看到的區域
  • 然後你試著把方框在那個拼圖上任意移動,然後觀察方框內的畫面,這個就像是GB 的畫面移動方式
  • 然後你在方框內平放一個 8 * 8 cm 的巧拼,上面畫有一個馬力歐,讓他在方框內任意移動, 當紙娃娃向右移動快移出方框的時候,你也同步的把方框往右移
  • GB 的顯示系統大概就是這個樣子,拼圖代表 256 * 256 pixel 的虛擬螢幕(scroll),巧拼代表 8 * 8 pixel 的 tile,方框代表 144* 160 pixel 的顯示螢幕(screen),而馬力歐代表一個 sprite ,他由1個 or 2 個 tile 組成

Read More

從零開始的 Gameboy 模擬器開發 -- Step 2

建立 opcode map

在開始之前讀取第一道指令之前,我們要做一件很不有趣的事情,就是建立所有 op code 的 map

首先我們建立 opcode_map.c,裡面的內容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void not_support_cb_code() { ASSERT_CODE(0, "not support CB code"); }
void not_support_op_code() { ASSERT_CODE(0, "not support op code"); }

void op_00() { not_support_op_code(); }
.......
void op_FF() { not_support_op_code(); }

void op_cb_00() { not_support_cb_code(); }
.......
void op_cb_FF() { not_support_cb_code(); }

opcode_fun g_opcode_fun_map[0x100] = {
GEN_FUN_MAP(, 0), GEN_FUN_MAP(, 1), GEN_FUN_MAP(, 2), GEN_FUN_MAP(, 3),
GEN_FUN_MAP(, 4), GEN_FUN_MAP(, 5), GEN_FUN_MAP(, 6), GEN_FUN_MAP(, 7),
GEN_FUN_MAP(, 8), GEN_FUN_MAP(, 9), GEN_FUN_MAP(, A), GEN_FUN_MAP(, B),
GEN_FUN_MAP(, C), GEN_FUN_MAP(, D), GEN_FUN_MAP(, E), GEN_FUN_MAP(, F)
};

opcode_fun g_opcode_cb_fun_map[0x100] = {
GEN_FUN_MAP(cb_, 0), GEN_FUN_MAP(cb_, 1), GEN_FUN_MAP(cb_, 2), GEN_FUN_MAP(cb_, 3),
GEN_FUN_MAP(cb_, 4), GEN_FUN_MAP(cb_, 5), GEN_FUN_MAP(cb_, 6), GEN_FUN_MAP(cb_, 7),
GEN_FUN_MAP(cb_, 8), GEN_FUN_MAP(cb_, 9), GEN_FUN_MAP(cb_, A), GEN_FUN_MAP(cb_, B),
GEN_FUN_MAP(cb_, C), GEN_FUN_MAP(cb_, D), GEN_FUN_MAP(cb_, E), GEN_FUN_MAP(cb_, F)
};

其中 GEN_FUN_MAP() macro 是幫你產生 op_00(), op_01 ... op_FF 的格式,因為一個一個打實在太累了,當然你有毅力我也不反對

Read More

從零開始的 Gameboy 模擬器開發 -- Step 1

建立硬體描述

我們首先對 cpu 做描述, 先介紹 LR35902 這顆 cpu 其中的 4 個 word Register(Register,以後均簡稱 Reg) 分別為 AF,BC,DE,HL,這 4 個 word reg,比較特別的是,它們個別又可以拆成 byte reg ,例如 AF 就可以拆成兩個 byte reg A(accumulator)F(Flags) 來使用的,或者是合併讀取,例如 HL 常常當作 ram address 使用

到這邊如果你覺得陌生的話,建議你可以去惡補一下 cpu 暫存器的知識

考量 reg 可以分開讀取,或是合併讀取的特性,所以我們需要建立某種的描述,是可以分開,也可以合併的讀寫,翻翻 C 的手冊,發現使用 union 就可以達到這種目的了,所以我們使用 typedef 建立起對 byte reg 與 wordd reg 的描述

Read More

從零開始的 Gameboy 模擬器開發 -- Step 0

緣由

工作上使用 8051 蠻多年了,以前就有想要寫一個 cpu 模擬器的念頭,某一陣子還收到一間美商寫 arm 模擬器的工作邀約,不過以不熟為理由推掉了,後來看到 Jserv 與 yodalee 的文章,想說我應該也可以做到這件事,就像是 George Mallory 說的,"因為山就在那,所以我登山(Because it's there)",做這件事的起因也沒什麼特別的,差不多也就是因為我覺得我可以,所以我去做看看的感覺


語言的選擇

使用 C 語言,原因很單純就是,我只有找到一個 project 的 code 是比較乾淨的,然後他剛好是 C code 這樣,我之前有找到幾個 gbe 的 project ,但 source code 實在是太亂了,對於一個模擬器的新手要看他們的code 進而理出整個邏輯是很困難的,所以這次先選擇使用 C 開發,可能之後做完後會找機會 porting 到其他語言像是 rust、python 這兩個抽象性較高的語言,或是使用 Java Script,這樣也許會有機會可以在 web 上玩,或是 Haskell 感覺也蠻有趣的

Read More

RPI-4 安裝 android tv

首先你需要下載 android tv for raspberry pi 4 的 image file ,使用的是 LineageOS 17.1 Android TV (Android 10)

在安裝之前有幾點要注意的

  • 只能支援 HDMI
  • 最初解析度為 1920*1080

所以說,如果你的螢幕是 DVI 的話,你可以離開了,因為不會有畫面,先提醒你以免白忙一場

下載後使用 Win32 Disk Imager 燒錄即可,這邊跟之前的 Rpi 做法並沒有不一樣,如果還是不行,那你可以參考以前的教學,燒完後,插上卡片,直接開機就可以進入到 android tv 了

這邊有燒錄相關教學

這邊也有一點很重要的要先講,就是如果你等下遇到任何問題找不到答案的,你應該要回去官網找,那邊通常都已經有答案了

Read More

kodi 教學,心得

Kodi 是一套 media center 軟體,其前身為 xbmc,這邊列出一些相關的資源

遠程控制 -- 使用手機 APP: Yatse

Yastse 是一款 Kodi 的遙控及投放工具,你可以在 google store 找到

不過你必須要先在 kodi 打開遠程控制,打開的地方在

控制->允許通過 HTTP 遠程控制,允許異地程序遠程控制

你也可以打開Web界面,這樣就可以直接使用瀏覽器控制 kodi

遠程控制 -- 使用 firefox

Firefox 有很多 kodi 的套件可供遠端控制,這裡不再詳述

使用 kodi 檔案總管,並從 usb copy 檔案到 kodi

選擇 系統->檔案總管

你就可以啟動 kodi 的檔案總管,左邊的框是操作的地方,按 C 可以叫出選單,按空白可以複選檔案例如你可以按 C 選複製,就會複製到右邊,若右邊的你找不到你要的路徑,就必須要新增瀏覽路徑

Read More

how-to-install-kodi-in-raspberry-pi-4

RPI 4 安裝 kodi 的心得

因為之前的rpi 效能都不太好,所以, 許久沒碰 rpi, 這次出了8GB 號稱可以接近桌機的效能,所以就買一台試看看

PS: 寫在前頭,如果你打算使用 DVI 螢幕當作 RPI 的螢幕的話,你可能要注意,rpi 有機會不能輸出畫面

購買

我這次是去台灣樹梅派購買的,我購買的是 8GB + 散熱殼,那個散熱殼我蠻滿意的,風扇也是靜音風扇,只是風扇安裝需要一點技巧,好像裝錯邊風扇就會很吵,記得風扇正反不要裝錯,有貼貼紙的地方是反面,否則你的風扇不會轉

安裝 kodi,使用 LibreElec

在 rpi 4 上面安裝 kodi 已經很簡單了,LibreElec 這個專案已經把 os + kodi 整合起來,所以我們就直接安裝 libreelec 就可以了,請到以下網站抓取 image file

https://libreelec.tv/raspberry-pi-4/

該網站提供的下載的檔案叫做 "LibreELEC-RPi4.arm-9.2.6.img.gz",下載完後使用 7z,解開她得到 img file 後,就可以使用 Win32 Disk Imager 燒錄即可,這邊跟之前的 Rpi 做法並沒有不一樣

如果還是不行,那你可以參考以前的教學

燒完之後,插入至RPI後,接上電源就可以使用了

Read More

指數型投資(Investment of indexing)

前言

  • 這篇是給目前不能自己挑到好股票, 但又想做投資的人看的
  • 這邊主要的核心概念是"分散", 若是能挑到好股票的人看了這篇, 不但沒幫助, 反而會有害

核心概念 -- 分散投資標的以降低風險

  • 分散股票種類: 購買 ETF 分散投資目標的風險
  • 分散購入時機: 定期定額
  • 分散股票區域性: 購入全球 ETF
  • 分散股票類型: 股票 + 債的資產配置

我先講結論, 然後再慢慢解釋我為何這樣推薦, 而作法就是

"定期定額購買 指數型 ETF "

方法很多種, 從簡單到複雜:

  1. 利用富邦證劵, 定期定額購買富邦采吉50(006208) ETF
  2. 利用複委託, 例如大昌證券複委託 , 定期定額購買 VT + BNDW, 或是 AOA 系列的 ETF
  3. 開網路劵商, 如 Firstrade or TD Ameritrade 帳戶, 定期定額購買 VT + BNDW + VNQ ... etc

Read More