use crate::preamble::*;
use crate::z80::*;
impl Z80 {
pub fn execute(&mut self, opcode: &Token) -> usize {
let pc = self.pc().value() as i32;
self.context
.symbols_mut()
.set_symbol_to_value("$", pc)
.unwrap();
match opcode {
Token::OpCode(ref mnemonic, ref arg1, ref arg2, ref arg3) => {
self.execute_opcode(*mnemonic, arg1.as_ref(), arg2.as_ref(), arg3.as_ref())
}
Token::Defs(_) | Token::Defb(_) | Token::Defw(_) => {
let lst = opcode.disassemble_data().unwrap();
lst.listing().iter().map(|token| self.execute(token)).sum()
}
_ => panic!("{:?} is not yet handled", opcode)
}
}
fn execute_opcode(
&mut self,
mnemonic: Mnemonic,
arg1: Option<&DataAccess>,
arg2: Option<&DataAccess>,
arg3: Option<&cpclib_asm::preamble::Register8>
) -> usize {
let opcode = Token::OpCode(mnemonic, arg1.cloned(), arg2.cloned(), arg3.cloned());
let count = opcode
.number_of_bytes_with_context(self.context.env.symbols_mut())
.unwrap() as _;
self.pc_mut().add(count);
let mut duration = opcode.estimated_duration().unwrap();
let mut inc_duration = || {
duration += 1;
};
match mnemonic {
Mnemonic::Add => {
match (arg1, arg2) {
(Some(&DataAccess::Register8(tokens::Register8::A)), Some(_)) => {
let val = self.get_value(arg1.unwrap()).unwrap();
self.get_register_8_mut(arg1.unwrap()).add(val as _);
}
(Some(&DataAccess::Register16(tokens::Register16::Hl)), Some(_)) => {
let val = self.get_value(arg2.unwrap()).unwrap();
if mnemonic == Mnemonic::Add {
self.get_register_16_mut(arg1.unwrap()).add(val);
}
else {
self.get_register_16_mut(arg1.unwrap()).sub(val);
}
}
_ => panic!("Untreated case {} {:?} {:?}", mnemonic, arg1, arg2)
}
}
Mnemonic::Sub => {
match (arg1, arg2) {
(Some(_), None) => {
let val = self.get_value(arg1.unwrap()).unwrap();
self.a_mut().sub(val as _);
}
_ => unimplemented!()
}
}
Mnemonic::And => {
let val = self.get_value(arg1.unwrap()).unwrap() as _;
self.get_register_8_mut(&tokens::Register8::A.into())
.and(val);
}
Mnemonic::Res => {
let bit = self.get_value(arg1.unwrap()).unwrap() as _;
self.get_register_8_mut(arg2.unwrap()).res_bit(bit)
}
Mnemonic::Set => {
let bit = self.get_value(arg1.unwrap()).unwrap() as _;
self.get_register_8_mut(arg2.unwrap()).set_bit(bit)
}
Mnemonic::Ret => self.ret(),
Mnemonic::Pop => {
let word = self.read_memory_word(self.sp().value());
self.bc_mut().set(word);
self.sp_mut().add(2);
}
Mnemonic::Ldi => {
let byte = self.read_memory_byte(self.hl().value());
self.write_memory_byte(self.de().value(), byte);
self.bc_mut().inc();
self.de_mut().inc();
self.hl_mut().inc();
}
Mnemonic::ExHlDe => self.ex_de_hl(),
Mnemonic::Inc => {
match arg1 {
Some(&DataAccess::Register8(ref _reg)) => {
self.get_register_8_mut(arg1.unwrap()).inc()
}
Some(&DataAccess::Register16(ref _reg)) => {
self.get_register_16_mut(arg1.unwrap()).inc()
}
_ => unreachable!()
}
}
Mnemonic::Dec => {
match arg1 {
Some(&DataAccess::Register8(ref _reg)) => {
self.get_register_8_mut(arg1.unwrap()).dec()
}
Some(&DataAccess::Register16(ref _reg)) => {
self.get_register_16_mut(arg1.unwrap()).dec()
}
_ => unreachable!()
}
}
Mnemonic::Djnz => {
self.b_mut().dec();
if self.b().value() != 0 {
inc_duration();
let delta = match arg1 {
Some(&DataAccess::Expression(Expr::Label(_))) => {
self.get_value(arg1.unwrap()).unwrap() as i32
- self
.get_value(&DataAccess::Expression(Expr::Label("$".into())))
.unwrap() as i32
- 2
}
_ => self.get_value(arg2.unwrap()).unwrap() as i32
};
if delta > 0 {
self.pc_mut().add(delta as _);
}
else if delta < 0 {
self.pc_mut().sub(-delta as _);
}
else {
self.pc_mut().sub(opcode.number_of_bytes().unwrap() as _);
}
}
}
Mnemonic::Jr => {
dbg!(arg2);
let delta = match arg2 {
Some(&DataAccess::Expression(Expr::Label(_))) => {
self.get_value(arg2.unwrap()).unwrap() as i32
- self
.get_value(&DataAccess::Expression(Expr::Label("$".into())))
.unwrap() as i32
- 2
}
_ => self.get_value(arg2.unwrap()).unwrap() as i32
};
if match arg1 {
None => true,
Some(DataAccess::FlagTest(ref flag)) => self.is_flag_active(flag),
_ => unreachable!()
} {
inc_duration();
if delta > 0 {
self.pc_mut().add(delta as _);
}
else if delta < 0 {
self.pc_mut().sub(-delta as _);
}
else if delta == 0 {
self.pc_mut().sub(opcode.number_of_bytes().unwrap() as _);
}
}
}
Mnemonic::Jp => {
match (arg1, arg2) {
(None, Some(_)) => {
let value = self.get_value(arg2.unwrap()).unwrap();
self.pc_mut().set(value);
}
(Some(DataAccess::FlagTest(ref flag)), _) => {
if self.is_flag_active(flag) {
let value = self.get_value(arg2.unwrap()).unwrap();
self.pc_mut().set(value);
inc_duration();
}
else {
self.pc_mut().sub(opcode.number_of_bytes().unwrap() as _);
}
}
_ => unreachable!()
}
}
Mnemonic::Ld => {
match (arg1, arg2) {
(Some(&DataAccess::Register8(_)), Some(_)) => {
let val = self
.get_value(arg2.unwrap())
.unwrap_or_else(|| panic!("Unable to get value of {:?}", &arg2));
self.get_register_8_mut(arg1.unwrap()).set(val as u8);
}
(Some(&DataAccess::Register16(ref _reg16)), Some(_)) => {
let val = self.get_value(arg2.unwrap()).unwrap();
self.get_register_16_mut(arg1.unwrap()).set(val);
}
(Some(&DataAccess::MemoryRegister16(ref _reg)), Some(_)) => {
let address = self.get_value(arg1.unwrap()).unwrap();
let value = self.get_value(arg2.unwrap()).unwrap();
self.write_memory_byte(address, value as _);
}
_ => panic!("Untreated case {} {:?} {:?}", mnemonic, arg1, arg2)
}
}
Mnemonic::Nop => {
}
_ => panic!("Untreated case {} {:?} {:?}", mnemonic, arg1, arg2)
}
duration
}
fn write_memory_byte(&self, _addr: u16, _val: u8) {
eprintln!("[ERROR] Memory byte not written");
}
fn read_memory_byte(&self, _addr: u16) -> u8 {
eprintln!("[ERROR] Memory byte not read");
u8::default()
}
fn read_memory_word(&self, addr: u16) -> u16 {
let low = self.read_memory_byte(addr);
let high = self.read_memory_byte(addr + 1); u16::from(low) + u16::from(high) * 256
}
fn get_value(&self, access: &DataAccess) -> Option<u16> {
match access {
DataAccess::Memory(ref exp) => {
self.eval_expr(exp)
.map(|address| u16::from(self.read_memory_byte(address)))
}
DataAccess::IndexRegister16WithIndex(..) => None,
DataAccess::IndexRegister16(_) | &DataAccess::Register16(_) => {
Some(self.get_register_16(access).value())
}
DataAccess::IndexRegister8(_) | &DataAccess::Register8(_) => {
Some(self.get_register_8(access).value().into())
}
DataAccess::MemoryRegister16(ref reg) => {
Some(u16::from(self.read_memory_byte(
self.get_register_16(&DataAccess::Register16(*reg)).value()
)))
}
DataAccess::Expression(ref expr) => self.eval_expr(expr),
DataAccess::FlagTest(_) => panic!(),
_ => unimplemented!()
}
}
fn is_flag_active(&self, flag: &FlagTest) -> bool {
flag.flag_is_active(self.f().value())
}
fn get_register_16(&self, reg: &DataAccess) -> &crate::z80::Register16 {
match reg {
DataAccess::IndexRegister16(ref reg) => {
match reg {
IndexRegister16::Ix => self.ix(),
IndexRegister16::Iy => self.iy()
}
}
DataAccess::Register16(ref reg) => {
match reg {
tokens::Register16::Af => self.af(),
tokens::Register16::Bc => self.bc(),
tokens::Register16::De => self.de(),
tokens::Register16::Hl => self.hl(),
tokens::Register16::Sp => self.sp()
}
}
_ => unreachable!()
}
}
fn get_register_16_mut(&mut self, reg: &DataAccess) -> &mut crate::z80::Register16 {
match reg {
DataAccess::IndexRegister16(ref reg) => {
match reg {
IndexRegister16::Ix => self.ix_mut(),
IndexRegister16::Iy => self.iy_mut()
}
}
DataAccess::Register16(ref reg) => {
match reg {
tokens::Register16::Af => self.af_mut(),
tokens::Register16::Bc => self.bc_mut(),
tokens::Register16::De => self.de_mut(),
tokens::Register16::Hl => self.hl_mut(),
tokens::Register16::Sp => self.sp_mut()
}
}
_ => unreachable!()
}
}
fn get_register_8(&self, reg: &DataAccess) -> &crate::z80::Register8 {
match reg {
DataAccess::Register8(ref reg) => {
match reg {
tokens::Register8::A => self.a(),
tokens::Register8::B => self.b(),
tokens::Register8::D => self.d(),
tokens::Register8::H => self.h(),
tokens::Register8::C => self.c(),
tokens::Register8::E => self.e(),
tokens::Register8::L => self.l()
}
}
DataAccess::IndexRegister8(ref reg) => {
match reg {
IndexRegister8::Ixl => self.ixl(),
IndexRegister8::Ixh => self.ixh(),
IndexRegister8::Iyl => self.iyl(),
IndexRegister8::Iyh => self.iyh()
}
}
_ => panic!()
}
}
fn get_register_8_mut(&mut self, reg: &DataAccess) -> &mut crate::z80::Register8 {
match reg {
DataAccess::Register8(ref reg) => {
match reg {
tokens::Register8::A => self.a_mut(),
tokens::Register8::B => self.b_mut(),
tokens::Register8::D => self.d_mut(),
tokens::Register8::H => self.h_mut(),
tokens::Register8::C => self.c_mut(),
tokens::Register8::E => self.e_mut(),
tokens::Register8::L => self.l_mut()
}
}
DataAccess::IndexRegister8(ref reg) => {
match reg {
IndexRegister8::Ixl => self.ixl_mut(),
IndexRegister8::Ixh => self.ixh_mut(),
IndexRegister8::Iyl => self.iyl_mut(),
IndexRegister8::Iyh => self.iyh_mut()
}
}
_ => panic!()
}
}
#[allow(clippy::cast_sign_loss)]
fn eval_expr(&self, expr: &Expr) -> Option<u16> {
match expr.resolve(&self.context.env) {
Ok(val) => Some(val.abs().unwrap().int().unwrap() as u16),
Err(_) => None
}
}
pub fn setup_symbol_table(&mut self, symbols: &SymbolsTableCaseDependent) {
*self.context.env.symbols_mut() = symbols.clone()
}
pub fn ret(&mut self) {
let address = self.read_memory_word(self.sp().value());
self.sp_mut().add(2);
self.pc_mut().set(address);
}
}
pub trait FlagIsActive {
fn flag_is_active(self, f_value: u8) -> bool;
}
impl FlagIsActive for &FlagTest {
fn flag_is_active(self, f_value: u8) -> bool {
(match self {
FlagTest::C => f_value & (1 << FlagPos::Carry as u8),
FlagTest::NC => !(f_value & (1 << FlagPos::Carry as u8)),
FlagTest::Z => f_value & (1 << FlagPos::Zero as u8),
FlagTest::NZ => !(f_value & (1 << FlagPos::Zero as u8)),
FlagTest::PO => f_value & (1 << FlagPos::Parity as u8),
FlagTest::PE => !(f_value & (1 << FlagPos::Parity as u8)),
FlagTest::P => f_value & (1 << FlagPos::Sign as u8),
FlagTest::M => !(f_value & (1 << FlagPos::Sign as u8))
}) != 0
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_flags() {
assert!(FlagTest::Z.flag_is_active(0b01000000));
assert!(FlagTest::NZ.flag_is_active(0b00000000));
}
#[test]
fn jp_value() {
let mut z80 = Z80::default();
z80.pc_mut().set(0x4000);
assert_eq!(z80.pc().value(), 0x4000);
z80.execute(&Token::OpCode(
Mnemonic::Jp,
None,
Some(DataAccess::Expression(Expr::Value(0x4000))),
None
));
assert_eq!(z80.pc().value(), 0x4000);
}
#[test]
fn jp_symbol() {
let mut z80 = Z80::default();
let mut symbols = SymbolsTableCaseDependent::default();
symbols.set_symbol_to_value("LABEL", 0x4000u16);
z80.setup_symbol_table(&symbols);
z80.pc_mut().set(0x4000);
assert_eq!(z80.pc().value(), 0x4000);
z80.execute(&Token::OpCode(
Mnemonic::Jp,
None,
Some(DataAccess::Expression(Expr::Label("LABEL".into()))),
None
));
assert_eq!(z80.pc().value(), 0x4000);
}
#[test]
fn jp_dollar() {
let mut z80 = Z80::default();
z80.pc_mut().set(0x4000);
assert_eq!(z80.pc().value(), 0x4000);
z80.execute(&Token::OpCode(
Mnemonic::Jp,
None,
Some(DataAccess::Expression(Expr::Label("$".into()))),
None
));
assert_eq!(z80.pc().value(), 0x4000);
}
#[test]
fn jr_dollar() {
let mut z80 = Z80::default();
z80.pc_mut().set(0x4000);
assert_eq!(z80.pc().value(), 0x4000);
z80.execute(&Token::OpCode(
Mnemonic::Jr,
None,
Some(DataAccess::Expression(Expr::Label("$".into()))),
None
));
assert_eq!(z80.pc().value(), 0x4000);
}
}