Difference between revisions of "Sega System C2 hardware notes (2003)"

From Sega Retro

(Created page with "{{unofficialDoc|source=http://cgfm2.emuviews.com/txt/c2tech.txt}} <pre> Sega System C2 hardware notes by Charles MacDonald WWW: http://cgfm2.emuviews.com Unpublished w...")
 
Line 2: Line 2:
  
  
<pre>
+
<pre>-------------------------------------------------------------------------------
 +
notaz's SVP doc
 +
$Id: svpdoc.txt 964 2014-09-23 00:27:41Z notaz $
 +
Copyright 2008, Grazvydas Ignotas (notaz)
 +
-------------------------------------------------------------------------------
  
Sega System C2 hardware notes
+
If you use this, please credit me in your work or it's documentation.
by Charles MacDonald
+
Tasco Deluxe should also be credited for his pioneering work on the subject.
WWW: http://cgfm2.emuviews.com
+
Thanks.
  
Unpublished work Copyright 2000-2003 Charles MacDonald
+
Use monospace font and disable word wrap when reading this document.
  
This document is in a very preliminary state and is subject to change.
+
updates:
Most everything within has been tested and verified on a System C2 board,
+
2014-09-23: minor additions about memory map
but please be aware that my testing methods or interpretations of results
+
2008-03-05: added a few notes about arithmetic op operands.
could be flawed. I can't guarantee that everything is 100% accurate.
+
2008-02-06: added Tasco Deluxe's correction about PMC register reads.
  
Table of contents
 
  
  1. 68000 memory map
+
-------------------------------------------------------------------------------
2. uPD7759
+
  Table of Contents
3. Video hardware and EPM5032 registers
+
-------------------------------------------------------------------------------
4. I/O chip
+
5. Hardware information
+
  0. Introduction
6. Jumper settings
+
  1. Overview
7. Connector pinouts
+
  2. The SSP160x DSP
8. Credits and Acknowledgements
+
    2.1. General registers
9. Disclaimer
+
    2.2. External registers
 +
    2.3. Pointer registers
 +
    2.4. The instruction set
 +
  3. Memory map
 +
  4. Other notes
  
----------------------------------------------------------------------------
 
68000 memory map
 
----------------------------------------------------------------------------
 
  
$000000-$0FFFFF : Data from EPROMs in EVEN0 and ODD0 sockets.
+
-------------------------------------------------------------------------------
  $100000-$1FFFFF : Data from EPROMs in EVEN1 and ODD1 sockets.
+
  0. Introduction
$200000-$7FFFFF : Reading or writing this area causes a lockup.
+
-------------------------------------------------------------------------------
$800000-$83FFFF : Protection register and video control.
 
$840000-$87FFFF : I/O chip.
 
$880000-$8BFFFF : uPD7759 interface.
 
$8C0000-$8FFFFF : Color RAM (1K, mirrored every 1K)
 
$900000-$9FFFFF : Mirror of $800000-$8FFFFF area.
 
$A00000-$BFFFFF : Reading or writing this area causes a lockup.
 
$C00000-$DFFFFF : VDP
 
$E00000-$FFFFFF : Work RAM (64K, mirrored every 64K)
 
  
The details of the protection register, video control register, I/O chip,
+
This document is an attempt to provide technical information needed to
and uPD7759 are explained later on.
+
emulate Sega's SVP chip. It is based on reverse engineering Virtua Racing
 +
game and on various Internet sources. Only some of the information provided
 +
here has been verified on the real hardware, so some things are likely to be
 +
inaccurate.
  
If any EPROMs are missing from the program ROM sockets the corresponding
+
The following information sources were used while writing this document
memory locations will return the prefetch value. For example:
+
and emulator implementation:
  
; Assume EVEN1/ODD1 missing
+
  [1] SVP Reference Guide (annotated) and SVP Register Guide (annotated)
        move.w  #$100000, d0    ; Read from second ROM pair
+
      by Tasco Deluxe < tasco.deluxe @ gmail.com >
        nop                    ; D0 = $4E71
+
      http://www.sharemation.com/TascoDLX/SVP%20Reference%20Guide%202007.02.11.txt
 +
      http://www.sharemation.com/TascoDLX/SVP%20Register%20Guide%202007.02.11.txt
 +
  [2] SSP1610 disassembler
 +
      written by Pierpaolo Prazzoli, MAME source code.
 +
      http://mamedev.org/
 +
  [3] SSP1601 DSP datasheet
 +
      http://notaz.gp2x.de/docs/SSP1601.pdf
 +
  [4] DSP page (with code samples) in Samsung Semiconductor website from 1997
 +
      retrieved from Internet Archive: The Wayback Machine
 +
      http://web.archive.org/web/19970607052826/www.sec.samsung.com/Products/dsp/dspcore.htm
 +
  [5] Sega's SVP Chip: The Road not Taken?
 +
      Ken Horowitz, Sega-16
 +
      http://sega-16.com/feature_page.php?id=37&title=Sega's%20SVP%20Chip:%20The%20Road%20not%20Taken?
  
The VDP is only accessible at specific addresses within the memory range
 
allocated to it. Reading or writing an invalid address will cause a lockup.
 
Here's a bitmask of the address bus to indicate which addresses are valid:
 
  
  MSB                  LSB
+
-------------------------------------------------------------------------------
110??000????????000rrrrr
+
  1. Overview
 +
-------------------------------------------------------------------------------
  
1 - Bit must be '1'
+
The only game released with SVP chip was Virtua Racing. There are at least 4
0 - Bit must be '0'
+
versions of the game: USA, Jap and 2 different Eur revisions. Three of them
? - Value does not matter
+
share identical SSP160x code, one of the Eur revisions has some differences.
r - VDP internal register ($00-$1F)
 
  
To my knowledge all games only access the VDP at $C00000-$C0001F, and do not
+
From the software developer's point of view, the game cartridge contains
use any of the mirrored locations.
+
at least:
  
For all memory within $800000-$9FFFFF, writing to even addresses has no
+
  * Samsung SSP160x 16-bit DSP core, which includes [3]:
effect and reading from them returns the MSB of the prefetch value.
+
    * Two independent high-speed RAM banks, accessed in single clock cycle,
 +
      256 words each.
 +
    * 16 x 16 bit multiply unit.
 +
    * 32-bit ALU, status register.
 +
    * Hardware stack of 6 levels.
 +
  * 128KB of DRAM.
 +
  * 2KB of IRAM (instruction RAM).
 +
  * Memory controller with address mapping capability.
 +
  * 2MB of game ROM.
  
----------------------------------------------------------------------------
+
[5] claims there is also "2 Channels PWM" in the cartridge, but it's either
uPD7759
+
not used or not there at all. European cartridge doesn't have audio pins
----------------------------------------------------------------------------
+
connected.
 +
Various sources claim that SSP160x is SSP1601 which is likely to be true,
 +
because the code doesn't seem to use any SSP1605+ features.
  
The System C2 board uses a NEC uPD7759 chip which can play back ADPCM
 
samples. It can use up to 128K of ROM directly, so additional bits are
 
provided through the I/O chip to control banking, allowing for 512K of ROM
 
to be used in four 128K banks.
 
  
Writing to any odd address within $880000-$8BFFFF will send the value to
+
-------------------------------------------------------------------------------
  the message input of the uPD7759. Reading any odd address returns $FF.
+
  2. The SSP160x DSP
 +
-------------------------------------------------------------------------------
  
The status of the uPD7759 /BUSY pin can be read through bit 6 of I/O chip
+
SSP160x is 16-bit DSP, capable of performing multiplication + addition in
port C. I don't know how the uPD7759 is reset, which apparently is necessary
+
single clock cycle [3]. It has 8 general, 8 external and 8 pointer registers.
when switching banks so the chip will re-read the header data at the start
+
There is a status register which has operation control bits and condition
of the bank.
+
flags. Condition flags are set/cleared during ALU (arithmetic, logic)
 +
operations. It also has 6-level hardware stack and 2 internal RAM banks
 +
RAM0 and RAM1, 256 words each.
  
----------------------------------------------------------------------------
+
The device is only capable of addressing 16-bit words, so all addresses refer
Video hardware and EPM5032 registers
+
to words (16bit value in ROM, accessed by 68k through address 0x84 would be
----------------------------------------------------------------------------
+
accessed by SSP160x using address 0x42).
  
