Some refactoring
This commit is contained in:
parent
92ad30faf8
commit
eb5edf12e5
|
@ -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
|
||||
=========
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue