SVP Register Guide (2008-02-06)

From Sega Retro

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: https://web.archive.org/web/20081016151832/www.sharemation.com/TascoDLX/SVP%20Register%20Guide%202008.02.06.txt

==================

SVP Register Guide (annotated)

by Tasco Deluxe < tasco.deluxe @ gmail.com >

Final Update:  2008.02.06 -- fully revised, many corrections

[Previous update:  2007.02.11 -- released to the public]
[Previous update:  2007.01.10 (unpublished) -- revised and corrected]
[Previous update:  2006.04.18 (unpublished) -- revised]
[Previous update:  2005.07.20 (unpublished) -- added annotation]
[First edition:    2004.03.19 (unpublished)]

============================================

Copyright (c) 2004 - 2008, Tasco Deluxe.  Some rights reserved.

This work is licensed under the Creative Commons Attribution License.
To view a copy of this license, visit http://creativecommons.org/licenses/by/2.5/
or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

DO NOT modify or redistribute this document without reading the license.

Attribution should be in the form of name (Tasco Deluxe) AND email address (tasco.deluxe @ gmail.com).


*** Disclaimer***

All information herein was obtained by reverse engineering code from the US version of Virtua Racing
for the Sega Genesis system.  Some information may be incorrect and/or incomplete.  Use at your own risk!


*** This document is offered as a supplement to the SVP Reference Guide ***

^^^^^^^^^^^^^^^^
    Contents
^^^^^^^^^^^^^^^^

A.      Primary Register Set

A.01    Null Register - r_0
A.02    Multiplier Input Registers X,Y - r_1, r_2
A.03    Accumulator Registers - r_3, r_f, acc
A.04    Status Register - r_4
A.05    Stack Register - r_5
A.06    Program Counter Register - r_6
A.07    Product Register - r_7
A.08    External Registers - r_8, r_9, r_a, r_b
A.08.1    External Status/Control Register - r_8
A.08.2    External Command Register - r_b
A.09    Programmable Memory Access Registers - r_8, r_9, r_a, r_b, r_c
A.10    Programmable Memory Access Control Register - r_e

B.      Pointer Register Set

B.01    RAM Banks
B.02    Pointer Registers - p_A*, p_B*
B.03    Data Pointer Registers - dp_A*, dp_B*

X.      PMAR Programming Guide

X.01    Programming the PMARs
X.02    PMAR Control Register
X.02.1    Control - Address
X.02.2    Control - Mode
X.03    Untested Modes


^^^^^^^^^^^^^^^^^^^^^^^^^^
A.    Primary Register Set
^^^^^^^^^^^^^^^^^^^^^^^^^^

A.01  Null Register - r_0
=========================
Used for blind reads and blind writes.

Most commonly, the Null Register is used as an operand for LD instructions.
When used as the source register, the destination is accessed but no data is written.
When used as the destination register, the source is accessed but no data is read.

Blind reads and blind writes are useful when accessing PMARs (see the PMAR Programming Guide).
Also useful for advancing registers without accessing data in memory.


A.02  Multiplier Input Registers - r_1, r_2
===========================================
Stores the multiplicands for the multiplication unit.

The values in these registers are multiplied and the product is stored in the Product Register r_7.
Either of these registers can be loaded by a LD instruction, or both by a MLD, MPYA, or MPYS instruction.

These registers can also be used to store data for general purposes if the product register is not in use.


A.03  Accumulator Registers - r_3, r_f, acc
===========================================
Actually, a single register for arithmetic operations.

The Accumulator is 32-bits wide with r_3 representing the upper 16 bits and r_f representing
the lower 16 bits.  In this guide, acc is used as an alias for the concatenation of r_3 and r_f.

Most instructions either operate on r_3 (16 bits) or acc (32 bits).  For instance, ADD and SUB are
16-bit operations, so they affect r_3.  On the other hand, SHL, SHR, MLD, MPYA, and MPYS affect acc.
However, the AND instruction in the form of AND r_3, short 0x00 seems to be used to clear acc.

r_f may also be used when dealing with the PMARs (see the section titled PMAR Programming Guide).


A.04  Status Register - r_4
===========================
Controls various functions.

?????????rr??mmm [16-bit]
    

         rr    PMAR Control flags
         ------------------------
         BA    These two bits determine if the corresponding registers access external registers or PMARs
               if A is set, r_8 and r_9 access PMARs
               if B is set, r_a and r_b access PMARs


             mmm   Pointer Register Modulo
             -----------------------------
             ...   Indicates the modulo value used for the pointer registers' modulo post-increment or post-decrement
             * The value mmm indicates a power of 2 on which the register will wrap around.
             * See the section on Pointer Registers for details.