An Altera EPM5032 EPLD device is used to control some aspects of the
+
[3] mentions interrupt pins, but interrupts don't seem to be used by SVP code
video hardware and provide a protection feature that games use to prevent
+
(actually there are functions which look like interrupt handler routines, but
bootlegging. It has the following pinout:
+
they don't seem to do anything important).
  
Pin    Type            Description
+
2.1. General registers
1      Input          /VSYNC from VDP pin 41
+
----------------------
2     Clock          53.693 MHz clock from OSC1
 
3      Output          Output to D1A input of 74LS08.
 
4      Output          To /BLANK input on color encoder
 
5      Output          Clock input of LS373 to latch color bus data
 
6      Output          To /SHADE input on color encoder
 
9      Input          68000 A8
 
10    Input          68000 /LDS
 
11    Input          Bit 7 of latched color bus data
 
12    Input/Output    Connected to pin 19 of 315-5242
 
13    Input          /HSYNC from VDP pin 43
 
14    Input          SPA/B from VDP pin 40
 
15    Input          Connected to pin 3 of 315-5394
 
16    Input          68000 R//W
 
17    Input          68000 D3
 
18    Input          68000 D2
 
19    Input          68000 D1
 
20    Input          68000 D0
 
23    Output          Color RAM A8
 
24    Output          Color RAM A7
 
25    Output          Color RAM A6
 
26    Output          Color RAM A5
 
27    Output          Bit 6 of latched color bus data
 
28    Output          Bit 5 of latched color bus data
 
  
Pins 7,22 are +5V, pins 8,21 are ground.
+
There are 8 general registers: -, X, Y, A, ST, STACK, PC and P ([2] [4]).
 +
Size is given in bits.
  
Pin 3 is connected to D1A of an AND gate, D1B is from +5V and the output
+
2.1.1. "-"
of the gate goes to 315-5394 pin 1. I don't know what this is for.
+
  Constant register with all bits set (0xffff). Also used for programming
 +
  external registers (blind reads/writes, see 2.2).
 +
  size: 16
  
The /HSYNC output of the VDP appears to be the dot clock, as it is fed
+
2.1.2. "X"
into the clock input of the color encoder.
+
  Generic register. Also acts as a multiplier 1 for P register.
 +
  size: 16
  
The EPM5032 controls the clock input of a LS373 which is used to latch
+
2.1.3. "Y"
the color bus outputs. The latched data is then sent to the EPM5032 and
+
  Generic register. Also acts as a multiplier 2 for P register.
color RAM.
+
  size: 16
  
The internal registers of the EPM5032 only appear at odd addresses. A8 is
+
2.1.4. "A"
used to select the protection or video control register, so they are
+
  Accumulator. Stores the result of all ALU (but not multiply) operations,
mirrored:
+
  status register is updated according to this. When directly accessed,
 +
  only upper word is read/written. Low word can be accessed by using AL
 +
  (see 2.2.8).
 +
  size: 32
  
$800000-$8001FF : Protection register
+
2.1.5. "ST"
  $800200-$8003FF : Video control register
+
  STatus register. Bits 0-9 are CONTROL, other are FLAG [2]. Only some of
  :
+
  them are actually used by SVP.
  $83FC00-$83FDFF : Protection register
+
  Bits: fedc ba98 7654 3210
$83FE00-$83FFFF : Video control register
+
    210 - RPL    "Loop size". If non-zero, makes (rX+) and (rX-) respectively
 +
                  modulo-increment and modulo-decrement (see 2.3). The value
 +
                  shows which power of 2 to use, i.e. 4 means modulo by 16.
 +
    43 - RB    Unknown. Not used by SVP code.
 +
    5  - ST5    Affects behavior of external registers. See 2.2.
 +
    6  - ST6    Affects behavior of external registers. See 2.2.
 +
                  According to [3] (5,6) bits correspond to hardware pins.
 +
    7  - IE    Interrupt enable? Not used by SVP code.
 +
    8  - OP    Saturated value? Not used by SVP code.
 +
    9  - MACS  MAC shift? Not used by SVP code.
 +
    a  - GPI_0 Interrupt 0 enable/status? Not used by SVP code.
 +
    b  - GPI_1 Interrupt 1 enable/status? Not used by SVP code.
 +
    c  - L      L flag. Similar to carry? Not used by SVP code.
 +
    d  - Z      Zero flag. Set after ALU operations, when all 32 accumulator
 +
                  bits become zero.
 +
    e  - OV    Overflow flag. Not used by SVP code.
 +
    f  - N      Negative flag. Set after ALU operations, when bit31 in
 +
                  accumulator is 1.
 +
  size: 16
  
These registers are write only. Reading any odd address returns the
+
2.1.6. "STACK"
currently selected value from the protection table in D3-D0, with D7-D4
+
  Hardware stack of 6 levels [3]. Values are "pushed" by directly writing to
set to one.
+
  it, or by "call" instruction. "Pop" is performed by directly reading the
 +
  register or by "ret" instruction.
 +
  size: 16
  
All games access the protection register at $800001 and the video control
+
2.1.7. "PC"
register at $800201.
+
  Program Counter. Can be written directly to perform a jump. It is not clear
 +
  if it is possible to read it (SVP code never does).
 +
  size: 16
  
Video control register
+
2.1.8. "P"
 +
  multiply Product - multiplication result register.
 +
  Always contains 32-bit multiplication result of X, Y and 2 (P = X * Y * 2).
 +
  X and Y are sign-extended before performing the multiplication.
 +
  size: 32
  
Bits 3-0 of the value written to the video control register are used
+
2.2. External registers
as follows:
+
-----------------------
  
D3 : ? (No effect)
+
The external registers, as the name says, are external to SSP160x, they are
D2 : 0= Pixels 262-319 are blanked, 1= Pixels 262-319 are visible.
+
hooked to memory controller in SVP, so by accessing them we actually program
D1 : 0= Pixels are wider and there is some flickering, 1= Normal display
+
the memory controller. They act as programmable memory access registers or
D0 : 0= Screen on, 1= Screen blanked
+
external status registers [1]. Some of them can act as both, depending on how
 +
ST5 ans ST6 bits are set in status register. After a register is programmed,
 +
accessing it causes reads/writes from/to external memory (see section 3 for
 +
the memory map). The access may also cause some additional effects, like
 +
incremental of address, associated with accessed register.
 +
In this document and my emu, instead of using names EXT0-EXT7
 +
from [4] I used different names for these registers. Those names are from
 +
Tasco Deluxe's [1] doc.
  
All games write $06 for a normal display and $07 to turn off the screen.
+
All these registers can be blind-accessed (as said in [1]) by performing
 +
(ld -, PMx) or (ld PMx, -). This programs them to access memory (except PMC,
 +
where the effect is different).
 +
All registers are 16-bit.
  
When the screen is blanked via bit 0 or 2, the /BLANK input on the color
+
2.2.1. "PM0"
encoder is asserted and a black color is output, which is unrelated to any
+
  If ST5 or ST6 is set, acts as Programmable Memory access register
value stored in color RAM. This also disables shadow/hilight effects so
+
  (see 2.2.7). Else it acts as status of XST (2.2.4). It is also mapped
it isn't possible to make the black color lighter or darker.
+
  to a15004 on 68k side:
 +
    ???????? ??????10
 +
    0: set, when SSP160x has written something to XST
 +
        (cleared when a15004 is read by 68k)
 +
    1: set, when 68k has written something to a15000 or a15002
 +
        (cleared on PM0 read by SSP160x)
 +
  Note that this is likely to be incorrect, but such behavior is OK for
 +
  emulation to work.
  
It would seem that the Sega C2 video hardware only allows a 320 pixel
+
2.2.2. "PM1"
display to be used. Trying to use a 256 pixel display results in an
+
  Programmable Memory access register. Only accessed with ST bits set by
unstable display. While the VDP may be putting out the right signals,
+
  SVP code.
chances are the EPM5032 is programmed to support the 320 pixel mode
 
exclusively.
 
  
Shadow/Hilight mode
+
2.2.3. "PM2"
 +
  Same as PM1.
  
The VDP outputs a signal which indicates if the current pixel data on
+
2.2.4. "XST"
the color bus should be shown normally, or if shadow/hilight effects should
+
  If ST5 or ST6 is set, acts as Programmable Memory access register
be applied. I'm assuming the EPM5032 gets this information, as it is in
+
  (only used by memory test code). Else it acts as eXternal STatus
control of the /SHADE pin of the color encoder. There is no distinction
+
  register, which is also mapped to a15000 and a15002 on 68k side.
made between shadow or hilight sprites (pixel data is $3E or $3F) either.
+
  Affects PM0 when written to.
  
It is up to bit 15 of the color RAM data to tell the color encoder to
+
2.2.5. "PM4"
apply shadow or hilight effects, regardless of the VDP which can only
+
  Programmable Memory access register. Not affected by ST5 and ST6 bits,
indicate in general if an effect should be applied, not which one it is.
+
  always stays in PMAR mode.
  
Color RAM
+
2.2.6. "EXT5"
 +
  Not used by SVP, so not covered by this document.
  
The analog RGB output of the VDP is not used. Instead the VDP has an 8-bit
+
2.2.7. "PMC"
bus (which I'll call the color bus, using Yamaha's terminology) that
+
  Programmable Memory access Control. It is set using 2 16bit writes, first
transmits graphics data. It would seem to have the following format:
+
  address, then mode word. After setting PMAC, PMx should be blind accessed
 +
  using (ld -, PMx) or (ld PMx, -) to program it for reading or writing
 +
  external memory respectively. Every PMx register can be programmed to
 +
  access it's own memory location with it's own mode. Registers are programmed
 +
  separately for reading and writing.
  
D7 - Normal or shadow/hilight effect indicator
+
  Reading PMC register also shifts it's state (from "waiting for address" to
D6 - Sprite or background pixel indicator
+
  "waiting for mode" and back). In state "waiting for address" reads return
D5 - Bit 1 of palette select
+
  address word related to last PMx register accessed. If read in "waiting for
D4 - Bit 0 of palette select
+
  mode" state, we get the same value as in other state, but rotated by 4 (or
D3 - Bit 3 of pixel data
+
  with nibbles swapped, VR always does this to words with both bytes equal,
D2 - Bit 2 of pixel data
+
  like 'abab' to get 'baba' for chessboard dithering effect).
D1 - Bit 1 of pixel data
 
D0 - Bit 0 of pixel data
 
  
Bits 7-5 go through the EPM5032 chip, so it isn't possible to tell which
+
  The address word contains bits 0-15 of the memory word-address.
bits serve what purpose. The function of these bits could be swapped around.
+
  The mode word format is as follows:
 +
    dsnnnv?? ???aaaaa
 +
    a: bits 16-20 of memory word-address.
 +
    n: auto-increment value. If set, after every access of PMx, word-address
 +
        value related to it will be incremented by (words):
 +
          1 - 1    5 - 16
 +
          2 - 2    6 - 32
 +
          3 - 4    7 - 128
 +
          4 - 8
 +
    d: make auto-increment negative - decrement by count listed above.
 +
    s: special-increment mode. If current address is even (when accessing
 +
        programmed PMx), increment it by 1. Else, increment by 32. It is not
 +
        clear what happens if d and n bits are also set (never done by SVP).
 +
    v: over-write mode when writing, unknown when reading (not used).
 +
        Over-write mode splits the word being written into 4 nibbles and only
 +
        writes out ones which are non zero.
 +
  When auto-increment is performed, it affects all 21 address bits.
  
