diff --git a/cart.db b/cart.db index a489d594..bf00dbb0 100644 Binary files a/cart.db and b/cart.db differ 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 a489d594..bf00dbb0 100644 Binary files a/src/cart/db/cart.db and b/src/cart/db/cart.db differ 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 a396add1..00000000 Binary files a/src/data/bsnes_old.ico and /dev/null differ diff --git a/src/data/snes_controller.bmp b/src/data/snes_controller.bmp deleted file mode 100644 index 76f7a44a..00000000 Binary files a/src/data/snes_controller.bmp and /dev/null differ diff --git a/src/interface.h b/src/interface.h index eac1a992..d079a62d 100644 --- a/src/interface.h +++ b/src/interface.h @@ -33,11 +33,14 @@ #include "snes/snes.h" +#include "chip/superfx/superfx.h" #include "chip/srtc/srtc.h" #include "chip/sdd1/sdd1.h" #include "chip/c4/c4.h" #include "chip/dsp1/dsp1.h" #include "chip/dsp2/dsp2.h" +#include "chip/dsp3/dsp3.h" +#include "chip/dsp4/dsp4.h" #include "chip/obc1/obc1.h" #include "chip/st010/st010.h" diff --git a/src/memory/bmemory/bmemory.cpp b/src/memory/bmemory/bmemory.cpp index 3d3650cc..746968d8 100644 --- a/src/memory/bmemory/bmemory.cpp +++ b/src/memory/bmemory/bmemory.cpp @@ -31,6 +31,8 @@ void bMemBus::load_cart() { if(cartridge.info.c4) cart_map_c4(); if(cartridge.info.dsp1) cart_map_dsp1(); if(cartridge.info.dsp2) cart_map_dsp2(); + if(cartridge.info.dsp3) cart_map_dsp3(); + if(cartridge.info.dsp4) cart_map_dsp4(); if(cartridge.info.obc1) cart_map_obc1(); if(cartridge.info.st010)cart_map_st010(); @@ -58,13 +60,19 @@ char t[256]; dprintf("* Region : %s", (cartridge.info.region == Cartridge::NTSC) ? "NTSC" : "PAL"); strcpy(t, ""); - if(cartridge.info.srtc) strcat(t, "S-RTC, "); - if(cartridge.info.sdd1) strcat(t, "S-DD1, "); - if(cartridge.info.c4) strcat(t, "Cx4, "); - if(cartridge.info.dsp1) strcat(t, "DSP-1, "); - if(cartridge.info.dsp2) strcat(t, "DSP-2, "); - if(cartridge.info.obc1) strcat(t, "OBC-1, "); - if(cartridge.info.st010)strcat(t, "ST010, "); + if(cartridge.info.superfx)strcat(t, "SuperFX, "); + if(cartridge.info.sa1) strcat(t, "SA-1, "); + if(cartridge.info.srtc) strcat(t, "S-RTC, "); + if(cartridge.info.sdd1) strcat(t, "S-DD1, "); + if(cartridge.info.c4) strcat(t, "Cx4, "); + if(cartridge.info.dsp1) strcat(t, "DSP-1, "); + if(cartridge.info.dsp2) strcat(t, "DSP-2, "); + if(cartridge.info.dsp3) strcat(t, "DSP-3, "); + if(cartridge.info.dsp4) strcat(t, "DSP-4, "); + if(cartridge.info.obc1) strcat(t, "OBC-1, "); + if(cartridge.info.st010) strcat(t, "ST010, "); + if(cartridge.info.st011) strcat(t, "ST011, "); + if(cartridge.info.st018) strcat(t, "ST018, "); strrtrim(t, ", "); dprintf("* Coprocessor(s) : %s", (strlen(t) == 0) ? "None" : t); dprintf("* Reset:%0.4x NMI[n]:%0.4x IRQ[n]:%0.4x BRK[n]:%0.4x COP[n]:%0.4x", diff --git a/src/memory/bmemory/bmemory.h b/src/memory/bmemory/bmemory.h index 51e2b7c6..d8bf4fac 100644 --- a/src/memory/bmemory/bmemory.h +++ b/src/memory/bmemory/bmemory.h @@ -39,6 +39,10 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART }; void write_dsp1 (uint32 addr, uint8 data); uint8 read_dsp2 (uint32 addr); void write_dsp2 (uint32 addr, uint8 data); + uint8 read_dsp3 (uint32 addr); + void write_dsp3 (uint32 addr, uint8 data); + uint8 read_dsp4 (uint32 addr); + void write_dsp4 (uint32 addr, uint8 data); uint8 read_obc1 (uint32 addr); void write_obc1 (uint32 addr, uint8 data); uint8 read_st010 (uint32 addr); @@ -52,6 +56,8 @@ enum { TYPE_WRAM, TYPE_MMIO, TYPE_CART }; void cart_map_c4(); void cart_map_dsp1(); void cart_map_dsp2(); + void cart_map_dsp3(); + void cart_map_dsp4(); void cart_map_obc1(); void cart_map_st010(); diff --git a/src/memory/bmemory/bmemory_mapper_generic.cpp b/src/memory/bmemory/bmemory_mapper_generic.cpp index 788fffa7..e86b454d 100644 --- a/src/memory/bmemory/bmemory_mapper_generic.cpp +++ b/src/memory/bmemory/bmemory_mapper_generic.cpp @@ -167,6 +167,30 @@ void bMemBus::cart_map_dsp2() { } } +void bMemBus::cart_map_dsp3() { +//$[20-3f|a0-bf]:[8000-ffff] + for(uint bank = 0x20; bank <= 0x3f; bank++) { + for(uint page = 0x80; page <= 0xff; page++) { + page_read [0x0000 + (bank << 8) + page] = &bMemBus::read_dsp3; + page_read [0x8000 + (bank << 8) + page] = &bMemBus::read_dsp3; + page_write[0x0000 + (bank << 8) + page] = &bMemBus::write_dsp3; + page_write[0x8000 + (bank << 8) + page] = &bMemBus::write_dsp3; + } + } +} + +void bMemBus::cart_map_dsp4() { +//$[30-3f|b0-bf]:[8000-ffff] + for(uint bank = 0x30; bank <= 0x3f; bank++) { + for(uint page = 0x80; page <= 0xff; page++) { + page_read [0x0000 + (bank << 8) + page] = &bMemBus::read_dsp4; + page_read [0x8000 + (bank << 8) + page] = &bMemBus::read_dsp4; + page_write[0x0000 + (bank << 8) + page] = &bMemBus::write_dsp4; + page_write[0x8000 + (bank << 8) + page] = &bMemBus::write_dsp4; + } + } +} + void bMemBus::cart_map_obc1() { //$[00-3f|80-bf]:[6000-7fff] for(uint bank = 0x00; bank <= 0x3f; bank++) { diff --git a/src/memory/bmemory/bmemory_rw.cpp b/src/memory/bmemory/bmemory_rw.cpp index 2c6a37bd..f0500d5b 100644 --- a/src/memory/bmemory/bmemory_rw.cpp +++ b/src/memory/bmemory/bmemory_rw.cpp @@ -39,29 +39,35 @@ void bMemBus::write_ram(uint32 addr, uint8 data) { // uint8 bMemBus::read_sdd1(uint32 addr) { - addr = sdd1->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