summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.6.0/gme/Nes_Cpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/gme/game-music-emu-0.6.0/gme/Nes_Cpu.h')
-rw-r--r--plugins/gme/game-music-emu-0.6.0/gme/Nes_Cpu.h114
1 files changed, 114 insertions, 0 deletions
diff --git a/plugins/gme/game-music-emu-0.6.0/gme/Nes_Cpu.h b/plugins/gme/game-music-emu-0.6.0/gme/Nes_Cpu.h
new file mode 100644
index 00000000..694296f7
--- /dev/null
+++ b/plugins/gme/game-music-emu-0.6.0/gme/Nes_Cpu.h
@@ -0,0 +1,114 @@
+// NES 6502 CPU emulator
+
+// Game_Music_Emu 0.5.5
+#ifndef NES_CPU_H
+#define NES_CPU_H
+
+#include "blargg_common.h"
+
+typedef blargg_long nes_time_t; // clock cycle count
+typedef unsigned nes_addr_t; // 16-bit address
+enum { future_nes_time = INT_MAX / 2 + 1 };
+
+class Nes_Cpu {
+public:
+ typedef BOOST::uint8_t uint8_t;
+
+ // Clear registers, map low memory and its three mirrors to address 0,
+ // and mirror unmapped_page in remaining memory
+ void reset( void const* unmapped_page = 0 );
+
+ // Map code memory (memory accessed via the program counter). Start and size
+ // must be multiple of page_size. If mirror is true, repeats code page
+ // throughout address range.
+ enum { page_size = 0x800 };
+ void map_code( nes_addr_t start, unsigned size, void const* code, bool mirror = false );
+
+ // Access emulated memory as CPU does
+ uint8_t const* get_code( nes_addr_t );
+
+ // 2KB of RAM at address 0
+ uint8_t low_mem [0x800];
+
+ // NES 6502 registers. Not kept updated during a call to run().
+ struct registers_t {
+ BOOST::uint16_t pc;
+ BOOST::uint8_t a;
+ BOOST::uint8_t x;
+ BOOST::uint8_t y;
+ BOOST::uint8_t status;
+ BOOST::uint8_t sp;
+ };
+ registers_t r;
+
+ // Set end_time and run CPU from current time. Returns true if execution
+ // stopped due to encountering bad_opcode.
+ bool run( nes_time_t end_time );
+
+ // Time of beginning of next instruction to be executed
+ nes_time_t time() const { return state->time + state->base; }
+ void set_time( nes_time_t t ) { state->time = t - state->base; }
+ void adjust_time( int delta ) { state->time += delta; }
+
+ nes_time_t irq_time() const { return irq_time_; }
+ void set_irq_time( nes_time_t );
+
+ nes_time_t end_time() const { return end_time_; }
+ void set_end_time( nes_time_t );
+
+ // Number of undefined instructions encountered and skipped
+ void clear_error_count() { error_count_ = 0; }
+ unsigned long error_count() const { return error_count_; }
+
+ // CPU invokes bad opcode handler if it encounters this
+ enum { bad_opcode = 0xF2 };
+
+public:
+ Nes_Cpu() { state = &state_; }
+ enum { page_bits = 11 };
+ enum { page_count = 0x10000 >> page_bits };
+ enum { irq_inhibit = 0x04 };
+private:
+ struct state_t {
+ uint8_t const* code_map [page_count + 1];
+ nes_time_t base;
+ int time;
+ };
+ state_t* state; // points to state_ or a local copy within run()
+ state_t state_;
+ nes_time_t irq_time_;
+ nes_time_t end_time_;
+ unsigned long error_count_;
+
+ void set_code_page( int, void const* );
+ inline int update_end_time( nes_time_t end, nes_time_t irq );
+};
+
+inline BOOST::uint8_t const* Nes_Cpu::get_code( nes_addr_t addr )
+{
+ return state->code_map [addr >> page_bits] + addr
+ #if !BLARGG_NONPORTABLE
+ % (unsigned) page_size
+ #endif
+ ;
+}
+
+inline int Nes_Cpu::update_end_time( nes_time_t t, nes_time_t irq )
+{
+ if ( irq < t && !(r.status & irq_inhibit) ) t = irq;
+ int delta = state->base - t;
+ state->base = t;
+ return delta;
+}
+
+inline void Nes_Cpu::set_irq_time( nes_time_t t )
+{
+ state->time += update_end_time( end_time_, (irq_time_ = t) );
+}
+
+inline void Nes_Cpu::set_end_time( nes_time_t t )
+{
+ state->time += update_end_time( (end_time_ = t), irq_time_ );
+}
+
+#endif