The color bus goes to 4K of color RAM, which is arranged as 2Kx16. The color
+
2.2.8. "AL"
RAM data is fed into a 315-5242 encoder, which outputs 15-bit RGB color
+
  This register acts more like a general register.
and can apply shadow or hilight effects.
+
  If this register is blind-accessed, it is "dummy programmed", i.e. nothing
 +
  happens and PMC is reset to "waiting for address" state.
 +
  In all other cases, it is Accumulator Low - 16 least significant bits of
 +
  accumulator. Normally reading acc (ld X, A) you get 16 most significant
 +
  bits, so this allows you access the low word of 32bit accumulator.
  
Part of the color bus is shared with the EPM5032 chip which controls the
+
2.3. Pointer registers
color encoder, provides palette banking (there's more color RAM than could
+
----------------------
be addressed by the color bus), and to control the palettes selected as
 
part of a protection feature. Here's a layout of how the color RAM is
 
interfaced to the rest of the system:
 
  
A0  - Color bus bit 0
+
There are 8 8-bit pointer registers rX, which are internal to SSP160x and are
A1  - Color bus bit 1
+
used to access internal RAM banks RAM0 and RAM1, or program memory indirectly.
A2  - Color bus bit 2
+
r0-r3 (ri) point to RAM0, r4-r7 (rj) point to RAM1. Each bank has 256 words of
A3  - Color bus bit 3
+
RAM, so 8bit registers can fully address them. The registers can be accessed
A4  - Color bus bit 4
+
directly, or 2 indirection levels can be used [ (rX), ((rX)) ]. They work
A5  - EPM5032 pin 26 (Color bus bit 5)
+
similar to * and ** operators in C, only they use different types of memory
A6  - EPM5032 pin 25
+
and ((rX)) also performs post-increment. First indirection level (rX) accesses
A7  - EPM5032 pin 24
+
a word in RAMx, second accesses program memory at address read from (rX), and
A8  - EPM5032 pin 23 (Color bus bit 6)
+
increments value in (rX).
A9  - I/O chip port H bit 0
 
A10 - I/O chip port H bit 1
 
  
  This arrangement divides the color RAM into four 1K units which are
+
Only r0,r1,r2,r4,r5,r6 can be directly modified (ldi r0, 5), or by using
selected by I/O chip port H. The EPM5032 controls how the current 1K unit
+
modifiers. 3 modifiers can be applied when using first indirection level
of color RAM is used.
+
(optional):
 +
  + : post-increment (ld a, (r0+) ). Increment register value after operation.
 +
      Can be made modulo-increment by setting RPL bits in status register
 +
      (see 2.1.5).
 +
  - : post-decrement. Also can be made modulo-decrement by using RPL bits in ST.
 +
  +!: post-increment, unaffected by RPL (probably).
 +
These are only used on 1st indirection level, so things like ( ld a, ((r0+)) )
 +
and (ld X, r6-) are probably invalid.
  
