Compare commits
No commits in common. "aa22e93049a9c77cf5442738fee6c5a89d886b4d" and "a77d0a0f62aa62032a3bc21c7f37f25e3775d5b1" have entirely different histories.
aa22e93049
...
a77d0a0f62
|
@ -164,7 +164,8 @@ impl Apu {
|
|||
|
||||
if self.ctrl.enabled {
|
||||
// Frame Sequencer reset to Step 0
|
||||
// TODO: With the current implementation of the frame sequencer, what does this even mean?
|
||||
// TODO: With the current implementation of the frame sequencer,
|
||||
// what does this even mean?
|
||||
|
||||
// Square Duty units are reset to first step
|
||||
self.ch1.duty_pos = 0;
|
||||
|
@ -180,6 +181,8 @@ impl Apu {
|
|||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
// TODO: Clear readable sound registers
|
||||
|
||||
self.ch1.sweep = Default::default();
|
||||
self.ch1.duty = Default::default();
|
||||
self.ch1.envelope = Default::default();
|
||||
|
@ -423,6 +426,7 @@ impl Channel1 {
|
|||
}
|
||||
|
||||
if self.freq_timer == 0 {
|
||||
// TODO: Why is this 2048?
|
||||
self.freq_timer = (2048 - self.frequency()) * 4;
|
||||
self.duty_pos = (self.duty_pos + 1) % 8;
|
||||
}
|
||||
|
@ -568,6 +572,7 @@ impl Channel2 {
|
|||
}
|
||||
|
||||
if self.freq_timer == 0 {
|
||||
// TODO: Why is this 2048?
|
||||
self.freq_timer = (2048 - self.frequency()) * 4;
|
||||
self.duty_pos = (self.duty_pos + 1) % 8;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ pub(crate) mod ch4 {
|
|||
pub struct Frequency(u8);
|
||||
impl Debug;
|
||||
_initial, _: 7;
|
||||
_length_disable, _: 6;
|
||||
_length_disable, _: 6; // TODO: same as FrequencyHigh, figure out what this is
|
||||
}
|
||||
|
||||
impl Frequency {
|
||||
|
@ -224,7 +224,7 @@ pub(crate) mod common {
|
|||
pub struct FrequencyHigh(u8);
|
||||
impl Debug;
|
||||
_initial, _: 7;
|
||||
_length_disable, _: 6;
|
||||
_length_disable, _: 6; // TODO: Figure out what the hell this is
|
||||
pub freq_bits, set_freq_bits: 2, 0;
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ pub(crate) mod common {
|
|||
pub struct SoundDuty(u8);
|
||||
impl Debug;
|
||||
from into WavePattern, _wave_pattern, _: 7, 6;
|
||||
_sound_length, _: 5, 0;
|
||||
_sound_length, _: 5, 0; // TODO: Getter only used if bit 6 in NR14 is set
|
||||
}
|
||||
|
||||
impl SoundDuty {
|
||||
|
|
|
@ -240,6 +240,7 @@ impl BusIo for Bus {
|
|||
0x49 => self.ppu.monochrome.obj_palette_1.into(),
|
||||
0x4A => self.ppu.pos.window_y,
|
||||
0x4B => self.ppu.pos.window_x,
|
||||
0x4D => 0xFF, // TODO: CGB Specific Register
|
||||
_ => {
|
||||
eprintln!("Read 0xFF from unused IO register {:#06X}.", addr);
|
||||
0xFF
|
||||
|
@ -311,7 +312,7 @@ impl BusIo for Bus {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
0xFEA0..=0xFEFF => {} // FIXME: As far as I know, writes to here do nothing.
|
||||
0xFEA0..=0xFEFF => {} // TODO: As far as I know, writes to here do nothing.
|
||||
0xFF00..=0xFF7F => {
|
||||
// IO Registers
|
||||
|
||||
|
|
|
@ -114,7 +114,10 @@ impl Cartridge {
|
|||
}
|
||||
|
||||
fn find_mbc(memory: &[u8]) -> MBCKind {
|
||||
match memory[MBC_TYPE_ADDRESS] {
|
||||
let id = memory[MBC_TYPE_ADDRESS];
|
||||
|
||||
// TODO: Refactor this to match the other enums in this module
|
||||
match id {
|
||||
0x00 => MBCKind::None,
|
||||
0x01 => MBCKind::MBC1,
|
||||
0x02 => MBCKind::MBC1,
|
||||
|
@ -122,7 +125,7 @@ impl Cartridge {
|
|||
0x19 => MBCKind::MBC5,
|
||||
0x13 => MBCKind::MBC3WithBattery,
|
||||
0x11 => MBCKind::MBC3,
|
||||
id => unimplemented!("id {:#04X} is an unsupported MBC", id),
|
||||
_ => unimplemented!("id {:#04X} is an unsupported MBC", id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
36
src/cpu.rs
36
src/cpu.rs
|
@ -14,6 +14,8 @@ pub struct Cpu {
|
|||
reg: Registers,
|
||||
flags: Flags,
|
||||
ime: ImeState,
|
||||
// TODO: Merge halted and state properties
|
||||
halted: Option<HaltKind>,
|
||||
state: State,
|
||||
}
|
||||
|
||||
|
@ -43,34 +45,24 @@ impl Cpu {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn ime(&self) -> ImeState {
|
||||
self.ime
|
||||
pub(crate) fn ime(&self) -> &ImeState {
|
||||
&self.ime
|
||||
}
|
||||
|
||||
pub(crate) fn set_ime(&mut self, state: ImeState) {
|
||||
self.ime = state;
|
||||
}
|
||||
|
||||
pub(crate) fn halt_cpu(&mut self, kind: HaltKind) {
|
||||
self.state = State::Halt(kind);
|
||||
pub(crate) fn halt(&mut self, state: HaltKind) {
|
||||
self.halted = Some(state);
|
||||
}
|
||||
|
||||
fn resume_execution(&mut self) {
|
||||
self.state = State::Execute;
|
||||
fn resume(&mut self) {
|
||||
self.halted = None;
|
||||
}
|
||||
|
||||
pub(crate) fn is_halted(&self) -> bool {
|
||||
match self.state {
|
||||
State::Halt(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn halt_kind(&self) -> Option<HaltKind> {
|
||||
match self.state {
|
||||
State::Halt(kind) => Some(kind),
|
||||
_ => None,
|
||||
}
|
||||
pub(crate) fn halted(&self) -> Option<HaltKind> {
|
||||
self.halted
|
||||
}
|
||||
|
||||
pub fn load_cartridge(&mut self, path: &str) -> std::io::Result<()> {
|
||||
|
@ -127,7 +119,7 @@ impl Cpu {
|
|||
return elapsed;
|
||||
}
|
||||
|
||||
if let Some(kind) = self.halt_kind() {
|
||||
if let Some(kind) = self.halted() {
|
||||
use HaltKind::*;
|
||||
|
||||
self.bus.clock();
|
||||
|
@ -200,7 +192,7 @@ impl Cpu {
|
|||
let enable = self.int_enable();
|
||||
|
||||
// TODO: Ensure that this behaviour is correct
|
||||
if self.is_halted() {
|
||||
if self.halted.is_some() {
|
||||
// When we're here either a HALT with IME set or
|
||||
// a HALT with IME not set and No pending Interrupts was called
|
||||
|
||||
|
@ -209,7 +201,7 @@ impl Cpu {
|
|||
// nothing actually needs to be added here. This is just documentation
|
||||
// since it's a bit weird why nothing is being done
|
||||
|
||||
self.resume_execution();
|
||||
self.resume();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,7 +264,7 @@ impl Cpu {
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
enum State {
|
||||
Execute,
|
||||
Halt(HaltKind),
|
||||
// Halt,
|
||||
// Stop,
|
||||
}
|
||||
|
||||
|
|
|
@ -590,12 +590,12 @@ impl Instruction {
|
|||
// HALT | Enter CPU low power consumption mode until interrupt occurs
|
||||
use HaltKind::*;
|
||||
|
||||
let kind = match cpu.ime() {
|
||||
let kind = match *cpu.ime() {
|
||||
ImeState::Enabled => ImeEnabled,
|
||||
_ if cpu.int_request() & cpu.int_enable() != 0 => SomePending,
|
||||
_ => NonePending,
|
||||
};
|
||||
cpu.halt_cpu(kind);
|
||||
cpu.halt(kind);
|
||||
Cycle::new(4)
|
||||
}
|
||||
Instruction::ADC(source) => match source {
|
||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -63,16 +63,16 @@ fn main() -> Result<()> {
|
|||
};
|
||||
|
||||
// Initialize Audio
|
||||
// let spsc: AudioSPSC<f32> = Default::default();
|
||||
// let (prod, cons) = spsc.init();
|
||||
// let (_stream, stream_handle) = OutputStream::try_default().expect("Initialized Audio");
|
||||
// let sink = Sink::try_new(&stream_handle)?;
|
||||
// sink.append(cons);
|
||||
// game_boy.apu_mut().set_producer(prod);
|
||||
let spsc: AudioSPSC<f32> = Default::default();
|
||||
let (prod, cons) = spsc.init();
|
||||
let (_stream, stream_handle) = OutputStream::try_default().expect("Initialized Audio");
|
||||
let sink = Sink::try_new(&stream_handle)?;
|
||||
sink.append(cons);
|
||||
game_boy.apu_mut().set_producer(prod);
|
||||
|
||||
// std::thread::spawn(move || {
|
||||
// sink.sleep_until_end();
|
||||
// });
|
||||
std::thread::spawn(move || {
|
||||
sink.sleep_until_end();
|
||||
});
|
||||
|
||||
let mut start = Instant::now();
|
||||
let frame_time = Duration::from_secs_f64(1.0 / 59.73); // 59.73 Hz on Host
|
||||
|
|
Loading…
Reference in New Issue