Fixed a lot of stuff
This commit is contained in:
parent
27b897cd0d
commit
ad2af7a2ec
57
src/chip.rs
57
src/chip.rs
@ -16,4 +16,59 @@ impl Chip {
|
||||
ram: Box::new([0u8; 8 * 1024 + 1024]),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const GPIO0: u16 = 0x000;
|
||||
pub const GPIO1: u16 = 0x001;
|
||||
pub const GPIO2: u16 = 0x002;
|
||||
pub const GPIO3: u16 = 0x003;
|
||||
pub const GPIO4: u16 = 0x004;
|
||||
pub const GPIO5: u16 = 0x005;
|
||||
pub const GPIO6: u16 = 0x006;
|
||||
pub const GPIO7: u16 = 0x007;
|
||||
pub const GPIO8: u16 = 0x008;
|
||||
pub const GPIO9: u16 = 0x009;
|
||||
pub const GPIOA: u16 = 0x00A;
|
||||
pub const GPIOB: u16 = 0x00B;
|
||||
pub const GPIOC: u16 = 0x00C;
|
||||
pub const GPIOD: u16 = 0x00D;
|
||||
pub const GPIOE: u16 = 0x00E;
|
||||
pub const GPIOF: u16 = 0x00F;
|
||||
pub const VPORT0_DIR: u16 = 0x010;
|
||||
pub const VPORT0_OUT: u16 = 0x011;
|
||||
pub const VPORT0_IN: u16 = 0x012;
|
||||
pub const VPORT0_INTFLAGS: u16 = 0x013;
|
||||
pub const VPORT1_DIR: u16 = 0x014;
|
||||
pub const VPORT1_OUT: u16 = 0x015;
|
||||
pub const VPORT1_IN: u16 = 0x016;
|
||||
pub const VPORT1_INTFLAGS: u16 = 0x017;
|
||||
pub const VPORT2_DIR: u16 = 0x018;
|
||||
pub const VPORT2_OUT: u16 = 0x019;
|
||||
pub const VPORT2_IN: u16 = 0x01A;
|
||||
pub const VPORT2_INTFLAGS: u16 = 0x01B;
|
||||
pub const VPORT3_DIR: u16 = 0x01C;
|
||||
pub const VPORT3_OUT: u16 = 0x01D;
|
||||
pub const VPORT3_IN: u16 = 0x01E;
|
||||
pub const VPORT3_INTFLAGS: u16 = 0x01F;
|
||||
pub const PRODSIGNATURES_ADCACAL0: u16 = 0x020;
|
||||
pub const PRODSIGNATURES_ADCACAL1: u16 = 0x021;
|
||||
pub const PRODSIGNATURES_ADCBCAL0: u16 = 0x024;
|
||||
pub const PRODSIGNATURES_ADCBCAL1: u16 = 0x025;
|
||||
pub const OCD_OCDR0: u16 = 0x02E;
|
||||
pub const OCD_OCDR1: u16 = 0x02F;
|
||||
pub const PRODSIGNATURES_DACA0OFFCAL: u16 = 0x030;
|
||||
pub const PRODSIGNATURES_DACA0GAINCAL: u16 = 0x031;
|
||||
pub const PRODSIGNATURES_DACB0OFFCAL: u16 = 0x032;
|
||||
pub const PRODSIGNATURES_DACB0GAINCAL: u16 = 0x033;
|
||||
pub const CCP: u16 = 0x034;
|
||||
pub const PRODSIGNATURES_DACA1GAINCAL: u16 = 0x035;
|
||||
pub const PRODSIGNATURES_DACB1OFFCAL: u16 = 0x036;
|
||||
pub const PRODSIGNATURES_DACB1GAINCAL: u16 = 0x037;
|
||||
pub const RAMPD: u16 = 0x038;
|
||||
pub const RAMPX: u16 = 0x039;
|
||||
pub const RAMPY: u16 = 0x03A;
|
||||
pub const RAMPZ: u16 = 0x03B;
|
||||
pub const EIND: u16 = 0x03C;
|
||||
pub const SPL: u16 = 0x03D;
|
||||
pub const SPH: u16 = 0x03E;
|
||||
pub const SREG: u16 = 0x03F;
|
||||
|
||||
54
src/chip_definitions.rs
Normal file
54
src/chip_definitions.rs
Normal file
@ -0,0 +1,54 @@
|
||||
pub const GPIO0: u16 = 0x000;
|
||||
pub const GPIO1: u16 = 0x001;
|
||||
pub const GPIO2: u16 = 0x002;
|
||||
pub const GPIO3: u16 = 0x003;
|
||||
pub const GPIO4: u16 = 0x004;
|
||||
pub const GPIO5: u16 = 0x005;
|
||||
pub const GPIO6: u16 = 0x006;
|
||||
pub const GPIO7: u16 = 0x007;
|
||||
pub const GPIO8: u16 = 0x008;
|
||||
pub const GPIO9: u16 = 0x009;
|
||||
pub const GPIOA: u16 = 0x00A;
|
||||
pub const GPIOB: u16 = 0x00B;
|
||||
pub const GPIOC: u16 = 0x00C;
|
||||
pub const GPIOD: u16 = 0x00D;
|
||||
pub const GPIOE: u16 = 0x00E;
|
||||
pub const GPIOF: u16 = 0x00F;
|
||||
pub const VPORT0_DIR: u16 = 0x010;
|
||||
pub const VPORT0_OUT: u16 = 0x011;
|
||||
pub const VPORT0_IN: u16 = 0x012;
|
||||
pub const VPORT0_INTFLAGS: u16 = 0x013;
|
||||
pub const VPORT1_DIR: u16 = 0x014;
|
||||
pub const VPORT1_OUT: u16 = 0x015;
|
||||
pub const VPORT1_IN: u16 = 0x016;
|
||||
pub const VPORT1_INTFLAGS: u16 = 0x017;
|
||||
pub const VPORT2_DIR: u16 = 0x018;
|
||||
pub const VPORT2_OUT: u16 = 0x019;
|
||||
pub const VPORT2_IN: u16 = 0x01A;
|
||||
pub const VPORT2_INTFLAGS: u16 = 0x01B;
|
||||
pub const VPORT3_DIR: u16 = 0x01C;
|
||||
pub const VPORT3_OUT: u16 = 0x01D;
|
||||
pub const VPORT3_IN: u16 = 0x01E;
|
||||
pub const VPORT3_INTFLAGS: u16 = 0x01F;
|
||||
pub const PRODSIGNATURES_ADCACAL0: u16 = 0x020;
|
||||
pub const PRODSIGNATURES_ADCACAL1: u16 = 0x021;
|
||||
pub const PRODSIGNATURES_ADCBCAL0: u16 = 0x024;
|
||||
pub const PRODSIGNATURES_ADCBCAL1: u16 = 0x025;
|
||||
pub const OCD_OCDR0: u16 = 0x02E;
|
||||
pub const OCD_OCDR1: u16 = 0x02F;
|
||||
pub const PRODSIGNATURES_DACA0OFFCAL: u16 = 0x030;
|
||||
pub const PRODSIGNATURES_DACA0GAINCAL: u16 = 0x031;
|
||||
pub const PRODSIGNATURES_DACB0OFFCAL: u16 = 0x032;
|
||||
pub const PRODSIGNATURES_DACB0GAINCAL: u16 = 0x033;
|
||||
pub const CCP: u16 = 0x034;
|
||||
pub const PRODSIGNATURES_DACA1GAINCAL: u16 = 0x035;
|
||||
pub const PRODSIGNATURES_DACB1OFFCAL: u16 = 0x036;
|
||||
pub const PRODSIGNATURES_DACB1GAINCAL: u16 = 0x037;
|
||||
pub const RAMPD: u16 = 0x038;
|
||||
pub const RAMPX: u16 = 0x039;
|
||||
pub const RAMPY: u16 = 0x03A;
|
||||
pub const RAMPZ: u16 = 0x03B;
|
||||
pub const EIND: u16 = 0x03C;
|
||||
pub const SPL: u16 = 0x03D;
|
||||
pub const SPH: u16 = 0x03E;
|
||||
pub const SREG: u16 = 0x03F;
|
||||
212
src/cpu.rs
212
src/cpu.rs
@ -4,6 +4,9 @@
|
||||
use decoder;
|
||||
use decoder::{IncrementMode, Instruction};
|
||||
use regs::{StatusFlag, GeneralPurposeRegister, GeneralPurposeRegisterPair};
|
||||
use chip_definitions;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CPUError {
|
||||
@ -11,6 +14,7 @@ pub enum CPUError {
|
||||
OutOfBoundsException,
|
||||
UnsupportedAddress,
|
||||
DecodingError(decoder::DecodingError),
|
||||
Exit,
|
||||
}
|
||||
|
||||
enum FlagUpdateMode {
|
||||
@ -22,17 +26,38 @@ enum FlagUpdateMode {
|
||||
#[derive(Debug)]
|
||||
pub struct CPU {
|
||||
// General purpose registers
|
||||
registers: [u8; 32],
|
||||
pub registers: [u8; 32],
|
||||
|
||||
// PC
|
||||
pc: u32,
|
||||
|
||||
// For now have the stack pointer in here as well. In reality it is part of
|
||||
// the IO registers
|
||||
sp: u16,
|
||||
pub pc: u32,
|
||||
|
||||
// The same is true for the status register
|
||||
sreg: u8,
|
||||
pub sreg: u8,
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Display for CPU {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "CPU @ 0x{:X} (file offset = 0x{:X})\n", self.pc, 2 * self.pc)?;
|
||||
write!(f, "SREG: 0x{:02X}: ", self.sreg)?;
|
||||
for i in 0..7 {
|
||||
let t = self.sreg & (1 << i);
|
||||
if t > 0 {
|
||||
write!(f, "{}", StatusFlag::try_from(t).unwrap())?;
|
||||
} else {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
}
|
||||
write!(f, "\n")?;
|
||||
write!(f, "Registers:\n")?;
|
||||
for i in 0..32 {
|
||||
write!(f, " R{:-2} = 0x{:02X} ", i, self.registers[i])?;
|
||||
if (i + 1) % 10 == 0{
|
||||
write!(f, "\n");
|
||||
}
|
||||
}
|
||||
write!(f, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
@ -40,13 +65,22 @@ impl CPU {
|
||||
CPU {
|
||||
registers: [0u8; 32],
|
||||
pc: 0, // Reset vector
|
||||
sp: 0xFFFF, // Random value, uninitialized
|
||||
sreg: 0, // Uninitialized as well
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sp(&self, mem: &[u8]) -> u16 {
|
||||
mem[chip_definitions::SPL as usize] as u16 | ((mem[chip_definitions::SPH as usize] as u16) << 8)
|
||||
}
|
||||
|
||||
fn set_sp(&self, mem: &mut [u8], val: u16) {
|
||||
mem[chip_definitions::SPL as usize] = val as u8;
|
||||
mem[chip_definitions::SPH as usize] = (val >> 8) as u8;
|
||||
}
|
||||
|
||||
|
||||
fn test_flag(&self, flag: StatusFlag) -> bool {
|
||||
self.sreg & flag as u8 > 0
|
||||
(self.sreg & (flag as u8)) > 0
|
||||
}
|
||||
|
||||
fn set_flag(&mut self, flag: StatusFlag) {
|
||||
@ -58,6 +92,7 @@ impl CPU {
|
||||
}
|
||||
|
||||
fn set_clear_flag(&mut self, flag: StatusFlag, test: bool) {
|
||||
print!("[{:?}->{}] ", flag, test);
|
||||
if test {
|
||||
self.set_flag(flag);
|
||||
} else {
|
||||
@ -83,13 +118,15 @@ impl CPU {
|
||||
}
|
||||
|
||||
fn push(&mut self, ram: &mut [u8], val: u8) {
|
||||
ram[self.sp as usize] = val;
|
||||
self.sp -= 1;
|
||||
let sp = self.get_sp(&ram);
|
||||
ram[sp as usize] = val;
|
||||
self.set_sp(ram, sp.wrapping_sub(1));
|
||||
}
|
||||
|
||||
fn pop(&mut self, ram: &mut [u8]) -> u8 {
|
||||
self.sp += 1;
|
||||
ram[self.sp as usize]
|
||||
let sp = self.get_sp(&ram);
|
||||
self.set_sp(ram, sp.wrapping_add(1));
|
||||
ram[sp.wrapping_add(1) as usize]
|
||||
}
|
||||
|
||||
fn update_flags(&mut self, mode: FlagUpdateMode, rd: u8, rr: u8, s: u8) {
|
||||
@ -138,7 +175,7 @@ impl CPU {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(CPUError::DecodingError(e)),
|
||||
};
|
||||
print!("CPU: pc={:06X} Fetch: {:?} -> ", self.pc, ins);
|
||||
print!("CPU: pc={:06X} sp={:04X} Fetch: {:?} -> ", self.pc, self.get_sp(ram), ins);
|
||||
|
||||
self.pc += (ins.size() / 2) as u32;
|
||||
|
||||
@ -171,23 +208,13 @@ impl CPU {
|
||||
} else {
|
||||
rd.wrapping_sub(rr)
|
||||
};
|
||||
self.update_flags(FlagUpdateMode::HSVNZC, rd, rr, s);
|
||||
/*
|
||||
self.set_clear_flag(StatusFlag::Carry, ((!r.into() & i.into()) | (r.into() & i.into()) | (r.into() & !i.into())) & 0x80 == 0x80);
|
||||
cpu_.sreg_.C = ((~Rd & Rr) | (Rr & R) | (R & ~Rd)) & 0x80;
|
||||
self.set_clear_flag(StatusFlag::Zero, s == 0 && self.test_flag(StatusFlag::Zero));
|
||||
cpu_.sreg_.Z = R == 0;
|
||||
cpu_.sreg_.N = R & 0x80;
|
||||
cpu_.sreg_.V = ((Rd & ~Rr & ~R) | (~Rd & Rr & R)) & 0x80;
|
||||
cpu_.sreg_.S = cpu_.sreg_.N ^ cpu_.sreg_.V;
|
||||
cpu_.sreg_.H = ((~Rd & Rr) | (Rr & R) | (R & ~Rd)) & 0x08;
|
||||
*/},
|
||||
self.update_flags(FlagUpdateMode::HSVNZC_KeepZero, rd, rr, s);
|
||||
},
|
||||
Instruction::BR_IF(offset, flag, test) => {
|
||||
if self.test_flag(flag) == test {
|
||||
self.pc = self.pc.wrapping_add(offset as _);
|
||||
}
|
||||
},
|
||||
// ST(GeneralPurposeRegisterPair, GeneralPurposeRegister, IncrementMode),
|
||||
Instruction::ST(ref ptr, ref src_reg, ref inc_mode) => {
|
||||
let base = self.get_register_pair(ptr);
|
||||
let addr = match *inc_mode {
|
||||
@ -202,9 +229,12 @@ impl CPU {
|
||||
},
|
||||
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
||||
};
|
||||
if addr as usize >= ram.len() {
|
||||
return Err(CPUError::OutOfBoundsException);
|
||||
}
|
||||
ram[addr as usize] = self.get_register(src_reg);
|
||||
},
|
||||
Instruction::LD(ref ptr, ref dst_reg, ref inc_mode) => {
|
||||
Instruction::LD(ref dst_reg, ref ptr, ref inc_mode) => {
|
||||
let base = self.get_register_pair(ptr);
|
||||
let addr = match *inc_mode {
|
||||
IncrementMode::None => base,
|
||||
@ -218,6 +248,9 @@ impl CPU {
|
||||
},
|
||||
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
||||
};
|
||||
if addr as usize >= ram.len() {
|
||||
return Err(CPUError::OutOfBoundsException);
|
||||
}
|
||||
let v = ram[addr as usize];
|
||||
self.set_register(dst_reg, v);
|
||||
},
|
||||
@ -231,7 +264,7 @@ impl CPU {
|
||||
self.set_register_pair(&30u8.into(), Z.wrapping_add(1));
|
||||
},
|
||||
_ => {
|
||||
// This instruction does only support PostIncrement
|
||||
// This instruction does only support None + PostIncrement
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -244,41 +277,26 @@ impl CPU {
|
||||
self.set_register_pair(&30u8.into(), Z.wrapping_add(1));
|
||||
},
|
||||
_ => {
|
||||
// This instruction does only support PostIncrement
|
||||
// This instruction does only support None + PostIncrement
|
||||
},
|
||||
}
|
||||
},
|
||||
Instruction::OUT(ref addr, ref val) => {
|
||||
/*
|
||||
0x03D: 'SPL',
|
||||
0x03E: 'SPH',
|
||||
0x03F: 'SREG',
|
||||
*/
|
||||
let val = self.get_register(val) as u16;
|
||||
match *addr {
|
||||
0x3D => self.sp = self.sp & 0xFF00 | val,
|
||||
0x3E => self.sp = self.sp & 0x00FF | (val << 8),
|
||||
0x3F => self.sreg = val as u8,
|
||||
_ => return Err(CPUError::UnsupportedAddress)
|
||||
}
|
||||
let val = self.get_register(val);
|
||||
ram[*addr as usize] = val;
|
||||
},
|
||||
Instruction::IN(ref reg, ref addr) => {
|
||||
let _sp = self.sp; // Non-lexical lifetimes plz
|
||||
match *addr {
|
||||
0x3D => self.set_register(reg, (_sp & 0xFF) as u8),
|
||||
0x3E => self.set_register(reg, (_sp >> 8) as u8),
|
||||
_ => return Err(CPUError::UnsupportedAddress)
|
||||
}
|
||||
self.set_register(reg, ram[*addr as usize]);
|
||||
}
|
||||
Instruction::CALL(ref addr) => {
|
||||
let ret_to = self.pc + 2;
|
||||
let ret_to = self.pc;
|
||||
self.push(ram, ((ret_to >> 16) & 0xFF) as u8);
|
||||
self.push(ram, ((ret_to >> 8) & 0xFF) as u8);
|
||||
self.push(ram, (ret_to & 0xFF) as u8);
|
||||
self.pc = *addr;
|
||||
},
|
||||
Instruction::RCALL(ref addr) => {
|
||||
let ret_to = self.pc + 2;
|
||||
let ret_to = self.pc;
|
||||
self.push(ram, ((ret_to >> 16) & 0xFF) as u8);
|
||||
self.push(ram, ((ret_to >> 8) & 0xFF) as u8);
|
||||
self.push(ram, (ret_to & 0xFF) as u8);
|
||||
@ -300,17 +318,31 @@ impl CPU {
|
||||
},
|
||||
Instruction::SUBI(ref reg, ref v) => {
|
||||
let v = self.registers[reg.as_usize()].wrapping_sub(*v);
|
||||
|
||||
// HACK! Make use of more flags...
|
||||
let r = self.get_register(reg);
|
||||
self.set_clear_flag(StatusFlag::Carry, v > r);
|
||||
self.registers[reg.as_usize()] = v;
|
||||
// TODO: flags
|
||||
},
|
||||
Instruction::SBC(ref d, ref r) => {
|
||||
let v = self.registers[d.as_usize()].wrapping_sub(self.registers[r.as_usize()]);
|
||||
// TODO: - carry
|
||||
let mut v = self.registers[d.as_usize()].wrapping_sub(self.registers[r.as_usize()]);
|
||||
if self.test_flag(StatusFlag::Carry) {
|
||||
v = v.wrapping_sub(1);
|
||||
}
|
||||
// HACK! Make use of more flags...
|
||||
let dd = self.get_register(d);
|
||||
self.set_clear_flag(StatusFlag::Carry, v > dd);
|
||||
self.registers[d.as_usize()] = v;
|
||||
},
|
||||
Instruction::SBCI(ref d, ref r) => {
|
||||
let v = self.registers[d.as_usize()].wrapping_sub(*r);
|
||||
// TODO: - carry
|
||||
let mut v = self.registers[d.as_usize()].wrapping_sub(*r);
|
||||
if self.test_flag(StatusFlag::Carry) {
|
||||
v = v.wrapping_sub(1);
|
||||
}
|
||||
// HACK! Make use of more flags...
|
||||
let dd = self.get_register(d);
|
||||
self.set_clear_flag(StatusFlag::Carry, v > dd);
|
||||
self.registers[d.as_usize()] = v;
|
||||
},
|
||||
Instruction::MOVW(ref d, ref r) => {
|
||||
@ -319,26 +351,52 @@ impl CPU {
|
||||
},
|
||||
Instruction::OR(ref d, ref r) => {
|
||||
let t = self.get_register(d) | self.get_register(r);
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_register(d, t);
|
||||
}
|
||||
Instruction::ORI(ref d, ref v) => {
|
||||
let t = self.get_register(d) | *v;
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_register(d, t);
|
||||
},
|
||||
Instruction::AND(ref d, ref r) => {
|
||||
let t = self.get_register(d) & self.get_register(r);
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_clear_flag(StatusFlag::Negative, t & 0x80 == 0x80);
|
||||
self.set_register(d, t);
|
||||
}
|
||||
},
|
||||
Instruction::TST(ref r) => {
|
||||
let t = self.get_register(r);
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_clear_flag(StatusFlag::Negative, t & 0x80 == 0x80);
|
||||
},
|
||||
Instruction::ANDI(ref d, ref v) => {
|
||||
let t = self.get_register(d) & *v;
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_register(d, t);
|
||||
},
|
||||
Instruction::ADD(ref d, ref r) => {
|
||||
let t = self.get_register(d) + self.get_register(r);
|
||||
let t = self.get_register(d).wrapping_add(self.get_register(r));
|
||||
let dd = self.get_register(d);
|
||||
self.set_clear_flag(StatusFlag::Carry, t < dd);
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_register(d, t);
|
||||
},
|
||||
Instruction::ADC(ref d, ref r) => {
|
||||
let mut t = self.get_register(d).wrapping_add(self.get_register(r));
|
||||
if self.test_flag(StatusFlag::Carry) {
|
||||
t = t.wrapping_add(1);
|
||||
}
|
||||
let dd = self.get_register(d);
|
||||
self.set_clear_flag(StatusFlag::Carry, t < dd);
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_register(d, t);
|
||||
},
|
||||
Instruction::SUB(ref d, ref r) => {
|
||||
let t = self.get_register(d) - self.get_register(r);
|
||||
let dd = self.get_register(d);
|
||||
self.set_clear_flag(StatusFlag::Carry, t > dd);
|
||||
self.set_clear_flag(StatusFlag::Zero, t == 0);
|
||||
self.set_register(d, t);
|
||||
},
|
||||
Instruction::MOV(ref d, ref r) => {
|
||||
@ -347,12 +405,54 @@ impl CPU {
|
||||
},
|
||||
Instruction::ADIW(ref d, ref v) => {
|
||||
let v = self.get_register_pair(d).wrapping_add(*v);
|
||||
let dd = self.get_register_pair(d);
|
||||
self.set_clear_flag(StatusFlag::Carry, v < dd);
|
||||
self.set_clear_flag(StatusFlag::Zero, v == 0);
|
||||
self.set_register_pair(d, v);
|
||||
},
|
||||
Instruction::SBIW(ref d, ref v) => {
|
||||
let v = self.get_register_pair(d).wrapping_sub(*v as _);
|
||||
let dd = self.get_register_pair(d);
|
||||
self.set_clear_flag(StatusFlag::Carry, v > dd);
|
||||
self.set_clear_flag(StatusFlag::Zero, v == 0);
|
||||
self.set_register_pair(d, v);
|
||||
}
|
||||
},
|
||||
Instruction::DEC(ref r) => {
|
||||
let v = self.get_register(r).wrapping_sub(1);
|
||||
self.set_register(r, v);
|
||||
self.set_clear_flag(StatusFlag::Carry, v == 0xFF);
|
||||
self.set_clear_flag(StatusFlag::Zero, v == 0);
|
||||
},
|
||||
Instruction::INC(ref r) => {
|
||||
let v = self.get_register(r).wrapping_add(1);
|
||||
self.set_register(r, v);
|
||||
self.set_clear_flag(StatusFlag::Carry, v == 0);
|
||||
self.set_clear_flag(StatusFlag::Zero, v == 0);
|
||||
},
|
||||
Instruction::STS16(ref addr, ref r) => {
|
||||
ram[*addr as usize] = self.get_register(r);
|
||||
},
|
||||
Instruction::STS8(ref addr, ref r) => {
|
||||
ram[*addr as usize] = self.get_register(r);
|
||||
},
|
||||
Instruction::LDS16(ref r, ref addr) => {
|
||||
self.set_register(r, ram[*addr as usize]);
|
||||
},
|
||||
Instruction::LDS8(ref r, ref addr) => {
|
||||
self.set_register(r, ram[*addr as usize]);
|
||||
},
|
||||
Instruction::SBRS(ref r, ref bit) => {
|
||||
let r = self.get_register(r);
|
||||
if (r & (1 << *bit)) > 0 {
|
||||
self.pc += 1;
|
||||
}
|
||||
},
|
||||
Instruction::SBRC(ref r, ref bit) => {
|
||||
let r = self.get_register(r);
|
||||
if (r & (1 << *bit)) == 0{
|
||||
self.pc += 1;
|
||||
}
|
||||
},
|
||||
Instruction::NOP => {},
|
||||
_ => return Err(CPUError::UnimplementedInstruction)
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ pub enum Instruction {
|
||||
LAC(GeneralPurposeRegister),
|
||||
LAS(GeneralPurposeRegister),
|
||||
LAT(GeneralPurposeRegister),
|
||||
LD(GeneralPurposeRegisterPair, GeneralPurposeRegister, IncrementMode),
|
||||
LD(GeneralPurposeRegister, GeneralPurposeRegisterPair, IncrementMode),
|
||||
LDI(GeneralPurposeRegister, u8),
|
||||
LDS8(GeneralPurposeRegister, u8), // Two variants, with u8 and u16
|
||||
LDS16(GeneralPurposeRegister, u16),
|
||||
@ -234,17 +234,17 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
||||
let do_store = v & 0b0010_0000_0000 != 0;
|
||||
match (do_store, v & 0b0001_0000_0000_0000 > 0, (v >> 2) & 0b11, mode) {
|
||||
// LD X
|
||||
(false, true, 0b11, 0b00) => return Ok(Instruction::LD(26.into(), dr, IncrementMode::None)),
|
||||
(false, true, 0b11, 0b01) => return Ok(Instruction::LD(26.into(), dr, IncrementMode::PostIncrement)),
|
||||
(false, true, 0b11, 0b10) => return Ok(Instruction::LD(26.into(), dr, IncrementMode::PreDecrement)),
|
||||
(false, true, 0b11, 0b00) => return Ok(Instruction::LD(dr, 26.into(), IncrementMode::None)),
|
||||
(false, true, 0b11, 0b01) => return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PostIncrement)),
|
||||
(false, true, 0b11, 0b10) => return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PreDecrement)),
|
||||
// LD Y
|
||||
(false, false, 0b10, 0b00) => return Ok(Instruction::LD(28.into(), dr, IncrementMode::None)),
|
||||
(false, true, 0b10, 0b01) => return Ok(Instruction::LD(28.into(), dr, IncrementMode::PostIncrement)),
|
||||
(false, true, 0b10, 0b10) => return Ok(Instruction::LD(28.into(), dr, IncrementMode::PreDecrement)),
|
||||
(false, false, 0b10, 0b00) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::None)),
|
||||
(false, true, 0b10, 0b01) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PostIncrement)),
|
||||
(false, true, 0b10, 0b10) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PreDecrement)),
|
||||
// LD Z
|
||||
(false, false, 0b00, 0b00) => return Ok(Instruction::LD(30.into(), dr, IncrementMode::None)),
|
||||
(false, true, 0b00, 0b01) => return Ok(Instruction::LD(30.into(), dr, IncrementMode::PostIncrement)),
|
||||
(false, true, 0b00, 0b10) => return Ok(Instruction::LD(30.into(), dr, IncrementMode::PreDecrement)),
|
||||
(false, false, 0b00, 0b00) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::None)),
|
||||
(false, true, 0b00, 0b01) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PostIncrement)),
|
||||
(false, true, 0b00, 0b10) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PreDecrement)),
|
||||
// ST X
|
||||
(true, true, 0b11, 0b00) => return Ok(Instruction::ST(26.into(), dr, IncrementMode::None)),
|
||||
(true, true, 0b11, 0b01) => return Ok(Instruction::ST(26.into(), dr, IncrementMode::PostIncrement)),
|
||||
@ -433,14 +433,13 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
||||
// 0b1111_0000_0000_0000 => <class 'BRCS'> <class 'BREQ'> <class 'BRHS'> <class 'BRIE'> <class 'BRLO'> <class 'BRLT'> <class 'BRMI'> <class 'BRTS'> <class 'BRVS'>
|
||||
// 0b1111_0100_0000_0000 => <class 'BRCC'> <class 'BRGE'> <class 'BRHC'> <class 'BRID'> <class 'BRNE'> <class 'BRPL'> <class 'BRSH'> <class 'BRTC'> <class 'BRVC'>
|
||||
0b1111_0100_0000_0000 | 0b1111_0000_0000_0000 => {
|
||||
let flag_should_be_set = ((v >> 10) & 1) == 1;
|
||||
let flag_should_be_set = ((v >> 10) & 1) == 0;
|
||||
let flag = StatusFlag::try_from_idx((v & 0b111) as u8).unwrap();
|
||||
let mut k = (v >> 3) as i8;
|
||||
k = if k > (1 << 6) {
|
||||
(k as i16 - 1 << 8) as i8
|
||||
} else {
|
||||
k
|
||||
};
|
||||
|
||||
if k >= (1 << 6) {
|
||||
k = k.wrapping_sub(1 << 7);
|
||||
}
|
||||
return Ok(Instruction::BR_IF(k, flag, flag_should_be_set));
|
||||
}
|
||||
_ => {}
|
||||
@ -509,13 +508,13 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
||||
// return "10q0 qq1r rrrr 1qqq".replace(' ', '') ST Y IV
|
||||
// return "10q0 qq1r rrrr 0qqq".replace(' ', '') ST Z IV
|
||||
if (v >> 12) & 0b1101 == 0b1000 {
|
||||
let w = ((v >> 10) & 1) == 1;
|
||||
let w = ((v >> 9) & 1) == 1;
|
||||
let dr = (((v >> 4) & 0b11111) as u8).into();
|
||||
let q = (((v >> 8) & 0b10_0000) | ((v >> 7) & 0b1_1000) | (v & 0b111)) as u8;
|
||||
match (v & 0b1000, w) {
|
||||
(0b1000, false) => return Ok(Instruction::LD(28.into(), dr, IncrementMode::ConstantOffset(q))),
|
||||
(0b1000, false) => return Ok(Instruction::LD(dr, 28.into(), IncrementMode::ConstantOffset(q))),
|
||||
(0b1000, true) => return Ok(Instruction::ST(28.into(), dr, IncrementMode::ConstantOffset(q))),
|
||||
(0b0000, false) => return Ok(Instruction::LD(30.into(), dr, IncrementMode::ConstantOffset(q))),
|
||||
(0b0000, false) => return Ok(Instruction::LD(dr, 30.into(), IncrementMode::ConstantOffset(q))),
|
||||
(0b0000, true) => return Ok(Instruction::ST(30.into(), dr, IncrementMode::ConstantOffset(q))),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
11
src/main.rs
11
src/main.rs
@ -8,21 +8,28 @@ mod cpu;
|
||||
mod regs;
|
||||
mod decoder;
|
||||
mod chip;
|
||||
mod chip_definitions;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let mut rom = read_file("rom.bin").unwrap();
|
||||
let mut ram = [0u8; 8 * 1024 + 8 * 1024];
|
||||
let mut cpu = cpu::CPU::new();
|
||||
for _ in 0..28000 {
|
||||
for _ in 0..280000 {
|
||||
let r = cpu.step(&mut rom, &mut ram);
|
||||
print!("[{:02X} {:02X}] ", cpu.registers[28], cpu.registers[29]);
|
||||
println!("{:?}", r);
|
||||
match r {
|
||||
Err(cpu::CPUError::OutOfBoundsException) => break,
|
||||
Err(cpu::CPUError::Exit) => break,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if cpu.pc == 0xaea / 2 {
|
||||
println!("{}", cpu);
|
||||
}
|
||||
}
|
||||
println!("{:#?}", cpu);
|
||||
println!("{}", cpu);
|
||||
|
||||
write_file("/tmp/endstate.ram", &ram).unwrap();
|
||||
|
||||
|
||||
33
src/regs.rs
33
src/regs.rs
@ -1,24 +1,41 @@
|
||||
use std::cmp::PartialEq;
|
||||
use std::fmt;
|
||||
|
||||
// Sreg flags, ordered from bit 7 to bit 0.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum StatusFlag {
|
||||
// I
|
||||
GlobalInterruptEnable,
|
||||
GlobalInterruptEnable = 1 << 7,
|
||||
// T
|
||||
BitCopyStorage,
|
||||
BitCopyStorage = 1 << 6,
|
||||
// H
|
||||
HalfCarry,
|
||||
HalfCarry = 1 << 5,
|
||||
// S
|
||||
SignBit,
|
||||
SignBit = 1 << 4,
|
||||
// V
|
||||
TwosComplementOverflow,
|
||||
TwosComplementOverflow = 1 << 3,
|
||||
// N
|
||||
Negative,
|
||||
Negative = 1 << 2,
|
||||
// Z
|
||||
Zero,
|
||||
Zero = 1 << 1,
|
||||
// C
|
||||
Carry,
|
||||
Carry = 1 << 0,
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Display for StatusFlag {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", match *self {
|
||||
StatusFlag::GlobalInterruptEnable => "I",
|
||||
StatusFlag::BitCopyStorage => "T",
|
||||
StatusFlag::HalfCarry => "H",
|
||||
StatusFlag::SignBit => "S",
|
||||
StatusFlag::TwosComplementOverflow => "V",
|
||||
StatusFlag::Negative => "N",
|
||||
StatusFlag::Zero => "Z",
|
||||
StatusFlag::Carry => "C",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for StatusFlag {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user