iter
This commit is contained in:
parent
dcbc514485
commit
4009845fce
300
src/cpu.rs
300
src/cpu.rs
@ -2,15 +2,22 @@
|
|||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
use decoder;
|
use decoder;
|
||||||
use decoder::Instruction;
|
use decoder::{IncrementMode, Instruction};
|
||||||
|
use regs::{StatusFlag, GeneralPurposeRegister, GeneralPurposeRegisterPair};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CPUError {
|
pub enum CPUError {
|
||||||
UnimplementedInstruction,
|
UnimplementedInstruction,
|
||||||
OutOfBoundsException,
|
OutOfBoundsException,
|
||||||
|
UnsupportedAddress,
|
||||||
DecodingError(decoder::DecodingError),
|
DecodingError(decoder::DecodingError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FlagUpdateMode {
|
||||||
|
HSVNZC,
|
||||||
|
HSVNZC_KeepZero,
|
||||||
|
}
|
||||||
|
|
||||||
// CPU
|
// CPU
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CPU {
|
pub struct CPU {
|
||||||
@ -38,6 +45,88 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_flag(&self, flag: StatusFlag) -> bool {
|
||||||
|
self.sreg & flag as u8 > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_flag(&mut self, flag: StatusFlag) {
|
||||||
|
self.sreg |= flag as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_flag(&mut self, flag: StatusFlag) {
|
||||||
|
self.sreg &= !(flag as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_clear_flag(&mut self, flag: StatusFlag, test: bool) {
|
||||||
|
if test {
|
||||||
|
self.set_flag(flag);
|
||||||
|
} else {
|
||||||
|
self.clear_flag(flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_register_pair(&self, r: &GeneralPurposeRegisterPair) -> u16 {
|
||||||
|
((self.registers[r.high()] as u16) << 8) | self.registers[r.low()] as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_register_pair(&mut self, r: &GeneralPurposeRegisterPair, v: u16) {
|
||||||
|
self.registers[r.high()] = (v >> 8) as u8;
|
||||||
|
self.registers[r.low()] = (v & 0xFF) as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_register(&self, r: &GeneralPurposeRegister) -> u8 {
|
||||||
|
self.registers[r.as_usize()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_register(&mut self, r: &GeneralPurposeRegister, v: u8) {
|
||||||
|
self.registers[r.as_usize()] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, ram: &mut [u8], val: u8) {
|
||||||
|
ram[self.sp as usize] = val;
|
||||||
|
self.sp -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self, ram: &mut [u8]) -> u8 {
|
||||||
|
self.sp += 1;
|
||||||
|
ram[self.sp as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_flags(&mut self, mode: FlagUpdateMode, rd: u8, rr: u8, s: u8) {
|
||||||
|
match mode {
|
||||||
|
FlagUpdateMode::HSVNZC => {
|
||||||
|
// H: Set if there was a borrow from bit 3; cleared otherwise
|
||||||
|
// S: N ⊕ V, For signed tests.
|
||||||
|
// V: Set if two's complement overflow resulted from the operation; cleared otherwise.
|
||||||
|
// N: R7 Set if MSB of the result is set; cleared otherwise.
|
||||||
|
// Z: Set if the result is $00; cleared otherwise.
|
||||||
|
// C: Set if the absolute value of K is larger than the absolute value of Rd; cleared otherwise.
|
||||||
|
// cpu_.sreg_.C = ((~Rd & Rr) | (Rr & R) | (R & ~Rd)) & 0x80;
|
||||||
|
self.set_clear_flag(StatusFlag::Carry, ((!rd & rr) | (rr & s) | (s & !rd)) & 0x80 == 0x80);
|
||||||
|
self.set_clear_flag(StatusFlag::Zero, s == 0);
|
||||||
|
self.set_clear_flag(StatusFlag::Negative, (s & 0x80) == 0x80);
|
||||||
|
self.set_clear_flag(StatusFlag::TwosComplementOverflow, ((rd & !rr & !s) | (!rd & rr & s)) & 0x80 == 0x80);
|
||||||
|
let t = self.test_flag(StatusFlag::Negative) ^ self.test_flag(StatusFlag::TwosComplementOverflow);
|
||||||
|
self.set_clear_flag(StatusFlag::SignBit, t);
|
||||||
|
self.set_clear_flag(StatusFlag::HalfCarry, ((!rd & rr) | (rr & s) | (s & !rd)) & 0x08 == 0x08);
|
||||||
|
//cpu_.sreg_.H = ((~Rd & Rr) | (Rr & R) | (R & ~Rd)) & 0x08;
|
||||||
|
|
||||||
|
// self.set_clear_flag(StatusFlag::Zero, r.wrapping_sub(v) == 0);
|
||||||
|
// self.set_clear_flag(StatusFlag::Carry, v > r);
|
||||||
|
}
|
||||||
|
FlagUpdateMode::HSVNZC_KeepZero => {
|
||||||
|
self.set_clear_flag(StatusFlag::Carry, ((!rd & rr) | (rr & s) | (s & !rd)) & 0x80 == 0x80);
|
||||||
|
let t = self.test_flag(StatusFlag::Zero);
|
||||||
|
self.set_clear_flag(StatusFlag::Zero, s == 0 && t);
|
||||||
|
self.set_clear_flag(StatusFlag::Negative, (s & 0x80) == 0x80);
|
||||||
|
self.set_clear_flag(StatusFlag::TwosComplementOverflow, ((rd & !rr & !s) | (!rd & rr & s)) & 0x80 == 0x80);
|
||||||
|
let t = self.test_flag(StatusFlag::Negative) ^ self.test_flag(StatusFlag::TwosComplementOverflow);
|
||||||
|
self.set_clear_flag(StatusFlag::SignBit, t);
|
||||||
|
self.set_clear_flag(StatusFlag::HalfCarry, ((!rd & rr) | (rr & s) | (s & !rd)) & 0x08 == 0x08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns # of ticks the executed instruction took
|
// Returns # of ticks the executed instruction took
|
||||||
pub fn step(&mut self, rom: &mut [u8], ram: &mut [u8]) -> Result<usize, CPUError> {
|
pub fn step(&mut self, rom: &mut [u8], ram: &mut [u8]) -> Result<usize, CPUError> {
|
||||||
// Instruction fetch
|
// Instruction fetch
|
||||||
@ -56,12 +145,215 @@ impl CPU {
|
|||||||
// Instruction execute
|
// Instruction execute
|
||||||
match ins {
|
match ins {
|
||||||
Instruction::JMP(v) => self.pc = v,
|
Instruction::JMP(v) => self.pc = v,
|
||||||
Instruction::CLR(ref r) => self.registers[r.as_usize()] = 0,
|
Instruction::CLR(ref r) => self.set_register(r, 0),
|
||||||
Instruction::EOR(ref d, ref r) =>
|
Instruction::EOR(ref d, ref r) =>
|
||||||
self.registers[d.as_usize()] ^= self.registers[r.as_usize()],
|
self.registers[d.as_usize()] ^= self.registers[r.as_usize()],
|
||||||
Instruction::LDI(ref r, v) => self.registers[r.as_usize()] = v,
|
Instruction::LDI(ref r, v) => self.set_register(r, v),
|
||||||
Instruction::SER(ref r) => self.registers[r.as_usize()] = 0xFF,
|
Instruction::SER(ref r) => self.set_register(r, 0xFF),
|
||||||
Instruction::RJMP(v) => self.pc = self.pc.wrapping_add(v as _),
|
Instruction::RJMP(v) => self.pc = self.pc.wrapping_add(v as _),
|
||||||
|
Instruction::CLR_FLAG(v) => self.clear_flag(v),
|
||||||
|
Instruction::SET_FLAG(v) => self.set_flag(v),
|
||||||
|
Instruction::CPI(ref r, v) => {
|
||||||
|
let rv = self.get_register(r);
|
||||||
|
self.update_flags(FlagUpdateMode::HSVNZC, rv, v, rv.wrapping_sub(v));
|
||||||
|
},
|
||||||
|
Instruction::CP(ref r, ref i) => {
|
||||||
|
let rv = self.get_register(r);
|
||||||
|
let iv = self.get_register(i);
|
||||||
|
self.update_flags(FlagUpdateMode::HSVNZC, rv, iv, rv.wrapping_sub(iv));
|
||||||
|
},
|
||||||
|
Instruction::CPC(ref rd, ref rr) => {
|
||||||
|
let rd: u8 = self.get_register(rd);
|
||||||
|
let rr: u8 = self.get_register(rr);
|
||||||
|
|
||||||
|
let s = if self.test_flag(StatusFlag::Carry) {
|
||||||
|
rd.wrapping_sub(rr).wrapping_sub(1)
|
||||||
|
} 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;
|
||||||
|
*/},
|
||||||
|
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 {
|
||||||
|
IncrementMode::None => base,
|
||||||
|
IncrementMode::PreDecrement => {
|
||||||
|
self.set_register_pair(ptr, base.wrapping_sub(1));
|
||||||
|
base.wrapping_sub(1)
|
||||||
|
},
|
||||||
|
IncrementMode::PostIncrement => {
|
||||||
|
self.set_register_pair(ptr, base.wrapping_add(1));
|
||||||
|
base
|
||||||
|
},
|
||||||
|
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
||||||
|
};
|
||||||
|
ram[addr as usize] = self.get_register(src_reg);
|
||||||
|
},
|
||||||
|
Instruction::LD(ref ptr, ref dst_reg, ref inc_mode) => {
|
||||||
|
let base = self.get_register_pair(ptr);
|
||||||
|
let addr = match *inc_mode {
|
||||||
|
IncrementMode::None => base,
|
||||||
|
IncrementMode::PreDecrement => {
|
||||||
|
self.set_register_pair(ptr, base.wrapping_sub(1));
|
||||||
|
base.wrapping_sub(1)
|
||||||
|
},
|
||||||
|
IncrementMode::PostIncrement => {
|
||||||
|
self.set_register_pair(ptr, base.wrapping_add(1));
|
||||||
|
base
|
||||||
|
},
|
||||||
|
IncrementMode::ConstantOffset(o) => base.wrapping_add(o as _),
|
||||||
|
};
|
||||||
|
let v = ram[addr as usize];
|
||||||
|
self.set_register(dst_reg, v);
|
||||||
|
},
|
||||||
|
Instruction::ELPM(ref dst_reg, ref inc_mode) => {
|
||||||
|
// TODO: RAMPZ
|
||||||
|
let Z = self.get_register_pair(&30u8.into());
|
||||||
|
let d = rom[Z as usize];
|
||||||
|
self.set_register(dst_reg, d);
|
||||||
|
match *inc_mode {
|
||||||
|
IncrementMode::PostIncrement => {
|
||||||
|
self.set_register_pair(&30u8.into(), Z.wrapping_add(1));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// This instruction does only support PostIncrement
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Instruction::LPM(ref dst_reg, ref inc_mode) => {
|
||||||
|
let Z = self.get_register_pair(&30u8.into());
|
||||||
|
let d = rom[Z as usize];
|
||||||
|
self.set_register(dst_reg, d);
|
||||||
|
match *inc_mode {
|
||||||
|
IncrementMode::PostIncrement => {
|
||||||
|
self.set_register_pair(&30u8.into(), Z.wrapping_add(1));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// This instruction does only support 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)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::CALL(ref addr) => {
|
||||||
|
let ret_to = self.pc + 2;
|
||||||
|
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;
|
||||||
|
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 = (self.pc as i32 + *addr as i32) as u32;
|
||||||
|
},
|
||||||
|
Instruction::RET => {
|
||||||
|
let mut ret_to = self.pop(ram) as u32;
|
||||||
|
ret_to += (self.pop(ram) as u32) << 8;
|
||||||
|
ret_to += (self.pop(ram) as u32) << 16;
|
||||||
|
self.pc = ret_to as _;
|
||||||
|
},
|
||||||
|
Instruction::POP(ref reg) => {
|
||||||
|
let v = self.pop(ram);
|
||||||
|
self.registers[reg.as_usize()] = v;
|
||||||
|
},
|
||||||
|
Instruction::PUSH(ref reg) => {
|
||||||
|
let v = self.registers[reg.as_usize()];
|
||||||
|
self.push(ram, v);
|
||||||
|
},
|
||||||
|
Instruction::SUBI(ref reg, ref v) => {
|
||||||
|
let v = self.registers[reg.as_usize()].wrapping_sub(*v);
|
||||||
|
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
|
||||||
|
self.registers[d.as_usize()] = v;
|
||||||
|
},
|
||||||
|
Instruction::SBCI(ref d, ref r) => {
|
||||||
|
let v = self.registers[d.as_usize()].wrapping_sub(*r);
|
||||||
|
// TODO: - carry
|
||||||
|
self.registers[d.as_usize()] = v;
|
||||||
|
},
|
||||||
|
Instruction::MOVW(ref d, ref r) => {
|
||||||
|
let t = self.get_register_pair(r);
|
||||||
|
self.set_register_pair(d, t);
|
||||||
|
},
|
||||||
|
Instruction::OR(ref d, ref r) => {
|
||||||
|
let t = self.get_register(d) | self.get_register(r);
|
||||||
|
self.set_register(d, t);
|
||||||
|
}
|
||||||
|
Instruction::ORI(ref d, ref v) => {
|
||||||
|
let t = self.get_register(d) | *v;
|
||||||
|
self.set_register(d, t);
|
||||||
|
},
|
||||||
|
Instruction::AND(ref d, ref r) => {
|
||||||
|
let t = self.get_register(d) & self.get_register(r);
|
||||||
|
self.set_register(d, t);
|
||||||
|
}
|
||||||
|
Instruction::ANDI(ref d, ref v) => {
|
||||||
|
let t = self.get_register(d) & *v;
|
||||||
|
self.set_register(d, t);
|
||||||
|
},
|
||||||
|
Instruction::ADD(ref d, ref r) => {
|
||||||
|
let t = self.get_register(d) + self.get_register(r);
|
||||||
|
self.set_register(d, t);
|
||||||
|
},
|
||||||
|
Instruction::SUB(ref d, ref r) => {
|
||||||
|
let t = self.get_register(d) - self.get_register(r);
|
||||||
|
self.set_register(d, t);
|
||||||
|
},
|
||||||
|
Instruction::MOV(ref d, ref r) => {
|
||||||
|
let v = self.get_register(r);
|
||||||
|
self.set_register(d, v);
|
||||||
|
},
|
||||||
|
Instruction::ADIW(ref d, ref v) => {
|
||||||
|
let v = self.get_register_pair(d).wrapping_add(*v);
|
||||||
|
self.set_register_pair(d, v);
|
||||||
|
},
|
||||||
|
Instruction::SBIW(ref d, ref v) => {
|
||||||
|
let v = self.get_register_pair(d).wrapping_sub(*v as _);
|
||||||
|
self.set_register_pair(d, v);
|
||||||
|
}
|
||||||
|
Instruction::NOP => {},
|
||||||
_ => return Err(CPUError::UnimplementedInstruction)
|
_ => return Err(CPUError::UnimplementedInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,7 @@ pub enum Instruction {
|
|||||||
SBI(IORegister, u8),
|
SBI(IORegister, u8),
|
||||||
SBIC(IORegister, u8),
|
SBIC(IORegister, u8),
|
||||||
SBIS(IORegister, u8),
|
SBIS(IORegister, u8),
|
||||||
SBIW(GeneralPurposeRegisterPair, u8),
|
SBIW(GeneralPurposeRegisterPair, u16),
|
||||||
SBR(GeneralPurposeRegister, u8),
|
SBR(GeneralPurposeRegister, u8),
|
||||||
SBRC(GeneralPurposeRegister, u8),
|
SBRC(GeneralPurposeRegister, u8),
|
||||||
SBRS(GeneralPurposeRegister, u8),
|
SBRS(GeneralPurposeRegister, u8),
|
||||||
@ -203,7 +203,7 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
let K = (((v & 0b1100_0000) >> 2) | (v & 0b1111)) as u8;
|
let K = (((v & 0b1100_0000) >> 2) | (v & 0b1111)) as u8;
|
||||||
let d = (v & 0b1111_0000 >> 4) as u8;
|
let d = ((v & 0b1111_0000) >> 4) as u8;
|
||||||
let r = (v & 0b1111) as u8;
|
let r = (v & 0b1111) as u8;
|
||||||
let A = ((v & 0b1111_1000) >> 3) as u16;
|
let A = ((v & 0b1111_1000) >> 3) as u16;
|
||||||
let b = (v & 0b0111) as u8;
|
let b = (v & 0b0111) as u8;
|
||||||
@ -211,7 +211,7 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
0b1001_0110_0000_0000 => return Ok(Instruction::ADIW(((d & 0b11) * 2 + 24).into(), K as u16)),
|
0b1001_0110_0000_0000 => return Ok(Instruction::ADIW(((d & 0b11) * 2 + 24).into(), K as u16)),
|
||||||
0b0000_0001_0000_0000 => return Ok(Instruction::MOVW((d * 2).into(), (r * 2).into())),
|
0b0000_0001_0000_0000 => return Ok(Instruction::MOVW((d * 2).into(), (r * 2).into())),
|
||||||
0b0000_0010_0000_0000 => return Ok(Instruction::MULS((d + 16).into(), (r + 16).into())),
|
0b0000_0010_0000_0000 => return Ok(Instruction::MULS((d + 16).into(), (r + 16).into())),
|
||||||
0b1001_0111_0000_0000 => return Ok(Instruction::SBIW(((d & 0b11) * 2 + 24).into(), K)),
|
0b1001_0111_0000_0000 => return Ok(Instruction::SBIW(((d & 0b11) * 2 + 24).into(), K as u16)),
|
||||||
0b1110_1111_0000_0000 => return Ok(Instruction::SER((d + 16).into())),
|
0b1110_1111_0000_0000 => return Ok(Instruction::SER((d + 16).into())),
|
||||||
0b1001_1010_0000_0000 => return Ok(Instruction::SBI(A, b)),
|
0b1001_1010_0000_0000 => return Ok(Instruction::SBI(A, b)),
|
||||||
0b1001_1011_0000_0000 => return Ok(Instruction::SBIS(A, b)),
|
0b1001_1011_0000_0000 => return Ok(Instruction::SBIS(A, b)),
|
||||||
@ -436,8 +436,8 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
let flag_should_be_set = ((v >> 10) & 1) == 1;
|
let flag_should_be_set = ((v >> 10) & 1) == 1;
|
||||||
let flag = StatusFlag::try_from_idx((v & 0b111) as u8).unwrap();
|
let flag = StatusFlag::try_from_idx((v & 0b111) as u8).unwrap();
|
||||||
let mut k = (v >> 3) as i8;
|
let mut k = (v >> 3) as i8;
|
||||||
k = if k > (1 << 7) {
|
k = if k > (1 << 6) {
|
||||||
(1 << 7) - k
|
(k as i16 - 1 << 8) as i8
|
||||||
} else {
|
} else {
|
||||||
k
|
k
|
||||||
};
|
};
|
||||||
@ -468,7 +468,7 @@ pub fn decode(data: &[u8]) -> Result<Instruction, DecodingError> {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Rcall/jmp: 1101 kkkk kkkk kkkk
|
// Rcall/jmp: 1101 kkkk kkkk kkkk
|
||||||
// SBR 0110 KKKK dddd KKKK <- seems invalid!!!
|
// SBR 0110 KKKK dddd KKKK
|
||||||
// ORI: 0110 KKKK dddd KKKK
|
// ORI: 0110 KKKK dddd KKKK
|
||||||
// ANDI 0111 KKKK dddd KKKK
|
// ANDI 0111 KKKK dddd KKKK
|
||||||
// CPI 0011 KKKK dddd KKKK
|
// CPI 0011 KKKK dddd KKKK
|
||||||
|
|||||||
25
src/main.rs
25
src/main.rs
@ -1,22 +1,31 @@
|
|||||||
|
#![allow(non_snake_case)]
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Read;
|
use std::io::{Read, Write};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
mod cpu;
|
mod cpu;
|
||||||
mod regs;
|
mod regs;
|
||||||
mod decoder;
|
mod decoder;
|
||||||
|
mod chip;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
let mut rom = read_file("rom.bin").unwrap();
|
let mut rom = read_file("rom.bin").unwrap();
|
||||||
let mut ram = [0u8; 1024];
|
let mut ram = [0u8; 8 * 1024 + 8 * 1024];
|
||||||
let mut cpu = cpu::CPU::new();
|
let mut cpu = cpu::CPU::new();
|
||||||
for _ in 0..40 {
|
for _ in 0..28000 {
|
||||||
println!("{:?}", cpu.step(&mut rom, &mut ram));
|
let r = cpu.step(&mut rom, &mut ram);
|
||||||
|
println!("{:?}", r);
|
||||||
|
match r {
|
||||||
|
Err(cpu::CPUError::OutOfBoundsException) => break,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
println!("{:#?}", cpu);
|
println!("{:#?}", cpu);
|
||||||
|
|
||||||
|
write_file("/tmp/endstate.ram", &ram).unwrap();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
let mut off = 0;
|
let mut off = 0;
|
||||||
while off < data.len() {
|
while off < data.len() {
|
||||||
@ -35,4 +44,10 @@ pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, io::Error> {
|
|||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
try!(file.read_to_end(&mut buf));
|
try!(file.read_to_end(&mut buf));
|
||||||
Ok(buf.into_boxed_slice())
|
Ok(buf.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_file<P: AsRef<Path>>(path: P, data: &[u8]) -> Result<(), io::Error> {
|
||||||
|
let mut file = try!(fs::File::create(path));
|
||||||
|
try!(file.write_all(&data));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@ -133,12 +133,12 @@ impl PartialEq for GeneralPurposeRegisterPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GeneralPurposeRegisterPair {
|
impl GeneralPurposeRegisterPair {
|
||||||
fn first(&self) -> u8 {
|
pub fn low(&self) -> usize {
|
||||||
self.0
|
self.0 as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn second(&self) -> u8 {
|
pub fn high(&self) -> usize {
|
||||||
self.0 + 1
|
self.0 as usize + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user