spaces
This commit is contained in:
parent
53b4454f98
commit
e4d8bba720
|
@ -18,22 +18,22 @@ impl DMC {
|
|||
}
|
||||
|
||||
pub fn clock(&mut self) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub fn write_control(&mut self, value: u8) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub fn direct_load(&mut self, value: u8) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub fn write_sample_address(&mut self, value: u8) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub fn write_sample_length(&mut self, value: u8) {
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ pub struct Apu {
|
|||
triangle: Triangle,
|
||||
noise: Noise,
|
||||
dmc: DMC,
|
||||
|
||||
|
||||
square_table: Vec<f32>,
|
||||
tnd_table: Vec<f32>,
|
||||
|
||||
|
@ -234,7 +234,7 @@ impl Apu {
|
|||
fn write_frame_counter(&mut self, value: u8) {
|
||||
// 0 selects 4-step sequence, 1 selects 5-step sequence
|
||||
self.frame_sequence = if value & (1<<7) == 0 { 4 } else { 5 };
|
||||
// If set, the frame interrupt flag is cleared, otherwise it is unaffected.
|
||||
// If set, the frame interrupt flag is cleared, otherwise it is unaffected.
|
||||
if value & (1<<6) != 0 {
|
||||
self.interrupt_inhibit = false;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::envelope::Envelope;
|
|||
const NOISE_TABLE: [u16; 16] = [4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068];
|
||||
|
||||
// $400E M---.PPPP Mode and period (write)
|
||||
// bit 7 M--- ---- Mode flag
|
||||
// bit 7 M--- ---- Mode flag
|
||||
pub struct Noise {
|
||||
pub sample: u16, // output value that gets sent to the mixer
|
||||
pub enabled: bool,
|
||||
|
@ -37,7 +37,7 @@ impl Noise {
|
|||
} else {
|
||||
self.timer -= 1;
|
||||
}
|
||||
// The mixer receives the current envelope volume except when
|
||||
// The mixer receives the current envelope volume except when
|
||||
// Bit 0 of the shift register is set, or the length counter is zero
|
||||
self.sample = if self.linear_feedback_sr & 1 == 1 || self.length_counter == 0 {
|
||||
0
|
||||
|
|
|
@ -100,7 +100,7 @@ impl Square {
|
|||
}
|
||||
}
|
||||
|
||||
// Whenever the current period changes for any reason, whether by $400x writes or by sweep, the target period also changes.
|
||||
// Whenever the current period changes for any reason, whether by $400x writes or by sweep, the target period also changes.
|
||||
pub fn calculate_target_period(&mut self) {
|
||||
// The sweep unit continuously calculates each channel's target period in this way:
|
||||
// A barrel shifter shifts the channel's 11-bit raw timer period right by the shift count, producing the change amount.
|
||||
|
|
|
@ -12,7 +12,7 @@ pub struct Triangle {
|
|||
waveform_counter: usize,
|
||||
pub length_counter: u8,
|
||||
length_counter_halt: bool, // (this bit is also the linear counter's control flag)
|
||||
|
||||
|
||||
linear_counter: u8,
|
||||
counter_reload_value: u8,
|
||||
linear_counter_reload: bool,
|
||||
|
@ -37,9 +37,9 @@ impl Triangle {
|
|||
pub fn clock(&mut self) {
|
||||
if self.timer == 0 {
|
||||
self.timer = self.timer_period;
|
||||
// The sequencer is clocked by the timer as long as both the linear counter and the length counter are nonzero.
|
||||
// The sequencer is clocked by the timer as long as both the linear counter and the length counter are nonzero.
|
||||
if self.linear_counter != 0 && self.length_counter != 0 {
|
||||
self.waveform_counter = (self.waveform_counter + 1) % 32;
|
||||
self.waveform_counter = (self.waveform_counter + 1) % 32;
|
||||
}
|
||||
} else {
|
||||
self.timer -= 1;
|
||||
|
@ -60,7 +60,7 @@ impl Triangle {
|
|||
self.linear_counter_reload = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn clock_length_counter(&mut self) {
|
||||
if !(self.length_counter == 0 || self.length_counter_halt) {
|
||||
self.length_counter -= 1;
|
||||
|
|
|
@ -42,8 +42,8 @@ impl AudioCallback for ApuSampler {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn initialize(sdl_context: &Sdl, buffer: Arc<Mutex<Vec<f32>>>)
|
||||
-> Result<sdl2::audio::AudioDevice<ApuSampler>, String>
|
||||
pub fn initialize(sdl_context: &Sdl, buffer: Arc<Mutex<Vec<f32>>>)
|
||||
-> Result<sdl2::audio::AudioDevice<ApuSampler>, String>
|
||||
{
|
||||
let audio_subsystem = sdl_context.audio()?;
|
||||
let desired_spec = AudioSpecDesired {
|
||||
|
|
|
@ -107,7 +107,7 @@ impl Mapper for Mmc3 {
|
|||
},
|
||||
|
||||
0x6000..=0x7FFF => self.prg_ram_bank[address % 0x2000], // PRG-RAM
|
||||
|
||||
|
||||
0x8000..=0xFFFF => { // reading from PRG ROM, dealing with 8K banks of 16K chunks
|
||||
let offset_8k = address % 0x2000;
|
||||
let num_banks = self.cart.prg_rom_size * 2;
|
||||
|
@ -118,7 +118,7 @@ impl Mapper for Mmc3 {
|
|||
0xA000..=0xBFFF => self.bank_registers[7],
|
||||
0xC000..=0xDFFF => self.bank_registers[6],
|
||||
0xE000..=0xFFFF => num_banks - 1,
|
||||
_ => panic!("oh no"),
|
||||
_ => panic!("oh no"),
|
||||
}
|
||||
},
|
||||
false => {
|
||||
|
@ -134,7 +134,7 @@ impl Mapper for Mmc3 {
|
|||
let chunk_num = bank_num / 2;
|
||||
let chunk_half = (bank_num % 2) * 0x2000;
|
||||
self.cart.prg_rom[chunk_num][chunk_half + offset_8k]
|
||||
|
||||
|
||||
},
|
||||
_ => {
|
||||
println!("bad address read from MMC3: 0x{:X}", address);
|
||||
|
|
|
@ -67,7 +67,7 @@ impl super::Cpu {
|
|||
let low_byte = self.read(operand_address) as usize;
|
||||
// BUG TIME! from https://wiki.nesdev.com/w/index.php/Errata
|
||||
// "JMP ($xxyy), or JMP indirect, does not advance pages if the lower eight bits
|
||||
// of the specified address is $FF; the upper eight bits are fetched from $xx00,
|
||||
// of the specified address is $FF; the upper eight bits are fetched from $xx00,
|
||||
// 255 bytes earlier, instead of the expected following byte."
|
||||
let high_byte = if operand_address & 0xFF == 0xFF {
|
||||
(self.read(operand_address as usize - 0xFF) as usize) << 8
|
||||
|
|
|
@ -137,7 +137,7 @@ impl Cpu {
|
|||
}
|
||||
|
||||
pub fn step(&mut self) -> u64 {
|
||||
|
||||
|
||||
// skip cycles from OAM DMA if necessary
|
||||
if self.delay > 0 {
|
||||
self.delay -= 1;
|
||||
|
|
|
@ -164,7 +164,7 @@ impl super::Cpu {
|
|||
pub fn cli(&mut self, _address: usize, _mode: Mode) {
|
||||
self.P &= 0xFF - INTERRUPT_DISABLE_FLAG;
|
||||
}
|
||||
|
||||
|
||||
pub fn clv(&mut self, _address: usize, _mode: Mode) {
|
||||
self.P &= 0xFF - OVERFLOW_FLAG;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ impl super::Cpu {
|
|||
Mode::ZPY => 2,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn add_offset_to_pc(&mut self, offset: i8) {
|
||||
match offset >= 0 {
|
||||
true => {
|
||||
|
|
|
@ -147,7 +147,8 @@ Failed tests from instr_test-v5/rom_singles/:
|
|||
|
||||
|
||||
|
||||
1. A12 stuff controls when IRQs
|
||||
2. Don't think the timing stuff is related to the palette and background table issues in SMB3
|
||||
|
||||
1. A12 stuff controls when IRQs fire. Don't think there are serious problems with when IRQs fire anymore,
|
||||
though vertical scroll is still shaky in Kirby.
|
||||
2. Don't think the timing stuff is related to the palette and background table issues in SMB2/3.
|
||||
How can the palette be wrong? Or is it not, but the attribute bits are reading wrong?
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
impl super::Ppu {
|
||||
|
||||
|
||||
// cpu writes to 0x2000, PPUCTRL
|
||||
pub fn write_controller(&mut self, byte: u8) {
|
||||
|
||||
|
@ -144,14 +144,14 @@ impl super::Ppu {
|
|||
As for 0x3F00 through 0x3FFF, the palette RAM indexes and their mirrors, need to find corresponding nametable?
|
||||
There are 4 nametables, duplicated once, so 8. There is one palette RAM index, mirrored 7 times, so 8.
|
||||
So to get from the fifth pallete RAM mirror, which would be 0x3F80, you'd select the 5th nametable,
|
||||
which would be the first mirrored nametable, 0x3000?
|
||||
which would be the first mirrored nametable, 0x3000?
|
||||
No, just subtract 0x1000. https://forums.nesdev.com/viewtopic.php?f=3&t=18627:
|
||||
|
||||
"However, I couldn't find any info on exactly which address should be used to populate the read buffer in this scenario.
|
||||
"However, I couldn't find any info on exactly which address should be used to populate the read buffer in this scenario.
|
||||
From other emulators, it appears to be PPU_ADDR - 0x1000, but I can't really intuit why that is the case."
|
||||
|
||||
"It's the case because the majority of the time (that is, on just about every board but GTROM),
|
||||
video memory $3000-$3FFF mirrors $2000-$2FFF. When PA13 is high ($2000-$3FFF), nothing is listening
|
||||
"It's the case because the majority of the time (that is, on just about every board but GTROM),
|
||||
video memory $3000-$3FFF mirrors $2000-$2FFF. When PA13 is high ($2000-$3FFF), nothing is listening
|
||||
to PA12 (the line that distinguishes $0000-$0FFF from $1000-$1FFF and distinguishes $2000-$2FFF from $3000-$3FFF)."
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::cartridge::Mirror;
|
||||
|
||||
impl super::Ppu {
|
||||
|
||||
|
||||
pub fn read(&mut self, addr: usize) -> u8 {
|
||||
let address = addr % 0x4000;
|
||||
match addr {
|
||||
|
@ -26,7 +26,7 @@ impl super::Ppu {
|
|||
// Addresses $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C.
|
||||
// Note that this goes for writing as well as reading.
|
||||
// A symptom of not having implemented this correctly in an emulator is the sky being black in Super Mario Bros.,
|
||||
// which writes the backdrop color through $3F10.
|
||||
// which writes the backdrop color through $3F10.
|
||||
match address % 0x10 {
|
||||
0x00 => {
|
||||
self.palette_ram[0] = value;
|
||||
|
|
|
@ -31,7 +31,7 @@ pub struct Ppu {
|
|||
nametable_C: Vec<u8>,
|
||||
nametable_D: Vec<u8>,
|
||||
|
||||
// The palette shared by both background and sprites.
|
||||
// The palette shared by both background and sprites.
|
||||
// Consists of 32 bytes, each of which represents an index into the global PALETTE_TABLE.
|
||||
// The first 16 bytes are for the background, the second half for the sprites.
|
||||
palette_ram: Vec<u8>, // Palette RAM indexes.
|
||||
|
@ -197,10 +197,10 @@ impl Ppu {
|
|||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// During dots 280 to 304 of the pre-render scanline (end of vblank)
|
||||
// If rendering is enabled, at the end of vblank, shortly after the horizontal bits
|
||||
// are copied from t to v at dot 257, the PPU will repeatedly copy the vertical bits
|
||||
// If rendering is enabled, at the end of vblank, shortly after the horizontal bits
|
||||
// are copied from t to v at dot 257, the PPU will repeatedly copy the vertical bits
|
||||
// from t to v from dots 280 to 304, completing the full initialization of v from t:
|
||||
if rendering && self.scanline == 261 && self.line_cycle >= 280 && self.line_cycle <= 304 {
|
||||
self.copy_vertical();
|
||||
|
|
|
@ -87,7 +87,7 @@ impl super::Ppu {
|
|||
let low_palette_bit = (self.background_palette_sr_low & (1 << (7-self.x)) != 0) as u8;
|
||||
let high_palette_bit = (self.background_palette_sr_high & (1 << (7-self.x)) != 0) as u8;
|
||||
let palette_offset = (high_palette_bit << 1) | low_palette_bit;
|
||||
|
||||
|
||||
if x < 8 && !self.show_background_left {
|
||||
background_pixel = 0;
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ impl super::Ppu {
|
|||
// let pixel = self.read(palette_address as usize) as usize;
|
||||
let pixel = self.palette_ram[palette_address as usize] as usize;
|
||||
let color: (u8, u8, u8) = super::PALETTE_TABLE[pixel];
|
||||
|
||||
|
||||
(x,y,color)
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,7 @@ impl super::Ppu {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn evaluate_sprites(&mut self) {
|
||||
pub fn evaluate_sprites(&mut self) {
|
||||
let mut sprite_count = 0;
|
||||
for n in 0..64 {
|
||||
let y_coord = self.primary_oam[(n*4)+0];
|
||||
|
@ -214,7 +214,7 @@ impl super::Ppu {
|
|||
} else {
|
||||
self.sprite_size as usize - 1 - (self.scanline - sprite_y_position)
|
||||
};
|
||||
// For 8x16 sprites, the PPU ignores the pattern table selection and selects a pattern table from bit 0 of this number.
|
||||
// For 8x16 sprites, the PPU ignores the pattern table selection and selects a pattern table from bit 0 of this number.
|
||||
} else {
|
||||
address = if sprite_tile_index & 1 == 0 { 0x0 } else { 0x1000 };
|
||||
address += (sprite_tile_index & 0xFFFF-1) << 4; // turn off bottom bit BEFORE shifting
|
||||
|
@ -264,8 +264,8 @@ impl super::Ppu {
|
|||
}
|
||||
|
||||
pub fn inc_y(&mut self) {
|
||||
// If rendering is enabled, fine Y is incremented at dot 256 of each scanline,
|
||||
// overflowing to coarse Y, and finally adjusted to wrap among the nametables vertically.
|
||||
// If rendering is enabled, fine Y is incremented at dot 256 of each scanline,
|
||||
// overflowing to coarse Y, and finally adjusted to wrap among the nametables vertically.
|
||||
let mut fine_y = (self.v & 0b01110000_00000000) >> 12;
|
||||
let mut coarse_y = (self.v & 0b00000011_11100000) >> 5;
|
||||
if fine_y < 7 {
|
||||
|
@ -273,7 +273,7 @@ impl super::Ppu {
|
|||
} else {
|
||||
fine_y = 0;
|
||||
// Row 29 is the last row of tiles in a nametable. To wrap to the next nametable when
|
||||
// incrementing coarse Y from 29, the vertical nametable is switched by toggling bit
|
||||
// incrementing coarse Y from 29, the vertical nametable is switched by toggling bit
|
||||
// 11, and coarse Y wraps to row 0.
|
||||
if coarse_y == 29 {
|
||||
self.v ^= 1<<11;
|
||||
|
@ -320,7 +320,7 @@ impl super::Ppu {
|
|||
}
|
||||
|
||||
pub fn y_in_range(&self, y_coord: u8) -> bool {
|
||||
self.scanline >= (y_coord as usize) &&
|
||||
self.scanline >= (y_coord as usize) &&
|
||||
self.scanline - (y_coord as usize) < self.sprite_size as usize
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue