You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

378 lines
8.7 KiB

  1. package chip8
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "math/rand"
  6. )
  7. // W represents the width of the screen
  8. const W = 64
  9. // H represents the height of the screen
  10. const H = 32
  11. // Chip8 contains all the data and methods for the Chip8 emulator
  12. type Chip8 struct {
  13. opcode uint16
  14. memory [4096]byte
  15. // register
  16. v [16]byte
  17. index uint16
  18. pc uint16
  19. Gfx [W * H]byte
  20. delayTimer byte
  21. soundTimer byte
  22. stack [16]uint16
  23. sp int
  24. Key [16]byte
  25. DrawFlag bool
  26. }
  27. // Initialize registers and memory
  28. func NewChip8() Chip8 {
  29. c := Chip8{}
  30. c.pc = 0x200
  31. c.opcode = 0
  32. c.index = 0
  33. c.sp = 0
  34. for i := 0; i < len(fontSet); i++ {
  35. c.memory[i] = fontSet[i]
  36. }
  37. return c
  38. }
  39. // EmulateCycle emulates the chip8 cycle
  40. func (c *Chip8) EmulateCycle() {
  41. // Fetch Opcode
  42. c.opcode = uint16(c.memory[c.pc])<<8 | uint16(c.memory[c.pc+1])
  43. x := byte((c.opcode & 0x0F00) >> 8)
  44. y := byte((c.opcode & 0x00F0) >> 4)
  45. nn := byte(c.opcode & 0x00FF)
  46. nnn := uint16(c.opcode & 0x0FFF)
  47. // Decode Opcode
  48. // https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
  49. switch c.opcode & 0xF000 {
  50. case 0x0000:
  51. switch c.opcode & 0x000F {
  52. case 0x0000:
  53. // 00E0 Clear screen
  54. for i := 0; i < len(c.Gfx); i++ {
  55. c.Gfx[i] = 0
  56. }
  57. c.pc += 2
  58. c.DrawFlag = true
  59. case 0x000E:
  60. // 00EE Returns from a subroutine
  61. c.sp--
  62. c.pc = c.stack[c.sp]
  63. c.pc += 2
  64. default:
  65. fmt.Printf("Unknown opcode [0x0000]: 0x%X\n", c.opcode)
  66. }
  67. case 0x1000:
  68. // 1NNN Jumps to address NNN
  69. c.pc = nnn
  70. case 0x2000:
  71. // 2NNN Calls subroutine at NNN
  72. c.stack[c.sp] = c.pc
  73. c.sp++
  74. c.pc = nnn
  75. case 0x3000:
  76. // 3XNN Skips the next instruction if VX equals NN. (Usually
  77. // the next instruction is a jump to skip a code block)
  78. if c.v[x] == nn {
  79. c.pc += 2
  80. }
  81. c.pc += 2
  82. case 0x4000:
  83. // 4XNN Skips the next instruction if VX doesn't equal NN.
  84. // (Usually the next instruction is a jump to skip a code
  85. // block)
  86. if c.v[x] != nn {
  87. c.pc += 2
  88. }
  89. c.pc += 2
  90. case 0x5000:
  91. // 5XY0 Skips the next instruction if VX equals VY. (Usually
  92. // the next instruction is a jump to skip a code block)
  93. if c.v[x] == c.v[y] {
  94. c.pc += 2
  95. }
  96. c.pc += 2
  97. case 0x6000:
  98. // 6XNN Sets VX to NN
  99. c.v[x] = nn
  100. c.pc += 2
  101. case 0x7000:
  102. // 7XNN Adds NN to VX. (Carry flag is not changed)
  103. c.v[x] += nn
  104. c.pc += 2
  105. case 0x8000:
  106. switch c.opcode & 0x000F {
  107. case 0x0000:
  108. // 0x8XY0 Sets VX to the value of VY
  109. c.v[x] = c.v[y]
  110. c.pc += 2
  111. case 0x0001:
  112. // 0x8XY1 Sets VX to VX or VY. (Bitwise OR operation)
  113. c.v[x] = (c.v[x] | c.v[y])
  114. c.pc += 2
  115. case 0x0002:
  116. // 0x8XY2 Sets VX to VX and VY. (Bitwise AND operation)
  117. c.v[x] = (c.v[x] & c.v[y])
  118. c.pc += 2
  119. case 0x0003:
  120. // 0x8XY3 Sets VX to VX xor VY
  121. c.v[x] = (c.v[x] ^ c.v[y])
  122. c.pc += 2
  123. case 0x0004:
  124. // 0x8XY4 Adds VY to VX. VF is set to 1 when there's a
  125. // carry, and to 0 when there isn't
  126. if c.v[y] > (0xFF - c.v[x]) {
  127. c.v[0xF] = 1
  128. } else {
  129. c.v[0xF] = 0
  130. }
  131. c.v[x] += c.v[y]
  132. c.pc += 2
  133. case 0x0005:
  134. // 0x8XY5 VY is subtracted from VX. VF is set to 0 when
  135. // there's a borrow, and 1 when there isn't
  136. if c.v[x] > c.v[y] {
  137. c.v[0xF] = 1
  138. } else {
  139. c.v[0xF] = 0
  140. }
  141. c.v[x] -= c.v[y]
  142. c.pc += 2
  143. case 0x0006:
  144. // 0x8XY6 Stores the least significant bit of VX in VF
  145. // and then shifts VX to the right by 1
  146. if c.opcode&0x1 >= 1 {
  147. c.v[0xF] = 1
  148. } else {
  149. c.v[0xF] = 0
  150. }
  151. c.v[x] = c.v[x] >> 1
  152. c.pc += 2
  153. case 0x0007:
  154. // 0x8XY7 Sets VX to VY minus VX. VF is set to 0 when
  155. // there's a borrow, and 1 when there isn't
  156. if c.v[y] > c.v[x] {
  157. c.v[0xF] = 1
  158. } else {
  159. c.v[0xF] = 0
  160. }
  161. c.v[x] = c.v[y] - c.v[x]
  162. c.pc += 2
  163. case 0x000E:
  164. // 0x8XYE Stores the most significant bit of VX in VF
  165. // and then shifts VX to the left by 1
  166. if c.opcode&0x80 == 0x80 {
  167. c.v[0xF] = 1
  168. } else {
  169. c.v[0xF] = 0
  170. }
  171. c.v[x] = c.v[x] << 1
  172. c.pc += 2
  173. default:
  174. fmt.Printf("Unknown opcode [0x8000]: 0x%X\n", c.opcode)
  175. }
  176. case 0x9000:
  177. // 9XY0 Skips the next instruction if VX doesn't equal VY.
  178. // (Usually the next instruction is a jump to skip a code
  179. // block)
  180. if c.v[x] != c.v[y] {
  181. c.pc += 2
  182. }
  183. c.pc += 2
  184. case 0xA000:
  185. // ANNN set index to NNN position
  186. c.index = nnn
  187. c.pc += 2
  188. case 0xB000:
  189. // BNNN Jumps to the address NNN plus V0
  190. c.pc = nnn + uint16(c.v[0])
  191. case 0xC000:
  192. // CXNN Sets VX to the result of a bitwise and operation on a
  193. // random number (Typically: 0 to 255) and NN
  194. r := byte(rand.Intn(255))
  195. c.v[x] = r & nn
  196. c.pc += 2
  197. case 0xD000:
  198. // DXYN Draws a sprite at coordinate (VX, VY) that has a width
  199. // of 8 pixels and a height of N+1 pixels. Each row of 8 pixels
  200. // is read as bit-coded starting from memory location I; I
  201. // value doesn’t change after the execution of this
  202. // instruction. As described above, VF is set to 1 if any
  203. // screen pixels are flipped from set to unset when the sprite
  204. // is drawn, and to 0 if that doesn’t happen
  205. height := c.opcode & 0x000F
  206. var pixel byte
  207. c.v[0xF] = 0
  208. for yline := uint16(0); yline < height; yline++ {
  209. pixel = c.memory[c.index+yline]
  210. for xline := uint16(0); xline < 8; xline++ {
  211. if (pixel & (0x80 >> xline)) != 0 {
  212. pos := (uint16(c.v[x]) + xline) + ((uint16(c.v[y]) + yline) * W)
  213. if pos >= 2048 {
  214. break
  215. }
  216. if c.Gfx[pos] == 1 {
  217. c.v[0xF] = 1
  218. }
  219. c.Gfx[pos] ^= 1
  220. }
  221. }
  222. }
  223. c.DrawFlag = true
  224. c.pc += 2
  225. case 0xE000:
  226. switch c.opcode & 0x00FF {
  227. case 0x009E:
  228. // EX9E Skips the next instruction if the key stored in
  229. // VX is pressed. (Usually the next instruction is a
  230. // jump to skip a code block)
  231. if c.Key[c.v[x]] != 0 {
  232. c.pc += 2
  233. }
  234. c.pc += 2
  235. case 0x00A1:
  236. // EXA1 Skips the next instruction if the key stored in
  237. // VX isn't pressed. (Usually the next instruction is a
  238. // jump to skip a code block)
  239. if c.Key[c.v[x]] != 1 {
  240. c.pc += 2
  241. }
  242. c.pc += 2
  243. default:
  244. fmt.Printf("Unknown opcode [0xE000]: 0x%X\n", c.opcode)
  245. }
  246. case 0xF000:
  247. switch c.opcode & 0x00FF {
  248. case 0x0007:
  249. // FX07 Sets VX to the value of the delay timer
  250. c.v[x] = c.delayTimer
  251. c.pc += 2
  252. case 0x000A:
  253. // FX0A A key press is awaited, and then stored in VX.
  254. // (Blocking Operation. All instruction halted until
  255. // next key event)
  256. pressed := false
  257. for i := 0; i < 16; i++ {
  258. if c.Key[i] == 1 {
  259. c.v[x] = byte(i)
  260. pressed = true
  261. }
  262. }
  263. if !pressed {
  264. return
  265. }
  266. c.pc += 2
  267. case 0x0015:
  268. // FX15 Sets the delay timer to VX
  269. c.delayTimer = c.v[x]
  270. c.pc += 2
  271. case 0x0018:
  272. // FX18 Sets the sound timer to VX
  273. c.soundTimer = c.v[x]
  274. c.pc += 2
  275. case 0x001E:
  276. // FX1E Adds VX to I. VF is not affected
  277. c.index += uint16(c.v[x])
  278. c.pc += 2
  279. case 0x0029:
  280. // FX29 Sets I to the location of the sprite for the
  281. // character in VX. Characters 0-F (in hexadecimal) are
  282. // represented by a 4x5 font
  283. c.index = uint16(c.v[x]) * 5
  284. c.pc += 2
  285. case 0x0033:
  286. c.memory[c.index] = c.v[x] / 100
  287. c.memory[c.index+1] = (c.v[x] / 10) % 10
  288. c.memory[c.index+2] = (c.v[x] / 100) % 10
  289. c.pc += 2
  290. case 0x0055:
  291. // FX55 Stores V0 to VX (including VX) in memory
  292. // starting at address I. The offset from I is
  293. // increased by 1 for each value written, but I itself
  294. // is left unmodified
  295. for i := uint16(0); i <= uint16(x); i++ {
  296. c.memory[c.index+i] = c.v[i]
  297. }
  298. c.pc += 2
  299. case 0x0065:
  300. // 0xFX65 Fills V0 to VX (including VX) with values
  301. // from memory starting at address I. The offset from I
  302. // is increased by 1 for each value written, but I
  303. // itself is left unmodified
  304. for i := uint16(0); i <= uint16(x); i++ {
  305. c.v[i] = c.memory[c.index+i]
  306. }
  307. c.pc += 2
  308. default:
  309. fmt.Printf("Unknown opcode [0xF000]: 0x%X\n", c.opcode)
  310. }
  311. default:
  312. fmt.Printf("Unknown opcode: 0x%X\n", c.opcode)
  313. }
  314. // Update timers
  315. if c.delayTimer > 0 {
  316. c.delayTimer--
  317. }
  318. if c.soundTimer > 0 {
  319. if c.soundTimer == 1 {
  320. fmt.Printf("Beep!\n")
  321. }
  322. c.soundTimer--
  323. }
  324. }
  325. // LoadGame loads the rom file of the given file path into the Chip8 memory
  326. func (c *Chip8) LoadGame(filepath string) error {
  327. buffer, err := ioutil.ReadFile(filepath)
  328. if err != nil {
  329. return err
  330. }
  331. for i := 0; i < len(buffer); i++ {
  332. // 0x200 == 512
  333. c.memory[512+i] = buffer[i]
  334. }
  335. return nil
  336. }
  337. var fontSet = [80]byte{
  338. 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
  339. 0x20, 0x60, 0x20, 0x20, 0x70, // 1
  340. 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
  341. 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
  342. 0x90, 0x90, 0xF0, 0x10, 0x10, // 4
  343. 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
  344. 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
  345. 0xF0, 0x10, 0x20, 0x40, 0x40, // 7
  346. 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
  347. 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
  348. 0xF0, 0x90, 0xF0, 0x90, 0x90, // A
  349. 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
  350. 0xF0, 0x80, 0x80, 0x80, 0xF0, // C
  351. 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
  352. 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
  353. 0xF0, 0x80, 0xF0, 0x80, 0x80, // F
  354. }