Hello, as some of you may know, I have been reverse engineering Virtua Racing to see how the SVP works myself. It is currently known that it's an SSP1601 chip running a custom ROM that generates Mega Drive tile data from model data and that the 68000 can directly access the SVP's DRAM (which is mapped at $300000 on the 68000 side). The chip's XST register can also be directly written to at $A15000. However, I wanted to see how this specific ROM worked. Here are my current findings: $300000-$305FFF - Tile buffer #1 $306000-$30BFFF - Tile buffer #2 $30EC00-$30FBFF - Model/camera data $30FC00-$30FDFF - Sprite data $30FE00 - Screen mirror flag $30FE02 - Command finished flag $30FE04 - Tile buffer address $30FE06 - Command sent flag $30FE08 - Command ID $30FE10 - Command parameter (SEGA logo sequence frame ID, title screen end transition sequence frame ID) The SVP is initialized by clearing DRAM and setting the XST to the string "OH" and disabling the chip's so called "halt flag" (referenced from the current SVP documentation as of November 2018). A command is handled by setting the "sent flag" to a nonzero value and then setting the command ID and then checking the "finished flag" to see if it's nonzero. Here are the command I have documented: 0 - Invalid 1 - Communication test 2 - Render models and sprites (with camera, used by Virtua Racing mode and Free Run mode in Virtua Racing) 3 - Render models and sprites (with camera, used by during Virtua Racing mode when the goal is reached or a game over has happened) 4 - Renders models and sprites (with camera and split screen, used by the 2P VS. mode in Virtua Racing) 5 - Render SEGA sequence (Used by the SEGA screen in Virtua Racing) 6 - Render models (with camera, used by the title screen in Virtua Racing, also renders the Virtua Racing logo close-in transition for the end of the title screen) 7 - Render the "VR" texture (used by the ending of the title screen sequence) 8 - Render models and sprites (with camera and course ranking table taking up the first 6 sprite slots, used by the title screen in Virtua Racing) 9 - Render models (Has smaller position range, but more precision, used by the mode select screen in Virtua Racing) $A - Render models and sprites (with camera, used by the instant replay in Virtua Racing) $B - Render models and sprites (with a fixed camera, used by the instant replay in Virtua Racing) $C - Render models (with camera, has smaller position range, but more precision) $D - Invalid $E - Invalid $F - Invalid When a command is sent and completed, a DMA transfer can be done directly from DRAM to VRAM. Virtua Racing uses double buffering using the tile buffers as seen above so after each transfer, it swaps the buffer to use. The buffer is not cleared by the SVP, so it must be done manually by the 68000. As for model data, in commands 4 and 6, the first model slot is generally the main camera and can also render the main map. Commands 5 treats the first slot like any other model. Command 5 is special, as the placement of the SEGA models are done by the SVP itself and where they are is determined by $30FE10, which gets constantly incremented every frame. In command 5, the only other movement that can be applied is Z axis rotation. For each model, it uses $40 bytes of DRAM for its variables, and this is what I have found so far (it also applies to the camera): $00 - Visible flag $02 - X position $04 - Y position $06 - Z position $08 - X angle $0A - Y angle $0C - Z angle $26 - Model data pointer (which is divided by 2 because the SVP handles things by words instead of bytes, and typically OR'd with $8000000 to handle autoincrement on the SVP's side) For each sprite, it uses $10 bytes of DRAM for its variables, and this is what I have documented: $00 - Visible flag $04 - X and Y position (00YY YYXX XXXY YYYX in binary, note X position is divided by 4 here) $06 - Sprite data pointer (same format as a model data pointer) The model format is very simple. The first word is just the poly count minus 1, and what follows is the actual poly data. The first 2 bytes for each poly are a set of flags. The high byte handles the colors of the poly. A poly can have up to 2 colors, which are dithered together. Each nibble is a palette index. The low byte is a set of flags with the following bitfield: 0CDS0000 S - Shape (0 = square, 1 = triangle) D - Dithering pattern (0 = vertical line, 1 = checkerboard) C = Backface culling flag (0 = off, 1 = on) Then for each vertex, it's just its X position, Y position, and Z position, all being signed word values. 4 vertices for a square poly and 3 for a triangle poly. For sprites, its format is also rather simple. The first word is the width of the sprite divided by 4 minus 1. The second word is the height of the sprite minus 1. This means sprites can only have widths that are multiples of 4. The rest is the actual pixel data, which is generally formatted like a bitmap, while also still using the same pixel format as the Genesis (meaning that each byte still represents 2 pixels with each nibble being a palette index). The way I formatted the ROM to make this run was to change the header up a little and implement the DSP ROM and debugging functions. I changed the local and international names to be like in Virtua Racing and put "53 56 00 00 20 00 04 00" at $1C8 in the header as well. I then ripped the DSP ROM and debugging functions (located at $800 and ends at $1FFFF in Virtua Racing) and padded from the end of the header to $800 and put the data at $800. Also, some other notes, mainly regarding previously stated information I found in the past, including Sega Retro: As far as I know, there is no texture mapping supported at all for polygons. Same for lighting, seeing as it's only kinda simulated by the colors and dithering set on certain polygons. The SVP wouldn't seem to know what the palette was to try and calculate lighting. I'm highly unsure about "PWM audio" that I've read about on some websites, seeing as the audio pins on the Virtua Racing cartridge aren't even connected to anything. And that's all I have for now. I think it's generally enough to get something working at least, but there's still work to do.
So, command 2 is pretty much command 6, except it can render sprites! See updated OP for more information.
How exactly does one research this? Are you using an emulator? Are you disassembling the binary? I'm curious to begin my Model2 research, and aside from what the emulator spits out as save states, I would like to investigate it further but do not know how to approach it, especially if I do it at the hardware level for increased accuracy.
I disassembled Virtua Racing and its SVP code using the SSP1601 module for IDA found on the Picodrive emulator website. Also used some previously existing documention to help out along with lots of experimenting with writing to certain addresses.
I wonder if it's possible to make use of the SVP by plugging Virtua Racer into a homemade S&K-style cart.
That was the original plan for the SVP, wasn't it? A separate cart with the chip on that SVP-compatible games could plug into so they could keep prices down. As it turned out, not needed as there was only ever one SVP game.
I guess it helps when the chip being researched is also dumped with the cart. This isn't the case for Model2 and Model2 requires IDA pro and a processor tweaking which I have no idea how to do. Your method seems similar to what I've already done, and bit bashing is fun, no :specialed:?
So, I've been really digging into the actual SVP code for a bit with the help of IDA and the SSP1601 module that was released by Notaz (author of PicoDrive, which was the first emulator to emulate the SVP!), alongside previously existing documentation, and a debugging tool I created to trace execution. Things I've noticed so far: Alongside a 6 level hardware stack, the SVP also implements a software stack. My best guess is that they probably wanted to avoid wasting stack space, since there's only 6 levels. It dynamically loads code into IRAM. Obvious copy and pasted code in places (kek) Other things that were already documented but I still wanna bring up: One thing I find pretty neat about the SSP1601 is the ability to branch to a subroutine on a condition. (i.e. "call z=1,Label" will only call "Label" if the zero flag is set). The same thing applies to the "mod" instruction (used for bit shifting, negating, and getting an absolute value). For some reason, when it does multiplication, the result is multiplied by 2. You can store a pointer in a RAM bank and then use a RAM pointer and effectively use it like you would an address register on the 68000. Although, it always automatically increments. Also, I did see that previous documentation said that "PWM audio" was a thing on the SVP, but as far as I know, that's bullshit, as Virtua Racing doesn't even make use of the audio pins on the cartridge. Let's see where this leads up, shall we?
I've been using that as reference since the very beginning, and I used it to help create my SVP debugging tool. Unfortunately, it only really ever describes the SSP1601 instructions and register set in detail, and not really much of how it was programmed to achieve 3D on the Genesis, probably because they were just more worried about getting to even emulate at all correctly. (The best it does really is describe how memory is laid out in Virtua Racing and a little bit on some functionality)
As far as I know, no. I've only ever seen code that just sets the flag to 1 (which is set to DISABLE debug mode, lol) and moves on from there.
So, it turns out command 7 doesn't cause corruptions, but rather it's supposed to just render the one "VR" texture on screen for when the title screen sequence it about to end and loop back to the SEGA logo. Updated the OP. The reason why I thought it caused a glitchy mess before was that I tested the command outside of Virtua Racing, and thus, it was reading corrupt data. Also, command 6 also renders the transition from the title screen to the SEGA logo. (Where the Virtua Racing logo closes in on the screen).
Hello, newbie here! I'm working on my own implementation of the SVP chip inside Virtua Racing on an FPGA (so other people could use this to build their own games based on this architecture). In order to be able to test my design I was looking for alternatives for an assembler to be able to build test binaries and stuff. As the options were kinda scarce and I was just starting to learn Rust... I decided to build my own! It's kinda crappy and not very flexible, but here's the source code in case anyone in the community wants to do anything with it: https://github.com/jdesiloniz/ssp16asm I tried following more or less strictly the terminology of Samsung's samples available online, but I'll maybe take some time to relax that and accept the usual names associated with VR code (i.e.: PM0 instead of EXT0 for external registers...). Also, as of now I've only implemented the actual instructions used in VR and didn't add the extended parameters available in some of the Samsung samples (mostly used for shifting/adding carry in arithmetic ops, or using square for multiplications). Just hoping it's useful for your research, as on my behalf all the reverse engineering done in the last decade is being really useful for mine! Thanks a lot!
Awesome shit right there. I had my own SSP1601 macro set for use with ASM68K (in which was based off of Natsumi's Z80 macro set ) so I could assemble SSP1601 code a while back, but I'd have to dig that up and clean it up if I'd ever want to release it, but that's unlikely.
Thanks! For the missing pieces in my case I'm based on some docs I found on one DSP that seems to be heavily based on the Samsung SSP16XX family (i.e.: CD2450), and some of the sources from the original SSP16XX website that don't assemble with my current ruleset. Some of the instructions have either 3 or 4 operands, which was way confusing at first. In either case, those are never used by VR (and thus, not documented at all around the information related to the game). In any case I think it's amazing that the community here is taking the different route to try to understand how the game USED the DSP, rather than trying to emulate it. That opens the gates for people building new software based on this architecture rather than just limit ourselves to Virtua Racing over and over. My hope is that somehow, with the combined efforts of the community, people could build that software and even assemble new cartridges with that. I'm using a Cyclone V on my project but my guess is that when it's finished the design will fit far smaller FPGAs, as long as they have some DSP blocks and enough GPIO to communicate with the cartridge port of the Mega Drive/Genesis.