aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2017-11-08 11:41:14 -0500
committerDeterminant <[email protected]>2017-11-08 11:41:14 -0500
commit2bba9f76f6643120d609a7766a3ffbaf32abcfff (patch)
tree87560a79ea799e03c0e209faf8e691478a8abd6e
init
-rw-r--r--.gitignore4
-rw-r--r--Cargo.toml6
-rw-r--r--src/lib.rs1
-rw-r--r--src/main.rs15
-rw-r--r--src/mos6502.rs257
5 files changed, 283 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..143b1ca
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+
+/target/
+**/*.rs.bk
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..9f9157d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "runes"
+version = "0.1.0"
+authors = ["Determinant <[email protected]>"]
+
+[dependencies]
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<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();
+ 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<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())
+ }
+}
+
+ 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}
+ }
+ }
+