serial as mmio peripheral

This commit is contained in:
Alex Janka 2023-02-21 10:10:24 +11:00
parent 2609fb966d
commit c622a2ae4a
5 changed files with 137 additions and 46 deletions

View file

@ -1,9 +1,9 @@
use self::mmio::{Apu, Joypad};
use self::mmio::{Apu, Joypad, Serial};
pub use self::rom::Rom;
use crate::{processor::SplitRegister, verbose_println};
use crate::{processor::SplitRegister, util::set_bit, verbose_println, Cpu};
use gilrs::ConnectedGamepadsIterator;
use minifb::Key;
use std::io::{stdout, Write};
// use std::io::{stdout, Write};
mod mmio;
pub(crate) mod rom;
@ -27,12 +27,11 @@ pub struct Memory {
pub(super) user_mode: bool,
joypad: Joypad,
apu: Apu,
serial: Serial,
}
impl Memory {
pub fn init(bootrom: Vec<u8>, bootrom_enabled: bool, rom: Rom) -> Self {
let mut apu = Apu::default();
apu.init();
Self {
bootrom,
bootrom_enabled,
@ -48,7 +47,8 @@ impl Memory {
io: [0xFF; 76],
user_mode: false,
joypad: Joypad::default(),
apu,
apu: Apu::init_default(),
serial: Serial::default(),
}
}
@ -85,33 +85,16 @@ impl Memory {
// change this with MBC code...
self.rom.set(address, data);
}
0x8000..0xA000 => {
self.vram[(address - 0x8000) as usize] = data;
}
0xA000..0xC000 => {
self.rom.set_ram(address, data);
}
0xC000..0xE000 => {
self.ram[(address - 0xC000) as usize] = data;
}
0xE000..0xFE00 => {
self.ram[(address - 0xE000) as usize] = data;
}
0xFE00..0xFEA0 => {
self.oam[(address - 0xFE00) as usize] = data;
}
0x8000..0xA000 => self.vram[(address - 0x8000) as usize] = data,
0xA000..0xC000 => self.rom.set_ram(address, data),
0xC000..0xE000 => self.ram[(address - 0xC000) as usize] = data,
0xE000..0xFE00 => self.ram[(address - 0xE000) as usize] = data,
0xFE00..0xFEA0 => self.oam[(address - 0xFE00) as usize] = data,
0xFEA0..0xFF00 => {}
0xFF00..0xFF4C => {
self.set_io(address, data);
stdout().flush().unwrap();
}
0xFF50 => {
self.bootrom_enabled = false;
}
0xFF00..0xFF4C => self.set_io(address, data),
0xFF50 => self.bootrom_enabled = false,
0xFF4C..0xFF50 | 0xFF51..0xFF80 => {}
0xFF80..0xFFFF => {
self.cpu_ram[(address - 0xFF80) as usize] = data;
}
0xFF80..0xFFFF => self.cpu_ram[(address - 0xFF80) as usize] = data,
0xFFFF => {
verbose_println!("interrupts set to {:#b}", data);
verbose_println!(" / {:#X}", data);
@ -124,6 +107,8 @@ impl Memory {
// range: 0xFF00 - 0xFF4B inclusive
match address {
0xFF00 => self.joypad.as_register(),
0xFF01 => self.serial.get_queued(),
0xFF02 => self.serial.get_control(),
0xFF10..0xFF40 => self.apu.get_register(address),
_ => self.io[(address - 0xFF00) as usize],
}
@ -140,12 +125,8 @@ impl Memory {
// joypad
self.joypad.mmio_write(data);
}
0xFF02 => {
if data == 0x81 {
print!("{}", self.get(0xFF01) as char);
stdout().flush().unwrap();
}
}
0xFF01 => self.serial.update_queued(data),
0xFF02 => self.serial.update_control(data),
0xFF04 => self.io[addr_l] = 0,
0xFF07 => self.masked_io(addr_l, data, 0b111),
0xFF0F => self.masked_io(addr_l, data, 0b11111),
@ -219,6 +200,15 @@ impl Memory {
}
}
impl Cpu {
pub fn advance_mmio_clocks(&mut self, steps: usize) {
self.memory.apu.tick(steps);
if self.memory.serial.tick(steps) {
self.memory.set(0xFF0F, set_bit(self.memory.get(0xFF0F), 3));
}
}
}
pub fn masked_update(current: u8, data: u8, mask: u8) -> u8 {
(current & (!mask)) | (data & mask)
}

View file

@ -1,6 +1,6 @@
use self::types::{Channels, DacSample, Mixer, VinEnable, Volume};
use crate::{
processor::{memory::Address, timer::CLOCK_SPEED, Cpu},
processor::{memory::Address, timer::CLOCK_SPEED},
util::{get_bit, set_or_clear_bit},
};
use async_ringbuf::{AsyncHeapProducer, AsyncHeapRb};
@ -95,6 +95,12 @@ impl Default for Apu {
const CYCLES_PER_FRAME: usize = 70224;
impl Apu {
pub fn init_default() -> Self {
let mut r = Self::default();
r.init();
r
}
pub fn init(&mut self) {
let sample_rate = self.config.sample_rate.0;
let rb_len = sample_rate as usize / 60;
@ -150,7 +156,7 @@ impl Apu {
}
}
fn tick(&mut self, steps: usize) {
pub fn tick(&mut self, steps: usize) {
self.buffer.append(
&mut izip!(
self.channels.one.tick(steps).into_iter(),
@ -303,9 +309,3 @@ impl Apu {
}
}
}
impl Cpu {
pub fn advance_apu_clock(&mut self, steps: usize) {
self.memory.apu.tick(steps);
}
}

View file

@ -1,4 +1,6 @@
mod apu;
mod joypad;
mod serial;
pub use apu::Apu;
pub use joypad::Joypad;
pub use serial::Serial;

View file

@ -0,0 +1,99 @@
use std::io::{stdout, Write};
use crate::util::get_bit;
enum ClockSource {
Internal,
External,
}
#[allow(dead_code)]
enum ClockSpeed {
Normal,
Fast,
}
#[allow(dead_code)]
struct SerialControl {
transfer_in_progress: bool,
clock_speed: ClockSpeed,
clock_source: ClockSource,
}
impl Default for SerialControl {
fn default() -> Self {
Self {
transfer_in_progress: false,
clock_speed: ClockSpeed::Normal,
clock_source: ClockSource::Internal,
}
}
}
pub struct Serial {
byte: u8,
bits_transferred: u8,
control: SerialControl,
}
impl Serial {
pub fn tick(&mut self, steps: usize) -> bool {
let mut will_interrupt = false;
for _ in 0..steps {
if self.control.transfer_in_progress {
let (remainder, finished) = self.bits_transferred.overflowing_sub(1);
self.bits_transferred = if finished {
self.control.transfer_in_progress = false;
will_interrupt = true;
print!("{}", self.byte as char);
stdout().flush().unwrap();
7
} else {
remainder
}
}
}
will_interrupt
}
pub fn update_queued(&mut self, data: u8) {
self.byte = data;
}
pub fn get_queued(&self) -> u8 {
self.byte
}
pub fn update_control(&mut self, data: u8) {
self.control.transfer_in_progress = get_bit(data, 7);
// CGB - add clock speed
self.control.clock_source = if get_bit(data, 0) {
ClockSource::Internal
} else {
ClockSource::External
};
}
pub fn get_control(&self) -> u8 {
0b01111110
| (if self.control.transfer_in_progress {
0b1
} else {
0b0
} << 7)
| match self.control.clock_source {
ClockSource::Internal => 0b1,
ClockSource::External => 0b0,
}
}
}
impl Default for Serial {
fn default() -> Self {
Self {
byte: 0,
bits_transferred: 7,
control: SerialControl::default(),
}
}
}

View file

@ -28,7 +28,7 @@ impl Cpu {
let clock_cycles = (machine_cycles as usize) * 4;
self.advance_gpu_clock(clock_cycles);
self.advance_apu_clock(clock_cycles);
self.advance_mmio_clocks(clock_cycles);
self.timers.div_counter += clock_cycles;
let mut div_diff = (self.timers.div_counter / 256) as u8;