diff --git a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs index c0c8c3b12c..378cb7676e 100644 --- a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs +++ b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs @@ -101,7 +101,8 @@ namespace BizHawk.Client.ApiHawk case "VB": case "NGP": - case "DNGP": + case "DNGP": + case "O2": return 0; // like I give a shit default: diff --git a/BizHawk.Emulation.Common/Database/Database.cs b/BizHawk.Emulation.Common/Database/Database.cs index 5068cd22ed..9d79a2b950 100644 --- a/BizHawk.Emulation.Common/Database/Database.cs +++ b/BizHawk.Emulation.Common/Database/Database.cs @@ -340,6 +340,10 @@ namespace BizHawk.Emulation.Common case ".NGC": game.System = "NGP"; break; + + case ".O2": + game.System = "O2"; + break; } game.Name = Path.GetFileNameWithoutExtension(fileName)?.Replace('_', ' '); diff --git a/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs b/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs index 2bbd5a4749..3ddc936331 100644 --- a/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs +++ b/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs @@ -200,6 +200,9 @@ namespace BizHawk.Emulation.Common Firmware("AppleII", "DiskII", "DiskII.rom"); var appleII_DiskII = File("D4181C9F046AAFC3FB326B381BAAC809D9E38D16", 256, "DiskII.rom", "Disk II"); Option("AppleII", "DiskII", appleII_DiskII); + + FirmwareAndOption("b2e1955d957a475de2411770452eff4ea19f4cee", 1024, "O2", "BIOS", "Odyssey2.bin", "Odyssey 2 Bios"); + FirmwareAndOption("a6120aed50831c9c0d95dbdf707820f601d9452e", 1024, "O2", "BIOS-C52", "PhillipsC52.bin", "Phillips C52 Bios"); } // adds a defined firmware ID to the database diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 22306b5309..d4d84c445c 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -475,6 +475,8 @@ + + Gambatte.cs diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/LibO2Em.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/LibO2Em.cs new file mode 100644 index 0000000000..d4e4fdb6d9 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/LibO2Em.cs @@ -0,0 +1,16 @@ +using BizHawk.Common.BizInvoke; +using BizHawk.Emulation.Cores.Waterbox; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Consoles.Magnavox +{ + public abstract class LibO2Em : LibWaterboxCore + { + [BizImport(CC)] + public abstract bool Init(byte[] rom, int romlen, byte[] bios, int bioslen); + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/O2Em.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/O2Em.cs new file mode 100644 index 0000000000..b3055049d0 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/O2Em.cs @@ -0,0 +1,52 @@ +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Waterbox; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Consoles.Magnavox +{ + [CoreAttributes("o2em", "", true, false, "", "", false)] + public class O2Em : WaterboxCore + { + private LibO2Em _core; + + [CoreConstructor("O2")] + public O2Em(CoreComm comm, byte[] rom) + :base(comm, new Configuration + { + DefaultFpsNumerator = 60, + DefaultFpsDenominator = 1, + DefaultWidth = 320, + DefaultHeight = 240, + MaxSamples = 2048, + MaxWidth = 320, + MaxHeight = 240, + SystemId = "O2" + }) + { + var bios = comm.CoreFileProvider.GetFirmware("O2", "BIOS", true); + _core = PreInit(new PeRunnerOptions + { + Filename = "o2em.wbx", + SbrkHeapSizeKB = 4 * 1024, + SealedHeapSizeKB = 4 * 1024, + InvisibleHeapSizeKB = 4 * 1024, + PlainHeapSizeKB = 4 * 1024, + }); + + + if (!_core.Init(rom, rom.Length, bios, bios.Length)) + throw new InvalidOperationException("Init() failed"); + + PostInit(); + } + + protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound) + { + return new LibWaterboxCore.FrameInfo(); + } + } +} diff --git a/waterbox/o2em/.vscode/settings.json b/waterbox/o2em/.vscode/settings.json new file mode 100644 index 0000000000..a5401e1c1f --- /dev/null +++ b/waterbox/o2em/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "editor.tabSize": 4, + "editor.insertSpaces": false, + "editor.detectIndentation": false +} \ No newline at end of file diff --git a/waterbox/o2em/CHANGELOG b/waterbox/o2em/CHANGELOG new file mode 100644 index 0000000000..71dbb60f39 --- /dev/null +++ b/waterbox/o2em/CHANGELOG @@ -0,0 +1,316 @@ +v1.18: 01/15/2007 + + - added the option -biosdir to define bios directory path + - added the option -romdir to define rom directory path + - added the option -help to help display + - directory search fix : When you don't have the "roms/" and/or "bios/" + directory, the program will dump core (by Walter de Jong). + - O2Launcher works now, o2em ignore roms and bios path if o2Launcher + is running. + - quad display fix: changed the way quad chars are drawn, fixes problems + in KTAA as well as score display in Black Hole and Red Baron (Soeren Gust) + - support for Soerens MegaCART bank switching (Information about + how to use this will be included in the next verison of Soerens + Bios-Documentation) (Soeren Gust) + - new feature in debugger: savevpp to make an uncompressed dump of the VPP + screen and slide data (Soeren Gust) + - dis48: fix to work under linux again (Soeren Gust) + - init_sound volume is not set to maximum (By Gunter Wambaugh) + - added makefile and options for freeBSD (By Gunter Wambaugh) + - Other minor fixes. + + + all the next changes were implemented by Manopac: + + - added the option -s0 to redefine the system keys (see o2em.txt for usage) + - bugfix: highscore-file is only written if scoretype is set + - changed Default Stick 1 key from right to "L" to enable Fire and + movement at the same time + - two joysticks can be used now: first stick in command-line is mapped to joystick 1, + second to joystick 2 (compatible to old command line options) + - changes in debugger: status of registers is now displayed after instructions + are executed + - new features in debugger: savedatah and savedatab to save data from memory + as sourcecode ("db xxx") + - changed Default Stick 1 key from right to "L" to enable Fire + and movement at the same time + - two joysticks can be used now: first stick in command-line is mapped to + joystick 1, second to joystick 2 (compatible to old command line options) + - changes in debugger: status of registers is now displayed after + instructions are executed + - new features in debugger: savedatah and savedatab to save data from memory + as sourcecode ("db xxx") + - removed the limit that KTAA was the only 3K enabled rom (every + rom divideable by 3K is allowed now) + - dis48: added option -bios to disassemble bios (start at address 0) + - dis48: empty line after each page + - new feature to save the highscore in games (F6 to set in game) + - new feature to save/load state (F2/F3) (with command line option savefile) + - new features in debugger: savevdc and saveext to save data from Extram and VDC + - new feature in debugger: viewsprite + - new feature in debugger: bp (breakpoint) - o2em runs with output until + breakpoint is reached (bpc to clear) + - new feature in debugger: so (step over) - runs to next instruction in memory + - more explicit register display (P1 & PSW) + - fixed the "double size sprites are shifted only 1 instead of 2 pixles" bug + - new features in debugger (load / save file, change values in memory, + assemble to memory) + +v1.17: 05/01/2005 + + - BIOS identified by CRC, to activate a specific BIOS type: -o2rom, or + -g7400, or -c52, or -jopac. The old form can be used. See O2EM.txt for more. + + - Automatic identification of BIOS VP+ when the selected game is only VP+. + + - Creation of the standard directories (ROMS, BIOS, VOICE) when uncompressing + O2EM archive. + + - ATLANTIS, FROGGER, COMANDO NOTURNO and CATCH THE BALL now work without + graphic bugs. This correction is based on a specific patch for each game. + Thanks Rafael Cardoso for reports these bugs. + + +V1.16: 12/28/2004 + + - Fixed a slowdown in Pick Axe Pete (based on a patch by Arlindo de + Oliveira). + + - Reverted back to the old palette for O2 games, while using the new + palette for Videpac Plus games (selected based on bios version in use). + + +V1.15: 12/12/2004 + + - Added support for 12kb and 16kb games. Trans American Rally+ works now. + + - Added fixes to the VP+ gfx emulation made by Soeren Gust. Flashpoint + works properly now. + + - Fixed a bug in the Windows-specific emulation timing code that caused + the emulator to crash when run on a Windows machine which was on for a + few days without a reboot. + + - Fixed a bug in the emulation of the DAA instruction, which caused bugs + in the score of several games (Le Tresor Englouti, Cosmic Conflict, etc.). + + - Fixed instruction timings (patch by Soeren) + + - Modified the palette to use values calculated from the Videopac+ RGB + encoder specs by René van den Enden, instead of guessed values. + + - Other minor fixes. + + + +V1.01: 10/23/2002 + + - Major speed optimization. + + - Implemented VDC <-> VP+ collision detection. + + - On the original machines it is possible to make all VDC + colors bright by clearing P17. This affects the background and + dark grid colors. Implemented. Now the Killer Bees! intro screen + works correctly. + + - Fixed the wrong color order when mixing between VP+ and VDC graphics. + Jopac Moto Crash now works. Fixed by Soeren Gust. + + - Now the VBLANK pulse is visible on the T1 input. This can be used + to differentiate between PAL and NTSC. + + - Other minor fixes. + + + +V1.00: 09/12/2002 + + - Implemented complete Videopac+ G7400 emulation. Implemented it from + scratch, based on the EF9340/41 datasheet (sent by Simon Scudder), on + the technical docs made by Soeren Gust and disassembling the VP+ bios. + You will need a Videopac+ bios image file in order to use this feature. + You can use the -bios option to select it, rename the file to o2rom.bin, + or select it in O2EM Launcher settings. Please note that a few O2 games + do not work with the VP+ bios, so most likely you will need both bios + versions to be able to run all the games. For copyright reasons these + files are not included with O2EM, but you can find them in the Internet. + + - Added a default configuration file. Now you can specify your preferred + options in a configuration file, instead of typing it every time you + execute the emulator. The command line options override the default + settings in the file. See O2EM.txt for more. + + - Extended the -s1 and -s2 switches to allow customizable keys with the + joystick emulation. Based on a patch written by Zimmerman that + implemented customizable keys it in a different way. See O2EM.txt for + more. + + - Added support to the Four in 1 Row game. + + - Added the -exrom switch to enable the use of a special ROM mapping mode. + See O2EM.txt for more. + + - Improved the sound with Frogger and Popeye. + + - Minor fixes. + + + +V0.90: 08/07/2002 + + - Fixed the color palette, based on screen shots from a real O2 console. + + - Fixed a bug in the sprite drawing priority. Now in several games the + sprites look better (Demon Attack, Turtles, Atlantis, Computer Golf, + Football, Helicopter Rescue, etc.). + + - Modified the emulation of sprites and characters in the border region of + the screen. Fixed the bug of character wrapping to the other side of the + screen and other problems (Atlantis and others). Now the main characters of + P.T.Barnum's Acrobats! do not fall from the edge of screen. + + - Fixed the audio pitch and implemented white noise emulation. Now + explosions sound much better! + + - Fixed a background line blinking problem that used to affect lots of + games. + + - Fixed the color bar at the left of the screen. + + - Enhanced the support for European/Pal games. Now several games look and + play better. Shark Hunter intro works correctly. Frogger and Depth Charge + are fully playable ! + + - Implemented an audio filter that accurately emulates the behavior of the + low-pass filter present in the audio output of the real console. The sound + is better now. (Enable it with -filter). + + - Fixed the screen size. Now you can see all the graphics in the game, + including the time in Labyrinth. + + - Implemented Dot Grid emulation. Now Marksman is playable. + + - Implemented a cached video emulation, to make it run faster with slow + machines / video cards. + + - Implemented screen shots (use the F8 key and the -scshot option) + + - Implemented the sprite shifted/smooth modes. Now the main character of + Q*bert looks hi-res. + + - Several minor fixes. + + + The following fixes were made by Soeren Gust: + + + - Implemented the missing JNI instruction. + + - Implemented the 1kb data ROM / 3kb program ROM addressing mode used by + Musician. + + - Fixed the height of the grid lines. + + - Added support for 3Kb per bank + + + +V0.87: 06/21/2002 + + - Fixed a collision bug introduced with version 0.86. + Now Cosmic Conflict runs again. Thanks to Dan Boris for reporting + this bug. + + - Implemented the option to set the O2 bios file name/dir, as + requested by my friend Heitor, to enable him to support it with his + nice O2EMLauncher frontend for O2EM 0.8x, as requested by its users. + Get O2EMLauncher here: http://www.odyssey.com.br/o2emlauncher/ + + + +Version 0.86: + + - Fixed a bug in the drawing of quad characters. Now you can play + Q*Bert and Nimble Numbers Ned. Some other games will also have + improved graphics or text (Popeye, Super Cobra, etc.) . + + - Fixed another bug in the collision detection. Now Demon Attack + works correctly. + + + +Version 0.85: + + - Fixed the collision detection. Now you can play Killer Bees! + + - Implemented partial support to mid-screen changes to the VDC + registers without interrupts. Now several games look better, and some + that didn't work can be played, including Power Lords and Super Cobra. + + - Fixed a bug in the video emulation that made some games like Turtles + and Shark Hunter appear with some strange static characters. + + + +Version 0.80: + +The following changes were already implemented by Daniel Boris in version +0.701. Implemented them again in the sources based on version v0.65: + + - Fixed a bug in the CPU core related to the handling of branch + instructions near page boundaries. (Without it Sid the Spellbinder + crashed after the first level). + + - CPU core now jumps to the correct address on an external interrupt. + Killer Bees runs again. + + - Fixed shape of '$' character and added missing 64th character to + character set (ripped the correct character data from the v0.701 + executable file). + + - Fixed bug in drawing of bottom grid line. + + - Added Voice support. Re implemented it from scratch, based on O2 + technical specs released by Dan Boris and disassembling Smithereens + and Turtles (now it always work with Turtles). + +The following changes are new to version 0.80: + + - Updated the code to compile with Allegro 4.0.x and to work + without changes under Windows, Linux and DOS, with optimizations + for each. + + - Implemented the option of windowed or fullscreen video modes, + with scaling, centering and optional 50% scanlines. + + - Cleaned the code to make it more portable and maintainable. + + - Improved timing, using the most accurate way available for + each platform. + + - Fixed the keyboard scan code translation table. + + - Fixed and improved the built-in debugger. + + - Fixed the reset. It now works with Turtles. + + - Fixed joystick detection code. + + - Implemented variable speed control relative to original O2. + + - Implemented individual volume control for sounds and voice. + + - Implemented Pause/Information (F1). + + - Avoided collision of keyboard input with key joystick + emulation. Now Caps Lock enables/disables the W,D,S,A,Space keys + for keyboard input when they are used by joystick emulation. + Works well with games like K.C.'s Krazy Chase. + + - It now releases more CPU time to the system (if possible). + + - Other minor changes/fixes. + + + diff --git a/waterbox/o2em/COPYING b/waterbox/o2em/COPYING new file mode 100644 index 0000000000..255c6f4511 --- /dev/null +++ b/waterbox/o2em/COPYING @@ -0,0 +1,138 @@ + + The Clarified Artistic License + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Distribution fee" is a fee you charge for providing a copy + of this Package to another party. + + "Freely Available" means that no fee is charged for the right to + use the item, though there may be fees involved in handling the + item. It also means that recipients of the item may redistribute + it under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain, or those made Freely Available, or from +the Copyright Holder. A Package modified in such a way shall still be +considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or an + equivalent medium, or placing the modifications on a major network + archive site allowing unrestricted access to them, or by allowing the + Copyright Holder to include your modifications in the Standard Version + of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + + e) permit and encourge anyone who receives a copy of the modified Package + permission to make your modifications Freely Available + in some specific way. + + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + + e) offer the machine-readable source of the Package, with your + modifications, by mail order. + +5. You may charge a distribution fee for any distribution of this Package. +If you offer support for this Package, you may charge any fee you choose +for that support. You may not charge a license fee for the right to use +this Package itself. You may distribute this Package in aggregate with +other (possibly commercial and possibly nonfree) programs as part of a +larger (possibly commercial and possibly nonfree) software distribution, +and charge license fees for other parts of that software distribution, +provided that you do not advertise this Package as a product of your own. +If the Package includes an interpreter, You may embed this Package's +interpreter within an executable of yours (by linking); this shall be +construed as a mere form of aggregation, provided that the complete +Standard Version of the interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of the Standard Version of the Package with a commercial +distribution is always permitted provided that the use of this Package +is embedded; that is, when no overt attempt is made to make this Package's +interfaces visible to the end user of the commercial distribution. +Such use shall not be construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End + diff --git a/waterbox/o2em/Makefile b/waterbox/o2em/Makefile new file mode 100644 index 0000000000..e7c1641880 --- /dev/null +++ b/waterbox/o2em/Makefile @@ -0,0 +1,41 @@ +CC = x86_64-nt64-midipix-gcc + +CCFLAGS:= \ + -Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \ + -std=c99 -fomit-frame-pointer -fvisibility=hidden \ + -D_GNU_SOURCE \ + -O0 -g + +TARGET = o2em.wbx + +LDFLAGS = -Wl,--dynamicbase,--export-all-symbols + +ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c') +OBJ_DIR:=$(ROOT_DIR)/obj + +_OBJS:=$(SRCS:.c=.o) +OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS)) + +$(OBJ_DIR)/%.o: %.c + @mkdir -p $(@D) + @$(CC) -c -o $@ $< $(CCFLAGS) + +all: $(TARGET) + +.PHONY: clean all + +$(TARGET).in: $(OBJS) + @$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so + +$(TARGET): $(TARGET).in +# strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104 + cp $< $@ + +clean: + rm -rf $(OBJ_DIR) + rm -f $(TARGET).in + rm -f $(TARGET) + +#install: +# $(CP) $(TARGET) $(DEST_$(ARCH)) diff --git a/waterbox/o2em/README b/waterbox/o2em/README new file mode 100644 index 0000000000..8811fe86c5 --- /dev/null +++ b/waterbox/o2em/README @@ -0,0 +1,341 @@ + + + O2EM v1.18 (Jan/2007) + + an Odyssey 2 & Videopac+ emulator + + copyright 1996/1998 by Daniel Boris + + Developed by Daniel Boris, Andre de la Rocha and Arlindo Oliveira + + This package is released under the + Clarified Artistic License (see COPYING) + + Project Homepage + http://o2em.sourceforge.net + +--------------------------------------------------------------------------- + + +O2EM is an open source Odyssey2 / Videopac console emulator, created by +Daniel Boris in 1996. Since version 0.80 it has been developed by André de +la Rocha and since version 1.16 it has been developed by Arlindo M. de Oliveira. + +This release includes the source code for O2EM v1.18 and binaries for +Windows. The sources probably can also be compiled under other platforms +that support the Allegro game library. The binary version for Linux/X11 and +DOS continues available just until the version 1.16. + +With the Windows binary, the latest stable version of the Allegro DLL is also +included. To use the Linux version you must get the Allegro library for Linux +yourself and install it as root. The DOS version does not need additional +files. + +O2EM is a command line based program, but there are several Windows frontends +you can use. The "official" one is O2EM Launcher, created by Heitor +Barcellos. + +In order to build O2EM from its sources, you need either the MingW or Cygwin +packages on Windows, DJGPP on DOS and GCC on Linux. See the links below. + +The latest version of O2EM can be found at http://o2em.sourceforge.net If you +want to send bug reports, or be part of the O2EM development, go to the O2EM +project page at SourceForge : http://sourceforge.net/projects/o2em/ + + + +Useful links: + +Dan Boris' home page: http://www.atarihq.com/danb/ +Allegro library: http://alleg.sourceforge.net/ +MingW C/C++ compiler: http://sourceforge.net/projects/mingw/ +Soeren Gust page : http://soeren.informationstheater.de/ +Odyssey2 Home: http://www.classicgaming.com/o2home/ +Odysseymania the brazilian webpage : http://odysseymania.classicgaming.com.br +OdysseyBR Group: http://gamesource.groups.yahoo.com/group/OdysseyBR/ +Videopac Forum: http://www.videopac.org + +Acknowledgments: + + +We wish to thank the following people: + + Keita Iida (Keita/Pooka/Fygar) + for his enthusiasm, for the O2EM beta testing, and general encouragement. + + Marco Kerstens (MarcoK) + for providing Videopac schematics, and general support. + + Matthew Pritchard + for sending some official O2 programming documents. + + Bo Krogsgaard (Therion23) + for putting the idea of doing the emulator into my head to start with. + + Jason F. Gohlke + for providing valuable Voice tech info as well as the voice samples. + + Soeren Gust : For sending his patches to O2EM and for technical + information about the console. Part of his technical document was + used to implement VP+ emulation. + + René van den Enden : for providing information about several + unsupported games and other help. + + Simon Scudder : for sending technical information about the O2 + (including the datasheet of the VP+ gfx chipset), sampled sounds and + his nice O2 disassembler. + + Heitor Barcellos : for creating the O2EM Launcher frontend. + + Marcelo Ribeiro : for the icon used with the windows version of O2EM, + bug reports, and for information about O2 games. + + Rafael : for compiling a big list of bugs present in O2EM v0.87. + + Zimmerman : for sending his patch to add key customization, on which + v1.00 customization was based. + + Arlindo de Oliveira : for sending patches to fix bugs in O2EM and for + his interest in keeping the O2 emulation alive. + + The members of the OdysseyBR user group: for several bug reports, as + well for support in general. + +----------------------------------------------------------------------------- + +Building: + +o2em depends on Allegro, for Ubuntu / Debian, run: + +sudo apt-get install liballegro4-dev + +----------------------------------------------------------------------------- + +Quick Setup: + +To get O2EM up and running quickly follow these steps: + +1. Unzip the O2EM archive on your hard drive, that will create the necessary + standard directories: ROMS, BIOS and VOICE into the main directory O2EM118. +2. Download the bios ROM O2ROM.BIN (or G7400.BIN, or C52.BIN, or JOPAC.BIN) + and put it into BIOS directory. +3. Download one or more game ROMs, for example KCMUNCH.BIN for KC Munchkin and + put the ROM in ROMS directory. +4. From the O2EM118 directory type: o2em KCMUNCH.BIN to start the game.If wants + to play KC Munchkin with BIOS VP+, type: o2em KCMUNCH.BIN -g7400 + +--------------------------------------------------------------------------- +Setup: + + Before you can run O2EM you need a copy of the Odyssey2 or Videopac bios +ROM. For copyright reasons, this ROM image can not be included in this +archive. This ROM image is stored inside the 8048 processor and can be read +out with the appropriate equipment. The image should be 1024 bytes long and +should be in the BIOS directory into the main directory O2EM118. + + You will also need cartridge images, but again for copyright reasons +these can not be provided. PLEASE DO NOT E-mail us asking for ROM images! All +messages asking for ROM images will be promptly deleted. + + If you wish to use Voice emulation for games like KC's Krazy Chase. +Download the voice samples and unzip them into the VOICE directory +into the main directory O2EM118. There are two sets of voice samples, +mainsamp.zip which is the main voice samples and sidsamp.zip which are the +samples used by the game Sid the Spellbinder. You only need the Sid samples +if you want voice in that game. + +--------------------------------------------------------------------------- + + +Usage: + + +o2em [options] + + = file to load with extension + + +options: + +-help Help display + +-wsize=n Window size used by the emulator (1=original, 2=double size, etc.) + +-fullscreen Use full screen mode + +-scanlines Enable scanlines use by the video emulation. Scanlines are a + feature that makes your display look like a TV screen. + +-nosound Turn off sound emulation + +-novoice Turn off voice emulation + +-svolume=n Set sound volume (0-100) + +-vvolume=n Set voice volume (0-100) + +-debug Start the emulator in debug mode + +-speed=n Relative speed (100 = original speed) + +-nolimit Turn off speed limiter + +-bios=file Set the file name and directory to find the console + bios. By default it looks for a file named o2rom.bin. + You can use a bios file from an Odyssey2, Videopac or + Videopac+ console. If you want to run VP+ games (in + VP+ mode) then you need a VP+ bios. + +-romdir=path Set the directory to find the game rom. By default it + looks for path named .../roms + +-biosdir=path Set the directory to find the console bios. By default it + looks for path named .../bios + +-o2rom Start the emulator with Odyssey 2 bios (default for most games). + +-c52 Start the emulator with french Odyssey 2 bios. + +-g7400 Start the emulator with VP+ bios (default for detected VP+ only games). + +-jopac Start the emulator with french VP+ bios. + +-euro This option enables the use of European timing / 50Hz mode. + This option is usually not needed as most of the games that + really require this mode will be auto-detected. + +-filter Enable the low-pass audio filter. + +-scshot=file Set the screen shot file name or template. The screen shot + will be saved when you press the F8 key in the emulator. + The extension of the file you give will set the file type. + supported file types are bmp, pcx and tga. You can also give + a template to save several files, using the @ character. + Using an option like -scshot=dump@.bmp will save files with + names like dump00.bmp, dump01.bmp, etc. The pictures will + have a resolution of (320x240)*wsize. + +-exrom Enable the use of an alternative ROM mapping for 4Kb games, to + support some games that use a special 3kb program rom/1kb data + ROM mode. The only known that use it are Four in 1 Row and + Musician and both are detected by their CRC and set correctly. + So this option is to be used only with games that are currently + unknown to O2EM. Do not enable it as default, as it will make + all the 4kb games that do not use this special mode crash. + +-s0=QUIT,PAUSE,DEBUG,RESET,SCREENCAP,SAVE,LOAD,INJECT_HIGH + These option defines which keys are used for some of the system + keys, if you use this option, you have to enter all 8 keys, to + override the original keys (ESC,F1,F4,F5,F8,F2,F3,F6) + +-s1=mode/keys Define stick 1 mode/keys +-s2=mode/keys Define stick 2 mode/keys + + These options define how the console joysticks are emulated. + You can use a joystick connected to your computer or use + the keyboard. You can specify a mode number (compatible with + previous versions of O2EM) to disable the joystick emulation, + to select an actual joystick or to set a default keyboard + emulation mode : + 0=Disable, + 1=Default Right keys (arrows keys and right shift) + 2=Default Left keys (W,S,A,D,SPACE) + 3=Joystick + Example: -s1=1 -s2=3 + + You can also specify a list of 5 keyboard codes that will + be used to emulate the joystick, separated by comas + (without spaces), using this order : UP,DOWN,LEFT,RIGHT,FIRE. + The following codes are accepted (not case sensitive): + A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0_PAD,1_PAD,2_PAD,3_PAD,4_PAD,5_PAD,6_PAD,7_PAD,8_PAD,9_PAD, + TILDE, MINUS, EQUALS, BACKSPACE, TAB, OPENBRACE, CLOSEBRACE, + ENTER, COLON, QUOTE, BACKSLASH, BACKSLASH2, COMMA, STOP, + SLASH, SPACE, INSERT, DEL, HOME, END, PGUP, PGDN, LEFT, + RIGHT, UP, DOWN, SLASH_PAD, ASTERISK, MINUS_PAD, PLUS_PAD, + DEL_PAD, ENTER_PAD, PRTSCR, PAUSE, ABNT_C1, YEN, KANA, AT, + CIRCUMFLEX, COLON2, KANJI, LSHIFT, RSHIFT, LCONTROL, + RCONTROL, ALT, ALTGR, LWIN, RWIN, MENU, SCRLOCK, NUMLOCK + Example: -s1=y,h,g,j,lcontrol -s2=8_PAD,5_PAD,4_PAD,6_PAD,RCONTROL + +-scoreadr=address where the high-score is saved for specific rom +-scoretype=type how the high-score is saved for specific rom +-score=highscore default highscore on launch ("inject" with F6) +-scorefile=file file where the highscore is saved on exit + +-savefile=file filename for save/load state + + + + +---------------------------------------------------------------------------- + +Default configuration file: + +O2EM now can use a configuration file to set the default options, so you can +specify your preferred options in this file, instead of typing it every time +you execute the emulator. The command line options override the default +settings in the file. This file must be called o2em_def.cfg and be in the +same directory of O2EM118. This configuration file is a text file where you can +put the same options you would use when calling O2EM by the command line, but +each option must be in a different line and you should not precede it with +the - character. You can also put comment lines in the file, starting the +line with the # character. Example configuration file: + + # My config + wsize=3 + Euro + scanlines + filter + g7400 + s1=8_pad,5_pad,4_pad,6_pad,rcontrol + + +You disable any option set in this file when you call O2EM in the command +line, passing the =0 parameter to the option. For this example configuration, +you could disable the filter option set in the file putting -filter=0 when +you call O2EM. + + +---------------------------------------------------------------------------- + +Controls: + + Arrow keys + L = Default joystick 1 emulation + + W,D,S,A + Space = Default joystick 2 emulation + + ESC/F12 = Leave the emulator + + F1 = Pause/Information + + F2 = Save State-File + + F3 = Load State-File + + F4 = Enter debugger + + F5 = Reset emulator (same as pressing the reset on the O2 keyboard) + + F6 = Inject Highscore + + F8 = Make a screen shot + + Caps Lock = Enables/Disables the O2 keyboard input of the keys used by + joystick emulation + +---------------------------------------------------------------------------- + +Debugger: + +The emulator comes with a built in debugger that was used for development. +The debugger is not very polished and fairly incomplete but it can be useful +for single stepping through programs and watching their behavior. + +H = display help + +---------------------------------------------------------------------------- + + diff --git a/waterbox/o2em/audio.c b/waterbox/o2em/audio.c new file mode 100644 index 0000000000..345eb55002 --- /dev/null +++ b/waterbox/o2em/audio.c @@ -0,0 +1,95 @@ + +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * O2 audio emulation + */ + +#include +#include +#include +#include "cpu.h" +#include "types.h" +#include "config.h" +#include "vmachine.h" +#include "audio.h" + +#define SAMPLE_RATE 44100 +#define PERIOD1 11 +#define PERIOD2 44 + +#define SOUND_BUFFER_LEN 1056 + +#define AUD_CTRL 0xAA +#define AUD_D0 0xA7 +#define AUD_D1 0xA8 +#define AUD_D2 0xA9 + +int sound_IRQ; + +static double flt_a = 0.0, flt_b = 0.0; +static unsigned char flt_prv = 0; + +void audio_process(unsigned char *buffer) +{ + unsigned long aud_data; + int volume, re_circ, noise, enabled, intena, period, pnt, cnt, rndbit, pos; + + aud_data = (VDCwrite[AUD_D2] | (VDCwrite[AUD_D1] << 8) | (VDCwrite[AUD_D0] << 16)); + + intena = VDCwrite[0xA0] & 0x04; + + pnt = cnt = 0; + + noise = VDCwrite[AUD_CTRL] & 0x10; + enabled = VDCwrite[AUD_CTRL] & 0x80; + rndbit = (enabled && noise) ? (rand() % 2) : 0; + + while (pnt < SOUND_BUFFER_LEN) + { + pos = (tweakedaudio) ? (pnt / 3) : (MAXLINES - 1); + volume = AudioVector[pos] & 0x0F; + enabled = AudioVector[pos] & 0x80; + period = (AudioVector[pos] & 0x20) ? PERIOD1 : PERIOD2; + re_circ = AudioVector[pos] & 0x40; + + buffer[pnt++] = (enabled) ? ((aud_data & 0x01) ^ rndbit) * (0x10 * volume) : 0; + cnt++; + + if (cnt >= period) + { + cnt = 0; + aud_data = (re_circ) ? ((aud_data >> 1) | ((aud_data & 1) << 23)) : (aud_data >> 1); + rndbit = (enabled && noise) ? (rand() % 2) : 0; + + if (enabled && intena && (!sound_IRQ)) + { + sound_IRQ = 1; + ext_IRQ(); + } + } + } + + //if (app_data.filter) + //filter(buffer, SOUND_BUFFER_LEN); +} + +void update_audio(void) +{ + unsigned char scratch[4096]; + audio_process(scratch); +} + +void init_audio(void) +{ + sound_IRQ = 0; +} diff --git a/waterbox/o2em/audio.h b/waterbox/o2em/audio.h new file mode 100644 index 0000000000..6d4a805cc4 --- /dev/null +++ b/waterbox/o2em/audio.h @@ -0,0 +1,14 @@ +#ifndef __AUDIO_H +#define __AUDIO_H + +void update_audio(void); +void init_audio(void); +void init_sound_stream(void); + + +extern int sound_IRQ; + + +#endif + + diff --git a/waterbox/o2em/bitmap.c b/waterbox/o2em/bitmap.c new file mode 100644 index 0000000000..715fe79c5f --- /dev/null +++ b/waterbox/o2em/bitmap.c @@ -0,0 +1,22 @@ +#include "bitmap.h" +#include +#include + +void clear(Bitmap* b) +{ + memset(b->dat, 0, b->w * b->h); +} + +Bitmap* NewBitmap(int w, int h) +{ + Bitmap* b = malloc(sizeof(Bitmap) + w * h); + b->w = w; + b->h = h; + b->line = malloc(sizeof(uint8_t*) * h); + b->dat = malloc(w * h); + for (int i = 0; i < h; i++) + b->line[i] = b->dat + w * i; + + clear(b); + return b; +} diff --git a/waterbox/o2em/bitmap.h b/waterbox/o2em/bitmap.h new file mode 100644 index 0000000000..dec2e6e437 --- /dev/null +++ b/waterbox/o2em/bitmap.h @@ -0,0 +1,13 @@ +#pragma once +#include + +typedef struct +{ + uint8_t** line; + uint8_t* dat; + int w; + int h; +} Bitmap; + +void clear(Bitmap* b); +Bitmap* NewBitmap(int w, int h); diff --git a/waterbox/o2em/config.h b/waterbox/o2em/config.h new file mode 100644 index 0000000000..715a373990 --- /dev/null +++ b/waterbox/o2em/config.h @@ -0,0 +1,14 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#define O2EM_VERSION "1.18" +#define RELEASE_DATE "(Jan/2007)" + +#define ROM_O2 1 +#define ROM_G7400 2 +#define ROM_C52 3 +#define ROM_JOPAC 4 +#define ROM_UNKNOWN 99 + +#endif + diff --git a/waterbox/o2em/cpu.c b/waterbox/o2em/cpu.c new file mode 100644 index 0000000000..addf20d4cf --- /dev/null +++ b/waterbox/o2em/cpu.c @@ -0,0 +1,1670 @@ + +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + ** Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * 8048 microcontroller emulation + */ + +#include +#include "types.h" +#include "vmachine.h" +#include "keyboard.h" +#include "voice.h" +#include "vdc.h" +#include "vpp.h" +#include "cpu.h" + +static int64_t clk; + +#define push(d) \ + { \ + intRAM[sp++] = (d); \ + if (sp > 23) \ + sp = 8; \ + } +#define pull() (sp--, (sp < 8) ? (sp = 23) : 0, intRAM[sp]) +#define make_psw() \ + { \ + psw = (cy << 7) | ac | f0 | bs | 0x08; \ + psw = psw | ((sp - 8) >> 1); \ + } +#define illegal(o) \ + { \ + } +#define undef(i) \ + { \ + printf("** unimplemented instruction %x, %x**\n", i, pc); \ + } +#define ROM(adr) (rom[(adr)&0xfff]) + +void init_cpu(void) +{ + pc = 0; + sp = 8; + bs = 0; + p1 = p2 = 0xFF; + ac = cy = f0 = 0; + A11 = A11ff = 0; + timer_on = 0; + count_on = 0; + reg_pnt = 0; + tirq_en = xirq_en = irq_ex = xirq_pend = tirq_pend = 0; +} + +void ext_IRQ(void) +{ + int_clk = 5; /* length of pulse on /INT */ + if (xirq_en && !irq_ex) + { + irq_ex = 1; + xirq_pend = 0; + clk += 2; + make_psw(); + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = 0x03; + A11ff = A11; + A11 = 0; + } + if (pendirq && (!xirq_en)) + xirq_pend = 1; +} + +void tim_IRQ(void) +{ + if (tirq_en && !irq_ex) + { + irq_ex = 2; + tirq_pend = 0; + clk += 2; + make_psw(); + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = 0x07; + A11ff = A11; + A11 = 0; + } + if (pendirq && (!tirq_en)) + tirq_pend = 1; +} + +void make_psw_debug(void) +{ + make_psw(); +} + +int64_t cpu_exec(int64_t ncycles) +{ + int64_t startclk = clk; + int64_t targetclk = clk + ncycles; + + Byte op; + ADDRESS adr; + Byte dat; + int temp; + + while (clk < targetclk) + { + lastpc = pc; + op = ROM(pc++); + switch (op) + { + case 0x00: /* NOP */ + clk++; + break; + case 0x01: /* ILL */ + illegal(op); + clk++; + break; + case 0x02: /* OUTL BUS,A */ + clk += 2; + undef(0x02); + break; + case 0x03: /* ADD A,#data */ + clk += 2; + cy = ac = 0; + dat = ROM(pc++); + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x04: /* JMP */ + pc = ROM(pc) | A11; + clk += 2; + break; + case 0x05: /* EN I */ + xirq_en = 1; + clk++; + break; + case 0x06: /* ILL */ + clk++; + illegal(op); + break; + case 0x07: /* DEC A */ + acc--; + clk++; + break; + case 0x08: /* INS A,BUS*/ + clk += 2; + acc = in_bus(); + break; + case 0x09: /* IN A,Pp */ + acc = p1; + clk += 2; + break; + case 0x0A: /* IN A,Pp */ + acc = read_P2(); + clk += 2; + break; + case 0x0B: /* ILL */ + clk++; + illegal(op); + break; + case 0x0C: /* MOVD A,P4 */ + clk += 2; + acc = read_PB(0); + break; + case 0x0D: /* MOVD A,P5 */ + clk += 2; + acc = read_PB(1); + break; + case 0x0E: /* MOVD A,P6 */ + clk += 2; + acc = read_PB(2); + break; + case 0x0F: /* MOVD A,P7 */ + clk += 2; + acc = read_PB(3); + break; + case 0x10: /* INC @Ri */ + intRAM[intRAM[reg_pnt] & 0x3F]++; + clk++; + break; + case 0x11: /* INC @Ri */ + intRAM[intRAM[reg_pnt + 1] & 0x3F]++; + clk++; + break; + case 0x12: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x01) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x13: /* ADDC A,#data */ + clk += 2; + dat = ROM(pc++); + ac = 0; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + + case 0x14: /* CALL */ + make_psw(); + adr = ROM(pc) | A11; + pc++; + clk += 2; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0x15: /* DIS I */ + xirq_en = 0; + clk++; + break; + case 0x16: /* JTF */ + clk += 2; + dat = ROM(pc); + if (t_flag) + pc = (pc & 0xF00) | dat; + else + pc++; + t_flag = 0; + break; + case 0x17: /* INC A */ + acc++; + clk++; + break; + case 0x18: /* INC Rr */ + intRAM[reg_pnt]++; + clk++; + break; + case 0x19: /* INC Rr */ + intRAM[reg_pnt + 1]++; + clk++; + break; + case 0x1A: /* INC Rr */ + intRAM[reg_pnt + 2]++; + clk++; + break; + case 0x1B: /* INC Rr */ + intRAM[reg_pnt + 3]++; + clk++; + break; + case 0x1C: /* INC Rr */ + intRAM[reg_pnt + 4]++; + clk++; + break; + case 0x1D: /* INC Rr */ + intRAM[reg_pnt + 5]++; + clk++; + break; + case 0x1E: /* INC Rr */ + intRAM[reg_pnt + 6]++; + clk++; + break; + case 0x1F: /* INC Rr */ + intRAM[reg_pnt + 7]++; + clk++; + break; + case 0x20: /* XCH A,@Ri */ + clk++; + dat = acc; + acc = intRAM[intRAM[reg_pnt] & 0x3F]; + intRAM[intRAM[reg_pnt] & 0x3F] = dat; + break; + case 0x21: /* XCH A,@Ri */ + clk++; + dat = acc; + acc = intRAM[intRAM[reg_pnt + 1] & 0x3F]; + intRAM[intRAM[reg_pnt + 1] & 0x3F] = dat; + break; + case 0x22: /* ILL */ + clk++; + illegal(op); + break; + case 0x23: /* MOV a,#data */ + clk += 2; + acc = ROM(pc++); + break; + + case 0x24: /* JMP */ + pc = ROM(pc) | 0x100 | A11; + clk += 2; + break; + case 0x25: /* EN TCNTI */ + tirq_en = 1; + clk++; + break; + case 0x26: /* JNT0 */ + clk += 2; + dat = ROM(pc); + if (!get_voice_status()) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x27: /* CLR A */ + clk++; + acc = 0; + break; + case 0x28: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt]; + intRAM[reg_pnt] = dat; + clk++; + break; + case 0x29: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt + 1]; + intRAM[reg_pnt + 1] = dat; + clk++; + break; + case 0x2A: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt + 2]; + intRAM[reg_pnt + 2] = dat; + clk++; + break; + case 0x2B: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt + 3]; + intRAM[reg_pnt + 3] = dat; + clk++; + break; + case 0x2C: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt + 4]; + intRAM[reg_pnt + 4] = dat; + clk++; + break; + case 0x2D: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt + 5]; + intRAM[reg_pnt + 5] = dat; + clk++; + break; + case 0x2E: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt + 6]; + intRAM[reg_pnt + 6] = dat; + clk++; + break; + case 0x2F: /* XCH A,Rr */ + dat = acc; + acc = intRAM[reg_pnt + 7]; + intRAM[reg_pnt + 7] = dat; + clk++; + break; + case 0x30: /* XCHD A,@Ri */ + clk++; + adr = intRAM[reg_pnt] & 0x3F; + dat = acc & 0x0F; + acc = acc & 0xF0; + acc = acc | (intRAM[adr] & 0x0F); + intRAM[adr] &= 0xF0; + intRAM[adr] |= dat; + break; + case 0x31: /* XCHD A,@Ri */ + clk++; + adr = intRAM[reg_pnt + 1] & 0x3F; + dat = acc & 0x0F; + acc = acc & 0xF0; + acc = acc | (intRAM[adr] & 0x0F); + intRAM[adr] &= 0xF0; + intRAM[adr] |= dat; + break; + case 0x32: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x02) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x33: /* ILL */ + clk++; + illegal(op); + break; + case 0x34: /* CALL */ + make_psw(); + adr = ROM(pc) | 0x100 | A11; + pc++; + clk += 2; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0x35: /* DIS TCNTI */ + tirq_en = 0; + tirq_pend = 0; + clk++; + break; + case 0x36: /* JT0 */ + clk += 2; + dat = ROM(pc); + if (get_voice_status()) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x37: /* CPL A */ + acc = acc ^ 0xFF; + clk++; + break; + case 0x38: /* ILL */ + clk++; + illegal(op); + break; + case 0x39: /* OUTL P1,A */ + clk += 2; + write_p1(acc); + break; + case 0x3A: /* OUTL P2,A */ + clk += 2; + p2 = acc; + break; + case 0x3B: /* ILL */ + clk++; + illegal(op); + break; + case 0x3C: /* MOVD P4,A */ + clk += 2; + write_PB(0, acc); + break; + case 0x3D: /* MOVD P5,A */ + clk += 2; + write_PB(1, acc); + break; + case 0x3E: /* MOVD P6,A */ + clk += 2; + write_PB(2, acc); + break; + case 0x3F: /* MOVD P7,A */ + clk += 2; + write_PB(3, acc); + break; + case 0x40: /* ORL A,@Ri */ + clk++; + acc = acc | intRAM[intRAM[reg_pnt] & 0x3F]; + break; + case 0x41: /* ORL A,@Ri */ + clk++; + acc = acc | intRAM[intRAM[reg_pnt + 1] & 0x3F]; + break; + case 0x42: /* MOV A,T */ + clk++; + acc = itimer; + break; + case 0x43: /* ORL A,#data */ + clk += 2; + acc = acc | ROM(pc++); + break; + case 0x44: /* JMP */ + pc = ROM(pc) | 0x200 | A11; + clk += 2; + break; + case 0x45: /* STRT CNT */ + /* printf("START: %d=%d\n",master_clk/22,itimer); */ + count_on = 1; + clk++; + break; + case 0x46: /* JNT1 */ + clk += 2; + dat = ROM(pc); + if (!read_t1()) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x47: /* SWAP A */ + clk++; + dat = (acc & 0xF0) >> 4; + acc = acc << 4; + acc = acc | dat; + break; + case 0x48: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt]; + break; + case 0x49: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt + 1]; + break; + case 0x4A: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt + 2]; + break; + case 0x4B: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt + 3]; + break; + case 0x4C: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt + 4]; + break; + case 0x4D: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt + 5]; + break; + case 0x4E: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt + 6]; + break; + case 0x4F: /* ORL A,Rr */ + clk++; + acc = acc | intRAM[reg_pnt + 7]; + break; + + case 0x50: /* ANL A,@Ri */ + acc = acc & intRAM[intRAM[reg_pnt] & 0x3F]; + clk++; + break; + case 0x51: /* ANL A,@Ri */ + acc = acc & intRAM[intRAM[reg_pnt + 1] & 0x3F]; + clk++; + break; + case 0x52: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x04) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x53: /* ANL A,#data */ + clk += 2; + acc = acc & ROM(pc++); + break; + case 0x54: /* CALL */ + make_psw(); + adr = ROM(pc) | 0x200 | A11; + pc++; + clk += 2; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0x55: /* STRT T */ + timer_on = 1; + clk++; + break; + case 0x56: /* JT1 */ + clk += 2; + dat = ROM(pc); + if (read_t1()) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x57: /* DA A */ + clk++; + if (((acc & 0x0F) > 0x09) || ac) + { + if (acc > 0xf9) + cy = 1; + acc += 6; + } + dat = (acc & 0xF0) >> 4; + if ((dat > 9) || cy) + { + dat += 6; + cy = 1; + } + acc = (acc & 0x0F) | (dat << 4); + break; + case 0x58: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt]; + break; + case 0x59: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt + 1]; + break; + case 0x5A: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt + 2]; + break; + case 0x5B: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt + 3]; + break; + case 0x5C: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt + 4]; + break; + case 0x5D: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt + 5]; + break; + case 0x5E: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt + 6]; + break; + case 0x5F: /* ANL A,Rr */ + clk++; + acc = acc & intRAM[reg_pnt + 7]; + break; + + case 0x60: /* ADD A,@Ri */ + clk++; + cy = ac = 0; + dat = intRAM[intRAM[reg_pnt] & 0x3F]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x61: /* ADD A,@Ri */ + clk++; + cy = ac = 0; + dat = intRAM[intRAM[reg_pnt + 1] & 0x3F]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x62: /* MOV T,A */ + clk++; + itimer = acc; + break; + case 0x63: /* ILL */ + clk++; + illegal(op); + break; + case 0x64: /* JMP */ + pc = ROM(pc) | 0x300 | A11; + clk += 2; + break; + case 0x65: /* STOP TCNT */ + clk++; + /* printf("STOP %d\n",master_clk/22); */ + count_on = timer_on = 0; + break; + case 0x66: /* ILL */ + clk++; + illegal(op); + break; + case 0x67: /* RRC A */ + dat = cy; + cy = acc & 0x01; + acc = acc >> 1; + if (dat) + acc = acc | 0x80; + else + acc = acc & 0x7F; + clk++; + break; + case 0x68: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x69: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt + 1]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x6A: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt + 2]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x6B: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt + 3]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x6C: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt + 4]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x6D: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt + 5]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x6E: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt + 6]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x6F: /* ADD A,Rr */ + clk++; + cy = ac = 0; + dat = intRAM[reg_pnt + 7]; + if (((acc & 0x0f) + (dat & 0x0f)) > 0x0f) + ac = 0x40; + temp = acc + dat; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x70: /* ADDC A,@Ri */ + clk++; + ac = 0; + dat = intRAM[intRAM[reg_pnt] & 0x3F]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x71: /* ADDC A,@Ri */ + clk++; + ac = 0; + dat = intRAM[intRAM[reg_pnt + 1] & 0x3F]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + + case 0x72: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x08) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x73: /* ILL */ + clk++; + illegal(op); + break; + case 0x74: /* CALL */ + make_psw(); + adr = ROM(pc) | 0x300 | A11; + pc++; + clk += 2; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0x75: /* EN CLK */ + clk++; + undef(op); + break; + case 0x76: /* JF1 address */ + clk += 2; + dat = ROM(pc); + if (f1) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x77: /* RR A */ + clk++; + dat = acc & 0x01; + acc = acc >> 1; + if (dat) + acc = acc | 0x80; + else + acc = acc & 0x7f; + break; + + case 0x78: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x79: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt + 1]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x7A: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt + 2]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x7B: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt + 3]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x7C: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt + 4]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x7D: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt + 5]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x7E: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt + 6]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + case 0x7F: /* ADDC A,Rr */ + clk++; + ac = 0; + dat = intRAM[reg_pnt + 7]; + if (((acc & 0x0f) + (dat & 0x0f) + cy) > 0x0f) + ac = 0x40; + temp = acc + dat + cy; + cy = 0; + if (temp > 0xFF) + cy = 1; + acc = (temp & 0xFF); + break; + + case 0x80: /* MOVX A,@Ri */ + acc = ext_read(intRAM[reg_pnt]); + clk += 2; + break; + case 0x81: /* MOVX A,@Ri */ + acc = ext_read(intRAM[reg_pnt + 1]); + clk += 2; + break; + case 0x82: /* ILL */ + clk++; + illegal(op); + break; + case 0x83: /* RET */ + clk += 2; + pc = ((pull() & 0x0F) << 8); + pc = pc | pull(); + break; + case 0x84: /* JMP */ + pc = ROM(pc) | 0x400 | A11; + clk += 2; + break; + case 0x85: /* CLR F0 */ + clk++; + f0 = 0; + break; + case 0x86: /* JNI address */ + clk += 2; + dat = ROM(pc); + if (int_clk > 0) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x87: /* ILL */ + illegal(op); + clk++; + break; + case 0x88: /* BUS,#data */ + clk += 2; + undef(op); + break; + case 0x89: /* ORL Pp,#data */ + write_p1(p1 | ROM(pc++)); + clk += 2; + break; + case 0x8A: /* ORL Pp,#data */ + p2 = p2 | ROM(pc++); + clk += 2; + break; + case 0x8B: /* ILL */ + illegal(op); + clk++; + break; + case 0x8C: /* ORLD P4,A */ + write_PB(0, read_PB(0) | acc); + clk += 2; + break; + case 0x8D: /* ORLD P5,A */ + write_PB(1, read_PB(1) | acc); + clk += 2; + break; + case 0x8E: /* ORLD P6,A */ + write_PB(2, read_PB(2) | acc); + clk += 2; + break; + case 0x8F: /* ORLD P7,A */ + write_PB(3, read_PB(3) | acc); + clk += 2; + break; + case 0x90: /* MOVX @Ri,A */ + ext_write(acc, intRAM[reg_pnt]); + clk += 2; + break; + case 0x91: /* MOVX @Ri,A */ + ext_write(acc, intRAM[reg_pnt + 1]); + clk += 2; + break; + case 0x92: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x10) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x93: /* RETR*/ + /* printf("RETR %d\n",master_clk/22); */ + clk += 2; + dat = pull(); + pc = (dat & 0x0F) << 8; + cy = (dat & 0x80) >> 7; + ac = dat & 0x40; + f0 = dat & 0x20; + bs = dat & 0x10; + if (bs) + reg_pnt = 24; + else + reg_pnt = 0; + pc = pc | pull(); + irq_ex = 0; + A11 = A11ff; + break; + case 0x94: /* CALL */ + make_psw(); + adr = ROM(pc) | 0x400 | A11; + pc++; + clk += 2; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0x95: /* CPL F0 */ + f0 = f0 ^ 0x20; + clk++; + break; + case 0x96: /* JNZ address */ + clk += 2; + dat = ROM(pc); + if (acc != 0) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0x97: /* CLR C */ + cy = 0; + clk++; + break; + case 0x98: /* ANL BUS,#data */ + clk += 2; + undef(op); + break; + case 0x99: /* ANL Pp,#data */ + write_p1(p1 & ROM(pc++)); + clk += 2; + break; + case 0x9A: /* ANL Pp,#data */ + p2 = p2 & ROM(pc++); + clk += 2; + break; + case 0x9B: /* ILL */ + illegal(op); + clk++; + break; + case 0x9C: /* ANLD P4,A */ + write_PB(0, read_PB(0) & acc); + clk += 2; + break; + case 0x9D: /* ANLD P5,A */ + write_PB(1, read_PB(1) & acc); + clk += 2; + break; + case 0x9E: /* ANLD P6,A */ + write_PB(2, read_PB(2) & acc); + clk += 2; + break; + case 0x9F: /* ANLD P7,A */ + write_PB(3, read_PB(3) & acc); + clk += 2; + break; + case 0xA0: /* MOV @Ri,A */ + intRAM[intRAM[reg_pnt] & 0x3F] = acc; + clk++; + break; + case 0xA1: /* MOV @Ri,A */ + intRAM[intRAM[reg_pnt + 1] & 0x3F] = acc; + clk++; + break; + case 0xA2: /* ILL */ + clk++; + illegal(op); + break; + case 0xA3: /* MOVP A,@A */ + acc = ROM((pc & 0xF00) | acc); + clk += 2; + break; + case 0xA4: /* JMP */ + pc = ROM(pc) | 0x500 | A11; + clk += 2; + break; + case 0xA5: /* CLR F1 */ + clk++; + f1 = 0; + break; + case 0xA6: /* ILL */ + illegal(op); + clk++; + break; + case 0xA7: /* CPL C */ + cy = cy ^ 0x01; + clk++; + break; + case 0xA8: /* MOV Rr,A */ + intRAM[reg_pnt] = acc; + clk++; + break; + case 0xA9: /* MOV Rr,A */ + intRAM[reg_pnt + 1] = acc; + clk++; + break; + case 0xAA: /* MOV Rr,A */ + intRAM[reg_pnt + 2] = acc; + clk++; + break; + case 0xAB: /* MOV Rr,A */ + intRAM[reg_pnt + 3] = acc; + clk++; + break; + case 0xAC: /* MOV Rr,A */ + intRAM[reg_pnt + 4] = acc; + clk++; + break; + case 0xAD: /* MOV Rr,A */ + intRAM[reg_pnt + 5] = acc; + clk++; + break; + case 0xAE: /* MOV Rr,A */ + intRAM[reg_pnt + 6] = acc; + clk++; + break; + case 0xAF: /* MOV Rr,A */ + intRAM[reg_pnt + 7] = acc; + clk++; + break; + case 0xB0: /* MOV @Ri,#data */ + intRAM[intRAM[reg_pnt] & 0x3F] = ROM(pc++); + clk += 2; + break; + case 0xB1: /* MOV @Ri,#data */ + intRAM[intRAM[reg_pnt + 1] & 0x3F] = ROM(pc++); + clk += 2; + break; + case 0xB2: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x20) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0xB3: /* JMPP @A */ + adr = (pc & 0xF00) | acc; + pc = (pc & 0xF00) | ROM(adr); + clk += 2; + break; + case 0xB4: /* CALL */ + make_psw(); + adr = ROM(pc) | 0x500 | A11; + pc++; + clk += 2; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0xB5: /* CPL F1 */ + f1 = f1 ^ 0x01; + clk++; + break; + case 0xB6: /* JF0 address */ + clk += 2; + dat = ROM(pc); + if (f0) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0xB7: /* ILL */ + clk++; + illegal(op); + break; + case 0xB8: /* MOV Rr,#data */ + intRAM[reg_pnt] = ROM(pc++); + clk += 2; + break; + case 0xB9: /* MOV Rr,#data */ + intRAM[reg_pnt + 1] = ROM(pc++); + clk += 2; + break; + case 0xBA: /* MOV Rr,#data */ + intRAM[reg_pnt + 2] = ROM(pc++); + clk += 2; + break; + case 0xBB: /* MOV Rr,#data */ + intRAM[reg_pnt + 3] = ROM(pc++); + clk += 2; + break; + case 0xBC: /* MOV Rr,#data */ + intRAM[reg_pnt + 4] = ROM(pc++); + clk += 2; + break; + case 0xBD: /* MOV Rr,#data */ + intRAM[reg_pnt + 5] = ROM(pc++); + clk += 2; + break; + case 0xBE: /* MOV Rr,#data */ + intRAM[reg_pnt + 6] = ROM(pc++); + clk += 2; + break; + case 0xBF: /* MOV Rr,#data */ + intRAM[reg_pnt + 7] = ROM(pc++); + clk += 2; + break; + case 0xC0: /* ILL */ + illegal(op); + clk++; + break; + case 0xC1: /* ILL */ + illegal(op); + clk++; + break; + case 0xC2: /* ILL */ + illegal(op); + clk++; + break; + case 0xC3: /* ILL */ + illegal(op); + clk++; + break; + case 0xC4: /* JMP */ + pc = ROM(pc) | 0x600 | A11; + clk += 2; + break; + case 0xC5: /* SEL RB0 */ + bs = reg_pnt = 0; + clk++; + break; + case 0xC6: /* JZ address */ + clk += 2; + dat = ROM(pc); + if (acc == 0) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0xC7: /* MOV A,PSW */ + clk++; + make_psw(); + acc = psw; + break; + case 0xC8: /* DEC Rr */ + intRAM[reg_pnt]--; + clk++; + break; + case 0xC9: /* DEC Rr */ + intRAM[reg_pnt + 1]--; + clk++; + break; + case 0xCA: /* DEC Rr */ + intRAM[reg_pnt + 2]--; + clk++; + break; + case 0xCB: /* DEC Rr */ + intRAM[reg_pnt + 3]--; + clk++; + break; + case 0xCC: /* DEC Rr */ + intRAM[reg_pnt + 4]--; + clk++; + break; + case 0xCD: /* DEC Rr */ + intRAM[reg_pnt + 5]--; + clk++; + break; + case 0xCE: /* DEC Rr */ + intRAM[reg_pnt + 6]--; + clk++; + break; + case 0xCF: /* DEC Rr */ + intRAM[reg_pnt + 7]--; + clk++; + break; + case 0xD0: /* XRL A,@Ri */ + acc = acc ^ intRAM[intRAM[reg_pnt] & 0x3F]; + clk++; + break; + case 0xD1: /* XRL A,@Ri */ + acc = acc ^ intRAM[intRAM[reg_pnt + 1] & 0x3F]; + clk++; + break; + case 0xD2: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x40) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0xD3: /* XRL A,#data */ + clk += 2; + acc = acc ^ ROM(pc++); + break; + case 0xD4: /* CALL */ + make_psw(); + adr = ROM(pc) | 0x600 | A11; + pc++; + clk += 2; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0xD5: /* SEL RB1 */ + bs = 0x10; + reg_pnt = 24; + clk++; + break; + case 0xD6: /* ILL */ + illegal(op); + clk++; + break; + case 0xD7: /* MOV PSW,A */ + psw = acc; + clk++; + cy = (psw & 0x80) >> 7; + ac = psw & 0x40; + f0 = psw & 0x20; + bs = psw & 0x10; + if (bs) + reg_pnt = 24; + else + reg_pnt = 0; + sp = (psw & 0x07) << 1; + sp += 8; + break; + case 0xD8: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt]; + clk++; + break; + case 0xD9: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt + 1]; + clk++; + break; + case 0xDA: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt + 2]; + clk++; + break; + case 0xDB: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt + 3]; + clk++; + break; + case 0xDC: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt + 4]; + clk++; + break; + case 0xDD: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt + 5]; + clk++; + break; + case 0xDE: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt + 6]; + clk++; + break; + case 0xDF: /* XRL A,Rr */ + acc = acc ^ intRAM[reg_pnt + 7]; + clk++; + break; + case 0xE0: /* ILL */ + clk++; + illegal(op); + break; + case 0xE1: /* ILL */ + clk++; + illegal(op); + break; + case 0xE2: /* ILL */ + clk++; + illegal(op); + break; + case 0xE3: /* MOVP3 A,@A */ + + adr = 0x300 | acc; + acc = ROM(adr); + clk += 2; + break; + case 0xE4: /* JMP */ + pc = ROM(pc) | 0x700 | A11; + clk += 2; + break; + case 0xE5: /* SEL MB0 */ + A11 = 0; + A11ff = 0; + clk++; + break; + case 0xE6: /* JNC address */ + clk += 2; + dat = ROM(pc); + if (!cy) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0xE7: /* RL A */ + clk++; + dat = acc & 0x80; + acc = acc << 1; + if (dat) + acc = acc | 0x01; + else + acc = acc & 0xFE; + break; + case 0xE8: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt]--; + dat = ROM(pc); + if (intRAM[reg_pnt] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xE9: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt + 1]--; + dat = ROM(pc); + if (intRAM[reg_pnt + 1] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xEA: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt + 2]--; + dat = ROM(pc); + if (intRAM[reg_pnt + 2] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xEB: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt + 3]--; + dat = ROM(pc); + if (intRAM[reg_pnt + 3] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xEC: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt + 4]--; + dat = ROM(pc); + if (intRAM[reg_pnt + 4] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xED: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt + 5]--; + dat = ROM(pc); + if (intRAM[reg_pnt + 5] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xEE: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt + 6]--; + dat = ROM(pc); + if (intRAM[reg_pnt + 6] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xEF: /* DJNZ Rr,address */ + clk += 2; + intRAM[reg_pnt + 7]--; + dat = ROM(pc); + if (intRAM[reg_pnt + 7] != 0) + { + pc = pc & 0xF00; + pc = pc | dat; + } + else + pc++; + break; + case 0xF0: /* MOV A,@Ri */ + clk++; + acc = intRAM[intRAM[reg_pnt] & 0x3F]; + break; + case 0xF1: /* MOV A,@Ri */ + clk++; + acc = intRAM[intRAM[reg_pnt + 1] & 0x3F]; + break; + case 0xF2: /* JBb address */ + clk += 2; + dat = ROM(pc); + if (acc & 0x80) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0xF3: /* ILL */ + illegal(op); + clk++; + break; + case 0xF4: /* CALL */ + clk += 2; + make_psw(); + adr = ROM(pc) | 0x700 | A11; + pc++; + push(pc & 0xFF); + push(((pc & 0xF00) >> 8) | (psw & 0xF0)); + pc = adr; + break; + case 0xF5: /* SEL MB1 */ + if (irq_ex) + { + A11ff = 0x800; + } + else + { + A11 = 0x800; + A11ff = 0x800; + } + clk++; + break; + case 0xF6: /* JC address */ + clk += 2; + dat = ROM(pc); + if (cy) + pc = (pc & 0xF00) | dat; + else + pc++; + break; + case 0xF7: /* RLC A */ + dat = cy; + cy = (acc & 0x80) >> 7; + acc = acc << 1; + if (dat) + acc = acc | 0x01; + else + acc = acc & 0xFE; + clk++; + break; + case 0xF8: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt]; + break; + case 0xF9: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt + 1]; + break; + case 0xFA: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt + 2]; + break; + case 0xFB: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt + 3]; + break; + case 0xFC: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt + 4]; + break; + case 0xFD: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt + 5]; + break; + case 0xFE: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt + 6]; + break; + case 0xFF: /* MOV A,Rr */ + clk++; + acc = intRAM[reg_pnt + 7]; + break; + } + + master_clk += clk; + h_clk += clk; + clk_counter += clk; + + /* flag for JNI */ + if (int_clk > clk) + int_clk -= clk; + else + int_clk = 0; + + /* pending IRQs */ + if (xirq_pend) + ext_IRQ(); + if (tirq_pend) + tim_IRQ(); + + if (h_clk > LINECNT - 1) + { + h_clk -= LINECNT; + if (enahirq && (VDCwrite[0xA0] & 0x01)) + ext_IRQ(); + if (count_on && mstate == 0) + { + itimer++; + if (itimer == 0) + { + t_flag = 1; + tim_IRQ(); + draw_region(); + } + } + } + + if (timer_on) + { + master_count += clk; + if (master_count > 31) + { + master_count -= 31; + itimer++; + if (itimer == 0) + { + t_flag = 1; + tim_IRQ(); + } + } + } + + if ((mstate == 0) && (master_clk > VBLCLK)) + handle_vbl(); + + if ((mstate == 1) && (master_clk > evblclk)) + { + handle_evbl(); + if (app_data.crc == 0xA7344D1F) + handle_evbll(); /* Atlantis */ + break; + } + } + return clk - startclk; +} diff --git a/waterbox/o2em/cpu.h b/waterbox/o2em/cpu.h new file mode 100644 index 0000000000..1082d0f46e --- /dev/null +++ b/waterbox/o2em/cpu.h @@ -0,0 +1,63 @@ +#ifndef CPU_H +#define CPU_H + +#include "types.h" + +extern Byte acc; /* Accumulator */ +extern ADDRESS pc; /* Program counter */ + +extern Byte itimer; /* Internal timer */ +extern Byte reg_pnt; /* pointer to register bank */ +extern Byte timer_on; /* 0=timer off/1=timer on */ +extern Byte count_on; /* 0=count off/1=count on */ + +extern Byte t_flag; /* Timer flag */ + +extern Byte psw; /* Processor status word */ +extern Byte sp; /* Stack pointer (part of psw) */ + +extern Byte p1; /* I/O port 1 */ +extern Byte p2; /* I/O port 2 */ + +extern Byte xirq_pend; +extern Byte tirq_pend; + +void init_cpu(void); +int64_t cpu_exec(int64_t ncycles); +void ext_IRQ(void); +void tim_IRQ(void); +void make_psw_debug(void); + +Byte acc; /* Accumulator */ +ADDRESS pc; /* Program counter */ + +Byte itimer; /* Internal timer */ +Byte reg_pnt; /* pointer to register bank */ +Byte timer_on; /* 0=timer off/1=timer on */ +Byte count_on; /* 0=count off/1=count on */ +Byte psw; /* Processor status word */ +Byte sp; /* Stack pointer (part of psw) */ + +Byte p1; /* I/O port 1 */ +Byte p2; /* I/O port 2 */ +Byte xirq_pend; /* external IRQ pending */ +Byte tirq_pend; /* timer IRQ pending */ +Byte t_flag; /* Timer flag */ + +ADDRESS lastpc; +ADDRESS A11; /* PC bit 11 */ +ADDRESS A11ff; +Byte bs; /* Register Bank (part of psw) */ +Byte f0; /* Flag Bit (part of psw) */ +Byte f1; /* Flag Bit 1 */ +Byte ac; /* Aux Carry (part of psw) */ +Byte cy; /* Carry flag (part of psw) */ +Byte xirq_en; /* external IRQ's enabled */ +Byte tirq_en; /* Timer IRQ enabled */ +Byte irq_ex; /* IRQ executing */ + +int master_count; + + +#endif /* CPU_H */ + diff --git a/waterbox/o2em/crc32.c b/waterbox/o2em/crc32.c new file mode 100644 index 0000000000..fc58b7d466 --- /dev/null +++ b/waterbox/o2em/crc32.c @@ -0,0 +1,97 @@ + +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * CRC32 functions used to identify files + */ + +// Some stuff ported from here: +// http://www.opensource.apple.com/source/xnu/xnu-1504.7.4/bsd/libkern/crc32.c + +#include "crc32.h" + +static const uint32_t crc32tab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +uint32_t crc32_buf(const void *buf, size_t size) +{ + uint32_t crc = ~0; + const uint8_t *p = buf; + + while (size--) + crc = (crc >> 8) ^ crc32tab[(crc ^ (*p++)) & 0xFF]; + return ~crc; +} diff --git a/waterbox/o2em/crc32.h b/waterbox/o2em/crc32.h new file mode 100644 index 0000000000..f011a2fea4 --- /dev/null +++ b/waterbox/o2em/crc32.h @@ -0,0 +1,4 @@ +#pragma once +#include +#include "types.h" +uint32_t crc32_buf(const void *buf, size_t len); diff --git a/waterbox/o2em/cset.c b/waterbox/o2em/cset.c new file mode 100644 index 0000000000..353e2fccb6 --- /dev/null +++ b/waterbox/o2em/cset.c @@ -0,0 +1,83 @@ +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * O2 character table + */ + +#include "types.h" +#include "cset.h" + +const Byte cset[512] = { + 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x3C, 0x66, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, + 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00, + 0xCC, 0xCC, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x00, + 0xFE, 0xC0, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00, + 0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00, + 0xFE, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00, + 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, + 0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x18, 0x7E, 0x58, 0x7E, 0x1A, 0x7E, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, + 0xFC, 0xC6, 0xC6, 0xFC, 0xC0, 0xC0, 0xC0, 0x00, + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, + 0xFE, 0xC0, 0xC0, 0xF8, 0xC0, 0xC0, 0xFE, 0x00, + 0xFC, 0xC6, 0xC6, 0xFC, 0xD8, 0xCC, 0xC6, 0x00, + 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x7C, 0xC6, 0xC6, 0xC6, 0xDE, 0xCC, 0x76, 0x00, + 0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00, + 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFC, 0x00, + 0xFE, 0xC0, 0xC0, 0xF8, 0xC0, 0xC0, 0xC0, 0x00, + 0x7C, 0xC6, 0xC0, 0xC0, 0xCE, 0xC6, 0x7E, 0x00, + 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, + 0x06, 0x06, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, + 0xC6, 0xCC, 0xD8, 0xF0, 0xD8, 0xCC, 0xC6, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, + 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, + 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, + 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, + 0xFC, 0xC6, 0xC6, 0xFC, 0xC6, 0xC6, 0xFC, 0x00, + 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, + 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, + 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0x00, + 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0xCE, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xCE, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x3C, 0x00, + 0x1C, 0x1C, 0x18, 0x1E, 0x18, 0x18, 0x1C, 0x00, + 0x1C, 0x1C, 0x18, 0x1E, 0x18, 0x34, 0x26, 0x00, + 0x38, 0x38, 0x18, 0x78, 0x18, 0x2C, 0x64, 0x00, + 0x38, 0x38, 0x18, 0x78, 0x18, 0x18, 0x38, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x18, 0x18, 0x00, + 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x00, + 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0x00, + 0x38, 0x38, 0x12, 0xFE, 0xB8, 0x28, 0x6C, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x00, + 0x00, 0x00, 0x0C, 0x08, 0x08, 0xFF, 0x7E, 0x00, + 0x00, 0x03, 0x63, 0xFF, 0xFF, 0x18, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x38, 0xFF, 0x7E, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x6E, 0xFF, 0x7E, 0x00}; diff --git a/waterbox/o2em/cset.h b/waterbox/o2em/cset.h new file mode 100644 index 0000000000..1528ba8c32 --- /dev/null +++ b/waterbox/o2em/cset.h @@ -0,0 +1,6 @@ +#ifndef __CSET_H +#define __CSET_H + +extern const Byte cset[512]; + +#endif diff --git a/waterbox/o2em/keyboard.c b/waterbox/o2em/keyboard.c new file mode 100644 index 0000000000..2fa54e067d --- /dev/null +++ b/waterbox/o2em/keyboard.c @@ -0,0 +1,41 @@ +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * Keyboard emulation + */ + +#include +#include +#include +#include "types.h" +#include "cpu.h" +#include "config.h" +#include "vmachine.h" +#include "vdc.h" +#include "audio.h" +#include "voice.h" +#include "vpp.h" +#include "keyboard.h" +#include "score.h" + +void do_reset(void) +{ + init_cpu(); + init_roms(); + init_vpp(); + clearscr(); +} + +void do_highscore(void) +{ + set_score(app_data.scoretype, app_data.scoreaddress, app_data.default_highscore); +} diff --git a/waterbox/o2em/keyboard.h b/waterbox/o2em/keyboard.h new file mode 100644 index 0000000000..b5cc55bb03 --- /dev/null +++ b/waterbox/o2em/keyboard.h @@ -0,0 +1,7 @@ +#ifndef __KEYBOARD_H +#define __KEYBOARD_H + +void handle_key(void); + +#endif + diff --git a/waterbox/o2em/main.c b/waterbox/o2em/main.c new file mode 100644 index 0000000000..24ebc07497 --- /dev/null +++ b/waterbox/o2em/main.c @@ -0,0 +1,312 @@ +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + */ + +#include +#include +#include +#include +#include "crc32.h" +#include "audio.h" +#include "vmachine.h" +#include "config.h" +#include "vdc.h" +#include "cpu.h" +#include "keyboard.h" +#include "voice.h" +#include "score.h" + +#include "../emulibc/emulibc.h" +#include "../emulibc/waterboxcore.h" + +char name_f, rom_f, c_j; +char pathx, *k, identify; +static int load_bios(const char *data, int size); +static int load_cart(const char *data, int size); +int parse_option(char *attr, char *val); + +ECL_EXPORT int Init(const char *rom, int romlen, const char *bios, int bioslen) +{ + int i, cnt, cnt2; + + app_data.bank = 0; + app_data.voice = 1; + app_data.exrom = 0; + app_data.three_k = 0; + app_data.crc = 0; + app_data.euro = 0; + app_data.openb = 0; + app_data.vpp = 0; + app_data.bios = 0; + app_data.scoretype = 0; + app_data.scoreaddress = 0; + app_data.default_highscore = 0; + app_data.megaxrom = 0; + + init_audio(); + + if (!load_bios(bios, bioslen)) + return 0; + + if (!load_cart(rom, romlen)) + return 0; + + //if (app_data.voice) + //load_voice_samples(NULL); + init_display(); + init_cpu(); + init_system(); + //set_score(app_data.scoretype, app_data.scoreaddress, app_data.default_highscore); + + //run(); + //if (app_data.scoretype != 0) + //save_highscore(get_score(app_data.scoretype, app_data.scoreaddress), + //scorefile); + + return 1; +} + +ECL_EXPORT void FrameAdvance(FrameInfo* f) +{ + cpu_exec(20000); + f->Samples = 735; + f->Width = 320; + f->Height = 240; + blit(f->VideoBuffer); +} +ECL_EXPORT void GetMemoryAreas(MemoryArea* m) +{ + m[0].Data = intRAM; + m[0].Name = "RAM"; + m[0].Size = 64; + m[0].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY | MEMORYAREA_FLAGS_WORDSIZE1; +} + +ECL_EXPORT void SetInputCallback(void (*callback)(void)) +{ + // TODO +} + +int parse_option(char *attr, char *val) +{ + int control_scheme; + if (!strcmp(attr, "nolimit")) + { + } + else if (!strcmp(attr, "novoice")) + { + app_data.voice = !(val[0] != '0'); + } + else if ((!strcmp(attr, "s1")) || (!strcmp(attr, "s2"))) + { + } + else if (!strcmp(attr, "fullscreen")) + { + } + else if (!strcmp(attr, "euro")) + { + app_data.euro = (val[0] != '0'); + } + else if (!strcmp(attr, "exrom")) + { + app_data.exrom = (val[0] != '0'); + } + else if (!strcmp(attr, "3k")) + { + app_data.three_k = (val[0] != '0'); + } + else if (!strcmp(attr, "g7400")) + { + } + else if (!strcmp(attr, "scoreadr")) + { + control_scheme = -1; + sscanf(val, "%d", &control_scheme); + if ((control_scheme >= 0) && (control_scheme <= 255)) + app_data.scoreaddress = control_scheme; + else + { + fprintf(stderr, "Invalid value for option %s\n", attr); + return 0; + } + } + else if (!strcmp(attr, "scoretype")) + { + control_scheme = -1; + sscanf(val, "%d", &control_scheme); + if ((control_scheme >= 0) && (control_scheme <= 9999)) + app_data.scoretype = control_scheme; + else + { + fprintf(stderr, "Invalid value for option %s\n", attr); + return 0; + } + } + else if (!strcmp(attr, "score")) + { + control_scheme = -1; + sscanf(val, "%d", &control_scheme); + if ((control_scheme >= 0) && (control_scheme <= 999999)) + app_data.default_highscore = control_scheme; + else + { + fprintf(stderr, "Invalid value for option %s\n", attr); + return 0; + } + } + return 1; +} + +static int load_bios(const char *data, int size) +{ + if (size != 1024) + return 0; + + for (int i = 0; i < 8; i++) + { + memcpy(rom_table[i], data, 1024); + } + uint32_t crc = crc32_buf(rom_table[0], 1024); + if (crc == 0x8016A315) + { + printf("Odyssey2 bios ROM loaded\n"); + app_data.vpp = 0; + app_data.bios = ROM_O2; + } + else if (crc == 0xE20A9F41) + { + printf("Videopac+ G7400 bios ROM loaded\n"); + app_data.vpp = 1; + app_data.bios = ROM_G7400; + } + else if (crc == 0xA318E8D6) + { + printf("C52 bios ROM loaded\n"); + app_data.vpp = 0; + app_data.bios = ROM_C52; + } + else if (crc == 0x11647CA5) + { + printf("Jopac bios ROM loaded\n"); + app_data.vpp = 1; + app_data.bios = ROM_JOPAC; + } + else + { + printf("Bios ROM loaded (unknown version)\n"); + app_data.vpp = 0; + app_data.bios = ROM_UNKNOWN; + return 0; + } + return 1; +} + +static int load_cart(const char *data, int size) +{ + app_data.crc = crc32_buf(data, size); + if (app_data.crc == 0xAFB23F89) + app_data.exrom = 1; /* Musician */ + if (app_data.crc == 0x3BFEF56B) + app_data.exrom = 1; /* Four in 1 Row! */ + if (app_data.crc == 0x9B5E9356) + app_data.exrom = 1; /* Four in 1 Row! (french) */ + + if (app_data.crc == 0x975AB8DA || app_data.crc == 0xE246A812) + { + fprintf(stderr, "Error: file is an incomplete ROM dump\n"); + return 0; + } + + if (size & 1023) + { + fprintf(stderr, "Error: file is an invalid ROM dump\n"); + return 0; + } + + const int l = size; + int nb, i; + + /* special MegaCART design by Soeren Gust */ + if ((l == 32768) || (l == 65536) || (l == 131072) || (l == 262144) || (l == 524288) || (l == 1048576)) + { + app_data.megaxrom = 1; + app_data.bank = 1; + megarom = malloc(1048576); + memcpy(megarom, data, size); + + /* mirror shorter files into full megabyte */ + if (l < 65536) + memcpy(megarom + 32768, megarom, 32768); + if (l < 131072) + memcpy(megarom + 65536, megarom, 65536); + if (l < 262144) + memcpy(megarom + 131072, megarom, 131072); + if (l < 524288) + memcpy(megarom + 262144, megarom, 262144); + if (l < 1048576) + memcpy(megarom + 524288, megarom, 524288); + /* start in bank 0xff */ + memcpy(&rom_table[0][1024], megarom + 4096 * 255 + 1024, 3072); + printf("MegaCart %ldK", l / 1024); + nb = 1; + } + else if (((l % 3072) == 0)) + { + app_data.three_k = 1; + nb = l / 3072; + + for (int offset = 0, i = nb - 1; i >= 0; i--, offset += 3072) + { + memcpy(&rom_table[i][1024], data + offset, 3072); + } + printf("%dK", nb * 3); + } + else + { + nb = l / 2048; + if ((nb == 2) && (app_data.exrom)) + { + memcpy(&extROM[0], data, 1024); + memcpy(&rom_table[0][1024], data + 1024, 3072); + printf("3K EXROM"); + } + else + { + for (int offset = 0, i = nb - 1; i >= 0; i--, offset += 2048) + { + memcpy(&rom_table[i][1024], data + offset, 2048); + memcpy(&rom_table[i][3072], &rom_table[i][2048], 1024); /* simulate missing A10 */ + } + printf("%dK", nb * 2); + } + } + + rom = rom_table[0]; + if (nb == 1) + app_data.bank = 1; + else if (nb == 2) + app_data.bank = app_data.exrom ? 1 : 2; + else if (nb == 4) + app_data.bank = 3; + else + app_data.bank = 4; + + if ((rom_table[nb - 1][1024 + 12] == 'O') && (rom_table[nb - 1][1024 + 13] == 'P') && (rom_table[nb - 1][1024 + 14] == 'N') && (rom_table[nb - 1][1024 + 15] == 'B')) + app_data.openb = 1; + + printf(" CRC: %08lX\n", app_data.crc); + return 1; +} + +int main(void) +{ + return 0; +} diff --git a/waterbox/o2em/score.c b/waterbox/o2em/score.c new file mode 100644 index 0000000000..883b812375 --- /dev/null +++ b/waterbox/o2em/score.c @@ -0,0 +1,143 @@ + +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * + * http://o2em.sourceforge.net + * + * + * + * Score loading/saving by manopac + */ + +#include +#include +#include +#include +#include +#include +#include "vmachine.h" +#include "types.h" +#include "score.h" + +/*-------------------------------------------------- + Calculate Score from given Values + Scoretype = abcd: + ramtype a = 1: ext ram / 2: int ram + valuetype b = 1: 1 Byte each Digit / 2: 1/2 Byte each Digit + direct�on c = 1: higher value digits first / 2: low value digits first + count d = number of digits + --------------------------------------------------*/ +int get_score(int scoretype, int scoreaddress) +{ + int score=0; + + if (scoretype!=0) + { + int position; + int i; + Byte *RAM; + + int count = scoretype%10; + int direction = ((scoretype/10)%10)==1?1:-1; + float valuetype = (float) (3-((scoretype/100)%10))/2; + int ramtype = scoretype/1000; + + position = scoreaddress+ (direction==1?0:(count*valuetype-1)); + RAM = ramtype==1?extRAM:intRAM; + + for(i=0;i>(((i+1)%2)*4)*(abs((int) ((valuetype-1)*2))))&15); + } + } + + return(score); +} + +/*-------------------------------------------------- + Set HighScore into Memory + Scoretype = abcd: + ramtype a = 1: ext ram / 2: int ram + valuetype b = 1: 1 Byte each Digit / 2: 1/2 Byte each Digit + direct�on c = 1: higher value digits first / 2: low value digits first + count d = number of digits + --------------------------------------------------*/ + +void set_score(int scoretype, int scoreaddress, int score) +{ + + if (scoretype!=0 && score>0) + { + int position; + int i; + Byte *RAM; + int digit; + + int count = scoretype%10; + int direction = ((scoretype/10)%10)==1?-1:1; + float valuetype = (float) (3-((scoretype/100)%10))/2; + int ramtype = scoretype/1000; + + position = scoreaddress+ (direction==1?0:(count*valuetype-1)); + RAM = ramtype==1?extRAM:intRAM; + + for(i=count-1;i>=0;i--) + { + digit = score / power(10,i); + RAM[position+(int)(valuetype*i*direction)]=((valuetype==0.5)&&(i%2==0))?(RAM[position+(int)(valuetype*i*direction)]<<4)+digit:digit; + score = score - digit*power(10,i); + } + } +} + + + +/*----------------------------------------------------- + Save Highscore to File +-------------------------------------------------------*/ +void save_highscore(int highscore,char *scorefile) +{ + FILE *fn; + + highscore = highscore==app_data.default_highscore?0:highscore; + + fn = fopen(scorefile,"w"); + if (fn==NULL) { + fprintf(stderr,"Error opening highscore-file %s: %i\n",scorefile,errno); + exit(EXIT_FAILURE); + } + + if (fprintf(fn,"%i",highscore)<=0) + { + fprintf(stderr,"Error writing to highscore-file %s: %i\n",scorefile,errno); + exit(EXIT_FAILURE); + } + + fclose(fn); +} + + +/*********************************** + Integer-Implementation of pow + ***********************************/ +int power(int base, int higher) +{ + if (higher==0) { + return(1); + } else if (higher==1) { + return(base); + } else { + int i; + int value=base; + + for (i=2;i<=higher;i++) + { + value = value*base; + } + return(value); + } +} diff --git a/waterbox/o2em/score.h b/waterbox/o2em/score.h new file mode 100644 index 0000000000..0868801ea0 --- /dev/null +++ b/waterbox/o2em/score.h @@ -0,0 +1,10 @@ +#ifndef __SCORE_H +#define __SCORE_H + +int get_score(int scoretype, int scoreaddress); +void set_score(int scoretype, int scoreaddress, int highscore); +void save_highscore(int highscore,char *scorefile); +int power(int base, int higher); + +#endif + diff --git a/waterbox/o2em/types.h b/waterbox/o2em/types.h new file mode 100644 index 0000000000..1201c1bc0f --- /dev/null +++ b/waterbox/o2em/types.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +typedef uint8_t Byte; +typedef uint16_t ADDRESS; +#define MAXC 1024 diff --git a/waterbox/o2em/vdc.c b/waterbox/o2em/vdc.c new file mode 100644 index 0000000000..97a275db75 --- /dev/null +++ b/waterbox/o2em/vdc.c @@ -0,0 +1,556 @@ +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * O2 Video Display Controller emulation + */ + +#include +#include +#include +#include "types.h" +#include "vmachine.h" +#include "config.h" +#include "keyboard.h" +#include "cset.h" +#include "cpu.h" +#include "vpp.h" +#include "vdc.h" +#include "audio.h" +#include "voice.h" +#include "bitmap.h" + +#define COL_SP0 0x01 +#define COL_SP1 0x02 +#define COL_SP2 0x04 +#define COL_SP3 0x08 +#define COL_VGRID 0x10 +#define COL_HGRID 0x20 +#define COL_VPP 0x40 +#define COL_CHAR 0x80 + +#define X_START 8 +#define Y_START 24 + +static const uint32_t colortable[2][16] = { + /* O2 palette */ + {0x000000, 0x0e3dd4, 0x00981b, 0x00bbd9, 0xc70008, 0xcc16b3, 0x9d8710, + 0xe1dee1, 0x5f6e6b, 0x6aa1ff, 0x3df07a, 0x31ffff, 0xff4255, 0xff98ff, + 0xd9ad5d, 0xffffff}, + /* VP+ G7400 palette */ + {0x000000, 0x0000b6, 0x00b600, 0x00b6b6, 0xb60000, 0xb600b6, 0xb6b600, + 0xb6b6b6, 0x494949, 0x4949ff, 0x49ff49, 0x49ffff, 0xff4949, 0xff49ff, + 0xffff49, 0xffffff}}; + +static Bitmap* bitmap; + +/* Collision buffer */ +static Byte *col = NULL; + +/* The pointer to the graphics buffer */ +static Byte *vscreen = NULL; + +static int cached_lines[MAXLINES]; + +Byte coltab[256]; + +long clip_low; +long clip_high; + +int wsize; + +static void create_cmap(void); +static void draw_char(Byte ypos, Byte xpos, Byte chr, Byte col); +static void draw_quad(Byte ypos, Byte xpos, Byte cp0l, Byte cp0h, Byte cp1l, + Byte cp1h, Byte cp2l, Byte cp2h, Byte cp3l, Byte cp3h); +static void draw_grid(void); +void mputvid(unsigned int ad, unsigned int len, Byte d, Byte c); + +void draw_region(void) +{ + int i; + if (regionoff == 0xffff) + { + i = (master_clk / (LINECNT - 1) - 5); + } + else + { + i = (master_clk / 22 + regionoff); + } + i = (snapline(i, VDCwrite[0xA0], 0)); + if (app_data.crc == 0xA7344D1F) + { + i = (master_clk / 22 + regionoff) + 6; + i = (snapline(i, VDCwrite[0xA0], 0) + 6); + } /*Atlantis*/ + + if (app_data.crc == 0xD0BC4EE6) + { + i = (master_clk / 24 + regionoff) - 6; + i = (snapline(i, VDCwrite[0xA0], 0) + 7); + } /*Frogger*/ + + if (app_data.crc == 0x26517E77) + { + i = (master_clk / 22 + regionoff); + i = (snapline(i, VDCwrite[0xA0], 0) - 5); + } /*Comando Noturno*/ + + if (app_data.crc == 0xA57E1724) + { + i = (master_clk / (LINECNT - 1) - 5); + i = (snapline(i, VDCwrite[0xA0], 0) - 3); + } /*Catch the ball*/ + + if (i < 0) + i = 0; + clip_low = last_line * (long)BMPW; + clip_high = i * (long)BMPW; + if (clip_high > BMPW * BMPH) + clip_high = BMPW * BMPH; + if (clip_low < 0) + clip_low = 0; + if (clip_low < clip_high) + draw_display(); + last_line = i; +} + +static uint32_t colors[256]; + +static void create_cmap(void) +{ + int i; + + /* Initialise parts of the colors array */ + for (i = 0; i < 16; i++) + { + /* Use the color values from the color table */ + colors[i] = colortable[app_data.vpp ? 1 : 0][i]; + colors[i + 32] = colors[i]; + } + + for (i = 16; i < 32; i++) + colors[i] = 0; + for (i = 48; i < 256; i++) + colors[i] = 0; +} + +void clearscr(void) +{ + clear(bitmap); +} + +void mputvid(unsigned int ad, unsigned int len, Byte d, Byte c) +{ + if ((ad > (unsigned long)clip_low) && (ad < (unsigned long)clip_high)) + { + unsigned int i; + if (((len & 3) == 0) && (sizeof(unsigned long) == 4)) + { + unsigned long dddd = (((unsigned long)d) & 0xff) | ((((unsigned long)d) & 0xff) << 8) | ((((unsigned long)d) & 0xff) << 16) | ((((unsigned long)d) & 0xff) << 24); + unsigned long cccc = (((unsigned long)c) & 0xff) | ((((unsigned long)c) & 0xff) << 8) | ((((unsigned long)c) & 0xff) << 16) | ((((unsigned long)c) & 0xff) << 24); + for (i = 0; i> 2; i++) + { + *((unsigned long *)(vscreen + ad)) = dddd; + cccc |= *((unsigned long *)(col + ad)); + *((unsigned long *)(col + ad)) = cccc; + coltab[c] |= ((cccc | (cccc >> 8) | (cccc >> 16) | (cccc >> 24)) & 0xff); + ad += 4; + } + } + else + { + for (i = 0; i < len; i++) + { + vscreen[ad] = d; + col[ad] |= c; + coltab[c] |= col[ad++]; + } + } + } +} + +static void draw_grid(void) +{ + unsigned int pnt, pn1; + Byte mask, d; + int j, i, x, w; + Byte color; + + if (VDCwrite[0xA0] & 0x40) + { + for (j = 0; j < 9; j++) + { + pnt = (((j * 24) + 24) * BMPW); + for (i = 0; i < 9; i++) + { + pn1 = pnt + (i * 32) + 20; + color = ColorVector[j * 24 + 24]; + mputvid( + pn1, + 4, + (color & 0x07) | ((color & 0x40) >> 3) | (color & 0x80 ? 0 : 8), COL_HGRID); + color = ColorVector[j * 24 + 25]; + mputvid( + pn1 + BMPW, + 4, + (color & 0x07) | ((color & 0x40) >> 3) | (color & 0x80 ? 0 : 8), COL_HGRID); + color = ColorVector[j * 24 + 26]; + mputvid( + pn1 + BMPW * 2, + 4, + (color & 0x07) | ((color & 0x40) >> 3) | (color & 0x80 ? 0 : 8), COL_HGRID); + } + } + } + + mask = 0x01; + for (j = 0; j < 9; j++) + { + pnt = (((j * 24) + 24) * BMPW); + for (i = 0; i < 9; i++) + { + pn1 = pnt + (i * 32) + 20; + if ((pn1 + BMPW * 3 >= (unsigned long)clip_low) && (pn1 <= (unsigned long)clip_high)) + { + d = VDCwrite[0xC0 + i]; + if (j == 8) + { + d = VDCwrite[0xD0 + i]; + mask = 1; + } + if (d & mask) + { + color = ColorVector[j * 24 + 24]; + mputvid( + pn1, + 36, + (color & 0x07) | ((color & 0x40) >> 3) | (color & 0x80 ? 0 : 8), COL_HGRID); + color = ColorVector[j * 24 + 25]; + mputvid( + pn1 + BMPW, + 36, + (color & 0x07) | ((color & 0x40) >> 3) | (color & 0x80 ? 0 : 8), COL_HGRID); + color = ColorVector[j * 24 + 26]; + mputvid( + pn1 + BMPW * 2, + 36, + (color & 0x07) | ((color & 0x40) >> 3) | (color & 0x80 ? 0 : 8), COL_HGRID); + } + } + } + mask = mask << 1; + } + + mask = 0x01; + w = 4; + if (VDCwrite[0xA0] & 0x80) + { + w = 32; + } + for (j = 0; j < 10; j++) + { + pnt = (j * 32); + mask = 0x01; + d = VDCwrite[0xE0 + j]; + for (x = 0; x < 8; x++) + { + pn1 = pnt + (((x * 24) + 24) * BMPW) + 20; + if (d & mask) + { + for (i = 0; i < 24; i++) + { + if ((pn1 >= (unsigned long)clip_low) && (pn1 <= (unsigned long)clip_high)) + { + color = ColorVector[x * 24 + 24 + i]; + mputvid( + pn1, + w, + (color & 0x07) | ((color & 0x40) >> 3) | (color & 0x80 ? 0 : 8), COL_VGRID); + } + pn1 += BMPW; + } + } + mask = mask << 1; + } + } +} + +void finish_display(void) +{ + vpp_finish_bmp(vscreen, 9, 5, BMPW - 9, BMPH - 5, bitmap->w, bitmap->h); +} + +void blit(uint32_t* dst) +{ + uint8_t* src = vscreen; + src += 5 * BMPW; + src += 9; + for (int j = 0; j < 240; j++) + { + for (int i = 0; i < 320; i++) + { + *dst++ = colors[*src++]; + } + src += 20; + } +} + +void clear_collision(void) +{ + load_colplus(col); + coltab[0x01] = coltab[0x02] = 0; + coltab[0x04] = coltab[0x08] = 0; + coltab[0x10] = coltab[0x20] = 0; + coltab[0x40] = coltab[0x80] = 0; +} + +void draw_display(void) +{ + int i, j, x, sm, t; + Byte y, b, d1, cl, c; + + unsigned int pnt, pnt2; + + for (i = clip_low / BMPW; i < clip_high / BMPW; i++) + memset( + vscreen + i * BMPW, + ((ColorVector[i] & 0x38) >> 3) | (ColorVector[i] & 0x80 ? 0 : 8), BMPW); + + if (VDCwrite[0xA0] & 0x08) + draw_grid(); + + if (useforen && (!(VDCwrite[0xA0] & 0x20))) + return; + + for (i = 0x10; i < 0x40; i += 4) + draw_char(VDCwrite[i], VDCwrite[i + 1], VDCwrite[i + 2], + VDCwrite[i + 3]); + + /* draw quads, position mapping happens in ext_write (vmachine.c)*/ + for (i = 0x40; i < 0x80; i += 0x10) + draw_quad(VDCwrite[i], VDCwrite[i + 1], VDCwrite[i + 2], + VDCwrite[i + 3], VDCwrite[i + 6], VDCwrite[i + 7], + VDCwrite[i + 10], VDCwrite[i + 11], VDCwrite[i + 14], + VDCwrite[i + 15]); + + c = 8; + for (i = 12; i >= 0; i -= 4) + { + pnt2 = 0x80 + (i * 2); + y = VDCwrite[i]; + x = VDCwrite[i + 1] - 8; + t = VDCwrite[i + 2]; + cl = ((t & 0x38) >> 3); + cl = ((cl & 2) | ((cl & 1) << 2) | ((cl & 4) >> 2)) + 8; + /*174*/ + if ((x < 164) && (y > 0) && (y < 232)) + { + pnt = y * BMPW + (x * 2) + 20 + sproff; + if (t & 4) + { + if ((pnt + BMPW * 32 >= (unsigned long)clip_low) && (pnt <= (unsigned long)clip_high)) + { + for (j = 0; j < 8; j++) + { + sm = (((j % 2 == 0) && (((t >> 1) & 1) != (t & 1))) || ((j % 2 == 1) && (t & 1))) ? 1 : 0; + d1 = VDCwrite[pnt2++]; + for (b = 0; b < 8; b++) + { + if (d1 & 0x01) + { + if ((x + b + sm < 159) && (y + j < 247)) + { + mputvid(sm + pnt, 4, cl, c); + mputvid(sm + pnt + BMPW, 4, cl, c); + mputvid(sm + pnt + 2 * BMPW, 4, cl, c); + mputvid(sm + pnt + 3 * BMPW, 4, cl, c); + } + } + pnt += 4; + d1 = d1 >> 1; + } + pnt += BMPW * 4 - 32; + } + } + } + else + { + if ((pnt + BMPW * 16 >= (unsigned long)clip_low) && (pnt <= (unsigned long)clip_high)) + { + for (j = 0; j < 8; j++) + { + sm = (((j % 2 == 0) && (((t >> 1) & 1) != (t & 1))) || ((j % 2 == 1) && (t & 1))) ? 1 : 0; + d1 = VDCwrite[pnt2++]; + for (b = 0; b < 8; b++) + { + if (d1 & 0x01) + { + if ((x + b + sm < 160) && (y + j < 249)) + { + mputvid(sm + pnt, 2, cl, c); + mputvid(sm + pnt + BMPW, 2, cl, c); + } + } + pnt += 2; + d1 = d1 >> 1; + } + pnt += BMPW * 2 - 16; + } + } + } + } + c = c >> 1; + } +} + +void draw_char(Byte ypos, Byte xpos, Byte chr, Byte col) +{ + int j, c; + Byte cl, d1; + int y, b, n; + unsigned int pnt; + + y = (ypos & 0xFE); + pnt = y * BMPW + ((xpos - 8) * 2) + 20; + + ypos = ypos >> 1; + n = 8 - (ypos % 8) - (chr % 8); + if (n < 3) + n = n + 7; + + if ((pnt + BMPW * 2 * n >= (unsigned long)clip_low) && (pnt <= (unsigned long)clip_high)) + { + + c = (int)chr + ypos; + if (col & 0x01) + c += 256; + if (c > 511) + c = c - 512; + + cl = ((col & 0x0E) >> 1); + cl = ((cl & 2) | ((cl & 1) << 2) | ((cl & 4) >> 2)) + 8; + + if ((y > 0) && (y < 232) && (xpos < 157)) + { + for (j = 0; j < n; j++) + { + d1 = cset[c + j]; + for (b = 0; b < 8; b++) + { + if (d1 & 0x80) + { + if ((xpos - 8 + b < 160) && (y + j < 240)) + { + mputvid(pnt, 2, cl, COL_CHAR); + mputvid(pnt + BMPW, 2, cl, COL_CHAR); + } + } + pnt += 2; + d1 = d1 << 1; + } + pnt += BMPW * 2 - 16; + } + } + } +} + +/* This quad drawing routine can display the quad cut off effect used in KTAA. + * It needs more testing with other games, especially the clipping. + * This code is quite slow and needs a rewrite by somebody with more experience + * than I (sgust) have */ + +void draw_quad(Byte ypos, Byte xpos, Byte cp0l, Byte cp0h, Byte cp1l, Byte cp1h, + Byte cp2l, Byte cp2h, Byte cp3l, Byte cp3h) +{ + /* char set pointers */ + int chp[4]; + /* colors */ + Byte col[4]; + /* pointer into screen bitmap */ + unsigned int pnt; + /* offset into current line */ + unsigned int off; + /* loop variables */ + int i, j, lines; + + /* get screen bitmap position of quad */ + pnt = (ypos & 0xfe) * BMPW + ((xpos - 8) * 2) + 20; + /* abort drawing if completely below the bottom clip */ + if (pnt > (unsigned long)clip_high) + return; + /* extract and convert char-set offsets */ + chp[0] = cp0l | ((cp0h & 1) << 8); + chp[1] = cp1l | ((cp1h & 1) << 8); + chp[2] = cp2l | ((cp2h & 1) << 8); + chp[3] = cp3l | ((cp3h & 1) << 8); + for (i = 0; i < 4; i++) + chp[i] = (chp[i] + (ypos >> 1)) & 0x1ff; + lines = 8 - (chp[3] + 1) % 8; + /* abort drawing if completely over the top clip */ + if (pnt + BMPW * 2 * lines < (unsigned long)clip_low) + return; + /* extract and convert color information */ + col[0] = (cp0h & 0xe) >> 1; + col[1] = (cp1h & 0xe) >> 1; + col[2] = (cp2h & 0xe) >> 1; + col[3] = (cp3h & 0xe) >> 1; + for (i = 0; i < 4; i++) + col[i] = ((col[i] & 2) | ((col[i] & 1) << 2) | ((col[i] & 4) >> 2)) + 8; + /* now draw the quad line by line controlled by the last quad */ + while (lines-- > 0) + { + off = 0; + /* draw all 4 sub-quads */ + for (i = 0; i < 4; i++) + { + /* draw sub-quad pixel by pixel, but stay in same line */ + for (j = 0; j < 8; j++) + { + if ((cset[chp[i]] & (1 << (7 - j))) && (off < BMPW)) + { + mputvid(pnt + off, 2, col[i], COL_CHAR); + mputvid(pnt + off + BMPW, 2, col[i], COL_CHAR); + } + /* next pixel */ + off += 2; + } + /* space between sub-quads */ + off += 16; + } + /* advance char-set pointers */ + for (i = 0; i < 4; i++) + chp[i] = (chp[i] + 1) & 0x1ff; + /* advance screen bitmap pointer */ + pnt += BMPW * 2; + } +} + +void init_display(void) +{ + create_cmap(); + bitmap = NewBitmap(BMPW, BMPH); + if (!bitmap) + { + fprintf(stderr, "Could not allocate memory for screen buffer.\n"); + exit(EXIT_FAILURE); + } + vscreen = (Byte *)bitmap->dat; + clear(bitmap); + col = (Byte *)malloc(BMPW * BMPH); + if (!col) + { + fprintf(stderr, "Could not allocate memory for collision buffer.\n"); + free(vscreen); + exit(EXIT_FAILURE); + } + memset(col, 0, BMPW * BMPH); +} diff --git a/waterbox/o2em/vdc.h b/waterbox/o2em/vdc.h new file mode 100644 index 0000000000..5689b94953 --- /dev/null +++ b/waterbox/o2em/vdc.h @@ -0,0 +1,29 @@ +#ifndef __VDC_H +#define __VDC_H + +#define BMPW 340 +#define BMPH 250 +#define WNDW 320 +#define WNDH 240 + +#define BOX_W MIN(512, SCREEN_W-16) +#define BOX_H MIN(256, (SCREEN_H-64)&0xFFF0) + +#define BOX_L ((SCREEN_W - BOX_W) / 2) +#define BOX_R ((SCREEN_W + BOX_W) / 2) +#define BOX_T ((SCREEN_H - BOX_H) / 2) +#define BOX_B ((SCREEN_H + BOX_H) / 2) + +extern Byte coltab[]; +extern long clip_low; +extern long clip_high; + +void init_display(void); +void draw_display(void); +void draw_region(void); +void finish_display(); +void clear_collision(void); +void clearscr(void); + +void blit(uint32_t* dst); +#endif diff --git a/waterbox/o2em/vmachine.c b/waterbox/o2em/vmachine.c new file mode 100644 index 0000000000..1460e8550d --- /dev/null +++ b/waterbox/o2em/vmachine.c @@ -0,0 +1,746 @@ +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * Main O2 machine emulation + */ + +#include +#include +#include +#include "audio.h" +#include "types.h" +#include "cpu.h" +#include "keyboard.h" +#include "config.h" +#include "vdc.h" +#include "vpp.h" +#include "voice.h" +#include "vmachine.h" + +static Byte x_latch, y_latch; +static int romlatch = 0; +static Byte line_count; +static int fps = FPS_NTSC; + +static Byte snapedlines[MAXLINES + 2 * MAXSNAP][256][2]; + +int evblclk = EVBLCLK_NTSC; + +struct resource app_data; +int frame = 0; + +int int_clk; /* counter for length of /INT pulses */ +int master_clk; /* Master clock */ +int h_clk; /* horizontal clock */ +unsigned long clk_counter; +int last_line; +int key2vcnt = 0; +int mstate; + +int pendirq = 0; +int enahirq = 1; +int useforen = 0; +long regionoff = 0xffff; +int mxsnap = 2; +int sproff = 0; +int tweakedaudio = 0; + +Byte rom_table[8][4096]; + +Byte intRAM[64]; +Byte extRAM[256]; +Byte extROM[1024]; +Byte VDCwrite[256]; +Byte ColorVector[MAXLINES]; +Byte AudioVector[MAXLINES]; +Byte *rom; +Byte *megarom; + +int key2[128]; + +static void do_kluges(void); +static void setvideomode(int t); + +void handle_vbl(void) +{ + update_audio(); + update_voice(); + draw_region(); + ext_IRQ(); + mstate = 1; +} + +void handle_evbl(void) +{ + static long last = 0; + int i; + + last_line = 0; + master_clk -= evblclk; + frame++; + finish_display(); + + if (app_data.crc == 0xA7344D1F) + { + for (i = 0; i < 140; i++) + { + ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80); + AudioVector[i] = VDCwrite[0xAA]; + } + } /*Atlantis*/ + else + { + for (i = 0; i < MAXLINES; i++) + { + ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80); + AudioVector[i] = VDCwrite[0xAA]; + } + } + if (key2vcnt++ > 10) + { + key2vcnt = 0; + for (i = 0; i < 128; i++) + key2[i] = 0; + } + mstate = 0; +} + +void handle_evbll(void) +{ + static long last = 0; + int i; + + /******************* 150 */ + + for (i = 150; i < MAXLINES; i++) + { + ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (p1 & 0x80); + AudioVector[i] = VDCwrite[0xAA]; + } + + if (key2vcnt++ > 10) + { + key2vcnt = 0; + for (i = 0; i < 128; i++) + key2[i] = 0; + } + mstate = 0; +} + +void init_system(void) +{ + int i, j, k; + + last_line = 0; + mstate = 0; + master_clk = 0; + h_clk = 0; + line_count = 0; + itimer = 0; + clk_counter = 0; + init_roms(); + for (i = 0; i < 256; i++) + { + VDCwrite[i] = 0; + extRAM[i] = 0; + } + for (i = 0; i < 64; i++) + { + intRAM[i] = 0; + } + for (i = 0; i < MAXLINES; i++) + AudioVector[i] = ColorVector[i] = 0; + + for (i = 0; i < MAXLINES + 2 * MAXSNAP; i++) + for (j = 0; j < 256; j++) + for (k = 0; k < 2; k++) + snapedlines[i][j][k] = 0; + + for (i = 0; i < 128; i++) + key2[i] = 0; + key2vcnt = 0; + if (app_data.euro) + setvideomode(1); + else + setvideomode(0); + do_kluges(); + init_vpp(); + clear_collision(); +} + +void init_roms(void) +{ + rom = rom_table[0]; + romlatch = 0; +} + +Byte read_t1(void) +{ + /*17*/ + if ((h_clk > 16) || (master_clk > VBLCLK)) + return 1; + else + return 0; +} + +void write_p1(Byte d) +{ + if ((d & 0x80) != (p1 & 0x80)) + { + int i, l; + l = snapline((int)((float)master_clk / 22.0 + 0.1), VDCwrite[0xA3], + 1); + for (i = l; i < MAXLINES; i++) + ColorVector[i] = (VDCwrite[0xA3] & 0x7f) | (d & 0x80); + } + p1 = d; + if (app_data.bank == 2) + { + rom = rom_table[~p1 & 0x01]; + } + else if (app_data.bank == 3) + { + rom = rom_table[~p1 & 0x03]; + } + else if (app_data.bank == 4) + { + rom = rom_table[(p1 & 1) ? 0 : romlatch]; + } +} + +Byte read_P2(void) +{ + int i, si, so, km; + + return 0; + // TODO + /*if (NeedsPoll) + poll_keyboard(); + + if (!(p1 & 0x04)) + { + si = (p2 & 7); + so = 0xff; + if (si < 6) + { + for (i = 0; i < 8; i++) + { + km = key_map[si][i]; + if ((key[km] && ((!joykeystab[km]) || (key_shifts & KB_CAPSLOCK_FLAG))) || (key2[km])) + { + so = i ^ 0x07; + } + } + } + if (so != 0xff) + { + p2 = p2 & 0x0F; + p2 = p2 | (so << 5); + } + else + { + p2 = p2 | 0xF0; + } + } + else + { + p2 = p2 | 0xF0; + } + return (p2);*/ +} + +Byte ext_read(ADDRESS adr) +{ + Byte d; + Byte si; + Byte m; + int i; + + if (!(p1 & 0x08) && !(p1 & 0x40)) + { + /* Handle VDC Read */ + switch (adr) + { + case 0xA1: + d = VDCwrite[0xA0] & 0x02; + if (master_clk > VBLCLK) + d = d | 0x08; + if (h_clk < (LINECNT - 7)) + d = d | 0x01; + if (sound_IRQ) + d = d | 0x04; + sound_IRQ = 0; + return d; + case 0xA2: + si = VDCwrite[0xA2]; + m = 0x01; + d = 0; + for (i = 0; i < 8; i++) + { + if (si & m) + { + if (coltab[1] & m) + d = d | (coltab[1] & (m ^ 0xFF)); + if (coltab[2] & m) + d = d | (coltab[2] & (m ^ 0xFF)); + if (coltab[4] & m) + d = d | (coltab[4] & (m ^ 0xFF)); + if (coltab[8] & m) + d = d | (coltab[8] & (m ^ 0xFF)); + if (coltab[0x10] & m) + d = d | (coltab[0x10] & (m ^ 0xFF)); + if (coltab[0x20] & m) + d = d | (coltab[0x20] & (m ^ 0xFF)); + if (coltab[0x80] & m) + d = d | (coltab[0x80] & (m ^ 0xFF)); + } + m = m << 1; + } + clear_collision(); + return d; + case 0xA5: + if (!(VDCwrite[0xA0] & 0x02)) + { + return x_latch; + } + else + { + x_latch = h_clk * 12; + return x_latch; + } + case 0xA4: + if (!(VDCwrite[0xA0] & 0x02)) + { + return y_latch; + } + else + { + y_latch = master_clk / 22; + if (y_latch > 241) + y_latch = 0xFF; + return y_latch; + } + default: + return VDCwrite[adr]; + } + } + else if (!(p1 & 0x10)) + { + /* Handle ext RAM Read */ + if (app_data.megaxrom && (adr >= 0x80)) + { + /* MegaCART registers are mirrored every 4 bytes */ + if ((adr & 0x83) == 0x83) + { + /* TODO: emulate EEPROM data in */ + return 0xff; + } + else + return extRAM[adr & 0x83]; + } + else + return extRAM[adr & 0xFF]; + } + else if (!(p1 & 0x20)) + { + /* Read a Videopac+ register */ + return vpp_read(adr); + } + else if (app_data.exrom && (p1 & 0x02)) + { + /* Handle read from exrom */ + return extROM[(p2 << 8) | (adr & 0xFF)]; + } + else if (app_data.megaxrom && !(p1 & 0x02) && !(p1 & 0x40)) + { + /* Handle data read from MegaCART */ + return megarom[(extRAM[0x81] << 12) | ((p2 & 0x0f) << 8) | (adr & 0xff)]; + } + + return 0; +} + +Byte in_bus(void) +{ + Byte si = 0, d = 0, mode = 0, jn = 0, sticknum = 0; + + if ((p1 & 0x08) && (p1 & 0x10)) + { + /* Handle joystick read */ + if (!(p1 & 0x04)) + { + si = (p2 & 7); + } + d = 0xFF; + // si == 1 => joystick 0 + // si != 1 => joystick 1 + // &= 0xfe up + // &= 0xfd right + // &= 0xfb down + // &= 0xf7 left + // &= 0xef both (?) buttons + } + return d; +} + +void ext_write(Byte dat, ADDRESS adr) +{ + int i; + + if (!(p1 & 0x08)) + { + /* Handle VDC Write */ + if (adr == 0xA0) + { + if ((VDCwrite[0xA0] & 0x02) && !(dat & 0x02)) + { + y_latch = master_clk / 22; + x_latch = h_clk * 12; + if (y_latch > 241) + y_latch = 0xFF; + } + if ((master_clk <= VBLCLK) && (VDCwrite[0xA0] != dat)) + { + draw_region(); + } + } + else if (adr == 0xA3) + { + int l; + l = snapline((int)((float)master_clk / 22.0 + 0.5), dat, 1); + for (i = l; i < MAXLINES; i++) + ColorVector[i] = (dat & 0x7f) | (p1 & 0x80); + } + else if (adr == 0xAA) + { + for (i = master_clk / 22; i < MAXLINES; i++) + AudioVector[i] = dat; + } + else if ((adr >= 0x40) && (adr <= 0x7f) && ((adr & 2) == 0)) + { + /* simulate quad: all 4 sub quad position registers + * are mapped to the same internal register */ + adr = adr & 0x71; + /* Another minor thing: the y register always returns + * bit 0 as 0 */ + if ((adr & 1) == 0) + dat = dat & 0xfe; + VDCwrite[adr] = VDCwrite[adr + 4] = VDCwrite[adr + 8] = VDCwrite[adr + 12] = dat; + } + VDCwrite[adr] = dat; + } + else if (!(p1 & 0x10) && !(p1 & 0x40)) + { + adr = adr & 0xFF; + + if (adr < 0x80) + { + /* Handle ext RAM Write */ + extRAM[adr] = dat; + } + else + { + if (app_data.bank == 4) + { + romlatch = (~dat) & 7; + rom = rom_table[(p1 & 1) ? 0 : romlatch]; + } + + /* Handle The Voice */ + if (!(dat & 0x20)) + reset_voice(); + else + { + if (adr == 0xE4) + set_voice_bank(0); + else if ((adr >= 0xE8) && (adr <= 0xEF)) + set_voice_bank(adr - 0xE7); + else if (((adr >= 0x80) && (adr <= 0xDF)) || ((adr >= 0xF0) && (adr <= 0xFF))) + trigger_voice(adr); + } + } + } + else if (!(p1 & 0x20)) + { + /* Write to a Videopac+ register */ + vpp_write(dat, adr); + } +} + +static void do_kluges(void) +{ + if (app_data.crc == 0xA7344D1F) + pendirq = 1; /* Atlantis */ + if (app_data.crc == 0xFB83171E) + pendirq = 1; /* Blockout */ + if (app_data.crc == 0xD38153F6) + pendirq = 1; /* Blockout (french) */ + if (app_data.crc == 0x881CEAE4) + pendirq = 1; /* Wall Street */ + + if (app_data.crc == 0x9E42E766) + useforen = 1; /* Turtles */ + if (app_data.crc == 0x1C750349) + useforen = 1; /* Turtles (European version) */ + if (app_data.crc == 0x202F2749) + useforen = 1; /* Q*bert */ + if (app_data.crc == 0x06861A9C) + useforen = 1; /* Flashpoint 5 (Videopac adaption) */ + + if (app_data.crc == 0xFB83171E) + enahirq = 0; /* Blockout*/ + if (app_data.crc == 0xD38153F6) + enahirq = 0; /* Blockout (french) */ + + if (app_data.crc == 0xFB83171E) + regionoff = 1; /* Blockout*/ + if (app_data.crc == 0xD38153F6) + regionoff = 1; /* Blockout (french) */ + if (app_data.crc == 0x202F2749) + regionoff = 0; /* Q*bert */ + if (app_data.crc == 0x5216771A) + regionoff = 1; /* Popeye */ + if (app_data.crc == 0x0C2E4811) + regionoff = 11; /* Out of this World! / Helicopter Rescue! */ + if (app_data.crc == 0x67069924) + regionoff = 11; /* Smithereens! */ + if (app_data.crc == 0x44D1A8A5) + regionoff = 11; /* Smithereens! (European version) */ + if (app_data.crc == 0x2391C2FB) + regionoff = 11; /* Smithereens! + */ + if (app_data.crc == 0xBB4AD548) + regionoff = 11; /* Smithereens! modified 1 */ + if (app_data.crc == 0x25057C11) + regionoff = 11; /* Smithereens! modified 2 */ + if (app_data.crc == 0xB936BD78) + regionoff = 12; /* Type & Tell */ + if (app_data.crc == 0xAD8B9AE0) + regionoff = 2; /* Type & Tell modified 1 */ + if (app_data.crc == 0x5C02BEE6) + regionoff = 2; /* Type & Tell modified 2 */ + if (app_data.crc == 0xDC30AD3D) + regionoff = 10; /* Dynasty! */ + if (app_data.crc == 0x7810BAD5) + regionoff = 8; /* Dynasty! (European) */ + if (app_data.crc == 0xA7344D1F) + regionoff = 0; /* Atlantis */ + if (app_data.crc == 0xD0BC4EE6) + regionoff = 12; /* Frogger */ + if (app_data.crc == 0xA57D84F3) + regionoff = 8; /* Frogger BR */ + if (app_data.crc == 0x825976A9) + regionoff = 0; /* Mousing Cat 8kb */ + if (app_data.crc == 0xF390BFEC) + regionoff = 0; /* Mousing Cat 4kb */ + if (app_data.crc == 0x61A350E6) + regionoff = 0; /* Mousing Cat (french) */ + if (app_data.crc == 0x3BFEF56B) + regionoff = 1; /* Four in 1 Row! */ + if (app_data.crc == 0x7C747245) + regionoff = 1; /* Four in 1 Row! modified */ + if (app_data.crc == 0x9B5E9356) + regionoff = 1; /* Four in 1 Row! (french) */ + + if (app_data.crc == 0x6CEBAB74) + regionoff = 12; /* P.T. Barnum's Acrobats! (European version) */ + if (app_data.crc == 0xE7B26A56) + regionoff = 12; /* P.T. Barnum's Acrobats! (European version - Extra keys) */ + + if (app_data.crc == 0xFB83171E) + mxsnap = 3; /* Blockout*/ + if (app_data.crc == 0xD38153F6) + mxsnap = 3; /* Blockout (french) */ + if (app_data.crc == 0xA57E1724) + mxsnap = 12; /* Catch the Ball / Noughts and Crosses */ + if (app_data.crc == 0xBE4FF48E) + mxsnap = 12; /* Catch the Ball / Noughts and Crosses modified */ + if (app_data.crc == 0xFD179F6D) + mxsnap = 3; /* Clay Pigeon! */ + if (app_data.crc == 0x9C9DDDF9) + mxsnap = 3; /* Verkehr */ + if (app_data.crc == 0x95936B07) + mxsnap = 3; /* Super Cobra */ + if (app_data.crc == 0x881CEAE4) + mxsnap = 3; /* Wall Street */ + if (app_data.crc == 0x9E42E766) + mxsnap = 0; /* Turtles */ + if (app_data.crc == 0x1C750349) + mxsnap = 0; /* Turtles (European version) */ + if (app_data.crc == 0xD0BC4EE6) + mxsnap = 3; /* Frogger */ + if (app_data.crc == 0xA57D84F3) + mxsnap = 3; /* Frogger BR */ + if (app_data.crc == 0x3BFEF56B) + mxsnap = 6; /* Four in 1 Row! */ + if (app_data.crc == 0x9B5E9356) + mxsnap = 6; /* Four in 1 Row! (french) */ + if (app_data.crc == 0x7C747245) + mxsnap = 6; /* Four in 1 Row! modified */ + + if (app_data.crc == 0xA7344D1F) + setvideomode(1); /* Atlantis */ + if (app_data.crc == 0x39E31BF0) + setvideomode(1); /* Jake */ + if (app_data.crc == 0x92D0177B) + setvideomode(1); /* Jake (hack) */ + if (app_data.crc == 0x3351FEDA) + setvideomode(1); /* Power Lords */ + if (app_data.crc == 0x40AE062D) + setvideomode(1); /* Power Lords (alternate) */ + if (app_data.crc == 0xD158EEBA) + setvideomode(1); /* Labirinth */ + if (app_data.crc == 0x26B0FF5B) + setvideomode(1); /* Nightmare */ + if (app_data.crc == 0xDF36683F) + setvideomode(1); /* Shark Hunter */ + if (app_data.crc == 0xAF307559) + setvideomode(1); /* Super Bee 8Kb */ + if (app_data.crc == 0x9585D511) + setvideomode(1); /* Super Bee 4Kb */ + if (app_data.crc == 0x58FA6766) + setvideomode(1); /* War of the Nerves */ + if (app_data.crc == 0x58FA6766) + setvideomode(1); /* War of the Nerves */ + if (app_data.crc == 0x39989464) + setvideomode(1); /* Hockey! / Soccer! */ + if (app_data.crc == 0x3BFEF56B) + setvideomode(1); /* Four in 1 Row! */ + if (app_data.crc == 0x9B5E9356) + setvideomode(1); /* Four in 1 Row! (french) */ + if (app_data.crc == 0x7C747245) + setvideomode(1); /* Four in 1 Row! modified */ + if (app_data.crc == 0x68560DC7) + setvideomode(1); /* Jopac Moto Crash */ + if (app_data.crc == 0x020FCA15) + setvideomode(1); /* Jopac Moto Crash modified (non VP+) */ + if (app_data.crc == 0xC4134DF8) + setvideomode(1); /* Helicopter Rescue + */ + if (app_data.crc == 0x0D2D721D) + setvideomode(1); /* Trans American Rally + */ + if (app_data.crc == 0x9D72D4E9) + setvideomode(1); /* Blobbers */ + if (app_data.crc == 0xB2F0F0B4) + setvideomode(1); /* Le Tresor Englouti + */ + if (app_data.crc == 0x0B2DEB61) + setvideomode(1); /* Tutankham */ + if (app_data.crc == 0x313547EB) + setvideomode(1); /* VP53 */ + if (app_data.crc == 0x06861A9C) + setvideomode(1); /* Flashpoint 5 (Videopac adaption) */ + if (app_data.crc == 0xA57E1724) + setvideomode(0); /* Catch the Ball / Noughts and Crosses */ + if (app_data.crc == 0xBE4FF48E) + setvideomode(0); /* Catch the Ball / Noughts and Crosses modified */ + if (app_data.crc == 0xFB83171E) + setvideomode(0); /* Blockout*/ + if (app_data.crc == 0xD38153F6) + setvideomode(0); /* Blockout (french) */ + if (app_data.crc == 0x9BFC3E01) + setvideomode(0); /* Demon Attack */ + if (app_data.crc == 0x50AF9D45) + setvideomode(0); /* Demon Attack + */ + if (app_data.crc == 0x9884EF36) + setvideomode(0); /* Demon Attack + modified */ + if (app_data.crc == 0x4A578DFE) + setvideomode(0); /* Restaurant ntsc */ + if (app_data.crc == 0x863D5E2D) + setvideomode(0); /* Shark Hunter ntsc */ + + if (app_data.crc == 0xD62814A3) + evblclk = 12000; /* Pick Axe Pete */ + if (app_data.crc == 0xB2FFB353) + evblclk = 12000; /* Pick Axe Pete + */ + if (app_data.crc == 0x81C20196) + evblclk = 12000; /* Pick Axe Pete + (modified) */ + + if ((app_data.crc == 0xF390BFEC) || (app_data.crc == 0x825976A9) || (app_data.crc == 0x61A350E6)) + { /* Mousing Cat */ + setvideomode(1); + evblclk = 7642; + } + + if (app_data.crc == 0xD0BC4EE6) + { /* Frogger */ + setvideomode(1); + evblclk = 7642; + } + if (app_data.crc == 0x26517E77) + { /* Commando Noturno */ + setvideomode(1); + evblclk = 6100; + regionoff = 12; + } + if (app_data.crc == 0xA57E1724) + { /* Catch the ball*/ + regionoff = 5; + sproff = 1; + } + + if ((app_data.crc == 0x2DCB77F0) || (app_data.crc == 0xF6882734)) + { /* Depth Charge / Marksman */ + setvideomode(1); + evblclk = 8000; + } + if (app_data.crc == 0x881CEAE4) + { /* Wall Street */ + setvideomode(1); + evblclk = 6100; + } + if (app_data.crc == 0xD0BC4EE6) + tweakedaudio = 1; /* Frogger */ + if (app_data.crc == 0xA57D84F3) + tweakedaudio = 1; /* Frogger BR */ + if (app_data.crc == 0x5216771A) + tweakedaudio = 1; /* Popeye */ + if (app_data.crc == 0xAFB23F89) + tweakedaudio = 1; /* Musician */ + if (app_data.crc == 0xC4134DF8) + tweakedaudio = 1; /* Helicopter Rescue + */ + if (app_data.crc == 0x0D2D721D) + tweakedaudio = 1; /* Trans American Rally + */ + + if (app_data.crc == 0xD3B09FEC) + sproff = 1; /* Volleyball! */ + if (app_data.crc == 0x551E38A2) + sproff = 1; /* Volleyball! (french) */ +} + +int snapline(int pos, Byte reg, int t) +{ + int i; + if (pos < MAXLINES + MAXSNAP + MAXSNAP) + { + for (i = 0; i < mxsnap; i++) + { + if (snapedlines[pos + MAXSNAP - i][reg][t]) + return pos - i; + if (snapedlines[pos + MAXSNAP + i][reg][t]) + return pos + i; + } + snapedlines[pos + MAXSNAP][reg][t] = 1; + } + return pos; +} + +static void setvideomode(int t) +{ + if (t) + { + evblclk = EVBLCLK_PAL; + fps = FPS_PAL; + } + else + { + evblclk = EVBLCLK_NTSC; + fps = FPS_NTSC; + } +} diff --git a/waterbox/o2em/vmachine.h b/waterbox/o2em/vmachine.h new file mode 100644 index 0000000000..57ba491fe0 --- /dev/null +++ b/waterbox/o2em/vmachine.h @@ -0,0 +1,82 @@ +#ifndef VMACHINE_H +#define VMACHINE_H + +#include "types.h" + +#define LINECNT 21 +#define MAXLINES 500 +#define MAXSNAP 50 + +#define VBLCLK 5493 +#define EVBLCLK_NTSC 5964 +#define EVBLCLK_PAL 7259 + +#define FPS_NTSC 60 +#define FPS_PAL 50 + +extern int last_line; + +extern int evblclk; + +extern int master_clk; /* Master clock */ +extern int int_clk; /* counter for length of /INT pulses for JNI */ +extern int h_clk; /* horizontal clock */ +extern Byte coltab[256]; +extern int mstate; + +extern Byte rom_table[8][4096]; +extern Byte intRAM[]; +extern Byte extRAM[]; +extern Byte extROM[]; +extern Byte VDCwrite[256]; +extern Byte ColorVector[MAXLINES]; +extern Byte AudioVector[MAXLINES]; +extern Byte *rom; +extern Byte *megarom; + +extern int frame; +extern int key2[128]; +extern int key2vcnt; +extern unsigned long clk_counter; + +extern int enahirq; +extern int pendirq; +extern int useforen; +extern long regionoff; +extern int sproff; +extern int tweakedaudio; + +Byte read_P2(void); +int snapline(int pos, Byte reg, int t); +void ext_write(Byte dat, ADDRESS adr); +Byte ext_read(ADDRESS adr); +void handle_vbl(void); +void handle_evbl(void); +void handle_evbll(void); +Byte in_bus(void); +void write_p1(Byte d); +Byte read_t1(void); +void init_system(void); +void init_roms(void); +void run(void); + +extern struct resource { + int bank; + int speed; + int voice; + int exrom; + int three_k; + int euro; + int openb; + int megaxrom; + int vpp; + int bios; + uint32_t crc; + int scoretype; + int scoreaddress; + int default_highscore; +} app_data; + + +#endif /* VMACHINE_H */ + diff --git a/waterbox/o2em/voice.c b/waterbox/o2em/voice.c new file mode 100644 index 0000000000..b1eba1b24b --- /dev/null +++ b/waterbox/o2em/voice.c @@ -0,0 +1,143 @@ +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * O2 Voice emulation + */ + +#include +#include "vmachine.h" +#include "cpu.h" +#include "voice.h" + +//static SAMPLE *voices[9][128]; +static int voice_bank = 0; +static int voice_num = -1; +static int voice_addr = 0; +static int voice_ok = 0; +static int voice_st = 0; +static unsigned long clk_voice_start = 0; + +void load_voice_samples(char *path) +{ + /*int bank, sam, i, ld = 0; + char name[MAXC]; + SAMPLE *sp = NULL; + + printf("Loading voice samples... "); + fflush(stdout); + + for (i = 0; i < 9; i++) { + for (sam = 0; sam < 128; sam++) { + if (i) + bank = 0xE8 + i - 1; + else + bank = 0xE4; + sprintf(name, "%svoice/%02x%02x.wav", path, bank, sam + 0x80); + + voices[i][sam] = load_sample(name); + + if (!voices[i][sam]) { + sprintf(name, "%svoice/%02X%02X.WAV", path, bank, sam + 0x80); + voices[i][sam] = load_sample(name); + } + + if (voices[i][sam]) { + ld++; + if (!sp) + sp = voices[i][sam]; + } + } + } + + printf("%d samples loaded\n", ld); + + if (ld > 0) { + voice_num = allocate_voice(sp); + if (voice_num != -1) + voice_ok = 1; + else { + printf(" ERROR: could not allocate sound card voice\n"); + voice_ok = 0; + } + }*/ + +} + +void update_voice(void) +{ + /*if (!voice_ok) + return; + if (voice_st == 2) { + if (voice_get_position(voice_num) < 0) { + if ((voice_bank >= 0) && (voice_bank < 9) && (voice_addr >= 0x80) + && (voice_addr <= 0xff)) { + if (voices[voice_bank][voice_addr - 0x80]) { + reallocate_voice(voice_num, + voices[voice_bank][voice_addr - 0x80]); + voice_set_volume(voice_num, (255 * app_data.vvolume) / 100); + voice_start(voice_num); + clk_voice_start = clk_counter; + voice_st = 1; + } else { + voice_st = 0; + } + } + } + } else if (voice_st == 1) { + if ((voice_get_position(voice_num) < 0) + || (clk_counter - clk_voice_start > 20)) { + voice_st = 0; + } + }*/ +} + +void trigger_voice(int addr) +{ + /*if (voice_ok) { + if (voice_st) + update_voice(); + if ((voice_st == 0) && (voice_bank >= 0) && (voice_bank < 9) + && (addr >= 0x80) && (addr <= 0xff)) { + voice_addr = addr; + voice_st = 2; + update_voice(); + } + }*/ +} + +void set_voice_bank(int bank) +{ + /*if (!voice_ok) + return; + if ((bank >= 0) && (bank <= 8)) + voice_bank = bank;*/ +} + +int get_voice_status(void) +{ + /*if (voice_ok) { + update_voice(); + if (voice_st) + return 1; + }*/ + return 0; +} + +void reset_voice(void) +{ + /*if (voice_ok) { + voice_stop(voice_num); + voice_bank = 0; + voice_addr = 0; + voice_st = 0; + }*/ +} diff --git a/waterbox/o2em/voice.h b/waterbox/o2em/voice.h new file mode 100644 index 0000000000..1afbead738 --- /dev/null +++ b/waterbox/o2em/voice.h @@ -0,0 +1,12 @@ +#ifndef __VOICE_H +#define __VOICE_H + +void load_voice_samples(char *path); +void update_voice(void); +void trigger_voice(int addr); +void reset_voice(void); +void set_voice_bank(int bank); +int get_voice_status(void); + +#endif + diff --git a/waterbox/o2em/vpp.c b/waterbox/o2em/vpp.c new file mode 100644 index 0000000000..cd4bc829f1 --- /dev/null +++ b/waterbox/o2em/vpp.c @@ -0,0 +1,588 @@ +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * Videopac+ G7400 emulation + */ + +#include +#include +#include +#include "types.h" +#include "vmachine.h" +#include "vdc.h" +#include "vpp_cset.h" +#include "vpp.h" +#include "bitmap.h" + +static void vpp_draw_char(int x, int y, Byte ch, Byte c0, Byte c1, Byte ext, + Byte dw, Byte dh, Byte ul); +static void vpp_update_screen(void); + +static Byte LumReg = 0xff, TraReg = 0xff; +static Byte *colplus = NULL; +static int vppon = 1; +static int vpp_cx = 0; +static int vpp_cy = 0; +static Byte vpp_data = 0; +static int inc_curs = 1; +static int slice = 0; +static int vpp_y0 = 0; +static Byte vpp_r = 0; +Byte dchars[2][960]; +Byte vpp_mem[40][32][4]; +static int frame_cnt = 0; +static int blink_st = 0; +static int slicemode = 0; +static int need_update = 0; +static Bitmap* vppbmp; + +Byte read_PB(Byte p) +{ + p &= 0x3; + switch (p) + { + case 0: + return LumReg >> 4; + break; + case 1: + return LumReg & 0xf; + break; + case 2: + return TraReg >> 4; + break; + case 3: + return TraReg & 0xf; + break; + } + return 0; +} + +void write_PB(Byte p, Byte val) +{ + p &= 0x3; + val &= 0xf; + + switch (p) + { + case 0: + LumReg = (val << 4) | (LumReg & 0xf); + break; + case 1: + LumReg = (LumReg & 0xf0) | val; + break; + case 2: + TraReg = (val << 4) | (TraReg & 0xf); + break; + case 3: + TraReg = (TraReg & 0xf0) | val; + break; + } + need_update = 1; +} + +Byte vpp_read(ADDRESS adr) +{ + Byte t; + static Byte ta = 0; + static Byte tb = 0; + + switch (adr) + { + case 4: + return ta; + case 5: + /* get return value from last read */ + t = tb; + /* the real VPP starts a read cycle, + * the data gets returned at next read */ + if (slicemode) + { + Byte ext, chr; + chr = vpp_mem[vpp_cx][vpp_cy][0]; + ext = (vpp_mem[vpp_cx][vpp_cy][1] & 0x80) ? 1 : 0; + if (chr < 0xA0) + { + ta = 0; + fprintf(stderr, "unsupported: CHARROM read %d %d %d\n", chr, + ext, slice); + } + else + { + ta = dchars[ext][(chr - 0xA0) * 10 + slice]; + ta = ((ta & 0x80) >> 7) | ((ta & 0x40) >> 5) | ((ta & 0x20) >> 3) | ((ta & 0x10) >> 1) | ((ta & 0x08) << 1) | ((ta & 0x04) << 3) | ((ta & 0x02) << 5) | ((ta & 0x01) << 7); + } + tb = 0xff; /* real VPP seems to return junk */ + slice = (slice + 1) % 10; + } + else + { + ta = vpp_mem[vpp_cx][vpp_cy][1]; + tb = vpp_mem[vpp_cx][vpp_cy][0]; + if (inc_curs) + { + vpp_cx++; + if (vpp_cx >= 40) + { + vpp_cx = 0; + vpp_cy++; + if (vpp_cy >= 24) + vpp_cy = 0; + } + } + } + return t; + case 6: + return 0; + default: + return 0; + } +} + +void vpp_write(Byte dat, ADDRESS adr) +{ + static Byte ta; + + switch (adr) + { + case 0: + if (!slicemode) + vpp_mem[vpp_cx][vpp_cy][1] = dat; + else + ta = dat; + break; + case 1: + if (slicemode) + { + Byte ext, chr; + chr = vpp_mem[vpp_cx][vpp_cy][0]; + ext = (vpp_mem[vpp_cx][vpp_cy][1] & 0x80) ? 1 : 0; + if (chr >= 0xA0) + dchars[ext][(chr - 0xA0) * 10 + slice] = ((ta & 0x80) >> 7) | ((ta & 0x40) >> 5) | ((ta & 0x20) >> 3) | ((ta & 0x10) >> 1) | ((ta & 0x08) << 1) | ((ta & 0x04) << 3) | ((ta & 0x02) << 5) | ((ta & 0x01) << 7); + slice = (slice + 1) % 10; + } + else + { + vpp_mem[vpp_cx][vpp_cy][0] = dat; + if ((dat > 0x7f) && (dat < 0xa0) && (!(vpp_mem[vpp_cx][vpp_cy][1] & 0x80))) + { + vpp_mem[vpp_cx][vpp_cy][2] = dat; + vpp_mem[vpp_cx][vpp_cy][3] = vpp_mem[vpp_cx][vpp_cy][1]; + } + else + { + vpp_mem[vpp_cx][vpp_cy][2] = vpp_mem[vpp_cx][vpp_cy][3] = 0; + } + if (inc_curs) + { + vpp_cx++; + if (vpp_cx >= 40) + { + vpp_cx = 0; + vpp_cy++; + if (vpp_cy >= 24) + vpp_cy = 0; + } + } + } + break; + case 2: + vpp_data = dat; + break; + case 3: + switch (dat & 0xe0) + { + case 0x00: /* plus_cmd_brow */ + vpp_cy = vpp_data & 0x1f; + vpp_cx = 0; + break; + case 0x20: /* plus_cmd_loady */ + vpp_cy = vpp_data & 0x1f; + break; + case 0x40: /* plus_cmd_loadx */ + vpp_cx = (vpp_data & 0x3f) % 40; + break; + case 0x60: /* plus_cmd_incc */ + vpp_cx++; + if (vpp_cx >= 40) + { + vpp_cx = 0; + vpp_cy++; + if (vpp_cy >= 24) + vpp_cy = 0; + } + break; + case 0x80: /* plus_cmd_loadm */ + slicemode = 0; + slice = (vpp_data & 0x1f) % 10; + switch (vpp_data & 0xe0) + { + case 0x00: /* plus_loadm_wr */ + inc_curs = 1; + break; + case 0x20: /* plus_loadm_rd */ + inc_curs = 1; + break; + case 0x40: /* plus_loadm_wrni */ + inc_curs = 0; + break; + case 0x60: /* plus_loadm_rdni */ + inc_curs = 0; + break; + case 0x80: /* plus_loadm_wrsl */ + slicemode = 1; + break; + case 0xA0: /* plus_loadm_rdsl */ + slicemode = 1; + break; + default: + break; + } + break; + case 0xA0: /* plus_cmd_loadr */ + vpp_r = vpp_data; + break; + case 0xC0: /* plus_cmd_loady0 */ + if (vpp_data & 0x20) + fprintf(stderr, "unsupported: global double height"); + vpp_y0 = (vpp_data & 0x1f) % 24; + break; + default: + break; + } + break; + default: + break; + } + + need_update = 1; +} + +void vpp_finish_bmp(Byte *vmem, int offx, int offy, int w, int h, int totw, + int toth) +{ + int i, x, y, t, c, nc, clrx, clry; + int tcol[16], m[8] = {0x01, 0x10, 0x04, 0x40, 0x02, 0x20, 0x08, 0x80}; + Byte *pnt, *pnt2, *pnt3; + + if (vppon) + { + memset(colplus, 0, BMPW * BMPH); + vppon = 0; + } + + if (TraReg == 0xff) + return; + + vppon = 1; + + frame_cnt--; + if (frame_cnt <= 0) + { + frame_cnt = 100; + blink_st = 1 - blink_st; + need_update = 1; + } + + if (need_update) + vpp_update_screen(); + + for (i = 0; i < 8; i++) + tcol[i] = tcol[i + 8] = !(TraReg & m[i]); + + if (w > totw - offx) + w = totw - offx; + if (h > toth - offy) + h = toth - offy; + + if (w > vppbmp->w) + w = vppbmp->w; + if (h > vppbmp->h) + h = vppbmp->h; + + clrx = clry = 0; + for (i = 0; (!clrx) && (i < totw); i++) + if (tcol[vmem[offy * totw + i] & 7]) + clrx = 1; + for (i = 0; (!clry) && (i < toth); i++) + if (tcol[vmem[i * totw + offx] & 7]) + clry = 1; + if (clrx) + for (y = 0; y < offy; y++) + for (x = 0; x < totw; x++) + vmem[y * totw + x] = 0; + if (clry) + for (y = 0; y < toth; y++) + for (x = 0; x < offx; x++) + vmem[y * totw + x] = 0; + + for (y = 0; y < h; y++) + { + pnt = vmem + (offy + y) * totw + offx; + pnt2 = (Byte *)vppbmp->line[y]; + + x = 0; + while (x < w) + { + pnt3 = pnt; + c = *pnt++; + t = x++; + + if ((((x + offx) & 3) == 0) && (sizeof(unsigned long) == 4)) + { + unsigned long cccc, dddd, *p = (unsigned long *)pnt; + int t2 = x, w2 = w - 4; + cccc = (((unsigned long)c) & 0xff) | ((((unsigned long)c) & 0xff) << 8) | ((((unsigned long)c) & 0xff) << 16) | ((((unsigned long)c) & 0xff) << 24); + dddd = *p++; + while ((x < w2) && (dddd == cccc)) + { + x += 4; + dddd = *p++; + } + pnt += x - t2; + } + + if (c < 16) + { + if (tcol[c]) + { + if (app_data.openb) + for (i = 0; i < x - t; i++) + *pnt3++ = *pnt2++ & 0xf; + else + { + memcpy(pnt3, pnt2, x - t); + pnt2 += x - t; + } + } + else + { + for (i = 0; i < x - t; i++) + { + nc = *pnt2++; + if ((nc & 0x10) && app_data.openb) + { + *pnt3++ = nc & 0xf; + } + else if (nc & 8) + { + colplus[pnt3++ - vmem] = 0x40; + } + else + { + pnt3++; + } + } + } + } + } + } +} + +static void vpp_draw_char(int x, int y, Byte ch, Byte c0, Byte c1, Byte ext, + Byte dw, Byte dh, Byte ul) +{ + int xx, yy, d, m, k; + + if ((x > 39) || (y > 24) || (ext > 1)) + return; + + d = (dh == 2) ? 5 : 0; + + for (yy = 0; yy < 10; yy++) + { + if (ul && (d == 9)) + k = 255; + else if (ch >= 0xA0) + k = dchars[ext][(ch - 0xA0) * 10 + d]; + else if (ch >= 0x80) + k = 255; + else + k = vpp_cset[ext][ch * 10 + d]; + + m = (dw == 2) ? 0x08 : 0x80; + + for (xx = 0; xx < 8; xx++) + { + vppbmp->line[y * 10 + yy][x * 8 + xx] = (k & m) ? c1 : c0; + if ((xx % 2) || (dw == 0)) + m >>= 1; + } + if ((yy % 2) || (dh == 0)) + d++; + } +} + +static void vpp_update_screen(void) +{ + int i, x, y, l, chr, attr, ext, c0, c1, dw, dh, hpar, vpar, lvd, lhd, + ser_chr, ser_atr, ul, conc, box, swapcol; + int tlum[8], m[8] = {0x01, 0x10, 0x04, 0x40, 0x02, 0x20, 0x08, 0x80}; + + clear(vppbmp); + + for (i = 0; i < 8; i++) + tlum[i] = (LumReg & m[i]) ? 0 : 8; + + vpar = lvd = 0; + for (y = 0; y < 25; y++) + { + + vpar = (lvd == 0) ? 0 : 1 - vpar; + + l = (y == 0) ? 31 : (y - 1 + vpp_y0) % 24; + c0 = ul = conc = box = 0; + + hpar = lhd = 0; + for (x = 0; x < 40; x++) + { + hpar = (lhd == 0) ? 0 : 1 - hpar; + + chr = vpp_mem[x][l][0]; + attr = vpp_mem[x][l][1]; + c1 = attr & 0x7; + c1 = ((c1 & 2) | ((c1 & 1) << 2) | ((c1 & 4) >> 2)); + ext = (attr & 0x80) ? 1 : 0; + + ser_chr = vpp_mem[x][l][2]; + ser_atr = vpp_mem[x][l][3]; + if (ser_chr) + { + c0 = (ser_atr >> 4) & 0x7; + c0 = ((c0 & 2) | ((c0 & 1) << 2) | ((c0 & 4) >> 2)); + ul = ser_chr & 4; + conc = ser_chr & 1; + box = ser_chr & 2; + } + + if (ext) + { + c0 = (attr >> 4) & 0x7; + c0 = ((c0 & 2) | ((c0 & 1) << 2) | ((c0 & 4) >> 2)); + dw = dh = 0; + } + else + { + dw = (attr & 0x20) ? (hpar ? 2 : 1) : 0; + dh = (attr & 0x10) ? (vpar ? 2 : 1) : 0; + if (dw) + lhd = 1; + if (dh) + lvd = 1; + } + + swapcol = 0; + + /* cursor display */ + if ((x == vpp_cx) && (l == vpp_cy)) + { + /* on cursor position */ + if (vpp_r & 0x10) + { + /* cursor display active */ + swapcol = !swapcol; + if ((vpp_r & 0x80) && blink_st) + { + /* blinking active */ + swapcol = !swapcol; + } + } + } + + /* invert attribute */ + if ((!ext) && (attr & 0x40)) + swapcol = !swapcol; + + /* blinking chars */ + if ((vpp_r & 0x80) && !(attr & 8) && !blink_st) + { + /* cursor handling is done already */ + if (!(vpp_r & 0x10) || (x != vpp_cx) || (l != vpp_cy)) + { + c1 = c0; + } + } + + if (((y == 0) && (vpp_r & 8)) || ((y != 0) && (vpp_r & 1))) + { + if ((!conc) || (!(vpp_r & 4))) + { + if (box || (!(vpp_r & 2))) + { + if (swapcol) + vpp_draw_char(x, y, chr, c1 | tlum[c1], + c0 | tlum[c0], ext, dw, dh, ul); + else + vpp_draw_char(x, y, chr, c0 | tlum[c0], + c1 | tlum[c1], ext, dw, dh, ul); + } + else + { + vpp_draw_char(x, y, 255, (app_data.openb) ? 16 : 0, 0, + 0, 0, 0, 0); + } + } + } + } + } + + if (vpp_r & 0x20) + { + for (y = vppbmp->h - 1; y >= 10; y--) + for (x = 0; x < vppbmp->w; x++) + vppbmp->line[y][x] = vppbmp->line[(y - 10) / 2 + 10][x]; + } + + need_update = 0; +} + +void load_colplus(Byte *col) +{ + if (vppon) + memcpy(col, colplus, BMPW * BMPH); + else + memset(col, 0, BMPW * BMPH); +} + +void init_vpp(void) +{ + int i, j, k; + if (!colplus) + colplus = (Byte *)malloc(BMPW * BMPH); + if (!vppbmp) + vppbmp = NewBitmap(BMPW, BMPH); + clear(vppbmp); + + memset(colplus, 0, BMPW * BMPH); + + LumReg = TraReg = 0xff; + vpp_cx = 0; + vpp_cy = 0; + vpp_y0 = 0; + vpp_r = 0; + inc_curs = 1; + vpp_data = 0; + frame_cnt = 0; + blink_st = 0; + slice = 0; + slicemode = 0; + need_update = 1; + vppon = 1; + + for (i = 0; i < 2; i++) + for (j = 0; j < 960; j++) + dchars[i][j] = 0; + + for (i = 0; i < 40; i++) + for (j = 0; j < 32; j++) + for (k = 0; k < 4; k++) + vpp_mem[i][j][k] = 0; +} diff --git a/waterbox/o2em/vpp.h b/waterbox/o2em/vpp.h new file mode 100644 index 0000000000..a9e1276dcd --- /dev/null +++ b/waterbox/o2em/vpp.h @@ -0,0 +1,12 @@ +#ifndef __VPP_H +#define __VPP_H + +Byte read_PB(Byte p); +void write_PB(Byte p, Byte val); +Byte vpp_read(ADDRESS adr); +void vpp_write(Byte dat, ADDRESS adr); +void vpp_finish_bmp(Byte *vmem, int offx, int offy, int w, int h, int totw, int toth); +void init_vpp(void); +void load_colplus(Byte *col); + +#endif diff --git a/waterbox/o2em/vpp_cset.c b/waterbox/o2em/vpp_cset.c new file mode 100644 index 0000000000..46d3c5cf12 --- /dev/null +++ b/waterbox/o2em/vpp_cset.c @@ -0,0 +1,279 @@ + +/* + * O2EM Free Odyssey2 / Videopac+ Emulator + * + * Created by Daniel Boris (c) 1997,1998 + * + * Developed by Andre de la Rocha + * Arlindo M. de Oliveira + * + * http://o2em.sourceforge.net + * + * + * + * Videopac+ character table + */ + +#include "types.h" +#include "vpp_cset.h" + +const Byte vpp_cset[2][1280] = { + {/* Alphanumeric */ + 0x00, 0x38, 0x44, 0x40, 0x20, 0x10, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x00, 0x00, + 0x00, 0x08, 0x10, 0x3c, 0x20, 0x30, 0x20, 0x3c, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x24, 0x3c, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x50, 0x38, 0x14, 0x54, 0x38, 0x10, 0x00, + 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x10, 0x20, + 0x00, 0x28, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x28, 0x00, 0x00, + 0x00, 0x20, 0x18, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x00, 0x00, + 0x00, 0x20, 0x18, 0x00, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x10, 0x08, 0x3c, 0x20, 0x30, 0x20, 0x3c, 0x00, 0x00, + 0x00, 0x3c, 0x50, 0x50, 0x58, 0x50, 0x50, 0x3c, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x3c, 0x20, 0x30, 0x20, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x20, 0x7f, 0x20, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x08, 0x04, 0xfe, 0x04, 0x08, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x54, 0x38, 0x10, 0x00, + 0x00, 0x18, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x08, 0x10, 0x38, 0x44, 0x7c, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x10, 0x20, + 0x00, 0x10, 0x28, 0x00, 0x44, 0x44, 0x4c, 0x34, 0x00, 0x00, + 0x00, 0x20, 0x10, 0x34, 0x4c, 0x44, 0x4c, 0x34, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x7c, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x10, 0x38, 0x44, 0x7c, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x52, 0x5e, 0x50, 0x3e, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x38, 0x44, 0x7c, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x40, 0xc0, 0x40, 0x44, 0x4c, 0x14, 0x3e, 0x04, 0x00, + 0x00, 0x40, 0xc0, 0x40, 0x4c, 0x52, 0x04, 0x08, 0x1e, 0x00, + 0x00, 0xe0, 0x20, 0x40, 0x24, 0xcc, 0x14, 0x3e, 0x04, 0x00, + 0x00, 0x10, 0x28, 0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x3c, 0x20, 0x30, 0x20, 0x3c, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x34, 0x4c, 0x44, 0x4c, 0x34, 0x00, 0x00, + 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4c, 0x0c, 0x00, 0x00, + 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, + 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, + 0x00, 0x10, 0x54, 0x38, 0x10, 0x38, 0x54, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x01, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x80, + 0x00, 0x10, 0x28, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x04, 0x18, 0x20, 0x40, 0x7c, 0x00, 0x00, + 0x00, 0x7c, 0x04, 0x08, 0x18, 0x04, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x08, 0x18, 0x28, 0x48, 0x7c, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x7c, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x7c, 0x04, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x04, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, + 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x5c, 0x54, 0x5c, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, + 0x00, 0x7c, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7c, 0x00, 0x00, + 0x00, 0x7c, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x40, 0x40, 0x4c, 0x44, 0x3c, 0x00, 0x00, + 0x00, 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, + 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x48, 0x30, 0x00, 0x00, + 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, + 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00, 0x00, + 0x00, 0x44, 0x6c, 0x54, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x44, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, + 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x44, 0x44, 0x44, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, + 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00, 0x00, + 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00, 0x00, + 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x04, 0x02, 0x01, + 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x00, 0x30, 0x10, 0x10, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x34, 0x4c, 0x44, 0x4c, 0x34, 0x00, 0x00, + 0x00, 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x04, 0x04, 0x3c, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x18, 0x24, 0x20, 0x70, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x44, 0x44, 0x3c, 0x04, 0x24, 0x18, + 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x48, 0x30, + 0x00, 0x20, 0x20, 0x24, 0x28, 0x30, 0x28, 0x24, 0x00, 0x00, + 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x68, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x3c, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x04, + 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x38, 0x20, 0x20, 0x20, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4c, 0x34, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x44, 0x54, 0x54, 0x28, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x44, 0x4c, 0x34, 0x04, 0x44, 0x38, + 0x00, 0x00, 0x00, 0x7c, 0x08, 0x10, 0x20, 0x7c, 0x00, 0x00, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {/* Separated semi-graphic */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x70, 0x00, 0x70, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x07, 0x00, 0x70, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x77, 0x00, 0x70, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x70, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x07, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x77, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x70, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x07, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x77, 0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70, 0x00, + 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70, 0x00, + 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70, 0x00, + 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x70, 0x70, 0x00, 0x70, 0x70, 0x00, + 0x70, 0x70, 0x00, 0x70, 0x70, 0x70, 0x00, 0x70, 0x70, 0x00, + 0x07, 0x07, 0x00, 0x70, 0x70, 0x70, 0x00, 0x70, 0x70, 0x00, + 0x77, 0x77, 0x00, 0x70, 0x70, 0x70, 0x00, 0x70, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x70, 0x70, 0x00, + 0x70, 0x70, 0x00, 0x07, 0x07, 0x07, 0x00, 0x70, 0x70, 0x00, + 0x07, 0x07, 0x00, 0x07, 0x07, 0x07, 0x00, 0x70, 0x70, 0x00, + 0x77, 0x77, 0x00, 0x07, 0x07, 0x07, 0x00, 0x70, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x70, 0x70, 0x00, + 0x70, 0x70, 0x00, 0x77, 0x77, 0x77, 0x00, 0x70, 0x70, 0x00, + 0x07, 0x07, 0x00, 0x77, 0x77, 0x77, 0x00, 0x70, 0x70, 0x00, + 0x77, 0x77, 0x00, 0x77, 0x77, 0x77, 0x00, 0x70, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, + 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, + 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, + 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x70, 0x70, 0x00, 0x07, 0x07, 0x00, + 0x70, 0x70, 0x00, 0x70, 0x70, 0x70, 0x00, 0x07, 0x07, 0x00, + 0x07, 0x07, 0x00, 0x70, 0x70, 0x70, 0x00, 0x07, 0x07, 0x00, + 0x77, 0x77, 0x00, 0x70, 0x70, 0x70, 0x00, 0x07, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, + 0x70, 0x70, 0x00, 0x07, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, + 0x07, 0x07, 0x00, 0x07, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, + 0x77, 0x77, 0x00, 0x07, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x07, 0x07, 0x00, + 0x70, 0x70, 0x00, 0x77, 0x77, 0x77, 0x00, 0x07, 0x07, 0x00, + 0x07, 0x07, 0x00, 0x77, 0x77, 0x77, 0x00, 0x07, 0x07, 0x00, + 0x77, 0x77, 0x00, 0x77, 0x77, 0x77, 0x00, 0x07, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, + 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, + 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, + 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x70, 0x70, 0x00, 0x77, 0x77, 0x00, + 0x70, 0x70, 0x00, 0x70, 0x70, 0x70, 0x00, 0x77, 0x77, 0x00, + 0x07, 0x07, 0x00, 0x70, 0x70, 0x70, 0x00, 0x77, 0x77, 0x00, + 0x77, 0x77, 0x00, 0x70, 0x70, 0x70, 0x00, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x77, 0x77, 0x00, + 0x70, 0x70, 0x00, 0x07, 0x07, 0x07, 0x00, 0x77, 0x77, 0x00, + 0x07, 0x07, 0x00, 0x07, 0x07, 0x07, 0x00, 0x77, 0x77, 0x00, + 0x77, 0x77, 0x00, 0x07, 0x07, 0x07, 0x00, 0x77, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x00, 0x77, 0x77, 0x00, + 0x70, 0x70, 0x00, 0x77, 0x77, 0x77, 0x00, 0x77, 0x77, 0x00, + 0x07, 0x07, 0x00, 0x77, 0x77, 0x77, 0x00, 0x77, 0x77, 0x00, + 0x77, 0x77, 0x00, 0x77, 0x77, 0x77, 0x00, 0x77, 0x77, 0x00, + /* Mosaic semi-graphic */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, + 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, + 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, + 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, + 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, + 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, + 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, + 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; diff --git a/waterbox/o2em/vpp_cset.h b/waterbox/o2em/vpp_cset.h new file mode 100644 index 0000000000..29987836dc --- /dev/null +++ b/waterbox/o2em/vpp_cset.h @@ -0,0 +1,6 @@ +#ifndef __VPP_CSET_H +#define __VPP_CSET_H + +extern const Byte vpp_cset[2][1280]; + +#endif