On reset, the initial value of the Status Register is 0000 (!speculation!).


A.05  Stack Register - r_5
==========================
Used to access the stack.

Upon executing a CALL instruction, the return address is pushed onto the stack.
To return from the subroutine, a LD instruction pops the return address to the
Program Counter register [ld r_6, r_5].

VR's SVP code doesn't explicitly write to the Stack Register so its currently
unknown if that is even possible.

The location of the stack is unknown, but it may be positioned high in RAM bank A.
If there is separate internal memory for the stack, its size is unknown, but VR's
SVP code only appears to stack a few calls at a time.  Often, the code opts to
use a software stack.


A.06  Program Counter Register - r_6
====================================
Contains the address to execute next.

Code addresses are interpreted as follows:

x0000 thru x03ff, in Instruction RAM (!a.k.a. PRAM!)
x0400 thru xffff, in ROM

This register can be altered indirectly via BRA or CALL instructions or directly via LD instructions.

It's currently unclear, but on reset, the initial value of this register is either:

a) The value located at x00e7 in ROM

or
 
b) The value x0400 (i.e., the lowest executable ROM address)

For VR, they are both the same value.


A.07  Product Register - r_7
============================
Used to store the product of multiplication inputs X and Y (r_1 and r_2).

The Product Register is read-only and considered to be 32 bits wide.

The only instructions to use the Product Register explicitly are LD [ld r_3, r_7] and ADD [add r_3, r_7].

For a LD instruction, the value stored in the Product Register is shifted left once (i.e., doubled) then 
stored in the Accumulator register (upper 16 bits in r_3, lower 16 bits in r_f).

For a ADD instruction, the value stored in the Product Register is shifted left once (i.e., doubled) then
added to the Accumulator Register (upper 16 bits in r_3, lower 16 bits in r_f).


A.08  External Registers - r_8, r_9, r_a, r_b
=============================================
When Status Register (r_4) bit 5 is cleared, r_8 and r_9 function as external registers.
When Status Register (r_4) bit 6 is cleared, r_a and r_b function as external registers.

r_8  Read - External Status Register, Write - External Control Register
r_9  unknown / unused
r_a  unknown / unused
r_b  Read / Write - External Command Register


A.08.1  External Status/Control Register - r_8
----------------------------------------------
??????????????c? [16-bit, read]
   
              c   External Command Available
              ------------------------------
              0   ---
              1   An external command was written to the External Command Register (by the M68000).


???iii?????????? [16-bit, write]
   
   iii   Interrupt Enable (!unconfirmed!)
   ----------------------
   CBA   Individual enable bits for three interrupt routines (A, B, and C)
   * SVP interrupts are NOT used in VR, though the code that handles them remains.
   * The interrupt routines are vectored via branch instructions at the top of IRAM (03fa, 03fc, 03fe).
   * Triggers for the interrupts are unknown. (!maybe timer or maybe external!)


A.08.2  External Command Register - r_b
---------------------------------------
Used to transfer commands between the M68000.

VR uses M68000 address xa15000 (mirrored at xa15002) to map the Command Register.

The meaning of the command is specific to the application.  In VR's case,
the register is receive the operating mode command (render mode 'OH' or test mode 'RT')
but mostly to communicate with the M68000 in test mode.


A.09  Programmable Memory Access Register - r_8, r_9, r_a, r_b, r_c
===================================================================
The Programmable Memory Access Registers (or PMARs, for short) allow
read or write access to either DRAM, Instruction RAM, or ROM (via paging).

When Status Register (r_4) bit 5 is set, r_8 and r_9 function as PMARs.
When Status Register (r_4) bit 6 is set, r_a and r_b function as PMARs.
r_c always functions as a PMAR regardless of r_4.

The PMARs are programmed via the Programmable Memory Access Control Register r_e.
Instructions on programming the PMARs are provided in the section titled PMAR Programming Guide.


A.10  Programmable Memory Access Control Register - r_e
=======================================================
The Control Register is the key to programming the PMARs.

Details on its function are described in the section titled PMAR Programming Guide.



^^^^^^^^^^^^^^^^^^^^^^^^^^^^
B.    RAM Bank Register Set
^^^^^^^^^^^^^^^^^^^^^^^^^^^^


B.01  RAM Bank
==============
There are two RAM banks, each 256 words, referred to as RAM bank A and RAM bank B.

Each bank has its own register set consisting of:

- 3 Pointer Registers
- 4 Data Pointer Registers

The SVP, like many DSPs, is capable of accessing both RAM banks at the same time.
This is important for the MPY instructions which read two words, one from each bank,
in the same clock cycle.


B.02  Pointer Register - p_A*, p_B*
===================================
Pointer Registers are able to access banked RAM directly and ROM indirectly.

There are two sets of Pointer Registers, one for each RAM bank [A and B].

p_A0, p_A1, and p_A2 belong to RAM bank A.
p_B0, p_B1, and p_B2 belong to RAM bank B.

They are byte-sized and can be accessed in the following ways:

Register                                 p_reg        Read/Write p_reg
RAM Indirect                             [p_reg]      Read/Write at RAM address p_reg
RAM Indirect w/ Post Increment           [p_reg++]    Read/Write at RAM address p_reg, then increment p_reg by 1
RAM Indirect w/ Modulo Post Decrement    [p_reg--]    Read/Write at RAM address p_reg, then modulo decrement p_reg by 1
RAM Indirect w/ Modulo Post Increment    [p_reg+!]    Read/Write at RAM address p_reg, then modulo increment p_reg by 1
ROM Indirect w/ Indirect Post Increment  ([p_reg]++)  Read from ROM address [p_reg], then increment [p_reg] by 1

Modulo Increment/Decrement
--------------------------
Modulo increment and decrement can be used to constrain Pointer Registers to an aligned range of addresses.

The modulo value is stored in the Status Register (r_4) as a power of 2.  Possible values range from 1 (2^1 = 2)
to 7 (2^7 = 128).  A value of 0 effectively disables the modulo, so a modulo post-increment would be treated
as a normal post-increment.

When modulo is active, for a modulo value of n, the increment or decrement is only applied to the lowest n bits.

For example,
- If modulo = 4 (2^4 = 16) when p_A0 = 0x0f, p_A0+! will advance to p_A0 = 0x00 (wrap)
- If modulo = 5 (2^5 = 32) when p_A0 = 0x0f, p_A0+! will advance to p_A0 = 0x10 (no wrap)

- If modulo = 5 (2^5 = 32) when p_A0 = 0x3f, p_A0+! will advance to p_A0 = 0x20 (wrap)
- If modulo = 6 (2^6 = 64) when p_A0 = 0x3f, p_A0+! will advance to p_A0 = 0x00 (wrap)

- If modulo = 4 (2^4 = 16) when p_A0 = 0x10, p_A0-- will advance to p_A0 = 0x1f (wrap)
- If modulo = 5 (2^6 = 32) when p_A0 = 0x00, p_A0-- will advance to p_A0 = 0x1f (wrap)


B.03  Data Pointer Register - dp_A*, dp_B*
==========================================
Data Pointer Registers are able to store source data and access ROM directly.

There are two sets of Data Pointer Registers, one for each RAM bank [A and B].
The Data Pointers don't actually access RAM, but they are used as source data
for instructions that access both RAM banks (e.g., multiply instructions).

dp_A0, dp_A1, dp_A2, and dp_A3 belong to RAM bank A.
dp_B0, dp_B1, dp_B2, and dp_B3 belong to RAM bank B.

They can be accessed in the following ways:

Register                        dp_reg      Read/Write dp_reg
ROM Indirect w/ Post Increment  (dp_reg++)  Read from ROM address dp_reg, then increment dp_reg by 1



^^^^^^^^^^^^^^^^^^^^^^^^^^^^
X.    PMAR Programming Guide
^^^^^^^^^^^^^^^^^^^^^^^^^^^^


X.01  Programming the PMARs
===========================
The process of programming a PMAR can be simplified in three steps:

Step 1  Write 16-bit address to r_e
Step 2  Write 16-bit mode to r_e
Step 3  Read from or write to the PMAR you wish to assign access
        * A blind read or blind write is used to assign access to a PMAR

Read access and write access for a single PMAR can and must be programmed separately.
This allows a single PMAR to read from one location and write to a completely different location.

Keep in mind when transferring data between PMARs, an intermediate data register is required.


X.02  PMAR Control Register
===========================
Normally, the Control Register is accessed by writing the appropriate value, but
the register can also be read from in certain cases.

The assigned address of a PMAR can be changed by writing the new value and using
a blind read on r_e to adjust the latch (uses the previously assigned mode).
The reverse of this procedure can be used to change the mode.

