diff --git a/CMakeLists.txt b/CMakeLists.txt index 77e06ec2..45c3379b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,7 @@ set(EXTRA_COMPONENT_DIRS set(NES_COMPONENTS "nofrendo nofrendo-esp32") ### GBC ### -# set(GBC_COMPONENTS "gameboycore") -# set(GBC_COMPONENTS "gnuboy") +set(GBC_COMPONENTS "gnuboy") ### SMS ### # set(SMS_COMPONENTS "smsplus") diff --git a/components/box-emu-hal/CMakeLists.txt b/components/box-emu-hal/CMakeLists.txt index c9a5dc0e..d4bdd2ec 100644 --- a/components/box-emu-hal/CMakeLists.txt +++ b/components/box-emu-hal/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( INCLUDE_DIRS "include" SRC_DIRS "src" - REQUIRES "driver" "esp_lcd" "spi_flash" "nvs_flash" "codec" "display" "display_drivers" "controller" "ads1x15" "qwiicnes" "input_drivers" "ft5x06" "tt21100" + REQUIRES "driver" "heap" "esp_lcd" "esp_psram" "spi_flash" "nvs_flash" "codec" "display" "display_drivers" "controller" "ads1x15" "qwiicnes" "input_drivers" "ft5x06" "tt21100" ) diff --git a/components/box-emu-hal/include/i2s_audio.h b/components/box-emu-hal/include/i2s_audio.h index a48ad1e2..ee074fb3 100644 --- a/components/box-emu-hal/include/i2s_audio.h +++ b/components/box-emu-hal/include/i2s_audio.h @@ -7,7 +7,9 @@ extern "C" { #endif void audio_init(); +int16_t* get_audio_buffer(); void audio_play_frame(uint8_t *data, uint32_t num_bytes); +void set_audio_volume(int percent); #ifdef __cplusplus } diff --git a/components/box-emu-hal/include/spi_lcd.h b/components/box-emu-hal/include/spi_lcd.h index 628a1540..7050ab40 100644 --- a/components/box-emu-hal/include/spi_lcd.h +++ b/components/box-emu-hal/include/spi_lcd.h @@ -14,6 +14,7 @@ #pragma once #include +#include //***************************************************************************** // @@ -32,6 +33,7 @@ uint16_t make_color(uint8_t r, uint8_t g, uint8_t b); void set_pixel(const uint16_t x, const uint16_t y, const uint16_t color); uint16_t* get_vram0(); uint16_t* get_vram1(); +uint8_t* get_frame_buffer(); void delay_us(size_t num_us); uint16_t reorder_color(uint16_t color); void lcd_set_drawing_frame(const uint16_t xs, const uint16_t ys, const uint16_t width, const uint16_t height); diff --git a/components/box-emu-hal/src/i2s_audio.cpp b/components/box-emu-hal/src/i2s_audio.cpp index a8fcafe9..d43d7918 100644 --- a/components/box-emu-hal/src/i2s_audio.cpp +++ b/components/box-emu-hal/src/i2s_audio.cpp @@ -46,6 +46,17 @@ static i2s_chan_handle_t tx_handle = NULL; static i2s_chan_handle_t rx_handle = NULL; +static const int AUDIO_BUFFER_SIZE = EXAMPLE_SAMPLE_RATE / 3 + 1; +static int16_t *audio_buffer; + +int16_t *get_audio_buffer() { + return audio_buffer; +} + +void set_audio_volume(int percent) { + es8311_codec_set_voice_volume(percent); +} + static esp_err_t i2s_driver_init(void) { printf("initializing i2s driver...\n"); @@ -178,6 +189,9 @@ void audio_init() { i2c_driver_init(); es7210_init_default(); es8311_init_default(); + + audio_buffer = (int16_t*)heap_caps_malloc(AUDIO_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + initialized = true; } diff --git a/components/box-emu-hal/src/spi_lcd.cpp b/components/box-emu-hal/src/spi_lcd.cpp index a686e85f..f9ab8e5b 100644 --- a/components/box-emu-hal/src/spi_lcd.cpp +++ b/components/box-emu-hal/src/spi_lcd.cpp @@ -13,44 +13,8 @@ static constexpr size_t display_height = 240; static constexpr size_t pixel_buffer_size = display_width*NUM_ROWS_IN_FRAME_BUFFER; std::shared_ptr display; -// for gnuboy -uint16_t* displayBuffer[2]; -struct fb -{ - uint8_t *ptr; - int w, h; - int pelsize; - int pitch; - int indexed; - struct - { - int l, r; - } cc[4]; - int yuv; - int enabled; - int dirty; -}; -struct fb fb; -struct obj -{ - uint8_t y; - uint8_t x; - uint8_t pat; - uint8_t flags; -}; -struct lcd -{ - uint8_t vbank[2][8192]; - union - { - uint8_t mem[256]; - struct obj obj[40]; - } oam; - uint8_t pal[128]; -}; -static struct lcd lcd; -int frame = 0; - +static constexpr size_t frame_buffer_size = (256 * 240 * 2); +static uint8_t *frame_buffer; //This function is called (in irq context!) just before a transmission starts. It will //set the D/C line to the value indicated in the user field. @@ -74,25 +38,29 @@ void lcd_spi_post_transfer_callback(spi_transaction_t *t) } -// TODO: see if IRAM_ATTR improves the display refresh frequency // create the lcd_write function -extern "C" void lcd_write(const uint8_t *data, size_t length, uint16_t user_data) { +static const int spi_queue_size = 10; +static spi_transaction_t ts_[spi_queue_size]; +static size_t ts_index = 0; +extern "C" void IRAM_ATTR lcd_write(const uint8_t *data, size_t length, uint16_t user_data) { if (length == 0) { // oddly the esp-idf-cxx spi driver asserts if we try to send 0 data... return; } esp_err_t ret; - spi_transaction_t t; // declared static so spi driver can still access it - memset(&t, 0, sizeof(t)); //Zero out the transaction - t.length=length*8; //Length is in bytes, transaction length is in bits. - t.tx_buffer=data; //Data - t.user=(void*)user_data; //whether or not to flush - ret=spi_device_polling_transmit(spi, &t); //Transmit! - // ret=spi_device_queue_trans(spi, &t, portMAX_DELAY); //Transmit! - // assert(ret==ESP_OK); //Should have had no issues. + //spi_transaction_t t; // declared static so spi driver can still access it + spi_transaction_t *t = &ts_[ts_index]; + memset(t, 0, sizeof(*t)); //Zero out the transaction + t->length=length*8; //Length is in bytes, transaction length is in bits. + t->tx_buffer=data; //Data + t->user=(void*)user_data; //whether or not to flush + ret=spi_device_polling_transmit(spi, t); //Transmit! + // ret=spi_device_queue_trans(spi, t, portMAX_DELAY); //Transmit! if (ret != ESP_OK) { fmt::print("Could not write to lcd: {} '{}'\n", ret, esp_err_to_name(ret)); } + ts_index++; + if (ts_index >= spi_queue_size) ts_index = 0; } #define U16x2toU32(m,l) ((((uint32_t)(l>>8|(l&0xFF)<<8))<<16)|(m>>8|(m&0xFF)<<8)) @@ -120,11 +88,15 @@ extern "C" void set_pixel(const uint16_t x, const uint16_t y, const uint16_t col } extern "C" uint16_t* get_vram0() { - return displayBuffer[0]; + return display->vram0(); } extern "C" uint16_t* get_vram1() { - return displayBuffer[1]; + return display->vram1(); +} + +extern "C" uint8_t* get_frame_buffer() { + return frame_buffer; } extern "C" void delay_us(size_t num_us) { @@ -182,7 +154,7 @@ extern "C" void lcd_init() { .mode=0, //SPI mode 0 .clock_speed_hz=60*1000*1000, //Clock out at 60 MHz .spics_io_num=GPIO_NUM_5, //CS pin - .queue_size=7, //We want to be able to queue 7 transactions at a time + .queue_size=spi_queue_size, //We want to be able to queue 7 transactions at a time .pre_cb=lcd_spi_pre_transfer_callback, .post_cb=lcd_spi_post_transfer_callback, }; @@ -217,18 +189,7 @@ extern "C" void lcd_init() { .rotation = espp::Display::Rotation::LANDSCAPE, .software_rotation_enabled = true, }); + + frame_buffer = (uint8_t*)heap_caps_malloc(frame_buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); initialized = true; - // for gnuboy - displayBuffer[0] = display->vram0(); - displayBuffer[1] = display->vram1(); - memset(&fb, 0, sizeof(fb)); - // got these from https://github.com/OtherCrashOverride/go-play/blob/master/gnuboy-go/main/main.c - fb.w = 160; - fb.h = 144; - fb.pelsize = 2; - fb.pitch = fb.w * fb.pelsize; - fb.indexed = 0; - fb.ptr = (uint8_t*)displayBuffer[0]; - fb.enabled = 1; - fb.dirty = 0; } diff --git a/components/gameboycore/CMakeLists.txt b/components/gameboycore/CMakeLists.txt deleted file mode 100644 index 2f676a2a..00000000 --- a/components/gameboycore/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -set(ENDIAN "__LITTLEENDIAN__") - -idf_component_register( - INCLUDE_DIRS "include" - SRC_DIRS "src" - REQUIRES box-emu-hal - ) - -# target_compile_features(gameboycore PUBLIC cxx_std_11) -target_compile_options(${COMPONENT_LIB} PRIVATE -Wall -Wextra) -target_compile_definitions(${COMPONENT_LIB} PRIVATE GAMEBOYCORE_STATIC=1 ${ENDIAN}=1 _CRT_SECURE_NO_WARNINGS=1) -target_compile_definitions(${COMPONENT_LIB} PUBLIC USE_GAMEBOY_GAMEBOYCORE) diff --git a/components/gameboycore/include/gameboycore/alu.h b/components/gameboycore/include/gameboycore/alu.h deleted file mode 100644 index 10a24e19..00000000 --- a/components/gameboycore/include/gameboycore/alu.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - \file alu.h - \author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_ALU_H -#define GAMEBOYCORE_ALU_H - -#include - -namespace gb -{ - /*! - \class ALU - \brief Arithmetic and logic unit - */ - class ALU - { - public: - enum Flags - { - Z = 1 << 7, - N = 1 << 6, - H = 1 << 5, - C = 1 << 4 - }; - - public: - ALU(uint8_t& flags); - ~ALU(); - - /** - ADD - */ - void add(uint8_t& a, uint8_t n); - void add(uint16_t& hl, uint16_t n); - void addr(uint16_t& sp, int8_t n); - - /** - ADC - */ - void addc(uint8_t& a, uint8_t n); - - /** - SUB - */ - void sub(uint8_t& a, uint8_t n); - - /** - SUBC - */ - void subc(uint8_t& a, uint8_t n); - - /** - AND - */ - void anda(uint8_t& a, uint8_t n); - - /** - OR - */ - void ora(uint8_t& a, uint8_t n); - - /** - XOR - */ - void xora(uint8_t& a, uint8_t n); - - /** - Compare - */ - void compare(uint8_t& a, uint8_t n); - - private: - void setFlag(uint8_t mask, bool set); - - private: - uint8_t& flags_; - }; - -} -#endif // GAMEBOYCORE_ALU_H diff --git a/components/gameboycore/include/gameboycore/apu.h b/components/gameboycore/include/gameboycore/apu.h deleted file mode 100644 index 123bffd1..00000000 --- a/components/gameboycore/include/gameboycore/apu.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - \file apu.h - \brief Audio Emulation - \author Natesh Narain - \date Nov 3 2016 - \defgroup Audio -*/ - - -#ifndef GAMEBOYCORE_APU_H -#define GAMEBOYCORE_APU_H - -#include "gameboycore/gameboycore_api.h" -#include "gameboycore/mmu.h" - -#include -#include - -namespace gb -{ - /** - \class APU - \brief Emulate Gameboy sound functions - \ingroup API - \ingroup Audio - */ - class GAMEBOYCORE_API APU - { - public: - enum - { - CHANNEL_COUNT = 2, ///< Number of audio channels the APU provides (Stereo sound: left, right) - SAMPLE_RATE = 44100 ///< Audio sample rate - }; - public: - //! Smart pointer type - using Ptr = std::unique_ptr; - //! Callback used to provide audio to the host system - using AudioSampleCallback = std::function; - - public: - - APU(MMU::Ptr& mmu); - APU(const APU&) = delete; - ~APU(); - - /** - Update APU with the elasped cycles. For use by the CPU - */ - void update(uint8_t cycles); - - /** - Get Sound 1 output - */ - uint8_t getSound1Volume(); - - /** - Get Sound 2 output - */ - uint8_t getSound2Volume(); - - /** - Get Sound 3 output - */ - uint8_t getSound3Volume(); - - /** - Get Sound 4 output - */ - uint8_t getSound4Volume(); - - /** - Set the host callback - */ - void setAudioSampleCallback(AudioSampleCallback callback); - - private: - class Impl; - Impl* impl_; - }; -} - -#endif diff --git a/components/gameboycore/include/gameboycore/cartinfo.h b/components/gameboycore/include/gameboycore/cartinfo.h deleted file mode 100644 index f5ff2938..00000000 --- a/components/gameboycore/include/gameboycore/cartinfo.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - @file cartinfo.h - @author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_CARTINFO_H -#define GAMEBOYCORE_CARTINFO_H - -#include "gameboycore/memorymap.h" -#include - -namespace gb -{ - /** - Structure containing cartridge information, contained in header - */ - struct CartInfo - { - uint8_t type; - uint8_t rom_size; - uint8_t ram_size; - char game_title[(memorymap::GAME_TITLE_END - memorymap::GAME_TITLE_START) + 1]; - bool cgb_enabled; - }; - - /** - \brief Used to parse rom image for information contained in header - */ - class RomParser - { - public: - RomParser(); - - static CartInfo parse(const uint8_t* image); - }; -} - -#endif diff --git a/components/gameboycore/include/gameboycore/channel.h b/components/gameboycore/include/gameboycore/channel.h deleted file mode 100644 index cbb8a6ad..00000000 --- a/components/gameboycore/include/gameboycore/channel.h +++ /dev/null @@ -1,118 +0,0 @@ - -/** - \file channel.h - \brief Base class for Sound channel - \author Natesh Narain - \date Nov 5 2016 -*/ - -#ifndef GAMEBOYCORE_CHANNEL_H -#define GAMEBOYCORE_CHANNEL_H - -#include - -namespace gb -{ - namespace detail - { - /** - \class Channel - \brief Base class for Sound channel - \ingroup Audio - */ - class Channel - { - enum{ - //! Mask covers DAC bits - DAC_MASK = 0xF8 - }; - - public: - Channel(uint8_t& nrx1, uint8_t& nrx2, uint8_t& nrx3, uint8_t& nrx4) : - nrx1_(nrx1), - nrx2_(nrx2), - nrx3_(nrx3), - nrx4_(nrx4), - length_counter_(0), - enabled_(false) - { - } - - ~Channel() - { - } - - virtual void trigger() - { - // only enable channel if the DAC is on - if(isDacEnabled()) - enabled_ = true; - - if (length_counter_ == 0) - length_counter_ = 64; - } - - bool isEnabled() const - { - return enabled_; - } - - uint8_t getLength() const - { - return length_counter_; - } - - void setLength(int length) - { - length_counter_ = length; - } - - void setDacPower(uint8_t p) - { - if (p == 0) - enabled_ = false; - } - - virtual bool isDacEnabled() const - { - return (nrx2_ & DAC_MASK) != 0; - } - - void clockLength() - { - if (!isCounterMode()) return; - - if (length_counter_ > 0) - { - length_counter_--; - } - - if (length_counter_ == 0) - enabled_ = false; - } - - private: - bool isCounterMode() - { - return (nrx4_ & 0x40) != 0; - } - - protected: - //! NRx1 APU Register - uint8_t& nrx1_; - //! NRx2 APU Register - uint8_t& nrx2_; - //! NRx3 APU Register - uint8_t& nrx3_; - //! NRx4 APU Register - uint8_t& nrx4_; - - //! Length Counter - int length_counter_; - //! Channel Enabled flag - bool enabled_; - }; - } -} - -#endif diff --git a/components/gameboycore/include/gameboycore/cpu.h b/components/gameboycore/include/gameboycore/cpu.h deleted file mode 100644 index f29d7787..00000000 --- a/components/gameboycore/include/gameboycore/cpu.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - \file cpu.h - \brief Gameboy CPU - \author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_CPU_H -#define GAMEBOYCORE_CPU_H - -#include "gameboycore/mmu.h" -#include "gameboycore/gpu.h" -#include "gameboycore/apu.h" -#include "gameboycore/link.h" -#include "gameboycore/instruction.h" - -#include -#include -#include -#include - -namespace gb -{ - /*! - \class CPU - \brief Emulates Gameboy CPU instructions - \ingroup API - */ - class GAMEBOYCORE_API CPU - { - public: - //! CPU state - struct Status - { - uint16_t af; - uint8_t a; - uint8_t f; - - uint16_t bc; - uint8_t b; - uint8_t c; - - uint16_t de; - uint8_t d; - uint8_t e; - - uint16_t hl; - uint8_t h; - uint8_t l; - - uint16_t pc; - uint16_t sp; - - bool halt; - bool stopped; - bool ime; - uint8_t enabled_interrupts; - - bool flag_z; - bool flag_n; - bool flag_h; - bool flag_c; - }; - - //! Flags set by the most recent instruction - enum Flags - { - Z = 1 << 7, - N = 1 << 6, - H = 1 << 5, - C = 1 << 4 - }; - - //! Smart pointer type - using Ptr = std::unique_ptr; - - public: - CPU(MMU::Ptr& mmu, GPU::Ptr& gpu, APU::Ptr& apu, Link::Ptr& link); - CPU(const CPU&) = delete; - ~CPU(); - - /** - Run one CPU fetch, decode, execute cycle - */ - void step(); - - /** - Reset the CPU state - */ - void reset(); - - /** - \return true if the CPU is halted - */ - bool isHalted() const noexcept; - - /** - Set CPU debug mode - */ - void setDebugMode(bool debug_mode) noexcept; - - /** - Set a callback for every CPU instruction. - */ - void setInstructionCallback(std::function) noexcept; - - /** - Serialize the CPU state - */ - std::array serialize() const noexcept; - - /** - Deserialize the CPU state - */ - void deserialize(const std::array& data) noexcept; - - /** - Get the current status of the CPU - */ - Status getStatus() const; - - private: - // Private implementation class - class Impl; - Impl* impl_; - }; -} - -#endif // GAMEBOYCORE_CPU_H diff --git a/components/gameboycore/include/gameboycore/detail/audio/noise_channel.h b/components/gameboycore/include/gameboycore/detail/audio/noise_channel.h deleted file mode 100644 index cc70f89e..00000000 --- a/components/gameboycore/include/gameboycore/detail/audio/noise_channel.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - \author Natesh Narain - \date Nov 3 2016 -*/ - -#ifndef GAMEBOYCORE_NOISE_H -#define GAMEBOYCORE_NOISE_H - -#include -#include - -namespace gb -{ - namespace detail - { - /** - \class NoiseChannel - \brief Generate white noise - \ingroup Audio - */ - class NoiseChannel - { - public: - NoiseChannel() : - length_(0), - length_envelope_(0), - envelope_add_mode_(false), - envelope_default_(0), - division_ratio_(0), - width_mode_(false), - shift_clock_frequency_(0), - length_enabled_(false), - trigger_(false), - volume_(0), - output_volume_(0), - length_counter_(0), - timer_load_(0), - timer_(0), - divisor_table_{{8, 16, 32, 48, 64, 80, 96, 112}}, - lfsr_(0), - dac_enabled_(false), - is_enabled_(false) - { - } - - void step() - { - // count down timer - if (--timer_ <= 0) - { - // reload timer - timer_ = timer_load_; - - // It has a 15 - bit shift register with feedback.When clocked by the frequency timer, the low two bits(0 and 1) are XORed, - // all bits are shifted right by one, and the result of the XOR is put into the now - empty high bit. If width mode is 1 (NR43), - // the XOR result is ALSO put into bit 6 AFTER the shift, resulting in a 7 - bit LFSR. - // The waveform output is bit 0 of the LFSR, INVERTED. - uint8_t xored = (lfsr_ & 0x01) ^ ((lfsr_ >> 1) & 0x01); - lfsr_ >>= 1; - lfsr_ |= (xored << 14); - - if (width_mode_) - { - lfsr_ = (lfsr_ & 0x04) | (xored << 6); - } - - if (is_enabled_ && dac_enabled_ && (lfsr_ & 0x01) == 0) - { - output_volume_ = volume_; - } - else - { - output_volume_ = 0; - } - } - } - - void clockLength() - { - if (length_enabled_ && length_counter_ > 0) - { - if (--length_counter_ <= 0) - { - is_enabled_ = false; - } - } - } - - void clockVolume() - { - // count down envelope timer - if (envelope_timer_-- <= 0) - { - // reload envelope timer - envelope_timer_ = length_envelope_; - - if (envelope_add_mode_ && volume_ < 15) - { - volume_++; - } - else if (!envelope_add_mode_ && volume_ > 0) - { - volume_--; - } - } - } - - uint8_t read(uint16_t register_number) - { - switch (register_number) - { - case 0: - return length_ & 0x3F; - case 1: - return (envelope_default_ << 4) | (envelope_add_mode_ << 3) | (length_envelope_ & 0x07); - case 2: - return (shift_clock_frequency_ << 4) | (width_mode_ << 3) | (division_ratio_ & 0x07); - case 3: - return (trigger_ << 7) | (length_enabled_ << 6); - default: - return 0; - } - } - - void write(uint8_t value, uint16_t register_number) - { - switch (register_number) - { - case 0: - length_ = value & 0x3F; - break; - case 1: - length_envelope_ = value & 0x07; - envelope_add_mode_ = (value & 0x08) != 0; - envelope_default_ = (value & 0xF0) >> 4; - break; - case 2: - division_ratio_ = value & 0x07; - width_mode_ = (value & 0x08) != 0; - shift_clock_frequency_ = (value & 0xF0) >> 4; - break; - case 3: - length_enabled_ = (value & 0x40) != 0; - trigger_ = (value & 0x80) != 0; - - if (trigger_) - trigger(); - break; - default: - break; - } - } - - uint8_t getVolume() const - { - return output_volume_; - } - - bool isEnabled() const - { - return is_enabled_; - } - - void disable() - { - is_enabled_ = false; - } - - private: - void trigger() - { - length_counter_ = 64 - length_; - envelope_timer_ = length_envelope_; - volume_ = envelope_default_; - - timer_load_ = divisor_table_[division_ratio_] << shift_clock_frequency_; - timer_ = timer_load_; - } - - uint8_t length_; - uint8_t length_envelope_; - bool envelope_add_mode_; - uint8_t envelope_default_; - uint8_t division_ratio_; - bool width_mode_; - uint8_t shift_clock_frequency_; - bool length_enabled_; - bool trigger_; - - uint8_t volume_; - uint8_t output_volume_; - uint8_t length_counter_; - uint8_t envelope_timer_; - int timer_load_; - int timer_; - - std::array divisor_table_; - uint16_t lfsr_; - - bool dac_enabled_; - bool is_enabled_; - }; - } -} - -#endif // GAMEBOY_NOISE_H diff --git a/components/gameboycore/include/gameboycore/detail/audio/square_wave_channel.h b/components/gameboycore/include/gameboycore/detail/audio/square_wave_channel.h deleted file mode 100644 index 26b2e63e..00000000 --- a/components/gameboycore/include/gameboycore/detail/audio/square_wave_channel.h +++ /dev/null @@ -1,319 +0,0 @@ - -/** - \file square.h - \brief Square wave generator - \author Natesh Narain - \date Nov 21 2016 -*/ - -#ifndef GAMEBOYCORE_SQUARE_WAVE_CHANNEL_H -#define GAMEBOYCORE_SQUARE_WAVE_CHANNEL_H - -#include -#include - -namespace gb -{ - namespace detail - { - /** - \class Square - \brief Square wave generator channels - \ingroup Audio - */ - class SquareWaveChannel - { - public: - static constexpr int LENGTH_MASK = 0x3F; - static constexpr int DAC_MASK = 0xF8; - - public: - - SquareWaveChannel(bool sweep = true) - : sweep_period_{ 0 } - , sweep_negate_{ false } - , sweep_shift_{ 0 } - , sweep_timer_{ 0 } - , frequency_shadow_{ 0 } - , sweep_enabled_{ sweep } - , duty_{ 0 } - , length_{ 0 } - , length_counter_{ 0 } - , volume_{ 0 } - , envelope_add_mode_{ false } - , envelop_period_{ 0 } - , dac_enabled_{ false } - , volume_counter_{ 0 } - , envelop_timer_{ 0 } - , frequency_{ 0 } - , trigger_{ false } - , length_enabled_{ false } - , is_enabled_{ false } - , waveform_idx_{ 0 } - , waveform_timer_{0} - , waveform_timer_load_{ 0 } - , output_volume_{0} - { - // waveforms with different duty cycles - waveform_[0] = { 0, 0, 0, 0, 0, 0, 0, 1 }; - waveform_[1] = { 1, 0, 0, 0, 0, 0, 0, 1 }; - waveform_[2] = { 1, 0, 0, 0, 0, 1, 1, 1 }; - waveform_[3] = { 0, 1, 1, 1, 1, 1, 1, 0 }; - } - - ~SquareWaveChannel() - { - } - - void step() - { - // clock the waveform timer - if (waveform_timer_-- <= 0) - { - // reset timer - waveform_timer_ = waveform_timer_load_; - - // next waveform value - waveform_idx_ = (waveform_idx_ + 1) % waveform_[0].size(); - } - - // compute the output volume - // volume is zero if not enabled - if (isEnabled() && dac_enabled_) - { - output_volume_ = volume_counter_; - } - else - { - output_volume_ = 0; - } - - // output is low if the waveform is low - if (waveform_[duty_][waveform_idx_] == 0) - { - output_volume_ = 0; - } - } - - void clockLength() - { - if (length_enabled_ && length_counter_ > 0) - { - // decrement the length counter and disable the channel when it reaches zero - if (length_counter_-- == 0) - { - is_enabled_ = false; - } - } - } - - void clockVolume() - { - // clock the envelop timer - if (envelop_timer_-- <= 0) - { - // reset envelop timer - envelop_timer_ = envelop_period_; - - if (envelop_period_ != 0) - { - if (envelope_add_mode_ && volume_counter_ < 15) - { - volume_counter_++; - } - else if (!envelope_add_mode_ && volume_counter_ > 0) - { - volume_counter_--; - } - } - } - } - - void clockSweep() - { - // clock sweep timer - if (sweep_timer_-- <= 0) - { - // reload sweep timer - sweep_timer_ = sweep_period_; - - if (sweep_enabled_ && sweep_period_ > 0) - { - auto newFreq = sweepCalculation(); - - if (newFreq <= 2047 && sweep_shift_ > 0) - { - frequency_shadow_ = (uint16_t)newFreq; - waveform_timer_load_ = newFreq; - sweepCalculation(); - } - - sweepCalculation(); - } - } - } - - uint8_t read(uint16_t register_number) - { - // deconstruct byte value into variables - - switch (register_number) - { - case 0: - return ((sweep_period_ & 0x07) << 4) | (sweep_negate_ << 3) | (sweep_shift_ & 0x07); - case 1: - return ((duty_ & 0x03) << 6) | (length_ & 0x3F); - case 2: - return ((volume_ & 0x0F) << 4) | (envelope_add_mode_ << 3) | (envelop_period_ & 0x07); - case 3: - return frequency_ & 0x00FF; - case 4: - return ((frequency_ & 0x0700) >> 8) | (trigger_ << 7) | (length_enabled_ << 6); - } - - return 0; - } - - void write(uint8_t value, uint16_t register_number) - { - // construct byte values from variables - - switch (register_number) - { - case 0: - sweep_period_ = (value & 0x70) >> 4; - sweep_negate_ = (value & 0x08) != 0; - sweep_shift_ = value & 0x07; - - sweep_timer_ = sweep_period_; - break; - case 1: - duty_ = (value >> 6); - length_ = (value & 0x3F); - length_counter_ = 64 - length_; - break; - case 2: - volume_ = (value >> 4); - envelope_add_mode_ = (value & 0x08) != 0; - envelop_period_ = (value & 0x07); - - dac_enabled_ = (value & DAC_MASK) != 0; - volume_counter_ = volume_; - envelop_timer_ = envelop_period_; - - break; - case 3: - frequency_ = (frequency_ & 0xFF00) | value; - break; - case 4: - frequency_ = (frequency_ & 0x00FF) | ((value & 0x07) << 8); - length_enabled_ = (value & 0x40) != 0; - trigger_ = (value & 0x80) != 0; - - if (trigger_) - trigger(); - - break; - } - } - - void trigger() - { - is_enabled_ = true; - - waveform_timer_load_ = calculateWaveformTimer(); - waveform_timer_ = waveform_timer_load_; - - // sweep - frequency_shadow_ = frequency_; - sweep_timer_ = sweep_period_; - - sweep_enabled_ = (sweep_period_ > 0) || (sweep_shift_ > 0); - } - - int calculateWaveformTimer() - { - return (2048 - frequency_) * 4; - } - - int sweepCalculation() - { - int f = 0; - - f = frequency_shadow_ >> sweep_shift_; - - if (sweep_negate_) - { - f = frequency_shadow_ - f; - } - else - { - f = frequency_shadow_ + f; - } - - sweep_enabled_ = f < 2047; - - return f; - } - - uint8_t getVolume() const - { - return output_volume_; - } - - bool isEnabled() const - { - return is_enabled_; - } - - void disable() - { - is_enabled_ = false; - } - - private: - // NR10 FF10: -PPP NSSS Sweep period, negate, shift - uint8_t sweep_period_; - bool sweep_negate_; - uint8_t sweep_shift_; - - int sweep_timer_; - uint16_t frequency_shadow_; - bool sweep_enabled_; - - // NR11 FF11: DDLL LLLL Duty, Length load (64-L) - uint8_t duty_; - uint8_t length_; - int length_counter_; - - // NR12 FF12: VVVV APPP Starting volume, Envelope add mode, period - uint8_t volume_; - bool envelope_add_mode_; - uint8_t envelop_period_; - - bool dac_enabled_; - uint8_t volume_counter_; - int envelop_timer_; - - // NR13 FF13: FFFF FFFF Frequency LSB - uint16_t frequency_; - - // NR14 FF14 TL-- -FFF Trigger, Length enable, Frequency MSB - bool trigger_; - bool length_enabled_; - - // - bool is_enabled_; - - std::array, 4> waveform_; - int waveform_idx_; - int waveform_timer_; - int waveform_timer_load_; - - uint8_t output_volume_; - - }; - } -} - -#endif // GAMEBOYCORE_SOUND_H diff --git a/components/gameboycore/include/gameboycore/detail/audio/wave_channel.h b/components/gameboycore/include/gameboycore/detail/audio/wave_channel.h deleted file mode 100644 index 98826c40..00000000 --- a/components/gameboycore/include/gameboycore/detail/audio/wave_channel.h +++ /dev/null @@ -1,194 +0,0 @@ - -/** - \author Natesh Narain -*/ - -#ifndef GAMEBOY_WAVE_CHANNEL_H -#define GAMEBOY_WAVE_CHANNEL_H - -#include - -namespace gb -{ - namespace detail - { - /** - \class Wave - \brief Wave register - \ingroup Audio - */ - class WaveChannel - { - public: - static const int LENGTH_MASK = 0xFF; - - public: - WaveChannel() : - dac_enabled_(false), - length_load_(0), - volume_code_(0), - frequency_(0), - length_enabled_(false), - trigger_(false), - wave_ram_{0}, - timer_load_(0), - timer_(0), - sample_index_(0), - length_counter_(0), - volume_(0), - shift_table_{{4, 0, 1, 2}}, - is_enabled_(false) - { - } - - ~WaveChannel() - { - } - - void clockLength() - { - // wave channel length counter will disable channel when it gets to zero - if (length_enabled_ && length_counter_ > 0) - { - if (length_counter_-- <= 0) - { - is_enabled_ = false; - } - } - } - - void step() - { - // wave channel internal timer - if (timer_-- <= 0) - { - timer_ = timer_load_; - - // next sample index - sample_index_ = (sample_index_ + 1) % wave_ram_.size(); - - // get the next volume - volume_ = wave_ram_[sample_index_]; - volume_ >>= shift_table_[volume_code_]; - } - - if (!dac_enabled_ || !is_enabled_) - volume_ = 0; - } - - uint8_t read(uint16_t register_number) - { - switch (register_number) - { - case 0: - return (dac_enabled_ << 7); - case 1: - return length_load_; - case 2: - return volume_code_ << 5; - case 3: - return frequency_ & 0x00FF; - case 4: - return (trigger_ << 7) | (length_enabled_ << 6) | ((frequency_ & 0x0700) >> 8); - default: - return 0; - } - } - - void write(uint8_t value, uint16_t register_number) - { - switch (register_number) - { - case 0: - dac_enabled_ = (value & 0x80) != 0; - break; - - case 1: - length_load_ = value; - break; - - case 2: - volume_code_ = (value & 0x60) >> 5; - break; - - case 3: - frequency_ = (frequency_ & 0xFF00) | value; - break; - - case 4: - frequency_ = (frequency_ & 0x00FF) | ((value & 0x0007) << 8); - length_enabled_ = (value & 0x40) != 0; - trigger_ = (value & 0x80) != 0; - - if (trigger_) - trigger(); - - break; - } - } - - uint8_t readWaveRam(uint16_t addr) - { - auto idx = (addr & 0x000F) * 2; - return ((wave_ram_[idx]) << 4) | wave_ram_[idx+1]; - } - - void writeWaveRam(uint8_t value, uint16_t addr) - { - auto idx = (addr & 0x0F) * 2; - - wave_ram_[idx] = (value & 0xF0) >> 4; - wave_ram_[idx+1] = value & 0x0F; - } - - bool isEnabled() const - { - return is_enabled_; - } - - uint8_t getVolume() const - { - return volume_; - } - - void disable() - { - is_enabled_ = false; - } - - private: - - void trigger() - { - is_enabled_ = true; - - timer_load_ = (2048 - frequency_) * 2; - timer_ = timer_load_; - - length_counter_ = length_load_; - } - - bool dac_enabled_; - uint8_t length_load_; - uint8_t volume_code_; - uint16_t frequency_; - bool length_enabled_; - bool trigger_; - - std::array wave_ram_; - - - int timer_load_; - int timer_; - int sample_index_; - int length_counter_; - uint8_t volume_; - - std::array shift_table_; - - bool is_enabled_; - }; - } -} - -#endif // GAMEBOYCORE_WAVE_H diff --git a/components/gameboycore/include/gameboycore/detail/hash.h b/components/gameboycore/include/gameboycore/detail/hash.h deleted file mode 100644 index 23f8a5a3..00000000 --- a/components/gameboycore/include/gameboycore/detail/hash.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef GAMEBOYCORE_DETAIL_HASH -#define GAMEBOYCORE_DETAIL_HASH - -#include -#include - -namespace gb -{ - namespace detail - { - // boost::hash_combine - template - inline void hash_combine(std::size_t& seed, T const& v) - { - seed ^= std::hash{}(v) + 0x9E3779B9 + (seed << 6) + (seed >> 2); - } - - /** - Vector Hash - */ - template - struct ContainerHash - { - using argument_type = T; - using result_type = std::size_t; - - result_type operator()(argument_type const& in) const - { - std::size_t seed = 0; - for (const auto& i : in) - hash_combine(seed, i); - - return seed; - } - }; - } -} - -#endif diff --git a/components/gameboycore/include/gameboycore/detail/rtc/rtc.h b/components/gameboycore/include/gameboycore/detail/rtc/rtc.h deleted file mode 100644 index ce2d3afa..00000000 --- a/components/gameboycore/include/gameboycore/detail/rtc/rtc.h +++ /dev/null @@ -1,109 +0,0 @@ -/** - \file rtc.h - \brief Real Time Clock Emulation - \author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_RTC_H -#define GAMEBOYCORE_RTC_H - -#include - -#include -#include -#include - -namespace gb -{ - namespace detail - { - /** - \class RTC - \brief Real Time Clock - \ingroup MBC - */ - class RTC - { - private: - static constexpr uint8_t REGISTER_BASE = 0x08; - - enum Registers - { - SECONDS_REGISTER = 0, - MINUTES_REGISTER, - HOURS_REGISTER, - DAY_LSB_REGISTER, - DAY_MSB_REGISTER - }; - - public: - RTC() - : enabled_{false} - , selected_{0} - , time_data_{0, 0, 0} - { - time_provider_ = RTC::getTime; - } - - ~RTC() - { - } - - uint8_t get() const - { - return time_data_[selected_]; - } - - void setEnable(bool enable) - { - enabled_ = enable; - } - - void latch() - { - const auto time = time_provider_(); - time_data_[0] = time.seconds; - time_data_[1] = time.minutes; - time_data_[2] = time.hours; - time_data_[3] = time.days & 0xFF; - time_data_[4] = (time.days & 0x100) >> 8; - } - - void select(uint8_t reg) - { - selected_ = reg - REGISTER_BASE; - } - - bool isEnabled() const - { - return enabled_; - } - - void setTimeProvider(TimeProvider fn) - { - time_provider_ = fn; - } - - static const Time getTime() - { - const auto time = std::time(0); - const auto now = std::localtime(&time); - - const auto seconds = static_cast(now->tm_sec); - const auto minutes = static_cast(now->tm_min); - const auto hours = static_cast(now->tm_hour); - const auto days = static_cast(now->tm_yday); - - return Time{ seconds, minutes, hours, days }; - } - - private: - bool enabled_; - uint8_t selected_; - std::array time_data_; - TimeProvider time_provider_; - }; - } -} - -#endif // GAMEBOYCORE_RTC_H diff --git a/components/gameboycore/include/gameboycore/gameboycore.h b/components/gameboycore/include/gameboycore/gameboycore.h deleted file mode 100644 index 1c854d1e..00000000 --- a/components/gameboycore/include/gameboycore/gameboycore.h +++ /dev/null @@ -1,174 +0,0 @@ -/** - \file gameboycore.h - \brief Encapsulate Gameboy hardware - \author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_H -#define GAMEBOYCORE_H - -#include "gameboycore/gameboycore_api.h" - -#include "gameboycore/cpu.h" -#include "gameboycore/mmu.h" -#include "gameboycore/gpu.h" -#include "gameboycore/apu.h" -#include "gameboycore/joypad.h" -#include "gameboycore/link.h" - -#include -#include -#include - -//! GameboyCore namespace -namespace gb -{ - /** - \brief Encapsulation for Gameboy emulation - \class GameboyCore - \ingroup API - */ - class GAMEBOYCORE_API GameboyCore - { - public: - enum class ColorTheme - { - DEFAULT, - GOLD, - GREEN - }; - - GameboyCore(); - GameboyCore(const GameboyCore&) = delete; - ~GameboyCore(); - - /** - runs `steps` number of steps on the gameboycore - */ - void update(int steps = 1); - - /** - Run emulation for a single frame - */ - void emulateFrame(); - - /** - Load a ROM file - */ - void open(const std::string& filename); - - /** - Load byte buffer into virtual memroy - */ - void loadROM(const std::vector& buffer); - - /** - Load byte buffer into virtual memory - */ - void loadROM(const uint8_t* rom, uint32_t size); - - /** - Reset the GameboyCore state - */ - void reset(); - - /** - Enable debug output - */ - void setDebugMode(bool debug); - - /** - Set Color theme - */ - void setColorTheme(ColorTheme theme); - - /** - * Read memory - */ - uint8_t readMemory(uint16_t addr); - - /** - * Write memory - */ - void writeMemory(uint16_t addr, uint8_t value); - - /** - Set scanline callback - */ - void setScanlineCallback(GPU::RenderScanlineCallback callback); - - /** - Set VBlank callback - */ - void setVBlankCallback(GPU::VBlankCallback callback); - - /** - Set audio sample callback - */ - void setAudioSampleCallback(APU::AudioSampleCallback callback); - - /** - Joypad key input event - */ - void input(Joy::Key key, bool pressed); - - /** - Get battery RAM - - This copies the battery backed RAM from the emulator and returns it to the user - */ - std::vector getBatteryRam() const; - - /** - Set battery RAM - */ - void setBatteryRam(const std::vector& ram); - - /** - Write a byte to the serial port - */ - void linkWrite(uint8_t byte); - - /** - Set Link ready callback - - Set a callback that fires when the core is ready to transfer a byte to the serial port - */ - void setLinkReadyCallback(Link::ReadyCallback callback); - - /** - Serialize GameboyCore state - */ - std::vector serialize() const; - - /** - Deserialize GameboyCore state - */ - void deserialize(const std::vector& data); - - /** - Set the time to be read from the RTC register (MBC3) - */ - void setTimeProvider(const TimeProvider provider); - - /** - Set instruction callback - */ - void setInstructionCallback(std::function instr); - - CPU::Ptr& getCPU(); - MMU::Ptr& getMMU(); - GPU::Ptr& getGPU(); - APU::Ptr& getAPU(); - Joy::Ptr& getJoypad(); - Link::Ptr& getLink(); - - bool isDone() const; - - private: - class Impl; - Impl* impl_; - }; -} - -#endif // GAMEBOYCORE_H diff --git a/components/gameboycore/include/gameboycore/gameboycore_api.h b/components/gameboycore/include/gameboycore/gameboycore_api.h deleted file mode 100644 index d9e5d66d..00000000 --- a/components/gameboycore/include/gameboycore/gameboycore_api.h +++ /dev/null @@ -1,25 +0,0 @@ - -/** - \file gameboycore_api.h - \brief Define export macros - \author Natesh Narain - \date Nov 12 2016 - \defgroup API -*/ - -#ifndef GAMEBOYCORE_API_H -#define GAMEBOYCORE_API_H - -/* DLL Export/Import */ - -#if defined(_MSC_VER) && !defined(GAMEBOYCORE_STATIC) -# if defined(GAMEBOYCORE_EXPORT) -# define GAMEBOYCORE_API __declspec(dllexport) -# else -# define GAMEBOYCORE_API __declspec(dllimport) -# endif -#else -# define GAMEBOYCORE_API -#endif - -#endif diff --git a/components/gameboycore/include/gameboycore/gpu.h b/components/gameboycore/include/gameboycore/gpu.h deleted file mode 100644 index 24ca325d..00000000 --- a/components/gameboycore/include/gameboycore/gpu.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - \file gpu.h - \brief GPU emulation - \author Natesh Narain - \date Oct 23 2016 - - \defgroup Graphics -*/ - -#ifndef GAMEBOYCORE_GPU_H -#define GAMEBOYCORE_GPU_H - -#include "gameboycore_api.h" -#include "gameboycore/mmu.h" -#include "gameboycore/pixel.h" -#include "gameboycore/sprite.h" - -#include -#include -#include -#include -#include - -namespace gb -{ - /** - \class GPU - \brief Handle LCD state, compute scanlines and send to an external renderer - \ingroup API - \ingroup Graphics - */ - class GAMEBOYCORE_API GPU - { - public: - //! Smart pointer type - using Ptr = std::unique_ptr; - - //! Array on Pixel objects representing a single scan line produced by the GPU - using Scanline = std::array; - - /** - Callback function called by the GPU when it has produced a new scan line - Provides the Scanline and the line number - */ - using RenderScanlineCallback = std::function; - - /** - Callback function call by the GPU when VBlank is reached - */ - using VBlankCallback = std::function; - - public: - explicit GPU(MMU::Ptr& mmu); - GPU(const GPU&) = delete; - ~GPU(); - - /** - Update the GPU with elasped cycles. Used by the CPU - */ - void update(uint8_t cycles, bool ime); - - /** - Set the host system callback - */ - void setRenderCallback(RenderScanlineCallback callback); - - /** - Set the host system vblank callback - */ - void setVBlankCallback(VBlankCallback callback); - - /** - Set Default Palette Color - */ - void setPaletteColor(uint8_t r, uint8_t g, uint8_t b, int idx); - - /** - \return Background tilemap data - */ - std::vector getBackgroundTileMap(); - - /** - \return currently cached tile data - */ - std::array getSpriteCache() const; - - /** - \return Hashed background map - */ - std::size_t getBackgroundHash(); - - private: - //! Private Implementation class - class Impl; - Impl* impl_; - }; -} - -#endif diff --git a/components/gameboycore/include/gameboycore/instruction.h b/components/gameboycore/include/gameboycore/instruction.h deleted file mode 100644 index 1adae1d1..00000000 --- a/components/gameboycore/include/gameboycore/instruction.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * \file instruction.h - * \author Natesh Narain - * \date April 21 2019 -*/ - -#ifndef GAMEBOYCORE_INSTRUCTION_H -#define GAMEBOYCORE_INSTRUCTION_H - -#include -#include -#include - -namespace gb -{ - struct Instruction - { - enum class OpcodePage - { - PAGE1, - PAGE2 - }; - - //! Instruction Opcode - uint8_t opcode; - //! Opcode Page - OpcodePage page; - //! Opcode Data - std::array operand_data; - - Instruction(uint8_t opcode, OpcodePage page, std::array data) - : opcode{opcode} - , page{page} - , operand_data{data} - { - } - }; - - /** - Stringify a Instruction struct - */ - std::string disassemble(const Instruction& instruction); - -} - -#endif // GAMEBOYCORE_INSTRUCTION_H diff --git a/components/gameboycore/include/gameboycore/interrupt_provider.h b/components/gameboycore/include/gameboycore/interrupt_provider.h deleted file mode 100644 index c8a8032a..00000000 --- a/components/gameboycore/include/gameboycore/interrupt_provider.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef GAMEBOYCORE_INTERRUPT_PROVIDER_H -#define GAMEBOYCORE_INTERRUPT_PROVIDER_H - -#include "gameboycore/mmu.h" -#include "gameboycore/memorymap.h" - -#include - -namespace gb -{ - /** - \class InterruptProvider - \brief Used to set interrupt flag register for a single interrupt - */ - class InterruptProvider - { - public: - enum class Interrupt - { - VBLANK = (1 << 0), - LCDSTAT = (1 << 1), - TIMER = (1 << 2), - SERIAL = (1 << 3), - JOYPAD = (1 << 4) - }; - - public: - InterruptProvider(MMU& mmu, Interrupt interrupt) : - flags_(mmu.get(memorymap::INTERRUPT_FLAG)), - interrupt_(interrupt) - { - } - - /** - Set the interrupt - */ - void set() - { - flags_ |= static_cast(interrupt_); - } - - ~InterruptProvider() - { - } - - private: - uint8_t& flags_; - Interrupt interrupt_; - }; - -} - -#endif diff --git a/components/gameboycore/include/gameboycore/joypad.h b/components/gameboycore/include/gameboycore/joypad.h deleted file mode 100644 index 01757813..00000000 --- a/components/gameboycore/include/gameboycore/joypad.h +++ /dev/null @@ -1,63 +0,0 @@ - -/** - \file joypad.h - \brief Emulate Gameboy user input - \author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_JOYPAD_H -#define GAMEBOYCORE_JOYPAD_H - -#include "gameboycore/gameboycore_api.h" -#include "gameboycore/mmu.h" - -#include -#include - -namespace gb -{ - /** - \class Joy - \brief Emulate Gameboy Joypad - \ingroup API - */ - class GAMEBOYCORE_API Joy - { - public: - //! Keys on the Gameboy - enum class Key - { - RIGHT = 0, - LEFT = 1, - UP = 2, - DOWN = 3, - A = 4, - B = 5, - SELECT = 6, - START = 7 - }; - - //! Smart pointer type - using Ptr = std::unique_ptr; - - explicit Joy(MMU& mmu); - Joy(const Joy&); - ~Joy(); - - /** - Press Key on the Gameboy - */ - void press(Key key); - /** - Release Key on the Gameboy - */ - void release(Key key); - - private: - //! Private Implementation - class Impl; - Impl* impl_; - }; -} - -#endif // GAMEBOY_JOYPAD_H diff --git a/components/gameboycore/include/gameboycore/link.h b/components/gameboycore/include/gameboycore/link.h deleted file mode 100644 index e7301771..00000000 --- a/components/gameboycore/include/gameboycore/link.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - \file link.h - \brief Link port emulation - \author Natesh Narain - \date Nov 30 2016 -*/ - -#ifndef GAMEBOYCORE_LINK_H -#define GAMEBOYCORE_LINK_H - -#include "gameboycore/gameboycore_api.h" -#include "gameboycore/mmu.h" - -#include -#include -#include - -namespace gb -{ - /** - \class Link - \brief Emulate link port - \ingroup API - */ - class GAMEBOYCORE_API Link - { - public: - enum class Mode - { - INTERNAL, ///< Internal Clock Mode - EXTERNAL ///< External Clock Mode - }; - - //! Smart pointer type - using Ptr = std::unique_ptr; - - //! Callback to signal transfer ready status - using ReadyCallback = std::function; - - public: - explicit Link(MMU::Ptr& mmu); - Link(const Link&) = delete; - ~Link(); - - /** - Update with CPU cycles elapsed - */ - void update(uint8_t cycles); - - /** - Write a byte buffer into the core - */ - void recieve(uint8_t byte); - - /** - Signal that this core is ready to transfer a byte - */ - void setReadyCallback(const ReadyCallback& callback); - - private: - class Impl; - Impl* impl_; - }; -} - -#endif diff --git a/components/gameboycore/include/gameboycore/link_cable.h b/components/gameboycore/include/gameboycore/link_cable.h deleted file mode 100644 index 3af65a3d..00000000 --- a/components/gameboycore/include/gameboycore/link_cable.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - \file link_cable.h - \brief Gameboy Link Cable Emulation - \author Natesh Narain - \date Dec 10 2016 -*/ - -#ifndef GAMEBOYCORE_LINK_CABLE_H -#define GAMEBOYCORE_LINK_CABLE_H - -#include "gameboycore/gameboycore_api.h" -#include "gameboycore/link.h" - -#include -#include - -namespace gb -{ - /** - \class Link Cable - \brief Contains Gameboy link cable logic - \ingroup API - */ - class GAMEBOYCORE_API LinkCable - { - public: - //! Callback from Link Cable - using RecieveCallback = std::function; - - LinkCable(); - ~LinkCable(); - - void link1ReadyCallback(uint8_t byte, Link::Mode mode); - void link2ReadyCallback(uint8_t byte, Link::Mode mode); - - void setLink1RecieveCallback(const RecieveCallback& callback); - void setLink2RecieveCallback(const RecieveCallback& callback); - - private: - class Impl; - Impl* impl_; - }; -} - -#endif // GAMEBOYCORE_LINK_CABLE_H diff --git a/components/gameboycore/include/gameboycore/mbc.h b/components/gameboycore/include/gameboycore/mbc.h deleted file mode 100644 index 93128aac..00000000 --- a/components/gameboycore/include/gameboycore/mbc.h +++ /dev/null @@ -1,179 +0,0 @@ - -/** - \file mbc.h - \brief Interface memory bank controllers - \author Natesh Narain - \date Oct 11 2016 - - \defgroup MBC Memory Bank Controllers -*/ - -#ifndef GAMEBOYCORE_MBC_H -#define GAMEBOYCORE_MBC_H - -#include -#include -#include - -namespace gb -{ - namespace detail - { - enum { - KILO_BYTE = 1024, - BANK_SIZE = (16 * KILO_BYTE) - }; - - /** - \class MBC - \brief Memory Bank Controller Interface - \ingroup MBC - */ - class MBC - { - public: - enum class Type { - ROM_ONLY = 0x00, - MBC1 = 0x01, - MBC1_RAM = 0x02, - MBC1_RAM_BAT = 0x03, - MBC2 = 0x05, - MBC2_BAT = 0x06, - ROM_RAM = 0x08, - ROM_RAM_BAT = 0x09, - MMM01 = 0x0B, - MMM01_RAM = 0x0C, - MMM01_RAM_BAT = 0x0D, - MBC3_TIME_BAT = 0x0F, - MBC3_TIME_RAM_BAT = 0x10, - MBC3 = 0x11, - MBC3_RAM = 0x12, - MBC3_RAM_BAT = 0x13, - MBC4 = 0x15, - MBC4_RAM = 0x16, - MBC4_RAM_BAT = 0x17, - MBC5 = 0x19, - MBC5_RAM = 0x1A, - MBC5_RAM_BAT = 0x1B, - MBC5_RUMBLE = 0x1C, - MBC5_RUMBLE_RAM = 0x1D, - MBC5_RUMBLE_RAM_BAT = 0x1E - }; - - //! ROM types specified in cartridge header - enum class ROM - { - KB32 = 0x00, ///< 32 kB - KB64 = 0x01, ///< 64 kB - KB128 = 0x02, ///< 128 kB - KB256 = 0x03, ///< 256 kB - KB512 = 0x04, ///< 512 kB - MB1 = 0x05, ///< 1 MB - MB2 = 0x06, ///< 2 MB - MB4 = 0x07, ///< 4 MB - MB1_1 = 0x52, ///< 1.1 MB - MB1_2 = 0x53, ///< 1.2 MB - MB1_5 = 0x54 ///< 1.5 MB - }; - - //! External RAM types specified in the cartridge header - enum class XRAM - { - NONE = 0x00, ///< No External RAM - KB2 = 0x01, ///< 2 kB of External RAM - KB8 = 0x02, ///< 8 kB of External RAM - KB32 = 0x03 ///< (4 x 8 kB) of External RAM - }; - - public: - using Ptr = std::unique_ptr; - - public: - MBC(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable = false); - virtual ~MBC(); - - virtual void write(uint8_t value, uint16_t addr); - virtual uint8_t read(uint16_t addr) const; - - uint8_t readVram(uint16_t addr, uint8_t bank); - - uint8_t& get(uint16_t addr); - uint8_t* getptr(uint16_t addr); - - /** - Get the virtual memory location from the logical address - */ - int resolveAddress(const uint16_t& addr) const; - - std::vector getRange(uint16_t start, uint16_t end) const; - void setMemory(uint16_t start, const std::vector& mem); - - std::vector getXram() const; - - int getRomBank() const; - int getRamBank() const; - bool isXramEnabled() const; - - std::size_t getVirtualMemorySize() const; - - protected: - /** - Called when a write to ROM occurs - */ - virtual void control(uint8_t value, uint16_t addr) = 0; - - //! virtual memory - // std::vector memory_; - uint8_t *memory_; - size_t memory_size_; - //! Flag inidicating if external ram is enabled - bool xram_enable_; - //! ROM bank number - int rom_bank_; - //! RAM bank number - int ram_bank_; - - private: - /** - \return index of address into virtual memory - */ - int getIndex(uint16_t addr, int rom_bank, int ram_bank) const; - - /** - */ - int getIoIndex(uint16_t addr) const; - - /** - Get the VRAM offset given the current state of the VBK register - */ - int getVramOffset() const; - - /** - Get the internal ram bank offset given the current state of the SVBK register - */ - int getInternalRamOffset() const; - - /** - */ - unsigned int kilo(unsigned int n) const; - - /** - Load memory - */ - void loadMemory(const uint8_t* rom, std::size_t size, uint8_t rom_size, uint8_t ram_size); - - //! number of switchable rom banks - int num_rom_banks_; - //! number of cartridge ram banks - int num_cartridge_ram_banks_; - //! CGB enabled - bool cgb_enabled_; - //! CGB mode has 2 vram banks for character and map data - int vram_banks_; - //! number internal ram banks - int num_internal_ram_banks_; - }; - } -} - -#endif // GAMEBOYCORE_MBC_H diff --git a/components/gameboycore/include/gameboycore/mbc1.h b/components/gameboycore/include/gameboycore/mbc1.h deleted file mode 100644 index e9f6f9ac..00000000 --- a/components/gameboycore/include/gameboycore/mbc1.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * \file mbc1.h - * \author Natesh Narain - * \brief Memory Back Controller 1 - * \date Oct 11 2016 -*/ -#ifndef GAMEBOYCORE_MBC1_H -#define GAMEBOYCORE_MBC1_H - -#include "gameboycore/mbc.h" - -#include - -namespace gb -{ - namespace detail - { - /** - \class MBC1 - \brief Memory Bank Controller 1 - \ingroup MBC - */ - class MBC1 : public MBC - { - private: - - //! RAM or ROM bank switching mode - enum class MemoryMode - { - ROM = 0, RAM = 1 ///< determines how address range $4000 - $5000 is used - }; - - public: - MBC1(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enabled); - - protected: - virtual void control(uint8_t value, uint16_t addr); - - private: - void selectRomBank(uint8_t lo, uint8_t hi); - void selectRamBank(uint8_t ram_bank_number); - - uint8_t rom_bank_lower_bits_; // bit 0 - 4 - uint8_t rom_bank_upper_bits_; // bit 5 and 6 - - MemoryMode mode_; - }; - } -} - -#endif diff --git a/components/gameboycore/include/gameboycore/mbc2.h b/components/gameboycore/include/gameboycore/mbc2.h deleted file mode 100644 index 481274e5..00000000 --- a/components/gameboycore/include/gameboycore/mbc2.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - \file mbc2.h - \brief Memory Bank Controller 2 - \author Natesh Narain - \date Nov 20 2016 -*/ - -#ifndef GAMEBOYCORE_MBC2_H -#define GAMEBOYCORE_MBC2_H - -#include "gameboycore/mbc.h" - -namespace gb -{ - namespace detail - { - /** - \class MBC2 - \brief Memory Bank Controller 2 - \ingroup MBC - */ - class MBC2 : public MBC - { - public: - - MBC2(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable); - ~MBC2(); - - virtual void write(uint8_t value, uint16_t addr); - - protected: - virtual void control(uint8_t value, uint16_t addr); - - private: - }; - } -} - -#endif // !GAMEBOYCORE_MBC2_H - diff --git a/components/gameboycore/include/gameboycore/mbc3.h b/components/gameboycore/include/gameboycore/mbc3.h deleted file mode 100644 index dc528148..00000000 --- a/components/gameboycore/include/gameboycore/mbc3.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - \file mbc2.h - \brief Memory Bank Controller 3 - \author Natesh Narain - \date Nov 20 2016 -*/ - -#ifndef GAMEBOYCORE_MBC3_H -#define GAMEBOYCORE_MBC3_H - -#include "gameboycore/mbc.h" -#include "gameboycore/detail/rtc/rtc.h" -#include - -namespace gb -{ - namespace detail - { - /** - \class MBC3 - \brief Memory Bank Controller 3 - \ingroup MBC - */ - class MBC3 : public MBC - { - public: - MBC3(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable); - ~MBC3(); - - virtual uint8_t read(uint16_t addr) const; - - void setTimeProvider(TimeProvider provider); - - protected: - virtual void control(uint8_t value, uint16_t addr); - - private: - RTC rtc_; - uint8_t latch_ctl_; - }; - } -} - -#endif \ No newline at end of file diff --git a/components/gameboycore/include/gameboycore/mbc5.h b/components/gameboycore/include/gameboycore/mbc5.h deleted file mode 100644 index 2fbcb056..00000000 --- a/components/gameboycore/include/gameboycore/mbc5.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef GAMEBOYCORE_MBC5_H -#define GAMEBOYCORE_MBC5_H - -#include "gameboycore/mbc.h" - -namespace gb -{ - namespace detail - { - class MBC5 : public MBC - { - public: - - MBC5(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable); - ~MBC5(); - - void control(uint8_t value, uint16_t addr); - - private: - void selectRomBank(uint8_t lo, uint8_t hi); - - uint8_t rom_bank_lower_bits_; - uint8_t rom_bank_upper_bit_; - }; - } -} - -#endif // GAMEBOYCORE_MBC5_H diff --git a/components/gameboycore/include/gameboycore/memorymap.h b/components/gameboycore/include/gameboycore/memorymap.h deleted file mode 100644 index 7fecb2f8..00000000 --- a/components/gameboycore/include/gameboycore/memorymap.h +++ /dev/null @@ -1,195 +0,0 @@ -/** - \file memorymap.h - \brief Constants that define the CPU memory map - \author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_MEMORYMAP_H -#define GAMEBOYCORE_MEMORYMAP_H - -namespace gb{ - //! Defines values for specific locations in the Gameboy memory map - namespace memorymap{ - enum Locations { - PERMANENT_ROM_BANK_START = 0x0000, ///< - - INTERRUPT_HANDLER_VBLANK = 0x0040, - INTERRUPT_HANDLER_LCDSTAT = 0x0048, - INTERRUPT_HANDLER_TIMER = 0x0050, - INTERRUPT_HANDLER_SERIAL = 0x0058, - INTERRUPT_HANDLER_JOYPAD = 0x0060, - - PROGRAM_START = 0x0100, - - NINTENDO_LOGO_START = 0x0104, - NINTENDO_LOGO_END = 0x0133, - - GAME_TITLE_START = 0x0134, - GAME_TITLE_END = 0x013E, - - GAME_DESTINATION_START = 0x013F, - GAME_DESTINATION_END = 0x0142, - - COLOR_COMPATABILITY = 0x0143, - - NEW_LICENSE_START = 0x0144, - NEW_LICENSE_END = 0x0145, - - SGB_COMPATABILITY = 0x0146, - - CART_TYPE = 0x0147, - - CART_ROM_SIZE = 0x0148, - CART_RAM_SIZE = 0x0149, - - DETINATION_CODE = 0x014A, - - OLD_LICENSE = 0x014B, - - MASK_ROM_VERSION = 0x014C, - - COMPLEMENT_CHECKSUM = 0x014D, - - CHECKSUM_START = 0x014E, - CHECKSUM_END = 0x014F, - - PERMANENT_ROM_BANK_END = 0x3FFF, - - SWITCHABLE_ROM_BANK_START = 0x4000, - SWITCHABLE_ROM_BANK_END = 0x7FFF, - - CHARACTER_RAM_START = 0x8000, - CHARACTER_RAM_END = 0x97FF, - - BG_MAP_DATA_1_START = 0x9800, - BG_MAP_DATA_1_END = 0x9BFF, - - BG_MAP_DATA_2_START = 0x9C00, - BG_MAP_DATA_2_END = 0x9FFF, - - EXTERNAL_RAM_START = 0xA000, - EXTERNAL_RAM_END = 0xBFFF, - - WORK_RAM_BANK_0_START = 0xC000, - WORK_RAM_BANK_0_END = 0xCFFF, - - WORK_RAM_BANK_1_START = 0xD000, - WORK_RAM_BANK_1_END = 0xDFFF, - - OAM_START = 0xFE00, - OAM_END = 0xFE9F, - - JOYPAD_REGISTER = 0xFF00, - - SB_REGISTER = 0xFF01, - SC_REGISTER = 0xFF02, - - DIVIDER_LO_REGISTER = 0xFF03, - DIVIDER_REGISER = 0xFF04, - - TIMER_COUNTER_REGISTER = 0xFF05, - TIMER_MODULO_REGISTER = 0xFF06, - TIMER_CONTROLLER_REGISTER = 0xFF07, - - NR10_REGISTER = 0xFF10, // Channel 1 Sweep - NR11_REGISTER = 0xFF11, // Channel 1 Sound length/Wave Pattern - NR12_REGISTER = 0xFF12, // Channel 1 Volume Envelop - NR13_REGISTER = 0xFF13, // Channel 1 Frequency LOW - NR14_REGISTER = 0xFF14, // Channel 1 Frequency HIGH - - NR20_REGISTER = 0xFF15, // UNUSED - NR21_REGISTER = 0xFF16, // Channel 2 Sound length/Wave Pattern - NR22_REGISTER = 0xFF17, // Channel 2 Volume Envelop - NR23_REGISTER = 0xFF18, // Channel 2 Frequency LOW - NR24_REGISTER = 0xFF19, // Channel 2 Frequency HIGH - - NR30_REGISTER = 0xFF1A, // Channel 3 ON/OFF - NR31_REGISTER = 0xFF1B, // Channel 3 Sound length - NR32_REGISTER = 0xFF1C, // Channel 3 Select Output Level - NR33_REGISTER = 0xFF1D, // Channel 3 Frequency LOW - NR34_REGISTER = 0xFF1E, // Channel 3 Frequency HIGH - - NR41_REGISTER = 0xFF20, // Channel 4 Sound length - NR42_REGISTER = 0xFF21, // Channel 4 Volume Envelope - NR43_REGISTER = 0xFF22, // Channel 4 Polynomial Counter - NR44_REGISTER = 0xFF23, // Channel 4 Counter/consecutive selection - - NR50_REGISTER = 0xFF24, // Sound Control Register ON/OFF / Volume Control - NR51_REGISTER = 0xFF25, // Output terminal selection - NR52_REGISTER = 0xFF26, // Sound On/Off - - WAVE_PATTERN_RAM_START = 0xFF30, - WAVE_PATTERN_RAM_END = 0xFF3F, - - LCDC_REGISTER = 0xFF40, - LCD_STAT_REGISTER = 0xFF41, - SCY_REGISTER = 0xFF42, - SCX_REGISTER = 0xFF43, - LY_REGISTER = 0xFF44, - LYC_REGISTER = 0xFF45, - - BGP_REGISTER = 0xFF47, - OBP0_REGISTER = 0xFF48, - OBP1_REGISTER = 0xFF49, - - WY_REGISTER = 0xFF4A, - WX_REGISTER = 0xFF4B, - - KEY1_REGISER = 0xFF4D, - - DMA_REGISTER = 0xFF46, - - VBK_REGISTER = 0xFF4F, ///< VRAM Bank Selection - - HDMA1 = 0xFF51, ///< New D -*/ - -#ifndef GAMEBOYCORE_MMU_H -#define GAMEBOYCORE_MMU_H - -#include "gameboycore/gameboycore_api.h" -#include "gameboycore/time.h" - -#include -#include -#include -#include - -namespace gb -{ - /** - \class MMU - \brief Memory interface - \ingroup API - */ - class GAMEBOYCORE_API MMU - { - public: - //! Smart pointer type - using Ptr = std::unique_ptr; - - using MemoryWriteHandler = std::function; - using MemoryReadHandler = std::function; - - public: - MMU(const uint8_t* rom, uint32_t size); - MMU(const MMU&) = delete; - ~MMU(); - - /** - @return the value of memory at the psecified location - */ - uint8_t read(uint16_t) const; - uint8_t read(uint16_t); - /** - Write a byte to the specified location - */ - void write(uint8_t value, uint16_t addr); - /** - Write a word to the specified location - */ - void write(uint16_t value, uint16_t addr); - - /** - */ - uint8_t readVram(uint16_t addr, uint8_t bank); - - /** - tranfer `n` bytes from `src` to `dest` - */ - void dma(uint16_t dest, uint16_t src, uint16_t n); - - /** - Add a IO write handler - - \param addr IO address - \handler the handler - */ - void addWriteHandler(uint16_t addr, MemoryWriteHandler handler); - - /** - Add an IO read handler - - \param addr IO address - \param handler the handler - */ - void addReadHandler(uint16_t addr, MemoryReadHandler handler); - - /** - \return Battery RAM - */ - std::vector getBatteryRam() const; - - /** - Set battery RAM - - \param buffer containing battery RAM - */ - void setBatteryRam(const std::vector& battery_ram); - - /** - Set the time to be read from the RTC register (MBC3) - */ - void setTimeProvider(const TimeProvider provider); - - /** - Check if OAM transfer has occured - */ - bool getOamTransferStatus() const; - - /** - @return true if rom is CGB compatible - */ - bool cgbEnabled() const; - - /** - \return a reference to a memory location - */ - uint8_t& get(uint16_t); - - /** - \return point to memory location - */ - uint8_t* getptr(uint16_t); - - /** - Get the virtual memory location from the logical address - */ - int resolveAddress(const uint16_t& addr) const; - - /** - Get size of virtual memory - */ - std::size_t getVirtualMemorySize() const; - - private: - class Impl; - Impl* impl_; - }; -} - -#endif // GAMEBOY_MMU_H diff --git a/components/gameboycore/include/gameboycore/oam.h b/components/gameboycore/include/gameboycore/oam.h deleted file mode 100644 index 84767ef9..00000000 --- a/components/gameboycore/include/gameboycore/oam.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef GAMEBOYCORE_OAM_H -#define GAMEBOYCORE_OAM_H - -#include "gameboycore/mmu.h" -#include "gameboycore/memorymap.h" -#include "gameboycore/sprite.h" - -#include - -namespace gb -{ - /** - \brief Access Gameboy Object Attribute Memory - */ - class OAM - { - public: - OAM(MMU& mmu); - ~OAM(); - - Sprite getSprite(std::size_t idx) const; - std::array getSprites() const; - - private: - MMU& mmu_; - }; -} - -#endif // GAMEBOYCORE_OAM_H diff --git a/components/gameboycore/include/gameboycore/opcode_cycles.h b/components/gameboycore/include/gameboycore/opcode_cycles.h deleted file mode 100644 index 10647822..00000000 --- a/components/gameboycore/include/gameboycore/opcode_cycles.h +++ /dev/null @@ -1,70 +0,0 @@ - -/** - \brief Contains all opcode cycle information - \author Natesh Narain - \date Oct 30, 2016 -*/ - -#ifndef GAMEBOYCORE_OPCODE_CYCLES_H -#define GAMEBOYCORE_OPCODE_CYCLES_H - -#include - -static constexpr uint8_t opcode_page1[256] = { - 1,3,2,2,1,1,2,1,5,2,2,2,1,1,2,1, - 0,3,2,2,1,1,2,1,3,2,2,2,1,1,2,1, - 2,3,2,2,1,1,2,1,2,2,2,2,1,1,2,1, - 2,3,2,2,3,3,3,1,2,2,2,2,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 2,2,2,2,2,2,0,2,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 2,3,3,4,3,4,2,4,2,4,3,0,3,6,2,4, - 2,3,3,0,3,4,2,4,2,4,3,0,3,0,2,4, - 3,3,2,0,0,4,2,4,4,1,4,0,0,0,2,4, - 3,3,2,1,0,4,2,4,3,2,4,1,0,0,2,4 -}; - -static constexpr uint8_t opcode_page1_branch[256] = { - 1,3,2,2,1,1,2,1,5,2,2,2,1,1,2,1, - 0,3,2,2,1,1,2,1,3,2,2,2,1,1,2,1, - 3,3,2,2,1,1,2,1,3,2,2,2,1,1,2,1, - 3,3,2,2,3,3,3,1,3,2,2,2,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 2,2,2,2,2,2,0,2,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1, - 5,3,4,4,6,4,2,4,5,4,4,0,6,6,2,4, - 5,3,4,0,6,4,2,4,5,4,4,0,6,0,2,4, - 3,3,2,0,0,4,2,4,4,1,4,0,0,0,2,4, - 3,3,2,1,0,4,2,4,3,2,4,1,0,0,2,4, -}; - -static constexpr uint8_t opcode_page2[256] = { - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,3,2,2,2,2,2,2,2,3,2, - 2,2,2,2,2,2,3,2,2,2,2,2,2,2,3,2, - 2,2,2,2,2,2,3,2,2,2,2,2,2,2,3,2, - 2,2,2,2,2,2,3,2,2,2,2,2,2,2,3,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2, - 2,2,2,2,2,2,4,2,2,2,2,2,2,2,4,2 -}; - -#endif // GAMEBOY_OPCODE_CYCLES_H diff --git a/components/gameboycore/include/gameboycore/opcodeinfo.h b/components/gameboycore/include/gameboycore/opcodeinfo.h deleted file mode 100644 index 7e76812e..00000000 --- a/components/gameboycore/include/gameboycore/opcodeinfo.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * \file opcodeinfo.h - * \brief Define opcode metadata - * \author Natesh Narain -*/ -#ifndef GAMEBOYCORE_OPCODEINFO_H -#define GAMEBOYCORE_OPCODEINFO_H - -#include - -namespace gb -{ - /** - Which page of instructions - */ - enum class OpcodePage - { - PAGE1, PAGE2 - }; - - enum class OperandType - { - NONE, // No operands - IMM8, // 8 bit immediate data - IMM16 // 16 bit immediate data - }; - - /** - Struct containing metadata - */ - struct OpcodeInfo - { - uint8_t cycles; - const char *disassembly; - OperandType userdata; - - OpcodeInfo(uint8_t cycles, const char* disassembly, OperandType userdata = OperandType::NONE) - : cycles{cycles} - , disassembly{disassembly} - , userdata{userdata} - { - } - }; - - OpcodeInfo getOpcodeInfo(uint8_t opcode, OpcodePage page); -} - -#endif // GAMEBOY_OPCODEINFO_H diff --git a/components/gameboycore/include/gameboycore/palette.h b/components/gameboycore/include/gameboycore/palette.h deleted file mode 100644 index 6dfd7012..00000000 --- a/components/gameboycore/include/gameboycore/palette.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * \file palette.h - * \author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_PALETTE_H -#define GAMEBOYCORE_PALETTE_H - -#include "gameboycore/pixel.h" - -#include -#include - -namespace gb -{ - class Palette - { - public: - Palette() - { - reset(); - } - - std::array get(uint8_t reg) - { - std::array palette; - - auto color3 = (reg & 0xC0) >> 6; - auto color2 = (reg & 0x30) >> 4; - auto color1 = (reg & 0x0C) >> 2; - auto color0 = (reg & 0x03); - - palette[3] = colors_[color3]; - palette[2] = colors_[color2]; - palette[1] = colors_[color1]; - palette[0] = colors_[color0]; - - return palette; - } - - void reset() - { - colors_[0] = Pixel(255); - colors_[1] = Pixel(192); - colors_[2] = Pixel(96); - colors_[3] = Pixel(0); - } - - void set(uint8_t r, uint8_t g, uint8_t b, int idx) - { - colors_[idx] = Pixel(r, g, b); - } - - private: - std::array colors_; - }; -} - -#endif // GAMEBOYCORE_PALETTE_H diff --git a/components/gameboycore/include/gameboycore/pixel.h b/components/gameboycore/include/gameboycore/pixel.h deleted file mode 100644 index 88b0c65c..00000000 --- a/components/gameboycore/include/gameboycore/pixel.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * \file pixel.h - * \author Natesh Narain - * \date Oct 23 2016 -*/ - -#ifndef GAMEBOYCORE_PIXEL_H -#define GAMEBOYCORE_PIXEL_H - -#include - -namespace gb -{ - //! Pixel type - struct Pixel - { - Pixel() : - r(0), g(0), b(0) - { - } - - Pixel(uint8_t r, uint8_t g, uint8_t b) : - r(r), g(g), b(b) - { - } - - explicit Pixel(uint8_t v) : r(v), g(v), b(v) - { - } - - uint8_t r; ///< Red - uint8_t g; ///< Green - uint8_t b; ///< Blue - - bool operator==(const Pixel& rhs) - { - return this->r == rhs.r && this->g == rhs.g && this->b == rhs.b; - } - }; -} - -#endif // GAMEBOYCORE_PIXEL_H diff --git a/components/gameboycore/include/gameboycore/sprite.h b/components/gameboycore/include/gameboycore/sprite.h deleted file mode 100644 index 7917bc02..00000000 --- a/components/gameboycore/include/gameboycore/sprite.h +++ /dev/null @@ -1,77 +0,0 @@ - -/** - @author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_SPRITE_H -#define GAMEBOYCORE_SPRITE_H - -#include - -namespace gb -{ - /** - Sprite object that are stored in OAM - */ - class Sprite - { - public: - uint8_t y; ///< y pixel coordinate - uint8_t x; ///< x pixel coordinate - uint8_t tile; ///< tile number - uint8_t attr; ///< attribute data - - uint8_t height; ///< sprite height in pixels - - Sprite() - : y{0} - , x{0} - , tile{0} - , attr{0} - , height{0} - { - } - - bool isHorizontallyFlipped() const - { - return (attr & (1 << 5)) != 0; - } - - bool isVerticallyFlipped() const - { - return (attr & (1 << 6)) != 0; - } - - bool hasPriority() const - { - return (attr & (1 << 7)) == 0; - } - - uint8_t paletteOBP0() const - { - return !!(attr & (1 << 4)); - } - - uint8_t getCgbPalette() const - { - return (attr & 0x07); - } - - uint8_t getCharacterBank() const - { - return !!(attr & (1 << 3)); - } - - bool operator==(const Sprite& rhs) - { - return - this->y == rhs.y && - this->x == rhs.x && - this->tile == rhs.tile && - this->attr == rhs.attr && - this->height == rhs.height; - } - }; -} - -#endif // GAMEBOYCORE_SPRITE_H diff --git a/components/gameboycore/include/gameboycore/tile.h b/components/gameboycore/include/gameboycore/tile.h deleted file mode 100644 index 3083c2d9..00000000 --- a/components/gameboycore/include/gameboycore/tile.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef GAMEBOYCORE_TILE_H -#define GAMEBOYCORE_TILE_H - -#include - -namespace gb -{ - struct Tile - { - uint8_t color[64]; - }; -} - -#endif // GAMEBOYCORE_TILE_H diff --git a/components/gameboycore/include/gameboycore/tilemap.h b/components/gameboycore/include/gameboycore/tilemap.h deleted file mode 100644 index cb6ae4fa..00000000 --- a/components/gameboycore/include/gameboycore/tilemap.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - \file tilemap.h - \author Natesh Narain - \date Sept 15 2016 -*/ - -#ifndef GAMEBOYCORE_TILEMAP_H -#define GAMEBOYCORE_TILEMAP_H - -#include "gameboycore/tileram.h" -#include "gameboycore/pixel.h" -#include "gameboycore/sprite.h" -#include "gameboycore/palette.h" -#include "gameboycore/memorymap.h" - -#include -#include -#include - -namespace gb -{ - namespace detail - { - /** - \brief Class that knows how to render background map data - */ - class TileMap - { - public: - /* Map types */ - enum class Map - { - BACKGROUND = (1 << 3), - WINDOW_OVERLAY = (1 << 6) - }; - - using Line = std::array; - - public: - - TileMap(MMU& mmu, Palette& palette); - ~TileMap(); - - Line getBackground(int line, bool cgb_enable); - Line getWindowOverlay(int line); - - void drawSprites(std::array& scanline, Line& color_line, int line, bool cgb_enable, std::array,8>& cgb_palette); - - std::array getSpriteCache() const; - std::vector getBackgroundTileMap(); - - std::size_t hashBackground(); - - private: - uint16_t getAddress(Map map) const; - void forEachBackgroundTile(std::function fn); - - private: - detail::TileRAM tileram_; - MMU& mmu_; - uint8_t& scx_; - uint8_t& scy_; - Palette& palette_; - - std::array sprite_cache_; - }; - } -} - -#endif // GAMEBOYCORE_TILEMAP_H diff --git a/components/gameboycore/include/gameboycore/tileram.h b/components/gameboycore/include/gameboycore/tileram.h deleted file mode 100644 index b5a0d7e2..00000000 --- a/components/gameboycore/include/gameboycore/tileram.h +++ /dev/null @@ -1,63 +0,0 @@ - -/** - @author Natesh Narain -*/ - - -#ifndef GAMEBOYCORE_DISPLAY_H -#define GAMEBOYCORE_DISPLAY_H - -#include "gameboycore/mmu.h" -#include "gameboycore/tile.h" -#include "gameboycore/sprite.h" - -#include -#include -#include - -namespace gb -{ - namespace detail - { - /** - \brief Class that knows how to read Tile RAM in the Gameboy memory map - */ - class TileRAM - { - public: - static const unsigned int NUM_TILES = 192; - static const unsigned int TILE_SIZE = 16; - - using TileRow = std::array; - using TileLine = std::array; - - public: - // TODO: remove this constructor - TileRAM(MMU& mmu); - ~TileRAM(); - - Tile getSpriteTile(const Sprite& sprite) const; - std::vector getTiles(); - - TileRow getRow(int row, uint8_t tilenum, bool umode, uint8_t character_bank = 0); - - template - uint16_t getTileAddress(int32_t base_addr, uint8_t tilenum) const - { - return (uint16_t)(base_addr + ((T)tilenum * TILE_SIZE)); - } - - private: - void setRow(Tile& tile, uint8_t msb, uint8_t lsb, int row) const; - - Tile flipV(const Tile& old) const; - Tile flipH(const Tile& old) const; - - private: - uint8_t* tile_ram_; - MMU& mmu_; - }; - } -} - -#endif // GAMEBOYCORE_DISPLAY_H diff --git a/components/gameboycore/include/gameboycore/time.h b/components/gameboycore/include/gameboycore/time.h deleted file mode 100644 index 64bee6c3..00000000 --- a/components/gameboycore/include/gameboycore/time.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef GAMEBOYCORE_TIME_H -#define GAMEBOYCORE_TIME_H - -#include -#include - -namespace gb -{ - struct Time - { - Time(uint8_t s, uint8_t m, uint8_t h, uint16_t d) - : seconds{ s } - , minutes{ m } - , hours{ h } - , days{ d } - { - } - - Time() : Time{0,0,0,0} - { - } - - uint8_t seconds; - uint8_t minutes; - uint8_t hours; - uint16_t days; - }; - - using TimeProvider = std::function; -} - -#endif // GAMEBOYCORE_TIME_H diff --git a/components/gameboycore/include/gameboycore/timer.h b/components/gameboycore/include/gameboycore/timer.h deleted file mode 100644 index 32be8b57..00000000 --- a/components/gameboycore/include/gameboycore/timer.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * \file timer.h - * \author Natesh Narain - * \date Oct 15 2016 -*/ - -#ifndef GAMEBOY_TIMER_H -#define GAMEBOY_TIMER_H - -#include "gameboycore/mmu.h" -#include "gameboycore/memorymap.h" -#include "gameboycore/interrupt_provider.h" - -#include -#include - -namespace gb -{ - /** - \brief Opcode accurate timer - */ - class Timer - { - public: - Timer(MMU& mmu); - ~Timer(); - - void update(const uint8_t cycles); - - private: - void tick(); - - uint8_t& controller_; // TAC - uint8_t& counter_; // TIMA - uint8_t& modulo_; // TMA - uint8_t& divider_; // DIV - - int t_clock_; - int base_clock_; - int div_clock_; - - InterruptProvider timer_interrupt_; - }; -} - -#endif // GAMEBOYCORE_TIMER_H diff --git a/components/gameboycore/src/alu.cpp b/components/gameboycore/src/alu.cpp deleted file mode 100644 index 191cc0c0..00000000 --- a/components/gameboycore/src/alu.cpp +++ /dev/null @@ -1,150 +0,0 @@ - -#include "gameboycore/alu.h" - -#include "bitutil.h" - -namespace gb -{ - ALU::ALU(uint8_t& flags) : - flags_(flags) - { - } - - void ALU::add(uint8_t& a, uint8_t n) - { - bool is_half_carry = isHalfCarry(a, n); - bool is_full_carry = isFullCarry(a, n); - - a += n; - - setFlag(ALU::Flags::H, is_half_carry); - setFlag(ALU::Flags::C, is_full_carry); - setFlag(ALU::Flags::Z, (a == 0)); - setFlag(ALU::Flags::N, false); - } - - void ALU::add(uint16_t& hl, uint16_t n) - { - bool is_half_carry = isHalfCarry16(hl, n); - bool is_full_carry = isFullCarry16(hl, n); - - hl += n; - - setFlag(ALU::Flags::H, is_half_carry); - setFlag(ALU::Flags::C, is_full_carry); - setFlag(ALU::Flags::N, false); - } - - void ALU::addr(uint16_t& sp, int8_t n) - { - int result = sp + n; - - setFlag(Flags::C, ((sp ^ n ^ (result & 0xFFFF)) & 0x100) == 0x100); - setFlag(Flags::H, ((sp ^ n ^ (result & 0xFFFF)) & 0x10) == 0x10); - - sp = (uint16_t)result; - - setFlag(ALU::Flags::Z, false); - setFlag(ALU::Flags::N, false); - } - - void ALU::addc(uint8_t& a, uint8_t n) - { - int carry = (isSet(flags_, ALU::Flags::C)) ? 1 : 0; - - int result = (int)a + (int)n + carry; - - setFlag(ALU::Flags::H, ((a & 0x0F) + (n & 0x0F) + carry) > 0x0F); - setFlag(ALU::Flags::C, result > 0xFF); - setFlag(ALU::Flags::Z, ((uint8_t)result == 0)); - setFlag(ALU::Flags::N, false); - - a = (uint8_t)result; - } - - void ALU::sub(uint8_t& a, uint8_t n) - { - bool is_half_borrow = isHalfBorrow(a, n); - bool is_full_borrow = isFullBorrow(a, n); - - a -= n; - - setFlag(ALU::Flags::H, is_half_borrow); - setFlag(ALU::Flags::C, is_full_borrow); - setFlag(ALU::Flags::Z, (a == 0)); - setFlag(ALU::Flags::N, true); - } - - void ALU::subc(uint8_t& a, uint8_t n) - { - int carry = (isSet(flags_, ALU::Flags::C)) ? 1 : 0; - int result = (int)a - n - carry; - - setFlag(ALU::Flags::C, result < 0); - setFlag(ALU::Flags::H, ((a & 0x0F) - (n & 0x0F) - carry) < 0); - - a = (uint8_t)result; - - setFlag(ALU::Flags::Z, (a == 0)); - setFlag(ALU::Flags::N, true); - } - - void ALU::anda(uint8_t& a, uint8_t n) - { - a &= n; - - setFlag(ALU::Flags::N, false); - setFlag(ALU::Flags::H, true); - setFlag(ALU::Flags::C, false); - setFlag(ALU::Flags::Z, (a == 0)); - } - - void ALU::ora(uint8_t& a, uint8_t n) - { - a |= n; - - setFlag(ALU::Flags::N, false); - setFlag(ALU::Flags::Z, (a == 0)); - setFlag(ALU::Flags::H, false); - setFlag(ALU::Flags::C, false); - } - - void ALU::xora(uint8_t& a, uint8_t n) - { - a ^= n; - - setFlag(ALU::Flags::Z, (a == 0)); - setFlag(ALU::Flags::N, false); - setFlag(ALU::Flags::H, false); - setFlag(ALU::Flags::C, false); - } - - void ALU::compare(uint8_t& a, uint8_t n) - { - bool is_half_borrow = isHalfBorrow(a, n); - bool is_full_borrow = isFullBorrow(a, n); - - uint8_t r = a - n; - - setFlag(ALU::Flags::H, is_half_borrow); - setFlag(ALU::Flags::C, is_full_borrow); - setFlag(ALU::Flags::Z, (r == 0)); - setFlag(ALU::Flags::N, true); - } - - void ALU::setFlag(uint8_t mask, bool set) - { - if (set) - { - setMask(flags_, mask); - } - else - { - clearMask(flags_, mask); - } - } - - ALU::~ALU() - { - } -} diff --git a/components/gameboycore/src/apu.cpp b/components/gameboycore/src/apu.cpp deleted file mode 100644 index 69467a47..00000000 --- a/components/gameboycore/src/apu.cpp +++ /dev/null @@ -1,507 +0,0 @@ - -/** - \author Natesh Narain -*/ - -#include "gameboycore/apu.h" -#include "gameboycore/memorymap.h" -#include "gameboycore/detail/audio/square_wave_channel.h" -#include "gameboycore/detail/audio/wave_channel.h" -#include "gameboycore/detail/audio/noise_channel.h" - -#include "bitutil.h" - -#include -#include -#include - -namespace gb -{ - /* Private Interface */ - - class APU::Impl - { - //! Cycles for 512 Hz with ~4.2 MHz clock - static constexpr unsigned int CYCLES_512HZ = 8192; - //! APU down sampling rate (CPU clock / sample rate of host system) - static constexpr unsigned int DOWNSAMPLE_RATE = 4200000 / 44100; - //! Starting address of the APU registers - static constexpr uint16_t APU_REG_BASE = memorymap::NR10_REGISTER; - - public: - explicit Impl(MMU::Ptr& mmu) : - mmu_(mmu), - square1_(true), - square2_(false), - frame_sequencer_counter_(CYCLES_512HZ), - frame_sequencer_(0), - down_sample_counter_(0) - { - // intercept all read/write attempts here - for (uint16_t i = memorymap::NR10_REGISTER; i <= memorymap::WAVE_PATTERN_RAM_END; ++i) - { - mmu->addReadHandler(i, std::bind(&Impl::read, this, std::placeholders::_1)); - mmu->addWriteHandler(i, std::bind(&Impl::write, this, std::placeholders::_1, std::placeholders::_2)); - } - - // init register memory - std::fill(apu_registers.begin(), apu_registers.end(), (uint8_t)0); - - // set extra read bits - initExtraBits(); - } - - /** - update with cycles - */ - void update(uint8_t cycles) - { - // ignore if apu is disabled - if (!isEnabled()) return; - - while (cycles--) - { - // frame sequencer clock - if (frame_sequencer_counter_-- <= 0) - { - frame_sequencer_counter_ = CYCLES_512HZ; - - clockFrameSequencer(); - } - - // run channel logic - square1_.step(); - square2_.step(); - wave_.step(); - noise_.step(); - - // down sampling is required since the APU can generate audio at a rate faster than the host system will play - if (--down_sample_counter_ == 0) - { - down_sample_counter_ = DOWNSAMPLE_RATE; - - // generate left and right audio samples - mixVolumes(); - } - } - } - - uint8_t getSound1Volume() const noexcept - { - return square1_.getVolume(); - } - - uint8_t getSound2Volume() const noexcept - { - return square2_.getVolume(); - } - - uint8_t getSound3Volume() const noexcept - { - return wave_.getVolume(); - } - - uint8_t getSound4Volume() const noexcept - { - return noise_.getVolume(); - } - - void setAudioSampleCallback(AudioSampleCallback callback) - { - send_audio_sample_ = callback; - } - - private: - - void clockFrameSequencer() - { - switch (frame_sequencer_) - { - case 0: - case 2: - clockLength(); - square1_.clockSweep(); - break; - case 4: - clockLength(); - break; - case 6: - clockLength(); - square1_.clockSweep(); - break; - case 7: - clockVolume(); - break; - } - - frame_sequencer_++; - - if (frame_sequencer_ >= 8) - { - frame_sequencer_ = 0; - } - } - - void mixVolumes() - { - static constexpr float AMPLITUDE = 30000; - - // convert sound output between [0, 1] - const auto sound1 = (float)square1_.getVolume() / 15.f; - const auto sound2 = (float)square2_.getVolume() / 15.f; - const auto sound3 = (float)wave_.getVolume() / 15.f; - const auto sound4 = (float)noise_.getVolume() / 15.f; - - float left_sample = 0; - float right_sample = 0; - - // add left channel contributions - if (channel_left_enabled_[0]) - left_sample += sound1; - if (channel_left_enabled_[1]) - left_sample += sound2; - if (channel_left_enabled_[2]) - left_sample += sound3; - if (channel_left_enabled_[3]) - left_sample += sound4; - - // add right channel contributions - if (channel_right_enabled_[0]) - right_sample += sound1; - if (channel_right_enabled_[1]) - right_sample += sound2; - if (channel_right_enabled_[2]) - right_sample += sound3; - if (channel_right_enabled_[3]) - right_sample += sound4; - - // average the totals - left_sample /= 4.0f; - right_sample /= 4.0f; - - // volume per channel between [0, 1] - const auto right_volume = ((float)right_volume_) / 7.f; - const auto left_volume = ((float)left_volume_) / 7.f; - - // generate a sample - const auto left = (int16_t)(left_sample * left_volume * AMPLITUDE); - const auto right = (int16_t)(right_sample * right_volume * AMPLITUDE); - - // send the samples to the host system - if (send_audio_sample_) - send_audio_sample_(left, right); - } - - void clockLength() noexcept - { - square1_.clockLength(); - square2_.clockLength(); - wave_.clockLength(); - noise_.clockLength(); - } - - void clockVolume() noexcept - { - square1_.clockVolume(); - square2_.clockVolume(); - noise_.clockVolume(); - } - - bool isEnabled() const noexcept - { - return isBitSet(apuRead(memorymap::NR52_REGISTER), 7) != 0; - } - - uint8_t read(uint16_t addr) - { - uint8_t value = 0; - - const auto& extras = extra_bits_[addr - APU_REG_BASE]; - - if (addr == memorymap::NR52_REGISTER) - { - value = apuRead(addr) & 0xF0; - - value |= square1_.isEnabled() << 0; - value |= square2_.isEnabled() << 1; - value |= wave_.isEnabled() << 2; - value |= noise_.isEnabled() << 3; - } - else - { - if (addr >= memorymap::NR10_REGISTER && addr <= memorymap::NR14_REGISTER) - { - value = square1_.read(addr - memorymap::NR10_REGISTER); - } - else if (addr >= memorymap::NR20_REGISTER && addr <= memorymap::NR24_REGISTER) - { - value = square2_.read(addr - memorymap::NR20_REGISTER); - } - else if (addr >= memorymap::NR30_REGISTER && addr <= memorymap::NR34_REGISTER) - { - value = wave_.read(addr - memorymap::NR30_REGISTER); - } - else if (addr >= memorymap::WAVE_PATTERN_RAM_START && addr <= memorymap::WAVE_PATTERN_RAM_END) - { - value = wave_.readWaveRam(addr); - } - else if (addr >= memorymap::NR41_REGISTER && addr <= memorymap::NR44_REGISTER) - { - value = noise_.read(addr - memorymap::NR41_REGISTER); - } - else if (addr >= memorymap::NR50_REGISTER && addr <= memorymap::NR52_REGISTER) - { - value = apuRead(addr); - } - } - - return value | extras; - } - - void write(uint8_t value, uint16_t addr) - { - if (addr == memorymap::NR52_REGISTER) - { - // check if APU is being disabled - if (isClear(value, 0x80)) - { - clearRegisters(); - - square1_.disable(); - square2_.disable(); - wave_.disable(); - noise_.disable(); - - frame_sequencer_ = 0; - } - - // check is being enabled - if (!isEnabled() && isSet(value, 0x80)) - { - frame_sequencer_counter_ = CYCLES_512HZ; - } - - apuWrite(value, addr); - } - else if (addr == memorymap::NR50_REGISTER && isEnabled()) - { - right_volume_ = value & 0x07; - right_enabled_ = (value & 0x08) != 0; - - left_volume_ = (value & 0x70) >> 4; - left_enabled_ = (value & 0x80) != 0; - - apuWrite(value, addr); - } - else if (addr == memorymap::NR51_REGISTER && isEnabled()) - { - channel_right_enabled_[0] = (value & 0x01) != 0; - channel_right_enabled_[1] = (value & 0x02) != 0; - channel_right_enabled_[2] = (value & 0x04) != 0; - channel_right_enabled_[3] = (value & 0x08) != 0; - channel_left_enabled_[0] = (value & 0x10) != 0; - channel_left_enabled_[1] = (value & 0x20) != 0; - channel_left_enabled_[2] = (value & 0x40) != 0; - channel_left_enabled_[3] = (value & 0x80) != 0; - - apuWrite(value, addr); - } - else - { - if (isEnabled()) - { - if (addr >= memorymap::NR10_REGISTER && addr <= memorymap::NR14_REGISTER) - { - square1_.write(value, addr - memorymap::NR10_REGISTER); - } - else if (addr >= memorymap::NR20_REGISTER && addr <= memorymap::NR24_REGISTER) - { - square2_.write(value, addr - memorymap::NR20_REGISTER); - } - else if (addr >= memorymap::NR30_REGISTER && addr <= memorymap::NR34_REGISTER) - { - wave_.write(value, addr - memorymap::NR30_REGISTER); - } - else if (addr >= memorymap::WAVE_PATTERN_RAM_START && addr <= memorymap::WAVE_PATTERN_RAM_END) - { - wave_.writeWaveRam(value, addr); - } - else if (addr >= memorymap::NR41_REGISTER && addr <= memorymap::NR44_REGISTER) - { - noise_.write(value, addr - memorymap::NR41_REGISTER); - } - } - } - } - - uint8_t apuRead(uint16_t addr) const noexcept - { - return apu_registers[addr - APU_REG_BASE]; - } - - void apuWrite(uint8_t value, uint16_t addr) noexcept - { - apu_registers[addr - APU_REG_BASE] = value; - } - - void clearRegisters() - { - for (auto addr = APU_REG_BASE; addr < memorymap::WAVE_PATTERN_RAM_START; ++addr) - { - if (addr == memorymap::NR52_REGISTER) continue; - mmu_->write((uint8_t)0, addr); - } - } - - void initExtraBits() noexcept - { - // NR10 - NR14 - extra_bits_[0x00] = 0x80; - extra_bits_[0x01] = 0x3F; - extra_bits_[0x02] = 0x00; - extra_bits_[0x03] = 0xFF; - extra_bits_[0x04] = 0xBF; - - // NR20 - NR24 - extra_bits_[0x05] = 0xFF; - extra_bits_[0x06] = 0x3F; - extra_bits_[0x07] = 0x00; - extra_bits_[0x08] = 0xFF; - extra_bits_[0x09] = 0xBF; - - // NR30 - NR34 - extra_bits_[0x0A] = 0x7F; - extra_bits_[0x0B] = 0xFF; - extra_bits_[0x0C] = 0x9F; - extra_bits_[0x0D] = 0xFF; - extra_bits_[0x0E] = 0xBF; - - // NR40 - NR44 - extra_bits_[0x0F] = 0xFF; - extra_bits_[0x10] = 0xFF; - extra_bits_[0x11] = 0x00; - extra_bits_[0x12] = 0x00; - extra_bits_[0x13] = 0xBF; - - // NR50 - NR52 - extra_bits_[0x14] = 0x00; - extra_bits_[0x15] = 0x00; - extra_bits_[0x16] = 0x70; - - // - extra_bits_[0x17] = 0xFF; - extra_bits_[0x18] = 0xFF; - extra_bits_[0x19] = 0xFF; - extra_bits_[0x1A] = 0xFF; - extra_bits_[0x1B] = 0xFF; - extra_bits_[0x1C] = 0xFF; - extra_bits_[0x1D] = 0xFF; - extra_bits_[0x1E] = 0xFF; - extra_bits_[0x1F] = 0xFF; - - // wave ram - extra_bits_[0x20] = 0x00; - extra_bits_[0x21] = 0x00; - extra_bits_[0x22] = 0x00; - extra_bits_[0x23] = 0x00; - extra_bits_[0x24] = 0x00; - extra_bits_[0x25] = 0x00; - extra_bits_[0x26] = 0x00; - extra_bits_[0x27] = 0x00; - extra_bits_[0x28] = 0x00; - extra_bits_[0x29] = 0x00; - extra_bits_[0x2A] = 0x00; - extra_bits_[0x2B] = 0x00; - extra_bits_[0x2C] = 0x00; - extra_bits_[0x2D] = 0x00; - extra_bits_[0x2E] = 0x00; - extra_bits_[0x2F] = 0x00; - } - - private: - MMU::Ptr& mmu_; - - //! Sound 1 - Square wave with Sweep - detail::SquareWaveChannel square1_; - //! Sound 2 - Square wave - detail::SquareWaveChannel square2_; - //! Sound 3 - Wave from wave ram - detail::WaveChannel wave_; - //! Sound 4 - Noise Channel - detail::NoiseChannel noise_; - - //! callback to host when an audio sample is computed - AudioSampleCallback send_audio_sample_; - - //! APU cycle counter - int frame_sequencer_counter_; - - //! APU internal timer - int frame_sequencer_; - - //! APU registers - std::array apu_registers; - - //! left volume - uint8_t left_volume_; - //! left enabled - bool left_enabled_; - //! right volume - uint8_t right_volume_; - //! right enabled - bool right_enabled_; - - //! left channel enables - bool channel_left_enabled_[4]; - //! right channel enables - bool channel_right_enabled_[4]; - - //! - uint8_t down_sample_counter_; - - //! bits that are ORed into the value when read - std::array extra_bits_; - }; - - /* Public Interface */ - - APU::APU(MMU::Ptr& mmu) : - impl_(new Impl(mmu)) - { - } - - void APU::update(uint8_t cycles) - { - impl_->update(cycles); - } - - uint8_t APU::getSound1Volume() - { - return impl_->getSound1Volume(); - } - - uint8_t APU::getSound2Volume() - { - return impl_->getSound2Volume(); - } - - uint8_t APU::getSound3Volume() - { - return impl_->getSound3Volume(); - } - - uint8_t APU::getSound4Volume() - { - return impl_->getSound4Volume(); - } - - void APU::setAudioSampleCallback(AudioSampleCallback callback) - { - impl_->setAudioSampleCallback(callback); - } - - APU::~APU() - { - delete impl_; - } -} \ No newline at end of file diff --git a/components/gameboycore/src/bitutil.h b/components/gameboycore/src/bitutil.h deleted file mode 100644 index c1c44666..00000000 --- a/components/gameboycore/src/bitutil.h +++ /dev/null @@ -1,158 +0,0 @@ - -/** - Bit operation macros - - @author Natesh Narain -*/ - -#ifndef BITUTIL_H -#define BITUTIL_H - -//! Bit value -template -inline T bv(T b) -{ - return 1 << b; -} - -//! set mask y in x -template -inline void setMask(Tx& x, Ty y) noexcept -{ - x |= (Tx)y; -} - -//! clear mask y in x -template -inline void clearMask(Tx& x, Ty y) noexcept -{ - x &= ~((Tx)y); -} -//! toggle mask y in x -template -inline void toggleMask(Tx& x, Ty y) noexcept -{ - x ^= (Tx)y; -} - -//! set bit y in x -template -inline void setBit(Tx& x, Ty y) noexcept -{ - setMask(x, bv(y)); -} -//! clear bit y in x -template -inline void clearBit(Tx& x, Ty y) noexcept -{ - clearMask(x, bv(y)); -} -//! toggle bit y in x -template -inline void toggleBit(Tx& x, Ty y) noexcept -{ - toggleMask(x, bv(y)); -} - -//! -template -inline Tx lownybble(const Tx& x) noexcept -{ - return x & 0x0F; -} - -//! -template -inline T highnybble(const T& t) noexcept -{ - return (t >> 4); -} - -//! Create a WORD -template -inline uint16_t word(const Tx& hi, const Ty& lo) noexcept -{ - return ((hi & 0xFFFF) << 8) | (lo & 0xFFFF); -} - -//! Get bit -template -inline Tx getBit(const Tx& x, const Ty& n) noexcept -{ - return !!(x & bv(n)); -} - -//! check if mask y is set in x -template -inline bool isSet(const Tx& x, const Ty& y) noexcept -{ - return (x & y) != 0; -} - -//! check if mask y is clear in x -template -inline bool isClear(const Tx& x, const Ty& y) noexcept -{ - return !(x & y); -} -//! check if bit y is set in x -//#define isBitSet(x,y) ( isSet(x, bv(y)) ) -template -inline bool isBitSet(const Tx& x, const Ty& y) noexcept -{ - return isSet(x, bv(y)); -} -//! check if bit y is clear in x -template -inline bool isBitClear(const Tx& x, const Ty& y) noexcept -{ - return isClear(x, bv(y)); -} - -/* Full and Half Carry */ - -template -inline bool isHalfCarry(const Tx& x, const Ty& y) noexcept -{ - return (((x & 0x0F) + (y & 0x0F)) & 0x10) != 0; -} - -template -inline bool isFullCarry(const Tx& x, const Ty& y) noexcept -{ - return (((x & 0x0FF) + (y & 0x0FF)) & 0x100) != 0; -} - -template -inline bool isHalfCarry16(const Tx& x, const Ty& y) noexcept -{ - return ((((x & 0x0FFF) + (y & 0x0FFF)) & 0x1000) != 0); -} - -template -inline bool isFullCarry16(const Tx& x, const Ty& y) noexcept -{ - return ((((x & 0x0FFFF) + ((y & 0x0FFFF))) & 0x10000) != 0); -} - -template -inline bool isHalfBorrow(const Tx& x, const Ty& y) noexcept -{ - return ((x & 0x0F) < (y & 0x0F)); -} -template -inline bool isFullBorrow(const Tx& x, const Ty& y) noexcept -{ - return ((x & 0xFF) < (y & 0xFF)); -} - -#endif // BITUTIL_H - - - - - - - - - diff --git a/components/gameboycore/src/cartinfo.cpp b/components/gameboycore/src/cartinfo.cpp deleted file mode 100644 index d99d587a..00000000 --- a/components/gameboycore/src/cartinfo.cpp +++ /dev/null @@ -1,30 +0,0 @@ - -#include "gameboycore/cartinfo.h" -#include "gameboycore/mbc.h" -#include - -namespace gb -{ - RomParser::RomParser() - { - } - - CartInfo RomParser::parse(const uint8_t* image) - { - CartInfo info; - info.type = image[memorymap::CART_TYPE]; - info.rom_size = image[memorymap::CART_ROM_SIZE]; - info.ram_size = image[memorymap::CART_RAM_SIZE]; - std::memcpy( - info.game_title, - &image[memorymap::GAME_TITLE_START], - memorymap::GAME_TITLE_END - memorymap::GAME_TITLE_START - ); - info.game_title[(memorymap::GAME_TITLE_END - memorymap::GAME_TITLE_START)] = '\0'; - - auto cgb_flag = image[memorymap::COLOR_COMPATABILITY]; - info.cgb_enabled = (cgb_flag == 0x80) || (cgb_flag == 0xC0); - - return info; - } -} diff --git a/components/gameboycore/src/cpu.cpp b/components/gameboycore/src/cpu.cpp deleted file mode 100644 index 65082010..00000000 --- a/components/gameboycore/src/cpu.cpp +++ /dev/null @@ -1,2476 +0,0 @@ - -#include "gameboycore/cpu.h" -#include "gameboycore/alu.h" -#include "gameboycore/timer.h" -#include "gameboycore/opcodeinfo.h" -#include "gameboycore/opcode_cycles.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "bitutil.h" -#include "shiftrotate.h" - -// check endianness -#if !defined(__BIGENDIAN__) && !defined(__LITTLEENDIAN__) -# error "Either __BIGENDIAN__ or __LITTLEENDIAN__ must be defined" -#endif - -namespace gb -{ - /* Private Interface */ - - class CPU::Impl - { - public: - union Register - { - struct { -#ifdef __LITTLEENDIAN__ - uint8_t lo; - uint8_t hi; -#else - uint8_t hi; - uint8_t lo; -#endif - }; - uint16_t val; - }; - - enum InterruptMask - { - VBLANK = 1 << 0, - LCDC_STAT = 1 << 1, - TIME_OVERFLOW = 1 << 2, - SERIAL_TRANSFER_COMPLETE = 1 << 3, - JOYPAD = 1 << 4 - }; - - enum class InterruptVector - { - VBLANK = 0x0040, - LCDC_STAT = 0x0048, - TIME_OVERFLOW = 0x0050, - SERIAL_TRANSFER_COMPLETE = 0x0058, - JOYPAD = 0x0060 - }; - - Impl(MMU::Ptr& mmu, GPU::Ptr& gpu, APU::Ptr& apu, Link::Ptr& link) - : af_{0} - , bc_{0} - , de_{0} - , hl_{0} - , sp_{0} - , pc_{0} - , mmu_{ mmu } - , gpu_{ gpu } - , apu_{ apu } - , link_{ link } - , alu_{ af_.lo } - , timer_{ *mmu.get() } - , halted_{ false } - , stopped_{ false } - , interrupt_master_enable_{ false } - , interrupt_master_enable_pending_{ -1 } - , interrupt_master_disable_pending_{ -1 } - , debug_mode_{ false } - , current_pc_{0} - , cycle_count_{ 0 } - , interrupt_flags_{ mmu_->get(memorymap::INTERRUPT_FLAG) } - , interrupt_enable_{ mmu_->get(memorymap::INTERRUPT_ENABLE) } - , cgb_enabled_{ mmu->cgbEnabled() } - { - } - - void step() - { - // set current PC for debugging - current_pc_ = pc_.val; - - cycle_count_ = 0; - - if (!halted_) - { - // fetch next opcode - uint8_t opcode = mmu_->read(pc_.val++); - - // $CB means decode from the second page of instructions - if (opcode != 0xCB) - { - // decode from first page - cycle_count_ += decode1(opcode); - } - else - { - // read the second page opcode - opcode = mmu_->read(pc_.val++); - // decode from second page - cycle_count_ += decode2(opcode); - } - } - else - { - cycle_count_ += 1; - } - - checkPowerMode(); - checkInterrupts(); - - auto cpu_cycles = cycle_count_ * 4; - auto instr_cycles = cycle_count_; - - if (!stopped_) - { - gpu_->update((uint8_t)cpu_cycles, interrupt_master_enable_); - apu_->update((uint8_t)cpu_cycles); - link_->update((uint8_t)cpu_cycles); - timer_.update((uint8_t)instr_cycles); - } - } - - uint8_t decode1(uint8_t opcode) - { - int cycles = -1; - - switch (opcode) - { - // NOP - case 0x00: - break; - // STOP - case 0x10: - stop(); - break; - - /* Load Instructions */ - - // 8 bit loads immediate - case 0x3E: // LD A,d8 - af_.hi = load8Imm(); - break; - case 0x06: // LD B,d8 - bc_.hi = load8Imm(); - break; - case 0x0E: // LD C,d8 - bc_.lo = load8Imm(); - break; - case 0x16: // LD D,d8 - de_.hi = load8Imm(); - break; - case 0x1E: // LD E,d8 - de_.lo = load8Imm(); - break; - case 0x26: // LD H,d8 - hl_.hi = load8Imm(); - break; - case 0x2E: // LD L,d8 - hl_.lo = load8Imm(); - break; - case 0x36: // LD (HL),d8 - mmu_->write(load8Imm(), hl_.val); - break; - - // load 16 bit immediate - case 0x01: // LD BC,d16 - bc_.val = load16Imm(); - break; - case 0x11: // LD DE,d16 - de_.val = load16Imm(); - break; - case 0x21: // LD HL,d16 - hl_.val = load16Imm(); - break; - case 0x31: // LD SP,d16 - sp_.val = load16Imm(); - break; - - // load A into memory - case 0x02: - mmu_->write(af_.hi, bc_.val); - break; - case 0x12: - mmu_->write(af_.hi, de_.val); - break; - - // load A from memory - case 0x0A: // LD A,(BC) - af_.hi = mmu_->read(bc_.val); - break; - case 0x1A: // LD A,(DE) - af_.hi = mmu_->read(de_.val); - break; - - // transfer (Register to register, memory to register) - case 0x40: // LD B,B - bc_.hi = bc_.hi; - break; - case 0x41: // LD B,C - bc_.hi = bc_.lo; - break; - case 0x42: // LD B,D - bc_.hi = de_.hi; - break; - case 0x43: // LD B,E - bc_.hi = de_.lo; - break; - case 0x44: // LD B,H - bc_.hi = hl_.hi; - break; - case 0x45: // LD B,L - bc_.hi = hl_.lo; - break; - case 0x46: // LD B,(HL) - bc_.hi = mmu_->read(hl_.val); - break; - case 0x47: // LD B,A - bc_.hi = af_.hi; - break; - case 0x48: // LD C,B - bc_.lo = bc_.hi; - break; - case 0x49: // LD C,C - bc_.lo = bc_.lo; - break; - case 0x4A: // LD C,D - bc_.lo = de_.hi; - break; - case 0x4B: // LD C,E - bc_.lo = de_.lo; - break; - case 0x4C: // LD C,H - bc_.lo = hl_.hi; - break; - case 0x4D: // LD C,L - bc_.lo = hl_.lo; - break; - case 0x4E: // LD C,(HL) - bc_.lo = mmu_->read(hl_.val); - break; - case 0x4F: // LD C,A - bc_.lo = af_.hi; - break; - - case 0x50: // LD D,B - de_.hi = bc_.hi; - break; - case 0x51: // LD D,C - de_.hi = bc_.lo; - break; - case 0x52: // LD D,D - de_.hi = de_.hi; - break; - case 0x53: // LD D,E - de_.hi = de_.lo; - break; - case 0x54: // LD D,H - de_.hi = hl_.hi; - break; - case 0x55: // LD D,L - de_.hi = hl_.lo; - break; - case 0x56: // LD D,(HL) - de_.hi = mmu_->read(hl_.val); - break; - case 0x57: // LD D,A - de_.hi = af_.hi; - break; - case 0x58: // LD E,B - de_.lo = bc_.hi; - break; - case 0x59: // LD E,C - de_.lo = bc_.lo; - break; - case 0x5A: // LD E,D - de_.lo = de_.hi; - break; - case 0x5B: // LD E,E - de_.lo = de_.lo; - break; - case 0x5C: // LD E,H - de_.lo = hl_.hi; - break; - case 0x5D: // LD E,L - de_.lo = hl_.lo; - break; - case 0x5E: // LD E,(HL) - de_.lo = mmu_->read(hl_.val); - break; - case 0x5F: // LD E,A - de_.lo = af_.hi; - break; - - case 0x60: // LD H,B - hl_.hi = bc_.hi; - break; - case 0x61: // LD H,C - hl_.hi = bc_.lo; - break; - case 0x62: // LD H,D - hl_.hi = de_.hi; - break; - case 0x63: // LD H,E - hl_.hi = de_.lo; - break; - case 0x64: // LD H,H - hl_.hi = hl_.hi; - break; - case 0x65: // LD H,L - hl_.hi = hl_.lo; - break; - case 0x66: // LD H,(HL) - hl_.hi = mmu_->read(hl_.val); - break; - case 0x67: // LD H,A - hl_.hi = af_.hi; - break; - case 0x68: // LD L,B - hl_.lo = bc_.hi; - break; - case 0x69: // LD L,C - hl_.lo = bc_.lo; - break; - case 0x6A: // LD L,D - hl_.lo = de_.hi; - break; - case 0x6B: // LD L,E - hl_.lo = de_.lo; - break; - case 0x6C: // LD L,H - hl_.lo = hl_.hi; - break; - case 0x6D: // LD L,L - hl_.lo = hl_.lo; - break; - case 0x6E: // LD L,(HL) - hl_.lo = mmu_->read(hl_.val); - break; - case 0x6F: // LD L,A - hl_.lo = af_.hi; - break; - - case 0x78: // LD A,B - af_.hi = bc_.hi; - break; - case 0x79: // LD A,C - af_.hi = bc_.lo; - break; - case 0x7A: // LD A,D - af_.hi = de_.hi; - break; - case 0x7B: // LD A,E - af_.hi = de_.lo; - break; - case 0x7C: // LD A,H - af_.hi = hl_.hi; - break; - case 0x7D: // LD A,L - af_.hi = hl_.lo; - break; - case 0x7E: // LD A,(HL) - af_.hi = mmu_->read(hl_.val); - break; - case 0x7F: // LD A,A - af_.hi = af_.hi; - break; - - // register to memory - case 0x70: // LD (HL),B - mmu_->write(bc_.hi, hl_.val); - break; - case 0x71: // LD (HL),C - mmu_->write(bc_.lo, hl_.val); - break; - case 0x72: // LD (HL),D - mmu_->write(de_.hi, hl_.val); - break; - case 0x73: // LD (HL),E - mmu_->write(de_.lo, hl_.val); - break; - case 0x74: // LD (HL),H - mmu_->write(hl_.hi, hl_.val); - break; - case 0x75: // LD (HL),L - mmu_->write(hl_.lo, hl_.val); - break; - case 0x77: // LD (HL),A - mmu_->write(af_.hi, hl_.val); - break; - - // Load Increment/Decrement - // (HL+/-) <- A & A <- (HL+/-) - case 0x22: // LD (HL+),A - mmu_->write(af_.hi, hl_.val++); - break; - case 0x32: // LD (HL-),A - mmu_->write(af_.hi, hl_.val--); - break; - case 0x2A: // LD A,(HL+) - af_.hi = mmu_->read(hl_.val++); - break; - case 0x3A: // LD A,(HL-) - af_.hi = mmu_->read(hl_.val--); - break; - - // IN/OUT Instructions. Load and Store to IO Registers (immediate or using C register). IO Offset is $FF00 - case 0xE0: // LDH (a8),A - out(0xFF00 + load8Imm()); - break; - case 0xF0: // LDH A,(a8) - in(0xFF00 + load8Imm()); - break; - case 0xE2: // LD (C),A - out(0xFF00 + bc_.lo); - break; - case 0xF2: // LD A,(C) - in(0xFF00 + bc_.lo); - break; - case 0xEA: // LD (a16),A - out(load16Imm()); - break; - case 0xFA: // LD A,(a16) - in(load16Imm()); - break; - - /* Increment Instruction */ - - // 16 bit increment - case 0x03: // INC BC - inc(bc_.val); - break; - case 0x13: // INC DE - inc(de_.val); - break; - case 0x23: // INC HL - inc(hl_.val); - break; - case 0x33: // INC SP - inc(sp_.val); - break; - - // 16 bit decrement - case 0x0B: // DEC BC - dec(bc_.val); - break; - case 0x1B: // DEC DE - dec(de_.val); - break; - case 0x2B: // DEC HL - dec(hl_.val); - break; - case 0x3B: // DEC SP - dec(sp_.val); - break; - - // 8 bit increment - case 0x04: // INC B - inc(bc_.hi); - break; - case 0x0C: // INC C - inc(bc_.lo); - break; - case 0x14: // INC D - inc(de_.hi); - break; - case 0x1C: // INC E - inc(de_.lo); - break; - case 0x24: // INC H - inc(hl_.hi); - break; - case 0x2C: // INC L - inc(hl_.lo); - break; - case 0x34: // INC (HL) - inca(hl_.val); - break; - case 0x3C: // INC A - inc(af_.hi); - break; - - // 8 bit decrement - case 0x05: // DEC B - dec(bc_.hi); - break; - case 0x0D: // DEC C - dec(bc_.lo); - break; - case 0x15: // DEC D - dec(de_.hi); - break; - case 0x1D: // DEC C - dec(de_.lo); - break; - case 0x25: // DEC H - dec(hl_.hi); - break; - case 0x2D: // DEC L - dec(hl_.lo); - break; - case 0x35: // DEC (HL) - deca(hl_.val); - break; - case 0x3D: // DEC A - dec(af_.hi); - break; - - /* Stack Instructions */ - - // Push - case 0xC5: // PUSH BC - push(bc_.val); - break; - case 0xD5: // PUSH DE - push(de_.val); - break; - case 0xE5: // PUSH HL - push(hl_.val); - break; - case 0xF5: // PUSH AF - push(af_.val); - break; - - // Pop - case 0xC1: // POP BC - bc_.val = pop(); - break; - case 0xD1: // POP DE - de_.val = pop(); - break; - case 0xE1: // POP HL - hl_.val = pop(); - break; - case 0xF1: // POP AF - af_.val = pop(); - af_.lo &= 0xF0; // explicitly clear lower 4 bits - break; - - // Load - - case 0x08: // LD (a16),SP - mmu_->write(sp_.val, load16Imm()); - break; - case 0xF8: // LD HL,SP+r8 - //hl_.val = (uint16_t)((int16_t)sp_.val + (int8_t)load8Imm()); - hl_.val = ldHLSPe(); - break; - case 0xF9: // LD SP,HL - sp_.val = hl_.val; - break; - - case 0x76: - halted_ = true; - break; - - /* Jumps */ - case 0xC3: // JP a16 - jp(load16Imm()); - break; - - case 0xE9: // JP (HL) - jp(hl_.val); - break; - - // conditional jumps - case 0xC2: // JP NZ,nn - if (isClear(af_.lo, Flags::Z)) { - jp(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - cycles = opcode_page1[opcode]; - } - break; - case 0xCA: // JP Z,nn - if (isSet(af_.lo, Flags::Z)) { - jp(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - cycles = opcode_page1[opcode]; - } - break; - case 0xD2: // JP NC,nn - if (isClear(af_.lo, Flags::C)) { - jp(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - cycles = opcode_page1[opcode]; - } - break; - case 0xDA: // JP C,nn - if (isSet(af_.lo, Flags::C)) { - jp(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - cycles = opcode_page1[opcode]; - } - break; - - // relative jumps - case 0x18: // JR r8 - jr((int8_t)load8Imm()); - break; - - // relative conditional jumps - case 0x20: // JR NZ,n - if (isClear(af_.lo, Flags::Z)) { - jr((int8_t)load8Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val++; // skip next byte - } - break; - case 0x28: // JR Z,n - if (isSet(af_.lo, Flags::Z)) { - jr((int8_t)load8Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val++; // skip next byte - } - break; - case 0x30: // JR NC,n - if (isClear(af_.lo, Flags::C)) { - jr((int8_t)load8Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val++; // skip next byte - } - break; - case 0x38: // JR C,n - if (isSet(af_.lo, Flags::C)) { - jr((int8_t)load8Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val++; // skip next byte - } - break; - - /* Call */ - case 0xCD: // CALL nn - call(load16Imm()); - break; - - // call condition - case 0xC4: // CALL NZ,nn - if (isClear(af_.lo, Flags::Z)) { - call(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - } - break; - case 0xCC: // CALL Z,nn - if (isSet(af_.lo, Flags::Z)) { - call(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - } - break; - case 0xD4: // CALL NC,nn - if (isClear(af_.lo, Flags::C)) { - call(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - } - break; - case 0xDC: // CALL C,nn - if (isSet(af_.lo, Flags::C)) { - call(load16Imm()); - cycles = opcode_page1_branch[opcode]; - } - else { - pc_.val += 2; - } - break; - - /* Returns */ - case 0xC9: // RET - ret(); - break; - - // conditional returns - case 0xC0: // RET NZ - if (isClear(af_.lo, Flags::Z)) { - ret(); - cycles = opcode_page1_branch[opcode]; - } - break; - case 0xC8: // RET Z - if (isSet(af_.lo, Flags::Z)) { - ret(); - cycles = opcode_page1_branch[opcode]; - } - break; - case 0xD0: // RET NC - if (isClear(af_.lo, Flags::C)) { - ret(); - cycles = opcode_page1_branch[opcode]; - } - break; - case 0xD8: // RET C - if (isSet(af_.lo, Flags::C)) { - ret(); - cycles = opcode_page1_branch[opcode]; - } - break; - - // return from interrupt - case 0xD9: // RETI - reti(); - break; - - /* Reset Instructions */ - case 0xC7: // RST $00 - call(0x00); - break; - case 0xCF: // RST $08 - call(0x08); - break; - case 0xD7: // RST $10 - call(0x10); - break; - case 0xDF: // RST $18 - call(0x18); - break; - case 0xE7: // RST $20 - call(0x20); - break; - case 0xEF: // RST $28 - call(0x28); - break; - case 0xF7: // RST $30 - call(0x30); - break; - case 0xFF: // RST $38 - call(0x38); - break; - - /* Decimal Adjust */ - case 0x27: - daa(); - break; - - /* Complement */ - - // Register A - case 0x2F: // CPL - toggleMask(af_.hi, 0xFF); - setMask(af_.lo, CPU::Flags::N); - setMask(af_.lo, CPU::Flags::H); - break; - // Carry Flag - case 0x3F: // CCF - toggleMask(af_.lo, CPU::Flags::C); - clearMask(af_.lo, CPU::Flags::N); - clearMask(af_.lo, CPU::Flags::H); - break; - - /* Set Carry Flag */ - case 0x37: // SCF - setMask(af_.lo, CPU::Flags::C); - clearMask(af_.lo, CPU::Flags::N); - clearMask(af_.lo, CPU::Flags::H); - break; - - /* Disable and Enable Interrupt */ - case 0xF3: // DI - interrupt_master_disable_pending_ = 0; - break; - case 0xFB: // EI - interrupt_master_enable_pending_ = 0; - break; - - /* Arithmetic Operations */ - // add 8 bit - case 0x87: // ADD A,A - alu_.add(af_.hi, af_.hi); - break; - case 0x80: // ADD A,B - alu_.add(af_.hi, bc_.hi); - break; - case 0x81: // ADD A,C - alu_.add(af_.hi, bc_.lo); - break; - case 0x82: // ADD A,D - alu_.add(af_.hi, de_.hi); - break; - case 0x83: // ADD A,E - alu_.add(af_.hi, de_.lo); - break; - case 0x84: // ADD A,H - alu_.add(af_.hi, hl_.hi); - break; - case 0x85: // ADD A,L - alu_.add(af_.hi, hl_.lo); - break; - case 0x86: // ADD A,(HL) - alu_.add(af_.hi, mmu_->read(hl_.val)); - break; - case 0xC6: // ADD A,n - alu_.add(af_.hi, load8Imm()); - break; - - // add with carry - case 0x8F: // ADC A,A - alu_.addc(af_.hi, af_.hi); - break; - case 0x88: // ADC A,B - alu_.addc(af_.hi, bc_.hi); - break; - case 0x89: // ADC A,C - alu_.addc(af_.hi, bc_.lo); - break; - case 0x8A: // ADC A,D - alu_.addc(af_.hi, de_.hi); - break; - case 0x8B: // ADC A,E - alu_.addc(af_.hi, de_.lo); - break; - case 0x8C: // ADC A,H - alu_.addc(af_.hi, hl_.hi); - break; - case 0x8D: // ADC A,L - alu_.addc(af_.hi, hl_.lo); - break; - case 0x8E: // ADC A,(HL) - alu_.addc(af_.hi, mmu_->read(hl_.val)); - break; - case 0xCE: // ADC A,n - alu_.addc(af_.hi, load8Imm()); - break; - - // 16 bit addition - case 0x09: // ADD HL,BC - alu_.add(hl_.val, bc_.val); - break; - case 0x19: // ADD HL,DE - alu_.add(hl_.val, de_.val); - break; - case 0x29: // ADD HL,HL - alu_.add(hl_.val, hl_.val); - break; - case 0x39: // ADD HL,SP - alu_.add(hl_.val, sp_.val); - break; - - case 0xE8: // ADD SP,n - alu_.addr(sp_.val, (int8_t)load8Imm()); - break; - - // subtract - case 0x97: // SUB A,A - alu_.sub(af_.hi, af_.hi); - break; - case 0x90: // SUB A,B - alu_.sub(af_.hi, bc_.hi); - break; - case 0x91: // SUB A,C - alu_.sub(af_.hi, bc_.lo); - break; - case 0x92: // SUB A,D - alu_.sub(af_.hi, de_.hi); - break; - case 0x93: // SUB A,E - alu_.sub(af_.hi, de_.lo); - break; - case 0x94: // SUB A,H - alu_.sub(af_.hi, hl_.hi); - break; - case 0x95: // SUB A,L - alu_.sub(af_.hi, hl_.lo); - break; - case 0x96: // SUB A,(HL) - alu_.sub(af_.hi, mmu_->read(hl_.val)); - break; - case 0xD6: // SUB A,n - alu_.sub(af_.hi, load8Imm()); - break; - - // substract with carry - case 0x9F: // SBC A,A - alu_.subc(af_.hi, af_.hi); - break; - case 0x98: // SBC A,B - alu_.subc(af_.hi, bc_.hi); - break; - case 0x99: // SBC A,C - alu_.subc(af_.hi, bc_.lo); - break; - case 0x9A: // SBC A,D - alu_.subc(af_.hi, de_.hi); - break; - case 0x9B: // SBC A,E - alu_.subc(af_.hi, de_.lo); - break; - case 0x9C: // SBC A,H - alu_.subc(af_.hi, hl_.hi); - break; - case 0x9D: // SBC A,L - alu_.subc(af_.hi, hl_.lo); - break; - case 0x9E: // SBC A,(HL) - alu_.subc(af_.hi, mmu_->read(hl_.val)); - break; - case 0xDE: // SBC A,n - alu_.subc(af_.hi, load8Imm()); - break; - - /* Logical Operations */ - case 0xA7: // AND A,A - alu_.anda(af_.hi, af_.hi); - break; - case 0xA0: // AND A,B - alu_.anda(af_.hi, bc_.hi); - break; - case 0xA1: // AND A,C - alu_.anda(af_.hi, bc_.lo); - break; - case 0xA2: // AND A,D - alu_.anda(af_.hi, de_.hi); - break; - case 0xA3: // AND A,E - alu_.anda(af_.hi, de_.lo); - break; - case 0xA4: // AND A,H - alu_.anda(af_.hi, hl_.hi); - break; - case 0xA5: // AND A,L - alu_.anda(af_.hi, hl_.lo); - break; - case 0xA6: // AND A,(HL) - alu_.anda(af_.hi, mmu_->read(hl_.val)); - break; - case 0xE6: // AND A,n - alu_.anda(af_.hi, load8Imm()); - break; - - case 0xB7: // OR A,A - alu_.ora(af_.hi, af_.hi); - break; - case 0xB0: // OR A,B - alu_.ora(af_.hi, bc_.hi); - break; - case 0xB1: // OR A,C - alu_.ora(af_.hi, bc_.lo); - break; - case 0xB2: // OR A,D - alu_.ora(af_.hi, de_.hi); - break; - case 0xB3: // OR A,E - alu_.ora(af_.hi, de_.lo); - break; - case 0xB4: // OR A,H - alu_.ora(af_.hi, hl_.hi); - break; - case 0xB5: // OR A,L - alu_.ora(af_.hi, hl_.lo); - break; - case 0xB6: // OR A,(HL) - alu_.ora(af_.hi, mmu_->read(hl_.val)); - break; - case 0xF6: // OR A,n - alu_.ora(af_.hi, load8Imm()); - break; - - case 0xAF: // XOR A,A - alu_.xora(af_.hi, af_.hi); - break; - case 0xA8: // XOR A,B - alu_.xora(af_.hi, bc_.hi); - break; - case 0xA9: // XOR A,C - alu_.xora(af_.hi, bc_.lo); - break; - case 0xAA: // XOR A,D - alu_.xora(af_.hi, de_.hi); - break; - case 0xAB: // XOR A,E - alu_.xora(af_.hi, de_.lo); - break; - case 0xAC: // XOR A,H - alu_.xora(af_.hi, hl_.hi); - break; - case 0xAD: // XOR A,L - alu_.xora(af_.hi, hl_.lo); - break; - case 0xAE: // XOR A,(HL) - alu_.xora(af_.hi, mmu_->read(hl_.val)); - break; - case 0xEE: // OR A,n - alu_.xora(af_.hi, load8Imm()); - break; - - /* Comparison */ - case 0xBF: // CP A,A - alu_.compare(af_.hi, af_.hi); - break; - case 0xB8: // CP A,B - alu_.compare(af_.hi, bc_.hi); - break; - case 0xB9: // CP A,C - alu_.compare(af_.hi, bc_.lo); - break; - case 0xBA: // CP A,D - alu_.compare(af_.hi, de_.hi); - break; - case 0xBB: // CP A,E - alu_.compare(af_.hi, de_.lo); - break; - case 0xBC: // CP A,H - alu_.compare(af_.hi, hl_.hi); - break; - case 0xBD: // CP A,L - alu_.compare(af_.hi, hl_.lo); - break; - case 0xBE: // CP A,(HL) - alu_.compare(af_.hi, mmu_->read(hl_.val)); - break; - case 0xFE: // CP A,n - alu_.compare(af_.hi, load8Imm()); - break; - - /* Rotate A*/ - - case 0x07: // RLCA - af_.hi = rlca(af_.hi, af_.lo); - break; - case 0x17: // RLA - af_.hi = rla(af_.hi, af_.lo); - break; - case 0x0F: // RRCA - af_.hi = rrca(af_.hi, af_.lo); - break; - case 0x1F: // RRA - af_.hi = rra(af_.hi, af_.lo); - break; - - default: - throw std::runtime_error("Unimplemented Instruction"); - break; - } - - if (debug_mode_) - { - sendInstructionData(opcode, current_pc_, OpcodePage::PAGE1); - } - - if (cycles == -1) - { - cycles = opcode_page1[opcode]; - } - - return (uint8_t)cycles; - } - - uint8_t decode2(uint8_t opcode) - { - uint8_t tmp; - - switch (opcode) - { - /* SWAP */ - case 0x37: // SWAP A - af_.hi = swap(af_.hi); - break; - case 0x30: // SWAP B - bc_.hi = swap(bc_.hi); - break; - case 0x31: // SWAP C - bc_.lo = swap(bc_.lo); - break; - case 0x32: // SWAP D - de_.hi = swap(de_.hi); - break; - case 0x33: // SWAP E - de_.lo = swap(de_.lo); - break; - case 0x34: // SWAP H - hl_.hi = swap(hl_.hi); - break; - case 0x35: // SWAP L - hl_.lo = swap(hl_.lo); - break; - case 0x36: // SWAP (HL) - mmu_->write(swap(mmu_->read(hl_.val)), hl_.val); - break; - - /* Rotate */ - - case 0x00: // RLC B - bc_.hi = rotateLeft(bc_.hi, 1, af_.lo); - break; - case 0x01: // RLC C - bc_.lo = rotateLeft(bc_.lo, 1, af_.lo); - break; - case 0x02: // RLC D - de_.hi = rotateLeft(de_.hi, 1, af_.lo); - break; - case 0x03: // RLC E - de_.lo = rotateLeft(de_.lo, 1, af_.lo); - break; - case 0x04: // RLC H - hl_.hi = rotateLeft(hl_.hi, 1, af_.lo); - break; - case 0x05: // RLC L - hl_.lo = rotateLeft(hl_.lo, 1, af_.lo); - break; - case 0x06: // RLC (HL) - mmu_->write(rotateLeft(mmu_->read(hl_.val), 1, af_.lo), hl_.val); - break; - case 0x07: // RLC A - af_.hi = rotateLeft(af_.hi, 1, af_.lo); - break; - - case 0x08: // RRC B - bc_.hi = rotateRight(bc_.hi, 1, af_.lo); - break; - case 0x09: // RRC C - bc_.lo = rotateRight(bc_.lo, 1, af_.lo); - break; - case 0x0A: // RRC D - de_.hi = rotateRight(de_.hi, 1, af_.lo); - break; - case 0x0B: // RRC E - de_.lo = rotateRight(de_.lo, 1, af_.lo); - break; - case 0x0C: // RRC H - hl_.hi = rotateRight(hl_.hi, 1, af_.lo); - break; - case 0x0D: // RRC L - hl_.lo = rotateRight(hl_.lo, 1, af_.lo); - break; - case 0x0E: // RRC (HL) - mmu_->write(rotateRight(mmu_->read(hl_.val), 1, af_.lo), hl_.val); - break; - case 0x0F: // RRC A - af_.hi = rotateRight(af_.hi, 1, af_.lo); - break; - - //......................... - - case 0x10: // RL B - bc_.hi = rotateLeftCarry(bc_.hi, 1, af_.lo); - break; - case 0x11: // RL C - bc_.lo = rotateLeftCarry(bc_.lo, 1, af_.lo); - break; - case 0x12: // RL D - de_.hi = rotateLeftCarry(de_.hi, 1, af_.lo); - break; - case 0x13: // RL E - de_.lo = rotateLeftCarry(de_.lo, 1, af_.lo); - break; - case 0x14: // RL H - hl_.hi = rotateLeftCarry(hl_.hi, 1, af_.lo); - break; - case 0x15: // RL L - hl_.lo = rotateLeftCarry(hl_.lo, 1, af_.lo); - break; - case 0x16: // RL (HL) - mmu_->write(rotateLeftCarry(mmu_->read(hl_.val), 1, af_.lo), hl_.val); - break; - case 0x17: // RL A - af_.hi = rotateLeftCarry(af_.hi, 1, af_.lo); - break; - - case 0x18: // RR B - bc_.hi = rotateRightCarry(bc_.hi, 1, af_.lo); - break; - case 0x19: // RR C - bc_.lo = rotateRightCarry(bc_.lo, 1, af_.lo); - break; - case 0x1A: // RR D - de_.hi = rotateRightCarry(de_.hi, 1, af_.lo); - break; - case 0x1B: // RR E - de_.lo = rotateRightCarry(de_.lo, 1, af_.lo); - break; - case 0x1C: // RR H - hl_.hi = rotateRightCarry(hl_.hi, 1, af_.lo); - break; - case 0x1D: // RR L - hl_.lo = rotateRightCarry(hl_.lo, 1, af_.lo); - break; - case 0x1E: // RR (HL) - mmu_->write(rotateRightCarry(mmu_->read(hl_.val), 1, af_.lo), hl_.val); - break; - case 0x1F: // RR A - af_.hi = rotateRightCarry(af_.hi, 1, af_.lo); - break; - - /* Shift */ - - case 0x20: // SLA B - bc_.hi = shiftLeft(bc_.hi, 1, af_.lo); - break; - case 0x21: // SLA C - bc_.lo = shiftLeft(bc_.lo, 1, af_.lo); - break; - case 0x22: // SLA D - de_.hi = shiftLeft(de_.hi, 1, af_.lo); - break; - case 0x23: // SLA E - de_.lo = shiftLeft(de_.lo, 1, af_.lo); - break; - case 0x24: // SLA H - hl_.hi = shiftLeft(hl_.hi, 1, af_.lo); - break; - case 0x25: // SLA L - hl_.lo = shiftLeft(hl_.lo, 1, af_.lo); - break; - case 0x26: // SLA (HL) - mmu_->write(shiftLeft(mmu_->read(hl_.val), 1, af_.lo), hl_.val); - break; - case 0x27: // SLA A - af_.hi = shiftLeft(af_.hi, 1, af_.lo); - break; - - case 0x28: // SRA B - bc_.hi = shiftRightA(bc_.hi, 1, af_.lo); - break; - case 0x29: // SRA C - bc_.lo = shiftRightA(bc_.lo, 1, af_.lo); - break; - case 0x2A: // SRA D - de_.hi = shiftRightA(de_.hi, 1, af_.lo); - break; - case 0x2B: // SRA E - de_.lo = shiftRightA(de_.lo, 1, af_.lo); - break; - case 0x2C: // SRA H - hl_.hi = shiftRightA(hl_.hi, 1, af_.lo); - break; - case 0x2D: // SRA L - hl_.lo = shiftRightA(hl_.lo, 1, af_.lo); - break; - case 0x2E: // SRA (HL) - mmu_->write(shiftRightA(mmu_->read(hl_.val), 1, af_.lo), hl_.val); - break; - case 0x2F: // SRA A - af_.hi = shiftRightA(af_.hi, 1, af_.lo); - break; - - case 0x38: // SRL B - bc_.hi = shiftRightL(bc_.hi, 1, af_.lo); - break; - case 0x39: // SRL C - bc_.lo = shiftRightL(bc_.lo, 1, af_.lo); - break; - case 0x3A: // SRL D - de_.hi = shiftRightL(de_.hi, 1, af_.lo); - break; - case 0x3B: // SRL E - de_.lo = shiftRightL(de_.lo, 1, af_.lo); - break; - case 0x3C: // SRL H - hl_.hi = shiftRightL(hl_.hi, 1, af_.lo); - break; - case 0x3D: // SRL L - hl_.lo = shiftRightL(hl_.lo, 1, af_.lo); - break; - case 0x3E: // SRL (HL) - mmu_->write(shiftRightL(mmu_->read(hl_.val), 1, af_.lo), hl_.val); - break; - case 0x3F: // SRL A - af_.hi = shiftRightL(af_.hi, 1, af_.lo); - break; - - /* Bit */ - - // bit 0 - case 0x40: // BIT 0,B - bit(bc_.hi, 0); - break; - case 0x41: // BIT 0,C - bit(bc_.lo, 0); - break; - case 0x42: // BIT 0,D - bit(de_.hi, 0); - break; - case 0x43: // BIT 0,E - bit(de_.lo, 0); - break; - case 0x44: // BIT 0,H - bit(hl_.hi, 0); - break; - case 0x45: // BIT 0,L - bit(hl_.lo, 0); - break; - case 0x46: // BIT 0,(HL) - bit(mmu_->read(hl_.val), 0); - break; - case 0x47: // BIT 0,A - bit(af_.hi, 0); - break; - // bit 1 - case 0x48: // BIT 1,B - bit(bc_.hi, 1); - break; - case 0x49: // BIT 1,C - bit(bc_.lo, 1); - break; - case 0x4A: // BIT 1,D - bit(de_.hi, 1); - break; - case 0x4B: // BIT 1,E - bit(de_.lo, 1); - break; - case 0x4C: // BIT 1,H - bit(hl_.hi, 1); - break; - case 0x4D: // BIT 1,L - bit(hl_.lo, 1); - break; - case 0x4E: // BIT 1,(HL) - bit(mmu_->read(hl_.val), 1); - break; - case 0x4F: // BIT 1,A - bit(af_.hi, 1); - break; - - // bit 2 - case 0x50: // BIT 2,B - bit(bc_.hi, 2); - break; - case 0x51: // BIT 2,C - bit(bc_.lo, 2); - break; - case 0x52: // BIT 2,D - bit(de_.hi, 2); - break; - case 0x53: // BIT 2,E - bit(de_.lo, 2); - break; - case 0x54: // BIT 2,H - bit(hl_.hi, 2); - break; - case 0x55: // BIT 2,L - bit(hl_.lo, 2); - break; - case 0x56: // BIT 2,(HL) - bit(mmu_->read(hl_.val), 2); - break; - case 0x57: // BIT 2,A - bit(af_.hi, 2); - break; - - // bit 3 - case 0x58: // BIT 3,B - bit(bc_.hi, 3); - break; - case 0x59: // BIT 3,C - bit(bc_.lo, 3); - break; - case 0x5A: // BIT 3,D - bit(de_.hi, 3); - break; - case 0x5B: // BIT 3,E - bit(de_.lo, 3); - break; - case 0x5C: // BIT 3,H - bit(hl_.hi, 3); - break; - case 0x5D: // BIT 3,L - bit(hl_.lo, 3); - break; - case 0x5E: // BIT 3,(HL) - bit(mmu_->read(hl_.val), 3); - break; - case 0x5F: // BIT 3,A - bit(af_.hi, 3); - break; - - // bit 4 - case 0x60: // BIT 4,B - bit(bc_.hi, 4); - break; - case 0x61: // BIT 4,C - bit(bc_.lo, 4); - break; - case 0x62: // BIT 4,D - bit(de_.hi, 4); - break; - case 0x63: // BIT 4,E - bit(de_.lo, 4); - break; - case 0x64: // BIT 4,H - bit(hl_.hi, 4); - break; - case 0x65: // BIT 4,L - bit(hl_.lo, 4); - break; - case 0x66: // BIT 4,(HL) - bit(mmu_->read(hl_.val), 4); - break; - case 0x67: // BIT 4,A - bit(af_.hi, 4); - break; - - // bit 5 - case 0x68: // BIT 5,B - bit(bc_.hi, 5); - break; - case 0x69: // BIT 5,C - bit(bc_.lo, 5); - break; - case 0x6A: // BIT 5,D - bit(de_.hi, 5); - break; - case 0x6B: // BIT 5,E - bit(de_.lo, 5); - break; - case 0x6C: // BIT 5,H - bit(hl_.hi, 5); - break; - case 0x6D: // BIT 5,L - bit(hl_.lo, 5); - break; - case 0x6E: // BIT 5,(HL) - bit(mmu_->read(hl_.val), 5); - break; - case 0x6F: // BIT 5,A - bit(af_.hi, 5); - break; - - // bit 6 - case 0x70: // BIT 6,B - bit(bc_.hi, 6); - break; - case 0x71: // BIT 6,C - bit(bc_.lo, 6); - break; - case 0x72: // BIT 6,D - bit(de_.hi, 6); - break; - case 0x73: // BIT 6,E - bit(de_.lo, 6); - break; - case 0x74: // BIT 6,H - bit(hl_.hi, 6); - break; - case 0x75: // BIT 6,L - bit(hl_.lo, 6); - break; - case 0x76: // BIT 6,(HL) - bit(mmu_->read(hl_.val), 6); - break; - case 0x77: // BIT 6,A - bit(af_.hi, 6); - break; - // bit 7 - case 0x78: // BIT 7,B - bit(bc_.hi, 7); - break; - case 0x79: // BIT 7,C - bit(bc_.lo, 7); - break; - case 0x7A: // BIT 7,D - bit(de_.hi, 7); - break; - case 0x7B: // BIT 7,E - bit(de_.lo, 7); - break; - case 0x7C: // BIT 7,H - bit(hl_.hi, 7); - break; - case 0x7D: // BIT 7,L - bit(hl_.lo, 7); - break; - case 0x7E: // BIT 7,(HL) - bit(mmu_->read(hl_.val), 7); - break; - case 0x7F: // BIT 7,A - bit(af_.hi, 7); - break; - - /* Reset */ - case 0x80: // RES 0,B - clearBit(bc_.hi, 0); - break; - case 0x81: // RES 0,C - clearBit(bc_.lo, 0); - break; - case 0x82: // RES 0,D - clearBit(de_.hi, 0); - break; - case 0x83: // RES 0,E - clearBit(de_.lo, 0); - break; - case 0x84: // RES 0,H - clearBit(hl_.hi, 0); - break; - case 0x85: // RES 0,L - clearBit(hl_.lo, 0); - break; - case 0x86: // RES 0,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 0); - mmu_->write(tmp, hl_.val); - break; - case 0x87: // RES 0,A - clearBit(af_.hi, 0); - break; - case 0x88: // RES 1,B - clearBit(bc_.hi, 1); - break; - case 0x89: // RES 1,C - clearBit(bc_.lo, 1); - break; - case 0x8A: // RES 1,D - clearBit(de_.hi, 1); - break; - case 0x8B: // RES 1,E - clearBit(de_.lo, 1); - break; - case 0x8C: // RES 1,H - clearBit(hl_.hi, 1); - break; - case 0x8D: // RES 1,L - clearBit(hl_.lo, 1); - break; - case 0x8E: // RES 1,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 1); - mmu_->write(tmp, hl_.val); - break; - case 0x8F: // RES 1,A - clearBit(af_.hi, 1); - break; - - case 0x90: // RES 2,B - clearBit(bc_.hi, 2); - break; - case 0x91: // RES 2,C - clearBit(bc_.lo, 2); - break; - case 0x92: // RES 2,D - clearBit(de_.hi, 2); - break; - case 0x93: // RES 2,E - clearBit(de_.lo, 2); - break; - case 0x94: // RES 2,H - clearBit(hl_.hi, 2); - break; - case 0x95: // RES 2,L - clearBit(hl_.lo, 2); - break; - case 0x96: // RES 2,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 2); - mmu_->write(tmp, hl_.val); - break; - case 0x97: // RES 2,A - clearBit(af_.hi, 2); - break; - case 0x98: // RES 3,B - clearBit(bc_.hi, 3); - break; - case 0x99: // RES 3,C - clearBit(bc_.lo, 3); - break; - case 0x9A: // RES 3,D - clearBit(de_.hi, 3); - break; - case 0x9B: // RES 3,E - clearBit(de_.lo, 3); - break; - case 0x9C: // RES 3,H - clearBit(hl_.hi, 3); - break; - case 0x9D: // RES 3,L - clearBit(hl_.lo, 3); - break; - case 0x9E: // RES 3,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 3); - mmu_->write(tmp, hl_.val); - break; - case 0x9F: // RES 3,A - clearBit(af_.hi, 3); - break; - - case 0xA0: // RES 4,B - clearBit(bc_.hi, 4); - break; - case 0xA1: // RES 4,C - clearBit(bc_.lo, 4); - break; - case 0xA2: // RES 4,D - clearBit(de_.hi, 4); - break; - case 0xA3: // RES 4,E - clearBit(de_.lo, 4); - break; - case 0xA4: // RES 4,H - clearBit(hl_.hi, 4); - break; - case 0xA5: // RES 4,L - clearBit(hl_.lo, 4); - break; - case 0xA6: // RES 4,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 4); - mmu_->write(tmp, hl_.val); - break; - case 0xA7: // RES 4,A - clearBit(af_.hi, 4); - break; - case 0xA8: // RES 5,B - clearBit(bc_.hi, 5); - break; - case 0xA9: // RES 5,C - clearBit(bc_.lo, 5); - break; - case 0xAA: // RES 5,D - clearBit(de_.hi, 5); - break; - case 0xAB: // RES 5,E - clearBit(de_.lo, 5); - break; - case 0xAC: // RES 5,H - clearBit(hl_.hi, 5); - break; - case 0xAD: // RES 5,L - clearBit(hl_.lo, 5); - break; - case 0xAE: // RES 5,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 5); - mmu_->write(tmp, hl_.val); - break; - case 0xAF: // RES 5,A - clearBit(af_.hi, 5); - break; - - case 0xB0: // RES 6,B - clearBit(bc_.hi, 6); - break; - case 0xB1: // RES 6,C - clearBit(bc_.lo, 6); - break; - case 0xB2: // RES 6,D - clearBit(de_.hi, 6); - break; - case 0xB3: // RES 6,E - clearBit(de_.lo, 6); - break; - case 0xB4: // RES 6,H - clearBit(hl_.hi, 6); - break; - case 0xB5: // RES 6,L - clearBit(hl_.lo, 6); - break; - case 0xB6: // RES 6,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 6); - mmu_->write(tmp, hl_.val); - break; - case 0xB7: // RES 6,A - clearBit(af_.hi, 6); - break; - case 0xB8: // RES 7,B - clearBit(bc_.hi, 7); - break; - case 0xB9: // RES 7,C - clearBit(bc_.lo, 7); - break; - case 0xBA: // RES 7,D - clearBit(de_.hi, 7); - break; - case 0xBB: // RES 7,E - clearBit(de_.lo, 7); - break; - case 0xBC: // RES 7,H - clearBit(hl_.hi, 7); - break; - case 0xBD: // RES 7,L - clearBit(hl_.lo, 7); - break; - case 0xBE: // RES 7,(HL) - tmp = mmu_->read(hl_.val); - clearBit(tmp, 7); - mmu_->write(tmp, hl_.val); - break; - case 0xBF: // RES 7,A - clearBit(af_.hi, 7); - break; - - /* Set */ - - case 0xC0: // SET 0,B - setBit(bc_.hi, 0); - break; - case 0xC1: // SET 0,C - setBit(bc_.lo, 0); - break; - case 0xC2: // SET 0,D - setBit(de_.hi, 0); - break; - case 0xC3: // SET 0,E - setBit(de_.lo, 0); - break; - case 0xC4: // SET 0,H - setBit(hl_.hi, 0); - break; - case 0xC5: // SET 0,L - setBit(hl_.lo, 0); - break; - case 0xC6: // SET 0,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 0); - mmu_->write(tmp, hl_.val); - break; - case 0xC7: // SET 0,A - setBit(af_.hi, 0); - break; - case 0xC8: // SET 1,B - setBit(bc_.hi, 1); - break; - case 0xC9: // SET 1,C - setBit(bc_.lo, 1); - break; - case 0xCA: // SET 1,D - setBit(de_.hi, 1); - break; - case 0xCB: // SET 1,E - setBit(de_.lo, 1); - break; - case 0xCC: // SET 1,H - setBit(hl_.hi, 1); - break; - case 0xCD: // SET 1,L - setBit(hl_.lo, 1); - break; - case 0xCE: // SET 1,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 1); - mmu_->write(tmp, hl_.val); - break; - case 0xCF: // SET 1,A - setBit(af_.hi, 1); - break; - - case 0xD0: // SET 2,B - setBit(bc_.hi, 2); - break; - case 0xD1: // SET 2,C - setBit(bc_.lo, 2); - break; - case 0xD2: // SET 2,D - setBit(de_.hi, 2); - break; - case 0xD3: // SET 2,E - setBit(de_.lo, 2); - break; - case 0xD4: // SET 2,H - setBit(hl_.hi, 2); - break; - case 0xD5: // SET 2,L - setBit(hl_.lo, 2); - break; - case 0xD6: // SET 2,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 2); - mmu_->write(tmp, hl_.val); - break; - case 0xD7: // SET 2,A - setBit(af_.hi, 2); - break; - case 0xD8: // SET 3,B - setBit(bc_.hi, 3); - break; - case 0xD9: // SET 3,C - setBit(bc_.lo, 3); - break; - case 0xDA: // SET 3,D - setBit(de_.hi, 3); - break; - case 0xDB: // SET 3,E - setBit(de_.lo, 3); - break; - case 0xDC: // SET 3,H - setBit(hl_.hi, 3); - break; - case 0xDD: // SET 3,L - setBit(hl_.lo, 3); - break; - case 0xDE: // SET 3,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 3); - mmu_->write(tmp, hl_.val); - break; - case 0xDF: // SET 3,A - setBit(af_.hi, 3); - break; - - case 0xE0: // SET 4,B - setBit(bc_.hi, 4); - break; - case 0xE1: // SET 4,C - setBit(bc_.lo, 4); - break; - case 0xE2: // SET 4,D - setBit(de_.hi, 4); - break; - case 0xE3: // SET 4,E - setBit(de_.lo, 4); - break; - case 0xE4: // SET 4,H - setBit(hl_.hi, 4); - break; - case 0xE5: // SET 4,L - setBit(hl_.lo, 4); - break; - case 0xE6: // SET 4,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 4); - mmu_->write(tmp, hl_.val); - break; - case 0xE7: // SET 4,A - setBit(af_.hi, 4); - break; - case 0xE8: // SET 5,B - setBit(bc_.hi, 5); - break; - case 0xE9: // SET 5,C - setBit(bc_.lo, 5); - break; - case 0xEA: // SET 5,D - setBit(de_.hi, 5); - break; - case 0xEB: // SET 5,E - setBit(de_.lo, 5); - break; - case 0xEC: // SET 5,H - setBit(hl_.hi, 5); - break; - case 0xED: // SET 5,L - setBit(hl_.lo, 5); - break; - case 0xEE: // SET 5,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 5); - mmu_->write(tmp, hl_.val); - break; - case 0xEF: // SET 5,A - setBit(af_.hi, 5); - break; - - case 0xF0: // SET 6,B - setBit(bc_.hi, 6); - break; - case 0xF1: // SET 6,C - setBit(bc_.lo, 6); - break; - case 0xF2: // SET 6,D - setBit(de_.hi, 6); - break; - case 0xF3: // SET 6,E - setBit(de_.lo, 6); - break; - case 0xF4: // SET 6,H - setBit(hl_.hi, 6); - break; - case 0xF5: // SET 6,L - setBit(hl_.lo, 6); - break; - case 0xF6: // SET 6,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 6); - mmu_->write(tmp, hl_.val); - break; - case 0xF7: // SET 6,A - setBit(af_.hi, 6); - break; - case 0xF8: // SET 7,B - setBit(bc_.hi, 7); - break; - case 0xF9: // SET 7,C - setBit(bc_.lo, 7); - break; - case 0xFA: // SET 7,D - setBit(de_.hi, 7); - break; - case 0xFB: // SET 7,E - setBit(de_.lo, 7); - break; - case 0xFC: // SET 7,H - setBit(hl_.hi, 7); - break; - case 0xFD: // SET 7,L - setBit(hl_.lo, 7); - break; - case 0xFE: // SET 7,(HL) - tmp = mmu_->read(hl_.val); - setBit(tmp, 7); - mmu_->write(tmp, hl_.val); - break; - case 0xFF: // SET 7,A - setBit(af_.hi, 7); - break; - - default: - throw std::runtime_error("Unimplemented Instruction"); - break; - } - - if (debug_mode_) - { - sendInstructionData(opcode, current_pc_, OpcodePage::PAGE2); - } - - return opcode_page2[opcode]; - } - - void checkInterrupts() - { - // when EI or DI is used to change the IME the change takes effect after the next instruction is executed - - if (interrupt_master_disable_pending_ >= 0) - { - interrupt_master_disable_pending_++; - if (interrupt_master_disable_pending_ == 2) - { - interrupt_master_enable_ = false; - interrupt_master_disable_pending_ = -1; - } - } - - if (interrupt_master_enable_pending_ >= 0) - { - interrupt_master_enable_pending_++; - if (interrupt_master_enable_pending_ == 2) - { - interrupt_master_enable_ = true; - interrupt_master_enable_pending_ = -1; - } - } - - if (interrupt_master_enable_) - { - // mask off disabled interrupts - uint8_t pending_interrupts = interrupt_flags_ & interrupt_enable_; - - if (isSet(pending_interrupts, InterruptMask::JOYPAD)) - interrupt(InterruptVector::JOYPAD, InterruptMask::JOYPAD); - - if (isSet(pending_interrupts, InterruptMask::SERIAL_TRANSFER_COMPLETE)) - interrupt(InterruptVector::SERIAL_TRANSFER_COMPLETE, InterruptMask::SERIAL_TRANSFER_COMPLETE); - - if (isSet(pending_interrupts, InterruptMask::TIME_OVERFLOW)) - interrupt(InterruptVector::TIME_OVERFLOW, InterruptMask::TIME_OVERFLOW); - - if (isSet(pending_interrupts, InterruptMask::LCDC_STAT)) - interrupt(InterruptVector::LCDC_STAT, InterruptMask::LCDC_STAT); - - if (isSet(pending_interrupts, InterruptMask::VBLANK)) - interrupt(InterruptVector::VBLANK, InterruptMask::VBLANK); - } - } - - void interrupt(InterruptVector vector, InterruptMask mask) - { - interrupt_master_enable_ = false; - - push(pc_.val); - pc_.val = static_cast(vector); - - clearMask(interrupt_flags_, mask); - - cycle_count_ += 5; - } - - void checkPowerMode() - { - uint8_t pending_interrupts = interrupt_enable_ & interrupt_flags_; - - if (!stopped_) - { - if (pending_interrupts != 0) - { - halted_ = false; - } - } - else - { - if (isSet(pending_interrupts, InterruptMask::JOYPAD)) - { - stopped_ = false; - halted_ = false; - } - } - } - - void sendInstructionData(uint8_t opcode, uint16_t addr, OpcodePage page) - { - if (instruction_callback_) - { - const auto instr = fetchInstructionData(opcode, addr, page); - instruction_callback_(instr, addr); - } - } - - Instruction fetchInstructionData(uint8_t opcode, uint16_t opcode_addr, OpcodePage page) - { - OpcodeInfo opcodeinfo = getOpcodeInfo(opcode, page); - - if (opcodeinfo.userdata == OperandType::NONE) - { - return Instruction{ opcode, static_cast(page), {0, 0} }; - } - else - { - if (opcodeinfo.userdata == OperandType::IMM8) - { - const auto data = mmu_->read(opcode_addr + 1); - return Instruction{ opcode, static_cast(page), {data, 0} }; - } - else // OperandType::IMM16 - { - const auto lo = mmu_->read(opcode_addr + 1); - const auto hi = mmu_->read(opcode_addr + 2); - - return Instruction{ opcode, static_cast(page), {lo, hi} }; - } - } - } - - uint8_t load8Imm() - { - return mmu_->read(pc_.val++); - } - - uint16_t load16Imm() - { - uint8_t lo = load8Imm(); - uint8_t hi = load8Imm(); - - return word(hi, lo); - } - - void in(uint16_t addr) - { - // read from offset into IO registers - af_.hi = mmu_->read(addr); - } - - void out(uint16_t addr) - { - // write out to the IO registers given the offset - mmu_->write(af_.hi, addr); - } - - void inc(uint16_t& i) - { - i++; - } - - void dec(uint8_t& d) - { - bool half_carry = isHalfBorrow(d, 1); - - d--; - - setFlag(CPU::Flags::Z, d == 0); - setFlag(CPU::Flags::N, true); - setFlag(CPU::Flags::H, half_carry); - } - - void inca(uint16_t addr) - { - uint8_t b = mmu_->read(addr); - inc(b); - mmu_->write(b, addr); - } - - void deca(uint16_t addr) - { - uint8_t b = mmu_->read(addr); - dec(b); - mmu_->write(b, addr); - } - - void push(uint16_t value) - { - uint8_t hi = (value & 0xFF00) >> 8; - uint8_t lo = (value & 0x00FF); - - mmu_->write(hi, sp_.val - 1); - mmu_->write(lo, sp_.val - 2); - - sp_.val -= 2; - } - - uint16_t pop() - { - uint8_t lo = mmu_->read(sp_.val); - uint8_t hi = mmu_->read(sp_.val + 1); - - sp_.val += 2; - - return word(hi, lo); - } - - void jp(uint16_t addr) - { - pc_.val = addr; - } - - void jr(int8_t r) - { - pc_.val += r; - } - - void inc(uint8_t& i) - { - bool half_carry = isHalfCarry(i, 1); - - i++; - - setFlag(CPU::Flags::Z, i == 0); - setFlag(CPU::Flags::N, false); - setFlag(CPU::Flags::H, half_carry); - } - - void dec(uint16_t& d) - { - d--; - } - - void call(uint16_t addr) - { - push(pc_.val); - pc_.val = addr; - } - - void ret() - { - pc_.val = pop(); - } - - void reti() - { - ret(); - interrupt_master_enable_ = true; - } - - uint8_t swap(uint8_t byte) - { - uint8_t hi = (byte & 0xF0) >> 4; - uint8_t lo = byte & 0x0F; - - uint8_t newByte = (lo << 4) | hi; - - setFlag(CPU::Flags::Z, newByte == 0); - setFlag(CPU::Flags::N, false); - setFlag(CPU::Flags::H, false); - setFlag(CPU::Flags::C, false); - - return newByte; - } - - void daa() - { - bool n = isSet(af_.lo, CPU::Flags::N) != 0; - bool h = isSet(af_.lo, CPU::Flags::H) != 0; - bool c = isSet(af_.lo, CPU::Flags::C) != 0; - - int a = (int)af_.hi; - - if (!n) - { - if (c || (a > 0x99)) { - a = (a + 0x60) & 0xFF; - setFlag(Flags::C, true); - } - if (h || ((a & 0x0F) > 9)) { - a = (a + 0x06) & 0xFF; - setFlag(Flags::H, false); - } - } - else if (c && h) - { - a = (a + 0x9A) & 0xFF; - setFlag(Flags::H, false); - } - else if (c) - { - a = (a + 0xA0) & 0xFF; - } - else if (h) - { - a = (a + 0xFA) & 0xFF; - setFlag(Flags::H, false); - } - - setFlag(Flags::Z, a == 0); - - af_.hi = (uint8_t)a; - } - - uint16_t ldHLSPe() - { - int8_t e = (int8_t)load8Imm(); - int result = sp_.val + e; - - setFlag(Flags::C, ((sp_.val ^ e ^ (result & 0xFFFF)) & 0x100) == 0x100); - setFlag(Flags::H, ((sp_.val ^ e ^ (result & 0xFFFF)) & 0x10) == 0x10); - - setFlag(ALU::Flags::Z, false); - setFlag(ALU::Flags::N, false); - - return (uint16_t)result; - } - - void stop() - { - if (cgb_enabled_) - { - // TODO: CGB support - } - else - { - // TODO: Remove the KEY1 check - auto key1_reg = mmu_->read(memorymap::KEY1_REGISER); - - // check for preparing speed switch - if (key1_reg & 0x01) return; - - stopped_ = true; - halted_ = true; - pc_.val++; - } - } - - void setFlag(uint8_t mask, bool set) - { - if (set) - { - setMask(af_.lo, mask); - } - else - { - clearMask(af_.lo, mask); - } - } - - void reset() - { - af_.hi = (cgb_enabled_) ? 0x11 : 0x00; - af_.lo = 0; - - bc_.val = 0; - de_.val = 0; - hl_.val = 0; - sp_.val = memorymap::HIGH_RAM_END; - pc_.val = memorymap::PROGRAM_START; - - cycle_count_ = 0; - halted_ = false; - stopped_ = false; - interrupt_master_enable_ = false; - interrupt_master_enable_pending_ = -1; - interrupt_master_disable_pending_ = -1; - - // set normal speed mode of CGB - mmu_->write((uint8_t)0x00, memorymap::KEY1_REGISER); - } - - void setDebugMode(bool debug_mode) noexcept - { - debug_mode_ = debug_mode; - } - - void setInstructionCallback(const std::function& callback) noexcept - { - instruction_callback_ = callback; - } - - bool isHalted() const noexcept - { - return halted_; - } - - void bit(uint8_t val, uint8_t n) - { - uint8_t b = (val & bv(n)) >> n; - - setFlag(CPU::Flags::Z, b == 0); - setFlag(CPU::Flags::H, true); - setFlag(CPU::Flags::N, false); - } - - std::array serialize() const noexcept - { - return { - af_.hi, - af_.lo, - bc_.hi, - bc_.lo, - de_.hi, - de_.lo, - hl_.hi, - hl_.lo, - sp_.hi, - sp_.lo, - pc_.hi, - pc_.lo - }; - } - - void deserialize(const std::array& data) noexcept - { - af_.hi = data[0]; - af_.lo = data[1]; - bc_.hi = data[2]; - bc_.lo = data[3]; - de_.hi = data[4]; - de_.lo = data[5]; - hl_.hi = data[6]; - hl_.lo = data[7]; - sp_.hi = data[8]; - sp_.lo = data[9]; - pc_.hi = data[10]; - pc_.lo = data[11]; - } - - CPU::Status getStatus() const - { - Status status; - status.af = af_.val; - status.a = af_.hi; - status.f = af_.lo; - status.bc = bc_.val; - status.b = bc_.hi; - status.c = bc_.lo; - status.de = de_.val; - status.d = de_.hi; - status.e = de_.lo; - status.hl = hl_.val; - status.h = hl_.hi; - status.l = hl_.lo; - status.sp = sp_.val; - status.pc = pc_.val; - status.halt = halted_; - status.stopped = stopped_; - status.ime = interrupt_master_enable_; - status.enabled_interrupts = interrupt_enable_; - - status.flag_z = !!(af_.lo & Flags::Z); - status.flag_n = !!(af_.lo & Flags::N); - status.flag_h = !!(af_.lo & Flags::H); - status.flag_c = !!(af_.lo & Flags::C); - - return status; - } - - private: - Register af_; - Register bc_; - Register de_; - Register hl_; - Register sp_; - Register pc_; - - MMU::Ptr& mmu_; - GPU::Ptr& gpu_; - APU::Ptr& apu_; - Link::Ptr& link_; - - ALU alu_; - - Timer timer_; - - bool halted_; - bool stopped_; - - bool interrupt_master_enable_; - int interrupt_master_enable_pending_; - int interrupt_master_disable_pending_; - - bool debug_mode_; - uint16_t current_pc_; - std::function instruction_callback_; - - int cycle_count_; - - uint8_t& interrupt_flags_; - uint8_t& interrupt_enable_; - - bool cgb_enabled_; - }; - - /* Public Interface */ - - CPU::CPU(MMU::Ptr& mmu, GPU::Ptr& gpu, APU::Ptr& apu, Link::Ptr& link) : - impl_(new Impl(mmu, gpu, apu, link)) - { - reset(); - } - - CPU::~CPU() - { - delete impl_; - } - - void CPU::step() - { - impl_->step(); - } - - void CPU::reset() - { - impl_->reset(); - } - - bool CPU::isHalted() const noexcept - { - return impl_->isHalted(); - } - - void CPU::setDebugMode(bool debug_mode) noexcept - { - impl_->setDebugMode(debug_mode); - } - - void CPU::setInstructionCallback(std::function callback) noexcept - { - impl_->setInstructionCallback(callback); - } - - std::array CPU::serialize() const noexcept - { - return impl_->serialize(); - } - - void CPU::deserialize(const std::array& data) noexcept - { - impl_->deserialize(data); - } - - CPU::Status CPU::getStatus() const - { - return impl_->getStatus(); - } -} diff --git a/components/gameboycore/src/gameboycore.cpp b/components/gameboycore/src/gameboycore.cpp deleted file mode 100644 index 85eade84..00000000 --- a/components/gameboycore/src/gameboycore.cpp +++ /dev/null @@ -1,326 +0,0 @@ - -#include "gameboycore/gameboycore.h" -#include "gameboycore/cartinfo.h" -#include "bitutil.h" - -#include -#include -#include - -namespace gb -{ - /* Private Interface */ - - class GameboyCore::Impl - { - public: - CPU::Ptr cpu; - MMU::Ptr mmu; - GPU::Ptr gpu; - APU::Ptr apu; - Joy::Ptr joy; - Link::Ptr link; - - GPU::RenderScanlineCallback scanline_callback_; - GPU::VBlankCallback vblank_callback_; - APU::AudioSampleCallback audio_sample_callback_; - - void setScanlineCallback(GPU::RenderScanlineCallback fn) - { - scanline_callback_ = fn; - - if (gpu) - gpu->setRenderCallback(scanline_callback_); - } - - void setVBlankCallback(GPU::VBlankCallback fn) - { - vblank_callback_ = fn; - - if (gpu) - gpu->setVBlankCallback(vblank_callback_); - } - - void setAudioSampleCallback(APU::AudioSampleCallback fn) - { - audio_sample_callback_ = fn; - - if (apu) - apu->setAudioSampleCallback(audio_sample_callback_); - } - - void loadROM(const uint8_t* rom, uint32_t size) - { - mmu.reset(new MMU(rom, size)); - - gpu.reset(new GPU(mmu)); - apu.reset(new APU(mmu)); - link.reset(new Link(mmu)); - - cpu.reset(new CPU(mmu, gpu, apu, link)); - - joy.reset(new Joy(*mmu)); - - // setup callback - gpu->setRenderCallback(scanline_callback_); - gpu->setVBlankCallback(vblank_callback_); - apu->setAudioSampleCallback(audio_sample_callback_); - - setColorTheme(ColorTheme::GOLD); - } - - std::vector serialize() const - { - const auto cpu_data = cpu->serialize(); - - const auto ram_start = mmu->getptr(memorymap::SWITCHABLE_ROM_BANK_END + 1); - const auto ram_end = mmu->getptr(memorymap::INTERRUPT_ENABLE); - - const auto serialize_size = cpu_data.size() + static_cast(ram_end - ram_start); - - std::vector data; - data.reserve(serialize_size); - - std::copy(cpu_data.begin(), cpu_data.end(), std::back_inserter(data)); - std::copy(ram_start, ram_end, std::back_inserter(data)); - - return data; - } - - void deserialize(const std::vector& data) - { - std::array cpu_state; - std::copy(data.begin(), data.begin() + cpu_state.size(), cpu_state.begin()); - - const auto ram_start = mmu->getptr(memorymap::SWITCHABLE_ROM_BANK_END + 1); - std::copy(data.begin() + cpu_state.size(), data.end(), ram_start); - } - - void setTimeProvider(const TimeProvider provider) - { - mmu->setTimeProvider(provider); - } - - void setInstructionCallback(std::function fn) - { - cpu->setInstructionCallback(fn); - } - - void setColorTheme(ColorTheme theme) - { - switch (theme) - { - case gb::GameboyCore::ColorTheme::DEFAULT: - gpu->setPaletteColor(255, 255, 255, 0); - gpu->setPaletteColor(196, 196, 196, 1); - gpu->setPaletteColor( 96, 96, 96, 2); - gpu->setPaletteColor( 0, 0, 0, 3); - break; - case gb::GameboyCore::ColorTheme::GOLD: - gpu->setPaletteColor(252, 232, 140, 0); - gpu->setPaletteColor(220, 180, 92, 1); - gpu->setPaletteColor(152, 124, 60, 2); - gpu->setPaletteColor(76, 60, 28, 3); - break; - case gb::GameboyCore::ColorTheme::GREEN: - gpu->setPaletteColor(155, 188, 15, 0); - gpu->setPaletteColor(139, 172, 15, 1); - gpu->setPaletteColor( 48, 98, 48, 2); - gpu->setPaletteColor( 15, 56, 15, 3); - break; - default: - break; - } - } - }; - - /* Public Interface */ - - GameboyCore::GameboyCore() : - impl_(new Impl) - { - } - - GameboyCore::~GameboyCore() - { - delete impl_; - } - - void GameboyCore::update(int steps) - { - while(steps--) - { - impl_->cpu->step(); - } - } - - void GameboyCore::emulateFrame() - { - auto& cpu = impl_->cpu; - auto& ly = impl_->mmu->get(memorymap::LY_REGISTER); - - // Run to starting point of line=0 - while (ly != 0) - { - cpu->step(); - } - - // run for a frames worth of scanlines line=144 - while (ly <= 143) - { - cpu->step(); - } - } - - void GameboyCore::open(const std::string& filename) - { - std::ifstream file{ filename, std::ios::ate | std::ios::binary }; - if (!file.is_open()) - { - throw std::runtime_error(std::string("Could not load ROM file: " + filename)); - } - - auto size = (std::size_t)file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector buffer; - buffer.resize(size); - - file.read((char*)buffer.data(), buffer.size()); - - loadROM(buffer); - } - - void GameboyCore::loadROM(const std::vector& buffer) - { - loadROM(buffer.data(), buffer.size()); - } - - void GameboyCore::loadROM(const uint8_t* rom, uint32_t size) - { - impl_->loadROM(rom, size); - } - - void GameboyCore::reset() - { - impl_->cpu->reset(); - } - - void GameboyCore::setDebugMode(bool debug) - { - impl_->cpu->setDebugMode(debug); - } - - void GameboyCore::setColorTheme(ColorTheme theme) - { - impl_->setColorTheme(theme); - } - - uint8_t GameboyCore::readMemory(uint16_t addr) - { - return impl_->mmu->read(addr); - } - - void GameboyCore::writeMemory(uint16_t addr, uint8_t value) - { - impl_->mmu->write(value, addr); - } - - void GameboyCore::setScanlineCallback(GPU::RenderScanlineCallback callback) - { - impl_->setScanlineCallback(callback); - } - - void GameboyCore::setVBlankCallback(GPU::VBlankCallback callback) - { - impl_->setVBlankCallback(callback); - } - - void GameboyCore::setAudioSampleCallback(APU::AudioSampleCallback callback) - { - impl_->setAudioSampleCallback(callback); - } - - void GameboyCore::input(Joy::Key key, bool pressed) - { - if (pressed) - impl_->joy->press(key); - else - impl_->joy->release(key); - } - - std::vector GameboyCore::getBatteryRam() const - { - return impl_->mmu->getBatteryRam(); - } - - void GameboyCore::setBatteryRam(const std::vector& ram) - { - impl_->mmu->setBatteryRam(ram); - } - - void GameboyCore::linkWrite(uint8_t byte) - { - impl_->link->recieve(byte); - } - - void GameboyCore::setLinkReadyCallback(Link::ReadyCallback callback) - { - impl_->link->setReadyCallback(callback); - } - - std::vector GameboyCore::serialize() const - { - return impl_->serialize(); - } - - void GameboyCore::deserialize(const std::vector& data) - { - impl_->deserialize(data); - } - - void GameboyCore::setTimeProvider(const TimeProvider provider) - { - impl_->setTimeProvider(provider); - } - - void GameboyCore::setInstructionCallback(std::function fn) - { - impl_->setInstructionCallback(fn); - } - - CPU::Ptr& GameboyCore::getCPU() - { - return impl_->cpu; - } - - MMU::Ptr& GameboyCore::getMMU() - { - return impl_->mmu; - } - - GPU::Ptr& GameboyCore::getGPU() - { - return impl_->gpu; - } - - APU::Ptr& GameboyCore::getAPU() - { - return impl_->apu; - } - - Joy::Ptr& GameboyCore::getJoypad() - { - return impl_->joy; - } - - Link::Ptr& GameboyCore::getLink() - { - return impl_->link; - } - - bool GameboyCore::isDone() const - { - return impl_->cpu->isHalted(); - } -} diff --git a/components/gameboycore/src/gpu.cpp b/components/gameboycore/src/gpu.cpp deleted file mode 100644 index 1e1330d7..00000000 --- a/components/gameboycore/src/gpu.cpp +++ /dev/null @@ -1,490 +0,0 @@ -#include "gameboycore/gpu.h" -#include "gameboycore/palette.h" -#include "gameboycore/memorymap.h" -#include "gameboycore/pixel.h" -#include "gameboycore/interrupt_provider.h" -#include "gameboycore/tilemap.h" - -#include "gameboycore/detail/hash.h" - -#include "bitutil.h" - -namespace gb -{ - static constexpr auto HBLANK_CYCLES = 207; - static constexpr auto OAM_ACCESS_CYCLES = 83; - static constexpr auto LCD_TRANSFER_CYCLES = 175; - - static constexpr auto LINE_CYCLES = 456; - static constexpr auto VBLANK_LINE = 144; - static constexpr auto MAX_LINES = 153; - - /* Private Implementation */ - - class GPU::Impl - { - public: - enum class Mode - { - HBLANK, - VBLANK, - OAM, - LCD - }; - - /** - Data needed for HDMA transfer - */ - struct Hdma - { - Hdma() : - transfer_active(false), - source(0), - destination(0), - length(0) - { - } - - bool transfer_active; - uint16_t source; - uint16_t destination; - uint16_t length; - }; - - using CgbPalette = std::array, 8>; - - explicit Impl(MMU::Ptr& mmu) : - mmu_(mmu), - mode_(Mode::OAM), - cycle_count_(0), - line_(0), - lcdc_(mmu->get(memorymap::LCDC_REGISTER)), - stat_(mmu->get(memorymap::LCD_STAT_REGISTER)), - hdma5_(mmu->get(memorymap::HDMA5)), - vblank_provider_(*mmu.get(), InterruptProvider::Interrupt::VBLANK), - stat_provider_(*mmu.get(), InterruptProvider::Interrupt::LCDSTAT), - tilemap_(*mmu.get(), palette_), - cgb_enabled_(mmu->cgbEnabled()) - { - mmu->addWriteHandler(memorymap::LCDC_REGISTER, std::bind(&Impl::lcdcWriteHandler, this, std::placeholders::_1, std::placeholders::_2)); - mmu->addWriteHandler(memorymap::BGPD, std::bind(&Impl::paletteWriteHandler, this, std::placeholders::_1, std::placeholders::_2)); - mmu->addWriteHandler(memorymap::OBPD, std::bind(&Impl::paletteWriteHandler, this, std::placeholders::_1, std::placeholders::_2)); - mmu->addWriteHandler(memorymap::HDMA5, std::bind(&Impl::hdma5WriteHandler, this, std::placeholders::_1, std::placeholders::_2)); - } - - void update(uint8_t cycles, bool ime) - { - if (isClear(lcdc_, memorymap::LCDC::ENABLE)) return; - - cycle_count_ += cycles; - - switch (mode_) - { - case Mode::HBLANK: - // check if the HBLANK period is over - if (hasElapsed(HBLANK_CYCLES)) - { - // update the scan line - updateLY(); - // check if LY matches LYC - compareLyToLyc(ime); - - // check if in VBlank mode - if (line_ == VBLANK_LINE) - { - mode_ = Mode::VBLANK; - vblank_provider_.set(); - - if (vblank_callback_) - vblank_callback_(); - } - else - { - mode_ = Mode::OAM; - } - - checkStatInterrupts(ime); - } - break; - case Mode::OAM: - if (hasElapsed(OAM_ACCESS_CYCLES)) - { - mode_ = Mode::LCD; - } - break; - case Mode::LCD: - if (hasElapsed(LCD_TRANSFER_CYCLES)) - { - // render the current scan line - renderScanline(); - - mode_ = Mode::HBLANK; - // perform an hdma transfer - doHdma(); - checkStatInterrupts(ime); - } - break; - case Mode::VBLANK: - if (hasElapsed(LINE_CYCLES)) - { - updateLY(); - compareLyToLyc(ime); - - if (line_ == 0) - { - mode_ = Mode::OAM; - checkStatInterrupts(ime); - } - } - break; - } - - // update LCDC stat mode - stat_ = (stat_ & 0xFC) | (static_cast(mode_)); - } - - void setRenderCallback(RenderScanlineCallback callback) - { - render_scanline_ = callback; - } - - void setVBlankCallback(VBlankCallback callback) - { - vblank_callback_ = callback; - } - - void setDefaultPaletteColor(uint8_t r, uint8_t g, uint8_t b, int idx) - { - palette_.set(r, g, b, idx); - } - - std::vector getBackgroundTileMap() - { - return tilemap_.getBackgroundTileMap(); - } - - std::array getSpriteCache() const - { - return tilemap_.getSpriteCache(); - } - - std::size_t getBackgroundHash() - { - return tilemap_.hashBackground(); - } - - private: - - void renderScanline() - { - Scanline scanline; - std::array color_line; - - auto background_palette = palette_.get(mmu_->read(memorymap::BGP_REGISTER)); - - // get lcd config - - const auto background_enabled = isSet(lcdc_, memorymap::LCDC::BG_DISPLAY_ON) != 0; - const auto window_enabled = isSet(lcdc_, memorymap::LCDC::WINDOW_ON) != 0; - const auto sprites_enabled = isSet(lcdc_, memorymap::LCDC::OBJ_ON) != 0; - - // get background tile line - const auto background = tilemap_.getBackground(line_, cgb_enabled_); - - // get window overlay tile line - const auto window = tilemap_.getWindowOverlay(line_); - const auto wx = mmu_->read(memorymap::WX_REGISTER); - const auto wy = mmu_->read(memorymap::WY_REGISTER); - - // compute a scan line - for (auto pixel_idx = 0u; pixel_idx < scanline.size(); ++pixel_idx) - { - auto tileinfo = 0u; - - if (window_enabled && line_ >= (int)wy && (int)pixel_idx >= (wx - 7)) - tileinfo = window[pixel_idx]; - else if (background_enabled || cgb_enabled_) - tileinfo = background[pixel_idx]; - else - tileinfo = 0; - - auto color_number = tileinfo & 0x03; - auto color_palette = (tileinfo >> 2) & 0x07; - auto priority = (tileinfo >> 5); - - color_line[pixel_idx] = (uint8_t)(color_number | (priority << 2)); - - if (cgb_enabled_) - { - scanline[pixel_idx] = cgb_background_palettes_[color_palette][color_number]; - } - else - { - scanline[pixel_idx] = background_palette[color_number]; - } - } - - if (sprites_enabled) - tilemap_.drawSprites(scanline, color_line, line_, cgb_enabled_, cgb_sprite_palette_); - - // send scan line to the renderer - if (render_scanline_ && line_ < VBLANK_LINE) - render_scanline_(scanline, line_); - } - - bool hasElapsed(int mode_cycles) - { - if (cycle_count_ >= mode_cycles) - { - cycle_count_ -= mode_cycles; - return true; - } - return false; - } - - void updateLY() - { - line_ = (line_ + 1) % MAX_LINES; - mmu_->write((uint8_t)line_, memorymap::LY_REGISTER); - } - - void lcdcWriteHandler(uint8_t value, uint16_t) - { - bool enable = (value & memorymap::LCDC::ENABLE) != 0; - - if (enable && isClear(lcdc_, memorymap::LCDC::ENABLE)) - { - line_ = 0; - cycle_count_ = 0; - } - - lcdc_ = value; - } - - void paletteWriteHandler(uint8_t value, uint16_t addr) - { - if (addr == memorymap::BGPD) - { - setPalette(cgb_background_palettes_, value, memorymap::BGPI); - } - else if(addr == memorymap::OBPD) - { - setPalette(cgb_sprite_palette_, value, memorymap::OBPI); - } - } - - void setPalette(CgbPalette& palettes, uint8_t value, uint16_t index_reg) - { - // get the background palette index - const auto index = mmu_->read(index_reg); - - // extract high byte, color index and palette index info from background palette index - auto hi = index & 0x01; - auto color_idx = (index >> 1) & 0x03; - auto palette_idx = (index >> 3) & 0x07; - - // RGB value break down - // MSB: | xBBBBBGG | - // LBS: | GGGRRRRR | - - auto& palette_color = palettes[palette_idx][color_idx]; - - if (hi) - { - palette_color.b = (value >> 2) & 0x1F; - palette_color.g |= ((value & 0x03) << 3); - - palette_color = translateRGB(palette_color); - } - else - { - palette_color.g = ((value & 0xE0) >> 5); - palette_color.r = (value & 0x1F); - } - - // auto increment index if increment flag is set - if (isBitSet(index, 7)) - { - mmu_->write((uint8_t)(index + 1), index_reg); - } - } - - Pixel translateRGB(const Pixel& pixel) - { - Pixel out; - out.r = scale(pixel.r); - out.g = scale(pixel.g); - out.b = scale(pixel.b); - - return out; - } - - uint8_t scale(uint8_t v) - { - auto old_range = (0x1F - 0x00); - auto new_range = (0xFF - 0x00); - - return (uint8_t)((v * new_range) / old_range); - } - - void hdma5WriteHandler(uint8_t value, uint16_t) - { - uint16_t src = word(mmu_->read(memorymap::HDMA1), mmu_->read(memorymap::HDMA2)) & 0xFFF0; - uint16_t dest = word(((mmu_->read(memorymap::HDMA3) & 0x1F) | 0x80), mmu_->read(memorymap::HDMA4)) & 0xFFF0; - uint16_t length = ((value & 0x7F) + 1) * 0x10; - - if (isBitClear(value, 7) && !hdma_.transfer_active) - { - // perform a general purpose DMA - mmu_->dma(dest, src, length); - } - else if (isBitClear(value, 7) && hdma_.transfer_active) - { - // disable an active hdma transfer - hdma_.transfer_active = false; - } - else - { - // initialize an HDMA transfer - hdma_.source = src; - hdma_.destination = dest; - hdma_.length = length; - hdma_.transfer_active = true; - } - - hdma5_ = value; - } - - void doHdma() - { - if (hdma_.transfer_active) - { - // hdma only works between this range - if (line_ >= 0 && line_ <= 143) - { - // transfer $10 bytes - mmu_->dma(hdma_.destination, hdma_.source, 0x10); - // advance source $10 bytes - hdma_.source += 0x10; - // advance destination $10 bytes - hdma_.destination += 0x10; - // count down the length - hdma_.length -= 0x10; - - if (hdma_.length == 0) - { - hdma_.transfer_active = false; - } - } - } - } - - void compareLyToLyc(bool ime) - { - auto lyc = mmu_->read(memorymap::LYC_REGISTER); - - if ((uint8_t)line_ == lyc) - { - //stat_ |= memorymap::Stat::LYCLY; - setMask(stat_, memorymap::Stat::LYCLY); - } - else - { - //stat_ &= ~(memorymap::Stat::LYCLY); - clearMask(stat_, memorymap::Stat::LYCLY); - } - - // check the ly=lyc flag - if (stat_ & memorymap::Stat::LYCLY) - { - if (ime) - stat_provider_.set(); - } - } - - void checkStatInterrupts(bool ime) - { - // check mode selection interrupts - uint8_t mask = (1 << (3 + static_cast(mode_))); - - if (stat_ & mask) - { - if (ime) - stat_provider_.set(); - } - } - - private: - MMU::Ptr& mmu_; - - Mode mode_; - int cycle_count_; - int line_; - uint8_t& lcdc_; - uint8_t& stat_; - uint8_t& hdma5_; - Hdma hdma_; - - InterruptProvider vblank_provider_; - InterruptProvider stat_provider_; - - detail::TileMap tilemap_; - Palette palette_; - - RenderScanlineCallback render_scanline_; - VBlankCallback vblank_callback_; - - bool cgb_enabled_; - - CgbPalette cgb_background_palettes_; - CgbPalette cgb_sprite_palette_; - }; - - /* Public Implementation */ - - GPU::GPU(MMU::Ptr& mmu) : - impl_(new Impl(mmu)) - { - } - - GPU::~GPU() - { - delete impl_; - } - - void GPU::update(uint8_t cycles, bool ime) - { - impl_->update(cycles, ime); - } - - void GPU::setRenderCallback(RenderScanlineCallback callback) - { - impl_->setRenderCallback(callback); - } - - void GPU::setVBlankCallback(VBlankCallback callback) - { - impl_->setVBlankCallback(callback); - } - - void GPU::setPaletteColor(uint8_t r, uint8_t g, uint8_t b, int idx) - { - impl_->setDefaultPaletteColor(r, g, b, idx); - } - - std::vector GPU::getBackgroundTileMap() - { - return impl_->getBackgroundTileMap(); - } - - std::array GPU::getSpriteCache() const - { - return impl_->getSpriteCache(); - } - - std::size_t GPU::getBackgroundHash() - { - return impl_->getBackgroundHash(); - } - -} // namespace gb diff --git a/components/gameboycore/src/instruction.cpp b/components/gameboycore/src/instruction.cpp deleted file mode 100644 index 691b7bfb..00000000 --- a/components/gameboycore/src/instruction.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "gameboycore/instruction.h" -#include "gameboycore/opcodeinfo.h" - -#include - -namespace gb -{ - std::string disassemble(const Instruction& instruction) - { - const auto opcode = instruction.opcode; - const auto page = static_cast(instruction.page); - - const auto info = getOpcodeInfo(opcode, page); - - //char buf[32]; - std::array buf; - - switch (info.userdata) - { - case OperandType::NONE: - std::sprintf(&buf[0], "%s", info.disassembly); - break; - case OperandType::IMM8: - std::sprintf(&buf[0], info.disassembly, instruction.operand_data[0]); - break; - case OperandType::IMM16: - std::sprintf(&buf[0], info.disassembly, (instruction.operand_data[0] | instruction.operand_data[1] << 8)); - break; - default: - break; - } - - return std::string(&buf[0]); - } -} \ No newline at end of file diff --git a/components/gameboycore/src/joypad.cpp b/components/gameboycore/src/joypad.cpp deleted file mode 100644 index c720f878..00000000 --- a/components/gameboycore/src/joypad.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - \author Natesh Narain - \date Oct 8 2016 -*/ - -#include "gameboycore/joypad.h" -#include "gameboycore/interrupt_provider.h" - -namespace gb -{ - /* Private Implementation */ - - class Joy::Impl - { - public: - explicit Impl(MMU& mmu) : - mmu_(mmu), - reg_(mmu.get(memorymap::JOYPAD_REGISTER)), - keys_(0xFF), - interrupt_provider_(mmu, InterruptProvider::Interrupt::JOYPAD) - { - // add handlers - mmu_.addReadHandler(memorymap::JOYPAD_REGISTER, std::bind(&Impl::readJoypad, this, std::placeholders::_1)); - } - - void press(Key key) - { - keys_ &= ~(1 << static_cast(key)); - interrupt_provider_.set(); - } - - void release(Key key) - { - keys_ |= (1 << static_cast(key)); - } - - private: - uint8_t readJoypad(uint16_t) const - { - uint8_t hi = (reg_ & 0xF0); - - if ((hi & 0x30) == 0x10 || (hi & 0x30) == 0x20) - { - // first 2 bits of high nybble is group selection - uint8_t group = ((~(reg_ >> 4)) & 0x03) - 1; - - uint8_t selection = (keys_ >> (group * 4)) & 0x0F; - - return (reg_ & 0xF0) | selection; - } - else - { - return reg_ | 0x0F; - } - } - - private: - MMU& mmu_; - uint8_t& reg_; - uint8_t keys_; - - InterruptProvider interrupt_provider_; - }; - - - /* Public Implementation */ - - Joy::Joy(MMU& mmu) : - impl_(new Impl(mmu)) - { - - } - - Joy::~Joy() - { - delete impl_; - } - - void Joy::press(Key key) - { - impl_->press(key); - } - - void Joy::release(Key key) - { - impl_->release(key); - } -} \ No newline at end of file diff --git a/components/gameboycore/src/link.cpp b/components/gameboycore/src/link.cpp deleted file mode 100644 index 8b876c43..00000000 --- a/components/gameboycore/src/link.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include "gameboycore/link.h" -#include "gameboycore/memorymap.h" -#include "gameboycore/interrupt_provider.h" - -#include "bitutil.h" - -#include -#include // TODO: remove - -namespace gb -{ - /* Private Interface */ - - class Link::Impl - { - public: - - explicit Impl(MMU::Ptr& mmu) : - control_(mmu->get(memorymap::SC_REGISTER)), - byte_to_transfer_(0), - byte_to_recieve_(0), - serial_interrupt_{ *mmu.get(), InterruptProvider::Interrupt::SERIAL }, - shift_clock_(0), - shift_counter_(0), - shift_clock_rate_(0), - pending_recieve_(false) - { - // serial byte handlers - mmu->addReadHandler(memorymap::SB_REGISTER, std::bind(&Impl::recieveHandler, this, std::placeholders::_1)); - mmu->addWriteHandler(memorymap::SB_REGISTER, std::bind(&Impl::sendHandler, this, std::placeholders::_1, std::placeholders::_2)); - - // control callback - mmu->addWriteHandler(memorymap::SC_REGISTER, std::bind(&Impl::control, this, std::placeholders::_1, std::placeholders::_2)); - } - - ~Impl() - { - } - - void update(uint8_t cycles) - { - if (!isTransferring() || pending_recieve_) return; - - // if using internal shift clock, run clocking logic - if (getLinkMode() == Link::Mode::INTERNAL) - { - internalClock(cycles); - } - else - { - // transferring in external clock mode, signal transfer ready - - signalReady(); - } - } - - void internalClock(uint8_t cycles) - { - // increment shift clock - shift_clock_ += cycles; - - if (shift_clock_ >= shift_clock_rate_) - { - shift_clock_ -= shift_clock_rate_; - - shift_counter_++; - - if (shift_counter_ == 8) - { - // signal to the host system that this core is ready to do the transfer - signalReady(); - - shift_counter_ = 0; - } - } - } - - void control(uint8_t value, uint16_t) noexcept - { - control_ = (control_ & 0x80) | 0x02 | value; - - shift_clock_rate_ = getTransferRate(value); - - pending_recieve_ = false; - } - - void sendHandler(uint8_t value, uint16_t) noexcept - { - byte_to_transfer_ = value; - } - - uint8_t recieveHandler(uint16_t) const noexcept - { - return byte_to_recieve_; - } - - /** - Data into the core - */ - void recieve(uint8_t byte) - { - // recieve the byte - byte_to_recieve_ = byte; - // set serial interrupt - serial_interrupt_.set(); - // clear transfer flag - clearMask(control_, memorymap::SC::TRANSFER); - - pending_recieve_ = false; - } - - void setReadyCallback(const ReadyCallback& callback) - { - ready_callback_ = callback; - } - - private: - - bool isTransferring() const noexcept - { - return isSet(control_, memorymap::SC::TRANSFER) != 0; - } - - int getTransferRate(uint8_t sc) - { - // TODO: CGB speed modes - (void)sc; - return 4194304 / 8192; - } - - void signalReady() - { - if (ready_callback_) - { - ready_callback_(byte_to_transfer_, getLinkMode()); - pending_recieve_ = true; - } - } - - Mode getLinkMode() const noexcept - { - if (isSet(control_, memorymap::SC::CLOCK_MODE)) - { - return Mode::INTERNAL; - } - else - { - return Mode::EXTERNAL; - } - } - - private: - //! Serial Control Register - uint8_t& control_; - - //! Byte to be transfered to the opponent gameboy - uint8_t byte_to_transfer_; - //! Byte recieved by the opponent gameboy - uint8_t byte_to_recieve_; - - //! ready callback - ReadyCallback ready_callback_; - - //! Serial interrupt provider - InterruptProvider serial_interrupt_; - - //! Internal Timer - int shift_clock_; - //! Count the shift clock overflows - int shift_counter_; - //! Transfer rate - int shift_clock_rate_; - - //! Flag indicating that the link port is waiting to recieve a byte - bool pending_recieve_; - }; - - /* Public Interface */ - - Link::Link(MMU::Ptr& mmu) : - impl_(new Impl(mmu)) - { - } - - void Link::update(uint8_t cycles) - { - impl_->update(cycles); - } - - void Link::recieve(uint8_t byte) - { - impl_->recieve(byte); - } - - void Link::setReadyCallback(const ReadyCallback& callback) - { - impl_->setReadyCallback(callback); - } - - Link::~Link() - { - delete impl_; - } -} \ No newline at end of file diff --git a/components/gameboycore/src/link_cable.cpp b/components/gameboycore/src/link_cable.cpp deleted file mode 100644 index 00b52abd..00000000 --- a/components/gameboycore/src/link_cable.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include "gameboycore/link_cable.h" - -namespace gb -{ - /* Private Implementation */ - - class LinkCable::Impl - { - public: - //! Contains link ready status, byte to transfer and clocking mode - struct LinkData - { - LinkData() : - mode(Link::Mode::EXTERNAL), - byte(0), - ready(false) - { - } - - Link::Mode mode; - uint8_t byte; - bool ready; - }; - - void link1ReadyCallback(uint8_t byte, Link::Mode mode) - { - link_data1_.byte = byte; - link_data1_.mode = mode; - link_data1_.ready = true; - - update(); - } - - void link2ReadyCallback(uint8_t byte, Link::Mode mode) - { - link_data2_.byte = byte; - link_data2_.mode = mode; - link_data2_.ready = true; - - update(); - } - - void setLink1RecieveCallback(const RecieveCallback& callback) - { - recieve1_ = callback; - } - - void setLink2RecieveCallback(const RecieveCallback& callback) - { - recieve2_ = callback; - } - - private: - void update() - { - if (link_data1_.ready && link_data2_.ready) - { - // both links indicate they are ready to transfer - - if (link_data1_.mode != link_data2_.mode) - { - transfer(); - } - } - else - { - // only one link is ready to tranfer, or neither are - - - if (link_data1_.ready) - { - if (link_data1_.mode == Link::Mode::INTERNAL) - { - // if this link is the master device, supply it with a $FF - link_data2_.byte = 0xFF; - transfer(); - } - } - - if (link_data2_.ready) - { - if (link_data2_.mode == Link::Mode::INTERNAL) - { - link_data1_.byte = 0xFF; - transfer(); - } - } - - } - } - - void transfer() - { - if (recieve1_) - recieve1_(link_data2_.byte); - - if (recieve2_) - recieve2_(link_data1_.byte); - - link_data1_.ready = false; - link_data2_.ready = false; - } - - private: - RecieveCallback recieve1_; - RecieveCallback recieve2_; - - LinkData link_data1_; - LinkData link_data2_; - }; - - /* Public Implementation */ - - LinkCable::LinkCable() : - impl_(new Impl) - { - } - - LinkCable::~LinkCable() - { - delete impl_; - } - - void LinkCable::link1ReadyCallback(uint8_t byte, Link::Mode mode) - { - impl_->link1ReadyCallback(byte, mode); - } - - void LinkCable::link2ReadyCallback(uint8_t byte, Link::Mode mode) - { - impl_->link2ReadyCallback(byte, mode); - } - - void LinkCable::setLink1RecieveCallback(const RecieveCallback& callback) - { - impl_->setLink1RecieveCallback(callback); - } - - void LinkCable::setLink2RecieveCallback(const RecieveCallback& callback) - { - impl_->setLink2RecieveCallback(callback); - } - -} \ No newline at end of file diff --git a/components/gameboycore/src/mbc.cpp b/components/gameboycore/src/mbc.cpp deleted file mode 100644 index 6ab77229..00000000 --- a/components/gameboycore/src/mbc.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include "gameboycore/mbc.h" -#include "gameboycore/memorymap.h" - -#include -#include -#include - -namespace gb -{ - namespace detail - { - MBC::MBC(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable) : - xram_enable_(false), - rom_bank_(0), - ram_bank_(0), - num_rom_banks_(0), - num_cartridge_ram_banks_(0), - cgb_enabled_(cgb_enable), - vram_banks_(0), - num_internal_ram_banks_(0) - { - loadMemory(rom, size, rom_size, ram_size); - } - - void MBC::write(uint8_t value, uint16_t addr) - { - // check for write to ROM - if (addr <= 0x7FFF) - { - control(value, addr); - } - else - { - // get the memory index from the addr - auto idx = getIndex(addr, rom_bank_, ram_bank_); - - // check if writing to external RAM - if (addr >= 0xA000 && addr <= 0xBFFF) - { - // write to external ram if it is enabled - if (xram_enable_) - memory_[idx] = value; - } - else - { - memory_[idx] = value; - } - } - } - - uint8_t MBC::read(uint16_t addr) const - { - // return FF is read from external ram and it is not enabled - if (addr >= 0xA000 && addr <= 0xBFFF && !xram_enable_) - { - return 0xFF; - } - - auto idx = getIndex(addr, rom_bank_, ram_bank_); - return memory_[idx]; - } - - uint8_t MBC::readVram(uint16_t addr, uint8_t bank) - { - auto index = (addr) + (16 * KILO_BYTE * (num_rom_banks_ - 1)) + ((8 * KILO_BYTE) * bank); - return memory_[index]; - } - - uint8_t& MBC::get(uint16_t addr) - { - return memory_[getIndex(addr, rom_bank_, ram_bank_)]; - } - - uint8_t* MBC::getptr(uint16_t addr) - { - return &memory_[getIndex(addr, rom_bank_, ram_bank_)]; - } - - int MBC::resolveAddress(const uint16_t& addr) const - { - return getIndex(addr, rom_bank_, ram_bank_); - } - - std::vector MBC::getRange(uint16_t start, uint16_t end) const - { - auto start_idx = getIndex(start, rom_bank_, ram_bank_); - auto end_idx = getIndex(end, rom_bank_, ram_bank_); - // return std::vector(memory_.begin() + start_idx, memory_.begin() + end_idx); - return std::vector(&memory_[0] + start_idx, &memory_[0] + end_idx); - } - - void MBC::setMemory(uint16_t start, const std::vector& mem) - { - // TODO: error checks - // std::copy(mem.begin(), mem.end(), memory_.begin() + getIndex(start, rom_bank_, ram_bank_)); - std::copy(mem.begin(), mem.end(), &memory_[0] + getIndex(start, rom_bank_, ram_bank_)); - } - - std::vector MBC::getXram() const - { - // index the points around external RAM to capture all bank - auto start = getIndex(memorymap::EXTERNAL_RAM_START, rom_bank_, 0); - auto end = getIndex(memorymap::EXTERNAL_RAM_END, rom_bank_, num_cartridge_ram_banks_ - 1); - - // Copy external RAM range. Add 1 so range [START, END] is inclusive - // return std::vector(memory_.begin() + start, memory_.begin() + end + 1); - return std::vector(&memory_[0] + start, &memory_[0] + end + 1); - } - - int MBC::getRomBank() const - { - return rom_bank_; - } - - int MBC::getRamBank() const - { - return ram_bank_; - } - - bool MBC::isXramEnabled() const - { - return xram_enable_; - } - - int MBC::getIndex(uint16_t addr, int rom_bank, int ram_bank) const - { - switch (addr & 0xF000) - { - case 0x0000: - case 0x1000: - case 0x2000: - case 0x3000: - return addr; - case 0x4000: - case 0x5000: - case 0x6000: - case 0x7000: - return (addr) + (kilo(16) * rom_bank); - case 0x8000: - case 0x9000: - return (addr) + (kilo(16) * (num_rom_banks_-1)) + getVramOffset(); - case 0xA000: - case 0xB000: - return (addr) + (kilo(16) * (num_rom_banks_ - 1)) + (kilo(8) * (vram_banks_ - 1)) + (kilo(8) * ram_bank); - case 0xC000: - return (addr) + (kilo(16) * (num_rom_banks_ - 1)) + (kilo(8) * (vram_banks_ - 1)) + (kilo(8) * (num_cartridge_ram_banks_-1)); - case 0xD000: - return (addr)+(kilo(16) * (num_rom_banks_ - 1)) + (kilo(8) * (vram_banks_ - 1)) + (kilo(8) * (num_cartridge_ram_banks_ - 1)) + getInternalRamOffset(); - case 0xE000: - case 0xF000: - return (addr)+(kilo(16) * (num_rom_banks_ - 1)) + (kilo(8) * (vram_banks_ - 1)) + (kilo(8) * (num_cartridge_ram_banks_ - 1)) + (kilo(4) * (num_internal_ram_banks_-1)); - } - - return 0; - } - - int MBC::getIoIndex(uint16_t addr) const - { - return (addr)+ - (kilo(16) * (num_rom_banks_ - 1)) + - (kilo(8) * (vram_banks_ - 1)) + - (kilo(8) * (num_cartridge_ram_banks_ - 1)) + - (kilo(4)* (num_internal_ram_banks_-1)); - } - - int MBC::getVramOffset() const - { - return kilo(8) * (memory_[getIoIndex(memorymap::VBK_REGISTER)] & 0x01); - } - - int MBC::getInternalRamOffset() const - { - auto bank_number = memory_[getIoIndex(memorymap::SVBK_REGISTER)] & 0x07; - if (bank_number < 2) bank_number = 0; - - return kilo(4) * (bank_number); - } - - void MBC::loadMemory(const uint8_t* rom, std::size_t size, uint8_t rom_size, uint8_t ram_size) - { - // lookup tables for number of ROM banks a cartridge has - static const unsigned int rom_banks1[] = { - 2, 4, 8, 16, 32, 64, 128, 256 - }; - static const unsigned int rom_banks2[] = { - 72, 80, 96 - }; - - if (rom_size <= static_cast(MBC::ROM::MB4)) - { - // look up the total number of banks this cartridge has - auto cartridge_rom_banks = rom_banks1[rom_size]; - // the number of switchable ROM banks is 2 less than the total - // since there are always 2 available in the $0000 - $3FFF range - num_rom_banks_ = cartridge_rom_banks - 1; - } - else - { - // the number of switchable ROM banks is 2 less than the total - // since there are always 2 available in the $0000 - $3FFF range - num_rom_banks_ = rom_banks2[rom_size] - 1; - } - - num_cartridge_ram_banks_ = (static_cast(ram_size) == MBC::XRAM::KB32) ? 4 : 1; - - num_internal_ram_banks_ = (cgb_enabled_) ? 7 : 1; - vram_banks_ = (cgb_enabled_) ? 2 : 1; - - // memory sizes - const auto rom_bank0_fixed = kilo(16); // $0000 - $3FFF - const auto rom_switchable = kilo(16) * num_rom_banks_; // $4000 - $7FFF - const auto vram = kilo(8) * vram_banks_; // $8000 - $9FFF - const auto ram_cartridge_switchable = kilo(8) * num_cartridge_ram_banks_; // $A000 - $B000 - const auto ram_bank0_fixed = kilo(4); // $C000 - $CFFF - const auto ram_internal_switchable = kilo(4) * num_internal_ram_banks_; // $D000 - $DFFF - const auto high_ram = kilo(8); // $E000 - $FFFF - - const auto memory_size = rom_bank0_fixed + rom_switchable + vram + ram_cartridge_switchable + ram_bank0_fixed + ram_internal_switchable + high_ram; - memory_size_ = memory_size; - // memory_.resize(memory_size); - - // std::memcpy((char*)&memory_[0], rom, size); - } - - unsigned int MBC::kilo(unsigned int n) const - { - return KILO_BYTE * n; - } - - std::size_t MBC::getVirtualMemorySize() const - { - // return memory_.size(); - return memory_size_; - } - - MBC::~MBC() - { - } - } -} diff --git a/components/gameboycore/src/mbc1.cpp b/components/gameboycore/src/mbc1.cpp deleted file mode 100644 index 5fd87ca3..00000000 --- a/components/gameboycore/src/mbc1.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "gameboycore/mbc1.h" - -namespace gb -{ - namespace detail - { - MBC1::MBC1(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enabled) : - MBC(rom, size, rom_size, ram_size, cgb_enabled), - rom_bank_lower_bits_(0), - rom_bank_upper_bits_(0), - mode_(MemoryMode::ROM) - { - } - - void MBC1::control(uint8_t value, uint16_t addr) - { - if (addr <= 0x1FFF) - { - xram_enable_ = ((value & 0x0F) == 0x0A); - } - else if (addr >= 0x2000 && addr <= 0x3FFF) - { - rom_bank_lower_bits_ = value & 0x1F; - - if (mode_ == MemoryMode::ROM) - { - selectRomBank(rom_bank_lower_bits_, rom_bank_upper_bits_); - } - else - { - rom_bank_upper_bits_ = 0; - selectRomBank(rom_bank_lower_bits_, rom_bank_upper_bits_); - } - } - else if (addr >= 0x4000 && addr <= 0x5FFF) - { - if (mode_ == MemoryMode::ROM) - { - rom_bank_upper_bits_ = value & 0x03; - selectRomBank(rom_bank_lower_bits_, rom_bank_upper_bits_); - } - else - { - selectRamBank(value & 0x3); - } - } - else if (addr >= 0x6000 && addr <= 0x7FFF) - { - mode_ = static_cast(value & 0x01); - - if (mode_ == MemoryMode::RAM) - { - rom_bank_upper_bits_ = 0; - selectRomBank(rom_bank_lower_bits_, rom_bank_upper_bits_); - } - } - } - - void MBC1::selectRomBank(uint8_t lo, uint8_t hi) - { - auto bank_number = ((hi << 5) | lo); - - // potentially remap the rom bank number - switch (bank_number) - { - case 0x00: - case 0x20: - case 0x40: - case 0x60: - bank_number++; - break; - default: - // ... - break; - } - - rom_bank_ = bank_number - 1; - } - - void MBC1::selectRamBank(uint8_t ram_bank_number) - { - ram_bank_ = ram_bank_number; - } - } -} \ No newline at end of file diff --git a/components/gameboycore/src/mbc2.cpp b/components/gameboycore/src/mbc2.cpp deleted file mode 100644 index ead09bda..00000000 --- a/components/gameboycore/src/mbc2.cpp +++ /dev/null @@ -1,45 +0,0 @@ - -#include "gameboycore/mbc2.h" - -#include "bitutil.h" - -namespace gb -{ - namespace detail - { - MBC2::MBC2(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable) : - MBC(rom, size, rom_size, ram_size, cgb_enable) - { - } - - void MBC2::write(uint8_t value, uint16_t addr) - { - // MBC2 only uses the lower 4 bits - MBC::write(value & 0x0F, addr); - } - - void MBC2::control(uint8_t value, uint16_t addr) - { - if (addr <= 0x1FFF) - { - // least significant bit of upper byte in address must be zero - if (isClear(addr, 0x0100)) - { - xram_enable_ = ((value & 0x0F) == 0x0A); - } - } - else if (addr >= 0x2000 && addr <= 0x3FFF) - { - // least significant bit of upper byte in address must be one - if (isSet(addr, 0x0100)) - { - rom_bank_ = (value & 0x0F) - 1; - } - } - } - - MBC2::~MBC2() - { - } - } -} diff --git a/components/gameboycore/src/mbc3.cpp b/components/gameboycore/src/mbc3.cpp deleted file mode 100644 index 8a8caf73..00000000 --- a/components/gameboycore/src/mbc3.cpp +++ /dev/null @@ -1,78 +0,0 @@ - -#include "gameboycore/mbc3.h" - -namespace gb -{ - namespace detail - { - MBC3::MBC3(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable) - : MBC(rom, size, rom_size, ram_size, cgb_enable) - , latch_ctl_{0} - { - } - - uint8_t MBC3::read(uint16_t addr) const - { - if (addr >= 0xA000 && addr <= 0xBFFF && rtc_.isEnabled()) - { - return rtc_.get(); - } - else - { - return MBC::read(addr); - } - } - - void MBC3::control(uint8_t value, uint16_t addr) - { - if (addr <= 0x1FFF) - { - xram_enable_ = ((value & 0x0F) == 0x0A); - } - else if (addr >= 0x2000 && addr <= 0x3FFF) - { - auto bank_select = (value == 0) ? 1 : value; - rom_bank_ = bank_select - 1; - } - else if (addr >= 0x4000 && addr <= 0x5FFF) - { - // is a RAM bank number - if (value <= 0x03) - { - ram_bank_ = value & 0x0F; - rtc_.setEnable(false); - } - else if (value >= 0x08 && value <= 0x0C) - { - rtc_.setEnable(true); - rtc_.select(value); - } - } - else if(addr >= 0x6000 && addr <= 0x7FFF) - { - if (value == 0x00) - { - latch_ctl_++; - } - else if (latch_ctl_ == 1 && value == 0x01) - { - rtc_.latch(); - latch_ctl_ = 0; - } - else - { - latch_ctl_ = 0; - } - } - } - - void MBC3::setTimeProvider(TimeProvider provider) - { - rtc_.setTimeProvider(provider); - } - - MBC3::~MBC3() - { - } - } -} diff --git a/components/gameboycore/src/mbc5.cpp b/components/gameboycore/src/mbc5.cpp deleted file mode 100644 index 06aa5f46..00000000 --- a/components/gameboycore/src/mbc5.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "gameboycore/mbc5.h" - -namespace gb -{ - namespace detail - { - MBC5::MBC5(const uint8_t* rom, uint32_t size, uint8_t rom_size, uint8_t ram_size, bool cgb_enable) : - MBC(rom, size, rom_size, ram_size, cgb_enable), - rom_bank_lower_bits_(0), - rom_bank_upper_bit_(0) - { - } - - void MBC5::control(uint8_t value, uint16_t addr) - { - if (addr <= 0x1FFF) - { - // enable / disable external ram - xram_enable_ = ((value & 0x0F) == 0x0A); - } - else if (addr >= 0x2000 && addr <= 0x2FFF) - { - // lower 8 bits of rom bank number - rom_bank_lower_bits_ = value; - selectRomBank(rom_bank_lower_bits_, rom_bank_upper_bit_); - } - else if (addr >= 0x3000 && addr <= 0x3FFF) - { - // 9th bit of rom bank number - rom_bank_upper_bit_ = value; - selectRomBank(rom_bank_lower_bits_, rom_bank_upper_bit_); - } - else if (addr >= 0x4000 && addr <= 0x5FFF) - { - // ram bank number - ram_bank_ = value & 0x0F; - } - } - - void MBC5::selectRomBank(uint8_t lo, uint8_t hi) - { - rom_bank_ = ((hi & 0x0001) << 8) | (lo & 0xFFFF); - - if (rom_bank_ > 0) rom_bank_ -= 1; - } - - MBC5::~MBC5() - { - } - } -} \ No newline at end of file diff --git a/components/gameboycore/src/mmu.cpp b/components/gameboycore/src/mmu.cpp deleted file mode 100644 index 888509fa..00000000 --- a/components/gameboycore/src/mmu.cpp +++ /dev/null @@ -1,334 +0,0 @@ - -/** - \author Natesh Narain -*/ - -#include "gameboycore/mmu.h" -#include "gameboycore/mbc.h" -#include "gameboycore/mbc1.h" -#include "gameboycore/mbc2.h" -#include "gameboycore/mbc3.h" -#include "gameboycore/mbc5.h" -#include "gameboycore/cartinfo.h" -#include "gameboycore/memorymap.h" - -#include "bitutil.h" - -#include -#include -#include - -namespace gb -{ - /* Private Interface */ - - class MMU::Impl - { - public: - Impl(const uint8_t* rom, uint32_t size) - : oam_updated_{false} - , cgb_enabled_{false} - { - load(rom, size); - } - - ~Impl() - { - } - - void load(const uint8_t* rom, uint32_t size) - { - CartInfo header = RomParser::parse(rom); - - cgb_enabled_ = header.cgb_enabled; - - switch (static_cast(header.type)) - { - // Supports MBC1 - // Note: MBC1 handles the ROM only case - case detail::MBC::Type::ROM_ONLY: - case detail::MBC::Type::MBC1: - case detail::MBC::Type::MBC1_RAM: - case detail::MBC::Type::MBC1_RAM_BAT: - mbc_.reset(new detail::MBC1(rom, size, header.rom_size, header.ram_size, cgb_enabled_)); - break; - - case detail::MBC::Type::MBC2: - case detail::MBC::Type::MBC2_BAT: - mbc_.reset(new detail::MBC2(rom, size, header.rom_size, header.ram_size, cgb_enabled_)); - break; - - case detail::MBC::Type::MBC3: - case detail::MBC::Type::MBC3_RAM: - case detail::MBC::Type::MBC3_RAM_BAT: - case detail::MBC::Type::MBC3_TIME_BAT: - case detail::MBC::Type::MBC3_TIME_RAM_BAT: - mbc_.reset(new detail::MBC3(rom, size, header.rom_size, header.ram_size, cgb_enabled_)); - break; - - // TODO: MBC4 - case detail::MBC::Type::MBC5: - case detail::MBC::Type::MBC5_RAM: - case detail::MBC::Type::MBC5_RAM_BAT: - case detail::MBC::Type::MBC5_RUMBLE: - case detail::MBC::Type::MBC5_RUMBLE_RAM: - case detail::MBC::Type::MBC5_RUMBLE_RAM_BAT: - mbc_.reset(new detail::MBC5(rom, size, header.rom_size, header.ram_size, cgb_enabled_)); - break; - - default: - throw std::runtime_error("Unsupported cartridge type :("); - break; - } - - // initialize joypad keys to not pressed - mbc_->write(0x0F, memorymap::JOYPAD_REGISTER); - - loadResetValues(); - } - - uint8_t read(uint16_t addr) - { - if (addr >= 0xFF00 && addr <= 0xFF7F && read_handlers_[addr - 0xFF00]) - { - return read_handlers_[addr - 0xFF00](addr); - } - else - { - return mbc_->read(addr); - } - } - - void write(uint8_t value, uint16_t addr) - { - if (addr == memorymap::DMA_REGISTER) - { - oamTransfer(value); - } - else if (addr == memorymap::JOYPAD_REGISTER) - { - mbc_->write(value | 0x0F, addr); - } - else if (addr == memorymap::DIVIDER_REGISER) - { - mbc_->write(0, addr); - } - else - { - if (addr >= 0xFF00 && addr <= 0xFF7F && write_handlers_[addr - 0xFF00]) - { - write_handlers_[addr - 0xFF00](value, addr); - } - else - { - mbc_->write(value, addr); - } - } - } - - void write(uint16_t value, uint16_t addr) - { - uint8_t hi = (value & 0xFF00) >> 8; - uint8_t lo = (value & 0x00FF); - - write(lo, addr + 0); - write(hi, addr + 1); - } - - uint8_t readVram(uint16_t addr, uint8_t bank) - { - return (cgb_enabled_ || bank == 0) ? mbc_->readVram(addr, bank) : 0; - } - - void dma(uint16_t dest, uint16_t src, uint16_t n) - { - while (n--) - { - write(read(src++), dest++); - } - } - - void oamTransfer(uint8_t base) - { - // increments of $100 bytes - uint16_t addr = ((base & 0x00FF) << 8); - // copy to OAM - std::memcpy(mbc_->getptr(memorymap::OAM_START), mbc_->getptr(addr), memorymap::OAM_END - memorymap::OAM_START); - - // set flag indicating oam transfer has taken place - oam_updated_ = true; - } - - std::vector getBatteryRam() const - { - return mbc_->getXram(); - } - - void setBatteryRam(const std::vector& battery_ram) - { - mbc_->setMemory(memorymap::EXTERNAL_RAM_START, battery_ram); - } - - void setTimeProvider(const TimeProvider provider) - { - // The time provider is only valid for MBC3 - if (auto mbc_ptr = static_cast(mbc_.get())) - { - mbc_ptr->setTimeProvider(provider); - } - } - - int resolveAddress(const uint16_t& addr) const - { - return mbc_->resolveAddress(addr); - } - - void loadResetValues() - { - // load reset values into registers - mbc_->write(0x00, memorymap::TIMER_COUNTER_REGISTER); - mbc_->write(0x00, memorymap::TIMER_MODULO_REGISTER); - mbc_->write(0x00, memorymap::TIMER_CONTROLLER_REGISTER); - - mbc_->write(0x80, memorymap::NR10_REGISTER); - mbc_->write(0xBF, memorymap::NR11_REGISTER); - mbc_->write(0xF3, memorymap::NR12_REGISTER); - mbc_->write(0xBF, memorymap::NR14_REGISTER); - mbc_->write(0x3F, memorymap::NR21_REGISTER); - mbc_->write(0x00, memorymap::NR22_REGISTER); - mbc_->write(0xBF, memorymap::NR24_REGISTER); - mbc_->write(0x7F, memorymap::NR30_REGISTER); - mbc_->write(0xFF, memorymap::NR31_REGISTER); - mbc_->write(0x9F, memorymap::NR32_REGISTER); - mbc_->write(0xBF, memorymap::NR33_REGISTER); - mbc_->write(0xFF, memorymap::NR41_REGISTER); - mbc_->write(0x00, memorymap::NR42_REGISTER); - mbc_->write(0x00, memorymap::NR43_REGISTER); - mbc_->write(0xBF, memorymap::NR44_REGISTER); - mbc_->write(0x77, memorymap::NR50_REGISTER); - mbc_->write(0xF3, memorymap::NR51_REGISTER); - mbc_->write(0xF1, memorymap::NR52_REGISTER); // TODO: super gameboy mode - - mbc_->write(0x91, memorymap::LCDC_REGISTER); - mbc_->write(0x00, memorymap::SCY_REGISTER); - mbc_->write(0x00, memorymap::SCX_REGISTER); - mbc_->write(0x00, memorymap::LYC_REGISTER); - mbc_->write(0xFC, memorymap::BGP_REGISTER); - mbc_->write(0xFF, memorymap::OBP0_REGISTER); - mbc_->write(0xFF, memorymap::OBP1_REGISTER); - mbc_->write(0x00, memorymap::WX_REGISTER); - mbc_->write(0x00, memorymap::WY_REGISTER); - mbc_->write(0x00, memorymap::INTERRUPT_ENABLE); - } - - public: - detail::MBC::Ptr mbc_; - - std::array write_handlers_; - std::array read_handlers_; - - bool oam_updated_; - bool cgb_enabled_; - }; - - - /* Public Interface */ - - MMU::MMU(const uint8_t* rom, uint32_t size) : - impl_(new Impl(rom, size)) - { - } - - MMU::~MMU() - { - delete impl_; - } - - uint8_t MMU::read(uint16_t addr) const - { - return impl_->mbc_->read(addr); - } - - uint8_t MMU::read(uint16_t addr) - { - return impl_->read(addr); - } - - void MMU::write(uint8_t value, uint16_t addr) - { - impl_->write(value, addr); - } - - void MMU::write(uint16_t value, uint16_t addr) - { - impl_->write(value, addr); - } - - uint8_t MMU::readVram(uint16_t addr, uint8_t bank) - { - return impl_->readVram(addr, bank); - } - - void MMU::dma(uint16_t dest, uint16_t src, uint16_t n) - { - impl_->dma(dest, src, n); - } - - void MMU::addWriteHandler(uint16_t addr, MemoryWriteHandler handler) - { - impl_->write_handlers_[addr - 0xFF00] = handler; - } - - void MMU::addReadHandler(uint16_t addr, MemoryReadHandler handler) - { - impl_->read_handlers_[addr - 0xFF00] = handler; - } - - std::vector MMU::getBatteryRam() const - { - return impl_->getBatteryRam(); - } - - void MMU::setBatteryRam(const std::vector& battery_ram) - { - impl_->setBatteryRam(battery_ram); - } - - void MMU::setTimeProvider(const TimeProvider provider) - { - impl_->setTimeProvider(provider); - } - - bool MMU::getOamTransferStatus() const - { - bool ret = impl_->oam_updated_; - impl_->oam_updated_ = false; - - return ret; - } - - bool MMU::cgbEnabled() const - { - return impl_->cgb_enabled_; - } - - uint8_t& MMU::get(uint16_t addr) - { - return impl_->mbc_->get(addr); - } - - uint8_t* MMU::getptr(uint16_t addr) - { - return impl_->mbc_->getptr(addr); - } - - int MMU::resolveAddress(const uint16_t& addr) const - { - return impl_->resolveAddress(addr); - } - - std::size_t MMU::getVirtualMemorySize() const - { - return impl_->mbc_->getVirtualMemorySize(); - } -} diff --git a/components/gameboycore/src/oam.cpp b/components/gameboycore/src/oam.cpp deleted file mode 100644 index bc74cf13..00000000 --- a/components/gameboycore/src/oam.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "gameboycore/oam.h" -#include "bitutil.h" - -namespace gb -{ - OAM::OAM(MMU& mmu) : - mmu_(mmu) - { - } - - Sprite OAM::getSprite(std::size_t idx) const - { - // get location of sprite in memory - auto sprite_base = uint16_t(memorymap::OAM_START + (idx * 4)); - - auto ptr = mmu_.getptr(sprite_base); - - // read OAM attributes from OAM table - Sprite sprite; - sprite.y = ptr[0]; - sprite.x = ptr[1]; - sprite.tile = ptr[2]; - sprite.attr = ptr[3]; - - return sprite; - } - - std::array OAM::getSprites() const - { - // check if sprites are 8x16 or 8x8 - auto lcdc = mmu_.read(memorymap::LCDC_REGISTER); - const bool mode_8x16 = isSet(lcdc, memorymap::LCDC::OBJ_8x16) != 0; - - std::array sprites; - - for (auto i = 0u; i < sprites.size(); ++i) - { - auto& sprite = sprites[i]; - sprite = getSprite(i); - - if (mode_8x16) - { - sprite.height = 16; - } - else - { - sprite.height = 8; - } - } - - return sprites; - } - - OAM::~OAM() - { - } -} \ No newline at end of file diff --git a/components/gameboycore/src/opcodeinfo.cpp b/components/gameboycore/src/opcodeinfo.cpp deleted file mode 100644 index 44aac093..00000000 --- a/components/gameboycore/src/opcodeinfo.cpp +++ /dev/null @@ -1,585 +0,0 @@ - -#include "gameboycore/opcodeinfo.h" - -namespace gb -{ - static const OpcodeInfo opcodeinfo1[] = { - { 4, "nop" }, // 0x00 - { 12, "ld BC,%04X", OperandType::IMM16 }, // 0x01 - { 8, "ld (BC),A" }, // 0x02 - { 8, "inc BC" }, // 0x03 - { 4, "inc B" }, // 0x04 - { 4, "dec B" }, // 0x05 - { 8, "ld B,%02X", OperandType::IMM8 }, // 0x06 - { 4, "rlca", }, // 0x07 - { 20, "ld (%04X)SP", OperandType::IMM16 }, // 0x08 - { 8, "add HL,BC", }, // 0x09 - { 8, "ld A,(BC)", }, // 0x0A - { 4, "dec BC" }, // 0x0B - { 4, "inc C" }, // 0x0C - { 4, "dec C" }, // 0x0D - { 8, "ld C,%02X", OperandType::IMM8 }, // 0x0E - { 4, "rrca", }, // 0x0F - - { 4, "stop %02X", OperandType::IMM8 }, // 0x10 - { 12, "ld DE,%04X", OperandType::IMM16 }, // 0x11 - { 8, "ld (DE),A", }, // 0x12 - { 8, "inc DE", }, // 0x13 - { 4, "inc D", }, // 0x14 - { 4, "dec D", }, // 0x15 - { 8, "ld D,%02X", OperandType::IMM8 }, // 0x16 - { 4, "rla", }, // 0x17 - { 12, "jr %02X", OperandType::IMM8 }, // 0x18 - { 8, "add HL,DE", }, // 0x19 - { 8, "ld A,(DE)", }, // 0x1A - { 8, "dec DE", }, // 0x1B - { 4, "inc E", }, // 0x1C - { 4, "dec E", }, // 0x1D - { 8, "ld E,%02X", OperandType::IMM8 }, // 0x1E - { 4, "rra", }, // 0x1F - - { 8, "jr NZ,%02X", OperandType::IMM8 }, // 0x20 - { 12, "ld HL,%04X", OperandType::IMM16 }, // 0x21 - { 8, "ld (HL+),A", }, // 0x22 - { 8, "inc HL", }, // 0x23 - { 4, "inc H", }, // 0x24 - { 4, "dec H", }, // 0x25 - { 8, "ld H,%02X", OperandType::IMM8 }, // 0x26 - { 4, "daa", }, // 0x27 - { 8, "jr Z,%02X", OperandType::IMM8 }, // 0x28 - { 8, "add HL,HL", }, // 0x29 - { 8, "ld A,(HL+)", }, // 0x2A - { 8, "dec HL", }, // 0x2B - { 4, "inc L", }, // 0x2C - { 4, "dec L", }, // 0x2D - { 8, "ld L,%02X", OperandType::IMM8 }, // 0x2E - { 4, "cpl", }, // 0x2F - - { 8, "jr NC,%02X", OperandType::IMM8 }, // 0x30 - { 12, "ld SP,%04X", OperandType::IMM16 }, // 0x31 - { 8, "ld (HL-),A", }, // 0x32 - { 8, "inc SP", }, // 0x33 - { 12, "inc (HL)", }, // 0x34 - { 12, "dec (HL)", }, // 0x35 - { 12, "ld (HL),%02X", OperandType::IMM8 }, // 0x36 - { 4, "scf", }, // 0x37 - { 8, "jr C,%02X", OperandType::IMM8 }, // 0x38 - { 8, "add HL,SP", }, // 0x39 - { 8, "ld A,(HL-)", }, // 0x3A - { 8, "dec SP", }, // 0x3B - { 4, "inc A", }, // 0x3C - { 4, "dec A", }, // 0x3D - { 8, "ld A,%02X", OperandType::IMM8 }, // 0x3E - { 4, "ccf", }, // 0x3F - - { 4, "ld B,B", }, // 0x40 - { 4, "ld B,C", }, // 0x41 - { 4, "ld B,D", }, // 0x42 - { 4, "ld B,E", }, // 0x43 - { 4, "ld B,H", }, // 0x44 - { 4, "ld B,L", }, // 0x45 - { 8, "ld B,(HL)", }, // 0x46 - { 4, "ld B,A", }, // 0x47 - { 4, "ld C,B", }, // 0x48 - { 4, "ld C,C", }, // 0x49 - { 4, "ld C,D", }, // 0x4A - { 4, "ld C,E", }, // 0x4B - { 4, "ld C,H", }, // 0x4C - { 4, "ld C,L", }, // 0x4D - { 8, "ld C,(HL)", }, // 0x4E - { 4, "ld C,A", }, // 0x4F - - { 4, "ld D,B", }, // 0x50 - { 4, "ld D,C", }, // 0x51 - { 4, "ld D,D", }, // 0x52 - { 4, "ld D,E", }, // 0x53 - { 4, "ld D,H", }, // 0x54 - { 4, "ld D,L", }, // 0x55 - { 8, "ld D,(HL)", }, // 0x56 - { 4, "ld D,A", }, // 0x57 - { 4, "ld E,B", }, // 0x58 - { 4, "ld E,C", }, // 0x59 - { 4, "ld E,D", }, // 0x5A - { 4, "ld E,E", }, // 0x5B - { 4, "ld E,H", }, // 0x5C - { 4, "ld E,L", }, // 0x5D - { 8, "ld E,(HL)", }, // 0x5E - { 4, "ld E,A", }, // 0x5F - - { 4, "ld H,B", }, // 0x60 - { 4, "ld H,C", }, // 0x61 - { 4, "ld H,D", }, // 0x62 - { 4, "ld H,E", }, // 0x63 - { 4, "ld H,H", }, // 0x64 - { 4, "ld H,L", }, // 0x65 - { 8, "ld H,(HL)", }, // 0x66 - { 4, "ld H,A", }, // 0x67 - { 4, "ld L,B", }, // 0x68 - { 4, "ld L,C", }, // 0x69 - { 4, "ld L,D", }, // 0x6A - { 4, "ld L,E", }, // 0x6B - { 4, "ld L,H", }, // 0x6C - { 4, "ld L,L", }, // 0x6D - { 8, "ld L,(HL)", }, // 0x6E - { 4, "ld L,A", }, // 0x6F - - { 8, "ld (HL),B", }, // 0x70 - { 8, "ld (HL),C", }, // 0x71 - { 8, "ld (HL),D", }, // 0x72 - { 8, "ld (HL),E", }, // 0x73 - { 8, "ld (HL),H", }, // 0x74 - { 8, "ld (HL),L", }, // 0x75 - { 4, "halt", }, // 0x76 - { 8, "ld (HL),A", }, // 0x77 - { 4, "ld A,B", }, // 0x78 - { 4, "ld A,C", }, // 0x79 - { 4, "ld A,D", }, // 0x7A - { 4, "ld A,E", }, // 0x7B - { 4, "ld A,H", }, // 0x7C - { 4, "ld A,L", }, // 0x7D - { 4, "ld A,(HL)", }, // 0x7E - { 4, "ld A,A", }, // 0x7F - - { 4, "add A,B", }, // 0x80 - { 4, "add A,C", }, // 0x81 - { 4, "add A,D", }, // 0x82 - { 4, "add A,E", }, // 0x83 - { 4, "add A,H", }, // 0x84 - { 4, "add A,L", }, // 0x85 - { 8, "add A,(HL)", }, // 0x86 - { 4, "add A,A", }, // 0x87 - { 4, "adc A,B", }, // 0x88 - { 4, "adc A,C", }, // 0x89 - { 4, "adc A,D", }, // 0x8A - { 4, "adc A,E", }, // 0x8B - { 4, "adc A,H", }, // 0x8C - { 4, "adc A,L", }, // 0x8D - { 8, "adc A,(HL)", }, // 0x8E - { 4, "adc A,A", }, // 0x8F - - { 4, "sub B", }, // 0x90 - { 4, "sub C", }, // 0x91 - { 4, "sub D", }, // 0x92 - { 4, "sub E", }, // 0x93 - { 4, "sub H", }, // 0x94 - { 4, "sub L", }, // 0x95 - { 8, "sub (HL)", }, // 0x96 - { 4, "sub A", }, // 0x97 - { 4, "sbc A,B", }, // 0x98 - { 4, "sbc A,C", }, // 0x99 - { 4, "sbc A,D", }, // 0x9A - { 4, "sbc A,E", }, // 0x9B - { 4, "sbc A,H", }, // 0x9C - { 4, "sbc A,L", }, // 0x9D - { 8, "sbc A,(HL)",}, // 0x9E - { 4, "sbc A,A", }, // 0x9F - - { 4, "and B", }, // 0xA0 - { 4, "and C", }, // 0xA1 - { 4, "and D", }, // 0xA2 - { 4, "and E", }, // 0xA3 - { 4, "and H", }, // 0xA4 - { 4, "and L", }, // 0xA5 - { 8, "and (HL)", }, // 0xA6 - { 4, "and A", }, // 0xA7 - { 4, "xor B", }, // 0xA8 - { 4, "xor C", }, // 0xA9 - { 4, "xor D", }, // 0xAA - { 4, "xor E", }, // 0xAB - { 4, "xor H", }, // 0xAC - { 4, "xor L", }, // 0xAD - { 8, "xor (HL)", }, // 0xAE - { 4, "xor A", }, // 0xAF - - { 4, "or B", }, // 0xB0 - { 4, "or C", }, // 0xB1 - { 4, "or D", }, // 0xB2 - { 4, "or E", }, // 0xB3 - { 4, "or H", }, // 0xB4 - { 4, "or L", }, // 0xB5 - { 8, "or (HL)", }, // 0xB6 - { 4, "or A", }, // 0xB7 - { 4, "cp B", }, // 0xB8 - { 4, "cp C", }, // 0xB9 - { 4, "cp D", }, // 0xBA - { 4, "cp E", }, // 0xBB - { 4, "cp H", }, // 0xBC - { 4, "cp L", }, // 0xBD - { 4, "cp (HL)", }, // 0xBE - { 4, "cp A", }, // 0xBF - - { 8, "ret NZ", }, // 0xC0 - { 12, "pop BC", }, // 0xC1 - { 12, "jp NZ,%04X", OperandType::IMM16 }, // 0xC2 - { 16, "jp %04X", OperandType::IMM16 }, // 0xC3 - { 12, "call NZ,%04X", OperandType::IMM16 }, // 0xC4 - { 16, "push BC", }, // 0xC5 - { 8, "add A,%02X", OperandType::IMM8 }, // 0xC6 - { 16, "rst 00", }, // 0xC7 - { 8, "ret Z", }, // 0xC8 - { 8, "ret", }, // 0xC9 - { 12, "jp Z,%04X", OperandType::IMM16 }, // 0xCA - { 0, "prefix" }, // 0xCB - { 12, "call Z,%04X", OperandType::IMM16 }, // 0xCC - { 24, "call %04X", OperandType::IMM16 }, // 0xCD - { 8, "adc A,%02X", OperandType::IMM8 }, // 0xCE - { 16, "rst 08h", }, // 0xCF - - { 8, "ret NC", }, // 0xD0 - { 12, "pop DE", }, // 0xD1 - { 12, "jp NC,%04X", OperandType::IMM16 }, // 0xD2 - { 0, "invalid" }, // 0xD3 - { 12, "call NC,%04X", OperandType::IMM16 }, // 0xD4 - { 16, "push DE", }, // 0xD5 - { 8, "sub %02X", OperandType::IMM8 }, // 0xD6 - { 16, "rst 10", }, // 0xD7 - { 8, "ret C", }, // 0xD8 - { 16, "reti", }, // 0xD9 - { 12, "jp C,%04X", OperandType::IMM16 }, // 0xDA - { 0, "invalid" }, // 0xDB - { 12, "call C,%04X", OperandType::IMM16 }, // 0xDC - { 0, "invalid" }, // 0xDD - { 8, "sbc A,%02X", OperandType::IMM8 }, // 0xDE - { 16, "rst 18", }, // 0xDF - - { 12, "ldh (%02X),A", OperandType:: IMM8}, // 0xE0 - { 12, "pop HL", }, // 0xE1 - { 8, "ld (C),A", }, // 0xE2 - { 0, "invalid" }, // 0xE3 - { 0, "invalid" }, // 0xE4 - { 16, "push HL", }, // 0xE5 - { 8, "and %02X", OperandType::IMM8 }, // 0xE6 - { 16, "rst 20", }, // 0xE7 - { 8, "add SP,%02X", OperandType::IMM8 }, // 0xE8 - { 4, "jp (HL)", }, // 0xE9 - { 16, "ld (%04X),A", OperandType:: IMM16}, // 0xEA - { 0, "invalid" }, // 0xEB - { 0, "invalid" }, // 0xEC - { 0, "invalid" }, // 0xED - { 8, "xor %02X", OperandType::IMM8 }, // 0xEE - { 16, "rst 28", }, // 0xEF - - { 12, "ldh A,(%02X)", OperandType::IMM8 }, // 0xF0 - { 12, "pop AF", }, // 0xF1 - { 8, "ld (A),C", }, // 0xF2 - { 4, "di", }, // 0xF3 - { 0, "invalid" }, // 0xF4 - { 16, "push AF", }, // 0xF5 - { 8, "or %02X", OperandType::IMM8 }, // 0xF6 - { 16, "rst 30", }, // 0xF7 - { 12, "ld HL,SP+r8", }, // 0xF8 - { 8, "ld SP,HL", }, // 0xF9 - { 16, "ld A,(%04X)", OperandType::IMM16 }, // 0xFA - { 4, "ei", }, // 0xFB - { 0, "invalid" }, // 0xFC - { 0, "invalid" }, // 0xFD - { 8, "cp %02X", OperandType::IMM8 }, // 0xFE - { 16, "rst 38" } // 0xFF - }; - - static const OpcodeInfo opcodeinfo2[] = { - { 8, "RLC B" }, // 00 - { 8, "RLC C" }, // 01 - { 8, "RLC D" }, // 02 - { 8, "RLC E" }, // 03 - { 8, "RLC H" }, // 04 - { 8, "RLC L" }, // 05 - { 16, "RLC (HL)" }, // 06 - { 8, "RLC A" }, // 07 - - { 8, "RRC B" }, // 08 - { 8, "RRC C" }, // 09 - { 8, "RRC D" }, // 0A - { 8, "RRC E" }, // 0B - { 8, "RRC H" }, // 0C - { 8, "RRC L" }, // 0D - { 16, "RRC (HL)" }, // 0E - { 8, "RRC A" }, // 0F - - { 8, "RL B" }, // 10 - { 8, "RL C" }, // 11 - { 8, "RL D" }, // 12 - { 8, "RL E" }, - { 8, "RL H" }, - { 8, "RL L" }, - { 16, "RL (HL)" }, - { 8, "RL A" }, - - { 8, "RR B" }, - { 8, "RR C" }, - { 8, "RR D" }, - { 8, "RR E" }, - { 8, "RR H" }, - { 8, "RR L" }, - { 16, "RR (HL)" }, - { 8, "RR A" }, - - { 8, "SLA B" }, - { 8, "SLA C" }, - { 8, "SLA D" }, - { 8, "SLA E" }, - { 8, "SLA H" }, - { 8, "SLA L" }, - { 16, "SLA (HL)" }, - { 8, "SLA A" }, - - { 8, "SRA B" }, - { 8, "SRA C" }, - { 8, "SRA D" }, - { 8, "SRA E" }, - { 8, "SRA H" }, - { 8, "SRA L" }, - { 16, "SRA (HL)" }, - { 8, "SRA A" }, - - { 8, "SWAP B" }, - { 8, "SWAP C" }, - { 8, "SWAP D" }, - { 8, "SWAP E" }, - { 8, "SWAP H" }, - { 8, "SWAP L" }, - { 16, "SWAP (HL)" }, - { 8, "SWAP A" }, - - { 8, "SRL B" }, - { 8, "SRL C" }, - { 8, "SRL D" }, - { 8, "SRL E" }, - { 8, "SRL H" }, - { 8, "SRL L" }, - { 16, "SRL (HL)" }, - { 8, "SRL A" }, - - { 8, "BIT 0,B" }, - { 8, "BIT 0,C" }, - { 8, "BIT 0,D" }, - { 8, "BIT 0,E" }, - { 8, "BIT 0,H" }, - { 8, "BIT 0,L" }, - { 16, "BIT 0,(HL)" }, - { 8, "BIT 0,A" }, - - { 8, "BIT 1,B" }, - { 8, "BIT 1,C" }, - { 8, "BIT 1,D" }, - { 8, "BIT 1,E" }, - { 8, "BIT 1,H" }, - { 8, "BIT 1,L" }, - { 16, "BIT 1,(HL)" }, - { 8, "BIT 1,A" }, - - { 8, "BIT 2,B" }, - { 8, "BIT 2,C" }, - { 8, "BIT 2,D" }, - { 8, "BIT 2,E" }, - { 8, "BIT 2,H" }, - { 8, "BIT 2,L" }, - { 16, "BIT 2,(HL)" }, - { 8, "BIT 2,A" }, - - { 8, "BIT 3,B" }, - { 8, "BIT 3,C" }, - { 8, "BIT 3,D" }, - { 8, "BIT 3,E" }, - { 8, "BIT 3,H" }, - { 8, "BIT 3,L" }, - { 16, "BIT 3,(HL)" }, - { 8, "BIT 3,A" }, - - { 8, "BIT 4,B" }, - { 8, "BIT 4,C" }, - { 8, "BIT 4,D" }, - { 8, "BIT 4,E" }, - { 8, "BIT 4,H" }, - { 8, "BIT 4,L" }, - { 16, "BIT 4,(HL)" }, - { 8, "BIT 4,A" }, - - { 8, "BIT 5,B" }, - { 8, "BIT 5,C" }, - { 8, "BIT 5,D" }, - { 8, "BIT 5,E" }, - { 8, "BIT 5,H" }, - { 8, "BIT 5,L" }, - { 16, "BIT 5,(HL)" }, - { 8, "BIT 5,A" }, - - { 8, "BIT 6,B" }, - { 8, "BIT 6,C" }, - { 8, "BIT 6,D" }, - { 8, "BIT 6,E" }, - { 8, "BIT 6,H" }, - { 8, "BIT 6,L" }, - { 16, "BIT 6,(HL)" }, - { 8, "BIT 6,A" }, - - { 8, "BIT 7,B" }, - { 8, "BIT 7,C" }, - { 8, "BIT 7,D" }, - { 8, "BIT 7,E" }, - { 8, "BIT 7,H" }, - { 8, "BIT 7,L" }, - { 16, "BIT 7,(HL)" }, - { 8, "BIT 7,A" }, - - // - - { 8, "RES 0,B" }, - { 8, "RES 0,C" }, - { 8, "RES 0,D" }, - { 8, "RES 0,E" }, - { 8, "RES 0,H" }, - { 8, "RES 0,L" }, - { 16, "RES 0,(HL)" }, - { 8, "RES 0,A" }, - - { 8, "RES 1,B" }, - { 8, "RES 1,C" }, - { 8, "RES 1,D" }, - { 8, "RES 1,E" }, - { 8, "RES 1,H" }, - { 8, "RES 1,L" }, - { 16, "RES 1,(HL)" }, - { 8, "RES 1,A" }, - - { 8, "RES 2,B" }, - { 8, "RES 2,C" }, - { 8, "RES 2,D" }, - { 8, "RES 2,E" }, - { 8, "RES 2,H" }, - { 8, "RES 2,L" }, - { 16, "RES 2,(HL)" }, - { 8, "RES 2,A" }, - - { 8, "RES 3,B" }, - { 8, "RES 3,C" }, - { 8, "RES 3,D" }, - { 8, "RES 3,E" }, - { 8, "RES 3,H" }, - { 8, "RES 3,L" }, - { 16, "RES 3,(HL)" }, - { 8, "RES 3,A" }, - - { 8, "RES 4,B" }, - { 8, "RES 4,C" }, - { 8, "RES 4,D" }, - { 8, "RES 4,E" }, - { 8, "RES 4,H" }, - { 8, "RES 4,L" }, - { 16, "RES 4,(HL)" }, - { 8, "RES 4,A" }, - - { 8, "RES 5,B" }, - { 8, "RES 5,C" }, - { 8, "RES 5,D" }, - { 8, "RES 5,E" }, - { 8, "RES 5,H" }, - { 8, "RES 5,L" }, - { 16, "RES 5,(HL)" }, - { 8, "RES 5,A" }, - - { 8, "RES 6,B" }, - { 8, "RES 6,C" }, - { 8, "RES 6,D" }, - { 8, "RES 6,E" }, - { 8, "RES 6,H" }, - { 8, "RES 6,L" }, - { 16, "RES 6,(HL)" }, - { 8, "RES 6,A" }, - - { 8, "RES 7,B" }, - { 8, "RES 7,C" }, - { 8, "RES 7,D" }, - { 8, "RES 7,E" }, - { 8, "RES 7,H" }, - { 8, "RES 7,L" }, - { 16, "RES 7,(HL)" }, - { 8, "RES 7,A" }, - // - - { 8, "SET 0,B" }, - { 8, "SET 0,C" }, - { 8, "SET 0,D" }, - { 8, "SET 0,E" }, - { 8, "SET 0,H" }, - { 8, "SET 0,L" }, - { 16, "SET 0,(HL)" }, - { 8, "SET 0,A" }, - - { 8, "SET 1,B" }, - { 8, "SET 1,C" }, - { 8, "SET 1,D" }, - { 8, "SET 1,E" }, - { 8, "SET 1,H" }, - { 8, "SET 1,L" }, - { 16, "SET 1,(HL)" }, - { 8, "SET 1,A" }, - - { 8, "SET 2,B" }, - { 8, "SET 2,C" }, - { 8, "SET 2,D" }, - { 8, "SET 2,E" }, - { 8, "SET 2,H" }, - { 8, "SET 2,L" }, - { 16, "SET 2,(HL)" }, - { 8, "SET 2,A" }, - - { 8, "SET 3,B" }, - { 8, "SET 3,C" }, - { 8, "SET 3,D" }, - { 8, "SET 3,E" }, - { 8, "SET 3,H" }, - { 8, "SET 3,L" }, - { 16, "SET 3,(HL)" }, - { 8, "SET 3,A" }, - - { 8, "SET 4,B" }, - { 8, "SET 4,C" }, - { 8, "SET 4,D" }, - { 8, "SET 4,E" }, - { 8, "SET 4,H" }, - { 8, "SET 4,L" }, - { 16, "SET 4,(HL)" }, - { 8, "SET 4,A" }, - - { 8, "SET 5,B" }, - { 8, "SET 5,C" }, - { 8, "SET 5,D" }, - { 8, "SET 5,E" }, - { 8, "SET 5,H" }, - { 8, "SET 5,L" }, - { 16, "SET 5,(HL)" }, - { 8, "SET 5,A" }, - - { 8, "SET 6,B" }, - { 8, "SET 6,C" }, - { 8, "SET 6,D" }, - { 8, "SET 6,E" }, - { 8, "SET 6,H" }, - { 8, "SET 6,L" }, - { 16, "SET 6,(HL)" }, - { 8, "SET 6,A" }, - - { 8, "SET 7,B" }, - { 8, "SET 7,C" }, - { 8, "SET 7,D" }, - { 8, "SET 7,E" }, - { 8, "SET 7,H" }, - { 8, "SET 7,L" }, - { 16, "SET 7,(HL)" }, - { 8, "SET 7,A" }, - - }; - - OpcodeInfo getOpcodeInfo(uint8_t opcode, OpcodePage page) - { - if (page == OpcodePage::PAGE1) - { - return opcodeinfo1[opcode]; - } - else // page == OpcodePage::PAGE2 - { - return opcodeinfo2[opcode]; - } - } -} diff --git a/components/gameboycore/src/shiftrotate.cpp b/components/gameboycore/src/shiftrotate.cpp deleted file mode 100644 index 1af8d4e9..00000000 --- a/components/gameboycore/src/shiftrotate.cpp +++ /dev/null @@ -1,205 +0,0 @@ - -#include "shiftrotate.h" -#include "bitutil.h" - -#define C_BIT 4 -#define C_MASK (1 << C_BIT) - -#define Z_BIT 7 -#define Z_MASK (1 << Z_BIT) - -namespace gb -{ - static void setFlag(uint8_t& flags, uint8_t mask, bool set) - { - if (set) - { - setMask(flags, mask); - } - else - { - clearMask(flags, mask); - } - } - - uint8_t rlca(uint8_t val, uint8_t& flags) - { - uint8_t r = 0; - - uint8_t bit7 = (isBitSet(val, 7)) ? 1 : 0; - - r = (val << 1) | bit7; - - flags = 0; // clear N, Z and H - // flags |= (bit7 << C_BIT); - setFlag(flags, C_MASK, bit7 == 1); - - return r; - } - - uint8_t rla(uint8_t val, uint8_t& flags) - { - uint8_t r = 0; - uint8_t c = (isBitSet(flags, C_BIT)) ? 1 : 0; - - uint8_t bit7 = (isBitSet(val, 7)) ? 1 : 0; - - r = (val << 1) | c; - - flags = 0; - flags |= (bit7 << C_BIT); - - return r; - } - - - uint8_t rrca(uint8_t val, uint8_t& flags) - { - uint8_t r = 0; - - uint8_t bit0 = (isBitSet(val, 0)) ? 1 : 0; - - r = (val >> 1) | (bit0 << 7); - - flags = 0; // clear N, Z and H - flags |= (bit0 << C_BIT); - - return r; - } - - uint8_t rra(uint8_t val, uint8_t& flags) - { - uint8_t r = 0; - uint8_t c = (isBitSet(flags, C_BIT)) ? 1 : 0; - - uint8_t bit0 = (isBitSet(val, 0)) ? 1 : 0; - - r = (val >> 1) | (c << 7); - - flags = 0; - flags |= (bit0 << C_BIT); - - return r; - } - - uint8_t rotateLeft(uint8_t val, uint8_t n, uint8_t& flags) - { - uint8_t r = 0; - - uint8_t bit7 = (isBitSet(val, 7)) ? 1 : 0; - - r = (val << n) | bit7; - - flags = 0; // clear N, Z and H - //flags |= (bit7 << C_BIT); - - setFlag(flags, C_MASK, bit7 == 1); - setFlag(flags, Z_MASK, r == 0); - - return r; - } - - uint8_t rotateLeftCarry(uint8_t val, uint8_t n, uint8_t& flags) - { - uint8_t r = 0; - uint8_t c = (isBitSet(flags, C_BIT)) ? 1 : 0; - - uint8_t bit7 = (isBitSet(val, 7)) ? 1 : 0; - - r = (val << n) | c; - - flags = 0; - //flags |= (bit7 << C_BIT); - - setFlag(flags, C_MASK, bit7 == 1); - setFlag(flags, Z_MASK, r == 0); - - return r; - } - - uint8_t rotateRight(uint8_t val, uint8_t n, uint8_t& flags) - { - uint8_t r = 0; - - uint8_t bit0 = (isBitSet(val, 0)) ? 1 : 0; - - r = (val >> n) | (bit0 << 7); - - flags = 0; // clear N, Z and H - //flags |= (bit0 << C_BIT); - - setFlag(flags, C_MASK, bit0 == 1); - setFlag(flags, Z_MASK, r == 0); - - return r; - } - - uint8_t rotateRightCarry(uint8_t val, uint8_t n, uint8_t& flags) - { - uint8_t r = 0; - uint8_t c = (isBitSet(flags, C_BIT)) ? 1 : 0; - - uint8_t bit0 = (isBitSet(val, 0)) ? 1 : 0; - - r = (val >> n) | (c << 7); - - flags = 0; - //flags |= (bit0 << C_BIT); - - setFlag(flags, C_MASK, bit0 == 1); - setFlag(flags, Z_MASK, r == 0); - - return r; - } - - uint8_t shiftLeft(uint8_t val, uint8_t n, uint8_t& flags) - { - uint8_t r = 0; - uint8_t bit7 = (isBitSet(val, 7)) ? 1 : 0; - - r = (val << n); - - flags = 0; - setFlag(flags, C_MASK, bit7 == 1); - setFlag(flags, Z_MASK, r == 0); - - return r; - } - - uint8_t shiftRightA(uint8_t val, uint8_t n, uint8_t& flags) - { - uint8_t r = 0; - uint8_t bit0 = (isBitSet(val, 0)) ? 1 : 0; - - r = (val >> n) | (val & 0x80); - - flags = 0; - // flags |= (bit0 << C_BIT); - - // if (r == 0) flags |= Z_MASK; - - setFlag(flags, C_MASK, bit0 == 1); - setFlag(flags, Z_MASK, r == 0); - - return r; - } - - uint8_t shiftRightL(uint8_t val, uint8_t n, uint8_t& flags) - { - uint8_t r = 0; - uint8_t bit0 = (isBitSet(val, 0)) ? 1 : 0; - - r = (val >> n); - - flags = 0; - // flags |= (bit0 << C_BIT); - - // if (r == 0) flags |= Z_MASK; - - setFlag(flags, C_MASK, bit0 == 1); - setFlag(flags, Z_MASK, r == 0); - - return r; - } - -} diff --git a/components/gameboycore/src/shiftrotate.h b/components/gameboycore/src/shiftrotate.h deleted file mode 100644 index e7fe34b0..00000000 --- a/components/gameboycore/src/shiftrotate.h +++ /dev/null @@ -1,55 +0,0 @@ - -/** - @author Natesh Narain -*/ - -#ifndef GAMEBOYCORE_SHIFT_ROTATE_H -#define GAMEBOYCORE_SHIFT_ROTATE_H - -#include - -namespace gb -{ - uint8_t rlca(uint8_t val, uint8_t& flags); - - uint8_t rla(uint8_t val, uint8_t& flags); - - - uint8_t rrca(uint8_t val, uint8_t& flags); - - uint8_t rra(uint8_t val, uint8_t& flags); - - /** - Rotate bits left and set carry flags - */ - uint8_t rotateLeft(uint8_t val, uint8_t n, uint8_t& flags); - - /** - Rotate bits left through the carry flag - */ - uint8_t rotateLeftCarry(uint8_t val, uint8_t n, uint8_t& flags); - - /** - Rotate bits right adn set carry flag - */ - uint8_t rotateRight(uint8_t val, uint8_t n, uint8_t& flags); - - /** - Rotate bits right through carry flag - */ - uint8_t rotateRightCarry(uint8_t val, uint8_t n, uint8_t& flags); - - /** - Shift bits left - */ - uint8_t shiftLeft(uint8_t val, uint8_t n, uint8_t& flags); - - /** - Shift bits right. Keep sign bit - */ - uint8_t shiftRightA(uint8_t val, uint8_t n, uint8_t& flags); - - uint8_t shiftRightL(uint8_t val, uint8_t n, uint8_t& flags); -} - -#endif \ No newline at end of file diff --git a/components/gameboycore/src/tilemap.cpp b/components/gameboycore/src/tilemap.cpp deleted file mode 100644 index b35c690b..00000000 --- a/components/gameboycore/src/tilemap.cpp +++ /dev/null @@ -1,284 +0,0 @@ - -#include "gameboycore/tilemap.h" -#include "gameboycore/oam.h" -#include "gameboycore/palette.h" -#include "gameboycore/detail/hash.h" - -#include "bitutil.h" - -#include - -namespace gb -{ - namespace detail - { - TileMap::TileMap(MMU& mmu, Palette& palette) : - tileram_(mmu), - mmu_(mmu), - scx_(mmu.get(memorymap::SCX_REGISTER)), - scy_(mmu.get(memorymap::SCY_REGISTER)), - palette_(palette) - { - } - - TileMap::Line TileMap::getBackground(int line, bool cgb_enable) - { - static constexpr auto tiles_per_row = 32; - static constexpr auto tiles_per_col = 32; - static constexpr auto tile_width = 8; - static constexpr auto tile_height = 8; - - const auto start = getAddress(Map::BACKGROUND); - const auto umode = (mmu_.read(memorymap::LCDC_REGISTER) & memorymap::LCDC::CHARACTER_DATA) != 0; - - TileMap::Line tileline{}; - - // scroll x - const auto scx = mmu_.read(memorymap::SCX_REGISTER); - // scroll y - const auto scy = mmu_.read(memorymap::SCY_REGISTER); - - // starting row given the scroll - const auto tile_row = ((scy + line) / tile_height); - // starting column given the scroll - const auto start_tile_col = scx / tile_width; - auto pixel_row = (scy + line) % tile_height; - - auto idx = 0; - for (auto tile_col = start_tile_col; tile_col < start_tile_col + 21; ++tile_col) - { - // calculate tile address - const auto tile_offset = (uint16_t)(start + (tiles_per_row * (tile_row % tiles_per_row)) + (tile_col % tiles_per_col)); - - // read tile character code from map - const auto tilenum = mmu_.readVram(tile_offset, 0); - // read tile attributes - const auto tileattr = mmu_.readVram(tile_offset, 1); - - // extract tile attributes - const auto palette_number = (cgb_enable) ? (tileattr & 0x07) : 0; - const auto character_bank = (cgb_enable) ? ((tileattr >> 3) & 0x01) : 0; - const auto flip_horizontal = (cgb_enable && (tileattr & 0x20) != 0); - const auto flip_vertical = (cgb_enable && (tileattr & 0x40) != 0); - const auto backgroud_priority = (cgb_enable && (tileattr & 0x80) != 0); - - if (flip_vertical) - pixel_row = tile_height - pixel_row - 1; - - // get the row of the tile the current scan line is on. - auto row = tileram_.getRow(pixel_row, tilenum, umode, (uint8_t)character_bank); - - // horizontally flip the row if the flag is set - if (flip_horizontal) - std::reverse(row.begin(), row.end()); - - // calculate pixel column number - auto pixel_col = tile_col * tile_width; - - // - for (auto i = 0u; i < row.size(); ++i) - { - if (pixel_col >= scx && pixel_col <= scx + 160 && idx < 160) - tileline[idx++] = (uint8_t)(row[i] | (palette_number << 2) | (backgroud_priority << 5)); - - pixel_col++; - } - } - - return tileline; - } - - TileMap::Line TileMap::getWindowOverlay(int line) - { - static constexpr auto tiles_per_row = 32; - static constexpr auto tile_height = 8; - - TileMap::Line tileline{}; - - auto wy = mmu_.read(memorymap::WY_REGISTER); - auto umode = (mmu_.read(memorymap::LCDC_REGISTER) & memorymap::LCDC::CHARACTER_DATA) != 0; - - auto window_row = line - wy; - auto tile_row = window_row / tile_height; - auto idx = 0; - - auto start = getAddress(Map::WINDOW_OVERLAY); - - for (auto tile_col = 0; tile_col < 20; ++tile_col) - { - auto tile_offset = start + ((tiles_per_row * tile_row) + tile_col); - auto tilenum = mmu_.read((uint16_t)tile_offset); - - const auto pixel_row = tileram_.getRow(line % tile_height, tilenum, umode); - - for (const auto pixel : pixel_row) - { - tileline[idx++] = pixel; - } - } - - return tileline; - } - - void TileMap::drawSprites( - std::array& scanline, - std::array& info, - int line, - bool cgb_enable, - std::array, 8>& cgb_palette) - { - OAM oam{ mmu_ }; - - auto palette0 = palette_.get(mmu_.read(memorymap::OBP0_REGISTER)); - auto palette1 = palette_.get(mmu_.read(memorymap::OBP1_REGISTER)); - - if (mmu_.getOamTransferStatus()) - { - sprite_cache_ = oam.getSprites(); - } - - auto count = 0; - - for (const auto& sprite : sprite_cache_) - { - if (count > 10) break; - - - // check for out of bounds coordinates - if (sprite.x == 0 || sprite.x >= 168) continue; - if (sprite.y == 0 || sprite.y >= 160) continue; - - auto x = sprite.x - 8; - auto y = sprite.y - 16; - - // check if the sprite contains the line - if (line >= y && line < y + sprite.height) - { - // get the pixel row in tile - auto row = line - y; - - if (sprite.isVerticallyFlipped()) - row = sprite.height - row - 1; - - auto sprite_line = tileram_.getRow(row, sprite.tile, true, sprite.getCharacterBank()); - - if (sprite.isHorizontallyFlipped()) - std::reverse(sprite_line.begin(), sprite_line.end()); - - // get color palette for this sprite - - std::array palette; - - if (cgb_enable) - { - palette = cgb_palette[sprite.getCgbPalette()]; - } - else - { - palette = (sprite.paletteOBP0() == 0) ? palette0 : palette1; - } - - for (auto i = 0; i < 8; ++i) - { - // skip this pixel if outside the window - if ((x + i) < 0 || (x + i) >= 160) continue; - - auto color = info[x + i] & 0x03; - auto background_priority = (bool)(info[x + i] >> 2); - - if (sprite.hasPriority()) - { - if (sprite_line[i] != 0 && !background_priority) - scanline[x + i] = palette[sprite_line[i]]; - } - else - { - // if priority is to the background the sprite is behind colors 1-3 - if (color == 0 && sprite_line[i] != 0) - scanline[x + i] = palette[sprite_line[i]]; - } - - } - - count++; - } - } - } - - uint16_t TileMap::getAddress(Map map) const - { - auto lcdc = mmu_.read(memorymap::LCDC_REGISTER); - - if (map == Map::BACKGROUND) - { - return (isSet(lcdc, memorymap::LCDC::BG_CODE_AREA)) ? 0x9C00 : 0x9800; - } - else - { - return (isSet(lcdc, memorymap::LCDC::WINDOW_CODE_AREA)) ? 0x9C00 : 0x9800; - } - } - - std::array TileMap::getSpriteCache() const - { - return sprite_cache_; - } - - std::vector TileMap::getBackgroundTileMap() - { - // make std::array? - std::vector tiles; - - forEachBackgroundTile([&](uint8_t tile){ - tiles.push_back(tile); - }); - - return tiles; - } - - std::size_t TileMap::hashBackground() - { - std::size_t seed = 0; - - forEachBackgroundTile([&](uint8_t tilenum){ - hash_combine(seed, tilenum); - }); - - return seed; - } - - void TileMap::forEachBackgroundTile(std::function fn) - { - static constexpr auto tiles_per_row = 32; - static constexpr auto tiles_per_col = 32; - static constexpr auto tile_width = 8; - static constexpr auto tile_height = 8; - - const auto start = getAddress(Map::BACKGROUND); - - const auto scx = mmu_.read(memorymap::SCX_REGISTER); - const auto scy = mmu_.read(memorymap::SCY_REGISTER); - - const auto start_tile_col = scx / tile_width; - - for (auto line = 0; line < 144; line += 8) - { - const auto tile_row = ((scy + line) / tile_height); - - for (auto tile_col = start_tile_col; tile_col < start_tile_col + 20; ++tile_col) - { - // calculate tile address - const auto tile_offset = start + (tiles_per_row * (tile_row % tiles_per_row)) + (tile_col % tiles_per_col); - // read tile character code from map - const auto tilenum = mmu_.readVram((uint16_t)tile_offset, 0); - - fn(tilenum); - } - } - } - - TileMap::~TileMap() - { - } - } -} diff --git a/components/gameboycore/src/tileram.cpp b/components/gameboycore/src/tileram.cpp deleted file mode 100644 index e8f9d3b4..00000000 --- a/components/gameboycore/src/tileram.cpp +++ /dev/null @@ -1,163 +0,0 @@ - -#include "gameboycore/tileram.h" -#include "gameboycore/memorymap.h" - -#include - -namespace gb -{ - namespace detail - { - TileRAM::TileRAM(MMU& mmu) : - tile_ram_(mmu.getptr(0x8000)), - mmu_(mmu) - { - } - - TileRAM::TileRow TileRAM::getRow(int row, uint8_t tilenum, bool umode, uint8_t character_bank) - { - TileRow tile_row; - - // get the tile address depending on whether current using unsigned mode or signed mode - uint16_t addr = (umode) - ? getTileAddress(0x8000, tilenum) - : getTileAddress(0x9000, tilenum); - - auto row_offset = uint16_t(row * 2); - auto lsb = mmu_.readVram(addr + row_offset, character_bank); - auto msb = mmu_.readVram(addr + row_offset + 1, character_bank); - - auto idx = 0; - for (auto bit = (int)(tile_row.size() - 1); bit >= 0; --bit) - { - uint8_t mask = (1 << bit); - uint8_t color = (((msb & mask) >> bit) << 1) | ((lsb & mask) >> bit); - - tile_row[idx++] = color; - } - - return tile_row; - } - - Tile TileRAM::getSpriteTile(const Sprite& sprite) const - { - auto tile_ptr = mmu_.getptr(getTileAddress(0x8000, sprite.tile)); - - Tile tile; - auto row = 0; - - for (auto i = 0u; i < TILE_SIZE; i += 2) - { - uint8_t lsb = tile_ptr[i + 0]; - uint8_t msb = tile_ptr[i + 1]; - - setRow(tile, msb, lsb, row); - row++; - } - - // apply sprite attributes - if (sprite.isVerticallyFlipped()) - tile = flipV(tile); - if (sprite.isHorizontallyFlipped()) - tile = flipH(tile); - - return tile; - } - - Tile TileRAM::flipV(const Tile& old) const - { - static const auto NUM_ROWS = 8; - static const auto PIXELS_PER_ROW = 8; - - Tile tile; - - for (auto row = 0; row < NUM_ROWS; ++row) - { - auto target_row = NUM_ROWS - row - 1; - - auto old_idx = (row * PIXELS_PER_ROW); - auto target_idx = (target_row * PIXELS_PER_ROW); - - tile.color[target_idx + 0] = old.color[old_idx + 0]; - tile.color[target_idx + 1] = old.color[old_idx + 1]; - tile.color[target_idx + 2] = old.color[old_idx + 2]; - tile.color[target_idx + 3] = old.color[old_idx + 3]; - tile.color[target_idx + 4] = old.color[old_idx + 4]; - tile.color[target_idx + 5] = old.color[old_idx + 5]; - tile.color[target_idx + 6] = old.color[old_idx + 6]; - tile.color[target_idx + 7] = old.color[old_idx + 7]; - } - - return tile; - } - - Tile TileRAM::flipH(const Tile& old) const - { - static const auto NUM_COLS = 8; - static const auto NUM_ROWS = 8; - static const auto PIXELS_PER_ROW = 8; - - Tile tile; - - for (auto col = 0; col < NUM_COLS; ++col) - { - auto old_idx = col; - auto target_idx = NUM_COLS - col; - - for (auto row = 0; row < NUM_ROWS; ++row) - { - auto row_offset = (row * PIXELS_PER_ROW) - 1; - tile.color[target_idx + row_offset] = old.color[old_idx + row_offset]; - } - } - - return tile; - } - - std::vector TileRAM::getTiles() - { - std::vector tiles; - - for (auto i = 0u; i < NUM_TILES; i++) - { - unsigned int offset = i * TILE_SIZE; - uint8_t* current_tile_ptr = tile_ram_ + offset; - - Tile tile; - int row = 0; - - for (auto j = 0u; j < TILE_SIZE; j += 2) - { - uint8_t lsb = current_tile_ptr[j + 0]; - uint8_t msb = current_tile_ptr[j + 1]; - - setRow(tile, msb, lsb, row); - row++; - } - - tiles.push_back(tile); - } - - return tiles; - } - - void TileRAM::setRow(Tile& tile, uint8_t msb, uint8_t lsb, int row) const - { - int offset = row * 8; - - int pixel = 0; - for (int i = 7; i >= 0; i--) - { - uint8_t mask = (1 << i); - uint8_t color = (((msb & mask) >> i) << 1) | ((lsb & mask) >> i); - - tile.color[offset + pixel] = color; - pixel++; - } - } - - TileRAM::~TileRAM() - { - } - } -} diff --git a/components/gameboycore/src/timer.cpp b/components/gameboycore/src/timer.cpp deleted file mode 100644 index 362263d7..00000000 --- a/components/gameboycore/src/timer.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "gameboycore/timer.h" - -namespace gb -{ - Timer::Timer(MMU& mmu) : - controller_(mmu.get(memorymap::TIMER_CONTROLLER_REGISTER)), - counter_(mmu.get(memorymap::TIMER_COUNTER_REGISTER)), - modulo_(mmu.get(memorymap::TIMER_MODULO_REGISTER)), - divider_(mmu.get(memorymap::DIVIDER_REGISER)), - t_clock_(0), - base_clock_(0), - div_clock_(0), - timer_interrupt_(mmu, InterruptProvider::Interrupt::TIMER) - { - } - - void Timer::update(const uint8_t machine_cycles) - { - // M clock increments at 1/4 the T clock rate - t_clock_ += machine_cycles * 4; - - // timer ticks occur at 1/16 the CPU cycles - while (t_clock_ >= 16) - { - t_clock_ -= 16; - tick(); - } - } - - void Timer::tick() - { - // base clock dividers - static constexpr int freqs[] = { - 64, // 4 KHz - 1, // 262 KHz (base) - 4, // 65 KHz - 16 // 16 KHz - }; - - base_clock_++; - div_clock_++; - - // do divider clock - if (div_clock_ == 16) - { - divider_++; - div_clock_ = 0; - } - - // only if timer is enabled - if (controller_ & 0x04) - { - // get frequency - auto freq = freqs[controller_ & 0x03]; - - // increment counter - while (base_clock_ >= freq) - { - base_clock_ -= freq; - - if (counter_ == 0xFF) - { - counter_ = modulo_; - timer_interrupt_.set(); - } - else - { - counter_++; - } - } - } - } - - Timer::~Timer() - { - } -} \ No newline at end of file diff --git a/components/gnuboy/CMakeLists.txt b/components/gnuboy/CMakeLists.txt index 4a76a564..eeca8068 100644 --- a/components/gnuboy/CMakeLists.txt +++ b/components/gnuboy/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register( - INCLUDE_DIRS "." - SRC_DIRS "." + INCLUDE_DIRS "include" + SRC_DIRS "src" REQUIRES box-emu-hal ) diff --git a/components/gnuboy/cpu.h b/components/gnuboy/include/gnuboy/cpu.h similarity index 91% rename from components/gnuboy/cpu.h rename to components/gnuboy/include/gnuboy/cpu.h index da24fcfa..9257ec13 100644 --- a/components/gnuboy/cpu.h +++ b/components/gnuboy/include/gnuboy/cpu.h @@ -3,7 +3,8 @@ -#include "defs.h" +#include "gnuboy/defs.h" +#include union reg diff --git a/components/gnuboy/cpucore.h b/components/gnuboy/include/gnuboy/cpucore.h similarity index 99% rename from components/gnuboy/cpucore.h rename to components/gnuboy/include/gnuboy/cpucore.h index 16441e2c..88723822 100644 --- a/components/gnuboy/cpucore.h +++ b/components/gnuboy/include/gnuboy/cpucore.h @@ -3,8 +3,8 @@ ** The variable defs of this header are candidates for moving into cpu.c */ -#include "defs.h" -#include +#include "gnuboy/defs.h" +// #include static const byte cycles_table[256] = { diff --git a/components/gnuboy/cpuregs.h b/components/gnuboy/include/gnuboy/cpuregs.h similarity index 94% rename from components/gnuboy/cpuregs.h rename to components/gnuboy/include/gnuboy/cpuregs.h index 9049a44f..0c463e1d 100644 --- a/components/gnuboy/cpuregs.h +++ b/components/gnuboy/include/gnuboy/cpuregs.h @@ -6,8 +6,8 @@ -#include "defs.h" -#include "cpu.h" +#include "gnuboy/defs.h" +#include "gnuboy/cpu.h" #define LB(r) ((r).b[LO][LO]) #define HB(r) ((r).b[LO][HI]) diff --git a/components/gnuboy/defs.h b/components/gnuboy/include/gnuboy/defs.h similarity index 100% rename from components/gnuboy/defs.h rename to components/gnuboy/include/gnuboy/defs.h diff --git a/components/gnuboy/fastmem.h b/components/gnuboy/include/gnuboy/fastmem.h similarity index 95% rename from components/gnuboy/fastmem.h rename to components/gnuboy/include/gnuboy/fastmem.h index 87554505..803fcf08 100644 --- a/components/gnuboy/fastmem.h +++ b/components/gnuboy/include/gnuboy/fastmem.h @@ -3,8 +3,8 @@ #define __FASTMEM_H__ -#include "defs.h" -#include "mem.h" +#include "gnuboy/defs.h" +#include "gnuboy/mem.h" inline static byte readb(int a) diff --git a/components/gnuboy/fb.h b/components/gnuboy/include/gnuboy/fb.h similarity index 89% rename from components/gnuboy/fb.h rename to components/gnuboy/include/gnuboy/fb.h index 97d16ae1..a552c6e0 100644 --- a/components/gnuboy/fb.h +++ b/components/gnuboy/include/gnuboy/fb.h @@ -4,9 +4,7 @@ #define __FB_H__ -#include "defs.h" - - +#include "gnuboy/defs.h" struct fb { diff --git a/components/gnuboy/gnuboy.h b/components/gnuboy/include/gnuboy/gnuboy.h similarity index 97% rename from components/gnuboy/gnuboy.h rename to components/gnuboy/include/gnuboy/gnuboy.h index e8c778d8..aed9a8f6 100644 --- a/components/gnuboy/gnuboy.h +++ b/components/gnuboy/include/gnuboy/gnuboy.h @@ -16,7 +16,7 @@ void ev_poll(); void vid_close(); void vid_preinit(); -void vid_init(); +// void vid_init(); // NOT NEEDED void vid_begin(); void vid_end(); void vid_setpal(int i, int r, int g, int b); @@ -64,7 +64,7 @@ void init_exports(); void show_exports(); /* hw.c */ -#include "defs.h" /* need byte for below */ +#include "gnuboy/defs.h" /* need byte for below */ void hw_interrupt(byte i, byte mask); /* palette.c */ diff --git a/components/gnuboy/hw.h b/components/gnuboy/include/gnuboy/hw.h similarity index 95% rename from components/gnuboy/hw.h rename to components/gnuboy/include/gnuboy/hw.h index 83a4c0fb..c1cdfb67 100644 --- a/components/gnuboy/hw.h +++ b/components/gnuboy/include/gnuboy/hw.h @@ -2,7 +2,7 @@ #define __HW_H__ -#include "defs.h" +#include "gnuboy/defs.h" #define PAD_RIGHT 0x01 diff --git a/components/gnuboy/input.h b/components/gnuboy/include/gnuboy/input.h similarity index 100% rename from components/gnuboy/input.h rename to components/gnuboy/include/gnuboy/input.h diff --git a/components/gnuboy/lcd.h b/components/gnuboy/include/gnuboy/lcd.h similarity index 97% rename from components/gnuboy/lcd.h rename to components/gnuboy/include/gnuboy/lcd.h index decc4e38..7826b4fe 100644 --- a/components/gnuboy/lcd.h +++ b/components/gnuboy/include/gnuboy/lcd.h @@ -1,7 +1,7 @@ #ifndef __LCD_H__ #define __LCD_H__ -#include "defs.h" +#include "gnuboy/defs.h" struct vissprite { diff --git a/components/gnuboy/loader.h b/components/gnuboy/include/gnuboy/loader.h similarity index 64% rename from components/gnuboy/loader.h rename to components/gnuboy/include/gnuboy/loader.h index 202e39b8..74a50631 100644 --- a/components/gnuboy/loader.h +++ b/components/gnuboy/include/gnuboy/loader.h @@ -14,11 +14,9 @@ typedef struct loader_s extern loader_t loader; -void loader_init(char *s); -void loader_init_raw(uint8_t *romdata, size_t rom_data_size); +void loader_init(unsigned char *romptr, unsigned int rom_size); void loader_unload(); -int rom_load(); -int rom_load_raw(uint8_t *romdata, size_t rom_data_size); +int rom_load(unsigned char *romptr, unsigned int rom_size); int sram_load(); int sram_save(); void state_load(int n); diff --git a/components/gnuboy/mem.h b/components/gnuboy/include/gnuboy/mem.h similarity index 95% rename from components/gnuboy/mem.h rename to components/gnuboy/include/gnuboy/mem.h index 247f1087..303061b4 100644 --- a/components/gnuboy/mem.h +++ b/components/gnuboy/include/gnuboy/mem.h @@ -2,7 +2,7 @@ #define __MEM_H__ -#include "defs.h" +#include "gnuboy/defs.h" @@ -30,7 +30,7 @@ struct mbc struct rom { - byte* bank[512]; + byte (* bank)[16384]; char name[20]; int length; }; diff --git a/components/gnuboy/noise.h b/components/gnuboy/include/gnuboy/noise.h similarity index 99% rename from components/gnuboy/noise.h rename to components/gnuboy/include/gnuboy/noise.h index a0d16c6d..d29602b1 100644 --- a/components/gnuboy/noise.h +++ b/components/gnuboy/include/gnuboy/noise.h @@ -3,7 +3,7 @@ #define __NOISE_H__ -#include "defs.h" +#include "gnuboy/defs.h" #include /*DRAM_ATTR*/ static const byte noise7[] = diff --git a/components/gnuboy/pcm.h b/components/gnuboy/include/gnuboy/pcm.h similarity index 86% rename from components/gnuboy/pcm.h rename to components/gnuboy/include/gnuboy/pcm.h index 884cb28d..e9c0004d 100644 --- a/components/gnuboy/pcm.h +++ b/components/gnuboy/include/gnuboy/pcm.h @@ -3,7 +3,7 @@ #define __PCM_H__ -#include "defs.h" +#include "gnuboy/defs.h" #include struct pcm diff --git a/components/gnuboy/rc.h b/components/gnuboy/include/gnuboy/rc.h similarity index 100% rename from components/gnuboy/rc.h rename to components/gnuboy/include/gnuboy/rc.h diff --git a/components/gnuboy/regs.h b/components/gnuboy/include/gnuboy/regs.h similarity index 99% rename from components/gnuboy/regs.h rename to components/gnuboy/include/gnuboy/regs.h index 4457fd90..1b16679e 100644 --- a/components/gnuboy/regs.h +++ b/components/gnuboy/include/gnuboy/regs.h @@ -3,7 +3,7 @@ #define __REGS_H__ -#include "mem.h" +#include "gnuboy/mem.h" /* General internal/io stuff */ diff --git a/components/gnuboy/rtc.h b/components/gnuboy/include/gnuboy/rtc.h similarity index 92% rename from components/gnuboy/rtc.h rename to components/gnuboy/include/gnuboy/rtc.h index da7f21a9..04d60c1b 100644 --- a/components/gnuboy/rtc.h +++ b/components/gnuboy/include/gnuboy/rtc.h @@ -3,7 +3,7 @@ #include -#include "defs.h" +#include "gnuboy/defs.h" struct rtc { diff --git a/components/gnuboy/sound.h b/components/gnuboy/include/gnuboy/sound.h similarity index 100% rename from components/gnuboy/sound.h rename to components/gnuboy/include/gnuboy/sound.h diff --git a/components/gnuboy/main.c b/components/gnuboy/main.c deleted file mode 100644 index 71949bb9..00000000 --- a/components/gnuboy/main.c +++ /dev/null @@ -1,318 +0,0 @@ -#include -#include -#include -#include -#include - -#include "gnuboy.h" -#include "input.h" -#include "rc.h" -#include "loader.h" - - -void die(char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - abort(); -} - - -#if 0 -#include "Version" - - -static char *defaultconfig[] = -{ - "bind esc quit", - "bind up +up", - "bind down +down", - "bind left +left", - "bind right +right", - "bind d +a", - "bind s +b", - "bind enter +start", - "bind space +select", - "bind tab +select", - "bind joyup +up", - "bind joydown +down", - "bind joyleft +left", - "bind joyright +right", - "bind joy0 +b", - "bind joy1 +a", - "bind joy2 +select", - "bind joy3 +start", - "bind 1 \"set saveslot 1\"", - "bind 2 \"set saveslot 2\"", - "bind 3 \"set saveslot 3\"", - "bind 4 \"set saveslot 4\"", - "bind 5 \"set saveslot 5\"", - "bind 6 \"set saveslot 6\"", - "bind 7 \"set saveslot 7\"", - "bind 8 \"set saveslot 8\"", - "bind 9 \"set saveslot 9\"", - "bind 0 \"set saveslot 0\"", - "bind ins savestate", - "bind del loadstate", - "source gnuboy.rc", - NULL -}; - - -static void banner() -{ - printf("\ngnuboy " VERSION "\n"); -} - -static void copyright() -{ - banner(); - printf( -"Copyright (C) 2000-2001 Laguna and Gilgamesh\n" -"Portions contributed by other authors; see CREDITS for details.\n" -"\n" -"This program is free software; you can redistribute it and/or modify\n" -"it under the terms of the GNU General Public License as published by\n" -"the Free Software Foundation; either version 2 of the License, or\n" -"(at your option) any later version.\n" -"\n" -"This program is distributed in the hope that it will be useful,\n" -"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" -"GNU General Public License for more details.\n" -"\n" -"You should have received a copy of the GNU General Public License\n" -"along with this program; if not, write to the Free Software\n" -"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n" -"\n"); -} - -static void usage(char *name) -{ - copyright(); - printf("Type %s --help for detailed help.\n\n", name); - exit(1); -} - -static void copying() -{ - copyright(); - exit(0); -} - -static void help(char *name) -{ - banner(); - printf("Usage: %s [options] romfile\n", name); - printf("\n" -" --source FILE read rc commands from FILE\n" -" --bind KEY COMMAND bind KEY to perform COMMAND\n" -" --VAR=VALUE set rc variable VAR to VALUE\n" -" --VAR set VAR to 1 (turn on boolean options)\n" -" --no-VAR set VAR to 0 (turn off boolean options)\n" -" --showvars list all available rc variables\n" -" --help display this help and exit\n" -" --version output version information and exit\n" -" --copying show copying permissions\n" -""); - exit(0); -} - - -static void version(char *name) -{ - printf("%s-" VERSION "\n", name); - exit(0); -} - - -void doevents() -{ - event_t ev; - int st; - - ev_poll(); - while (ev_getevent(&ev)) - { - if (ev.type != EV_PRESS && ev.type != EV_RELEASE) - continue; - st = (ev.type != EV_RELEASE); - rc_dokey(ev.code, st); - } -} - - - - -static void shutdown() -{ - vid_close(); - pcm_close(); -} - -void die(char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} - -static int bad_signals[] = -{ - /* These are all standard, so no need to #ifdef them... */ - SIGINT, SIGSEGV, SIGTERM, SIGFPE, SIGABRT, SIGILL, -#ifdef SIGQUIT - SIGQUIT, -#endif -#ifdef SIGPIPE - SIGPIPE, -#endif - 0 -}; - -static void fatalsignal(int s) -{ - die("Signal %d\n", s); -} - -static void catch_signals() -{ - int i; - for (i = 0; bad_signals[i]; i++) - signal(bad_signals[i], fatalsignal); -} - - - -static char *base(char *s) -{ - char *p; - p = strrchr(s, DIRSEP_CHAR); - if (p) return p+1; - return s; -} - - -int main(int argc, char *argv[]) -{ - int i; - char *opt, *arg, *cmd, *s, *rom = 0; - - /* Avoid initializing video if we don't have to */ - for (i = 1; i < argc; i++) - { - if (!strcmp(argv[i], "--help")) - help(base(argv[0])); - else if (!strcmp(argv[i], "--version")) - version(base(argv[0])); - else if (!strcmp(argv[i], "--copying")) - copying(); - else if (!strcmp(argv[i], "--bind")) i += 2; - else if (!strcmp(argv[i], "--source")) i++; - else if (!strcmp(argv[i], "--showvars")) - { - show_exports(); - exit(0); - } - else if (argv[i][0] == '-' && argv[i][1] == '-'); - else if (argv[i][0] == '-' && argv[i][1]); - else rom = argv[i]; - } - - if (!rom) usage(base(argv[0])); - - /* If we have special perms, drop them ASAP! */ - vid_preinit(); - - init_exports(); - - s = strdup(argv[0]); - sys_sanitize(s); - sys_initpath(s); - - for (i = 0; defaultconfig[i]; i++) - rc_command(defaultconfig[i]); - - cmd = malloc(strlen(rom) + 11); - sprintf(cmd, "source %s", rom); - s = strchr(cmd, '.'); - if (s) *s = 0; - strcat(cmd, ".rc"); - rc_command(cmd); - - for (i = 1; i < argc; i++) - { - if (!strcmp(argv[i], "--bind")) - { - if (i + 2 >= argc) die("missing arguments to bind\n"); - cmd = malloc(strlen(argv[i+1]) + strlen(argv[i+2]) + 9); - sprintf(cmd, "bind %s \"%s\"", argv[i+1], argv[i+2]); - rc_command(cmd); - free(cmd); - i += 2; - } - else if (!strcmp(argv[i], "--source")) - { - if (i + 1 >= argc) die("missing argument to source\n"); - cmd = malloc(strlen(argv[i+1]) + 6); - sprintf(cmd, "source %s", argv[++i]); - rc_command(cmd); - free(cmd); - } - else if (!strncmp(argv[i], "--no-", 5)) - { - opt = strdup(argv[i]+5); - while ((s = strchr(opt, '-'))) *s = '_'; - cmd = malloc(strlen(opt) + 7); - sprintf(cmd, "set %s 0", opt); - rc_command(cmd); - free(cmd); - free(opt); - } - else if (argv[i][0] == '-' && argv[i][1] == '-') - { - opt = strdup(argv[i]+2); - if ((s = strchr(opt, '='))) - { - *s = 0; - arg = s+1; - } - else arg = "1"; - while ((s = strchr(opt, '-'))) *s = '_'; - while ((s = strchr(arg, ','))) *s = ' '; - - cmd = malloc(strlen(opt) + strlen(arg) + 6); - sprintf(cmd, "set %s %s", opt, arg); - - rc_command(cmd); - free(cmd); - free(opt); - } - /* short options not yet implemented */ - else if (argv[i][0] == '-' && argv[i][1]); - } - - /* FIXME - make interface modules responsible for atexit() */ - atexit(shutdown); - catch_signals(); - vid_init(); - pcm_init(); - - rom = strdup(rom); - sys_sanitize(rom); - - loader_init(rom); - - emu_reset(); - emu_run(); - - /* never reached */ - return 0; -} -#endif diff --git a/components/gnuboy/cpu.c b/components/gnuboy/src/cpu.c similarity index 98% rename from components/gnuboy/cpu.c rename to components/gnuboy/src/cpu.c index 8d99af04..c74fddba 100644 --- a/components/gnuboy/cpu.c +++ b/components/gnuboy/src/cpu.c @@ -1,18 +1,18 @@ #pragma GCC optimize ("O3") -#include "gnuboy.h" -#include "defs.h" -#include "regs.h" -#include "hw.h" -#include "lcd.h" -#include "cpu.h" -#include "mem.h" -#include "fastmem.h" -#include "cpuregs.h" -#include "cpucore.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/regs.h" +#include "gnuboy/hw.h" +#include "gnuboy/lcd.h" +#include "gnuboy/cpu.h" +#include "gnuboy/mem.h" +#include "gnuboy/fastmem.h" +#include "gnuboy/cpuregs.h" +#include "gnuboy/cpucore.h" #ifdef USE_ASM -#include "asm.h" +#include "gnuboy/asm.h" #endif diff --git a/components/gnuboy/debug.c b/components/gnuboy/src/debug.c similarity index 97% rename from components/gnuboy/debug.c rename to components/gnuboy/src/debug.c index 25e783f1..6519c400 100644 --- a/components/gnuboy/debug.c +++ b/components/gnuboy/src/debug.c @@ -1,16 +1,16 @@ #include #include -#include "gnuboy.h" -#include "defs.h" -#include "cpu.h" -#include "mem.h" -#include "regs.h" -#include "rc.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/cpu.h" +#include "gnuboy/mem.h" +#include "gnuboy/regs.h" +#include "gnuboy/rc.h" -#include "cpuregs.h" +#include "gnuboy/cpuregs.h" #ifndef GNUBOY_DISABLE_DEBUG_DISASSEMBLE -#include "fastmem.h" +#include "gnuboy/fastmem.h" static char *mnemonic_table[256] = { diff --git a/components/gnuboy/emu.c b/components/gnuboy/src/emu.c similarity index 76% rename from components/gnuboy/emu.c rename to components/gnuboy/src/emu.c index 200eca2e..76500b97 100644 --- a/components/gnuboy/emu.c +++ b/components/gnuboy/src/emu.c @@ -1,16 +1,14 @@ -#include "gnuboy.h" -#include "defs.h" -#include "regs.h" -#include "hw.h" -#include "cpu.h" -#include "sound.h" -#include "mem.h" -#include "lcd.h" -#include "rtc.h" -#include "rc.h" -#include "fb.h" - -#include "spi_lcd.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/regs.h" +#include "gnuboy/hw.h" +#include "gnuboy/cpu.h" +#include "gnuboy/sound.h" +#include "gnuboy/mem.h" +#include "gnuboy/lcd.h" +#include "gnuboy/rtc.h" +#include "gnuboy/rc.h" + static int framelen = 16743; static int framecount; @@ -69,12 +67,10 @@ void emu_step() */ void emu_run() { - // FIXME: how to handle timing? - // void *timer = sys_timer(); + void *timer = sys_timer(); int delay; - // FIXME: what does vid do? - // vid_begin(); + vid_begin(); lcd_begin(); for (;;) { @@ -92,29 +88,22 @@ void emu_run() /* Step through visible line scanning phase */ emu_step(); } - static size_t frame_num=0; - printf("frame: %d\n", frame_num++); - lcd_write_frame(0, 0, 160, 144, fb.ptr); + /* VBLANK BEGIN */ - // FIXME: what does this do? - // vid_end(); + vid_end(); rtc_tick(); sound_mix(); /* pcm_submit() introduces delay, if it fails we use sys_sleep() instead */ - // FIXME: what does this do... - // if (!pcm_submit()) + if (!pcm_submit()) { - /* FIXME: need to replace this with waits? delay = framelen - sys_elapsed(timer); sys_sleep(delay); sys_elapsed(timer); - */ } - // FIXME: what does this function do? - // doevents(); - // vid_begin(); + doevents(); + vid_begin(); if (framecount) { if (!--framecount) die("finished\n"); } if (!(R_LCDC & 0x80)) { diff --git a/components/gnuboy/events.c b/components/gnuboy/src/events.c similarity index 96% rename from components/gnuboy/events.c rename to components/gnuboy/src/events.c index ca05eed2..f24cd621 100644 --- a/components/gnuboy/events.c +++ b/components/gnuboy/src/events.c @@ -6,7 +6,7 @@ */ -#include "input.h" +#include "gnuboy/input.h" char keystates[MAX_KEYS]; diff --git a/components/gnuboy/exports.c b/components/gnuboy/src/exports.c similarity index 92% rename from components/gnuboy/exports.c rename to components/gnuboy/src/exports.c index 54050a04..be1cd4a7 100644 --- a/components/gnuboy/exports.c +++ b/components/gnuboy/src/exports.c @@ -1,8 +1,8 @@ #include #include -#include "gnuboy.h" -#include "rc.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/rc.h" extern rcvar_t rcfile_exports[], emu_exports[], loader_exports[], lcd_exports[], rtc_exports[], debug_exports[], sound_exports[], diff --git a/components/gnuboy/fastmem.c b/components/gnuboy/src/fastmem.c similarity index 98% rename from components/gnuboy/fastmem.c rename to components/gnuboy/src/fastmem.c index 767fb8c8..cc442ef5 100644 --- a/components/gnuboy/fastmem.c +++ b/components/gnuboy/src/fastmem.c @@ -1,6 +1,6 @@ -#include "fastmem.h" +#include "gnuboy/fastmem.h" #include diff --git a/components/gnuboy/hw.c b/components/gnuboy/src/hw.c similarity index 93% rename from components/gnuboy/hw.c rename to components/gnuboy/src/hw.c index ad821074..ecdae040 100644 --- a/components/gnuboy/hw.c +++ b/components/gnuboy/src/hw.c @@ -2,14 +2,14 @@ #include -#include "gnuboy.h" -#include "defs.h" -#include "cpu.h" -#include "hw.h" -#include "regs.h" -#include "lcd.h" -#include "mem.h" -#include "fastmem.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/cpu.h" +#include "gnuboy/hw.h" +#include "gnuboy/regs.h" +#include "gnuboy/lcd.h" +#include "gnuboy/mem.h" +#include "gnuboy/fastmem.h" #include "esp_attr.h" diff --git a/components/gnuboy/inflate.c b/components/gnuboy/src/inflate.c similarity index 99% rename from components/gnuboy/inflate.c rename to components/gnuboy/src/inflate.c index 24729cc8..67b66a4c 100644 --- a/components/gnuboy/inflate.c +++ b/components/gnuboy/src/inflate.c @@ -1,4 +1,4 @@ -#include "gnuboy.h" +#include "gnuboy/gnuboy.h" /* Slightly modified from its original form so as not to exit the * program on errors. The resulting file remains in the public diff --git a/components/gnuboy/keytable.c b/components/gnuboy/src/keytable.c similarity index 98% rename from components/gnuboy/keytable.c rename to components/gnuboy/src/keytable.c index 8e637e10..5f8c8186 100644 --- a/components/gnuboy/keytable.c +++ b/components/gnuboy/src/keytable.c @@ -10,8 +10,8 @@ #include #include -#include "gnuboy.h" -#include "input.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/input.h" /* keytable - Mapping of key names to codes, and back. A single code can have more than one name, in which case the first will be used diff --git a/components/gnuboy/lcd.c b/components/gnuboy/src/lcd.c similarity index 97% rename from components/gnuboy/lcd.c rename to components/gnuboy/src/lcd.c index 7f1b186f..7d9e95e0 100755 --- a/components/gnuboy/lcd.c +++ b/components/gnuboy/src/lcd.c @@ -2,22 +2,24 @@ #include -#include "gnuboy.h" -#include "defs.h" -#include "regs.h" -#include "hw.h" -#include "mem.h" -#include "lcd.h" -#include "rc.h" -#include "fb.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/regs.h" +#include "gnuboy/hw.h" +#include "gnuboy/mem.h" +#include "gnuboy/lcd.h" +#include "gnuboy/rc.h" +#include "gnuboy/fb.h" #ifdef USE_ASM -#include "asm.h" +#include "gnuboy/asm.h" #endif #include #include #include +#include "spi_lcd.h" + struct lcd lcd; struct scan scan; @@ -737,7 +739,8 @@ inline static void updatepalette(int i) // bit 10-14 blue b = (c >> 10) & 0x1f; - PAL2[i] = (r << 11) | (g << (5 + 1)) | (b); + // PAL2[i] = (r << 11) | (g << (5 + 1)) | (b); + PAL2[i] = make_color(r << 3 , g << 3 , b << 3); } inline void pal_write(int i, byte b) diff --git a/components/gnuboy/lcdc.c b/components/gnuboy/src/lcdc.c similarity index 97% rename from components/gnuboy/lcdc.c rename to components/gnuboy/src/lcdc.c index 5c4121f0..d4b17afa 100644 --- a/components/gnuboy/lcdc.c +++ b/components/gnuboy/src/lcdc.c @@ -2,12 +2,12 @@ #include -#include "gnuboy.h" -#include "defs.h" -#include "hw.h" -#include "cpu.h" -#include "regs.h" -#include "lcd.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/hw.h" +#include "gnuboy/cpu.h" +#include "gnuboy/regs.h" +#include "gnuboy/lcd.h" #include diff --git a/components/gnuboy/loader.c b/components/gnuboy/src/loader.c similarity index 70% rename from components/gnuboy/loader.c rename to components/gnuboy/src/loader.c index e62e50db..04695bb0 100644 --- a/components/gnuboy/loader.c +++ b/components/gnuboy/src/loader.c @@ -4,38 +4,26 @@ #include #include +#include "nvs_flash.h" #include "esp_partition.h" #include "esp_system.h" #include "esp_heap_caps.h" -#ifndef GNUBOY_NO_MINIZIP -/* -** use http://www.winimage.com/zLibDll/minizip.html v1.1 -** which needs zlib -*/ -#include -#endif /* GNUBOY_USE_MINIZIP */ - - -#include "gnuboy.h" -#include "defs.h" -#include "regs.h" -#include "mem.h" -#include "hw.h" -#include "lcd.h" -#include "rtc.h" -#include "rc.h" -#include "sound.h" - +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/regs.h" +#include "gnuboy/mem.h" +#include "gnuboy/hw.h" +#include "gnuboy/lcd.h" +#include "gnuboy/rtc.h" +#include "gnuboy/rc.h" +#include "gnuboy/sound.h" +// #include "settings.h" + +void* FlashAddress = 0; FILE* RomFile = NULL; uint8_t BankCache[512 / 8]; - -#ifndef GNUBOY_NO_MINIZIP -static int check_zip(char *filename); -static byte *loadzipfile(char *archive, int *filesize); -#endif /* GNUBOY_USE_MINIZIP */ - static int mbc_table[256] = { 0, 1, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, @@ -111,196 +99,76 @@ static int forcedmg=0, gbamode=0; static int memfill = 0, memrand = -1; -extern const char* SD_BASE_PATH; - - static void initmem(void *mem, int size) { char *p = mem; - memset(p, 0xff /*memfill*/, size); + //memset(p, 0xff /*memfill*/, size); + if (memfill >= 0) + memset(p, memfill, size); } -static byte *loadfile(FILE *f, int *len) -{ - int l = 0, c = 0; - byte *d = NULL; -#ifdef GNUBOY_ENABLE_ORIGINAL_SLOW_INCREMENTAL_LOADER - int p = 0; - byte buf[512]; +static byte *inf_buf; +static int inf_pos, inf_len; +static byte *_data_ptr = NULL; - for(;;) - { - c = fread(buf, 1, sizeof buf, f); - if (c <= 0) break; - l += c; - d = realloc(d, l); - if (!d) return 0; - memcpy(d+p, buf, c); - p += c; - } -#else /* fast and no space check */ - /* alloc and read once - NOTE no sanity check on filesize */ - fseek(f, 0, SEEK_END); - l = ftell(f); - fseek(f, 0, SEEK_SET); - d = (byte*) malloc(l); - if (d != NULL) - { - c = fread((void *) d, (size_t) l, 1, f); - if (c != 1) - { - l = 0; - /* NOTE if this fails caller doesn't catch it (ditto the slow and "safe" version) */ - } - } -#endif /* GNUBOY_ENABLE_ORIGINAL_SLOW_INCREMENTAL_LOADER */ - *len = l; - return d; -} - - -// TODO: update this to take in a pointer to the right location... -int rom_load() +int rom_load(uint8_t *rom_data, size_t rom_data_size) { - byte c, *data, *header; + /*byte c, *data, *header; int len = 0, rlen; - // TODO: figure out what this address is... - data = (void*)0x3f800000; + const esp_partition_t* part; + spi_flash_mmap_handle_t hrom; + esp_err_t err; - printf("loader: Reading from flash.\n"); + nvs_flash_init(); - // copy from flash - spi_flash_mmap_handle_t hrom; + part=esp_partition_find_first(0x40, 1, NULL); - const esp_partition_t* part = esp_partition_find_first(0x40, 0, NULL); if (part == 0) { - printf("esp_partition_find_first failed.\n"); - abort(); + printf("Couldn't find rom part!\n"); } - for (size_t offset = 0; offset < 0x400000; offset += 0x100000) { - esp_err_t err = esp_partition_read(part, offset, (void *)(data + offset), 0x100000); - if (err != ESP_OK) { - printf("esp_partition_read failed. size = %lx, offset = %x (%d)\n", part->size, offset, err); - abort(); - } + err = esp_partition_mmap(part, 0, 3*1024*1024, SPI_FLASH_MMAP_DATA, (const void**)&data, &hrom); + if (err != ESP_OK) { + printf("Couldn't map rom part!\n"); } - printf("Initialized. ROM@%p\n", data); - header = data; - - memcpy(rom.name, header+0x0134, 16); - //if (rom.name[14] & 0x80) rom.name[14] = 0; - //if (rom.name[15] & 0x80) rom.name[15] = 0; - rom.name[16] = 0; - printf("loader: rom.name='%s'\n", rom.name); - - int tmp = *((int*)(header + 0x0144)); - c = (tmp >> 24) & 0xff; - mbc.type = mbc_table[c]; - mbc.batt = (batt_table[c] && !nobatt) || forcebatt; - rtc.batt = rtc_table[c]; - - tmp = *((int*)(header + 0x0148)); - mbc.romsize = romsize_table[(tmp & 0xff)]; - mbc.ramsize = ramsize_table[((tmp >> 8) & 0xff)]; - - if (!mbc.romsize) die("unknown ROM size %02X\n", header[0x0148]); - if (!mbc.ramsize) die("unknown SRAM size %02X\n", header[0x0149]); - - const char* mbcName; - switch (mbc.type) + BankCache[0] = 1; + */ + byte c, *data, *header; + int len = 0, rlen; + data = heap_caps_malloc(0x400000, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + _data_ptr = data; + /* + // nvs_flash_init(); + data = (void*)0x3f800000; { - case MBC_NONE: - mbcName = "MBC_NONE"; - break; - - case MBC_MBC1: - mbcName = "MBC_MBC1"; - break; - - case MBC_MBC2: - mbcName = "MBC_MBC2"; - break; - - case MBC_MBC3: - mbcName = "MBC_MBC3"; - break; - - case MBC_MBC5: - mbcName = "MBC_MBC5"; - break; - - case MBC_RUMBLE: - mbcName = "MBC_RUMBLE"; - break; + printf("loader: Reading from flash.\n"); - case MBC_HUC1: - mbcName = "MBC_HUC1"; - break; + // copy from flash + spi_flash_mmap_handle_t hrom; - case MBC_HUC3: - mbcName = "MBC_HUC3"; - break; - - default: - mbcName = "(unknown)"; - break; - } - - rlen = 16384 * mbc.romsize; - int sram_length = 8192 * mbc.ramsize; - printf("loader: mbc.type=%s, mbc.romsize=%d (%dK), mbc.ramsize=%d (%dK)\n", mbcName, mbc.romsize, rlen / 1024, mbc.ramsize, sram_length / 1024); - - // ROM - rom.bank[0] = data; - rom.length = rlen; - - // SRAM - ram.sram_dirty = 1; - ram.sbank = malloc(sram_length); - if (!ram.sbank) - { - // not enough free RAM, - // check if PSRAM has free space - if (rlen <= (0x100000 * 3) && - sram_length <= 0x100000) + const esp_partition_t* part = esp_partition_find_first(0x40, 0, NULL); + if (part == 0) { - ram.sbank = data + (0x100000 * 3); - printf("SRAM using PSRAM.\n"); + printf("esp_partition_find_first failed.\n"); + abort(); } - else + + for (size_t offset = 0; offset < 0x400000; offset += 0x100000) { - printf("No free spece for SRAM.\n"); - abort(); + esp_err_t err = esp_partition_read(part, offset, (void *)(data + offset), 0x100000); + if (err != ESP_OK) + { + printf("esp_partition_read failed. size = %x, offset = %x (%d)\n", part->size, offset, err); + abort(); + } } } - - - initmem(ram.sbank, 8192 * mbc.ramsize); - initmem(ram.ibank, 4096 * 8); - - mbc.rombank = 1; - mbc.rambank = 0; - - tmp = *((int*)(header + 0x0140)); - c = tmp >> 24; - hw.cgb = ((c == 0x80) || (c == 0xc0)) && !forcedmg; - hw.gba = (hw.cgb && gbamode); - - return 0; -} - -int rom_load_raw(uint8_t *romdata, size_t rom_data_size) -{ - byte c, *data, *header; - int len = 0, rlen; - - data = romdata; - rlen = rom_data_size; - - printf("loader: initialized. ROM@%p\n", data); + */ + memcpy(data, rom_data, rom_data_size); + // data = rom_data; + printf("Initialized. ROM@%p\n", data); header = data; memcpy(rom.name, header+0x0134, 16); @@ -367,7 +235,8 @@ int rom_load_raw(uint8_t *romdata, size_t rom_data_size) printf("loader: mbc.type=%s, mbc.romsize=%d (%dK), mbc.ramsize=%d (%dK)\n", mbcName, mbc.romsize, rlen / 1024, mbc.ramsize, sram_length / 1024); // ROM - rom.bank[0] = data; + //rom.bank[0] = data; + rom.bank = data; rom.length = rlen; // SRAM @@ -412,7 +281,7 @@ int sram_load() /* Consider sram loaded at this point, even if file doesn't exist */ ram.loaded = 1; - + /* const esp_partition_t* part; spi_flash_mmap_handle_t hrom; esp_err_t err; @@ -435,7 +304,7 @@ int sram_load() printf("sram_load: sram load OK.\n"); ram.sram_dirty = 0; } - } + }*/ return 0; } @@ -447,7 +316,7 @@ int sram_save() if (!mbc.batt || !ram.loaded || !mbc.ramsize) return -1; - const esp_partition_t* part; + /*const esp_partition_t* part; spi_flash_mmap_handle_t hrom; esp_err_t err; @@ -475,7 +344,7 @@ int sram_save() { printf("sram_load: sram save OK.\n"); } - } + }*/ return 0; } @@ -483,6 +352,7 @@ int sram_save() void state_save(int n) { + /* FILE *f; char *name; @@ -497,11 +367,13 @@ void state_save(int n) fclose(f); } free(name); + */ } void state_load(int n) { + /* FILE *f; char *name; @@ -520,6 +392,7 @@ void state_load(int n) mem_updatemap(); } free(name); + */ } void rtc_save() @@ -543,8 +416,11 @@ void rtc_load() void loader_unload() { - // TODO: unmap flash - + printf("freeing data\n"); + if (_data_ptr != NULL) + free(_data_ptr); + printf("data freed!\n"); + /* sram_save(); if (romfile) free(romfile); if (sramfile) free(sramfile); @@ -552,9 +428,10 @@ void loader_unload() if (rom.bank) free(rom.bank); if (ram.sbank) free(ram.sbank); romfile = sramfile = saveprefix = 0; - rom.bank[0] = 0; + rom.bank = 0; ram.sbank = 0; mbc.type = mbc.romsize = mbc.ramsize = mbc.batt = 0; + */ } /* basename/dirname like function */ @@ -583,18 +460,9 @@ static void cleanup() /* IDEA - if error, write emergency savestate..? */ } -void loader_init(char *s) +void loader_init(uint8_t *romptr, size_t rom_size) { - char *name, *p; - - rom_load(); - rtc_load(); - - //atexit(cleanup); -} - -void loader_init_raw(uint8_t *romdata, size_t rom_data_size) { - rom_load_raw(romdata, rom_data_size); + rom_load(romptr, rom_size); rtc_load(); } diff --git a/components/gnuboy/mem.c b/components/gnuboy/src/mem.c similarity index 72% rename from components/gnuboy/mem.c rename to components/gnuboy/src/mem.c index 4a99c058..864a523e 100644 --- a/components/gnuboy/mem.c +++ b/components/gnuboy/src/mem.c @@ -2,14 +2,14 @@ #include -#include "gnuboy.h" -#include "defs.h" -#include "hw.h" -#include "regs.h" -#include "mem.h" -#include "rtc.h" -#include "lcd.h" -#include "sound.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/hw.h" +#include "gnuboy/regs.h" +#include "gnuboy/mem.h" +#include "gnuboy/rtc.h" +#include "gnuboy/lcd.h" +#include "gnuboy/sound.h" #include "esp_partition.h" #include "esp_attr.h" @@ -18,87 +18,6 @@ struct mbc mbc; struct rom rom; struct ram ram; -extern FILE* RomFile; -extern uint8_t BankCache[512 / 8]; - -static inline byte* GetRomPtr(short bank) -{ - // GBC pages are 16k. - const size_t BANK_SIZE = 0x4000; - byte* const PSRAM = (byte*)0x3f800000; - const size_t OFFSET = bank * BANK_SIZE; - - if (RomFile) - { - short slot = bank >> 3; - uint8_t bit = 1 << (bank & 0x7); - - if (!(BankCache[slot] & bit)) - { - //printf("GetRomPtr: Loading bank=%d, slot=%d, bit=%d.\n", bank, slot, bit); - - // Stop the SPI bus - // FIXME: do i need to do this? - // odroid_display_lock_gb_display(); - - //odroid_display_drain_spi(); - - // Load the 16K page - if (fseek(RomFile, OFFSET, SEEK_SET)) - { - printf("GetRomPtr: fseek failed. OFFSET=%d\n", OFFSET); - - // FIXME: do i need to do this - // odroid_audio_terminate(); - - // FIXME: how should i show errors on the display? - // odroid_display_show_sderr(ODROID_SD_ERR_BADFILE); - abort(); - } - - #if 0 - const size_t BLOCK_SIZE = 512; - for (size_t offset = 0; offset < BANK_SIZE; offset += BLOCK_SIZE) - { - size_t count = fread((uint8_t*)PSRAM + (bank * BANK_SIZE) + offset, 1, BLOCK_SIZE, RomFile); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("memw"); - - if (count < BLOCK_SIZE) break; - } - #else - size_t count = fread((uint8_t*)PSRAM + OFFSET, 1, BANK_SIZE, RomFile); - if (count < BANK_SIZE) - { - printf("GetRomPtr: fread failed. bank=%d, count=%d\n", bank, count); - - // FIXME: do i need to do this - // odroid_audio_terminate(); - - // FIXME: how should I show errors on the display? - // odroid_display_show_sderr(ODROID_SD_ERR_BADFILE); - abort(); - } - #endif - - BankCache[slot] |= bit; - - //printf("%s: bank=%d, result=%p\n", __func__, bank, (void*)PSRAM + OFFSET); - - // FIXME: do i need to do this? - // odroid_display_unlock_gb_display(); - } - } - - byte* result = PSRAM + OFFSET; - //printf("%s: bank=%d, result=%p\n", __func__, bank, result); - - return result; -} - /* * In order to make reads and writes efficient, we keep tables * (indexed by the high nibble of the address) specifying which @@ -116,12 +35,6 @@ void IRAM_ATTR mem_updatemap() int n; byte **map; - mbc.rombank &= (mbc.romsize - 1); - - rom.bank[mbc.rombank] = GetRomPtr(mbc.rombank); - - mbc.rambank &= (mbc.ramsize - 1); - map = mbc.rmap; map[0x0] = rom.bank[0]; map[0x1] = rom.bank[0]; @@ -142,8 +55,8 @@ void IRAM_ATTR mem_updatemap() //if (0 && (R_STAT & 0x03) == 0x03) //{ - map[0x8] = NULL; - map[0x9] = NULL; + map[0x8] = NULL; + map[0x9] = NULL; //} //else //{ @@ -158,7 +71,7 @@ void IRAM_ATTR mem_updatemap() // } // else // { - map[0xA] = map[0xB] = NULL; + map[0xA] = map[0xB] = NULL; //} #if 1 @@ -211,58 +124,58 @@ void IRAM_ATTR ioreg_write(byte r, byte b) { switch (r) { - case RI_VBK: - case RI_BCPS: - case RI_OCPS: - case RI_BCPD: - case RI_OCPD: - case RI_SVBK: - case RI_KEY1: - case RI_HDMA1: - case RI_HDMA2: - case RI_HDMA3: - case RI_HDMA4: - case RI_HDMA5: + case RI_VBK: + case RI_BCPS: + case RI_OCPS: + case RI_BCPD: + case RI_OCPD: + case RI_SVBK: + case RI_KEY1: + case RI_HDMA1: + case RI_HDMA2: + case RI_HDMA3: + case RI_HDMA4: + case RI_HDMA5: return; } } switch(r) { - case RI_TIMA: - case RI_TMA: - case RI_TAC: - case RI_SCY: - case RI_SCX: - case RI_WY: - case RI_WX: + case RI_TIMA: + case RI_TMA: + case RI_TAC: + case RI_SCY: + case RI_SCX: + case RI_WY: + case RI_WX: REG(r) = b; break; - case RI_BGP: + case RI_BGP: if (R_BGP == b) break; pal_write_dmg(0, 0, b); pal_write_dmg(8, 1, b); R_BGP = b; break; - case RI_OBP0: + case RI_OBP0: if (R_OBP0 == b) break; pal_write_dmg(64, 2, b); R_OBP0 = b; break; - case RI_OBP1: + case RI_OBP1: if (R_OBP1 == b) break; pal_write_dmg(72, 3, b); R_OBP1 = b; break; - case RI_IF: - case RI_IE: + case RI_IF: + case RI_IE: REG(r) = b & 0x1F; break; - case RI_P1: + case RI_P1: REG(r) = b; pad_refresh(); break; - case RI_SC: + case RI_SC: /* FIXME - this is a hack for stupid roms that probe serial */ if ((b & 0x81) == 0x81) { @@ -272,81 +185,81 @@ void IRAM_ATTR ioreg_write(byte r, byte b) } R_SC = b; /* & 0x7f; */ break; - case RI_SB: + case RI_SB: REG(r) = b; break; - case RI_DIV: + case RI_DIV: REG(r) = 0; break; - case RI_LCDC: + case RI_LCDC: lcdc_change(b); break; - case RI_STAT: + case RI_STAT: stat_write(b); break; - case RI_LYC: + case RI_LYC: REG(r) = b; stat_trigger(); break; - case RI_VBK: + case RI_VBK: REG(r) = b | 0xFE; mem_updatemap(); break; - case RI_BCPS: + case RI_BCPS: R_BCPS = b & 0xBF; R_BCPD = lcd.pal[b & 0x3F]; break; - case RI_OCPS: + case RI_OCPS: R_OCPS = b & 0xBF; R_OCPD = lcd.pal[64 + (b & 0x3F)]; break; - case RI_BCPD: + case RI_BCPD: R_BCPD = b; pal_write(R_BCPS & 0x3F, b); if (R_BCPS & 0x80) R_BCPS = (R_BCPS+1) & 0xBF; break; - case RI_OCPD: + case RI_OCPD: R_OCPD = b; pal_write(64 + (R_OCPS & 0x3F), b); if (R_OCPS & 0x80) R_OCPS = (R_OCPS+1) & 0xBF; break; - case RI_SVBK: + case RI_SVBK: REG(r) = b & 0x07; mem_updatemap(); break; - case RI_DMA: + case RI_DMA: hw_dma(b); break; - case RI_KEY1: + case RI_KEY1: REG(r) = (REG(r) & 0x80) | (b & 0x01); break; - case RI_HDMA1: + case RI_HDMA1: REG(r) = b; break; - case RI_HDMA2: + case RI_HDMA2: REG(r) = b; //& 0xF0; break; - case RI_HDMA3: + case RI_HDMA3: REG(r) = b; //& 0x1F; break; - case RI_HDMA4: + case RI_HDMA4: REG(r) = b; //& 0xF0; break; - case RI_HDMA5: + case RI_HDMA5: hw_hdma_cmd(b); break; } switch (r) { - case RI_BGP: - case RI_OBP0: - case RI_OBP1: + case RI_BGP: + case RI_OBP0: + case RI_OBP1: /* printf("palette reg %02X write %02X at LY=%02X\n", r, b, R_LY); */ - case RI_HDMA1: - case RI_HDMA2: - case RI_HDMA3: - case RI_HDMA4: - case RI_HDMA5: + case RI_HDMA1: + case RI_HDMA2: + case RI_HDMA3: + case RI_HDMA4: + case RI_HDMA5: /* printf("HDMA %d: %02X\n", r - RI_HDMA1 + 1, b); */ break; } @@ -358,44 +271,44 @@ byte IRAM_ATTR ioreg_read(byte r) { switch(r) { - case RI_SC: + case RI_SC: r = R_SC; R_SC &= 0x7f; return r; - case RI_P1: - case RI_SB: - case RI_DIV: - case RI_TIMA: - case RI_TMA: - case RI_TAC: - case RI_LCDC: - case RI_STAT: - case RI_SCY: - case RI_SCX: - case RI_LY: - case RI_LYC: - case RI_BGP: - case RI_OBP0: - case RI_OBP1: - case RI_WY: - case RI_WX: - case RI_IE: - case RI_IF: + case RI_P1: + case RI_SB: + case RI_DIV: + case RI_TIMA: + case RI_TMA: + case RI_TAC: + case RI_LCDC: + case RI_STAT: + case RI_SCY: + case RI_SCX: + case RI_LY: + case RI_LYC: + case RI_BGP: + case RI_OBP0: + case RI_OBP1: + case RI_WY: + case RI_WX: + case RI_IE: + case RI_IF: return REG(r); - case RI_VBK: - case RI_BCPS: - case RI_OCPS: - case RI_BCPD: - case RI_OCPD: - case RI_SVBK: - case RI_KEY1: - case RI_HDMA1: - case RI_HDMA2: - case RI_HDMA3: - case RI_HDMA4: - case RI_HDMA5: + case RI_VBK: + case RI_BCPS: + case RI_OCPS: + case RI_BCPD: + case RI_OCPD: + case RI_SVBK: + case RI_KEY1: + case RI_HDMA1: + case RI_HDMA2: + case RI_HDMA3: + case RI_HDMA4: + case RI_HDMA5: if (hw.cgb) return REG(r); - default: + default: return 0xff; } } @@ -418,17 +331,17 @@ void IRAM_ATTR mbc_write(int a, byte b) /* printf("mbc %d: rom bank %02X -[%04X:%02X]-> ", mbc.type, mbc.rombank, a, b); */ switch (mbc.type) { - case MBC_MBC1: + case MBC_MBC1: switch (ha & 0xE) { - case 0x0: + case 0x0: mbc.enableram = ((b & 0x0F) == 0x0A); break; - case 0x2: + case 0x2: if ((b & 0x1F) == 0) b = 0x01; mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F); break; - case 0x4: + case 0x4: if (mbc.model) { mbc.rambank = b & 0x03; @@ -436,7 +349,7 @@ void IRAM_ATTR mbc_write(int a, byte b) } mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5); break; - case 0x6: + case 0x6: mbc.model = b & 0x1; break; } @@ -455,59 +368,58 @@ void IRAM_ATTR mbc_write(int a, byte b) } break; - case MBC_MBC3: + case MBC_MBC3: switch (ha & 0xE) { - case 0x0: + case 0x0: mbc.enableram = ((b & 0x0F) == 0x0A); break; - case 0x2: + case 0x2: if ((b & 0x7F) == 0) b = 0x01; mbc.rombank = b & 0x7F; break; - case 0x4: + case 0x4: rtc.sel = b & 0x0f; mbc.rambank = b & 0x03; break; - case 0x6: + case 0x6: rtc_latch(b); break; } break; - case MBC_RUMBLE: + case MBC_RUMBLE: switch (ha & 0xF) { - case 0x4: - case 0x5: + case 0x4: + case 0x5: /* FIXME - save high bit as rumble state */ /* mask off high bit */ b &= 0x7; break; } /* fall thru */ - case MBC_MBC5: + case MBC_MBC5: switch (ha & 0xF) { - case 0x0: - case 0x1: + case 0x0: + case 0x1: mbc.enableram = ((b & 0x0F) == 0x0A); break; - case 0x2: + case 0x2: //if ((b & 0xFF) == 0) b = 0x01; mbc.rombank = (mbc.rombank & 0x100) | (b); break; - case 0x3: + case 0x3: mbc.rombank = (mbc.rombank & 0x0FF) | ((int)(b&1)<<8); break; - case 0x4: - case 0x5: + case 0x4: + case 0x5: mbc.rambank = b & 0x0f; //printf("MBC5: Mapped rambank=%d\n", mbc.rambank); break; - default: - // FIXME: what does this do and why do we get here? - // printf("MBC_MBC5: invalid write to 0x%x (0x%x)\n", a, b); + default: + printf("MBC_MBC5: invalid write to 0x%x (0x%x)\n", a, b); break; } break; @@ -515,14 +427,14 @@ void IRAM_ATTR mbc_write(int a, byte b) case MBC_HUC1: /* FIXME - this is all guesswork -- is it right??? */ switch (ha & 0xE) { - case 0x0: + case 0x0: mbc.enableram = ((b & 0x0F) == 0x0A); break; - case 0x2: + case 0x2: if ((b & 0x1F) == 0) b = 0x01; mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F); break; - case 0x4: + case 0x4: if (mbc.model) { mbc.rambank = b & 0x03; @@ -530,27 +442,27 @@ void IRAM_ATTR mbc_write(int a, byte b) } mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5); break; - case 0x6: + case 0x6: mbc.model = b & 0x1; break; } break; - case MBC_HUC3: + case MBC_HUC3: switch (ha & 0xE) { - case 0x0: + case 0x0: mbc.enableram = ((b & 0x0F) == 0x0A); break; - case 0x2: + case 0x2: b &= 0x7F; mbc.rombank = b ? b : 1; break; - case 0x4: + case 0x4: rtc.sel = b & 0x0f; mbc.rambank = b & 0x03; break; - case 0x6: + case 0x6: rtc_latch(b); break; } @@ -576,17 +488,17 @@ void IRAM_ATTR mem_write(int a, byte b) /* printf("write to 0x%04X: 0x%02X\n", a, b); */ switch (ha) { - case 0x0: - case 0x2: - case 0x4: - case 0x6: + case 0x0: + case 0x2: + case 0x4: + case 0x6: mbc_write(a, b); break; - case 0x8: + case 0x8: /* if ((R_STAT & 0x03) == 0x03) break; */ vram_write(a & 0x1FFF, b); break; - case 0xA: + case 0xA: if (!mbc.enableram) break; if (rtc.sel&8) { @@ -610,7 +522,7 @@ void IRAM_ATTR mem_write(int a, byte b) //printf("mem_write: bank=%d, sram %p=0x%d\n", mbc.rambank, (void*)(a & 0x1fff), b); //printf("mem_write: check - write=0x%x, read=0x%x\n", b, ram.sbank[mbc.rambank][a & 0x1FFF]); break; - case 0xC: + case 0xC: if ((a & 0xF000) == 0xC000) { ram.ibank[0][a & 0x0FFF] = b; @@ -619,7 +531,7 @@ void IRAM_ATTR mem_write(int a, byte b) n = R_SVBK & 0x07; ram.ibank[n?n:1][a & 0x0FFF] = b; break; - case 0xE: + case 0xE: if (a < 0xFE00) { mem_write(a & 0xDFFF, b); @@ -665,17 +577,17 @@ byte IRAM_ATTR mem_read(int a) switch (ha) { - case 0x0: - case 0x2: + case 0x0: + case 0x2: //if (a >= 16384) return 0xff; return rom.bank[0][a & 0x3fff]; - case 0x4: - case 0x6: + case 0x4: + case 0x6: return rom.bank[mbc.rombank][a & 0x3FFF]; - case 0x8: + case 0x8: /* if ((R_STAT & 0x03) == 0x03) return 0xFF; */ return lcd.vbank[R_VBK&1][a & 0x1FFF]; - case 0xA: + case 0xA: if (!mbc.enableram && mbc.type == MBC_HUC3) return 0x01; if (!mbc.enableram) @@ -690,12 +602,12 @@ byte IRAM_ATTR mem_read(int a) __asm__("memw"); //printf("mem_read: bank=%d, sram %p=0x%d\n", mbc.rambank, (void*)(a & 0x1fff), ram.sbank[mbc.rambank][a & 0x1FFF]); return ram.sbank[mbc.rambank][a & 0x1FFF]; - case 0xC: + case 0xC: if ((a & 0xF000) == 0xC000) return ram.ibank[0][a & 0x0FFF]; n = R_SVBK & 0x07; return ram.ibank[n?n:1][a & 0x0FFF]; - case 0xE: + case 0xE: if (a < 0xFE00) return mem_read(a & 0xDFFF); if ((a & 0xFF00) == 0xFE00) { diff --git a/components/gnuboy/newsound.c b/components/gnuboy/src/newsound.c similarity index 100% rename from components/gnuboy/newsound.c rename to components/gnuboy/src/newsound.c diff --git a/components/gnuboy/palette.c b/components/gnuboy/src/palette.c similarity index 96% rename from components/gnuboy/palette.c rename to components/gnuboy/src/palette.c index b0c93d23..2ce7f590 100644 --- a/components/gnuboy/palette.c +++ b/components/gnuboy/src/palette.c @@ -1,9 +1,9 @@ #if 0 #include -#include "gnuboy.h" -#include "defs.h" -#include "fb.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/fb.h" static byte palmap[32768]; diff --git a/components/gnuboy/path.c b/components/gnuboy/src/path.c similarity index 96% rename from components/gnuboy/path.c rename to components/gnuboy/src/path.c index 09471cc9..8f9b7945 100644 --- a/components/gnuboy/path.c +++ b/components/gnuboy/src/path.c @@ -2,7 +2,7 @@ #include #include -#include "gnuboy.h" +#include "gnuboy/gnuboy.h" #ifdef ALT_PATH_SEP #define SEP ';' diff --git a/components/gnuboy/rccmds.c b/components/gnuboy/src/rccmds.c similarity index 96% rename from components/gnuboy/rccmds.c rename to components/gnuboy/src/rccmds.c index 5efa0eed..c7dbdca0 100644 --- a/components/gnuboy/rccmds.c +++ b/components/gnuboy/src/rccmds.c @@ -1,11 +1,11 @@ #include #include -#include "gnuboy.h" -#include "defs.h" -#include "rc.h" -#include "hw.h" -#include "loader.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/rc.h" +#include "gnuboy/hw.h" +#include "gnuboy/loader.h" diff --git a/components/gnuboy/rcfile.c b/components/gnuboy/src/rcfile.c similarity index 83% rename from components/gnuboy/rcfile.c rename to components/gnuboy/src/rcfile.c index 71697b51..2d1055f2 100644 --- a/components/gnuboy/rcfile.c +++ b/components/gnuboy/src/rcfile.c @@ -3,10 +3,10 @@ #include #include -#include "gnuboy.h" -#include "defs.h" -#include "rc.h" -#include "hw.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/rc.h" +#include "gnuboy/hw.h" char *rcpath; diff --git a/components/gnuboy/rckeys.c b/components/gnuboy/src/rckeys.c similarity index 89% rename from components/gnuboy/rckeys.c rename to components/gnuboy/src/rckeys.c index 22157311..3aa8d8de 100644 --- a/components/gnuboy/rckeys.c +++ b/components/gnuboy/src/rckeys.c @@ -2,10 +2,10 @@ #include #include -#include "gnuboy.h" -#include "defs.h" -#include "rc.h" -#include "input.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/rc.h" +#include "gnuboy/input.h" char *keybind[MAX_KEYS]; diff --git a/components/gnuboy/rcvars.c b/components/gnuboy/src/rcvars.c similarity index 97% rename from components/gnuboy/rcvars.c rename to components/gnuboy/src/rcvars.c index bd57946d..c4c6aee3 100644 --- a/components/gnuboy/rcvars.c +++ b/components/gnuboy/src/rcvars.c @@ -2,9 +2,9 @@ #include #include -#include "gnuboy.h" -#include "defs.h" -#include "rc.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/rc.h" static rcvar_t *rcvars; diff --git a/components/gnuboy/refresh.c b/components/gnuboy/src/refresh.c similarity index 96% rename from components/gnuboy/refresh.c rename to components/gnuboy/src/refresh.c index 67adb4dc..ebc3c198 100644 --- a/components/gnuboy/refresh.c +++ b/components/gnuboy/src/refresh.c @@ -1,11 +1,11 @@ -#include "gnuboy.h" -#include "defs.h" -#include "lcd.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/lcd.h" #define BUF (scan.buf) #ifdef USE_ASM -#include "asm.h" +#include "gnuboy/asm.h" #endif diff --git a/components/gnuboy/rtc.c b/components/gnuboy/src/rtc.c similarity index 96% rename from components/gnuboy/rtc.c rename to components/gnuboy/src/rtc.c index 4e29f080..6b7aebde 100644 --- a/components/gnuboy/rtc.c +++ b/components/gnuboy/src/rtc.c @@ -4,10 +4,10 @@ #include #include -#include "defs.h" -#include "mem.h" -#include "rtc.h" -#include "rc.h" +#include "gnuboy/defs.h" +#include "gnuboy/mem.h" +#include "gnuboy/rtc.h" +#include "gnuboy/rc.h" struct rtc rtc; diff --git a/components/gnuboy/save.c b/components/gnuboy/src/save.c similarity index 96% rename from components/gnuboy/save.c rename to components/gnuboy/src/save.c index 01ee3550..e616e326 100644 --- a/components/gnuboy/save.c +++ b/components/gnuboy/src/save.c @@ -3,16 +3,16 @@ #include #include -#include "gnuboy.h" -#include "defs.h" -#include "cpu.h" -#include "cpuregs.h" -#include "hw.h" -#include "regs.h" -#include "lcd.h" -#include "rtc.h" -#include "mem.h" -#include "sound.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/cpu.h" +#include "gnuboy/cpuregs.h" +#include "gnuboy/hw.h" +#include "gnuboy/regs.h" +#include "gnuboy/lcd.h" +#include "gnuboy/rtc.h" +#include "gnuboy/mem.h" +#include "gnuboy/sound.h" diff --git a/components/gnuboy/sound.c b/components/gnuboy/src/sound.c similarity index 97% rename from components/gnuboy/sound.c rename to components/gnuboy/src/sound.c index 8555b601..7833d4c5 100644 --- a/components/gnuboy/sound.c +++ b/components/gnuboy/src/sound.c @@ -2,21 +2,19 @@ #include -#include "gnuboy.h" -#include "defs.h" -#include "pcm.h" -#include "sound.h" -#include "cpu.h" -#include "hw.h" -#include "regs.h" -#include "rc.h" -#include "noise.h" +#include "gnuboy/gnuboy.h" +#include "gnuboy/defs.h" +#include "gnuboy/pcm.h" +#include "gnuboy/sound.h" +#include "gnuboy/cpu.h" +#include "gnuboy/hw.h" +#include "gnuboy/regs.h" +#include "gnuboy/rc.h" +#include "gnuboy/noise.h" #include #include "freertos/FreeRTOS.h" -struct pcm pcm; - static const byte DRAM_ATTR dmgwave[16] = { 0xac, 0xdd, 0xda, 0x48, diff --git a/components/gnuboy/split.c b/components/gnuboy/src/split.c similarity index 100% rename from components/gnuboy/split.c rename to components/gnuboy/src/split.c diff --git a/components/nofrendo-esp32/video_audio.c b/components/nofrendo-esp32/video_audio.c index 6a663691..eefd0663 100644 --- a/components/nofrendo-esp32/video_audio.c +++ b/components/nofrendo-esp32/video_audio.c @@ -16,7 +16,6 @@ #include #include #include -// #include "driver/rtc_io.h" //Nes stuff wants to define this as well... #undef false @@ -95,13 +94,9 @@ static void osd_stopsound(void) static int osd_init_sound(void) { - audio_frame=malloc(4*DEFAULT_FRAGSIZE); - - // odroid_audio_init(odroid_settings_AudioSink_get(), DEFAULT_SAMPLERATE); + audio_frame=get_audio_buffer(); audio_init(); - audio_callback = NULL; - return 0; } @@ -123,7 +118,6 @@ static void clear(uint8 color); static bitmap_t *lock_write(void); static void free_write(int num_dirties, rect_t *dirty_rects); static void custom_blit(bitmap_t *bmp, int num_dirties, rect_t *dirty_rects); -static char fb[1]; //dummy QueueHandle_t vidQueue; @@ -141,21 +135,6 @@ viddriver_t sdlDriver = false /* invalidate flag */ }; - // GB -#define GAMEBOY_WIDTH (160) -#define GAMEBOY_HEIGHT (144) - - -// SMS -#define SMS_WIDTH (256) -#define SMS_HEIGHT (192) - -#define GAMEGEAR_WIDTH (160) -#define GAMEGEAR_HEIGHT (144) - -#define PIXEL_MASK (0x1F) - - // NES #define NES_GAME_WIDTH (256) #define NES_GAME_HEIGHT (224) /* NES_VISIBLE_HEIGHT */ @@ -173,6 +152,7 @@ void ili9341_write_frame_nes(const uint8_t* buffer, uint16_t* myPalette, uint8_t // width/height are just the NES_GAME_WIDTH/HEIGHT lcd_set_drawing_frame(0, 0, NES_GAME_WIDTH-1, NES_GAME_HEIGHT-1); + // uint16_t* line_buffer = get_frame_buffer(); uint16_t* line_buffer = get_vram0(); for (y = 0; y < NES_GAME_HEIGHT; y += LINE_COUNT) { int linesWritten = 0; @@ -254,7 +234,7 @@ static void clear(uint8 color) static bitmap_t *lock_write(void) { // SDL_LockSurface(mySurface); - myBitmap = bmp_createhw((uint8*)fb, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_WIDTH*2); + myBitmap = bmp_createhw((uint8*)get_frame_buffer(), DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_WIDTH*2); return myBitmap; } @@ -264,8 +244,9 @@ static void free_write(int num_dirties, rect_t *dirty_rects) bmp_destroy(&myBitmap); } -static uint8_t lcdfb[256 * 224]; +// static uint8_t lcdfb[256 * 224]; static void custom_blit(bitmap_t *bmp, int num_dirties, rect_t *dirty_rects) { + uint8_t *lcdfb = get_frame_buffer(); if (bmp->line[0] != NULL) { memcpy(lcdfb, bmp->line[0], 256 * 224); @@ -349,36 +330,21 @@ static int ConvertJoystickInput() static struct InputState state; get_input_state(&state); - // A - if (state.a) + if (!state.a) result |= (1<<13); - - // B - if (state.b) + if (!state.b) result |= (1 << 14); - - // select - if (state.select) + if (!state.select) result |= (1 << 0); - - // start - if (state.start) + if (!state.start) result |= (1 << 3); - - // left - if (state.left) + if (!state.right) result |= (1 << 5); - - // right - if (state.right) + if (!state.left) result |= (1 << 7); - - // down - if (state.down) + if (!state.up) result |= (1 << 4); - - // up - if (state.up) + if (!state.down) result |= (1 << 6); return result; @@ -395,10 +361,6 @@ void osd_getinput(void) 0,0,0,0,event_soft_reset,event_joypad1_a,event_joypad1_b,event_hard_reset }; static int oldb=0xffff; - // we have to call touchpad_read to determine if the user needs to quit... - uint8_t _num_touches, _btn_state; - uint16_t _x,_y; - touchpad_read(&_num_touches, &_x, &_y, &_btn_state); if (user_quit()) { nes_poweroff(); } @@ -407,7 +369,6 @@ void osd_getinput(void) int x; oldb=b; event_t evh; -// printf("Input: %x\n", b); for (x=0; x<16; x++) { if (chg&1) { evh=event_get(ev[x]); diff --git a/components/nofrendo/bitmap.c b/components/nofrendo/bitmap.c index 4b064a24..a2ad385c 100644 --- a/components/nofrendo/bitmap.c +++ b/components/nofrendo/bitmap.c @@ -29,6 +29,9 @@ #include #include +#include "spi_lcd.h" +#include "esp_heap_caps.h" + void bmp_clear(const bitmap_t *bitmap, uint8 color) { memset(bitmap->data, color, bitmap->pitch * bitmap->height); @@ -77,25 +80,20 @@ static bitmap_t *_make_bitmap(uint8 *data_addr, bool hw, int width, /* Allocate and initialize a bitmap structure */ #define FRAME_BUFFER_LENGTH ((256 + (2 * 8)) * 240) -uint8 frameBuffer[FRAME_BUFFER_LENGTH]; +static uint8 *frameBuffer = NULL; // [FRAME_BUFFER_LENGTH]; bitmap_t *bmp_create(int width, int height, int overdraw) { - printf("bmp_create: width=%d, height=%d, overdraw=%d\n", width, height, overdraw); + printf("bmp_create: width=%d, height=%d, overdraw=%d\n", width, height, overdraw); uint8 *addr; int pitch; pitch = width + (overdraw * 2); /* left and right */ - //addr = _my_malloc((pitch * height) + 3); /* add max 32-bit aligned adjustment */ - //if (NULL == addr) - // return NULL; - - if (pitch * height > FRAME_BUFFER_LENGTH) - { - abort(); - } - - addr = frameBuffer; + // addr = get_frame_buffer(); + if (frameBuffer == NULL) { + frameBuffer = (uint8*)heap_caps_malloc(FRAME_BUFFER_LENGTH, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + } + addr = frameBuffer; return _make_bitmap(addr, false, width, height, width, overdraw); } diff --git a/components/nofrendo/cpu/nes6502.c b/components/nofrendo/cpu/nes6502.c index 7887dad3..5a7db41d 100644 --- a/components/nofrendo/cpu/nes6502.c +++ b/components/nofrendo/cpu/nes6502.c @@ -40,7 +40,7 @@ #define ADD_CYCLES(x) \ { \ remaining_cycles -= (x); \ - cpu.total_cycles += (x); \ + nes_cpu.total_cycles += (x); \ } /* @@ -554,9 +554,9 @@ { \ i_flag = 0; \ ADD_CYCLES(2); \ - if (cpu.int_pending && remaining_cycles > 0) \ + if (nes_cpu.int_pending && remaining_cycles > 0) \ { \ - cpu.int_pending = 0; \ + nes_cpu.int_pending = 0; \ IRQ_PROC(); \ ADD_CYCLES(INT_CYCLES); \ } \ @@ -686,8 +686,8 @@ #define JAM() \ { \ PC--; \ - cpu.jammed = true; \ - cpu.int_pending = 0; \ + nes_cpu.jammed = true; \ + nes_cpu.int_pending = 0; \ ADD_CYCLES(2); \ } #endif /* !NES6502_TESTOPS */ @@ -896,9 +896,9 @@ PC = PULL(); \ PC |= PULL() << 8; \ ADD_CYCLES(6); \ - if (0 == i_flag && cpu.int_pending && remaining_cycles > 0) \ + if (0 == i_flag && nes_cpu.int_pending && remaining_cycles > 0) \ { \ - cpu.int_pending = 0; \ + nes_cpu.int_pending = 0; \ IRQ_PROC(); \ ADD_CYCLES(INT_CYCLES); \ } \ @@ -1133,7 +1133,7 @@ /* internal CPU context */ -nes6502_context cpu; +nes6502_context nes_cpu; static int remaining_cycles = 0; /* so we can release timeslice */ /* memory region pointers */ static uint8 *ram = NULL, *stack = NULL; @@ -1164,7 +1164,7 @@ INLINE uint32 bank_readword(register uint32 address) ** be fetching a word across page boundaries, which only would ** make sense if the banks were physically consecutive. */ - return (uint32) (*(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK))); + return (uint32) (*(uint16 *)(nes_cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK))); } #else /* !HOST_LITTLE_ENDIAN */ @@ -1182,9 +1182,9 @@ INLINE uint32 zp_readword(register uint8 address) INLINE uint32 bank_readword(register uint32 address) { #ifdef TARGET_CPU_PPC - return __lhbrx(cpu.mem_page[address >> NES6502_BANKSHIFT], address & NES6502_BANKMASK); + return __lhbrx(nes_cpu.mem_page[address >> NES6502_BANKSHIFT], address & NES6502_BANKMASK); #else /* !TARGET_CPU_PPC */ - uint32 x = (uint32) *(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK)); + uint32 x = (uint32) *(uint16 *)(nes_cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK)); return (x << 8) | (x >> 8); #endif /* !TARGET_CPU_PPC */ } @@ -1193,12 +1193,12 @@ INLINE uint32 bank_readword(register uint32 address) INLINE uint8 bank_readbyte(register uint32 address) { - return cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK]; + return nes_cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK]; } INLINE void bank_writebyte(register uint32 address, register uint8 value) { - cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK] = value; + nes_cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK] = value; } /* read a byte of 6502 memory */ @@ -1220,7 +1220,7 @@ static uint8 mem_readbyte(uint32 address) /* check memory range handlers */ else { - for (mr = cpu.read_handler; mr->min_range != 0xFFFFFFFF; mr++) + for (mr = nes_cpu.read_handler; mr->min_range != 0xFFFFFFFF; mr++) { if (address >= mr->min_range && address <= mr->max_range) return mr->read_func(address); @@ -1245,7 +1245,7 @@ static void mem_writebyte(uint32 address, uint8 value) /* check memory range handlers */ else { - for (mw = cpu.write_handler; mw->min_range != 0xFFFFFFFF; mw++) + for (mw = nes_cpu.write_handler; mw->min_range != 0xFFFFFFFF; mw++) { if (address >= mw->min_range && address <= mw->max_range) { @@ -1266,16 +1266,16 @@ void nes6502_setcontext(nes6502_context *context) ASSERT(context); - cpu = *context; + nes_cpu = *context; /* set dead page for all pages not pointed at anything */ for (loop = 0; loop < NES6502_NUMBANKS; loop++) { - if (NULL == cpu.mem_page[loop]) - cpu.mem_page[loop] = null_page; + if (NULL == nes_cpu.mem_page[loop]) + nes_cpu.mem_page[loop] = null_page; } - ram = cpu.mem_page[0]; /* quick zero-page/RAM references */ + ram = nes_cpu.mem_page[0]; /* quick zero-page/RAM references */ stack = ram + STACK_OFFSET; } @@ -1286,7 +1286,7 @@ void nes6502_getcontext(nes6502_context *context) ASSERT(context); - *context = cpu; + *context = nes_cpu; /* reset dead pages to null */ for (loop = 0; loop < NES6502_NUMBANKS; loop++) @@ -1305,32 +1305,32 @@ uint8 nes6502_getbyte(uint32 address) /* get number of elapsed cycles */ uint32 nes6502_getcycles(bool reset_flag) { - uint32 cycles = cpu.total_cycles; + uint32 cycles = nes_cpu.total_cycles; if (reset_flag) - cpu.total_cycles = 0; + nes_cpu.total_cycles = 0; return cycles; } #define GET_GLOBAL_REGS() \ { \ - PC = cpu.pc_reg; \ - A = cpu.a_reg; \ - X = cpu.x_reg; \ - Y = cpu.y_reg; \ - SCATTER_FLAGS(cpu.p_reg); \ - S = cpu.s_reg; \ + PC = nes_cpu.pc_reg; \ + A = nes_cpu.a_reg; \ + X = nes_cpu.x_reg; \ + Y = nes_cpu.y_reg; \ + SCATTER_FLAGS(nes_cpu.p_reg); \ + S = nes_cpu.s_reg; \ } #define STORE_LOCAL_REGS() \ { \ - cpu.pc_reg = PC; \ - cpu.a_reg = A; \ - cpu.x_reg = X; \ - cpu.y_reg = Y; \ - cpu.p_reg = COMBINE_FLAGS(); \ - cpu.s_reg = S; \ + nes_cpu.pc_reg = PC; \ + nes_cpu.a_reg = A; \ + nes_cpu.x_reg = X; \ + nes_cpu.y_reg = Y; \ + nes_cpu.p_reg = COMBINE_FLAGS(); \ + nes_cpu.s_reg = S; \ } #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -1368,7 +1368,7 @@ uint32 nes6502_getcycles(bool reset_flag) */ int nes6502_execute(int timeslice_cycles) { - int old_cycles = cpu.total_cycles; + int old_cycles = nes_cpu.total_cycles; uint32 temp, addr; /* for macros */ uint8 btemp, baddr; /* for macros */ @@ -1427,18 +1427,18 @@ int nes6502_execute(int timeslice_cycles) GET_GLOBAL_REGS(); /* check for DMA cycle burning */ - if (cpu.burn_cycles && remaining_cycles > 0) + if (nes_cpu.burn_cycles && remaining_cycles > 0) { int burn_for; - burn_for = MIN(remaining_cycles, cpu.burn_cycles); + burn_for = MIN(remaining_cycles, nes_cpu.burn_cycles); ADD_CYCLES(burn_for); - cpu.burn_cycles -= burn_for; + nes_cpu.burn_cycles -= burn_for; } - if (0 == i_flag && cpu.int_pending && remaining_cycles > 0) + if (0 == i_flag && nes_cpu.int_pending && remaining_cycles > 0) { - cpu.int_pending = 0; + nes_cpu.int_pending = 0; IRQ_PROC(); ADD_CYCLES(INT_CYCLES); } @@ -2400,18 +2400,18 @@ int nes6502_execute(int timeslice_cycles) STORE_LOCAL_REGS(); /* Return our actual amount of executed cycles */ - return (cpu.total_cycles - old_cycles); + return (nes_cpu.total_cycles - old_cycles); } /* Issue a CPU Reset */ void nes6502_reset(void) { - cpu.p_reg = Z_FLAG | R_FLAG | I_FLAG; /* Reserved bit always 1 */ - cpu.int_pending = 0; /* No pending interrupts */ - cpu.int_latency = 0; /* No latent interrupts */ - cpu.pc_reg = bank_readword(RESET_VECTOR); /* Fetch reset vector */ - cpu.burn_cycles = RESET_CYCLES; - cpu.jammed = false; + nes_cpu.p_reg = Z_FLAG | R_FLAG | I_FLAG; /* Reserved bit always 1 */ + nes_cpu.int_pending = 0; /* No pending interrupts */ + nes_cpu.int_latency = 0; /* No latent interrupts */ + nes_cpu.pc_reg = bank_readword(RESET_VECTOR); /* Fetch reset vector */ + nes_cpu.burn_cycles = RESET_CYCLES; + nes_cpu.jammed = false; } /* following macro is used for below 2 functions */ @@ -2426,11 +2426,11 @@ void nes6502_nmi(void) { DECLARE_LOCAL_REGS - if (false == cpu.jammed) + if (false == nes_cpu.jammed) { GET_GLOBAL_REGS(); NMI_PROC(); - cpu.burn_cycles += INT_CYCLES; + nes_cpu.burn_cycles += INT_CYCLES; STORE_LOCAL_REGS(); } } @@ -2440,17 +2440,17 @@ void nes6502_irq(void) { DECLARE_LOCAL_REGS - if (false == cpu.jammed) + if (false == nes_cpu.jammed) { GET_GLOBAL_REGS(); if (0 == i_flag) { IRQ_PROC(); - cpu.burn_cycles += INT_CYCLES; + nes_cpu.burn_cycles += INT_CYCLES; } else { - cpu.int_pending = 1; + nes_cpu.int_pending = 1; } STORE_LOCAL_REGS(); } @@ -2459,7 +2459,7 @@ void nes6502_irq(void) /* Set dead cycle period */ void nes6502_burn(int cycles) { - cpu.burn_cycles += cycles; + nes_cpu.burn_cycles += cycles; } /* Release our timeslice */ diff --git a/components/nofrendo/nes/nes.c b/components/nofrendo/nes/nes.c index c50f5252..59f92344 100644 --- a/components/nofrendo/nes/nes.c +++ b/components/nofrendo/nes/nes.c @@ -364,18 +364,19 @@ extern bool forceConsoleReset; /* main emulation loop */ void nes_emulate(void) { + nes_prep_emulation(); + while (false == nes.poweroff) + { + nes_emulateframe(0); + } +} + +void nes_prep_emulation() { osd_setsound(nes.apu->process); nes.scanline_cycles = 0; nes.fiq_cycles = (int) NES_FIQ_PERIOD; - float totalElapsedTime = 0; - int frame = 0; - int skipFrame = 0; - - struct timeval tv_start; - struct timeval tv_stop; - for (int i = 0; i < 4; ++i) { nes_renderframe(1); @@ -388,36 +389,48 @@ void nes_emulate(void) { nes_reset(SOFT_RESET); } + nes_emulateframe(1); +} - while (false == nes.poweroff) - { - gettimeofday(&tv_start, NULL); +void nes_emulateframe(unsigned char reset) { + static float totalElapsedTime = 0; + static int frame = 0; + static int skipFrame = 0; + if (reset) { + frame = skipFrame = 0; + totalElapsedTime = 0; + } + + struct timeval tv_start; + struct timeval tv_stop; + + gettimeofday(&tv_start, NULL); - bool renderFrame = ((skipFrame % 2) == 0); + // if skipframe is 0 or 2 we don't render + bool renderFrame = ((skipFrame % 2) == 0); - nes_renderframe(renderFrame); - system_video(renderFrame); + nes_renderframe(renderFrame); + system_video(renderFrame); - if (skipFrame % 7 == 0) ++skipFrame; - ++skipFrame; + // if skipframe is 7 or 0, we increment + if (skipFrame % 7 == 0) ++skipFrame; + ++skipFrame; - do_audio_frame(); + do_audio_frame(); - gettimeofday(&tv_stop, NULL); + gettimeofday(&tv_stop, NULL); - float time_sec = tv_stop.tv_sec - tv_start.tv_sec + 1e-6f * (tv_stop.tv_usec - tv_start.tv_usec); - totalElapsedTime += time_sec; - ++frame; + float time_sec = tv_stop.tv_sec - tv_start.tv_sec + 1e-6f * (tv_stop.tv_usec - tv_start.tv_usec); + totalElapsedTime += time_sec; + ++frame; - if (frame == 60) - { - float fps = frame / totalElapsedTime; + if (frame == 60) { + float fps = frame / totalElapsedTime; - printf("HEAP:0x%lx, FPS:%f\n", esp_get_free_heap_size(), fps); + printf("HEAP:0x%lx, FPS:%f\n", esp_get_free_heap_size(), fps); - frame = 0; - totalElapsedTime = 0; - } + frame = 0; + totalElapsedTime = 0; } } @@ -487,7 +500,7 @@ int nes_insertcart(const char *filename, nes_t *machine) nes6502_setcontext(machine->cpu); /* rom file */ - machine->rominfo = rom_load(filename); + machine->rominfo = nes_rom_load(filename); if (NULL == machine->rominfo) goto _fail; diff --git a/components/nofrendo/nes/nes.h b/components/nofrendo/nes/nes.h index 39b28af3..c614bddc 100644 --- a/components/nofrendo/nes/nes.h +++ b/components/nofrendo/nes/nes.h @@ -106,6 +106,8 @@ extern void nes_setfiq(uint8 state); extern void nes_nmi(void); extern void nes_irq(void); extern void nes_emulate(void); +extern void nes_prep_emulation(void); +extern void nes_emulateframe(unsigned char reset); extern void nes_reset(int reset_type); diff --git a/components/nofrendo/nes/nes_rom.c b/components/nofrendo/nes/nes_rom.c index 80d151a8..b414e0bd 100644 --- a/components/nofrendo/nes/nes_rom.c +++ b/components/nofrendo/nes/nes_rom.c @@ -437,7 +437,7 @@ char *rom_getinfo(rominfo_t *rominfo) } /* Load a ROM image into memory */ -rominfo_t *rom_load(const char *filename) +rominfo_t *nes_rom_load(const char *filename) { unsigned char *rom=(unsigned char*)osd_getromdata(); rominfo_t *rominfo; diff --git a/components/nofrendo/nes/nes_rom.h b/components/nofrendo/nes/nes_rom.h index ba86d2f6..ae126e5b 100644 --- a/components/nofrendo/nes/nes_rom.h +++ b/components/nofrendo/nes/nes_rom.h @@ -62,7 +62,7 @@ typedef struct rominfo_s extern int rom_checkmagic(const char *filename); -extern rominfo_t *rom_load(const char *filename); +extern rominfo_t *nes_rom_load(const char *filename); extern void rom_free(rominfo_t **rominfo); extern char *rom_getinfo(rominfo_t *rominfo); diff --git a/main/gameboy.cpp b/main/gameboy.cpp new file mode 100644 index 00000000..4bd6302a --- /dev/null +++ b/main/gameboy.cpp @@ -0,0 +1,193 @@ +#include "gameboy.hpp" + +#include +#include "format.hpp" +#include "spi_lcd.h" +#include "i2s_audio.h" +#include "input.h" +#include "st7789.hpp" +#include "task.hpp" + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" + +static const size_t gameboy_screen_width = 160; + +#if USE_GAMEBOY_GNUBOY +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +} + +uint16_t* displayBuffer[2]; +struct fb fb; +struct pcm pcm; +uint8_t currentBuffer; +uint16_t* framebuffer; +int frame = 0; +uint elapsedTime = 0; + +#define AUDIO_SAMPLE_RATE (16000) + +int32_t* audioBuffer[2]; +volatile uint8_t currentAudioBuffer = 0; +volatile uint16_t currentAudioSampleCount; +volatile int32_t* currentAudioBufferPtr; + +extern "C" void die(char *fmt, ...) { + fmt::print("DIE!\n"); +} + +static std::shared_ptr gbc_task; + +void run_to_vblank(std::mutex &m, std::condition_variable& cv) +{ + /* FRAME BEGIN */ + static auto start = std::chrono::high_resolution_clock::now(); + + /* FIXME: djudging by the time specified this was intended + to emulate through vblank phase which is handled at the + end of the loop. */ + cpu_emulate(2280); + + /* FIXME: R_LY >= 0; comparsion to zero can also be removed + altogether, R_LY is always 0 at this point */ + while (R_LY > 0 && R_LY < 144) + { + emu_step(); + } + + /* VBLANK BEGIN */ + + //vid_end(); + if ((frame % 2) == 0) { + // xQueueSend(video_q, &framebuffer, portMAX_DELAY); + auto _frame = displayBuffer[currentBuffer]; + for (int y=0; y<144; y+=48) { + lcd_write_frame(0, y, 160, 48, (uint8_t*)&_frame[y*160]); + } + // swap buffers + // currentBuffer = currentBuffer ? 0 : 1; + // framebuffer = displayBuffer[currentBuffer]; + // fb.ptr = (uint8_t*)framebuffer; + } + + rtc_tick(); + + sound_mix(); + + if (pcm.pos > 100) { + currentAudioBufferPtr = audioBuffer[currentAudioBuffer]; + currentAudioSampleCount = pcm.pos; + + // void* tempPtr = (void*)0x1234; + // xQueueSend(audio_q, &tempPtr, portMAX_DELAY); + audio_play_frame((uint8_t*)currentAudioBufferPtr, currentAudioSampleCount * 2); + + // Swap buffers + // currentAudioBuffer = currentAudioBuffer ? 0 : 1; + // pcm.buf = (int16_t*)audioBuffer[currentAudioBuffer]; + pcm.pos = 0; + } + + if (!(R_LCDC & 0x80)) { + /* LCDC operation stopped */ + /* FIXME: djudging by the time specified, this is + intended to emulate through visible line scanning + phase, even though we are already at vblank here */ + cpu_emulate(32832); + } + + while (R_LY > 0) { + /* Step through vblank phase */ + emu_step(); + } + ++frame; + if ((frame % 60) == 0) { + auto end = std::chrono::high_resolution_clock::now(); + float elapsed = std::chrono::duration(end - start).count(); + fmt::print("gameboy: FPS {}\n", (float) frame / elapsed); + } +} +#endif + +void init_gameboy(const std::string& rom_filename, uint8_t *romdata, size_t rom_data_size) { + // WIDTH = gameboy_screen_width, so 320-WIDTH is gameboy_screen_width + espp::St7789::set_offset((320-gameboy_screen_width) / 2, (240-144) / 2); + static bool initialized = false; + +#if USE_GAMEBOY_GNUBOY + // Note: Magic number obtained by adjusting until audio buffer overflows stop. + const int audioBufferLength = AUDIO_SAMPLE_RATE / 3 + 1; // / 10 + //printf("CHECKPOINT AUDIO: HEAP:0x%x - allocating 0x%x\n", esp_get_free_heap_size(), audioBufferLength * sizeof(int16_t) * 2 * 2); + const int AUDIO_BUFFER_SIZE = audioBufferLength * sizeof(int16_t) * 2; + + if (!initialized) { + // displayBuffer[0] = (uint16_t*)heap_caps_malloc(160*144*2, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + // displayBuffer[1] = (uint16_t*)heap_caps_malloc(160*144*2, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + // audioBuffer[0] = (int32_t*)heap_caps_malloc(AUDIO_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + // audioBuffer[1] = (int32_t*)heap_caps_malloc(AUDIO_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + } + displayBuffer[0] = (uint16_t*)get_frame_buffer(); + displayBuffer[1] = (uint16_t*)get_frame_buffer(); + audioBuffer[0] = (int32_t*)get_audio_buffer(); + audioBuffer[1] = (int32_t*)get_audio_buffer(); + + memset(&fb, 0, sizeof(fb)); + fb.w = 160; + fb.h = 144; + fb.pelsize = 2; + fb.pitch = fb.w * fb.pelsize; + fb.indexed = 0; + fb.ptr = (uint8_t*)displayBuffer[0]; + fb.enabled = 1; + fb.dirty = 0; + framebuffer = displayBuffer[0]; + + // pcm.len = count of 16bit samples (x2 for stereo) + memset(&pcm, 0, sizeof(pcm)); + pcm.hz = AUDIO_SAMPLE_RATE; + pcm.stereo = 1; + pcm.len = /*pcm.hz / 2*/ audioBufferLength; + pcm.buf = (int16_t*)audioBuffer[0]; + pcm.pos = 0; + + sound_reset(); + + fmt::print("GAMEBOY enabled: GNUBOY\n"); + loader_init(romdata, rom_data_size); + emu_reset(); + initialized = true; + gbc_task = std::make_shared(espp::Task::Config{ + .name = "gbc task", + .callback = run_to_vblank, + .stack_size_bytes = 10*1024, + .priority = 20, + .core_id = 1 + }); + gbc_task->start(); +#endif +} + +void run_gameboy_rom() { + uint8_t _num_touches, _btn_state; + uint16_t _x,_y; + touchpad_read(&_num_touches, &_x, &_y, &_btn_state); +} + +void deinit_gameboy() { + fmt::print("quitting gameboy emulation!\n"); +#if USE_GAMEBOY_GNUBOY + loader_unload(); + gbc_task.reset(); +#endif +} diff --git a/main/gameboy.hpp b/main/gameboy.hpp index 5e684489..506d8269 100644 --- a/main/gameboy.hpp +++ b/main/gameboy.hpp @@ -1,72 +1,7 @@ #pragma once -#include -#include "format.hpp" -#include "spi_lcd.h" -#include "st7789.hpp" +#include -#ifdef USE_GAMEBOY_GAMEBOYCORE -#include "gameboycore/gameboycore.h" - -static std::shared_ptr core; -#endif -#ifdef USE_GAMEBOY_GNUBOY -extern "C" { -#include "gnuboy.h" -#include "loader.h" -} -#endif - -void init_gameboy(const std::string& rom_filename, uint8_t *romdata, size_t rom_data_size) { - // WIDTH = 160, so 320-WIDTH is 160 - espp::St7789::set_offset((320-160) / 2, 0); - -#ifdef USE_GAMEBOY_GAMEBOYCORE - fmt::print("GAMEBOY enabled: GAMEBOYCORE\n"); - - // Create an instance of the gameboy emulator core - core = std::make_shared(); - - // Set callbacks for video and audio - core->setScanlineCallback([](const gb::GPU::Scanline& scanline, int line){ - fmt::print("Line {}\n", line); - // scanline is just std::array, where pixel is uint8_t r,g,b - // make array of lv_color_t - static std::array color_data; - size_t index = 0; - for (auto &pixel : scanline) { - color_data[index++] = make_color(pixel.r, pixel.g, pixel.b); - } - lcd_write_frame(0, line, 160, 1, (const uint8_t*)&color_data[0]); - }); - core->setAudioSampleCallback([](int16_t l, int16_t r){ - fmt::print("L: {} R: {}\n", l, r); - }); - - fmt::print("Opening rom {}!\n", rom_filename); - core->loadROM(romdata, rom_data_size); -#endif -#ifdef USE_GAMEBOY_GNUBOY - fmt::print("GAMEBOY enabled: GNUBOY\n"); - loader_init_raw(romdata, rom_data_size); - emu_reset(); -#endif -} - -void run_gameboy_rom() { -#ifdef USE_GAMEBOY_GAMEBOYCORE - fmt::print("gameboycore: emulating frame\n"); - core->emulateFrame(); -#endif -#ifdef USE_GAMEBOY_GNUBOY - emu_run(); -#endif -} - -void deinit_gameboy() { -#ifdef USE_GAMEBOY_GAMEBOYCORE - core.reset(); -#endif -#ifdef USE_GAMEBOY_GNUBOY -#endif -} +void init_gameboy(const std::string& rom_filename, uint8_t *romdata, size_t rom_data_size); +void run_gameboy_rom(); +void deinit_gameboy(); diff --git a/main/main.cpp b/main/main.cpp index f95da459..59efb3f1 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -29,10 +29,15 @@ extern std::shared_ptr display; using namespace std::chrono_literals; -// NOTE: to see the indev configuration for the esp32 s3 box, look at -// bsp/src/boards/esp32_s3_box.c:56. Regarding whether it uses the FT5x06 or the -// TT21100, it uses the tp_prob function which checks to see if the devie -// addresses for those chips exist on the i2c bus (indev_tp.c:37) +// GB +#define GAMEBOY_WIDTH (160) +#define GAMEBOY_HEIGHT (144) +// SMS +#define SMS_WIDTH (256) +#define SMS_HEIGHT (192) +// GG +#define GAMEGEAR_WIDTH (160) +#define GAMEGEAR_HEIGHT (144) extern "C" void app_main(void) { fmt::print("Starting esp-box-emu...\n"); @@ -107,9 +112,10 @@ extern "C" void app_main(void) { while (!user_quit()) { run_gameboy_rom(); } + deinit_gameboy(); break; case Emulator::NES: - init_nes(rom_filename, display->vram0(), romdata, rom_size_bytes); + init_nes(rom_filename, romdata, rom_size_bytes); while (!user_quit()) { run_nes_rom(); } diff --git a/main/nes.cpp b/main/nes.cpp new file mode 100644 index 00000000..ca8cde23 --- /dev/null +++ b/main/nes.cpp @@ -0,0 +1,60 @@ +#include "nes.hpp" + +#ifdef USE_NES_NOFRENDO +extern "C" { +#include "event.h" +#include "gui.h" +#include +} + +static nes_t* console_nes; +#endif + +#include + +#include "format.hpp" +#include "spi_lcd.h" +#include "input.h" +#include "st7789.hpp" + +void init_nes(const std::string& rom_filename, uint8_t *romdata, size_t rom_data_size) { +#ifdef USE_NES_NOFRENDO + espp::St7789::set_offset((320-NES_SCREEN_WIDTH) / 2, 0); + + static bool initialized = false; + if (!initialized) { + event_init(); + osd_init(); + gui_init(); + vidinfo_t video; + osd_getvideoinfo(&video); + vid_init(video.default_width, video.default_height, video.driver); + console_nes = nes_create(); + event_set_system(system_nes); + } else { + nes_reset(HARD_RESET); + } + initialized = true; + + nes_insertcart(rom_filename.c_str(), console_nes); + vid_setmode(NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); + nes_prep_emulation(); +#endif +} + +void run_nes_rom() { + // we have to call touchpad_read to determine if the user needs to quit... + uint8_t _num_touches, _btn_state; + uint16_t _x,_y; + touchpad_read(&_num_touches, &_x, &_y, &_btn_state); +#ifdef USE_NES_NOFRENDO + nes_emulateframe(0); +#endif +} + +void deinit_nes() { +#ifdef USE_NES_NOFRENDO + nes_poweroff(); + nes_destroy(&console_nes); +#endif +} diff --git a/main/nes.hpp b/main/nes.hpp index ad76e20f..a30e5bd3 100644 --- a/main/nes.hpp +++ b/main/nes.hpp @@ -1,46 +1,7 @@ #pragma once -extern "C" { -#include "event.h" -#include "gui.h" -#include -} - #include -#include "format.hpp" -#include "spi_lcd.h" -#include "st7789.hpp" - -nes_t* console_nes; - -void init_nes(const std::string& rom_filename, uint16_t* vram_ptr, uint8_t *romdata, size_t rom_data_size) { - espp::St7789::set_offset((320-NES_SCREEN_WIDTH) / 2, 0); - - static bool initialized = false; - if (!initialized) { - event_init(); - osd_init(); - gui_init(); - vidinfo_t video; - osd_getvideoinfo(&video); - vid_init(video.default_width, video.default_height, video.driver); - console_nes = nes_create(); - event_set_system(system_nes); - } else { - nes_reset(HARD_RESET); - } - initialized = true; - - nes_insertcart(rom_filename.c_str(), console_nes); - vid_setmode(NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); -} - -void run_nes_rom() { - nes_emulate(); -} - -void deinit_nes() { - nes_poweroff(); - nes_destroy(&console_nes); -} +void init_nes(const std::string& rom_filename, uint8_t *romdata, size_t rom_data_size); +void run_nes_rom(); +void deinit_nes();