#![allow(dead_code)]
use std::{cell::RefCell, rc::Rc};
use crate::libs::{memory::Memory, ports::Ports};
use super::{
hook::FuncHook,
util::{join_bytes, sign_extend, split_word, tern_op_b},
z80_base::{Register16, Z80Data},
z80_tables::{
self, HALF_CARRY_ADD_TABLE, HALF_CARRY_SUB_TABLE, OVERFLOW_ADD_TABLE, OVERFLOW_SUB_TABLE,
},
};
pub const FLAG_C: u8 = 0x01;
pub const FLAG_N: u8 = 0x02;
pub const FLAG_P: u8 = 0x04;
pub const FLAG_V: u8 = FLAG_P;
pub const FLAG_3: u8 = 0x08;
pub const FLAG_H: u8 = 0x10;
pub const FLAG_5: u8 = 0x20;
pub const FLAG_Z: u8 = 0x40;
pub const FLAG_S: u8 = 0x80;
pub(crate) fn jp(data: &mut Z80Data, memory: &mut Memory) {
let mut jp_temp: u16 = data.pc;
let pcl = memory.read_byte(jp_temp);
jp_temp += 1;
let pch = memory.read_byte(jp_temp);
data.pc = join_bytes(pch, pcl);
}
pub(crate) fn dec(data: &mut Z80Data, value: &mut u8) {
data.F = data.F & FLAG_C | tern_op_b((*value & 0x0f) != 0, 0, FLAG_H) | FLAG_N;
*value = (*value).wrapping_sub(1);
data.F |= tern_op_b(*value == 0x7f, FLAG_V, 0) | z80_tables::get().sz53_table[*value as usize];
}
pub(crate) fn inc(data: &mut Z80Data, value: &mut u8) {
*value = (*value).wrapping_add(1);
data.F = (data.F & FLAG_C)
| tern_op_b(*value == 0x80, FLAG_V, 0)
| tern_op_b((*value & 0x0f) != 0, 0, FLAG_H)
| z80_tables::get().sz53_table[*value as usize];
}
pub(crate) fn jr(data: &mut Z80Data, memory: &mut Memory) {
let jr_temp: i16 = sign_extend(memory.read_byte(data.pc));
memory.contend_read_no_mreq_loop(data.pc, 1, 5);
data.pc = data.pc.wrapping_add(jr_temp as u16);
}
pub(crate) fn ld16nnrr(data: &mut Z80Data, memory: &mut Memory, reg_l: u8, reg_h: u8) {
let mut ld_temp: u16;
ld_temp = memory.read_byte(data.pc) as u16;
data.pc += 1;
ld_temp |= (memory.read_byte(data.pc) as u16) << 8;
data.pc += 1;
memory.write_byte(ld_temp, reg_l);
ld_temp += 1;
memory.write_byte(ld_temp, reg_h);
}
pub(crate) fn ld16rrnn_ex(data: &mut Z80Data, memory: &mut Memory) -> (u8, u8) {
let mut ld_temp: u16;
ld_temp = memory.read_byte(data.pc) as u16;
data.pc += 1;
ld_temp |= (memory.read_byte(data.pc) as u16) << 8;
data.pc += 1;
let reg_l = memory.read_byte(ld_temp);
ld_temp += 1;
let reg_h = memory.read_byte(ld_temp);
(reg_l, reg_h)
}
pub fn sub(data: &mut Z80Data, value: u8) {
let sub_temp: u16 = (data.A as u16).wrapping_sub(value as u16);
let lookup: u8 =
((data.A & 0x88) >> 3) | ((value & 0x88) >> 2) | (((sub_temp & 0x88) >> 1) as u8);
data.A = sub_temp as u8;
data.F = tern_op_b(sub_temp & 0x100 != 0, FLAG_C, 0)
| FLAG_N
| HALF_CARRY_SUB_TABLE[(lookup & 0x07) as usize]
| OVERFLOW_SUB_TABLE[(lookup >> 4) as usize]
| z80_tables::get().sz53_table[data.A as usize];
}
pub fn and(data: &mut Z80Data, value: u8) {
data.A &= value;
data.F = FLAG_H | z80_tables::get().sz53p_table[data.A as usize];
}
pub fn adc(data: &mut Z80Data, value: u8) {
let adc_temp: u16 = (data.A as u16) + (value as u16) + (((data.F) & FLAG_C) as u16);
let lookup: u8 = (((data.A as u16) & 0x88) >> 3
| ((value as u16) & 0x88) >> 2
| (adc_temp & 0x88) >> 1) as u8;
data.A = adc_temp as u8;
data.F = tern_op_b((adc_temp & 0x100) != 0, FLAG_C, 0)
| HALF_CARRY_ADD_TABLE[(lookup & 0x07) as usize]
| OVERFLOW_ADD_TABLE[(lookup >> 4) as usize]
| z80_tables::get().sz53_table[data.A as usize];
}
pub(crate) fn adc16(data: &mut Z80Data, value: u16) {
let add16_temp: usize = (data.hl() as usize) + (value as usize) + ((data.F & FLAG_C) as usize);
let lookup: u8 = ((((data.hl()) & 0x8800) >> 11) as usize
| (((value) & 0x8800) >> 10) as usize
| (add16_temp & 0x8800) >> 9) as u8;
data.set_hl(add16_temp as u16);
data.F = tern_op_b((add16_temp & 0x10000) != 0, FLAG_C, 0)
| OVERFLOW_ADD_TABLE[(lookup >> 4) as usize]
| data.H & (FLAG_3 | FLAG_5 | FLAG_S)
| HALF_CARRY_ADD_TABLE[(lookup & 0x07) as usize]
| tern_op_b(data.hl() != 0, 0, FLAG_Z);
}
pub(crate) fn add16(data: &mut Z80Data, value1: &mut Register16, value2: u16) {
let add16_temp: usize = (value1.get() as usize) + (value2 as usize);
let lookup: u8 = ((value1.get() & 0x0800) >> 11
| (value2 & 0x0800) >> 10
| ((add16_temp as u16) & 0x0800) >> 9) as u8;
value1.set(add16_temp as u16);
data.F = data.F & (FLAG_V | FLAG_Z | FLAG_S)
| tern_op_b((add16_temp & 0x10000) != 0, FLAG_C, 0)
| ((add16_temp >> 8) as u8) & (FLAG_3 | FLAG_5)
| HALF_CARRY_ADD_TABLE[lookup as usize];
}
pub fn add(data: &mut Z80Data, value: u8) {
let add_temp: usize = (data.A as usize) + (value as usize);
let lookup: u8 =
((data.A & 0x88) >> 3) | ((value & 0x88) >> 2) | (((add_temp & 0x88) >> 1) as u8);
data.A = add_temp as u8;
data.F = tern_op_b(add_temp & 0x100 != 0, FLAG_C, 0)
| HALF_CARRY_ADD_TABLE[(lookup & 0x07) as usize]
| OVERFLOW_ADD_TABLE[(lookup >> 4) as usize]
| z80_tables::get().sz53_table[data.A as usize];
}
pub fn or(data: &mut Z80Data, value: u8) {
data.A |= value;
data.F = z80_tables::get().sz53p_table[data.A as usize];
}
pub fn pop16(data: &mut Z80Data, memory: &mut Memory) -> (u8, u8) {
let reg_l = memory.read_byte(data.sp);
data.sp += 1;
let reg_h = memory.read_byte(data.sp);
data.sp += 1;
(reg_l, reg_h)
}
pub fn push16(data: &mut Z80Data, memory: &mut Memory, reg_l: u8, reg_h: u8) {
data.sp = data.sp.wrapping_sub(1);
memory.write_byte(data.sp, reg_h);
data.sp = data.sp.wrapping_sub(1);
memory.write_byte(data.sp, reg_l);
}
pub(crate) fn ret(data: &mut Z80Data, memory: &mut Memory, hook: Rc<RefCell<dyn FuncHook>>) {
hook.borrow_mut().handle_ret_hook(data, memory, data.pc);
let (pcl, pch) = pop16(data, memory);
data.pc = join_bytes(pch, pcl);
}
pub(crate) fn rl(data: &mut Z80Data, mut value: u8) -> u8 {
let rl_temp = value;
value = (value << 1) | (data.F & FLAG_C);
data.F = (rl_temp >> 7) | z80_tables::get().sz53p_table[value as usize];
value
}
pub(crate) fn rlc(data: &mut Z80Data, mut value: u8) -> u8 {
value = value.rotate_left(1);
data.F = (value & FLAG_C) | z80_tables::get().sz53p_table[value as usize];
value
}
pub(crate) fn rr(data: &mut Z80Data, mut value: u8) -> u8 {
let rr_temp = value;
value = (value >> 1) | (data.F << 7);
data.F = (rr_temp & FLAG_C) | z80_tables::get().sz53p_table[value as usize];
value
}
pub(crate) fn rrc(data: &mut Z80Data, mut value: u8) -> u8 {
data.F = value & FLAG_C;
value = value.rotate_right(1);
data.F |= z80_tables::get().sz53p_table[value as usize];
value
}
pub(crate) fn rst(data: &mut Z80Data, memory: &mut Memory, value: u8) {
let (pch, pcl) = split_word(data.pc);
push16(data, memory, pcl, pch);
data.pc = value as u16;
}
pub fn sbc(data: &mut Z80Data, value: u8) {
let sbc_temp: u16 = (data.A as u16)
.wrapping_sub(value as u16)
.wrapping_sub((data.F & FLAG_C) as u16);
let lookup: u8 =
((data.A & 0x88) >> 3) | ((value & 0x88) >> 2) | ((sbc_temp & 0x88) >> 1) as u8;
data.A = sbc_temp as u8;
data.F = tern_op_b((sbc_temp & 0x100) != 0, FLAG_C, 0)
| FLAG_N
| HALF_CARRY_SUB_TABLE[lookup as usize & 0x07]
| OVERFLOW_SUB_TABLE[(lookup >> 4) as usize]
| z80_tables::get().sz53_table[data.A as usize];
}
pub(crate) fn sbc16(data: &mut Z80Data, value: u16) {
let sub16_temp: usize = (data.hl() as usize)
.wrapping_sub(value as usize)
.wrapping_sub((data.F & FLAG_C) as usize);
let lookup: u8 =
((data.hl() & 0x8800) >> 11 | (value & 0x8800) >> 10 | ((sub16_temp as u16) & 0x8800) >> 9)
.try_into()
.unwrap();
data.set_hl(sub16_temp as u16);
data.F = tern_op_b((sub16_temp & 0x10000) != 0, FLAG_C, 0)
| FLAG_N
| OVERFLOW_SUB_TABLE[lookup as usize >> 4]
| data.H & (FLAG_3 | FLAG_5 | FLAG_S)
| HALF_CARRY_SUB_TABLE[(lookup & 0x07) as usize]
| tern_op_b(data.hl() != 0, 0, FLAG_Z);
}
pub(crate) fn sla(data: &mut Z80Data, mut value: u8) -> u8 {
data.F = value >> 7;
value <<= 1;
data.F |= z80_tables::get().sz53p_table[value as usize];
value
}
pub(crate) fn sll(data: &mut Z80Data, mut value: u8) -> u8 {
data.F = value >> 7;
value = (value << 1) | 0x01;
data.F |= z80_tables::get().sz53p_table[value as usize];
value
}
pub(crate) fn sra(data: &mut Z80Data, mut value: u8) -> u8 {
data.F = value & FLAG_C;
value = (value & 0x80) | (value >> 1);
data.F |= z80_tables::get().sz53p_table[value as usize];
value
}
pub(crate) fn srl(data: &mut Z80Data, mut value: u8) -> u8 {
data.F = value & FLAG_C;
value >>= 1;
data.F |= z80_tables::get().sz53p_table[value as usize];
value
}
pub fn xor(data: &mut Z80Data, value: u8) {
data.A ^= value;
data.F = z80_tables::get().sz53p_table[data.A as usize];
}
pub(crate) fn bit(data: &mut Z80Data, bit: u8, value: u8) {
data.F = data.F & FLAG_C | FLAG_H | value & (FLAG_3 | FLAG_5);
if value & (0x01 << bit) == 0 {
data.F |= FLAG_P | FLAG_Z;
}
if bit == 7 && (value & 0x80) != 0 {
data.F |= FLAG_S;
}
}
pub(crate) fn biti(data: &mut Z80Data, bit: u8, value: u8, address: u16) {
data.F = data.F & FLAG_C | FLAG_H | (address >> 8) as u8 & (FLAG_3 | FLAG_5);
if value & (0x01 << bit) == 0 {
data.F |= FLAG_P | FLAG_Z;
}
if (bit == 7) && (value & 0x80) != 0 {
data.F |= FLAG_S;
}
}
pub(crate) fn jp_hl(
data: &mut Z80Data,
memory: &mut Memory,
ports: &mut Ports,
hook: Rc<RefCell<dyn FuncHook>>,
) {
let jmp_tgt = data.hl();
let bail_out = {
hook.borrow_mut()
.handle_jp_hl_hook(data, memory, ports, jmp_tgt)
.is_break()
};
if bail_out {
ret(data, memory, hook);
return;
}
data.set_pc(jmp_tgt);
}
pub(crate) fn call(
data: &mut Z80Data,
memory: &mut Memory,
ports: &mut Ports,
hook: Rc<RefCell<dyn FuncHook>>,
) {
let call_temp_l: u8 = memory.read_byte(data.pc);
data.pc += 1;
let call_temp_h: u8 = memory.read_byte(data.pc);
let new_pc = join_bytes(call_temp_h, call_temp_l);
memory.contend_read_no_mreq(data.pc, 1);
data.pc += 1;
let (pch, pcl) = split_word(data.pc);
push16(data, memory, pcl, pch);
let old_pc = data.pc;
let bail_out = {
hook.borrow_mut()
.handle_call_hook(data, memory, ports, new_pc, old_pc)
.is_break()
};
if bail_out {
ret(data, memory, hook);
return;
}
data.pc = new_pc;
}
pub fn cp(data: &mut Z80Data, value: u8) {
let cp_temp: u16 = (data.A as u16).wrapping_sub(value as u16);
let lookup: u8 = (data.A & 0x88) >> 3 | (value & 0x88) >> 2 | ((cp_temp & 0x88) >> 1) as u8;
data.F = tern_op_b(
(cp_temp & 0x100) != 0,
FLAG_C,
tern_op_b(cp_temp != 0, 0, FLAG_Z),
) | FLAG_N
| HALF_CARRY_SUB_TABLE[(lookup & 0x07) as usize]
| OVERFLOW_SUB_TABLE[(lookup >> 4) as usize]
| value & (FLAG_3 | FLAG_5)
| (cp_temp as u8 & FLAG_S);
}
pub(crate) fn in_u8_ex(data: &mut Z80Data, ports: &Ports, port: u16) -> u8 {
let reg = ports.read_port(port);
data.F = data.F & FLAG_C | z80_tables::get().sz53p_table[reg as usize];
reg
}
pub(crate) fn slt_trap(
_data: &mut Z80Data,
_memory: &mut Memory,
_address: i16,
_level: u8,
) -> isize {
0
}
pub fn is_zf(data: &mut Z80Data) -> bool {
(data.F & FLAG_Z) != 0
}
pub fn is_nz(data: &mut Z80Data) -> bool {
(data.F & FLAG_Z) == 0
}
pub fn is_cf(data: &mut Z80Data) -> bool {
(data.F & FLAG_C) != 0
}
pub fn is_nc(data: &mut Z80Data) -> bool {
(data.F & FLAG_C) == 0
}
pub fn is_sf(data: &mut Z80Data) -> bool {
(data.F & FLAG_S) != 0
}
pub fn increase_cycles(data: &mut Z80Data, n: u64) {
data.cycles += n;
}