Skip to content

Commit

Permalink
various instruction implementations and starting to implement stat in…
Browse files Browse the repository at this point in the history
…terrupt
  • Loading branch information
jonathanballs committed Sep 12, 2024
1 parent 5a82680 commit 798d860
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/cartridge/mbc1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl MBC for MBC1 {
match addr {
0x0..=0x1FFF => (), // enable ram in theory
0x2000..=0x3FFF => self.rom_bank = value & 0x1F,
0x6000..=0x7FFF => (), // banking mode
0xA000..=0xBFFF => self.ram[addr as usize - 0xA000] = value,
_ => {
dbg!(addr);
Expand Down
50 changes: 29 additions & 21 deletions src/cpu/execution/alu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,24 @@ impl CPU {
self.registers.set_r16(a, result);
}

pub(in crate::cpu) fn inc(&mut self, memory: &mut MMU, a: R8) {
let value = self.get_r8_byte(memory, a);
pub(in crate::cpu) fn inc(&mut self, mmu: &mut MMU, a: R8) {
let value = self.get_r8_byte(mmu, a);
let result = value.wrapping_add(1);
self.set_r8_byte(memory, a, result);
self.set_r8_byte(mmu, a, result);

self.registers.f.zero = result == 0;
self.registers.f.subtract = false;
// Half carry will occur when the lower nibble was 0b1111
self.registers.f.half_carry = (value & 0xF) == 0xF;
}

pub(in crate::cpu) fn dec(&mut self, mmu: &mut MMU, a: R8) {
let value = self.get_r8_byte(mmu, a);
pub(in crate::cpu) fn dec(&mut self, mmu: &mut MMU, r: R8) {
let value = self.get_r8_byte(mmu, r);
let result = value.wrapping_sub(1);
self.set_r8_byte(mmu, a, result);
self.set_r8_byte(mmu, r, result);

self.registers.f.zero = result == 0;
self.registers.f.subtract = false;
self.registers.f.subtract = true;
// Half carry will occur when the lower nibble was 0b0000
self.registers.f.half_carry = (value & 0xF) == 0x0;
}
Expand All @@ -85,12 +85,12 @@ impl CPU {
*
*/
pub(in crate::cpu) fn add(&mut self, b: u8) {
let result = self.registers.a.wrapping_add(b);
let (result, carry) = self.registers.a.overflowing_add(b);

self.registers.f.zero = result == 0;
self.registers.f.subtract = false;
// Carry if a and b go over 0xFF
self.registers.f.carry = (self.registers.a as u16) + (b as u16) > 0xFF;
self.registers.f.carry = carry;
// Half carry if the lower nibbles of a and b go over 0xF
self.registers.f.half_carry = (self.registers.a & 0xF) + (b & 0xF) > 0xF;

Expand All @@ -99,26 +99,25 @@ impl CPU {

pub(in crate::cpu) fn add_r16(&mut self, a_reg: R16, b: u16) {
let a = self.registers.get_r16(a_reg);
let result = a.wrapping_add(b);
let (result, carry) = a.overflowing_add(b);

self.registers.f.half_carry = (a & 0x0FFF) + (b & 0x0FFF) > 0x0FFF;
self.registers.f.subtract = false;
self.registers.f.carry = result < a;
self.registers.f.carry = carry;
self.registers.set_r16(a_reg, result);
}

pub(in crate::cpu) fn adc(&mut self, value: u8) {
let result = self
.registers
.a
.wrapping_add(value)
.wrapping_add(self.registers.f.carry as u8);
self.registers.a = result;
let a = self.registers.a;
let c = self.registers.f.carry as u8;
let result = a.wrapping_add(value).wrapping_add(c);

self.registers.f.zero = result == 0;
self.registers.f.carry = value > self.registers.a;
self.registers.f.half_carry = (value & 0x0F) == 0x0F; // Hmmmm...
self.registers.f.subtract = false;
self.registers.f.half_carry = (a as u16 & 0xF) + (value as u16 & 0xF) + c as u16 > 0xF;
self.registers.f.carry = (a as u16) + (value as u16) + (c as u16) > 0xFF;

self.registers.a = result;
}

pub(in crate::cpu) fn sub(&mut self, b: u8) {
Expand All @@ -136,7 +135,16 @@ impl CPU {
self.registers.f.carry = self.registers.a < b;
}

pub(in crate::cpu) fn sbc(&mut self, b: u8) {
self.sub(b.wrapping_add(self.registers.f.carry as u8));
pub(in crate::cpu) fn sbc(&mut self, value: u8) {
let a = self.registers.a;
let c = self.registers.f.carry as u8;
let result = a.wrapping_sub(value).wrapping_sub(c);

self.registers.f.zero = result == 0;
self.registers.f.subtract = true;
self.registers.f.half_carry = (a & 0xF).wrapping_sub(value & 0xF).wrapping_sub(c) > 0xF;
self.registers.f.carry = (a as u16) < (value as u16) + (c as u16);

self.registers.a = result;
}
}
27 changes: 24 additions & 3 deletions src/cpu/execution/bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl CPU {
}

pub(in crate::cpu) fn sla(&mut self, mmu: &mut MMU, reg: R8) {
let value = self.get_r8_byte(mmu, R8::A);
let value = self.get_r8_byte(mmu, reg);
let new_value = value << 1;
self.set_r8_byte(mmu, reg, new_value);

Expand All @@ -77,11 +77,11 @@ impl CPU {

pub(in crate::cpu) fn rlca(&mut self) {
let value = self.registers.a;
self.registers.f.carry = value >> 7 > 0;
self.registers.f.carry = value & 0x80 == 0x80;
self.registers.f.zero = false;
self.registers.f.half_carry = false;
self.registers.f.subtract = false;
self.registers.a = (self.registers.a << 1) | (self.registers.a >> 7);
self.registers.a = (value << 1) | (value >> 7);
}

pub(in crate::cpu) fn cpl(&mut self) {
Expand Down Expand Up @@ -113,6 +113,27 @@ impl CPU {
self.set_r8_byte(mmu, r, result);
}

pub(in crate::cpu) fn rra(&mut self, mmu: &mut MMU) {
self.rr(mmu, R8::A);
self.registers.f.zero = false;
}

pub(in crate::cpu) fn rrc(&mut self, mmu: &mut MMU, r: R8) {
let value = self.get_r8_byte(mmu, r);
let result = value >> 1 | (value << 7);
self.registers.f.carry = value & 1 > 0;
self.registers.f.half_carry = false;
self.registers.f.subtract = false;
self.registers.f.zero = result == 0;

self.set_r8_byte(mmu, r, result);
}

pub(in crate::cpu) fn rrca(&mut self, mmu: &mut MMU) {
self.rrc(mmu, R8::A);
self.registers.f.zero = false;
}

pub(in crate::cpu) fn daa(&mut self) {
let mut correction = 0;
let mut set_carry = false;
Expand Down
18 changes: 18 additions & 0 deletions src/cpu/execution/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,22 @@ impl CPU {
pub(in crate::cpu) fn ldh_addr(&mut self, mmu: &mut MMU, offset: u8, value: u8) {
mmu.write_byte(0xFF00 + offset as u16, value)
}

pub(in crate::cpu) fn ld_hl_sp(&mut self, e8: u8) {
let sp = self.registers.sp;
let offset = e8 as i8 as i16 as u16; // Convert i8 to u16 via i16 to preserve sign
let result = sp.wrapping_add(offset);

// Set flags based on the addition of the lower bytes
let half_carry = (sp & 0xF) + (offset & 0xF) > 0xF;
let carry = (sp & 0xFF) + (offset & 0xFF) > 0xFF;

self.registers.set_r16(R16::HL, result);

// Set flags
self.registers.f.zero = false;
self.registers.f.subtract = false;
self.registers.f.half_carry = half_carry;
self.registers.f.carry = carry;
}
}
15 changes: 15 additions & 0 deletions src/cpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ impl CPU {
Instruction::LdhImm8memA(offset) => self.ldh_addr(mmu, offset, self.registers.a),
Instruction::LdhAImm8mem(addr) => self.lda(mmu.read_byte(0xFF00 + addr as u16)),
Instruction::LdhACmem => self.lda(mmu.read_byte(0xFF00 + self.registers.c as u16)),
Instruction::LdHlSpImm8(n) => self.ld_hl_sp(n),
Instruction::LdSpHl => self.ld_r16(R16::SP, self.registers.get_r16(R16::HL)),

// Arithmetic
Instruction::IncR8(reg) => self.inc(mmu, reg),
Expand Down Expand Up @@ -85,6 +87,9 @@ impl CPU {
Instruction::SwapR8(reg) => self.swap(mmu, reg),
Instruction::Scf => self.scf(),
Instruction::RrR8(r) => self.rr(mmu, r),
Instruction::Rra => self.rra(mmu),
Instruction::Rrca => self.rrca(mmu),
Instruction::RrcR8(r) => self.rrc(mmu, r),

// Jump instructions
Instruction::JpImm16(addr) => self.jp(addr.wrapping_sub(length)),
Expand Down Expand Up @@ -130,6 +135,7 @@ impl CPU {
.yellow()
);
enable_debug();
dbg!(&instruction);
dbg!(self.registers.pc);
}
};
Expand Down Expand Up @@ -157,6 +163,15 @@ impl CPU {
self.registers.pc = 0x40;
}

// stat
if mmu.ie & 2 > 0 && mmu.ppu.stat_irq {
//mmu.ppu.stat_irq = false;
//self.ime = false;
//
//self.push(mmu, return_pc);
//self.registers.pc = 0x48;
}

// timer
if mmu.ie & 4 > 0 && mmu.timer.timer_irq {
mmu.timer.timer_irq = false;
Expand Down
1 change: 1 addition & 0 deletions src/mmu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl MMU {
// VBlank interrupt
0xFF0F => {
(self.ppu.vblank_irq as u8)
| ((self.ppu.stat_irq as u8) << 1)
| ((self.timer.timer_irq as u8) << 2)
| ((self.joypad.joypad_irq as u8) << 4)
}
Expand Down
41 changes: 37 additions & 4 deletions src/mmu/ppu.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
use std::{
thread,
fmt, thread,
time::{Duration, Instant},
};

use crate::debugger::is_gameboy_doctor;

const VRAM_SIZE: usize = 0x2000;
const VOAM_SIZE: usize = 0xA0;

pub type Tile = [[u8; 8]; 8];

#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct PPU {
frame_available: bool,
frame_number: u32,
last_frame_time: Instant,
pub vblank_irq: bool,
pub stat_irq: bool,

vram: [u8; VRAM_SIZE],
voam: [u8; VOAM_SIZE],
Expand Down Expand Up @@ -42,6 +45,7 @@ impl PPU {
frame_number: 1,
last_frame_time: Instant::now(),
vblank_irq: false,
stat_irq: false,

scy: 0,
scx: 0,
Expand Down Expand Up @@ -81,11 +85,15 @@ impl PPU {
self.vblank_irq = true
}

if self.ly == self.lyc && self.stat & 0x40 == 0x40 {
self.stat_irq = true;
}

// Frame finished - flush to screen
if self.ly == 0 {
// Calculate how long to sleep
let elapsed = self.last_frame_time.elapsed();
let frame_duration = Duration::from_secs_f64(1.0 / 240.0);
let frame_duration = Duration::from_secs_f64(1.0 / 60.0);

if elapsed < frame_duration {
thread::sleep(frame_duration - elapsed);
Expand All @@ -110,7 +118,16 @@ impl PPU {
0xFF10..=0xFF3F => return 0,

0xFF40 => self.lcdc,
0xFF41 => self.stat,
0xFF41 => {
let mut ret = self.stat & 0xF8;
if self.ly == self.lyc {
ret |= 0x4;
}

// just put it into mode 3...

return ret;
}
0xFF42 => self.scy,
0xFF43 => self.scx,
0xFF44 => {
Expand Down Expand Up @@ -219,3 +236,19 @@ impl PPU {
ret
}
}

impl fmt::Debug for PPU {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PPU")
.field("scy", &self.scy)
.field("scx", &self.scx)
.field("ly", &self.ly)
.field("lyc", &self.lyc)
.field("wy", &self.wy)
.field("wx", &self.wx)
.field("lcdc", &self.lcdc)
.field("bgp", &self.bgp)
.field("modeclock", &self.modeclock)
.finish()
}
}

0 comments on commit 798d860

Please sign in to comment.