From 2bba9f76f6643120d609a7766a3ffbaf32abcfff Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 8 Nov 2017 11:41:14 -0500 Subject: init --- src/lib.rs | 1 + src/main.rs | 15 ++++ src/mos6502.rs | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 src/lib.rs create mode 100644 src/main.rs create mode 100644 src/mos6502.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..fa67f49 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +mod mos6502; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3544029 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,15 @@ +mod mos6502; +use mos6502::disasm; +fn main() { + let code = [0xa9, 0x01, 0x8d, 0x00, 0x02, 0xa9, 0x05, 0x8d, 0x01, 0x02, 0xa9, 0x08, 0x8d, 0x02, 0x02 ]; + let code2 = [0xa9, 0x03, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x02 ]; + let dasm = disasm::Disassembler::new(code2.iter()); + for l in dasm { + println!("{}", l); + } + let a = 0x03; + let b = 0x4c; + let c = 0x08; + let d = 0x06; + println!("{}", disasm::parse(code2[0], &[a, b, c, d])); +} diff --git a/src/mos6502.rs b/src/mos6502.rs new file mode 100644 index 0000000..94de974 --- /dev/null +++ b/src/mos6502.rs @@ -0,0 +1,257 @@ +macro_rules! make_optable { + ($x:ident, $t: ty) => (pub const $x: [$t; 0x100] = [ + /* 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf */ + brk, ora, nil, nil, nil, ora, asl, nil, php, ora, asl, nil, nil, ora, asl, nil, + bpl, ora, nil, nil, nil, ora, asl, nil, clc, ora, nil, nil, nil, ora, asl, nil, + jsr, and, nil, nil, bit, and, rol, nil, plp, and, rol, nil, bit, and, rol, nil, + bmi, and, nil, nil, nil, and, rol, nil, sec, and, nil, nil, nil, and, rol, nil, + rti, eor, nil, nil, nil, eor, lsr, nil, pha, eor, lsr, nil, jmp, eor, lsr, nil, + bvc, eor, nil, nil, nil, eor, lsr, nil, cli, eor, nil, nil, nil, eor, lsr, nil, + rts, adc, nil, nil, nil, adc, ror, nil, pla, adc, ror, nil, jmp, adc, ror, nil, + bvs, adc, nil, nil, nil, adc, ror, nil, sei, adc, nil, nil, nil, adc, ror, nil, + nil, sta, nil, nil, sty, sta, stx, nil, dey, nil, txa, nil, sty, sta, stx, nil, + bcc, sta, nil, nil, sty, sta, stx, nil, tya, sta, txs, nil, nil, sta, nil, nil, + ldy, lda, ldx, nil, ldy, lda, ldx, nil, tay, lda, tax, nil, ldy, lda, ldx, nil, + bcs, lda, nil, nil, ldy, lda, ldx, nil, clv, lda, tsx, nil, ldy, lda, ldx, nil, + cpy, cmp, nil, nil, cpy, cmp, dec, nil, iny, cmp, dex, nil, cpy, cmp, dec, nil, + bne, cmp, nil, nil, nil, cmp, dec, nil, cld, cmp, nil, nil, nil, cmp, dec, nil, + cpx, sbc, nil, nil, cpx, sbc, inc, nil, inx, sbc, nop, nil, cpx, sbc, inc, nil, + beq, sbc, nil, nil, nil, sbc, inc, nil, sed, sbc, nil, nil, nil, sbc, inc, nil + ];); +} + +macro_rules! make_addrtable { + ($x:ident, $t: ty) => (pub const $x: [$t; 0x100] = [ + nil, xin, nil, nil, nil, zpg, zpg, nil, nil, imm, acc, nil, nil, abs, abs, nil, + rel, iny, nil, nil, nil, zpx, zpx, nil, nil, aby, nil, nil, nil, abx, abx, nil, + abs, xin, nil, nil, zpg, zpg, zpg, nil, nil, imm, acc, nil, abs, abs, abs, nil, + rel, iny, nil, nil, nil, zpx, zpx, nil, nil, aby, nil, nil, nil, abx, abx, nil, + nil, xin, nil, nil, nil, zpg, zpg, nil, nil, imm, acc, nil, abs, abs, abs, nil, + rel, iny, nil, nil, nil, zpx, zpx, nil, nil, aby, nil, nil, nil, abx, abx, nil, + nil, xin, nil, nil, nil, zpg, zpg, nil, nil, imm, acc, nil, ind, abs, abs, nil, + rel, iny, nil, nil, nil, zpx, zpx, nil, nil, aby, nil, nil, nil, abx, abx, nil, + nil, xin, nil, nil, zpg, zpg, zpg, nil, nil, nil, nil, nil, abs, abs, abs, nil, + rel, iny, nil, nil, zpx, zpx, zpy, nil, nil, aby, nil, nil, nil, abx, nil, nil, + imm, xin, imm, nil, zpg, zpg, zpg, nil, nil, imm, nil, nil, abs, abs, abs, nil, + rel, iny, nil, nil, zpx, zpx, zpy, nil, nil, aby, nil, nil, abx, abx, aby, nil, + imm, xin, nil, nil, zpg, zpg, zpg, nil, nil, imm, nil, nil, abs, abs, abs, nil, + rel, iny, nil, nil, nil, zpx, zpx, nil, nil, aby, nil, nil, nil, abx, abx, nil, + imm, xin, nil, nil, zpg, zpg, zpg, nil, nil, imm, nil, nil, abs, abs, abs, nil, + rel, iny, nil, nil, nil, zpx, zpx, nil, nil, aby, nil, nil, nil, abx, abx, nil + ];); +} + +macro_rules! ids2strs { + ($($x:ident), *) => { + $(#[allow(non_upper_case_globals)] + const $x: &str = stringify!($x);)* + }; +} + +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; + 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(); + if b >> 7 == 0 { + format!("+${:02x}, x", b & 0x7f) + } else { + format!("-${:02x}, x", b & 0x7f) + } + } + 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 { + raw_code: T + } + + impl<'a, T> Disassembler<'a, T> where T: Iterator { + 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 { + type Item = String; + fn next(&mut self) -> Option { + 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()) + } +} + + mod ops { + use mos6502::CPU; + make_optable!(OPS, fn (&mut CPU)); + + fn adc(cpu: &mut CPU) {} + fn and(cpu: &mut CPU) {} + fn asl(cpu: &mut CPU) {} + fn bcc(cpu: &mut CPU) {} + fn bcs(cpu: &mut CPU) {} + fn beq(cpu: &mut CPU) {} + fn bit(cpu: &mut CPU) {} + fn bmi(cpu: &mut CPU) {} + fn bne(cpu: &mut CPU) {} + fn bpl(cpu: &mut CPU) {} + fn brk(cpu: &mut CPU) {} + fn bvc(cpu: &mut CPU) {} + fn bvs(cpu: &mut CPU) {} + fn clc(cpu: &mut CPU) {} + fn cld(cpu: &mut CPU) {} + fn cli(cpu: &mut CPU) {} + fn clv(cpu: &mut CPU) {} + fn cmp(cpu: &mut CPU) {} + fn cpx(cpu: &mut CPU) {} + fn cpy(cpu: &mut CPU) {} + fn dec(cpu: &mut CPU) {} + fn dex(cpu: &mut CPU) {} + fn dey(cpu: &mut CPU) {} + fn eor(cpu: &mut CPU) {} + fn inc(cpu: &mut CPU) {} + fn inx(cpu: &mut CPU) {} + fn iny(cpu: &mut CPU) {} + fn jmp(cpu: &mut CPU) {} + fn jsr(cpu: &mut CPU) {} + fn lda(cpu: &mut CPU) {} + fn ldx(cpu: &mut CPU) {} + fn ldy(cpu: &mut CPU) {} + fn lsr(cpu: &mut CPU) {} + fn nop(cpu: &mut CPU) {} + fn ora(cpu: &mut CPU) {} + fn pha(cpu: &mut CPU) {} + fn php(cpu: &mut CPU) {} + fn pla(cpu: &mut CPU) {} + fn plp(cpu: &mut CPU) {} + fn rol(cpu: &mut CPU) {} + fn ror(cpu: &mut CPU) {} + fn rti(cpu: &mut CPU) {} + fn rts(cpu: &mut CPU) {} + fn sbc(cpu: &mut CPU) {} + fn sec(cpu: &mut CPU) {} + fn sed(cpu: &mut CPU) {} + fn sei(cpu: &mut CPU) {} + fn sta(cpu: &mut CPU) {} + fn stx(cpu: &mut CPU) {} + fn sty(cpu: &mut CPU) {} + fn tax(cpu: &mut CPU) {} + fn tay(cpu: &mut CPU) {} + fn tsx(cpu: &mut CPU) {} + fn txa(cpu: &mut CPU) {} + fn txs(cpu: &mut CPU) {} + fn tya(cpu: &mut CPU) {} + fn nil(cpu: &mut CPU) {} + } + + mod addr { + use mos6502::CPU; + make_addrtable!(ADDR_MODES, fn (&mut CPU)); + + fn acc(cpu: &mut CPU) {} + fn imm(cpu: &mut CPU) {} + fn zpg(cpu: &mut CPU) {} + fn zpx(cpu: &mut CPU) {} + fn zpy(cpu: &mut CPU) {} + fn rel(cpu: &mut CPU) {} + fn abs(cpu: &mut CPU) {} + fn abx(cpu: &mut CPU) {} + fn aby(cpu: &mut CPU) {} + fn ind(cpu: &mut CPU) {} + fn xin(cpu: &mut CPU) {} + fn iny(cpu: &mut CPU) {} + fn nil(cpu: &mut CPU) {} + } + + pub trait VMem { + fn read(addr: u16) -> u8; + fn write(addr: u16, data: u8); + } + + pub struct CPU { + /* registers */ + a: u8, + x: u8, + y: u8, + status: u8, + pc: u8, + sp: u8, + /* internal state */ + ea: u16, /* effective address */ + } + + impl CPU { + fn step(&mut self, opcode: u8) { + ops::OPS[opcode as usize](self); + addr::ADDR_MODES[opcode as usize](self); + } + fn new() -> Self { + CPU{a: 0, x: 0, y: 0, status: 0, pc: 0, sp: 0, ea: 0} + } + } + -- cgit v1.2.3-70-g09d2