use quote::quote;
use feo3boy_microcode_generator::define_microcode;
use crate::gbz80types::Flags;
use crate::microcode::args::{Reg16, Reg8};
pub mod args;
pub mod combocodes;
impl ValType {
pub fn bytes(self) -> usize {
match self {
ValType::U8 | ValType::Bool | ValType::Flags => 1,
ValType::U16 => 2,
}
}
}
impl Microcode {
pub fn is_terminal(self) -> bool {
matches!(
self,
Microcode::FetchNextInstruction | Microcode::ParseOpcode | Microcode::ParseCBOpcode
)
}
}
#[define_microcode(Microcode)]
pub mod defs {
use crate::gbz80types::Flags;
allowed_types! {
name = ValType,
types = [
u8 => U8,
bool => Bool,
u16 => U16,
Flags => Flags,
],
}
#[microcode_extern(Yield)]
pub fn r#yield() {}
#[microcode_extern(ReadReg)]
pub fn read_reg(
#[field]
reg: Reg8,
) -> u8 {
}
#[microcode_extern(WriteReg)]
pub fn write_reg(
#[field]
reg: Reg8,
val: u8,
) {
}
#[microcode_extern(ReadReg16)]
pub fn read_reg(
#[field]
reg: Reg16,
) -> u16 {
}
#[microcode_extern(WriteReg16)]
pub fn write_reg(
#[field]
reg: Reg16,
val: u16,
) {
}
#[microcode_extern(ReadMem)]
pub fn read_mem(addr: u16) -> u8 {}
#[microcode_extern(WriteMem)]
pub fn write_mem(addr: u16, val: u8) {}
#[microcode_extern(GetFlagsMasked)]
pub fn get_flags_masked(#[field] mask: Flags) -> Flags {}
#[microcode_extern(SetFlagsMasked)]
pub fn set_flags_masked(#[field] mask: Flags, flags: Flags) {}
#[microcode(Append)]
#[inline]
pub fn append(
#[field]
val: u8,
) -> u8 {
val
}
#[microcode(Dup16)]
#[inline]
pub fn dup(v: u16) -> (u16, u16) {
(v, v)
}
#[microcode(Discard8)]
#[inline]
pub fn discard8(_: u8) {}
#[microcode(Discard16)]
#[inline]
pub fn discard16(_: u16) {}
#[microcode(Swap816)]
#[inline]
pub fn swap816(top: u8, second: u16) -> (u8, u16) {
(top, second)
}
#[microcode(Intersperse)]
#[inline]
pub fn intersperse(addr: u16, val: u16) -> (u8, u16, u8, u16) {
let [low, high] = val.to_le_bytes();
(high, addr, low, addr)
}
#[microcode(Not)]
#[inline]
pub fn not(val: bool) -> bool {
!val
}
#[microcode(Add)]
pub fn add(lhs: u8, rhs: u8) -> (u8, Flags) {
let mut flags = Flags::empty();
if (lhs & 0xf) + (rhs & 0xf) > 0xf {
flags |= Flags::HALFCARRY;
}
let (res, carry) = lhs.overflowing_add(rhs);
flags |= Flags::check_zero(res) | Flags::check_carry(carry);
(res, flags)
}
#[microcode(Adc)]
pub fn adc(prevflags: Flags, lhs: u8, rhs: u8) -> (u8, Flags) {
let (mut res, mut flags) = add(lhs, rhs);
if prevflags.contains(Flags::CARRY) {
let (res2, flags2) = add(res, 1);
res = res2;
flags = flags2 | (flags - Flags::ZERO);
}
(res, flags)
}
#[microcode(Sub)]
pub fn sub(lhs: u8, rhs: u8) -> (u8, Flags) {
let mut flags = Flags::SUB;
if (lhs & 0xf) < (rhs & 0xf) {
flags |= Flags::HALFCARRY;
}
let (res, carry) = lhs.overflowing_sub(rhs);
flags |= Flags::check_zero(res) | Flags::check_carry(carry);
(res, flags)
}
#[microcode(Sbc)]
pub fn sbc(prevflags: Flags, lhs: u8, rhs: u8) -> (u8, Flags) {
let (mut res, mut flags) = sub(lhs, rhs);
if prevflags.contains(Flags::CARRY) {
let (res2, flags2) = sub(res, 1);
res = res2;
flags = flags2 | (flags - Flags::ZERO);
}
(res, flags)
}
#[microcode(And)]
#[inline]
pub fn and(lhs: u8, rhs: u8) -> (u8, Flags) {
let res = lhs & rhs;
let flags = Flags::HALFCARRY | Flags::check_zero(res);
(res, flags)
}
#[microcode(Or)]
#[inline]
pub fn or(lhs: u8, rhs: u8) -> (u8, Flags) {
let res = lhs | rhs;
let flags = Flags::check_zero(res);
(res, flags)
}
#[microcode(Xor)]
#[inline]
pub fn xor(lhs: u8, rhs: u8) -> (u8, Flags) {
let res = lhs ^ rhs;
let flags = Flags::check_zero(res);
(res, flags)
}
#[microcode(RotateLeft8)]
#[inline]
pub fn rotate_left8(val: u8) -> (u8, Flags) {
let res = val.rotate_left(1);
let flags = Flags::check_zero(res) | Flags::check_carry(res & 1 != 0);
(res, flags)
}
#[microcode(RotateLeft9)]
pub fn rotate_left9(prevflags: Flags, val: u8) -> (u8, Flags) {
let rotated = val.rotate_left(1);
let res = rotated & 0xfe | prevflags.contains(Flags::CARRY) as u8;
let flags = Flags::check_carry(rotated & 1 != 0) | Flags::check_zero(res);
(res, flags)
}
#[microcode(RotateRight8)]
#[inline]
pub fn rotate_right8(val: u8) -> (u8, Flags) {
let res = val.rotate_right(1);
let flags = Flags::check_zero(res) | Flags::check_carry(res & 0x80 != 0);
(res, flags)
}
#[microcode(RotateRight9)]
pub fn rotate_right9(prevflags: Flags, val: u8) -> (u8, Flags) {
let rotated = val.rotate_right(1);
let res = rotated & 0x7f | ((prevflags.contains(Flags::CARRY) as u8) << 7);
let flags = Flags::check_carry(val & 1 != 0) | Flags::check_zero(res);
(res, flags)
}
#[microcode(Compliment)]
pub fn compliment(val: u8) -> (u8, Flags) {
const FLAGS: Flags = Flags::SUB.union(Flags::HALFCARRY);
let res = !val;
(res, FLAGS)
}
#[microcode(ShiftLeft)]
pub fn shift_left(val: u8) -> (u8, Flags) {
let res = val << 1;
let flags = Flags::check_zero(res) | Flags::check_carry(val & 0x80 != 0);
(res, flags)
}
#[microcode(ShiftRight)]
pub fn shift_right(val: u8) -> (u8, Flags) {
let res = val >> 1;
let flags = Flags::check_zero(res) | Flags::check_carry(val & 1 != 0);
(res, flags)
}
#[microcode(ShiftRightSignExt)]
pub fn shift_right_sign_ext(val: u8) -> (u8, Flags) {
let res = ((val as i8) >> 1) as u8;
let flags = Flags::check_zero(res) | Flags::check_carry(val & 1 != 0);
(res, flags)
}
#[microcode(Swap)]
pub fn swap(val: u8) -> (u8, Flags) {
let res = ((val & 0x0f) << 4) | ((val & 0xf0) >> 4);
let flags = Flags::check_zero(res);
(res, flags)
}
#[microcode(DecimalAdjust)]
pub fn decmial_adjust(prevflags: Flags, val: u8) -> (u8, Flags) {
let mut flags = Flags::empty();
let mut res = val;
if prevflags.contains(Flags::SUB) {
if prevflags.contains(Flags::CARRY) {
flags |= Flags::CARRY;
res = res.wrapping_sub(0x60);
}
if prevflags.contains(Flags::HALFCARRY) {
res = res.wrapping_sub(0x06);
}
} else {
if prevflags.contains(Flags::CARRY) || val > 0x99 {
flags |= Flags::CARRY;
res = res.wrapping_add(0x60);
}
if prevflags.contains(Flags::HALFCARRY) || res & 0xf > 9 {
res = res.wrapping_add(0x06);
}
}
flags |= Flags::check_zero(res);
(res, flags)
}
#[microcode(TestBit)]
#[inline]
pub fn test_bit(
#[field]
bit: u8,
val: u8,
) -> Flags {
Flags::check_zero(val & (1 << bit)) | Flags::HALFCARRY
}
#[microcode(SetBit)]
#[inline]
pub fn set_bit(
#[field]
bit: u8,
val: u8,
) -> u8 {
val | (1 << bit)
}
#[microcode(ResetBit)]
#[inline]
pub fn reset_bit(
#[field]
bit: u8,
val: u8,
) -> u8 {
val & !(1 << bit)
}
#[microcode(Inc16)]
#[inline]
pub fn inc16(val: u16) -> u16 {
val.wrapping_add(1)
}
#[microcode(Dec16)]
#[inline]
pub fn dec16(val: u16) -> u16 {
val.wrapping_sub(1)
}
#[microcode(Add16)]
#[inline]
pub fn add16(lhs: u16, rhs: u16) -> (u16, Flags) {
let mut flags = Flags::empty();
if (lhs & 0x7ff) + (rhs & 0x7ff) > 0x7ff {
flags |= Flags::HALFCARRY;
}
let (res, carry) = lhs.overflowing_add(rhs);
flags |= Flags::check_carry(carry);
(res, flags)
}
#[microcode(OffsetAddr)]
pub fn offset_addr(addr: u16, offset: u8) -> (u16, Flags) {
let offset = offset as i8 as i16 as u16;
let mut flags = Flags::empty();
if (addr & 0xf) + (offset & 0xf) > 0xf {
flags |= Flags::HALFCARRY;
}
if (addr & 0xff) + (offset & 0xff) > 0xff {
flags |= Flags::CARRY;
}
(addr.wrapping_add(offset), flags)
}
#[microcode(Stop)]
pub fn stop() {
panic!("STOP is bizarre and complicated and not implemented.")
}
#[microcode_extern(Halt)]
pub fn halt() {}
#[microcode_extern(EnableInterrupts)]
pub fn enable_interrupts(
#[field]
immediate: bool,
) {
}
#[microcode_extern(DisableInterrupts)]
pub fn disable_interrupts() {}
#[microcode_extern(CheckHalt)]
pub fn check_halt() -> bool {}
#[microcode_extern(ClearHalt)]
pub fn clear_halt() {}
#[microcode_extern(CheckIme)]
pub fn check_ime() -> bool {}
#[microcode_extern(GetActiveInterrupts)]
pub fn get_active_interrupts() -> u8 {}
#[microcode_extern(PopInterrupt)]
pub fn pop_interrupt() -> u16 {}
#[microcode_extern(PopHaltBug)]
pub fn pop_halt_bug() -> bool {}
#[microcode_extern(TickImeOnEnd)]
pub fn tick_ime_on_end() {}
#[microcode_extern(Skip)]
pub fn skip(
#[field]
steps: usize,
) {
}
#[microcode_extern(SkipIf)]
pub fn skip_if(
#[field]
steps: usize,
cond: bool,
) {
}
#[microcode_extern(FetchNextInstruction)]
pub fn fetch_next_instruction() {}
#[microcode_extern(ParseOpcode)]
pub fn parse_opcode(opcode: u8) {}
#[microcode_extern(ParseCBOpcode)]
pub fn parse_cb_opcode(opcode: u8) {}
}