未分類

CHIP8模擬器開發-指令集

CHIP-8每個指令占2 Bytes並以big-endian的方式存放在記憶體當中,另外有10個額外的指令可加入,但本次筆記並沒有實作。

底下指令集的部分我也不知道為什麼心血來潮想把它翻成中文,建議還是去看原文版可能比較好懂啦(?

NNN: 記憶體位址
NN、N: 8bits或4bits的常數
X and Y: register的名稱(0 ~ F)
I: Index register

指令集

1. 0NNN - SYS addr

已不使用,Jump到某個Machine code程序中

2. 00E0 - CLS

清除畫面
實作方法: 請依據繪圖引擎不同自行設計

3. 00EE - RET

Return from a subroutine
實作方法: 將Stack最上層的address放到ProgramCounter裡,並將StackPointer減少一層

4. 1NNN - JP addr

跳到NNN這個address執行
實作方法: ProgramCounter <= NNN

5. 2NNN - CALL addr

呼叫NNN位址中的子程序
實作方法: 將StackPointer增加1,並把目前的ProgramCounter放到Stack中,最後把ProgramCounter更改為NNN

6. 3XNN - SE Vx, byte

if Vx = kk, 跳過下一個指令
實作方法: 比較Vx占存器所儲存的值是否與常數NN相同,如果結果為真,就跳過一次Opcode

7. 4XNN - SNE Vx, byte

if Vx != kk, 跳過下一個指令
實作方法: 比較Vx占存器所儲存的值是否與常數NN相異,如果結果為真,就跳過一次Opcode

8. 5XY0 - SE Vx, Vy

if Vx = Vy, 跳過下一個指令
實作方法: 比較Vx占存器所儲存的值是否與Vy占存器所儲存的值相同,如果結果為真,就跳過一次Opcode

9. 6XNN - LD Vx, byte

將Vx的值設為NN
實作方法: Vx <= NN

10. 7XNN - ADD Vx, byte

Vx的值加上NN之後,再放到Vx中
實作方法: Vx = Vx + NN

11. 8XY0 - LD Vx, Vy

Vy的值放到Vx
實作方法: Vx = Vy

12. 8XY1 - OR Vx, Vy

Vx與Vy的每個bit做OR位元運算
實作方法: Vx = Vx | Vy

13. 8XY2 - AND Vx, Vy

Vx與Vy的每個bit做AND位元運算
實作方法: Vx = Vx & Vy

14. 8XY3 - XOR Vx, Vy

Vx與Vy的每個bit做XOR位元運算
實作方法: Vx = Vx ^ Vy

15. 8XY4 - ADD Vx, Vy

將Vx的值設為Vx+Vy,若相加數值超過255則將VF(CarryFlag)設為1
實作方法: Vx = Vx + Vy, 若相加結果無法完整放於8bits中,則將VF設為1,並把低位元的8bits放到Vx中

16. 8XY5 - SUB Vx, Vy

將Vx的值設為Vx-Vy,若Vx>Vy則將VF設為1,否則為0
實作方法: Vx = Vx - Vy, 若Vx>Vy則將VF的值設為1,否則為0,並將相減結果存放至Vx中

17. 8XY6 - SHR Vx {, Vy}

將Vx最大位元的數值放到VF中,並將Vx除以2
實作方法: 將Vx最大位元放置VF中後,把Vx向右位移1bit

18. 8XY7 - SUBN Vx, Vy

將Vx的值設為Vy-Vx,若Vy>Vx則將VF設為1,否則為0
實作方法: Vx = Vy - Vx, 若Vy>Vx則將VF的值設為1,否則為0,並將相減結果存放至Vx中

19. 8XYE - SHL Vx {, Vy}

將Vx最大位元的數值放到VF中,並將Vx乘以2
實作方法: 將Vx最大位元放置VF中後,把Vx向右位移1bit

20. 9xy0 - SNE Vx, Vy

if Vx != Vy 跳過下一個指令
實作方法: 若Vx != Vy,則跳過一次Opcode

21. ANNN - LD I, addr

將I的值設為NNN
實作方法: 恩…如上所述

22. BNNN - JP V0, addr

程式跳至NNN+V0的位置執行
實作方法: 將ProgramCounter的值設為NNN再加上暫存器V0的值

23. CXNN - RND Vx, byte

隨機產生一個8bits的數字與常數NN做AND運算,並值放置Vx中
實作方法: 呼叫C語言中的亂數產生器產生0~255的數字,並透過8XY2的概念來執行AND運算,運算結果放到Vx的值中

24. DXYN - DRW Vx, Vy, nibble

在(Vx, Vy)的座標上繪製一個從I所儲存的位址開始n bytes的sprite,若畫面有任何已存在的pixel被修改,則將VF設為1(CollisionFlag)
實作方法: 從I所儲存的位址開始以byte為單位繪製畫面,每個pixel繪製之前都須與現有畫面上的pixel做XOR運算(參閱8XY3 opcode),若結果為真,則將VF值改為1否則為0。詳細繪製方法請參閱繪圖引擎的相關文件。

25. Ex9E - SKP Vx

若存放在Vx的KeyCode等於目前所按下的按鍵,則跳過下個Opcode
實作方法: 檢查目前按下的KeyCode是否等於Vx的值,若兩值相等則將ProgramCounter加2

26. EXA1 - SKNP Vx

若存放在Vx的KeyCode目前沒有被按下,則跳過下個Opcode
實作方法: 檢查Vx目前的KeyCode是否處於非按下的情況,若為非按下的情況則將ProgramCounter加2

27. FX07 - LD Vx, DT

Vx的值設為目前的Delay Time

28. Fx0A - LD Vx, K

等待按鍵輸入,當任一按鍵觸發時將其KeyCode存放至Vx中
實作方法: 這是一個blocking的Opcode,會等待任一按鍵觸發之後將其值存放至Vx當中

29. FX15 - LD DT, Vx

將目前Delay Timer的值設為Vx所存放的值

30. FX18 - LD ST, Vx

將目前Sound Timer的值設為Vx所存放的值

31. FX1E - ADD I, Vx

將I與Vx的值相加之後存放至I當中

32. FX29 - LD F, Vx

將Vx的值對應到正確字型記憶體位置後存放到I
實作方法: 第一次看到這個有點不解,舉個範例來解釋比較清楚,由於我們存放預設字型的位置是0x0000~0x0050,每個字各占5 bytes大小,假設Vx暫存器的值是3,那麼它所對應的字型3記憶體位置應為0x000F開始,所以將0x000F放至I當中。簡單來說因為每個字占5bytes而且又是從0開始,所以將Vx當中的值乘上5後即可存放至I。

33. FX33 - LD B, Vx

將Vx中的值轉換成BCD表示法,並將結果分別存放至記憶體位址I(百位數字),I+1(十位數字),I+2(個位數)
實作方法: BCD轉換不多談,來說明一下I存放的方法,由於I存放的是記憶體位址,所以必須藉由memory[I]這樣的存取方式存放值到記憶體當中。

34. FX55 - LD [I], Vx

俗稱的register dump,把特定範圍register所存放的值複製一份到從I開始的連續記憶體當中
實作方法: V0~Vx依序將值複製到I, I+1, I+2….V+x當中

35. FX65 - LD Vx, [I]

從I開始的memory當中依序取出值存放到register當中
實作方法: I, I+1, I+2….V+x依序將值複製到V0~Vx當中

CHIP8模擬器開發系列文章

  1. CHIP8模擬器開發-模擬器與CHIP8簡介
  2. CHIP8模擬器開發-指令集
  3. CHIP8模擬器開發-來寫程式吧
分享到