├── jni ├── Application.mk └── Android.mk ├── libretro ├── link.T ├── dmy_renderer.h ├── dmy_renderer.cpp └── libretro.cpp ├── .gitignore ├── Makefile.common ├── README ├── docs ├── PAR.txt ├── gbddk.txt ├── Netplay.txt ├── README.sdl ├── README.win32 └── COPYING-2.0.txt ├── .travis.yml ├── .github └── workflows │ └── compilation.yml ├── gb_core ├── gb_types.h ├── serializer.h ├── renderer.h ├── rom.cpp ├── cheat.cpp ├── gb.h ├── gb.cpp ├── op_cb.h ├── apu.cpp └── op_normal.h ├── gbr_interface ├── gbr.h └── gbr.cpp ├── .gitlab-ci.yml ├── libretro-common └── include │ └── compat │ └── msvc │ └── stdint.h └── Makefile /jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := all 2 | APP_STL := c++_static 3 | -------------------------------------------------------------------------------- /libretro/link.T: -------------------------------------------------------------------------------- 1 | { 2 | global: retro_*; 3 | local: *; 4 | }; 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | *.exe 5 | tgbdual 6 | .goutputstream-* 7 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | CORE_DIR := $(LOCAL_PATH)/.. 4 | 5 | include $(CORE_DIR)/Makefile.common 6 | 7 | COREFLAGS := -D__LIBRETRO__ -DFRONTEND_SUPPORTS_RGB565 $(INCFLAGS) 8 | 9 | GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" 10 | ifneq ($(GIT_VERSION)," unknown") 11 | COREFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" 12 | endif 13 | 14 | include $(CLEAR_VARS) 15 | LOCAL_MODULE := retro 16 | LOCAL_SRC_FILES := $(SOURCES_CXX) 17 | LOCAL_CFLAGS := $(COREFLAGS) 18 | LOCAL_LDFLAGS := -Wl,-version-script=$(CORE_DIR)/libretro/link.T 19 | include $(BUILD_SHARED_LIBRARY) 20 | -------------------------------------------------------------------------------- /Makefile.common: -------------------------------------------------------------------------------- 1 | LIBRETRO_COMM_DIR := $(CORE_DIR)/libretro-common 2 | INCFLAGS := -I$(CORE_DIR) \ 3 | -I$(CORE_DIR)/gb_core \ 4 | -I$(CORE_DIR)/libretro 5 | 6 | ifneq (,$(findstring msvc200,$(platform))) 7 | INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc 8 | endif 9 | 10 | SOURCES_CXX := $(CORE_DIR)/gb_core/apu.cpp \ 11 | $(CORE_DIR)/gb_core/cheat.cpp \ 12 | $(CORE_DIR)/gb_core/cpu.cpp \ 13 | $(CORE_DIR)/gb_core/gb.cpp \ 14 | $(CORE_DIR)/gb_core/lcd.cpp \ 15 | $(CORE_DIR)/gb_core/mbc.cpp \ 16 | $(CORE_DIR)/gb_core/rom.cpp \ 17 | $(CORE_DIR)/libretro/dmy_renderer.cpp \ 18 | $(CORE_DIR)/libretro/libretro.cpp 19 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | TGB Dual is an open source (GPLv2) GB/GBC emulator with game link cable support. 2 | 3 | This is a port of it to libretro. To emulate two units side by side, use 4 | the core options in your frontend. In older frontends, you'll need to use 5 | your frontend's "Sufami Turbo" interface, placing the ROMs in "slots" A and B. 6 | The Sufami Turbo BIOS itself can be any file; it is ignored by the emulator. 7 | Use the Player 1 and Player 2 controllers to control each unit. 8 | 9 | In addition, some of the Japanese comments in the source code have been run 10 | through Google Translate to English, and CP932 and EUC-JP encoded files have 11 | been converted to UTF-8. 12 | 13 | Original sources from 14 | http://gigo.retrogames.com/download.html#tgb-dual 15 | http://shinh.skr.jp/tgbdualsdl/ 16 | 17 | -------------------------------------------------------------------------------- /docs/PAR.txt: -------------------------------------------------------------------------------- 1 | 2 | GB-PAR TGB独自拡張に関する覚書 Second Release Version 3 | 4 | GB-PARのコードにはPS-PARなどにある 繰り返し、条件判定等のコードは存在していないように思われる。 5 | そこで、16進8桁というGB-PARの大原則に従いつつチートコードを拡張することにした。 6 | 7 | 注…以下に示す条件判定・繰り返しはいずれも8桁*2つで意味をなす。 8 | 1つ目は各々のコードに対応した値を、2つ目は01からのコードを記述する。 9 | 10 | 10…繰り返し 11 | アドレスで指定した間隔を空けて、指定した回数だけ連続したメモリに書き込む。 12 | 13 | 例・C000からの20バイトを255にする 14 | 10140000 15 | 01FF00C0 16 | 17 | 例・C859から4バイトおきに12回分255にする 18 | 100C0400 19 | 01FF59C8 20 | 21 | 20,21,22…条件判定 22 | 条件が満たされたときのみ2つ目のコードが有効になる 23 | ( 20…= , 21…< , 22…> ) 24 | 25 | 例・C888が85hの時のみC999を01にする 26 | 208588C8 27 | 010199C9 28 | 29 | 例・C888が80hより小さい時のみC999を80にする 30 | 218088C8 31 | 018099C9 32 | 33 | written by Hii 2000/10/31 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | os: linux 3 | dist: trusty 4 | sudo: required 5 | addons: 6 | apt: 7 | packages: 8 | - g++-7 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | env: 12 | global: 13 | - CORE=tgbdual 14 | - COMPILER_NAME=gcc CXX=g++-7 CC=gcc-7 15 | matrix: 16 | - PLATFORM=linux_x64 17 | - PLATFORM=3ds 18 | before_script: 19 | - pwd 20 | - mkdir -p ~/bin 21 | - ln -s /usr/bin/gcc-7 ~/bin/gcc 22 | - ln -s /usr/bin/g++-7 ~/bin/g++ 23 | - ln -s /usr/bin/cpp-7 ~/bin/cpp 24 | - export PATH=~/bin:$PATH 25 | - ls -l ~/bin 26 | - echo $PATH 27 | - g++-7 --version 28 | - g++ --version 29 | script: 30 | - cd ~/ 31 | - git clone --depth=50 https://github.com/libretro/libretro-super 32 | - cd libretro-super/travis 33 | - ./build.sh 34 | -------------------------------------------------------------------------------- /.github/workflows/compilation.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | repository_dispatch: 7 | types: [run_build] 8 | 9 | jobs: 10 | build-ps2: 11 | runs-on: ubuntu-latest 12 | container: ps2dev/ps2dev:latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Install dependencies 17 | run: | 18 | apk add build-base git bash 19 | 20 | - name: Compile project 21 | run: | 22 | make platform=ps2 clean all 23 | 24 | - name: Get short SHA 25 | id: slug 26 | run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" 27 | 28 | - name: Upload artifacts 29 | if: ${{ success() }} 30 | uses: actions/upload-artifact@v2 31 | with: 32 | name: tgbdual_libretro_ps2-${{ steps.slug.outputs.sha8 }} 33 | path: tgbdual_libretro_ps2.a 34 | -------------------------------------------------------------------------------- /docs/gbddk.txt: -------------------------------------------------------------------------------- 1 | 2 | TGB Device DLL 仕様書 3 | 4 | 1.エクスポートする関数: 5 | 6 | bool InitDevice(HWND hWnd,GBDEV_DAT *dat); 7 | デバイスの初期化を行います。 8 | 9 | void UninitDevice(void); 10 | デバイスの開放を行います 11 | 12 | void GetDeviceName(char *name); 13 | デバイス名(説明)を返します 14 | 15 | BYTE SerialTransfer(BYTE dat); 16 | GB側から転送されたときに呼ばれます 17 | 18 | bool GetInfraredLED(void); 19 | デバイスの赤外線LEDが点灯しているかどうかを返します 20 | そもそも赤外線が無い場合はOFFを返してください 21 | (1:ON 0:OFF) 22 | 23 | 24 | 2.GBDEV_DAT構造体 25 | TGB側が提供するサービスルーチンの集まりです 26 | 27 | struct GBDEV_DAT{ 28 | void(*trash_device)(); 29 | BYTE(*send_dat)(BYTE); 30 | bool(*get_led)(); 31 | }; 32 | 33 | ・trash_device 34 | これを呼ぶとGBからデバイスが切り離されます。 35 | trash_deviceからUninitDeviceが呼ばれます。 36 | 37 | ・send_dat 38 | デバイス側からGBにデータを送ります。 39 | (実際にはデータは交換されるので、デバイス側クロックでの通信と言うこと) 40 | 41 | ・get_led 42 | GBの赤外線LEDの状態が帰ります 43 | 44 | 45 | 3.出来ること(出来るかもしれないこと) 46 | ポケットプリンタ、リモコンシミュレータ、ポケットピカチュウ、… 47 | など、GBと通信を行うあらゆるデバイス。 48 | 実機との通信レイヤみたいなのも出来るかもしれません。 49 | -------------------------------------------------------------------------------- /gb_core/gb_types.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //----------------------------------------- 21 | // 型定義部 22 | 23 | #ifndef _GB_TYPES 24 | #define _GB_TYPES 25 | 26 | typedef unsigned char byte; 27 | typedef unsigned short word; 28 | typedef unsigned long dword; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /gb_core/serializer.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERIALIZER_H__ 2 | #define __SERIALIZER_H__ 3 | 4 | #include 5 | 6 | // convenience macros for common uses 7 | #define s_ARRAY(a) s.process((a), sizeof(a)) 8 | #define s_VAR(v) s.process(&(v), sizeof(v)) 9 | 10 | // short and simple serializing to buffer / file / thin air. 11 | // inspired by the much nicer one found in bsnes. 12 | class serializer 13 | { 14 | public: 15 | enum mode_t { COUNT, SAVE_BUF, LOAD_BUF }; 16 | serializer(void *target, mode_t mode) 17 | { 18 | my_mode = mode; 19 | my_target.ptr = target; 20 | } 21 | inline size_t process(void *data, size_t size) 22 | { 23 | switch(my_mode) { 24 | case COUNT: 25 | my_target.counter[0] += size; 26 | return size; 27 | case SAVE_BUF: 28 | memcpy(my_target.buf, data, size); 29 | my_target.buf += size; 30 | return size; 31 | case LOAD_BUF: 32 | memcpy(data, my_target.buf, size); 33 | my_target.buf += size; 34 | return size; 35 | default: 36 | break; 37 | } 38 | return 0; 39 | } 40 | private: 41 | mode_t my_mode; 42 | union { 43 | void *ptr; 44 | size_t *counter; 45 | unsigned char *buf; 46 | } my_target; 47 | }; 48 | 49 | #endif //__SERIALIZER_H__ 50 | 51 | -------------------------------------------------------------------------------- /docs/Netplay.txt: -------------------------------------------------------------------------------- 1 | 2 | TGB Dual ネット通信説明書 rev.1 3 | 4 | 通信の手順: 5 | 6 | 最初に、起動して直ぐの状態でメニューの通信を選びます。 7 | それ以外は不可です。 8 | 9 | 次に使用するROMを指定します。 10 | 自分と"相手側"の指定が必須ですが、 11 | 相手側にuse same rom image と入力するとそういうことも出来ます。(面倒な方へ) 12 | というか、デフォルトでそうしたので、違うROMで通信を行うとき以外は 13 | 相手側はいじらなくてOKです。 14 | (というか、実装者が面倒なんですね、安っぽいです) 15 | ここで注意! 16 | ☆存在しないファイル名を指定すると、落ちます。くれぐれも御間違いの無いように… 17 | 18 | 次にサーバ、クライアントのごたごたを決めます。 19 | サーバになる人は、サーバをチェックして、接続開始ボタンをクリックします。 20 | そのままクライアントの人が接続してくるまでお待ちください。 21 | クライアントになる人は、クライアントをチェックして、 22 | サーバの人に予め教えてもらったIPアドレスを入力してから接続開始ボタンをクリックします。 23 | (予め教えてもらう必要があります) 24 | ここで注意! 25 | ☆サーバが待機状態に入る前にクライアントが接続しようとすると、 26 | "異常"をきたします。ええ、それはもう、大変です。 27 | ですから何としても避けるのが得策と思われます。 28 | 29 | それが終わると、自動で、いろいろ前処理を行います。 30 | この前処理は3フェーズに分かれていて、 31 | 1、通信性能計測 32 | 2、通信前処理1 33 | 3、通信前処理2 34 | となっております。 35 | 36 | その後、一見普通に起動します。 37 | が、もうこの状態で通信が可能になっています。 38 | 因みにこのとき同時にチャットウインドウが開きます。 39 | このウインドウは閉じられません。 40 | (意図的にそうしてあります) 41 | 42 | あと、接続が切れるとロムは解放されます。 43 | それと、通信中にリセットは行えません。 44 | 45 | あとそれから、かなりマシンパワーがいるかもしれません。 46 | 目安はシングル起動時の1.5から2.0倍のマシン性能を要求します。 47 | フルフレーム描画で、60FPSに達しないときは、通信時は、エミュレーション速度が下がります。 48 | シングル起動、リミッタ無し、スキップ0で、100FPSを超えないマシンでの通信対戦は 49 | 出来なくは無いですが、あまりお勧めできません。 50 | (いや、ほんと、パワーで押し切って欲しいです…Pentium4 1.5GHzですし…) 51 | ちなみに私のデバッグ環境の 52 | K6-III 450MHz X PentiumIII 400MHz 10Base-T 53 | の環境では非常に滑らかな対戦が可能でした。 54 | 55 | 56 | それでは皆さん良い週末を! 57 | 58 | 2000年 12月吉日 59 | 60 | -------------------------------------------------------------------------------- /libretro/dmy_renderer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | #include "../gb_core/renderer.h" 21 | 22 | class dmy_renderer : public renderer 23 | { 24 | public: 25 | dmy_renderer(int which); 26 | virtual ~dmy_renderer(){}; 27 | 28 | virtual void reset() {} 29 | virtual word get_sensor(bool x_y) { return 0; } 30 | virtual void set_bibrate(bool bibrate) {} 31 | 32 | virtual void render_screen(byte *buf,int width,int height,int depth); 33 | virtual word map_color(word gb_col); 34 | virtual word unmap_color(word gb_col); 35 | virtual int check_pad(); 36 | virtual void refresh(); 37 | virtual byte get_time(int type); 38 | virtual void set_time(int type,byte dat); 39 | 40 | dword fixed_time; 41 | private: 42 | int cur_time; 43 | int which_gb; 44 | bool rgb565; 45 | }; 46 | -------------------------------------------------------------------------------- /docs/README.sdl: -------------------------------------------------------------------------------- 1 | ・これはなに? 2 | 3 | 凄いとウワサの TGB Dual をなんとなく Linux その他で 4 | 動くであろう SDL を用いて移植したものです。 5 | 6 | いちおう Linux と Linux Zaurus で動作確認してます。 7 | たぶん SDL が動いてリトルエンディアンな環境なら割と動くかと。 8 | 9 | オリジナルのドキュメントは docs の下にあります。 10 | 11 | オリジナル同様、このパッケージは GPL2 にて配布されます。 12 | 13 | 14 | ・動かしかた。 15 | 16 | make して cd sdl_ui して ./tgbdual で OK。 17 | 18 | TGB.ini は DirectInput のキーコードで指定します。 19 | 付属の dinput_sdl.h を参照するなり、 20 | Windows 版の TGB Dual で設定して移動して下さい。 21 | 22 | まず起動時にカレントディレクトリの TGB.ini を 23 | 読み込もうとして、無ければコンパイル時に指定したディレクトリを見ます。 24 | 次に save データですが TGB.ini の save_dir を見ます。 25 | もしこのエントリが存在しないか、 Windows でなくて 26 | save_dir が : を含む場合(Windowsの設定ファイルを他システムで利用時)、 27 | $(HOME)/.tgbdual/save を使います。ああややこしい。 28 | 29 | キー配置はデフォルトではオリジナルのものと同じですが、 30 | いくつかキーが増えています。 31 | [sys_key] の部分に 32 | full_type, full_code, reset_type, reset_code, quit_type, quit_code 33 | を設定できます。それぞれ意味はフルスクリーン、リセット、終了で、 34 | デフォルトでは f, r, ESCAPE が割当てられています。 35 | また、special の部分に no_dinput = 1 を指定すると 36 | キーコードを SDL のキーコードで指定できます。 37 | 38 | 39 | ・ぼくがやったこと。 40 | 41 | 自信を持って言えます。何もやってません。 42 | TGB Dual のコア部分は立派です。 43 | 44 | lcd.cpp のインラインアセンブラは VC 表記でしたんで C に翻訳しました。 45 | どうせ ARM に移植したいのでアセンブラにはしませんでした。 46 | 後で gcc のインラインアセンブラにしてみましたが、 47 | たいして速くならなかったのでやめました。 48 | 49 | 絵は少しフォーマットを変えたらすぐにうまくいきました。 50 | 51 | 音楽は流し込めば鳴りました。 52 | 53 | 入力は普通に取りました。 54 | 55 | TGB.ini を読み込むクラスはできています。 56 | 書き込みはまあいらないという方向で。 57 | 58 | ROM は gz か zip も読みます。 59 | 60 | Big Endian 対応は面倒そうです。 61 | 62 | セーブデータは gzip 圧縮されています。 63 | state save は gzip 圧縮されてません。 gb_core に手入れたくないので。 64 | 65 | 66 | ・まだやりたいこと。 67 | 68 | コードクリーニング。 69 | 70 | 2. チップ の意味がわかんないよ?大丈夫? 71 | 72 | 通信。ソース見る限り厳しげ。 73 | 74 | SL-A300 (リナザウ) 対応。(ペン入力) 75 | 76 | 他にも未実装なものがありますが、要望があれば対応するかもしれません。 77 | 78 | 79 | ・やりたくないこと。 80 | 81 | UI にまつわる全て。 82 | 83 | PAR。 84 | 85 | 複数 ROM 。通信さえあればいい気が。 86 | 87 | 88 | ・謝辞 89 | 90 | オリジナル作者であり、ソースを公開された Hii さん。 91 | 92 | 阿川さんの zgnuboy の zip 読み込みを参考にしました。 93 | 94 | Windows 対応パッチを ryoh さんにいただきました。 95 | -------------------------------------------------------------------------------- /gb_core/renderer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //--------------------------------------------- 21 | // エミュレーション結果の表現法/インターフェース 22 | // Emulation interface representation method of result 23 | 24 | #ifndef RENDERER_H 25 | #define RENDERER_H 26 | 27 | #include "gb_types.h" 28 | 29 | class sound_renderer 30 | { 31 | public: 32 | virtual void render(short *buf,int samples)=0; 33 | }; 34 | 35 | class renderer 36 | { 37 | public: 38 | void set_sound_renderer(sound_renderer *ref) { snd_render=ref; }; 39 | 40 | virtual void reset()=0; 41 | virtual void refresh()=0; 42 | virtual void render_screen(byte *buf,int width,int height,int depth)=0; 43 | virtual int check_pad()=0; 44 | virtual word map_color(word gb_col)=0; 45 | virtual word unmap_color(word gb_col)=0; 46 | 47 | virtual byte get_time(int type)=0; 48 | virtual void set_time(int type,byte dat)=0; 49 | 50 | virtual word get_sensor(bool x_y)=0; 51 | 52 | virtual void set_bibrate(bool bibrate)=0; 53 | 54 | protected: 55 | sound_renderer *snd_render; 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /gbr_interface/gbr.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | #include "../gb_core/renderer.h" 21 | 22 | #pragma pack(push,gbr_procs_pack) 23 | #pragma pack(4) 24 | 25 | struct gbr_procs{ 26 | void(*load)(unsigned char*,int); // 読み込み // Read 27 | void(*unload)(); // 解放 (忘れるとメモリリークが起こります) // Release (A memory leak occurs when you forget) 28 | void(*run)(); // CPUを走らせる(456*154クロック) // Run the CPU (456 * 154 clocks) 29 | void(*render)(short*,int); // メモリに波形を書き込みます // write the waveform memory 30 | void(*select)(int); // 選曲します // track selection 31 | void(*enable)(int,int); // チャンネルのOn/Offを変更します // turn channel On/Off 32 | void(*effect)(int,int); // エフェクタのOn/Offを変更します // turn effect On/Off 33 | }; 34 | 35 | #pragma pack(pop,gbr_procs_pack) 36 | 37 | class gbr_sound : public sound_renderer 38 | { 39 | public: 40 | gbr_sound(gbr_procs *ref_procs); 41 | ~gbr_sound(); 42 | 43 | void render(short *buf,int samples); 44 | short *get_bef(); 45 | 46 | private: 47 | gbr_procs *procs; 48 | 49 | bool change; 50 | int rest,now; 51 | short bef_buf[160*2*10+2]; 52 | }; 53 | 54 | class gbr 55 | { 56 | public: 57 | gbr(renderer *ref,gbr_procs *ref_procs); 58 | ~gbr(); 59 | 60 | void run(); 61 | void reset(); 62 | void load_rom(byte *buf,int size); 63 | void select(int num) { cur_num=num; procs->select(num); } 64 | int get_num(void) { return cur_num; } 65 | void set_enable(int ch,int enable) { procs->enable(ch,enable); } 66 | void set_effect(int eff,int enable) { procs->effect(eff,enable); } 67 | 68 | private: 69 | gbr_procs *procs; 70 | gbr_sound *gbr_snd; 71 | renderer *m_renderer; 72 | 73 | int cur_num; 74 | int frames; 75 | unsigned short vframe[160*144]; 76 | short r,g; 77 | }; 78 | -------------------------------------------------------------------------------- /gb_core/rom.cpp: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //----------------------------------------------- 21 | // ROMイメージ管理部 (含SRAM) // ROM image management unit (SRAM included) 22 | 23 | #include "gb.h" 24 | #include 25 | #include 26 | 27 | rom::rom() 28 | { 29 | b_loaded = false; 30 | b_persistent = false; 31 | 32 | dat = NULL; 33 | sram = NULL; 34 | } 35 | 36 | rom::~rom() 37 | { 38 | if (!b_persistent) 39 | free(dat); 40 | free(sram); 41 | } 42 | 43 | bool rom::has_battery() 44 | { 45 | static const int has_bat[]= 46 | {0,0,0,1,0, 0,1,0,0,1, 47 | 0,0,1,1,0, 1,1,0,0,1, 48 | 0,0,0,0,0, 0,0,1,0,1, 49 | 1,0, 0,0,0,0,0,0,0,0}; // 0x20以下 50 | return has_bat[(info.cart_type>0x20)?3:info.cart_type]==1; 51 | } 52 | 53 | int rom::get_sram_size() 54 | { 55 | static const int tbl_ram[]={1,1,1,4,16,8};//0と1は保険 56 | return 0x2000*tbl_ram[info.ram_size]; 57 | } 58 | 59 | bool rom::load_rom(byte *buf,int size,byte *ram,int ram_size, bool persistent) 60 | { 61 | byte momocol_title[16]={0x4D,0x4F,0x4D,0x4F,0x43,0x4F,0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 62 | 63 | if (b_loaded){ 64 | if (!persistent) 65 | free(dat); 66 | free(sram); 67 | } 68 | 69 | memcpy(info.cart_name,buf+0x134,16); 70 | info.cart_name[16]='\0'; 71 | info.cart_name[17]='\0'; 72 | info.cart_type=buf[0x147]; 73 | info.rom_size=buf[0x148]; 74 | info.ram_size=buf[0x149]; 75 | 76 | if (memcmp(info.cart_name,momocol_title,16)==0){ 77 | info.cart_type=0x100;//mmm01 78 | } 79 | 80 | byte tmp2=buf[0x143]; 81 | 82 | info.gb_type=(tmp2&0x80)?3:1; 83 | 84 | if (info.rom_size>8) 85 | return false; 86 | 87 | if (persistent) 88 | dat = (byte*)buf; 89 | else 90 | { 91 | dat=(byte*)malloc(size); 92 | memcpy(dat,buf,size); 93 | } 94 | first_page=dat; 95 | 96 | sram=(byte*)malloc(get_sram_size()); 97 | if (ram) 98 | memcpy(sram,ram,ram_size&0xffffff00); 99 | 100 | b_loaded = true; 101 | b_persistent = persistent; 102 | 103 | return true; 104 | } 105 | 106 | void rom::serialize(serializer &s) 107 | { 108 | s_VAR(info); 109 | s.process(sram, get_sram_size()); 110 | } 111 | 112 | -------------------------------------------------------------------------------- /gb_core/cheat.cpp: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | #include "gb.h" 21 | #include 22 | #include 23 | #include 24 | 25 | cheat::cheat(gb *ref) 26 | { 27 | ref_gb=ref; 28 | cheat_list.clear(); 29 | create_cheat_map(); 30 | } 31 | 32 | cheat::~cheat() 33 | { 34 | cheat_list.clear(); 35 | } 36 | 37 | void cheat::clear() 38 | { 39 | cheat_list.clear(); 40 | create_cheat_map(); 41 | } 42 | 43 | void cheat::add_cheat(cheat_dat *dat) 44 | { 45 | if (dat->code==0) 46 | ref_gb->get_cpu()->write(dat->adr,dat->dat); 47 | else{ 48 | cheat_list.push_back(*dat); 49 | create_cheat_map(); 50 | } 51 | } 52 | 53 | void cheat::delete_cheat(char *name) 54 | { 55 | std::list::iterator ite; 56 | 57 | for (ite=cheat_list.begin();ite!=cheat_list.end();ite++){ 58 | if (strcmp(ite->name,name)==0){ 59 | cheat_list.erase(ite); 60 | break; 61 | } 62 | } 63 | 64 | create_cheat_map(); 65 | } 66 | 67 | std::list::iterator cheat::find_cheat(char *name) 68 | { 69 | std::list::iterator ite; 70 | 71 | for (ite=cheat_list.begin();ite!=cheat_list.end();ite++){ 72 | if (strcmp(ite->name,name)==0){ 73 | return ite; 74 | } 75 | } 76 | return ite; 77 | } 78 | 79 | void cheat::create_unique_name(char *buf) 80 | { 81 | int num; 82 | bool end=false; 83 | char tmp[16]; 84 | std::list::iterator ite; 85 | 86 | for (num=0;!end;num++){ 87 | end=true; 88 | sprintf(tmp,"cheat_%03d",num); 89 | for (ite=cheat_list.begin();ite!=cheat_list.end();ite++) 90 | if (strcmp(ite->name,tmp)==0) 91 | end=false; 92 | } 93 | 94 | strcpy(buf,tmp); 95 | } 96 | 97 | void cheat::create_cheat_map() 98 | { 99 | int i; 100 | std::list::iterator ite; 101 | cheat_dat *tmp; 102 | 103 | memset(cheat_map,0,sizeof(int)*0x10000); 104 | 105 | for (ite=cheat_list.begin();ite!=cheat_list.end();ite++){ 106 | tmp=&(*ite); 107 | do{ 108 | switch(tmp->code){ 109 | case 0x01: 110 | case 0x90: 111 | case 0x91: 112 | case 0x92: 113 | case 0x93: 114 | case 0x94: 115 | case 0x95: 116 | case 0x96: 117 | case 0x97: 118 | case 0xA1: 119 | cheat_map[tmp->adr]=1; 120 | break; 121 | case 0x10: 122 | for (i=0;idat;i++) 123 | cheat_map[tmp->next->adr+(tmp->adr+1)*i]=1; 124 | tmp=tmp->next; 125 | break; 126 | } 127 | tmp=tmp->next; 128 | }while(tmp); 129 | } 130 | } 131 | 132 | byte cheat::cheat_read(word adr) 133 | { 134 | std::list::iterator ite; 135 | cheat_dat *tmp; 136 | 137 | for (ite=cheat_list.begin();ite!=cheat_list.end();ite++){ 138 | tmp=&(*ite); 139 | 140 | if (!tmp->enable) 141 | continue; 142 | 143 | do{ 144 | switch(tmp->code){ 145 | case 0x01: 146 | if (tmp->adr==adr) 147 | return tmp->dat; 148 | tmp=NULL; 149 | break; 150 | case 0x10: 151 | if ((tmp->next->adr<=adr)&&((adr-tmp->next->adr)<(tmp->adr+1)*tmp->dat)&& 152 | (((adr-tmp->next->adr)%(tmp->adr+1))==0)) 153 | return tmp->next->dat; 154 | tmp=NULL; 155 | break; 156 | case 0x20: 157 | if (ref_gb->get_cpu()->read_direct(tmp->adr)==tmp->dat) 158 | tmp=tmp->next; 159 | else 160 | tmp=NULL; 161 | break; 162 | case 0x21: 163 | if (ref_gb->get_cpu()->read_direct(tmp->adr)dat) 164 | tmp=tmp->next; 165 | else 166 | tmp=NULL; 167 | break; 168 | case 0x22: 169 | if (ref_gb->get_cpu()->read_direct(tmp->adr)>tmp->dat) 170 | tmp=tmp->next; 171 | else 172 | tmp=NULL; 173 | break; 174 | case 0x90: 175 | case 0x91: 176 | case 0x92: 177 | case 0x93: 178 | case 0x94: 179 | case 0x95: 180 | case 0x96: 181 | case 0x97: 182 | if (tmp->adr==adr) 183 | { 184 | if ((adr>=0xD000)&&(adr<0xE000)) 185 | { 186 | if (((ref_gb->get_cpu()->get_ram_bank()-ref_gb->get_cpu()->get_ram())/0x1000)==(tmp->code-0x90)) 187 | return tmp->dat; 188 | tmp=NULL; 189 | } 190 | else 191 | return tmp->dat; 192 | } 193 | break; 194 | } 195 | }while(tmp); 196 | } 197 | 198 | // return 0; 199 | return ref_gb->get_cpu()->read_direct(adr); 200 | } 201 | 202 | void cheat::cheat_write(word adr,byte dat) 203 | { 204 | } 205 | -------------------------------------------------------------------------------- /docs/README.win32: -------------------------------------------------------------------------------- 1 | 2 | TGB Dual Ver. Vol.7' (Build:2053) 3 | 4 | §1 TGB Dual Version (以下 TGB Dual) とは…?: 5 | 6 | DMGシステム及びその上位機種(CGB)をエミュレーションします。 7 | いわゆるGameboy(Color)エミュレータです。 8 | 9 | システム必要最低条件 10 | 32bitWindows & DirectX5 以上の環境 11 | (必然的にNTは駄目) 12 | サウンドカード必須(無論ビデオカードも) 13 | ジョイスティックは無くても可 14 | 15 | 16 | §2 概要/エミュレーションの実装状況: 17 | 18 | 1.DMG/CGB 19 | 20 | ・CPU…多分大丈夫だと。 21 | ・サウンドチップ(多分PSG系だと思う)…大体OKではなかろうかと。 22 | ・その他のGBの中身…多分大体OK(実機が無いので詳細不明) 23 | 24 | 2.チップ 25 | 26 | カートリッジ側に含まれるチップのサポート状況は以下の通り 27 | 28 | 対応ROMサイズ: 29 | 0,1,2,3,4,5,6,7,8 30 | 対応SRAMサイズ: 31 | 0,1,2,3,4,5 32 | 対応カートリッジタイプ: 33 | 0,1,2,3,5,6,8,9,A,C,D,F,10,11,12,13,19,1A,1B,1C,1D,1E,22,FE,FF 34 | 対応チップ: 35 | MBC1/2/3/5/7/RTC/モーションセンサー,HuC-1(*),HuC-3(*),MMM01(*) 36 | (*は一部未実装の機能を含む) 37 | 38 | 8,9,A はかなり不完全です。 39 | C,D はRTCエミュレーションも行います。 40 | 1C,1D,1E はRumbleエミュレーションをFFBで行います。 41 | 22(MBC7?+MotionSensor+SerialEEPROM)は完全に実装してあります。 42 | モーションセンサーはアナログジョイスティックでの操作も可能です。 43 | 44 | FE(HuC-3)の時計機能は実装しておりません。 45 | FF(HuC-1)の赤外線通信は実装しておりません。 46 | 1F(Pocket Camera),FD(TAMA5)には未対応です。 47 | 48 | なおカートリッジタイプの内 4,7,B,E,14,15,16,17,18,20,21,は存在しません。 49 | その他(23-FC)は現時点では未定義です 50 | 51 | 対応ROMサイズは"8"がMBC5のマップできる最大容量である64MBitですので、 52 | これ以上のものが登場するかは非常に怪しいところです(新しいマッパが出るかは非常に疑わしい)。 53 | 対応SRAMサイズは"5"が容量の公式に当てはまらないので、なんともいえません。 54 | 55 | 参考:各MBCのRAM容量の限界 56 | MBC1の限界…16/8モード・8KB、4/32モード・32KB 57 | MBC2の限界…512*4Bit固定(チップに内臓) 58 | MBC3の限界…32KB(ただしポケモンクリスタルではD2が有効らしく64KB/ 59 | 全てのゲームで有効かも/) 60 | MBC5の限界…128KB 61 | 62 | 3.付加機能 63 | 64 | 何か色々(把握しきれていない)…ありますが特筆すべきものとしては(説明が必要な) 65 | オンライン通信機能…ローカルでの通信と同等の精度でオンライン通信を行えます。別途付属テキストに詳細あり。 66 | チートコード…PARのコード及びXT-Zのコードに一応対応しています。 67 | さらに繰り返し、条件分岐コードを独自拡張として備えています。 68 | 仕様は別途付属テキストにあります。 69 | 70 | 4.周辺機器のエミュレーション 71 | 72 | GBにはシリアルポート接続の周辺機器が多数(?)発売されていますが、TGB Dualはシリアル通信を 73 | DLLでフックすることが出来ます。(或いは赤外線通信も…実装しているのに往々にして動いてくれないの…) 74 | DLLの仕様は別途記載 75 | 76 | 現在利用可能なもの…TPPE DLL版(ポケットプリンタ)、TPPE 改(POPさん作、同梱させて頂いております) 77 | TBR(バーコードリーダ)、何やら赤外線操作プラグイン 78 | 79 | 5.GBR 80 | 81 | TGB DualはGBRの再生に対応しています。 82 | 再生はdevicesフォルダに入っているtgbr_dll.dllを用いています。 83 | これは数値演算しか行わないので、他アプリケーションでもご使用いただけるかもしれません。 84 | 85 | (一応)仕様: 86 | 87 | gbr_procs *get_interface() 88 | 唯一のエクスポート関数です。 89 | サービスルーチンへのポインタが入った構造体が返ってきます。 90 | 91 | struct gbr_procs{ 92 | void(*load)(BYTE*,int); // 読み込み(メモリデータ、サイズ) 93 | void(*unload)(); // 解放 (忘れるとメモリリークが起こります) 94 | void(*run)(); // CPUを走らせる(456*154クロック、一画面分、これを秒間59.6回ぐらい呼んで下さい) 95 | void(*render)(short*,int); // メモリに波形を書き込みます(バッファ、サンプル数(片チャンネル分の)) 96 | void(*select)(int); // 選曲します(0-255) 97 | void(*enable)(int,int); // チャンネルのOn/Offを変更します(チャンネル番号、On/Off(1/0)) 98 | void(*effect)(int,int); // エフェクタのOn/Offを変更します(エフェクタ番号、On/Off(1/0)) 99 | }; 100 | (4バイト境界) 101 | 102 | 16ビット、44100Hz専用です。 103 | 104 | §3 操作法 105 | 106 | ほとんどの機能は再定義可能ですが、アクセラレータはいじれないので、 107 | 説明しておきます。 108 | 109 | Alt+Enter : フルスクリーン/ウインドウモード切替 110 | Ctrl+P : スクリーンショット 111 | Ctrl+O : サウンドレコード開始/停止 112 | 113 | その他記述すべき事柄 114 | 115 | コマンドラインからの起動: 116 | TGB_Dual.exe [filename] [/f] 117 | 118 | filenameは読み込むファイル名、""で囲えばパスに空白が入ってもOK 119 | /f…フルスクリーン状態で起動 120 | 121 | TGB/TGB Dualは状態保存の際に使用するすべての情報をTGB.iniに記録しています。 122 | レジストリは一切使用していません。 123 | 124 | セーブデータについて: 125 | TGB/TGB Dualに於いて、SRAMデータは "(ROMイメージのファイル名).sav" という名前で保存されます(TGBは*.ramと両用)。 126 | Slot2のSRAMデータは "(ROMイメージのファイル名).sa2" という名前で保存されます。 127 | これらの内容は '単にSRAMをダンプしたもの' です。 128 | 129 | ステートセーブについては、"(ROMイメージのファイル名).sv?" のファイル名で保存されます。 130 | ステートセーブの構造を以下に記します。 131 | 132 | /* やっぱり、ソースコードを参照のこと */ 133 | 134 | 135 | §4 開発環境/動作確認環境 136 | 137 | 開発環境: 138 | 139 | 某AT互換機 140 | OS : Windows2000(非SP1)/Windows98 Dual Boot 141 | MB : VIA MVP3 (3次キャッシュ2MB) 142 | CPU : K6-III 450MHz 143 | RAM : 128MB SDRAM CL-2 144 | Video: TNT2 32MB 145 | Sound: SB Live! Value 146 | LAN : 10Base-T 147 | 148 | Visual C++ 6.0 Enterprise Edition SP5 & DirectX8.0a SDK 149 | にて製作 150 | 151 | 152 | 動作確認: 153 | 154 | 某AT互換機 155 | OS : Windows2000(非SP1) 156 | MB : なんかフリーウェイの赤マザー(名前忘れた) 157 | CPU : Athlon 750MHz 158 | MEM : 128 SDRAM CL-2 159 | Video: G400 160 | Sound: オンボード 161 | 162 | 某AT互換機 163 | OS : Windows98 164 | MB : 不明(Socket7、66MHzの品、2次キャッシュ容量は忘れた) 165 | CPU : K6-233MHz 166 | MEM : 32*2MB EDORAM 167 | Video: Graphics Blaster Exxtrame 4MB 168 | Sound: 不明(ISAの品) 169 | (この環境でたいがい60FPS出ます) 170 | 171 | AT互換機 172 | OS : Windows2000 173 | MB : 忘れた… 174 | CPU : Duron800Mhz 175 | MEM : 256MB SDRAM 176 | Video: GeForce2MX 200? の品 177 | Sound: オンボード 178 | 179 | AMDばっか…何でだろ… 180 | 181 | §5 その他留意点 182 | 183 | MBC3の時計の時間(e.g.ポケモン金銀クリスタル、カードヒーロー)を変えるには… 184 | 3つ方法があります。 185 | まず一つ目はMBC3/RTC編集機能を使うことです。 186 | MBC3/RTCを搭載しているROMを読み込んでいるときにメニューからこれを起動していただくと 187 | 設定ダイアログが出てきて、これで変更可能です。 188 | ただ、ポケモンなどは、RTCの値に何らかの値を加減したものをゲーム中の時刻として使っているようで、 189 | 相対的な時刻を考えつつ設定する必要があります。 190 | あとの2つは、ともにエミュレータの機能ではないですが、Windowsの時計をいじる、 191 | もしくは、ファイルを編集する。その2つです。 192 | ファイルに関して書いておくと、.SAVファイルの最後4バイトに、現在時刻からのずれ(単位:秒) 193 | が書き込まれています。(サイズがちょっと大きいから分かるはず) 194 | 負の数は2の補数で。 195 | 196 | 197 | /* 198 | §6 DTAについて 199 | ソース読んだら分かるからいいか… 200 | */ 201 | 202 | §7 ちょっと書きたいこと 203 | 204 | ☆高度な抽象化 205 | ゲームボーイというものを高度に抽象化したコーディング、 206 | 画像サウンドにOS依存部を完全に排出、 207 | また、OS依存部も抽象化してあるので、 208 | 決まったインターフェースをインプリメントするだけでさまざまなOSに対応可能! 209 | (理論的には) 210 | 211 | ☆精密なサウンド 212 | 以前の分解能1/240(s)に対し、1/44100(s)にまで精密化。 213 | あらゆるサウンド効果、すべてのボイス機能を再現可能です。 214 | (それが滑らかかどうかはまた別問題…) 215 | 216 | 217 | §8 TGB vs TGB Dual 218 | 219 | 機能性…Dualのほうが上のはずなんだが…TGBにしかない機能があるらしい(Rumbleで画面フラッシュとか、ショートカットキーとか) 220 | 速度…TGBのほうが少し上、スキップ時はDualのほうが圧倒的に上 221 | エミュレーション精度…Dualのほう圧倒的にが上 222 | グラフィックス…Dualのほうは完璧、旧TGBはかなりあやふや 223 | サウンド…Dualのほうがだいぶ上 224 | 通信精度…Dualのほうが圧倒的に上 225 | 226 | Vol.4と同時に旧TGBは公開中止しました。(ファイル自体は置いてあるので、適当にぱくって行って下さい) 227 | 228 | 229 | §9 分別不可話題 230 | 231 | 何故に新銘柄なんて作ったのか? 232 | もうぶっちゃけた話、読めないとか何とかよりも、GBクラスのインスタンスを2つ作らなくてはならなかったんです。 233 | 何としても作らなくてはならなかったので(閃いたアイデアを捨てるのは勿体無い)、 234 | 全体からクラスで使っているグローバル変数、OS依存部、クラス内でインスタンス間競合が起こりそうなSTATICメンバ変数 235 | これらを完全に排除しなくてはならなかったわけです。 236 | (当初、違うコンセプトで拡張していこうと思ったのですが…表には出ていない(手元にまだある)TGB 0.246の残骸からみるに 237 | 多分これはいけなかったんでしょう。本当に崩壊しましたからねー…) 238 | クラス設計がゆがんでいる部分、手抜きコーディング、その他色々きちゃない部分もついでに一掃すべく 239 | きっぱり新しく作り始めたと言うことです。 240 | 241 | (でーもー…後で見るとDualも充分汚くみえる) 242 | 243 | §10 謝辞 244 | 245 | お受験に出るゲームボーイを書かれたろっきゅーさん 246 | GBSpecを書かれたkOOPaさん(Marat Fayzullinさん, Pascal Felberさん, Paul Robsonさん, Martin Korthさん) 247 | GB DEV FAQsを書かれたGeeBeeさん 248 | GBC 解析白書2000を書かれた某吉さん 249 | GBRについて教えてくださったIzumiさん 250 | その他参考にさせていただいた資料を作られた全ての方々 251 | 動作レポートを送っていただいたちいじさん、ボニさん 252 | アドバイスを頂いた全ての方々 253 | 置き場所を提供して下さっているRetrogamesさん 254 | 255 | 改めて御礼申し上げます。 256 | 257 | 258 | §11 著作権 259 | 260 | Copyright(C) 2000-2001 Hii 261 | 262 | (このプログラムはGPLVer.2に基づいて頒布されます) 263 | 264 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # DESCRIPTION: GitLab CI/CD for libRetro (NOT FOR GitLab-proper) 2 | 3 | ############################################################################## 4 | ################################# BOILERPLATE ################################ 5 | ############################################################################## 6 | 7 | # Core definitions 8 | .core-defs: 9 | variables: 10 | JNI_PATH: . 11 | CORENAME: tgbdual 12 | 13 | # Inclusion templates, required for the build to work 14 | include: 15 | ################################## DESKTOPS ################################ 16 | # Windows 64-bit 17 | - project: 'libretro-infrastructure/ci-templates' 18 | file: '/windows-x64-mingw.yml' 19 | 20 | # Windows 32-bit 21 | - project: 'libretro-infrastructure/ci-templates' 22 | file: '/windows-i686-mingw.yml' 23 | 24 | # Windows msvc10 64-bit 25 | - project: 'libretro-infrastructure/ci-templates' 26 | file: '/windows-x64-msvc10-msys2.yml' 27 | 28 | # Windows msvc10 32-bit 29 | - project: 'libretro-infrastructure/ci-templates' 30 | file: '/windows-i686-msvc10-msys2.yml' 31 | 32 | # Windows msvc05 32-bit 33 | - project: 'libretro-infrastructure/ci-templates' 34 | file: '/windows-i686-msvc05-msys2.yml' 35 | 36 | # Linux 64-bit 37 | - project: 'libretro-infrastructure/ci-templates' 38 | file: '/linux-x64.yml' 39 | 40 | # Linux 32-bit 41 | - project: 'libretro-infrastructure/ci-templates' 42 | file: '/linux-i686.yml' 43 | 44 | # MacOS 64-bit 45 | - project: 'libretro-infrastructure/ci-templates' 46 | file: '/osx-x64.yml' 47 | 48 | # MacOS ARM 64-bit 49 | - project: 'libretro-infrastructure/ci-templates' 50 | file: '/osx-arm64.yml' 51 | 52 | ################################## CELLULAR ################################ 53 | # Android 54 | - project: 'libretro-infrastructure/ci-templates' 55 | file: '/android-jni.yml' 56 | 57 | # iOS 58 | - project: 'libretro-infrastructure/ci-templates' 59 | file: '/ios-arm64.yml' 60 | 61 | # iOS (armv7) 62 | - project: 'libretro-infrastructure/ci-templates' 63 | file: '/ios9.yml' 64 | 65 | ################################## CONSOLES ################################ 66 | # PlayStation Portable 67 | - project: 'libretro-infrastructure/ci-templates' 68 | file: '/psp-static.yml' 69 | 70 | # PlayStation Vita 71 | - project: 'libretro-infrastructure/ci-templates' 72 | file: '/vita-static.yml' 73 | 74 | # PlayStation2 75 | - project: 'libretro-infrastructure/ci-templates' 76 | file: '/ps2-static.yml' 77 | 78 | # Nintendo 3DS 79 | - project: 'libretro-infrastructure/ci-templates' 80 | file: '/ctr-static.yml' 81 | 82 | # Nintendo WiiU 83 | - project: 'libretro-infrastructure/ci-templates' 84 | file: '/wiiu-static.yml' 85 | 86 | # Nintendo Switch 87 | - project: 'libretro-infrastructure/ci-templates' 88 | file: '/libnx-static.yml' 89 | 90 | # tvOS (AppleTV) 91 | - project: 'libretro-infrastructure/ci-templates' 92 | file: '/tvos-arm64.yml' 93 | 94 | #################################### MISC ################################## 95 | # Emscripten 96 | - project: 'libretro-infrastructure/ci-templates' 97 | file: '/emscripten-static.yml' 98 | 99 | # Stages for building 100 | stages: 101 | - build-prepare 102 | - build-shared 103 | - build-static 104 | 105 | ############################################################################## 106 | #################################### STAGES ################################## 107 | ############################################################################## 108 | # 109 | ################################### DESKTOPS ################################# 110 | # Windows 64-bit 111 | libretro-build-windows-x64: 112 | extends: 113 | - .libretro-windows-x64-mingw-make-default 114 | - .core-defs 115 | 116 | # Windows 32-bit 117 | libretro-build-windows-i686: 118 | extends: 119 | - .libretro-windows-i686-mingw-make-default 120 | - .core-defs 121 | 122 | # Windows msvc10 64-bit 123 | libretro-build-windows-msvc10-x64: 124 | extends: 125 | - .libretro-windows-x64-msvc10-msys2-make-default 126 | - .core-defs 127 | 128 | # Windows msvc10 32-bit 129 | libretro-build-windows-msvc10-i686: 130 | extends: 131 | - .libretro-windows-i686-msvc10-msys2-make-default 132 | - .core-defs 133 | 134 | # Windows msvc05 32-bit 135 | libretro-build-windows-msvc05-i686: 136 | extends: 137 | - .libretro-windows-i686-msvc05-msys2-make-default 138 | - .core-defs 139 | 140 | # Linux 64-bit 141 | libretro-build-linux-x64: 142 | extends: 143 | - .libretro-linux-x64-make-default 144 | - .core-defs 145 | 146 | # Linux 32-bit 147 | libretro-build-linux-i686: 148 | extends: 149 | - .libretro-linux-i686-make-default 150 | - .core-defs 151 | 152 | # MacOS 64-bit 153 | libretro-build-osx-x64: 154 | extends: 155 | - .libretro-osx-x64-make-10-7 156 | - .core-defs 157 | 158 | # MacOS ARM 64-bit 159 | libretro-build-osx-arm64: 160 | extends: 161 | - .libretro-osx-arm64-make-default 162 | - .core-defs 163 | 164 | ################################### CELLULAR ################################# 165 | # Android ARMv7a 166 | android-armeabi-v7a: 167 | extends: 168 | - .libretro-android-jni-armeabi-v7a 169 | - .core-defs 170 | 171 | # Android ARMv8a 172 | android-arm64-v8a: 173 | extends: 174 | - .libretro-android-jni-arm64-v8a 175 | - .core-defs 176 | 177 | # Android 64-bit x86 178 | android-x86_64: 179 | extends: 180 | - .libretro-android-jni-x86_64 181 | - .core-defs 182 | 183 | # Android 32-bit x86 184 | android-x86: 185 | extends: 186 | - .libretro-android-jni-x86 187 | - .core-defs 188 | 189 | # iOS 190 | libretro-build-ios-arm64: 191 | extends: 192 | - .libretro-ios-arm64-make-default 193 | - .core-defs 194 | 195 | # iOS (armv7) [iOS 9 and up] 196 | libretro-build-ios9: 197 | extends: 198 | - .libretro-ios9-make-default 199 | - .core-defs 200 | 201 | # tvOS 202 | libretro-build-tvos-arm64: 203 | extends: 204 | - .libretro-tvos-arm64-make-default 205 | - .core-defs 206 | 207 | ################################### CONSOLES ################################# 208 | # PlayStation 2 209 | libretro-build-ps2: 210 | extends: 211 | - .libretro-ps2-static-retroarch-master 212 | - .core-defs 213 | 214 | # PlayStation Portable 215 | libretro-build-psp: 216 | extends: 217 | - .libretro-psp-static-retroarch-master 218 | - .core-defs 219 | 220 | # PlayStation Vita 221 | libretro-build-vita: 222 | extends: 223 | - .libretro-vita-static-retroarch-master 224 | - .core-defs 225 | 226 | # Nintendo 3DS 227 | libretro-build-ctr: 228 | extends: 229 | - .libretro-ctr-static-retroarch-master 230 | - .core-defs 231 | 232 | # Nintendo WiiU 233 | libretro-build-wiiu: 234 | extends: 235 | - .libretro-wiiu-static-retroarch-master 236 | - .core-defs 237 | 238 | # Nintendo Switch 239 | libretro-build-libnx-aarch64: 240 | extends: 241 | - .libretro-libnx-static-retroarch-master 242 | - .core-defs 243 | 244 | #################################### MISC ################################## 245 | # Emscripten 246 | libretro-build-emscripten: 247 | extends: 248 | - .libretro-emscripten-static-retroarch-master 249 | - .core-defs 250 | -------------------------------------------------------------------------------- /libretro-common/include/compat/msvc/stdint.h: -------------------------------------------------------------------------------- 1 | /* ISO C9x compliant stdint.h for Microsoft Visual Studio 2 | * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 3 | * 4 | * Copyright (c) 2006-2008 Alexander Chemeris 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * 3. The name of the author may be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __RARCH_STDINT_H 32 | #define __RARCH_STDINT_H 33 | 34 | #if _MSC_VER && (_MSC_VER < 1600) 35 | /* Pre-MSVC 2010 needs an implementation of stdint.h. */ 36 | 37 | #if _MSC_VER > 1000 38 | #pragma once 39 | #endif 40 | 41 | #include 42 | 43 | /* For Visual Studio 6 in C++ mode and for many Visual Studio versions when 44 | * compiling for ARM we should wrap include with 'extern "C++" {}' 45 | * or compiler give many errors like this: 46 | * 47 | * error C2733: second C linkage of overloaded function 'wmemchr' not allowed 48 | */ 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | # include 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | /* Define _W64 macros to mark types changing their size, like intptr_t. */ 58 | #ifndef _W64 59 | # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 60 | # define _W64 __w64 61 | # else 62 | # define _W64 63 | # endif 64 | #endif 65 | 66 | 67 | /* 7.18.1 Integer types. */ 68 | 69 | /* 7.18.1.1 Exact-width integer types. */ 70 | 71 | /* Visual Studio 6 and Embedded Visual C++ 4 doesn't 72 | * realize that, e.g. char has the same size as __int8 73 | * so we give up on __intX for them. 74 | */ 75 | #if (_MSC_VER < 1300) 76 | typedef signed char int8_t; 77 | typedef signed short int16_t; 78 | typedef signed int int32_t; 79 | typedef unsigned char uint8_t; 80 | typedef unsigned short uint16_t; 81 | typedef unsigned int uint32_t; 82 | #else 83 | typedef signed __int8 int8_t; 84 | typedef signed __int16 int16_t; 85 | typedef signed __int32 int32_t; 86 | typedef unsigned __int8 uint8_t; 87 | typedef unsigned __int16 uint16_t; 88 | typedef unsigned __int32 uint32_t; 89 | #endif 90 | typedef signed __int64 int64_t; 91 | typedef unsigned __int64 uint64_t; 92 | 93 | 94 | /* 7.18.1.2 Minimum-width integer types. */ 95 | typedef int8_t int_least8_t; 96 | typedef int16_t int_least16_t; 97 | typedef int32_t int_least32_t; 98 | typedef int64_t int_least64_t; 99 | typedef uint8_t uint_least8_t; 100 | typedef uint16_t uint_least16_t; 101 | typedef uint32_t uint_least32_t; 102 | typedef uint64_t uint_least64_t; 103 | 104 | /* 7.18.1.3 Fastest minimum-width integer types. */ 105 | typedef int8_t int_fast8_t; 106 | typedef int16_t int_fast16_t; 107 | typedef int32_t int_fast32_t; 108 | typedef int64_t int_fast64_t; 109 | typedef uint8_t uint_fast8_t; 110 | typedef uint16_t uint_fast16_t; 111 | typedef uint32_t uint_fast32_t; 112 | typedef uint64_t uint_fast64_t; 113 | 114 | /* 7.18.1.4 Integer types capable of holding object pointers. */ 115 | #ifdef _WIN64 /* [ */ 116 | typedef signed __int64 intptr_t; 117 | typedef unsigned __int64 uintptr_t; 118 | #else /* _WIN64 ][ */ 119 | typedef _W64 signed int intptr_t; 120 | typedef _W64 unsigned int uintptr_t; 121 | #endif /* _WIN64 ] */ 122 | 123 | /* 7.18.1.5 Greatest-width integer types. */ 124 | typedef int64_t intmax_t; 125 | typedef uint64_t uintmax_t; 126 | 127 | /* 7.18.2 Limits of specified-width integer types. */ 128 | 129 | #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) 130 | /* [ See footnote 220 at page 257 and footnote 221 at page 259. */ 131 | 132 | /* 7.18.2.1 Limits of exact-width integer types. */ 133 | #define INT8_MIN ((int8_t)_I8_MIN) 134 | #define INT8_MAX _I8_MAX 135 | #define INT16_MIN ((int16_t)_I16_MIN) 136 | #define INT16_MAX _I16_MAX 137 | #define INT32_MIN ((int32_t)_I32_MIN) 138 | #define INT32_MAX _I32_MAX 139 | #define INT64_MIN ((int64_t)_I64_MIN) 140 | #define INT64_MAX _I64_MAX 141 | #define UINT8_MAX _UI8_MAX 142 | #define UINT16_MAX _UI16_MAX 143 | #define UINT32_MAX _UI32_MAX 144 | #define UINT64_MAX _UI64_MAX 145 | 146 | /* 7.18.2.2 Limits of minimum-width integer types. */ 147 | #define INT_LEAST8_MIN INT8_MIN 148 | #define INT_LEAST8_MAX INT8_MAX 149 | #define INT_LEAST16_MIN INT16_MIN 150 | #define INT_LEAST16_MAX INT16_MAX 151 | #define INT_LEAST32_MIN INT32_MIN 152 | #define INT_LEAST32_MAX INT32_MAX 153 | #define INT_LEAST64_MIN INT64_MIN 154 | #define INT_LEAST64_MAX INT64_MAX 155 | #define UINT_LEAST8_MAX UINT8_MAX 156 | #define UINT_LEAST16_MAX UINT16_MAX 157 | #define UINT_LEAST32_MAX UINT32_MAX 158 | #define UINT_LEAST64_MAX UINT64_MAX 159 | 160 | /* 7.18.2.3 Limits of fastest minimum-width integer types. */ 161 | #define INT_FAST8_MIN INT8_MIN 162 | #define INT_FAST8_MAX INT8_MAX 163 | #define INT_FAST16_MIN INT16_MIN 164 | #define INT_FAST16_MAX INT16_MAX 165 | #define INT_FAST32_MIN INT32_MIN 166 | #define INT_FAST32_MAX INT32_MAX 167 | #define INT_FAST64_MIN INT64_MIN 168 | #define INT_FAST64_MAX INT64_MAX 169 | #define UINT_FAST8_MAX UINT8_MAX 170 | #define UINT_FAST16_MAX UINT16_MAX 171 | #define UINT_FAST32_MAX UINT32_MAX 172 | #define UINT_FAST64_MAX UINT64_MAX 173 | 174 | /* 7.18.2.4 Limits of integer types capable of holding object pointers. */ 175 | #ifdef _WIN64 /* [ */ 176 | # define INTPTR_MIN INT64_MIN 177 | # define INTPTR_MAX INT64_MAX 178 | # define UINTPTR_MAX UINT64_MAX 179 | #else /* _WIN64 ][ */ 180 | # define INTPTR_MIN INT32_MIN 181 | # define INTPTR_MAX INT32_MAX 182 | # define UINTPTR_MAX UINT32_MAX 183 | #endif /* _WIN64 ] */ 184 | 185 | /* 7.18.2.5 Limits of greatest-width integer types */ 186 | #define INTMAX_MIN INT64_MIN 187 | #define INTMAX_MAX INT64_MAX 188 | #define UINTMAX_MAX UINT64_MAX 189 | 190 | /* 7.18.3 Limits of other integer types */ 191 | 192 | #ifdef _WIN64 /* [ */ 193 | # define PTRDIFF_MIN _I64_MIN 194 | # define PTRDIFF_MAX _I64_MAX 195 | #else /* _WIN64 ][ */ 196 | # define PTRDIFF_MIN _I32_MIN 197 | # define PTRDIFF_MAX _I32_MAX 198 | #endif /* _WIN64 ] */ 199 | 200 | #define SIG_ATOMIC_MIN INT_MIN 201 | #define SIG_ATOMIC_MAX INT_MAX 202 | 203 | #ifndef SIZE_MAX /* [ */ 204 | # ifdef _WIN64 /* [ */ 205 | # define SIZE_MAX _UI64_MAX 206 | # else /* _WIN64 ][ */ 207 | # define SIZE_MAX _UI32_MAX 208 | # endif /* _WIN64 ] */ 209 | #endif /* SIZE_MAX ] */ 210 | 211 | /* WCHAR_MIN and WCHAR_MAX are also defined in */ 212 | #ifndef WCHAR_MIN /* [ */ 213 | # define WCHAR_MIN 0 214 | #endif /* WCHAR_MIN ] */ 215 | #ifndef WCHAR_MAX // [ 216 | # define WCHAR_MAX _UI16_MAX 217 | #endif /* WCHAR_MAX ] */ 218 | 219 | #define WINT_MIN 0 220 | #define WINT_MAX _UI16_MAX 221 | 222 | #endif /* __STDC_LIMIT_MACROS ] */ 223 | 224 | /* 7.18.4 Limits of other integer types */ 225 | 226 | #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) 227 | /* [ See footnote 224 at page 260 */ 228 | 229 | /* 7.18.4.1 Macros for minimum-width integer constants */ 230 | 231 | #define INT8_C(val) val##i8 232 | #define INT16_C(val) val##i16 233 | #define INT32_C(val) val##i32 234 | #define INT64_C(val) val##i64 235 | 236 | #define UINT8_C(val) val##ui8 237 | #define UINT16_C(val) val##ui16 238 | #define UINT32_C(val) val##ui32 239 | #define UINT64_C(val) val##ui64 240 | 241 | /* 7.18.4.2 Macros for greatest-width integer constants */ 242 | #define INTMAX_C INT64_C 243 | #define UINTMAX_C UINT64_C 244 | 245 | #endif 246 | /* __STDC_CONSTANT_MACROS ] */ 247 | 248 | #else 249 | /* Sanity for everything else. */ 250 | #include 251 | #endif 252 | 253 | #endif 254 | 255 | -------------------------------------------------------------------------------- /libretro/dmy_renderer.cpp: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | // libretro implementation of the renderer, should probably be renamed from dmy. 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "dmy_renderer.h" 27 | #include "../gb_core/gb.h" 28 | #include "libretro.h" 29 | 30 | extern gb *g_gb[2]; 31 | 32 | extern retro_log_printf_t log_cb; 33 | extern retro_video_refresh_t video_cb; 34 | extern retro_audio_sample_batch_t audio_batch_cb; 35 | extern retro_input_poll_t input_poll_cb; 36 | extern retro_input_state_t input_state_cb; 37 | extern retro_environment_t environ_cb; 38 | 39 | extern bool gblink_enable; 40 | 41 | extern int audio_2p_mode; 42 | 43 | #define MSG_FRAMES 60 44 | #define SAMPLES_PER_FRAME (44100/60) 45 | 46 | bool _screen_2p_vertical = false; 47 | bool _screen_switched = false; // set to draw player 2 on the left/top 48 | extern bool libretro_supports_bitmasks; 49 | int _show_player_screens = 2; // 0 = p1 only, 1 = p2 only, 2 = both players 50 | 51 | dmy_renderer::dmy_renderer(int which) 52 | { 53 | which_gb = which; 54 | 55 | retro_pixel_format pixfmt = RETRO_PIXEL_FORMAT_RGB565; 56 | rgb565 = environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pixfmt); 57 | 58 | #ifndef FRONTEND_SUPPORTS_RGB565 59 | if (rgb565 && log_cb) 60 | log_cb(RETRO_LOG_INFO, "Frontend supports RGB565; will use that instead of XRGB1555.\n"); 61 | #endif 62 | } 63 | 64 | word dmy_renderer::map_color(word gb_col) 65 | { 66 | #ifndef SKIP_COLOR_CORRECTION 67 | #ifndef FRONTEND_SUPPORTS_RGB565 68 | if(rgb565) 69 | { 70 | #endif 71 | return ((gb_col&0x001f) << 11) | 72 | ((gb_col&0x03e0) << 1) | 73 | ((gb_col&0x0200) >> 4) | 74 | ((gb_col&0x7c00) >> 10); 75 | #ifndef FRONTEND_SUPPORTS_RGB565 76 | } 77 | return ((gb_col&0x001f) << 10) | 78 | ((gb_col&0x03e0) ) | 79 | ((gb_col&0x7c00) >> 10); 80 | #endif 81 | #else 82 | return gb_col; 83 | #endif 84 | } 85 | 86 | word dmy_renderer::unmap_color(word gb_col) 87 | { 88 | #ifndef SKIP_COLOR_CORRECTION 89 | #ifndef FRONTEND_SUPPORTS_RGB565 90 | if(rgb565) 91 | { 92 | #endif 93 | return ((gb_col&0x001f) << 10) | 94 | ((gb_col&0x07c0) >> 1) | 95 | ((gb_col&0xf800) >> 11); 96 | #ifndef FRONTEND_SUPPORTS_RGB565 97 | } 98 | return ((gb_col&0x001f) << 10) | 99 | ((gb_col&0x03e0) ) | 100 | ((gb_col&0x7c00) >> 10); 101 | #endif 102 | #else 103 | return gb_col; 104 | #endif 105 | } 106 | 107 | void dmy_renderer::refresh() { 108 | static int16_t stream[SAMPLES_PER_FRAME*2]; 109 | 110 | if (g_gb[1] && gblink_enable) 111 | { 112 | // if dual gb mode 113 | if (audio_2p_mode == 2) 114 | { 115 | // mix down to one per channel (dual mono) 116 | int16_t tmp_stream[SAMPLES_PER_FRAME*2]; 117 | this->snd_render->render(tmp_stream, SAMPLES_PER_FRAME); 118 | for(int i = 0; i < SAMPLES_PER_FRAME; ++i) 119 | { 120 | int l = tmp_stream[(i*2)+0], r = tmp_stream[(i*2)+1]; 121 | stream[(i*2)+which_gb] = int16_t( (l+r) / 2 ); 122 | } 123 | } 124 | else if (audio_2p_mode == which_gb) 125 | { 126 | // only play gb 0 or 1 127 | this->snd_render->render(stream, SAMPLES_PER_FRAME); 128 | } 129 | if (which_gb == 1) 130 | { 131 | // only do audio callback after both gb's are rendered. 132 | audio_batch_cb(stream, SAMPLES_PER_FRAME); 133 | 134 | audio_2p_mode &= 3; 135 | memset(stream, 0, sizeof(stream)); 136 | } 137 | } 138 | else 139 | { 140 | this->snd_render->render(stream, SAMPLES_PER_FRAME); 141 | audio_batch_cb(stream, SAMPLES_PER_FRAME); 142 | } 143 | fixed_time = time(NULL); 144 | } 145 | 146 | int dmy_renderer::check_pad() 147 | { 148 | int16_t joypad_bits; 149 | if (libretro_supports_bitmasks) 150 | joypad_bits = input_state_cb(which_gb, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); 151 | else 152 | { 153 | unsigned i; 154 | joypad_bits = 0; 155 | for (i = 0; i < (RETRO_DEVICE_ID_JOYPAD_R3 + 1); i++) 156 | joypad_bits |= input_state_cb(which_gb, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0; 157 | } 158 | 159 | // update pad state: a,b,select,start,down,up,left,right 160 | return 161 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_A)) ? 1 : 0) << 0 | 162 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_B)) ? 1 : 0) << 1 | 163 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT)) ? 1 : 0) << 2 | 164 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_START)) ? 1 : 0) << 3 | 165 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)) ? 1 : 0) << 4 | 166 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_UP)) ? 1 : 0) << 5 | 167 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)) ? 1 : 0) << 6 | 168 | ((joypad_bits & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)) ? 1 : 0) << 7; 169 | } 170 | 171 | void dmy_renderer::render_screen(byte *buf,int width,int height,int depth) 172 | { 173 | static byte joined_buf[160*144*2*2]; // two screens' worth of 16-bit data 174 | const int half = sizeof(joined_buf)/2; 175 | int pitch = width*((depth+7)/8); 176 | int switched_gb = which_gb; 177 | if (_screen_switched) 178 | switched_gb = 1 - switched_gb; 179 | 180 | // are we running two gb's? 181 | if(g_gb[1] && gblink_enable) 182 | { 183 | // are we drawing both gb's to the screen? 184 | if (_show_player_screens == 2) 185 | { 186 | if(_screen_2p_vertical) 187 | { 188 | memcpy(joined_buf + switched_gb*half, buf, half); 189 | if(which_gb == 1) 190 | video_cb(joined_buf, width, height*2, pitch); 191 | } 192 | else 193 | { 194 | for (int row = 0; row < height; ++row) 195 | memcpy(joined_buf + pitch*(2*row + switched_gb), buf+pitch*row, pitch); 196 | if(which_gb == 1) 197 | video_cb(joined_buf, width*2, height, pitch*2); 198 | } 199 | } 200 | else 201 | { 202 | // are we currently on the gb that we want to draw? 203 | // (this ignores the "switch player screens" setting) 204 | if (_show_player_screens == which_gb) 205 | memcpy(joined_buf, buf, half); 206 | if (which_gb == 1) 207 | video_cb(joined_buf, width, height, pitch); 208 | } 209 | } 210 | else 211 | video_cb(buf, width, height, pitch); 212 | } 213 | 214 | byte dmy_renderer::get_time(int type) 215 | { 216 | dword now = fixed_time-cur_time; 217 | 218 | switch(type) 219 | { 220 | case 8: // second 221 | return (byte)(now%60); 222 | case 9: // minute 223 | return (byte)((now/60)%60); 224 | case 10: // hour 225 | return (byte)((now/(60*60))%24); 226 | case 11: // day (L) 227 | return (byte)((now/(24*60*60))&0xff); 228 | case 12: // day (H) 229 | return (byte)((now/(256*24*60*60))&1); 230 | } 231 | return 0; 232 | } 233 | 234 | void dmy_renderer::set_time(int type,byte dat) 235 | { 236 | dword now = fixed_time; 237 | dword adj = now - cur_time; 238 | 239 | switch(type) 240 | { 241 | case 8: // second 242 | adj = (adj/60)*60+(dat%60); 243 | break; 244 | case 9: // minute 245 | adj = (adj/(60*60))*60*60+(dat%60)*60+(adj%60); 246 | break; 247 | case 10: // hour 248 | adj = (adj/(24*60*60))*24*60*60+(dat%24)*60*60+(adj%(60*60)); 249 | break; 250 | case 11: // day (L) 251 | adj = (adj/(256*24*60*60))*256*24*60*60+(dat*24*60*60)+(adj%(24*60*60)); 252 | break; 253 | case 12: // day (H) 254 | adj = (dat&1)*256*24*60*60+(adj%(256*24*60*60)); 255 | break; 256 | } 257 | cur_time = now - adj; 258 | } 259 | 260 | -------------------------------------------------------------------------------- /gbr_interface/gbr.cpp: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | #include "gbr.h" 21 | #include 22 | 23 | gbr_sound::gbr_sound(gbr_procs *ref_procs) 24 | { 25 | procs=ref_procs; 26 | change=false; 27 | rest=0; 28 | now=0; 29 | } 30 | 31 | gbr_sound::~gbr_sound() 32 | { 33 | } 34 | 35 | void gbr_sound::render(short *buf,int samples) 36 | { 37 | procs->render(buf,samples); 38 | rest=(samples<1600)?samples:1600; 39 | memcpy(bef_buf,buf,rest*4); 40 | change=true; 41 | now=0; 42 | } 43 | 44 | short *gbr_sound::get_bef() 45 | { 46 | rest-=160; 47 | now+=160; 48 | if (rest<0) 49 | return 0; 50 | return bef_buf+now; 51 | } 52 | 53 | //----------------------------------------------- 54 | 55 | char playing_num[11][80]={ 56 | "0111110011000001111001100110110110001100111100000011000110000000000000000000000", 57 | "0110011011000011001101100110110110001101100110000011000110000000000000000000000", 58 | "0110011011000011001101100110110111001101100110000011100110000000000000000000011", 59 | "0110011011000011001101100110110111001101100110000011100110000000000000000000011", 60 | "0110011011000011001101100110110111101101100110000011110110000000000000000000000", 61 | "0110011011000011001101100110110110101101100110000011010110011100000000000000000", 62 | "0110011011000011001101100110110110111101100000000011011110110110000000000000000", 63 | "0111110011000011111100111100110110011101101110000011001110110110000000000000011", 64 | "0110000011000011001100011000110110011101100110000011001110110110000000000000011", 65 | "0110000011000011001100011000110110001101100110000011000110110110110000000000000", 66 | "0110000011111011001100011000110110001100111110000011000110011100110000000000000" 67 | }; 68 | 69 | char playing_time[11][80]={ 70 | "0111110011000001111001100110110110001100111100000011111101101100011011111000000", 71 | "0110011011000011001101100110110110001101100110000000110001101100011011000000000", 72 | "0110011011000011001101100110110111001101100110000000110001101110111011000000011", 73 | "0110011011000011001101100110110111001101100110000000110001101110111011000000011", 74 | "0110011011000011001101100110110111101101100110000000110001101111111011000000000", 75 | "0110011011000011001101100110110110101101100110000000110001101111111011000000000", 76 | "0110011011000011001101100110110110111101100000000000110001101101011011111000000", 77 | "0111110011000011111100111100110110011101101110000000110001101101011011000000011", 78 | "0110000011000011001100011000110110011101100110000000110001101100011011000000011", 79 | "0110000011000011001100011000110110001101100110000000110001101100011011000000000", 80 | "0110000011111011001100011000110110001100111110000000110001101100011011111000000" 81 | }; 82 | 83 | char num_pat[10][11][7]={ 84 | { 85 | "011110", 86 | "110011", 87 | "110011", 88 | "110111", 89 | "110111", 90 | "111111", 91 | "111011", 92 | "111011", 93 | "110011", 94 | "110011", 95 | "011110" 96 | }, 97 | { 98 | "001100", 99 | "011100", 100 | "111100", 101 | "101100", 102 | "001100", 103 | "001100", 104 | "001100", 105 | "001100", 106 | "001100", 107 | "001100", 108 | "111111" 109 | }, 110 | { 111 | "011110", 112 | "110011", 113 | "110011", 114 | "110011", 115 | "110011", 116 | "110011", 117 | "000111", 118 | "011110", 119 | "111000", 120 | "110000", 121 | "111111" 122 | }, 123 | { 124 | "011110", 125 | "110011", 126 | "110011", 127 | "110011", 128 | "110011", 129 | "110011", 130 | "000110", 131 | "110011", 132 | "110011", 133 | "110011", 134 | "011110" 135 | }, 136 | { 137 | "110011", 138 | "110011", 139 | "110011", 140 | "110011", 141 | "110011", 142 | "110011", 143 | "110011", 144 | "111111", 145 | "000011", 146 | "000011", 147 | "000011" 148 | }, 149 | { 150 | "111111", 151 | "110000", 152 | "110000", 153 | "110000", 154 | "110000", 155 | "111110", 156 | "110011", 157 | "000011", 158 | "110011", 159 | "110011", 160 | "011110" 161 | }, 162 | { 163 | "011110", 164 | "110011", 165 | "110011", 166 | "110011", 167 | "110011", 168 | "110000", 169 | "111110", 170 | "110011", 171 | "110011", 172 | "110011", 173 | "011110" 174 | }, 175 | { 176 | "111111", 177 | "000011", 178 | "000011", 179 | "000011", 180 | "000011", 181 | "000011", 182 | "000011", 183 | "000011", 184 | "000011", 185 | "000011", 186 | "000011" 187 | }, 188 | { 189 | "011110", 190 | "110011", 191 | "110011", 192 | "110011", 193 | "110011", 194 | "110011", 195 | "011110", 196 | "110011", 197 | "110011", 198 | "110011", 199 | "011110" 200 | }, 201 | { 202 | "011110", 203 | "110011", 204 | "110011", 205 | "110011", 206 | "110011", 207 | "110011", 208 | "110011", 209 | "011111", 210 | "000011", 211 | "000011", 212 | "111110" 213 | } 214 | }; 215 | 216 | char colon[11][3]={ 217 | "00", 218 | "00", 219 | "11", 220 | "11", 221 | "00", 222 | "00", 223 | "00", 224 | "11", 225 | "11", 226 | "00", 227 | "00" 228 | }; 229 | 230 | gbr::gbr(renderer *ref,gbr_procs *ref_procs) 231 | { 232 | m_renderer=ref; 233 | procs=ref_procs; 234 | 235 | gbr_snd=new gbr_sound(procs); 236 | 237 | m_renderer->set_sound_renderer(gbr_snd); 238 | reset(); 239 | } 240 | 241 | gbr::~gbr() 242 | { 243 | } 244 | 245 | void gbr::reset() 246 | { 247 | cur_num=0; 248 | m_renderer->reset(); 249 | procs->select(0); 250 | frames=0; 251 | 252 | memset(vframe,0,160*144*2); 253 | 254 | int i,j; 255 | 256 | for (i=0;i<11;i++) 257 | for (j=0;j<79;j++) 258 | vframe[(i+1)*160+j]=(playing_num[i][j]=='0')?0x0000:0xffff; 259 | 260 | for (i=0;i<11;i++) 261 | for (j=0;j<79;j++) 262 | vframe[(i+18)*160+j]=(playing_time[i][j]=='0')?0x0000:0xffff; 263 | 264 | for (i=0;i<11;i++) 265 | for (j=0;j<2;j++) 266 | vframe[(i+18)*160+j+97]=(colon[i][j]=='0')?0x0000:0xffff; 267 | 268 | for (i=0;i<11;i++) 269 | for (j=0;j<2;j++) 270 | vframe[(i+18)*160+j+114]=(colon[i][j]=='0')?0x0000:0xffff; 271 | } 272 | 273 | void gbr::load_rom(unsigned char *buf,int size) 274 | { 275 | procs->load(buf,size); 276 | reset(); 277 | } 278 | 279 | void gbr::run() 280 | { 281 | procs->run(); 282 | m_renderer->refresh(); 283 | 284 | static int tmp,bef=0; // (a,b,select,start,down,up,left,right の順) 285 | tmp=m_renderer->check_pad(); 286 | 287 | if ((!(bef&0x80))&&(tmp&0x80)){ 288 | cur_num++; 289 | cur_num&=0xff; 290 | select(cur_num); 291 | frames=0; 292 | } 293 | if ((!(bef&0x40))&&(tmp&0x40)){ 294 | cur_num--; 295 | cur_num&=0xff; 296 | select(cur_num); 297 | frames=0; 298 | } 299 | if ((!(bef&0x20))&&(tmp&0x20)){ 300 | cur_num+=10; 301 | cur_num&=0xff; 302 | select(cur_num); 303 | frames=0; 304 | } 305 | if ((!(bef&0x10))&&(tmp&0x10)){ 306 | cur_num-=10; 307 | cur_num&=0xff; 308 | select(cur_num); 309 | frames=0; 310 | } 311 | 312 | int number,i,j; 313 | 314 | number=cur_num/100; 315 | for (i=0;i<11;i++) 316 | for (j=0;j<6;j++) 317 | vframe[(i+1)*160+j+83]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 318 | 319 | number=(cur_num/10)%10; 320 | for (i=0;i<11;i++) 321 | for (j=0;j<6;j++) 322 | vframe[(i+1)*160+j+90]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 323 | 324 | number=cur_num%10; 325 | for (i=0;i<11;i++) 326 | for (j=0;j<6;j++) 327 | vframe[(i+1)*160+j+97]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 328 | 329 | 330 | number=(frames/60/60/10)%10; // 十分 331 | for (i=0;i<11;i++) 332 | for (j=0;j<6;j++) 333 | vframe[(i+18)*160+j+83]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 334 | 335 | number=(frames/60/60)%10; // 一分 336 | for (i=0;i<11;i++) 337 | for (j=0;j<6;j++) 338 | vframe[(i+18)*160+j+90]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 339 | 340 | number=(frames/60/10)%6; // 十秒 341 | for (i=0;i<11;i++) 342 | for (j=0;j<6;j++) 343 | vframe[(i+18)*160+j+100]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 344 | 345 | number=(frames/60)%10; // 一秒 346 | for (i=0;i<11;i++) 347 | for (j=0;j<6;j++) 348 | vframe[(i+18)*160+j+107]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 349 | 350 | number=(int)((float)(frames%60)*1.6666666666f)/10; // 1/10秒 351 | for (i=0;i<11;i++) 352 | for (j=0;j<6;j++) 353 | vframe[(i+18)*160+j+117]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 354 | 355 | number=(int)((float)(frames%60)*1.6666666666f)%10; // 1/100秒 356 | for (i=0;i<11;i++) 357 | for (j=0;j<6;j++) 358 | vframe[(i+18)*160+j+124]=(num_pat[number][i][j]=='0')?0x0000:0xffff; 359 | 360 | 361 | r=m_renderer->map_color(0x001f); 362 | g=m_renderer->map_color(0x03e0); 363 | 364 | short *dat; 365 | if (dat=gbr_snd->get_bef()){ 366 | int bef=30+(dat[0]+32768)/1150,bef_2=87+(dat[1]+32768)/1150,cur,next; 367 | memset(vframe+30*160,0,114*160*2); 368 | for (i=0;i<160;i++){ 369 | // cur=30+((dat[i*2]+dat[i*2+1])/2+32768)/575; 370 | // next=30+((dat[i*2+2]+dat[i*2+3])/2+32768)/575; 371 | cur=30+(dat[i*2]+32768)/1150; 372 | next=30+(dat[i*2+2]+32768)/1150; 373 | if (befcur;j--) 378 | vframe[j*160+i]=r; 379 | if (cur=cur+(next-cur)/2;j--) 384 | vframe[j*160+i]=r; 385 | bef=cur; 386 | } 387 | for (i=0;i<160;i++){ 388 | // cur=30+((dat[i*2]+dat[i*2+1])/2+32768)/575; 389 | // next=30+((dat[i*2+2]+dat[i*2+3])/2+32768)/575; 390 | cur=87+(dat[i*2+1]+32768)/1150; 391 | next=87+(dat[i*2+3]+32768)/1150; 392 | if (bef_2cur;j--) 397 | vframe[j*160+i]=g; 398 | if (cur=cur+(next-cur)/2;j--) 403 | vframe[j*160+i]=g; 404 | bef_2=cur; 405 | } 406 | } 407 | 408 | m_renderer->render_screen((unsigned char*)vframe,160,144,16); 409 | bef=tmp; 410 | frames++; 411 | } 412 | -------------------------------------------------------------------------------- /gb_core/gb.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //-------------------------------------------------- 21 | // GB クラス定義部,その他 22 | 23 | #include 24 | 25 | #include "gb_types.h" 26 | #include "renderer.h" 27 | #include "serializer.h" 28 | 29 | #define INT_VBLANK 1 30 | #define INT_LCDC 2 31 | #define INT_TIMER 4 32 | #define INT_SERIAL 8 33 | #define INT_PAD 16 34 | 35 | class gb; 36 | class cpu; 37 | class lcd; 38 | class apu; 39 | class apu_snd; 40 | class rom; 41 | class mbc; 42 | class cheat; 43 | 44 | struct ext_hook{ 45 | byte (*send)(byte); 46 | bool (*led)(void); 47 | }; 48 | 49 | struct cheat_dat{ 50 | bool enable; 51 | byte code; 52 | word adr; 53 | byte dat; 54 | char name[255]; 55 | cheat_dat *next; 56 | }; 57 | 58 | struct gb_regs { 59 | byte P1,SB,SC,DIV,TIMA,TMA,TAC,IF,LCDC,STAT,SCY,SCX,LY,LYC,DMA,BGP,OBP1,OBP2,WY,WX,IE; 60 | }; 61 | 62 | struct gbc_regs { 63 | byte KEY1,VBK,HDMA1,HDMA2,HDMA3,HDMA4,HDMA5,RP,BCPS,BCPD,OCPS,OCPD,SVBK; 64 | }; 65 | 66 | union pare_reg { 67 | word w; 68 | struct{byte l,h;}b; 69 | }; 70 | 71 | struct cpu_regs { 72 | pare_reg AF; 73 | pare_reg BC; 74 | pare_reg DE; 75 | pare_reg HL; 76 | word SP; 77 | word PC; 78 | byte I; 79 | }; 80 | 81 | struct apu_stat{ 82 | bool sq1_playing; 83 | int sq1_sw_time; 84 | int sq1_sw_dir; 85 | int sq1_sw_shift; 86 | 87 | int sq1_len; 88 | int sq1_init_len; 89 | int sq1_type; 90 | 91 | int sq1_vol; 92 | int sq1_init_vol; 93 | int sq1_env_dir; 94 | int sq1_env_speed; 95 | 96 | int sq1_freq; 97 | int sq1_init_freq; 98 | 99 | int sq1_hold; 100 | 101 | 102 | bool sq2_playing; 103 | 104 | int sq2_len; 105 | int sq2_init_len; 106 | int sq2_type; 107 | 108 | int sq2_vol; 109 | int sq2_init_vol; 110 | int sq2_env_dir; 111 | int sq2_env_speed; 112 | 113 | int sq2_freq; 114 | int sq2_init_freq; 115 | 116 | int sq2_hold; 117 | 118 | 119 | bool wav_playing; 120 | int wav_vol; 121 | int wav_freq; 122 | int wav_init_freq; 123 | int wav_init_len; 124 | int wav_len; 125 | int wav_hold; 126 | 127 | 128 | bool noi_playing; 129 | int noi_len; 130 | int noi_init_len; 131 | 132 | int noi_vol; 133 | int noi_init_vol; 134 | int noi_env_dir; 135 | int noi_env_speed; 136 | 137 | int noi_freq; 138 | int noi_init_freq; 139 | int noi_hold; 140 | int noi_step; 141 | 142 | int master_enable; 143 | int ch_enable[4][2]; 144 | int master_vol[2]; 145 | int ch_on[4]; 146 | int wav_enable; 147 | }; 148 | 149 | struct apu_que { 150 | word adr; 151 | byte dat; 152 | int clock; 153 | }; 154 | 155 | struct rom_info { 156 | char cart_name[18]; 157 | int cart_type; 158 | byte rom_size; 159 | byte ram_size; 160 | 161 | bool check_sum; 162 | int gb_type; 163 | }; 164 | 165 | class gb 166 | { 167 | friend class cpu; 168 | public: 169 | gb(renderer *ref,bool b_lcd,bool b_apu); 170 | ~gb(); 171 | 172 | cpu *get_cpu() { return m_cpu; } 173 | lcd *get_lcd() { return m_lcd; } 174 | apu *get_apu() { return m_apu; } 175 | rom *get_rom() { return m_rom; } 176 | mbc *get_mbc() { return m_mbc; } 177 | renderer *get_renderer() { return m_renderer; } 178 | cheat *get_cheat() { return m_cheat; } 179 | gb *get_target() { return target; } 180 | gb_regs *get_regs() { return ®s; } 181 | gbc_regs *get_cregs() { return &c_regs; } 182 | 183 | void run(); 184 | void reset(); 185 | void set_skip(int frame); 186 | void set_use_gba(bool use) { use_gba=use; } 187 | bool load_rom(byte *buf,int size,byte *ram,int ram_size, bool persistent); 188 | 189 | void serialize(serializer &s); 190 | void serialize_firstrev(serializer &s); 191 | void serialize_legacy(serializer &s); 192 | 193 | size_t get_state_size(void); 194 | void save_state_mem(void *buf); 195 | void restore_state_mem(void *buf); 196 | 197 | void refresh_pal(); 198 | 199 | void set_target(gb *tar) { target=tar; } 200 | 201 | void hook_extport(ext_hook *ext); 202 | void unhook_extport(); 203 | 204 | private: 205 | cpu *m_cpu; 206 | lcd *m_lcd; 207 | apu *m_apu; 208 | rom *m_rom; 209 | mbc *m_mbc; 210 | renderer *m_renderer; 211 | 212 | cheat *m_cheat; 213 | 214 | gb *target; 215 | 216 | gb_regs regs; 217 | gbc_regs c_regs; 218 | 219 | word dmy[160*5]; // vframe はみ出した時用 220 | word vframe[160*(144+100)]; 221 | 222 | ext_hook hook_proc; 223 | 224 | int skip,skip_buf; 225 | int now_frame; 226 | int re_render; 227 | 228 | bool hook_ext; 229 | bool use_gba; 230 | }; 231 | 232 | class cheat 233 | { 234 | public: 235 | cheat(gb *ref); 236 | ~cheat(); 237 | 238 | byte cheat_read(word adr); 239 | void cheat_write(word adr,byte dat); 240 | 241 | bool cheak_cheat(word adr); 242 | void create_cheat_map(); 243 | 244 | void add_cheat(cheat_dat *dat); 245 | void delete_cheat(char *name); 246 | std::list::iterator find_cheat(char *name); 247 | void create_unique_name(char *buf); 248 | 249 | void clear(); 250 | 251 | std::list::iterator get_first() { return cheat_list.begin(); } 252 | std::list::iterator get_end() { return cheat_list.end(); } 253 | 254 | int *get_cheat_map() { return cheat_map; } 255 | 256 | private: 257 | std::list cheat_list; 258 | int cheat_map[0x10000]; 259 | 260 | gb *ref_gb; 261 | }; 262 | 263 | class lcd 264 | { 265 | public: 266 | lcd(gb *ref); 267 | ~lcd(); 268 | 269 | void render(void *buf,int scanline); 270 | void reset(); 271 | void clear_win_count() { now_win_line=9; } 272 | word *get_pal(int num) { return col_pal[num]; } 273 | word *get_mapped_pal(int num) { return mapped_pal[num]; } 274 | 275 | void set_enable(int layer,bool enable); 276 | bool get_enable(int layer); 277 | 278 | int get_sprite_count() { return sprite_count; }; 279 | 280 | void serialize(serializer &s); 281 | private: 282 | void bg_render(void *buf,int scanline); 283 | void win_render(void *buf,int scanline); 284 | void sprite_render(void *buf,int scanline); 285 | void bg_render_color(void *buf,int scanline); 286 | void win_render_color(void *buf,int scanline); 287 | void sprite_render_color(void *buf,int scanline); 288 | 289 | word m_pal16[4]; 290 | dword m_pal32[4]; 291 | word col_pal[16][4]; 292 | word mapped_pal[16][4]; 293 | 294 | int trans_count; 295 | byte trans_tbl[160+160],priority_tbl[320]; 296 | 297 | int now_win_line; 298 | int mul; 299 | int sprite_count; 300 | 301 | bool layer_enable[3]; 302 | 303 | gb *ref_gb; 304 | }; 305 | 306 | class apu 307 | { 308 | friend class apu_snd; 309 | public: 310 | apu(gb *ref); 311 | ~apu(); 312 | 313 | apu_snd *get_renderer() { return snd; } 314 | apu_stat *get_stat(); 315 | apu_stat *get_stat_cpy(); 316 | byte *get_mem(); 317 | 318 | byte read(word adr); 319 | void write(word adr,byte dat,int clock); 320 | 321 | void update(); 322 | void reset(); 323 | 324 | void serialize(serializer &s); 325 | private: 326 | gb *ref_gb; 327 | apu_snd *snd; 328 | }; 329 | 330 | class apu_snd : public sound_renderer 331 | { 332 | friend class apu; 333 | public: 334 | apu_snd(apu *papu); 335 | ~apu_snd(); 336 | 337 | void set_enable(int ch,bool enable); 338 | bool get_enable(int ch); 339 | void set_echo(bool echo){ b_echo=echo; }; 340 | void set_lowpass(bool lowpass){ b_lowpass=lowpass; }; 341 | bool get_echo(){ return b_echo; }; 342 | bool get_lowpass(){ return b_lowpass; }; 343 | 344 | 345 | void render(short *buf,int sample); 346 | void reset(); 347 | 348 | void serialize(serializer &s); 349 | private: 350 | void process(word adr,byte dat); 351 | void update(); 352 | short sq1_produce(int freq); 353 | short sq2_produce(int freq); 354 | short wav_produce(int freq,bool interpolation); 355 | short noi_produce(int freq); 356 | 357 | apu_stat stat; 358 | apu_stat stat_cpy,stat_tmp; 359 | apu_que write_que[0x10000]; 360 | int que_count; 361 | int bef_clock; 362 | apu *ref_apu; 363 | 364 | bool b_echo; 365 | bool b_lowpass; 366 | 367 | byte mem[0x100]; 368 | bool b_enable[4]; 369 | }; 370 | 371 | class mbc 372 | { 373 | public: 374 | mbc(gb *ref); 375 | ~mbc(); 376 | 377 | byte *get_rom() { return rom_page; } 378 | byte *get_sram() { return sram_page; } 379 | bool is_ext_ram() { return ext_is_ram; } 380 | void set_ext_is(bool ext) { ext_is_ram=ext; } 381 | 382 | int get_state(); 383 | void set_state(int dat); 384 | void set_page(int rom,int sram); 385 | 386 | byte read(word adr); 387 | void write(word adr,byte dat); 388 | byte ext_read(word adr); 389 | void ext_write(word adr,byte dat); 390 | void reset(); 391 | 392 | void serialize(serializer &s); 393 | private: 394 | void mbc1_write(word adr,byte dat); 395 | void mbc2_write(word adr,byte dat); 396 | void mbc3_write(word adr,byte dat); 397 | void mbc5_write(word adr,byte dat); 398 | void mbc7_write(word adr,byte dat); 399 | void huc1_write(word adr,byte dat); 400 | void huc3_write(word adr,byte dat); 401 | void tama5_write(word adr,byte dat); 402 | void mmm01_write(word adr,byte dat); 403 | 404 | byte *rom_page; 405 | byte *sram_page; 406 | 407 | bool mbc1_16_8; 408 | byte mbc1_dat; 409 | 410 | byte mbc3_latch; // 1 bits 411 | byte mbc3_sec; // 6 412 | byte mbc3_min; // 6 413 | byte mbc3_hour; // 5 414 | byte mbc3_dayl; // 8 415 | byte mbc3_dayh; // 1 416 | 417 | byte mbc3_timer; // 4 418 | bool ext_is_ram; // 1 419 | // total 32bits 420 | 421 | int mbc5_dat; 422 | 423 | bool mbc7_write_enable; 424 | bool mbc7_idle; 425 | byte mbc7_cs; 426 | byte mbc7_sk; 427 | byte mbc7_op_code; 428 | byte mbc7_adr; 429 | word mbc7_dat; 430 | byte mbc7_ret; 431 | byte mbc7_state; 432 | word mbc7_buf; 433 | byte mbc7_count; 434 | 435 | bool huc1_16_8; 436 | byte huc1_dat; 437 | 438 | gb *ref_gb; 439 | }; 440 | 441 | class rom 442 | { 443 | public: 444 | rom(); 445 | ~rom(); 446 | 447 | rom_info *get_info() { return &info; } 448 | byte *get_rom() { return first_page; } 449 | byte *get_sram() { return sram; } 450 | bool get_loaded() { return b_loaded; } 451 | 452 | bool has_battery(); 453 | int get_sram_size(); // byte単位 454 | 455 | void set_first(int page) { first_page=dat+0x4000*page; } 456 | 457 | bool load_rom(byte *buf,int size,byte *ram,int ram_size, bool persistent); 458 | 459 | void serialize(serializer &s); 460 | private: 461 | rom_info info; 462 | 463 | byte *dat; 464 | byte *sram; 465 | 466 | byte *first_page; 467 | 468 | bool b_loaded; 469 | bool b_persistent; 470 | }; 471 | 472 | class cpu 473 | { 474 | friend class gb; 475 | public: 476 | cpu(gb *ref); 477 | ~cpu(); 478 | 479 | byte read(word adr) { return (ref_gb->get_cheat()->get_cheat_map()[adr])?ref_gb->get_cheat()->cheat_read(adr):read_direct(adr); } 480 | 481 | byte read_direct(word adr); 482 | void write(word adr,byte dat); 483 | word inline readw(word adr) { return read(adr)|(read(adr+1)<<8); } 484 | void inline writew(word adr,word dat) { write(adr,(byte)dat);write(adr+1,dat>>8); } 485 | 486 | void exec(int clocks); 487 | byte seri_send(byte dat); 488 | void irq(int irq_type); 489 | void inline irq_process(); 490 | void reset(); 491 | void set_trace(bool trace) { b_trace=trace; } 492 | 493 | byte *get_vram() { return vram; } 494 | byte *get_ram() { return ram; } 495 | byte *get_oam() { return oam; } 496 | byte *get_stack() { return stack; } 497 | 498 | byte *get_ram_bank() { return ram_bank; } 499 | void set_ram_bank(int bank) { ram_bank=ram+bank*0x1000; } 500 | 501 | cpu_regs *get_regs() { return ®s; } 502 | 503 | int get_clock() { return total_clock; } 504 | bool get_speed() { return speed; } 505 | 506 | bool *get_halt() { return &halt; } 507 | 508 | void save_state(int *dat); 509 | void restore_state(int *dat); 510 | void save_state_ex(int *dat); 511 | void restore_state_ex(int *dat); 512 | 513 | void serialize(serializer &s); 514 | private: 515 | byte inline io_read(word adr); 516 | void inline io_write(word adr,byte dat); 517 | byte op_read() { return read(regs.PC++); } 518 | word op_readw() { regs.PC+=2;return readw(regs.PC-2); } 519 | 520 | int dasm(char *S,byte *A); 521 | void log(); 522 | 523 | gb *ref_gb; 524 | cpu_regs regs; 525 | 526 | byte ram[0x2000*4]; 527 | byte vram[0x2000*2]; 528 | byte stack[0x80]; 529 | byte oam[0xA0]; 530 | byte spare_oam[0x18]; 531 | byte ext_mem[16]; 532 | 533 | byte *vram_bank; 534 | byte *ram_bank; 535 | 536 | byte z802gb[256],gb2z80[256]; 537 | dword rp_que[256]; 538 | int que_cur; 539 | // word org_pal[16][4]; 540 | int total_clock,rest_clock,sys_clock,seri_occer,div_clock; 541 | bool halt,speed,speed_change,dma_executing; 542 | bool b_trace; 543 | int dma_src; 544 | int dma_dest; 545 | int dma_rest; 546 | int gdma_rest; 547 | bool b_dma_first; 548 | 549 | int last_int; 550 | bool int_desable; 551 | 552 | byte *dma_src_bank; 553 | byte *dma_dest_bank; 554 | 555 | byte _ff6c,_ff72,_ff73,_ff74,_ff75; 556 | }; 557 | -------------------------------------------------------------------------------- /gb_core/gb.cpp: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //------------------------------------------------- 21 | // GB その他エミュレーション部/外部とのインターフェース 22 | // Interface with external / other unit emulation GB 23 | 24 | #include "gb.h" 25 | #include 26 | 27 | gb::gb(renderer *ref,bool b_lcd,bool b_apu) 28 | { 29 | m_renderer=ref; 30 | 31 | m_lcd=new lcd(this); 32 | m_rom=new rom(); 33 | m_apu=new apu(this);// ROMより後に作られたし // I was made ​​later than the ROM 34 | m_mbc=new mbc(this); 35 | m_cpu=new cpu(this); 36 | m_cheat=new cheat(this); 37 | target=NULL; 38 | 39 | m_renderer->reset(); 40 | m_renderer->set_sound_renderer(b_apu?m_apu->get_renderer():NULL); 41 | 42 | reset(); 43 | 44 | hook_ext=false; 45 | use_gba=false; 46 | } 47 | 48 | gb::~gb() 49 | { 50 | m_renderer->set_sound_renderer(NULL); 51 | 52 | delete m_mbc; 53 | delete m_rom; 54 | delete m_apu; 55 | delete m_lcd; 56 | delete m_cpu; 57 | } 58 | 59 | void gb::reset() 60 | { 61 | regs.SC=0; 62 | regs.DIV=0; 63 | regs.TIMA=0; 64 | regs.TMA=0; 65 | regs.TAC=0; 66 | regs.LCDC=0x91; 67 | regs.STAT=0; 68 | regs.SCY=0; 69 | regs.SCX=0; 70 | regs.LY=153; 71 | regs.LYC=0; 72 | regs.BGP=0xFC; 73 | regs.OBP1=0xFF; 74 | regs.OBP2=0xFF; 75 | regs.WY=0; 76 | regs.WX=0; 77 | regs.IF=0; 78 | regs.IE=0; 79 | 80 | memset(&c_regs,0,sizeof(c_regs)); 81 | 82 | if (m_rom->get_loaded()) 83 | m_rom->get_info()->gb_type=(m_rom->get_rom()[0x143]&0x80)?(use_gba?4:3):1; 84 | 85 | m_cpu->reset(); 86 | m_lcd->reset(); 87 | m_apu->reset(); 88 | m_mbc->reset(); 89 | 90 | now_frame=0; 91 | skip=skip_buf=0; 92 | re_render=0; 93 | } 94 | 95 | void gb::hook_extport(ext_hook *ext) 96 | { 97 | hook_proc=*ext; 98 | hook_ext=true; 99 | } 100 | 101 | void gb::unhook_extport() 102 | { 103 | hook_ext=false; 104 | } 105 | 106 | void gb::set_skip(int frame) 107 | { 108 | skip_buf=frame; 109 | } 110 | 111 | bool gb::load_rom(byte *buf,int size,byte *ram,int ram_size, bool persistent) 112 | { 113 | if (m_rom->load_rom(buf,size,ram,ram_size, persistent)) 114 | { 115 | reset(); 116 | return true; 117 | } 118 | return false; 119 | } 120 | 121 | // savestate format matching the original TGB dual, pre-libretro port 122 | void gb::serialize_legacy(serializer &s) 123 | { 124 | int tbl_ram[]={1,1,1,4,16,8}; 125 | 126 | s.process(&m_rom->get_info()->gb_type, sizeof(int)); 127 | bool gbc = m_rom->get_info()->gb_type >= 3; // GB: 1, SGB: 2, GBC: 3... 128 | 129 | int cpu_dat[16]; // only used when gbc is true 130 | 131 | if(gbc) { 132 | s.process(m_cpu->get_ram(), 0x2000*4); 133 | s.process(m_cpu->get_vram(), 0x2000*2); 134 | } else { 135 | s.process(m_cpu->get_ram(), 0x2000); 136 | s.process(m_cpu->get_vram(), 0x2000); 137 | } 138 | s.process(m_rom->get_sram(), tbl_ram[m_rom->get_info()->ram_size]*0x2000); 139 | s.process(m_cpu->get_oam(), 0xA0); 140 | s.process(m_cpu->get_stack(), 0x80); 141 | 142 | int rom_page = (m_mbc->get_rom()-m_rom->get_rom())/0x4000; 143 | int ram_page = (m_mbc->get_sram()-m_rom->get_sram())/0x2000; 144 | s.process(&rom_page, sizeof(int)); 145 | s.process(&ram_page, sizeof(int)); 146 | m_mbc->set_page(rom_page, ram_page); // hackish, but should work. 147 | // basically, if we're serializing to count or save, the set_page 148 | // should have no effect assuming the calculations above are correct. 149 | // tl;dr: "if it's good enough for saving, it's good enough for loading" 150 | 151 | if(gbc) { 152 | m_cpu->save_state(cpu_dat); 153 | 154 | s.process(cpu_dat+0, 2*sizeof(int)); //int_page, vram_page 155 | /* s.process(cpu_dat+1, sizeof(int)); ^ just serialize both in one go */ 156 | } 157 | 158 | s.process(m_cpu->get_regs(), sizeof(cpu_regs)); // cpu_reg 159 | s.process(®s, sizeof(gb_regs)); //sys_reg 160 | 161 | if(gbc) { 162 | s.process(&c_regs, sizeof(gbc_regs)); //col_reg 163 | s.process(m_lcd->get_pal(0), sizeof(word)*8*4*2); //palette 164 | } 165 | 166 | int halt = !! (*m_cpu->get_halt()); 167 | s.process(&halt, sizeof(int)); 168 | (*m_cpu->get_halt()) = !! halt; // same errata as above 169 | 170 | // Originally the number of clocks until serial communication expires 171 | int dmy = 0; 172 | s.process(&dmy, sizeof(int)); 173 | 174 | int mbc_dat = m_mbc->get_state(); 175 | s.process(&mbc_dat, sizeof(int)); //MBC 176 | m_mbc->set_state(mbc_dat); 177 | 178 | int ext_is = !! m_mbc->is_ext_ram(); 179 | s.process(&ext_is, sizeof(int)); 180 | m_mbc->set_ext_is(!! ext_is); 181 | 182 | if(gbc) { 183 | // Many additional specifications 184 | /* i think this is inefficient... 185 | s.process(cpu_dat+2, sizeof(int)); 186 | 187 | s.process(cpu_dat+3, sizeof(int)); 188 | s.process(cpu_dat+4, sizeof(int)); 189 | s.process(cpu_dat+5, sizeof(int)); 190 | s.process(cpu_dat+6, sizeof(int)); 191 | 192 | s.process(cpu_dat+7, sizeof(int)); 193 | */ 194 | s.process(cpu_dat+2, 6*sizeof(int)); 195 | m_cpu->restore_state(cpu_dat); // same errata as above 196 | } 197 | 198 | // Added ver 1.1 199 | s.process(m_apu->get_stat(), sizeof(apu_stat)); 200 | s.process(m_apu->get_mem(), 0x30); 201 | s.process(m_apu->get_stat_cpy(), sizeof(apu_stat)); 202 | 203 | byte resurved[256]; 204 | memset(resurved, 0, 256); 205 | s.process(resurved, 256); // Reserved for future use 206 | } 207 | 208 | 209 | // TODO: put 'serialize' in other classes (cpu, mbc, ...) and call it from here. 210 | void gb::serialize_firstrev(serializer &s) 211 | { 212 | int tbl_ram[]={1,1,1,4,16,8}; 213 | 214 | s.process(&m_rom->get_info()->gb_type, sizeof(int)); 215 | bool gbc = m_rom->get_info()->gb_type >= 3; // GB: 1, SGB: 2, GBC: 3... 216 | 217 | int cpu_dat[16]; 218 | 219 | if(gbc) { 220 | s.process(m_cpu->get_ram(), 0x2000*4); 221 | s.process(m_cpu->get_vram(), 0x2000*2); 222 | } else { 223 | s.process(m_cpu->get_ram(), 0x2000); 224 | s.process(m_cpu->get_vram(), 0x2000); 225 | } 226 | s.process(m_rom->get_sram(), tbl_ram[m_rom->get_info()->ram_size]*0x2000); 227 | s.process(m_cpu->get_oam(), 0xA0); 228 | s.process(m_cpu->get_stack(), 0x80); 229 | 230 | int rom_page = (m_mbc->get_rom() - m_rom->get_rom()) / 0x4000; 231 | int ram_page = (m_mbc->get_sram() - m_rom->get_sram()) / 0x2000; 232 | s.process(&rom_page, sizeof(int)); // rom_page 233 | s.process(&ram_page, sizeof(int)); // ram_page 234 | m_mbc->set_page(rom_page, ram_page); // hackish, but should work. 235 | // basically, if we're serializing to count or save, the set_page 236 | // should have no effect assuming the calculations above are correct. 237 | // tl;dr: "if it's good enough for saving, it's good enough for loading" 238 | 239 | if(true || gbc) { // why not for normal gb as well? 240 | m_cpu->save_state(cpu_dat); 241 | m_cpu->save_state_ex(cpu_dat+8); 242 | s.process(cpu_dat, 12*sizeof(int)); 243 | m_cpu->restore_state(cpu_dat); // same errata as above 244 | m_cpu->restore_state_ex(cpu_dat+8); 245 | } 246 | 247 | s.process(m_cpu->get_regs(), sizeof(cpu_regs)); // cpu_reg 248 | s.process(®s, sizeof(gb_regs)); //sys_reg 249 | 250 | if(gbc) { 251 | s.process(&c_regs, sizeof(gbc_regs)); //col_reg 252 | s.process(m_lcd->get_pal(0), sizeof(word)*8*4*2); //palette 253 | } 254 | 255 | s.process(m_cpu->get_halt(), sizeof(bool)); 256 | 257 | int mbc_dat = m_mbc->get_state(); 258 | s.process(&mbc_dat, sizeof(int)); //MBC 259 | m_mbc->set_state(mbc_dat); 260 | 261 | bool ext_is = m_mbc->is_ext_ram(); 262 | s.process(&ext_is, sizeof(bool)); 263 | m_mbc->set_ext_is(ext_is); 264 | 265 | // Added ver 1.1 266 | s.process(m_apu->get_stat(), sizeof(apu_stat)); 267 | s.process(m_apu->get_mem(), 0x30); 268 | s.process(m_apu->get_stat_cpy(), sizeof(apu_stat)); 269 | } 270 | 271 | void gb::serialize(serializer &s) 272 | { 273 | s_VAR(regs); 274 | s_VAR(c_regs); 275 | 276 | m_rom->serialize(s); 277 | m_cpu->serialize(s); 278 | m_mbc->serialize(s); 279 | m_lcd->serialize(s); 280 | m_apu->serialize(s); 281 | } 282 | 283 | size_t gb::get_state_size(void) 284 | { 285 | size_t ret = 0; 286 | serializer s(&ret, serializer::COUNT); 287 | serialize(s); 288 | return ret; 289 | } 290 | 291 | void gb::save_state_mem(void *buf) 292 | { 293 | serializer s(buf, serializer::SAVE_BUF); 294 | serialize(s); 295 | } 296 | 297 | void gb::restore_state_mem(void *buf) 298 | { 299 | serializer s(buf, serializer::LOAD_BUF); 300 | serialize(s); 301 | } 302 | 303 | void gb::refresh_pal() 304 | { 305 | for (int i=0;i<64;i++) 306 | m_lcd->get_mapped_pal(i>>2)[i&3]=m_renderer->map_color(m_lcd->get_pal(i>>2)[i&3]); 307 | } 308 | 309 | void gb::run() 310 | { 311 | if (m_rom->get_loaded()){ 312 | if (regs.LCDC&0x80){ // LCDC 起動時 // Startup LCDC 313 | regs.LY=(regs.LY+1)%154; 314 | 315 | regs.STAT&=0xF8; 316 | if (regs.LYC==regs.LY){ 317 | regs.STAT|=4; 318 | if (regs.STAT&0x40) 319 | m_cpu->irq(INT_LCDC); 320 | } 321 | if (regs.LY==0){ 322 | m_renderer->refresh(); 323 | if (now_frame>=skip){ 324 | m_renderer->render_screen((byte*)vframe,160,144,16); 325 | now_frame=0; 326 | } 327 | else 328 | now_frame++; 329 | m_lcd->clear_win_count(); 330 | skip=skip_buf; 331 | } 332 | if (regs.LY>=144){ // VBlank 期間中 // During VBlank 333 | regs.STAT|=1; 334 | if (regs.LY==144){ 335 | m_cpu->exec(72); 336 | m_cpu->irq(INT_VBLANK); 337 | if (regs.STAT&0x10) 338 | m_cpu->irq(INT_LCDC); 339 | m_cpu->exec(456-80); 340 | } 341 | else if (regs.LY==153){ 342 | m_cpu->exec(80); 343 | regs.LY=0; 344 | // 前のラインのかなり早目から0になるようだ。 345 | // It's pretty early to be 0 from the previous line. 346 | m_cpu->exec(456-80); 347 | regs.LY=153; 348 | } 349 | else 350 | m_cpu->exec(456); 351 | } 352 | else{ // VBlank 期間外 // Period outside VBlank 353 | regs.STAT|=2; 354 | if (regs.STAT&0x20) 355 | m_cpu->irq(INT_LCDC); 356 | m_cpu->exec(80); // state=2 357 | regs.STAT|=3; 358 | m_cpu->exec(169); // state=3 359 | 360 | if (m_cpu->dma_executing){ // HBlank DMA 361 | if (m_cpu->b_dma_first){ 362 | m_cpu->dma_dest_bank=m_cpu->vram_bank; 363 | if (m_cpu->dma_src<0x4000) 364 | m_cpu->dma_src_bank=m_rom->get_rom(); 365 | else if (m_cpu->dma_src<0x8000) 366 | m_cpu->dma_src_bank=m_mbc->get_rom(); 367 | else if (m_cpu->dma_src>=0xA000&&m_cpu->dma_src<0xC000) 368 | m_cpu->dma_src_bank=m_mbc->get_sram()-0xA000; 369 | else if (m_cpu->dma_src>=0xC000&&m_cpu->dma_src<0xD000) 370 | m_cpu->dma_src_bank=m_cpu->ram-0xC000; 371 | else if (m_cpu->dma_src>=0xD000&&m_cpu->dma_src<0xE000) 372 | m_cpu->dma_src_bank=m_cpu->ram_bank-0xD000; 373 | else m_cpu->dma_src_bank=NULL; 374 | m_cpu->b_dma_first=false; 375 | } 376 | memcpy(m_cpu->dma_dest_bank+(m_cpu->dma_dest&0x1ff0),m_cpu->dma_src_bank+m_cpu->dma_src,16); 377 | // fprintf(m_cpu->file,"%03d : dma exec %04X -> %04X rest %d\n",regs.LY,m_cpu->dma_src,m_cpu->dma_dest,m_cpu->dma_rest); 378 | 379 | m_cpu->dma_src+=16; 380 | m_cpu->dma_src&=0xfff0; 381 | m_cpu->dma_dest+=16; 382 | m_cpu->dma_dest&=0xfff0; 383 | m_cpu->dma_rest--; 384 | if (!m_cpu->dma_rest) 385 | m_cpu->dma_executing=false; 386 | 387 | // m_cpu->total_clock+=207*(m_cpu->speed?2:1); 388 | // m_cpu->sys_clock+=207*(m_cpu->speed?2:1); 389 | // m_cpu->div_clock+=207*(m_cpu->speed?2:1); 390 | // regs.STAT|=3; 391 | 392 | if (now_frame>=skip) 393 | m_lcd->render(vframe,regs.LY); 394 | 395 | regs.STAT&=0xfc; 396 | m_cpu->exec(207); // state=3 397 | } 398 | else{ 399 | /* if (m_lcd->get_sprite_count()){ 400 | if (m_lcd->get_sprite_count()>=10){ 401 | m_cpu->exec(129); 402 | if ((regs.STAT&0x08)) 403 | m_cpu->irq(INT_LCDC); 404 | regs.STAT&=0xfc; 405 | if (now_frame>=skip) 406 | m_lcd->render(vframe,regs.LY); 407 | m_cpu->exec(78); // state=0 408 | } 409 | else{ 410 | m_cpu->exec(129*m_lcd->get_sprite_count()/10); 411 | if ((regs.STAT&0x08)) 412 | m_cpu->irq(INT_LCDC); 413 | regs.STAT&=0xfc; 414 | if (now_frame>=skip) 415 | m_lcd->render(vframe,regs.LY); 416 | m_cpu->exec(207-(129*m_lcd->get_sprite_count()/10)); // state=0 417 | } 418 | } 419 | else{ 420 | */ regs.STAT&=0xfc; 421 | if (now_frame>=skip) 422 | m_lcd->render(vframe,regs.LY); 423 | if ((regs.STAT&0x08)) 424 | m_cpu->irq(INT_LCDC); 425 | m_cpu->exec(207); // state=0 426 | // } 427 | } 428 | } 429 | } 430 | else{ // LCDC 停止時 // LCDC is stopped 431 | regs.LY=0; 432 | // regs.LY=(regs.LY+1)%154; 433 | re_render++; 434 | if (re_render>=154){ 435 | memset(vframe,0xff,160*144*2); 436 | m_renderer->refresh(); 437 | if (now_frame>=skip){ 438 | m_renderer->render_screen((byte*)vframe,160,144,16); 439 | now_frame=0; 440 | } 441 | else 442 | now_frame++; 443 | m_lcd->clear_win_count(); 444 | re_render=0; 445 | } 446 | regs.STAT&=0xF8; 447 | m_cpu->exec(456); 448 | } 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /docs/COPYING-2.0.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 675 Mass Ave, Cambridge, MA 02139, USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | -------------------------------------------------------------------------------- /gb_core/op_cb.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //bit test/set/reset opcode 21 | 22 | //B 000 C 001 D 010 E 011 H 100 L 101 A 111 23 | //BIT b,r :01 b r :state 8 24 | case 0x40: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B<<6)&0x40)^0x40);break; //BIT 0,B 25 | case 0x41: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C<<6)&0x40)^0x40);break; //BIT 0,C 26 | case 0x42: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D<<6)&0x40)^0x40);break; //BIT 0,D 27 | case 0x43: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E<<6)&0x40)^0x40);break; //BIT 0,E 28 | case 0x44: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H<<6)&0x40)^0x40);break; //BIT 0,H 29 | case 0x45: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L<<6)&0x40)^0x40);break; //BIT 0,L 30 | case 0x47: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A<<6)&0x40)^0x40);break; //BIT 0,A 31 | 32 | case 0x48: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B<<5)&0x40)^0x40);break; //BIT 1,B 33 | case 0x49: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C<<5)&0x40)^0x40);break; //BIT 1,C 34 | case 0x4A: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D<<5)&0x40)^0x40);break; //BIT 1,D 35 | case 0x4B: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E<<5)&0x40)^0x40);break; //BIT 1,E 36 | case 0x4C: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H<<5)&0x40)^0x40);break; //BIT 1,H 37 | case 0x4D: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L<<5)&0x40)^0x40);break; //BIT 1,L 38 | case 0x4F: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A<<5)&0x40)^0x40);break; //BIT 1,A 39 | 40 | case 0x50: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B<<4)&0x40)^0x40);break; //BIT 2,B 41 | case 0x51: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C<<4)&0x40)^0x40);break; //BIT 2,C 42 | case 0x52: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D<<4)&0x40)^0x40);break; //BIT 2,D 43 | case 0x53: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E<<4)&0x40)^0x40);break; //BIT 2,E 44 | case 0x54: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H<<4)&0x40)^0x40);break; //BIT 2,H 45 | case 0x55: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L<<4)&0x40)^0x40);break; //BIT 2,L 46 | case 0x57: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A<<4)&0x40)^0x40);break; //BIT 2,A 47 | 48 | case 0x58: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B<<3)&0x40)^0x40);break; //BIT 3,B 49 | case 0x59: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C<<3)&0x40)^0x40);break; //BIT 3,C 50 | case 0x5A: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D<<3)&0x40)^0x40);break; //BIT 3,D 51 | case 0x5B: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E<<3)&0x40)^0x40);break; //BIT 3,E 52 | case 0x5C: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H<<3)&0x40)^0x40);break; //BIT 3,H 53 | case 0x5D: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L<<3)&0x40)^0x40);break; //BIT 3,L 54 | case 0x5F: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A<<3)&0x40)^0x40);break; //BIT 3,A 55 | 56 | case 0x60: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B<<2)&0x40)^0x40);break; //BIT 4,B 57 | case 0x61: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C<<2)&0x40)^0x40);break; //BIT 4,C 58 | case 0x62: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D<<2)&0x40)^0x40);break; //BIT 4,D 59 | case 0x63: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E<<2)&0x40)^0x40);break; //BIT 4,E 60 | case 0x64: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H<<2)&0x40)^0x40);break; //BIT 4,H 61 | case 0x65: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L<<2)&0x40)^0x40);break; //BIT 4,L 62 | case 0x67: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A<<2)&0x40)^0x40);break; //BIT 4,A 63 | 64 | case 0x68: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B<<1)&0x40)^0x40);break; //BIT 5,B 65 | case 0x69: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C<<1)&0x40)^0x40);break; //BIT 5,C 66 | case 0x6A: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D<<1)&0x40)^0x40);break; //BIT 5,D 67 | case 0x6B: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E<<1)&0x40)^0x40);break; //BIT 5,E 68 | case 0x6C: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H<<1)&0x40)^0x40);break; //BIT 5,H 69 | case 0x6D: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L<<1)&0x40)^0x40);break; //BIT 5,L 70 | case 0x6F: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A<<1)&0x40)^0x40);break; //BIT 5,A 71 | 72 | case 0x70: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B)&0x40)^0x40);break; //BIT 6,B 73 | case 0x71: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C)&0x40)^0x40);break; //BIT 6,C 74 | case 0x72: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D)&0x40)^0x40);break; //BIT 6,D 75 | case 0x73: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E)&0x40)^0x40);break; //BIT 6,E 76 | case 0x74: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H)&0x40)^0x40);break; //BIT 6,H 77 | case 0x75: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L)&0x40)^0x40);break; //BIT 6,L 78 | case 0x77: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A)&0x40)^0x40);break; //BIT 6,A 79 | 80 | case 0x78: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_B>>1)&0x40)^0x40);break; //BIT 7,B 81 | case 0x79: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_C>>1)&0x40)^0x40);break; //BIT 7,C 82 | case 0x7A: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_D>>1)&0x40)^0x40);break; //BIT 7,D 83 | case 0x7B: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_E>>1)&0x40)^0x40);break; //BIT 7,E 84 | case 0x7C: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_H>>1)&0x40)^0x40);break; //BIT 7,H 85 | case 0x7D: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_L>>1)&0x40)^0x40);break; //BIT 7,L 86 | case 0x7F: REG_F=((REG_F&C_FLAG)|H_FLAG)|(((REG_A>>1)&0x40)^0x40);break; //BIT 7,A 87 | 88 | //state 12 89 | case 0x46: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l<<6)&0x40)^0x40);break; //BIT 0,(HL) 90 | case 0x4E: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l<<5)&0x40)^0x40);break; //BIT 1,(HL) 91 | case 0x56: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l<<4)&0x40)^0x40);break; //BIT 2,(HL) 92 | case 0x5E: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l<<3)&0x40)^0x40);break; //BIT 3,(HL) 93 | case 0x66: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l<<2)&0x40)^0x40);break; //BIT 4,(HL) 94 | case 0x6E: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l<<1)&0x40)^0x40);break; //BIT 5,(HL) 95 | case 0x76: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l)&0x40)^0x40);break; //BIT 6,(HL) 96 | case 0x7E: tmp.b.l=read(REG_HL);REG_F=((REG_F&C_FLAG)|H_FLAG)|(((tmp.b.l>>1)&0x40)^0x40);break; //BIT 7,(HL) 97 | 98 | //bit set opcode 99 | //SET b,r :11 b r : state 8 100 | 101 | case 0xC0: REG_B|=0x01;break; //SET 0,B 102 | case 0xC1: REG_C|=0x01;break; //SET 0,C 103 | case 0xC2: REG_D|=0x01;break; //SET 0,D 104 | case 0xC3: REG_E|=0x01;break; //SET 0,E 105 | case 0xC4: REG_H|=0x01;break; //SET 0,H 106 | case 0xC5: REG_L|=0x01;break; //SET 0,L 107 | case 0xC7: REG_A|=0x01;break; //SET 0,A 108 | 109 | case 0xC8: REG_B|=0x02;break; //SET 1,B 110 | case 0xC9: REG_C|=0x02;break; //SET 1,C 111 | case 0xCA: REG_D|=0x02;break; //SET 1,D 112 | case 0xCB: REG_E|=0x02;break; //SET 1,E 113 | case 0xCC: REG_H|=0x02;break; //SET 1,H 114 | case 0xCD: REG_L|=0x02;break; //SET 1,L 115 | case 0xCF: REG_A|=0x02;break; //SET 1,A 116 | 117 | case 0xD0: REG_B|=0x04;break; //SET 2,B 118 | case 0xD1: REG_C|=0x04;break; //SET 2,C 119 | case 0xD2: REG_D|=0x04;break; //SET 2,D 120 | case 0xD3: REG_E|=0x04;break; //SET 2,E 121 | case 0xD4: REG_H|=0x04;break; //SET 2,H 122 | case 0xD5: REG_L|=0x04;break; //SET 2,L 123 | case 0xD7: REG_A|=0x04;break; //SET 2,A 124 | 125 | case 0xD8: REG_B|=0x08;break; //SET 3,B 126 | case 0xD9: REG_C|=0x08;break; //SET 3,C 127 | case 0xDA: REG_D|=0x08;break; //SET 3,D 128 | case 0xDB: REG_E|=0x08;break; //SET 3,E 129 | case 0xDC: REG_H|=0x08;break; //SET 3,H 130 | case 0xDD: REG_L|=0x08;break; //SET 3,L 131 | case 0xDF: REG_A|=0x08;break; //SET 3,A 132 | 133 | case 0xE0: REG_B|=0x10;break; //SET 4,B 134 | case 0xE1: REG_C|=0x10;break; //SET 4,C 135 | case 0xE2: REG_D|=0x10;break; //SET 4,D 136 | case 0xE3: REG_E|=0x10;break; //SET 4,E 137 | case 0xE4: REG_H|=0x10;break; //SET 4,H 138 | case 0xE5: REG_L|=0x10;break; //SET 4,L 139 | case 0xE7: REG_A|=0x10;break; //SET 4,A 140 | 141 | case 0xE8: REG_B|=0x20;break; //SET 5,B 142 | case 0xE9: REG_C|=0x20;break; //SET 5,C 143 | case 0xEA: REG_D|=0x20;break; //SET 5,D 144 | case 0xEB: REG_E|=0x20;break; //SET 5,E 145 | case 0xEC: REG_H|=0x20;break; //SET 5,H 146 | case 0xED: REG_L|=0x20;break; //SET 5,L 147 | case 0xEF: REG_A|=0x20;break; //SET 5,A 148 | 149 | case 0xF0: REG_B|=0x40;break; //SET 6,B 150 | case 0xF1: REG_C|=0x40;break; //SET 6,C 151 | case 0xF2: REG_D|=0x40;break; //SET 6,D 152 | case 0xF3: REG_E|=0x40;break; //SET 6,E 153 | case 0xF4: REG_H|=0x40;break; //SET 6,H 154 | case 0xF5: REG_L|=0x40;break; //SET 6,L 155 | case 0xF7: REG_A|=0x40;break; //SET 6,A 156 | 157 | case 0xF8: REG_B|=0x80;break; //SET 7,B 158 | case 0xF9: REG_C|=0x80;break; //SET 7,C 159 | case 0xFA: REG_D|=0x80;break; //SET 7,D 160 | case 0xFB: REG_E|=0x80;break; //SET 7,E 161 | case 0xFC: REG_H|=0x80;break; //SET 7,H 162 | case 0xFD: REG_L|=0x80;break; //SET 7,L 163 | case 0xFF: REG_A|=0x80;break; //SET 7,A 164 | 165 | //state 16 166 | case 0xC6: tmp.b.l=read(REG_HL);tmp.b.l|=0x01;write(REG_HL,tmp.b.l);break; //SET 0,(HL) 167 | case 0xCE: tmp.b.l=read(REG_HL);tmp.b.l|=0x02;write(REG_HL,tmp.b.l);break; //SET 1,(HL) 168 | case 0xD6: tmp.b.l=read(REG_HL);tmp.b.l|=0x04;write(REG_HL,tmp.b.l);break; //SET 2,(HL) 169 | case 0xDE: tmp.b.l=read(REG_HL);tmp.b.l|=0x08;write(REG_HL,tmp.b.l);break; //SET 3,(HL) 170 | case 0xE6: tmp.b.l=read(REG_HL);tmp.b.l|=0x10;write(REG_HL,tmp.b.l);break; //SET 4,(HL) 171 | case 0xEE: tmp.b.l=read(REG_HL);tmp.b.l|=0x20;write(REG_HL,tmp.b.l);break; //SET 5,(HL) 172 | case 0xF6: tmp.b.l=read(REG_HL);tmp.b.l|=0x40;write(REG_HL,tmp.b.l);break; //SET 6,(HL) 173 | case 0xFE: tmp.b.l=read(REG_HL);tmp.b.l|=0x80;write(REG_HL,tmp.b.l);break; //SET 7,(HL) 174 | 175 | //bit reset opcode 176 | //RES b,r : 10 b r : state 8 177 | case 0x80: REG_B&=0xFE;break; //RES 0,B 178 | case 0x81: REG_C&=0xFE;break; //RES 0,C 179 | case 0x82: REG_D&=0xFE;break; //RES 0,D 180 | case 0x83: REG_E&=0xFE;break; //RES 0,E 181 | case 0x84: REG_H&=0xFE;break; //RES 0,H 182 | case 0x85: REG_L&=0xFE;break; //RES 0,L 183 | case 0x87: REG_A&=0xFE;break; //RES 0,A 184 | 185 | case 0x88: REG_B&=0xFD;break; //RES 1,B 186 | case 0x89: REG_C&=0xFD;break; //RES 1,C 187 | case 0x8A: REG_D&=0xFD;break; //RES 1,D 188 | case 0x8B: REG_E&=0xFD;break; //RES 1,E 189 | case 0x8C: REG_H&=0xFD;break; //RES 1,H 190 | case 0x8D: REG_L&=0xFD;break; //RES 1,L 191 | case 0x8F: REG_A&=0xFD;break; //RES 1,A 192 | 193 | case 0x90: REG_B&=0xFB;break; //RES 2,B 194 | case 0x91: REG_C&=0xFB;break; //RES 2,C 195 | case 0x92: REG_D&=0xFB;break; //RES 2,D 196 | case 0x93: REG_E&=0xFB;break; //RES 2,E 197 | case 0x94: REG_H&=0xFB;break; //RES 2,H 198 | case 0x95: REG_L&=0xFB;break; //RES 2,L 199 | case 0x97: REG_A&=0xFB;break; //RES 2,A 200 | 201 | case 0x98: REG_B&=0xF7;break; //RES 3,B 202 | case 0x99: REG_C&=0xF7;break; //RES 3,C 203 | case 0x9A: REG_D&=0xF7;break; //RES 3,D 204 | case 0x9B: REG_E&=0xF7;break; //RES 3,E 205 | case 0x9C: REG_H&=0xF7;break; //RES 3,H 206 | case 0x9D: REG_L&=0xF7;break; //RES 3,L 207 | case 0x9F: REG_A&=0xF7;break; //RES 3,A 208 | 209 | case 0xA0: REG_B&=0xEF;break; //RES 4,B 210 | case 0xA1: REG_C&=0xEF;break; //RES 4,C 211 | case 0xA2: REG_D&=0xEF;break; //RES 4,D 212 | case 0xA3: REG_E&=0xEF;break; //RES 4,E 213 | case 0xA4: REG_H&=0xEF;break; //RES 4,H 214 | case 0xA5: REG_L&=0xEF;break; //RES 4,L 215 | case 0xA7: REG_A&=0xEF;break; //RES 4,A 216 | 217 | case 0xA8: REG_B&=0xDF;break; //RES 5,B 218 | case 0xA9: REG_C&=0xDF;break; //RES 5,C 219 | case 0xAA: REG_D&=0xDF;break; //RES 5,D 220 | case 0xAB: REG_E&=0xDF;break; //RES 5,E 221 | case 0xAC: REG_H&=0xDF;break; //RES 5,H 222 | case 0xAD: REG_L&=0xDF;break; //RES 5,L 223 | case 0xAF: REG_A&=0xDF;break; //RES 5,A 224 | 225 | case 0xB0: REG_B&=0xBF;break; //RES 6,B 226 | case 0xB1: REG_C&=0xBF;break; //RES 6,C 227 | case 0xB2: REG_D&=0xBF;break; //RES 6,D 228 | case 0xB3: REG_E&=0xBF;break; //RES 6,E 229 | case 0xB4: REG_H&=0xBF;break; //RES 6,H 230 | case 0xB5: REG_L&=0xBF;break; //RES 6,L 231 | case 0xB7: REG_A&=0xBF;break; //RES 6,A 232 | 233 | case 0xB8: REG_B&=0x7F;break; //RES 7,B 234 | case 0xB9: REG_C&=0x7F;break; //RES 7,C 235 | case 0xBA: REG_D&=0x7F;break; //RES 7,D 236 | case 0xBB: REG_E&=0x7F;break; //RES 7,E 237 | case 0xBC: REG_H&=0x7F;break; //RES 7,H 238 | case 0xBD: REG_L&=0x7F;break; //RES 7,L 239 | case 0xBF: REG_A&=0x7F;break; //RES 7,A 240 | 241 | //state 16 242 | case 0x86: tmp.b.l=read(REG_HL);tmp.b.l&=0xFE;write(REG_HL,tmp.b.l);break; //RES 0,(HL) 243 | case 0x8E: tmp.b.l=read(REG_HL);tmp.b.l&=0xFD;write(REG_HL,tmp.b.l);break; //RES 1,(HL) 244 | case 0x96: tmp.b.l=read(REG_HL);tmp.b.l&=0xFB;write(REG_HL,tmp.b.l);break; //RES 2,(HL) 245 | case 0x9E: tmp.b.l=read(REG_HL);tmp.b.l&=0xF7;write(REG_HL,tmp.b.l);break; //RES 3,(HL) 246 | case 0xA6: tmp.b.l=read(REG_HL);tmp.b.l&=0xEF;write(REG_HL,tmp.b.l);break; //RES 4,(HL) 247 | case 0xAE: tmp.b.l=read(REG_HL);tmp.b.l&=0xDF;write(REG_HL,tmp.b.l);break; //RES 5,(HL) 248 | case 0xB6: tmp.b.l=read(REG_HL);tmp.b.l&=0xBF;write(REG_HL,tmp.b.l);break; //RES 6,(HL) 249 | case 0xBE: tmp.b.l=read(REG_HL);tmp.b.l&=0x7F;write(REG_HL,tmp.b.l);break; //RES 7,(HL) 250 | 251 | //shift rotate opcode 252 | //RLC s : 00 000 r : state 8 253 | case 0x00: REG_F=(REG_B>>7);REG_B=(REG_B<<1)|(REG_F);REG_F|=ZTable[REG_B];break;//RLC B 254 | case 0x01: REG_F=(REG_C>>7);REG_C=(REG_C<<1)|(REG_F);REG_F|=ZTable[REG_C];break;//RLC C 255 | case 0x02: REG_F=(REG_D>>7);REG_D=(REG_D<<1)|(REG_F);REG_F|=ZTable[REG_D];break;//RLC D 256 | case 0x03: REG_F=(REG_E>>7);REG_E=(REG_E<<1)|(REG_F);REG_F|=ZTable[REG_E];break;//RLC E 257 | case 0x04: REG_F=(REG_H>>7);REG_H=(REG_H<<1)|(REG_F);REG_F|=ZTable[REG_H];break;//RLC H 258 | case 0x05: REG_F=(REG_L>>7);REG_L=(REG_L<<1)|(REG_F);REG_F|=ZTable[REG_L];break;//RLC L 259 | case 0x07: REG_F=(REG_A>>7);REG_A=(REG_A<<1)|(REG_F);REG_F|=ZTable[REG_A];break;//RLC A 260 | 261 | case 0x06: tmp.b.l=read(REG_HL);REG_F=(tmp.b.l>>7);tmp.b.l=(tmp.b.l<<1)|(REG_F);REG_F|=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//RLC (HL) : state 16 262 | 263 | //RRC s : 00 001 r : state 8 264 | case 0x08: REG_F=(REG_B&0x01);REG_B=(REG_B>>1)|(REG_F<<7);REG_F|=ZTable[REG_B];break;//RRC B 265 | case 0x09: REG_F=(REG_C&0x01);REG_C=(REG_C>>1)|(REG_F<<7);REG_F|=ZTable[REG_C];break;//RRC C 266 | case 0x0A: REG_F=(REG_D&0x01);REG_D=(REG_D>>1)|(REG_F<<7);REG_F|=ZTable[REG_D];break;//RRC D 267 | case 0x0B: REG_F=(REG_E&0x01);REG_E=(REG_E>>1)|(REG_F<<7);REG_F|=ZTable[REG_E];break;//RRC E 268 | case 0x0C: REG_F=(REG_H&0x01);REG_H=(REG_H>>1)|(REG_F<<7);REG_F|=ZTable[REG_H];break;//RRC H 269 | case 0x0D: REG_F=(REG_L&0x01);REG_L=(REG_L>>1)|(REG_F<<7);REG_F|=ZTable[REG_L];break;//RRC L 270 | case 0x0F: REG_F=(REG_A&0x01);REG_A=(REG_A>>1)|(REG_F<<7);REG_F|=ZTable[REG_A];break;//RRC A 271 | 272 | case 0x0E: tmp.b.l=read(REG_HL);REG_F=(tmp.b.l&0x01);tmp.b.l=(tmp.b.l>>1)|(REG_F<<7);REG_F|=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//RRC (HL) :state 16 273 | 274 | //RL s : 00 010 r : state 8 275 | case 0x10: tmp.b.l=REG_F&0x01;REG_F=(REG_B>>7);REG_B=(REG_B<<1)|tmp.b.l;REG_F|=ZTable[REG_B];break;//RL B 276 | case 0x11: tmp.b.l=REG_F&0x01;REG_F=(REG_C>>7);REG_C=(REG_C<<1)|tmp.b.l;REG_F|=ZTable[REG_C];break;//RL C 277 | case 0x12: tmp.b.l=REG_F&0x01;REG_F=(REG_D>>7);REG_D=(REG_D<<1)|tmp.b.l;REG_F|=ZTable[REG_D];break;//RL D 278 | case 0x13: tmp.b.l=REG_F&0x01;REG_F=(REG_E>>7);REG_E=(REG_E<<1)|tmp.b.l;REG_F|=ZTable[REG_E];break;//RL E 279 | case 0x14: tmp.b.l=REG_F&0x01;REG_F=(REG_H>>7);REG_H=(REG_H<<1)|tmp.b.l;REG_F|=ZTable[REG_H];break;//RL H 280 | case 0x15: tmp.b.l=REG_F&0x01;REG_F=(REG_L>>7);REG_L=(REG_L<<1)|tmp.b.l;REG_F|=ZTable[REG_L];break;//RL L 281 | case 0x17: tmp.b.l=REG_F&0x01;REG_F=(REG_A>>7);REG_A=(REG_A<<1)|tmp.b.l;REG_F|=ZTable[REG_A];break;//RL A 282 | 283 | case 0x16: tmp.b.l=read(REG_HL);tmp.b.h=REG_F&0x01;REG_F=(tmp.b.l>>7);tmp.b.l=(tmp.b.l<<1)|tmp.b.h;REG_F|=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//RL (HL) :state 16 284 | 285 | //RR s : 00 011 r : state 8 286 | case 0x18: tmp.b.l=REG_F&0x01;REG_F=(REG_B&0x01);REG_B=(REG_B>>1)|(tmp.b.l<<7);REG_F|=ZTable[REG_B];break;//RR B 287 | case 0x19: tmp.b.l=REG_F&0x01;REG_F=(REG_C&0x01);REG_C=(REG_C>>1)|(tmp.b.l<<7);REG_F|=ZTable[REG_C];break;//RR C 288 | case 0x1A: tmp.b.l=REG_F&0x01;REG_F=(REG_D&0x01);REG_D=(REG_D>>1)|(tmp.b.l<<7);REG_F|=ZTable[REG_D];break;//RR D 289 | case 0x1B: tmp.b.l=REG_F&0x01;REG_F=(REG_E&0x01);REG_E=(REG_E>>1)|(tmp.b.l<<7);REG_F|=ZTable[REG_E];break;//RR E 290 | case 0x1C: tmp.b.l=REG_F&0x01;REG_F=(REG_H&0x01);REG_H=(REG_H>>1)|(tmp.b.l<<7);REG_F|=ZTable[REG_H];break;//RR H 291 | case 0x1D: tmp.b.l=REG_F&0x01;REG_F=(REG_L&0x01);REG_L=(REG_L>>1)|(tmp.b.l<<7);REG_F|=ZTable[REG_L];break;//RR L 292 | case 0x1F: tmp.b.l=REG_F&0x01;REG_F=(REG_A&0x01);REG_A=(REG_A>>1)|(tmp.b.l<<7);REG_F|=ZTable[REG_A];break;//RR A 293 | 294 | case 0x1E: tmp.b.l=read(REG_HL);tmp.b.h=REG_F&0x01;REG_F=(tmp.b.l&0x01);tmp.b.l=(tmp.b.l>>1)|(tmp.b.h<<7);REG_F|=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//RR (HL) :state 16 295 | 296 | //SLA s : 00 100 r : state 8 297 | case 0x20: REG_F=REG_B>>7;REG_B<<=1;REG_F|=ZTable[REG_B];break;//SLA B 298 | case 0x21: REG_F=REG_C>>7;REG_C<<=1;REG_F|=ZTable[REG_C];break;//SLA C 299 | case 0x22: REG_F=REG_D>>7;REG_D<<=1;REG_F|=ZTable[REG_D];break;//SLA D 300 | case 0x23: REG_F=REG_E>>7;REG_E<<=1;REG_F|=ZTable[REG_E];break;//SLA E 301 | case 0x24: REG_F=REG_H>>7;REG_H<<=1;REG_F|=ZTable[REG_H];break;//SLA H 302 | case 0x25: REG_F=REG_L>>7;REG_L<<=1;REG_F|=ZTable[REG_L];break;//SLA L 303 | case 0x27: REG_F=REG_A>>7;REG_A<<=1;REG_F|=ZTable[REG_A];break;//SLA A 304 | 305 | case 0x26: tmp.b.l=read(REG_HL);REG_F=tmp.b.l>>7;tmp.b.l<<=1;REG_F|=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//SLA (HL) :state 16 306 | 307 | //SRA s : 00 101 r : state 8 308 | case 0x28: REG_F=REG_B&0x01;REG_B=(REG_B>>1)|(REG_B&0x80);REG_F|=ZTable[REG_B];break;//SRA B 309 | case 0x29: REG_F=REG_C&0x01;REG_C=(REG_C>>1)|(REG_C&0x80);REG_F|=ZTable[REG_C];break;//SRA C 310 | case 0x2A: REG_F=REG_D&0x01;REG_D=(REG_D>>1)|(REG_D&0x80);REG_F|=ZTable[REG_D];break;//SRA D 311 | case 0x2B: REG_F=REG_E&0x01;REG_E=(REG_E>>1)|(REG_E&0x80);REG_F|=ZTable[REG_E];break;//SRA E 312 | case 0x2C: REG_F=REG_H&0x01;REG_H=(REG_H>>1)|(REG_H&0x80);REG_F|=ZTable[REG_H];break;//SRA H 313 | case 0x2D: REG_F=REG_L&0x01;REG_L=(REG_L>>1)|(REG_L&0x80);REG_F|=ZTable[REG_L];break;//SRA L 314 | case 0x2F: REG_F=REG_A&0x01;REG_A=(REG_A>>1)|(REG_A&0x80);REG_F|=ZTable[REG_A];break;//SRA A 315 | 316 | case 0x2E: tmp.b.l=read(REG_HL);REG_F=tmp.b.l&0x01;tmp.b.l>>=1;tmp.b.l|=(tmp.b.l<<1)&0x80;REG_F|=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//SRA (HL) :state 16 317 | 318 | //SRL s : 00 111 r : state 8 319 | case 0x38: REG_F=REG_B&0x01;REG_B>>=1;REG_F|=ZTable[REG_B];break;//SRL B 320 | case 0x39: REG_F=REG_C&0x01;REG_C>>=1;REG_F|=ZTable[REG_C];break;//SRL C 321 | case 0x3A: REG_F=REG_D&0x01;REG_D>>=1;REG_F|=ZTable[REG_D];break;//SRL D 322 | case 0x3B: REG_F=REG_E&0x01;REG_E>>=1;REG_F|=ZTable[REG_E];break;//SRL E 323 | case 0x3C: REG_F=REG_H&0x01;REG_H>>=1;REG_F|=ZTable[REG_H];break;//SRL H 324 | case 0x3D: REG_F=REG_L&0x01;REG_L>>=1;REG_F|=ZTable[REG_L];break;//SRL L 325 | case 0x3F: REG_F=REG_A&0x01;REG_A>>=1;REG_F|=ZTable[REG_A];break;//SRL A 326 | 327 | case 0x3E: tmp.b.l=read(REG_HL);REG_F=tmp.b.l&0x01;tmp.b.l>>=1;REG_F|=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//SRL (HL) :state 16 328 | 329 | //swap opcode 330 | //SWAP n : 00 110 r :state 8 331 | case 0x30: REG_B=(REG_B>>4)|(REG_B<<4);REG_F=ZTable[REG_B];break;//SWAP B 332 | case 0x31: REG_C=(REG_C>>4)|(REG_C<<4);REG_F=ZTable[REG_C];break;//SWAP C 333 | case 0x32: REG_D=(REG_D>>4)|(REG_D<<4);REG_F=ZTable[REG_D];break;//SWAP D 334 | case 0x33: REG_E=(REG_E>>4)|(REG_E<<4);REG_F=ZTable[REG_E];break;//SWAP E 335 | case 0x34: REG_H=(REG_H>>4)|(REG_H<<4);REG_F=ZTable[REG_H];break;//SWAP H 336 | case 0x35: REG_L=(REG_L>>4)|(REG_L<<4);REG_F=ZTable[REG_L];break;//SWAP L 337 | case 0x37: REG_A=(REG_A>>4)|(REG_A<<4);REG_F=ZTable[REG_A];break;//SWAP A 338 | 339 | case 0x36: tmp.b.l=read(REG_HL);tmp.b.l=(tmp.b.l>>4)|(tmp.b.l<<4);REG_F=ZTable[tmp.b.l];write(REG_HL,tmp.b.l);break;//SWAP (HL) : state 16 340 | -------------------------------------------------------------------------------- /gb_core/apu.cpp: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //-------------------------------------------------- 21 | // APU(PSG?)エミュレーション部 (レジスタ/波形生成) 22 | // APU unit (PSG?) Emulation (waveform generation register) 23 | 24 | #define UPDATE_INTERVAL 172 // 1/256秒あたりのサンプル数 // Number of samples per second / 256 25 | #define CLOKS_PER_INTERVAL 16384 // 1/256秒あたりのクロック数 (4MHz時) // Number of clock ticks per second / 256 (at 4MHz) 26 | 27 | #include "gb.h" 28 | #include 29 | 30 | static dword sq1_cur_pos=0; 31 | static dword sq2_cur_pos=0; 32 | static dword wav_cur_pos=0; 33 | static dword noi_cur_pos=0; 34 | 35 | apu::apu(gb *ref) 36 | { 37 | ref_gb=ref; 38 | snd=new apu_snd(this); 39 | reset(); 40 | } 41 | 42 | apu::~apu() 43 | { 44 | } 45 | 46 | void apu::reset() 47 | { 48 | // 49 | snd->reset(); 50 | } 51 | 52 | byte apu::read(word adr) 53 | { 54 | if (adr==0xff26) 55 | return (!snd->stat.master_enable)?0x00: 56 | (0x80|(((snd->stat.sq1_playing&&snd->stat.wav_vol)?1:0)| 57 | ((snd->stat.sq2_playing&&snd->stat.wav_vol)?2:0)| 58 | ((snd->stat.wav_enable&&snd->stat.wav_playing&&snd->stat.wav_vol)?4:0)| 59 | ((snd->stat.noi_playing&&snd->stat.noi_vol)?8:0))); 60 | else 61 | return snd->mem[adr-0xff10]; 62 | } 63 | 64 | void apu::write(word adr,byte dat,int clock) 65 | { 66 | static int bef_clock=clock; 67 | static int clocks=0; 68 | 69 | snd->mem[adr-0xFF10]=dat; 70 | 71 | snd->write_que[snd->que_count].adr=adr; 72 | snd->write_que[snd->que_count].dat=dat; 73 | snd->write_que[snd->que_count++].clock=clock; 74 | 75 | if (snd->que_count>=0x10000) 76 | snd->que_count=0xffff; 77 | 78 | snd->process(adr,dat); 79 | 80 | if (bef_clock>clock) 81 | bef_clock=clock; 82 | 83 | clocks+=clock-bef_clock; 84 | 85 | while (clocks>CLOKS_PER_INTERVAL*(ref_gb->get_cpu()->get_speed()?2:1)){ 86 | snd->update(); 87 | clocks-=CLOKS_PER_INTERVAL*(ref_gb->get_cpu()->get_speed()?2:1); 88 | } 89 | 90 | bef_clock=clock; 91 | } 92 | 93 | void apu::update() 94 | { 95 | } 96 | 97 | apu_stat *apu::get_stat() 98 | { 99 | return &snd->stat; 100 | } 101 | 102 | apu_stat *apu::get_stat_cpy() 103 | { 104 | return &snd->stat_cpy; 105 | } 106 | 107 | byte *apu::get_mem() 108 | { 109 | return snd->mem; 110 | } 111 | 112 | //--------------------------------------------------------------------- 113 | 114 | apu_snd::apu_snd(apu *papu) 115 | { 116 | ref_apu=papu; 117 | b_enable[0]=b_enable[1]=b_enable[2]=b_enable[3]=true; 118 | b_echo=false; 119 | b_lowpass=false; 120 | } 121 | 122 | apu_snd::~apu_snd() 123 | { 124 | } 125 | 126 | void apu_snd::reset() 127 | { 128 | que_count=0; 129 | bef_clock=0; 130 | memset(&stat,0,sizeof(stat)); 131 | stat.sq1_playing=false; 132 | stat.sq2_playing=false; 133 | stat.wav_playing=false; 134 | stat.noi_playing=false; 135 | stat.ch_enable[0][0]=stat.ch_enable[0][1]=stat.ch_enable[1][0]=stat.ch_enable[1][1]= 136 | stat.ch_enable[2][0]=stat.ch_enable[2][1]=stat.ch_enable[3][0]=stat.ch_enable[3][1]=1; 137 | stat.ch_on[0]=stat.ch_on[1]=stat.ch_on[2]=stat.ch_on[3]=1; 138 | stat.master_enable=1; 139 | stat.master_vol[0]=stat.master_vol[1]=7; 140 | 141 | memcpy(&stat_cpy,&stat,sizeof(stat)); 142 | 143 | byte gb_init_wav[]={0x06,0xFE,0x0E,0x7F,0x00,0xFF,0x58,0xDF,0x00,0xEC,0x00,0xBF,0x0C,0xED,0x03,0xF7}; 144 | byte gbc_init_wav[]={0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF}; 145 | 146 | if (ref_apu->ref_gb->get_rom()->get_info()->gb_type==1) // 初期型GB // GB early type 147 | memcpy(mem+20,gb_init_wav,16); 148 | else if (ref_apu->ref_gb->get_rom()->get_info()->gb_type>=3) // GBC 149 | memcpy(mem+20,gbc_init_wav,16); 150 | } 151 | 152 | void apu_snd::set_enable(int ch,bool enable) 153 | { 154 | b_enable[ch]=enable; 155 | } 156 | 157 | bool apu_snd::get_enable(int ch) 158 | { 159 | return b_enable[ch]; 160 | } 161 | 162 | void apu_snd::process(word adr,byte dat) 163 | { 164 | int tb[]={0,4,2,1}; 165 | int mul_t[]={2,1,1,1,1,1,1,1}; 166 | int div_t[]={1,1,2,3,4,5,6,7}; 167 | int div_t2[]={2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,1,1}; 168 | 169 | mem[adr-0xFF10]=dat; 170 | 171 | switch(adr){ 172 | case 0xFF10: 173 | stat.sq1_sw_time=(dat>>4)&7; 174 | stat.sq1_sw_dir=(dat>>3)&1; 175 | stat.sq1_sw_shift=dat&7; 176 | break; 177 | case 0xFF11: 178 | stat.sq1_type=(dat>>6)&3; 179 | stat.sq1_init_len=64-(dat&0x3F); 180 | stat.sq1_len=stat.sq1_init_len; 181 | break; 182 | case 0xFF12: 183 | stat.sq1_init_vol=(dat>>4)&0xF; 184 | stat.sq1_vol=stat.sq1_init_vol; 185 | stat.sq1_env_dir=(dat>>3)&1; 186 | stat.sq1_env_speed=dat&7; 187 | break; 188 | case 0xFF13: 189 | stat.sq1_init_freq&=0x700; 190 | stat.sq1_init_freq|=dat; 191 | stat.sq1_freq=stat.sq1_init_freq; 192 | break; 193 | case 0xFF14: 194 | stat.sq1_init_freq&=0xFF; 195 | stat.sq1_init_freq|=((dat&7)<<8); 196 | stat.sq1_freq=stat.sq1_init_freq; 197 | stat.sq1_hold=(dat>>6)&1; 198 | if (dat&0x80){ 199 | stat.sq1_playing=true; 200 | stat.sq1_vol=stat.sq1_init_vol; 201 | stat.sq1_len=stat.sq1_init_len; 202 | if ((!stat.sq1_playing)||(!stat.sq1_vol)) sq1_cur_pos=0; 203 | } 204 | break; 205 | case 0xFF16: 206 | stat.sq2_type=(dat>>6)&3; 207 | stat.sq2_init_len=64-(dat&0x3F); 208 | stat.sq2_len=stat.sq2_init_len; 209 | break; 210 | case 0xFF17: 211 | stat.sq2_init_vol=(dat>>4)&0xF; 212 | stat.sq2_vol=stat.sq2_init_vol; 213 | stat.sq2_env_dir=(dat>>3)&1; 214 | stat.sq2_env_speed=dat&7; 215 | break; 216 | case 0xFF18: 217 | stat.sq2_init_freq&=0x700; 218 | stat.sq2_init_freq|=dat; 219 | stat.sq2_freq=stat.sq2_init_freq; 220 | break; 221 | case 0xFF19: 222 | stat.sq2_init_freq&=0xFF; 223 | stat.sq2_init_freq|=((dat&7)<<8); 224 | stat.sq2_freq=stat.sq2_init_freq; 225 | stat.sq2_hold=(dat>>6)&1; 226 | if (dat&0x80){ 227 | if ((!stat.sq2_playing)||(!stat.sq2_vol)) sq2_cur_pos=0; 228 | stat.sq2_playing=true; 229 | stat.sq2_vol=stat.sq2_init_vol; 230 | stat.sq2_len=stat.sq2_init_len; 231 | } 232 | break; 233 | case 0xFF1A: 234 | stat.wav_enable=(dat&0x80)?1:0; 235 | break; 236 | case 0xFF1B: 237 | stat.wav_init_len=(256-dat); 238 | stat.wav_len=stat.wav_init_len; 239 | if ((stat.wav_len&&dat)||!stat.wav_hold) 240 | stat.wav_playing=true; 241 | else 242 | stat.wav_playing=false; 243 | break; 244 | case 0xFF1C: 245 | stat.wav_vol=tb[(dat>>5)&3]; 246 | // byte tmp; 247 | // tmp=stat.wav_vol*128/4; 248 | // voice_kind_count++; 249 | break; 250 | case 0xFF1D: 251 | stat.wav_freq&=0x700; 252 | stat.wav_freq|=dat; 253 | break; 254 | case 0xFF1E: 255 | stat.wav_freq&=0xFF; 256 | stat.wav_freq|=((dat&7)<<8); 257 | stat.wav_hold=(dat>>6)&1; 258 | if (dat&0x80){ 259 | stat.wav_len=stat.wav_init_len; 260 | stat.wav_playing=true; 261 | if (!stat.wav_playing) wav_cur_pos=0; 262 | } 263 | break; 264 | case 0xFF20://noi len 265 | stat.noi_init_len=64-(dat&0x3F); 266 | stat.noi_len=stat.noi_init_len; 267 | if (stat.noi_len==0) 268 | stat.noi_playing=false; 269 | break; 270 | case 0xFF21://noi env 271 | stat.noi_init_vol=(dat>>4)&0x0F; 272 | stat.noi_vol=stat.noi_init_vol; 273 | stat.noi_env_dir=(dat>>3)&1; 274 | stat.noi_env_speed=dat&7; 275 | if (stat.noi_vol==0) 276 | stat.noi_playing=false; 277 | break; 278 | case 0xFF22://noi freq 279 | stat.noi_init_freq=4194304*mul_t[dat&7]/div_t[dat&7]/div_t2[(dat>>4)&15]/8; 280 | stat.noi_freq=stat.noi_init_freq; 281 | stat.noi_step=(dat&8)?7:15; 282 | 283 | if ((dat>>6)==3) 284 | stat.noi_playing=false; 285 | break; 286 | case 0xFF23://noi kick 287 | stat.noi_hold=(dat>>6)&1; 288 | if (dat&0x80){ 289 | stat.noi_playing=true; 290 | stat.noi_len=stat.noi_init_len; 291 | stat.noi_vol=stat.noi_init_vol; 292 | if ((!stat.noi_playing)||(!stat.noi_vol)) noi_cur_pos=0; 293 | } 294 | break; 295 | case 0xFF24: 296 | stat.master_vol[0]=(dat&7); 297 | stat.master_vol[1]=((dat>>4)&7); 298 | // voice_kind_count++; 299 | break; 300 | case 0xFF25: 301 | 302 | stat.ch_enable[0][0]=((dat>>0)&1); 303 | stat.ch_enable[0][1]=((dat>>4)&1); 304 | stat.ch_enable[1][0]=((dat>>1)&1); 305 | stat.ch_enable[1][1]=((dat>>5)&1); 306 | stat.ch_enable[2][0]=((dat>>2)&1); 307 | stat.ch_enable[2][1]=((dat>>6)&1); 308 | stat.ch_enable[3][0]=((dat>>3)&1); 309 | stat.ch_enable[3][1]=((dat>>7)&1); 310 | 311 | // voice_kind_count++; 312 | break; 313 | case 0xFF26: 314 | stat.master_enable=(dat&0x80)?1:0; 315 | 316 | stat.ch_on[0]=dat&1; 317 | stat.ch_on[1]=(dat>>1)&1; 318 | stat.ch_on[2]=(dat>>2)&1; 319 | stat.ch_on[3]=(dat>>3)&1; 320 | break; 321 | } 322 | } 323 | 324 | static int sq_wav_dat[4][8]={ 325 | {0,1,0,0,0,0,0,0}, 326 | {1,1,0,0,0,0,0,0}, 327 | {1,1,1,1,0,0,0,0}, 328 | {0,0,1,1,1,1,1,1} 329 | }; 330 | 331 | inline short apu_snd::sq1_produce(int freq) 332 | { 333 | static dword cur_sample=0; 334 | dword cur_freq; 335 | short ret; 336 | 337 | if (freq>65000) 338 | return 15000; 339 | 340 | if (freq){ 341 | ret=sq_wav_dat[stat.sq1_type&3][cur_sample]*20000-10000; 342 | cur_freq=((freq*8)>0x10000)?0xffff:freq*8; 343 | sq1_cur_pos+=(cur_freq<<16)/44100; 344 | if (sq1_cur_pos&0xffff0000){ 345 | cur_sample=(cur_sample+(sq1_cur_pos>>16))&7; 346 | sq1_cur_pos&=0xffff; 347 | } 348 | } 349 | else 350 | ret=0; 351 | 352 | return ret; 353 | } 354 | 355 | inline short apu_snd::sq2_produce(int freq) 356 | { 357 | static dword cur_sample=0; 358 | dword cur_freq; 359 | short ret; 360 | 361 | if (freq>65000) 362 | return 15000; 363 | 364 | if (freq){ 365 | ret=sq_wav_dat[stat.sq2_type&3][cur_sample]*20000-10000; 366 | cur_freq=((freq*8)>0x10000)?0xffff:freq*8; 367 | sq2_cur_pos+=(cur_freq<<16)/44100; 368 | if (sq2_cur_pos&0xffff0000){ 369 | cur_sample=(cur_sample+(sq2_cur_pos>>16))&7; 370 | sq2_cur_pos&=0xffff; 371 | } 372 | } 373 | else 374 | ret=0; 375 | 376 | return ret; 377 | } 378 | 379 | inline short apu_snd::wav_produce(int freq,bool interpolation) 380 | { 381 | static dword cur_pos2=0; 382 | static byte bef_sample=0,cur_sample=0; 383 | dword cur_freq; 384 | short ret; 385 | 386 | if (freq>65000) 387 | return (mem[0x20]>>4)*4000-30000; 388 | 389 | if (freq){ 390 | if (interpolation){ 391 | ret=((cur_sample*2500-15000)*wav_cur_pos+(bef_sample*2500-15000)*(0x10000-wav_cur_pos))/0x10000; 392 | } 393 | else{ 394 | ret=cur_sample*2500-15000; 395 | } 396 | cur_freq=(freq>0x10000)?0xffff:freq; 397 | wav_cur_pos+=(cur_freq<<16)/44100; 398 | if (wav_cur_pos&0xffff0000){ 399 | bef_sample=cur_sample; 400 | cur_pos2=(cur_pos2+(wav_cur_pos>>16))&31; 401 | if (cur_pos2&1) 402 | cur_sample=mem[0x20+cur_pos2/2]&0xf; 403 | else 404 | cur_sample=mem[0x20+cur_pos2/2]>>4; 405 | wav_cur_pos&=0xffff; 406 | } 407 | } 408 | else 409 | ret=0; 410 | 411 | return ret; 412 | } 413 | 414 | static inline unsigned int _mrand(dword degree) 415 | { 416 | static int shift_reg=0x7f; 417 | static int bef_degree=0; 418 | int xor_reg=0; 419 | int masked; 420 | 421 | degree=(degree==7)?0:1; 422 | 423 | if (bef_degree!=degree){ 424 | shift_reg&=(degree?0x7fff:0x7f); 425 | if (!shift_reg) shift_reg=degree?0x7fff:0x7f; 426 | } 427 | bef_degree=degree; 428 | 429 | masked=shift_reg&3; 430 | while(masked) 431 | { 432 | xor_reg^=masked&0x01; 433 | masked>>=1; 434 | } 435 | 436 | if(xor_reg) 437 | shift_reg|=(degree?0x8000:0x80); 438 | else 439 | shift_reg&=~(degree?0x8000:0x80); 440 | shift_reg>>=1; 441 | 442 | return shift_reg; 443 | } 444 | /* 445 | inline short apu_snd::noi_produce(int freq) 446 | { 447 | static int cur_sample=10000; 448 | dword cur_freq; 449 | short ret; 450 | 451 | if (freq){ 452 | ret=cur_sample; 453 | cur_freq=((freq)>44100)?44100:freq; 454 | noi_cur_pos+=(cur_freq<<16)/44100; 455 | if (noi_cur_pos&0xffff0000){ 456 | cur_sample=(_mrand(stat.noi_step)&1)?12000:-10000; 457 | // cur_sample=(_mrand(stat.noi_step)&0x1f)*1000; 458 | noi_cur_pos&=0xffff; 459 | } 460 | } 461 | else 462 | ret=0; 463 | 464 | return ret; 465 | }*/ 466 | inline short apu_snd::noi_produce(int freq) 467 | { 468 | static int cur_sample=10000; 469 | dword cur_freq; 470 | short ret; 471 | int sc; 472 | if (freq){ 473 | ret=cur_sample; 474 | cur_freq=freq; 475 | noi_cur_pos+=cur_freq; 476 | sc=0; 477 | while(noi_cur_pos>44100){ 478 | if(sc==0) 479 | cur_sample=(_mrand(stat.noi_step)&1)?12000:-10000; 480 | else 481 | cur_sample+=(_mrand(stat.noi_step)&1)?12000:-10000; 482 | // cur_sample=(_mrand(stat.noi_step)&0x1f)*1000; 483 | noi_cur_pos-=44100; 484 | sc++; 485 | } 486 | 487 | if(sc > 0) 488 | cur_sample /= sc; 489 | 490 | 491 | } 492 | else 493 | ret=0; 494 | return ret; 495 | } 496 | 497 | void apu_snd::update() 498 | { 499 | static int counter=0; 500 | 501 | if (stat.sq1_playing&&stat.master_enable){ 502 | if (stat.sq1_env_speed&&(counter%(4*stat.sq1_env_speed)==0)){ 503 | stat.sq1_vol+=(stat.sq1_env_dir?1:-1); 504 | if (stat.sq1_vol<0) stat.sq1_vol=0; 505 | if (stat.sq1_vol>15) stat.sq1_vol=15; 506 | } 507 | if (stat.sq1_sw_time&&stat.sq1_sw_shift&&(counter%(2*stat.sq1_sw_time)==0)){ 508 | if (stat.sq1_sw_dir) 509 | stat.sq1_freq=stat.sq1_freq-(stat.sq1_freq>>stat.sq1_sw_shift); 510 | else 511 | stat.sq1_freq=stat.sq1_freq+(stat.sq1_freq>>stat.sq1_sw_shift); 512 | } 513 | if (stat.sq1_hold&&stat.sq1_len){ 514 | stat.sq1_len--; 515 | if (stat.sq1_len<=0){ 516 | stat.sq1_playing=false; 517 | } 518 | } 519 | } 520 | 521 | if (stat.sq2_playing&&stat.master_enable){ 522 | if (stat.sq2_env_speed&&(counter%(4*stat.sq2_env_speed)==0)){ 523 | stat.sq2_vol+=(stat.sq2_env_dir?1:-1); 524 | if (stat.sq2_vol<0) stat.sq2_vol=0; 525 | if (stat.sq2_vol>15) stat.sq2_vol=15; 526 | } 527 | if (stat.sq2_hold&&stat.sq2_len){ 528 | stat.sq2_len--; 529 | if (stat.sq2_len<=0){ 530 | stat.sq2_playing=false; 531 | } 532 | } 533 | } 534 | 535 | if (stat.wav_playing&&stat.master_enable){ 536 | if (stat.wav_hold&&stat.wav_len){ 537 | stat.wav_len--; 538 | if (stat.wav_len<=0){ 539 | stat.wav_playing=false; 540 | } 541 | } 542 | } 543 | 544 | if (stat.noi_playing&&stat.master_enable){ 545 | if (stat.noi_env_speed&&(counter%(4*stat.noi_env_speed)==0)){ 546 | stat.noi_vol+=(stat.noi_env_dir?1:-1); 547 | if (stat.noi_vol<0) stat.noi_vol=0; 548 | if (stat.noi_vol>15) stat.noi_vol=15; 549 | } 550 | if (stat.noi_hold&&stat.noi_len){ 551 | stat.noi_len--; 552 | if (stat.noi_len<=0) 553 | stat.noi_playing=false; 554 | } 555 | } 556 | 557 | counter++; 558 | } 559 | 560 | void apu_snd::render(short *buf,int sample) 561 | { 562 | static short filter[8820*2]; 563 | static int counter=0; 564 | 565 | memcpy(&stat_tmp,&stat,sizeof(stat)); 566 | memcpy(&stat,&stat_cpy,sizeof(stat_cpy)); 567 | 568 | int tmp_l,tmp_r,tmp; 569 | int now_clock=ref_apu->ref_gb->get_cpu()->get_clock(); 570 | int cur=0; 571 | static int tmp_sample=0,now_time,bef_sample_l[5]={0,0,0,0,0},bef_sample_r[5]={0,0,0,0,0}; 572 | int update_count=0; 573 | 574 | memset(buf,0,sample*4); 575 | 576 | for (int i=0;iwrite_que[cur].clock)&&(que_count)){ 580 | process(write_que[cur].adr,write_que[cur].dat); 581 | cur++; 582 | if (cur>=que_count) 583 | cur=0x10000; 584 | } 585 | 586 | tmp_l=tmp_r=0; 587 | if (stat.master_enable){ 588 | if (b_enable[0]&&stat.sq1_playing/*&&(stat.sq1_freq!=0x7ff)*/){ 589 | tmp=sq1_produce((131072/(2048-(stat.sq1_freq&0x7FF))))*stat.sq1_vol/20; 590 | if (stat.ch_enable[0][0]) 591 | tmp_l+=tmp*stat.master_vol[0]/8; 592 | if (stat.ch_enable[0][1]) 593 | tmp_r+=tmp*stat.master_vol[1]/8; 594 | } 595 | if (b_enable[1]&&stat.sq2_playing/*&&(stat.sq2_freq!=0x7ff)*/){ 596 | tmp=sq2_produce((131072/(2048-(stat.sq2_freq&0x7FF))))*stat.sq2_vol/20; 597 | if (stat.ch_enable[1][0]) 598 | tmp_l+=tmp*stat.master_vol[0]/8; 599 | if (stat.ch_enable[1][1]) 600 | tmp_r+=tmp*stat.master_vol[1]/8; 601 | } 602 | if (b_enable[2]&&stat.wav_playing/*&&(stat.wav_freq!=0x7ff)*/){ 603 | tmp=wav_produce((65536/(2048-(stat.wav_freq&0x7FF)))*32,false)*stat.wav_vol/10*stat.wav_enable; 604 | if (stat.ch_enable[2][0]) 605 | tmp_l+=tmp*stat.master_vol[0]/8; 606 | if (stat.ch_enable[2][1]) 607 | tmp_r+=tmp*stat.master_vol[1]/8; 608 | } 609 | if (b_enable[3]&&stat.noi_playing){ 610 | tmp=noi_produce(stat.noi_freq)*stat.noi_vol/20; 611 | if (stat.ch_enable[3][0]) 612 | tmp_l+=tmp*stat.master_vol[0]/8; 613 | if (stat.ch_enable[3][1]) 614 | tmp_r+=tmp*stat.master_vol[1]/8; 615 | } 616 | } 617 | if (b_echo){ 618 | // エコー 619 | // tmp_l/=2; 620 | // tmp_r/=2; 621 | int ttmp_l=tmp_l,ttmp_r=tmp_r; 622 | ttmp_l*=5;ttmp_r*=5; 623 | ttmp_l+=filter[counter*2]*2; 624 | ttmp_r+=filter[counter*2+1]*2; 625 | ttmp_l/=5; 626 | ttmp_r/=5; 627 | tmp_l=ttmp_l; 628 | tmp_r=ttmp_r; 629 | filter[counter*2]=tmp_l; 630 | filter[counter*2+1]=tmp_r; 631 | counter++; 632 | if (counter>=2000) 633 | counter=0; 634 | // tmp_l/=2; 635 | // tmp_r/=2; 636 | } 637 | if (b_lowpass){ 638 | // 出力をフィルタリング 639 | // Filtering the output 640 | bef_sample_l[4]=bef_sample_l[3]; 641 | bef_sample_l[3]=bef_sample_l[2]; 642 | bef_sample_l[2]=bef_sample_l[1]; 643 | bef_sample_l[1]=bef_sample_l[0]; 644 | bef_sample_l[0]=tmp_l; 645 | bef_sample_r[4]=bef_sample_r[3]; 646 | bef_sample_r[3]=bef_sample_r[2]; 647 | bef_sample_r[2]=bef_sample_r[1]; 648 | bef_sample_r[1]=bef_sample_r[0]; 649 | bef_sample_r[0]=tmp_r; 650 | tmp_l=(bef_sample_l[4]+bef_sample_l[3]*2+bef_sample_l[2]*8+bef_sample_l[1]*2+bef_sample_l[0])/14; 651 | tmp_r=(bef_sample_r[4]+bef_sample_r[3]*2+bef_sample_r[2]*8+bef_sample_r[1]*2+bef_sample_r[0])/14; 652 | } 653 | tmp_l=(tmp_l>32767)?32767:tmp_l; 654 | tmp_l=(tmp_l<-32767)?-32767:tmp_l; 655 | tmp_r=(tmp_r>32767)?32767:tmp_r; 656 | tmp_r=(tmp_r<-32767)?-32767:tmp_r; 657 | 658 | //どうやらうちの3.5インチベイ内蔵スピーカが出力を逆にしていたみたい… 659 | // Built-in speaker 3.5-inch bay had to reverse the output apparently... 660 | // buf[i*2]=tmp_l; 661 | // buf[i*2+1]=tmp_r; 662 | buf[i*2]=tmp_r; 663 | buf[i*2+1]=tmp_l; 664 | 665 | tmp_sample++; 666 | 667 | while(update_count*CLOKS_PER_INTERVAL*(ref_apu->ref_gb->get_cpu()->get_speed()?2:1)UPDATE_INTERVAL){ 672 | // tmp_sample-=UPDATE_INTERVAL; 673 | // update(); 674 | // } 675 | } 676 | while (curserialize(s); } 689 | void apu_snd::serialize(serializer &s) 690 | { 691 | // originally, the only things saved were stat, stat_cpy, 692 | // and the first 0x30 bytes of mem. 693 | s_VAR(stat); 694 | s_VAR(stat_cpy); 695 | s_ARRAY(mem); 696 | 697 | s_VAR(bef_clock); 698 | s_VAR(b_echo); 699 | s_VAR(b_lowpass); 700 | } 701 | 702 | -------------------------------------------------------------------------------- /gb_core/op_normal.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | TGB Dual - Gameboy Emulator - 3 | Copyright (C) 2001 Hii 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | //-------------------------------------------- 21 | // プリフィックスなしZ80オペコード 22 | 23 | #define REG_A regs.AF.b.h 24 | #define REG_F regs.AF.b.l 25 | #define REG_B regs.BC.b.h 26 | #define REG_C regs.BC.b.l 27 | #define REG_D regs.DE.b.h 28 | #define REG_E regs.DE.b.l 29 | #define REG_H regs.HL.b.h 30 | #define REG_L regs.HL.b.l 31 | #define REG_AF regs.AF.w 32 | #define REG_BC regs.BC.w 33 | #define REG_DE regs.DE.w 34 | #define REG_HL regs.HL.w 35 | #define REG_SP regs.SP 36 | #define REG_PC regs.PC 37 | 38 | #define ADD(arg) \ 39 | tmp.w=REG_A+arg; \ 40 | REG_F=tmp.b.h|ZTable[tmp.b.l]|((REG_A^arg^tmp.b.l)&H_FLAG); \ 41 | REG_A=tmp.b.l 42 | #define ADC(arg) \ 43 | tmp.w=REG_A+arg+(REG_F&C_FLAG); \ 44 | REG_F=tmp.b.h|ZTable[tmp.b.l]|((REG_A^arg^tmp.b.l)&H_FLAG); \ 45 | REG_A=tmp.b.l 46 | #define SUB(arg) \ 47 | tmp.w=REG_A-arg; \ 48 | REG_F=N_FLAG|-tmp.b.h|ZTable[tmp.b.l]|((REG_A^arg^tmp.b.l)&H_FLAG); \ 49 | REG_A=tmp.b.l 50 | #define SBC(arg) \ 51 | tmp.w=REG_A-arg-(REG_F&C_FLAG); \ 52 | REG_F=N_FLAG|-tmp.b.h|ZTable[tmp.b.l]|((REG_A^arg^tmp.b.l)&H_FLAG); \ 53 | REG_A=tmp.b.l 54 | #define CP(arg) \ 55 | tmp.w=REG_A-arg; \ 56 | REG_F=N_FLAG|-tmp.b.h|ZTable[tmp.b.l]|((REG_A^arg^tmp.b.l)&H_FLAG) 57 | #define AND(arg) REG_A&=arg;REG_F=H_FLAG|ZTable[REG_A] 58 | #define OR(arg) REG_A|=arg;REG_F=ZTable[REG_A] 59 | #define XOR(arg) REG_A^=arg;REG_F=ZTable[REG_A] 60 | #define INC(arg) arg++;REG_F=(REG_F&C_FLAG)|ZTable[arg]|((arg&0x0F)?0:H_FLAG) 61 | #define DEC(arg) arg--;REG_F=N_FLAG|(REG_F&C_FLAG)|ZTable[arg]|(((arg&0x0F)==0x0F)?H_FLAG:0) 62 | #define ADDW(arg) \ 63 | tmp.w=REG_HL+arg; \ 64 | REG_F=(REG_F&Z_FLAG)|(((REG_HL^arg^tmp.w)&0x1000)?H_FLAG:0)|((((unsigned long)REG_HL+(unsigned long)arg)&0x10000)?C_FLAG:0); \ 65 | REG_HL=tmp.w 66 | 67 | // GB orginal op_code 68 | 69 | case 0x08: writew(op_readw(),REG_SP);break; //LD (mn),SP 70 | case 0x10: if (speed_change) { speed_change=false;speed^=1;REG_PC++;/* 1バイト読み飛ばす */ } else { halt=true;REG_PC--; }break; //STOP(HALT?) 71 | 72 | //0x2A LD A,(mn) -> LD A,(HLI) Load A from (HL) and decrement HL 73 | case 0x2A: REG_A=read(REG_HL);REG_HL++;break; // LD A,(HLI) : 00 111 010 :state 13 74 | 75 | //0x22 LD (mn),A -> LD (HLI),A Save A at (HL) and decrement HL 76 | case 0x22: write(REG_HL,REG_A);REG_HL++;break; // LD (HLI),A : 00 110 010 :state 13 77 | 78 | //0x3A LD A,(mn) -> LD A,(HLD) Load A from (HL) and decrement HL 79 | case 0x3A: REG_A=read(REG_HL);REG_HL--;break; // LD A,(HLD) : 00 111 010 :state 13 80 | 81 | //0x32 LD (mn),A -> LD (HLD),A Save A at (HL) and decrement HL 82 | case 0x32: write(REG_HL,REG_A);REG_HL--;break; // LD (HLD),A : 00 110 010 :state 13 83 | 84 | case 0xD9: /*Log("Return Interrupts.\n");*/regs.I=1;REG_PC=readw(REG_SP);REG_SP+=2;int_desable=true;/*;ref_gb->get_regs()->IF=0*/;/*res->system_reg.IF&=~Int_hist[(Int_depth>0)?--Int_depth:Int_depth]*//*Int_depth=((Int_depth>0)?--Int_depth:Int_depth);*//*res->system_reg.IF=0;*//*Log("RETI %d\n",Int_depth);*/break;//RETI state 16 85 | case 0xE0: write(0xFF00+op_read(),REG_A);break;//LDH (n),A 86 | case 0xE2: write(0xFF00+REG_C,REG_A);break;//LDH (C),A 87 | case 0xE8: REG_SP+=(signed char)op_read();break;//ADD SP,n 88 | case 0xEA: write(op_readw(),REG_A);break;//LD (mn),A 89 | 90 | case 0xF0: REG_A=read(0xFF00+op_read());break;//LDH A,(n) 91 | case 0xF2: REG_A=read(0xFF00+REG_C);break;//LDH A,(c) 92 | case 0xF8: REG_HL=REG_SP+(signed char)op_read();break;//LD HL,SP+n 93 | case 0xFA: REG_A=read(op_readw());break;//LD A,(mn); 94 | 95 | // 8bit load op_code 96 | 97 | // regs B 000 C 001 D 010 E 011 H 100 L 101 A 111 98 | //LD r,s :01 r s :state 4(clocks) 99 | 100 | case 0x40: break; // LD B,B 101 | case 0x41: REG_B=REG_C;break; // LD B,C 102 | case 0x42: REG_B=REG_D;break; // LD B,D 103 | case 0x43: REG_B=REG_E;break; // LD B,E 104 | case 0x44: REG_B=REG_H;break; // LD B,H 105 | case 0x45: REG_B=REG_L;break; // LD B,L 106 | case 0x47: REG_B=REG_A;break; // LD B,A 107 | 108 | case 0x48: REG_C=REG_B;break; // LD C,B 109 | case 0x49: break; // LD C,C 110 | case 0x4A: REG_C=REG_D;break; // LD C,D 111 | case 0x4B: REG_C=REG_E;break; // LD C,E 112 | case 0x4C: REG_C=REG_H;break; // LD C,H 113 | case 0x4D: REG_C=REG_L;break; // LD C,L 114 | case 0x4F: REG_C=REG_A;break; // LD C,A 115 | 116 | case 0x50: REG_D=REG_B;break; // LD D,B 117 | case 0x51: REG_D=REG_C;break; // LD D,C 118 | case 0x52: break; // LD D,D 119 | case 0x53: REG_D=REG_E;break; // LD D,E 120 | case 0x54: REG_D=REG_H;break; // LD D,H 121 | case 0x55: REG_D=REG_L;break; // LD D,L 122 | case 0x57: REG_D=REG_A;break; // LD D,A 123 | 124 | case 0x58: REG_E=REG_B;break; // LD E,B 125 | case 0x59: REG_E=REG_C;break; // LD E,C 126 | case 0x5A: REG_E=REG_D;break; // LD E,D 127 | case 0x5B: break; // LD E,E 128 | case 0x5C: REG_E=REG_H;break; // LD E,H 129 | case 0x5D: REG_E=REG_L;break; // LD E,L 130 | case 0x5F: REG_E=REG_A;break; // LD E,A 131 | 132 | case 0x60: REG_H=REG_B;break; // LD H,B 133 | case 0x61: REG_H=REG_C;break; // LD H,C 134 | case 0x62: REG_H=REG_D;break; // LD H,D 135 | case 0x63: REG_H=REG_E;break; // LD H,E 136 | case 0x64: break; // LD H,H 137 | case 0x65: REG_H=REG_L;break; // LD H,L 138 | case 0x67: REG_H=REG_A;break; // LD H,A 139 | 140 | case 0x68: REG_L=REG_B;break; // LD L,B 141 | case 0x69: REG_L=REG_C;break; // LD L,C 142 | case 0x6A: REG_L=REG_D;break; // LD L,D 143 | case 0x6B: REG_L=REG_E;break; // LD L,E 144 | case 0x6C: REG_L=REG_H;break; // LD L,H 145 | case 0x6D: break; // LD L,L 146 | case 0x6F: REG_L=REG_A;break; // LD L,A 147 | 148 | case 0x78: REG_A=REG_B;break; // LD A,B 149 | case 0x79: REG_A=REG_C;break; // LD A,C 150 | case 0x7A: REG_A=REG_D;break; // LD A,D 151 | case 0x7B: REG_A=REG_E;break; // LD A,E 152 | case 0x7C: REG_A=REG_H;break; // LD A,H 153 | case 0x7D: REG_A=REG_L;break; // LD A,L 154 | case 0x7F: break; // LD A,A 155 | 156 | //LD r,n :00 r 110 n :state 7 157 | case 0x06: REG_B=op_read();break; // LD B,n 158 | case 0x0E: REG_C=op_read();break; // LD C,n 159 | case 0x16: REG_D=op_read();break; // LD D,n 160 | case 0x1E: REG_E=op_read();break; // LD E,n 161 | case 0x26: REG_H=op_read();break; // LD H,n 162 | case 0x2E: REG_L=op_read();break; // LD L,n 163 | case 0x3E: REG_A=op_read();break; // LD A,n 164 | 165 | //LD r,(HL) :01 r 110 :state 7 166 | case 0x46: REG_B=read(REG_HL);break; // LD B,(HL) 167 | case 0x4E: REG_C=read(REG_HL);break; // LD C,(HL) 168 | case 0x56: REG_D=read(REG_HL);break; // LD D,(HL) 169 | case 0x5E: REG_E=read(REG_HL);break; // LD E,(HL) 170 | case 0x66: REG_H=read(REG_HL);break; // LD H,(HL) 171 | case 0x6E: REG_L=read(REG_HL);break; // LD L,(HL) 172 | case 0x7E: REG_A=read(REG_HL);break; // LD A,(HL) 173 | 174 | //LD (HL),r :01 110 r :state 7 175 | case 0x70: write(REG_HL,REG_B);break; // LD (HL),B 176 | case 0x71: write(REG_HL,REG_C);break; // LD (HL),C 177 | case 0x72: write(REG_HL,REG_D);break; // LD (HL),D 178 | case 0x73: write(REG_HL,REG_E);break; // LD (HL),E 179 | case 0x74: write(REG_HL,REG_H);break; // LD (HL),H 180 | case 0x75: write(REG_HL,REG_L);break; // LD (HL),L 181 | case 0x77: write(REG_HL,REG_A);break; // LD (HL),A 182 | 183 | case 0x36: write(REG_HL,op_read());break; // LD (HL),n :00 110 110 :state 10 184 | case 0x0A: REG_A=read(REG_BC);break; // LD A,(BC) :00 001 010 :state 7 185 | case 0x1A: REG_A=read(REG_DE);break; // LD A,(DE) :00 011 010 : state 7 186 | case 0x02: write(REG_BC,REG_A);break; // LD (BC),A : 00 000 010 :state 7 187 | case 0x12: write(REG_DE,REG_A);break; // LD (DE),A : 00 010 010 :state 7 188 | 189 | //16bit load opcode 190 | //rp Pair Reg 00 BC 01 DE 10 HL 11 SP 191 | 192 | //LD rp,mn : 00 rp0 001 n m :state 10 193 | case 0x01: REG_BC=op_readw();break; //LD BC,(mn) 194 | case 0x11: REG_DE=op_readw();break; //LD DE,(mn) 195 | case 0x21: REG_HL=op_readw();break; //LD HL,(mn) 196 | case 0x31: REG_SP=op_readw();break; //LD SP,(mn) 197 | 198 | case 0xF9: REG_SP=REG_HL;break; //LD SP,HL : 11 111 001 :state 6 199 | 200 | //stack opcode 201 | //rq Pair Reg 00 BC 01 DE 10 HL 11 AF 202 | 203 | //PUSH rq : 11 rq0 101 : state 11(16?) 204 | case 0xC5: REG_SP-=2;writew(REG_SP,REG_BC);break; //PUSH BC 205 | case 0xD5: REG_SP-=2;writew(REG_SP,REG_DE);break; //PUSH DE 206 | case 0xE5: REG_SP-=2;writew(REG_SP,REG_HL);break; //PUSH HL 207 | case 0xF5: write(REG_SP-2,z802gb[REG_F]|0xe);write(REG_SP-1,REG_A);REG_SP-=2;break; //PUSH AF // 未使用ビットは1になるみたい(メタルギアより) 208 | 209 | //POP rq : 11 rq0 001 : state 10 (12?) 210 | case 0xC1: REG_B=read(REG_SP+1);REG_C=read(REG_SP);REG_SP+=2;break; //POP BC 211 | case 0xD1: REG_D=read(REG_SP+1);REG_E=read(REG_SP);REG_SP+=2;break; //POP DE 212 | case 0xE1: REG_H=read(REG_SP+1);REG_L=read(REG_SP);REG_SP+=2;break; //POP HL 213 | case 0xF1: REG_A=read(REG_SP+1);REG_F=gb2z80[read(REG_SP)&0xf0];REG_SP+=2;break; //POP AF 214 | 215 | //8bit arithmetic/logical opcode 216 | //regs B 000 C 001 D 010 E 011 H 100 L 101 A 111 217 | 218 | //ADD A,r : 10 000 r : state 4 219 | case 0x80: ADD(REG_B);break; //ADD A,B 220 | case 0x81: ADD(REG_C);break; //ADD A,C 221 | case 0x82: ADD(REG_D);break; //ADD A,D 222 | case 0x83: ADD(REG_E);break; //ADD A,E 223 | case 0x84: ADD(REG_H);break; //ADD A,H 224 | case 0x85: ADD(REG_L);break; //ADD A,L 225 | case 0x87: ADD(REG_A);break; //ADD A,A 226 | 227 | case 0xC6: tmpb=op_read();ADD(tmpb);break; //ADD A,n : 11 000 110 :state 7 228 | case 0x86: tmpb=read(REG_HL);ADD(tmpb);break; //ADD A,(HL) : 10 000 110 :state 7 229 | 230 | //ADC A,r : 10 001 r : state 4 231 | case 0x88: ADC(REG_B);break; //ADC A,B 232 | case 0x89: ADC(REG_C);break; //ADC A,C 233 | case 0x8A: ADC(REG_D);break; //ADC A,D 234 | case 0x8B: ADC(REG_E);break; //ADC A,E 235 | case 0x8C: ADC(REG_H);break; //ADC A,H 236 | case 0x8D: ADC(REG_L);break; //ADC A,L 237 | case 0x8F: ADC(REG_A);break; //ADC A,A 238 | 239 | case 0xCE: tmpb=op_read();ADC(tmpb);break; //ADC A,n : 11 001 110 :state 7 240 | case 0x8E: tmpb=read(REG_HL);ADC(tmpb);break; //ADC A,(HL) : 10 001 110 :state 7 241 | 242 | //SUB A,r : 10 010 r : state 4 243 | case 0x90: SUB(REG_B);break; //SUB A,B 244 | case 0x91: SUB(REG_C);break; //SUB A,C 245 | case 0x92: SUB(REG_D);break; //SUB A,D 246 | case 0x93: SUB(REG_E);break; //SUB A,E 247 | case 0x94: SUB(REG_H);break; //SUB A,H 248 | case 0x95: SUB(REG_L);break; //SUB A,L 249 | case 0x97: SUB(REG_A);break; //SUB A,A 250 | 251 | case 0xD6: tmpb=op_read();SUB(tmpb);break; //SUB A,n : 11 010 110 :state 7 252 | case 0x96: tmpb=read(REG_HL);SUB(tmpb);break; //SUB A,(HL) : 10 010 110 :state 7 253 | 254 | //SBC A,r : 10 011 r : state 4 255 | case 0x98: SBC(REG_B);break; //SBC A,B 256 | case 0x99: SBC(REG_C);break; //SBC A,C 257 | case 0x9A: SBC(REG_D);break; //SBC A,D 258 | case 0x9B: SBC(REG_E);break; //SBC A,E 259 | case 0x9C: SBC(REG_H);break; //SBC A,H 260 | case 0x9D: SBC(REG_L);break; //SBC A,L 261 | case 0x9F: SBC(REG_A);break; //SBC A,A 262 | 263 | case 0xDE: tmpb=op_read();SBC(tmpb);break; //SBC A,n : 11 011 110 :state 7 264 | case 0x9E: tmpb=read(REG_HL);SBC(tmpb);break; //SBC A,(HL) : 10 011 110 :state 7 265 | 266 | //AND A,r : 10 100 r : state 4 267 | case 0xA0: AND(REG_B);break; //AND A,B 268 | case 0xA1: AND(REG_C);break; //AND A,C 269 | case 0xA2: AND(REG_D);break; //AND A,D 270 | case 0xA3: AND(REG_E);break; //AND A,E 271 | case 0xA4: AND(REG_H);break; //AND A,H 272 | case 0xA5: AND(REG_L);break; //AND A,L 273 | case 0xA7: AND(REG_A);break; //AND A,A 274 | 275 | case 0xE6: tmpb=op_read();AND(tmpb);break; //AND A,n : 11 100 110 :state 7 276 | case 0xA6: tmpb=read(REG_HL);AND(tmpb);break; //AND A,(HL) : 10 100 110 :state 7 277 | 278 | //XOR A,r : 10 101 r : state 4 279 | case 0xA8: XOR(REG_B);break; //XOR A,B 280 | case 0xA9: XOR(REG_C);break; //XOR A,C 281 | case 0xAA: XOR(REG_D);break; //XOR A,D 282 | case 0xAB: XOR(REG_E);break; //XOR A,E 283 | case 0xAC: XOR(REG_H);break; //XOR A,H 284 | case 0xAD: XOR(REG_L);break; //XOR A,L 285 | case 0xAF: XOR(REG_A);break; //XOR A,A 286 | 287 | case 0xEE: tmpb=op_read();XOR(tmpb);break; //XOR A,n : 11 101 110 :state 7 288 | case 0xAE: tmpb=read(REG_HL);XOR(tmpb);break; //XOR A,(HL) : 10 101 110 :state 7 289 | 290 | //OR A,r : 10 110 r : state 4 291 | case 0xB0: OR(REG_B);break; //OR A,B 292 | case 0xB1: OR(REG_C);break; //OR A,C 293 | case 0xB2: OR(REG_D);break; //OR A,D 294 | case 0xB3: OR(REG_E);break; //OR A,E 295 | case 0xB4: OR(REG_H);break; //OR A,H 296 | case 0xB5: OR(REG_L);break; //OR A,L 297 | case 0xB7: OR(REG_A);break; //OR A,A 298 | 299 | case 0xF6: tmpb=op_read();OR(tmpb);break; //OR A,n : 11 110 110 :state 7 300 | case 0xB6: tmpb=read(REG_HL);OR(tmpb);break; //OR A,(HL) : 10 110 110 :state 7 301 | 302 | //CP A,r : 10 111 r : state 4 303 | case 0xB8: CP(REG_B);break; //CP A,B 304 | case 0xB9: CP(REG_C);break; //CP A,C 305 | case 0xBA: CP(REG_D);break; //CP A,D 306 | case 0xBB: CP(REG_E);break; //CP A,E 307 | case 0xBC: CP(REG_H);break; //CP A,H 308 | case 0xBD: CP(REG_L);break; //CP A,L 309 | case 0xBF: CP(REG_A);break; //CP A,A 310 | 311 | case 0xFE: tmpb=op_read();CP(tmpb);break; //CP A,n : 11 111 110 :state 7 312 | case 0xBE: tmpb=read(REG_HL);CP(tmpb);break; //CP A,(HL) : 10 111 110 :state 7 313 | 314 | //INC r : 00 r 100 : state 4 315 | case 0x04: INC(REG_B);break; //INC B 316 | case 0x0C: INC(REG_C);break; //INC C 317 | case 0x14: INC(REG_D);break; //INC D 318 | case 0x1C: INC(REG_E);break; //INC E 319 | case 0x24: INC(REG_H);break; //INC H 320 | case 0x2C: INC(REG_L);break; //INC L 321 | case 0x3C: INC(REG_A);break; //INC A 322 | case 0x34: tmpb=read(REG_HL);INC(tmpb);write(REG_HL,tmpb);break; //INC (HL) : 00 110 100 : state 11 323 | 324 | //DEC r : 00 r 101 : state 4 325 | case 0x05: DEC(REG_B);break; //DEC B 326 | case 0x0D: DEC(REG_C);break; //DEC C 327 | case 0x15: DEC(REG_D);break; //DEC D 328 | case 0x1D: DEC(REG_E);break; //DEC E 329 | case 0x25: DEC(REG_H);break; //DEC H 330 | case 0x2D: DEC(REG_L);break; //DEC L 331 | case 0x3D: DEC(REG_A);break; //DEC A 332 | case 0x35: tmpb=read(REG_HL);DEC(tmpb);write(REG_HL,tmpb);break; //DEC (HL) : 00 110 101 : state 11 333 | 334 | //16bit arismetic opcode 335 | //rp Pair Reg 00 BC 01 DE 10 HL 11 SP 336 | 337 | //ADD HL,BC : 00 rp1 001 :state 11 338 | case 0x09: ADDW(REG_BC);break; //ADD HL,BC 339 | case 0x19: ADDW(REG_DE);break; //ADD HL,DE 340 | case 0x29: ADDW(REG_HL);break; //ADD HL,HL 341 | case 0x39: ADDW(REG_SP);break; //ADD HL,SP 342 | 343 | //INC BC : 00 rp0 011 :state 11 344 | case 0x03: REG_BC++;;break; //INC BC 345 | case 0x13: REG_DE++;break; //INC DE 346 | case 0x23: REG_HL++;break; //INC HL 347 | case 0x33: REG_SP++;break; //INC SP 348 | 349 | //DEC BC : 00 rp1 011 :state 11 350 | case 0x0B: REG_BC--;break; //DEC BC 351 | case 0x1B: REG_DE--;break; //DEC DE 352 | case 0x2B: REG_HL--;break; //DEC HL 353 | case 0x3B: REG_SP--;break; //DEC SP 354 | 355 | //汎用:CPU制御 opcode 356 | 357 | /*case 0x27://DAA :state 4 358 | tmp.b.h=REG_A&0x0F; 359 | tmp.w=(REG_F&N_FLAG)? 360 | ((REG_F&C_FLAG)?(((REG_F&H_FLAG)?0x9A00:0xA000)+C_FLAG):((REG_F&H_FLAG)?0xFA00:0x0000)): 361 | ((REG_F&C_FLAG)?(((REG_F&H_FLAG)?0x6600:((tmp.b.h<0x0A)?0x6000:0x6600))+C_FLAG): 362 | ((REG_F&H_FLAG)?((REG_A<0xA0)?0x0600:(0x6600+C_FLAG)):((tmp.b.h<0x0A)?((REG_A<0xA0)?0x0000:(0x6000+C_FLAG)): 363 | ((REG_F<0x90)?0x600:(0x6600+C_FLAG))))); 364 | REG_A+=tmp.b.h; 365 | REG_F=ZTable[REG_A]|(tmp.b.l|(REG_F&N_FLAG)); 366 | break; 367 | */ 368 | case 0x27://DAA :state 4 369 | tmp.b.h=REG_A&0x0F; 370 | tmp.w=(REG_F&N_FLAG)? 371 | ( 372 | (REG_F&C_FLAG)? 373 | (((REG_F&H_FLAG)? 0x9A00:0xA000)+C_FLAG): 374 | ((REG_F&H_FLAG)? 0xFA00:0x0000) 375 | ) 376 | : 377 | ( 378 | (REG_F&C_FLAG)? 379 | (((REG_F&H_FLAG)? 0x6600:((tmp.b.h<0x0A)? 0x6000:0x6600))+C_FLAG): 380 | ( 381 | (REG_F&H_FLAG)? 382 | ((REG_A<0xA0)? 0x0600:(0x6600+C_FLAG)): 383 | ( 384 | (tmp.b.h<0x0A)? 385 | ((REG_A<0xA0)? 0x0000:(0x6000+C_FLAG)): 386 | ((REG_A<0x90)? 0x0600:(0x6600+C_FLAG)) 387 | ) 388 | ) 389 | ); 390 | REG_A+=tmp.b.h; 391 | REG_F=ZTable[REG_A]|(tmp.b.l|(REG_F&N_FLAG)); 392 | // FLAGS(REG_A,tmp.b.l|(REG_F&N_FLAG)); 393 | break; 394 | 395 | case 0x2F: //CPL(1の補数) :state4 396 | REG_A=~REG_A; 397 | REG_F|=(N_FLAG|H_FLAG); 398 | break; 399 | 400 | case 0x3F: //CCF(not carry) :state 4 401 | REG_F^=0x01; 402 | REG_F=REG_F&~(N_FLAG|H_FLAG); 403 | // REG_F|=(REG_F&C_FLAG)?0:H_FLAG; 404 | break; 405 | 406 | case 0x37: //SCF(set carry) :state 4 407 | REG_F=(REG_F&~(N_FLAG|H_FLAG))|C_FLAG; 408 | break; 409 | 410 | case 0x00: break; //NOP : state 4 411 | case 0xF3: regs.I=0;break; //DI : state 4 412 | case 0xFB: regs.I=1;int_desable=true;break; //EI : state 4 413 | 414 | case 0x76: 415 | #ifndef EXSACT_CORE 416 | if (ref_gb->get_regs()->TAC&0x04){//タイマ割りこみ 417 | word tmp; 418 | tmp=ref_gb->get_regs()->TIMA+(sys_clock+rest_clock)/timer_clocks[ref_gb->get_regs()->TAC&0x03]; 419 | 420 | if (tmp&0xFF00){//HALT中に割りこみがかかる場合 421 | total_clock+=(256-ref_gb->get_regs()->TIMA)*timer_clocks[ref_gb->get_regs()->TAC&0x03]-sys_clock; 422 | rest_clock-=(256-ref_gb->get_regs()->TIMA)*timer_clocks[ref_gb->get_regs()->TAC&0x03]-sys_clock; 423 | ref_gb->get_regs()->TIMA=ref_gb->get_regs()->TMA; 424 | halt=true; 425 | REG_PC--; 426 | irq(INT_TIMER); 427 | sys_clock=(sys_clock+rest_clock)&(timer_clocks[ref_gb->get_regs()->TAC&0x03]-1); 428 | } 429 | else{ 430 | ref_gb->get_regs()->TIMA=tmp&0xFF; 431 | sys_clock=(sys_clock+rest_clock)&(timer_clocks[ref_gb->get_regs()->TAC&0x03]-1); 432 | halt=true; 433 | total_clock+=rest_clock; 434 | rest_clock=0; 435 | REG_PC--; 436 | } 437 | } 438 | else{ 439 | halt=true; 440 | total_clock+=rest_clock; 441 | div_clock+=rest_clock; 442 | rest_clock=0; 443 | REG_PC--; 444 | } 445 | tmp_clocks=0; 446 | #else 447 | halt=true; 448 | REG_PC--; 449 | #endif 450 | break; //HALT : state 4 451 | 452 | //rotate/shift opcode 453 | case 0x07: REG_F=(REG_A>>7);REG_A=(REG_A<<1)|(REG_A>>7);break; //RLCA :state 4 454 | case 0x0F: REG_F=(REG_A&1);REG_A=(REG_A>>1)|(REG_A<<7);break; //RRCA :state 4 455 | case 0x17: tmp.b.l=REG_A>>7;REG_A=(REG_A<<1)|(REG_F&C_FLAG);REG_F=tmp.b.l;break; //RLA :state 4 456 | case 0x1F: tmp.b.l=REG_A&1;REG_A=(REG_A>>1)|(REG_F<<7);REG_F=tmp.b.l;break; //RRA :state 4 457 | 458 | //jump opcode 459 | 460 | //cc 条件 000 NZ non zero 001 Z zero 010 NC non carry 011 C carry 461 | case 0xC3: REG_PC=op_readw();break;//JP mn : state 10 (16?) 462 | 463 | //JP cc,mn : 11 cc 010 : state 16 or 12 464 | case 0xC2: if (REG_F&Z_FLAG) REG_PC+=2; else { REG_PC=op_readw();tmp_clocks=16; };break; // JPNZ mn 465 | case 0xCA: if (REG_F&Z_FLAG) { REG_PC=op_readw();tmp_clocks=16; } else REG_PC+=2;;break; // JPZ mn 466 | case 0xD2: if (REG_F&C_FLAG) REG_PC+=2; else { REG_PC=op_readw();tmp_clocks=16; };break; // JPNC mn 467 | case 0xDA: if (REG_F&C_FLAG) { REG_PC=op_readw();tmp_clocks=16; } else REG_PC+=2;;break; // JPC mn 468 | 469 | case 0xE9: REG_PC=REG_HL;break; //JP HL : state 4 470 | case 0x18: REG_PC+=(signed char)op_read();break;//JR e : state 12 471 | 472 | //JR cc,e : 00 1cc 000 : state 12(not jumped ->8) 473 | case 0x20: if (REG_F&Z_FLAG) REG_PC+=1; else {REG_PC+=(signed char)op_read();tmp_clocks=12;} break;// JRNZ 474 | case 0x28: if (REG_F&Z_FLAG) {REG_PC+=(signed char)op_read();tmp_clocks=12;} else REG_PC+=1; break;// JRZ 475 | case 0x30: if (REG_F&C_FLAG) REG_PC+=1; else {REG_PC+=(signed char)op_read();tmp_clocks=12;} break;// JRNC 476 | case 0x38: if (REG_F&C_FLAG) {REG_PC+=(signed char)op_read();tmp_clocks=12;} else REG_PC+=1; break;// JRC 477 | 478 | //call/ret opcode 479 | 480 | case 0xCD: REG_SP-=2;writew(REG_SP,REG_PC+2);REG_PC=op_readw();break; //CALL mn :state 24 481 | 482 | //CALL cc,mn : 11 0cc 100 : state 24 or 12 483 | case 0xC4: if (REG_F&Z_FLAG) REG_PC+=2; else {REG_SP-=2;writew(REG_SP,REG_PC+2);REG_PC=op_readw();tmp_clocks=24;} break; //CALLNZ mn 484 | case 0xCC: if (REG_F&Z_FLAG) {REG_SP-=2;writew(REG_SP,REG_PC+2);REG_PC=op_readw();tmp_clocks=24;} else REG_PC+=2; break; //CALLZ mn 485 | case 0xD4: if (REG_F&C_FLAG) REG_PC+=2; else {REG_SP-=2;writew(REG_SP,REG_PC+2);REG_PC=op_readw();tmp_clocks=24;} break; //CALLNC mn 486 | case 0xDC: if (REG_F&C_FLAG) {REG_SP-=2;writew(REG_SP,REG_PC+2);REG_PC=op_readw();tmp_clocks=24;} else REG_PC+=2; break; //CALLC mn 487 | 488 | //RST p : 11 t 111 (p=t<<3) : state 16 489 | case 0xC7: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x00;break; //RST 0x00 490 | case 0xCF: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x08;break; //RST 0x08 491 | case 0xD7: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x10;break; //RST 0x10 492 | case 0xDF: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x18;break; //RST 0x18 493 | case 0xE7: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x20;break; //RST 0x20 494 | case 0xEF: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x28;break; //RST 0x28 495 | case 0xF7: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x30;break; //RST 0x30 496 | case 0xFF: REG_SP-=2;writew(REG_SP,REG_PC);REG_PC=0x38;break; //RST 0x38 497 | 498 | case 0xC9: REG_PC=readw(REG_SP);REG_SP+=2;break; //RET state 16 499 | 500 | //RET cc : 11 0cc 000 : state 20 or 8 501 | case 0xC0: if (!(REG_F&Z_FLAG)) {REG_PC=readw(REG_SP);REG_SP+=2;tmp_clocks=20;} break; //RETNZ 502 | case 0xC8: if (REG_F&Z_FLAG) {REG_PC=readw(REG_SP);REG_SP+=2;tmp_clocks=20;} break; //RETZ 503 | case 0xD0: if (!(REG_F&C_FLAG)) {REG_PC=readw(REG_SP);REG_SP+=2;tmp_clocks=20;} break; //RETNC 504 | case 0xD8: if (REG_F&C_FLAG) {REG_PC=readw(REG_SP);REG_SP+=2;tmp_clocks=20;} break; //RETC 505 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEBUG = 0 2 | 3 | ifeq ($(platform),) 4 | platform = unix 5 | ifeq ($(shell uname -a),) 6 | platform = win 7 | else ifneq ($(findstring Darwin,$(shell uname -a)),) 8 | platform = osx 9 | arch = intel 10 | ifeq ($(shell uname -p),arm) 11 | arch = arm 12 | endif 13 | ifeq ($(shell uname -p),powerpc) 14 | arch = ppc 15 | endif 16 | else ifneq ($(findstring MINGW,$(shell uname -a)),) 17 | platform = win 18 | endif 19 | endif 20 | 21 | LIBS := 22 | 23 | # system platform 24 | system_platform = unix 25 | ifeq ($(shell uname -a),) 26 | EXE_EXT = .exe 27 | system_platform = win 28 | else ifneq ($(findstring Darwin,$(shell uname -a)),) 29 | system_platform = osx 30 | arch = intel 31 | ifeq ($(shell uname -p),arm) 32 | arch = ppc 33 | endif 34 | ifeq ($(shell uname -p),powerpc) 35 | arch = ppc 36 | endif 37 | else ifneq ($(findstring MINGW,$(shell uname -a)),) 38 | system_platform = win 39 | endif 40 | 41 | TARGET_NAME := tgbdual 42 | GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" 43 | ifneq ($(GIT_VERSION)," unknown") 44 | CXXFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" 45 | endif 46 | 47 | 48 | SPACE := 49 | SPACE := $(SPACE) $(SPACE) 50 | BACKSLASH := 51 | BACKSLASH := \$(BACKSLASH) 52 | filter_out1 = $(filter-out $(firstword $1),$1) 53 | filter_out2 = $(call filter_out1,$(call filter_out1,$1)) 54 | unixpath = $(subst \,/,$1) 55 | unixcygpath = /$(subst :,,$(call unixpath,$1)) 56 | 57 | # Unix 58 | ifeq ($(platform), unix) 59 | TARGET := $(TARGET_NAME)_libretro.so 60 | fpic := -fPIC 61 | SHARED := -shared -Wl,--version-script=libretro/link.T 62 | 63 | # Classic Platforms #################### 64 | # Platform affix = classic__<µARCH> 65 | # Help at https://modmyclassic.com/comp 66 | 67 | # (armv7 a7, hard point, neon based) ### 68 | # NESC, SNESC, C64 mini 69 | else ifeq ($(platform),$(filter $(platform),classic_armv7_a7 unix-armv7-hardfloat-neon)) 70 | TARGET := $(TARGET_NAME)_libretro.so 71 | fpic := -fPIC 72 | SHARED := -shared -Wl,--version-script=libretro/link.T 73 | CFLAGS += -Ofast \ 74 | -flto=4 -fwhole-program -fuse-linker-plugin \ 75 | -fdata-sections -ffunction-sections -Wl,--gc-sections \ 76 | -fno-stack-protector -fno-ident -fomit-frame-pointer \ 77 | -falign-functions=1 -falign-jumps=1 -falign-loops=1 \ 78 | -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \ 79 | -fmerge-all-constants -fno-math-errno \ 80 | -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard 81 | CXXFLAGS += $(CFLAGS) 82 | CPPFLAGS += $(CFLAGS) 83 | ASFLAGS += $(CFLAGS) 84 | HAVE_NEON = 1 85 | ARCH = arm 86 | ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1) 87 | CFLAGS += -march=armv7-a 88 | else 89 | CFLAGS += -march=armv7ve 90 | # If gcc is 5.0 or later 91 | ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1) 92 | LDFLAGS += -static-libgcc -static-libstdc++ 93 | endif 94 | endif 95 | ####################################### 96 | 97 | # OS X 98 | else ifeq ($(platform), osx) 99 | TARGET := $(TARGET_NAME)_libretro.dylib 100 | fpic := -fPIC 101 | SHARED := -dynamiclib 102 | 103 | ifeq ($(UNIVERSAL),1) 104 | ifeq ($(ARCHFLAGS),) 105 | ARCHFLAGS = -arch i386 -arch x86_64 106 | ifeq ($(archs),arm) 107 | ARCHFLAGS = -arch arm64 108 | endif 109 | ifeq ($(archs),ppc) 110 | ARCHFLAGS = -arch ppc -arch ppc64 111 | endif 112 | endif 113 | endif 114 | 115 | ifeq ($(shell uname -p),powerpc) 116 | FLAGS += -DMSB_FIRST 117 | OLD_GCC = 1 118 | endif 119 | OSXVER = `sw_vers -productVersion | cut -d. -f 2` 120 | OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"` 121 | MINVERSION= 122 | ifeq ($(OSX_LT_MAVERICKS),"YES") 123 | MINVERSION = -mmacosx-version-min=10.1 124 | else 125 | MINVERSION = -mmacosx-version-min=10.7 126 | endif 127 | ifeq ($(shell uname -p),arm) 128 | MINVERSION = 129 | endif 130 | 131 | ifeq ($(CROSS_COMPILE),1) 132 | TARGET_RULE = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT) 133 | CFLAGS += $(TARGET_RULE) 134 | CPPFLAGS += $(TARGET_RULE) 135 | CXXFLAGS += $(TARGET_RULE) 136 | LDFLAGS += $(TARGET_RULE) 137 | MINVERSION = 138 | endif 139 | 140 | fpic += $(MINVERSION) -stdlib=libc++ 141 | 142 | # iOS 143 | else ifneq (,$(findstring ios,$(platform))) 144 | TARGET := $(TARGET_NAME)_libretro_ios.dylib 145 | fpic := -fPIC 146 | SHARED := -dynamiclib 147 | 148 | ifeq ($(IOSSDK),) 149 | IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path) 150 | endif 151 | ifeq ($(platform), ios-arm64) 152 | CC = clang -arch arm64 -isysroot $(IOSSDK) 153 | CXX = clang++ -arch arm64 -isysroot $(IOSSDK) -stdlib=libc++ 154 | else 155 | CC = clang -arch armv7 -isysroot $(IOSSDK) 156 | CXX = clang++ -arch armv7 -isysroot $(IOSSDK) 157 | endif 158 | ifeq ($(platform),$(filter $(platform),ios9 ios-arm64)) 159 | MINVERSION = -miphoneos-version-min=8.0 160 | else 161 | MINVERSION = -miphoneos-version-min=5.0 162 | endif 163 | SHARED += $(MINVERSION) 164 | CFLAGS += $(MINVERSION) 165 | CXXFLAGS += $(MINVERSION) 166 | 167 | else ifeq ($(platform), tvos-arm64) 168 | TARGET := $(TARGET_NAME)_libretro_tvos.dylib 169 | fpic := -fPIC 170 | SHARED := -dynamiclib 171 | 172 | ifeq ($(IOSSDK),) 173 | IOSSDK := $(shell xcodebuild -version -sdk appletvos Path) 174 | endif 175 | 176 | CFLAGS += -DIOS 177 | 178 | CC = cc -arch arm64 -isysroot $(IOSSDK) 179 | CXX = clang++ -arch arm64 -isysroot $(IOSSDK) 180 | MINVERSION = -mappletvos-version-min=11.0 181 | SHARED += $(MINVERSION) 182 | CFLAGS += $(MINVERSION) 183 | CXXFLAGS += $(MINVERSION) 184 | 185 | # Theos 186 | else ifeq ($(platform), theos_ios) 187 | DEPLOYMENT_IOSVERSION = 5.0 188 | TARGET = iphone:latest:$(DEPLOYMENT_IOSVERSION) 189 | ARCHS = armv7 armv7s 190 | TARGET_IPHONEOS_DEPLOYMENT_VERSION=$(DEPLOYMENT_IOSVERSION) 191 | THEOS_BUILD_DIR := objs 192 | include $(THEOS)/makefiles/common.mk 193 | 194 | LIBRARY_NAME = $(TARGET_NAME)_libretro_ios 195 | 196 | # QNX 197 | else ifeq ($(platform), qnx) 198 | TARGET := $(TARGET_NAME)_libretro_$(platform).so 199 | fpic := -fPIC 200 | SHARED := -shared -Wl,--version-script=libretro/link.T 201 | CC = qcc -Vgcc_ntoarmv7le 202 | CXX = QCC -Vgcc_ntoarmv7le_cpp 203 | 204 | # Nintendo Switch (libnx) 205 | else ifeq ($(platform), libnx) 206 | include $(DEVKITPRO)/libnx/switch_rules 207 | EXT=a 208 | TARGET := $(TARGET_NAME)_libretro_$(platform).$(EXT) 209 | DEFINES := -DSWITCH=1 -U__linux__ -U__linux -DRARCH_INTERNAL 210 | CFLAGS := $(DEFINES) -g -O3 \ 211 | -fPIE -I$(LIBNX)/include/ -ffunction-sections -fdata-sections -ftls-model=local-exec -Wl,--allow-multiple-definition -specs=$(LIBNX)/switch.specs 212 | CFLAGS += $(INCDIRS) 213 | CFLAGS += -D__SWITCH__ -DHAVE_LIBNX -march=armv8-a -mtune=cortex-a57 -mtp=soft 214 | CXXFLAGS := $(ASFLAGS) $(CFLAGS) -fno-rtti -std=gnu++11 215 | CFLAGS += -std=gnu11 216 | STATIC_LINKING = 1 217 | 218 | # PS2 219 | else ifeq ($(platform), ps2) 220 | TARGET := $(TARGET_NAME)_libretro_$(platform).a 221 | CC = mips64r5900el-ps2-elf-gcc$(EXE_EXT) 222 | CXX = mips64r5900el-ps2-elf-g++$(EXE_EXT) 223 | AR = mips64r5900el-ps2-elf-ar$(EXE_EXT) 224 | STATIC_LINKING = 1 225 | OLD_GCC = 1 226 | FLAGS += -G0 -O3 -DSKIP_COLOR_CORRECTION 227 | 228 | # PSP 229 | else ifeq ($(platform), psp1) 230 | TARGET := $(TARGET_NAME)_libretro_$(platform).a 231 | CC = psp-gcc$(EXE_EXT) 232 | CXX = psp-g++$(EXE_EXT) 233 | AR = psp-ar$(EXE_EXT) 234 | STATIC_LINKING = 1 235 | FLAGS += -G0 236 | 237 | # Vita 238 | else ifeq ($(platform), vita) 239 | TARGET := $(TARGET_NAME)_libretro_$(platform).a 240 | CC = arm-vita-eabi-gcc$(EXE_EXT) 241 | CXX = arm-vita-eabi-g++$(EXE_EXT) 242 | AR = arm-vita-eabi-ar$(EXE_EXT) 243 | STATIC_LINKING = 1 244 | FLAGS += -DVITA -fno-short-enums 245 | 246 | # CTR (3DS) 247 | else ifeq ($(platform), ctr) 248 | TARGET := $(TARGET_NAME)_libretro_$(platform).a 249 | CC = $(DEVKITARM)/bin/arm-none-eabi-gcc$(EXE_EXT) 250 | CXX = $(DEVKITARM)/bin/arm-none-eabi-g++$(EXE_EXT) 251 | AR = $(DEVKITARM)/bin/arm-none-eabi-ar$(EXE_EXT) 252 | FLAGS += -march=armv6k -mtune=mpcore -mfloat-abi=hard 253 | FLAGS += -Wall -mword-relocations 254 | FLAGS += -fomit-frame-pointer -ffast-math 255 | FLAGS += -DARM11 -D_3DS 256 | STATIC_LINKING = 1 257 | 258 | # Nintendo Switch (libtransistor) 259 | else ifeq ($(platform), switch) 260 | EXT=a 261 | TARGET := $(TARGET_NAME)_libretro_$(platform).$(EXT) 262 | include $(LIBTRANSISTOR_HOME)/libtransistor.mk 263 | STATIC_LINKING=1 264 | 265 | # Nintendo WiiU 266 | else ifeq ($(platform), wiiu) 267 | TARGET := $(TARGET_NAME)_libretro_$(platform).a 268 | CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) 269 | CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT) 270 | AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) 271 | CFLAGS += -DGEKKO -DHW_RVL -DWIIU -D__wiiu__ -DHW_WUP -ffunction-sections -fdata-sections 272 | CFLAGS += -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST -I$(DEVKITPRO)/libogc/include 273 | CFLAGS += -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int 274 | STATIC_LINKING = 1 275 | 276 | # Emscripten 277 | else ifeq ($(platform), emscripten) 278 | TARGET := $(TARGET_NAME)_libretro_$(platform).bc 279 | STATIC_LINKING = 1 280 | 281 | # Windows MSVC 2003 Xbox 1 282 | else ifeq ($(platform), xbox1_msvc2003) 283 | TARGET := $(TARGET_NAME)_libretro_xdk1.lib 284 | CC = CL.exe 285 | CXX = CL.exe 286 | LD = lib.exe 287 | 288 | export INCLUDE := $(XDK)/xbox/include 289 | export LIB := $(XDK)/xbox/lib 290 | PATH := $(call unixcygpath,$(XDK)/xbox/bin/vc71):$(PATH) 291 | PSS_STYLE :=2 292 | CFLAGS += -D_XBOX -D_XBOX1 293 | CXXFLAGS += -D_XBOX -D_XBOX1 294 | STATIC_LINKING=1 295 | HAS_GCC := 0 296 | # Windows MSVC 2010 Xbox 360 297 | else ifeq ($(platform), xbox360_msvc2010) 298 | TARGET := $(TARGET_NAME)_libretro_xdk360.lib 299 | MSVCBINDIRPREFIX = $(XEDK)/bin/win32 300 | CC = "$(MSVCBINDIRPREFIX)/cl.exe" 301 | CXX = "$(MSVCBINDIRPREFIX)/cl.exe" 302 | LD = "$(MSVCBINDIRPREFIX)/lib.exe" 303 | 304 | export INCLUDE := $(XEDK)/include/xbox 305 | export LIB := $(XEDK)/lib/xbox 306 | PSS_STYLE :=2 307 | FLAGS += -DMSB_FIRST 308 | CFLAGS += -D_XBOX -D_XBOX360 309 | CXXFLAGS += -D_XBOX -D_XBOX360 310 | STATIC_LINKING=1 311 | HAS_GCC := 0 312 | 313 | # Windows MSVC 2003 x86 314 | else ifeq ($(platform), windows_msvc2003_x86) 315 | CC = cl.exe 316 | CXX = cl.exe 317 | 318 | PATH := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin"):$(PATH) 319 | PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../IDE") 320 | INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/include") 321 | LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS71COMNTOOLS)../../Vc7/lib") 322 | BIN := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin") 323 | 324 | WindowsSdkDir := $(INETSDK) 325 | 326 | export INCLUDE := $(INCLUDE);$(INETSDK)/Include;src/drivers/libretro/msvc/msvc-2005 327 | export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib 328 | TARGET := $(TARGET_NAME)_libretro.dll 329 | PSS_STYLE :=2 330 | LDFLAGS += -DLL 331 | CFLAGS += -D_CRT_SECURE_NO_DEPRECATE 332 | 333 | # Windows MSVC 2010 x64 334 | else ifeq ($(platform), windows_msvc2010_x64) 335 | CC = cl.exe 336 | CXX = cl.exe 337 | 338 | PATH := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin/amd64"):$(PATH) 339 | PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../IDE") 340 | LIB := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/lib/amd64") 341 | INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include") 342 | 343 | WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') 344 | WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') 345 | 346 | WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include") 347 | WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl") 348 | WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\x64") 349 | 350 | INCFLAGS_PLATFORM = -I"$(WindowsSDKIncludeDir)" 351 | export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKGlIncludeDir) 352 | export LIB := $(LIB);$(WindowsSDKLibDir) 353 | TARGET := $(TARGET_NAME)_libretro.dll 354 | PSS_STYLE :=2 355 | LDFLAGS += -DLL 356 | # Windows MSVC 2010 x86 357 | else ifeq ($(platform), windows_msvc2010_x86) 358 | CC = cl.exe 359 | CXX = cl.exe 360 | 361 | PATH := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin"):$(PATH) 362 | PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../IDE") 363 | LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS100COMNTOOLS)../../VC/lib") 364 | INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include") 365 | 366 | WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') 367 | WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') 368 | 369 | WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include") 370 | WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl") 371 | WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib") 372 | 373 | INCFLAGS_PLATFORM = -I"$(WindowsSDKIncludeDir)" 374 | export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKGlIncludeDir) 375 | export LIB := $(LIB);$(WindowsSDKLibDir) 376 | TARGET := $(TARGET_NAME)_libretro.dll 377 | PSS_STYLE :=2 378 | LDFLAGS += -DLL 379 | 380 | # Windows MSVC 2005 x86 381 | else ifeq ($(platform), windows_msvc2005_x86) 382 | CC = cl.exe 383 | CXX = cl.exe 384 | 385 | PATH := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin"):$(PATH) 386 | PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../IDE") 387 | INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/include") 388 | LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS80COMNTOOLS)../../VC/lib") 389 | BIN := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin") 390 | 391 | WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\MicrosoftSDK\InstalledSDKs\8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3" -v "Install Dir" | grep -o '[A-Z]:\\.*') 392 | 393 | WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include") 394 | WindowsSDKAtlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\atl") 395 | WindowsSDKCrtIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\crt") 396 | WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl") 397 | WindowsSDKMfcIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\mfc") 398 | WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib") 399 | 400 | export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKAtlIncludeDir);$(WindowsSDKCrtIncludeDir);$(WindowsSDKGlIncludeDir);$(WindowsSDKMfcIncludeDir) 401 | export LIB := $(LIB);$(WindowsSDKLibDir) 402 | TARGET := $(TARGET_NAME)_libretro.dll 403 | PSS_STYLE :=2 404 | LDFLAGS += -DLL 405 | CFLAGS += -D_CRT_SECURE_NO_DEPRECATE 406 | 407 | # Windows MSVC 2017 all architectures 408 | else ifneq (,$(findstring windows_msvc2017,$(platform))) 409 | 410 | NO_GCC := 1 411 | CFLAGS += -DNOMINMAX 412 | CXXFLAGS += -DNOMINMAX 413 | WINDOWS_VERSION = 1 414 | 415 | PlatformSuffix = $(subst windows_msvc2017_,,$(platform)) 416 | ifneq (,$(findstring desktop,$(PlatformSuffix))) 417 | WinPartition = desktop 418 | MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -FS 419 | LDFLAGS += -MANIFEST -LTCG:incremental -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 420 | LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib 421 | else ifneq (,$(findstring uwp,$(PlatformSuffix))) 422 | WinPartition = uwp 423 | MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -D_WINDLL -D_UNICODE -DUNICODE -D__WRL_NO_DEFAULT_LIB__ -EHsc -FS 424 | LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -LTCG -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO 425 | LIBS += WindowsApp.lib 426 | endif 427 | 428 | CFLAGS += $(MSVC2017CompileFlags) 429 | CXXFLAGS += $(MSVC2017CompileFlags) 430 | 431 | TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) 432 | 433 | CC = cl.exe 434 | CXX = cl.exe 435 | LD = link.exe 436 | 437 | reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>nul))) 438 | fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) 439 | 440 | ProgramFiles86w := $(shell cmd //c "echo %PROGRAMFILES(x86)%") 441 | ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") 442 | 443 | WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) 444 | WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) 445 | WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) 446 | WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) 447 | WindowsSdkDir := $(WindowsSdkDir) 448 | 449 | WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) 450 | WindowsSDKVersion := $(WindowsSDKVersion) 451 | 452 | VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools 453 | VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise 454 | VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional 455 | VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community 456 | 457 | VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) 458 | ifeq ($(VsInstallRoot), ) 459 | VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) 460 | endif 461 | ifeq ($(VsInstallRoot), ) 462 | VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) 463 | endif 464 | ifeq ($(VsInstallRoot), ) 465 | VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) 466 | endif 467 | VsInstallRoot := $(VsInstallRoot) 468 | 469 | VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') 470 | VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) 471 | 472 | WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared") 473 | WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt") 474 | WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um") 475 | WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)") 476 | WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)") 477 | 478 | # For some reason the HostX86 compiler doesn't like compiling for x64 479 | # ("no such file" opening a shared library), and vice-versa. 480 | # Work around it for now by using the strictly x86 compiler for x86, and x64 for x64. 481 | # NOTE: What about ARM? 482 | ifneq (,$(findstring x64,$(TargetArchMoniker))) 483 | VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX64 484 | else 485 | VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86 486 | endif 487 | 488 | PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH) 489 | PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE") 490 | INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include") 491 | LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/lib/$(TargetArchMoniker)") 492 | ifneq (,$(findstring uwp,$(PlatformSuffix))) 493 | LIB := $(shell IFS=$$'\n'; cygpath -w "$(LIB)/store") 494 | endif 495 | 496 | export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir) 497 | export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir) 498 | TARGET := $(TARGET_NAME)_libretro.dll 499 | PSS_STYLE :=2 500 | LDFLAGS += -DLL 501 | CFLAGS += -D_CRT_SECURE_NO_DEPRECATE 502 | 503 | # Windows 504 | else 505 | TARGET := $(TARGET_NAME)_libretro.dll 506 | CC ?= gcc 507 | CXX ?= g++ 508 | SHARED := -shared -Wl,--version-script=libretro/link.T 509 | LDFLAGS += -static-libgcc -static-libstdc++ -lwinmm 510 | endif 511 | 512 | CORE_DIR := . 513 | 514 | include Makefile.common 515 | 516 | OBJECTS := $(SOURCES_CXX:.cpp=.o) 517 | 518 | ifeq ($(DEBUG), 1) 519 | ifneq (,$(findstring msvc,$(platform))) 520 | CFLAGS += -Od -Zi -D_DEBUG 521 | CXXFLAGS += -Od -Zi -D_DEBUG 522 | else 523 | CFLAGS += -O0 -g 524 | CXXFLAGS += -O0 -g 525 | endif 526 | CFLAGS += -DDEBUG 527 | CXXFLAGS += -DDEBUG 528 | else 529 | CFLAGS += -O2 -DNDEBUG 530 | CXXFLAGS += -O2 -DNDEBUG 531 | endif 532 | 533 | ifneq (,$(findstring msvc,$(platform))) 534 | ifeq ($(DEBUG),1) 535 | CFLAGS += -MTd 536 | CXXFLAGS += -MTd 537 | else 538 | CFLAGS += -MT 539 | CXXFLAGS += -MT 540 | endif 541 | CFLAGS += -D_CRT_SECURE_NO_DEPRECATE 542 | CXXFLAGS += -D_CRT_SECURE_NO_DEPRECATE 543 | endif 544 | 545 | 546 | ifneq (,$(findstring msvc,$(platform))) 547 | else 548 | FLAGS += -ffast-math 549 | endif 550 | 551 | FLAGS += -DFRONTEND_SUPPORTS_RGB565 552 | 553 | LDFLAGS += $(fpic) 554 | FLAGS += $(fpic) 555 | FLAGS += $(INCFLAGS) 556 | 557 | ifeq ($(OLD_GCC), 1) 558 | WARNINGS := -Wall 559 | else ifeq ($(NO_GCC), 1) 560 | WARNINGS := 561 | else ifneq (,$(findstring msvc,$(platform))) 562 | WARNINGS := 563 | else 564 | WARNINGS := -Wall \ 565 | -Wno-sign-compare \ 566 | -Wno-unused-variable \ 567 | -Wno-unused-function \ 568 | -Wno-uninitialized \ 569 | -Wno-strict-aliasing \ 570 | -Wno-overflow \ 571 | -fno-strict-overflow 572 | endif 573 | 574 | FLAGS += -D__LIBRETRO__ $(WARNINGS) 575 | 576 | CXXFLAGS += $(FLAGS) 577 | CFLAGS += $(FLAGS) 578 | 579 | ifeq ($(platform), osx) 580 | ifndef ($(NOUNIVERSAL)) 581 | CFLAGS += $(ARCHFLAGS) 582 | CXXFLAGS += $(ARCHFLAGS) 583 | LFLAGS += $(ARCHFLAGS) 584 | endif 585 | endif 586 | 587 | OBJOUT = -o 588 | LINKOUT = -o 589 | 590 | ifneq (,$(findstring msvc,$(platform))) 591 | OBJOUT = -Fo 592 | LINKOUT = -out: 593 | ifeq ($(STATIC_LINKING),1) 594 | LD ?= lib.exe 595 | STATIC_LINKING=0 596 | else 597 | LD = link.exe 598 | endif 599 | else 600 | LD = $(CXX) 601 | endif 602 | 603 | INCFLAGS += $(INCFLAGS_PLATFORM) 604 | 605 | ifeq ($(platform), theos_ios) 606 | COMMON_FLAGS := -DIOS $(COMMON_DEFINES) $(INCFLAGS) -I$(THEOS_INCLUDE_PATH) -Wno-error 607 | $(LIBRARY_NAME)_CFLAGS += $(CFLAGS) $(COMMON_FLAGS) 608 | $(LIBRARY_NAME)_CXXFLAGS += $(CXXFLAGS) $(COMMON_FLAGS) 609 | ${LIBRARY_NAME}_FILES = $(SOURCES_CXX) $(SOURCES_C) 610 | include $(THEOS_MAKE_PATH)/library.mk 611 | else 612 | all: $(TARGET) 613 | $(TARGET): $(OBJECTS) 614 | ifeq ($(STATIC_LINKING), 1) 615 | $(AR) rcs $@ $(OBJECTS) 616 | else 617 | $(LD) $(LINKOUT)$@ $(SHARED) $(OBJECTS) $(LDFLAGS) $(LIBS) 618 | endif 619 | 620 | %.o: %.cpp 621 | $(CXX) -c $(OBJOUT)$@ $< $(CXXFLAGS) 622 | 623 | %.o: %.c 624 | $(CC) -c $(OBJOUT)$@ $< $(CFLAGS) 625 | 626 | clean: 627 | rm -f $(TARGET) $(OBJECTS) 628 | 629 | .PHONY: clean 630 | endif 631 | -------------------------------------------------------------------------------- /libretro/libretro.cpp: -------------------------------------------------------------------------------- 1 | #ifndef _GNU_SOURCE 2 | #define _GNU_SOURCE 1 // for fopencookie hack in serialize_size 3 | #endif 4 | 5 | #include 6 | 7 | #include "libretro.h" 8 | #include "../gb_core/gb.h" 9 | #include "dmy_renderer.h" 10 | 11 | #define RETRO_MEMORY_GAMEBOY_1_SRAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM) 12 | #define RETRO_MEMORY_GAMEBOY_1_RTC ((2 << 8) | RETRO_MEMORY_RTC) 13 | #define RETRO_MEMORY_GAMEBOY_2_SRAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM) 14 | #define RETRO_MEMORY_GAMEBOY_2_RTC ((3 << 8) | RETRO_MEMORY_RTC) 15 | 16 | #define RETRO_GAME_TYPE_GAMEBOY_LINK_2P 0x101 17 | 18 | static const struct retro_variable vars_single[] = { 19 | { "tgbdual_gblink_enable", "Link cable emulation (reload); disabled|enabled" }, 20 | { NULL, NULL }, 21 | }; 22 | 23 | static const struct retro_variable vars_dual[] = { 24 | { "tgbdual_gblink_enable", "Link cable emulation (reload); disabled|enabled" }, 25 | { "tgbdual_screen_placement", "Screen layout; left-right|top-down" }, 26 | { "tgbdual_switch_screens", "Switch player screens; normal|switched" }, 27 | { "tgbdual_single_screen_mp", "Show player screens; both players|player 1 only|player 2 only" }, 28 | { "tgbdual_audio_output", "Audio output; Game Boy #1|Game Boy #2" }, 29 | { NULL, NULL }, 30 | }; 31 | 32 | static const struct retro_subsystem_memory_info gb1_memory[] = { 33 | { "srm", RETRO_MEMORY_GAMEBOY_1_SRAM }, 34 | { "rtc", RETRO_MEMORY_GAMEBOY_1_RTC }, 35 | }; 36 | 37 | static const struct retro_subsystem_memory_info gb2_memory[] = { 38 | { "srm", RETRO_MEMORY_GAMEBOY_2_SRAM }, 39 | { "rtc", RETRO_MEMORY_GAMEBOY_2_RTC }, 40 | }; 41 | 42 | static const struct retro_subsystem_rom_info gb_roms[] = { 43 | { "GameBoy #1", "gb|gbc", false, false, false, gb1_memory, 1 }, 44 | { "GameBoy #2", "gb|gbc", false, false, false, gb2_memory, 1 }, 45 | }; 46 | 47 | static const struct retro_subsystem_info subsystems[] = { 48 | { "2 Player Game Boy Link", "gb_link_2p", gb_roms, 2, RETRO_GAME_TYPE_GAMEBOY_LINK_2P }, 49 | { NULL }, 50 | }; 51 | 52 | enum mode{ 53 | MODE_SINGLE_GAME, 54 | MODE_SINGLE_GAME_DUAL, 55 | MODE_DUAL_GAME 56 | }; 57 | 58 | static enum mode mode = MODE_SINGLE_GAME; 59 | 60 | gb *g_gb[2]; 61 | dmy_renderer *render[2]; 62 | 63 | retro_log_printf_t log_cb; 64 | retro_video_refresh_t video_cb; 65 | retro_audio_sample_batch_t audio_batch_cb; 66 | retro_environment_t environ_cb; 67 | retro_input_poll_t input_poll_cb; 68 | retro_input_state_t input_state_cb; 69 | 70 | extern bool _screen_2p_vertical; 71 | extern bool _screen_switched; 72 | extern int _show_player_screens; 73 | static size_t _serialize_size[2] = { 0, 0 }; 74 | 75 | bool gblink_enable = false; 76 | int audio_2p_mode = 0; 77 | // used to make certain core options only take effect once on core startup 78 | bool already_checked_options = false; 79 | bool libretro_supports_persistent_buffer = false; 80 | bool libretro_supports_bitmasks = false; 81 | struct retro_system_av_info *my_av_info; 82 | 83 | void retro_get_system_info(struct retro_system_info *info) 84 | { 85 | info->library_name = "TGB Dual"; 86 | #ifndef GIT_VERSION 87 | #define GIT_VERSION "" 88 | #endif 89 | info->library_version = "v0.8.3" GIT_VERSION; 90 | info->need_fullpath = false; 91 | info->valid_extensions = "gb|dmg|gbc|cgb|sgb"; 92 | } 93 | 94 | void retro_get_system_av_info(struct retro_system_av_info *info) 95 | { 96 | int w = 160, h = 144; 97 | info->geometry.max_width = w * 2; 98 | info->geometry.max_height = h * 2; 99 | 100 | if (g_gb[1] && _show_player_screens == 2) 101 | { 102 | // screen orientation for dual gameboy mode 103 | if(_screen_2p_vertical) 104 | h *= 2; 105 | else 106 | w *= 2; 107 | } 108 | 109 | info->timing.fps = 4194304.0 / 70224.0; 110 | info->timing.sample_rate = 44100.0f; 111 | info->geometry.base_width = w; 112 | info->geometry.base_height = h; 113 | info->geometry.aspect_ratio = float(w) / float(h); 114 | memcpy(my_av_info, info, sizeof(*my_av_info)); 115 | } 116 | 117 | 118 | 119 | void retro_init(void) 120 | { 121 | unsigned level = 4; 122 | struct retro_log_callback log; 123 | 124 | if(environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) 125 | log_cb = log.log; 126 | else 127 | log_cb = NULL; 128 | 129 | environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level); 130 | 131 | my_av_info = (retro_system_av_info*)malloc(sizeof(*my_av_info)); 132 | 133 | if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) 134 | libretro_supports_bitmasks = true; 135 | } 136 | 137 | void retro_deinit(void) 138 | { 139 | free(my_av_info); 140 | libretro_supports_bitmasks = false; 141 | } 142 | 143 | static void check_variables(void) 144 | { 145 | struct retro_variable var; 146 | 147 | // check whether link cable mode is enabled 148 | var.key = "tgbdual_gblink_enable"; 149 | var.value = NULL; 150 | if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) 151 | { 152 | if (!already_checked_options) { // only apply this setting on init 153 | if (!strcmp(var.value, "disabled")) 154 | gblink_enable = false; 155 | else if (!strcmp(var.value, "enabled")) 156 | gblink_enable = true; 157 | } 158 | } 159 | else 160 | gblink_enable = false; 161 | 162 | // check whether screen placement is horz (side-by-side) or vert 163 | var.key = "tgbdual_screen_placement"; 164 | var.value = NULL; 165 | if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) 166 | { 167 | if (!strcmp(var.value, "left-right")) 168 | _screen_2p_vertical = false; 169 | else if (!strcmp(var.value, "top-down")) 170 | _screen_2p_vertical = true; 171 | } 172 | else 173 | _screen_2p_vertical = false; 174 | 175 | // check whether player 1 and 2's screen placements are swapped 176 | var.key = "tgbdual_switch_screens"; 177 | var.value = NULL; 178 | if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) 179 | { 180 | if (!strcmp(var.value, "normal")) 181 | _screen_switched = false; 182 | else if (!strcmp(var.value, "switched")) 183 | _screen_switched = true; 184 | } 185 | else 186 | _screen_switched = false; 187 | 188 | // check whether to show both players' screens, p1 only, or p2 only 189 | var.key = "tgbdual_single_screen_mp"; 190 | var.value = NULL; 191 | if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) 192 | { 193 | if (!strcmp(var.value, "both players")) 194 | _show_player_screens = 2; 195 | else if (!strcmp(var.value, "player 1 only")) 196 | _show_player_screens = 0; 197 | else if (!strcmp(var.value, "player 2 only")) 198 | _show_player_screens = 1; 199 | } 200 | else 201 | _show_player_screens = 2; 202 | 203 | int screenw = 160, screenh = 144; 204 | if (gblink_enable && _show_player_screens == 2) 205 | { 206 | if (_screen_2p_vertical) 207 | screenh *= 2; 208 | else 209 | screenw *= 2; 210 | } 211 | my_av_info->geometry.base_width = screenw; 212 | my_av_info->geometry.base_height = screenh; 213 | my_av_info->geometry.aspect_ratio = float(screenw) / float(screenh); 214 | 215 | already_checked_options = true; 216 | environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, my_av_info); 217 | 218 | // check whether player 1 and 2's screen placements are swapped 219 | var.key = "tgbdual_audio_output"; 220 | var.value = NULL; 221 | if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) 222 | { 223 | if (!strcmp(var.value, "Game Boy #1")) 224 | audio_2p_mode = 0; 225 | else if (!strcmp(var.value, "Game Boy #2")) 226 | audio_2p_mode = 1; 227 | } 228 | else 229 | _screen_switched = false; 230 | } 231 | 232 | 233 | bool retro_load_game(const struct retro_game_info *info) 234 | { 235 | size_t rom_size; 236 | byte *rom_data; 237 | const struct retro_game_info_ext *info_ext = NULL; 238 | environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_single); 239 | check_variables(); 240 | 241 | unsigned i; 242 | 243 | struct retro_input_descriptor desc[] = { 244 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, 245 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, 246 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, 247 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, 248 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, 249 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, 250 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, 251 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, 252 | 253 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, 254 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, 255 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, 256 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, 257 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, 258 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, 259 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, 260 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, 261 | 262 | { 0 }, 263 | }; 264 | 265 | if (!info) 266 | return false; 267 | 268 | for (i = 0; i < 2; i++) 269 | { 270 | g_gb[i] = NULL; 271 | render[i] = NULL; 272 | } 273 | 274 | environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); 275 | 276 | render[0] = new dmy_renderer(0); 277 | g_gb[0] = new gb(render[0], true, true); 278 | 279 | if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &info_ext) && 280 | info_ext->persistent_data) 281 | { 282 | rom_data = (byte*)info_ext->data; 283 | rom_size = info_ext->size; 284 | libretro_supports_persistent_buffer = true; 285 | } 286 | else 287 | { 288 | rom_data = (byte*)info->data; 289 | rom_size = info->size; 290 | } 291 | 292 | if (!g_gb[0]->load_rom(rom_data, rom_size, NULL, 0, 293 | libretro_supports_persistent_buffer)) 294 | return false; 295 | 296 | for (i = 0; i < 2; i++) 297 | _serialize_size[i] = 0; 298 | 299 | if (gblink_enable) 300 | { 301 | mode = MODE_SINGLE_GAME_DUAL; 302 | environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_dual); 303 | 304 | render[1] = new dmy_renderer(1); 305 | g_gb[1] = new gb(render[1], true, true); 306 | 307 | if (!g_gb[1]->load_rom(rom_data, rom_size, NULL, 0, 308 | libretro_supports_persistent_buffer)) 309 | return false; 310 | 311 | // for link cables and IR: 312 | g_gb[0]->set_target(g_gb[1]); 313 | g_gb[1]->set_target(g_gb[0]); 314 | } 315 | else 316 | mode = MODE_SINGLE_GAME; 317 | 318 | check_variables(); 319 | 320 | return true; 321 | } 322 | 323 | 324 | bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num_info) 325 | { 326 | if (type != RETRO_GAME_TYPE_GAMEBOY_LINK_2P) 327 | return false; /* all other types are unhandled for now */ 328 | 329 | environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_dual); 330 | unsigned i; 331 | 332 | struct retro_input_descriptor desc[] = { 333 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, 334 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, 335 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, 336 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, 337 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, 338 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, 339 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Prev Audio Mode" }, 340 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Next Audio Mode" }, 341 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, 342 | { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, 343 | 344 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, 345 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, 346 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, 347 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, 348 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, 349 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, 350 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Prev Audio Mode" }, 351 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Next Audio Mode" }, 352 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, 353 | { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, 354 | 355 | { 0 }, 356 | }; 357 | 358 | if (!info) 359 | return false; 360 | 361 | for (i = 0; i < 2; i++) 362 | { 363 | g_gb[i] = NULL; 364 | render[i] = NULL; 365 | } 366 | 367 | check_variables(); 368 | 369 | environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); 370 | 371 | render[0] = new dmy_renderer(0); 372 | g_gb[0] = new gb(render[0], true, true); 373 | if (!g_gb[0]->load_rom((byte*)info[0].data, info[0].size, NULL, 0, false)) 374 | return false; 375 | 376 | for (i = 0; i < 2; i++) 377 | _serialize_size[i] = 0; 378 | 379 | if (gblink_enable) 380 | { 381 | render[1] = new dmy_renderer(1); 382 | g_gb[1] = new gb(render[1], true, true); 383 | 384 | if (!g_gb[1]->load_rom((byte*)info[1].data, info[1].size, NULL, 0, 385 | false)) 386 | return false; 387 | 388 | // for link cables and IR: 389 | g_gb[0]->set_target(g_gb[1]); 390 | g_gb[1]->set_target(g_gb[0]); 391 | } 392 | 393 | mode = MODE_DUAL_GAME; 394 | return true; 395 | } 396 | 397 | 398 | void retro_unload_game(void) 399 | { 400 | unsigned i; 401 | for(i = 0; i < 2; ++i) 402 | { 403 | if (g_gb[i]) 404 | { 405 | delete g_gb[i]; 406 | g_gb[i] = NULL; 407 | delete render[i]; 408 | render[i] = NULL; 409 | } 410 | } 411 | libretro_supports_persistent_buffer = false; 412 | } 413 | 414 | void retro_reset(void) 415 | { 416 | for(int i = 0; i < 2; ++i) 417 | { 418 | if (g_gb[i]) 419 | g_gb[i]->reset(); 420 | } 421 | } 422 | 423 | void retro_run(void) 424 | { 425 | bool updated = false; 426 | 427 | if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) 428 | check_variables(); 429 | 430 | input_poll_cb(); 431 | 432 | for (int line = 0;line < 154; line++) 433 | { 434 | if (g_gb[0]) 435 | g_gb[0]->run(); 436 | if (g_gb[1]) 437 | g_gb[1]->run(); 438 | } 439 | } 440 | 441 | 442 | 443 | void *retro_get_memory_data(unsigned id) 444 | { 445 | switch(mode) 446 | { 447 | case MODE_SINGLE_GAME: 448 | case MODE_SINGLE_GAME_DUAL: /* todo: hook this properly */ 449 | { 450 | switch(id) 451 | { 452 | case RETRO_MEMORY_SAVE_RAM: 453 | return g_gb[0]->get_rom()->get_sram(); 454 | case RETRO_MEMORY_RTC: 455 | return &(render[0]->fixed_time); 456 | case RETRO_MEMORY_VIDEO_RAM: 457 | return g_gb[0]->get_cpu()->get_vram(); 458 | case RETRO_MEMORY_SYSTEM_RAM: 459 | return g_gb[0]->get_cpu()->get_ram(); 460 | default: 461 | break; 462 | } 463 | } 464 | case MODE_DUAL_GAME: 465 | { 466 | switch(id) 467 | { 468 | case RETRO_MEMORY_GAMEBOY_1_SRAM: 469 | return g_gb[0]->get_rom()->get_sram(); 470 | case RETRO_MEMORY_GAMEBOY_1_RTC: 471 | return &(render[0]->fixed_time); 472 | case RETRO_MEMORY_GAMEBOY_2_SRAM: 473 | return g_gb[1]->get_rom()->get_sram(); 474 | case RETRO_MEMORY_GAMEBOY_2_RTC: 475 | return &(render[1]->fixed_time); 476 | default: 477 | break; 478 | } 479 | } 480 | } 481 | return NULL; 482 | } 483 | 484 | size_t retro_get_memory_size(unsigned id) 485 | { 486 | switch(mode) 487 | { 488 | case MODE_SINGLE_GAME: 489 | case MODE_SINGLE_GAME_DUAL: /* todo: hook this properly */ 490 | { 491 | switch(id) 492 | { 493 | case RETRO_MEMORY_SAVE_RAM: 494 | return g_gb[0]->get_rom()->get_sram_size(); 495 | case RETRO_MEMORY_RTC: 496 | return sizeof(render[0]->fixed_time); 497 | case RETRO_MEMORY_VIDEO_RAM: 498 | if (g_gb[0]->get_rom()->get_info()->gb_type >= 3) 499 | return 0x2000*2; //sizeof(cpu::vram); 500 | return 0x2000; 501 | case RETRO_MEMORY_SYSTEM_RAM: 502 | if (g_gb[0]->get_rom()->get_info()->gb_type >= 3) 503 | return 0x2000*4; //sizeof(cpu::ram); 504 | return 0x2000; 505 | default: 506 | break; 507 | } 508 | } 509 | case MODE_DUAL_GAME: 510 | { 511 | switch(id) 512 | { 513 | case RETRO_MEMORY_GAMEBOY_1_SRAM: 514 | return g_gb[0]->get_rom()->get_sram_size(); 515 | case RETRO_MEMORY_GAMEBOY_1_RTC: 516 | return sizeof(render[0]->fixed_time); 517 | case RETRO_MEMORY_GAMEBOY_2_SRAM: 518 | return g_gb[1]->get_rom()->get_sram_size(); 519 | case RETRO_MEMORY_GAMEBOY_2_RTC: 520 | return sizeof(render[1]->fixed_time); 521 | default: 522 | break; 523 | } 524 | } 525 | } 526 | return 0; 527 | } 528 | 529 | 530 | 531 | // question: would saving both gb's into the same file be desirable ever? 532 | // answer: yes, it's most likely needed to sync up netplay and for bsv records. 533 | size_t retro_serialize_size(void) 534 | { 535 | if (!(_serialize_size[0] + _serialize_size[1])) 536 | { 537 | unsigned i; 538 | 539 | for(i = 0; i < 2; ++i) 540 | { 541 | if (g_gb[i]) 542 | _serialize_size[i] = g_gb[i]->get_state_size(); 543 | } 544 | } 545 | return _serialize_size[0] + _serialize_size[1]; 546 | } 547 | 548 | bool retro_serialize(void *data, size_t size) 549 | { 550 | if (size == retro_serialize_size()) 551 | { 552 | unsigned i; 553 | uint8_t *ptr = (uint8_t*)data; 554 | 555 | for(i = 0; i < 2; ++i) 556 | { 557 | if (g_gb[i]) 558 | { 559 | g_gb[i]->save_state_mem(ptr); 560 | ptr += _serialize_size[i]; 561 | } 562 | } 563 | 564 | return true; 565 | } 566 | return false; 567 | } 568 | 569 | bool retro_unserialize(const void *data, size_t size) 570 | { 571 | if (size == retro_serialize_size()) 572 | { 573 | unsigned i; 574 | uint8_t *ptr = (uint8_t*)data; 575 | 576 | for(i = 0; i < 2; ++i) 577 | { 578 | if (g_gb[i]) 579 | { 580 | g_gb[i]->restore_state_mem(ptr); 581 | ptr += _serialize_size[i]; 582 | } 583 | } 584 | return true; 585 | } 586 | return false; 587 | } 588 | 589 | 590 | 591 | void retro_cheat_reset(void) 592 | { 593 | for(int i=0; i<2; ++i) 594 | { 595 | if(g_gb[i]) 596 | g_gb[i]->get_cheat()->clear(); 597 | } 598 | } 599 | 600 | void retro_cheat_set(unsigned index, bool enabled, const char *code) 601 | { 602 | #if 1==0 603 | if (log_cb) 604 | log_cb(RETRO_LOG_INFO, "CHEAT: id=%d, enabled=%d, code='%s'\n", index, enabled, code); 605 | // FIXME: work in progress. 606 | // As it stands, it seems TGB Dual only has support for Gameshark codes. 607 | // Unfortunately, the cheat.xml that ships with bsnes seems to only have 608 | // Game Genie codes, which are ROM patches rather than RAM. 609 | // http://nocash.emubase.de/pandocs.htm#gamegeniesharkcheats 610 | if(false && g_gb[0]) 611 | { 612 | cheat_dat cdat; 613 | cheat_dat *tmp=&cdat; 614 | 615 | strncpy(cdat.name, code, sizeof(cdat.name)); 616 | 617 | tmp->enable = true; 618 | tmp->next = NULL; 619 | 620 | while(false) 621 | { // basically, iterate over code.split('+') 622 | // TODO: remove all non-alnum chars here 623 | if (false) 624 | { // if strlen is 9, game genie 625 | // game genie format: for "ABCDEFGHI", 626 | // AB = New data 627 | // FCDE = Memory address, XORed by 0F000h 628 | // GIH = Check data (can be ignored for our purposes) 629 | word scramble; 630 | sscanf(code, "%2hhx%4hx", &tmp->dat, &scramble); 631 | tmp->code = 1; // TODO: test if this is correct for ROM patching 632 | tmp->adr = (((scramble&0xF) << 12) ^ 0xF000) | (scramble >> 4); 633 | } 634 | else if (false) 635 | { // if strlen is 8, gameshark 636 | // gameshark format for "ABCDEFGH", 637 | // AB External RAM bank number 638 | // CD New Data 639 | // GHEF Memory Address (internal or external RAM, A000-DFFF) 640 | byte adrlo, adrhi; 641 | sscanf(code, "%2hhx%2hhx%2hhx%2hhx", &tmp->code, &tmp->dat, &adrlo, &adrhi); 642 | tmp->adr = (adrhi<<8) | adrlo; 643 | } 644 | if(false) 645 | { // if there are more cheats left in the string 646 | tmp->next = new cheat_dat; 647 | tmp = tmp->next; 648 | } 649 | } 650 | } 651 | g_gb[0].get_cheat().add_cheat(&cdat); 652 | #endif 653 | } 654 | 655 | 656 | // start boilerplate 657 | 658 | unsigned retro_api_version(void) { return RETRO_API_VERSION; } 659 | unsigned retro_get_region(void) { return RETRO_REGION_NTSC; } 660 | 661 | void retro_set_controller_port_device(unsigned port, unsigned device) { } 662 | 663 | void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; } 664 | void retro_set_audio_sample(retro_audio_sample_t cb) { } 665 | void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; } 666 | void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; } 667 | void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; } 668 | 669 | 670 | void retro_set_environment(retro_environment_t cb) 671 | { 672 | static const struct retro_system_content_info_override content_overrides[] = { 673 | { 674 | "gb|dmg|gbc|cgb|sgb", /* extensions */ 675 | false, /* need_fullpath */ 676 | true /* persistent_data */ 677 | }, 678 | { NULL, false, false } 679 | }; 680 | environ_cb = cb; 681 | cb(RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO, (void*)subsystems); 682 | /* Request a persistent content data buffer */ 683 | cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE, 684 | (void*)content_overrides); 685 | } 686 | 687 | // end boilerplate 688 | --------------------------------------------------------------------------------