serial as mmio peripheral
This commit is contained in:
parent
2609fb966d
commit
c622a2ae4a
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
mod apu;
|
||||
mod joypad;
|
||||
mod serial;
|
||||
pub use apu::Apu;
|
||||
pub use joypad::Joypad;
|
||||
pub use serial::Serial;
|
||||
|
|
99
src/processor/memory/mmio/serial.rs
Normal file
99
src/processor/memory/mmio/serial.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue