Vampire Savior/Hacks

From Mizuumi Wiki
Jump to navigation Jump to search

End to end workflow for creating a MOD of VSAV, including lessons & exercises.

VSAV InputTest.jpg
VSAV LocationTest.jpg
VSAV MessageTest.jpg
VSAV SecretTest.jpg


I’m VMP_KyleW, an enthused VSAV competitor with an interest in VSAV related hobbies. Since the summer of 2018, I experimented & documented R.A.M. & R.O.M. manipulation for Vampire Savior. This page of Mizuumi Wiki has been reformatted to include the workflow & findings of my project in a format intended to be read as an article. The project was ambitious and challenging as I had very little knowledge on the subject. Truthfully, there is very little I did on my own. The majority of my effort was learning new content, new tools and collating information developed by others.

My project objectives:

  • Further explain bugs
  • Understand how the CPU can execute moves in situations the player cannot
  • Find hidden content like moves, taunts, animations
  • Unlock hidden content like Colors, Characters, Stages, & the Debug menu



This person has been the largest influence to the project. Felineki is truly a knowledgeable expert with a wealth of data. Please check out The Cutting Room Floor‘s Darkstalker titles located here:
Most, if not all of these Darkstalker contributions are from Felineki. Here are other examples of technical skills;
Additionally, They were kind enough to mentor me through some concepts as well as provided me with access to their work in progress Memory Map, including notes. SUPER THANK YOU Felineki!

Jed (Possum, MountainMan, Hudson)

Jed is a legend for their ability to meaningfully contribute & mod/hack most fighting games. Here are his VSAV videos which speak to his efforts;
Similarly to Felineki, he was very active in forum communities in the early 2000’s. Try google searching esoteric data about CPS-II, emulators or game music & their legacy is easily spotted. To further cite VSAV, Jed is responsible for creating a (.LUA) script which replicates most features of a “Training Mode” within VSAV on MAME.
Lastly, Jed’s VSAV color modding/hacking parameters are all public data on the Mizuumi wiki.
Jed, you are incredible, thanks for your hard work!


Goose is a PWN VSAV competitor, a friend of mine who plays an amazing Bulleta and excels at other hobbies including programming. Goose took on a modding project to create a custom “Benwa” portrait in the character select screen. He succeeded!
Playing on native CPS-II using a DarkSoft.
Lastly, Goose provided me with his notes on that project. Although it was entirely focused on graphics, I definitely learned valuable lessons/concepts for how VSAV game data is sorted, referenced & computed. If I do venture into a graphics modding project, the foundation is already set. Cheers to Goose!


SF2_Platnium has been wonderful to me. I was introduced to his efforts from this article during the summer of 2017;
He linked me to this valuable resource:
I could easily see the overlap between his project & my goals. Since then, we had numerous email exchanges discussing basic workflows for disassembly & data recreation. Overall, he helped me know what tools to use immediately & what tools to defer until after I understood more about MAME’s intermediate features. SF2_Platnium is my biggest inspiration as I take my project further. Thank You Thank You SF2_Platnium!


Although I’ve never corresponded with Dammit, It’s important to recognize this person’s efforts in creating the first generation of (.LUA) Scripts for CSP-II games. This individual is largely responsible for the Hit, Hurt & Push-Box visibility feature as well as the input display options. Dammit, you did a tremendous effort for the CPS-II community, we are indebted to you!

Pugsy’s Cheats Forum
Since the infancy of emulators, activist were interested in having “cheats” available to enhance gameplay; infinite health, infinite lives, etc. The earliest source I found for crediting these efforts is Pugsy’s Cheats. This is a forum which users would explore R.A.M. values and report them to Pugsy, who would collate the “cheats” into Mame’s PROGRAM INPUT LANGUAGE and provide a master “cheat” file for all game. This site is a testament to a grass root community effort from 2000-2010. Besides Pugsy himself, some active members focusing on VSAV were Mike_Haggar, KelvSYC & D9x. Thank You for establishing the “Cheats” files for MAME!

Jais & Alphakami

Jais & Tad are a support network, allowing a platform for theory-crafting, learning computer science concepts & most importantly, engaging with me as the project developed. Jais also reviewed the document. I was only able to complete this with your help. Thanks guys!


Jordyn is a friend of mine from back in the Cincy days. He reviewed this article as a knowledgeable source for Computer Science, Fighting Games, Reverse Engineering & competing with Demitri. Thanks Jordyn, you are awesome!

N-Bee N-Bee#7736

N-Bee is a friend of mine since early 2020 & contributed heavily during the ROM discovery period of my project . We met while both developing our own VSAV projects and they have been a tremendous inspiration & source of knowledge. N-Bee reviewed the ROM portion of this article as a knowledgeable source for Computer Science, Fighting Games, Reverse Engineering & competing with Q-Bee. Thanks so much N-Bee!

Surround yourself with supporting, knowledgeable & encouraging people

Updating & Sharing Thesis

This article will be as workflow-transparent as possible. Secondly, I am taking the effort to prove the findings so readers have a better understanding of concepts. I am sharing this in a wiki format largely at the request of the community, but also to offer a responsive platform for updating the document. I have a very basic understanding of these concepts from a non-formal learning perspective. I presume corrections need to be made after publication. Please feel empowered to notify me on Twitter @VMP_KyleW with errors, I am happy to correct them! I strive to only share accurate information.

My largest challenge was finding information for what tools to use as well as how and when to use them. I plan to mitigate these hurdles for people outside of the Computer Science Industry. The brilliant people before me tend to keep their tools & workflows internal. It is not clear as to why, we can only speculate. Some hypotheses are:

Results vs Process - Similar to scientist publishing public papers; to the public eye, there is a greater emphasis on the results of an experiment. Some amazing logic and problem solving would go into a hypothesis, to ultimately not be shared due to unfavorable or incomplete results.
Internal work without public intent - Some projects were designed only for an internal workflow. Sharing workflows and developmental data as OpenSource was never the desire. OpenSource publication takes a higher level testing, transparency and maintenance. For personal projects, this slows down production.

Legal Disclaimer

I personally own (3) separate copies of VSAV; Darkstalkers 3 for PS1, DS:Resurrection for XBox 360 & a JP-VSAV B-Board on CPS-II. Anyone interested in obtaining VSAV(.ZIP) should purchase a legal copy first! I will not specify how to obtain VSAV(.ZIP). I’m publishing this up on a good faith effort that Capcom will not award me a cease and desist.


  • Provide a framework for others to explore R.A.M. addresses in CPS-II games.
  • Provide a framework for others to explore R.O.M. Data in CPS-II games.
  • Share a collective understanding of VSAV’s R.A.M. & R.O.M. data with a diverse audience.

What I will not explain

Learn these before proceeding:

  • What Operating System you are running
  • How to install programs on your own Operating System
  • Basic Operating System (Windows)
Commands like copy, paste, find, replace
Navigation of directories
Accessing RUN (Window’s) command
Accessing COMMAND PROMPT (Window’s)
  • Mapping the controller in MAME;
TAB key > input (This game)
  • Creating SAVE STATES in MAME;
TAB key > Input (general) > user interface
TAB key > Input (general) > user interface
  • You should enable Windows to display file type extensions

My Environment

  • MAME default settings. Non custom configurations
  • Windows 10 Pro - Home edition; 64 bit operating system
Version 1809
OS Build 17763.615


These definitions are very basic, but essential to beginning the project.

  • R.O.M. - READ ONLY MEMORY. R.O.M. refers to all the data inside the game which is static & does not change. Some examples of R.O.M. are graphics, audio & program data. Often times, a file needed to play on an emulator is referenced as the games “ROM” file. This file is actually the “game data file” which is a combination of data and language needed to interface the processor. This file allocates all addresses for R.O.M. & R.A.M values.
  • R.A.M. - RANDOM ACCESS MEMORY. R.A.M. is allocated memory addresses that manage dynamic variables in a program. This includes variables like, which character is playing, how much life the player has & how much meter a player has. All of these values are dynamically stored in dedicated Memory addresses. R.A.M. is a location which temporary data is stored.
  • Dip Switch - Early arcade games do not offer a “Menu” to interface game options because it required too much memory. The solution to changing basic options like game difficulty was managed by physical switches on the Printed Circuit Board. These switches have a map key or legend provided with the installation manual of each title. Because these Dip Switches were used to manage basic options of games, the industry adopted the name “Dip Switch” to discuss the act of changing these settings, even for future games where the physical switches do not exist, Ha! One example of this is Darkstalkers: The Vampire Collection for Playstation 2 which offers unspecified “Dip Switch” options for custom game balancing. This term is known as generic trademark. Think of it like the “save” icon on most windows programs, the icon of a floppy disk is still used today, while physical floppy were announced dead, around 2007
  • Service Menu - VSAV does not have physical switches to manage game options. CPS-II’s B-Board offers a single button, called the “SERVICE BUTTON” which places the game into the “SERVICE MENU”. This Service Menu is where basic settings (input test, clock speed, round count, etc.) are managed.
  • Decimal, base10 - Standard counting uses our traditional method whereas any digit position could hold up to one of ten different symbols; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 that each represent a value in respect to which symbols are in which positions.
  • Hexadecimal, base16 - Hexadecimal counting uses a different method whereas any digit position could hold up to one of sixteen different symbols; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F that each represent a value in respect to which symbols are in which positions. All memory addresses and values within the R.O.M. and R.A.M. address are Base16 hexadecimal. Usually, but not always, Base16 hexadecimal format is identified with the prefix 0x. Nine units in Base16 hexadecimal is written as 0x9. Ten units is written as 0xA. Twenty Six units in Base16 hexadecimal is written as 0x1A.
  • Program Input Language - The arrangement of characters and commands to be read by a program.

R.A.M. Analysis

Obtain MAME-RR


Extract the (.ZIP) file such that the final product is a folder called “MAME-RR_v0139_vsav_train” which includes numerous data files, folders & an executable called MAME(.EXE). Rename this folder to be called “MAME”.

I placed this MAME folder on my Desktop. You could place it there or directly into your “C: Drive”

I am running version You can verify your version by Right Mouse Click on “Mame.Exe” > Properties > Details > File Version.

Obtain VSAV(.ZIP) for Emulator

Try searching google for the filename - Once you obtain VSAV(.ZIP), place it into the directory of MAME > roms.

Pugsy’s Cheats Analysis

Obtain Pugsy’s Cheats


1. click on the column header titled “MAME Cheat Files”.
2. Download the link from the top of the list, titled as “XML CHEAT Collection for MAME”.
3. This (.ZIP) folder is a compressed folder that needs to be “unzipped”. Windows 10 allowed me to complete this by by Left Mouse Clicking once on the (.ZIP) file then Right Mouse Clicking & selecting Extract All…
4. This will recreate the data as an interactable folder within the same directory. You can delete cheat0206(.ZIP), after extraction.
5. Within your new folder, there is a file named Cheat.7z. This a compressed (.7z) file which needs a unique program to unzip it.

Obtain 7-zip


1. download the executable compatible with your operating system. For me, this was the 64-bit installer for Windows 10.
2. Install the program.
3. Right Mouse Click on Cheat(.7z) and hover the Mouse Over 7-zip > Extract files....
4. The next dialogue defaults to placing a newly unzipped copy in the same directory.
5. Click OK.
6. Look inside your newly created folder called Cheats to find the file VSAV(.XML)
7. Right Mouse Click > Copy
8. Go to your MAME directory, and PASTE VSAV(.XML) into your subfolder called cheats.
Yes, the file already exist there, but I needed you to understand where VSAV(.XML) originated. It’s important to cite the sources of previous projects. Congrats, now you have all the tools to run VSAV on MAME as well as access the CHEATS feature within MAME.


I prefer to edit in NOTEPAD, so I did this - Within the directory of MAME > Cheats, Right Mouse Click on VSAV(.XML) > Open With > Notepad.

Explore VSAV(.XML)

This cheat file already contains some addresses and values. Basic MAME Cheats can only change R.A.M. Values. Changing R.O.M. values is best with a different tool. Here is a walk-through of their first example: Description, Address (in Base16 hexadecimal), Value (in Base16 hexadecimal), Program Input Language

<cheat desc="Infinite Time">
   <script state="run">

0x63 = 99 in Base10 decimal.

This cheat forces the clock to constantly read as 99.

Here is the totality of what Pugsy’s Cheats tells us for VSAV’s R.A.M. (omitting Program Input Language).

Infinite Time FF8109 63
Finish this Round Now! FF8109 0
Select Background FF8101 param
Soul Keeper 'ON' FF87BC FF
Soul Keeper 'OFF' FF87BC 0
Maximum POW PL1 FF8509 63
Infinite Energy PL1 FF8450 1200120
Drain All Energy Now! PL1 FF8450 0
Infinite Dark Force Time PL1 FF8577 70
Select Character PL1 FF8782 param
Soul Keeper 'ON' PL2 FF8BBC FF
Soul Keeper 'OFF' PL2 FF8BBC 0
Maximum POW PL2 FF8909 63
Infinite Energy PL2 FF8850 1200120
Drain All Energy Now! PL2 FF8850 0
Infinite Dark Force Time PL2 FF8977 70
Select Character PL2 FF8B82 param
No Background Music F026 0
Hide Background This one is complicated
Select Region FF8091 param
Select Title FF8089 param
Sound Test This one is complicated
Sound Test Timer Stop FF800B FF

Lots to learn!

Notice how almost all Address are 6-digits. That’s important information. We can easily assume that the total Address range of Program Space Memory is 000000 to FFFFFF.

Notice how the Address for No Background Music is only (4) digits. This is because Base16 hexadecimal format allows us to assume the leftmost values are 0’s. We can write the Base16 hexadecimal number 0xF026 as 00F026.

Regarding the value of param. This is a command for the CHEATS program that allows us to specify different values at the same address all within one CHEAT operation. These are for Select Character, Select Background, Select Region and Select Title.

Notice that addresses expect values with consistent formats:

  • Number that converts to binary representing systems like health or clock. This can be increasing or decreasing; INCREMENTING or DECREMENTING.
  • 00 or FF - This type of value is a FLAG.The condition is binary, which only allows two options. Flags are coded to verify an expected value. It can also be said that a FLAG of FF is looking for FF or anything not FF. Any value not FF will trigger the change.
  • Param values directly reference additional variables. This is called a POINTER.

Notice how PL1 (Player One) & PL2 (Player Two) have separate entries. Let’s get a better understanding of their relationship; here is a proof of concept confirming there is a consistent 0x400 address difference.

Select Character PL1 subtract Select Character PL2 =
FF8782 subtract FF8B82 = -0x400
Maximum POW PL1 subtract Maximum POW PL2 =
FF8509 subtract FF8909 = -0x400

We can confidently say that the design of R.A.M. addresses have a 0x400 gap between PL2 & PL1. Felineki told me this specifically, thanks for the tip!

Lastly, Let’s try to understand the ranges of R.A.M. for similar descriptions. I’ll note the lowest & highest findings from above.

  • Game R.A.M. Data; FF800B to FF8091
  • Match R.A.M. Data; FF8101 to FF8109
  • PL1 R.A.M. Data; FF8450 to FF87BC
  • PL2 R.A.M. Data; FF8850 to FF8BBC

Unanswered questions from this analysis:

  • What is the total range of R.A.M. addresses?
  • Where does R.A.M. delineate between game, match & player data?
  • Why are some values greater than two digits?

Cheats Script & Commands

The four basic commands inside of CHEATS are ON, OFF, CHANGE & RUN. This defines how or when the action will be executed. In an example of RUN, the script state is always enabled, running each frame. If you are interested in all of these details, I recommend you read pages 7 & 8 from PUGSY’S endorsed guide called HOLY CHEAT!, located here:

By copy and pasting program input language inside VSAV(.XML), you can now create your own cheats.

MAME Exercises

Time to load MAME & get into VSAV! Double Click the file MAME(.EXE) > Double-Click VSAV’s “Game Data” file. While running VSAV on this emulator, press the “TAB” button on your keyboard to open a sub-menu. Now Double-Click the option CHEAT. Here is where you activate the CHEATS we analyzed. Most of this tool is intuitive, but there a few interactions worth an explanation.

Exercise #1: Overflow

GOAL: Learn about memory overflow

Let’s analyze the Infinite Time cheat again.

<cheat desc="Infinite Time">
   <script state="run">

The specific command within this CHEAT program is the “run” command. You will notice that changing this cheat to “ON” will tell VSAV to constantly WRITE the value of 0x63 (remember that the prefix 0x signifies this as a Base 16 Hexidecimal number) for the entire time the cheat is “ON”. This command succeeds with no issues because the Address 0xFF8190 is expecting a DECREMENTING value. VSAV is not programmed to have a clock value greater than 0x63 or a combo-counter value greater than 0x63. Adding a cheat to go above the designed value will cause unintended graphics to load. This condition is called a MEMORY OVERFLOW or OVERFLOW.

The overflow in the above case is actually a type of memory overflow. It’s highly likely that there's an address table somewhere that looks up the graphics for the timer, and when the value exceeds 0x63, it is grabbing other graphics outside of that specific address table. It is also possible that the graphics engine can grab non-graphics data and represent it as a graphic.

Exercise #2: Pointers, Read & Write Operations

GOAL: Learn about pointers, read & write commands

Let’s analyze the Select Character cheat.

1. Go to VSAV’s Select Character screen
2. Active the Select Character cheat
3. Cycle through the options and choose “Jon Talbain”.
4. Notice how the character select graphics will change while you cycle through characters.
5. While playing as your CHEAT Jon Talbain, begin the battle
6. Activate the Select Character cheat
7. Cycle through the options and choose “Lord Raptor”.
8. Make Lord Raptor walk & you’ll see “Wild MISSINGNO appeared!”

In programming, a POINTER is a value that directly references another location.

This exercise demonstrates a lesson on when values are READ. POINTERS are dependent on when the Processor READS and WRITES data. Changing the Select Character value during the character select menu functioned normally. Changing the Select Character value during the battle caused graphical errors - MissingNo.

In this example, the Program Data told the Processor to READ & WRITE the primary character value and all nested value (Character specific graphics, hit-boxes, audio, etc.) during character selection. While in a battle, the Processor only READS these value. We are playing as “Lord Raptor” but all of the character’s graphics are still directed to “Jon Talbain” because they are WRITTEN at character selection.

Value can be WRITTEN & READ at different times. Consider this as you experiment.

Exercise #3: R.A.M. Versatility

GOAL: Learn about the versatility of R.A.M.

Add the following Cheat into your VSAV(.XML) file.

<cheat desc="0xFF800D Config Menu Options" <comment>Also activates match HUD announcements</comment>
	<item value="0x00">System 00</item>
	<item value="0x02">Game 02</item>
	<item value="0x04">Default 04</item>
	<item value="0x06">Save then Exit 06</item>
	<item value="0x08">Hidden Regions 08</item>
        <script state="run">

Service Menu Function example

0xFF800D is the address for manipulating a sub-menu called 7-CONFIGURATION MENU within the SERVICE MENU. Changing values inside the sub-menu forces the cursor to move to specific sub-options; SYSTEM, GAME, DEFAULT, or SAVE THEN EXIT.

Battle Function example

0xFF800D is also the address for manipulating the H.U.D. Announcements during battle. READY, FIGHT, K.O., LOSE, PERFECT Etc. The Program Data tells the Processor to READ & WRITE values and all referenced values during battle too.

It’s overwhelming to realize that an address of memory can be used for numerous tasks. That flexibility is the exact purpose of R.A.M. It’s RANDOM ACCESS MEMORY - Exercise #3 unveils that R.A.M. is relative to the current operation. Think of it as different game states, called FUNCTIONS. It’s know that developers deliberately assigned memory, each function has a repeatable way of interacting with available R.A.M., we have these discrete functions where R.A.M. could be unique:

  • Service Menu
  • Game Intro & Ending animations
  • Character Select
  • Battle
  • Story Mode Transitions

Unanswered questions from these exercises:

  • Where are memory overflow values coming from?
  • Is there R.A.M. values that remain during different functions?
  • How to determine if an address is a POINTER, FLAG, INCREMENT or DECREMENT format?
  • How best to document R.A.M. addresses with respect to each function?

Training Mode (.LUA) Analysis

The next tool to discover is a Lua program. These are often called lua scripts, it is an additional program that can be executed simultaneously alongside MAME to allow modifications. MAME allows lua scripts! Some brilliant people were able to produce these tools:

  • CPS-II real time hit-box/throw-box graphics
  • CPS-II Frame Data
  • MAME input display
  • VSAV exclusive - Training Mode

This exercise will explore the Training Mode (.LUA) created by Jed

Mizuumi’s VSAV wiki explains the custom training mode here:

You will notice these files are already downloaded when obtaining MAME-RR. I prefer to explore in NOTEPAD, so I chose to do this- - open the MAME directory & locate vsavscriptv2(.LUA) then Right Mouse Click > Open With > Notepad.

There is too much relevant data to list in this article. but know that numerous more addresses and values for R.A.M. manipulation are documented in this script. Using best practices, Jed wrote all Base-16 hexadecimal numbers with a prefix of 0x. Using the Windows FIND (CTRL+F) command, If you search for “0x”, you easily find adjacent corresponding descriptions. the second result informs us: Projectile On-Screen is @0xFF84AC. This check is obviously a BOOLEAN because there are only (2) answers; projectile is on-screen & projectile is not on-screen. A BOOLEAN FLAG can also be referred as a FLAG, BOOLEAN, or BOOL.

Additionally, we previously learned that PL2 has a repeatable +0x400 relationship to the PL1 address. So it’s safe to assume PL2 Projectile On-Screen is @0xFF88AC.

Continue your Windows FIND (CTRL+F) command of “0x” to find a few hundred more results for addresses and descriptions. Combining this information with Pugsy’s Cheat’s provides tremendous insight into VSAV’s memory.

MAME Debugger

MAME’s Debugger tool is fantastic. It is the most useful option to explore live memory.

Open the Debugger

MAME'S Debugger tool does not have a (.EXE) file. I started by accessing the Window’s RUN command. I prefer to use the keyboard shortcut of (WinKey + R) > type cmd > OK

We have to manually boot the program using the Window’s COMMAND PROMPT. My MAME directory is located on the Desktop. I have to specify this within the COMMAND PROMPT. To navigate to the Desktop, I have to “Change Directories”. I enter this into the COMMAND PROMPT; cd Desktop\MAME

The directory being referenced is now the desktop. If your MAME folder is located in your C: Drive, the required command is; cd C:\MAME

To load the Debugger Use the command; mame vsav -debug

The Debugger & the emulator will load. The Debugger needs a RUN command to initiate. To achieve the RUN command, I chose this workflow; select the window of the Debugger then press the “F5 key”.

Super congrats, you are in!

Exercise #4 Basic Flow of Data

GOAL: Obtain a basic understanding of the CPS-II’s data-flow.

At a very basic level - The Program Data tells the Processor which game state is enabled as well as how to execute every command to facilitate that state (character select, battle, etc.) . The Processor will process data, using MACHINE CODE. CPS-II uses a Motorola 68K processor, all of the MACHINE CODE commands are unique to this Motorola 68K processor. The Processor reads R.O.M. data (Graphics, Audio & Program Data), does manipulations to WRITE & READ R.A.M. values as required. The Audio & Graphics are simultaneously reading data from memory to display and generate sound. The Program Data & R.A.M are simultaneously WRITING & READING data to allow controller inputs.

Vsav CPS-II Basic Data Flow.png

Exercise #5 Debugger Tour

GOAL: Be introduced to the Debugger tool

I noted each pane in Orange.
  • Command Line & History - A panel to give commands & read output history of commands.
  • Machine Code - Also called “Machine Language”, this is the literal machine code commands given by the Motorola 68K.
  • Registers - Address Registers is a unique type of R.A.M. used as a temporary storage for values, exclusively for process calculations. The existence of address registers greatly improves the overall performance time.

Vsav MAME Debugger Overview.png

Exercise #6 Cheatinit + Save States

GOAL: Learn the Debugger command; Cheatinit

This Cheatinit command is very useful to discover addresses based on your own conditions, It searches the entirety of memory so results could be R.A.M. or R.O.M. data. The Cheatinit command compares the entirety of memory at (2) user-specified points in time. By setting your own conditions, you can search for the corresponding differences in value.

Let’s work through the Cheatinit command to locate the counter for “PLAYER ONE START INPUTS” at the character select screen. We know the game stores this value because five total inputs are required to select a Shadow Character in VSAV.

First, go to the character select screen and press PL1 START a total of nine times. Now SAVE STATE 1. Secondly, restart the Debugger (or the emulator), go to the character select screen and press PL1 START a total of six times. Create a SAVE STATE 2. Comparing the values of nine & six is easiest because their values are the same in Base10 decimal counting as well as Base16 hexadecimal counting because we’re not going above 0x9 and into 0xA.

Here is my preferred workflow to restart MAME & the Debugger while actively running the program;

1. In the Debugger menu, go to Debug > Hard Reset. This resets the emulator & Debugger. The emulator starts in a PAUSED mode.
2. Select the emulator window then press the “P Key” to unpause it. Now the Debugger begins and needs another RUN command.
3. Select the Debugger window and press the “F5 Key”. Now VSAV is running again.

Here is my preferred workflow for comparing the (2) SAVE STATES with the Cheatinit command;

Active the emulator window, press the “P Key” to PAUSE the emulator, LOAD STATE 1. activate the Debugger, enter the command Cheatinit. Once you press “Enter” it appears that nothing has happened! This is because the emulator is not running. Now, select the emulator & while it remains PAUSED, LOAD STATE 2 then press the “Tilde Key” also referred to as the “~ Key”. The “Tilde key” advances the emulator by (1) frame of animation. You now have a confirmation from the Debugger that it is tracking 81940 memory addresses for CHEATS. Issue the command; Cheatnext de, 3. Select the emulator and advance the emulator by (1) more frame & see the results on the Debugger: (36) cheats found. If the results were just a few hits, they would be listed out as history. This example found (36) results but it wants to know HOW we desire to receive the data. This command is called Cheatlist. It defaults to the history pane, but we actually want to create a (.TXT) file of the results. Give the Debugger this command; Cheatlist StartCompare.txt then advance the emulator by (1) frame to process the command. The Debugger now reads >Cheatlist startcompare(.TXT). The Debugger will create a (.TXT) file using the name we specified. The location of the newly created file is in our MAME directory.

Let’s discuss a few properties of the Cheatnext command before we analyze the (36) results. We provided the command Cheatnext de, 3. de represents a decreasing value while 3 represents 0x3. We compared nine start inputs against six start inputs, that’s a difference of 3, so a de of 3 was an input to Cheatnext.

While learning and experimenting with the Cheatinit command, it’s important to make an educated guess about the anticipated format of data. Would your custom condition be in FLAG, POINTER, INCREMENT or DECREMENT format? Your SAVE STATES & Cheatnext command should format accordingly.

Exercise #7 Cheatlist(.TXT) Analysis

GOAL: Analyze Cheatlist(.TXT)

Open the file StartCompare(.TXT). You will quickly notice the syntax is identical to VSAV(.XML). This is because the Cheatinit tool is used to generate CHEATS. You can copy & paste these results into your (.XML) file to enable CHEATS within MAME!

Before we begin that process, it’s important to realize the Cheatinit command returns all addresses of memory, meaning it gives addresses in R.O.M. & R.A.M. that meet the condition we set in CheatInit. We cannot use MAME cheats to manipulate R.O.M. During our Pugsy’s Cheats Exploring we documented R.A.M. address ranges for similar descriptions. It’s safe to assume that our answer for the number of Player One Start Inputs is within the address range FF800B to FF8BBC, because it’s R.A.M. Data!

  • Game R.A.M. Data; FF800B to FF8091
  • Match R.A.M. Data; FF8101 to FF8109
  • PL1 R.A.M. Data; FF8450 to FF87BC
  • PL2 R.A.M. Data; FF8850 to FF8BBC

Finally, look at all (36) addresses within the file StartCompare(.TXT). Only one result is within the range FF800B to FF8BBC.

<cheat desc="Possibility 36 : FF8444 (06)">
   <script state="run">

We found it! Player One’s quantity of Start inputs during the character select menu is at FF8444. Therefore, Player Two quantifies Start inputs during the character select menu at FF8844.

We can demonstrate this by creating a CHEAT to change the number of start inputs to always be at value 05. The cheat enables easy selection of a Shadow Character. Here is the script;

<cheat desc="Easy PL1 Shadow Character"> <comment>Choose Random Character</comment>
   <script state="run">

Exercise #8 Visualizing Memory

GOAL: Learn to visualize memory in real-time

Debugger > Debug > New Memory Window.

This new window is amazing. It is real time visualization into values of memory at every address.

While viewing addresses, remember that all numbers are in Base16 hexadecimal! This data reads left-to-right then top-to-bottom. Every pair of characters represent the current value stored in the position’s address. Starting at the top of the table, address 0x000000 equals 0x23 & address 0x000001 equals 0xDF. By default, the address listed at the beginning of the row is the first address in the sequence. By default, the address at the end of the row will always be the address listed at the beginning with a final digit of F. 0x00000F equals 0xD0.

Vsav Memeory Window Example.png

Use the open field to specify an address. This will jump the table to that address. I recommend you only search for addresses which have the last digit as 0x0. Doing so will keep the default formatting described above.

We can now answer one of our previous questions: What is the finite range for Program Space memory? By scrolling to the bottom of this window we see that all possible Program Space Memory addresses are implemented in definitively 6-digits; 0x000000 to 0xFFFFFF.

Exercise #9 Real Time R.A.M. Manipulation

GOAL: Learn to manipulate R.A.M. in real-time

MAME’s Debugger allows real time manipulation of R.A.M. inside this memory window. Only R.A.M. manipulation is allowed. In comparison to CHEATS, these changes do not continuously update the value. This tool allows us to test an address and confirm if it is R.O.M. or R.A.M., if you can change the value, it’s R.A.M.!

Exercise #10 Size of Values

GOAL: Learn about the size of values

From the Debugger’s New Memory Window, search for the address 0xFF8060. Go to the emulator and begin the game. As you press Player One Start, 0xFF8060 & 0xFF8061 simultaneously update to the value of 0x01. This is because the value of 0x01010101 is written to address 0xFF8060.

It is detailed at the beginning of the operator's manual for the Motorola 68k that a BYTE is 8 bits, a WORD is 16 bits and a DOUBLE WORD or DWORD is 32 bits. Please know that a BYTE is (2) digits in Base16 hexadecimal (0x00 to 0xFF), a WORD is (4) digits in Base16 hexadecimal (0x0000 to 0xFFFF) & a DWORD is (8) digits in Hex (0x00000000 to 0xFFFFFFFF).

You cannot use the Debugger’s New Memory Window to manipulate R.A.M. In real time when it is looking for a WORD or DWORD. There is simply too many digits to enter in the given time. Manipulating these addresses is best using CHEATS.

This answers our previous question; Why are some values greater than two digits?

Definition Length of Bits Number of Digits Hex Ranges
BIT 1 Not Applicable Not Applicable
BYTE 8 2 0x00 to 0xFF
WORD 16 4 0x0000 to 0xFFFF
DWORD 32 8 0x00000000 to 0xFFFFFFFF

We now have the tool & knowledge to answer another previous questions; Where does R.A.M. delineate between game, match & player data? Our previous notes show:

  • Game R.A.M. Data; FF800B to FF8091
  • Match R.A.M. Data; FF8101 to FF8109
  • PL1 R.A.M. Data; FF8450 to FF87BC
  • PL2 R.A.M. Data; FF8850 to FF8BBC

Let’s open a New Memory Window to visualize where changes occur. First, search for the address 0xFF8000, then scroll up a little to see a wider range of addresses, let the lowest visible address be 0xFF7F10.

Now, inside the emulator, hold the “ENTER key” and watch the memory as the game is sped up during Game Intro Mode. Notice how values from 0xFF7FA0 to 0XFF7FF0 are constantly changing at a rate significantly different then the values across line 0xFF8000. Notice how 0xFF8001 changes values every time the game transitions to a new game state. This is the delineation of R.A.M. during the game state.

Next let’s try to delineate Match Data. Search 0xFF8100 and scroll up to analyse the demo-mode similarly. Notice how address 0xFF8101 only updates when the Battle-Demo is active. It’s safe to assume that Match Data begins here.

Next, let’s analyze PL1 Data. Search 0xFF8450 and scroll up and review the Game Intro mode similarly. Notice that during the battle demo-mode, only values load starting at 0xFF8400. This is the delineation. We can assume PL2 R.A.M. addresses start at 0xFF8800. Lastly, we know the range of PL1 is 0xFF8400 to 0xFF87FF. We can assume the PL2 range is 0xFF8800 to 0xFFBFF.

Here are the results;
  • Game R.A.M. Data; FF8000 to FF80FF
  • Match R.A.M. Data; FF8100 to FF83FF
  • PL1 R.A.M. Data; FF8400 to FF87FF
  • PL2 R.A.M. Data; FF8800 to FF8BFF

Exercise #11 -ListXML_VSAV

GOAL: Learn about the Debugger command; -ListXML

I learned about this tool from a Youtube channel owned by Thank you for the demonstration!

Mame has a tool to list out the memory uses of each Game Data File. The MAME Debugger command is ListXML. We execute the command from the Window’s Command Prompt. Open the Command Prompt then change the directory to the MAME folder. Give this command: mame vsav -listxml > vsavDATA.xml. This creates a (.XML) file in your MAME directory. Open this file with NOTEPAD then scroll to the bottom.

Here is the last portion of information;

<mame build="0.139[RR] (Aug  8 2010)" debug="no" mameconfig="10">
   <game name="vsav" sourcefile="cps2.c">
  	 <description>Vampire Savior: The Lord of Vampire (Euro 970519)</description>
  	 <rom names="vm3e.03d" size="524288" crc="f5962a8c" sha1="e37d48b78186c7c097894d6c17faf7c9333f61eb" region="maincpu" offset="0"/>
  	 <rom names="vm3e.04d" size="524288" crc="21b40ea2" sha1="6790fa3e618850f518cbd470f44434a71be6f29f" region="maincpu" offset="80000"/>
  	 <rom names="vm3.05a" size="524288" crc="4118e00f" sha1="94ce8abc5ff547667f4c6022d84d0ed4cd062d7e" region="maincpu" offset="100000"/>
  	 <rom names="vm3.06a" size="524288" crc="2f4fd3a9" sha1="48549ff0121312ea4a18d0fa167a32f905c14c9f" region="maincpu" offset="180000"/>
  	 <rom names="vm3.07b" size="524288" crc="cbda91b8" sha1="31b20aa92422384b1d7a4706ad4c01ea2bd0e0d1" region="maincpu" offset="200000"/>
  	 <rom names="vm3.08a" size="524288" crc="6ca47259" sha1="485d8f3a132ccb3f7930cae74de8662d2d44e412" region="maincpu" offset="280000"/>
  	 <rom names="vm3.09b" size="524288" crc="f4a339e3" sha1="abd101a55f7d9ddb8aba04fe8d3f0f5d2006c925" region="maincpu" offset="300000"/>
  	 <rom names="vm3.10b" size="524288" crc="fffbb5b8" sha1="38aecb820bd1cbd17287848c3ffb013e1d464ddf" region="maincpu" offset="380000"/>
  	 <rom names="vm3.13m" size="4194304" crc="fd8a11eb" sha1="21b9773959e17976ff46b75a6a405042836b2c5f" region="gfx" offset="0"/>
  	 <rom names="vm3.15m" size="4194304" crc="dd1e7d4e" sha1="30476e061cdebdb1838b83f4ebd5efae12b7dbfb" region="gfx" offset="2"/>
  	 <rom names="vm3.17m" size="4194304" crc="6b89445e" sha1="2abd489839d143c46e25f4fc3db476b70607dc03" region="gfx" offset="4"/>
  	 <rom names="vm3.19m" size="4194304" crc="3830fdc7" sha1="ebd3f559c254d349e256c9feb3477f1ed7518206" region="gfx" offset="6"/>
  	 <rom names="vm3.14m" size="4194304" crc="c1a28e6c" sha1="012803af33174c0602649d2a2d84f6ee79f54ad2" region="gfx" offset="1000000"/>
  	 <rom names="vm3.16m" size="4194304" crc="194a7304" sha1="a19a9a6fb829953b054dc5c3b0dc017f60d37928" region="gfx" offset="1000002"/>
  	 <rom names="vm3.18m" size="4194304" crc="df9a9f47" sha1="ce29ff00cf4b6fdd9b3b1ed87823534f1d364eab" region="gfx" offset="1000004"/>
  	 <rom names="vm3.20m" size="4194304" crc="c22fc3d9" sha1="df7538c05b03a4ad94d369f8083799979e6fac42" region="gfx" offset="1000006"/>
  	 <rom names="vm3.01" size="131072" crc="f778769b" sha1="788ce1ad8a322179f634df9e62a31ad776b96762" region="audiocpu" offset="0"/>
  	 <rom names="vm3.02" size="131072" crc="cc09faa1" sha1="2962ef0ceaf7e7279de3c421ea998763330eb43e" region="audiocpu" offset="28000"/>
  	 <rom names="vm3.11m" size="4194304" crc="e80e956e" sha1="74181fca4b764fb3c56ceef2cb4c6fd6c18ec4b6" region="qsound" offset="0"/>
  	 <rom names="vm3.12m" size="4194304" crc="9cd71557" sha1="7059db25698a0b286314c5961c618f6d2e6f24a1" region="audiocpu" offset="400000"/>
  	 <chip type="cpu" tag="maincpu" name="68000" clock="16000000"/>
  	 <chip type="cpu" tag="audiocpu" name="Z80" clock="8000000"/>
  	 <chip type="audio" tag="qsound" name="Q-Sound" clock="4000000"/>
  	 <display type="raster" rotate="0" width="384" height="224" refresh="59.629403" pixclock="8000000" htotal="518" hbend="64" hbstart="448" vtotal="259" vbend="16" vbstart="240" />
  	 <sound channels="2"/>
  	 <input players="2" buttons="6" coins="2" service="yes">
  		 <control type="joy8way"/>

I highlighted the rom names & memory uses accordingly. We now have a basic understanding of which type of data is in each file;

I shared a few examples of MAME’s extremely powerful commands. There is so much more it can do, like watchpoint & step over. MAME’s official documentation is here;

VSAV(.ZIP) Analysis

GOAL: Assess data

We are going to unzip the Game Files. I chose to navigate to the MAME > roms directory. Now Right Mouse Click & Extract All… then open the new folder.

These (22) files represent the entirely of bytes needed to run the game. Notice how the file names of “vm3” match the (20) file names listed within the -listxml exercise. These are encrypted binary files. This data is in 'BINARY FORMAT.

Here is a table for reference:

File Name Memory Use File Size Memory Range Encryption
vm3e.03d Main C.P.U. 524288 Bytes 0x000000 - 0x07FFFF Byte Swap 12 34 = 21 43
vm3e.04d Main C.P.U. 524288 Bytes 0x080000 - 0x0FFFFF Byte Swap 12 34 = 21 43
vm3.05a Main C.P.U. 524288 Bytes 0x100000 - 0x17FFFF Byte Swap 12 34 = 21 43
vm3.06a Main C.P.U. 524288 Bytes 0x180000 - 0x1FFFFF Byte Swap 12 34 = 21 43
vm3.07b Main C.P.U. 524288 Bytes 0x200000 - 0x27FFFF Byte Swap 12 34 = 21 43
vm3.08a Main C.P.U. 524288 Bytes 0x280000 - 0x2FFFFF Byte Swap 12 34 = 21 43
vm3.09b Main C.P.U. 524288 Bytes 0x300000 - 0x37FFFF Byte Swap 12 34 = 21 43
vm3.10b Main C.P.U. 524288 Bytes 0x380000 - 0x3FFFFF Byte Swap 12 34 = 21 43
vm3.10b 0x0139DB extra space Not Applicable 0x3EC624 - 0x3FFFFF Byte Swap 12 34 = 21 43
vm3.13m Graphics
vm3.15m Graphics
vm3.17m Graphics
vm3.19m Graphics
vm3.14m Graphics
vm3.16m Graphics
vm3.18m Graphics
vm3.20m Graphics
vm3.01 Audio C.P.U.
vm3.02 Audio C.P.U.
vm3.11m Qsound
vm3.12m Qsound
qsound.bin Emulator required data
vsav.key Emulator required data

Shared R.A.M. Bug

While investigating a well documented Alter-Ego Reduction Bug, I noticed all of the interactions were using moves and move properties unique to their character.

Character Applicable Moves
Lei-Lei Chuukadan, Tenraiha
Bulleta ES-Pursuit (Apple Explosion)
Lilith D.F. Deactivation
Felicia D.F. Helper (Leaving the screen)

While investigating the R.A.M., I had no findings in PL1 R.A.M. Data & PL2 R.A.M. Data ranges;

  • PL1 R.A.M. Data; FF8400 to FF87FF
  • PL2 R.A.M. Data; FF8800 to FF8BFF

All of these unique moves had to be documented somewhere else! The logical place for Unique Player Data is directly after Standard Player Data ranges. By observing values in a New Memory Window, I confirmed that the theory is correct. The allocated ranges are now:

  • Game R.A.M. Data; FF8000 to FF80FF
  • Match R.A.M. Data; FF8100 to FF83FF
  • PL1 R.A.M. Data; FF8400 to FF87FF
  • PL2 R.A.M. Data; FF8800 to FF8BFF
  • Unique Player R.A.M. Data; FF8C000 to ??????

Lastly, by visualizing memory beginning at FF8C000 & doing all of the moves listed with the bug, it is revealed that all moves interact in the same address range of R.A.M.; 0xFF9400 to 0xFF94FF. My results were tweeted here;
  • Shared Player R.A.M. Projectile Data; FF9400 to FF94FF

Memory Map

A MEMORY MAP is a table which lists all addresses and their uses. As of the time I am writing this, the collective understanding of VSAV’s MEMORY MAP is available across numerous platforms:

  • Pugsy’s Cheat file
  • Pugsy’s Cheat Forums
  • Felineki’s notes
Thanks for sharing with me!
The Cutting Room Floor:
  • VSAV Training Mode script
  • ChooseaGoose’s notes
Thanks for sharing with me!
  • A custom cheat file shared by VMP_KyleW
  • XenoBlip’s Notes (Data is not verified!)

There is an opportunity to centralize this data, making it publicly available & publicly enabled to contribute.

Review Goals & Questions

Now that the lessons & workflows are complete, let’s do a final review of my project's goals & the outstanding questions.


Find hidden content
Unlock hidden content; Characters, Stages, Moves, Colors, Debug Menu
Further Explain Bugs
Understand how the CPU can do special moves in situations a player cannot
  • This concept was proven by understanding the POINTERS needed to command characters to do special moves. Once I knew these POINTERS, I was able to visualize the memory and confirm a CPU controlled opponent activates special moves by directly changing these POINTER values, rather then giving necessary controller inputs to execute special moves. Forcing these POINTERS causes unique results, such as removing restrictions of when specials can be executed as well as not requiring the meter necessary to complete an ES-Move.


Where are OVERFLOW values coming from?
  • This is unique per instance, The Program Data needs to be evaluated to understand each answer. A full Disassembly of the MACHINE CODE is needed.
Is there R.A.M. values that remain during unique game “modes”?
  • Open up the Debugger’s New Memory Window to visualize where these changes occur. Some values, such as which character you are using & what conditions are met to fight the Mid-Boss and Oboro are stored between matches.
How to determine if the address is in POINTER, FLAG, INCREMENT or DECREMENT format?
  • We can assess each case individually by manipulating R.A.M. and verifying results. However, the MACHINE CODE specifies the length of values per operation, a full Disassembly of the MACHINE CODE is needed to develop this answer.

Findings in R.A.M.

  • RAM Manipulation to access colors 0x08 & 0x09
  • RAM Manipulation to access unlisted Color Palettes
The RAM location for allocating P1 or P2's color is the last (2) digits of a hexadecimal number, so there are 256 possible variables; most of which are horrendous, but some real gold exist!
  • RAM Manipulation to access unintended stages
Black & DF-Enabled
Character Select
  • RAM Manipulation to access Mid-Boss variant stages
Iron Horse Iron Terror
Fetus of God
  • RAM Manipulation to access a hidden title screen
  • RAM Manipulation to play as D.F. Zabel
  • RAM Manipulation - Versus Screen Transitions Mid-Fight
  • RAM manipulation to force Character Intros
  • RAM & Win-Lose Checks
  • RAM & Hidden Menu Option
  • RAM & Special Boss Requirements
ES-Finished -
Lose a Bat -
  • RAM & Variables at Character Select Screen
  • RAM & PL1 MO/LI Remove Projectile Restrictions
  • RAM & CPU Special Moves as Instruction
  • RAM Manipulation - Verify Dizzy Bug Setups
  • RAM Manipulation - Stage assets & Wheels at Iron Horse Iron Terror
  • RAM Manipulation - Victor's Unused Functional Special Moves
  • RAM Manipulation - Anakaris's unlisted Special Moves
  • RAM Manipulation - Special Move Graphical Pointer Oddities
  • RAM Manipulation - Special Move Pointers
  • RAM Manipulation - Verify All Win-Poses
Jedah & Lilith
Lei-Lei & Q-Bee
Bishamon & Felicia
Gallon & Victor
Bulleta & Demitri
  • RAM Manipulation - Verify custom Intros
Jedah & Felicia
  • RAM Manipulation - Verify missing throw commands
  • RAM Manipulation - Enable a CARD system for collecting carnival style tickets
  • RAM Manipulation - Instantly fight Oboro with special ending conditions
  • RAM Manipulation - D.F. Details
  • RAM Manipulation - Shared RAM address details


To achieve a portion of my initial goals, the 'Disassembly of the MACHINE CODE is required. The output of this task is the total information of:

  • Where values are READ
  • Where values are WRITE
  • When values are READ
  • When values are WRITE
  • What values are READ
  • What values are WRITE

It’s not easy! All operations are listed in unique code directly relating to the PROCESSOR; the Motorola 68K. Each operation is a sequence of numerous calculations. When this is done, we obtain all of the MACHINE CODE instruction. We can begin to assume the actual PROGRAM SOURCE CODE. I’ve read in some forums that the CPS-II is believed to be written in Donald Knuth’s C Programming Language.

Just recently a freeware disassembler, developed by the NSA, called GHIDRA, became open-source as of March 2019. This Disassembler software is compatible with the Motorola 68K. (Thanks for the recommendation Zinac!)

One of my next projects is to begin the DISASSEMBLY task. Having a resource for understanding the M68K Machine Code is critical to the next leg of this project. I Highly recommend MarkeyJester's Beginner Tutorial. Have this site handy as you begin to learn the language.

R.O.M. Analysis

Binary Files & Decryption

Super THANK YOU to for mentoring me through this tasks!

The MAME Debugger tool has (2) exports we need to reference.

  • Within Mame's Debugger, run VSAV, then enter the following command.
DUMP VSAV-Word-Ascii.dmp,0,1000000,4,1
This command will create a (.DMP) within your MAME directory. This file is text enabled, you can read it with any notepad, wordpad, etc. Most importantly, this text file is the authoritative document for all of the bytes which are Data. This include ASCII text & reference tables. Although all byte values are represented, most are actually OpCode (Operation Code) which are further manipulated prior to feeding the M68K.
  • Within Mame's Debugger, run VSAV, then enter the following command.
DASM VSAV.asm,0,1000000
This command will create a (.ASM) within your MAME directory. This file is text enabled, you can read it with any notepad, wordpad, etc. Most importantly, this text file is the authoritative document for all of the bytes which are OpCode. This includes all instruction for the M68K. Although all byte values are represented, some are actually Data.

With these (2) references in hand, our next objective is to validate what is Data & what is OpCode. The following table depicts values of vm3e.03d. I chose these addresses because it's a combination of OpCode & Data, the Data is legible ASCII within the DUMP file, the OpCode is not legible ASCII.

Source vm3e.03d 0x000000 (OpCode) 0x000790 (ASCII Data) 0x07FFF0 (OpCode) Validation
Encrypted ROM DF23 746F 5542 2053 E53C 06A2 Encrypted
MAME DUMP 23DF 6F74 4255 5320 3CE5 A206 Data values are correct
MAME DASM 00FF 8000 7EBE 0483 0076 542E OpCode values are Correct

With the aid of , we found (4) tools which claim to decrypt CPS2 ROMS. I tested each tool, the results are presented in the table below.

Source vm3e.03d 0x000000 (OpCode) 0x000790 (ASCII Data) 0x07FFF0 (OpCode) Download Page Comment
X.C.O.P.Y. 00FF 8000 7EBE 0483 0076 542E Correct OpCode, Wrong Data
vsavdi FF00 0080 5542 2053 7600 2E54 Wrong Data, Wrong Opcode
CPS2dec FF00 0080 5542 2053 7600 2E54 Wrong Data, Wrong Opcode
SwapEndian 23DF 6F74 4255 5320 3CE5 A206 Correct Data, Wrong OpCode

While carefully reviewing both tables, nothing is an exact match, but, CPS2dec & vsavdi are both close! They need to be Byte-Swapped to completion. Luckily, the tool SwapEndian does the byte-swap function needed to complete the decryption. Use SwapEndian on the vsavdi file or after the CPS2dec tool & the decryption is complete!

Source vm3e.03d 0x000000 (OpCode) 0x000790 (ASCII Data) 0x07FFF0 (OpCode) Comment
(vsavdi or cps2dec) then SwapEndian 00FF 8000 4255 5320 0076 542E values are correct!

Now that we have a workflow for this unique hybrid-decryption, it's time to decrypt the first (8) files, then concatenate (add together linearly) each file in a HexEditor program to create a single binary file of decrypted bytes.

Here is a download link, of the completed file, for your convenience.

This file will properly load into a disassembler program like IDA-PRO or Ghidra!

Software of Interest

Diagnosing, analyzing and labeling Read Only Memory is best enabled with specific software solutions. This process is most commonly referred to as reversing. Ghidra, IDA-Pro & custom programmed tools are the most common software solutions for reversing the M68K language.

When you load the concatenated binary, described in section #3.1 titled Binary Files & Decryption, into your reversing software of choice, do not allow the program to auto-disassemble the M68K language. For VSAV and any other M68K language based game, the out-of-the-box auto-analysis options are not effective. Your entire platform will be overpopulated with so much incorrect analysis that you may as well start over.

Starting Line

The best place to start analyzing the ROM is the VSAV(.ASM) file created within section #3.1 titled Binary Files & Decryption. This (.ASM) file is a text format, legible in most raw text readers like Notepad or WordPad. Within this file, every OpCode (Operation code, or, Operation instruction) is provided and described. Please be aware that Data Structures and Data Tables are not processed as instructions and therefore return an ILLEGAL description or an OPCODE # description within the (.ASM) file.


There are too many RAM variables and ROM functions to discover within the binary that we must limit the scope of investigation and only focus on our own goals. A complete disassembly is an extremely unrealistic goal for a single individual.

Exercise #12 - Functions

Goal: Define a function within your disassembler

Functions are isolated portions of instruction that complete a particular task. Function are the building blocks to understanding how the game manages the RAM and is critical to any goal. The following exercise will use the working example of the Meter Stock Value in RAM to ultimately locate and define the ROM function for meter stock gain. We know that Player One’s meter stock Value resides at Address 0xFF8509 because of the original cheat file. Our task is to go to MAME Debugger and do a WATCHPOINT for that Address. This will stop game play when the Address is written to and allow us to investigate the context in which that write occurred. As soon as a battle starts, give the following debugger command:

Wpset FF8509,1,w

Now play the match & attack the opponent, using player one, until you gain a meter stock. When the watchpoint command activates, it will say “stopped at watchpoint #1 PC=29A70 & DATA=1”. This means that the line of instructions stopped at is 0x29A70 & the Value of Address 0xFF8509 was equal to 0x01. Before you press F5 to proceed past this watchpoint, take a look at the Machine Code window, as reference in section #1.10, titled MAME DEBUGGER. Be aware that the Watchpoint stopped at the step immediately after the Address trigger condition was met. This means that the Address of interest is actually the line of instruction just before 0x29A70, which is Address 0x29A6C.

With this information at hand, open VSAV(.ASM) and go to line #0x29A6C. You will find the following text:

  • 029A6C: 522E 0109 addq.b #1, ($109,A6)
  • Address: Value instruction (RAM Address of instruction)

The OpCode, starting at 0x29A6C, is 8 total bytes with a Value of 0x552E0109. These bytes are interpreted by the M68K processor as an instruction to Add a Quick Byte of 0x01 to (Address register #6 +109).

What is Address register #6?

Looking at the lower left hand side of the Mame Debugger tool, we see the REGISTERS window pane per section #1.10.3. Just next to the text A6, the Value of 0x00FF8400 is depicted. This means Address Register #6 is equal to 0xFF8400 and the actual Value of the instruction is 0xFF8400 + 0x109. That Address adds up to be 0xFF8509, which is the same location we gave in the Watchpoint command.

The following statement is not always accurate, but does generally hold true for VSAV. For most in-battle functions, A6 is equal to 0xFF8400, the Address of Player-1’s start of RAM. For most in-battle functions, A4 is equal to 0xFF8800, Player-2’s start of RAM.

Now that we found the instruction within VSAV(.ASM), let’s disassemble and document our findings within our disassembly software of choice. I’m only personally familiar with Ghidra, but the concept will apply to all software.

Within Ghidra, select on the data beginning at Address 0x029A6C and give it the manual disassembly command, this is the keyboard's D key by default. The program will interpret all bytes, starting at 0x029A6C, as M68K instruction until it reaches data that is not specifically M68K instructions or is directed to leave/complete that area of binary.

Secondly, select the OpCode at 0x029A6C and add a comment to say that '($109, A6) is actually equal to 0xFF8905' which is really the RAM Address for managing Meter Stock. By commenting on the interpreted binary, we leave harmless notes to ourselves. These are helpful for documenting our findings.

0xFF8905 = Meter Stock Value

We have now disassembled and documented a single occurrence of the Meter Stock reference within the OpCode. Our next goal is to locate then disassemble then label every other location in the OpCode that references this same RAM Address. The easiest way to locate all of the OpCode Addresses is to use the search command CTRL+F within the VSAV(.ASM) file. Search for the following string:

  • ($109,A6)

Take note of all Addresses where this instruction is called. There are nearly 60 instructions that directly reference this Address! It is a lot of work to locate, disassemble and comment on every relevant instruction as you find them, but I promise the hard work will pay off when you start to investigate other functions and relevant RAM Addresses are already documented within your disassembly software.

To continue investigating the Meter Stock function of VSAV, let’s go back to Address 0x29A6C within VSAV(.ASM) & find the start of the function.

The beginning of the function will be a bit before that instruction was given. Scroll up on the text file until you see any line of instruction interpreted as ILLEGAL or OPCODE #. These lines are DATA. This example line of DATA is at Address 0x29904. We need to give the command for a manual disassembly at the instruction just after the ILLEGAL or OPCODE # Address. The OpCode Address of interest is 0x29906.

Complete this task for all ~60 locations identified as likely referencing the Meter Stock RAM address.

Back to our example, the manual disassembly at 0x29906 uncovered (5) functions between that location and our location of interest, 0x29A6C. The function at 0x29A16 is the nearest one to our Address of interest and is in fact the beginning of the Meter Stock function. Name the function as “Meter Stock Gain”.

Every RAM Address referenced within this function is critical to the working of this function!

What RAM Addresses are referenced within the Meter Stock Gain function?

  • ($3B2, A6)
  • ($109, A6)
  • ($111, A6)
  • ($4, A6)
  • ($6, A6)

The next objective is to tap into your game knowledge and your MAME Debugger Watchpoint skills to determine what the RAM Address definitions are for each of these. Don’t forget to comment on them as you understand their uses. Use your game knowledge and the concepts of your current task to make context based guesses and checks for definitions. Yes, this is a lot of work.

Here are the answers:

  • ($3B2, A6) = Auto-Guard Flag
  • ($109, A6) = Meter Stock
  • ($111, A6) = Dark Force Flag
  • ($4, A6) = Player Status #1
  • ($6, A6) = Player Status #2

Continue this task until all of the RAM Addresses are defined and you are certain of the starting location & definition of the function you are investigating.

Data Types

Why can’t reverse engineering software just decipher all of the opcode? Simply put, the computer software cannot distinguish between data and opcode. Remember, the computer is reading binary. The Value 0x10101010 might be the beginning of sprite data, or it could be a processor instruction. This creates ambiguity in the parsing, and today’s software solutions for M68k do not have the ability to overcome it. This is where our manual work begins. As we delve into disassembling and following how the ROM is interacting with the CPU, we have to understand that context is important: What Values are in the registers? In RAM? What are the next ROM instructions doing with the Values it reads or writes? All of this context allows us to properly define the Data Type and be able to translate the binary. Data has a reason which it’s stored or read from memory. The Value can be set to anything, but the process that reads that Value assumes context. This is how data types work. The Value at a memory location is what it is, but through the lens of that context it may be used for vastly different purposes. That data could represent the number 3 or a pixel color on an image or the character C, for example, in memory it’s still saved as the same Value. The common Dissassembler Data Types you’ll need to work with are Strings, Lists and Jump Tables. We’ll have working examples of each but for now, it’s important to understand that a Data Type vastly changes the use of the Data, even if the Value is the same.

Here is a resource for Data Types in C, which are mostly referenced within Ghidra, as Ghidra tries to compile the disassembled Machine Code into a higher level language like C.

Exercise #13 - Strings

Goal: Define a String within in your disassembler

Strings are binary Values designed to be interpreted as legible text. This is common for numerous aspects of CPS2’s data, so let’s discover how to recognize and define Strings. The following exercise will use the working example of the Game End Credits to define Data as a Ghidra Data String. Within your disassembly software of choice, locate Address 0x13012. It is highly likely that the bytes of data are already being translated as a String in the primary data visualization window. Is any data legible? Here is a screenshot from my Ghidra:

VSAV String1.png

We can clearly see the text Vampire Savior Staff within the image for the Address range of 0x13012 through 0x13025. Select that entire Address range and allocate that data as a STRING. Within Ghidra, DS designates the data type as a Data String, as seen in this example.

VSAV String2.png

Now that you know the process, the next goal is to scroll through the entire data and define all data that is legible. Here is an example of data defined as a Data String within VSAV.

VSAV String3.png

Exercise #14 - Jump Tables

Goal: Define a Jump Table within your disassembler.

Jump Tables are a list of Values used to jump the current instruction to a specific portion of the Machine Code. It is very common for animations to use a Jump Table as most attacks have sequences. Attack animations have start-up, active and recovery frames while each portion may have unique properties. To better understand and define a Jump Table, the following exercise will use the working example of Q-Bee’s Homing Air-Dash function to define Data as a Ghidra Jump Table.

Jump instructions start with bytes 0x4EFB. Additionally, the Jump instruction always proceeds with a portion of OpCode data which is a referenced table of Values. Start at Address 0x23410 and do a manual disassembly command within your software of choice. This Address is the beginning of the function of Q-Bee’s Homing Air-Dash, name the function while you are there. The manual disassemble will discover all M68K instructions up to Address 0x2351C. This instruction is a JUMP instruction followed by reference data. Here is my Ghidra Example:

VSAV JumpTable1.png

The Jump instruction is ultimately telling the processor to jump ahead in the code to a specific destination, based on the results of a variable.. The forgiving thing about this reference data is that the first Value tells the jump command to proceed to the code immediately after the reference data. Lucky for us, that offset Value also tells us the total size of the Jump Table. 0x23520 + 0x0008 = 0x23528.

Place your cursor at 0x23528 and do a manual disassembly command. Here are my results within Ghidra:

VSAV JumpTable2.png

Because the instruction at 0x23518 is looking for a WORD, we know that this Jump Table represents (4) possible WORDS of data that can calculate the offset destination of the Jump instruction. The (4) destinations associated to this Jump Table are:

  • 0x23520 + 0x0008 = 0x23528
  • 0x23520 + 0x002E = 0x2354E
  • 0x23520 + 0x0244 = 0x23764
  • 0x23520 + 0x0254 = 0x23774

Select OpCode 0x23520 through 0x23527 and define it as a Jump Table - (4) Destination WORD. Here is my Ghidra for this exercise:

VSAV JumpTable3.png

Take this lesson and apply it to all Jump instructions that you come across while discovering your own goals.

Exercise #15 - Lists

Goal: Define a List within in your disassembler

Lists are similar to a String, but the values are intended to be interpreted as exclusively numbers. Let’s define a List. The following exercise will use the working example of Random Select’s character choices to better understand a List.

Navigate to Address 0x20C38 within your disassembly software. Complete a manual disassemble command and label this function as CHAR-SEL_Input-Check_K+K. This function is responsible for assessing the input of two kick attacks during Character Select.

Notice that Address 0x20C56 has the instruction as:

4E 75 rts

This is a very common instruction which means Return To Subroutine. It’s a way of completing a function then telling the processor to go back to the previous Address right before it was directed to this function.

This means that Address 0x20C58 likely starts lines of instructions for a broader function. This is a true statement for our example. That function is actually the Main Character Select function. Manually disassemble the code at 0x20C58 and you will auto-define instructions until Address 0x20C88. Take a look at the instruction for Address 0x20C80. It instructs the processor to move a byte of data to RAM Address ($382, A6). 0xFF8782 is the Address of the player’s character ID.

The data referenced a span style="color:#FF0000">List and the size in bytes.

This example of a List is actually a series of Character ID values that are read in sequential order. This represents the "Random" character during character select. This List resides in the Address range of 0x20C88 through 0x20C97.

VSAV Lists1.png

How did we determine the length of this List? Unlike the Jump Table, there is no direct answer as to what the final length of the List is. Quantifying a Lists’ length is a problem to solve using context, guess + checking and lastly, a recognition of the M68K instructions.

To further explain this exercise using those three lenses, we know that this Data represents Character ID values. There are only (18) characters in VSAV, so we would not be seeing Character ID values that are larger than the highest known Character ID values of 0x18. The instructions at Address 0x20C98 begin with the Value 0x4A. This number is much larger than any anticipated Character ID Value.

Another way to quantify the size of the List is to recognize a M68K instruction. There are a handful of common instructions that begin after a List. By recognizing those instructions, we can attempt to do a manual disassembly at expected values to assess if the results are logical. In my experience, some common instructions following a List include:

  • 4A 2D = Test Byte
  • 4A 2E = Test Byte
  • 54 2C = Add Byte (Quick)
  • 54 2E = Add Byte (Quick)
  • 54 6D = Add Word (Quick)
  • 0C 2E = Compare Byte
  • 10 2E = Move Byte
  • 1D 40 = Move Byte
  • 4E B9 = Jump to Subroutine
  • 42 2C = Clear Byte

The final detail to aid in the diagnosis of the length of a List, is that all instructions begin on even number addresses. Lists can only complete on addresses ending in 0x1, 0x3, 0x5, 0x7, 0x9, 0xB, 0xD, & 0xF.

R.O.M. Manipulation

We diagnosed & labelled RAM values, ROM Functions, Jump Tables, Strings and Lists. We now know all the inner workings of the code. What’s next? ROM Manipulation.

This example will discuss the method for accurately manipulating/modding/hacking a rom set, but needs to be in the context of your own goals. This section aims to share the process & means of achieving successful ROM manipulation.

The first two steps of ROM manipulations are highly contextualized. You need to answer the following questions;

  1. What are your goals?
  2. What type of code are you trying to change?

The goals inquiry gives direction for the actual changes of M68K instructions, but the second question will impact the sequence in which a change is made.

When altering a rom set for a manipulation/mod/hack project, we must start with the unaltered encrypted rom set that plays in any emulator. Do not start with the hybrid-decrypted rom set we previously used to load into the disassembly software from section #3.1 titled R.O.M. Analysis - Binary Files & Decryption.

OpCode Manipulation

OpCode exists as ENCRYPTED data within the original rom set files. The first task to change ROM value is to locate which file and address within that file is the location of interest.

Once you deduced the location within the specific file, based on the table from section #2.11 VSAV (.ZIP) Analysis, we need to DECRYPT that file.

There are (2) software solutions for decrypting the CPS2 rom set; X.C.O.P.Y. & a specialty package built for Radar2, courtesy of the legendary Pof.

I work on a Windows operating system, so I prefer the X.C.O.P.Y. method.

Open X.C.O.P.Y., select the game (VSAV), specify the file of interest & make sure the field for DECRYPT is populated. The output of this program is a DECRYPTED version of the same file.

We now need to Byte-Swap the new file. The software solutions I prefer for byte-swapping a file is called SwapEndian(.EXE).

Run SwapEndian as referenced within section #3.1 titled R.O.M. Analysis - Binary Files & Decryption.

You can now load this file into any Hex-Editor program, I prefer Frhed, to directly make changes to the instructions of OpCode that meet your own goals. You will have to have a basic understanding of the M68K language to know what new instructions are required. OpCode instructions for locations within the code are mostly relative. This means if you increase the total file size that you inadvertently ruined all of the downstream absolute references. Do not inflate or decrease the total file size!. All changes must be a one-to-one replacement of existing instructions. The only exception to this rule is if you purposefully make a Jump instruction to the very end of the available RAM space, add new instructions then complete with a 0x4E75 command, Return To Subroutine.

Once your changes are complete, run SwapEndian then X.C.O.P.Y. again to re-encrypt your file.

Data Type Manipulation

Lists and Strings exist as Decrypted data within the original rom set files. The first task to change these types of ROM values is to locate which file & what address within that file the location of interest resides.

Once you deduced the location within the specific file, based on the table from section #3.1 titled R.O.M. Analysis - Binary Files & Decryption, we need to Byte-Swap that file. The software solutions I prefer for byte-swapping a file is SwapEndian(.EXE).

Run SwapEndian as referenced within section #3.1 titled R.O.M. Analysis - Binary Files & Decryption.

You can now load this file into any Hex-Editor program, I prefer Frhed, to directly make changes to the Data Type that meet your own goals. OpCode instructions for locations within the code are mostly relative. This means if you increase the total file size that you also inadvertently ruined all of the downstream relative references. Do not inflate or decrease the total file size. All changes have to be a one-to-one replacement of existing data.

Once your changes are complete, run SwapEndian(.EXE) again to re-align your file.

Holistic Manipulation Overview

  1. Start with the encrypted rom set
  2. Decrypt with X.C.O.P.Y
  3. ByteSwap with SwapEndian
  4. Add all modifications to OpCode
  5. ByteSwap with SwapEndian
  6. Encrypt with X.C.O.P.Y
  7. ByteSwap with SwapEndian
  8. Add all modifications to your Data/Data Type
  9. ByteSwap with SwapEndian

Reversing an existing Mod/Hack Project

With a full understanding of the ROM manipulation workflow and our own software disassembly solution, we now have the means to reverse engineer an existing Mod/Hack project.

To analyze OpCode changes, use X.C.O.P.Y. then SwapEndian to decrypt and swap a Mod/Hack project file as well as the same file within an unaltered rom set. Rename these files to have an extension of (.BIN)

Obtain WinMerge ( and load both (.BIN) files. This neat little program will compare the data of (2) (.BIN) files and only highlight changes between the files. While assessing these changes, be aware that you are only assessing OpCode. Our Predefined Data Types are misrepresented in this configuration. You will need to reference your own disassembly software, as well any literature provided from the original author to place context to the addresses highlighted by Winmerge.

Once the changes have been assessed and understood, run a similar exercise to compare their changes in Data Types.

To analyze the Data changes, use SwapEndian to byte-swap a Mod/Hack project file as well as the same file within the unaltered rom set. Rename these files to have an extension of (.BIN).

Load both (.BIN) files into WinMerge. This program will compare the data of (2) (.BIN) files and only highlight differences between them. While assessing these differences, be aware that you are only assessing Data Types. OpCode is misrepresented in this configuration. You will need to reference your own disassembly software, as well any literature provided from the original author to place context to the addresses highlighted by Winmerge.




  • Leverage DarkSoft hardware to rewrite the binary files and play a graphics modifications on native CPS-II hardware.
  • Created & shared tools for interfacing graphics.


  • Published a custom CHEATS file representing R.A.M. manipulation efforts.
  • Explained the Alter-Ego Reduction Bug & clarified it as a Shared Ram Bug
  • Found a hidden move for Victor, from Night Warriors - Jed documented another attack in 2014.


  • Custom burnt an EPROM, essentially creating a “Software Patch” to emulate training mode on CPS-II hardware
  • Published a custom (.LUA) scripts for VSAV Training Mode
  • Provides addresses for character color manipulation


  • Documented hidden, unfinished and cut content on T.C.R.F.
  • Explained the infamous Dizzy Bug as an improper underflowing conditions


  • Published a custom (.LUA) scripts for VSAV Training Mode. This is built on top of Jed's initial work which adds significant more features.



  • Training Mode Hack, including random stage variants


  • Aesthetic Mod v1.3
  • Boss Hack
  • Test Menu Mod
Vampire Savior
General FAQHUDControlsTraining ModesCommunity Info/Find Players!GlossaryLinks
Characters AnakarisAulbath (Rikuo)BishamonBulleta (BB Hood)DemitriFeliciaGallon (Talbain)JedahLei-Lei (Hsien-ko)LilithMorriganQ-BeeSasquatchVictorZabel (Lord Raptor)
Mechanics EsotericsDark ForceCommand SupersRenda BonusTutorialSecrets
Other Extra CharactersJapanese Test MenuVampire Savior 2 ChangesVampire Chronicle ChangesPlayersHacksReverse Engineering