Compare commits
11 Commits
918c9020b5
...
vibe
| Author | SHA1 | Date | |
|---|---|---|---|
| 92787a1036 | |||
| d0f748baa5 | |||
| b3024e66c8 | |||
| 5848bdcdce | |||
| cc0278508e | |||
| 03c3c8a4ac | |||
| b8c49682e2 | |||
| 11f0bb06d6 | |||
| e9a40bd9f7 | |||
| 9be93f4aa9 | |||
| 74e86f1ab7 |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "sm83"]
|
||||||
|
path = sm83
|
||||||
|
url = https://github.com/SingleStepTests/sm83.git
|
||||||
3
.idea/dictionaries/project.xml
generated
3
.idea/dictionaries/project.xml
generated
@@ -6,7 +6,9 @@
|
|||||||
<w>addhl</w>
|
<w>addhl</w>
|
||||||
<w>addsp</w>
|
<w>addsp</w>
|
||||||
<w>dechl</w>
|
<w>dechl</w>
|
||||||
|
<w>gameboy</w>
|
||||||
<w>inchl</w>
|
<w>inchl</w>
|
||||||
|
<w>incu</w>
|
||||||
<w>instrs</w>
|
<w>instrs</w>
|
||||||
<w>jpcc</w>
|
<w>jpcc</w>
|
||||||
<w>jphl</w>
|
<w>jphl</w>
|
||||||
@@ -14,6 +16,7 @@
|
|||||||
<w>reti</w>
|
<w>reti</w>
|
||||||
<w>rrca</w>
|
<w>rrca</w>
|
||||||
<w>rrla</w>
|
<w>rrla</w>
|
||||||
|
<w>tama</w>
|
||||||
<w>vram</w>
|
<w>vram</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
|
|||||||
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@@ -2,5 +2,6 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/sm83" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
151
Cargo.lock
generated
151
Cargo.lock
generated
@@ -1,7 +1,156 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.172"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.95"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sdl2"
|
||||||
|
version = "0.35.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"sdl2-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sdl2-sys"
|
||||||
|
version = "0.35.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"version-compare",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.219"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.219"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.140"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untitled"
|
name = "untitled"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"sdl2",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version-compare"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
||||||
|
|||||||
@@ -6,3 +6,6 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
serde_json = "1.0.140"
|
||||||
|
glob = "0.3.2"
|
||||||
|
sdl2 = "0.35.2"
|
||||||
|
|||||||
1
sm83
Submodule
1
sm83
Submodule
Submodule sm83 added at f9c3021024
609
src/instructions.rs
Normal file
609
src/instructions.rs
Normal file
@@ -0,0 +1,609 @@
|
|||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum TargetRegister { A, B, C, D, E, H, L, }
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum TargetU16Register {AF, BC, DE, HL, SP, PC}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum Condition {
|
||||||
|
NZ, // Not Zero
|
||||||
|
Z, // Zero
|
||||||
|
NC, // Not Carry
|
||||||
|
C, // Carry
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Target {
|
||||||
|
U8Register(TargetRegister),
|
||||||
|
U16Register(TargetU16Register),
|
||||||
|
Immediate(u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum LoadTarget{
|
||||||
|
CopyR8R8(TargetRegister, TargetRegister),
|
||||||
|
CopyR8N8(TargetRegister, u8),
|
||||||
|
CopyR16N16(TargetU16Register, u16),
|
||||||
|
CopyHLR8(TargetRegister),
|
||||||
|
CopyHLN8(u8),
|
||||||
|
CopyR8HL(TargetRegister),
|
||||||
|
CopyR16A(TargetU16Register),
|
||||||
|
CopyN16A(u16),
|
||||||
|
CopyAR16(TargetU16Register),
|
||||||
|
CopyAN16(u16),
|
||||||
|
CopyHLIA,
|
||||||
|
CopyHLDA,
|
||||||
|
CopyAHLD,
|
||||||
|
CopyAHLI,
|
||||||
|
CopySPN16(u16),
|
||||||
|
CopyN16SP(u16),
|
||||||
|
CopyHLSPE8(i8),
|
||||||
|
CopySPHL,
|
||||||
|
CopyPortA(Target),
|
||||||
|
CopyAPort(Target)
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Instruction {
|
||||||
|
ADC(Target),
|
||||||
|
ADD(Target),
|
||||||
|
ADDHL(TargetU16Register),
|
||||||
|
ADDSP(i8),
|
||||||
|
AND(Target),
|
||||||
|
BIT(u8, Target),
|
||||||
|
CALL(Condition, u16),
|
||||||
|
CCF,
|
||||||
|
CP(Target),
|
||||||
|
CPL,
|
||||||
|
DAA,
|
||||||
|
DEC(Target),
|
||||||
|
DECU16(TargetU16Register),
|
||||||
|
DI,
|
||||||
|
EI,
|
||||||
|
HALT,
|
||||||
|
INC(Target),
|
||||||
|
INCU16(TargetU16Register),
|
||||||
|
JP(Condition, u16),
|
||||||
|
JPHL,
|
||||||
|
JR(Condition, i8),
|
||||||
|
LD(LoadTarget),
|
||||||
|
NOP,
|
||||||
|
OR(Target),
|
||||||
|
POP(TargetU16Register),
|
||||||
|
PUSH(TargetU16Register),
|
||||||
|
RES(u8, Target),
|
||||||
|
RET(Condition),
|
||||||
|
RETI,
|
||||||
|
RL(Target),
|
||||||
|
RLC(Target),
|
||||||
|
RR(Target),
|
||||||
|
RRC(Target),
|
||||||
|
RST(u8),
|
||||||
|
SBC(Target),
|
||||||
|
SCF,
|
||||||
|
SET(u8, Target),
|
||||||
|
SLA(Target),
|
||||||
|
SRA(Target),
|
||||||
|
SRL(Target),
|
||||||
|
STOP(u8),
|
||||||
|
SUB(Target),
|
||||||
|
SWAP(Target),
|
||||||
|
XOR(Target),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn get_u16(low: u8, high: u8) -> u16 {
|
||||||
|
((high as u16) << 8) | low as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_instruction(opcode: u8, arg1: u8, arg2: u8) -> Instruction {
|
||||||
|
match opcode {
|
||||||
|
0x00 => { Instruction::NOP }
|
||||||
|
0x01 => { Instruction::LD(LoadTarget::CopyR16N16(TargetU16Register::BC, get_u16(arg1, arg2))) }
|
||||||
|
0x02 => { Instruction::LD(LoadTarget::CopyR16A(TargetU16Register::BC)) }
|
||||||
|
0x03 => { Instruction::INCU16(TargetU16Register::BC) }
|
||||||
|
0x04 => { Instruction::INC(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x05 => { Instruction::DEC(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x06 => { Instruction::LD(LoadTarget::CopyR8N8(TargetRegister::B, arg1)) }
|
||||||
|
0x07 => { Instruction::RLC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x08 => { Instruction::LD(LoadTarget::CopyN16SP(get_u16(arg1, arg2))) }
|
||||||
|
0x09 => { Instruction::ADDHL(TargetU16Register::BC) }
|
||||||
|
0x0A => { Instruction::LD(LoadTarget::CopyAR16(TargetU16Register::BC)) }
|
||||||
|
0x0B => { Instruction::DECU16(TargetU16Register::BC) }
|
||||||
|
0x0C => { Instruction::INC(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x0D => { Instruction::DEC(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x0E => { Instruction::LD(LoadTarget::CopyR8N8(TargetRegister::C, arg1)) }
|
||||||
|
0x0F => { Instruction::RRC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x10 => { Instruction::STOP(arg1) }
|
||||||
|
0x11 => { Instruction::LD(LoadTarget::CopyR16N16(TargetU16Register::DE, get_u16(arg1, arg2))) }
|
||||||
|
0x12 => { Instruction::LD(LoadTarget::CopyR16A(TargetU16Register::DE)) }
|
||||||
|
0x13 => { Instruction::INCU16(TargetU16Register::DE) }
|
||||||
|
0x14 => { Instruction::INC(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x15 => { Instruction::DEC(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x16 => { Instruction::LD(LoadTarget::CopyR8N8(TargetRegister::D, arg1)) }
|
||||||
|
0x17 => { Instruction::RL(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x18 => { Instruction::JR(Condition::None, arg1 as i8) }
|
||||||
|
0x19 => { Instruction::ADDHL(TargetU16Register::DE) }
|
||||||
|
0x1A => { Instruction::LD(LoadTarget::CopyAR16(TargetU16Register::DE)) }
|
||||||
|
0x1B => { Instruction::DECU16(TargetU16Register::DE) }
|
||||||
|
0x1C => { Instruction::INC(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x1D => { Instruction::DEC(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x1E => { Instruction::LD(LoadTarget::CopyR8N8(TargetRegister::E, arg1)) }
|
||||||
|
0x1F => { Instruction::RR(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x20 => { Instruction::JR(Condition::NZ, arg1 as i8) }
|
||||||
|
0x21 => { Instruction::LD(LoadTarget::CopyR16N16(TargetU16Register::HL, get_u16(arg1, arg2))) }
|
||||||
|
0x22 => { Instruction::LD(LoadTarget::CopyHLIA) }
|
||||||
|
0x23 => { Instruction::INCU16(TargetU16Register::HL) }
|
||||||
|
0x24 => { Instruction::INC(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x25 => { Instruction::DEC(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x26 => { Instruction::LD(LoadTarget::CopyR8N8(TargetRegister::H, arg1)) }
|
||||||
|
0x27 => { Instruction::DAA }
|
||||||
|
0x28 => { Instruction::JR(Condition::Z, arg1 as i8) }
|
||||||
|
0x29 => { Instruction::ADDHL(TargetU16Register::HL) }
|
||||||
|
0x2A => { Instruction::LD(LoadTarget::CopyAHLI) }
|
||||||
|
0x2B => { Instruction::DECU16(TargetU16Register::HL) }
|
||||||
|
0x2C => { Instruction::INC(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x2D => { Instruction::DEC(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x2E => { Instruction::LD(LoadTarget::CopyR8N8(TargetRegister::L, arg1)) }
|
||||||
|
0x2F => { Instruction::CPL }
|
||||||
|
0x30 => { Instruction::JR(Condition::NC, arg1 as i8) }
|
||||||
|
0x31 => { Instruction::LD(LoadTarget::CopySPN16(get_u16(arg1, arg2))) }
|
||||||
|
0x32 => { Instruction::LD(LoadTarget::CopyHLDA) }
|
||||||
|
0x33 => { Instruction::INCU16(TargetU16Register::SP) }
|
||||||
|
0x34 => { Instruction::INC(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x35 => { Instruction::DEC(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x36 => { Instruction::LD(LoadTarget::CopyHLN8(arg1)) }
|
||||||
|
0x37 => { Instruction::SCF }
|
||||||
|
0x38 => { Instruction::JR(Condition::C, arg1 as i8) }
|
||||||
|
0x39 => { Instruction::ADDHL(TargetU16Register::SP) }
|
||||||
|
0x3A => { Instruction::LD(LoadTarget::CopyAHLD)}
|
||||||
|
0x3B => { Instruction::DECU16(TargetU16Register::SP) }
|
||||||
|
0x3C => { Instruction::INC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x3D => { Instruction::DEC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x3E => { Instruction::LD(LoadTarget::CopyR8N8(TargetRegister::A, arg1)) }
|
||||||
|
0x3F => { Instruction::CCF }
|
||||||
|
0x40 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::B, TargetRegister::B)) }
|
||||||
|
0x41 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::B, TargetRegister::C)) }
|
||||||
|
0x42 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::B, TargetRegister::D)) }
|
||||||
|
0x43 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::B, TargetRegister::E)) }
|
||||||
|
0x44 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::B, TargetRegister::H)) }
|
||||||
|
0x45 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::B, TargetRegister::L)) }
|
||||||
|
0x46 => { Instruction::LD(LoadTarget::CopyR8HL(TargetRegister::B)) }
|
||||||
|
0x47 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::B, TargetRegister::A)) }
|
||||||
|
0x48 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::C, TargetRegister::B)) }
|
||||||
|
0x49 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::C, TargetRegister::C)) }
|
||||||
|
0x4A => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::C, TargetRegister::D)) }
|
||||||
|
0x4B => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::C, TargetRegister::E)) }
|
||||||
|
0x4C => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::C, TargetRegister::H)) }
|
||||||
|
0x4D => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::C, TargetRegister::L)) }
|
||||||
|
0x4E => { Instruction::LD(LoadTarget::CopyR8HL(TargetRegister::C)) }
|
||||||
|
0x4F => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::C, TargetRegister::A)) }
|
||||||
|
0x50 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::D, TargetRegister::B)) }
|
||||||
|
0x51 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::D, TargetRegister::C)) }
|
||||||
|
0x52 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::D, TargetRegister::D)) }
|
||||||
|
0x53 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::D, TargetRegister::E)) }
|
||||||
|
0x54 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::D, TargetRegister::H)) }
|
||||||
|
0x55 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::D, TargetRegister::L)) }
|
||||||
|
0x56 => { Instruction::LD(LoadTarget::CopyR8HL(TargetRegister::D)) }
|
||||||
|
0x57 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::D, TargetRegister::A)) }
|
||||||
|
0x58 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::E, TargetRegister::B)) }
|
||||||
|
0x59 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::E, TargetRegister::C)) }
|
||||||
|
0x5A => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::E, TargetRegister::D)) }
|
||||||
|
0x5B => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::E, TargetRegister::E)) }
|
||||||
|
0x5C => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::E, TargetRegister::H)) }
|
||||||
|
0x5D => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::E, TargetRegister::L)) }
|
||||||
|
0x5E => { Instruction::LD(LoadTarget::CopyR8HL(TargetRegister::E)) }
|
||||||
|
0x5F => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::E, TargetRegister::A)) }
|
||||||
|
0x60 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::H, TargetRegister::B)) }
|
||||||
|
0x61 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::H, TargetRegister::C)) }
|
||||||
|
0x62 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::H, TargetRegister::D)) }
|
||||||
|
0x63 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::H, TargetRegister::E)) }
|
||||||
|
0x64 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::H, TargetRegister::H)) }
|
||||||
|
0x65 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::H, TargetRegister::L)) }
|
||||||
|
0x66 => { Instruction::LD(LoadTarget::CopyR8HL(TargetRegister::H)) }
|
||||||
|
0x67 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::H, TargetRegister::A)) }
|
||||||
|
0x68 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::L, TargetRegister::B)) }
|
||||||
|
0x69 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::L, TargetRegister::C)) }
|
||||||
|
0x6A => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::L, TargetRegister::D)) }
|
||||||
|
0x6B => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::L, TargetRegister::E)) }
|
||||||
|
0x6C => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::L, TargetRegister::H)) }
|
||||||
|
0x6D => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::L, TargetRegister::L)) }
|
||||||
|
0x6E => { Instruction::LD(LoadTarget::CopyR8HL(TargetRegister::L)) }
|
||||||
|
0x6F => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::L, TargetRegister::A)) }
|
||||||
|
0x70 => { Instruction::LD(LoadTarget::CopyHLR8(TargetRegister::B)) }
|
||||||
|
0x71 => { Instruction::LD(LoadTarget::CopyHLR8(TargetRegister::C)) }
|
||||||
|
0x72 => { Instruction::LD(LoadTarget::CopyHLR8(TargetRegister::D)) }
|
||||||
|
0x73 => { Instruction::LD(LoadTarget::CopyHLR8(TargetRegister::E)) }
|
||||||
|
0x74 => { Instruction::LD(LoadTarget::CopyHLR8(TargetRegister::H)) }
|
||||||
|
0x75 => { Instruction::LD(LoadTarget::CopyHLR8(TargetRegister::L)) }
|
||||||
|
0x76 => { Instruction::HALT }
|
||||||
|
0x77 => { Instruction::LD(LoadTarget::CopyHLR8(TargetRegister::A)) }
|
||||||
|
0x78 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::A, TargetRegister::B)) }
|
||||||
|
0x79 => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::A, TargetRegister::C)) }
|
||||||
|
0x7A => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::A, TargetRegister::D)) }
|
||||||
|
0x7B => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::A, TargetRegister::E)) }
|
||||||
|
0x7C => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::A, TargetRegister::H)) }
|
||||||
|
0x7D => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::A, TargetRegister::L)) }
|
||||||
|
0x7E => { Instruction::LD(LoadTarget::CopyR8HL(TargetRegister::A)) }
|
||||||
|
0x7F => { Instruction::LD(LoadTarget::CopyR8R8(TargetRegister::A, TargetRegister::A)) }
|
||||||
|
0x80 => { Instruction::ADD(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x81 => { Instruction::ADD(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x82 => { Instruction::ADD(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x83 => { Instruction::ADD(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x84 => { Instruction::ADD(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x85 => { Instruction::ADD(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x86 => { Instruction::ADD(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x87 => { Instruction::ADD(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x88 => { Instruction::ADC(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x89 => { Instruction::ADC(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x8A => { Instruction::ADC(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x8B => { Instruction::ADC(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x8C => { Instruction::ADC(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x8D => { Instruction::ADC(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x8E => { Instruction::ADC(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x8F => { Instruction::ADC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x90 => { Instruction::SUB(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x91 => { Instruction::SUB(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x92 => { Instruction::SUB(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x93 => { Instruction::SUB(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x94 => { Instruction::SUB(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x95 => { Instruction::SUB(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x96 => { Instruction::SUB(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x97 => { Instruction::SUB(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x98 => { Instruction::SBC(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x99 => { Instruction::SBC(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x9A => { Instruction::SBC(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x9B => { Instruction::SBC(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x9C => { Instruction::SBC(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x9D => { Instruction::SBC(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x9E => { Instruction::SBC(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x9F => { Instruction::SBC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xA0 => { Instruction::AND(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xA1 => { Instruction::AND(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xA2 => { Instruction::AND(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xA3 => { Instruction::AND(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xA4 => { Instruction::AND(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xA5 => { Instruction::AND(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xA6 => { Instruction::AND(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xA7 => { Instruction::AND(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xA8 => { Instruction::XOR(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xA9 => { Instruction::XOR(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xAA => { Instruction::XOR(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xAB => { Instruction::XOR(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xAC => { Instruction::XOR(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xAD => { Instruction::XOR(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xAE => { Instruction::XOR(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xAF => { Instruction::XOR(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xB0 => { Instruction::OR(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xB1 => { Instruction::OR(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xB2 => { Instruction::OR(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xB3 => { Instruction::OR(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xB4 => { Instruction::OR(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xB5 => { Instruction::OR(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xB6 => { Instruction::OR(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xB7 => { Instruction::OR(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xB8 => { Instruction::CP(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xB9 => { Instruction::CP(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xBA => { Instruction::CP(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xBB => { Instruction::CP(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xBC => { Instruction::CP(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xBD => { Instruction::CP(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xBE => { Instruction::CP(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xBF => { Instruction::CP(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xC0 => { Instruction::RET(Condition::NZ) }
|
||||||
|
0xC1 => { Instruction::POP(TargetU16Register::BC) }
|
||||||
|
0xC2 => { Instruction::JP(Condition::NZ, get_u16(arg1, arg2)) }
|
||||||
|
0xC3 => { Instruction::JP(Condition::None, get_u16(arg1, arg2)) }
|
||||||
|
0xC4 => { Instruction::CALL(Condition::NZ, get_u16(arg1, arg2)) }
|
||||||
|
0xC5 => { Instruction::PUSH(TargetU16Register::BC) }
|
||||||
|
0xC6 => { Instruction::ADD(Target::Immediate(arg1)) }
|
||||||
|
0xC7 => { Instruction::RST(0x00) }
|
||||||
|
0xC8 => { Instruction::RET(Condition::Z) }
|
||||||
|
0xC9 => { Instruction::RET(Condition::None) }
|
||||||
|
0xCA => { Instruction::JP(Condition::Z, get_u16(arg1, arg2)) }
|
||||||
|
0xCB => {match_cb_instruction(arg1)},
|
||||||
|
0xCC => { Instruction::CALL(Condition::Z, get_u16(arg1, arg2)) }
|
||||||
|
0xCD => { Instruction::CALL(Condition::None, get_u16(arg1, arg2)) }
|
||||||
|
0xCE => { Instruction::ADC(Target::Immediate(arg1)) }
|
||||||
|
0xCF => { Instruction::RST(0x01) }
|
||||||
|
0xD0 => { Instruction::RET(Condition::NC) }
|
||||||
|
0xD1 => { Instruction::POP(TargetU16Register::DE) }
|
||||||
|
0xD2 => { Instruction::JP(Condition::NC, get_u16(arg1, arg2)) }
|
||||||
|
0xD4 => { Instruction::CALL(Condition::NC, get_u16(arg1, arg2)) }
|
||||||
|
0xD5 => { Instruction::PUSH(TargetU16Register::DE) }
|
||||||
|
0xD6 => { Instruction::SUB(Target::Immediate(arg1)) }
|
||||||
|
0xD7 => { Instruction::RST(0x02) }
|
||||||
|
0xD8 => { Instruction::RET(Condition::C) }
|
||||||
|
0xD9 => { Instruction::RETI }
|
||||||
|
0xDA => { Instruction::JP(Condition::C, get_u16(arg1, arg2)) }
|
||||||
|
0xDC => { Instruction::CALL(Condition::C, get_u16(arg1, arg2)) }
|
||||||
|
0xDE => { Instruction::SBC(Target::Immediate(arg1)) }
|
||||||
|
0xDF => { Instruction::RST(0x03) }
|
||||||
|
0xE0 => { Instruction::LD(LoadTarget::CopyPortA(Target::Immediate(arg1))) }
|
||||||
|
0xE1 => { Instruction::POP(TargetU16Register::HL) }
|
||||||
|
0xE2 => { Instruction::LD(LoadTarget::CopyPortA(Target::U8Register(TargetRegister::C))) }
|
||||||
|
0xE5 => { Instruction::PUSH(TargetU16Register::HL) }
|
||||||
|
0xE6 => { Instruction::AND(Target::Immediate(arg1)) }
|
||||||
|
0xE7 => { Instruction::RST(0x04) }
|
||||||
|
0xE8 => { Instruction::ADDSP(arg1 as i8) }
|
||||||
|
0xE9 => { Instruction::JPHL }
|
||||||
|
0xEA => { Instruction::LD(LoadTarget::CopyN16A(get_u16(arg1, arg2))) }
|
||||||
|
0xEE => { Instruction::XOR(Target::Immediate(arg1)) }
|
||||||
|
0xEF => { Instruction::RST(0x05) }
|
||||||
|
0xF0 => { Instruction::LD(LoadTarget::CopyAPort(Target::Immediate(arg1))) }
|
||||||
|
0xF1 => { Instruction::POP(TargetU16Register::AF) }
|
||||||
|
0xF2 => { Instruction::LD(LoadTarget::CopyAPort(Target::U8Register(TargetRegister::C))) }
|
||||||
|
0xF3 => { Instruction::DI }
|
||||||
|
0xF5 => { Instruction::PUSH(TargetU16Register::AF) }
|
||||||
|
0xF6 => { Instruction::OR(Target::Immediate(arg1)) }
|
||||||
|
0xF7 => { Instruction::RST(0x06) }
|
||||||
|
0xF8 => { Instruction::LD(LoadTarget::CopyHLSPE8(arg1 as i8)) }
|
||||||
|
0xF9 => { Instruction::LD(LoadTarget::CopySPHL) }
|
||||||
|
0xFA => { Instruction::LD(LoadTarget::CopyAN16(get_u16(arg1, arg2))) }
|
||||||
|
0xFB => { Instruction::EI }
|
||||||
|
0xFE => { Instruction::CP(Target::Immediate(arg1)) }
|
||||||
|
0xFF => { Instruction::RST(0x07) }
|
||||||
|
_ => { panic!("Invalid u8 opcode: {:02X}", opcode); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_cb_instruction(opcode: u8) -> Instruction {
|
||||||
|
match opcode {
|
||||||
|
0x00 => { Instruction::RLC(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x01 => { Instruction::RLC(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x02 => { Instruction::RLC(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x03 => { Instruction::RLC(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x04 => { Instruction::RLC(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x05 => { Instruction::RLC(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x06 => { Instruction::RLC(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x07 => { Instruction::RLC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x08 => { Instruction::RRC(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x09 => { Instruction::RRC(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x0A => { Instruction::RRC(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x0B => { Instruction::RRC(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x0C => { Instruction::RRC(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x0D => { Instruction::RRC(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x0E => { Instruction::RRC(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x0F => { Instruction::RRC(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x10 => { Instruction::RL(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x11 => { Instruction::RL(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x12 => { Instruction::RL(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x13 => { Instruction::RL(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x14 => { Instruction::RL(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x15 => { Instruction::RL(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x16 => { Instruction::RL(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x17 => { Instruction::RL(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x18 => { Instruction::RR(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x19 => { Instruction::RR(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x1A => { Instruction::RR(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x1B => { Instruction::RR(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x1C => { Instruction::RR(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x1D => { Instruction::RR(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x1E => { Instruction::RR(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x1F => { Instruction::RR(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x20 => { Instruction::SLA(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x21 => { Instruction::SLA(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x22 => { Instruction::SLA(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x23 => { Instruction::SLA(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x24 => { Instruction::SLA(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x25 => { Instruction::SLA(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x26 => { Instruction::SLA(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x27 => { Instruction::SLA(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x28 => { Instruction::SRA(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x29 => { Instruction::SRA(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x2A => { Instruction::SRA(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x2B => { Instruction::SRA(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x2C => { Instruction::SRA(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x2D => { Instruction::SRA(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x2E => { Instruction::SRA(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x2F => { Instruction::SRA(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x30 => { Instruction::SWAP(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x31 => { Instruction::SWAP(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x32 => { Instruction::SWAP(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x33 => { Instruction::SWAP(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x34 => { Instruction::SWAP(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x35 => { Instruction::SWAP(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x36 => { Instruction::SWAP(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x37 => { Instruction::SWAP(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x38 => { Instruction::SRL(Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x39 => { Instruction::SRL(Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x3A => { Instruction::SRL(Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x3B => { Instruction::SRL(Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x3C => { Instruction::SRL(Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x3D => { Instruction::SRL(Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x3E => { Instruction::SRL(Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x3F => { Instruction::SRL(Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x40 => { Instruction::BIT(0, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x41 => { Instruction::BIT(0, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x42 => { Instruction::BIT(0, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x43 => { Instruction::BIT(0, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x44 => { Instruction::BIT(0, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x45 => { Instruction::BIT(0, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x46 => { Instruction::BIT(0, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x47 => { Instruction::BIT(0, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x48 => { Instruction::BIT(1, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x49 => { Instruction::BIT(1, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x4A => { Instruction::BIT(1, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x4B => { Instruction::BIT(1, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x4C => { Instruction::BIT(1, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x4D => { Instruction::BIT(1, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x4E => { Instruction::BIT(1, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x4F => { Instruction::BIT(1, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x50 => { Instruction::BIT(2, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x51 => { Instruction::BIT(2, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x52 => { Instruction::BIT(2, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x53 => { Instruction::BIT(2, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x54 => { Instruction::BIT(2, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x55 => { Instruction::BIT(2, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x56 => { Instruction::BIT(2, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x57 => { Instruction::BIT(2, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x58 => { Instruction::BIT(3, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x59 => { Instruction::BIT(3, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x5A => { Instruction::BIT(3, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x5B => { Instruction::BIT(3, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x5C => { Instruction::BIT(3, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x5D => { Instruction::BIT(3, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x5E => { Instruction::BIT(3, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x5F => { Instruction::BIT(3, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x60 => { Instruction::BIT(4, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x61 => { Instruction::BIT(4, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x62 => { Instruction::BIT(4, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x63 => { Instruction::BIT(4, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x64 => { Instruction::BIT(4, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x65 => { Instruction::BIT(4, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x66 => { Instruction::BIT(4, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x67 => { Instruction::BIT(4, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x68 => { Instruction::BIT(5, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x69 => { Instruction::BIT(5, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x6A => { Instruction::BIT(5, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x6B => { Instruction::BIT(5, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x6C => { Instruction::BIT(5, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x6D => { Instruction::BIT(5, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x6E => { Instruction::BIT(5, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x6F => { Instruction::BIT(5, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x70 => { Instruction::BIT(6, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x71 => { Instruction::BIT(6, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x72 => { Instruction::BIT(6, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x73 => { Instruction::BIT(6, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x74 => { Instruction::BIT(6, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x75 => { Instruction::BIT(6, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x76 => { Instruction::BIT(6, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x77 => { Instruction::BIT(6, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x78 => { Instruction::BIT(7, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x79 => { Instruction::BIT(7, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x7A => { Instruction::BIT(7, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x7B => { Instruction::BIT(7, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x7C => { Instruction::BIT(7, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x7D => { Instruction::BIT(7, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x7E => { Instruction::BIT(7, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x7F => { Instruction::BIT(7, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x80 => { Instruction::RES(0, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x81 => { Instruction::RES(0, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x82 => { Instruction::RES(0, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x83 => { Instruction::RES(0, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x84 => { Instruction::RES(0, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x85 => { Instruction::RES(0, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x86 => { Instruction::RES(0, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x87 => { Instruction::RES(0, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x88 => { Instruction::RES(1, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x89 => { Instruction::RES(1, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x8A => { Instruction::RES(1, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x8B => { Instruction::RES(1, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x8C => { Instruction::RES(1, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x8D => { Instruction::RES(1, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x8E => { Instruction::RES(1, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x8F => { Instruction::RES(1, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x90 => { Instruction::RES(2, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x91 => { Instruction::RES(2, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x92 => { Instruction::RES(2, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x93 => { Instruction::RES(2, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x94 => { Instruction::RES(2, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x95 => { Instruction::RES(2, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x96 => { Instruction::RES(2, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x97 => { Instruction::RES(2, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0x98 => { Instruction::RES(3, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0x99 => { Instruction::RES(3, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0x9A => { Instruction::RES(3, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0x9B => { Instruction::RES(3, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0x9C => { Instruction::RES(3, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0x9D => { Instruction::RES(3, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0x9E => { Instruction::RES(3, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0x9F => { Instruction::RES(3, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xA0 => { Instruction::RES(4, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xA1 => { Instruction::RES(4, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xA2 => { Instruction::RES(4, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xA3 => { Instruction::RES(4, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xA4 => { Instruction::RES(4, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xA5 => { Instruction::RES(4, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xA6 => { Instruction::RES(4, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xA7 => { Instruction::RES(4, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xA8 => { Instruction::RES(5, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xA9 => { Instruction::RES(5, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xAA => { Instruction::RES(5, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xAB => { Instruction::RES(5, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xAC => { Instruction::RES(5, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xAD => { Instruction::RES(5, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xAE => { Instruction::RES(5, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xAF => { Instruction::RES(5, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xB0 => { Instruction::RES(6, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xB1 => { Instruction::RES(6, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xB2 => { Instruction::RES(6, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xB3 => { Instruction::RES(6, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xB4 => { Instruction::RES(6, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xB5 => { Instruction::RES(6, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xB6 => { Instruction::RES(6, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xB7 => { Instruction::RES(6, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xB8 => { Instruction::RES(7, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xB9 => { Instruction::RES(7, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xBA => { Instruction::RES(7, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xBB => { Instruction::RES(7, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xBC => { Instruction::RES(7, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xBD => { Instruction::RES(7, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xBE => { Instruction::RES(7, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xBF => { Instruction::RES(7, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xC0 => { Instruction::SET(0, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xC1 => { Instruction::SET(0, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xC2 => { Instruction::SET(0, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xC3 => { Instruction::SET(0, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xC4 => { Instruction::SET(0, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xC5 => { Instruction::SET(0, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xC6 => { Instruction::SET(0, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xC7 => { Instruction::SET(0, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xC8 => { Instruction::SET(1, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xC9 => { Instruction::SET(1, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xCA => { Instruction::SET(1, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xCB => { Instruction::SET(1, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xCC => { Instruction::SET(1, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xCD => { Instruction::SET(1, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xCE => { Instruction::SET(1, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xCF => { Instruction::SET(1, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xD0 => { Instruction::SET(2, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xD1 => { Instruction::SET(2, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xD2 => { Instruction::SET(2, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xD3 => { Instruction::SET(2, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xD4 => { Instruction::SET(2, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xD5 => { Instruction::SET(2, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xD6 => { Instruction::SET(2, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xD7 => { Instruction::SET(2, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xD8 => { Instruction::SET(3, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xD9 => { Instruction::SET(3, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xDA => { Instruction::SET(3, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xDB => { Instruction::SET(3, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xDC => { Instruction::SET(3, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xDD => { Instruction::SET(3, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xDE => { Instruction::SET(3, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xDF => { Instruction::SET(3, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xE0 => { Instruction::SET(4, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xE1 => { Instruction::SET(4, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xE2 => { Instruction::SET(4, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xE3 => { Instruction::SET(4, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xE4 => { Instruction::SET(4, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xE5 => { Instruction::SET(4, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xE6 => { Instruction::SET(4, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xE7 => { Instruction::SET(4, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xE8 => { Instruction::SET(5, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xE9 => { Instruction::SET(5, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xEA => { Instruction::SET(5, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xEB => { Instruction::SET(5, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xEC => { Instruction::SET(5, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xED => { Instruction::SET(5, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xEE => { Instruction::SET(5, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xEF => { Instruction::SET(5, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xF0 => { Instruction::SET(6, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xF1 => { Instruction::SET(6, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xF2 => { Instruction::SET(6, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xF3 => { Instruction::SET(6, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xF4 => { Instruction::SET(6, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xF5 => { Instruction::SET(6, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xF6 => { Instruction::SET(6, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xF7 => { Instruction::SET(6, Target::U8Register(TargetRegister::A)) }
|
||||||
|
0xF8 => { Instruction::SET(7, Target::U8Register(TargetRegister::B)) }
|
||||||
|
0xF9 => { Instruction::SET(7, Target::U8Register(TargetRegister::C)) }
|
||||||
|
0xFA => { Instruction::SET(7, Target::U8Register(TargetRegister::D)) }
|
||||||
|
0xFB => { Instruction::SET(7, Target::U8Register(TargetRegister::E)) }
|
||||||
|
0xFC => { Instruction::SET(7, Target::U8Register(TargetRegister::H)) }
|
||||||
|
0xFD => { Instruction::SET(7, Target::U8Register(TargetRegister::L)) }
|
||||||
|
0xFE => { Instruction::SET(7, Target::U16Register(TargetU16Register::HL)) }
|
||||||
|
0xFF => { Instruction::SET(7, Target::U8Register(TargetRegister::A)) }
|
||||||
|
_ => { panic!("Invalid u16 opcode: {:02X}", opcode); }
|
||||||
|
}
|
||||||
|
}
|
||||||
493
src/lcd.rs
Normal file
493
src/lcd.rs
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
use crate::registers::LCDControlRegister;
|
||||||
|
use std::cmp::min;
|
||||||
|
|
||||||
|
// LCD Mode represents the current mode of the LCD controller
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum LCDMode {
|
||||||
|
HBlank = 0, // Horizontal Blank
|
||||||
|
VBlank = 1, // Vertical Blank
|
||||||
|
OAMSearch = 2, // Searching OAM (Object Attribute Memory)
|
||||||
|
PixelTransfer = 3, // Transferring data to LCD driver
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCD-related constants
|
||||||
|
pub const SCREEN_WIDTH: usize = 160;
|
||||||
|
pub const SCREEN_HEIGHT: usize = 144;
|
||||||
|
|
||||||
|
// LCD memory addresses
|
||||||
|
pub const LCDC_ADDR: usize = 0xFF40;
|
||||||
|
pub const STAT_ADDR: usize = 0xFF41;
|
||||||
|
pub const SCY_ADDR: usize = 0xFF42;
|
||||||
|
pub const SCX_ADDR: usize = 0xFF43;
|
||||||
|
pub const LY_ADDR: usize = 0xFF44;
|
||||||
|
pub const LYC_ADDR: usize = 0xFF45;
|
||||||
|
pub const DMA_ADDR: usize = 0xFF46;
|
||||||
|
pub const BGP_ADDR: usize = 0xFF47;
|
||||||
|
pub const OBP0_ADDR: usize = 0xFF48;
|
||||||
|
pub const OBP1_ADDR: usize = 0xFF49;
|
||||||
|
pub const WY_ADDR: usize = 0xFF4A;
|
||||||
|
pub const WX_ADDR: usize = 0xFF4B;
|
||||||
|
|
||||||
|
// LCD timing constants
|
||||||
|
pub const MODE_0_CYCLES: u32 = 204; // H-Blank
|
||||||
|
pub const MODE_1_CYCLES: u32 = 456 * 10; // V-Blank (10 scanlines)
|
||||||
|
pub const MODE_2_CYCLES: u32 = 80; // OAM Search
|
||||||
|
pub const MODE_3_CYCLES: u32 = 172; // Pixel Transfer
|
||||||
|
|
||||||
|
// OAM (Object Attribute Memory) constants
|
||||||
|
pub const OAM_SIZE: usize = 160; // 40 sprites * 4 bytes each
|
||||||
|
|
||||||
|
// GPU with LCD functionality
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GPU {
|
||||||
|
pub vram: Vec<u8>,
|
||||||
|
pub tile_set: [[[TilePixelValue; 8]; 8]; 384],
|
||||||
|
|
||||||
|
// LCD registers
|
||||||
|
pub lcd_control: LCDControlRegister,
|
||||||
|
pub lcd_status: u8,
|
||||||
|
pub scroll_y: u8,
|
||||||
|
pub scroll_x: u8,
|
||||||
|
pub ly: u8, // Current scanline
|
||||||
|
pub lyc: u8, // Scanline compare
|
||||||
|
pub window_y: u8,
|
||||||
|
pub window_x: u8,
|
||||||
|
pub bg_palette: u8,
|
||||||
|
pub obj_palette0: u8,
|
||||||
|
pub obj_palette1: u8,
|
||||||
|
|
||||||
|
// OAM (Object Attribute Memory) for sprites
|
||||||
|
pub oam: [u8; OAM_SIZE],
|
||||||
|
|
||||||
|
// LCD screen buffer (160x144 pixels)
|
||||||
|
pub screen_buffer: [[u8; SCREEN_WIDTH]; SCREEN_HEIGHT],
|
||||||
|
|
||||||
|
// LCD timing
|
||||||
|
pub mode_clock: u32,
|
||||||
|
pub mode: LCDMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum TilePixelValue { Zero, One, Two, Three }
|
||||||
|
|
||||||
|
impl GPU {
|
||||||
|
// Create a new GPU with default values
|
||||||
|
pub fn new(vram: Vec<u8>) -> Self {
|
||||||
|
GPU {
|
||||||
|
vram,
|
||||||
|
tile_set: [[[TilePixelValue::Zero; 8]; 8]; 384],
|
||||||
|
lcd_control: LCDControlRegister::from(0),
|
||||||
|
lcd_status: 0,
|
||||||
|
scroll_y: 0,
|
||||||
|
scroll_x: 0,
|
||||||
|
ly: 0,
|
||||||
|
lyc: 0,
|
||||||
|
window_y: 0,
|
||||||
|
window_x: 0,
|
||||||
|
bg_palette: 0,
|
||||||
|
obj_palette0: 0,
|
||||||
|
obj_palette1: 0,
|
||||||
|
oam: [0; OAM_SIZE],
|
||||||
|
screen_buffer: [[0; SCREEN_WIDTH]; SCREEN_HEIGHT],
|
||||||
|
mode_clock: 0,
|
||||||
|
mode: LCDMode::HBlank,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from VRAM
|
||||||
|
pub fn read_vram(&self, address: usize) -> u8 {
|
||||||
|
self.vram[address]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write to VRAM and update tile data if necessary
|
||||||
|
pub fn write_vram(&mut self, index: usize, value: u8) {
|
||||||
|
self.vram[index] = value;
|
||||||
|
|
||||||
|
// If our index is greater than 0x1800, we're not writing to the tile set storage
|
||||||
|
// so we can just return.
|
||||||
|
if index >= 0x1800 { return }
|
||||||
|
|
||||||
|
// Tiles rows are encoded in two bytes with the first byte always
|
||||||
|
// on an even address. Bitwise ANDing the address with 0xffe
|
||||||
|
// gives us the address of the first byte.
|
||||||
|
// For example, `12 & 0xFFFE == 12` and `13 & 0xFFFE == 12`
|
||||||
|
let normalized_index = index & 0xFFFE;
|
||||||
|
|
||||||
|
// First, we need to get the two bytes that encode the tile row.
|
||||||
|
let byte1 = self.vram[normalized_index];
|
||||||
|
let byte2 = self.vram[normalized_index + 1];
|
||||||
|
|
||||||
|
// Tiles are 8 rows tall. Since each row is encoded with two bytes, a tile
|
||||||
|
// is therefore 16 bytes in total.
|
||||||
|
let tile_index = index / 16;
|
||||||
|
// Every two bytes is a new row
|
||||||
|
let row_index = (index % 16) / 2;
|
||||||
|
|
||||||
|
// Now we're going to loop 8 times to get the 8 pixels that make up a given row.
|
||||||
|
for pixel_index in 0..8 {
|
||||||
|
// To determine a pixel's value, we must first find the corresponding bit that encodes
|
||||||
|
// that pixel value.
|
||||||
|
let mask = 1 << (7 - pixel_index);
|
||||||
|
let lsb = byte1 & mask;
|
||||||
|
let msb = byte2 & mask;
|
||||||
|
|
||||||
|
// If the masked values are not 0, the masked bit must be 1. If they are 0, the masked
|
||||||
|
// bit must be 0.
|
||||||
|
let value = match (lsb != 0, msb != 0) {
|
||||||
|
(true, true) => TilePixelValue::Three,
|
||||||
|
(false, true) => TilePixelValue::Two,
|
||||||
|
(true, false) => TilePixelValue::One,
|
||||||
|
(false, false) => TilePixelValue::Zero,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.tile_set[tile_index][row_index][pixel_index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from OAM
|
||||||
|
pub fn read_oam(&self, address: usize) -> u8 {
|
||||||
|
self.oam[address]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write to OAM
|
||||||
|
pub fn write_oam(&mut self, address: usize, value: u8) {
|
||||||
|
self.oam[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the LCD state
|
||||||
|
pub fn update(&mut self, cycles: u32) {
|
||||||
|
|
||||||
|
// If LCD is disabled, reset and return
|
||||||
|
if !self.lcd_control.lcd_enabled {
|
||||||
|
self.mode_clock = 0;
|
||||||
|
self.ly = 0;
|
||||||
|
self.mode = LCDMode::HBlank;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mode_clock += cycles;
|
||||||
|
|
||||||
|
// Update LCD based on current mode
|
||||||
|
match self.mode {
|
||||||
|
LCDMode::HBlank => {
|
||||||
|
if self.mode_clock >= MODE_0_CYCLES {
|
||||||
|
self.mode_clock = 0;
|
||||||
|
self.ly += 1;
|
||||||
|
|
||||||
|
if self.ly == SCREEN_HEIGHT as u8 {
|
||||||
|
// Enter V-Blank
|
||||||
|
self.mode = LCDMode::VBlank;
|
||||||
|
// TODO: Request V-Blank interrupt
|
||||||
|
} else {
|
||||||
|
// Start next scanline
|
||||||
|
self.mode = LCDMode::OAMSearch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LCDMode::VBlank => {
|
||||||
|
if self.mode_clock >= MODE_1_CYCLES / 10 {
|
||||||
|
self.mode_clock = 0;
|
||||||
|
self.ly += 1;
|
||||||
|
|
||||||
|
// Debug print for VBlank mode
|
||||||
|
println!("VBlank: LY = {}", self.ly);
|
||||||
|
|
||||||
|
if self.ly > 153 {
|
||||||
|
// End of V-Blank, start new frame
|
||||||
|
self.ly = 0;
|
||||||
|
self.mode = LCDMode::OAMSearch;
|
||||||
|
println!("End of VBlank, starting new frame");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LCDMode::OAMSearch => {
|
||||||
|
if self.mode_clock >= MODE_2_CYCLES {
|
||||||
|
self.mode_clock = 0;
|
||||||
|
self.mode = LCDMode::PixelTransfer;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LCDMode::PixelTransfer => {
|
||||||
|
if self.mode_clock >= MODE_3_CYCLES {
|
||||||
|
self.mode_clock = 0;
|
||||||
|
self.mode = LCDMode::HBlank;
|
||||||
|
// Render scanline
|
||||||
|
self.render_scanline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update LCD status register
|
||||||
|
self.update_status();
|
||||||
|
|
||||||
|
// Print debug info when LY changes
|
||||||
|
// if self.ly != old_ly {
|
||||||
|
// println!("LY changed: {} -> {} (Mode: {:?})", old_ly, self.ly, self.mode);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the LCD status register
|
||||||
|
fn update_status(&mut self) {
|
||||||
|
// Update mode bits
|
||||||
|
self.lcd_status = (self.lcd_status & 0xFC) | (self.mode as u8);
|
||||||
|
|
||||||
|
// Check LYC=LY coincidence flag
|
||||||
|
if self.ly == self.lyc {
|
||||||
|
self.lcd_status |= 0x04;
|
||||||
|
// TODO: Request LYC=LY interrupt if enabled
|
||||||
|
} else {
|
||||||
|
self.lcd_status &= !0x04;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check for mode interrupts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render a single scanline
|
||||||
|
fn render_scanline(&mut self) {
|
||||||
|
// Debug print for rendering
|
||||||
|
// if self.ly % 20 == 0 { // Print every 20th scanline to avoid flooding the console
|
||||||
|
// println!("Rendering scanline {} (Mode: {:?})", self.ly, self.mode);
|
||||||
|
// println!(" LCD Control: {:?}", self.lcd_control);
|
||||||
|
// println!(" Background Palette: 0x{:02X}", self.bg_palette);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if self.lcd_control.bg_and_window_enable {
|
||||||
|
self.render_background();
|
||||||
|
|
||||||
|
if self.lcd_control.window_enable {
|
||||||
|
self.render_window();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.lcd_control.object_enable {
|
||||||
|
self.render_sprites();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the background for the current scanline
|
||||||
|
fn render_background(&mut self) {
|
||||||
|
let tile_map_area = if self.lcd_control.bg_tile_map_area { 0x9C00 } else { 0x9800 };
|
||||||
|
let tile_data_area = if self.lcd_control.bg_and_window_tile_area { 0x8000 } else { 0x8800 };
|
||||||
|
let signed_addressing = tile_data_area == 0x8800;
|
||||||
|
|
||||||
|
// // Debug print for rendering
|
||||||
|
// if self.ly == 80 { // Only print for a specific scanline to avoid flooding the console
|
||||||
|
// println!("Rendering background for scanline {}", self.ly);
|
||||||
|
// println!(" Tile map area: 0x{:04X}", tile_map_area);
|
||||||
|
// println!(" Tile data area: 0x{:04X}", tile_data_area);
|
||||||
|
// println!(" Signed addressing: {}", signed_addressing);
|
||||||
|
// println!(" Background palette: 0x{:02X}", self.bg_palette);
|
||||||
|
// println!(" LCD Control: {:?}", self.lcd_control);
|
||||||
|
// }
|
||||||
|
|
||||||
|
let y_pos = self.ly.wrapping_add(self.scroll_y);
|
||||||
|
let tile_row = (y_pos / 8) as usize;
|
||||||
|
|
||||||
|
// Track if any non-zero pixels are set
|
||||||
|
let mut non_zero_pixels = 0;
|
||||||
|
|
||||||
|
for x in 0..SCREEN_WIDTH {
|
||||||
|
let x_pos = (x as u8).wrapping_add(self.scroll_x);
|
||||||
|
let tile_col = (x_pos / 8) as usize;
|
||||||
|
|
||||||
|
// Get the tile index from the tile map
|
||||||
|
let tile_map_addr = tile_map_area - 0x8000 + tile_row * 32 + tile_col;
|
||||||
|
let tile_index = self.vram[tile_map_addr];
|
||||||
|
|
||||||
|
// Get the tile data
|
||||||
|
let tile_data_addr = if signed_addressing {
|
||||||
|
// 8800 method uses signed addressing
|
||||||
|
let signed_index = tile_index as i8;
|
||||||
|
// Calculate the offset in i16 to handle negative indices correctly
|
||||||
|
let offset = 0x1000i16 + (signed_index as i16 * 16);
|
||||||
|
// Ensure the result is non-negative before converting to usize
|
||||||
|
if offset < 0 {
|
||||||
|
// Handle the error case - use a default address or log an error
|
||||||
|
println!("Warning: Negative tile data address calculated in render_background: {}", offset);
|
||||||
|
0 // Use tile 0 as a fallback
|
||||||
|
} else {
|
||||||
|
offset as usize
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 8000 method uses unsigned addressing
|
||||||
|
(tile_data_area - 0x8000) + (tile_index as usize * 16)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the specific row of the tile
|
||||||
|
let row = (y_pos % 8) as usize;
|
||||||
|
let row_addr = tile_data_addr + row * 2;
|
||||||
|
|
||||||
|
// Get the pixel data for the row
|
||||||
|
let byte1 = self.vram[row_addr];
|
||||||
|
let byte2 = self.vram[row_addr + 1];
|
||||||
|
|
||||||
|
// Get the specific pixel in the row
|
||||||
|
let bit = 7 - (x_pos % 8);
|
||||||
|
let pixel = ((byte1 >> bit) & 1) | (((byte2 >> bit) & 1) << 1);
|
||||||
|
|
||||||
|
// Map the pixel value through the palette
|
||||||
|
let color = (self.bg_palette >> (pixel * 2)) & 0x03;
|
||||||
|
|
||||||
|
// Set the pixel in the screen buffer
|
||||||
|
self.screen_buffer[self.ly as usize][x] = color;
|
||||||
|
|
||||||
|
// Count non-zero pixels
|
||||||
|
if color > 0 {
|
||||||
|
non_zero_pixels += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the window for the current scanline
|
||||||
|
fn render_window(&mut self) {
|
||||||
|
// Only render if the window is visible on this scanline
|
||||||
|
if self.window_y > self.ly {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile_map_area = if self.lcd_control.window_tile_map_area { 0x9C00 } else { 0x9800 };
|
||||||
|
let tile_data_area = if self.lcd_control.bg_and_window_tile_area { 0x8000 } else { 0x8800 };
|
||||||
|
let signed_addressing = tile_data_area == 0x8800;
|
||||||
|
|
||||||
|
let y_pos = self.ly - self.window_y;
|
||||||
|
let tile_row = (y_pos / 8) as usize;
|
||||||
|
|
||||||
|
for x in 0..SCREEN_WIDTH {
|
||||||
|
// Window X position is offset by 7
|
||||||
|
let window_x = self.window_x.wrapping_sub(7);
|
||||||
|
|
||||||
|
// Only render if this pixel is within the window
|
||||||
|
if (x as u8) < window_x {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x_pos = (x as u8) - window_x;
|
||||||
|
let tile_col = (x_pos / 8) as usize;
|
||||||
|
|
||||||
|
// Get the tile index from the tile map
|
||||||
|
let tile_map_addr = tile_map_area - 0x8000 + tile_row * 32 + tile_col;
|
||||||
|
let tile_index = self.vram[tile_map_addr];
|
||||||
|
|
||||||
|
// Get the tile data
|
||||||
|
let tile_data_addr = if signed_addressing {
|
||||||
|
// 8800 method uses signed addressing
|
||||||
|
let signed_index = tile_index as i8;
|
||||||
|
// Calculate the offset in i16 to handle negative indices correctly
|
||||||
|
let offset = 0x1000i16 + (signed_index as i16 * 16);
|
||||||
|
// Ensure the result is non-negative before converting to usize
|
||||||
|
if offset < 0 {
|
||||||
|
// Handle the error case - use a default address or log an error
|
||||||
|
println!("Warning: Negative tile data address calculated in render_window: {}", offset);
|
||||||
|
0 // Use tile 0 as a fallback
|
||||||
|
} else {
|
||||||
|
offset as usize
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 8000 method uses unsigned addressing
|
||||||
|
(tile_data_area - 0x8000) + (tile_index as usize * 16)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the specific row of the tile
|
||||||
|
let row = (y_pos % 8) as usize;
|
||||||
|
let row_addr = tile_data_addr + row * 2;
|
||||||
|
|
||||||
|
// Get the pixel data for the row
|
||||||
|
let byte1 = self.vram[row_addr];
|
||||||
|
let byte2 = self.vram[row_addr + 1];
|
||||||
|
|
||||||
|
// Get the specific pixel in the row
|
||||||
|
let bit = 7 - (x_pos % 8);
|
||||||
|
let pixel = ((byte1 >> bit) & 1) | (((byte2 >> bit) & 1) << 1);
|
||||||
|
|
||||||
|
// Map the pixel value through the palette
|
||||||
|
let color = (self.bg_palette >> (pixel * 2)) & 0x03;
|
||||||
|
|
||||||
|
// Set the pixel in the screen buffer
|
||||||
|
self.screen_buffer[self.ly as usize][x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render sprites for the current scanline
|
||||||
|
fn render_sprites(&mut self) {
|
||||||
|
// Sprite height depends on the object size flag
|
||||||
|
let sprite_height = if self.lcd_control.object_size { 16 } else { 8 };
|
||||||
|
|
||||||
|
// We can have up to 10 sprites per scanline
|
||||||
|
let mut sprites_on_line = 0;
|
||||||
|
|
||||||
|
// Check all 40 sprites
|
||||||
|
for sprite_idx in 0..40 {
|
||||||
|
if sprites_on_line >= 10 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sprite_addr = sprite_idx * 4;
|
||||||
|
let sprite_y = self.oam[sprite_addr].wrapping_sub(16);
|
||||||
|
let sprite_x = self.oam[sprite_addr + 1].wrapping_sub(8);
|
||||||
|
let tile_idx = self.oam[sprite_addr + 2];
|
||||||
|
let attributes = self.oam[sprite_addr + 3];
|
||||||
|
|
||||||
|
// Check if sprite is on this scanline
|
||||||
|
if self.ly < sprite_y || self.ly >= sprite_y.wrapping_add(sprite_height) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprites_on_line += 1;
|
||||||
|
|
||||||
|
// Get sprite flags
|
||||||
|
let palette = if attributes & 0x10 != 0 { self.obj_palette1 } else { self.obj_palette0 };
|
||||||
|
let x_flip = attributes & 0x20 != 0;
|
||||||
|
let y_flip = attributes & 0x40 != 0;
|
||||||
|
let priority = attributes & 0x80 != 0;
|
||||||
|
|
||||||
|
// Calculate the row of the sprite to use
|
||||||
|
let mut row = (self.ly - sprite_y) as usize;
|
||||||
|
if y_flip {
|
||||||
|
row = sprite_height as usize - 1 - row;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For 8x16 sprites, the bottom half uses the next tile
|
||||||
|
let tile = if sprite_height == 16 && row >= 8 {
|
||||||
|
(tile_idx & 0xFE) + 1
|
||||||
|
} else {
|
||||||
|
tile_idx
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the tile data address
|
||||||
|
let tile_addr = (0x8000 - 0x8000) + (tile as usize * 16) + (row % 8) * 2;
|
||||||
|
|
||||||
|
// Get the pixel data for the row
|
||||||
|
let byte1 = self.vram[tile_addr];
|
||||||
|
let byte2 = self.vram[tile_addr + 1];
|
||||||
|
|
||||||
|
// Draw the sprite pixels
|
||||||
|
for x in 0..8 {
|
||||||
|
// Skip if sprite pixel is off-screen
|
||||||
|
if sprite_x.wrapping_add(x) >= SCREEN_WIDTH as u8 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the pixel bit (flipped if needed)
|
||||||
|
let bit = if x_flip { x } else { 7 - x };
|
||||||
|
let pixel = ((byte1 >> bit) & 1) | (((byte2 >> bit) & 1) << 1);
|
||||||
|
|
||||||
|
// Skip transparent pixels
|
||||||
|
if pixel == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check background priority
|
||||||
|
let screen_x = sprite_x.wrapping_add(x) as usize;
|
||||||
|
if priority && self.screen_buffer[self.ly as usize][screen_x] != 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map the pixel value through the palette
|
||||||
|
let color = (palette >> (pixel * 2)) & 0x03;
|
||||||
|
|
||||||
|
// Set the pixel in the screen buffer
|
||||||
|
self.screen_buffer[self.ly as usize][screen_x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1667
src/main.rs
1667
src/main.rs
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,61 @@
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
const LCD_ENABLED_BIT: u8 = 7;
|
||||||
|
const WINDOW_TILE_MAP_AREA_BIT: u8 = 6;
|
||||||
|
const WINDOW_ENABLE_BIT: u8 = 5;
|
||||||
|
const BG_AND_WINDOW_TILE_DATA_AREA_BIT: u8 = 4;
|
||||||
|
const BG_TILE_MAP_AREA_BIT: u8 = 3;
|
||||||
|
const OBJECT_SIZE_BIT: u8 = 2;
|
||||||
|
const OBJECT_ENABLE_BIT: u8 = 1;
|
||||||
|
const BG_AND_WINDOW_ENABLE_BIT: u8 = 0;
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub(crate) struct LCDControlRegister {
|
||||||
|
pub(crate) lcd_enabled: bool,
|
||||||
|
pub(crate) window_tile_map_area: bool,
|
||||||
|
pub(crate) window_enable: bool,
|
||||||
|
pub(crate) bg_and_window_tile_area: bool,
|
||||||
|
pub(crate) bg_tile_map_area: bool,
|
||||||
|
pub(crate) object_size: bool,
|
||||||
|
pub(crate) object_enable: bool,
|
||||||
|
pub(crate) bg_and_window_enable: bool,
|
||||||
|
}
|
||||||
|
impl From<LCDControlRegister> for u8 {
|
||||||
|
fn from(flag: LCDControlRegister) -> u8 {
|
||||||
|
(if flag.lcd_enabled { 1 } else { 0 }) << LCD_ENABLED_BIT |
|
||||||
|
(if flag.window_tile_map_area { 1 } else { 0 }) << WINDOW_TILE_MAP_AREA_BIT |
|
||||||
|
(if flag.window_enable { 1 } else { 0 }) << WINDOW_ENABLE_BIT |
|
||||||
|
(if flag.bg_and_window_tile_area{ 1 } else { 0 }) << BG_AND_WINDOW_TILE_DATA_AREA_BIT |
|
||||||
|
(if flag.bg_tile_map_area { 1 } else { 0 }) << BG_TILE_MAP_AREA_BIT |
|
||||||
|
(if flag.object_size { 1 } else { 0 }) << OBJECT_SIZE_BIT |
|
||||||
|
(if flag.object_enable { 1 } else { 0 }) << OBJECT_ENABLE_BIT |
|
||||||
|
(if flag.bg_and_window_enable { 1 } else { 0 }) << BG_AND_WINDOW_ENABLE_BIT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for LCDControlRegister {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
let lcd_enabled = ((byte >> LCD_ENABLED_BIT) & 0b1) != 0;
|
||||||
|
let window_tile_map_area = ((byte >> WINDOW_TILE_MAP_AREA_BIT) & 0b1) != 0;
|
||||||
|
let window_enable = ((byte >> WINDOW_ENABLE_BIT) & 0b1) != 0;
|
||||||
|
let bg_and_window_tile_area = ((byte >> BG_AND_WINDOW_TILE_DATA_AREA_BIT) & 0b1) != 0;
|
||||||
|
let bg_tile_map_area = ((byte >> BG_TILE_MAP_AREA_BIT) & 0b1) != 0;
|
||||||
|
let object_size = ((byte >> OBJECT_SIZE_BIT) & 0b1) != 0;
|
||||||
|
let object_enable = ((byte >> OBJECT_ENABLE_BIT) & 0b1) != 0;
|
||||||
|
let bg_and_window_enable = ((byte >> BG_AND_WINDOW_ENABLE_BIT) & 0b1) != 0;
|
||||||
|
|
||||||
|
LCDControlRegister {
|
||||||
|
lcd_enabled,
|
||||||
|
window_tile_map_area,
|
||||||
|
window_enable,
|
||||||
|
bg_and_window_tile_area,
|
||||||
|
bg_tile_map_area,
|
||||||
|
object_size,
|
||||||
|
object_enable,
|
||||||
|
bg_and_window_enable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub(crate) struct FlagsRegister {
|
pub(crate) struct FlagsRegister {
|
||||||
pub(crate) zero: bool,
|
pub(crate) zero: bool,
|
||||||
pub(crate) subtract: bool,
|
pub(crate) subtract: bool,
|
||||||
@@ -7,6 +63,7 @@ pub(crate) struct FlagsRegister {
|
|||||||
pub(crate) carry: bool
|
pub(crate) carry: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ZERO_FLAG_BYTE_POSITION: u8 = 7;
|
const ZERO_FLAG_BYTE_POSITION: u8 = 7;
|
||||||
const SUBTRACT_FLAG_BYTE_POSITION: u8 = 6;
|
const SUBTRACT_FLAG_BYTE_POSITION: u8 = 6;
|
||||||
const HALF_CARRY_FLAG_BYTE_POSITION: u8 = 5;
|
const HALF_CARRY_FLAG_BYTE_POSITION: u8 = 5;
|
||||||
@@ -36,6 +93,7 @@ impl From<u8> for FlagsRegister {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct Registers {
|
pub(crate) struct Registers {
|
||||||
pub(crate) a: u8,
|
pub(crate) a: u8,
|
||||||
pub(crate) b: u8,
|
pub(crate) b: u8,
|
||||||
|
|||||||
Reference in New Issue
Block a user