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.

406 lines
15 KiB

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