chip8 0.1.1

A simple CHIP-8 emulator compatible with a no_std environment
Documentation
extern crate sdl2;
extern crate rand;
extern crate chip8;

use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Rect;
use sdl2::Sdl;
use sdl2::render::Renderer;

use std::fs;
use std::io::Read;

use std::thread;
use std::time;

use std::collections::HashMap;

use chip8::{Cpu, Memory};

struct SDLFrontend {
    chip8: Cpu,
    memory: Memory,
    sdl_context: Sdl,
    renderer: Renderer<'static>,
    keymap: HashMap<String,usize>
}

impl SDLFrontend {
    pub fn init() -> SDLFrontend {
        let sdl_context = sdl2::init().unwrap();
        let video_subsystem = sdl_context.video().unwrap();

        let window = video_subsystem.window("SDL frontend", 768, 384)
            .position_centered()
            .opengl()
            .build()
            .unwrap();

        let mut keymap = HashMap::new();
        keymap.insert("1".to_string(),0x1usize);
        keymap.insert("2".to_string(),0x2usize);
        keymap.insert("3".to_string(),0x3usize);
        keymap.insert("4".to_string(),0xCusize);
        keymap.insert("Q".to_string(),0x4usize);
        keymap.insert("W".to_string(),0x5usize);
        keymap.insert("E".to_string(),0x6usize);
        keymap.insert("R".to_string(),0xDusize);
        keymap.insert("A".to_string(),0x7usize);
        keymap.insert("S".to_string(),0x8usize);
        keymap.insert("D".to_string(),0x9usize);
        keymap.insert("F".to_string(),0xEusize);
        keymap.insert("Z".to_string(),0xAusize);
        keymap.insert("X".to_string(),0x0usize);
        keymap.insert("C".to_string(),0xBusize);
        keymap.insert("V".to_string(),0xFusize);

        SDLFrontend {
            chip8: Cpu::new(rand::random::<u8>),
            memory: Memory::new(),
            sdl_context: sdl_context,
            renderer: window.renderer().build().unwrap(),
            keymap: keymap
        }
    }
    pub fn load_program(&mut self, path: &str) {
        let mut f = fs::File::open(path).expect("file does not exists");
        let mut program = Vec::new();
        f.read_to_end(&mut program).expect("cannot read file");
        self.memory.load_program(program.as_slice());
    }
    fn update_screen(&mut self) {

        let w = 64usize;
        let h = 32usize;
        let scale = 768usize/w;

        self.renderer.set_draw_color(Color::RGB(255, 255, 255));
        self.renderer.clear();
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        for j in 0..h {
            for i in 0..w {
                if self.memory.video[i+64*j] {
                    self.renderer.fill_rect(Rect::new((i*scale) as i32,(j*scale) as i32,scale as u32,scale as u32)).unwrap();
                }
            }
        }
        self.renderer.present();
    }
    fn update_keys(&mut self) -> bool {
        let mut event_pump = self.sdl_context.event_pump().unwrap();
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    return false;
                },
                Event::KeyDown { keycode: Some(k), .. } => {
                    if let Some(p) = self.keymap.get(&k.name()) {
                        self.memory.keys[*p] = true;
                    } else if k == Keycode::Return {
                        self.chip8.reset();
                        self.memory.reset();
                    }
                },
                Event::KeyUp { keycode: Some(k), .. } => {
                    if let Some(p) = self.keymap.get(&k.name()) {
                        self.memory.keys[*p] = false;
                    }
                },
                _ => {}
            }
        }
        return true;
    }

    pub fn run(&mut self) {
        let mut running = true;
        let inst_per_frame = 20;
        let dur = time::Duration::new(0,1_000_000_000/60);
        let clock = time::SystemTime::now();
        while running {
            let start = clock.elapsed().unwrap();
            self.chip8.run(&mut self.memory, inst_per_frame);
            running = self.update_keys();
            self.update_screen();
            self.chip8.tick();
            let elapsed = clock.elapsed().unwrap() - start;

            if elapsed < dur {
                thread::sleep(dur-elapsed);
            }
        }
    }
}

fn main() {
    let path = std::env::args().nth(1).expect("must provide a ROM file!");

    let mut sdl_frontend = SDLFrontend::init();

    sdl_frontend.load_program(&path);
    sdl_frontend.run();

}