Implement basic CPU architecture with instruction set
This commit sets up a foundational CPU simulation with registers, a memory bus, and an initial instruction set implementation in Rust. It includes operations like ADD, SUB, AND, and bit manipulations, as well as basic project configurations through Cargo and IDE settings.
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
11
.idea/dictionaries/project.xml
generated
Normal file
11
.idea/dictionaries/project.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="project">
|
||||||
|
<words>
|
||||||
|
<w>adchl</w>
|
||||||
|
<w>adcn</w>
|
||||||
|
<w>addhl</w>
|
||||||
|
<w>rrca</w>
|
||||||
|
<w>rrla</w>
|
||||||
|
</words>
|
||||||
|
</dictionary>
|
||||||
|
</component>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/untitled.iml" filepath="$PROJECT_DIR$/.idea/untitled.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
11
.idea/untitled.iml
generated
Normal file
11
.idea/untitled.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="EMPTY_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untitled"
|
||||||
|
version = "0.1.0"
|
||||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "untitled"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
308
src/instructions.rs
Normal file
308
src/instructions.rs
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
use crate::registers::Registers;
|
||||||
|
|
||||||
|
struct CPU {
|
||||||
|
registers: Registers,
|
||||||
|
pc: u16,
|
||||||
|
bus: MemoryBus,
|
||||||
|
sp: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MemoryBus {
|
||||||
|
memory: [u8; 0xFFFF]
|
||||||
|
}
|
||||||
|
impl MemoryBus {
|
||||||
|
fn read_byte(&self, address: u16) -> u8 {
|
||||||
|
self.memory[address as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Target {
|
||||||
|
U8Register(TargetRegister),
|
||||||
|
U16Register(TargetU16Register),
|
||||||
|
Address(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum Instruction {
|
||||||
|
ADC(Target),
|
||||||
|
ADD(Target),
|
||||||
|
ADDHL(TargetU16Register),
|
||||||
|
AND(Target),
|
||||||
|
|
||||||
|
SUB(TargetRegister),
|
||||||
|
SBC(TargetRegister),
|
||||||
|
|
||||||
|
OR(TargetRegister),
|
||||||
|
XOR(TargetRegister),
|
||||||
|
CP(TargetRegister),
|
||||||
|
INC(TargetRegister),
|
||||||
|
DEC(TargetRegister),
|
||||||
|
CCF,
|
||||||
|
SCF,
|
||||||
|
RRA,
|
||||||
|
RLA,
|
||||||
|
RRCA,
|
||||||
|
CPL,
|
||||||
|
BIT(u8, TargetRegister),
|
||||||
|
}
|
||||||
|
enum TargetRegister { A, B, C, D, E, H, L, }
|
||||||
|
enum TargetU16Register {AF, BC, DE, HL, SP, PC}
|
||||||
|
impl CPU {
|
||||||
|
fn get_u8_reg_value(&mut self, target: TargetRegister) -> u8 {
|
||||||
|
match target {
|
||||||
|
TargetRegister::A => { self.registers.a }
|
||||||
|
TargetRegister::B => { self.registers.b }
|
||||||
|
TargetRegister::C => { self.registers.c }
|
||||||
|
TargetRegister::D => { self.registers.d }
|
||||||
|
TargetRegister::E => { self.registers.e }
|
||||||
|
TargetRegister::H => { self.registers.h }
|
||||||
|
TargetRegister::L => { self.registers.l }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_u16_reg_value(&mut self, target: TargetU16Register) -> u16 {
|
||||||
|
match target {
|
||||||
|
TargetU16Register::AF => {self.registers.get_af()}
|
||||||
|
TargetU16Register::BC => {self.registers.get_bc()}
|
||||||
|
TargetU16Register::DE => {self.registers.get_de()}
|
||||||
|
TargetU16Register::HL => {self.registers.get_hl()}
|
||||||
|
TargetU16Register::SP => {self.sp}
|
||||||
|
TargetU16Register::PC => {self.pc}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_target_value(&mut self, target: Target) -> u8 {
|
||||||
|
match target {
|
||||||
|
Target::U8Register(target_register) => { self.get_u8_reg_value(target_register) },
|
||||||
|
Target::U16Register(target_register) => { self.bus.read_byte(self.get_u16_reg_value(target_register)) },
|
||||||
|
Target::Address(address) => { self.bus.read_byte(address) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
fn execute(&mut self, instruction: Instruction) {
|
||||||
|
match instruction {
|
||||||
|
Instruction::ADC(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let (mut new_value, did_overflow) = self.registers.a.overflowing_add(value);
|
||||||
|
new_value += did_overflow as u8;
|
||||||
|
self.registers.a = new_value;
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::ADD(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let (new_value, did_overflow) = self.registers.a.overflowing_add(value);
|
||||||
|
self.registers.a = new_value;
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::ADDHL(target) => {
|
||||||
|
let value = self.get_u16_reg_value(target);
|
||||||
|
let (new_value, did_overflow) = self.registers.get_hl().overflowing_add(value);
|
||||||
|
self.registers.set_hl(new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xFF) + (value & 0xFF) > 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::AND(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
self.registers.a = value & self.registers.a;
|
||||||
|
self.registers.f.zero = self.registers.a == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = false;
|
||||||
|
self.registers.f.half_carry = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Instruction::SUB(target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
let (new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
||||||
|
self.registers.a = new_value;
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::SBC(target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
let (mut new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
||||||
|
new_value -= did_overflow as u8;
|
||||||
|
self.registers.a = new_value;
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::OR(target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
self.registers.a = value | self.registers.a;
|
||||||
|
self.registers.f.zero = self.registers.a == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::XOR(target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
self.registers.a = value ^ self.registers.a;
|
||||||
|
self.registers.f.zero = self.registers.a == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::CP(target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
let (new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::INC(target) => {
|
||||||
|
let (value, new_value) = match target {
|
||||||
|
TargetRegister::A => {
|
||||||
|
let value = self.registers.a;
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.registers.a = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::B => {
|
||||||
|
let value = self.registers.b;
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.registers.b = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::C => {
|
||||||
|
let value = self.registers.c;
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.registers.c = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::D => {
|
||||||
|
let value = self.registers.d;
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.registers.d = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::E => {
|
||||||
|
let value = self.registers.e;
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.registers.e = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::H => {
|
||||||
|
let value = self.registers.h;
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.registers.h = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::L => {
|
||||||
|
let value = self.registers.l;
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.registers.l = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::DEC(target) => {
|
||||||
|
let (value, new_value) = match target {
|
||||||
|
TargetRegister::A => {
|
||||||
|
let value = self.registers.a;
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.registers.a = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::B => {
|
||||||
|
let value = self.registers.b;
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.registers.b = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::C => {
|
||||||
|
let value = self.registers.c;
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.registers.c = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::D => {
|
||||||
|
let value = self.registers.d;
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.registers.d = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::E => {
|
||||||
|
let value = self.registers.e;
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.registers.e = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::H => {
|
||||||
|
let value = self.registers.h;
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.registers.h = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
},
|
||||||
|
TargetRegister::L => {
|
||||||
|
let value = self.registers.l;
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.registers.l = new_value;
|
||||||
|
(value, new_value)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::CCF => {
|
||||||
|
self.registers.f.carry = !self.registers.f.carry;
|
||||||
|
}
|
||||||
|
Instruction::SCF => {
|
||||||
|
self.registers.f.carry = true;
|
||||||
|
}
|
||||||
|
Instruction::RRA => {
|
||||||
|
let old_carry = self.registers.f.carry;
|
||||||
|
self.registers.f.carry = self.registers.a & 0x1 == 0x1;
|
||||||
|
self.registers.a = (self.registers.a >> 1) | (if old_carry { 0x80 } else { 0 });
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::RLA => {
|
||||||
|
let old_carry = self.registers.f.carry;
|
||||||
|
self.registers.f.carry = self.registers.a & 0x80 == 0x80;
|
||||||
|
self.registers.a = (self.registers.a << 1) | (if old_carry { 0x01 } else { 0 });
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::RRCA => {
|
||||||
|
self.registers.f.carry = self.registers.a & 0x1 == 0x1;
|
||||||
|
self.registers.a = self.registers.a >> 1;
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::CPL => {
|
||||||
|
self.registers.a = !self.registers.a;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.half_carry = true;
|
||||||
|
}
|
||||||
|
Instruction::BIT(bit, target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
self.registers.f.zero = value >> bit & 0x1 == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/main.rs
Normal file
6
src/main.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
mod registers;
|
||||||
|
mod instructions;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
79
src/registers.rs
Normal file
79
src/registers.rs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) struct FlagsRegister {
|
||||||
|
pub(crate) zero: bool,
|
||||||
|
pub(crate) subtract: bool,
|
||||||
|
pub(crate) half_carry: bool,
|
||||||
|
pub(crate) carry: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZERO_FLAG_BYTE_POSITION: u8 = 7;
|
||||||
|
const SUBTRACT_FLAG_BYTE_POSITION: u8 = 6;
|
||||||
|
const HALF_CARRY_FLAG_BYTE_POSITION: u8 = 5;
|
||||||
|
const CARRY_FLAG_BYTE_POSITION: u8 = 4;
|
||||||
|
|
||||||
|
impl std::convert::From<FlagsRegister> for u8 {
|
||||||
|
fn from(flag: FlagsRegister) -> u8 {
|
||||||
|
(if flag.zero { 1 } else { 0 }) << ZERO_FLAG_BYTE_POSITION |
|
||||||
|
(if flag.subtract { 1 } else { 0 }) << SUBTRACT_FLAG_BYTE_POSITION |
|
||||||
|
(if flag.half_carry { 1 } else { 0 }) << HALF_CARRY_FLAG_BYTE_POSITION |
|
||||||
|
(if flag.carry { 1 } else { 0 }) << CARRY_FLAG_BYTE_POSITION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<u8> for FlagsRegister {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
let zero = ((byte >> ZERO_FLAG_BYTE_POSITION) & 0b1) != 0;
|
||||||
|
let subtract = ((byte >> SUBTRACT_FLAG_BYTE_POSITION) & 0b1) != 0;
|
||||||
|
let half_carry = ((byte >> HALF_CARRY_FLAG_BYTE_POSITION) & 0b1) != 0;
|
||||||
|
let carry = ((byte >> CARRY_FLAG_BYTE_POSITION) & 0b1) != 0;
|
||||||
|
|
||||||
|
FlagsRegister {
|
||||||
|
zero,
|
||||||
|
subtract,
|
||||||
|
half_carry,
|
||||||
|
carry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) struct Registers {
|
||||||
|
pub(crate) a: u8,
|
||||||
|
pub(crate) b: u8,
|
||||||
|
pub(crate) c: u8,
|
||||||
|
pub(crate) d: u8,
|
||||||
|
pub(crate) e: u8,
|
||||||
|
pub(crate) f: FlagsRegister,
|
||||||
|
pub(crate) h: u8,
|
||||||
|
pub(crate) l: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registers {
|
||||||
|
pub(crate) fn get_af(&self) -> u16 {
|
||||||
|
(self.a as u16) << 8 | u8::from(self.f) as u16
|
||||||
|
}
|
||||||
|
pub(crate) fn set_af(&mut self, value: u16) {
|
||||||
|
self.a = ((value & 0xFF00) >> 8) as u8;
|
||||||
|
self.f = FlagsRegister::from((value & 0xFF) as u8);
|
||||||
|
}
|
||||||
|
pub(crate) fn get_bc(&self) -> u16 {
|
||||||
|
(self.b as u16) << 8 | self.c as u16
|
||||||
|
}
|
||||||
|
pub(crate) fn set_bc(&mut self, value: u16) {
|
||||||
|
self.b = ((value & 0xFF00) >> 8) as u8;
|
||||||
|
self.c = (value & 0xFF) as u8;
|
||||||
|
}
|
||||||
|
pub(crate) fn get_de(&self) -> u16 {
|
||||||
|
(self.d as u16) << 8 | self.e as u16
|
||||||
|
}
|
||||||
|
pub(crate) fn set_de(&mut self, value: u16) {
|
||||||
|
self.d = ((value & 0xFF00) >> 8) as u8;
|
||||||
|
self.e = (value & 0xFF) as u8;
|
||||||
|
}
|
||||||
|
pub(crate) fn get_hl(&self) -> u16 {
|
||||||
|
(self.h as u16) << 8 | self.l as u16
|
||||||
|
}
|
||||||
|
pub(crate) fn set_hl(&mut self, value: u16) {
|
||||||
|
self.h = ((value & 0xFF00) >> 8) as u8;
|
||||||
|
self.l = (value & 0xFF) as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user