From d68feb1fd98117ecb8c065ae60accb35fe058ffd Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sun, 18 Oct 2020 10:28:36 +0200 Subject: [PATCH] Add Sdl rendering, Add keyboard input --- README.md | 2 +- chip8/src/lib.rs | 20 ++++++--- roms/TETRIS | Bin 0 -> 494 bytes roms/chip8-picture.ch8 | Bin 0 -> 164 bytes roms/invaders.c8 | Bin 0 -> 1301 bytes roms/pong.c8 | Bin 0 -> 294 bytes roms/slipperyslope.ch8 | Bin 0 -> 2482 bytes src/main.rs | 90 ++++++++++++++++++++++++++++++++++++++--- 8 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 roms/TETRIS create mode 100644 roms/chip8-picture.ch8 create mode 100755 roms/invaders.c8 create mode 100755 roms/pong.c8 create mode 100644 roms/slipperyslope.ch8 diff --git a/README.md b/README.md index 5c33c5f..d0bce75 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # chip8-rs CHIP-8 emulator written in Rust. -(Done from the Go implementation: https://github.com/arnaucube/go-chip8) +(Done with the Go implementation: https://github.com/arnaucube/go-chip8) https://en.wikipedia.org/wiki/CHIP-8 diff --git a/chip8/src/lib.rs b/chip8/src/lib.rs index 4a5553a..f2293d8 100644 --- a/chip8/src/lib.rs +++ b/chip8/src/lib.rs @@ -16,7 +16,7 @@ pub struct Chip8 { sound_timer: u8, stack: [u16; 16], sp: isize, - key: [u8; 16], + pub key: [u8; 16], pub draw_flag: bool, } @@ -71,12 +71,13 @@ impl Chip8 { } } pub fn emulate_cycle(&mut self) { - self.opcode = (self.memory[self.pc as usize] as u16) << 8 - | self.memory[(self.pc + 1) as usize] as u16; + self.opcode = ((self.memory[self.pc as usize] as u16) << 8) + | (self.memory[(self.pc + 1) as usize] as u16); let x: usize = ((self.opcode & 0x0F00) >> 8) as usize; let y: usize = ((self.opcode & 0x00F0) >> 4) as usize; let nn: u8 = (self.opcode & 0x00FF) as u8; let nnn: u16 = (self.opcode & 0x0FFF) as u16; + // println!("{:?} {:?}", self.opcode, self.pc); // Decode Opcode // https://en.wikipedia.org/wiki/CHIP-8#Opcode_table @@ -275,7 +276,7 @@ impl Chip8 { if self.gfx[pos] == 1 { self.v[0xF] = 1; } else { - self.v[0xF] ^= 1; + self.gfx[pos] ^= 1; } } } @@ -367,7 +368,7 @@ impl Chip8 { } self.pc += 2; } - 0x0064 => { + 0x0065 => { // 0xFX65 Fills V0 to VX (including VX) with values // from memory starting at address I. The offset from I // is increased by 1 for each value written, but I @@ -382,6 +383,15 @@ impl Chip8 { } _ => println!("opc {:x}", self.opcode), } + if self.delay_timer > 0 { + self.delay_timer -= 1; + } + if self.sound_timer > 0 { + if self.sound_timer == 1 { + println!("Beep"); + } + self.sound_timer -= 1; + } } } diff --git a/roms/TETRIS b/roms/TETRIS new file mode 100644 index 0000000000000000000000000000000000000000..9f5e0874dbd03b5e99d32a1d81fe3cb343904cb4 GIT binary patch literal 494 zcmYk2yGsK>5XNWCX+%VlyR+~?lv`40X#skLaSFO}dqV`E0DV;L4@g-?2y(W#Fx1@3Mc&ZNDkgLrFV^Cm-+M2rg zjM!iiTd~UQN-JPj=OW-q-SKIcNeUgIT_rCjxXUNY#8M`~7%h>@zU5Ei75S|TQ{~eY zGs<{VJTwsmk7WRuU;r5gjH4KbX3PZ3XD-eHy%{*pF6KkV))=4 z`JzkR?q2g_p!I^6O7DgGA{(S6IyO{AmyQH@i$ojd4RavFCM58G9nu!nCcxtj#eU@= zw4d4X3(SKF+M#^Vj^%BF6v*8n(9SpgEx(^=+f_piamh`f#L!@1A(Y5IsX0;I_gJ9ar3bKc*%*)hU?J_db zHpya)flW574=cK`vDvNnWm{kNuoto79NUwy4is_bVa)mx!w{k+p1c1hX*=A&s%{wQRRi1nI9zSDv1 zJPLJiw$)+c()-6IejM1JczHl<1M;gJPYIVr@_U<${9*fTlx&tciEOvEkR3Vx2Doc) z3O)2`Rq?%YRUtWY*g(dLwdaA19X80Jse2cRyD{b%E?soEWt@3AL7PtV1uN2{^5bAUzCT&h3Dh;D&&*7BvD{v<+c;@^XuA) zH6HSE=u=q^X*C5})%ghW!|+LNgx~p!T>I8}=qU^;mivcc7~!vTqn!KhH+2OMYKU>} z7WaCs`!3{t3Co(DMbp%@ov?hq#Kw3RavLshi~)QI9XJ3ujyr|`=#Z-D5Jd}sK?w&y zqN{5F0f1Zu=vWYk&Uj5c4zRSe;x}5nN8?3TeX+>%05LyXLL80nN-d8cpE(0?F!?j$ z;AngSBt=?S04Va?lauMaqw#0;@3!nhP8<7Q{AvA*uxJCI#8**rxvYcnpQh&Kp1_lj z=jJ}2-T%9}d9S^_9bT+&KY#9(U$%OC-(FkWf~^-$lE#%uGJz_j>(EFpM&Xr;xN?2m}F*reTjZFfRof zTXCYrXT%-lj7$_oj4%ggWO!B(SbBMx@jOd1^z9a~JBLFMgmS+Om+1SMA3w7KqYs?a zRDua0R5#2%U2W1K5TL{qrcD9~g_vn27^Zq<`?MN015qPv5^98Xb=nNK{^xX9MFEQ0(9n^cvUT~Vjc{JvVlv!A|lx9~5`cIUbP literal 0 HcmV?d00001 diff --git a/roms/pong.c8 b/roms/pong.c8 new file mode 100755 index 0000000000000000000000000000000000000000..6af8d1e35400592ecbc0f2c816ff454fa0c06b96 GIT binary patch literal 294 zcmY%Tlg*Q3pUbo8)vaxJuH`W(T}flkU`j~%Ao_vbfI&#=xOh27=Kn<>t`$O5BrrZ$ zSp6@71xPX_$agc{+LplcU}5dQ1YRHs6zOHUa}A`rt)+cRf_)oPqI|oM8-q}Vo4rtz zyL{$v79}z@hyv+dVDbc*Jd~jDK|<+D zp9#=qcE*fA*ZnhQ%wQ4{tNiczFY~|9iAqLKrcA~JmJbqTjBXBP|AcZDefnqoDfOdf zibyKcmCzE=PnuUk8QwKO00RgdIB4#Gly~%ga zJwM+$_vGG;aRP1`8tpZl|8K+(+*&H?2j- zk0It>Z`|3tp%mKR4ejS{TJw(o%zO^x9k{|OtWv8~YOFTS*m#w;m2nuSQTy(f3m0mv zipmN@gU8r=qpX%;%(m@HrD9iDhNWFMlSXi}2sTO!C~ePd?@hD8%4oV~*GAI|uG=dC z)aw9}B1<5FBG)~hV+qn_C}&+=*8vb*@I23T5yZh4Xq2<*Y}xBcCv`oU?(sZ3o6+@* zYkS#px$O3#^B@Xkit+}t$in(CdI1HU5zPYmmC4T|p-h5DemeP4TFOqN7CdA_erLZ_ z-8!|kKS>xokca+F)%Dd@SI_ipoCzMZ<$O1Kv`)45TZAvd3$h>k+q&)q`vXne@RIeA2?nsB9U!d{nG{qL)WtNC9e zs{WUVihqe~1fJ*eWsbiR+D1OLB4+AV?^5jQnDKK#8i1095<^KUtwHHel;o0rb<9*z zQo5w({k}Tu9Ff`&m`$#fhs*)f$`9BBsLic@0zB76oT@kJ$C$;OAt<$-ZQcjwAoVml zb#!J|rcc(Xw5n&;Y4y||L_ytb@T0!TmiZp&39)k8 zdP$bMhc~oaO&>)W?%~(+-&jRoo2Kv1SOENMZVRN^ZCCOfob&3}&SbkcnR_I;z#+Ir{ zuZtKrJCjOaUbC*@z4z3KU0-bqB-)8N-7($qrh43%?x60aKE=06sB_df#t2hq+9r${ zO`}hg_)J9~D_p}LZe218XS6O;;fB<4MaBR3oQjOXLvZt`C?r&IPvOY9mI#RtB$Y^M za4vySjPY;1p%p)~D?KAUYGW%uq(*{RA_5d}k9;c!>NM1buAvQgaYd5Idxarn6eJ1G zXBY{L=3a(D29gtC#K{-e1kSYpa$F2b5Rcyhv)f4j{O&tjc@$^BGs?Joj3{tuT2!C` zPerPzkp^g35wAA#5-#v8W&=Y3op+Nu8V<211h9ynegy)w@XeA-7{iyCEGyUvJTM)* zO=J~)O&}9m9;Vy|bwm`=LK{(@(Z*HOE>g;J9Pd}0UkF@y6#&~Pzp, + vkeys: HashMap, chip8: Chip8, } @@ -23,26 +30,97 @@ impl SdlEmulator { let video_subsystem = sdl_context.video().unwrap(); let window = video_subsystem - .window("rust-sdl2 demo", 800, 600) + .window("rust-sdl2 demo", (w * zoom) as u32, (h * zoom) as u32) .position_centered() .build() .unwrap(); let mut canvas = window.into_canvas().build().unwrap(); + let mut vkeys: HashMap = HashMap::new(); + vkeys.insert(Keycode::Num1, 0x01); + vkeys.insert(Keycode::Num2, 0x02); + vkeys.insert(Keycode::Num3, 0x03); + vkeys.insert(Keycode::Num4, 0x0c); + vkeys.insert(Keycode::Q, 0x04); + vkeys.insert(Keycode::W, 0x05); + vkeys.insert(Keycode::E, 0x06); + vkeys.insert(Keycode::R, 0x07); + vkeys.insert(Keycode::A, 0x08); + vkeys.insert(Keycode::S, 0x09); + vkeys.insert(Keycode::D, 0x0E); + vkeys.insert(Keycode::F, 0x0A); + vkeys.insert(Keycode::Z, 0x00); + vkeys.insert(Keycode::X, 0x0B); + vkeys.insert(Keycode::V, 0x0F); + SdlEmulator { w, h, zoom, + sdl_context, canvas, + vkeys, chip8: c, } } fn draw_graphics(&mut self) { - // TODO + self.canvas.set_draw_color(Color::RGB(0, 0, 0)); + self.canvas.clear(); + self.canvas.set_draw_color(Color::RGB(255, 255, 255)); + for y in 0..self.h { + for x in 0..self.w { + let pixel = self.chip8.gfx[y * self.w + x]; + if pixel != 0 { + self.canvas.fill_rect(Rect::new( + (x * self.zoom) as i32, + (y * self.zoom) as i32, + (self.zoom) as u32, + (self.zoom) as u32, + )); + } + } + } + + self.canvas.present(); + self.chip8.draw_flag = false; } - fn set_keys(&mut self) { - // TODO + fn set_keys(&mut self) -> Result<(), String> { + let mut events = self.sdl_context.event_pump()?; + for event in events.poll_iter() { + match event { + Event::Quit { .. } => { + println!("Quit"); + std::process::exit(0); + } + Event::KeyDown { + keycode: Some(keycode), + .. + } => { + println!("k {:?}", keycode); + if self.vkeys.contains_key(&keycode) { + let k_hex = self.vkeys.get(&keycode).unwrap(); + self.chip8.key[*k_hex as usize] = 1; + } + } + Event::KeyUp { + keycode: Some(keycode), + .. + } => { + println!("k {:?}", keycode); + if self.vkeys.contains_key(&keycode) { + let k_hex = self.vkeys.get(&keycode).unwrap(); + self.chip8.key[*k_hex as usize] = 0; + } + if keycode == Keycode::Escape { + println!("EXIT"); + std::process::exit(0); + } + } + _ => {} + } + } + Ok(()) } } @@ -66,12 +144,14 @@ fn main() { println!("{:?}", file); let mut e = SdlEmulator::new(64, 32, 8); + e.chip8.load_game(file); + loop { e.chip8.emulate_cycle(); if e.chip8.draw_flag { e.draw_graphics(); } e.set_keys(); - // delay + std::thread::sleep(time::Duration::from_millis(1000 / 60)); } }