#![forbid(unsafe_code)]
#![warn(missing_debug_implementations)]
#![warn(missing_copy_implementations)]
#![warn(missing_docs)]
use str_id::StrID;
#[test]
fn check_type_size() {
assert_eq!(size_of::<Asm>(), size_of::<[usize; 2]>());
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum Asm {
Label(StrID),
LdReg8Reg8(Reg8, Reg8),
LdReg8Imm8(Reg8, u8),
LdReg16Lit(Reg16, u16),
LdReg16Sym(Reg16, StrID),
LdHltReg8(Reg8),
LdHltImm8(u8),
LdReg8Hlt(Reg8),
LdReg16tA(Reg16),
LdLitA(u16),
LdSymA(StrID),
LdhLitA(u16),
LdhSymA(StrID),
LdhCA,
LdAReg16t(Reg16),
LdALit(u16),
LdASym(StrID),
LdhALit(u16),
LdhASym(StrID),
LdhAC,
LdHliA,
LdHldA,
LdAHli,
LdAHld,
BinOpReg8(BinOp, Reg8),
BinOpHlt(BinOp),
BinOpImm8(BinOp, u8),
DecReg8(Reg8),
DecHlt,
IncReg8(Reg8),
IncHlt,
AddHlReg16(Reg16),
DecReg16(Reg16),
IncReg16(Reg16),
Cpl,
BitTestReg8(U3, Reg8),
BitTestHlt(U3),
ResetReg8(U3, Reg8),
ResetHlt(U3),
SetReg8(U3, Reg8),
SetHlt(U3),
UnOpReg8(UnOp, Reg8),
UnOpHlt(UnOp),
Rla,
Rlca,
Rra,
Rrca,
CallLit(u16),
CallSym(StrID),
CallCondLit(Cond, u16),
CallCondSym(Cond, StrID),
JumpHl,
JumpLit(u16),
JumpSym(StrID),
JumpCondLit(Cond, u16),
JumpCondSym(Cond, StrID),
JumpRelLit(u16),
JumpRelSym(StrID),
JumpRelCondLit(Cond, u16),
JumpRelCondSym(Cond, StrID),
ReturnCond(Cond),
Return,
ReturnFromInterrupt,
Reset(RstVec),
Ccf,
Scf,
AddHlSp,
AddSpDelta(i8),
DecSp,
IncSp,
LdSpLit(u16),
LdSpSym(StrID),
LdLitSp(u16),
LdSymSp(StrID),
LdHlSpDelta(i8),
LdSpHl,
PopAF,
PopReg16(Reg16),
PushAF,
PushReg16(Reg16),
DI,
EI,
Halt,
DAA,
Nop,
Stop,
DataBytes(Box<Vec<u8>>),
TileIndexes(Box<Vec<u32>>),
}
impl Asm {
#[inline]
#[must_use]
pub fn rom_size(&self) -> usize {
match self {
Asm::Label(_) => 0,
Asm::LdReg8Reg8(_, _) => 1,
Asm::LdReg8Imm8(_, _) => 2,
Asm::LdReg16Lit(_, _) => 3,
Asm::LdReg16Sym(_, _) => 3,
Asm::LdHltReg8(_) => 1,
Asm::LdHltImm8(_) => 2,
Asm::LdReg8Hlt(_) => 1,
Asm::LdReg16tA(_) => 3,
Asm::LdLitA(_) => 3,
Asm::LdSymA(_) => 3,
Asm::LdhLitA(_) => 2,
Asm::LdhSymA(_) => 2,
Asm::LdhCA => 1,
Asm::LdAReg16t(_) => 3,
Asm::LdALit(_) => 3,
Asm::LdASym(_) => 3,
Asm::LdhALit(_) => 2,
Asm::LdhASym(_) => 2,
Asm::LdhAC => 1,
Asm::LdHliA => 1,
Asm::LdHldA => 1,
Asm::LdAHli => 1,
Asm::LdAHld => 1,
Asm::BinOpReg8(_, _) => 1,
Asm::BinOpHlt(_) => 1,
Asm::BinOpImm8(_, _) => 2,
Asm::DecReg8(_) => 1,
Asm::DecHlt => 1,
Asm::IncReg8(_) => 1,
Asm::IncHlt => 1,
Asm::AddHlReg16(_) => 1,
Asm::DecReg16(_) => 1,
Asm::IncReg16(_) => 1,
Asm::Cpl => 1,
Asm::BitTestReg8(_, _) => 2,
Asm::BitTestHlt(_) => 2,
Asm::ResetReg8(_, _) => 2,
Asm::ResetHlt(_) => 2,
Asm::SetReg8(_, _) => 2,
Asm::SetHlt(_) => 2,
Asm::UnOpReg8(_, _) => 2,
Asm::UnOpHlt(_) => 2,
Asm::Rla => 1,
Asm::Rlca => 1,
Asm::Rra => 1,
Asm::Rrca => 1,
Asm::CallLit(_) => 3,
Asm::CallSym(_) => 3,
Asm::CallCondLit(_, _) => 3,
Asm::CallCondSym(_, _) => 3,
Asm::JumpHl => 1,
Asm::JumpLit(_) => 3,
Asm::JumpSym(_) => 3,
Asm::JumpCondLit(_, _) => 3,
Asm::JumpCondSym(_, _) => 3,
Asm::JumpRelLit(_) => 2,
Asm::JumpRelSym(_) => 2,
Asm::JumpRelCondLit(_, _) => 2,
Asm::JumpRelCondSym(_, _) => 2,
Asm::ReturnCond(_) => 1,
Asm::Return => 1,
Asm::ReturnFromInterrupt => 1,
Asm::Reset(_) => 1,
Asm::Ccf => 1,
Asm::Scf => 1,
Asm::AddHlSp => 1,
Asm::AddSpDelta(_) => 1,
Asm::DecSp => 1,
Asm::IncSp => 1,
Asm::LdSpLit(_) => 3,
Asm::LdSpSym(_) => 3,
Asm::LdLitSp(_) => 3,
Asm::LdSymSp(_) => 3,
Asm::LdHlSpDelta(_) => 2,
Asm::LdSpHl => 1,
Asm::PopAF => 1,
Asm::PopReg16(_) => 1,
Asm::PushAF => 1,
Asm::PushReg16(_) => 1,
Asm::DI => 1,
Asm::EI => 1,
Asm::Halt => 1,
Asm::DAA => 1,
Asm::Nop => 1,
Asm::Stop => 1,
Asm::DataBytes(items) => items.len(),
Asm::TileIndexes(items) => items.len() * core::mem::size_of::<u16>(),
}
}
}
impl core::fmt::Display for Asm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Asm::Label(label) => write!(f, "{label}:"),
Asm::LdReg8Reg8(dst, src) => write!(f, "ld {dst}, {src}"),
Asm::LdReg8Imm8(reg, imm) => write!(f, "ld {reg}, ${imm:02X}"),
Asm::LdReg16Lit(reg, lit) => write!(f, "ld {reg}, ${lit:04X}"),
Asm::LdReg16Sym(reg, sym) => write!(f, "ld {reg}, {sym}"),
Asm::LdHltReg8(reg) => write!(f, "ld [hl], {reg}"),
Asm::LdHltImm8(imm) => write!(f, "ld [hl], ${imm:02X}"),
Asm::LdReg8Hlt(reg) => write!(f, "ld {reg}, [hl]"),
Asm::LdReg16tA(reg) => write!(f, "ld [{reg}], a"),
Asm::LdLitA(lit) => write!(f, "ld [${lit:04X}], a"),
Asm::LdSymA(sym) => write!(f, "ld [{sym}], a"),
Asm::LdhLitA(lit) => write!(f, "ldh ${lit:04X}, a"),
Asm::LdhSymA(sym) => write!(f, "ldh {sym}, a"),
Asm::LdhCA => write!(f, "ld [c], a"),
Asm::LdAReg16t(reg) => write!(f, "ld a, [{reg}]"),
Asm::LdALit(lit) => write!(f, "ld a, [${lit:04X}]"),
Asm::LdASym(sym) => write!(f, "ld a, [{sym}]"),
Asm::LdhALit(lit) => write!(f, "ldh a, [${lit:04X}]"),
Asm::LdhASym(sym) => write!(f, "ldh a, [{sym}]"),
Asm::LdhAC => write!(f, "ldh a, [c]"),
Asm::LdHliA => write!(f, "ld [hli], a"),
Asm::LdHldA => write!(f, "ld [hld], a"),
Asm::LdAHli => write!(f, "ld a, [hli]"),
Asm::LdAHld => write!(f, "ld a, [hld]"),
Asm::BinOpReg8(op, reg) => write!(f, "{op} a, {reg}"),
Asm::BinOpHlt(op) => write!(f, "{op} a, [hl]"),
Asm::BinOpImm8(op, imm) => write!(f, "{op} a, ${imm:02X}"),
Asm::DecReg8(reg) => write!(f, "dec {reg}"),
Asm::DecHlt => write!(f, "dec [hl]"),
Asm::IncReg8(reg) => write!(f, "inc {reg}"),
Asm::IncHlt => write!(f, "inc [hl]"),
Asm::AddHlReg16(reg) => write!(f, "add hl, {reg}"),
Asm::DecReg16(reg) => write!(f, "dec {reg}"),
Asm::IncReg16(reg) => write!(f, "inc {reg}"),
Asm::Cpl => write!(f, "cpl a"),
Asm::BitTestReg8(u3, reg) => write!(f, "bit {u3}, {reg}"),
Asm::BitTestHlt(u3) => write!(f, "bit {u3}, [hl]"),
Asm::ResetReg8(u3, reg) => write!(f, "res {u3}, {reg}"),
Asm::ResetHlt(u3) => write!(f, "res {u3}, [hl]"),
Asm::SetReg8(u3, reg) => write!(f, "set {u3}, {reg}"),
Asm::SetHlt(u3) => write!(f, "set {u3}, [hl]"),
Asm::UnOpReg8(op, reg) => write!(f, "{op} {reg}"),
Asm::UnOpHlt(op) => write!(f, "{op} [hl]"),
Asm::Rla => write!(f, "rla"),
Asm::Rlca => write!(f, "rlca"),
Asm::Rra => write!(f, "rra"),
Asm::Rrca => write!(f, "rrca"),
Asm::CallLit(lit) => write!(f, "call ${lit:04X}"),
Asm::CallSym(sym) => write!(f, "call {sym}"),
Asm::CallCondLit(cond, lit) => write!(f, "call {cond}, ${lit:04X}"),
Asm::CallCondSym(cond, sym) => write!(f, "call {cond}, {sym}"),
Asm::JumpHl => write!(f, "jp hl"),
Asm::JumpLit(lit) => write!(f, "jp ${lit:04X}"),
Asm::JumpSym(sym) => write!(f, "jp {sym}"),
Asm::JumpCondLit(cond, lit) => write!(f, "jp {cond}, ${lit:04X}"),
Asm::JumpCondSym(cond, sym) => write!(f, "jp {cond}, {sym}"),
Asm::JumpRelLit(lit) => write!(f, "jr ${lit:04X}"),
Asm::JumpRelSym(sym) => write!(f, "jr {sym}"),
Asm::JumpRelCondLit(cond, lit) => write!(f, "jp {cond}, ${lit:04X}"),
Asm::JumpRelCondSym(cond, sym) => write!(f, "jp {cond}, {sym}"),
Asm::ReturnCond(cond) => write!(f, "ret {cond}"),
Asm::Return => write!(f, "ret"),
Asm::ReturnFromInterrupt => write!(f, "reti"),
Asm::Reset(vec) => write!(f, "rst {vec}"),
Asm::Ccf => write!(f, "ccf"),
Asm::Scf => write!(f, "scf"),
Asm::AddHlSp => write!(f, "add hl, sp"),
Asm::AddSpDelta(i) => write!(f, "add sp, {i}"),
Asm::DecSp => write!(f, "dec sp"),
Asm::IncSp => write!(f, "inc sp"),
Asm::LdSpLit(lit) => write!(f, "ld sp, ${lit:04X}"),
Asm::LdSpSym(sym) => write!(f, "ld sp, {sym}"),
Asm::LdLitSp(lit) => write!(f, "ld ${lit:04X}, sp"),
Asm::LdSymSp(sym) => write!(f, "ld {sym}, sp"),
Asm::LdHlSpDelta(i) => write!(f, "ld hl, sp{i:+}"),
Asm::LdSpHl => write!(f, "ld sp, hl"),
Asm::PopAF => write!(f, "pop af"),
Asm::PopReg16(reg) => write!(f, "pop {reg}"),
Asm::PushAF => write!(f, "push af"),
Asm::PushReg16(reg) => write!(f, "push {reg}"),
Asm::DI => write!(f, "di"),
Asm::EI => write!(f, "ei"),
Asm::Halt => write!(f, "halt"),
Asm::DAA => write!(f, "daa"),
Asm::Nop => write!(f, "nop"),
Asm::Stop => write!(f, "stop"),
Asm::DataBytes(items) => {
for (i, chunk) in items.chunks(16).enumerate() {
if i > 0 {
writeln!(f)?;
}
write!(f, "db ")?;
for (i, c) in chunk.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "${c:02X}")?;
}
}
Ok(())
}
Asm::TileIndexes(items) => {
for (i, item) in items.iter().enumerate() {
if i > 0 {
writeln!(f)?;
}
if *item > 99999999_u32 {
eprintln!("Warning: Illegal pixel index value: {item}");
}
write!(f, "dw `{item:08}")?;
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, Copy)]
#[allow(missing_docs)]
pub enum Reg8 {
A,
B,
C,
D,
E,
H,
L,
}
impl core::fmt::Display for Reg8 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Reg8::A => "a",
Reg8::B => "b",
Reg8::C => "c",
Reg8::D => "d",
Reg8::E => "e",
Reg8::H => "h",
Reg8::L => "l",
}
)
}
}
#[derive(Debug, Clone, Copy)]
#[allow(missing_docs)]
pub enum Reg16 {
BC,
DE,
HL,
}
impl core::fmt::Display for Reg16 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Reg16::BC => "bc",
Reg16::DE => "de",
Reg16::HL => "hl",
}
)
}
}
#[derive(Debug, Clone, Copy)]
#[allow(missing_docs)]
pub enum U3 {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
}
impl core::fmt::Display for U3 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
U3::_0 => "0",
U3::_1 => "1",
U3::_2 => "2",
U3::_3 => "3",
U3::_4 => "4",
U3::_5 => "5",
U3::_6 => "6",
U3::_7 => "7",
}
)
}
}
#[derive(Debug, Clone, Copy)]
pub enum Cond {
Z,
NZ,
C,
NC,
}
impl core::fmt::Display for Cond {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Cond::Z => "z",
Cond::NZ => "nz",
Cond::C => "c",
Cond::NC => "nc",
}
)
}
}
#[derive(Debug, Clone, Copy)]
#[allow(missing_docs)]
pub enum RstVec {
X00,
X08,
X10,
X18,
X20,
X28,
X30,
X38,
}
impl core::fmt::Display for RstVec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
RstVec::X00 => "$00",
RstVec::X08 => "$08",
RstVec::X10 => "$10",
RstVec::X18 => "$18",
RstVec::X20 => "$20",
RstVec::X28 => "$28",
RstVec::X30 => "$30",
RstVec::X38 => "$38",
}
)
}
}
#[derive(Debug, Clone, Copy)]
pub enum UnOp {
Rl,
Rlc,
Rr,
Rrc,
Sla,
Sra,
Srl,
Swap,
}
impl core::fmt::Display for UnOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
UnOp::Rl => "rl",
UnOp::Rlc => "rlc",
UnOp::Rr => "rr",
UnOp::Rrc => "rrc",
UnOp::Sla => "sla",
UnOp::Sra => "sra",
UnOp::Srl => "srl",
UnOp::Swap => "swap",
}
)
}
}
#[derive(Debug, Clone, Copy)]
pub enum BinOp {
Adc,
Add,
And,
Cp,
Or,
Sbc,
Sub,
Xor,
}
impl core::fmt::Display for BinOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
BinOp::Adc => "adc",
BinOp::Add => "add",
BinOp::And => "and",
BinOp::Cp => "cp",
BinOp::Or => "or",
BinOp::Sbc => "sbc",
BinOp::Sub => "sub",
BinOp::Xor => "xor",
}
)
}
}