aboutsummaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/chip.rs197
1 files changed, 186 insertions, 11 deletions
diff --git a/src/cpu/chip.rs b/src/cpu/chip.rs
index eb117c9..8c9032e 100644
--- a/src/cpu/chip.rs
+++ b/src/cpu/chip.rs
@@ -74,6 +74,27 @@ impl From<u8> for REGISTER16MEM {
}
#[derive(Debug)]
+enum REGISTER16STK {
+ UD = -1,
+ BC = 0,
+ DE = 1,
+ HL = 2,
+ AF = 3,
+}
+
+impl From<u8> for REGISTER16STK {
+ fn from(value: u8) -> Self {
+ match value {
+ 0 => REGISTER16STK::BC,
+ 1 => REGISTER16STK::DE,
+ 2 => REGISTER16STK::HL,
+ 3 => REGISTER16STK::AF,
+ _ => REGISTER16STK::UD
+ }
+ }
+}
+
+#[derive(Debug)]
pub struct Flags {
pub zero: u8, //Zero flag
pub n: u8, //Subtraction flag (BCD)
@@ -90,6 +111,17 @@ impl Flags {
carry: 0,
}
}
+
+ fn get_cond(&self, cond: u8) -> u16 {
+ match cond {
+ 0 => { (self.n as u16) << 8 | self.zero as u16 }
+ 1 => { self.zero as u16 }
+ 2 => { (self.n as u16) << 8 | self.carry as u16 }
+ 3 => { self.carry as u16 }
+ _ => { panic!("Invalid Condition for Flags!") }
+
+ }
+ }
}
#[derive(Debug)]
@@ -107,6 +139,7 @@ pub struct Chip {
pub byte2: u8,
pub byte3: u8,
pub flags: Flags, //Lower bits of AF, Flags register
+ pub ime: u8, // IME (Interrupt) flag
pub rom_bank_0: [u8; 16384],
pub rom_bank_n: [u8; 16384],
pub external_ram_bank_n: [u8; 8192],
@@ -132,6 +165,7 @@ impl Chip {
byte2: 0,
byte3: 0,
flags: Flags::new(),
+ ime: 0,
rom_bank_0: [0; 16384],
rom_bank_n: [0; 16384],
external_ram_bank_n: [00; 8192],
@@ -298,6 +332,47 @@ impl Chip {
_ => { panic!("Cannot get register address: Unknown register code {:?}", register_code) }
}
}
+
+
+ // Get the memory address pointed to by a register pair. This is basically the r16stk table
+ // This returns a 16 bit memory address
+ fn get_r16stk_register(&mut self, register_code: REGISTER16STK) -> u16 {
+
+ match register_code {
+ REGISTER16STK::BC => { (self.b as u16) << 8 | self.c as u16 },
+ REGISTER16STK::DE => { (self.d as u16) << 8 | self.e as u16 },
+ REGISTER16STK::HL => { (self.h as u16) << 8 | self.l as u16 },
+ REGISTER16STK::AF => {
+ // We do this because in reality, the flags are just a single register F, and the bit shift
+ // corresponds to the flag position in the register byte
+ let f = self.flags.zero << 7 | self.flags.n << 6 | self.flags.h << 5 | self.flags.carry << 4;
+ (self.a as u16) << 8 | f as u16
+ },
+ _ => { panic!("Cannot get register address: Unknown register code {:?}", register_code) }
+ }
+ }
+
+ // Set the memory address pointed to by a register pair. This is basically the r16stk table
+ // This returns a 16 bit memory address
+ fn set_r16stk_register(&mut self, register_code: REGISTER16STK, value: u16) {
+ let high = (value >> 8) as u8;
+ let low = (value & 0xff) as u8;
+ match register_code {
+ REGISTER16STK::BC => { self.b = high; self.c = low; },
+ REGISTER16STK::DE => { self.d = high; self.e = low; },
+ REGISTER16STK::HL => { self.h = high; self.l = low; },
+ REGISTER16STK::AF => {
+ // We do this because in reality, the flags are just a single register F, and the bit shift
+ // corresponds to the flag position in the register byte
+ self.a = high;
+ self.flags.zero = low & 0b10000000;
+ self.flags.n = low & 0b01000000;
+ self.flags.h = low & 0b00100000;
+ self.flags.carry = low & 0b00010000;
+ },
+ _ => { panic!("Cannot get register address: Unknown register code {:?}", register_code) }
+ }
+ }
// Return the half-carry and carry of adding two u8s
fn check_carry_add_u8(&self, lhs: u8, rhs: u8) -> (bool, bool) {
@@ -328,7 +403,7 @@ impl Chip {
println!("{:b} {:b} {:b}", oct1, oct2, oct3);
match (oct1, oct2, oct3) {
- (0b11, 0b001, 0b001) => { }, //CB-prefixed instructions
+ // (0b11, 0b001, 0b001) => { }, //CB-prefixed instructions
(0b00, 0b000, 0b000) => { println!("NOOP") }, //noop
(0b00, 0b001, 0b000) => { self.ld_u16_sp() }, //LD (u16), SP
(0b00, 0b010, 0b000) => { println!("STOP") }, //STOP
@@ -347,21 +422,27 @@ impl Chip {
(0b01, 0b110, 0b110) => { self.halt() }, //HALT
(0b01, dst_r8, src_r8) => { self.ld_r8_r8(src_r8, dst_r8) }, //LD r8, r8
(0b10, op, r8) => { self.alu_a_r8(op, r8); }, //ALU A, r8
- (0b11, 0b000..=0b011, 0b000) => { }, //RET condition
+ (0b11, 0b000..=0b011, 0b000) => { self.ret_cond(oct2) }, //RET condition
(0b11, 0b100, 0b000) => { self.ldh_i16_a() }, //LD (FF00 + u8), A
(0b11, 0b101, 0b000) => { self.add_sp_i8() }, //ADD SP, i8
(0b11, 0b110, 0b000) => { self.ldh_a_i16() }, //LD A, (FF00 + u8)
(0b11, 0b111, 0b000) => { self.ld_hl_sp_imm8() }, //LD HL, SP + i8
(0b11, 0b000|0b010|0b100|0b110, 0b001) => { self.pop_r16(oct2) }, //POP r16
- (0b11, 0b001|0b011|0b101|0b111, 0b001) => { }, //0: RET, 1: RETI, 2: JP HL, 3: LD SP, HL
- (0b11, 0b000..=0b011, 0b010) => { }, //JP
- (0b11, 0b100, 0b010) => { }, //LD (FF00 + C), A
- (0b11, 0b101, 0b010) => { }, //LD (u16), A
- (0b11, 0b110, 0b010) => { }, //LD A, (FF00 + C)
- (0b11, 0b111, 0b010) => { }, //LD A, (u16)
- (0b11, opcode, 0b011) => { }, //0: JP u16, 1: CB prefix, 6: DI, 7: EI
+ (0b11, 0b001, 0b001) => { self.ret() }, // RET
+ (0b11, 0b011, 0b001) => { self.reti() }, // RETI
+ (0b11, 0b101, 0b001) => { self.jp_hl() }, // JP HL
+ (0b11, 0b111, 0b001) => { self.ld_sp_hl() }, // LD SP, HL
+ (0b11, 0b000..=0b011, 0b010) => { self.jp_cond(oct2) }, //JP
+ (0b11, 0b100, 0b010) => { self.ldh_c_a() }, //LD (FF00 + C), A
+ (0b11, 0b101, 0b010) => { self.ld_n16_a() }, //LD (u16), A
+ (0b11, 0b110, 0b010) => { self.ldh_a_c() }, //LD A, (FF00 + C)
+ (0b11, 0b111, 0b010) => { self.ld_a_n16() }, //LD A, (u16)
+ (0b11, 0b000, 0b011) => { self.jp_u16() }, //JP u16
+ (0b11, 0b001, 0b011) => { }, //CB prefix
+ (0b11, 0b110, 0b011) => { self.di() }, //DI
+ (0b11, 0b111, 0b011) => { self.ei() }, //EI
(0b11, 0b000..=0b011, 0b100) => { }, //CALL condition
- (0b11, 0b000|0b010|0b100|0b110, 0b101) => { }, //PUSH r16
+ (0b11, 0b000|0b010|0b100|0b110, 0b101) => { self.push_r16(oct2) }, //PUSH r16
(0b11, 0b001, 0b101) => { }, //CALL u16
(0b11, opcode, 0b110) => { }, //ALU a, u8
(0b11, exp, 0b111) => { }, //RST
@@ -371,6 +452,100 @@ impl Chip {
self.pc += next;
}
+
+
+ fn ei(&mut self) {
+ self.ime = 1;
+ }
+ fn di(&mut self) {
+ self.ime = 0;
+ }
+
+ // Jump to address u16
+ fn jp_u16(&mut self) {
+ let address = (self.byte2 as u16) << 8 | self.byte3 as u16;
+ self.pc = address;
+ }
+
+ // Jump based on condition
+ fn jp_cond(&mut self, cond: u8) {
+ // If condition true, JUMP
+ if self.flags.get_cond(cond) != 0 {
+ self.jp_u16();
+ }
+ }
+
+ // Load value of HL into SP
+ fn ld_sp_hl(&mut self) {
+ self.sp = self.get_r16_register(REGISTER16::SP);
+ }
+ // Jump to address to HL
+ fn jp_hl(&mut self) {
+ self.pc = self.get_r16_register(REGISTER16::HL);
+ }
+
+ // Enable interrupts and RETURN
+ fn reti(&mut self) {
+ // Enable interrupt
+ self.ei();
+ self.ret();
+ }
+
+ // RETURN
+ fn ret(&mut self) {
+ let low = self.read_memory(self.sp);
+ self.sp += 1;
+ let high = self.read_memory(self.sp);
+ self.sp += 1;
+ let value = (((high as u16) << 8) as u16) | (low as u16);
+ self.pc = value;
+ }
+ // RETURN based on condition
+ fn ret_cond(&mut self, ret_code: u8) {
+ // If condition true, RET
+ if self.flags.get_cond(ret_code) != 0 {
+ self.ret();
+ }
+ }
+
+ // Push to stack
+ fn push_r16(&mut self, r16: u8) {
+ let value = self.get_r16stk_register(r16.into());
+ let high = (value >> 8) as u8;
+ let low = (value & 0xff) as u8;
+ self.sp -= 1;
+ self.write_memory(self.sp, high);
+ self.sp -= 1;
+ self.write_memory(self.sp, low);
+ }
+
+ // Load value in reg A from [n16]
+ fn ld_a_n16(&mut self) {
+ let address = (self.byte2 as u16) << 8 | self.byte3 as u16;
+ let value = self.read_memory(address);
+ self.set_r8_register(REGISTER8::A, value);
+ }
+
+ // Load [0xff00 + c] into reg A
+ fn ldh_a_c(&mut self) {
+ let address = 0xff00 + self.get_r8_register(REGISTER8::C) as u16;
+ let value = self.read_memory(address);
+ self.set_r8_register(REGISTER8::A, value);
+ }
+
+ // Load reg A value into memory address byte2 << 8|byte3
+ fn ld_n16_a(&mut self) {
+ let value = self.get_r8_register(REGISTER8::A);
+ let address = (self.byte2 as u16) << 8 | self.byte3 as u16;
+ self.write_memory(address, value);
+ }
+ // Load value in register A into $ff00 + C
+ fn ldh_c_a(&mut self) {
+ let value = self.get_r8_register(REGISTER8::A);
+ let address = self.get_r8_register(REGISTER8::C);
+ self.write_memory(0xff00 + address as u16, value)
+ }
+
// POP address from stack and save to register
fn pop_r16(&mut self, r16: u8) {
let low = self.read_memory(self.sp);
@@ -378,7 +553,7 @@ impl Chip {
let high = self.read_memory(self.sp);
self.sp += 1;
let value = (((high as u16) << 8) as u16) | (low as u16);
- self.set_r16_register(r16.into(), value);
+ self.set_r16stk_register(r16.into(), value);
}