Despite the possibilities of the EPM5032 controlling multiple aspects
+
r3 and r7 are special and can not be changed (at least Samsung samples [4] and
about how the color RAM is accessed, nearly all games have the same
+
SVP code never do). They are fixed to the start of their RAM banks. (They are
implementation:
+
probably changeable for ssp1605+, Samsung's old DSP page claims that).
 +
1 of these 4 modifiers must be used on these registers (short form direct
 +
addressing? [2]):
 +
  |00: RAMx[0] The very first word in the RAM bank.
 +
  |01: RAMx[1] Second word
 +
  |10: RAMx[2] ...
 +
  |11: RAMx[3]
  
- The sprite/background indicator bit selects the first 512 bytes of the
+
2.4. The instruction set
  current 1K for background pixels, and the latter 512 bytes for sprite
+
------------------------
  pixels.
 
  
- Writing to the protection register sets two bank select values which
+
The Samsung SSP16 series assembler uses right-to-left notation ([2] [4]):
  divide the 512 bytes for backgrounds or sprites into four banks of
+
ld X, Y
  128 bytes:
+
means value from Y should be copied to X.
  
  D0-D1 choose the background palette bank
+
Size of every instruction is word, some have extension words for immediate
  D3-D2 choose the sprite palette bank
+
values. When writing an interpreter, 7 most significant bits are usually
 +
enough to determine which opcode it is.
  
  - The lower 6 bits of the color bus (color palette and pixel data) are
+
encoding bits are marked as:
  used as an index into the remaining 128 bytes (64 words), and the value
+
rrrr - general or external register, in order specified in 2.1 and 2.2
  selected is sent to the color encoder.
+
      (0 is '-', 1 'X', ..., 8 is 'PM0', ..., 0xf is 'AL')
 +
dddd - same as above, as destination operand
 +
ssss - same as above, as source operand
 +
jpp - pointer register index, 0-7
 +
j    - specifies RAM bank, i.e. RAM0 or RAM1
 +
i*  - immediate value bits
 +
a*  - offset in internal RAM bank
 +
mm  - modifier for pointer register, depending on register:
 +
        r0-r2,r4-r6  r3,r7  examples
 +
      0:    (none)    |00  ld  a, (r0)      cmp a, (r7|00)
 +
      1:        +!    |01  ld  (r0+!), a    ld  (r7|01), a
 +
      2:          -    |10  add a, (r0-)
 +
      3:          +    |11
 +
cccc - encodes condition, only 3 used by SVP, see check_cond() below
 +
ooo  - operation to perform
  
  Here's a memory map of color RAM to represent this setup, for the
+
Operation is written in C-style pseudo-code, where:
  current 1K chunk being used:
+
program_memory[X] - access program memory at address X
 +
RAMj[X]            - access internal RAM bank j=0,1 (RAM0 or RAM1), word
 +
                    offset X
 +
RIJ[X]            - pointer register rX, X=0-7
 +
pr_modif_read(m,X) - read pointer register rX, applying modifier m:
 +
                      if register is r3 or r7, return value m
 +
                      else switch on value m:
 +
                        0: return rX;
 +
                        1: tmp = rX; rX++; return tmp; // rX+!
 +
                        2: tmp = rX; modulo_decrement(rX); return tmp; // rX-
 +
                        3: tmp = rX; modulo_increment(rX); return tmp; // rX+
 +
                      the modulo value used (if used at all) depends on ST
 +
                      RPL bits (see 2.1.5)
 +
check_cond(c,f)    - checks if a flag matches f bit:
 +
                    switch (c) {
 +
                      case 0: return true;
 +
                      case 5: return (Z == f) ? true : false; // check Z flag
 +
                      case 7: return (N == f) ? true : false; // check N flag
 +
                    } // other conditions are possible, but they are not used
 +
update_flags()    - update ST flags according to last ALU operation.
 +
sign_extend(X)    - sign extend 16bit value X to 32bits.
 +
next_op_address() - address of instruction after current instruction.
  
$0000-$007F : Background palette data, for bank 0
+
2.4.1. ALU instructions
$0080-$00FF : Background palette data, for bank 1
 
$0000-$017F : Background palette data, for bank 2
 
$0180-$01FF : Background palette data, for bank 3
 
$0200-$027F : Sprite palette data, for bank 0
 
$0280-$02FF : Sprite palette data, for bank 1
 
$0300-$037F : Sprite palette data, for bank 2
 
$0380-$03FF : Sprite palette data, for bank 3
 
  
Remember that by writing to the protection register, one of four banks
+
All of these instructions update flags, which are set according to full 32bit
can be selected for the backgrounds and for the sprites.
+
accumulator. The SVP code only checks N and Z flags, so it is not known when
 +
exactly OV and L flags are set. Operations are performed on full A, so
 +
(andi A, 0) would clear all 32 bits of A.
  
When the CPU is accessing color RAM no banking is applied by the EPM5032,
+
They share the same addressing modes. The exact arithmetic operation is
and it can freely read or write color RAM in 1K units as selected by
+
determined by 3 most significant (ooo) bits:
port H of the I/O chip.
+
  001 - sub - subtract    (OP -=)
 +
  011 - cmp - compare      (OP -, flags are updated according to result)
 +
  100 - add - add          (OP +=)
 +
  101 - and - binary AND  (OP &=)
 +
  110 - or - binary OR    (OP |=)
 +
  111 - eor - exclusive OR (OP ^=)
  
  VDP registers
+
  syntax        encoding            operation
 +
OP  A, s      ooo0 0000 0000 rrrr  A OP r << 16;
 +
OP  A, (ri)  ooo0 001j 0000 mmpp  A OP RAMj[pr_modif_read(m,jpp)] << 16;
 +
OP  A, adr    ooo0 011j aaaa aaaa  A OP RAMj[a] << 16;
 +
OPi A, imm    ooo0 1000 0000 0000  A OP i << 16;
 +
              iiii iiii iiii iiii
 +
op  A, ((ri)) ooo0 101j 0000 mmpp  tmp = pr_modif_read(m,jpp);
 +
                                    A OP program_memory[RAMj[tmp]] << 16;
 +
                                    RAMj[tmp]++;
 +
op  A, ri    ooo1 001j 0000 00pp  A OP RIJ[jpp] << 16;
 +
OPi simm      ooo1 1000 iiii iiii  A OP i << 16;
  
I'll only list some of the register bits that have alternate functions or
+
Note that in (OP A, s) case, if s is 32bit register, operation is performed on
ones that are worth mentioning.
+
all 32 bits, including when s is accumulator itself, like for (and A, A), which
 +
is a valid operation.
  
Register $80
+
There is also "perform operation on accumulator" instruction:
  
  D3 : 1= Alternating lines of the display are blanked, the lines selected
+
  syntax        encoding            operation
        change on even and odd frames.
+
mod cond, op  1001 000f cccc 0ooo  if (check_cond(c,f)) switch(o) {
D1 : 1= This bit locks up the hardware when set.
+
                                      case 2: A >>= 1; break; // arithmetic shift
D0 : 1= External video input enable, but this results in bad sync since
+
                                      case 3: A <<= 1; break;
        there is no external video source.
+
                                      case 6: A = -A;  break; // negate A
 +
                                      case 7: A = abs(A); break; // absolute val.
 +
                                    } // other operations are possible, but
 +
                                      // they are not used by SVP.
  
Register $8B
+
2.4.2. Load (move) instructions
  
D7 : 1= VDP controls color bus. Reading or writing color RAM at any address
+
These instructions never affect flags (even ld A).
        only affects address zero, and the data read/written will often be
+
If destination is A, and source is 16bit, only upper word is transfered (same
        corrupted.
+
thing happens on opposite). If dest. is A, and source is P, whole 32bit value
      0= CPU controls color bus. During this time garbage data is displayed
+
is transfered. It is not clear if P can be destination operand (probably not,
        on the screen if it is enabled. (through the video control
+
no code ever does this).
        register only, if the screen is blanked by bit 6 of register $81
+
Writing to STACK pushes a value there, reading pops. It is not known what
        there will still be garbage shown)
+
happens on overflow/underflow (never happens in SVP code).
D6 : 1= Setting this bit locks up the hardware when set.
+
ld -, - is used as a nop.
  
  All games only access color RAM during the vertical blanking period, so
+
  syntax        encoding            operation
  the graphical garbage shown when the CPU hogs the color bus isn't visible.
+
ld  d, s      0000 0000 dddd ssss  d = s;
 +
ld  d, (ri)  0000 001j dddd mmpp  d = RAMj[pr_modif_read(m,jpp)];
 +
ld  (ri), s  0000 010j ssss mmpp  RAMj[pr_modif_read(m,jpp)] = s;
 +
ldi d, imm    0000 1000 dddd 0000  d = i;
 +
              iiii iiii iiii iiii
 +
ld  d, ((ri)) 0000 101j dddd mmpp  tmp = pr_modif_read(m,jpp);
 +
                                    d = program_memory[RAMj[tmp]];
 +
                                    RAMj[tmp]++;
 +
ldi (ri), imm 0000 110l 0000 mmpp  RAMj[pr_modif_read(m,jpp)] = i;
 +
              iiii iiii iiii iiii
 +
ld  adr, a    0000 111j aaaa aaaa  RAMj[a] = A;
 +
ld  d, ri    0001 001j dddd 00pp  d = RIJ[jpp];
 +
ld  ri, s    0001 010j ssss 00pp  RIJ[jpp] = s;
 +
ldi ri, simm  0001 1jpp iiii iiii  RIJ[jpp] = i;
 +
  ld  d, (a)    0100 1010 dddd 0000  d = program_memory[A[31:16]];
 +
                                    // read a word from program memory. Offset
 +
                                    // is the upper word in A.
  
Register $8C
+
2.4.3. Program control instructions
  
D7 : 1= Setting this bit locks up the hardware when set.
+
Only 3 instructions: call, ret (alias of ld PC, STACK) and branch. Indirect
D6 : 1= Display is enabled
+
jumps can be performed by simply writing to PC.
      0= Display is blanked (black)
 
D5 : 1= Bad sync, lines seem to be cropped to 256 pixels.
 
D4 : 0= The background/sprite indicator bit is always set to zero, so
 
        the current background palette bank is used for sprites as well.
 
      1= The background/sprite indicator bit works normally.
 
D0 : 1= 320-pixel display
 
      0= This should be a 256-pixel display, but you just get bad sync
 
        instead.
 
  
  Bits 1 and 2 of this register do not enable interlacing regardless of
+
  syntax          encoding            operation
  any setting.
+
  call cond, addr  0100 100f cccc 0000  if (check_cond(c,f)) {
 +
                  aaaa aaaa aaaa aaaa    STACK = next_op_address(); PC = a;
 +
                                      }
 +
bra  cond, addr  0100 110f cccc 0000  if (check_cond(c,f)) PC = a;
 +
                  aaaa aaaa aaaa aaaa
 +
ret              0000 0000 0110 0101  PC = STACK; // same as ld PC, STACK
  
----------------------------------------------------------------------------
+
2.4.4. Multiply-accumulate instructions
I/O chip
 
----------------------------------------------------------------------------
 
  
The System C2 hardware uses a 315-5296 I/O chip, as found in many other Sega
+
Not sure if (ri) and (rj) really get loaded into X and Y, but multiplication
boards. It has 8 internal registers, eight I/O ports, and provides an
+
result surely is loaded into P. There is probably optional 3rd operand (1, 0;
interface to Yamaha FM sound chips.
+
encoded by bit16, default 1), but it's not used by SVP code.
  
  Here is a description of the I/O ports. I tested the board in a mini NeoGeo
+
  syntax          encoding            operation
  cabinet, so some of the button descriptions are specific to the NeoGeo only.
+
  mld  (rj), (ri)  1011 0111 nnjj mmii  A = 0; update_flags();
 +
                                      X = RAM0[pr_modif_read(m,0ii)];
 +
                                      Y = RAM1[pr_modif_read(m,1jj)];
 +
                                      P = sign_extend(X) * sign_extend(Y) * 2
 +
mpya (rj), (ri)  1001 0111 nnjj mmii  A += P; update_flags();
 +
                                      X = RAM0[pr_modif_read(m,0ii)];
 +
                                      Y = RAM1[pr_modif_read(m,1jj)];
 +
                                      P = sign_extend(X) * sign_extend(Y) * 2
 +
mpys (rj), (ri)  0011 0111 nnjj mmii  A -= P; update_flags();
 +
                                      X = RAM0[pr_modif_read(m,0ii)];
 +
                                      Y = RAM1[pr_modif_read(m,1jj)];
 +
                                      P = sign_extend(X) * sign_extend(Y) * 2
  
  $840001 - Port A - Player 1 inputs
+
-------------------------------------------------------------------------------
 +
  3. Memory map
 +
-------------------------------------------------------------------------------
  
D7 : 0= UP pressed, 1= released
+
The SSP160x can access it's own program memory, and external memory through EXT
D6 : 0= DOWN pressed, 1= released
+
registers (see 2.2). Program memory is read-execute-only, the size of this
D5 : 0= LEFT pressed, 1= released
+
space is 64K words (this is how much 16bit PC can address):
D4 : 0= RIGHT pressed, 1= released
 
D3 : 0= Button D pressed, 1= released
 
D2 : 0= Button C pressed, 1= released
 
D1 : 0= Button B pressed, 1= released
 
D0 : 0= Button A pressed, 1= released
 
  
  $840003 - Port B - Player 2 inputs
+
  byte address word address  name
 +
        0-  7ff        0- 3ff  IRAM
 +
      800-1ffff      400-ffff  ROM
  
D7 : 0= UP pressed, 1= released
+
There were reports that SVP has internal ROM, but fortunately they were wrong.
D6 : 0= DOWN pressed, 1= released
+
The location 800-1ffff is mapped from the same location in the 2MB game ROM.
D5 : 0= LEFT pressed, 1= released
+
The IRAM is read-only (as SSP160x doesn't have any means of writing to it's
D4 : 0= RIGHT pressed, 1= released
+
program memory), but it can be changed through external memory space, as it's
D3 : 0= Button D pressed, 1= released
+
also mapped there.
D2 : 0= Button C pressed, 1= released
 
D1 : 0= Button B pressed, 1= released
 
D0 : 0= Button A pressed, 1= released
 
  
$840005 - Port C - Miscellaneous inputs
+
The external memory space seems to match the one visible by 68k, with some
 +
differences:
  
  D7 : From MB3773P pin 1. (/RESET output)
+
      68k space      SVP space  word address name
  D6 : From uPD7759 pin 18. (/BUSY output)
+
        0-1fffff      0-1fffff      0- fffff  game ROM
  D5 : From pin 8 of CN2.
+
  200000-2fffff              ?              ?  unused (1)
  D4 : From pin 7 of CN2.
+
  300000-31ffff  300000-31ffff  180000-18ffff  DRAM
  D3 : From pin 5 of CN2.
+
  320000-37ffff              ?              ?  3 mirrors od DRAM
  D2 : From pin 4 of CN2.
+
  380000-38ffff              ?              ? unused (1)
  D1 : From pin 3 of CN2.
+
              ?  390000-3907ff 1c8000-1c83ff IRAM
  D0 : From pin 2 of CN2.
+
  390000-39ffff              ?              ? "cell arrange" 1
 +
  3a0000-3affff              ?              ? "cell arrange" 2
 +
  3b0000-3fffff              ?              ? unused (2)
 +
  a15000-a1500f            n/a            n/a Status/control registers
  
The trace to D7 comes out of a 74LS244 who's input is the MB3773P /RESET
+
  unused (1) - reads seem to return data from internal bus (last word read by
signal. It looks like the LS244 is always enabled as far as I can tell,
+
                SSP160x). Writes probably have no effect.
so D7 will not be tristated and can't be used for anything else.
+
  unused (2) - reads return 0xffff, writes have no effect.
  
$840007 - Port D - Miscellaneous outputs
+
The external memory can be read/written by SSP160x (except game ROM, which can
 +
only be read).
  
D7 : To pin 3 of JP15. (Watchdog clock control)
+
"cell arrange" 1 and 2 are similar to the one used in SegaCD, they map
D6 : To MUTE input pin on TDA1518BQ amplifier.
+
300000-30ffff location to 390000-39ffff and 3a0000-3affff, where linear image
D5 : To CN2 pin 10. (Unknown purpose)
+
written to 300000 can be read as VDP patterns at 390000. Virtua Racing doesn't
D4 : To CN2 pin 11. (Unknown purpose)
+
seem to use this feature, it is only used by memory test code.
D3 : To CN1 pin K. (Coin lockout 2)
 
D2 : To CN1 pin 9. (Coin lockout 1)
 
D1 : To CN1 pin J. (Coin meter 2)
 
D0 : To CN1 pin 8. (Coin meter 1)
 
  
The I/O chip pins for bits D0-D6 go through a A1603C amplifier, which allows
+
Here is the list of status/control registers (16bit size):
large loads to be driven such as the coin meters, lockout hardware, and
 
mute switch of the amplifier. Therefore pins 10, 11 of CN2 may be able to
 
control lamps or other external hardware.
 
  
  $840009 - Port E - Service / Coin inputs
+
  addr  rst v description
 +
  a15000  ffff  w/r command/result register. Visible as XST for SSP160x
 +
                see (2.2.4).
 +
  a15002  ffff  mirror of the above.
 +
  a15004    0  status of command/result register (see 2.2.1).
 +
  a15006  ffff  possibly halts the SVP. Before doing DMA from DRAM, 68k code
 +
                writes 0xa, and after it's finished, writes 0. This is probably
 +
                done to prevent SVP accessing DRAM and avoid bus clashes.
 +
  a15008  ffff  possibly causes an interrupt. There is (unused?) code which
 +
                writes 0, 1, and again 0 in sequence.
 +
  a1500a  ffff  ?
 +
  a1500c  ffff  ?
 +
  a1500e  ffff  ?
  
D7 : Always returns '1'
+
-------------------------------------------------------------------------------
D6 : 0= SELECT GAME button pressed, 1= released
+
  4. Other notes
D5 : 0= 2P START button pressed, 1= released
+
-------------------------------------------------------------------------------
D4 : 0= 1P START button pressed, 1= released
 
D3 : 0= Service switch pressed, 1= released
 
D2 : 0= Test switch pressed, 1= released
 
  D1 : 0= Coin inserted in 1P slot, 1= no coin
 
D0 : 0= Coin inserted in 2P slot, 1= no coin
 
  
$84000B - Port F - DIP switch #1
+
The game has arcade-style memory self-check mode, which can be accessed by
 +
pressing _all_ buttons (including directions) on 3-button controller. There was
 +
probably some loopback plug for this.
  
D7 : Switch #1 is 1=off, 0=on
+
SVP seems to have DMA latency issue similar to one in Sega CD, as the code
D6 : Switch #2 is 1=off, 0=on
+
always sets DMA source address value larger by 2, then intended for copy.
D5 : Switch #3 is 1=off, 0=on
+
This is even true for DMAs from ROM, as it's probably hooked through SVP's
D4 : Switch #4 is 1=off, 0=on
+
memory controller.
D3 : Switch #5 is 1=off, 0=on
 
D2 : Switch #6 is 1=off, 0=on
 
D1 : Switch #7 is 1=off, 0=on
 
D0 : Switch #8 is 1=off, 0=on
 
  
$84000D - Port G - DIP switch #2
+
The entry point for the code seems to be at address 0x800 (word 0x400) in ROM,
 +
but it is not clear where the address is fetched from when the system powers
 +
up. The memory test code also sets up "ld PC, .." opcodes at 0x7f4, 0x7f8 and
 +
0x7fc, which jump to some routines, possibly interrupt handlers. This means
 +
that mentioned addresses might be built-in interrupt vectors.
  
D7 : Switch #1 is 1=off, 0=on
+
The SVP code doesn't seem to be timing sensitive, so it can be emulated without
D6 : Switch #2 is 1=off, 0=on
+
knowing timing of the instructions or even how fast the chip is clocked.
D5 : Switch #3 is 1=off, 0=on
+
Overclocking doesn't have any effect, underclocking causes slowdowns. Running
D4 : Switch #4 is 1=off, 0=on
+
10-12M instructions/sec (or possibly less) is sufficient.</pre>
D3 : Switch #5 is 1=off, 0=on
 
D2 : Switch #6 is 1=off, 0=on
 
D1 : Switch #7 is 1=off, 0=on
 
D0 : Switch #8 is 1=off, 0=on
 
 
 
$84000F - Port H - Miscellaneous outputs
 
 
 
D7 : To pin A19 of CN4
 
D6 : To pin B19 of CN4
 
D5 : ?
 
D4 : ?
 
D3 : To pin 31 of uPD7759 sample ROM (A18 on a 27C040)
 
D2 : To pin 30 of uPD7759 sample ROM (A17 on a 27C040)
 
D1 : To A10 of color RAM
 
D0 : To A9 of color RAM
 
 
 
Bits 0,1 are used to control part of the color RAM banking, by selecting
 
a 1K bank out of the total 4K of color RAM. The remaining address bits
 
come from the EPM5032 EPLD chip and the VDP color bus.
 
 
 
Bits 2,3 go through a set of jumpers that connect the pins indicated in
 
the sample ROM socket to ground or to these pins.
 
 
 
Bits 4,5 may be additional outputs for selecting the type of EPROM used
 
for uPD7759 samples, but I haven't confirmed this.
 
 
 
Bits 6,7 are outputs to the additional pins of the CN3.
 
 
 
Protection registers
 
 
 
$840011 - Returns $53 ('S') when read.
 
$840013 - Returns $45 ('E') when read.
 
$840015 - Returns $47 ('G') when read.
 
$840017 - Returns $41 ('A') when read.
 
 
 
Writing to these registers does nothing, they are read-only.
 
 
 
Control registers
 
 
 
$840019 - ? (Returns $FD when read)
 
$84001B - ? (Returns $88 when read)
 
$84001D - ? (Returns $FD when read)
 
$84001F - ? (Returns $88 when read)
 
 
 
Bits 2-0 of $84001D controls the state of the CNT2-0 output pins, which are
 
used as follows:
 
 
 
CNT0 - Connected to test point 2.
 
CNT1 - ?
 
CNT2 - Connected to pin 6 of missing GAL16V8 chip (IC23)
 
 
 
----------------------------------------------------------------------------
 
Hardware information
 
----------------------------------------------------------------------------
 
 
 
Audio output
 
 
 
The left channel output of the YM3438 is connected to the rest of the audio
 
mixing and amplification circuitry, the right channel output pin is
 
unconnected. So even though a stereo sound chip is used, only mono output
 
is available.
 
 
 
Test points
 
 
 
TP1 - From pin D of CN1. (+5V source, but missing FLT9 in path)
 
TP2 - From CNT0 output of I/O chip. (bit 0 of $84001D)
 
TP3 - From CKOT. (FM sound chip clock from I/O chip)
 
TP4 - From 68000 pin 26. (FC2)
 
TP5 - From 68000 pin 19. (/VMA)
 
TP6 - From 68000 pin 20. (E)
 
TP7 - From pin B18 of CN4. (additional pin of standard expansion connector)
 
TP8 - From 15 of IC36. (where an extra GAL16V8 would go)
 
 
 
The YM3438 doesn't use the clock signal from the I/O chip.
 
 
 
Watchdog disable
 
 
 
Cut the trace going between pin 1 of the Fujitsu MB3773 and a resistor to
 
disconnect the /RESET output signal from the watchdog chip.
 
 
 
----------------------------------------------------------------------------
 
Jumper settings
 
----------------------------------------------------------------------------
 
 
 
JP5 - EPROM size for IC 31, 32
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
3-2 shorted: EPROMs are 27C020
 
2-1 shorted: EPROMs are 27C040
 
 
 
JP7 - EPROM size for IC 33, 34
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
3-2 shorted: EPROMs are 27C020
 
2-1 shorted: EPROMs are 27C040
 
 
 
JP15 - Watchdog control
 
~~~~~~~~~~~~~~~~~~~~~~~
 
This jumper normally has pins 2,1 shorted and pin 3 left open. Each pin has
 
the following assignment:
 
 
 
1 - Output from VDP /HSYNC pin which is also shared with pin 13 (an input)
 
    on the EPM5032 EPLD chip.
 
2 - Goes to the MB3773B CK input. (input clock to watchdog chip)
 
3 - Output from bit 7 of I/O chip port D.
 
 
 
It would seem that in the default state, the watchdog chip is prevented from
 
causing a reset by receiving the horizontal sync pulse from the VDP.
 
However, in my tests the system would always reset, so I disconnected the
 
watchdog chip. It could be that /HSYNC was mislabeled in the Genesis
 
schematics (JP15 pin 1 goes to VDP pin 43) or that perhaps /HSYNC doesn't
 
work as one would expect.
 
 
 
If the jumper has pins 3-2 shorted instead, then bit 7 of I/O chip port D
 
provides the clock signal. I don't know how often bit 7 would have to be
 
toggled to keep the watchdog going.
 
 
 
JP16 - Unknown
 
~~~~~~~~~~~~~~
 
If pins 2-1 are shorted, the system is temporarily halted.
 
 
 
JP17-JP20 - uPD7759 EPROM configuration
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
JP17
 
Pin 1 - From pin 12 of IC23 (74LS08).
 
Pin 2 - Connected to pin 24 of socket. (/OE)
 
Pin 3 - Connected to JP18 pin 1. (and something else?)
 
 
 
JP18
 
Pin 1 - Connected to JP17 pin 3. (and something else?)
 
Pin 2 - Connected to pin 2 of socket. (A16)
 
Pin 3 - Ground
 
 
 
JP19
 
Pin 1 - From bit 2 of I/O chip port H.
 
Pin 2 - Connected to pin 30 of socket. (A17)
 
Pin 3 - Ground
 
 
 
JP20
 
Pin 1 - From bit 3 of I/O chip port H.
 
Pin 2 - Connected to pin 31 of socket. (A18)
 
Pin 3 - Ground
 
 
 
I don't have the complete description of these jumpers, but basically they
 
configure certain pins of the EPROM socket to handle chips with different
 
capacities.
 
 
 
In a Puyo Puyo 2 board with a 27C040, all four jumpers have pins 2-1 shorted
 
with pin 3 left open.
 
 
 
----------------------------------------------------------------------------
 
Connector pinouts
 
----------------------------------------------------------------------------
 
 
 
CN1 (56-pin JAMMA edge connector)
 
 
 
  Not included, it's a standard JAMMA connector.
 
 
 
CN2 (12-pin right-angle header)
 
 
 
  1 - Ground
 
  2 - Bit 0 of I/O chip port C
 
  3 - Bit 1 of I/O chip port C
 
  4 - Bit 2 of I/O chip port C
 
  5 - Bit 3 of I/O chip port C
 
  6 - Ground
 
  7 - Bit 4 of I/O chip port C
 
  8 - Bit 5 of I/O chip port C
 
  9 - (N.C.)
 
10 - Bit 5 of I/O chip port D
 
11 - Bit 4 of I/O chip port D
 
12 - Ground
 
 
 
Pins 1-5,7-8 are additional inputs, which might be used for other types
 
of input devices.
 
 
 
Pins 10,11 are outputs and are capable of driving large loads. They may
 
be used for lamps or other external hardware.
 
 
 
CN3 (10-pin right-angle header)
 
 
 
  1 - +5V
 
  2 - +5V
 
  3 - +5V
 
  4 - +5V
 
  5 - (N.C.)
 
  6 - Ground
 
  7 - Ground
 
  8 - Ground
 
  9 - Ground
 
10 - +12V
 
 
 
CN4 (20-pin two-row header)
 
 
 
A1  - +5V                      B1  - +5V
 
A2  - Ground                  B2  - Ground
 
A3  - (N.C.)                  B3  - (N.C.)
 
A4  - 68000 A1                B4  - 68000 A2
 
A5  - 68000 A3                B5  - 68000 A4
 
A6  - 68000 A5                B6  - 68000 D0
 
A7  - 68000 D1                B7  - 68000 D2
 
A8  - 68000 D3                B8  - 68000 D4
 
A9  - 68000 D5                B9  - 68000 D6
 
A10 - 68000 D7                B10 - 68000 /RD
 
A11 - 68000 /LWR              B11 - 68000 /UWR
 
A12 - /RESET                  B12 - /CS
 
A13 - (N.C.)                  B13 - (N.C.)
 
A14 - Ground                  B14 - Ground
 
A15 - +5V                      B15 - +5V
 
A16 - ?                        B16 - ?
 
A17 - To CN2 pin 7            B17 - To CN2 pin 8
 
A18 - ?                        B18 - ?
 
A19 - I/O chip port H bit 6    B19 - I/O chip port H pit 7
 
A20 - ?                        B20 - ?
 
 
 
The chip select signal for pin B12 comes from pin 17 of IC26, which is a
 
GAL16V8 labeled as Sega part 315-5395. I don't know where in the memory map
 
this is located at.
 
 
 
I/O chip port C bits 4,5 are inputs connected to pins A17/B17, which are
 
also shared with CN2 pins 7,8.
 
 
 
I/O chip port H bits 6,7 are outputs connected to pins A19/B19.
 
 
 
Pins 16-20 for both rows are a Sega C2 specific addition to this standard
 
type of connector which is used in other Sega boards. (After Burner II,
 
Galaxy Force II, System 16B, System 18, System 24) This connector is used
 
in other games for an I/O board. (e.g. analog inputs for Heavyweight Champ
 
on System 16B, 4-player inputs for D.D. Crew on System 18)
 
 
 
----------------------------------------------------------------------------
 
Credits and Acknowledgements
 
----------------------------------------------------------------------------
 
 
 
- Haze for his assistance with c2emu and technical advice.
 
- Aaron Giles for documenting the protection scheme.
 
- MD Game Sales for the Sega C2 boards.
 
- Chris MacDonald for support and testing.
 
 
 
----------------------------------------------------------------------------
 
Disclaimer
 
----------------------------------------------------------------------------
 
 
 
If you use any information from this document, please credit me
 
(Charles MacDonald) and optionally provide a link to my webpage
 
(http://cgfm2.emuviews.com/) so interested parties can access it.
 
 
 
The credit text should be present in the accompanying documentation of
 
whatever project which used the information, or even in the program
 
itself (e.g. an about box).
 
 
 
Regarding distribution, you cannot put this document on another
 
website, nor link directly to it.
 
 
 
</pre>
 

Revision as of 14:40, 16 September 2016

Logo-txt.svg
This is a copy of an "unofficial" document containing original research, for use as a source on Sega Retro. This page likely exists for historical purposes - the contents should ideally be copy-edited and wikified to make better use of Sega Retro's software.
Original source: http://cgfm2.emuviews.com/txt/c2tech.txt


-------------------------------------------------------------------------------
 notaz's SVP doc
 $Id: svpdoc.txt 964 2014-09-23 00:27:41Z notaz $
 Copyright 2008, Grazvydas Ignotas (notaz)
-------------------------------------------------------------------------------

If you use this, please credit me in your work or it's documentation.
Tasco Deluxe should also be credited for his pioneering work on the subject.
Thanks.

Use monospace font and disable word wrap when reading this document.

updates:
2014-09-23: minor additions about memory map
2008-03-05: added a few notes about arithmetic op operands.
2008-02-06: added Tasco Deluxe's correction about PMC register reads.


-------------------------------------------------------------------------------
 Table of Contents 
-------------------------------------------------------------------------------
 
  0. Introduction
  1. Overview
  2. The SSP160x DSP
    2.1. General registers
    2.2. External registers
    2.3. Pointer registers
    2.4. The instruction set
  3. Memory map
  4. Other notes


-------------------------------------------------------------------------------
 0. Introduction
-------------------------------------------------------------------------------

This document is an attempt to provide technical information needed to
emulate Sega's SVP chip. It is based on reverse engineering Virtua Racing
game and on various Internet sources. Only some of the information provided
here has been verified on the real hardware, so some things are likely to be
inaccurate.

The following information sources were used while writing this document
and emulator implementation:

  [1] SVP Reference Guide (annotated) and SVP Register Guide (annotated)
      by Tasco Deluxe < tasco.deluxe @ gmail.com >
      http://www.sharemation.com/TascoDLX/SVP%20Reference%20Guide%202007.02.11.txt
      http://www.sharemation.com/TascoDLX/SVP%20Register%20Guide%202007.02.11.txt
  [2] SSP1610 disassembler
      written by Pierpaolo Prazzoli, MAME source code.
      http://mamedev.org/
  [3] SSP1601 DSP datasheet
      http://notaz.gp2x.de/docs/SSP1601.pdf
  [4] DSP page (with code samples) in Samsung Semiconductor website from 1997
      retrieved from Internet Archive: The Wayback Machine
      http://web.archive.org/web/19970607052826/www.sec.samsung.com/Products/dsp/dspcore.htm
  [5] Sega's SVP Chip: The Road not Taken?
      Ken Horowitz, Sega-16
      http://sega-16.com/feature_page.php?id=37&title=Sega's%20SVP%20Chip:%20The%20Road%20not%20Taken?


-------------------------------------------------------------------------------
 1. Overview
-------------------------------------------------------------------------------

The only game released with SVP chip was Virtua Racing. There are at least 4
versions of the game: USA, Jap and 2 different Eur revisions. Three of them
share identical SSP160x code, one of the Eur revisions has some differences.

From the software developer's point of view, the game cartridge contains
at least:

  * Samsung SSP160x 16-bit DSP core, which includes [3]:
    * Two independent high-speed RAM banks, accessed in single clock cycle,
      256 words each.
    * 16 x 16 bit multiply unit.
    * 32-bit ALU, status register.
    * Hardware stack of 6 levels.
  * 128KB of DRAM.
  * 2KB of IRAM (instruction RAM).
  * Memory controller with address mapping capability.
  * 2MB of game ROM.

[5] claims there is also "2 Channels PWM" in the cartridge, but it's either
not used or not there at all. European cartridge doesn't have audio pins
connected.
Various sources claim that SSP160x is SSP1601 which is likely to be true,
because the code doesn't seem to use any SSP1605+ features.


-------------------------------------------------------------------------------
 2. The SSP160x DSP
-------------------------------------------------------------------------------

SSP160x is 16-bit DSP, capable of performing multiplication + addition in
single clock cycle [3]. It has 8 general, 8 external and 8 pointer registers.
There is a status register which has operation control bits and condition
flags. Condition flags are set/cleared during ALU (arithmetic, logic)
operations. It also has 6-level hardware stack and 2 internal RAM banks
RAM0 and RAM1, 256 words each.

The device is only capable of addressing 16-bit words, so all addresses refer
to words (16bit value in ROM, accessed by 68k through address 0x84 would be
accessed by SSP160x using address 0x42).

[3] mentions interrupt pins, but interrupts don't seem to be used by SVP code
(actually there are functions which look like interrupt handler routines, but
they don't seem to do anything important).

2.1. General registers
----------------------

There are 8 general registers: -, X, Y, A, ST, STACK, PC and P ([2] [4]).
Size is given in bits.

2.1.1. "-"
   Constant register with all bits set (0xffff). Also used for programming
   external registers (blind reads/writes, see 2.2).
   size: 16

2.1.2. "X"
   Generic register. Also acts as a multiplier 1 for P register.
   size: 16

2.1.3. "Y"
   Generic register. Also acts as a multiplier 2 for P register.
   size: 16

2.1.4. "A"
   Accumulator. Stores the result of all ALU (but not multiply) operations,
   status register is updated according to this. When directly accessed,
   only upper word is read/written. Low word can be accessed by using AL
   (see 2.2.8).
   size: 32

2.1.5. "ST"
   STatus register. Bits 0-9 are CONTROL, other are FLAG [2]. Only some of
   them are actually used by SVP.
   Bits: fedc ba98 7654 3210
     210 - RPL    "Loop size". If non-zero, makes (rX+) and (rX-) respectively
                  modulo-increment and modulo-decrement (see 2.3). The value
                  shows which power of 2 to use, i.e. 4 means modulo by 16.
     43  - RB     Unknown. Not used by SVP code.
     5   - ST5    Affects behavior of external registers. See 2.2.
     6   - ST6    Affects behavior of external registers. See 2.2.
                  According to [3] (5,6) bits correspond to hardware pins.
     7   - IE     Interrupt enable? Not used by SVP code.
     8   - OP     Saturated value? Not used by SVP code.
     9   - MACS   MAC shift? Not used by SVP code.
     a   - GPI_0  Interrupt 0 enable/status? Not used by SVP code.
     b   - GPI_1  Interrupt 1 enable/status? Not used by SVP code.
     c   - L      L flag. Similar to carry? Not used by SVP code.
     d   - Z      Zero flag. Set after ALU operations, when all 32 accumulator
                  bits become zero.
     e   - OV     Overflow flag. Not used by SVP code.
     f   - N      Negative flag. Set after ALU operations, when bit31 in
                  accumulator is 1.
   size: 16

2.1.6. "STACK"
   Hardware stack of 6 levels [3]. Values are "pushed" by directly writing to
   it, or by "call" instruction. "Pop" is performed by directly reading the
   register or by "ret" instruction.
   size: 16

2.1.7. "PC"
   Program Counter. Can be written directly to perform a jump. It is not clear
   if it is possible to read it (SVP code never does).
   size: 16

2.1.8. "P"
   multiply Product - multiplication result register.
   Always contains 32-bit multiplication result of X, Y and 2 (P = X * Y * 2).
   X and Y are sign-extended before performing the multiplication.
   size: 32

2.2. External registers
-----------------------

The external registers, as the name says, are external to SSP160x, they are
hooked to memory controller in SVP, so by accessing them we actually program
the memory controller. They act as programmable memory access registers or
external status registers [1]. Some of them can act as both, depending on how
ST5 ans ST6 bits are set in status register. After a register is programmed,
accessing it causes reads/writes from/to external memory (see section 3 for
the memory map). The access may also cause some additional effects, like
incremental of address, associated with accessed register.
In this document and my emu, instead of using names EXT0-EXT7
from [4] I used different names for these registers. Those names are from
Tasco Deluxe's [1] doc.

All these registers can be blind-accessed (as said in [1]) by performing
(ld -, PMx) or (ld PMx, -). This programs them to access memory (except PMC,
where the effect is different).
All registers are 16-bit.

2.2.1. "PM0"
   If ST5 or ST6 is set, acts as Programmable Memory access register
   (see 2.2.7). Else it acts as status of XST (2.2.4). It is also mapped
   to a15004 on 68k side:
     ???????? ??????10
     0: set, when SSP160x has written something to XST
        (cleared when a15004 is read by 68k)
     1: set, when 68k has written something to a15000 or a15002
        (cleared on PM0 read by SSP160x)
   Note that this is likely to be incorrect, but such behavior is OK for
   emulation to work.

2.2.2. "PM1"
   Programmable Memory access register. Only accessed with ST bits set by
   SVP code.

2.2.3. "PM2"
   Same as PM1.

2.2.4. "XST"
   If ST5 or ST6 is set, acts as Programmable Memory access register
   (only used by memory test code). Else it acts as eXternal STatus
   register, which is also mapped to a15000 and a15002 on 68k side.
   Affects PM0 when written to.

2.2.5. "PM4"
   Programmable Memory access register. Not affected by ST5 and ST6 bits,
   always stays in PMAR mode.

2.2.6. "EXT5"
   Not used by SVP, so not covered by this document.

2.2.7. "PMC"
   Programmable Memory access Control. It is set using 2 16bit writes, first
   address, then mode word. After setting PMAC, PMx should be blind accessed
   using (ld -, PMx) or (ld PMx, -) to program it for reading or writing
   external memory respectively. Every PMx register can be programmed to
   access it's own memory location with it's own mode. Registers are programmed
   separately for reading and writing.

   Reading PMC register also shifts it's state (from "waiting for address" to
   "waiting for mode" and back). In state "waiting for address" reads return
   address word related to last PMx register accessed. If read in "waiting for
   mode" state, we get the same value as in other state, but rotated by 4 (or
   with nibbles swapped, VR always does this to words with both bytes equal,
   like 'abab' to get 'baba' for chessboard dithering effect).

   The address word contains bits 0-15 of the memory word-address.
   The mode word format is as follows:
     dsnnnv?? ???aaaaa
     a: bits 16-20 of memory word-address.
     n: auto-increment value. If set, after every access of PMx, word-address
        value related to it will be incremented by (words):
          1 - 1    5 - 16
          2 - 2    6 - 32
          3 - 4    7 - 128
          4 - 8
     d: make auto-increment negative - decrement by count listed above.
     s: special-increment mode. If current address is even (when accessing
        programmed PMx), increment it by 1. Else, increment by 32. It is not
        clear what happens if d and n bits are also set (never done by SVP).
     v: over-write mode when writing, unknown when reading (not used).
        Over-write mode splits the word being written into 4 nibbles and only
        writes out ones which are non zero.
   When auto-increment is performed, it affects all 21 address bits.

2.2.8. "AL"
   This register acts more like a general register.
   If this register is blind-accessed, it is "dummy programmed", i.e. nothing
   happens and PMC is reset to "waiting for address" state.
   In all other cases, it is Accumulator Low - 16 least significant bits of
   accumulator. Normally reading acc (ld X, A) you get 16 most significant
   bits, so this allows you access the low word of 32bit accumulator.

2.3. Pointer registers
----------------------

There are 8 8-bit pointer registers rX, which are internal to SSP160x and are
used to access internal RAM banks RAM0 and RAM1, or program memory indirectly.
r0-r3 (ri) point to RAM0, r4-r7 (rj) point to RAM1. Each bank has 256 words of
RAM, so 8bit registers can fully address them. The registers can be accessed
directly, or 2 indirection levels can be used [ (rX), ((rX)) ]. They work
similar to * and ** operators in C, only they use different types of memory
and ((rX)) also performs post-increment. First indirection level (rX) accesses
a word in RAMx, second accesses program memory at address read from (rX), and
increments value in (rX).

Only r0,r1,r2,r4,r5,r6 can be directly modified (ldi r0, 5), or by using
modifiers. 3 modifiers can be applied when using first indirection level
(optional):
  + : post-increment  (ld a, (r0+) ). Increment register value after operation.
      Can be made modulo-increment by setting RPL bits in status register
      (see 2.1.5).
  - : post-decrement. Also can be made modulo-decrement by using RPL bits in ST.
  +!: post-increment, unaffected by RPL (probably).
These are only used on 1st indirection level, so things like ( ld a, ((r0+)) )
and (ld X, r6-) are probably invalid.

r3 and r7 are special and can not be changed (at least Samsung samples [4] and
SVP code never do). They are fixed to the start of their RAM banks. (They are
probably changeable for ssp1605+, Samsung's old DSP page claims that).
1 of these 4 modifiers must be used on these registers (short form direct
addressing? [2]):
  |00: RAMx[0] The very first word in the RAM bank.
  |01: RAMx[1] Second word
  |10: RAMx[2] ...
  |11: RAMx[3]

2.4. The instruction set
------------------------

The Samsung SSP16 series assembler uses right-to-left notation ([2] [4]):
ld X, Y
means value from Y should be copied to X.

Size of every instruction is word, some have extension words for immediate
values. When writing an interpreter, 7 most significant bits are usually
enough to determine which opcode it is.

encoding bits are marked as:
rrrr - general or external register, in order specified in 2.1 and 2.2
       (0 is '-', 1 'X', ..., 8 is 'PM0', ..., 0xf is 'AL')
dddd - same as above, as destination operand
ssss - same as above, as source operand
jpp  - pointer register index, 0-7
j    - specifies RAM bank, i.e. RAM0 or RAM1
i*   - immediate value bits
a*   - offset in internal RAM bank
mm   - modifier for pointer register, depending on register:
         r0-r2,r4-r6   r3,r7   examples
       0:     (none)     |00   ld  a, (r0)       cmp a, (r7|00)
       1:         +!     |01   ld  (r0+!), a     ld  (r7|01), a
       2:          -     |10   add a, (r0-)
       3:          +     |11
cccc - encodes condition, only 3 used by SVP, see check_cond() below
ooo  - operation to perform

Operation is written in C-style pseudo-code, where:
program_memory[X]  - access program memory at address X
RAMj[X]            - access internal RAM bank j=0,1 (RAM0 or RAM1), word
                     offset X
RIJ[X]             - pointer register rX, X=0-7
pr_modif_read(m,X) - read pointer register rX, applying modifier m:
                       if register is r3 or r7, return value m
                       else switch on value m:
                         0: return rX;
                         1: tmp = rX; rX++; return tmp; // rX+!
                         2: tmp = rX; modulo_decrement(rX); return tmp; // rX-
                         3: tmp = rX; modulo_increment(rX); return tmp; // rX+
                       the modulo value used (if used at all) depends on ST
                       RPL bits (see 2.1.5)
check_cond(c,f)    - checks if a flag matches f bit:
                     switch (c) {
                       case 0: return true;
                       case 5: return (Z == f) ? true : false; // check Z flag
                       case 7: return (N == f) ? true : false; // check N flag
                     } // other conditions are possible, but they are not used
update_flags()     - update ST flags according to last ALU operation.
sign_extend(X)     - sign extend 16bit value X to 32bits.
next_op_address()  - address of instruction after current instruction.

2.4.1. ALU instructions

All of these instructions update flags, which are set according to full 32bit
accumulator. The SVP code only checks N and Z flags, so it is not known when
exactly OV and L flags are set. Operations are performed on full A, so
(andi A, 0) would clear all 32 bits of A.

They share the same addressing modes. The exact arithmetic operation is
determined by 3 most significant (ooo) bits:
  001 - sub - subtract     (OP -=)
  011 - cmp - compare      (OP -, flags are updated according to result)
  100 - add - add          (OP +=)
  101 - and - binary AND   (OP &=)
  110 - or  - binary OR    (OP |=)
  111 - eor - exclusive OR (OP ^=)

 syntax        encoding             operation
 OP  A, s      ooo0 0000 0000 rrrr  A OP r << 16;
 OP  A, (ri)   ooo0 001j 0000 mmpp  A OP RAMj[pr_modif_read(m,jpp)] << 16;
 OP  A, adr    ooo0 011j aaaa aaaa  A OP RAMj[a] << 16;
 OPi A, imm    ooo0 1000 0000 0000  A OP i << 16;
               iiii iiii iiii iiii
 op  A, ((ri)) ooo0 101j 0000 mmpp  tmp = pr_modif_read(m,jpp);
                                    A OP program_memory[RAMj[tmp]] << 16;
                                    RAMj[tmp]++;
 op  A, ri     ooo1 001j 0000 00pp  A OP RIJ[jpp] << 16;
 OPi simm      ooo1 1000 iiii iiii  A OP i << 16;

Note that in (OP A, s) case, if s is 32bit register, operation is performed on
all 32 bits, including when s is accumulator itself, like for (and A, A), which
is a valid operation.

There is also "perform operation on accumulator" instruction:

 syntax        encoding             operation
 mod cond, op  1001 000f cccc 0ooo  if (check_cond(c,f)) switch(o) {
                                      case 2: A >>= 1; break; // arithmetic shift
                                      case 3: A <<= 1; break;
                                      case 6: A = -A;  break; // negate A
                                      case 7: A = abs(A); break; // absolute val.
                                    } // other operations are possible, but
                                      // they are not used by SVP.

2.4.2. Load (move) instructions

These instructions never affect flags (even ld A).
If destination is A, and source is 16bit, only upper word is transfered (same
thing happens on opposite). If dest. is A, and source is P, whole 32bit value
is transfered. It is not clear if P can be destination operand (probably not,
no code ever does this).
Writing to STACK pushes a value there, reading pops. It is not known what
happens on overflow/underflow (never happens in SVP code).
ld -, - is used as a nop.

 syntax        encoding             operation
 ld  d, s      0000 0000 dddd ssss  d = s;
 ld  d, (ri)   0000 001j dddd mmpp  d = RAMj[pr_modif_read(m,jpp)];
 ld  (ri), s   0000 010j ssss mmpp  RAMj[pr_modif_read(m,jpp)] = s;
 ldi d, imm    0000 1000 dddd 0000  d = i;
               iiii iiii iiii iiii
 ld  d, ((ri)) 0000 101j dddd mmpp  tmp = pr_modif_read(m,jpp);
                                    d = program_memory[RAMj[tmp]];
                                    RAMj[tmp]++;
 ldi (ri), imm 0000 110l 0000 mmpp  RAMj[pr_modif_read(m,jpp)] = i;
               iiii iiii iiii iiii
 ld  adr, a    0000 111j aaaa aaaa  RAMj[a] = A;
 ld  d, ri     0001 001j dddd 00pp  d = RIJ[jpp];
 ld  ri, s     0001 010j ssss 00pp  RIJ[jpp] = s;
 ldi ri, simm  0001 1jpp iiii iiii  RIJ[jpp] = i;
 ld  d, (a)    0100 1010 dddd 0000  d = program_memory[A[31:16]];
                                    // read a word from program memory. Offset
                                    // is the upper word in A.

2.4.3. Program control instructions

Only 3 instructions: call, ret (alias of ld PC, STACK) and branch. Indirect
jumps can be performed by simply writing to PC.

 syntax           encoding             operation
 call cond, addr  0100 100f cccc 0000  if (check_cond(c,f)) {
                  aaaa aaaa aaaa aaaa    STACK = next_op_address(); PC = a;
                                       }
 bra  cond, addr  0100 110f cccc 0000  if (check_cond(c,f)) PC = a;
                  aaaa aaaa aaaa aaaa
 ret              0000 0000 0110 0101  PC = STACK; // same as ld PC, STACK

2.4.4. Multiply-accumulate instructions

Not sure if (ri) and (rj) really get loaded into X and Y, but multiplication
result surely is loaded into P. There is probably optional 3rd operand (1, 0;
encoded by bit16, default 1), but it's not used by SVP code.

 syntax           encoding             operation
 mld  (rj), (ri)  1011 0111 nnjj mmii  A = 0; update_flags();
                                       X = RAM0[pr_modif_read(m,0ii)];
                                       Y = RAM1[pr_modif_read(m,1jj)];
                                       P = sign_extend(X) * sign_extend(Y) * 2
 mpya (rj), (ri)  1001 0111 nnjj mmii  A += P; update_flags();
                                       X = RAM0[pr_modif_read(m,0ii)];
                                       Y = RAM1[pr_modif_read(m,1jj)];
                                       P = sign_extend(X) * sign_extend(Y) * 2
 mpys (rj), (ri)  0011 0111 nnjj mmii  A -= P; update_flags();
                                       X = RAM0[pr_modif_read(m,0ii)];
                                       Y = RAM1[pr_modif_read(m,1jj)];
                                       P = sign_extend(X) * sign_extend(Y) * 2

-------------------------------------------------------------------------------
 3. Memory map
-------------------------------------------------------------------------------

The SSP160x can access it's own program memory, and external memory through EXT
registers (see 2.2). Program memory is read-execute-only, the size of this
space is 64K words (this is how much 16bit PC can address):

   byte address  word address  name
        0-  7ff        0- 3ff  IRAM
      800-1ffff      400-ffff  ROM

There were reports that SVP has internal ROM, but fortunately they were wrong.
The location 800-1ffff is mapped from the same location in the 2MB game ROM.
The IRAM is read-only (as SSP160x doesn't have any means of writing to it's
program memory), but it can be changed through external memory space, as it's
also mapped there.

The external memory space seems to match the one visible by 68k, with some
differences:

       68k space      SVP space   word address  name
        0-1fffff       0-1fffff       0- fffff  game ROM
   200000-2fffff              ?              ?  unused (1)
   300000-31ffff  300000-31ffff  180000-18ffff  DRAM
   320000-37ffff              ?              ?  3 mirrors od DRAM
   380000-38ffff              ?              ?  unused (1)
               ?  390000-3907ff  1c8000-1c83ff  IRAM
   390000-39ffff              ?              ?  "cell arrange" 1
   3a0000-3affff              ?              ?  "cell arrange" 2
   3b0000-3fffff              ?              ?  unused (2)
   a15000-a1500f            n/a            n/a  Status/control registers

   unused (1) - reads seem to return data from internal bus (last word read by
                SSP160x). Writes probably have no effect.
   unused (2) - reads return 0xffff, writes have no effect.

The external memory can be read/written by SSP160x (except game ROM, which can
only be read).

"cell arrange" 1 and 2 are similar to the one used in SegaCD, they map
300000-30ffff location to 390000-39ffff and 3a0000-3affff, where linear image
written to 300000 can be read as VDP patterns at 390000. Virtua Racing doesn't
seem to use this feature, it is only used by memory test code.

Here is the list of status/control registers (16bit size):

   addr   rst v  description
   a15000  ffff  w/r command/result register. Visible as XST for SSP160x
                 see (2.2.4).
   a15002  ffff  mirror of the above.
   a15004     0  status of command/result register (see 2.2.1).
   a15006  ffff  possibly halts the SVP. Before doing DMA from DRAM, 68k code
                 writes 0xa, and after it's finished, writes 0. This is probably
                 done to prevent SVP accessing DRAM and avoid bus clashes.
   a15008  ffff  possibly causes an interrupt. There is (unused?) code which
                 writes 0, 1, and again 0 in sequence.
   a1500a  ffff  ?
   a1500c  ffff  ?
   a1500e  ffff  ?

-------------------------------------------------------------------------------
 4. Other notes
-------------------------------------------------------------------------------

The game has arcade-style memory self-check mode, which can be accessed by
pressing _all_ buttons (including directions) on 3-button controller. There was
probably some loopback plug for this.

SVP seems to have DMA latency issue similar to one in Sega CD, as the code
always sets DMA source address value larger by 2, then intended for copy.
This is even true for DMAs from ROM, as it's probably hooked through SVP's
memory controller.

The entry point for the code seems to be at address 0x800 (word 0x400) in ROM,
but it is not clear where the address is fetched from when the system powers
up. The memory test code also sets up "ld PC, .." opcodes at 0x7f4, 0x7f8 and
0x7fc, which jump to some routines, possibly interrupt handlers. This means
that mentioned addresses might be built-in interrupt vectors.

The SVP code doesn't seem to be timing sensitive, so it can be emulated without
knowing timing of the instructions or even how fast the chip is clocked.
Overclocking doesn't have any effect, underclocking causes slowdowns. Running
10-12M instructions/sec (or possibly less) is sufficient.