Allow for the state to be const initialized

This commit is contained in:
Jan Bujak 2023-10-20 05:56:29 +00:00
parent af8ce41088
commit 8ebc612a53
10 changed files with 102 additions and 74 deletions

View file

@ -303,7 +303,7 @@ def generate_opcode_attributes
}
impl OpcodeAttributes {
fn empty() -> OpcodeAttributes {
const fn empty() -> OpcodeAttributes {
OpcodeAttributes {
attr: 0
}

View file

@ -115,14 +115,14 @@ pub struct State {
}
impl State {
pub fn new() -> State {
pub const fn new() -> State {
State {
pc: 0,
a: 0,
x: 0,
y: 0,
sp: 0xFD,
status: (StatusFlag::Unused | StatusFlag::IRQDisable).bits(),
status: StatusFlag::Unused.bits() | StatusFlag::IRQDisable.bits(),
irq_line_state: false,
nmi_latch_state: false,
nmi_pending: false,

View file

@ -716,7 +716,7 @@ macro_rules! decoding_logic {
}
impl OpcodeAttributes {
fn empty() -> OpcodeAttributes {
const fn empty() -> OpcodeAttributes {
OpcodeAttributes {
attr: 0
}

View file

@ -41,7 +41,7 @@ pub struct State {
}
impl State {
pub fn new() -> State {
pub const fn new() -> State {
State {
dmc_dma_requested: false,
dmc_dma_source_address: 0,

View file

@ -14,7 +14,7 @@ pub struct Filter {
}
impl Filter {
pub fn new() -> Filter {
pub const fn new() -> Filter {
Filter {
delay_00: 0.0,
delay_01: 0.0,

View file

@ -255,7 +255,8 @@ end
def generate_scanlines( constant_name, chunks_per_scanline )
output "static #{constant_name}: &'static [Scanline] = &["
output "static #{constant_name}: &'static [Scanline] = #{constant_name}_CONST;"
output "const #{constant_name}_CONST: &'static [Scanline] = &["
index = 0
chunks_per_scanline.each do |scanline|
@ -278,7 +279,8 @@ end
def generate_chunks( constant_name, chunks_per_scanline )
output "static #{constant_name}: &'static [Chunk] = &["
output "static #{constant_name}: &'static [Chunk] = #{constant_name}_CONST;"
output "const #{constant_name}_CONST: &'static [Chunk] = &["
index = 0
chunks_per_scanline.flat_map { |scanline| scanline[:chunks] }.each do |chunk|

View file

@ -1,7 +1,6 @@
use core::mem;
use core::default::Default;
use core::slice;
use alloc::vec::Vec;
use emumisc::{WrappingExtra, BitExtra, HiLoAccess, PeekPoke, At, is_b5_set, is_b6_set, is_b7_set, reverse_bits};
@ -18,7 +17,7 @@ pub trait Context: Sized {
pub trait Interface: Sized + Context {
#[inline]
fn framebuffer( &self ) -> &Framebuffer {
fn framebuffer( &mut self ) -> &Framebuffer {
Private::framebuffer( self )
}
@ -95,7 +94,7 @@ pub struct State {
palette_ram: [u8; 32],
sprite_list_ram: [u8; 256],
secondary_sprite_list_ram: [u8; 32],
framebuffer: Framebuffer,
framebuffer: Option< Framebuffer >,
odd_frame_flag: bool,
vblank_flag_was_cleared: bool,
@ -151,12 +150,17 @@ pub struct State {
}
impl State {
pub fn new() -> State {
pub const fn new() -> State {
let last_scanline = match SCANLINES_CONST.last() {
Some(value) => value,
None => unreachable!()
};
State {
palette_ram: [0; 32],
sprite_list_ram: [0; 64 * 4],
secondary_sprite_list_ram: [0; 8 * 4],
framebuffer: Framebuffer::new(),
framebuffer: None,
odd_frame_flag: false,
vblank_flag_was_cleared: false,
@ -173,7 +177,7 @@ impl State {
bg_palette_index_lo_shift_register: 0,
bg_palette_index_hi_shift_register: 0,
sprites: [Sprite::default(); 8],
sprites: [Sprite::new(); 8],
sprite_list_address: 0,
ppudata_read_buffer: 0,
@ -192,11 +196,11 @@ impl State {
background_palette_index_latch: 0,
tile_lo_latch: 0,
tile_hi_latch: 0,
scanline_index: SCANLINES.len() as u8 - 1, // Point at the prerender scanline.
scanline_index: SCANLINES_CONST.len() as u8 - 1, // Point at the prerender scanline.
scanline_counter: 0,
chunk_index: SCANLINES.last().unwrap().first_chunk_index,
chunk_index: last_scanline.first_chunk_index,
chunk_counter: 0,
action_index: CHUNKS[ SCANLINES.last().unwrap().first_chunk_index as usize ].first_action_index,
action_index: CHUNKS_CONST[ last_scanline.first_chunk_index as usize ].first_action_index,
auxiliary_sprite_list_address: 0,
secondary_sprite_list_address: 0,
sprite_list_data_latch: 0,
@ -210,9 +214,12 @@ impl State {
}
}
fn initialize_framebuffer_if_needed( &mut self ) {
}
#[inline]
pub fn framebuffer( &self ) -> &Framebuffer {
&self.framebuffer
pub fn framebuffer( &mut self ) -> &mut Framebuffer {
self.framebuffer.get_or_insert_with( Framebuffer::default )
}
}
@ -220,7 +227,7 @@ impl State {
struct PpuCtrl(u8);
impl PpuCtrl {
fn new() -> PpuCtrl {
const fn new() -> PpuCtrl {
PpuCtrl(0)
}
@ -273,7 +280,7 @@ impl PpuCtrl {
struct PpuMask(u8);
impl PpuMask {
fn new() -> PpuMask {
const fn new() -> PpuMask {
PpuMask(0)
}
@ -296,7 +303,7 @@ impl PpuMask {
struct PpuStatus(u8);
impl PpuStatus {
fn new() -> PpuStatus {
const fn new() -> PpuStatus {
PpuStatus(0)
}
@ -455,18 +462,11 @@ impl PpuStatus {
Each scanline takes 341 PPU cycles, with each cycle producing one pixel.
*/
#[derive(PartialEq, Eq)]
pub struct Framebuffer {
buffer: Vec< u16 >
buffer: alloc::boxed::Box<[u16; 256 * 240]>
}
impl PartialEq for Framebuffer {
fn eq( &self, other: &Framebuffer ) -> bool {
&self.buffer[..] == &other.buffer[..]
}
}
impl Eq for Framebuffer {}
impl Framebuffer {
fn new() -> Framebuffer {
Framebuffer::default()
@ -534,11 +534,8 @@ impl< 'a > Iterator for FramebufferIterator< 'a > {
impl Default for Framebuffer {
fn default() -> Self {
let mut buffer = Vec::new();
buffer.resize( 256 * 240, 0 );
Framebuffer {
buffer
buffer: alloc::boxed::Box::new([0; 256 * 240])
}
}
}
@ -649,6 +646,16 @@ struct Sprite {
}
impl Sprite {
#[inline]
const fn new() -> Self {
Sprite {
pattern_lo_shift_register: 0,
pattern_hi_shift_register: 0,
attributes_latch: 0,
dots_until_is_displayed: 0
}
}
#[inline]
fn display_sprite_behind_background( &self ) -> bool {
is_b5_set( self.attributes_latch )
@ -662,12 +669,7 @@ impl Sprite {
impl Default for Sprite {
fn default() -> Self {
Sprite {
pattern_lo_shift_register: 0,
pattern_hi_shift_register: 0,
attributes_latch: 0,
dots_until_is_displayed: 0
}
Self::new()
}
}
@ -883,12 +885,12 @@ trait Private: Sized + Context {
(self.sprite_tile_hi_address() >> 8) as u8
}
fn framebuffer( &self ) -> &Framebuffer {
&self.state().framebuffer
fn framebuffer( &mut self ) -> &Framebuffer {
self.state_mut().framebuffer()
}
fn swap_framebuffer( &mut self, mut other: Framebuffer ) -> Framebuffer {
mem::swap( &mut self.state_mut().framebuffer, &mut other );
mem::swap( self.state_mut().framebuffer(), &mut other );
other
}
@ -1077,7 +1079,13 @@ trait Private: Sized + Context {
// let color_in_system_palette_index = self.state_mut().palette_ram.peek( (palette_index as usize * 4) + color_in_palette_index as usize );
let nth = self.state().n_pixel;
let pixel = ((self.state().ppumask.color_emphasize_bits() as u16) << 6) | (color_in_system_palette_index as u16);
self.state_mut().framebuffer.buffer.poke( nth, pixel );
{
let framebuffer = match self.state_mut().framebuffer {
Some( ref mut framebuffer ) => framebuffer,
None => unsafe { core::hint::unreachable_unchecked() }
};
framebuffer.buffer.poke( nth, pixel );
}
self.state_mut().n_pixel += 1;
}
@ -1093,6 +1101,8 @@ trait Private: Sized + Context {
}
fn execute( &mut self ) {
self.state_mut().framebuffer(); // Make sure the framebuffer is initialized.
self.execute_next_action();
self.on_cycle();

View file

@ -16,7 +16,8 @@ macro_rules! ppu_scheduling_logic {
last_action_index: u16
}
static SCANLINES: &'static [Scanline] = &[
static SCANLINES: &'static [Scanline] = SCANLINES_CONST;
const SCANLINES_CONST: &'static [Scanline] = &[
Scanline {
times: 1,
first_chunk_index: 0,
@ -59,7 +60,8 @@ macro_rules! ppu_scheduling_logic {
},
];
static CHUNKS: &'static [Chunk] = &[
static CHUNKS: &'static [Chunk] = CHUNKS_CONST;
const CHUNKS_CONST: &'static [Chunk] = &[
Chunk {
times: 1,
first_action_index: 0,

View file

@ -160,11 +160,11 @@ pub struct State {
}
impl State {
pub fn new() -> State {
pub const fn new() -> State {
State {
cycles_to_next_step: SEQUENCER_STEPS_MODE_0[ 2 ].0,
cycles_to_next_step: SEQUENCER_STEPS_MODE_0_CONST[ 2 ].0,
sequencer_reconfigured: None,
sequencer_table: SEQUENCER_STEPS_MODE_0,
sequencer_table: SEQUENCER_STEPS_MODE_0_CONST,
sequencer_current_step: 2,
sequencer_mode: SequencerMode::Mode0,
inhibit_interrupts: false,
@ -250,7 +250,7 @@ impl Sequence {
fn clk_volume_generator( &self ) -> bool { self.6 }
}
static SEQUENCER_STEPS_MODE_0: &'static [Sequence] = &[
const SEQUENCER_STEPS_MODE_0_CONST: &'static [Sequence] = &[
Sequence( 1, 1, false, false, false, false, false ),
Sequence( 1, 2, false, false, false, false, false ),
Sequence( 1, 3, false, false, false, false, false ),
@ -262,6 +262,8 @@ static SEQUENCER_STEPS_MODE_0: &'static [Sequence] = &[
Sequence( 1, 3, true, false, false, false, false )
];
static SEQUENCER_STEPS_MODE_0: &'static [Sequence] = SEQUENCER_STEPS_MODE_0_CONST;
static SEQUENCER_STEPS_MODE_1: &'static [Sequence] = &[
Sequence( 1, 1, false, false, false, false, false ),
Sequence( 3, 2, false, true, true, true, true ),
@ -313,7 +315,7 @@ struct Channel {
}
impl Channel {
fn new() -> Channel {
const fn new() -> Channel {
Channel {
length_counter: 0,
length_counter_disabled: false,
@ -365,7 +367,7 @@ struct VolumeGenerator {
}
impl VolumeGenerator {
fn new() -> VolumeGenerator {
const fn new() -> VolumeGenerator {
VolumeGenerator {
is_manually_controlled: false,
should_loop: false,
@ -445,7 +447,7 @@ struct ChannelSquare {
}
impl ChannelSquare {
fn new( is_second_channel: bool ) -> ChannelSquare {
const fn new( is_second_channel: bool ) -> ChannelSquare {
ChannelSquare {
base: Channel::new(),
duty: SquareChannelDuty::Duty125,
@ -592,7 +594,7 @@ struct ChannelTriangle {
}
impl ChannelTriangle {
fn new() -> ChannelTriangle {
const fn new() -> ChannelTriangle {
ChannelTriangle {
base: Channel::new(),
period: 0,
@ -699,7 +701,7 @@ struct ChannelNoise {
}
impl ChannelNoise {
fn new() -> ChannelNoise {
const fn new() -> ChannelNoise {
ChannelNoise {
base: Channel::new(),
volume_generator: VolumeGenerator::new(),
@ -786,7 +788,7 @@ struct ChannelDeltaModulation {
// The DMC channel plays back DPCM samples stored in memory as 1-bit deltas.
// A bit of 1 will increment the output; a bit of 0 will decrement the output.
impl ChannelDeltaModulation {
fn new() -> ChannelDeltaModulation {
const fn new() -> ChannelDeltaModulation {
ChannelDeltaModulation {
enabled: false,

View file

@ -50,7 +50,7 @@ pub trait Interface: Sized + Context {
Private::execute_cycle( self )
}
fn framebuffer( &self ) -> &rp2c02::Framebuffer {
fn framebuffer( &mut self ) -> &rp2c02::Framebuffer {
Private::framebuffer( self )
}
@ -87,12 +87,13 @@ impl< T: Context > Interface for T {}
impl< T: Context > Private for T {}
pub struct State {
mapper_null: MapperNull,
ram: [u8; 2048],
cpu_state: mos6502::State,
ppu_state: rp2c02::State,
apu_state: virtual_apu::State,
dma_state: dma::State,
mapper: Box< dyn Mapper >,
mapper: Option< Box< dyn Mapper > >,
error: Option< Box< dyn Error > >,
ready: bool,
cpu_cycle: u32,
@ -107,14 +108,15 @@ pub struct State {
}
impl State {
pub fn new() -> State {
pub const fn new() -> State {
State {
mapper_null: MapperNull,
ram: [0; 2048],
cpu_state: mos6502::State::new(),
ppu_state: rp2c02::State::new(),
apu_state: virtual_apu::State::new(),
dma_state: dma::State::new(),
mapper: Box::new( MapperNull ),
mapper: None,
error: None,
ready: false,
cpu_cycle: 0,
@ -130,9 +132,19 @@ impl State {
}
#[inline]
pub fn framebuffer( &self ) -> &rp2c02::Framebuffer {
pub fn framebuffer( &mut self ) -> &rp2c02::Framebuffer {
self.ppu_state.framebuffer()
}
#[inline]
fn mapper( &self ) -> &dyn Mapper {
self.mapper.as_ref().map( |mapper| &**mapper ).unwrap_or( &self.mapper_null )
}
#[inline]
fn mapper_mut( &mut self ) -> &mut dyn Mapper {
self.mapper.as_mut().map( |mapper| &mut **mapper ).unwrap_or( &mut self.mapper_null )
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
@ -221,12 +233,12 @@ impl< C: Context > rp2c02::Context for Orphan< C > {
#[inline]
fn peek_video_memory( &self, address: u16 ) -> u8 {
self.as_ref().state().mapper.peek_video_memory( address )
self.as_ref().state().mapper().peek_video_memory( address )
}
#[inline]
fn poke_video_memory( &mut self, address: u16, value: u8 ) {
self.as_mut().state_mut().mapper.poke_video_memory( address, value );
self.as_mut().state_mut().mapper_mut().poke_video_memory( address, value );
}
}
@ -320,7 +332,7 @@ trait Private: Sized + Context {
let mapper = create_mapper( rom )?;
self.state_mut().mapper = mapper;
self.state_mut().mapper = Some( mapper );
self.state_mut().ready = true;
self.hard_reset();
@ -328,7 +340,7 @@ trait Private: Sized + Context {
}
fn hard_reset( &mut self ) {
let mut mapper: Box< dyn Mapper + 'static > = Box::new( MapperNull );
let mut mapper: Option< Box< dyn Mapper + 'static > > = None;
mem::swap( &mut mapper, &mut self.state_mut().mapper );
let ready = self.state().ready;
@ -405,8 +417,8 @@ trait Private: Sized + Context {
Ok( self.state().full_frame_counter != last_counter_value )
}
fn framebuffer( &self ) -> &rp2c02::Framebuffer {
rp2c02::Interface::framebuffer( self.newtype() )
fn framebuffer( &mut self ) -> &rp2c02::Framebuffer {
rp2c02::Interface::framebuffer( self.newtype_mut() )
}
fn swap_framebuffer( &mut self, other: rp2c02::Framebuffer ) -> rp2c02::Framebuffer {
@ -461,11 +473,11 @@ trait Private: Sized + Context {
_ => unsafe { fast_unreachable!() }
}
}, {
self.state().mapper.peek_expansion_rom( address )
self.state().mapper().peek_expansion_rom( address )
}, {
self.state().mapper.peek_sram( address )
self.state().mapper().peek_sram( address )
}, {
self.state().mapper.peek_rom( address )
self.state().mapper().peek_rom( address )
}
)
}
@ -533,11 +545,11 @@ trait Private: Sized + Context {
}
}
}, {
self.state().mapper.poke_expansion_rom( address, value );
self.state().mapper().poke_expansion_rom( address, value );
}, {
self.state_mut().mapper.poke_sram( address, value );
self.state_mut().mapper_mut().poke_sram( address, value );
}, {
self.state_mut().mapper.poke_rom( address, value );
self.state_mut().mapper_mut().poke_rom( address, value );
}
)
}