diff --git a/src/chip.rs b/src/chip.rs index 30746ae..d097f75 100644 --- a/src/chip.rs +++ b/src/chip.rs @@ -16,4 +16,59 @@ impl Chip { ram: Box::new([0u8; 8 * 1024 + 1024]), } } -} \ No newline at end of file +} + +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; diff --git a/src/chip_definitions.rs b/src/chip_definitions.rs new file mode 100644 index 0000000..65d41c4 --- /dev/null +++ b/src/chip_definitions.rs @@ -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; diff --git a/src/cpu.rs b/src/cpu.rs index c1b3e77..0049534 100644 --- a/src/cpu.rs +++ b/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) } diff --git a/src/decoder.rs b/src/decoder.rs index 9cda401..3d5641f 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -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 { 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 { // 0b1111_0000_0000_0000 => // 0b1111_0100_0000_0000 => 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 { // 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))), _ => {}, } diff --git a/src/main.rs b/src/main.rs index 5498195..cf3361a 100644 --- a/src/main.rs +++ b/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(); diff --git a/src/regs.rs b/src/regs.rs index 2588002..e8b02c5 100644 --- a/src/regs.rs +++ b/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 for StatusFlag {