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:
2025-04-26 08:40:42 +01:00
commit e6113316bf
11 changed files with 453 additions and 0 deletions

308
src/instructions.rs Normal file
View 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
View File

@@ -0,0 +1,6 @@
mod registers;
mod instructions;
fn main() {
println!("Hello, world!");
}

79
src/registers.rs Normal file
View 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;
}
}