Some refactoring

This commit is contained in:
Sergio Martin 2024-01-16 18:42:29 +01:00
parent 92ad30faf8
commit eb5edf12e5
11 changed files with 72 additions and 260 deletions

View File

@ -17,6 +17,7 @@ Changes
+ Forced alignment at the start of a page to prevent crossing cache line boundaries
+ Simplifying instruction decode
- Minimize compiled code size to reduce pressure on L1i cache
- Reduce heap allocations
Credits
=========

29
extern/hqn/hqn.cpp vendored
View File

@ -68,25 +68,6 @@ error_t HQNState::setSampleRate(int rate)
return ret;
}
// Load a ROM image
error_t HQNState::loadROM(const char *filename)
{
// unload any existing rom data
unloadRom();
if (!load_file(filename, (char**)(&m_romData), &m_romSize))
{
return "Failed to open file";
}
// Now finally load the rom. Ugh
Mem_File_Reader r(m_romData, (int)m_romSize);
Auto_File_Reader a(r);
error_t result = m_emu->load_ines(a);
if (m_listener)
m_listener->onLoadROM(this, filename);
return result;
}
error_t HQNState::saveState(void *dest, size_t size, size_t *size_out)
{
@ -120,16 +101,6 @@ error_t HQNState::loadState(const char *data, size_t size)
return result;
}
void HQNState::unloadRom()
{
if (m_romData)
{
delete[] m_romData;
m_romData = nullptr;
m_romSize = 0;
}
}
// Advance the emulator
error_t HQNState::advanceFrame(bool sleep)
{

8
extern/hqn/hqn.h vendored
View File

@ -58,11 +58,6 @@ public:
inline Nes_Emu *emu() const
{ return m_emu; }
/*
Load a NES rom from the named file.
Returns NULL or error string.
*/
error_t loadROM(const char *filename);
/*
Advance the emulator by one frame. If sleep is true and there is a frame
@ -120,9 +115,6 @@ public:
{ return m_keyboard; }
private:
// Safely unload the currently loaded rom
void unloadRom();
/* ROM file stored in memory because reasons */
uint8_t *m_romData;
size_t m_romSize;

View File

@ -1,141 +0,0 @@
// Nes_Emu 0.7.0. http://www.slack.net/~ant/
#include "Nes_Cart.h"
#include <stdlib.h>
#include <string.h>
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details. You should have received a copy of the GNU Lesser General
Public License along with this module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "blargg_source.h"
char const Nes_Cart::not_ines_file [] = "Not an iNES file";
Nes_Cart::Nes_Cart()
{
prg_ = NULL;
chr_ = NULL;
clear();
}
Nes_Cart::~Nes_Cart()
{
clear();
}
void Nes_Cart::clear()
{
if ( prg_ )
free( prg_ );
prg_ = NULL;
if ( chr_ )
free( chr_ );
chr_ = NULL;
prg_size_ = 0;
chr_size_ = 0;
mapper = 0;
}
long Nes_Cart::round_to_bank_size( long n )
{
n += bank_size - 1;
return n - n % bank_size;
}
const char * Nes_Cart::resize_prg( long size )
{
if ( size != prg_size_ )
{
// padding allows CPU to always read operands of instruction, which
// might go past end of data
void* p = realloc( prg_, round_to_bank_size( size ) + 2 );
CHECK_ALLOC( p || !size );
prg_ = (uint8_t*) p;
prg_size_ = size;
}
return 0;
}
const char * Nes_Cart::resize_chr( long size )
{
if ( size != chr_size_ )
{
void* p = realloc( chr_, round_to_bank_size( size ) );
CHECK_ALLOC( p || !size );
chr_ = (uint8_t*) p;
chr_size_ = size;
}
return 0;
}
// iNES reading
struct ines_header_t {
uint8_t signature [4];
uint8_t prg_count; // number of 16K PRG banks
uint8_t chr_count; // number of 8K CHR banks
uint8_t flags; // MMMM FTBV Mapper low, Four-screen, Trainer, Battery, V mirror
uint8_t flags2; // MMMM --XX Mapper high 4 bits
uint8_t zero [8]; // if zero [7] is non-zero, treat flags2 as zero
};
BOOST_STATIC_ASSERT( sizeof (ines_header_t) == 16 );
const char * Nes_Cart::load_ines( Auto_File_Reader in )
{
RETURN_ERR( in.open() );
ines_header_t h;
RETURN_ERR( in->read( &h, sizeof h ) );
if ( 0 != memcmp( h.signature, "NES\x1A", 4 ) )
return not_ines_file;
if ( h.zero [7] ) // handle header defaced by a fucking idiot's handle
h.flags2 = 0;
set_mapper( h.flags, h.flags2 );
if ( h.flags & 0x04 ) // skip trainer
RETURN_ERR( in->skip( 512 ) );
RETURN_ERR( resize_prg( h.prg_count * 16 * 1024L ) );
RETURN_ERR( resize_chr( h.chr_count * 8 * 1024L ) );
RETURN_ERR( in->read( prg(), prg_size() ) );
RETURN_ERR( in->read( chr(), chr_size() ) );
return 0;
}
const char * Nes_Cart::load_ines( const uint8_t* buffer )
{
ines_header_t h;
size_t bufferPos = 0;
{ size_t copySize = sizeof(ines_header_t); memcpy(&h, &buffer[bufferPos], copySize); bufferPos += copySize; }
if ( h.zero [7] ) h.flags2 = 0;
set_mapper( h.flags, h.flags2 );
// skip trainer
if ( h.flags & 0x04 ) bufferPos += 512;
resize_prg( h.prg_count * 16 * 1024L );
resize_chr( h.chr_count * 8 * 1024L );
{ size_t copySize = prg_size(); memcpy(prg(), &buffer[bufferPos], copySize); bufferPos += copySize; }
{ size_t copySize = chr_size(); memcpy(chr(), &buffer[bufferPos], copySize); bufferPos += copySize; }
return 0;
}

View File

@ -1,7 +1,19 @@
// NES cartridge data (PRG, CHR, mapper)
// Nes_Emu 0.7.0
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details. You should have received a copy of the GNU Lesser General
Public License along with this module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
// Nes_Emu 0.7.0. http://www.slack.net/~ant/
#ifndef NES_CART_H
#define NES_CART_H
@ -10,77 +22,88 @@
#include "blargg_common.h"
#include "abstract_file.h"
class Nes_Cart {
public:
Nes_Cart();
~Nes_Cart();
Nes_Cart() = default;
struct ines_header_t {
uint8_t signature [4];
uint8_t prg_count; // number of 16K PRG banks
uint8_t chr_count; // number of 8K CHR banks
uint8_t flags; // MMMM FTBV Mapper low, Four-screen, Trainer, Battery, V mirror
uint8_t flags2; // MMMM --XX Mapper high 4 bits
uint8_t zero [8]; // if zero [7] is non-zero, treat flags2 as zero
};
BOOST_STATIC_ASSERT( sizeof (ines_header_t) == 16 );
// Load iNES file
const char * load_ines( const uint8_t* buffer );
const char * load_ines( Auto_File_Reader );
static const char not_ines_file [];
// to do: support UNIF?
// True if data is currently loaded
bool loaded() const { return prg_ != NULL; }
// Free data
void clear();
// True if cartridge claims to have battery-backed memory
bool has_battery_ram() const;
const char * load_ines( const uint8_t* buffer )
{
ines_header_t h;
size_t bufferPos = 0;
{ size_t copySize = sizeof(ines_header_t); memcpy(&h, &buffer[bufferPos], copySize); bufferPos += copySize; }
if ( h.zero [7] ) h.flags2 = 0;
set_mapper( h.flags, h.flags2 );
// skip trainer
if ( h.flags & 0x04 ) bufferPos += 512;
// Allocating memory for prg and chr
prg_size_ = h.prg_count * 16 * 1024L;
chr_size_ = h.chr_count * 8 * 1024L;
auto p = malloc(prg_size_ + chr_size_);
prg_ = (uint8_t*)p;
chr_ = &prg_[prg_size_];
{ size_t copySize = prg_size(); memcpy(prg(), &buffer[bufferPos], copySize); bufferPos += copySize; }
{ size_t copySize = chr_size(); memcpy(chr(), &buffer[bufferPos], copySize); bufferPos += copySize; }
return 0;
}
inline bool has_battery_ram() const { return mapper & 0x02; }
// Set mapper and information bytes. LSB and MSB are the standard iNES header
// bytes at offsets 6 and 7.
inline void set_mapper( int mapper_lsb, int mapper_msb )
{
mapper = mapper_msb * 0x100 + mapper_lsb;
}
inline int mapper_code() const { return ((mapper >> 8) & 0xf0) | ((mapper >> 4) & 0x0f); }
// Size of PRG data
long prg_size() const { return prg_size_; }
// Size of CHR data
long chr_size() const { return chr_size_; }
// Change size of PRG (code) data
const char * resize_prg( long );
// Change size of CHR (graphics) data
const char * resize_chr( long );
// Set mapper and information bytes. LSB and MSB are the standard iNES header
// bytes at offsets 6 and 7.
void set_mapper( int mapper_lsb, int mapper_msb );
unsigned mapper_data() const { return mapper; }
// Initial mirroring setup
int mirroring() const { return mapper & 0x09; }
// iNES mapper code
int mapper_code() const;
// Pointer to beginning of PRG data
uint8_t * prg() { return prg_; }
uint8_t const* prg() const { return prg_; }
inline uint8_t * prg() { return prg_; }
inline uint8_t const* prg() const { return prg_; }
// Pointer to beginning of CHR data
uint8_t * chr() { return chr_; }
uint8_t const* chr() const { return chr_; }
inline uint8_t * chr() { return chr_; }
inline uint8_t const* chr() const { return chr_; }
// End of public interface
private:
enum { bank_size = 8 * 1024L }; // bank sizes must be a multiple of this
uint8_t *prg_;
uint8_t *chr_;
long prg_size_;
long chr_size_;
unsigned mapper;
long round_to_bank_size( long n );
};
inline bool Nes_Cart::has_battery_ram() const { return mapper & 0x02; }
inline void Nes_Cart::set_mapper( int mapper_lsb, int mapper_msb )
{
mapper = mapper_msb * 0x100 + mapper_lsb;
}
inline int Nes_Cart::mapper_code() const { return ((mapper >> 8) & 0xf0) | ((mapper >> 4) & 0x0f); }
#endif

View File

@ -369,7 +369,6 @@ void Nes_Core::write_io( nes_addr_t addr, int data )
// if strobe goes low, latch data
if ( joypad.w4016 & 1 & ~data )
{
joypad_read_count++;
joypad.joypad_latches [0] = current_joypad [0];
joypad.joypad_latches [1] = current_joypad [1];
}
@ -614,8 +613,6 @@ nes_time_t Nes_Core::emulate_frame(int joypad1, int joypad2)
current_joypad [0] = (joypad1 |= ~0xFF);
current_joypad [1] = (joypad2 |= ~0xFF);
joypad_read_count = 0;
cpu_time_offset = ppu.begin_frame( nes.timestamp ) - 1;
ppu_2002_time = 0;
clock_ = cpu_time_offset;

View File

@ -50,7 +50,6 @@ public: private: friend class Nes_Emu;
public:
unsigned long current_joypad [2];
int joypad_read_count;
Nes_Cart const* cart;
Nes_Mapper* mapper;
nes_state_t nes;

View File

@ -84,20 +84,8 @@ inline void Nes_Emu::clear_sound_buf()
sound_buf->clear();
}
// Emulation
void Nes_Emu::close()
{
if ( cart() )
{
emu.close();
private_cart.clear();
}
}
const char * Nes_Emu::set_cart( Nes_Cart const* new_cart )
{
close();
RETURN_ERR( auto_init() );
RETURN_ERR( emu.open( new_cart ) );
@ -173,7 +161,6 @@ const char * Nes_Emu::emulate_frame( int joypad1, int joypad2 )
f->chan_count = sound_buf->samples_per_frame();
f->palette_begin = emu.ppu.palette_begin;
f->palette_size = emu.ppu.palette_size;
f->joypad_read_count = emu.joypad_read_count;
f->burst_phase = emu.ppu.burst_phase;
f->pitch = emu.ppu.host_row_bytes;
f->pixels = emu.ppu.host_pixels + f->left;
@ -191,18 +178,10 @@ const char * Nes_Emu::emulate_frame( int joypad1, int joypad2 )
const char * Nes_Emu::load_ines( const uint8_t* buffer )
{
close();
private_cart.load_ines( buffer );
return set_cart( &private_cart );
}
const char * Nes_Emu::load_ines( Auto_File_Reader in )
{
close();
RETURN_ERR( private_cart.load_ines( in ) );
return set_cart( &private_cart );
}
const char * Nes_Emu::save_battery_ram( Auto_File_Writer out )
{
RETURN_ERR( out.open() );

View File

@ -20,7 +20,6 @@ public:
// Basic setup
// Load iNES file into emulator and clear recording
const char * load_ines( Auto_File_Reader );
const char * load_ines( const uint8_t* buffer );
// Set sample rate for sound generation
@ -91,10 +90,6 @@ public:
// Pointer to current cartridge, or NULL if none is loaded
Nes_Cart const* cart() const { return emu.cart; }
// Free any memory and close cartridge, if one was currently open. A new cartridge
// must be opened before further emulation can take place.
void close();
// Emulate powering NES off and then back on. If full_reset is false, emulates
// pressing the reset button only, which doesn't affect memory, otherwise
// emulates powering system off then on.
@ -223,7 +218,6 @@ private:
virtual void loading_state( Nes_State const& ) { }
void load_state( Nes_State_ const& );
void save_state( Nes_State_* s ) const { emu.save_state( s ); }
int joypad_read_count() const { return emu.joypad_read_count; }
long timestamp() const { return emu.nes.frame_count; }
void set_timestamp( long t ) { emu.nes.frame_count = t; }

View File

@ -8,7 +8,6 @@ quickerNESSrc = [
'Nes_Fme7_Apu.cpp',
'Nes_Ppu.cpp',
'Blip_Buffer.cpp',
'Nes_Cart.cpp',
'Nes_Ppu_Impl.cpp',
'Data_Reader.cpp',
'Nes_Ppu_Rendering.cpp',

View File

@ -22,9 +22,7 @@ class QuickerNESInstance : public EmuInstance
virtual bool loadROMFileImpl(const std::string& romData) override
{
// Loading rom data
Mem_File_Reader romReader(romData.data(), (int)romData.size());
Auto_File_Reader romFile(romReader);
auto result = _nes->load_ines(romFile);
auto result = _nes->load_ines((uint8_t*)romData.data());
return result == 0;
}