The value returned by a read from r_e when the address is latched is the current (updated) address
from the last PMAR access.  The value returned when the mode is latched has not quite been determined.
In VR's SVP code, a word is written when the address is latched, and subsequently read back when
the mode is latched.  The value returned is (apparently) a 4-bit rotation of written data.
A blind read access on r_f is performed afterwards, likely to prevent a false PMAR assignment.

The control words written -- address and mode, respectively -- are described here.


X.02.1  Control -- Address
--------------------------
The 16-bit address you wish to access, whether read or write.

The memory location that the address refers to depends on the mode.


X.02.2  Control -- Mode
-----------------------
A description of the address (i.e., mode of access).

The mode word is:

dsnnnv?????bpppp [16-bit]

 
           b   Memory Bus
           --------------
           0   ROM addressing
           1   RAM addressing -- Instruction RAM or DRAM
 

            pppp   Memory Page
            ------------------
            For ROM addressing,
            ....   Each page accounts for 64 KWords of ROM
                   * for increment / decrement modes, address may wrap at the end of a page (!speculation!)
            For RAM addressing,
            1000   DRAM
            1100   Instruction RAM, starts at address 8000
                   * other pages are untested


     v   Overwrite Mode
     ------------------
     0   ---
     1   Enable overwrite mode, 4-bit source value of 0 does not overwrite destination
         * Only useful for write access -- effect on read access is untested / unknown


d   Increment / Decrement Mode
------------------------------
0   Increment Address
1   Decrement Address
    * After a PMAR is accessed, its address is automatically incremented or decremented 
      depending on this mode and the Displacement Value


  nnn   Displacement Value
  ------------------------
  000   no displacement
  001   1 word displacement
  010   2 word displacement
  011   4 word displacement
  100   8 word displacement
  101   16 word displacement
  110   32 word displacement
  111   custom displacement (* see "Special Modes" below *)

 s   Bitmap Access Mode (* see "Special Modes" below *)
 ----------------------
 0   ---
 1   Special displacement for writing to pattern memory


X.03  Special Modes
===================

Custom Displacement
-------------------
To use a custom displacement value, the following steps are performed (!per VR's SVP code!):

- The PMAR register is assigned with a blind read or write
- A custom Displacement Value (in words) is written to r_e
- A blind read is performed on r_f (probably to reset the control register)


Bitmap Access Mode
------------------
This mode allows access to memory (specifically pattern memory) in a linear format.
The address is incremented by 32 at even addresses.

Since Genesis/MegaDrive graphics are organized as 8x8 pixel cells, this special mode
is required to write linearly to the pattern memory (or similarly to read from it).

The scroll plane allocated to a SVP game (i.e., Virtua Racing) is setup to display
patterns in double-tall rows.  This format allows virtual cells of 8x16.

Cell layout:

00 02 04 06 08 0A 0C 0E 10 12 14 16 18 1A 1C 1E
01 03 05 07 09 0B 0D 0F 11 13 15 17 19 1B 1D 1F
20 22 24 26 28 2A 2C 2E 30 32 34 36 38 3A 3C 3E
21 23 25 27 29 2B 2D 2F 31 33 35 37 39 3B 3D 3F
40 42 44 ...
41 43 45 ...

* NOTE:  Wnen in interlaced mode 2, the layout is single rows straight through.

Illustrated below, the words at offsets 0000 and 0001 represent the top row (8 pixels)
of a virtual cell.  The next two words at offsets 0002 and 0003 represent the next row.
After the bottom row at offsets 001E and 001F, the next words at offsets 0020 and 0021
jump back up to line 1 to represent the top row of the next cell over.

line 1  ->  0000 0001 0020 0021
line 2  ->  0002 0003 0022 0023
line 3  ->  0004 0005 0024 0025
line 4  ->  0006 0007 0026 0027
line 5  ->  0008 0009 0028 0029
line 6  ->  000A 000B 002A 002B
line 7  ->  000C 000D 002C 002D
line 8  ->  000E 000F 002E 002F
line 9  ->  0010 0011 0030 0031
line 10 ->  0012 0013 0032 0033
line 11 ->  0014 0015 0034 0035
line 12 ->  0016 0017 0036 0037
line 13 ->  0018 0019 0038 0039
line 14 ->  001A 001B 003A 003B
line 15 ->  001C 001D 003C 003D
line 16 ->  001E 001F 003E 003F

In Bitmap Access Mode, the address is incremented so that when moving from an odd address
to an even address it skips ahead by 32 allowing data to be written straight through a line.

Using Bitmap Access Mode with a Displacement Value other than 0 has not been tested.
It is assumed to be ignored, given the nature of the mode.

The effect of using Decrement mode with Bitmap Access Mode is untested/unknown.