From 85fa3cc968832a6e41d184d208324d89771d3c43 Mon Sep 17 00:00:00 2001 From: byuu Date: Mon, 15 Oct 2007 10:03:36 +0000 Subject: [PATCH] Update to bsnes v025 release. bsnes is exactly three years old today. I've posted a new version which adds DSP-3 and DSP-4 special chip support. The DSP-3 is used by SD Gundam GX, and the DSP-4 is used by Top Gear 3000. Please note that the DSP-3 is not fully emulated, thusly SD Gundam GX is not fully playable. Also, due to lack of timing emulation with the DSP-4, the Top Gear 3000 track sometimes flickers in split screen mode. However, it is believed that Top Gear 3000 is fully playable. I should also note that I have started on SuperFX emulation, as some will inevitably see said code in my source releases. What I have now is nothing more than a skeleton implementation, and absolutely nothing using it is playable yet. I am making absolutely no promises that I will ever be able to emulate this chip. It will take at least several months of work, and even then, the speed will probably be too slow to reach 60fps on any system, but ... I'm working on it. While I have no way to run tests on the actual SuperFX hardware, I will do the best I can to emulate the chip accurately. I will be emulating the caching and cycle delays as best I can, but the information I have on this chip is extremely limited, so don't expect miracles. Lastly, as promised, I have released the special chips I have personally emulated to the public domain. See license.txt for more information if interested. I cannot release the special chips whose code I did not write to the public domain, but all of that is already available under the GPLv2 (from ZSNES) or the SNES9x license. Changelog: - Added DSP-3 support, thanks to John Weidman, Kris Bleakley, Lancer, z80 gaiden - Added DSP-4 support, thanks to Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden - Started on support for SuperFX, no games playable as chip emulation is less than 1% complete - Unsupported special chips will now display an alert - Missing stbios.bin file when loading Sufami Turbo cartridges will now display an alert - Video settings now saved separately for windowed and fullscreen mode - Advanced option video<.mode>.synchronize can be enabled for vsync, but will cause sound crackling - Added menu option to toggle FPS counter - Minor source code cleanup --- cart.db | Bin 3276 -> 3448 bytes license.txt | 37 +- readme.txt | 14 +- src/Makefile | 23 +- src/base.h | 2 +- src/cart/cart.cpp | 35 +- src/cart/cart.h | 21 +- src/cart/cart_file.cpp | 1 + src/cart/cart_header.cpp | 40 +- src/cart/cart_normal.cpp | 10 - src/cart/db/cart.db | Bin 3276 -> 3448 bytes src/cart/db/cartdb.txt | 6 + src/cart/db/dbcreate.cpp | 6 +- src/cc.bat | 1 + src/chip/c4/c4.cpp | 2 - src/chip/c4/c4.h | 2 +- src/chip/dsp1/dsp1.cpp | 2 - src/chip/dsp1/dsp1.h | 2 +- src/chip/dsp2/dsp2.cpp | 2 - src/chip/dsp2/dsp2.h | 5 +- src/chip/dsp3/dsp3.cpp | 33 + src/chip/dsp3/dsp3.h | 11 + src/chip/dsp3/dsp3emu.c | 1142 +++++++++ src/chip/dsp4/dsp4.cpp | 51 + src/chip/dsp4/dsp4.h | 11 + src/chip/dsp4/dsp4emu.c | 2146 +++++++++++++++++ src/chip/dsp4/dsp4emu.h | 108 + src/chip/obc1/obc1.cpp | 2 - src/chip/obc1/obc1.h | 2 +- src/chip/sdd1/sdd1.cpp | 2 - src/chip/sdd1/sdd1.h | 2 +- src/chip/srtc/srtc.cpp | 2 - src/chip/srtc/srtc.h | 2 +- src/chip/st010/st010.cpp | 2 - src/chip/st010/st010.h | 2 +- src/chip/superfx/core/core.h | 3 + src/chip/superfx/core/op0x.cpp | 7 + src/chip/superfx/memory/read.cpp | 64 + src/chip/superfx/memory/write.cpp | 63 + src/chip/superfx/regs.h | 174 ++ src/chip/superfx/superfx.cpp | 42 + src/chip/superfx/superfx.h | 17 + src/clean.bat | 1 + src/cpu/scpu/dma/dma.cpp | 7 +- src/cpu/scpu/scpu.h | 4 +- src/data/bsnes_old.ico | Bin 4286 -> 0 bytes src/data/snes_controller.bmp | Bin 20276 -> 0 bytes src/interface.h | 3 + src/memory/bmemory/bmemory.cpp | 22 +- src/memory/bmemory/bmemory.h | 6 + src/memory/bmemory/bmemory_mapper_generic.cpp | 24 + src/memory/bmemory/bmemory_rw.cpp | 30 +- src/memory/bmemory/mapper/mapper.cpp | 39 +- src/memory/bmemory/mapper/mapper.h | 1 + src/memory/bmemory/mapper/mapper_pcb.cpp | 12 + src/snes/snes.cpp | 86 +- src/ui/bsnes.rc | 6 +- src/ui/config.cpp | 66 +- src/ui/lui/event.cpp | 121 +- src/ui/lui/event.h | 21 +- src/ui/lui/main.cpp | 12 +- src/ui/lui/ui.cpp | 4 +- src/ui/lui/ui_main.cpp | 124 +- src/ui/lui/ui_main.h | 4 +- src/ui/video/d3d.cpp | 8 +- src/ui/video/d3d.h | 2 +- src/ui/video/ddraw.cpp | 2 +- src/ui/video/video.h | 28 +- 68 files changed, 4425 insertions(+), 307 deletions(-) create mode 100644 src/chip/dsp3/dsp3.cpp create mode 100644 src/chip/dsp3/dsp3.h create mode 100644 src/chip/dsp3/dsp3emu.c create mode 100644 src/chip/dsp4/dsp4.cpp create mode 100644 src/chip/dsp4/dsp4.h create mode 100644 src/chip/dsp4/dsp4emu.c create mode 100644 src/chip/dsp4/dsp4emu.h create mode 100644 src/chip/superfx/core/core.h create mode 100644 src/chip/superfx/core/op0x.cpp create mode 100644 src/chip/superfx/memory/read.cpp create mode 100644 src/chip/superfx/memory/write.cpp create mode 100644 src/chip/superfx/regs.h create mode 100644 src/chip/superfx/superfx.cpp create mode 100644 src/chip/superfx/superfx.h delete mode 100644 src/data/bsnes_old.ico delete mode 100644 src/data/snes_controller.bmp diff --git a/cart.db b/cart.db index a489d594f1d3d4ed7658ccd7646303e77a988fd6..bf00dbb0c961d02c6cfa8b55093cd78ec7d670e8 100644 GIT binary patch delta 81 zcmX>j`9o@h0*~&hyED!QmlmWJDflK9W#%h{=NILqC>U8OMCKP~WU3b{coyd*=A|fT lga$imPM*jd!Q&C;tZV4(Wa^}AU^w|BqXbg}!(@4$wE)q48$$p9 delta 11 Scmew%bw+Z70?*_#JZk_R>jdin diff --git a/license.txt b/license.txt index 4b2a6214..e1edb2fb 100644 --- a/license.txt +++ b/license.txt @@ -52,12 +52,35 @@ Further, respective source code files are labeled with their correct licensing information in the header. The lack of such a header indicates said file falls under the bsnes license. -HQ2x Filter, author: MaxST, license: LGPL -JMA, author: NSRT Team, license: GPL (*) -libco, author: byuu, license: public domain -libui, author: byuu, license: public domain -NTSC Filter, author: blargg, license: LGPL -S-DD1, author: Andreas Naive, license: public domain -zlib, license: zlib license +HQ2x filter, author: MaxST, license: LGPL +JMA decompressor, author: NSRT Team, license: GPL (*) +NTSC filter, author: blargg, license: LGPL +zlib decompressor, license: zlib license (*) bsnes has received an exemption from the copyright holder to use this work. + +The software also includes works which have been released to the public domain, +which are not bound to any licensing agreements. Below is a complete list of all +such software. + +libco, author: byuu +libui, author: byuu +OBC-1 emu, author: byuu +S-DD1 emu, author: Andreas Naive +S-RTC emu, author: byuu + +Any software listed above as exemptions may be relicensed individually from +bsnes under their respective terms. However, no bsnes licensed portions can be +combined with such a derivative work. + +The software also includes the work of other copyright holders, which is +licensed under the terms of the bsnes license, with permission to do so from the +respective authors. Below is a complete list of all such software. + +Cx4 emu, authors: anomie, Overload, zsKnight, Nach +DSP-1 emu, authors: Overload, John Weidman, Neviksti, Andreas Naive +DSP-2 emu, author: Overload +DSP-3 emu, authors: John Weidman, Kris Bleakley, Lancer, z80 gaiden +DSP-4 emu, authors: Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden +S-DSP emu, author: blargg +ST-010 emu, authors: John Weidman, Matthew Kendora, Overload, Feather diff --git a/readme.txt b/readme.txt index 400d1c66..c2776a4f 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ bsnes -Version 0.024 +Version 0.025 Author: byuu -------- @@ -17,7 +17,7 @@ Please see license.txt for important licensing information. Shortcut Keys: -------------- Esc - Toggle menubar visibility -F11 - Toggle fullscreen +F11 - Toggle fullscreen mode ------------------ Known Limitations: @@ -66,16 +66,10 @@ Coprocessor used only by the following games: - Momotarou Densetsu Happy - Super Power League 4 -DSP-3 -Coprocessor used only by SD Gundam GX - -DSP-4 -Coprocessor used only by Top Gear 3000 - -ST011 +ST-011 SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita -ST018 +ST-018 SETA RISC CPU used only by Quick-move Shogi Match with Nidan Rank-holder Morita 2 BS-X (Broadcast Satellite) diff --git a/src/Makefile b/src/Makefile index e03daddf..a508645c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -81,7 +81,7 @@ endif ifeq ($(PLATFORM),win-mingw4-lui) OS = win CC = mingw32-gcc-sjlj -CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI +CFLAGS = -mconsole -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI AS = nasm ASFLAGS = -f win32 -DWIN32 LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32 @@ -154,8 +154,8 @@ OBJECTS = main.$(OBJ) $(LIBCO).$(OBJ) $(LIBUI).$(OBJ) \ libstring.$(OBJ) \ reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) bmemory.$(OBJ) \ cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \ - bppu.$(OBJ) snes.$(OBJ) srtc.$(OBJ) sdd1.$(OBJ) c4.$(OBJ) dsp1.$(OBJ) \ - dsp2.$(OBJ) obc1.$(OBJ) st010.$(OBJ) + bppu.$(OBJ) snes.$(OBJ) superfx.$(OBJ) srtc.$(OBJ) sdd1.$(OBJ) c4.$(OBJ) \ + dsp1.$(OBJ) dsp2.$(OBJ) dsp3.$(OBJ) dsp4.$(OBJ) obc1.$(OBJ) st010.$(OBJ) ifeq ($(GZIP_SUPPORT),true) OBJECTS += adler32.$(OBJ) compress.$(OBJ) crc32.$(OBJ) deflate.$(OBJ) \ @@ -259,13 +259,16 @@ snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* sne ##################### ### special chips ### ##################### -srtc.$(OBJ) : chip/srtc/srtc.cpp chip/srtc/* -sdd1.$(OBJ) : chip/sdd1/sdd1.cpp chip/sdd1/* -c4.$(OBJ) : chip/c4/c4.cpp chip/c4/* -dsp1.$(OBJ) : chip/dsp1/dsp1.cpp chip/dsp1/* -dsp2.$(OBJ) : chip/dsp2/dsp2.cpp chip/dsp2/* -obc1.$(OBJ) : chip/obc1/obc1.cpp chip/obc1/* -st010.$(OBJ): chip/st010/st010.cpp chip/st010/* +superfx.$(OBJ): chip/superfx/superfx.cpp chip/superfx/* chip/superfx/core/* chip/superfx/memory/* +srtc.$(OBJ) : chip/srtc/srtc.cpp chip/srtc/* +sdd1.$(OBJ) : chip/sdd1/sdd1.cpp chip/sdd1/* +c4.$(OBJ) : chip/c4/c4.cpp chip/c4/* +dsp1.$(OBJ) : chip/dsp1/dsp1.cpp chip/dsp1/* +dsp2.$(OBJ) : chip/dsp2/dsp2.cpp chip/dsp2/* +dsp3.$(OBJ) : chip/dsp3/dsp3.cpp chip/dsp3/* +dsp4.$(OBJ) : chip/dsp4/dsp4.cpp chip/dsp4/* +obc1.$(OBJ) : chip/obc1/obc1.cpp chip/obc1/* +st010.$(OBJ) : chip/st010/st010.cpp chip/st010/* ############ ### zlib ### diff --git a/src/base.h b/src/base.h index eb814610..6442456e 100644 --- a/src/base.h +++ b/src/base.h @@ -1,4 +1,4 @@ -#define BSNES_VERSION "0.024" +#define BSNES_VERSION "0.025" #define BSNES_TITLE "bsnes v" BSNES_VERSION #define MEMCORE bMemBus diff --git a/src/cart/cart.cpp b/src/cart/cart.cpp index 1d89e054..56202bbb 100644 --- a/src/cart/cart.cpp +++ b/src/cart/cart.cpp @@ -10,18 +10,24 @@ Cartridge cartridge; -void Cartridge::load_begin(uint cart_type) { +void Cartridge::load_begin(CartridgeType cart_type) { if(loaded() == true)return; info.type = cart_type; - info.srtc = false; - info.sdd1 = false; - info.c4 = false; - info.dsp1 = false; - info.dsp2 = false; - info.obc1 = false; - info.st010 = false; + info.superfx = false; + info.sa1 = false; + info.srtc = false; + info.sdd1 = false; + info.c4 = false; + info.dsp1 = false; + info.dsp2 = false; + info.dsp3 = false; + info.dsp4 = false; + info.obc1 = false; + info.st010 = false; + info.st011 = false; + info.st018 = false; info.dsp1_mapper = 0; @@ -30,7 +36,6 @@ void Cartridge::load_begin(uint cart_type) { strcpy(info.name, ""); strcpy(info.pcb, ""); info.region = NTSC; - info.cart_mmio = false; info.rom_size = 0; info.ram_size = 0; @@ -93,15 +98,15 @@ bool Cartridge::load_end() { } switch(info.type) { - case CART_NORMAL: { + case CartridgeNormal: { load_rom_normal(); load_ram_normal(); } break; - case CART_ST: { + case CartridgeSufamiTurbo: { load_rom_st(); load_ram_st(); } break; - case CART_STDUAL: { + case CartridgeSufamiTurboDual: { load_rom_stdual(); load_ram_stdual(); } break; @@ -118,13 +123,13 @@ bool Cartridge::unload() { r_mem->unload_cart(); switch(info.type) { - case CART_NORMAL: { + case CartridgeNormal: { save_ram_normal(); } break; - case CART_ST: { + case CartridgeSufamiTurbo: { save_ram_st(); } break; - case CART_STDUAL: { + case CartridgeSufamiTurboDual: { save_ram_stdual(); } break; } diff --git a/src/cart/cart.h b/src/cart/cart.h index 10d71bd5..3ede2949 100644 --- a/src/cart/cart.h +++ b/src/cart/cart.h @@ -15,10 +15,10 @@ db_item dbi; // -enum { - CART_NORMAL, - CART_ST, - CART_STDUAL, +enum CartridgeType { + CartridgeNormal, + CartridgeSufamiTurbo, + CartridgeSufamiTurboDual, }; bool cart_loaded; @@ -33,7 +33,7 @@ enum { ROM_SIZE = 0x17, RAM_SIZE = 0x18, REGION = 0x19, - LICENSE = 0x1a, + COMPANY = 0x1a, VERSION = 0x1b, ICKSUM = 0x1c, CKSUM = 0x1e, @@ -78,16 +78,19 @@ struct { uint rom_size; uint ram_size; -//set to true for games that need cart MMIO mapping (c4, dsp-n, ...), -//for games that map outside the standard MMIO range of $2000-$5fff - bool cart_mmio; + bool superfx; + bool sa1; bool srtc; bool sdd1; bool c4; bool dsp1; bool dsp2; + bool dsp3; + bool dsp4; bool obc1; bool st010; + bool st011; + bool st018; uint dsp1_mapper; @@ -114,7 +117,7 @@ struct { void read_header(); bool loaded() { return cart_loaded; } - void load_begin(uint cart_type); + void load_begin(CartridgeType cart_type); void load(const char *rom_fn); bool load_end(); bool unload(); diff --git a/src/cart/cart_file.cpp b/src/cart/cart_file.cpp index 7c7aa5f1..3dc8b1cb 100644 --- a/src/cart/cart_file.cpp +++ b/src/cart/cart_file.cpp @@ -13,6 +13,7 @@ bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { dprintf("* Loading \"%s\"...", fn); if(fexists(fn) == false) { + alert("Error: file '%s' not found!", fn); return false; } diff --git a/src/cart/cart_header.cpp b/src/cart/cart_header.cpp index 32a72b4f..1a93f594 100644 --- a/src/cart/cart_header.cpp +++ b/src/cart/cart_header.cpp @@ -1,13 +1,4 @@ void Cartridge::read_header() { - info.srtc = false; - info.sdd1 = false; - info.c4 = false; - info.dsp1 = false; - info.dsp2 = false; - info.obc1 = false; - - info.dsp1_mapper = 0; - if(info.header_index == 0x7fc0 && info.rom_size >= 0x401000) { info.mapper = EXLOROM; strcpy(info.pcb, "UNL-EXLOROM"); @@ -27,6 +18,16 @@ void Cartridge::read_header() { uint8 mapper = rom[info.header_index + MAPPER]; uint8 rom_type = rom[info.header_index + ROM_TYPE]; +uint8 company = rom[info.header_index + COMPANY]; + + if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { + info.superfx = true; + } + + if(mapper == 0x23 && (rom_type == 0x34 || rom_type == 0x35)) { + info.sa1 = true; + } + if(mapper == 0x35 && rom_type == 0x55) { info.srtc = true; } @@ -43,7 +44,7 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE]; info.dsp1 = true; } - if(mapper == 0x30 && rom_type == 0x05) { + if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) { info.dsp1 = true; } @@ -65,15 +66,28 @@ uint8 rom_type = rom[info.header_index + ROM_TYPE]; info.dsp2 = true; } + if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) { + info.dsp3 = true; + } + + if(mapper == 0x30 && rom_type == 0x03) { + info.dsp4 = true; + } + if(mapper == 0x30 && rom_type == 0x25) { info.obc1 = true; } if(mapper == 0x30 && rom_type == 0xf6) { + //TODO: both ST010 and ST011 share the same mapper + rom_type + //need way to determine which is which + //for now, default to supported ST010 info.st010 = true; } - info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1; + if(mapper == 0x30 && rom_type == 0xf5) { + info.st018 = true; + } if(rom[info.header_index + RAM_SIZE] & 7) { info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7); @@ -117,8 +131,8 @@ int32 score_lo = 0, if(rom[0x7fc0 + REGION] < 14)score_lo++; if(rom[0xffc0 + REGION] < 14)score_hi++; - if(rom[0x7fc0 + LICENSE] < 3)score_lo++; - if(rom[0xffc0 + LICENSE] < 3)score_hi++; + if(rom[0x7fc0 + COMPANY] < 3)score_lo++; + if(rom[0xffc0 + COMPANY] < 3)score_hi++; if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2; if(rom[0xffc0 + RESH] & 0x80)score_hi += 2; diff --git a/src/cart/cart_normal.cpp b/src/cart/cart_normal.cpp index fad95cb6..bf648908 100644 --- a/src/cart/cart_normal.cpp +++ b/src/cart/cart_normal.cpp @@ -20,21 +20,11 @@ uint offset = 0; info.crc32 = crc32_calculate(rom, info.rom_size); if(read_database() == true) { - info.srtc = false; - info.sdd1 = false; - info.c4 = false; - info.dsp1 = false; - info.dsp2 = false; - info.obc1 = false; - - info.dsp1_mapper = 0; - info.header_index = 0xffc0; info.mapper = PCB; strcpy(info.name, dbi.name); strcpy(info.pcb, dbi.pcb); info.region = NTSC; - info.cart_mmio = false; info.rom_size = dbi.rom; info.ram_size = dbi.ram; diff --git a/src/cart/db/cart.db b/src/cart/db/cart.db index a489d594f1d3d4ed7658ccd7646303e77a988fd6..bf00dbb0c961d02c6cfa8b55093cd78ec7d670e8 100644 GIT binary patch delta 81 zcmX>j`9o@h0*~&hyED!QmlmWJDflK9W#%h{=NILqC>U8OMCKP~WU3b{coyd*=A|fT lga$imPM*jd!Q&C;tZV4(Wa^}AU^w|BqXbg}!(@4$wE)q48$$p9 delta 11 Scmew%bw+Z70?*_#JZk_R>jdin diff --git a/src/cart/db/cartdb.txt b/src/cart/db/cartdb.txt index 668aadb1..8784e144 100644 --- a/src/cart/db/cartdb.txt +++ b/src/cart/db/cartdb.txt @@ -106,6 +106,12 @@ pcb = "BSC-1A7M-10" rom = 24mbit ram = 512kbit +[0xcf98ddaa] +name = "Super Mario World 2: Yoshi's Island (USA)" +pcb = "SHVC-1CB5B-01" +rom = 16mbit +ram = 256kbit + [0x64a91e64] name = "Wanderers from Ys (USA) [!]" pcb = "SHVC-1A3B-12" diff --git a/src/cart/db/dbcreate.cpp b/src/cart/db/dbcreate.cpp index 2ad529c5..deae0735 100644 --- a/src/cart/db/dbcreate.cpp +++ b/src/cart/db/dbcreate.cpp @@ -53,9 +53,9 @@ db_item dbi; dbi.ram = 0; for(int i = 1; i < count(line); i++) { - uint pos; - if(strpos(line[i], ";", pos) == true) { - strset(line[i], pos, 0); + int pos = strpos(line[i], ";"); + if(pos >= 0) { + strptr(line[i])[pos] = 0; } if(line[i] == "")continue; diff --git a/src/cc.bat b/src/cc.bat index 6e98adc1..2d9e2827 100644 --- a/src/cc.bat +++ b/src/cc.bat @@ -1,3 +1,4 @@ +::@make -r PLATFORM=win-mingw4-lui ::@make -r PLATFORM=win-visualc-lui @make -r PLATFORM=win-visualc-lui GZIP_SUPPORT=true JMA_SUPPORT=true @move bsnes.exe ../bsnes.exe>nul diff --git a/src/chip/c4/c4.cpp b/src/chip/c4/c4.cpp index 4ae0391b..d979fbf1 100644 --- a/src/chip/c4/c4.cpp +++ b/src/chip/c4/c4.cpp @@ -7,8 +7,6 @@ #include "../../base.h" -C4 *c4; - #include "c4data.cpp" #include "c4fn.cpp" #include "c4oam.cpp" diff --git a/src/chip/c4/c4.h b/src/chip/c4/c4.h index 74144553..95197c1e 100644 --- a/src/chip/c4/c4.h +++ b/src/chip/c4/c4.h @@ -93,4 +93,4 @@ public: C4(); }; -extern C4 *c4; +extern C4 c4; diff --git a/src/chip/dsp1/dsp1.cpp b/src/chip/dsp1/dsp1.cpp index f8bbb748..b9683c2a 100644 --- a/src/chip/dsp1/dsp1.cpp +++ b/src/chip/dsp1/dsp1.cpp @@ -1,7 +1,5 @@ #include "../../base.h" -DSP1 *dsp1; - #include "dsp1emu.cpp" void DSP1::init() {} diff --git a/src/chip/dsp1/dsp1.h b/src/chip/dsp1/dsp1.h index aa4f7b98..a91f14a0 100644 --- a/src/chip/dsp1/dsp1.h +++ b/src/chip/dsp1/dsp1.h @@ -15,4 +15,4 @@ public: void write(uint16 addr, uint8 data); }; -extern DSP1 *dsp1; +extern DSP1 dsp1; diff --git a/src/chip/dsp2/dsp2.cpp b/src/chip/dsp2/dsp2.cpp index b732a11c..be550fa5 100644 --- a/src/chip/dsp2/dsp2.cpp +++ b/src/chip/dsp2/dsp2.cpp @@ -1,7 +1,5 @@ #include "../../base.h" -DSP2 *dsp2; - #include "dsp2_op.cpp" void DSP2::init() {} diff --git a/src/chip/dsp2/dsp2.h b/src/chip/dsp2/dsp2.h index e0274e2d..d6462b85 100644 --- a/src/chip/dsp2/dsp2.h +++ b/src/chip/dsp2/dsp2.h @@ -1,5 +1,4 @@ -class DSP2 { -public: +class DSP2 { public: struct { bool waiting_for_command; uint command; @@ -40,4 +39,4 @@ struct { ~DSP2(); }; -extern DSP2 *dsp2; +extern DSP2 dsp2; diff --git a/src/chip/dsp3/dsp3.cpp b/src/chip/dsp3/dsp3.cpp new file mode 100644 index 00000000..128ffba5 --- /dev/null +++ b/src/chip/dsp3/dsp3.cpp @@ -0,0 +1,33 @@ +#include "../../base.h" + +namespace DSP3i { + #define bool8 bool + #include "dsp3emu.c" + #undef bool8 +}; + +void DSP3::init() { +} + +void DSP3::enable() { +} + +void DSP3::power() { + reset(); +} + +void DSP3::reset() { + DSP3i::DSP3_Reset(); +} + +uint8 DSP3::read(uint16 addr) { + DSP3i::dsp3_address = addr; + DSP3i::DSP3GetByte(); + return DSP3i::dsp3_byte; +} + +void DSP3::write(uint16 addr, uint8 data) { + DSP3i::dsp3_address = addr; + DSP3i::dsp3_byte = data; + DSP3i::DSP3SetByte(); +} diff --git a/src/chip/dsp3/dsp3.h b/src/chip/dsp3/dsp3.h new file mode 100644 index 00000000..83c368e7 --- /dev/null +++ b/src/chip/dsp3/dsp3.h @@ -0,0 +1,11 @@ +class DSP3 { public: + void init(); + void enable(); + void power(); + void reset(); + + uint8 read (uint16 addr); + void write(uint16 addr, uint8 data); +}; + +extern DSP3 dsp3; diff --git a/src/chip/dsp3/dsp3emu.c b/src/chip/dsp3/dsp3emu.c new file mode 100644 index 00000000..ab557718 --- /dev/null +++ b/src/chip/dsp3/dsp3emu.c @@ -0,0 +1,1142 @@ +//DSP-3 emulator code +//Copyright (c) 2003-2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden + +uint16 DSP3_DataROM[1024] = { + 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100, + 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001, + 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, + 0x0000, 0x000f, 0x0400, 0x0200, 0x0140, 0x0400, 0x0200, 0x0040, + 0x007d, 0x007e, 0x007e, 0x007b, 0x007c, 0x007d, 0x007b, 0x007c, + 0x0002, 0x0020, 0x0030, 0x0000, 0x000d, 0x0019, 0x0026, 0x0032, + 0x003e, 0x004a, 0x0056, 0x0062, 0x006d, 0x0079, 0x0084, 0x008e, + 0x0098, 0x00a2, 0x00ac, 0x00b5, 0x00be, 0x00c6, 0x00ce, 0x00d5, + 0x00dc, 0x00e2, 0x00e7, 0x00ec, 0x00f1, 0x00f5, 0x00f8, 0x00fb, + 0x00fd, 0x00ff, 0x0100, 0x0100, 0x0100, 0x00ff, 0x00fd, 0x00fb, + 0x00f8, 0x00f5, 0x00f1, 0x00ed, 0x00e7, 0x00e2, 0x00dc, 0x00d5, + 0x00ce, 0x00c6, 0x00be, 0x00b5, 0x00ac, 0x00a2, 0x0099, 0x008e, + 0x0084, 0x0079, 0x006e, 0x0062, 0x0056, 0x004a, 0x003e, 0x0032, + 0x0026, 0x0019, 0x000d, 0x0000, 0xfff3, 0xffe7, 0xffdb, 0xffce, + 0xffc2, 0xffb6, 0xffaa, 0xff9e, 0xff93, 0xff87, 0xff7d, 0xff72, + 0xff68, 0xff5e, 0xff54, 0xff4b, 0xff42, 0xff3a, 0xff32, 0xff2b, + 0xff25, 0xff1e, 0xff19, 0xff14, 0xff0f, 0xff0b, 0xff08, 0xff05, + 0xff03, 0xff01, 0xff00, 0xff00, 0xff00, 0xff01, 0xff03, 0xff05, + 0xff08, 0xff0b, 0xff0f, 0xff13, 0xff18, 0xff1e, 0xff24, 0xff2b, + 0xff32, 0xff3a, 0xff42, 0xff4b, 0xff54, 0xff5d, 0xff67, 0xff72, + 0xff7c, 0xff87, 0xff92, 0xff9e, 0xffa9, 0xffb5, 0xffc2, 0xffce, + 0xffda, 0xffe7, 0xfff3, 0x002b, 0x007f, 0x0020, 0x00ff, 0xff00, + 0xffbe, 0x0000, 0x0044, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffc1, 0x0001, 0x0002, 0x0045, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc5, 0x0003, 0x0004, 0x0005, 0x0047, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffca, 0x0006, 0x0007, 0x0008, + 0x0009, 0x004a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffd0, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x004e, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd7, 0x000f, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0x0053, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffdf, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, + 0x0059, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffe8, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0060, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xfff2, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, + 0x002b, 0x002c, 0x0068, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfffd, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0071, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc7, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, + 0x003e, 0x003f, 0x0040, 0x0041, 0x007b, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd4, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0x0044, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffe2, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, + 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0050, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfff1, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x005d, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffcb, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, + 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x006b, 0x0000, 0x0000, 0x0000, 0xffdc, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0044, 0x0000, 0x0000, + 0xffee, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, + 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0x0054, 0x0000, 0xffee, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0065, + 0xffbe, 0x0000, 0xfeac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffc1, 0x0001, 0x0002, 0xfead, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc5, 0x0003, 0x0004, 0x0005, 0xfeaf, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffca, 0x0006, 0x0007, 0x0008, + 0x0009, 0xfeb2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffd0, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0xfeb6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd7, 0x000f, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0xfebb, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffdf, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, + 0xfec1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffe8, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0xfec8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xfff2, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, + 0x002b, 0x002c, 0xfed0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfffd, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0xfed9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc7, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, + 0x003e, 0x003f, 0x0040, 0x0041, 0xfee3, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd4, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0xfeac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffe2, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, + 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0xfeb8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfff1, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0xfec5, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffcb, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, + 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0xfed3, 0x0000, 0x0000, 0x0000, 0xffdc, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0xfeac, 0x0000, 0x0000, + 0xffee, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, + 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0xfebc, 0x0000, 0xffee, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0xfecd, + 0x0154, 0x0218, 0x0110, 0x00b0, 0x00cc, 0x00b0, 0x0088, 0x00b0, + 0x0044, 0x00b0, 0x0000, 0x00b0, 0x00fe, 0xff07, 0x0002, 0x00ff, + 0x00f8, 0x0007, 0x00fe, 0x00ee, 0x07ff, 0x0200, 0x00ef, 0xf800, + 0x0700, 0x00ee, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, + 0xffff, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, + 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0x0001, 0x0000, 0x0001, + 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, + 0xffff, 0x0001, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, + 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0044, 0x0088, 0x00cc, + 0x0110, 0x0154, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + +void (*SetDSP3)(); +void DSP3_Command(); + +uint16 DSP3_DR; +uint16 DSP3_SR; +uint16 DSP3_MemoryIndex; + +void DSP3_Reset() +{ + DSP3_DR = 0x0080; + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_Command; +} + +void DSP3_MemorySize() +{ + DSP3_DR = 0x0300; + SetDSP3 = &DSP3_Reset; +} + +void DSP3_TestMemory() +{ + DSP3_DR = 0x0000; + SetDSP3 = &DSP3_Reset; +} + +void DSP3_DumpDataROM() +{ + DSP3_DR = DSP3_DataROM[DSP3_MemoryIndex++]; + if (DSP3_MemoryIndex == 1024) + SetDSP3 = &DSP3_Reset; +} + +void DSP3_MemoryDump() +{ + DSP3_MemoryIndex = 0; + SetDSP3 = &DSP3_DumpDataROM; + DSP3_DumpDataROM(); +} + +int16 DSP3_WinLo; +int16 DSP3_WinHi; + +void DSP3_OP06() +{ + DSP3_WinLo = (uint8)(DSP3_DR); + DSP3_WinHi = (uint8)(DSP3_DR >> 8); + DSP3_Reset(); +} + +void DSP3_OP03() +{ + int16 Lo = (uint8)(DSP3_DR); + int16 Hi = (uint8)(DSP3_DR >> 8); + int16 Ofs = (DSP3_WinLo * Hi << 1) + (Lo << 1); + DSP3_DR = Ofs >> 1; + SetDSP3 = &DSP3_Reset; +} + +int16 DSP3_AddLo; +int16 DSP3_AddHi; + +void DSP3_OP07_B() +{ + int16 Ofs = (DSP3_WinLo * DSP3_AddHi << 1) + (DSP3_AddLo << 1); + DSP3_DR = Ofs >> 1; + SetDSP3 = &DSP3_Reset; +} + +void DSP3_OP07_A() +{ + int16 Lo = (uint8)(DSP3_DR); + int16 Hi = (uint8)(DSP3_DR >> 8); + + if (Lo & 1) Hi += (DSP3_AddLo & 1); + + DSP3_AddLo += Lo; + DSP3_AddHi += Hi; + + if (DSP3_AddLo < 0) + DSP3_AddLo += DSP3_WinLo; + else + if (DSP3_AddLo >= DSP3_WinLo) + DSP3_AddLo -= DSP3_WinLo; + + if (DSP3_AddHi < 0) + DSP3_AddHi += DSP3_WinHi; + else + if (DSP3_AddHi >= DSP3_WinHi) + DSP3_AddHi -= DSP3_WinHi; + + DSP3_DR = DSP3_AddLo | (DSP3_AddHi << 8) | ((DSP3_AddHi >> 8) & 0xff); + SetDSP3 = &DSP3_OP07_B; +} + +void DSP3_OP07() +{ + uint32 dataOfs = ((DSP3_DR << 1) + 0x03b2) & 0x03ff; + + DSP3_AddHi = DSP3_DataROM[dataOfs]; + DSP3_AddLo = DSP3_DataROM[dataOfs + 1]; + + SetDSP3 = &DSP3_OP07_A; + DSP3_SR = 0x0080; +} + +uint16 DSP3_Codewords; +uint16 DSP3_Outwords; +uint16 DSP3_Symbol; +uint16 DSP3_BitCount; +uint16 DSP3_Index; +uint16 DSP3_Codes[512]; +uint16 DSP3_BitsLeft; +uint16 DSP3_ReqBits; +uint16 DSP3_ReqData; +uint16 DSP3_BitCommand; +uint8 DSP3_BaseLength; +uint16 DSP3_BaseCodes; +uint16 DSP3_BaseCode; +uint8 DSP3_CodeLengths[8]; +uint16 DSP3_CodeOffsets[8]; +uint16 DSP3_LZCode; +uint8 DSP3_LZLength; + +uint16 DSP3_X; +uint16 DSP3_Y; + +void DSP3_Coordinate() +{ + DSP3_Index++; + + switch (DSP3_Index) + { + case 3: + { + if (DSP3_DR == 0xffff) + DSP3_Reset(); + break; + } + case 4: + { + DSP3_X = DSP3_DR; + break; + } + case 5: + { + DSP3_Y = DSP3_DR; + DSP3_DR = 1; + break; + } + case 6: + { + DSP3_DR = DSP3_X; + break; + } + case 7: + { + DSP3_DR = DSP3_Y; + DSP3_Index = 0; + break; + } + } +} + +uint8 DSP3_Bitmap[8]; +uint8 DSP3_Bitplane[8]; +uint16 DSP3_BMIndex; +uint16 DSP3_BPIndex; +uint16 DSP3_Count; + +void DSP3_Convert_A() +{ + if (DSP3_BMIndex < 8) + { + DSP3_Bitmap[DSP3_BMIndex++] = (uint8) (DSP3_DR); + DSP3_Bitmap[DSP3_BMIndex++] = (uint8) (DSP3_DR >> 8); + + if (DSP3_BMIndex == 8) + { + short i, j; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + { + DSP3_Bitplane[j] <<= 1; + DSP3_Bitplane[j] |= (DSP3_Bitmap[i] >> j) & 1; + } + + DSP3_BPIndex = 0; + DSP3_Count--; + } + } + + if (DSP3_BMIndex == 8) + { + if (DSP3_BPIndex == 8) + { + if (!DSP3_Count) DSP3_Reset(); + DSP3_BMIndex = 0; + } + else + { + DSP3_DR = DSP3_Bitplane[DSP3_BPIndex++]; + DSP3_DR |= DSP3_Bitplane[DSP3_BPIndex++] << 8; + } + } +} + +void DSP3_Convert() +{ + DSP3_Count = DSP3_DR; + DSP3_BMIndex = 0; + SetDSP3 = &DSP3_Convert_A; +} + +bool DSP3_GetBits(uint8 Count) +{ + if (!DSP3_BitsLeft) + { + DSP3_BitsLeft = Count; + DSP3_ReqBits = 0; + } + + do { + if (!DSP3_BitCount) + { + DSP3_SR = 0xC0; + return false; + } + + DSP3_ReqBits <<= 1; + if (DSP3_ReqData & 0x8000) DSP3_ReqBits++; + DSP3_ReqData <<= 1; + + DSP3_BitCount--; + DSP3_BitsLeft--; + + } while (DSP3_BitsLeft); + + return true; +} + +void DSP3_Decode_Data() +{ + if (!DSP3_BitCount) + { + if (DSP3_SR & 0x40) + { + DSP3_ReqData = DSP3_DR; + DSP3_BitCount += 16; + } + else + { + DSP3_SR = 0xC0; + return; + } + } + + if (DSP3_LZCode == 1) + { + if (!DSP3_GetBits(1)) + return; + + if (DSP3_ReqBits) + DSP3_LZLength = 12; + else + DSP3_LZLength = 8; + + DSP3_LZCode++; + } + + if (DSP3_LZCode == 2) + { + if (!DSP3_GetBits(DSP3_LZLength)) + return; + + DSP3_LZCode = 0; + DSP3_Outwords--; + if (!DSP3_Outwords) SetDSP3 = &DSP3_Reset; + + DSP3_SR = 0x80; + DSP3_DR = DSP3_ReqBits; + return; + } + + if (DSP3_BaseCode == 0xffff) + { + if (!DSP3_GetBits(DSP3_BaseLength)) + return; + + DSP3_BaseCode = DSP3_ReqBits; + } + + if (!DSP3_GetBits(DSP3_CodeLengths[DSP3_BaseCode])) + return; + + DSP3_Symbol = DSP3_Codes[DSP3_CodeOffsets[DSP3_BaseCode] + DSP3_ReqBits]; + DSP3_BaseCode = 0xffff; + + if (DSP3_Symbol & 0xff00) + { + DSP3_Symbol += 0x7f02; + DSP3_LZCode++; + } + else + { + DSP3_Outwords--; + if (!DSP3_Outwords) + SetDSP3 = &DSP3_Reset; + } + + DSP3_SR = 0x80; + DSP3_DR = DSP3_Symbol; +} + +void DSP3_Decode_Tree() +{ + if (!DSP3_BitCount) + { + DSP3_ReqData = DSP3_DR; + DSP3_BitCount += 16; + } + + if (!DSP3_BaseCodes) + { + DSP3_GetBits(1); + if (DSP3_ReqBits) + { + DSP3_BaseLength = 3; + DSP3_BaseCodes = 8; + } + else + { + DSP3_BaseLength = 2; + DSP3_BaseCodes = 4; + } + } + + while (DSP3_BaseCodes) + { + if (!DSP3_GetBits(3)) + return; + + DSP3_ReqBits++; + + DSP3_CodeLengths[DSP3_Index] = (uint8) DSP3_ReqBits; + DSP3_CodeOffsets[DSP3_Index] = DSP3_Symbol; + DSP3_Index++; + + DSP3_Symbol += 1 << DSP3_ReqBits; + DSP3_BaseCodes--; + } + + DSP3_BaseCode = 0xffff; + DSP3_LZCode = 0; + + SetDSP3 = &DSP3_Decode_Data; + if (DSP3_BitCount) DSP3_Decode_Data(); +} + +void DSP3_Decode_Symbols() +{ + DSP3_ReqData = DSP3_DR; + DSP3_BitCount += 16; + + do { + + if (DSP3_BitCommand == 0xffff) + { + if (!DSP3_GetBits(2)) return; + DSP3_BitCommand = DSP3_ReqBits; + } + + switch (DSP3_BitCommand) + { + case 0: + { + if (!DSP3_GetBits(9)) return; + DSP3_Symbol = DSP3_ReqBits; + break; + } + case 1: + { + DSP3_Symbol++; + break; + } + case 2: + { + if (!DSP3_GetBits(1)) return; + DSP3_Symbol += 2 + DSP3_ReqBits; + break; + } + case 3: + { + if (!DSP3_GetBits(4)) return; + DSP3_Symbol += 4 + DSP3_ReqBits; + break; + } + } + + DSP3_BitCommand = 0xffff; + + DSP3_Codes[DSP3_Index++] = DSP3_Symbol; + DSP3_Codewords--; + + } while (DSP3_Codewords); + + DSP3_Index = 0; + DSP3_Symbol = 0; + DSP3_BaseCodes = 0; + + SetDSP3 = &DSP3_Decode_Tree; + if (DSP3_BitCount) DSP3_Decode_Tree(); +} + +void DSP3_Decode_A() +{ + DSP3_Outwords = DSP3_DR; + SetDSP3 = &DSP3_Decode_Symbols; + DSP3_BitCount = 0; + DSP3_BitsLeft = 0; + DSP3_Symbol = 0; + DSP3_Index = 0; + DSP3_BitCommand = 0xffff; + DSP3_SR = 0xC0; +} + +void DSP3_Decode() +{ + DSP3_Codewords = DSP3_DR; + SetDSP3 = &DSP3_Decode_A; +} + + +// Opcodes 1E/3E bit-perfect to 'dsp3-intro' log +// src: adapted from SD Gundam X/G-Next + +int16 op3e_x; +int16 op3e_y; + +int16 op1e_terrain[0x2000]; +int16 op1e_cost[0x2000]; +int16 op1e_weight[0x2000]; + +int16 op1e_cell; +int16 op1e_turn; +int16 op1e_search; + +int16 op1e_x; +int16 op1e_y; + +int16 op1e_min_radius; +int16 op1e_max_radius; + +int16 op1e_max_search_radius; +int16 op1e_max_path_radius; + +int16 op1e_lcv_radius; +int16 op1e_lcv_steps; +int16 op1e_lcv_turns; + +void DSP3_OP3E() +{ + op3e_x = (uint8)(DSP3_DR & 0x00ff); + op3e_y = (uint8)((DSP3_DR & 0xff00)>>8); + + DSP3_OP03(); + + op1e_terrain[ DSP3_DR ] = 0x00; + op1e_cost[ DSP3_DR ] = 0xff; + op1e_weight[ DSP3_DR ] = 0; + + op1e_max_search_radius = 0; + op1e_max_path_radius = 0; +} + +void DSP3_OP1E_A(); +void DSP3_OP1E_A1(); +void DSP3_OP1E_A2(); +void DSP3_OP1E_A3(); + +void DSP3_OP1E_B(); +void DSP3_OP1E_B1(); +void DSP3_OP1E_B2(); + +void DSP3_OP1E_C(); +void DSP3_OP1E_C1(); +void DSP3_OP1E_C2(); + +void DSP3_OP1E_D( int16, int16 *, int16 * ); +void DSP3_OP1E_D1( int16 move, int16 *lo, int16 *hi ); + +void DSP3_OP1E() +{ + int lcv; + + op1e_min_radius = (uint8)(DSP3_DR & 0x00ff); + op1e_max_radius = (uint8)((DSP3_DR & 0xff00)>>8); + + if( op1e_min_radius == 0 ) + op1e_min_radius++; + + if( op1e_max_search_radius >= op1e_min_radius ) + op1e_min_radius = op1e_max_search_radius+1; + + if( op1e_max_radius > op1e_max_search_radius ) + op1e_max_search_radius = op1e_max_radius; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_lcv_turns = 6; + op1e_turn = 0; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + + DSP3_OP1E_A(); +} + +void DSP3_OP1E_A() +{ + int lcv; + + if( op1e_lcv_steps == 0 ) { + op1e_lcv_radius++; + + op1e_lcv_steps = op1e_lcv_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_lcv_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_radius > op1e_max_radius ) { + op1e_turn++; + op1e_lcv_turns--; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_turns == 0 ) { + DSP3_DR = 0xffff; + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_OP1E_B; + return; + } + + DSP3_DR = (uint8)(op1e_x) | ((uint8)(op1e_y)<<8); + DSP3_OP03(); + + op1e_cell = DSP3_DR; + + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_OP1E_A1; +} + +void DSP3_OP1E_A1() +{ + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_OP1E_A2; +} + +void DSP3_OP1E_A2() +{ + op1e_terrain[ op1e_cell ] = (uint8)(DSP3_DR & 0x00ff); + + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_OP1E_A3; +} + +void DSP3_OP1E_A3() +{ + op1e_cost[ op1e_cell ] = (uint8)(DSP3_DR & 0x00ff); + + if( op1e_lcv_radius == 1 ) { + if( op1e_terrain[ op1e_cell ] & 1 ) { + op1e_weight[ op1e_cell ] = 0xff; + } else { + op1e_weight[ op1e_cell ] = op1e_cost[ op1e_cell ]; + } + } + else { + op1e_weight[ op1e_cell ] = 0xff; + } + + DSP3_OP1E_D( (int16)(op1e_turn+2), &op1e_x, &op1e_y ); + op1e_lcv_steps--; + + DSP3_SR = 0x0080; + DSP3_OP1E_A(); +} + + +void DSP3_OP1E_B() +{ + op1e_x = op3e_x; + op1e_y = op3e_y; + op1e_lcv_radius = 1; + + op1e_search = 0; + + DSP3_OP1E_B1(); + + SetDSP3 = &DSP3_OP1E_C; +} + + +void DSP3_OP1E_B1() +{ + while( op1e_lcv_radius < op1e_max_radius ) { + op1e_y--; + + op1e_lcv_turns = 6; + op1e_turn = 5; + + while( op1e_lcv_turns ) { + op1e_lcv_steps = op1e_lcv_radius; + + while( op1e_lcv_steps ) { + DSP3_OP1E_D1( op1e_turn, &op1e_x, &op1e_y ); + + if( 0 <= op1e_y && op1e_y < DSP3_WinHi && + 0 <= op1e_x && op1e_x < DSP3_WinLo ) { + DSP3_DR = (uint8)(op1e_x) | ((uint8)(op1e_y)<<8); + DSP3_OP03(); + + op1e_cell = DSP3_DR; + if( op1e_cost[ op1e_cell ] < 0x80 && + op1e_terrain[ op1e_cell ] < 0x40 ) { + DSP3_OP1E_B2(); + } // end cell perimeter + } + + op1e_lcv_steps--; + } // end search line + + op1e_turn--; + if( op1e_turn == 0 ) op1e_turn = 6; + + op1e_lcv_turns--; + } // end circle search + + op1e_lcv_radius++; + } // end radius search +} + + +void DSP3_OP1E_B2() +{ + int16 cell; + int16 path; + int16 x,y; + int16 lcv_turns; + + path = 0xff; + lcv_turns = 6; + + while( lcv_turns ) { + x = op1e_x; + y = op1e_y; + + DSP3_OP1E_D1( lcv_turns, &x, &y ); + + DSP3_DR = (uint8)(x) | ((uint8)(y)<<8); + DSP3_OP03(); + + cell = DSP3_DR; + + if( 0 <= y && y < DSP3_WinHi && + 0 <= x && x < DSP3_WinLo ) { + + if( op1e_terrain[ cell ] < 0x80 || op1e_weight[ cell ] == 0 ) { + if( op1e_weight[ cell ] < path ) { + path = op1e_weight[ cell ]; + } + } + } // end step travel + + lcv_turns--; + } // end while turns + + if( path != 0xff ) { + op1e_weight[ op1e_cell ] = path + op1e_cost[ op1e_cell ]; + } +} + + +void DSP3_OP1E_C() +{ + int lcv; + + op1e_min_radius = (uint8)(DSP3_DR & 0x00ff); + op1e_max_radius = (uint8)((DSP3_DR & 0xff00)>>8); + + if( op1e_min_radius == 0 ) + op1e_min_radius++; + + if( op1e_max_path_radius >= op1e_min_radius ) + op1e_min_radius = op1e_max_path_radius+1; + + if( op1e_max_radius > op1e_max_path_radius ) + op1e_max_path_radius = op1e_max_radius; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_lcv_turns = 6; + op1e_turn = 0; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + + DSP3_OP1E_C1(); +} + + +void DSP3_OP1E_C1() +{ + int lcv; + + if( op1e_lcv_steps == 0 ) { + op1e_lcv_radius++; + + op1e_lcv_steps = op1e_lcv_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_lcv_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_radius > op1e_max_radius ) { + op1e_turn++; + op1e_lcv_turns--; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_turns == 0 ) { + DSP3_DR = 0xffff; + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_Reset; + return; + } + + DSP3_DR = (uint8)(op1e_x) | ((uint8)(op1e_y)<<8); + DSP3_OP03(); + + op1e_cell = DSP3_DR; + + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_OP1E_C2; +} + + +void DSP3_OP1E_C2() +{ + DSP3_DR = op1e_weight[ op1e_cell ]; + + DSP3_OP1E_D( (int16)(op1e_turn+2), &op1e_x, &op1e_y ); + op1e_lcv_steps--; + + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_OP1E_C1; +} + + +void DSP3_OP1E_D( int16 move, int16 *lo, int16 *hi ) +{ + uint32 dataOfs = ((move << 1) + 0x03b2) & 0x03ff; + int16 Lo; + int16 Hi; + + DSP3_AddHi = DSP3_DataROM[dataOfs]; + DSP3_AddLo = DSP3_DataROM[dataOfs + 1]; + + Lo = (uint8)(*lo); + Hi = (uint8)(*hi); + + if (Lo & 1) Hi += (DSP3_AddLo & 1); + + DSP3_AddLo += Lo; + DSP3_AddHi += Hi; + + if (DSP3_AddLo < 0) + DSP3_AddLo += DSP3_WinLo; + else + if (DSP3_AddLo >= DSP3_WinLo) + DSP3_AddLo -= DSP3_WinLo; + + if (DSP3_AddHi < 0) + DSP3_AddHi += DSP3_WinHi; + else + if (DSP3_AddHi >= DSP3_WinHi) + DSP3_AddHi -= DSP3_WinHi; + + *lo = DSP3_AddLo; + *hi = DSP3_AddHi; +} + + +void DSP3_OP1E_D1( int16 move, int16 *lo, int16 *hi ) +{ + //uint32 dataOfs = ((move << 1) + 0x03b2) & 0x03ff; + int16 Lo; + int16 Hi; + + const unsigned short HiAdd[] = { + 0x00, 0xFF, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0xFF, 0x00 + }; + const unsigned short LoAdd[] = { + 0x00, 0x00, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x00 + }; + + if( (*lo) & 1 ) + DSP3_AddHi = HiAdd[ move + 8 ]; + else + DSP3_AddHi = HiAdd[ move + 0 ]; + DSP3_AddLo = LoAdd[ move ]; + + Lo = (uint8)(*lo); + Hi = (uint8)(*hi); + + if (Lo & 1) Hi += (DSP3_AddLo & 1); + + DSP3_AddLo += Lo; + DSP3_AddHi += Hi; + + *lo = DSP3_AddLo; + *hi = DSP3_AddHi; +} + + +void DSP3_OP10() +{ + if( DSP3_DR == 0xffff ) { + DSP3_Reset(); + } else { + // absorb 2 bytes + DSP3_DR = DSP3_DR; + } +} + + +void DSP3_OP0C_A() +{ + // absorb 2 bytes + + DSP3_DR = 0; + SetDSP3 = &DSP3_Reset; +} + + +void DSP3_OP0C() +{ + // absorb 2 bytes + + DSP3_DR = 0; + //SetDSP3 = &DSP3_OP0C_A; + SetDSP3 = &DSP3_Reset; +} + + +void DSP3_OP1C_C() +{ + // return 2 bytes + DSP3_DR = 0; + SetDSP3 = &DSP3_Reset; +} + + +void DSP3_OP1C_B() +{ + // absorb 2 bytes + + // return 2 bytes + DSP3_DR = 0; + SetDSP3 = &DSP3_OP1C_C; +} + + +void DSP3_OP1C_A() +{ + // absorb 2 bytes + + SetDSP3 = &DSP3_OP1C_B; +} + + +void DSP3_OP1C() +{ + // absorb 2 bytes + + SetDSP3 = &DSP3_OP1C_A; +} + + +void DSP3_Command() +{ + if (DSP3_DR < 0x40) + { + switch (DSP3_DR) + { + case 0x02: SetDSP3 = &DSP3_Coordinate; break; + case 0x03: SetDSP3 = &DSP3_OP03; break; + case 0x06: SetDSP3 = &DSP3_OP06; break; + case 0x07: SetDSP3 = &DSP3_OP07; return; + case 0x0c: SetDSP3 = &DSP3_OP0C; break; + case 0x0f: SetDSP3 = &DSP3_TestMemory; break; + case 0x10: SetDSP3 = &DSP3_OP10; break; + case 0x18: SetDSP3 = &DSP3_Convert; break; + case 0x1c: SetDSP3 = &DSP3_OP1C; break; + case 0x1e: SetDSP3 = &DSP3_OP1E; break; + case 0x1f: SetDSP3 = &DSP3_MemoryDump; break; + case 0x38: SetDSP3 = &DSP3_Decode; break; + case 0x3e: SetDSP3 = &DSP3_OP3E; break; + default: + return; + } + DSP3_SR = 0x0080; + DSP3_Index = 0; + } +} + +uint8 dsp3_byte; +uint16 dsp3_address; + +void DSP3SetByte() +{ + if (dsp3_address < 0xC000) + { + if (DSP3_SR & 0x04) + { + DSP3_DR = (DSP3_DR & 0xff00) + dsp3_byte; + (*SetDSP3)(); + } + else + { + DSP3_SR ^= 0x10; + + if (DSP3_SR & 0x10) + DSP3_DR = (DSP3_DR & 0xff00) + dsp3_byte; + else + { + DSP3_DR = (DSP3_DR & 0x00ff) + (dsp3_byte << 8); + (*SetDSP3)(); + } + } + } +} + +void DSP3GetByte() +{ + if (dsp3_address < 0xC000) + { + if (DSP3_SR & 0x04) + { + dsp3_byte = (uint8) DSP3_DR; + (*SetDSP3)(); + } + else + { + DSP3_SR ^= 0x10; + + if (DSP3_SR & 0x10) + dsp3_byte = (uint8) (DSP3_DR); + else + { + dsp3_byte = (uint8) (DSP3_DR >> 8); + (*SetDSP3)(); + } + } + + } + else + { + dsp3_byte = (uint8) DSP3_SR; + } +} + +void InitDSP3() +{ + DSP3_Reset(); +} diff --git a/src/chip/dsp4/dsp4.cpp b/src/chip/dsp4/dsp4.cpp new file mode 100644 index 00000000..d067d33f --- /dev/null +++ b/src/chip/dsp4/dsp4.cpp @@ -0,0 +1,51 @@ +#include "../../base.h" + +namespace DSP4i { + inline uint16 READ_WORD(uint8 *addr) { + return (addr[0]) + (addr[1] << 8); + } + + inline uint32 READ_DWORD(uint8 *addr) { + return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24); + } + + inline void WRITE_WORD(uint8 *addr, uint16 data) { + addr[0] = data; + addr[1] = data >> 8; + } + + #define bool8 bool + #include "dsp4emu.c" + #undef bool8 +}; + +void DSP4::init() { +} + +void DSP4::enable() { +} + +void DSP4::power() { + reset(); +} + +void DSP4::reset() { + DSP4i::InitDSP4(); +} + +uint8 DSP4::read(uint16 addr) { + if(addr < 0xc000) { + DSP4i::dsp4_address = addr; + DSP4i::DSP4GetByte(); + return DSP4i::dsp4_byte; + } + return 0x80; +} + +void DSP4::write(uint16 addr, uint8 data) { + if(addr < 0xc000) { + DSP4i::dsp4_address = addr; + DSP4i::dsp4_byte = data; + DSP4i::DSP4SetByte(); + } +} diff --git a/src/chip/dsp4/dsp4.h b/src/chip/dsp4/dsp4.h new file mode 100644 index 00000000..ae4c63c5 --- /dev/null +++ b/src/chip/dsp4/dsp4.h @@ -0,0 +1,11 @@ +class DSP4 { public: + void init(); + void enable(); + void power(); + void reset(); + + uint8 read (uint16 addr); + void write(uint16 addr, uint8 data); +}; + +extern DSP4 dsp4; diff --git a/src/chip/dsp4/dsp4emu.c b/src/chip/dsp4/dsp4emu.c new file mode 100644 index 00000000..668f5867 --- /dev/null +++ b/src/chip/dsp4/dsp4emu.c @@ -0,0 +1,2146 @@ +//DSP-4 emulator code +//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden + +/* +Due recognition and credit are given on Overload's DSP website. +Thank those contributors for their hard work on this chip. + + +Fixed-point math reminder: + +[sign, integer, fraction] +1.15.00 * 1.15.00 = 2.30.00 -> 1.30.00 (DSP) -> 1.31.00 (LSB is '0') +1.15.00 * 1.00.15 = 2.15.15 -> 1.15.15 (DSP) -> 1.15.16 (LSB is '0') +*/ + +#include "dsp4emu.h" + +struct DSP4_t DSP4; +struct DSP4_vars_t DSP4_vars; + +////////////////////////////////////////////////////////////// + +// input protocol + +static int16 DSP4_READ_WORD() +{ + int16 out; + + out = READ_WORD(DSP4.parameters + DSP4.in_index); + DSP4.in_index += 2; + + return out; +} + +static int32 DSP4_READ_DWORD() +{ + int32 out; + + out = READ_DWORD(DSP4.parameters + DSP4.in_index); + DSP4.in_index += 4; + + return out; +} + + +////////////////////////////////////////////////////////////// + +// output protocol + +#define DSP4_CLEAR_OUT() \ +{ DSP4.out_count = 0; DSP4.out_index = 0; } + +#define DSP4_WRITE_BYTE( d ) \ +{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count++; } + +#define DSP4_WRITE_WORD( d ) \ +{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count += 2; } + +#ifndef MSB_FIRST +#define DSP4_WRITE_16_WORD( d ) \ +{ memcpy(DSP4.output + DSP4.out_count, ( d ), 32); DSP4.out_count += 32; } +#else +#define DSP4_WRITE_16_WORD( d ) \ +{ int16 *p = ( d ), *end = ( d )+16; \ + for (; p != end; p++) \ + { \ + WRITE_WORD( DSP4.output + DSP4.out_count, *p ); \ + } \ + DSP4.out_count += 32; \ +} +#endif + +#ifdef PRINT_OP +#define DSP4_WRITE_DEBUG( x, d ) \ + WRITE_WORD( nop + x, d ); +#endif + +#ifdef DEBUG_DSP +#define DSP4_WRITE_DEBUG( x, d ) \ + WRITE_WORD( nop + x, d ); +#endif + +////////////////////////////////////////////////////////////// + +// used to wait for dsp i/o + +#define DSP4_WAIT( x ) \ + DSP4.in_index = 0; DSP4_vars.DSP4_Logic = x; return; + +////////////////////////////////////////////////////////////// + +// 1.7.8 -> 1.15.16 +#define SEX78( a ) ( ( (int32) ( (int16) (a) ) ) << 8 ) + +// 1.15.0 -> 1.15.16 +#define SEX16( a ) ( ( (int32) ( (int16) (a) ) ) << 16 ) + +#ifdef PRINT_OP +#define U16( a ) ( (uint16) ( a ) ) +#endif + +#ifdef DEBUG_DSP +#define U16( a ) ( (uint16) ( a ) ) +#endif + +////////////////////////////////////////////////////////////// + +// Attention: This lookup table is not verified +static const uint16 div_lut[64] = { 0x0000, 0x8000, 0x4000, 0x2aaa, 0x2000, 0x1999, 0x1555, 0x1249, 0x1000, 0x0e38, + 0x0ccc, 0x0ba2, 0x0aaa, 0x09d8, 0x0924, 0x0888, 0x0800, 0x0787, 0x071c, 0x06bc, + 0x0666, 0x0618, 0x05d1, 0x0590, 0x0555, 0x051e, 0x04ec, 0x04bd, 0x0492, 0x0469, + 0x0444, 0x0421, 0x0400, 0x03e0, 0x03c3, 0x03a8, 0x038e, 0x0375, 0x035e, 0x0348, + 0x0333, 0x031f, 0x030c, 0x02fa, 0x02e8, 0x02d8, 0x02c8, 0x02b9, 0x02aa, 0x029c, + 0x028f, 0x0282, 0x0276, 0x026a, 0x025e, 0x0253, 0x0249, 0x023e, 0x0234, 0x022b, + 0x0222, 0x0219, 0x0210, 0x0208, }; +int16 DSP4_Inverse(int16 value) +{ + // saturate bounds + if (value < 0) + { + value = 0; + } + if (value > 63) + { + value = 63; + } + + return div_lut[value]; +} + +////////////////////////////////////////////////////////////// + +// Prototype +void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop); + +////////////////////////////////////////////////////////////// + +// OP00 +void DSP4_Multiply(int16 Multiplicand, int16 Multiplier, int32 *Product) +{ + *Product = (Multiplicand * Multiplier << 1) >> 1; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP01() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.world_dy = DSP4_READ_DWORD(); + DSP4_vars.world_dx = DSP4_READ_DWORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_xenv = DSP4_READ_DWORD(); + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + DSP4_vars.view_turnoff_x = 0; + DSP4_vars.view_turnoff_dx = 0; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + DSP4_vars.view_x2 = (int16)(( ( ( DSP4_vars.world_x + DSP4_vars.world_xenv ) >> 16 ) * DSP4_vars.distance >> 15 ) + ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 )); + DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + + // 1. World x-location before transformation + // 2. Viewer x-position at the next + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.poly_raster[0][0] - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg1) + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + //////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + // add deltas for projection lines + DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx); + DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy); + + // update projection lines + DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv); + DSP4_vars.world_y += DSP4_vars.world_dy; + + // update road turnoff position + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // check for termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // road turnoff + if( (uint16) DSP4_vars.distance == 0x8001 ) + { + DSP4.in_count = 6; + DSP4_WAIT(2) resume2: + + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_x = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_dx = DSP4_READ_WORD(); + + // factor in new changes + DSP4_vars.view_x1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + DSP4_vars.view_xofs1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + + // update stepping values + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + DSP4.in_count = 2; + DSP4_WAIT(1) + } + + // already have 2 bytes read + DSP4.in_count = 6; + DSP4_WAIT(3) resume3 : + + // inspect inputs + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + DSP4_vars.world_xenv = 0; + } + while (1); + + // terminate op + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP03() +{ + DSP4_vars.OAM_RowMax = 33; + memset(DSP4_vars.OAM_Row, 0, 64); +} + + +////////////////////////////////////////////////////////////// + + +void DSP4_OP05() +{ + DSP4_vars.OAM_index = 0; + DSP4_vars.OAM_bits = 0; + memset(DSP4_vars.OAM_attr, 0, 32); + DSP4_vars.sprite_count = 0; +} + + +////////////////////////////////////////////////////////////// + +void DSP4_OP06() +{ + DSP4_CLEAR_OUT(); + DSP4_WRITE_16_WORD(DSP4_vars.OAM_attr); +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP07() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // sort inputs + + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = DSP4_vars.view_x1; + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // add shaping + DSP4_vars.view_x2 += DSP4_vars.view_dx; + DSP4_vars.view_y2 += DSP4_vars.view_dy; + + // vertical scroll calculation + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. Viewer x-position at the next + // 2. Viewer y-position below the horizon + // 3. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg2) + // 2. vertical scroll offset ($2110) + // 3. horizontal scroll offset ($210F) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // check for opcode termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 10; + DSP4_WAIT(2) resume2 : + + // inspect inputs + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP08() +{ + int16 win_left, win_right; + int16 view_x[2], view_y[2]; + int16 envelope[2][2]; + + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // process initial inputs for two polygons + + // clip values + DSP4_vars.poly_clipRt[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipRt[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_clipRt[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipRt[1][1] = DSP4_READ_WORD(); + + DSP4_vars.poly_clipLf[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipLf[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_clipLf[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_clipLf[1][1] = DSP4_READ_WORD(); + + // unknown (constant) (ex. 1P/2P = $00A6, $00A6, $00A6, $00A6) + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // unknown (constant) (ex. 1P/2P = $00A5, $00A5, $00A7, $00A7) + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // polygon centering (left,right) + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][1] = DSP4_READ_WORD(); + + // HDMA pointer locations + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[1][1] = DSP4_READ_WORD(); + + // starting DSP4_vars.raster line below the horizon + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_bottom[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_bottom[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_bottom[1][1] = DSP4_READ_WORD(); + + // top boundary line to clip + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][1] = DSP4_READ_WORD(); + DSP4_vars.poly_top[1][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[1][1] = DSP4_READ_WORD(); + + // unknown + // (ex. 1P = $2FC8, $0034, $FF5C, $0035) + // + // (ex. 2P = $3178, $0034, $FFCC, $0035) + // (ex. 2P = $2FC8, $0034, $FFCC, $0035) + + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // look at guidelines for both polygon shapes + DSP4_vars.distance = DSP4_READ_WORD(); + view_x[0] = DSP4_READ_WORD(); + view_y[0] = DSP4_READ_WORD(); + view_x[1] = DSP4_READ_WORD(); + view_y[1] = DSP4_READ_WORD(); + + // envelope shaping guidelines (one frame only) + envelope[0][0] = DSP4_READ_WORD(); + envelope[0][1] = DSP4_READ_WORD(); + envelope[1][0] = DSP4_READ_WORD(); + envelope[1][1] = DSP4_READ_WORD(); + + // starting base values to project from + DSP4_vars.poly_start[0] = view_x[0]; + DSP4_vars.poly_start[1] = view_x[1]; + + // starting DSP4_vars.raster lines to begin drawing + DSP4_vars.poly_raster[0][0] = view_y[0]; + DSP4_vars.poly_raster[0][1] = view_y[0]; + DSP4_vars.poly_raster[1][0] = view_y[1]; + DSP4_vars.poly_raster[1][1] = view_y[1]; + + // starting distances + DSP4_vars.poly_plane[0] = DSP4_vars.distance; + DSP4_vars.poly_plane[1] = DSP4_vars.distance; + + // SR = 0x00 + + // re-center coordinates + win_left = DSP4_vars.poly_cx[0][0] - view_x[0] + envelope[0][0]; + win_right = DSP4_vars.poly_cx[0][1] - view_x[0] + envelope[0][1]; + + // saturate offscreen data for polygon #1 + if (win_left < DSP4_vars.poly_clipLf[0][0]) + { + win_left = DSP4_vars.poly_clipLf[0][0]; + } + if (win_left > DSP4_vars.poly_clipRt[0][0]) + { + win_left = DSP4_vars.poly_clipRt[0][0]; + } + if (win_right < DSP4_vars.poly_clipLf[0][1]) + { + win_right = DSP4_vars.poly_clipLf[0][1]; + } + if (win_right > DSP4_vars.poly_clipRt[0][1]) + { + win_right = DSP4_vars.poly_clipRt[0][1]; + } + + // SR = 0x80 + + // initial output for polygon #1 + DSP4_CLEAR_OUT(); + DSP4_WRITE_BYTE(win_left & 0xff); + DSP4_WRITE_BYTE(win_right & 0xff); + + + do + { + int16 polygon; + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // terminate op + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 16; + + DSP4_WAIT(2) resume2 : + + // look at guidelines for both polygon shapes + view_x[0] = DSP4_READ_WORD(); + view_y[0] = DSP4_READ_WORD(); + view_x[1] = DSP4_READ_WORD(); + view_y[1] = DSP4_READ_WORD(); + + // envelope shaping guidelines (one frame only) + envelope[0][0] = DSP4_READ_WORD(); + envelope[0][1] = DSP4_READ_WORD(); + envelope[1][0] = DSP4_READ_WORD(); + envelope[1][1] = DSP4_READ_WORD(); + + //////////////////////////////////////////////////// + // projection begins + + // init + DSP4_CLEAR_OUT(); + + + ////////////////////////////////////////////// + // solid polygon renderer - 2 shapes + + for (polygon = 0; polygon < 2; polygon++) + { + int32 left_inc, right_inc; + int16 x1_final, x2_final; + int16 env[2][2]; + int16 poly; + + // SR = 0x00 + + // # DSP4_vars.raster lines to draw + DSP4_vars.segments = DSP4_vars.poly_raster[polygon][0] - view_y[polygon]; + + // prevent overdraw + if (DSP4_vars.segments > 0) + { + // bump drawing cursor + DSP4_vars.poly_raster[polygon][0] = view_y[polygon]; + DSP4_vars.poly_raster[polygon][1] = view_y[polygon]; + } + else + DSP4_vars.segments = 0; + + // don't draw outside the window + if (view_y[polygon] < DSP4_vars.poly_top[polygon][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (view_y[polygon] >= DSP4_vars.poly_top[polygon][0]) + DSP4_vars.segments = view_y[polygon] - DSP4_vars.poly_top[polygon][0]; + } + + // SR = 0x80 + + // tell user how many DSP4_vars.raster structures to read in + DSP4_WRITE_WORD(DSP4_vars.segments); + + // normal parameters + poly = polygon; + + ///////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 win_left, win_right; + + // road turnoff selection + if( (uint16) envelope[ polygon ][ 0 ] == (uint16) 0xc001 ) + poly = 1; + else if( envelope[ polygon ][ 1 ] == 0x3fff ) + poly = 1; + + /////////////////////////////////////////////// + // left side of polygon + + // perspective correction on additional shaping parameters + env[0][0] = envelope[polygon][0] * DSP4_vars.poly_plane[poly] >> 15; + env[0][1] = envelope[polygon][0] * DSP4_vars.distance >> 15; + + // project new shapes (left side) + x1_final = view_x[poly] + env[0][0]; + x2_final = DSP4_vars.poly_start[poly] + env[0][1]; + + // interpolate between projected points with shaping + left_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4_vars.segments) << 1; + if (DSP4_vars.segments == 1) + left_inc = -left_inc; + + /////////////////////////////////////////////// + // right side of polygon + + // perspective correction on additional shaping parameters + env[1][0] = envelope[polygon][1] * DSP4_vars.poly_plane[poly] >> 15;; + env[1][1] = envelope[polygon][1] * DSP4_vars.distance >> 15; + + // project new shapes (right side) + x1_final = view_x[poly] + env[1][0]; + x2_final = DSP4_vars.poly_start[poly] + env[1][1]; + + + // interpolate between projected points with shaping + right_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4_vars.segments) << 1; + if (DSP4_vars.segments == 1) + right_inc = -right_inc; + + /////////////////////////////////////////////// + // update each point on the line + + win_left = SEX16(DSP4_vars.poly_cx[polygon][0] - DSP4_vars.poly_start[poly] + env[0][0]); + win_right = SEX16(DSP4_vars.poly_cx[polygon][1] - DSP4_vars.poly_start[poly] + env[1][0]); + + // update DSP4_vars.distance drawn into world + DSP4_vars.poly_plane[polygon] = DSP4_vars.distance; + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + int16 x_left, x_right; + + // project new coordinates + win_left += left_inc; + win_right += right_inc; + + // grab integer portion, drop fraction (no rounding) + x_left = (int16)(win_left >> 16); + x_right = (int16)(win_right >> 16); + + // saturate offscreen data + if (x_left < DSP4_vars.poly_clipLf[polygon][0]) + x_left = DSP4_vars.poly_clipLf[polygon][0]; + if (x_left > DSP4_vars.poly_clipRt[polygon][0]) + x_left = DSP4_vars.poly_clipRt[polygon][0]; + if (x_right < DSP4_vars.poly_clipLf[polygon][1]) + x_right = DSP4_vars.poly_clipLf[polygon][1]; + if (x_right > DSP4_vars.poly_clipRt[polygon][1]) + x_right = DSP4_vars.poly_clipRt[polygon][1]; + + // 1. HDMA memory pointer + // 2. Left window position ($2126/$2128) + // 3. Right window position ($2127/$2129) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[polygon][0]); + DSP4_WRITE_BYTE(x_left & 0xff); + DSP4_WRITE_BYTE(x_right & 0xff); + + + // update memory pointers + DSP4_vars.poly_ptr[polygon][0] -= 4; + DSP4_vars.poly_ptr[polygon][1] -= 4; + } // end rasterize line + } + + //////////////////////////////////////////////// + // Post-update + + // new projection spot to continue rasterizing from + DSP4_vars.poly_start[polygon] = view_x[poly]; + } // end polygon rasterizer + } + while (1); + + // unknown output + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(0); + + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP09() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + case 4: + goto resume4; break; + case 5: + goto resume5; break; + case 6: + goto resume6; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // grab screen information + DSP4_vars.viewport_cx = DSP4_READ_WORD(); + DSP4_vars.viewport_cy = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.viewport_left = DSP4_READ_WORD(); + DSP4_vars.viewport_right = DSP4_READ_WORD(); + DSP4_vars.viewport_top = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + + // starting DSP4_vars.raster line below the horizon + DSP4_vars.poly_bottom[0][0] = DSP4_vars.viewport_bottom - DSP4_vars.viewport_cy; + DSP4_vars.poly_raster[0][0] = 0x100; + + do + { + //////////////////////////////////////////////////// + // check for new sprites + + DSP4.in_count = 4; + DSP4_WAIT(1) resume1 : + + //////////////////////////////////////////////// + // DSP4_vars.raster overdraw check + + DSP4_vars.raster = DSP4_READ_WORD(); + + // continue updating the DSP4_vars.raster line where overdraw begins + if (DSP4_vars.raster < DSP4_vars.poly_raster[0][0]) + { + DSP4_vars.sprite_clipy = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster); + DSP4_vars.poly_raster[0][0] = DSP4_vars.raster; + } + + ///////////////////////////////////////////////// + // identify sprite + + // op termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + goto terminate; + + + // no sprite + if (DSP4_vars.distance == 0x0000) + { + continue; + } + + //////////////////////////////////////////////////// + // process projection information + + // vehicle sprite + if ((uint16) DSP4_vars.distance == 0x9000) + { + int16 car_left, car_right, car_back; + int16 impact_left, impact_back; + int16 world_spx, world_spy; + int16 view_spx, view_spy; + uint16 energy; + + // we already have 4 bytes we want + DSP4.in_count = 14; + DSP4_WAIT(2) resume2 : + + // filter inputs + energy = DSP4_READ_WORD(); + impact_back = DSP4_READ_WORD(); + car_back = DSP4_READ_WORD(); + impact_left = DSP4_READ_WORD(); + car_left = DSP4_READ_WORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + car_right = DSP4_READ_WORD(); + + // calculate car's world (x,y) values + world_spx = car_right - car_left; + world_spy = car_back; + + // add in collision vector [needs bit-twiddling] + world_spx -= energy * (impact_left - car_left) >> 16; + world_spy -= energy * (car_back - impact_back) >> 16; + + // perspective correction for world (x,y) + view_spx = world_spx * DSP4_vars.distance >> 15; + view_spy = world_spy * DSP4_vars.distance >> 15; + + // convert to screen values + DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx; + DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - view_spy); + + // make the car's (x)-coordinate available + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(world_spx); + + // grab a few remaining vehicle values + DSP4.in_count = 4; + DSP4_WAIT(3) resume3 : + + // add vertical lift factor + DSP4_vars.sprite_y += DSP4_READ_WORD(); + } + // terrain sprite + else + { + int16 world_spx, world_spy; + int16 view_spx, view_spy; + + // we already have 4 bytes we want + DSP4.in_count = 10; + DSP4_WAIT(4) resume4 : + + // sort loop inputs + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_raster[0][1] = DSP4_READ_WORD(); + world_spx = DSP4_READ_WORD(); + world_spy = DSP4_READ_WORD(); + + // compute base DSP4_vars.raster line from the bottom + DSP4_vars.segments = DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster; + + // perspective correction for world (x,y) + view_spx = world_spx * DSP4_vars.distance >> 15; + view_spy = world_spy * DSP4_vars.distance >> 15; + + // convert to screen values + DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx - DSP4_vars.poly_cx[0][0]; + DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - DSP4_vars.segments + view_spy; + } + + // default sprite size: 16x16 + DSP4_vars.sprite_size = 1; + DSP4_vars.sprite_attr = DSP4_READ_WORD(); + + //////////////////////////////////////////////////// + // convert tile data to SNES OAM format + + do + { + uint16 header; + + int16 sp_x, sp_y, sp_attr, sp_dattr; + int16 sp_dx, sp_dy; + int16 pixels; + + bool8 draw; + + DSP4.in_count = 2; + DSP4_WAIT(5) resume5 : + + draw = TRUE; + + // opcode termination + DSP4_vars.raster = DSP4_READ_WORD(); + if (DSP4_vars.raster == -0x8000) + goto terminate; + + // stop code + if (DSP4_vars.raster == 0x0000 && !DSP4_vars.sprite_size) + break; + + // toggle sprite size + if (DSP4_vars.raster == 0x0000) + { + DSP4_vars.sprite_size = !DSP4_vars.sprite_size; + continue; + } + + // check for valid sprite header + header = DSP4_vars.raster; + header >>= 8; + if (header != 0x20 && + header != 0x2e && //This is for attractor sprite + header != 0x40 && + header != 0x60 && + header != 0xa0 && + header != 0xc0 && + header != 0xe0) + break; + + // read in rest of sprite data + DSP4.in_count = 4; + DSP4_WAIT(6) resume6 : + + draw = TRUE; + + ///////////////////////////////////// + // process tile data + + // sprite deltas + sp_dattr = DSP4_vars.raster; + sp_dy = DSP4_READ_WORD(); + sp_dx = DSP4_READ_WORD(); + + // update coordinates to screen space + sp_x = DSP4_vars.sprite_x + sp_dx; + sp_y = DSP4_vars.sprite_y + sp_dy; + + // update sprite nametable/attribute information + sp_attr = DSP4_vars.sprite_attr + sp_dattr; + + // allow partially visibile tiles + pixels = DSP4_vars.sprite_size ? 15 : 7; + + DSP4_CLEAR_OUT(); + + // transparent tile to clip off parts of a sprite (overdraw) + if (DSP4_vars.sprite_clipy - pixels <= sp_y && + sp_y <= DSP4_vars.sprite_clipy && + sp_x >= DSP4_vars.viewport_left - pixels && + sp_x <= DSP4_vars.viewport_right && + DSP4_vars.sprite_clipy >= DSP4_vars.viewport_top - pixels && + DSP4_vars.sprite_clipy <= DSP4_vars.viewport_bottom) + { + DSP4_OP0B(&draw, sp_x, DSP4_vars.sprite_clipy, 0x00EE, DSP4_vars.sprite_size, 0); + } + + + // normal sprite tile + if (sp_x >= DSP4_vars.viewport_left - pixels && + sp_x <= DSP4_vars.viewport_right && + sp_y >= DSP4_vars.viewport_top - pixels && + sp_y <= DSP4_vars.viewport_bottom && + sp_y <= DSP4_vars.sprite_clipy) + { + DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, DSP4_vars.sprite_size, 0); + } + + + // no following OAM data + DSP4_OP0B(&draw, 0, 0x0100, 0, 0, 1); + } + while (1); + } + while (1); + + terminate : DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +const uint16 OP0A_Values[16] = { 0x0000, 0x0030, 0x0060, 0x0090, 0x00c0, 0x00f0, 0x0120, 0x0150, 0xfe80, + 0xfeb0, 0xfee0, 0xff10, 0xff40, 0xff70, 0xffa0, 0xffd0 }; + +void DSP4_OP0A(int16 n2, int16 *o1, int16 *o2, int16 *o3, int16 *o4) +{ + *o4 = OP0A_Values[(n2 & 0x000f)]; + *o3 = OP0A_Values[(n2 & 0x00f0) >> 4]; + *o2 = OP0A_Values[(n2 & 0x0f00) >> 8]; + *o1 = OP0A_Values[(n2 & 0xf000) >> 12]; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop) +{ + int16 Row1, Row2; + + // SR = 0x00 + + // align to nearest 8-pixel row + Row1 = (sp_y >> 3) & 0x1f; + Row2 = (Row1 + 1) & 0x1f; + + // check boundaries + if (!((sp_y < 0) || ((sp_y & 0x01ff) < 0x00eb))) + { + *draw = 0; + } + if (size) + { + if (DSP4_vars.OAM_Row[Row1] + 1 >= DSP4_vars.OAM_RowMax) + *draw = 0; + if (DSP4_vars.OAM_Row[Row2] + 1 >= DSP4_vars.OAM_RowMax) + *draw = 0; + } + else + { + if (DSP4_vars.OAM_Row[Row1] >= DSP4_vars.OAM_RowMax) + { + *draw = 0; + } + } + + // emulator fail-safe (unknown if this really exists) + if (DSP4_vars.sprite_count >= 128) + { + *draw = 0; + } + + // SR = 0x80 + + if (*draw) + { + // Row tiles + if (size) + { + DSP4_vars.OAM_Row[Row1] += 2; + DSP4_vars.OAM_Row[Row2] += 2; + } + else + { + DSP4_vars.OAM_Row[Row1]++; + } + + // yield OAM output + DSP4_WRITE_WORD(1); + + // pack OAM data: x,y,name,attr + DSP4_WRITE_BYTE(sp_x & 0xff); + DSP4_WRITE_BYTE(sp_y & 0xff); + DSP4_WRITE_WORD(sp_attr); + + DSP4_vars.sprite_count++; + + // OAM: size,msb data + // save post-oam table data for future retrieval + DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= ((sp_x <0 || sp_x> 255) << DSP4_vars.OAM_bits); + DSP4_vars.OAM_bits++; + + DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= (size << DSP4_vars.OAM_bits); + DSP4_vars.OAM_bits++; + + // move to next byte in buffer + if (DSP4_vars.OAM_bits == 16) + { + DSP4_vars.OAM_bits = 0; + DSP4_vars.OAM_index++; + } + } + else if (stop) + { + // yield no OAM output + DSP4_WRITE_WORD(0); + } +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP0D() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.world_dy = DSP4_READ_DWORD(); + DSP4_vars.world_dx = DSP4_READ_DWORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_xenv = SEX78(DSP4_READ_WORD()); + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + DSP4_vars.view_x2 = (int16)(( ( ( DSP4_vars.world_x + DSP4_vars.world_xenv ) >> 16 ) * DSP4_vars.distance >> 15 ) + ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 )); + DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. World x-location before transformation + // 2. Viewer x-position at the current + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg1) + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + // add deltas for projection lines + DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx); + DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy); + + // update projection lines + DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv); + DSP4_vars.world_y += DSP4_vars.world_dy; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // inspect input + DSP4_vars.distance = DSP4_READ_WORD(); + + // terminate op + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 6; + DSP4_WAIT(2) resume2: + + // inspect inputs + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + DSP4_vars.world_xenv = 0; + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP0E() +{ + DSP4_vars.OAM_RowMax = 16; + memset(DSP4_vars.OAM_Row, 0, 64); +} + + +////////////////////////////////////////////////////////////// + +void DSP4_OP0F() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + case 4: + goto resume4; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.world_dy = DSP4_READ_DWORD(); + DSP4_vars.world_dx = DSP4_READ_DWORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_xenv = DSP4_READ_DWORD(); + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + DSP4_vars.view_turnoff_x = 0; + DSP4_vars.view_turnoff_dx = 0; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + DSP4_vars.view_x2 = (int16)(((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15); + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. World x-location before transformation + // 2. Viewer x-position at the next + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16)); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.poly_raster[0][0] - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < 4; DSP4_vars.lcv++) + { + // grab inputs + DSP4.in_count = 4; + DSP4_WAIT(1); + resume1 : + for (;;) + { + int16 distance; + int16 color, red, green, blue; + + distance = DSP4_READ_WORD(); + color = DSP4_READ_WORD(); + + // U1+B5+G5+R5 + red = color & 0x1f; + green = (color >> 5) & 0x1f; + blue = (color >> 10) & 0x1f; + + // dynamic lighting + red = (red * distance >> 15) & 0x1f; + green = (green * distance >> 15) & 0x1f; + blue = (blue * distance >> 15) & 0x1f; + color = red | (green << 5) | (blue << 10); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(color); + break; + } + } + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + //////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + // add deltas for projection lines + DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx); + DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy); + + // update projection lines + DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv); + DSP4_vars.world_y += DSP4_vars.world_dy; + + // update road turnoff position + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(2) resume2: + + // check for termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // road splice + if( (uint16) DSP4_vars.distance == 0x8001 ) + { + DSP4.in_count = 6; + DSP4_WAIT(3) resume3: + + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_x = DSP4_READ_WORD(); + DSP4_vars.view_turnoff_dx = DSP4_READ_WORD(); + + // factor in new changes + DSP4_vars.view_x1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + DSP4_vars.view_xofs1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ); + + // update stepping values + DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx; + + DSP4.in_count = 2; + DSP4_WAIT(2) + } + + // already have 2 bytes in queue + DSP4.in_count = 6; + DSP4_WAIT(4) resume4 : + + // inspect inputs + DSP4_vars.world_ddy = DSP4_READ_WORD(); + DSP4_vars.world_ddx = DSP4_READ_WORD(); + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + DSP4_vars.world_xenv = 0; + } + while (1); + + // terminate op + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP10() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_vars.DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + } + + //////////////////////////////////////////////////// + // sort inputs + + DSP4_READ_WORD(); // 0x0000 + DSP4_vars.world_y = DSP4_READ_DWORD(); + DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_top[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD(); + DSP4_vars.viewport_bottom = DSP4_READ_WORD(); + DSP4_vars.world_x = DSP4_READ_DWORD(); + DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD(); + DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD(); + DSP4_vars.world_yofs = DSP4_READ_WORD(); + DSP4_vars.distance = DSP4_READ_WORD(); + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting DSP4_vars.raster line + DSP4_vars.view_x1 = (int16)(DSP4_vars.world_x >> 16); + DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16); + DSP4_vars.view_xofs1 = DSP4_vars.view_x1; + DSP4_vars.view_yofs1 = DSP4_vars.world_yofs; + + // first DSP4_vars.raster line + DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0]; + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // add shaping + DSP4_vars.view_x2 += DSP4_vars.view_dx; + DSP4_vars.view_y2 += DSP4_vars.view_dy; + + // vertical scroll calculation + DSP4_vars.view_xofs2 = DSP4_vars.view_x2; + DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2; + + // 1. Viewer x-position at the next + // 2. Viewer y-position below the horizon + // 3. Number of DSP4_vars.raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(DSP4_vars.view_x2); + DSP4_WRITE_WORD(DSP4_vars.view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of DSP4_vars.raster lines used + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2; + + // prevent overdraw + if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0]) + DSP4_vars.segments = 0; + else + DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2; + + // don't draw outside the window + if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0]) + { + DSP4_vars.segments = 0; + + // flush remaining DSP4_vars.raster lines + if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0]) + DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(DSP4_vars.segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < 4; DSP4_vars.lcv++) + { + // grab inputs + DSP4.in_count = 4; + DSP4_WAIT(1); + resume1 : + for (;;) + { + int16 distance; + int16 color, red, green, blue; + + distance = DSP4_READ_WORD(); + color = DSP4_READ_WORD(); + + // U1+B5+G5+R5 + red = color & 0x1f; + green = (color >> 5) & 0x1f; + blue = (color >> 10) & 0x1f; + + // dynamic lighting + red = (red * distance >> 15) & 0x1f; + green = (green * distance >> 15) & 0x1f; + blue = (blue * distance >> 15) & 0x1f; + color = red | (green << 5) | (blue << 10); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(color); + break; + } + } + } + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (DSP4_vars.segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1; + + // starting step values + x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1); + y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs); + + // SR = 0x80 + + // rasterize line + for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++) + { + // 1. HDMA memory pointer (bg2) + // 2. vertical scroll offset ($2110) + // 3. horizontal scroll offset ($210F) + + DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]); + DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16)); + DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16)); + + // update memory address + DSP4_vars.poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn + DSP4_vars.view_x1 = DSP4_vars.view_x2; + DSP4_vars.view_y1 = DSP4_vars.view_y2; + DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2; + DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(2) resume2 : + + // check for opcode termination + DSP4_vars.distance = DSP4_READ_WORD(); + if (DSP4_vars.distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 10; + DSP4_WAIT(3) resume3 : + + + // inspect inputs + DSP4_vars.view_y2 = DSP4_READ_WORD(); + DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + DSP4_vars.view_x2 = DSP4_READ_WORD(); + DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15; + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP11(int16 A, int16 B, int16 C, int16 D, int16 *M) +{ + // 0x155 = 341 = Horizontal Width of the Screen + *M = ((A * 0x0155 >> 2) & 0xf000) | + ((B * 0x0155 >> 6) & 0x0f00) | + ((C * 0x0155 >> 10) & 0x00f0) | + ((D * 0x0155 >> 14) & 0x000f); +} + + + + + +///////////////////////////////////////////////////////////// +//Processing Code +///////////////////////////////////////////////////////////// +uint8 dsp4_byte; +uint16 dsp4_address; + +void InitDSP4() +{ + memset(&DSP4, 0, sizeof(DSP4)); + DSP4.waiting4command = TRUE; +} + +void DSP4SetByte() +{ + // clear pending read + if (DSP4.out_index < DSP4.out_count) + { + DSP4.out_index++; + return; + } + + if (DSP4.waiting4command) + { + if (DSP4.half_command) + { + DSP4.command |= (dsp4_byte << 8); + DSP4.in_index = 0; + DSP4.waiting4command = FALSE; + DSP4.half_command = FALSE; + DSP4.out_count = 0; + DSP4.out_index = 0; + + DSP4_vars.DSP4_Logic = 0; + + + switch (DSP4.command) + { + case 0x0000: + DSP4.in_count = 4; break; + case 0x0001: + DSP4.in_count = 44; break; + case 0x0003: + DSP4.in_count = 0; break; + case 0x0005: + DSP4.in_count = 0; break; + case 0x0006: + DSP4.in_count = 0; break; + case 0x0007: + DSP4.in_count = 34; break; + case 0x0008: + DSP4.in_count = 90; break; + case 0x0009: + DSP4.in_count = 14; break; + case 0x000a: + DSP4.in_count = 6; break; + case 0x000b: + DSP4.in_count = 6; break; + case 0x000d: + DSP4.in_count = 42; break; + case 0x000e: + DSP4.in_count = 0; break; + case 0x000f: + DSP4.in_count = 46; break; + case 0x0010: + DSP4.in_count = 36; break; + case 0x0011: + DSP4.in_count = 8; break; + default: + DSP4.waiting4command = TRUE; + break; + } + } + else + { + DSP4.command = dsp4_byte; + DSP4.half_command = TRUE; + } + } + else + { + DSP4.parameters[DSP4.in_index] = dsp4_byte; + DSP4.in_index++; + } + + if (!DSP4.waiting4command && DSP4.in_count == DSP4.in_index) + { + // Actually execute the command + DSP4.waiting4command = TRUE; + DSP4.out_index = 0; + DSP4.in_index = 0; + + switch (DSP4.command) + { + // 16-bit multiplication + case 0x0000: + { + int16 multiplier, multiplicand; + int32 product; + + multiplier = DSP4_READ_WORD(); + multiplicand = DSP4_READ_WORD(); + + DSP4_Multiply(multiplicand, multiplier, &product); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((uint16)(product)); + DSP4_WRITE_WORD((uint16)(product >> 16)); + } + break; + + // single-player track projection + case 0x0001: + DSP4_OP01(); break; + + // single-player selection + case 0x0003: + DSP4_OP03(); break; + + // clear OAM + case 0x0005: + DSP4_OP05(); break; + + // transfer OAM + case 0x0006: + DSP4_OP06(); break; + + // single-player track turnoff projection + case 0x0007: + DSP4_OP07(); break; + + // solid polygon projection + case 0x0008: + DSP4_OP08(); break; + + // sprite projection + case 0x0009: + DSP4_OP09(); break; + + // unknown + case 0x000A: + { + //int16 in1a = DSP4_READ_WORD(); + int16 in2a = DSP4_READ_WORD(); + //int16 in3a = DSP4_READ_WORD(); + int16 out1a, out2a, out3a, out4a; + + DSP4_OP0A(in2a, &out2a, &out1a, &out4a, &out3a); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(out1a); + DSP4_WRITE_WORD(out2a); + DSP4_WRITE_WORD(out3a); + DSP4_WRITE_WORD(out4a); + } + break; + + // set OAM + case 0x000B: + { + int16 sp_x = DSP4_READ_WORD(); + int16 sp_y = DSP4_READ_WORD(); + int16 sp_attr = DSP4_READ_WORD(); + bool8 draw = 1; + + DSP4_CLEAR_OUT(); + + DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, 0, 1); + } + break; + + // multi-player track projection + case 0x000D: + DSP4_OP0D(); break; + + // multi-player selection + case 0x000E: + DSP4_OP0E(); break; + + // single-player track projection with lighting + case 0x000F: + DSP4_OP0F(); break; + + // single-player track turnoff projection with lighting + case 0x0010: + DSP4_OP10(); break; + + // unknown: horizontal mapping command + case 0x0011: + { + int16 a, b, c, d, m; + + + d = DSP4_READ_WORD(); + c = DSP4_READ_WORD(); + b = DSP4_READ_WORD(); + a = DSP4_READ_WORD(); + + DSP4_OP11(a, b, c, d, &m); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(m); + + break; + } + + default: + break; + } + } +} + +void DSP4GetByte() +{ + if (DSP4.out_count) + { + dsp4_byte = (uint8) DSP4.output[DSP4.out_index&0x1FF]; + DSP4.out_index++; + if (DSP4.out_count == DSP4.out_index) + DSP4.out_count = 0; + } + else + { + dsp4_byte = 0xff; + } +} diff --git a/src/chip/dsp4/dsp4emu.h b/src/chip/dsp4/dsp4emu.h new file mode 100644 index 00000000..76103873 --- /dev/null +++ b/src/chip/dsp4/dsp4emu.h @@ -0,0 +1,108 @@ +//DSP-4 emulator code +//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden + +#ifndef DSP4EMU_H +#define DSP4EMU_H + +#undef TRUE +#undef FALSE +#define TRUE true +#define FALSE false + +struct DSP4_t +{ + bool8 waiting4command; + bool8 half_command; + uint16 command; + uint32 in_count; + uint32 in_index; + uint32 out_count; + uint32 out_index; + uint8 parameters[512]; + uint8 output[512]; +}; + +extern struct DSP4_t DSP4; + +struct DSP4_vars_t +{ + // op control + int8 DSP4_Logic; // controls op flow + + + // projection format + int16 lcv; // loop-control variable + int16 distance; // z-position into virtual world + int16 raster; // current raster line + int16 segments; // number of raster lines drawn + + // 1.15.16 or 1.15.0 [sign, integer, fraction] + int32 world_x; // line of x-projection in world + int32 world_y; // line of y-projection in world + int32 world_dx; // projection line x-delta + int32 world_dy; // projection line y-delta + int16 world_ddx; // x-delta increment + int16 world_ddy; // y-delta increment + int32 world_xenv; // world x-shaping factor + int16 world_yofs; // world y-vertical scroll + + int16 view_x1; // current viewer-x + int16 view_y1; // current viewer-y + int16 view_x2; // future viewer-x + int16 view_y2; // future viewer-y + int16 view_dx; // view x-delta factor + int16 view_dy; // view y-delta factor + int16 view_xofs1; // current viewer x-vertical scroll + int16 view_yofs1; // current viewer y-vertical scroll + int16 view_xofs2; // future viewer x-vertical scroll + int16 view_yofs2; // future viewer y-vertical scroll + int16 view_yofsenv; // y-scroll shaping factor + int16 view_turnoff_x; // road turnoff data + int16 view_turnoff_dx; // road turnoff delta factor + + + // drawing area + + int16 viewport_cx; // x-center of viewport window + int16 viewport_cy; // y-center of render window + int16 viewport_left; // x-left of viewport + int16 viewport_right; // x-right of viewport + int16 viewport_top; // y-top of viewport + int16 viewport_bottom; // y-bottom of viewport + + + // sprite structure + + int16 sprite_x; // projected x-pos of sprite + int16 sprite_y; // projected y-pos of sprite + int16 sprite_attr; // obj attributes + bool8 sprite_size; // sprite size: 8x8 or 16x16 + int16 sprite_clipy; // visible line to clip pixels off + int16 sprite_count; + + // generic projection variables designed for + // two solid polygons + two polygon sides + + int16 poly_clipLf[2][2]; // left clip boundary + int16 poly_clipRt[2][2]; // right clip boundary + int16 poly_ptr[2][2]; // HDMA structure pointers + int16 poly_raster[2][2]; // current raster line below horizon + int16 poly_top[2][2]; // top clip boundary + int16 poly_bottom[2][2]; // bottom clip boundary + int16 poly_cx[2][2]; // center for left/right points + int16 poly_start[2]; // current projection points + int16 poly_plane[2]; // previous z-plane distance + + + // OAM + int16 OAM_attr[16]; // OAM (size,MSB) data + int16 OAM_index; // index into OAM table + int16 OAM_bits; // offset into OAM table + + int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row) + int16 OAM_Row[32]; // current number of tiles per row +}; + +extern struct DSP4_vars_t DSP4_vars; + +#endif diff --git a/src/chip/obc1/obc1.cpp b/src/chip/obc1/obc1.cpp index 01bffac7..61001f04 100644 --- a/src/chip/obc1/obc1.cpp +++ b/src/chip/obc1/obc1.cpp @@ -1,7 +1,5 @@ #include "../../base.h" -OBC1 *obc1; - void OBC1::init() {} void OBC1::enable() {} diff --git a/src/chip/obc1/obc1.h b/src/chip/obc1/obc1.h index 81d885f3..24cea9a8 100644 --- a/src/chip/obc1/obc1.h +++ b/src/chip/obc1/obc1.h @@ -17,4 +17,4 @@ struct { ~OBC1(); }; -extern OBC1 *obc1; +extern OBC1 obc1; diff --git a/src/chip/sdd1/sdd1.cpp b/src/chip/sdd1/sdd1.cpp index 59afd23e..73d58fe1 100644 --- a/src/chip/sdd1/sdd1.cpp +++ b/src/chip/sdd1/sdd1.cpp @@ -1,7 +1,5 @@ #include "../../base.h" -SDD1 *sdd1; - #include "sdd1emu.cpp" void SDD1::init() {} diff --git a/src/chip/sdd1/sdd1.h b/src/chip/sdd1/sdd1.h index 591132f4..5da7e4ef 100644 --- a/src/chip/sdd1/sdd1.h +++ b/src/chip/sdd1/sdd1.h @@ -29,4 +29,4 @@ struct { SDD1(); }; -extern SDD1 *sdd1; +extern SDD1 sdd1; diff --git a/src/chip/srtc/srtc.cpp b/src/chip/srtc/srtc.cpp index 6d5ec861..649a0340 100644 --- a/src/chip/srtc/srtc.cpp +++ b/src/chip/srtc/srtc.cpp @@ -52,8 +52,6 @@ #include "../../base.h" -SRTC *srtc; - void SRTC::set_time() { time_t rawtime; tm *t; diff --git a/src/chip/srtc/srtc.h b/src/chip/srtc/srtc.h index 9dfee11d..64f5170e 100644 --- a/src/chip/srtc/srtc.h +++ b/src/chip/srtc/srtc.h @@ -49,4 +49,4 @@ struct { SRTC(); }; -extern SRTC *srtc; +extern SRTC srtc; diff --git a/src/chip/st010/st010.cpp b/src/chip/st010/st010.cpp index f65b7d6b..9db99739 100644 --- a/src/chip/st010/st010.cpp +++ b/src/chip/st010/st010.cpp @@ -2,8 +2,6 @@ #include "st010_data.h" #include "st010_op.cpp" -ST010 *st010; - int16 ST010::sin(int16 theta) { return sin_table[(theta >> 8) & 0xff]; } diff --git a/src/chip/st010/st010.h b/src/chip/st010/st010.h index f57bbdfe..33064743 100644 --- a/src/chip/st010/st010.h +++ b/src/chip/st010/st010.h @@ -37,4 +37,4 @@ static const uint8 arctan[32][32]; void write(uint16 addr, uint8 data); }; -extern ST010 *st010; +extern ST010 st010; diff --git a/src/chip/superfx/core/core.h b/src/chip/superfx/core/core.h new file mode 100644 index 00000000..c3588bac --- /dev/null +++ b/src/chip/superfx/core/core.h @@ -0,0 +1,3 @@ +void op_unknown() {} + +void op_00(); diff --git a/src/chip/superfx/core/op0x.cpp b/src/chip/superfx/core/op0x.cpp new file mode 100644 index 00000000..1ffaacc9 --- /dev/null +++ b/src/chip/superfx/core/op0x.cpp @@ -0,0 +1,7 @@ +//STOP +void SuperFX::op_00() { + regs.sfr.g = 0; + regs.sfr.b = 0; + regs.sfr.alt1 = 0; + regs.sfr.alt2 = 0; +} diff --git a/src/chip/superfx/memory/read.cpp b/src/chip/superfx/memory/read.cpp new file mode 100644 index 00000000..3546c493 --- /dev/null +++ b/src/chip/superfx/memory/read.cpp @@ -0,0 +1,64 @@ +uint8 SuperFX::mmio_read(uint16 addr) { + switch(addr) { + case 0x3000: return regs.r0.l; + case 0x3001: return regs.r0.h; + case 0x3002: return regs.r1.l; + case 0x3003: return regs.r1.h; + case 0x3004: return regs.r2.l; + case 0x3005: return regs.r2.h; + case 0x3006: return regs.r3.l; + case 0x3007: return regs.r3.h; + case 0x3008: return regs.r4.l; + case 0x3009: return regs.r4.h; + case 0x300a: return regs.r5.l; + case 0x300b: return regs.r5.h; + case 0x300c: return regs.r6.l; + case 0x300d: return regs.r6.h; + case 0x300e: return regs.r7.l; + case 0x300f: return regs.r7.h; + + case 0x3010: return regs.r8.l; + case 0x3011: return regs.r8.h; + case 0x3012: return regs.r9.l; + case 0x3013: return regs.r9.h; + case 0x3014: return regs.r10.l; + case 0x3015: return regs.r10.h; + case 0x3016: return regs.r11.l; + case 0x3017: return regs.r11.h; + case 0x3018: return regs.r12.l; + case 0x3019: return regs.r12.h; + case 0x301a: return regs.r13.l; + case 0x301b: return regs.r13.h; + case 0x301c: return regs.r14.l; + case 0x301d: return regs.r14.h; + case 0x301e: return regs.r15.l; + case 0x301f: return regs.r15.h; + +//0x3020 - 0x302f unused + + case 0x3030: return regs.sfr; + case 0x3031: return regs.sfr >> 8; + case 0x3032: return 0x00; //unused + case 0x3033: return 0x00; //BRAMR (write only) + case 0x3034: return regs.pbr; + case 0x3035: return 0x00; //unused + case 0x3036: return regs.rombr; + case 0x3037: return 0x00; //CFGR (write only) + case 0x3038: return 0x00; //SCBR (write only) + case 0x3039: return 0x00; //CLSR (write only) + case 0x303a: return 0x00; //SCMR (write only) + case 0x303b: return regs.vcr; + case 0x303c: return regs.rambr; + case 0x303d: return 0x00; //unused + case 0x303e: return regs.cbr; + case 0x303f: return regs.cbr >> 8; + +//0x3040 - 0x30ff unused + } + + if(addr >= 0x3100 && addr <= 0x32ff) { + return cache[addr - 0x3100]; + } + + return 0x00; +} diff --git a/src/chip/superfx/memory/write.cpp b/src/chip/superfx/memory/write.cpp new file mode 100644 index 00000000..b5bf951a --- /dev/null +++ b/src/chip/superfx/memory/write.cpp @@ -0,0 +1,63 @@ +void SuperFX::mmio_write(uint16 addr, uint8 data) { + switch(addr) { + case 0x3000: regs.r0.l = data; return; + case 0x3001: regs.r0.h = data; return; + case 0x3002: regs.r1.l = data; return; + case 0x3003: regs.r1.h = data; return; + case 0x3004: regs.r2.l = data; return; + case 0x3005: regs.r2.h = data; return; + case 0x3006: regs.r3.l = data; return; + case 0x3007: regs.r3.h = data; return; + case 0x3008: regs.r4.l = data; return; + case 0x3009: regs.r4.h = data; return; + case 0x300a: regs.r5.l = data; return; + case 0x300b: regs.r5.h = data; return; + case 0x300c: regs.r6.l = data; return; + case 0x300d: regs.r6.h = data; return; + case 0x300e: regs.r7.l = data; return; + case 0x300f: regs.r7.h = data; return; + + case 0x3010: regs.r8.l = data; return; + case 0x3011: regs.r8.h = data; return; + case 0x3012: regs.r9.l = data; return; + case 0x3013: regs.r9.h = data; return; + case 0x3014: regs.r10.l = data; return; + case 0x3015: regs.r10.h = data; return; + case 0x3016: regs.r11.l = data; return; + case 0x3017: regs.r11.h = data; return; + case 0x3018: regs.r12.l = data; return; + case 0x3019: regs.r12.h = data; return; + case 0x301a: regs.r13.l = data; return; + case 0x301b: regs.r13.h = data; return; + case 0x301c: regs.r14.l = data; return; + case 0x301d: regs.r14.h = data; return; + case 0x301e: regs.r15.l = data; return; + case 0x301f: regs.r15.h = data; return; + +//0x3020 - 0x302f unused + + case 0x3030: regs.sfr.l = data & 0x7e; return; //mask invalid bits + case 0x3031: regs.sfr.h = data & 0x9f; return; //mask invalid bits + case 0x3032: return; //unused + case 0x3033: regs.bramr = data; return; + case 0x3034: regs.pbr = data; return; + case 0x3035: return; //unused + case 0x3036: return; //ROMBR (read only) + case 0x3037: regs.cfgr = data; return; + case 0x3038: regs.scbr = data; return; + case 0x3039: regs.clsr = data; return; + case 0x303a: regs.scmr = data; return; + case 0x303b: return; //VCR (read only) + case 0x303c: return; //RAMBR (read only) + case 0x303d: return; //unused + case 0x303e: return; //CBR low (read only) + case 0x303f: return; //CBR high (read only) + +//0x3040 - 0x30ff unused + } + + if(addr >= 0x3100 && addr <= 0x32ff) { + cache[addr - 0x3100] = data; + return; + } +} diff --git a/src/chip/superfx/regs.h b/src/chip/superfx/regs.h new file mode 100644 index 00000000..30014a5b --- /dev/null +++ b/src/chip/superfx/regs.h @@ -0,0 +1,174 @@ +struct Reg16 { + union { + uint16 w; + struct { uint8 order_lsb2(l, h); }; + }; + + inline operator unsigned() const { return w; } + inline unsigned operator=(const unsigned i) { return w = i; } + + Reg16() : w(0) {} +}; + +template struct RegFlag8 { + uint8 data; + + inline operator bool() const { return data & bit; } + inline bool operator=(const bool i) { i ? data |= bit : data &= ~bit; return i; } +}; + +template struct RegFlag16 { + uint16 data; + + inline operator bool() const { return data & bit; } + inline bool operator=(const bool i) { i ? data |= bit : data &= ~bit; return i; } +}; + +struct SFR { + union { + uint16 w; + struct { uint8 order_lsb2(l, h); }; + RegFlag16<0x0002> z; //zero flag + RegFlag16<0x0004> c; //carry flag + RegFlag16<0x0008> s; //sign flag + RegFlag16<0x0010> v; //overflow flag + RegFlag16<0x0020> g; //go flag + RegFlag16<0x0040> r; //ROM read using r14 flag + RegFlag16<0x0100> alt1; //alternate instruction 1 flag + RegFlag16<0x0200> alt2; //alternate instruction 2 flag + RegFlag16<0x0400> il; //immediate lower 8-bit flag + RegFlag16<0x0800> ih; //immediate upper 8-bit flag + RegFlag16<0x1000> b; //WITH instruction flag + RegFlag16<0x8000> irq; //interrupt flag + }; + + inline operator unsigned() const { return w & 0x9f7e; } //invalid flag bits always return 0 when read + inline unsigned operator=(const unsigned i) { return w = i & 0x9f7e; } + + SFR() : w(0) {} +}; + +struct RAMBR { + union { + uint8 b; + RegFlag8<0x01> bank; + }; + + inline operator unsigned() const { return b & 0x01; } + inline unsigned operator=(const unsigned i) { return b = i & 0x01; } + + RAMBR() : b(0) {} +}; + +struct CBR { + uint16 w; + + inline operator unsigned() const { return w & 0xfff0; } + inline unsigned operator=(const unsigned i) { return w = i & 0xfff0; } + + CBR() : w(0) {} +}; + +struct SCMR { + union { + uint8 b; + RegFlag8<0x01> md0; //color mode low + RegFlag8<0x02> md1; //color mode high + RegFlag8<0x04> ht0; //height low + RegFlag8<0x08> ran; //ram enable + RegFlag8<0x10> ron; //rom enable + RegFlag8<0x20> ht1; //height high + }; + + inline operator unsigned() const { return b; } + inline unsigned operator=(const unsigned i) { return b = i; } + + SCMR() : b(0) {} +}; + +struct BRAMR { + union { + uint8 b; + RegFlag8<0x01> flag; + }; + + inline operator unsigned() const { return b; } + inline unsigned operator=(const unsigned i) { return b = i; } + + BRAMR() : b(0) {} +}; + +struct CFGR { + union { + uint8 b; + RegFlag8<0x20> ms0; //multiplier speed selection + RegFlag8<0x80> irq; //irq mask flag + }; + + inline operator unsigned() const { return b; } + inline unsigned operator=(const unsigned i) { return b = i; } + + CFGR() : b(0) {} +}; + +struct CLSR { + union { + uint8 b; + RegFlag8<0x01> flag; + }; + + inline operator unsigned() const { return b; } + inline unsigned operator=(const unsigned i) { return b = i; } + + CLSR() : b(0) {} +}; + +struct POR { + union { + uint8 b; + RegFlag8<0x01> transparent; //transparent flag + RegFlag8<0x02> dither; //dither flag + RegFlag8<0x04> highnibble; //high nibble flag + RegFlag8<0x08> freezehigh; //freeze high flag + RegFlag8<0x10> obj; //OBJ flag + }; + + inline operator unsigned() const { return b; } + inline unsigned operator=(const unsigned i) { return b = i; } + + POR() : b(0) {} +}; + +struct Regs { + Reg16 r0; //default source/destination register + Reg16 r1; //pixel plot X position register + Reg16 r2; //pixel plot Y position register + Reg16 r3; + Reg16 r4; //lower 16-bit result of lmult + Reg16 r5; + Reg16 r6; //multiplier for fmult and lmult + Reg16 r7; //fixed point texel X position for merge + Reg16 r8; //fixed point texel Y position for merge + Reg16 r9; + Reg16 r10; + Reg16 r11; //return address set by link + Reg16 r12; //loop counter + Reg16 r13; //loop point address + Reg16 r14; //rom address for getb, getbh, getbl, getbs + Reg16 r15; //program counter + + SFR sfr; //status/flag register + uint8 pbr; //program bank register + uint8 rombr; //rom bank register + RAMBR rambr; //ram bank register + CBR cbr; //cache base register + uint8 scbr; //screen base register + SCMR scmr; //screen mode register + BRAMR bramr; //backup ram register + uint8 vcr; //version code register + CFGR cfgr; //config register + CLSR clsr; //clock select register + + uint8 colr; //color register + POR por; //plot option register +} regs; diff --git a/src/chip/superfx/superfx.cpp b/src/chip/superfx/superfx.cpp new file mode 100644 index 00000000..d4adf6ee --- /dev/null +++ b/src/chip/superfx/superfx.cpp @@ -0,0 +1,42 @@ +#include "../../base.h" + +#include "core/op0x.cpp" + +#include "memory/read.cpp" +#include "memory/write.cpp" + +void SuperFX::init() { +} + +void SuperFX::enable() { + for(uint i = 0x3000; i <= 0x32ff; i++) { + r_mem->set_mmio_mapper(i, this); + } +} + +void SuperFX::power() { + reset(); +} + +void SuperFX::reset() { + regs.r0 = 0; + regs.r1 = 0; + regs.r2 = 0; + regs.r3 = 0; + regs.r4 = 0; + regs.r5 = 0; + regs.r6 = 0; + regs.r7 = 0; + regs.r8 = 0; + regs.r9 = 0; + regs.r10 = 0; + regs.r11 = 0; + regs.r12 = 0; + regs.r13 = 0; + regs.r14 = 0; + regs.r15 = 0; + + regs.sfr = 0; + + memset(cache, 0, sizeof cache); +} diff --git a/src/chip/superfx/superfx.h b/src/chip/superfx/superfx.h new file mode 100644 index 00000000..052e74f9 --- /dev/null +++ b/src/chip/superfx/superfx.h @@ -0,0 +1,17 @@ +class SuperFX : public MMIO { public: + #include "core/core.h" + + void init(); + void enable(); + void power(); + void reset(); + + uint8 mmio_read (uint16 addr); + void mmio_write(uint16 addr, uint8 data); + +private: + #include "regs.h" + uint8 cache[512]; //cache RAM +}; + +extern SuperFX superfx; diff --git a/src/clean.bat b/src/clean.bat index 134107c6..0452d928 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -1 +1,2 @@ +::@make PLATFORM=win-mingw4-lui clean @make PLATFORM=win-visualc-lui clean diff --git a/src/cpu/scpu/dma/dma.cpp b/src/cpu/scpu/dma/dma.cpp index c1d87fe5..87f916b3 100644 --- a/src/cpu/scpu/dma/dma.cpp +++ b/src/cpu/scpu/dma/dma.cpp @@ -83,8 +83,8 @@ inline uint32 sCPU::hdma_iaddr(uint8 i) { *****/ void sCPU::dma_transfertobusb(uint8 i, uint8 bbus) { - if(cartridge.info.sdd1 == true && sdd1->dma_active() == true) { - r_mem->write(0x2100 | bbus, sdd1->dma_read()); + if(cartridge.info.sdd1 == true && sdd1.dma_active() == true) { + r_mem->write(0x2100 | bbus, sdd1.dma_read()); } else { dma_transfer(0, bbus, dma_addr(i)); } @@ -111,8 +111,7 @@ void sCPU::dma_run() { dma_add_clocks(8); if(cartridge.info.sdd1 == true) { - sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), - channel[i].xfersize); + sdd1.dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr), channel[i].xfersize); } if(tracer.enabled() == true && tracer.cpudma_enabled() == true) { diff --git a/src/cpu/scpu/scpu.h b/src/cpu/scpu/scpu.h index a9c991ed..dc90a0c5 100644 --- a/src/cpu/scpu/scpu.h +++ b/src/cpu/scpu/scpu.h @@ -1,8 +1,6 @@ -class sCPU : public CPU { -public: +class sCPU : public CPU { public: void enter(); -public: #include "core/core.h" #include "dma/dma.h" #include "memory/memory.h" diff --git a/src/data/bsnes_old.ico b/src/data/bsnes_old.ico deleted file mode 100644 index a396add1a72bc149ec45f1cf5b39cd34a25bd022..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmeH}Pe@cz6o>DmIa1|IK*cf;+GiDl>7rK^g>-FbOZ<7({donjPT57$hK>YjthjzyNe)eeGEW@f1kIM>v}4@yr%7j_T1EF(_TZ=9eyD-NGne5{zWzEA^rpb?QR@1w zo4>G5@)i8PbL;TT1^j0mYtX#w>W^qA9EZKIF<+Am(K}t>OUkS|^7o!;LsM%gwFlb& z651KO3`QXh@8N#dU%zXTD(W@2hInS2XByEx0{VREbExxFzc@_55OhPM=Hqt|UW1*~ z7}tlm-3ssWVcT7_?a9{de#U15yz+UgxUPf7*atZY35Oa!ku$IN6Z*RDpCM>Mlf*C5 z#c!3|fMjr5X6SeNoZn06)?AjsRsZqwgHigFG{!9Md^&kwi;OI%kRy*2O@bd9Y~ zv9_O_ZFz0c{n!tepc_`?`$}J-wGz%l5{h}+c#52x&{|sAEd#B^a0Oia$H}{@W8Bo; zve0V-{eI1WovXjqeThL7+TB#$v(OB|VHk$O=TB>j=lXcZ{JjH@eef8bgU(rb0QaEm z^A4H`J`JFC^uY<(9hA2aTUddAWd-;fJ^M(7L}L8TL{0B+V&+41RmCGOA|ocuQy=D) uQpMlonr0K-z9}S$x{$=GDTVGpswe9w6 zzdn|)SxRe_x^>q+0*a!BBm@)`3Mwdw1$l|`6yyyFB!Qb31W*ZzX#35~&AqwzCV`;r z_SfI92Xbfb%-l2obLPyMGm{HXFM4D#z!dR40K#Cd2!8$oKLYSWT#hc&#nk6(m`5K( zUw{2IFdB{Et+(C+vIk}0(T5)ea}{&JQ*)jI??=B6X8d9XSig2Xh?o@tmMmTZHg4Dm zR=l_ZRGh8=Cir|g{3PCbD_C~tonTvdIM^taf<-bJSTlPzcx}M~u=?3&!Lv_21rq=H zPmrb2fMp98g1PWMFFPB2^6|&uL{1L)^Qu)~*^(t-;r#ia=ImKeUR(?|tX~gSuUrYT zGc&=j9(@$-h>HWumn{Q}pL-6>hdfuj_##M6NdcdI`YG75c{5nQehpZ%WFd%*{54py z;sx->KQ0Gz=l%{vM9c(_JQ4x#p9kBwe+=GxPYE7)UDAaZU2ps{w|LXU_-8=3E;z%)gaQ%Z|#&2hU$De;3EdJ|a@Yc4s zz}k1#g3UWOgSiXmfL9F$j6<;%f~P+zaX=l=D{Ct&&W&x7AWJ(rz6 z4c__N-@xiMYe4KrA3?#o;pZ422ot#F76TBAKL#>c4*2O${{ZI9*#u_JTmW^r1}t6r z3cOzk_U$_aVq-rAsj1mee>*`!!XA*3kqy*p4S4$L-+`B3eg$M@WrMH2`U+gXejQxB zdKHX}i~zUW4Tgq>fYa#&y}iAlySp103aU~(6crVL!oosOP*4C)oHzlFA3qMq>lnz* z%>_Boj*c8T0y3e!WMpK3g9i_S0|yR3+^HZ1+DUS9GSKOCK&#b)q@*M$*FLak&mORA z*Dfei0*Hq?jDt4z`RAX5PoYh1-@YAe+qMmS3~hAl)~#U6mM!4J4?hH(Hf;hiF)`4N z-UCWFF7LkkE{KYX0&lVLbm>xP!*CwJIkEuGoq6--foGn11}LBn z%z@(^85s$leDXX_2Q`);ORpJ!ngm9=$saN)0sh>3`(t*NdGri&o(@5wvY z)6-axuGbJAN=iPEQ)Q4upVIokxUqsg$7?M;jVC!>q~*jIWWtHMm=J$jwbfLtr;)Q$ z?cqjQeb$Z}L(G0kcSaKCzYASXleOj8E_P#Heggbi?edruHfU~MbF!!FSOSmbByZCi z>UzG>wbaPi2A3(ApN) z)&_T@QSb*-TYDT;($X457qxk))863WqN#EBx6ycg(OKmG_%HL@WQ8@}j{PHK)YkK9_`gKP)=R7r-C>Bzf5cSf{Z1T%?SH)$dLF zkQ|GfVdo3r2mfAM`4r+CpOwzy?(mD4U+5UfMw~JnJQMQ8pJ=Wbzt1VGUFjO+0}XU9 z8;(aEA69W=E+70mqvNI!;P|W#idBK&`j(sBd5BwqjN_?&@Sn8fsWN`YQ&XE3F7kyL zxFl@&80xpSg&j-q@oW1srUu-^T#{YNz+nB=nA};2tK|gC3GwjnG*$%eShxRR#!A}l z1#T8(janMe_8S|T_)9UCM-@ku?(P2cS^cZaaS@ZGU=pRsSzqeHt{4poLX!JIq)R z7k_O%>VZ!gVb(KQ-Y}OS^m&cW7}mysM&+_E*<-A5hq0NEx)>TLk00)1SAN41j!~A=s zLg!fqKGHW*uP0&S$3?h+t^YKim^|&4!$`uE99I1S6%e*Ds{IJp!=t z?{WG%mjm*1jG@3U9JHDw=JpU&79wmb$neoGxu{*<9o3E$cl9vJn&bo zdTF_uh`DIt31CqnOP0p_!C%x3Yq*qRXZ&fF^5O;YrQzXWB|RR=VU4IY#?Q&{%9sXB zqtpwXJXqL%qU5PDYbouc>tDVkh~ooxUdxNHlqhKP#lORVBMj6DO&ZA=CfhF-!Ec~c zD%FUYF4LLt9?hd`TIF;tmHI8M6!Sn~;}>*>5tf&{_}4{27HN_J?ph#2-6zR4lmIOI z(c`JX>AlsvjafM?BT2;@BuVzEm^Nw3FPQu!GHN^DDjG7q|E0?q#>F2> zF(|sg@wF}#ALlgl@h3!i_L)qt8Yd2zsQbJt64Es)zD$xLr;cet^s=`)IVJ;z-vEyS<0pmRIwxJe2Cl~ zZXI)watDe+Jd|bE(^;Z)G+Z&vOc-2z$UWk6hvza)sEozz#mvct$LIcqM!#y+D@-tu z(j|^!8a59i2V$mnVqW}TNO-+yorhT^Cq_tXq>UWDOj;eZ147lN({v;4kP8}DNDpgt zh}sZ1VZyIQdo2#OPVe)A!KfJJ%FP71juv38k>(83h;XmR8Yo5u_Q^ z?&Vjb7?IQS|G9m?I$mM(h;2p#v%i*$e@6ow6>Oj}9b{m@OtG8n4@>sc@o(Blxm=dlLkYpD}7+)6OPmN07sF9uoMrQg-4Vq(%7CZ}S z!Qxbt3Y}tgT>KduhmY2Phk|cu(+BO$s@ZzzYY4D-?BdYKH5I)7 zYHS#pwN-uyHt9Zz8q!o2u7owD$!qRJQXQTcJt_)+au{--FkUt&v`Z=N;}KY-CsI55 z(Q%e}l#W}nV?El3$p`;X|H^?42%it~{Ld~MGIti$<5kDnM=Gz5hL73dx_b>?$iZte zQZecrxdtVWiO@5iN~pr&s;2Vv^{~~Y>hR1H9gUwf>le}11Ji|=PyQhCGOa`X zcou)c!M|b-3qMc)iB?{iQit(NE{%;2SjnrKDG^fgnF*~i!i~8A{*bqF@l#g6(%?e-UQsw&j|y4#^L}jV)6|KP{1mL>`kx(% zJ>FOocUgzmCDKLqkB(iu28}xW3R1uInw%UMQ;d#@;iPmRob4sJeb5)=f1vdX1r`U# zex9S(%UU;DYK`u$BqC$0*L*(s2k~oa<**}YT>OH>Zm%1}P-;q1A{l^~osrj}{;k)B zNYWkx<2ct>qXXETs?Z!UG2a5A2ZEqZGljq7`FhvMx+cKx~Pv!_eGjB(*L zS0a;;{qpqGRJ}eq8LxQFRjh}C%Ia;*$)MK|JP6MfOL1}%>TjL zUQuLI{K2$TeSz$XSPQR zg?$jKAc$<7_h7ImJ+Pe&>ek8uVK5H);Sz zEkrc6f%opecA1&^PjURhjP>hbuW>4`kGT3(qa$Qk3#-e5Zl2hzxGP)sDJ|v;giPlSf4|Rm=)xY4l z#lwV73Z<+8NOCyI(LT}*WpJFQTM$G($y>I)RpaCgbOepD^$pV=SpC!Kl=ji}jzjJ5 zd9kA$)_1F3;{DKDVge8c~e(yrk#h5NMnaoTN0l2%gD zvw)-j1WPszj82<78RuXU^@eqs&0z+koj#9Bx6y8!ZXax#Eb<=bQ1BFP^rFnYEc^fQ zFQeY&Ku0%C3K+7$m?f1m9}a#&VVF<&NTFNcNvVvE(;x~OtbNiTzno6Sa529 z4~-0oP!p$r%oxz^ccs7O^X-LDicbqp(8uRo{E2cVNM|~3xn+;b-_z+I*F7wIY{?Zjt?1exhkKNr8C(CiDK#)+0|AJWDs*~^1Z{X_*B z1H3~-p|B-f9G~X66T6`4KRJK&iUB$t95FEXU3kRv+n6s<+4EN**xk!Iai$UE+6_Kt zt}Y}4jtl+V1Zjzaw>m+Pw#c`W*X ztG9dgS!ZVvdv}vD%Odx@mga3W>0AdBhSKna!m!KlWgI9xGb=v*%o`~BLEB6(h4!Jy zXJ0iHdSVme>L2=7@7lxyq$!nJqs#MivNE&d3oF{~MnA*EY93rxYh{H&G{}~|AxrI< zm{uhYpSjj!bR9*USJJ*83BbpnD8bg)DAAexy?@eT ze7EDXd$7PYPlrmo*(Q5ZeLltq@FYf!&!g+hlcm5)&cGk6F zH#=^>Q&xGP-8In=$du^74SLSP9_m|1O84mMPyd3Q5#9f}IRLlfy|(&jADz<$O{V^H z)Z(+R!or8|AHP6QCPCrse~L5}HhFYC4VaU*NR-hYhq$M~z%!me`iJGYq5$i_zelFz z5`&6tY2-i`wivB_mb3J+V6wE<&tH1@wI5_yI&&)>Isbbg^SORe(Q0+d%w3($wGq{I z!p@e2f5W`p-+gJ$(jq}nQZ5ogs3M*pzQt^#R$`krqBF}qJ)jIEmW#-|rM z%8jRgSeLYMbQ4%6{peoe zg!EGPNnfYQ5@bUBuxmuaQ*ROQStya0nH8kuVxqL-DH0W{-C{^Y{ZnVZyyeAtJenG;)vQ~4qL2BtT z8amoqTM#muR22!kZ=7~zD=0ylnwwjqTH``PjV6n!%Vg>5s4vMH*L1K1!QqEZcj=B6 z)pdqRd!Zb0&Cw0f4fXX6=NpBs%6MO`Orj)N++(p=OpweLGt3z~qJ%YNCy(ym%YMy2 zAj6>XV-5+4gnn99eEye3#U+@EPZb?!-bD`B$#@kBsqlY>9L~offset(addr) % cartridge.info.rom_size; + addr = sdd1.offset(addr) % cartridge.info.rom_size; return cartridge.rom[addr]; } void bMemBus::write_sdd1(uint32 addr, uint8 data) { if(cart_write_protect_enabled == true)return; - addr = sdd1->offset(addr) % cartridge.info.rom_size; + addr = sdd1.offset(addr) % cartridge.info.rom_size; cartridge.rom[addr] = data; } // -uint8 bMemBus::read_c4 (uint32 addr) { return c4->read(addr); } -void bMemBus::write_c4(uint32 addr, uint8 data) { c4->write(addr, data); } +uint8 bMemBus::read_c4 (uint32 addr) { return c4.read(addr); } +void bMemBus::write_c4(uint32 addr, uint8 data) { c4.write(addr, data); } -uint8 bMemBus::read_dsp1 (uint32 addr) { return dsp1->read(addr); } -void bMemBus::write_dsp1(uint32 addr, uint8 data) { dsp1->write(addr, data); } +uint8 bMemBus::read_dsp1 (uint32 addr) { return dsp1.read(addr); } +void bMemBus::write_dsp1(uint32 addr, uint8 data) { dsp1.write(addr, data); } -uint8 bMemBus::read_dsp2 (uint32 addr) { return dsp2->read(addr); } -void bMemBus::write_dsp2(uint32 addr, uint8 data) { dsp2->write(addr, data); } +uint8 bMemBus::read_dsp2 (uint32 addr) { return dsp2.read(addr); } +void bMemBus::write_dsp2(uint32 addr, uint8 data) { dsp2.write(addr, data); } -uint8 bMemBus::read_obc1 (uint32 addr) { return obc1->read(addr); } -void bMemBus::write_obc1(uint32 addr, uint8 data) { obc1->write(addr, data); } +uint8 bMemBus::read_dsp3 (uint32 addr) { return dsp3.read(addr); } +void bMemBus::write_dsp3(uint32 addr, uint8 data) { dsp3.write(addr, data); } -uint8 bMemBus::read_st010 (uint32 addr) { return st010->read(addr); } -void bMemBus::write_st010(uint32 addr, uint8 data) { st010->write(addr, data); } +uint8 bMemBus::read_dsp4 (uint32 addr) { return dsp4.read(addr); } +void bMemBus::write_dsp4(uint32 addr, uint8 data) { dsp4.write(addr, data); } + +uint8 bMemBus::read_obc1 (uint32 addr) { return obc1.read(addr); } +void bMemBus::write_obc1(uint32 addr, uint8 data) { obc1.write(addr, data); } + +uint8 bMemBus::read_st010 (uint32 addr) { return st010.read(addr); } +void bMemBus::write_st010(uint32 addr, uint8 data) { st010.write(addr, data); } diff --git a/src/memory/bmemory/mapper/mapper.cpp b/src/memory/bmemory/mapper/mapper.cpp index accfe7dc..1f86ddb8 100644 --- a/src/memory/bmemory/mapper/mapper.cpp +++ b/src/memory/bmemory/mapper/mapper.cpp @@ -1,30 +1,33 @@ bool bMemBus::cart_map_pcb(const char *pcb) { - if(!strcmp(pcb, "SHVC-1A3B-01")) { cart_map_shvc_1a3b_13(); return true; } - if(!strcmp(pcb, "SHVC-1A3B-11")) { cart_map_shvc_1a3b_13(); return true; } - if(!strcmp(pcb, "SHVC-1A3B-12")) { cart_map_shvc_1a3b_13(); return true; } - if(!strcmp(pcb, "SHVC-1A3B-13")) { cart_map_shvc_1a3b_13(); return true; } + if(!strcmp(pcb, "SHVC-1CB5B-01")) { cart_map_shvc_1cb5b_20(); return true; } + if(!strcmp(pcb, "SHVC-1CB5B-20")) { cart_map_shvc_1cb5b_20(); return true; } - if(!strcmp(pcb, "SHVC-1A3B-20")) { cart_map_shvc_1a3b_20(); return true; } + if(!strcmp(pcb, "SHVC-1A3B-01")) { cart_map_shvc_1a3b_13(); return true; } + if(!strcmp(pcb, "SHVC-1A3B-11")) { cart_map_shvc_1a3b_13(); return true; } + if(!strcmp(pcb, "SHVC-1A3B-12")) { cart_map_shvc_1a3b_13(); return true; } + if(!strcmp(pcb, "SHVC-1A3B-13")) { cart_map_shvc_1a3b_13(); return true; } - if(!strcmp(pcb, "SHVC-1A3M-10")) { cart_map_shvc_1a3m_30(); return true; } - if(!strcmp(pcb, "SHVC-1A3M-20")) { cart_map_shvc_1a3m_30(); return true; } - if(!strcmp(pcb, "SHVC-1A3M-21")) { cart_map_shvc_1a3m_30(); return true; } - if(!strcmp(pcb, "SHVC-1A3M-30")) { cart_map_shvc_1a3m_30(); return true; } + if(!strcmp(pcb, "SHVC-1A3B-20")) { cart_map_shvc_1a3b_20(); return true; } - if(!strcmp(pcb, "SHVC-1J3M-01")) { cart_map_shvc_1j3m_20(); return true; } - if(!strcmp(pcb, "SHVC-1J3M-10")) { cart_map_shvc_1j3m_20(); return true; } - if(!strcmp(pcb, "SHVC-1J3M-11")) { cart_map_shvc_1j3m_20(); return true; } - if(!strcmp(pcb, "SHVC-1J3M-20")) { cart_map_shvc_1j3m_20(); return true; } + if(!strcmp(pcb, "SHVC-1A3M-10")) { cart_map_shvc_1a3m_30(); return true; } + if(!strcmp(pcb, "SHVC-1A3M-20")) { cart_map_shvc_1a3m_30(); return true; } + if(!strcmp(pcb, "SHVC-1A3M-21")) { cart_map_shvc_1a3m_30(); return true; } + if(!strcmp(pcb, "SHVC-1A3M-30")) { cart_map_shvc_1a3m_30(); return true; } - if(!strcmp(pcb, "BSC-1A5M-01")) { cart_map_bsc_1a5m_01(); return true; } + if(!strcmp(pcb, "SHVC-1J3M-01")) { cart_map_shvc_1j3m_20(); return true; } + if(!strcmp(pcb, "SHVC-1J3M-10")) { cart_map_shvc_1j3m_20(); return true; } + if(!strcmp(pcb, "SHVC-1J3M-11")) { cart_map_shvc_1j3m_20(); return true; } + if(!strcmp(pcb, "SHVC-1J3M-20")) { cart_map_shvc_1j3m_20(); return true; } - if(!strcmp(pcb, "BSC-1A7M-01")) { cart_map_bsc_1a7m_01(); return true; } + if(!strcmp(pcb, "BSC-1A5M-01")) { cart_map_bsc_1a5m_01(); return true; } - if(!strcmp(pcb, "BSC-1A7M-10")) { cart_map_bsc_1a7m_10(); return true; } + if(!strcmp(pcb, "BSC-1A7M-01")) { cart_map_bsc_1a7m_01(); return true; } - if(!strcmp(pcb, "STC-SOLO")) { cart_map_stc_solo(); return true; } + if(!strcmp(pcb, "BSC-1A7M-10")) { cart_map_bsc_1a7m_10(); return true; } - if(!strcmp(pcb, "STC-DUAL")) { cart_map_stc_dual(); return true; } + if(!strcmp(pcb, "STC-SOLO")) { cart_map_stc_solo(); return true; } + + if(!strcmp(pcb, "STC-DUAL")) { cart_map_stc_dual(); return true; } return false; } diff --git a/src/memory/bmemory/mapper/mapper.h b/src/memory/bmemory/mapper/mapper.h index 2ce0a3a3..24cb1d4f 100644 --- a/src/memory/bmemory/mapper/mapper.h +++ b/src/memory/bmemory/mapper/mapper.h @@ -19,6 +19,7 @@ enum { void cart_map_range(uint mode, uint8 bank_lo, uint8 bank_hi, uint16 addr_lo, uint16 addr_hi, uint type, uint offset = 0); #define mapper(name) void cart_map_##name() + mapper(shvc_1cb5b_20); mapper(shvc_1a3b_13); mapper(shvc_1a3b_20); mapper(shvc_1a3m_30); diff --git a/src/memory/bmemory/mapper/mapper_pcb.cpp b/src/memory/bmemory/mapper/mapper_pcb.cpp index b4171115..a293d37a 100644 --- a/src/memory/bmemory/mapper/mapper_pcb.cpp +++ b/src/memory/bmemory/mapper/mapper_pcb.cpp @@ -1,3 +1,15 @@ +//SHVC-1CB5B-01 +//SHVC-1CB5B-20 +mapper(shvc_1cb5b_20) { + cartridge.info.superfx = true; //TODO: make this more elegant + + map(LINEAR, 0x00, 0x3f, 0x6000, 0x7fff, MAP_RAM); + map(LINEAR, 0x00, 0x3f, 0x8000, 0xffff, MAP_ROM); + map(LINEAR, 0x40, 0x5f, 0x0000, 0xffff, MAP_ROM); + map(LINEAR, 0x70, 0x71, 0x0000, 0xffff, MAP_RAM); + map(LINEAR, 0x80, 0xbf, 0x6000, 0x7fff, MAP_RAM); +} + //SHVC-1A3B-01 //SHVC-1A3B-11 //SHVC-1A3B-12 diff --git a/src/snes/snes.cpp b/src/snes/snes.cpp index f6db6388..31225c0b 100644 --- a/src/snes/snes.cpp +++ b/src/snes/snes.cpp @@ -1,6 +1,16 @@ #include "../base.h" SNES snes; +SuperFX superfx; +SRTC srtc; +SDD1 sdd1; +C4 c4; +DSP1 dsp1; +DSP2 dsp2; +DSP3 dsp3; +DSP4 dsp4; +OBC1 obc1; +ST010 st010; #include "scheduler/scheduler.cpp" #include "tracer/tracer.cpp" @@ -16,21 +26,16 @@ void SNES::runtoframe() { } void SNES::init() { - srtc = new SRTC(); - sdd1 = new SDD1(); - c4 = new C4(); - dsp1 = new DSP1(); - dsp2 = new DSP2(); - obc1 = new OBC1(); - st010 = new ST010(); - - srtc->init(); - sdd1->init(); - c4->init(); - dsp1->init(); - dsp2->init(); - obc1->init(); - st010->init(); + superfx.init(); + srtc.init(); + sdd1.init(); + c4.init(); + dsp1.init(); + dsp2.init(); + dsp3.init(); + dsp4.init(); + obc1.init(); + st010.init(); video_init(); audio_init(); @@ -52,13 +57,16 @@ void SNES::power() { r_ppu->power(); r_mem->power(); - if(cartridge.info.srtc) srtc->power(); - if(cartridge.info.sdd1) sdd1->power(); - if(cartridge.info.c4) c4->power(); - if(cartridge.info.dsp1) dsp1->power(); - if(cartridge.info.dsp2) dsp2->power(); - if(cartridge.info.obc1) obc1->power(); - if(cartridge.info.st010)st010->power(); + if(cartridge.info.superfx)superfx.power(); + if(cartridge.info.srtc) srtc.power(); + if(cartridge.info.sdd1) sdd1.power(); + if(cartridge.info.c4) c4.power(); + if(cartridge.info.dsp1) dsp1.power(); + if(cartridge.info.dsp2) dsp2.power(); + if(cartridge.info.dsp3) dsp3.power(); + if(cartridge.info.dsp4) dsp4.power(); + if(cartridge.info.obc1) obc1.power(); + if(cartridge.info.st010) st010.power(); r_mem->flush_mmio_mappers(); for(int i = 0x2100; i <= 0x213f; i++)r_mem->set_mmio_mapper(i, r_ppu); @@ -68,13 +76,16 @@ void SNES::power() { for(int i = 0x4200; i <= 0x421f; i++)r_mem->set_mmio_mapper(i, r_cpu); for(int i = 0x4300; i <= 0x437f; i++)r_mem->set_mmio_mapper(i, r_cpu); - if(cartridge.info.srtc) srtc->enable(); - if(cartridge.info.sdd1) sdd1->enable(); - if(cartridge.info.c4) c4->enable(); - if(cartridge.info.dsp1) dsp1->enable(); - if(cartridge.info.dsp2) dsp2->enable(); - if(cartridge.info.obc1) obc1->enable(); - if(cartridge.info.st010)st010->enable(); + if(cartridge.info.superfx)superfx.enable(); + if(cartridge.info.srtc) srtc.enable(); + if(cartridge.info.sdd1) sdd1.enable(); + if(cartridge.info.c4) c4.enable(); + if(cartridge.info.dsp1) dsp1.enable(); + if(cartridge.info.dsp2) dsp2.enable(); + if(cartridge.info.dsp3) dsp3.enable(); + if(cartridge.info.dsp4) dsp4.enable(); + if(cartridge.info.obc1) obc1.enable(); + if(cartridge.info.st010) st010.enable(); video_update(); } @@ -88,13 +99,16 @@ void SNES::reset() { r_ppu->reset(); r_mem->reset(); - if(cartridge.info.srtc) srtc->reset(); - if(cartridge.info.sdd1) sdd1->reset(); - if(cartridge.info.c4) c4->reset(); - if(cartridge.info.dsp1) dsp1->reset(); - if(cartridge.info.dsp2) dsp2->reset(); - if(cartridge.info.obc1) obc1->reset(); - if(cartridge.info.st010)st010->reset(); + if(cartridge.info.superfx)superfx.reset(); + if(cartridge.info.srtc) srtc.reset(); + if(cartridge.info.sdd1) sdd1.reset(); + if(cartridge.info.c4) c4.reset(); + if(cartridge.info.dsp1) dsp1.reset(); + if(cartridge.info.dsp2) dsp2.reset(); + if(cartridge.info.dsp3) dsp3.reset(); + if(cartridge.info.dsp4) dsp4.reset(); + if(cartridge.info.obc1) obc1.reset(); + if(cartridge.info.st010) st010.reset(); video_update(); } diff --git a/src/ui/bsnes.rc b/src/ui/bsnes.rc index 2399e59d..9a76d707 100644 --- a/src/ui/bsnes.rc +++ b/src/ui/bsnes.rc @@ -1,5 +1,3 @@ -#define IDI_APP_ICON 100 -#define IDI_CONTROLLER 101 +#define IDI_APP_ICON 100 -IDI_APP_ICON ICON DISCARDABLE "../data/bsnes.ico" -IDI_CONTROLLER BITMAP DISCARDABLE "../data/snes_controller.bmp" +IDI_APP_ICON ICON DISCARDABLE "../data/bsnes.ico" diff --git a/src/ui/config.cpp b/src/ui/config.cpp index 7c26c405..5db727be 100644 --- a/src/ui/config.cpp +++ b/src/ui/config.cpp @@ -26,46 +26,62 @@ IntegerSetting System::speed_fast (&config(), "system.speed_fast", "Fast IntegerSetting System::speed_fastest (&config(), "system.speed_fastest", "Fastest speed setting", IntegerSetting::Decimal, 200); struct Video { - static IntegerSetting synchronize; - static IntegerSetting fullscreen; - static IntegerSetting multiplier, aspect_correction, region; + static IntegerSetting mode; + struct Windowed { + static IntegerSetting synchronize, aspect_correction; + static IntegerSetting region, multiplier, hardware_filter, software_filter; + } windowed; + struct Fullscreen { + static IntegerSetting synchronize, aspect_correction; + static IntegerSetting region, multiplier, hardware_filter, software_filter; + } fullscreen; static IntegerSetting aspect_ntsc_x, aspect_ntsc_y, aspect_pal_x, aspect_pal_y; - static IntegerSetting hardware_filter, software_filter; static IntegerSetting frameskip; static IntegerSetting use_vram; } video; -IntegerSetting Video::synchronize(&config(), "video.synchronize", "Synchronize to video refresh rate.", IntegerSetting::Boolean, false); -IntegerSetting Video::fullscreen(0, "video.fullscreen", "", IntegerSetting::Boolean, false); -IntegerSetting Video::multiplier(&config(), "video.multiplier", "Video output size multiplier (1-5x)\n" - "1 = 1x (~256x224)\n" - "2 = 2x (~512x448)\n" - "etc.", - IntegerSetting::Decimal, 2); -IntegerSetting Video::aspect_correction(&config(), "video.aspect_correction", + +//0 = windowed, 1 = fullscreen, 2 = exclusive +IntegerSetting Video::mode(0, "video.mode", "Active video mode", IntegerSetting::Decimal, 0); + +IntegerSetting Video::Windowed::synchronize(&config(), "video.windowed.synchronize", "Synchronize to video refresh rate", IntegerSetting::Boolean, false); +IntegerSetting Video::Windowed::aspect_correction(&config(), "video.windowed.aspect_correction", "Correct video aspect ratio\n" - "Formula: width = width * video.aspect__x / video.aspect__y", + "Defaults assume display pixels are perfectly square\n" + "Formula: width = width * video.aspect__x / video.aspect__y\n", IntegerSetting::Boolean, true); -IntegerSetting Video::region(&config(), "video.region", "Video output region\n" +IntegerSetting Video::Windowed::region(&config(), "video.windowed.region", "Video output region\n" "0 = NTSC, 1 = PAL", IntegerSetting::Decimal, 0); +IntegerSetting Video::Windowed::multiplier(&config(), "video.windowed.multiplier", "Video output size multiplier (1-5x)\n" + "1 = 1x (<= 320x240)\n" + "2 = 2x (<= 640x480)\n" + "etc.", + IntegerSetting::Decimal, 2); +IntegerSetting Video::Windowed::hardware_filter(&config(), "video.windowed.hardware_filter", "Video hardware filter\n" + "0 = Point\n" + "1 = Linear\n", + IntegerSetting::Decimal, 1); +IntegerSetting Video::Windowed::software_filter(&config(), "video.windowed.software_filter", "Video software filter\n" + "0 = None\n" + "1 = NTSC\n" + "2 = HQ2x\n" + "3 = Scale2x\n", + IntegerSetting::Decimal, 0); + +IntegerSetting Video::Fullscreen::synchronize (&config(), "video.fullscreen.synchronize", "", IntegerSetting::Boolean, false); +IntegerSetting Video::Fullscreen::aspect_correction(&config(), "video.fullscreen.aspect_correction", "", IntegerSetting::Boolean, true); +IntegerSetting Video::Fullscreen::region (&config(), "video.fullscreen.region", "", IntegerSetting::Decimal, 0); +IntegerSetting Video::Fullscreen::multiplier (&config(), "video.fullscreen.multiplier", "", IntegerSetting::Decimal, 2); +IntegerSetting Video::Fullscreen::hardware_filter (&config(), "video.fullscreen.hardware_filter", "", IntegerSetting::Decimal, 1); +IntegerSetting Video::Fullscreen::software_filter (&config(), "video.fullscreen.software_filter", "", IntegerSetting::Decimal, 0); IntegerSetting Video::aspect_ntsc_x(&config(), "video.aspect_ntsc_x", "", IntegerSetting::Decimal, 54); IntegerSetting Video::aspect_ntsc_y(&config(), "video.aspect_ntsc_y", "", IntegerSetting::Decimal, 47); IntegerSetting Video::aspect_pal_x (&config(), "video.aspect_pal_x", "", IntegerSetting::Decimal, 32); IntegerSetting Video::aspect_pal_y (&config(), "video.aspect_pal_y", "", IntegerSetting::Decimal, 23); -IntegerSetting Video::hardware_filter(&config(), "video.hardware_filter", "Video hardware filter\n" - "0 = Point\n" - "1 = Linear\n", - IntegerSetting::Decimal, 1); -IntegerSetting Video::software_filter(&config(), "video.software_filter", "Video software filter\n" - "0 = None\n" - "1 = NTSC\n" - "2 = HQ2x\n" - "3 = Scale2x\n", - IntegerSetting::Decimal, 0); IntegerSetting Video::frameskip(0, "video.frameskip", "Video frameskip", IntegerSetting::Decimal, 0); -IntegerSetting Video::use_vram(&config(), "video.use_vram", "Use Video RAM instead of System RAM", IntegerSetting::Boolean, true); +IntegerSetting Video::use_vram(&config(), "video.use_vram", "Use Video RAM instead of System RAM when possible", IntegerSetting::Boolean, true); struct Audio { static IntegerSetting synchronize; diff --git a/src/ui/lui/event.cpp b/src/ui/lui/event.cpp index fb904381..a8cc00e9 100644 --- a/src/ui/lui/event.cpp +++ b/src/ui/lui/event.cpp @@ -1,5 +1,67 @@ namespace event { +void load_video_settings() { + video_settings.mode = config::video.mode; + switch(video_settings.mode) { default: + case 0: //windowed + video_settings.aspect_correction = config::video.windowed.aspect_correction; + video_settings.synchronize = config::video.windowed.synchronize; + video_settings.region = config::video.windowed.region; + video_settings.multiplier = config::video.windowed.multiplier; + video_settings.hardware_filter = config::video.windowed.hardware_filter; + video_settings.software_filter = config::video.windowed.software_filter; + break; + case 1: //fullscreen + video_settings.aspect_correction = config::video.fullscreen.aspect_correction; + video_settings.synchronize = config::video.fullscreen.synchronize; + video_settings.region = config::video.fullscreen.region; + video_settings.multiplier = config::video.fullscreen.multiplier; + video_settings.hardware_filter = config::video.fullscreen.hardware_filter; + video_settings.software_filter = config::video.fullscreen.software_filter; + break; + } +} + +void update_aspect_correction(bool aspect_correction) { + switch(config::video.mode) { default: + case 0: config::video.windowed.aspect_correction = aspect_correction; break; + case 1: config::video.fullscreen.aspect_correction = aspect_correction; break; + } + update_video_settings(); +} + +void update_multiplier(uint multiplier) { + switch(config::video.mode) { default: + case 0: config::video.windowed.multiplier = multiplier; break; + case 1: config::video.fullscreen.multiplier = multiplier; break; + } + update_video_settings(); +} + +void update_region(uint region) { + switch(config::video.mode) { default: + case 0: config::video.windowed.region = region; break; + case 1: config::video.fullscreen.region = region; break; + } + update_video_settings(); +} + +void update_hardware_filter(uint hardware_filter) { + switch(config::video.mode) { default: + case 0: config::video.windowed.hardware_filter = hardware_filter; break; + case 1: config::video.fullscreen.hardware_filter = hardware_filter; break; + } + update_video_settings(); +} + +void update_software_filter(uint software_filter) { + switch(config::video.mode) { default: + case 0: config::video.windowed.software_filter = software_filter; break; + case 1: config::video.fullscreen.software_filter = software_filter; break; + } + update_video_settings(); +} + void update_frame_counter() { if(r_ppu->status.frames_updated) { r_ppu->status.frames_updated = false; @@ -10,49 +72,59 @@ void update_frame_counter() { } void update_video_settings() { + load_video_settings(); + uint width = 256; -uint height = config::video.region == 0 ? 224 : 239; -uint multiplier = minmax<1, 5>(uint(config::video.multiplier)); +uint height = video_settings.region == 0 ? 224 : 239; +uint multiplier = minmax<1, 5>(video_settings.multiplier); width *= multiplier; height *= multiplier; - if(config::video.aspect_correction == true) { - if(config::video.region == 0) { //NTSC + if(video_settings.aspect_correction == true) { + if(video_settings.region == 0) { //NTSC width = uint( double(width) * double(config::video.aspect_ntsc_x) / double(config::video.aspect_ntsc_y) ); } else { //PAL width = uint( double(width) * double(config::video.aspect_pal_x) / double(config::video.aspect_pal_y) ); } } - if(config::video.fullscreen) { - //window_main.menu.hide(); - window_main.fullscreen(); - window_main.view.move((ui::get_screen_width() - width) / 2, (ui::get_screen_height() - height) / 2); - window_main.view.resize(width, height); - } else { - //window_main.menu.show(); + switch(video_settings.mode) { default: + case 0: //windowed window_main.unfullscreen(); window_main.resize(width, height); window_main.view.move(0, 0); window_main.view.resize(width, height); + break; + case 1: //fullscreen + window_main.fullscreen(); + window_main.view.move((ui::get_screen_width() - width) / 2, (ui::get_screen_height() - height) / 2); + window_main.view.resize(width, height); + break; } -} -void update_raster_settings() { uint filter, standard; - switch(uint(config::video.software_filter)) { default: + switch(video_settings.software_filter) { default: case 0: filter = VIDEOFILTER_DIRECT; break; case 1: filter = VIDEOFILTER_NTSC; break; case 2: filter = VIDEOFILTER_HQ2X; break; case 3: filter = VIDEOFILTER_SCALE2X; break; } - switch(uint(config::video.region)) { default: + switch(video_settings.region) { default: case 0: standard = SNES::VIDEOSTANDARD_NTSC; break; case 1: standard = SNES::VIDEOSTANDARD_PAL; break; } snes.set_video_filter(filter); snes.set_video_standard(standard); + + if(uiVideo) { + uiVideo->settings.synchronize = video_settings.synchronize; + uiVideo->settings.filter = video_settings.hardware_filter; + uiVideo->update_settings(); + } + +//update main window video mode checkbox settings + window_main.update_menu_settings(); } void toggle_menu() { @@ -61,7 +133,11 @@ void toggle_menu() { } void toggle_fullscreen() { - config::video.fullscreen = !config::video.fullscreen; + if(config::video.mode != 1) { //switch to fullscreen mode if not already in it + config::video.mode = 1; + } else { //switch to windowed mode if already in fullscreen mode + config::video.mode = 0; + } update_video_settings(); } @@ -99,9 +175,16 @@ char fn[PATH_MAX]; if(load_rom(fn) == false)return; if(cartridge.loaded() == true)cartridge.unload(); - cartridge.load_begin(Cartridge::CART_NORMAL); + cartridge.load_begin(Cartridge::CartridgeNormal); cartridge.load(fn); cartridge.load_end(); + +//warn if unsupported hardware detected + if(cartridge.info.superfx)alert("Warning: unsupported SuperFX chip detected."); + if(cartridge.info.sa1) alert("Warning: unsupported SA-1 chip detected."); + if(cartridge.info.st011) alert("Warning: unsupported ST011 chip detected."); + if(cartridge.info.st018) alert("Warning: unsupported ST018 chip detected."); + snes.power(); window_cheat_editor.refresh(); } @@ -111,7 +194,7 @@ char fn[PATH_MAX]; if(load_rom(fn) == false)return; if(cartridge.loaded() == true)cartridge.unload(); - cartridge.load_begin(Cartridge::CART_ST); + cartridge.load_begin(Cartridge::CartridgeSufamiTurbo); cartridge.load(fn); cartridge.load_end(); snes.power(); @@ -124,7 +207,7 @@ char fn_a[PATH_MAX], fn_b[PATH_MAX]; if(load_rom(fn_b) == false)return; if(cartridge.loaded() == true)cartridge.unload(); - cartridge.load_begin(Cartridge::CART_STDUAL); + cartridge.load_begin(Cartridge::CartridgeSufamiTurboDual); cartridge.load(fn_a); cartridge.load(fn_b); cartridge.load_end(); diff --git a/src/ui/lui/event.h b/src/ui/lui/event.h index cda6dfd5..84df77d2 100644 --- a/src/ui/lui/event.h +++ b/src/ui/lui/event.h @@ -1,12 +1,29 @@ namespace event { +struct VideoSettings { + uint mode; + bool synchronize; + bool aspect_correction; + uint region; + uint multiplier; + uint hardware_filter; + uint software_filter; +} video_settings; +void load_video_settings(); + +//change video settings for active video mode +void update_aspect_correction(bool); +void update_multiplier(uint); +void update_region(uint); +void update_hardware_filter(uint); +void update_software_filter(uint); + void update_frame_counter(); void update_video_settings(); -void update_raster_settings(); void toggle_menu(); void toggle_fullscreen(); -bool load_rom(char *fn); +bool load_rom(char*); void load_rom(); void load_rom_st(); void load_rom_stdual(); diff --git a/src/ui/lui/main.cpp b/src/ui/lui/main.cpp index caba8c93..35f5445f 100644 --- a/src/ui/lui/main.cpp +++ b/src/ui/lui/main.cpp @@ -24,7 +24,11 @@ va_list args; va_start(args, s); vsprintf(str, s, args); va_end(args); +#if defined(PLATFORM_WIN) + MessageBox(0, str, "bsnes", MB_OK); +#else fprintf(stdout, "%s\r\n", str); +#endif } void dprintf(const char *s, ...) { @@ -104,12 +108,16 @@ int main(int argc, char *argv[]) { ui::init(); config::config().load(config::filename); - config::config().save(config::filename); //in case program crashes on first run, config file settings can be modified + if(fexists(config::filename) == false) { + //in case program crashes on first run, save config file + //settings, so that they can be modified by hand ... + config::config().save(config::filename); + } init_snes(); ui_init(); if(argc >= 2) { - cartridge.load_begin(Cartridge::CART_NORMAL); + cartridge.load_begin(Cartridge::CartridgeNormal); cartridge.load(argv[1]); cartridge.load_end(); snes.power(); diff --git a/src/ui/lui/ui.cpp b/src/ui/lui/ui.cpp index 4f8c48ac..009375ff 100644 --- a/src/ui/lui/ui.cpp +++ b/src/ui/lui/ui.cpp @@ -35,7 +35,7 @@ void ui_init() { window_advanced.setup(); window_settings.setup(); - event::update_video_settings(); + event::update_video_settings(); //call first time to resize main window and update menubar window_main.show(); while(ui::events_pending()) { ui::run(); } @@ -68,7 +68,7 @@ void ui_init() { uiAudio->init(); uiInput->init(); - window_main.setup_menu(); + event::update_video_settings(); //call second time to update uiVideo->settings } void ui_term() { diff --git a/src/ui/lui/ui_main.cpp b/src/ui/lui/ui_main.cpp index 03b89572..0fd1bf6a 100644 --- a/src/ui/lui/ui_main.cpp +++ b/src/ui/lui/ui_main.cpp @@ -56,59 +56,68 @@ ui::Control *control = (ui::Control*)param; message(ui::Message::Close); } - if(control == &menu_settings_videomode_1x) { config::video.multiplier = 1; event::update_video_settings(); } - if(control == &menu_settings_videomode_2x) { config::video.multiplier = 2; event::update_video_settings(); } - if(control == &menu_settings_videomode_3x) { config::video.multiplier = 3; event::update_video_settings(); } - if(control == &menu_settings_videomode_4x) { config::video.multiplier = 4; event::update_video_settings(); } - if(control == &menu_settings_videomode_5x) { config::video.multiplier = 5; event::update_video_settings(); } + if(locked == false) { + //set locked to true to update below menu item check statuses without triggering events + if(control == &menu_settings_videomode_1x) { event::update_multiplier(1); } + if(control == &menu_settings_videomode_2x) { event::update_multiplier(2); } + if(control == &menu_settings_videomode_3x) { event::update_multiplier(3); } + if(control == &menu_settings_videomode_4x) { event::update_multiplier(4); } + if(control == &menu_settings_videomode_5x) { event::update_multiplier(5); } - if(control == &menu_settings_videomode_aspect_correction) { - config::video.aspect_correction = menu_settings_videomode_aspect_correction.checked(); - event::update_video_settings(); + if(control == &menu_settings_videomode_aspect_correction) { + event::update_aspect_correction(menu_settings_videomode_aspect_correction.checked()); + } + + if(control == &menu_settings_videomode_ntsc) { event::update_region(0); } + if(control == &menu_settings_videomode_pal) { event::update_region(1); } + + if(control == &menu_settings_videofilter_hwpoint) { event::update_hardware_filter(0); } + if(control == &menu_settings_videofilter_hwlinear) { event::update_hardware_filter(1); } + + if(control == &menu_settings_videofilter_swnone) { event::update_software_filter(0); } + if(control == &menu_settings_videofilter_swntsc) { event::update_software_filter(1); } + if(control == &menu_settings_videofilter_swhq2x) { event::update_software_filter(2); } + if(control == &menu_settings_videofilter_swscale2x) { event::update_software_filter(3); } + + if(control == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; } + if(control == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; } + if(control == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; } + if(control == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; } + if(control == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; } + if(control == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; } + if(control == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; } + if(control == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; } + if(control == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; } + if(control == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; } + + if(control == &menu_settings_mute) { + config::snes.mute = menu_settings_mute.checked(); + } + + if(control == &menu_settings_speedreg_enable) { + config::system.regulate_speed = menu_settings_speedreg_enable.checked(); + } + + if(control == &menu_settings_speedreg_slowest) { config::system.speed = 1; uiAudio->update_frequency(); } + if(control == &menu_settings_speedreg_slow) { config::system.speed = 2; uiAudio->update_frequency(); } + if(control == &menu_settings_speedreg_normal) { config::system.speed = 3; uiAudio->update_frequency(); } + if(control == &menu_settings_speedreg_fast) { config::system.speed = 4; uiAudio->update_frequency(); } + if(control == &menu_settings_speedreg_fastest) { config::system.speed = 5; uiAudio->update_frequency(); } } - if(control == &menu_settings_videomode_ntsc) { config::video.region = 0; event::update_raster_settings(); event::update_video_settings(); } - if(control == &menu_settings_videomode_pal) { config::video.region = 1; event::update_raster_settings(); event::update_video_settings(); } - - if(control == &menu_settings_videofilter_hwpoint) { config::video.hardware_filter = 0; uiVideo->update_hardware_filter(); } - if(control == &menu_settings_videofilter_hwlinear) { config::video.hardware_filter = 1; uiVideo->update_hardware_filter(); } - - if(control == &menu_settings_videofilter_swnone) { config::video.software_filter = 0; event::update_raster_settings(); } - if(control == &menu_settings_videofilter_swntsc) { config::video.software_filter = 1; event::update_raster_settings(); } - if(control == &menu_settings_videofilter_swhq2x) { config::video.software_filter = 2; event::update_raster_settings(); } - if(control == &menu_settings_videofilter_swscale2x) { config::video.software_filter = 3; event::update_raster_settings(); } - - if(control == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; } - if(control == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; } - if(control == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; } - if(control == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; } - if(control == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; } - if(control == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; } - if(control == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; } - if(control == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; } - if(control == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; } - if(control == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; } - - if(control == &menu_settings_mute) { - config::snes.mute = menu_settings_mute.checked(); - } - - if(control == &menu_settings_speedreg_enable) { - config::system.regulate_speed = menu_settings_speedreg_enable.checked(); - } - - if(control == &menu_settings_speedreg_slowest) { config::system.speed = 1; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_slow) { config::system.speed = 2; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_normal) { config::system.speed = 3; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_fast) { config::system.speed = 4; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_fastest) { config::system.speed = 5; uiAudio->update_frequency(); } - if(control == &menu_settings_config) { window_settings.show(); } if(control == &menu_misc_logaudio) { (menu_misc_logaudio.checked() == true) ? snes.log_audio_enable() : snes.log_audio_disable(); } + if(control == &menu_misc_showfps) { + config::misc.show_frame_counter = menu_misc_showfps.checked(); + if(config::misc.show_frame_counter == false) { + set_text(string() << BSNES_TITLE); + } + } + if(control == &menu_misc_about) { window_about.focus(); } @@ -122,6 +131,8 @@ ui::Control *control = (ui::Control*)param; void MainWindow::setup() { snesinterface.input_ready = bind(&MainWindow::input_ready, this); + locked = true; + ui::ControlGroup group; create(ui::Window::Center, 256, 224, BSNES_TITLE); set_background_color(0, 0, 0); @@ -233,6 +244,7 @@ ui::ControlGroup group; menu_misc.create(menu, "Misc"); menu_misc_logaudio.create(menu_misc, "Log Audio Data"); + menu_misc_showfps.create(menu_misc, "Show FPS"); menu_misc_sep1.create(menu_misc); menu_misc_about.create(menu_misc, "About ..."); menu_misc.finish(); @@ -242,9 +254,12 @@ ui::ControlGroup group; view.set_background_color(0, 0, 0); } -void MainWindow::setup_menu() { - config::video.multiplier = minmax<1, 5>(uint(config::video.multiplier)); - switch(uint(config::video.multiplier)) { +void MainWindow::update_menu_settings() { + locked = true; + + event::load_video_settings(); + + switch(event::video_settings.multiplier) { default: case 1: menu_settings_videomode_1x.check(); break; case 2: menu_settings_videomode_2x.check(); break; case 3: menu_settings_videomode_3x.check(); break; @@ -252,22 +267,19 @@ void MainWindow::setup_menu() { case 5: menu_settings_videomode_5x.check(); break; } - menu_settings_videomode_aspect_correction.check(config::video.aspect_correction); + menu_settings_videomode_aspect_correction.check(event::video_settings.aspect_correction); - config::video.region = minmax<0, 1>(uint(config::video.region)); - switch(uint(config::video.region)) { + switch(event::video_settings.region) { default: case 0: menu_settings_videomode_ntsc.check(); break; case 1: menu_settings_videomode_pal.check(); break; } - config::video.hardware_filter = minmax<0, 1>(uint(config::video.hardware_filter)); - switch(uint(config::video.hardware_filter)) { + switch(event::video_settings.hardware_filter) { default: case 0: menu_settings_videofilter_hwpoint.check(); break; case 1: menu_settings_videofilter_hwlinear.check(); break; } - config::video.software_filter = minmax<0, 3>(uint(config::video.software_filter)); - switch(uint(config::video.software_filter)) { + switch(event::video_settings.software_filter) { default: case 0: menu_settings_videofilter_swnone.check(); break; case 1: menu_settings_videofilter_swntsc.check(); break; case 2: menu_settings_videofilter_swhq2x.check(); break; @@ -278,4 +290,8 @@ void MainWindow::setup_menu() { menu_settings_speedreg_enable.check(config::system.regulate_speed); menu_settings_speedreg_normal.check(); + + menu_misc_showfps.check(config::misc.show_frame_counter); + + locked = false; } diff --git a/src/ui/lui/ui_main.h b/src/ui/lui/ui_main.h index c643c24e..4a56e637 100644 --- a/src/ui/lui/ui_main.h +++ b/src/ui/lui/ui_main.h @@ -57,6 +57,7 @@ ui::MenuGroup menu_settings; ui::MenuItem menu_settings_config; ui::MenuGroup menu_misc; ui::MenuCheckItem menu_misc_logaudio; + ui::MenuCheckItem menu_misc_showfps; ui::MenuSeparator menu_misc_sep1; ui::MenuItem menu_misc_about; @@ -65,7 +66,8 @@ ui::Container view; bool input_ready(); +bool locked; bool message(uint id, uintptr_t param = 0); void setup(); - void setup_menu(); + void update_menu_settings(); } window_main; diff --git a/src/ui/video/d3d.cpp b/src/ui/video/d3d.cpp index ebf4c1e8..1c8e509d 100644 --- a/src/ui/video/d3d.cpp +++ b/src/ui/video/d3d.cpp @@ -87,7 +87,7 @@ HRESULT hr; device->SetVertexShader(NULL); device->SetFVF(D3DVERTEX); - update_hardware_filter(); + update_settings(); if(caps.stretchrect == true) { device->CreateOffscreenPlainSurface(1024, 1024, D3DFMT_R5G6B5, @@ -104,10 +104,10 @@ HRESULT hr; return true; } -void VideoD3D::update_hardware_filter() { +void VideoD3D::update_settings() { if(!device)return; - switch(uint(config::video.hardware_filter)) { + switch(settings.filter) { case Video::FilterPoint: flags.filter = D3DTEXF_POINT; break; @@ -230,7 +230,7 @@ void VideoD3D::refresh(uint r_width, uint r_height) { device->EndScene(); - if(config::video.synchronize == true) { + if(settings.synchronize == true) { D3DRASTER_STATUS status; for(;;) { device->GetRasterStatus(0, &status); diff --git a/src/ui/video/d3d.h b/src/ui/video/d3d.h index 16138eb6..c10d0a68 100644 --- a/src/ui/video/d3d.h +++ b/src/ui/video/d3d.h @@ -43,7 +43,7 @@ struct { uint screen_height() { return GetSystemMetrics(SM_CYSCREEN); } bool update_video_mode(); - void update_hardware_filter(); + void update_settings(); bool capture_screenshot(); diff --git a/src/ui/video/ddraw.cpp b/src/ui/video/ddraw.cpp index c31e9734..3bc7ea71 100644 --- a/src/ui/video/ddraw.cpp +++ b/src/ui/video/ddraw.cpp @@ -18,7 +18,7 @@ void VideoDD::unlock() { } void VideoDD::refresh(uint r_width, uint r_height) { - if(config::video.synchronize == true) { + if(settings.synchronize) { for(;;) { BOOL in_vblank; lpdd7->GetVerticalBlankStatus(&in_vblank); diff --git a/src/ui/video/video.h b/src/ui/video/video.h index c2a525c1..6c88f619 100644 --- a/src/ui/video/video.h +++ b/src/ui/video/video.h @@ -1,12 +1,18 @@ -#ifndef VIDEO_H -#define VIDEO_H - -class Video { public: - -enum Filter { - FilterPoint, +#ifndef VIDEO_H +#define VIDEO_H + +class Video { public: + +struct Settings { + bool synchronize; + uint filter; + Settings() : synchronize(false), filter(0) {} +} settings; + +enum Filter { + FilterPoint, FilterLinear, -}; +}; virtual bool lock(uint16 *&data, uint &pitch) { return false; } virtual void unlock() {} @@ -16,10 +22,10 @@ enum Filter { virtual void init() {} virtual void term() {} - virtual void update_hardware_filter() {} + virtual void update_settings() {} Video() {} virtual ~Video() {} } *uiVideo; - -#endif + +#endif