diff options
author | Determinant <[email protected]> | 2017-11-17 15:00:24 -0500 |
---|---|---|
committer | Determinant <[email protected]> | 2017-11-17 15:00:24 -0500 |
commit | 2f4262c1273108abfcce00e897c520f5a7f4be41 (patch) | |
tree | 0915021d63092913de7cc88fe39088f936a4126d | |
parent | e2ccf6053d58a2a478814f4a26018989f6fa0f26 (diff) |
rearrange the proj
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.lock | 119 | ||||
-rw-r--r-- | Cargo.toml | 11 | ||||
-rw-r--r-- | README.rst | 5 | ||||
-rw-r--r-- | src/bin.rs (renamed from src/main.rs) | 97 | ||||
-rw-r--r-- | src/cartridge.rs | 32 | ||||
-rw-r--r-- | src/controller.rs | 34 | ||||
-rw-r--r-- | src/disasm.rs | 97 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/mapper.rs | 10 | ||||
-rw-r--r-- | src/memory.rs | 11 | ||||
-rw-r--r-- | src/mos6502.rs | 100 |
12 files changed, 314 insertions, 205 deletions
@@ -1,4 +1,3 @@ /target/ **/*.rs.bk -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..30e2288 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,119 @@ +[root] +name = "runes" +version = "0.1.0" +dependencies = [ + "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-zircon" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sdl2" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sdl2-sys" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" +"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" +"checksum lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "236eb37a62591d4a41a89b7763d7de3e06ca02d5ab2815446a8bae5d2f8c2d57" +"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" +"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" +"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" +"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" +"checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" +"checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" @@ -2,7 +2,16 @@ name = "runes" version = "0.1.0" authors = ["Determinant <[email protected]>"] +description = "A no-std NES emulator library written purely in Rust." -[dependencies.sdl2] +[dev-dependencies.sdl2] version = "0.31" features = ["unsafe_textures"] + +[lib] +name = "runes" +path = "src/lib.rs" + +[[example]] +name = "runes" +path = "src/bin.rs" @@ -1,7 +1,7 @@ RuNES ===== -As we know, there have been a ton of NES emulators implementation in various +As we know, there have been a ton of NES emulator implementations in various kinds of languages (mostly C). All of these emulators come with different accuracy and portability. RuNES is an attempt to build a reasonably accurate (instruction level accurate), light-weight and efficient emulation @@ -38,4 +38,5 @@ Build :: - cargo build --release + cargo build --release # build the library only (no std dep) + cargo build --examples --release # or build the example emulator (requires std) @@ -11,7 +11,7 @@ use std::io::Read; use core::cell::RefCell; use core::intrinsics::transmute; use cartridge::*; -use controller::stdctl::{Joystick, Button}; +use controller::stdctl; use std::time::{Instant, Duration}; use std::thread::sleep; @@ -42,6 +42,40 @@ const FB_SIZE: usize = PIX_HEIGHT * FB_PITCH * (PIXEL_SIZE as usize); const WIN_WIDTH: u32 = PIX_WIDTH as u32 * PIXEL_SIZE; const WIN_HEIGHT: u32 = PIX_HEIGHT as u32 * PIXEL_SIZE; +pub struct SimpleCart { + chr_rom: Vec<u8>, + prg_rom: Vec<u8>, + sram: Vec<u8>, + pub mirror_type: MirrorType +} + +impl SimpleCart { + pub fn new(chr_rom: Vec<u8>, + prg_rom: Vec<u8>, + sram: Vec<u8>, + mirror_type: MirrorType) -> Self { + SimpleCart{chr_rom, prg_rom, sram, mirror_type} + } +} + +impl Cartridge for SimpleCart { + fn get_size(&self, kind: BankType) -> usize { + match kind { + BankType::PrgRom => self.prg_rom.len(), + BankType::ChrRom => self.chr_rom.len(), + BankType::Sram => self.sram.len() + } + } + fn get_bank(&mut self, base: usize, size: usize, kind: BankType) -> *mut [u8] { + &mut (match kind { + BankType::PrgRom => &mut self.prg_rom, + BankType::ChrRom => &mut self.chr_rom, + BankType::Sram => &mut self.sram, + })[base..base + size] + } + fn get_mirror_type(&self) -> MirrorType {self.mirror_type} +} + struct SDLWindow<'a> { canvas: sdl2::render::WindowCanvas, events: sdl2::EventPump, @@ -49,9 +83,9 @@ struct SDLWindow<'a> { texture: sdl2::render::Texture, timer: Instant, duration_per_frame: Duration, - p1_button_states: [bool; 8], - p1_ctl: &'a Joystick, - p1_keymap: [Button; 256], + p1_button_state: u8, + p1_ctl: &'a stdctl::Joystick, + p1_keymap: [u8; 256], } macro_rules! gen_keymap { @@ -65,7 +99,7 @@ macro_rules! gen_keymap { } impl<'a> SDLWindow<'a> { - fn new(p1_ctl: &'a Joystick) -> Self { + fn new(p1_ctl: &'a stdctl::Joystick) -> Self { use Keycode::*; let sdl_context = sdl2::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); @@ -89,23 +123,23 @@ impl<'a> SDLWindow<'a> { PixelFormatEnum::RGB24, WIN_WIDTH, WIN_HEIGHT).unwrap(), timer: Instant::now(), duration_per_frame: Duration::from_millis(1000 / 60), - p1_button_states: [false; 8], - p1_ctl, p1_keymap: [Button::Null; 256] + p1_button_state: 0, + p1_ctl, p1_keymap: [stdctl::NULL; 256] }; { let keymap = &mut res.p1_keymap; - gen_keymap!(keymap, [I, Button::Up, - K, Button::Down, - J, Button::Left, - L, Button::Right, - Z, Button::A, - X, Button::B, - Return, Button::Start, - S, Button::Select, - Up, Button::Up, - Down, Button::Down, - Left, Button::Left, - Right, Button::Right + gen_keymap!(keymap, [I, stdctl::UP, + K, stdctl::DOWN, + J, stdctl::LEFT, + L, stdctl::RIGHT, + Z, stdctl::A, + X, stdctl::B, + Return, stdctl::START, + S, stdctl::SELECT, + Up, stdctl::UP, + Down, stdctl::DOWN, + Left, stdctl::LEFT, + Right, stdctl::RIGHT ]); } res @@ -114,7 +148,6 @@ impl<'a> SDLWindow<'a> { #[inline] fn poll(&mut self) -> bool { use Keycode::*; - let p1_button_states = &mut self.p1_button_states; let p1_keymap = &self.p1_keymap; for event in self.events.poll_iter() { match event { @@ -122,22 +155,12 @@ impl<'a> SDLWindow<'a> { return true; }, Event::KeyDown { keycode: Some(c), .. } => { - match p1_keymap[(c as usize) & 0xff] { - Button::Null => (), - i => { - p1_button_states[i as usize] = true; - self.p1_ctl.set(p1_button_states); - } - } + self.p1_button_state |= p1_keymap[(c as usize) & 0xff]; + self.p1_ctl.set(self.p1_button_state) }, Event::KeyUp { keycode: Some(c), .. } => { - match p1_keymap[(c as usize) & 0xff] { - Button::Null => (), - i => { - p1_button_states[i as usize] = false; - self.p1_ctl.set(p1_button_states); - } - } + self.p1_button_state &= !p1_keymap[(c as usize) & 0xff]; + self.p1_ctl.set(self.p1_button_state) }, _ => () } @@ -258,13 +281,13 @@ fn main() { } } */ - let p1ctl = Joystick::new(); + let p1ctl = stdctl::Joystick::new(); let mut win = SDLWindow::new(&p1ctl); let mut m = match mapper_id { - 0 | 2 => mapper::Mapper2::new(cartridge::Cartridge::new(chr_rom, prg_rom, sram, mirror)), + 0 | 2 => mapper::Mapper2::new(SimpleCart::new(chr_rom, prg_rom, sram, mirror)), _ => panic!("unsupported mapper {}", mapper_id) }; - let mt = m.get_cart().mirror_type; + let mt = m.get_cart().get_mirror_type(); let mapper = RefCell::new(&mut m as &mut memory::VMem); let mut ppu = ppu::PPU::new(memory::PPUMemory::new(&mapper, mt), &mut win); let mut cpu = mos6502::CPU::new(memory::CPUMemory::new(&mut ppu, &mapper, Some(&p1ctl), None)); diff --git a/src/cartridge.rs b/src/cartridge.rs index 0d21a42..524ef12 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -15,32 +15,8 @@ pub enum BankType { Sram, /* save ram */ } -pub struct Cartridge { - chr_rom: Vec<u8>, - prg_rom: Vec<u8>, - sram: Vec<u8>, - pub mirror_type: MirrorType -} - -impl Cartridge { - pub fn get_size(&self, kind: BankType) -> usize { - match kind { - BankType::PrgRom => self.prg_rom.len(), - BankType::ChrRom => self.chr_rom.len(), - BankType::Sram => self.sram.len() - } - } - pub fn get_bank(&mut self, base: usize, size: usize, kind: BankType) -> *mut [u8] { - &mut (match kind { - BankType::PrgRom => &mut self.prg_rom, - BankType::ChrRom => &mut self.chr_rom, - BankType::Sram => &mut self.sram, - })[base..base + size] - } - pub fn new(chr_rom: Vec<u8>, - prg_rom: Vec<u8>, - sram: Vec<u8>, - mirror_type: MirrorType) -> Self { - Cartridge{chr_rom, prg_rom, sram, mirror_type} - } +pub trait Cartridge { + fn get_size(&self, kind: BankType) -> usize; + fn get_bank(&mut self, base: usize, size: usize, kind: BankType) -> *mut [u8]; + fn get_mirror_type(&self) -> MirrorType; } diff --git a/src/controller.rs b/src/controller.rs index 2685cd1..f2ed4f7 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -8,18 +8,16 @@ pub trait Controller { pub mod stdctl { use core::cell::Cell; use controller::Controller; - #[derive(Copy, Clone)] - pub enum Button { - A = 0, - B = 1, - Select = 2, - Start = 3, - Up = 4, - Down = 5, - Left = 6, - Right = 7, - Null = 8, - } + pub const A: u8 = 1 << 0; + pub const B: u8 = 1 << 1; + pub const SELECT: u8 = 1 << 2; + pub const START: u8 = 1 << 3; + pub const UP: u8 = 1 << 4; + pub const DOWN: u8 = 1 << 5; + pub const LEFT: u8 = 1 << 6; + pub const RIGHT: u8 = 1 << 7; + pub const NULL: u8 = 0; + pub struct Joystick { strobe: Cell<bool>, reg: Cell<u8>, @@ -31,15 +29,9 @@ pub mod stdctl { Joystick{reg: Cell::new(0), strobe: Cell::new(false), back_reg: Cell::new(0)} } - pub fn set(&self, buttons: &[bool]) { - let mut reg = 0; - for (i, v) in buttons.iter().enumerate() { - if *v { - reg |= 1 << i; - } - } - self.reg.set(reg); - self.back_reg.set(reg); + pub fn set(&self, buttons: u8) { + self.reg.set(buttons); + self.back_reg.set(buttons); } } diff --git a/src/disasm.rs b/src/disasm.rs new file mode 100644 index 0000000..c9b3696 --- /dev/null +++ b/src/disasm.rs @@ -0,0 +1,97 @@ +use mos6502::{make_optable, make_addrtable}; + +mod disops { + make_optable!(OPS, &str); + ids2strs!(adc, and, asl, bcc, bcs, beq, bit, bmi, + bne, bpl, brk, bvc, bvs, clc, cld, cli, + clv, cmp, cpx, cpy, dec, dex, dey, eor, + inc, inx, iny, jmp, jsr, lda, ldx, ldy, + lsr, nop, ora, pha, php, pla, plp, rol, + ror, rti, rts, sbc, sec, sed, sei, sta, + stx, sty, tax, tay, tsx, txa, txs, tya, nil); +} + +mod disaddr { + pub type T<'a, 'b> = &'a mut Iterator<Item=&'b u8>; + make_addrtable!(ADDR_MODES, fn (T) -> String); + fn acc(_code: T) -> String { + "a".to_string() + } + fn imm(code: T) -> String { + format!("#${:02x}", code.next().unwrap()) + } + fn zpg(code: T) -> String { + format!("${:02x}", code.next().unwrap()) + } + fn zpx(code: T) -> String { + format!("${:02x}, x", code.next().unwrap()) + } + fn zpy(code: T) -> String { + format!("${:02x}, y", code.next().unwrap()) + } + fn rel(code: T) -> String { + let b = *code.next().unwrap() as i8 as i16; + if b >= 0 { + format!("+${:02x}, x", b) + } else { + format!("-${:02x}, x", -b) + } + } + fn abs(code: T) -> String { + let low = *code.next().unwrap() as u16; + let high = *code.next().unwrap() as u16; + format!("${:04x}", (high << 8) | low) + } + fn abx(code: T) -> String { + let low = *code.next().unwrap() as u16; + let high = *code.next().unwrap() as u16; + format!("${:04x}, x", (high << 8) | low) + } + fn aby(code: T) -> String { + let low = *code.next().unwrap() as u16; + let high = *code.next().unwrap() as u16; + format!("${:04x}, y", (high << 8) | low) + } + fn ind(code: T) -> String { + let low = *code.next().unwrap() as u16; + let high = *code.next().unwrap() as u16; + format!("(${:04x})", (high << 8) | low) + } + fn xin(code: T) -> String { + format!("(${:02x}, x)", code.next().unwrap()) + } + fn iny(code: T) -> String { + format!("(${:02x}), y", code.next().unwrap()) + } + fn nil(_code: T) -> String { + "".to_string() + } +} + +pub struct Disassembler<'a, T> where T: Iterator<Item=&'a u8> { + raw_code: T +} + +impl<'a, T> Disassembler<'a, T> where T: Iterator<Item=&'a u8> { + pub fn new(raw_code: T) -> Self { + Disassembler{raw_code} + } + fn parse(opcode: u8, code: &mut T) -> String { + format!("{} {}", disops::OPS[opcode as usize], + disaddr::ADDR_MODES[opcode as usize](code)) + } +} + +impl<'a, T> Iterator for Disassembler<'a, T> where T: Iterator<Item=&'a u8> { + type Item = String; + fn next(&mut self) -> Option<Self::Item> { + match self.raw_code.next() { + Some(opcode) => Some(Disassembler::parse(*opcode, &mut self.raw_code)), + None => None + } + } +} + +pub fn parse(opcode: u8, code: &[u8]) -> String { + Disassembler::parse(opcode, &mut code.iter()) +} @@ -1,4 +1,4 @@ -extern crate core; +#![no_std] mod memory; mod mos6502; mod ppu; diff --git a/src/mapper.rs b/src/mapper.rs index fc02ed2..583c452 100644 --- a/src/mapper.rs +++ b/src/mapper.rs @@ -3,8 +3,8 @@ extern crate core; use memory::VMem; use cartridge::{Cartridge, BankType}; -pub struct Mapper2<'a> { - cart: Cartridge, +pub struct Mapper2<'a, C> where C: Cartridge { + cart: C, prg_bank1: &'a [u8], prg_bank2: &'a [u8], chr_bank: &'a mut [u8], @@ -12,7 +12,7 @@ pub struct Mapper2<'a> { prg_nbank: usize } -impl<'a> VMem for Mapper2<'a> { +impl<'a, C> VMem for Mapper2<'a, C> where C: Cartridge { fn read(&self, addr: u16) -> u8 { let addr = addr as usize; if addr < 0x2000 { /* 0x2000 size bank */ @@ -46,8 +46,8 @@ impl<'a> VMem for Mapper2<'a> { } } -impl<'a> Mapper2<'a> { - pub fn new(cart: Cartridge) -> Self { +impl<'a, C> Mapper2<'a, C> where C: Cartridge { + pub fn new(cart: C) -> Self { unsafe { let nbank = cart.get_size(BankType::PrgRom) >> 14; let null = core::mem::uninitialized(); diff --git a/src/memory.rs b/src/memory.rs index 6a62678..fb07ad5 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -115,17 +115,6 @@ impl<'a> PPUMemory<'a> { mirror_type, mapper} } - - pub fn dump(&self) { - for (i, v) in self.palette.iter().enumerate() { - print!("{:02x} ", *v); - if (i & 0x7) == 0x7 {println!("@{:02x}", i)} - } - for (i, v) in self.nametable.iter().enumerate() { - print!("{:02x} ", *v); - if (i & 0x1f) == 0x1f {println!("@{:02x}", i)} - } - } } const MIRROR_IDX: [[u8; 4]; 5] = [ diff --git a/src/mos6502.rs b/src/mos6502.rs index 9dd3d85..f279a2a 100644 --- a/src/mos6502.rs +++ b/src/mos6502.rs @@ -1,4 +1,6 @@ #![allow(dead_code)] +#![allow(unused_macros)] + use memory::{CPUMemory, VMem}; pub const CPU_FREQ: u32 = 1789773; macro_rules! make_optable { @@ -121,104 +123,6 @@ macro_rules! ids2strs { }; } -pub mod disasm { - mod disops { - make_optable!(OPS, &str); - ids2strs!(adc, and, asl, bcc, bcs, beq, bit, bmi, - bne, bpl, brk, bvc, bvs, clc, cld, cli, - clv, cmp, cpx, cpy, dec, dex, dey, eor, - inc, inx, iny, jmp, jsr, lda, ldx, ldy, - lsr, nop, ora, pha, php, pla, plp, rol, - ror, rti, rts, sbc, sec, sed, sei, sta, - stx, sty, tax, tay, tsx, txa, txs, tya, nil); - } - - mod disaddr { - pub type T<'a, 'b> = &'a mut Iterator<Item=&'b u8>; - make_addrtable!(ADDR_MODES, fn (T) -> String); - fn acc(_code: T) -> String { - "a".to_string() - } - fn imm(code: T) -> String { - format!("#${:02x}", code.next().unwrap()) - } - fn zpg(code: T) -> String { - format!("${:02x}", code.next().unwrap()) - } - fn zpx(code: T) -> String { - format!("${:02x}, x", code.next().unwrap()) - } - fn zpy(code: T) -> String { - format!("${:02x}, y", code.next().unwrap()) - } - fn rel(code: T) -> String { - let b = *code.next().unwrap() as i8 as i16; - if b >= 0 { - format!("+${:02x}, x", b) - } else { - format!("-${:02x}, x", -b) - } - } - fn abs(code: T) -> String { - let low = *code.next().unwrap() as u16; - let high = *code.next().unwrap() as u16; - format!("${:04x}", (high << 8) | low) - } - fn abx(code: T) -> String { - let low = *code.next().unwrap() as u16; - let high = *code.next().unwrap() as u16; - format!("${:04x}, x", (high << 8) | low) - } - fn aby(code: T) -> String { - let low = *code.next().unwrap() as u16; - let high = *code.next().unwrap() as u16; - format!("${:04x}, y", (high << 8) | low) - } - fn ind(code: T) -> String { - let low = *code.next().unwrap() as u16; - let high = *code.next().unwrap() as u16; - format!("(${:04x})", (high << 8) | low) - } - fn xin(code: T) -> String { - format!("(${:02x}, x)", code.next().unwrap()) - } - fn iny(code: T) -> String { - format!("(${:02x}), y", code.next().unwrap()) - } - fn nil(_code: T) -> String { - "".to_string() - } - } - - pub struct Disassembler<'a, T> where T: Iterator<Item=&'a u8> { - raw_code: T - } - - impl<'a, T> Disassembler<'a, T> where T: Iterator<Item=&'a u8> { - pub fn new(raw_code: T) -> Self { - Disassembler{raw_code} - } - fn parse(opcode: u8, code: &mut T) -> String { - format!("{} {}", disops::OPS[opcode as usize], - disaddr::ADDR_MODES[opcode as usize](code)) - } - } - - impl<'a, T> Iterator for Disassembler<'a, T> where T: Iterator<Item=&'a u8> { - type Item = String; - fn next(&mut self) -> Option<Self::Item> { - match self.raw_code.next() { - Some(opcode) => Some(Disassembler::parse(*opcode, &mut self.raw_code)), - None => None - } - } - } - - pub fn parse(opcode: u8, code: &[u8]) -> String { - Disassembler::parse(opcode, &mut code.iter()) - } -} - macro_rules! stack_addr { ($sp: ident, $disp: expr) => (($sp.wrapping_sub($disp) as u16) | 0x0100); } |