Copy Link
Add to Bookmark
Report

Collection of C codes for the Sega Dreamcast

Dreamcast's profile picture
Published in 
Dreamcast
 · 4 Nov 2018

(De)scrambler for Dreamcast executables on normal CDs.

/ * dcrp.c - scrambles and unscrambles Dreamcast-executables 
*
* 2000 < c > Maiwe
*
* contact: jlo@ludd.luth.se
*
* /

/ * Notes:
* ~~~~~~
*
* Dreamcast(tm) has a special method for booting regular CDs as opposed
* to GDs. The executable file to be booted must be scrambled in a
* certain way in order to execute properly which is what this program
* does.
*
* /

#include < sys/stat.h >
#include < errno.h >
#include < unistd.h >
#include < stdlib.h >
#include < stdio.h >

int main(int, char **);
void usage(void);
void scramble(void);
void scramble2(int, char *);
void copy_data(char *);
void unscramble(void);
void unscramble2(int, char *);
void copy_data2(char *);

unsigned int permutation_key = 0;
unsigned short permutation_buf[0x10000];
char *input_buf;
char *output_buf;
int buf_pos;
int data_size;

int
main(argc, argv)
int argc;
char **argv;
{

struct stat st_buf;
FILE *ins, *outs;

if (argc != 4)
usage();

if (stat(argv[2], &st_buf) < 0) {
fprintf(stderr, "dcrp: %s: %s\n", argv[2], strerror(errno));
exit (-1);
}

data_size = st_buf.st_size;
if (!(input_buf = malloc(data_size))) {
fprintf(stderr, "dcrp: %s\n", strerror(errno));
exit (-1);
}
if (!(output_buf = malloc(data_size))) {
fprintf(stderr, "dcrp: %s\n", strerror(errno));
exit (-1);
}

ins = fopen(argv[2], "r");
if (ins == NULL) {
fprintf(stderr, "dcrp: %s: %s\n", argv[2], strerror(errno));
exit (-1);
}

outs = fopen(argv[3], "w");
if (outs == NULL) {
fprintf(stderr, "dcrp: %s: %s\n", argv[3], strerror(errno));
exit (-1);
}

if (fread(input_buf, data_size, 1, ins) != 1) {
if (ferror(ins)) {
fprintf(stderr, "dcrp: fread() failed: %s\n", strerror(errno));
exit (-1);
}
fprintf(stderr, "dcrp: fread() failed: not all of input file read\n");
exit (-1);
}

fclose(ins);

if (strcmp(argv[1], "scramble") == 0)
scramble();
else if (strcmp(argv[1], "unscramble") == 0)
unscramble();
else
usage();

if (fwrite(output_buf, data_size, 1, outs) != 1) {
if (ferror(outs)) {
fprintf(stderr, "dcrp: fwrite() failed: %s\n", strerror(errno));
exit (-1);
}
fprintf(stderr, "dcrp: fwrite() failed: not all of input file written\n");
exit (-1);
}

fprintf(stdout, "Done\n");

}

void
usage()
{
fprintf(stderr, "dcrp v1.1 13-Jun-2000 < c > Maiwe\n");
fprintf(stderr, "usage: dcrp < scramble | unscramble > < input > < output >\n");
exit (-1);
}

void
scramble()
{

int j;
char *ptr;
int align;
int size = data_size;

permutation_key = size & 0x0000ffff;
buf_pos = 0;

align = size & 0x0000001f;
if (align != 0)
size -= align;

ptr = input_buf;
j = 0x00200000;
do {
while (size >= j) {
scramble2(j, ptr);
size = size - j;
ptr = ptr + ((j>>2) < < 2);
}
j = j>>1;
} while (j >= 0x20);

if (align != 0)
copy_data(ptr);

}

void
scramble2(size, addr)
int size;
char *addr;
{

unsigned short *ptr = permutation_buf;
int i;
int bs = size>>5;
unsigned short *k;
unsigned short index;
int m;
unsigned short temp;

for (i = 0; i < bs; i++)
ptr[i] = i;

k = &ptr[bs-1];
for (m = bs - 1; m >= 0; m--) {
permutation_key = (permutation_key * 2109 + 9273) & 0x7fff;
index = (((permutation_key + 0xc000) & 0xffff) * m)>>16;

temp = ptr[index];
ptr[index] = *k;
*k = temp;
copy_data(addr + ((*k) < < 5));
k--;
}

}

void
copy_data(addr)
char *addr;
{
int i;

for (i = 0; i < 0x20 && buf_pos < data_size; i++)
*(output_buf + (buf_pos++)) = addr[i];
}

void
unscramble()
{

int j;
char *ptr;
int align;
int size = data_size;

permutation_key = size & 0x0000ffff;
buf_pos = 0;

align = size & 0x0000001f;
if (align != 0)
size -= align;

ptr = output_buf;
j = 0x00200000;
do {
while (size >= j) {
unscramble2(j, ptr);
size = size - j;
ptr = ptr + ((j>>2) < < 2);
}
j = j>>1;
} while (j >= 0x20);

if (align != 0)
copy_data2(ptr);

}

void
unscramble2(size, addr)
int size;
char *addr;
{

short *ptr = permutation_buf;
int i;
int bs = size>>5;
unsigned short *k;
unsigned short index;
int m;
unsigned short temp;

for (i = 0; i < bs; i++)
ptr[i] = i;

k = &ptr[bs-1];
for (m = bs - 1; m >= 0; m--) {
permutation_key = (permutation_key * 2109 + 9273) & 0x7fff;
index = (((permutation_key + 0xc000) & 0xffff) * m)>>16;

temp = ptr[index];
ptr[index] = *k;
*k = temp;
copy_data2(addr + ((*k) < < 5));
k--;
}

}

void
copy_data2(addr)
char *addr;
{
int i;

for (i = 0; i < 0x20 && buf_pos < data_size; i++)
addr[i] = *(input_buf + (buf_pos++));
}

Dreamcast memory layout

0x00000000 - 0x001fffff:	ROM 
0x00200000 - 0x0021ffff: flash ROM
0x00220000 - 0x003fffff: not used (mirror of flash ROM)
0x00400000 - 0x007fffff: hardware registers
0x00800000 - 0x009fffff: sound RAM
0x00a00000 - 0x00ffffff: not used (mirror of sound RAM)
0x01000000 - 0x01ffffff: system devices (?)
0x02000000 - 0x027fffff: not used (mirror of ROM)
0x02800000 - 0x02ffffff: not used (mirror of sound RAM)
0x03000000 - 0x03ffffff: system devices (?)
0x04000000 - 0x04ffffff: ???
0x05000000 - 0x057fffff: video RAM
0x05800000 - 0x05bfffff: ??? (prolly not this large)
0x05c00000 - 0x05ffffff: ??? (filled with 0xff) (not 100% on location)
0x06000000 - 0x063fffff: ??? (stuff at beginning then 0x00)
0x06400000 - 0x066fffff: ??? (pseudo-chaotic stuff)

0x0c000000 - 0x0cffffff: RAM

0x10000000 - 0x10??????: tile accelerator
0x10800000 - 0x10ffffff: mirror of video RAM (write only)

0x14000000 - 0x17ffffff: G2 devices (?)

2004-Oct-27: Corrected some minor stuff on registers a05f8068, 806c, 80d0 thanks to Pierre-Marc Jobin.
2004-May-10: Corrected and added some information. Some register names have changed.
2003-Oct-03: Corrected and added information about the YUV converter.
2001-Aug-18: Added and corrected some stuff. Some of this comes from Mikael Kalm's documentation
2001-Feb-09: Added some small bits concerning fog and corrected a few minor mistakes.
2001-Jan-31: New version of my PowerVR-documentation.

Thanks to Marcus Comstedt and bITmASTER for their documentations, on which I based this.

The nomenclature of the TA registers has changed slightly compared to my 'ta-reg.txt' file, but it should be easy to correlate the two.

Guide to the PowerVR-chip of the Dreamcast 
by Lars Olsson < jlo@ludd.luth.se >
v0.51, 2004-Oct-27





a05f8000: (id)
+------+
| 31-0 |
| id |
+------+

id:
0x17fd11db: Set5.xx development box or consumer machine
others: Set4 delopment box or others


a05f8004: (revision)
+----------------------+
| 31-8 | 7-4 | 3-0 |
| n/a | major | minor |
+----------------------+

major.minor:
0.1: Set5.16 development box (?)
>= 1.1: Set5.2x development box or consumer machine


a05f8008: (reset)
+-----------------------+
| 31-3 | 2 | 1 | 0 |
| n/a | bus | PVR | TA |
+-----------------------+

bus:
0: normal
1: reset VRAM bus

PVR:
0: normal
1: reset PVR

TA:
0: normal
1: reset Tile Accelerator


a05f8014: (startrender)
+-------+
| 31-0 |
| start |
+-------+

start:
Writing to this register initiates rendering sequence.


a05f8018:
+------+
| 31-0 |
| ??? |
+------+

under investigation



a05f8020: (ob_addr)
+--------------+
| 31-24 | 23-0 |
| n/a | base |
+--------------+

base:
Base address of the Object Buffer in VRAM to be used
when the PVR is rendering a scene. Bits 0-19 are always
zero.


a05f802c: (tilebuf_addr)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
Location of the Tile Buffer in VRAM (64-bit aligned) to be
used when the PVR is rendering a scene.


a05f8030: (spansort_cfg)
+-----------------------------------------+
| 31-17 | 16 | 15-9 | 8 | 7-1 | 0 |
| n/a | ce | n/a | span1 | n/a | span0 |
+-----------------------------------------+

ce:
0: enable TSP cache
1: disable TSP cache

span0 & span1: under investigation; set both to 1 for now


a05f8040: (border_col)
+--------------+
| 31-24 | 23-0 |
| n/a | col |
+--------------+

col:
Border color in RGB888-format.


a05f8044: (fb_display_cfg)
+----------------------------------------------------------------
| 31-24 | 23 | 22 | 21-16 | 15-8 | 7 | 6-4 |
| n/a | clock | stripen | striplen | threshold | n/a | extend |
+----------------------------------------------------------------
----------------------------------+
| 3-2 | 1 | 0 |
| pixelmode | linedouble | enable |
----------------------------------+

clock:
0: normal
1: pixel-clock runs at twice the speed (for VGA-mode)

stripen:
0: no strip buffer
1: enable strip buffer

striplen:
Under investigation; should specify the length of the
strip buffer in terms of 32 scanlines.

threshold:
Comparison value when the display mode is ARGB8888.

extend:
This value is inserted into the lower bits when the
display mode is RGB555 or RGB565 in order to extend
it to RGB888.

pixelmode: (alphamode is not set)
0: RGB0555 (2 bytes/pixel)
1: RGB565 (2 bytes/pixel)
2: RGB888 (3 bytes/pixel)
3: RGB0888 (4 bytes/pixel)

linedouble:
0: normal
1: scan lines are sent twice (for 240 scanlines)

enable:
0: disable display
1: enable display


a05f8048: (fb_render_cfg)
+--------------------------------------------------------+
| 31-24 | 23-16 | 15-8 | 7-4 | 3 | 2-0 |
| n/a | threshold | alpha | n/a | dither | render mode |
+--------------------------------------------------------+

threshold:
Threshold for alpha transparency

alpha:
This is inserted into the alpha channel for those
render modes that support it when writing to the
framebuffer.

dither:
0: dither disabled
1: dither enabled for 2 bytes/pixel displays

render mode:
0: RGB0555 (2 bytes/pixel, alpha is inserted into bit15)
1: RGB565 (2 bytes/pixel)
2: ARGB4444 (2 bytes/pixel)
3: ARGB1555 (2 bytes/pixel, alpha is determined by threshold)
4: RGB888 (3 bytes/pixel)
5: RGB0888 (4 bytes/pixel, alpha is inserted into bit24-31)
6: ARGB8888 (4 bytes/pixel)
7: ARGB4444 (2 bytes/pixel, same as 2?)


a05f804c: (fb_render_modulo)
+---------------+
| 31-9 | 8-0 |
| n/a | modulo |
+---------------+

(haven't got this to work in *RGB888 modes...)
modulo:
((bytes/pixel * width)/8


a05f8050: (fb_display_addr1)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
Address in VRAM for displaying odd fields (32-bit aligned)


a05f8054: (fb_display_addr2)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
Address in VRAM for displaying even fields (32-bit aligned)


a05f805c: (fb_display_size)
+---------------------------------+
| 31-30 | 29-20 | 19-10 | 9-0 |
| n/a | modulo | height | width |
+---------------------------------+

modulo:
Number of words in VRAM before next scanline starts, plus 1

height:
interlace: height/2 - 1
noninterlace: height/2 - 1
VGA: height - 1

width:
((width * bytes/pixel)/4) - 1


a05f8060: (fb_render_addr1)
+-------------------+
| 31-25 | 24 | 23-0 |
| n/a | tx | addr |
+-------------------+

tx:
0: 32-bit write
1: 64-bit write (for rendering to textures)

addr:
Address in VRAM for rendering of odd fields.


a05f8064: (fb_render_addr2)
+-------------------+
| 31-25 | 24 | 23-0 |
| n/a | tx | addr |
+-------------------+

tx:
0: 32-bit write
1: 64-bit write (for rendering to textures)

addr:
Address in VRAM for rendering of even fields.


a05f8068: (fb_clip_x)
+-------------------------------+
| 31-27 | 26-16 | 15-11 | 10-0 |
| n/a | max | n/a | min |
+-------------------------------+

Specifies the horizontal pixel clipping area - 1.


a05f806c: (fb_clip_y)
+-------------------------------+
| 31-27 | 26-16 | 15-11 | 10-0 |
| n/a | max | n/a | min |
+-------------------------------+

Specifies the vertical pixel clipping area - 1.


a05f8074: (shadow)
+----------------------------+
| 31-9 | 8 | 7-0 |
| n/a | enable | intensity |
+----------------------------+

enable:
0: cheap shadow disabled
1: cheap shadow enabled

intensity:
how much cheap shadow should affect polygon depending on
how far away the modifier volume is located


a05f8078: (object_clip)
+--------------+
| 31-0 (FLOAT) |
| distance |
+--------------+

distance:
Position of polygon culling.


a05f807c: (ob_cfg)
+-------------------------+
| 31-22 | 21 | 20 | 19-0 |
| n/a | as | n/a | u |
+-------------------------+

as:
0: translucent autosort selected by the isp_cfg register
1: translucent autosort selected by sort bit in Region Buffer

u:
under investigation; write 0x0007df77 for now.





a05f8080:
+------+
| 31-0 |
| ??? |
+------+

under investigation; write 0x00000007 for now


a05f8084: (???)
+--------------+
| 31-0 (FLOAT) |
| ??? |
+--------------+

Under investigation; write 0x00000000 for now


a05f8088: (bgplane_z)
+--------------+
| 31-0 (FLOAT) |
| distance |
+--------------+

distance:
Position of background plane.


a05f808c: (bgplane_cfg)
+----------------------------------+
| 31-29 | 28 | 27 |26-24 | 23-0 |
| n/a | ce | moden | isp | addr |
+----------------------------------+

ce:
0: enable TSP cache for bgplane
1: disable TSP cache for bgplane

moden:
0: disable modifier volume for bgplane
1: enable modifier volume for bgplane

isp:
0: ???
1: texture disabled
2: texture enabled
3: texture enabled + specular highlight + 16bit UV-coords
4: texture enabled + specular highlight + 32bit UV-coords
5: ???
6: ???
7: ???

addr:
Location of background plane in VRAM.


a05f8098: (isp_cfg)
+--------------------------------------------------+
| 31-24 | 23-14 | 13-4 | 3 | 2-1 | 0 |
| n/a | u1 | u2 | discard | n/a | sort |
+--------------------------------------------------+

u1:
under investigation; write 0x00800000 for now

u2:
under investigation; write 0x00000400 for now

discard:
When auto-sorting translucent polygons, the ISP may
have to process the same polygons multiple times in
case of overlap. Setting this bit will discard polygons
that have been completely processed one time from
further processing, reducing overhead.

sort: (only valid when specified so in the ob_cfg register)
0: auto-sort translucent polygons
1: do not auto-sort translucent polygons (must be submitted
in sorted order.)


a05f80a0: (vram_cfg1)
+----------------+
| 31-8 | 7-0 |
| n/a | refresh |
+----------------+

refresh:
Specifies the refresh-timer for the VRAM.
(normally set to 0x20)
if set to 0 and no read/write cycle is performed
for awhile, VRAM will lose all contents.


a05f80a4: (vram_cfg2)
+------+
| 31-0 |
| ??? |
+------+

under investigation; write 0x0000001f for now


a05f80a8: (vram_cfg3)
+------+
| 31-0 |
| ??? |
+------+

under investigation; write 0x15d1c951 for now


a05f80b0: (fog_table_col)
+------+
| 31-0 |
| col |
+------+

col:
Color used for fogging operations on polygons that use
the fogging table.


a05f80b4: (fog_vertex_col)
+------+
| 31-0 |
| col |
+------+

col:
Color used for fogging operation on polygons that do
manual processing of the fog.


a05f80b8: (fog_density)
+-----------------------------+
| 31-16 | 15-8 | 7-0 |
| n/a | mantissa | exponent |
+-----------------------------+

Specifies a coefficient for TSP fogging.

exponent:
power of 2


a05f80bc: (clamp_max)
+------+
| 31-0 |
| col |
+------+

col:
Colors above this RGB value will be set to this color.


a05f80c0: (clamp_min)
+------+
| 31-0 |
| col |
+------+

col:
Colors below this RGB value will be set to this color.


a05f80c4: (gun_pos)
+----------------------------------+
| 31 - 26 | 25 - 16 | 15-10 | 9-0 |
| ??? | vpos | n/a | hpos |
+----------------------------------+

vpos:
Vertical position of lightgun.

hpos:
Horizontal position of lightgun.


a05f80c8: (hpos_irq)
+--------------------------------------+
| 31-28 | 25-16 | 15-14 | 13-12 | 9-0 |
| n/a | pos | n/a | mode | lval |
+--------------------------------------+

(I had HPOS and VPOS IRQs mixed up before, hence the confusion :)

pos:
horizontal position of the HPOS IRQ.

mode:
0: generate IRQ when the scanline is the same as lval
1: ???
2: generate IRQ on every scanline
3: ???

line:
If specified by mode, generate an HPOS IRQ only on this
scanline.


a05f80cc: (vpos_irq)
+------------------------------+
| 31-28 | 25-16 | 15-10 | 9-0 |
| n/a | pos1 | n/a | pos2 |
+------------------------------+

pos1:
A VPOS1_IRQ will be generated when the raster reaches this
scanline.

pos2:
A VPOS2_IRQ will be generated when the raster reaches this
scanline.

for PAL:
pos1: 21
pos2: 310

for NTSC, 480 height
pos1: 21
pos2: 258

for NTSC, 240 height
pos1: 21
pos2B: 260

for VGA:
pos1: 21
pos2: 510


a05f80d0: (sync_cfg)
+------------------------------------------------------------------------+
| 31-10 | 9 | 8 | 7-6 | 5 | 4 | 3 | 2 | 1 | 0 |
| n/a | ??? | enable | video | ??? | interlace | ??? | HP | VP | ??? |
+------------------------------------------------------------------------+

enable:
0: video output disabled
1: video output enabled

video: (this doesn't seem to work on Japanese machines for some
reason. They do have PAL capabilities though because I
made a hardware modification to always output PAL.)
0: VGA
1: NTSC
2: PAL
3: n/a

interlace:
0: non-interlace
1: interlace

HP:
0: negative H-sync
1: positive H-sync

VP:
0: negative V-sync
1: positive V-sync


a05f80d4: (hborder)
+-----------------------------+
| 31-28 | 25-16 | 15-10 | 9-0 |
| n/a | start | n/a | end |
+-----------------------------+

Specifies the area of the horizontal border.

for PAL:
start: end:
116 843

for NTSC:
start: end:
126 837

for VGA:
start: end:
126 837


a05f80d8: (sync_load)
+-------------------------------+
| 31-28 | 25-16 | 15-10 | 9-0 |
| n/a | vsync | n/a | hsync |
+-------------------------------+

Specifies the refresh rate of the display.

for PAL, interlace:
vsync: hsync:
624 863

for PAL, noninterlace:
vsync: hsync:
312 863

for NTSC, interlace:
vsync: hsync:
524 857

for NTSC, noninterlace:
vsync: hsync:
262 857

for VGA:
vsync: hsync:
524 857


a05f80dc: (vborder)
+-----------------------------+
| 31-28 | 25-16 | 15-10 | 9-0 |
| n/a | start | n/a | end |
+-----------------------------+

Specifies the area of the vertical border.

for PAL:
start: end:
44 620

for NTSC, 480 height:
start: end:
36 516

for NTSC, 240 height:
start: end:
18 258

for VGA:
start: end:
40 520


a05f80e0: (sync_width)
+---------------------------------------------------------+
| 31-23 | 27-22 | 21-12 | 11-8 | 7 | 6-0 |
| n/a | x | y | vsync-width | n/a | hsync-width |
+---------------------------------------------------------+

Specifies the position(?) and width of the sync pulses.

for PAL, 480 height
x: y: hwidth: vwidth:
0x1f 362 0x05 0x3f

for PAL, 240 height
x: y: Vsync: Hsync:
0x1f 799 0x05 0x3f

for NTSC, 480 height
x: y: Vsync: Hsync:
0x1f 364 0x06 0x3f

for NTSC, 240 height
x: y: Vsync: Hsync:
0x0f 793 0x03 0x3f

for VGA:
x: y: Vsync: Hsync:
0x0f 793 0x03 0x3f


a05f80e4: (tsp_cfg)
+------------------------------------------------+
| 31-19 | 17 | 16 | 15-13 | 12-8 | 7-5 | 4-0 |
| n/a | cbe | ie | n/a | ??? | n/a | modulo |
+------------------------------------------------+

cbe:
0: little endian entries for codebook for VQ textures
1: big endian entries for codebook for VQ textures

ie:
0: little endian entries for index for VQ textures
1: big endian entries for index for VQ textures

modulo:
Modulo width for textures.


a05f80e8: (video_cfg)
+--------------------------------------------------------------+
| 31-22 | 21-16 | 15-9 | 8 | 7-4 | 3 | 2 | 1 | 0 |
| n/a | A | n/a | lores | ??? | blank | ??? | ??? | ??? |
+--------------------------------------------------------------+

A:
0x16

lores:
0: 640 width
1: 320 width

blank:
0: normal mode
1: border covers the whole screen


a05f80ec: (hpos)
+-------------+
| 31-10 | 9-0 |
| n/a | pos |
+-------------+

Specifies the horizontal position of the display.

for PAL:
pos:
174

for NTSC:
pos:
164

for VGA:
pos:
144


a05f80f0: (vpos)
+-----------------------------+
| 31-26 | 25-16 | 15-10 | 9-0 |
| n/a | even | n/a | odd |
+-----------------------------+

Specifies the vertical postition of the display for even and odd
fields.


for PAL interlace:
even: odd:
18 18

for PAL noninterlace:
even: odd:
18 17

for NTSC interlace:
even: odd:
18 18

for NTSC non interlace:
even: odd:
18 17

for VGA:
even: odd:
35 35


a05f80f4: (scaler_cfg)
+-------------------------------------+
| 31-19 | 18 | 17 | 16 | 15-0 |
| n/a | ??? | n/a | hscale | vscale |
+-------------------------------------+

hscale:
Horizontal scaler.

vscale:
Vertical scaler.


a05f8108: (palette_cfg)
+---------------+
| 31 - 2 | 1-0 |
| n/a | mode |
+---------------+

mode:
0: ARGB1555
1: RGB565
2: ARGB4444
3: ARGB8888


a05f810c: (sync_stat)
+----------------------------------------------+
| 31-14 | 13 | 12 | 11 | 10 | 9-0 |
| ??? | vblank | hblank | ??? | field | vpos |
+----------------------------------------------+
vblank:
0: normal
1: vblank in progress

hblank:
0: normal
1: hblank in progress

field:
0: odd field of interlace
1: even field of interlace

vpos:
Current vertical position of the rasterbeam.


a05f8110: (???)
+------+
| 31-0 |
| ??? |
+------+

under investigation; write 0x00093f39 for now


a05f8114: (???)
+------+
| 31-0 |
| ??? |
+------+

under investigation; write 0x00200000 for now


a05f8118: (ta_luminance)
+--------------------+
| 31-16 | 15-8 | 7-0 |
| n/a | b1 | b2 |
+--------------------+

under investigation; write 0x00008040 for now


a05f8124: (ta_opb_start)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
Start of Object Pointer Buffer in VRAM (128-byte aligned)
for vertex registration. The Tile Accelerator will examine
vertex data it receives and determine which tiles the objects
might appear in and create links to the object in the
referenced tiles.


a05f8128: (ta_ob_start)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
Start of Object Buffer in VRAM (64-bit aligned) for vertex
registration. This is where the vertex data sent to the
Tiling Accelerator will be stored.


a05f812c: (ta_opb_end)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
End of Object Pointer Buffer in VRAM (128-byte aligned) for
vertex registration. The Tiling Accelerator will not use
memory beyond this point when creating Object Links. The
direction the Object Pointer Buffer grows in can be user
specified so care must be taken to place this correctly. An
OPB_OVERRUN IRQ will be generated should this limit be
exceeded.


a05f8130: (ta_ob_end)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
End of Object Buffer in VRAM (64-bit aligned) for vertex
registration. the Tiling Accelerator will not use memory
beyond this point when receiving data. If this happens an
OB_OVERRUN IRQ will be generated.



a05f8134: (ta_opb_pos)
+--------------+
| 31-23 | 22-0 |
| n/a | addr |
+--------------+

addr:
Object Pointer Buffer position
This register contains the current address to be used by
the Object Pointer Buffer when more space needs to be
allocated.


a05f8138: (ta_ob_pos)
+--------------+
| 31-23 | 22-0 |
| n/a | addr |
+--------------+

addr:
Object Buffer position
This register contains the current address to be used by
the Object Buffer when Tile Accelerator receives vertex data.



a05f813c: (tilebuf_size)
+----------------+
| 31-16 | 15-0 |
| height | width |
+----------------+

height:
Height of tile buffer in 32-pixel high tiles, minus 1.

width:
Width of tile buffer in 32-pixel wide tiles, minus 1.


a05f8140: (ta_opb_cfg)
+--------------------------------------------------------------------
| 31-21 | 20 | 19-18 | 17-16 | 15-14 | 13-12 | 11-10 |
| n/a | opbdir | n/a | punch-through | n/a | transmod | n/a |
+--------------------------------------------------------------------
-------------------------------------------------------+
| 9-8 | 7-6 | 5-4 | 3 | 2 | 1-0 |
| transpoly | n/a | opaquemod | n/a | ??? | opaquepoly |
-------------------------------------------------------+

opbdir:
0: The Object Pointer Buffer grows upwards in VRAM
1: The Object Pointer Buffer grows downwards in VRAM

punch-through:
0: size_0 - Punch-through Polygons disabled
1: size_8 - 7 Object Pointers + 1 List Pointer
2: size_16 - 15 Object Pointers + 1 List Pointer
3: size_32 - 31 Object Pointers + 1 List Pointer

transmod:
0: size_0 - Translucent Modifiers disabled
1: size_8 - 7 Object Pointers + 1 List Pointer
2: size_16 - 15 Object Pointers + 1 List Pointer
3: size_32 - 31 Object Pointers + 1 List Pointer

transpoly:
0: size_0 - Translucent Polygons disabled
1: size_8 - 7 Object Pointers + 1 List Pointer
2: size_16 - 15 Object Pointers + 1 List Pointer
3: size_32 - 31 Object Pointers + 1 List Pointer

opaquemod:
0: size_0 - Opaque Modifiers disabled
1: size_8 - 7 Object Pointers + 1 List Pointer
2: size_16 - 15 Object Pointers + 1 List Pointer
3: size_32 - 31 Object Pointers + 1 List Pointer

opaquepoly:
0: size_0 - Opaque Polygons disabled
1: size_8 - 7 Object Pointers + 1 List Pointer
2: size_16 - 15 Object Pointers + 1 List Pointer
3: size_32 - 31 Object Pointers + 1 List Pointer


a05f8144: (ta_init)
+-------------+
| 31 | 30-0 |
| init | n/a |
+-------------+

init:
0: normal
1: initialize TA vertex registration parameters


a05f8148: (yuv_addr)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
Destination address in VRAM (32-byte aligned) for YUV
conversion.


a05f814c: (yuv_cfg1)
+--------------------------------------------------------------+
| 31-25 | 24 | 23-17 | 16 | 15-14 | 13-8 | 7-6 | 5-0 |
| n/a | format | n/a | mode | n/a | height | n/a | width |
+--------------------------------------------------------------+

format:
0: YUV420
1: YUV422

mode:
0: single transfer (size must be 16,32,64,128,256,512 or 1024)
1: multiple transfers in terms of 16x16 macro blocks

height:
height/32-1

width:
width/32-1

Notes:
After setting yuv_cfg1 and yuv_addr, data should be sent via
DMA to the YUV converter at address 0x10800000.


a05f8150: (yuv_stat)
+----------------+
| 31-13 | 12-0 |
| n/a | blocks |
+----------------+

blocks:
Indicates the number of 16x16 macroblocks currently
converted.


a05f8160: (ta_opl_reinit)
+---------------+
| 31 | 30-0 |
| reinit | n/a |
+---------------+

reinit:
0: normal
1: initialize TA vertex registration parameters (same as
ta_init) except ta_obp_pos and ta_ob_pos are not
initialized, allowing continuation of registration.


a05f8164: (ta_opl_init)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
Start of Object Pointer List allocation in VRAM
(128-byte aligned). The Object Pointer List is part
of the Object Pointer Buffer and this is where the Tile
Accelerator allocates memory if needed for the Object
Pointer Buffer. The direction of the allocation can be
specified in the ta_opb_cfg register.


a05f8180:
+------+
| 31-0 |
| ??? |
+------+


a05f8184:
+------+
| 31-0 |
| ??? |
+------+


a05f8190:
+------+
| 31-0 |
| ??? |
+------+


a05f8194:
+------+
| 31-0 |
| ??? |
+------+


a05f8198:
+------+
| 31-0 |
| ??? |
+------+


a05f8200 - a05f83ff: (fog_table)
+-------------------+
| 31-16 | 15-0 |
| n/a | fog entry |
+-------------------+

128 entries for use with fogging operations. The index of the table
is used as a depth-value and the element at that position is used to
specify a fog density. Polygons using fog_table will use the fog
density as the alpha value of the fog. Polygons that use fog_table2
change the polygon color to the fog density value and the polygon
alpha value will become the fog alpha value.


a05f8600 - a05f8fff: (opl_table)
+------+
| 31-0 |
| ??? |
+------+

This is quite likely where the Tile Accelerator stores pointers to
the current addresses in the Object Pointer List segments. It
seems the entries also contain additional information, such as the
type of object etc.


a05f9000 - a05f9fff: (palette_table)
+---------------+
| 31-0 |
| palette entry |
+---------------+

1024 entries for use with palettized textures. Palette is split into
banks depending on color mode. For 4bpp mode there are 64 banks
with 16 colors in each; for 8bpp mode there are 4 banks with 256
colors in each.




Notes:

Some uncertainties still linger, but this doc is a bit more correct than
the previous. Everything is unoffical though and should be taken for what it
is; only an attempt at understanding the workings of a complex chip. It is
not yet complete and most certainly contains errors in some parts, but I feel
somewhat confident that it is correct in at least an equal amount :-)

Reach me at: jlo@ludd.luth.se for any questions, comments or corrections...


/Lars Olsson

2001-Aug-18: filled in stuff on sprites and modifier volumes
2001-Aug-05: filled in stuff on blending modes + corrected and clarified some stuff

Introductory text on how to write display lists for sending to the Tile Accelerator.

Some notes on the Tiling Accelerator: 

update: filled in some stuff about blending modes and clarified and corrected
some stuff.

2001-08-18 update: filled in some stuff on sprites and modifier volumes

Note: There are a few different incarnations of the PowerVR-chipset and they
are not completely compatible with each other. Unfortunately previous versions
of this document contained information only relevant to the older CLX1 chipset
whereas the Dreamcast uses a chipset similar to the newer CLX2. Information has
now been updated and where differences exist they are noted with the tags CLX1
and CLX2. [This note was mistakenly excluded from the previous version.]


The interface used to communicate with the Tiling Accelerator is mapped to
memory at address 0x10000000. The normal mode of operation is not to access
this area directly but to use either the two Store Queues of the SH-4, or DMA
(currently not described in this document) to send information to it.
A transfer to the TA can be up to 64 bytes, which is the maximum size of the
two store queues. The full contents of a Store Queue is always sent, so it is
only possible to send either 32 bytes or 64 bytes to the Tiling Accelerator.
The data of such a transfer is hereafter referred to as a list, which is the
smallest piece of information the Tiling Accelerator can process.

A list consists of a command followed by parameters whose format depend on the
command. The general format for a list is as follows:

The first word is the command and consists of:
+-----------------+
bit: | 31-29 | 28-0 |
name:| cmd | options |
+-----------------+
cmd: 0 - END_OF_LIST
1 - USER_CLIP
2 - ???
3 - ???
4 - POLYGON / MODIFIER_VOLUME
5 - SPRITE
6 - ???
7 - VERTEX

options: The format of the options changes depending on the command.


This first word is followed by either 7 or 15 words of parameters, to make a
list of 32 or 64 bytes. Since the format changes for these, I will list the
commands, the options and the parameters together with a short description of
what they do. Reserved or unused options and parameters should be set to 0.

--------------------------------------------------------------------------------

Command 0 - END_OF_LIST:

Options:
~~~~~~~~
+----------------------+
| 28-0 |
| reserved? (set to 0) |
+----------------------+

Parameters:
~~~~~~~~~~~
1-7: Not used

Description:
~~~~~~~~~~~~
Sent after all data of a specific listtype has been sent to the Tiling
Accelerator and will generate an IRQ when registration for that listtype
has been completed. After terminating a listtype with this list it is not
possible to send more instances of that listtype in the same registration
process.



--------------------------------------------------------------------------------

Command 1 - USER_CLIP

Options:
~~~~~~~~
+----------------------+
| 28-0 |
| reserved? (set to 0) |
+----------------------+
Parameters:
~~~~~~~~~~~
1-3: Not used

4: +---------------------+
| 31-0 |
| Xmin |
+---------------------+
5: +---------------------+
| 31-0 |
| Ymin |
+---------------------+
6: +---------------------+
| 31-0 |
| Xmax |
+---------------------+
7: +---------------------+
| 31-0 |
| Ymax |
+---------------------+

Description:
~~~~~~~~~~~~
Sets the User Clipping for the Tile Buffer



--------------------------------------------------------------------------------

Command 4 - POLYGON / MODIFIER_VOLUME
Command 5 - SPRITE

Options:
~~~~~~~~
+----------------------------------------------------------+
| 28-27 | 26-24 | 23 | 22-20 | 19-18 |
| reserved? | listtype | unknown | reserved? | striplength |
+----------------------------------------------------------+
+--------------------------------------------------------------+
| 17-16 | 15-8 | 7 | 6 | 5-4 |
| clipmode | reserved? | modifier | modifier mode | colourtype |
+--------------------------------------------------------------+
+------------------------------------------+
| 3 | 2 | 1 | 0 |
| texture | specular | shading | UV format |
+------------------------------------------+

listtype (26-24):
~~~~~~~~~~~~~~~~~
0: opaque polygon
1: opaque modifier (only valid for MODIFIER)
2: transparent polygon
3: transparent modifier (only valid for MODIFIER)
4: punchthru polygon

striplength (19-18):
~~~~~~~~~~~~~~~~~~~~
0: striplength 1
1: striplength 2
2: striplength 4
3: striplength 6

clipmode (17-16):
~~~~~~~~~~~~~~~~~
0: disable user clip
1: reserved
2: user clip inside
3: user clip outside

modifier (7):
~~~~~~~~~~~~~
0: polygon is not affected by modifier volume
1: polygon is affected by modifier volume (only valid for POLYGON)

modifier mode (6):
~~~~~~~~~~~~~~~~~~
0: cheap shadow modifier
1: normal modifier

colour type (5-4):
~~~~~~~~~~~~~~~~~
0: 32bit ARGB packed colour
1: 32bit * 4 floating point colour (not valid for SPRITES)
2: intensity (not valid for SPRITES)
3: intensity from previous face (not valid for SPRITES)

texture (3):
~~~~~~~~~~~~
0: disable texture
1: enable texture

specular (2):
~~~~~~~~~~~~~
0: disable specular highlight
1: enable specular highlight (not valid for SPRITES)

shading (1):
~~~~~~~~~~~~
0: flat shading
1: gouraud shading (not valid for SPRITES)

UV format (0):
~~~~~~~~~~~~~~
0: 32 bit float (not valid for SPRITES)
1: 16 bit float

if polygon (listtype 0, 2, 4) is specified (for a POLYGON or SPRITE list):
1: +-------------------------------------------------------+
| 31-29 | 28-27 | 26 | 25 | 24 |
| depthmode | cullingmode | zwrite | texture | specular |
+-------------------------------------------------------+
+-----------------------------------------------------------+
| 23 | 22 | 21 | 20 | 19-0 |
| shading | UVFormat | reserved? | D calc exact | reserved? |
+-----------------------------------------------------------+
depthmode (31-29):
~~~~~~~~~~~~~~~~~~
0: never
1: less
2: equal
3: lessequal
4: greater
5: notequal
6: greaterequal
7: always

cullingmode (28-27):
~~~~~~~~~~~~~~~~~~~~
0: disable culling
1: cull small
2: cull counterclockwise
3: cull clockwise

zwrite (26):
~~~~~~~~~~~~
0: enable zwrite
1: disable zwrite

texture (25):
~~~~~~~~~~~~~
0: disable texture
1: enable texture

specular (24): (this doesnt seem correct; redundant + non-working)
~~~~~~~~~~~~~~
0: disable specular highlight
1: enable specular highlight

shading (23): (this doesnt seem correct; redundant + non-working)
~~~~~~~~~~~~~
0: flat shading
1: gouraud shading

UVFormat (22): (this doesnt seem correct; redundant + non-working)
~~~~~~~~~~~~~~
0: 32-bit float
1: 16-bit float

D calc exact (20):
~~~~~~~~~~~~~~~~~~
0: approximate mipmap D parameter
1: calculate mipmap D parameter exact


2: +-----------------------------------------------------------------+
| 31-29 | 28-26 | 25 | 24 | 23-22 | 21 | 20 |
| srcblend | dstblend | srcmode | dstmode | fog | clamp | alpha |
+-----------------------------------------------------------------+
+-------------------------------------------------------------------+
| 19 | 18-17 | 16-15 | 14-12 | 11-8 | 7-6 |
| text.alpha | UV flip | UV clamp | filter | mipmap | text. shading |
+-------------------------------------------------------------------+
+---------------+
| 5-3 | 2-0 |
| Usize | Vsize |
+---------------+

(blending info is not completely accurate)

srcblend (31-29):
~~~~~~~~~~~~~~~~~
0: zero (0, 0, 0, 0)
1: one (1, 1, 1, 1)
2: dst colour (ad, Rd, Gd, Bd)
3: inverse dst colour (1 - ad, 1 - Rd, 1 - Gd, 1 - Bd)
4: src alpha (as, as, as, as)
5: inverse src alpha (1 - as, 1 - as, 1 - as, 1 - as)
6: dst alpha (ad, ad, ad, ad)
7: inverse dst alpha (1 - ad, 1 - ad, 1 - ad, 1 - ad)

dstblend (28-26):
~~~~~~~~~~~~~~~~~
0: zero (0, 0, 0, 0)
1: one (1, 1, 1, 1)
2: src colour (as, Rs, Gs, Bs)
3: inverse src colour (1 - as, 1 - Rs, 1 - Gs, 1 - Bs)
4: src alpha (as, as, as, as)
5: inverse src alpha (1 - as, 1 - as, 1 - as, 1 - as)
6: dst alpha (ad, ad, ad, ad)
7: inverse dst alpha (1 - ad, 1 - ad, 1 - ad, 1 - ad)

srcmode (25):
~~~~~~~~~~~~~
0: disable src blending
1: enable src blending

dstmode (24):
~~~~~~~~~~~~~
0: disable dst blending
1: enable dst blending

fog (23-22):
~~~~~~~~~~~~
0: fog table
1: fog vertex
2: fog disabled
3: fog table2

clamp (21):
~~~~~~~~~~~
0: disable colour clamping
1: enable colour clamp

alpha (20):
~~~~~~~~~~~
0: disable alpha bit
1: enable alpha bit

texture alpha (19):
~~~~~~~~~~~~~~~~~~~
0: enable texture transparency
1: disable texture transparency

UV flip (18-17):
~~~~~~~~~~~~~~~~
0: disable UV flipping
1: flip V when repeating texture
2: flip U when repeating texture
3: flip U and V when repeating texture

UV clamp (16-15):
~~~~~~~~~~~~~~~~~
0: disable UV clamping
1: clamp V
2: clamp U
3: clamp U and V

filter (14-12):
~~~~~~~~~~~~~~~
0: point sample
1: bi-linear
2: ???
3: ???
4: tri-linear, one pass
5: ???
6: tri-linear, two passes
7: ???

mipmap (11-8):
~~~~~~~~~~~~~~
0: reserved?
1: D=0.25
2: D=0.50
3: D=0.75
4: D=1.00 (normal mode)
5: D=1.25
6: D=1.50
7: D=1.75
8: D=2.00
9: D=2.25
10: D=2.50
11: D=2.75
12: D=3.00
13: D=3.25
14: D=3.50
15: D=3.75

texture shading (7-6):
~~~~~~~~~~~~~~~~~~~~~~
0: colour = texture-RGB + offset-RGB
alpha = texture-alpha

1: colour = shading-RGB * texture-RGB + offset-RGB
alpha = texture-alpha

2: colour = (texture-RGB * texture-alpha)
+ (shading-RGB * (1 - texture-alpha)) + offset-RGB
alpha = shading-alpha

3: colour = (texture-RGB * shading-RGB) + offset-RGB
alpha = shading-alpha * texture-alpha

Usize (5-3):
~~~~~~~~~~~~
0: 8 pixels
1: 16 pixels
2: 32 pixels
3: 64 pixels
4: 128 pixels
5: 256 pixels
6: 512 pixels
7: 1024 pixels

Vsize (2-0):
~~~~~~~~~~~~
0: 8 pixels
1: 16 pixels
2: 32 pixels
3: 64 pixels
4: 128 pixels
5: 256 pixels
6: 512 pixels
7: 1024 pixels


if texture is specified:
3: +--------------------------------------------------------+
| 31 | 30 | 29-27 | 26-21 | 20-0 |
| mipmap | VQ | pixelformat | special* | texture surface |
+--------------------------------------------------------+

mipmap (31):
~~~~~~~~~~~~
0: disable mipmap
1: enable mipmap

VQ (30):
~~~~~~~~
0: disable compression
1: enable VQ compression for texture

pixelformat for texture (29-27):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0: ARGB15555
1: RGB565
2: ARGB4444
3: YUV422
4: BUMP
5: 4BPP_PALETTE
6: 8BPP_PALETTE

texture surface (20-0):
~~~~~~~~~~~~~~~~~~~~~~~
address in framebuffer for texture surface.
lowest 3 bits of address is automatically read as 0 and added.



special* (26-21):
~~~~~~~~~~~~~~~~
in palette mode these bits specify palette bank to be used.
in other cases they mean the following:

+-------------------------------------------+
| 26-25 | 24 | 23-22 | 21 |
| reserved? | twiddled | reserved? | stride |
+-------------------------------------------+

twiddled (24):
~~~~~~~~~~~~~~
0: twiddled texture
1: non-twiddled texture

stride (21):
~~~~~~~~~~~~
0: no stride
1: stride




if colour type intensity (2) is specified (also used for colours of SPRITES?):
4: +-------------------------+
| 31-0 |
| BaseColourAlpha (float) |
+-------------------------+
5: +-----------------------+
| 31-0 |
| BaseColourRed (float) |
+-----------------------+
6: +-------------------------+
| 31-0 |
| BaseColourGreen (float) |
+-------------------------+
7: +------------------------+
| 31-0 |
| BaseColourBlue (float) |
+------------------------+

if colour type intensity (2) is specified together with specular hightlight:

4-7: Not used

8: +-------------------------+
| 31-0 |
| BaseColourAlpha (float) |
+-------------------------+
9: +-----------------------+
| 31-0 |
| BaseColourRed (float) |
+-----------------------+
10: +-------------------------+
| 31-0 |
| BaseColourGreen (float) |
+-------------------------+
11: +------------------------+
| 31-0 |
| BaseColourBlue (float) |
+------------------------+
12: +---------------------------+
| 31-0 |
| OffsetColourAlpha (float) |
+---------------------------+
13: +-------------------------+
| 31-0 |
| OffsetColourRed (float) |
+-------------------------+
14: +---------------------------+
| 31-0 |
| OffsetColourGreen (float) |
+---------------------------+
15: +--------------------------+
| 31-0 |
| OffsetColourBlue (float) |
+--------------------------+



if modifier volume (listtype 1, 3) is specified:
1: +-----------------------------------+
| 31-29 | 28-0 |
| ModifierInstruction | reservered? |
+-----------------------------------+

ModifierInstruction (31-29):
~~~~~~~~~~~~~~~~~~~~~~~~~~~
0: other polygon
1: first polygon in inclusion volume
2: last polygon in exclusion volume



2-7: Not used

Description:
~~~~~~~~~~~~
This list does not draw any primitives but sets up the environent for primitives
following. One or more VERTEX lists are expected to follow and it is an error to
send any other list until the VERTEX lists have been sent and terminated (see
description of VERTEX below for elaboration).

A POLYGON is a standard polygon in 3d-space. A MODIFIER_VOLUME is a special
type of polygon that is never directly drawn but interacts with other
polygons. Depending on whether the polygons are inside or outside the
MODIFIER_VOLUME, different parameters for texturing, shading etc. will be
used. This can be an effective way of simulating shadows etc. A SPRITE is a
polygon in 2d-space, meaning it will not have to perform any kind of
perspective-correcting texturing or shading calculations (hence it will
generally be faster to render).

POLYGONS use any of the below VERTICES (except type 15, 16, and 17) depending
on the environment specified. SPRITES use types 15, 16 depending on whether
texturing is enabled whereas MODIFIER_VOLUMES always use type 17.

--------------------------------------------------------------------------------

Command 7 - VERTEX

Options:
~~~~~~~~
+----------------------------+
| 28 | 27-0 |
| eos | reserved? (set to 0) |
+----------------------------+

eos (28):
~~~~~~~~~
0: normal vertex
1: end-of-strip (indicates last vertex has been sent)

Parameters:
~~~~~~~~~~~
Parameters depend on the environment set by the POLYGON, MODIFIER_VOLUME, or
SPRITE list that must precede this. The eos-bit should be set for the last
vertex sent in a triangle-strip. In cases of SPRITE-lists this must always be
set because they contain all the vertices inside one VERTEX-list (this is
possibly also true for MODIFIER_VOLUMES). The different types depend on what
is specified in the previous environment. Using the wrong type may cause
unpredictable behaviour.


type 0: non-textured, packed-colour:

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: CLX1: CLX2:
+-------------+ Not used
| 31-0 |
| Base Colour |
+-------------+

5: Not used

6: CLX1: CLX2:
Not used +-------------+
| 31-0 |
| Base Colour |
+-------------+

7: Not used





type 1: non-textured, floating colour:

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +---------------------------+
| 31-0 |
| Base Colour Alpha (float) |
+---------------------------+
5: +-------------------------+
| 31-0 |
| Base Colour Red (float) |
+-------------------------+
6: +---------------------------+
| 31-0 |
| Base Colour Green (float) |
+---------------------------+
7: +--------------------------+
| 31-0 |
| Base Colour Blue (float) |
+--------------------------+





type 2: non-textured, intensity:

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: CLX1: CLX2:
+------------------------+ Not used
| 31-0 |
| Base Intensity (float) |
+------------------------+

5: Not used

6: CLX1: CLX2:
Not used +------------------------+
| 31-0 |
| Base Intensity (float) |
+------------------------+

7: Not used





type 3: textured, packed-colour:

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +------------+
| 31-0 |
| U (float) |
+------------+
5: +------------+
| 31-0 |
| V (float) |
+------------+
6: +-------------+
| 31-0 |
| Base Colour |
+-------------+
7: +---------------+
| 31-0 |
| Offset Colour |
+---------------+




type 4: textured, packed-colour, 16bit UV:

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +-----------------------+
| 31-16 | 15-0 |
| U (float) | V (float) |
+-----------------------+

5: Not used

6: +-------------+
| 31-0 |
| Base Colour |
+-------------+
7: +---------------+
| 31-0 |
| Offset Colour |
+---------------+





type 5: textured, floating colour:

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +------------+
| 31-0 |
| U (float) |
+------------+
5: +------------+
| 31-0 |
| V (float) |
+------------+

6-7: Not used

8: +---------------------------+
| 31-0 |
| Base Colour Alpha (float) |
+---------------------------+
9: +-------------------------+
| 31-0 |
| Base Colour Red (float) |
+-------------------------+
10: +---------------------------+
| 31-0 |
| Base Colour Green (float) |
+---------------------------+
11: +--------------------------+
| 31-0 |
| Base Colour Blue (float) |
+--------------------------+
12: +-----------------------------+
| 31-0 |
| Offset Colour Alpha (float) |
+-----------------------------+
13: +---------------------------+
| 31-0 |
| Offset Colour Red (float) |
+---------------------------+
14: +-----------------------------+
| 31-0 |
| Offset Colour Green (float) |
+-----------------------------+
15: +----------------------------+
| 31-0 |
| Offset Colour Blue (float) |
+----------------------------+





type 6: textured, floating colour, 16-bit UV

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +-----------------------+
| 31-16 | 15-0 |
| U (float) | V (float) |
+-----------------------+

5-7: Not used

8: +---------------------------+
| 31-0 |
| Base Colour Alpha (float) |
+---------------------------+
9: +-------------------------+
| 31-0 |
| Base Colour Red (float) |
+-------------------------+
10: +---------------------------+
| 31-0 |
| Base Colour Green (float) |
+---------------------------+
11: +--------------------------+
| 31-0 |
| Base Colour Blue (float) |
+--------------------------+
12: +-----------------------------+
| 31-0 |
| Offset Colour Alpha (float) |
+-----------------------------+
13: +---------------------------+
| 31-0 |
| Offset Colour Red (float) |
+---------------------------+
14: +-----------------------------+
| 31-0 |
| Offset Colour Green (float) |
+-----------------------------+
15: +----------------------------+
| 31-0 |
| Offset Colour Blue (float) |
+----------------------------+





type 7: textured, intensity

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +------------+
| 31-0 |
| U (float) |
+------------+
5: +------------+
| 31-0 |
| V (float) |
+------------+
6: +------------------------+
| 31-0 |
| Base Intensity (float) |
+------------------------+
7: +--------------------------+
| 31-0 |
| Offset Intensity (float) |
+--------------------------+





type 8: textured, intensity, 16-bit UV

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +------------------------+
| 31-16 | 15-0 |
| U (float) | V (float) |
+------------------------+

5: Not used

6: +------------------------+
| 31-0 |
| Base Intensity (float) |
+------------------------+
7: +--------------------------+
| 31-0 |
| Offset Intensity (float) |
+--------------------------+






type 9: non-textured, packed-color, affected by modifier volume

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +---------------+
| 31-0 |
| Base Colour 0 |
+---------------+
5: +---------------+
| 31-0 |
| Base Colour 1 |
+---------------+

6-7: Not used





type 10: non-textured, intensity, affected by modifier volume

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +---------------------+
| 31-0 |
| Intensity 0 (float) |
+---------------------+
5: +---------------------+
| 31-0 |
| Intensity 1 (float) |
+---------------------+

6-7: Not used






type 11: textured, packed-colour, affected by modifier volume:

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +-------------+
| 31-0 |
| U0 (float) |
+-------------+
5: +-------------+
| 31-0 |
| V0 (float) |
+-------------+
6: +---------------+
| 31-0 |
| Base Colour 0 |
+---------------+
7: +-----------------+
| 31-0 |
| Offset Colour 0 |
+-----------------+
8: +-------------+
| 31-0 |
| U1 (float) |
+-------------+
9: +-------------+
| 31-0 |
| V1 (float) |
+-------------+
10: +---------------+
| 31-0 |
| Base Colour 1 |
+---------------+
11: +-----------------+
| 31-0 |
| Offset Colour 1 |
+-----------------+

12-15: Not used






type 12: textured, packed-colour, 16-bit UV, affected by modifier volume

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +--------------+
| 31-16 | 15-0 |
| U0 | V0 |
+--------------+

5: Not used

6: +---------------+
| 31-0 |
| Base Colour 0 |
+---------------+
7: +-----------------+
| 31-0 |
| Offset Colour 0 |
+-----------------+
8: +--------------+
| 31-16 | 15-0 |
| U1 | V1 |
+--------------+

9: Not used

10: +---------------+
| 31-0 |
| Base Colour 1 |
+---------------+
11: +-----------------+
| 31-0 |
| Offset Colour 1 |
+-----------------+

12-15: Not used





type 13: textured, intensity, affected by modifier volume

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +-------------+
| 31-0 |
| U0 (float) |
+-------------+
5: +-------------+
| 31-0 |
| V0 (float) |
+-------------+
6: +--------------------------+
| 31-0 |
| Base Intensity 0 (float) |
+--------------------------+
7: +----------------------------+
| 31-0 |
| Offset Intensity 0 (float) |
+----------------------------+
8: +-------------+
| 31-0 |
| U1 (float) |
+-------------+
9: +-------------+
| 31-0 |
| V1 (float) |
+-------------+
10: +--------------------------+
| 31-0 |
| Base Intensity 1 (float) |
+--------------------------+
11: +----------------------------+
| 31-0 |
| Offset Intensity 1 (float) |
+----------------------------+

12-15: Not used





type 14: textured, intensity, 16-bit UV, affected by modifier volume

1: +------------+
| 31-0 |
| X (float) |
+------------+
2: +------------+
| 31-0 |
| Y (float) |
+------------+
3: +------------+
| 31-0 |
| Z (float) |
+------------+
4: +--------------+
| 31-16 | 15-0 |
| U0 | V0 |
+--------------+

5: Not used

6: +--------------------------+
| 31-0 |
| Base Intensity 0 (float) |
+--------------------------+
7: +----------------------------+
| 31-0 |
| Offset Intensity 0 (float) |
+----------------------------+
8: +--------------+
| 31-16 | 15-0 |
| U1 | V1 |
+--------------+

9: Not used

10: +--------------------------+
| 31-0 |
| Base Intensity 1 (float) |
+--------------------------+
11: +----------------------------+
| 31-0 |
| Offset Intensity 1 (float) |
+----------------------------+

12-15: Not used





type 15: non-textured sprite

1: +-------------+
| 31-0 |
| AX (float) |
+-------------+
2: +-------------+
| 31-0 |
| AY (float) |
+-------------+
3: +-------------+
| 31-0 |
| AZ (float) |
+-------------+
4: +-------------+
| 31-0 |
| BX (float) |
+-------------+
5: +-------------+
| 31-0 |
| BY (float) |
+-------------+
6: +-------------+
| 31-0 |
| BZ (float) |
+-------------+
7: +-------------+
| 31-0 |
| CX (float) |
+-------------+
8: +-------------+
| 31-0 |
| CY (float) |
+-------------+
9: +-------------+
| 31-0 |
| CZ (float) |
+-------------+
10: +-------------+
| 31-0 |
| DX (float) |
+-------------+
11: +-------------+
| 31-0 |
| DY (float) |
+-------------+

12-15: Not used




type 16: textured sprite

1: +-------------+
| 31-0 |
| AX (float) |
+-------------+
2: +-------------+
| 31-0 |
| AY (float) |
+-------------+
3: +-------------+
| 31-0 |
| AZ (float) |
+-------------+
4: +-------------+
| 31-0 |
| BX (float) |
+-------------+
5: +-------------+
| 31-0 |
| BY (float) |
+-------------+
6: +-------------+
| 31-0 |
| BZ (float) |
+-------------+
7: +-------------+
| 31-0 |
| CX (float) |
+-------------+
8: +-------------+
| 31-0 |
| CY (float) |
+-------------+
9: +-------------+
| 31-0 |
| CZ (float) |
+-------------+
10: +-------------+
| 31-0 |
| DX (float) |
+-------------+
11: +-------------+
| 31-0 |
| DY (float) |
+-------------+

12: Not used

13: +--------------+
| 31-16 | 15-0 |
| AU | AV |
+--------------+
14: +--------------+
| 31-16 | 15-0 |
| BU | BV |
+--------------+
15: +--------------+
| 31-16 | 15-0 |
| CU | CV |
+--------------+






type 17: shadow volume

1: +-------------+
| 31-0 |
| AX (float) |
+-------------+
2: +-------------+
| 31-0 |
| AY (float) |
+-------------+
3: +-------------+
| 31-0 |
| AZ (float) |
+-------------+
4: +-------------+
| 31-0 |
| BX (float) |
+-------------+
5: +-------------+
| 31-0 |
| BY (float) |
+-------------+
6: +-------------+
| 31-0 |
| BZ (float) |
+-------------+
7: +-------------+
| 31-0 |
| CX (float) |
+-------------+
8: +-------------+
| 31-0 |
| CY (float) |
+-------------+
9: +-------------+
| 31-0 |
| CZ (float) |
+-------------+

10-15: Not used


Description:
~~~~~~~~~~~~
Most of these should be self-explanatory, but a few maybe need to be clarified.
If a polygon is affected by a MODIFIER_VOLUME it should use type 9-14 which
have two instances of every parameter. This means that the parts of the polygon
(if any) that are outside the MODIFIER_VOLUME will use the first set of
parameters, while those parts inside will use the second set.

2001-Aug-08: corrected information regarding segment order

Document describing the hardware registers relating to the Tile Accelerator. there are still a few issues with this so take it with a grain of salt.

Reference guide to the TA registers 

This is a continuation of my previous text 'ta-into.txt' which described how
to construct TA lists. This document provides information about the
TA registers.

Thanks must go to Dan Potter and Sergio Moreira for very helpful contributions.


reach me at: jlo@ludd.luth.se



Introduction

The TA works by receiving lists containing vertex information. Unlike most
architectures, the PVR core uses a technique known as deferred rendering
whereby no polygons are rendered until the whole scene has been setup. The
advantage is that the PVR will only render those polygons that are actually
visible thus creating a very high fillrate. The downside is that this requires
more memory in form of buffers. Since the Dreamcast has 8 MB of VRAM this is
not that big of a problem. Besides the framebuffer, there are three buffers of
interest;

* The Vertex Buffer contains the information sent to the TA through the lists.

* The Object Pointer Buffer contains pointers into the Vertex Buffer for
objects that may appear inside a tile.

* The Tile Buffer contains pointers to the Object Pointer Buffer for every
primitive type (opaque polygon, translucent modifier etc)



The PVR can work in two different modes; vertex registration mode and vertex
rendering mode. If double-buffering is employed, vertex registration can take
place while rendering is underway, creating an efficient implementation of the
deferred rendering paradigm.



Vertex Buffer

The Vertex Buffer is the most simple one. It grows upwards in memory as more
information is sent to the TA. After setting it up, the PVR handles the
management of this buffer by itself so there is little do for the user.



Object Pointer Buffer

This buffer possesses the most complex structure of the three. Fortunately most
of it is managed by the PVR so the user doesn't have to worry too much about
its internal structure.

There are two different parts to this buffer. The first part consists of 5
matrices of Object Pointer Segments, one for each primitive type, arranged
in a special order, to be referenced from the Tile Buffer (described later).
This part of the buffer is fixed at a known size. The other part is variable
in size as new segments are allocated and linked from the first part.

The Object Pointer Segments are separate linked lists with the following
appearance;

Segment 0 for Tile 0, 0;
Object Pointer 0
Object Pointer 1
...
Object Pointer n
Pointer to Segment 1 for Tile 0, 0


The arrangement of the segments in memory is;

Segment 0, Tile 0, 0, opaque polygon
Segment 0, Tile 1, 0, opaque polygon
Segment 0, Tile 2, 0, opaque polygon
...
Segment 0, Tile x, 0, opaque polygon
Segment 0, Tile 0, 1, opaque polygon
Segment 0, Tile 1, 1, opaque polygon
Segment 0, Tile 2, 1, opaque polygon
...
Segment 0, Tile x, y, opaque polygon


The above is the Opaque Polygon Object Pointer Buffer Matrix. It is followed by
matrices for the rest of the primitives. The order (important) should be:

* Opaque Polygon
* Opaque Modifier
* Translucent Polygons
* Translucent Modifiers
* Punch-through Polygons

The sizes of the segments are controlled by register a05f8140;

a05f8140: (object pointer buffer control)
+---------------------------------------------------------------------
| 31-21 | 20 | 19-18 | 17-16 | 15-14 | 13-12 | 11-10 |
| n/a | unknown | n/a | punch-through | n/a | transmod | n/a |
+---------------------------------------------------------------------
-------------------------------------------------+
| 9-8 | 7-6 | 5-4 | 3-2 | 1-0 |
| transpoly | n/a | opaquemod | n/a | opaquepoly |
-------------------------------------------------+

unknown:
like name indicates :(
seems to always be set though


punch-through:
0: size_0: Punch-through Polygons disabled
1: size_8: 7 Object Pointers + 1 Segment Pointer
2: size_16: 15 Object Pointers + 1 Segment Pointer
3: size_32: 31 Object Pointers + 1 Segment Pointer

transmod:
0: size_0: Translucent Modifiers disabled
1: size_8: 7 Object Pointers + 1 Segment Pointer
2: size_16: 15 Object Pointers + 1 Segment Pointer
3: size_32: 31 Object Pointers + 1 Segment Pointer

transpoly:
0: size_0: Translucent Polygons disabled
1: size_8: 7 Object Pointers + 1 Segment Pointer
2: size_16: 15 Object Pointers + 1 Segment Pointer
3: size_32: 31 Object Pointers + 1 Segment Pointer

opaquemod:
0: size_0: Opaque Modifiers disabled
1: size_16: 7 Object Pointers + 1 Segment Pointer
2: size_32: 15 Object Pointers + 1 Segment Pointer
3: size_64: 31 Object Pointers + 1 Segment Pointer

opaquepoly:
0: size_0: opaque polygons disabled
1: size_16: 7 Object Pointers + 1 Segment Pointer
2: size_32: 15 Object Pointers + 1 Segment Pointer
3: size_64: 31 Object Pointers + 1 Segment Pointer


The Object Pointers are references to objects that appear inside the tile
associated with the segment. If there are more objects in one tile than fits
into one segment, the last word in the segment points to a new segment.
Notable here is that these new segments are allocated BEFORE the first
Object Pointer Buffer Matrix, so the linked lists actually grow downwards in
memory.



Tile Buffer

The PVR does not render the entire framebuffer when it is performing a
rendering sequence. Instead the framebuffer is divided into 32x32-pixel tiles
which the PVR processes seperately, reducing overhead by a large amount.
The Tile Buffer is divided into segments corresponding to the tiles the
framebuffer is split into. The size of the Tile Buffer is dependant on the
resolution of the framebuffer, ie. a 640x480 screen will make the Tile Buffer
contain 20x15 segments. The aspect ratio of the Tile Buffer should be written
to register a05f813c according to:

a05f813c: (tile buffer control)
+----------------+
| 31-16 | 15-0 |
| height | width |
+----------------+

height:
height of tile buffer in segments - 1

width:
width of tile buffer in segments - 1



The segments contain a control word followed by 5 pointers (one for each
primitive type). The control word has the following appearance:

+----------------------------------------------------+
| 31 | 30 | 29 | 28 | 27-15 | 13-8 | 7-2 | 1-0 |
| eob | ??? | sort | init | ??? | y | x | n/a |
+----------------------------------------------------+

eob: (set on last segment in Tile Buffer)
0: normal
1: end of Tile Buffer

sort:
0: autosorting translucent polygons off (the must be submitted
in sorted order to the TA)
1: autosorting translucent polygons on

init: (set on first segment in Tile Buffer)
0: normal
1: initialize Tile Buffer

y:
y position of the tile corresponding to this segment

x:
x position of the tile corresponding to this segment




The five words following are pointers into the Object Pointer Buffer. Bit 31
of the pointers is set when there is no primitive of that type. The order of
the pointers is as follows;

* opaque polygon
* opaque modifier
* translucent polygon
* translucent modifier
* punch-through polygon

Unlike the Vertex Buffer, the Tile Buffer must be setup manually before using
the TA. This is done by allocating a chunk of memory in the VRAM and filling
out the required Tile Buffer structure. If primitives of a specific type are
to be used, the Tile Segment must contain a pointer to the corresponding Object
Pointer Buffer Segment. Since the sizes of the Object Pointer Buffer Matrices
are known it is possible to calculate the location of this according to:

pointer = start_of_matrix + (width_of_tile_buffer * size_N * tile_Y)
+ (size_N * tile_X) (1)

where start_of_matrix is the address of the primitive's matrix and
size_N is the size of the segments in bytes.


The creation of the Tile Buffer need normally only be done once, at the very
beginning before any vertex registration or rendering is begun.



Sending vertex data to the Tile Accelerator

To be able to receive vertex data, the TA must have a Vertex Buffer in which
to put the received data aswell as an Object Pointer Buffer.

The register a05f8140 should be written with the size information for all the
different primitive types.

The register a05f8124 should be written with the address of the first
Object Pointer Buffer Matrix. Since this buffer has the potential to grow
arbitrarily large as more vertex data are received, register a05f812c contains
the last address that can be safely written to. Important to remember that the
Object Pointer Buffer actually grows downwards in memory so a05f812c should be
set to:

a05f812c = address_of_first_OPB_matrix - OPB_size (2)

To set up the Object Pointer Buffer, the start address should also be written
to register a05f8164 to initialize it. The current position in the
Object Pointer Buffer can be read from register a05f8134.

The Vertex Buffer start address should be written to register a05f8128 and the
end address to register a05f8130, because otherwise it could grow too large
and overwrite other data. a05f8138 contains the current position in
the vertex buffer.

To actually perform the initialization, 0x80000000 should be written to
register a05f8144 and then read (to clear the bit).

After this procedure has been performed vertex registration is possible.



Rendering vertex data to the framebuffer

To render data, vertex registration must have been initiated and finished. It
is then a simple matter of instructing the PVR where to get the data and kick
it off. Register a05f8020 should be written with the Vertex Buffer address and
register a05f802c with the address of the Tile Buffer. Register a05f8014 is
then written with all bits set to start the rendering procedure.



Summary of registers:

a05f8014: (start render)
+--------+
| 31-0 |
| render |
+--------+

render:
write 1 to all bits to start rendering procedure


a05f8020: (vertex buffer start, rendering mode)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
location of vertex buffer in VRAM (32-byte aligned)

a05f802c: (tile buffer start, rendering mode)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
location of tile buffer in VRAM (32-byte aligned)


a05f8124: (object pointer buffer start, registration mode)
+--------------+
| 31-24 | 23-0 |
| ??? | addr |
+--------------+

addr:
start of object pointer buffer in VRAM (32-byte aligned)

a05f8128: (vertex buffer start, registration mode)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
start of vertex buffer in VRAM (32-byte aligned)

a05f812c: (object pointer buffer end, registration mode)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
end of object pointer buffer in VRAM (128-byte aligned)

a05f8130: (vertex buffer end, registration mode)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
end of vertex buffer in VRAM (32-byte aligned)

a05f8134: (object pointer buffer position, registration mode)
+--------------+
| 31-23 | 22-0 |
| n/a | addr |
+--------------+

addr:
current object pointer buffer position according to;
(POSITION / 4) - size_N
where size_N is determined through register a05f8140

a05f8138: (vertex buffer position, registration mode)
+--------------+
| 31-23 | 23-0 |
| n/a | addr |
+--------------+

addr:
current vertex buffer position

a05f813c: (tile buffer control)
+----------------+
| 31-16 | 15-0 |
| height | width |
+----------------+

height:
height of tile buffer in segments - 1

width:
width of tile buffer in segments - 1


a05f8140: (object pointer buffer control)
+---------------------------------------------------------------------
| 31-21 | 20 | 19-18 | 17-16 | 15-14 | 13-12 | 11-10 |
| n/a | unknown | n/a | punch-through | n/a | transmod | n/a |
+---------------------------------------------------------------------
-------------------------------------------------+
| 9-8 | 7-6 | 5-4 | 3-2 | 1-0 |
| transpoly | n/a | opaquemod | n/a | opaquepoly |
-------------------------------------------------+

unknown:
like name indicates :(
seems to always be set though


punch-through:
0: size_0 - Punch-through Polygons disabled
1: size_8 - 7 Object Pointers + 1 Segment Pointer
2: size_16 - 15 Object Pointers + 1 Segment Pointer
3: size_32 - 31 Object Pointers + 1 Segment Pointer

transmod:
0: size_0 - Translucent Modifiers disabled
1: size_8 - 7 Object Pointers + 1 Segment Pointer
2: size_16 - 15 Object Pointers + 1 Segment Pointer
3: size_32 - 31 Object Pointers + 1 Segment Pointer

transpoly:
0: size_0 - Translucent Polygons disabled
1: size_8 - 7 Object Pointers + 1 Segment Pointer
2: size_16 - 15 Object Pointers + 1 Segment Pointer
3: size_32 - 31 Object Pointers + 1 Segment Pointer

opaquemod:
0: size_0 - Opaque Modifiers disabled
1: size_8 - 7 Object Pointers + 1 Segment Pointer
2: size_16 - 15 Object Pointers + 1 Segment Pointer
3: size_32 - 31 Object Pointers + 1 Segment Pointer

opaquepoly:
0: size_0 - Opaque Polygons disabled
1: size_8 - 7 Object Pointers + 1 Segment Pointer
2: size_16 - 15 Object Pointers + 1 Segment Pointer
3: size_32 - 31 Object Pointers + 1 Segment Pointer

a05f8144: (vertex registration init)
+-------------+
| 31 | 30-0 |
| init | n/a |
+-------------+

init:
0: normal
1: initialize vertex registration

a05f8164: (object pointer buffer init)
+--------------+
| 31-24 | 23-0 |
| n/a | addr |
+--------------+

addr:
address of object pointer buffer in VRAM (32-byte aligned)



Some Caveats

Nothing in this document is official; nothing should be expected to be correct.
I have tried hard to ensure that everything accurately reflects the reality
of the PVR, but there are no guarantees that this is the case.

If you find any inaccuracies, please contact me at: jlo@ludd.luth.se

Document describing the AICA hardware (rough, working notes)

AICA soundsystem of the Dreamcast 
by Lars Olsson < jlo@ludd.luth.se >
v0.1 (rough notes), 2001-Jun-15


The AICA registers are mapped both to the SH4 and the ARM7.
The base address is 0x00800000 on the ARM7-side and
0xa0700000 on the SH4-side.

The ARM7 is running at 25MHz (possibly slower...must do some checking)

It appears the registers are really 16-bit but arranged
on 32-bit boundries. The ARM7 can access the registers
either as 32-bit words or as 8-bit; the SH4 can only
access them as 32-bit (because of the G2 FIFO).



00800000 - 00802000: (64 sound channels)

each channel consists of 32 32-bit registers.


00800000 (ch0_cfg_addr_hi)
+----------------------------------------------------------------+
| 31-16 | 15-14 | 13-11 | 10 | 9 | 8-7 | 6-5 | 4-0 |
| n/a | key-event | n/a | u | loop | format | n/a | addr_hi |
+----------------------------------------------------------------+

key-event:
00: no change (or key off? need to recheck)
01: no change
10: key-off
11: key-on

(note: if loop is set it must be cleared for the waveform
to stop playing)

u:
only noise when set :/
(could be direction...im only using ADPCM waveform, which
could explain the noise..if so it rocks!!! (for my
xm-player that is, no need to waste sample-space by doing
repeats and stuff for ping-pong loops =)

loop:
0: waveform is played once
1: waveform is repeated according to loop-points

format:
0: 16bit
1: 8bit
2: ADPCM 4bit
3: ADPCM 4bit + loop (? dont know about this, since looping
seems to work fine for 2, but i haven't
tried diff start point than 0x0000 which
might require this setting since ADPCM
store delta instead of absolute values)

addr_hi:
highest 5 bits of waveform start address


00800004: (ch0_addr_lo)
+-----------------+
| 31-16 | 15-0 |
| n/a | addr_lo |
+-----------------+

addr_lo:
lowest 16 bits of waveform start address


00800008: (ch0_loop_start)
+---------------+
| 31-16 | 15-0 |
| n/a | start |
+---------------+

start:
starting sample of loop


0080000c: (ch0_loop_end)
+--------------+
| 31-16 | 15-0 |
| n/a | end |
+--------------+

end:
ending sample of loop


00800010: (ch0_adsr1)
+----------------------------------+
| 31-16 | 15-11 | 10-6 | 5 | 4-0 |
| n/a | DR | SR? | n/a | AR |
+----------------------------------+

envelope register for amplitude

DR:
decay rate

SR?:
sustain rate (need to check by doing a key off, only guess)

AR:
attack rate


00800014: (ch0_adsr2)
+---------------------------------------+
| 31-16 | 15 | 14 | 13-10 | 9-5 | 4-0 |
| n/a | n/a | ??? | ??? | ??? | ??? |
+---------------------------------------+

envelope register for amplitude

this register is seemingly kind of strange since
the behaviour of 00800010 changes in odd ways
when setting certain bits...will have to investigate
more thoroughly later...

unknown:
set to 0x1f


00800018: (ch0_pitch)
+----------------------+
| 31-16 | 15-11 | 10-0 |
| n/a | oct | fns |
+----------------------+

controls the pitch of the waveform

oct:
calculated according to:

[formula later]

fns:
calculated according to:

[formula later]


0080001c: (ch0_lfo1)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

envelope register for pitch

unknown:
set to 0x4210


00800020: (ch0_lfo2)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

envelope register for pitch

unknown:
set to 0x0000


00800024: (ch0_pan_volume)
+------------------------------------+
| 31-16 | 15-12 | 11-8 | 7-5 | 4-0 |
| n/a | ??? | volume | ??? | pan |
+------------------------------------+

volume:
aica level for this channel

pan: the position of this channel
this is sort of confusing:

0x00: almost in the middle
0x0f: all panned to the left
0x10: almost in the middle
0x1f: all panned to the right


00800028: (ch0_volume2?)
+--------------------------+
| 31-16 | 15-8 | 7-0 |
| n/a | volume | unknown |
+--------------------------+

volume:
logarithmic volume

unknown:
set to 0x24


0080002c: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x1fff


00800030: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x1fff


00800034: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x1fff


00800038: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x1fff


0080003c: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x1fff


00800040: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x0000


00800044: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x0000


00800048: (ch0_???)
+-----------------+
| 31-16 | 15-0 |
| n/a | unknown |
+-----------------+

unknown:
set to 0x0000

0080004c - 008007c: (not used, it seems)


[the other channels use the same layout as the above registers]

00800080 - 008000fc: (ch1)
00800100 - 0080017c: (ch2)
00800180 - 008001fc: (ch3)
00800200 - 0080027c: (ch4)
00800280 - 008002fc: (ch5)
00800300 - 0080037c: (ch6)
00800380 - 008003fc: (ch7)
00800400 - 0080047c: (ch8)
00800480 - 008004fc: (ch9)
00800500 - 0080057c: (ch10)
00800580 - 008005fc: (ch11)
00800600 - 0080067c: (ch12)
00800680 - 008006fc: (ch13)
00800700 - 0080077c: (ch14)
00800780 - 008007fc: (ch15)
00800800 - 0080087c: (ch16)
00800880 - 008008fc: (ch17)
00800900 - 0080097c: (ch18)
00800980 - 008009fc: (ch19)
00800a00 - 00800a7c: (ch20)
00800a80 - 00800afc: (ch21)
00800b00 - 00800b7c: (ch22)
00800b80 - 00800bfc: (ch23)
00800c00 - 00800c7c: (ch24)
00800c80 - 00800cfc: (ch25)
00800d00 - 00800d7c: (ch26)
00800d80 - 00800dfc: (ch27)
00800e00 - 00800e7c: (ch28)
00800e80 - 00800efc: (ch29)
00800f00 - 00800f7c: (ch30)
00800f80 - 00800ffc: (ch31)
00801000 - 0080107c: (ch32)
00801080 - 008010fc: (ch33)
00801100 - 0080117c: (ch34)
00801180 - 008011fc: (ch35)
00801200 - 0080127c: (ch36)
00801280 - 008012fc: (ch37)
00801300 - 0080137c: (ch38)
00801380 - 008013fc: (ch39)
00801400 - 0080147c: (ch40)
00801480 - 008014fc: (ch41)
00801500 - 0080157c: (ch42)
00801580 - 008015fc: (ch43)
00801600 - 0080167c: (ch44)
00801680 - 008016fc: (ch45)
00801700 - 0080177c: (ch46)
00801780 - 008017fc: (ch47)
00801800 - 0080187c: (ch48)
00801880 - 008018fc: (ch49)
00801900 - 0080197c: (ch50)
00801980 - 008019fc: (ch51)
00801a00 - 00801a7c: (ch52)
00801a80 - 00801afc: (ch53)
00801b00 - 00801b7c: (ch54)
00801b80 - 00801bfc: (ch55)
00801c00 - 00801c7c: (ch56)
00801c80 - 00801cfc: (ch57)
00801d00 - 00801d7c: (ch58)
00801d80 - 00801dfc: (ch59)
00801e00 - 00801e7c: (ch60)
00801e80 - 00801efc: (ch61)
00801f00 - 00801f7c: (ch62)
00801f80 - 00801ffc: (ch63)

00802000: (???)

00802004: (???)

00802008: (???)

0080200c: (???)

00802010: (???)

00802014: (???)

00802018: (???)

0080201c: (???)

00802020: (???)

00802024: (???)

00802028: (???)

0080202c: (???)

00802030: (???)

00802034: (???)

00802038: (???)

0080203c: (???)


00802040: (cd_pan_volume_left)
+---------------------------------------------+
| 31-16 | 15-13 | 12 | 11-8 | 7-5 | 4-0 |
| n/a | n/a | init? | volume | n/a | pan |
+---------------------------------------------+

volume:
aica level volume for CD audio for left channel

pan: the position of the left channel
this is sort of confusing:

0x00: almost in the middle
0x0f: all panned to the left
0x10: almost in the middle
0x1f: all panned to the right


00802044: (cd_pan_volume_right)
+---------------------------------------------+
| 31-16 | 15-13 | 12 | 11-8 | 7-5 | 4-0 |
| n/a | n/a | init? | volume | n/a | pan |
+---------------------------------------------+

volume:
aica level volume for CD audio for right channel

pan: the position of the right channel
this is sort of confusing:

0x00: almost in the middle
0x0f: all panned to the left
0x10: almost in the middle
0x1f: all panned to the right


00802890: (irq_timer_count)
+---------------+
| 31-16 | 15-0 |
| n/a | count |
+---------------+

count:
(set to 0x00d4)


0080289c: (???)
+--------------+
| 31-16 | 15-0 |
| n/a | ??? |
+--------------+


008028a4: (???)
+--------------+
| 31-16 | 15-0 |
| n/a | ??? |
+--------------+


008028a8: (???)
+------------------------+
| 31-16 | 15-8 | 7-0 |
| n/a | ??? | unknown |
+------------------------+

unknown:
set to 0x18


008028ac: (???)
+------------------------+
| 31-16 | 15-8 | 7-0 |
| n/a | ??? | unknown |
+------------------------+

unknown:
set to 0x50


008028b0: (???)
+------------------------+
| 31-16 | 15-8 | 7-0 |
| n/a | ??? | unknown |
+------------------------+

unknown:
set to 0x08


008028b4: (irq_mask)
+--------------+
| 31-16 | 15-0 |
| n/a | ??? |
+--------------+


008028b8: (irq_request)
+--------------+
| 31-16 | 15-0 |
| n/a | ??? |
+--------------+


008028bc: (irq_pending)
+--------------+
| 31-16 | 15-0 |
| n/a | ??? |
+--------------+


008028b?: (irq_clear)
+--------------+
| 31-16 | 15-0 |
| n/a | ??? |
+--------------+


00802d00: (irq_pend)
+--------------+
| 31-16 | 15-0 |
| n/a | mask |
+--------------+


00802d04: (irq_clear)
+--------------+
| 31-16 | 15-0 |
| n/a | pend |
+--------------+


00803bfc - 008033fc: (dsp registers)
+--------------+
| 31-16 | 15-0 |
| n/a | ???? |
+--------------+


[this is mayhaps also accessible to the ARM7 but not tested]

a0702c00: (av_ctrl)
+-------------------------------------+
| 31-16 | 15-10 | 9-8 | 7-1 | 0 |
| n/a | n/a | cable | n/a | reset |
+-------------------------------------+

cable:
type of video cable the display is to be set for:

0: VGA
1: ???
2: RGB
3: composite

reset:
0: normal
1: reset ARM7

This is reversed C code of the IP.BIN code that shows the logo. It is not 100% complete but most of the functionality should be apparent. There are a few bugs in Sega's code but unfortunately it still seems impossible to get rid of the "PRODUCED BY..." text. This piece of code was ripped from my reverse of the bootROM code. I've been toying with the idea of releasing the whole of it, but I'm not sure the Powers That Be would approve...

/* SEGA Dreamcast IP.BIN 
*
* Hacked by Lars Olsson
*
* Questions, corrections etc:
* jlo@ludd.luth.se
*
* Notes:
* ~~~~~~
*
* reg[REG] = access to register REG (including both normal
* CPU registers aswell as CPU-related memory-mapped
* registers, but NOT other hardware registers)
*
*
* Most names have been made up by me and can be very misleading,
* even to the point of being downright incorrect with regards to
* their actual functions
*
* Beware: this source code is only meant to illustrate the function
* of the BootROM and it is not a 100% translation of the actual code.
* A number of short cuts and simplifications have been made in order
* to clarify the operation, which was the purpose of this whole exercise.
*
* Compiling this source (in so far it is possible at all) will NOT
* produce a proper BootROM! For a myriad of reasons...
*
*/


#include "types.h"
#include "bootROM.h"
#include "hwregs.h"

/*******************************************************************************
*
* START OF IP.BIN
*
*****************************************************************************
/* This code is loaded from IP.BIN. The copy in ROM actually resides
* at 80008000 instead
*/

void
_ac008300()
{
reg[CCR] = 0x0000092b;
reg[R15] = 0x7e001000; / * use cache as memory for stack * /
init_splash_screen();
_ac00b700(); / * jump to bootstrap1 * /
}

void
copy_to_framebuffer(image) / * _8c008330 * /
uint32_t *image;
{
uint32_t width = 640; / * really not used! * /
uint32_t height = 480;
uint32_t *dst;
uint32_t size = 640 * 480;

dst = (uint32_t *)(0xa5200000 + (640 * 4 * 480));
do {
*dst-- = *image++;
} while (size-- != 0);
}

void
memset4(arg1, arg2, arg3) / * 8c00836c * /
uint32_t *dst;
uint32_t size;
uint32_t data;
{
dst += size;
size *= 2;

while (size-- != 0) {
*dst-- = data;
}
}

uint32_t
get_video_cable() / * _8c008380 * /
{
uint32_t cable;

cable = (*(uint16_t *)0xff800030 & 0x0300) | (*(uint32_t *)0xa0702c00 & 0xfffffcff);
*(uint32_t *)0xa0702c00 = cable;
return (cable);
}

void
init_splash_screen() / * 8c0083a8 * /
{
clear_variables();
*(uint32_t *)0x8ced3d9c = 0;
show_splash_screen();
}

void
clear_variables() / * _8c0083c0 * /
{
uint8_t *dst = (uint8_t *)0x8ced3d00; / * 1, R15 * /

while (dst < (uint8_t *)0x8ced3da0) {
*dst++ = 0;
}
}

void
show_splash_screen() / * 8c0083f8 * /
{
uint32_t old_SR;
uint32_t video_mode; / * 9, R15 * /
uint32_t i; / * 8, R15 * /
uint32_t initial_time; / * 7, R15, j * /
uint32_t current_time; / * 6, R15 * /
uint32_t time_diff; / * 5, R15 * /
uint32_t timeout; / * 4, R15 * /
uint32_t finished; / * 3, R15 * /
uint32_t delay; / * 2, R15 * /
uint32_t max_loop; / * 1, R15 * /

init_timer();

old_SR = (reg[SR]>>4) & 0x0000000f;
reg[SR] = (reg[SR] & 0xffffff0f) | 0x000000f0;

video_mode = get_video_mode();

reg[SR] = ((old_SR & 0x0000000f) < < 4) | (reg[SR] & 0xffffff0f);

switch (video_mode) {
case 1:
case 3:
i = 8;
break;
case 4:
/ * VGA * /
i = 9;
break;
default:
i = 6;
break;
}
/ * _8c008460 * /
old_SR = (reg[SR]>>4) & 0x0000000f;
reg[SR] = (reg[SR] & 0xffffff0f) | 0x000000f0;

init_graphics(i);

reg[SR] = ((old_SR & 0x0000000f) < < 4) | (reg[SR] & 0xffffff0f);

/ * render splash screen to framebuffer * /
render_frame(i);
set_display(1);

/ * wait a little while * /
initial_time = get_timer();
max_loop = 0;
finished = 0;
while (finished == 0) {
new_time = get_timer();
time_diff = get_time_difference(initial_time, new_time);
timeout = convert_time(time_diff);

delay = 0;
while (delay++ < 1000);

if (max_loop++ >= 4000) {
finished = 1;
}
if (timeout >= 6000000) {
break;
}
}
/ * 8c00851e * /

sys_do_bioscall(0); / * boot5() * /
}

/ * this renders images and text to framebuffer * /
void
render_frame(arg) / * 8c00853c * /
uin32_t arg;
{
uint32_t weird_value; / * 0, R15 * /

fill_8ced4000(arg, 0x00c0c0c0);
weird_value = compute_weird_value();
print_text(340, 189, "PRODUCED BY OR"); / * *(uint32_t *)0x8c009d98 * /
print_text(340, 213, "UNDER LICENSE FROM"); / * *(uint32_t *)0x8c009d9c * /
print_text(340, 237, "SEGA ENTERPRISES, LTD"); / * *(uint32_t *)0x8c009da0 * /
_8c008b68(337, 186, 780, 260); / * image? * /
_8c00892c(weird_value);
show_small_logo();
upload_image();
}

void
print_text(xpos, ypos, text) / * 8c0085cc * /
uint16_t xpos; / * _0012, R15 * /
uint16_t ypos; / * _0010, R15 * /
sint8_t *text; / * _000c, R15 * /
{
uint32_t len; / * _0008, R15 * /
uint16_t x; / * _0002, R15 * /
uint16_t y; / * _0000, R15 * /
uint32_t i; / * _0004, R15 * /

len = strlen(text);
x = xpos;
y = ypos;
i = 0;

while (i < len) {
/ * 8c0085f8 * /
if (text[i] == 'L' && text[i+1] == 'T') {
print_char(&x, &y, 0x1f); / * print LTD glyph * /
i += 2;
} else {
/ * 8c00862c * /
print_char(&x, &y, text[i]);
i++;
}
}
}

void
print_char(x, y, c) / * 8c008652 * /
uint16_t *x; / * _0034, R15 * /
uint16_t *y; / * _0030, R15 * /
sint8_t c; / * _002f, R15 * /
{
uint8_t buf[20]; / * _0004, R15 * /
uint32_t i; / * _0024, R15 * /
uint32_t *p; / * _0020, R15 * /
uint8_t *p2; / * _0000, R15 * /
uint32_t j; / * _0028, R15 * /

_8c009ba8(8, buf, (void *)0x8c009d40); / * bah...weird function * /
if (c == ' ') {
*x += 5;
return;
}

/ * find the char in a list * /
p = (uint32_t *)0xac00b46e;
p2 = (uint8_t *)0x8c009da4;
i = 63;
j = 0;
while (j < 63) {
if (p2[0] == c) {
break;
}
p = p + p2[2];
p2 += 3;
j++;
}
/ * 8c0086de * /

/ * WORK TO DO HERE * /

}

void
show_small_logo() / * 8c0087fc * /
{
mr_env_t env;
mr_t mr;

/ * The palette buffer is placed right before the local framebuffer.
* There exists a buffer overflow condition in the code that copies
* the palette which means it's possible to overwrite the rendered
* frame before it is shown! Unfortunately the size of the palette is
* limited to a 16-bit integer which means it's not possible to write
* enough data to cover the offending "PRODUCED BY..." text :(
* /
mr.palette = (uint8_t *)0x8ced3e00;
mr.image = (uint8_t *)0x8c00b820;

env.x = 300; / * position of logo * /
env.y = 298;
env.c = 0;
env.d = 0;

decode_small_logo(&mr, &env, 320, 90);
}

void
upload_image() / * 8c008b4c * /
{
uint32_t *frame = (uint32_t *)0x8ced4000;
uint32_t foo = 0; / * not used * /

copy_to_framebuffer(frame);
}

/ * copies sega logo probably * /
void
_8c008b68(a, b, c, d) / * 8c008b68 * /
sint16_t x1; / * _000e, R15 * /
sint16_t y1; / * _000c, R15 * /
sint16_t x2; / * _000a, R15 * /
sint16_t y2; / * _0008, R15 * /
{
uint32_t *d = (uint32_t *)0x8ced4000; / * _0004, R15 * /
uint32_t i = 0; / * _0000, R15 * /

d += (((((479 - y1) * 640) - x1) + 639) * 4);
while (d < (((((479 - y2) * 640) - x2) + 639) * 4) + 0x8ced40000) {
/ * 8c008bc4 * /
d++;
_8c008c54
}

}

/ * Now! This is a weird function indeed! * /
void
compute_weird_value() / * 8c0088b0 * /
{
uint32_t i = 0; / * _0014 R15 * /
uint32_t j = 0; / * _0004 R15 * /
uint8_t buf[12]; / * _0008 R15 * /

copy_string(buf, "SEGAKATANA"); / * 8c009d48 * /

while (j < sizeof(buf)) {
/ * 8c0088cc * /
i += buf[j] * buf[j + 1];
j += 2;
}
/ * 8c0088f6 * /
/ * i becomes 25747 after completing above * /
/ * what sync_cfg is, is a little harder to determine * /
/ * definitely 0x100, but perhaps also 0x10 (interlace) is set * /
return ((PVR->sync_cfg & 0xffffff3f) * i);
}

/ * weirdest yet... * /
void
_8c00892c(key)
uint32_t key;
{
uint8_t buf1[] = { 0xef, 0xcd, 0xab, 0x89, }; / * _0000, R15 * /
uint8_t buf2[] = { 0x67, 0x45, 0x23, 0x01, }; / * _0004, R15 * /
uint16_t k; / * _000c, R15 * /
uint8_t i; / * _000e, R15 * /
uint8_t j; / * _000f, R15 * /

if (key == 0x0067b768) {
return;
}

for (k = 0; k < 6; k++) {
/ * 8c00894c * /
j = buf2[0];
i = buf1[0];
*(uint32_t *)&buf2[0] = ((*(uint32_t *)&buf2[0]) < < 8) + i;
*(uint32_t *)&buf2[0] = ((*(uint32_t *)&buf1[0]) < < 8) + j;
}
/ * 8c00897a * /
}

void
fill_8ced4000(arg, col) / * 8c008aa0 * /
uint32_t arg, col;
{
memset4((uint32_t *)0x8ced4000, 0x0012c000, col);
}

void
print_pixel(x, y, pixel) / * _8c008ad0 * /
sint32_t x; / * _000c, R15 - 3, R15 * /
sint32_t y; / * _0008, R15 - 2, R15 * /
uint32_t pixel; / * _0004, R15 - 1, R15 * /
{
uint32_t *p:

p = (((((479 - y) * 640) - x) + 639) * 4) + (uint32_t *)0x8ced4000;
*p = pixel;
}

/ * interesting * /
void
decode_small_logo(mr, env, w, h) / * 8c008d74 * /
mr_t *mr; / * 11, _002c, R15 * /
mr_env_t *env; / * 10, _0028, R15 * /
sint16_t w; / * _0026, R15 * /
sint16_t h; / * _0024, R15 * /
{
uint8_t *p = mr->image; / * _0020, 8, R15 * /
uint8_t color; / * _001f, R15 * /
uint32_t *p2; / * _0014, 5, R15 * /
uint32_t j; / * _0010, 4, R15 * /
uint32_t i; / * _000c, 3, R15 * /
uint32_t len; / * _0004, R15 * /
sint16_t cur_x; / * _0002, R15 * /
sint16_t cur_y; / * _0000, R15 * /

/ * check if there is a small logo * /
if (p[0] != 'M' || p[1] != 'R') {
return;
}
/ * 8c008daa * /
p += 2;

mr->size = (sint32_t)read_int(p);
p += 8;

/ * p2 = image data * /
p2 = (uint8_t *)(mr->image + (sint32_t)read_int(p));
p += 4;

mr->width = (sint16_t)read_int(p);
/ * 8c008dea * /
p += 4;

mr->height = (sint16_t)read_int(p);
p += 4;

/ * this doesn't seem to be used anywhere * /
mr->foo = (sint16_t)read_int(p);
p += 4;

/ * number of colors * /
mr->colors = (sint16_t)read_int(p);
p += 4;

j = 0;
/ * This is an unsigned comparison but mr->colors is sign-extended * /
/ * No bounds checking but not easy to overwrite "PRODUCED.." text
* because mr->colors is only 16-bit, and while it can be negative,
* it will cause alot of thrashing when overwriting... * /
while (j < mr->colors) {
mr->palette[j] = read_int(p);
p += 4;
j++;
}
/ * 8c008e5e * /
p = p2;

cur_x = 0;
cur_y = 0;
j = 0;
/ * this is an unsigned comparison but a signed multiplication * /
while (j < (mr->width * mr->height)) {
p += decompress_data(p, &len, &color);
if (env->c == 2 && env->d == color) {
/ * 8c008e9e, transparency? never reached in any case * /
j += len;
cur_y += _8c009980(mr->width, cur_x + len); / * args in r0, r1 prolly * /
cur_x = _8c009af0(mr->width, cur_x + len); / * args in r0, r1, prolly * /

} else {
/ * 8c008ed2 * /
i = 0;
/ * unsigned comparison * /
while (i < len) {
/ * 8c008ee4 * /
/ * signed comparisons, both are sign-extended * /
if (cur_x < w && cur_y < h) {
/ * 8c008efa * /
/ * this must print the pixel * /
/ * if cur_y is negative, it's possible
to move the logo upwards * /
print_pixel(env->x + cur_x, env->y + cur_y, mr->palette[color]);

}
/ * 8c008f20 * /
j++;
/ * 8c008f26 * /
/ * signed comparison * /
if (++cur_x >= mr->width) {
cur_x = 0;
cur_y++;
}
/ * 8c008f42 * /
i++;
}
/ * 8c008f50 * /
}
/ * 8c008f50 * /
}
/ * 8c008f64 * /
}

uint32_t
decompress_data(p, len, color) / * 8c008f70 * /
uint8_t *p; / * _000c, R15 - 3, R15 * /
uint32_t *len; / * _0008, R15 - 2, R15 * /
uint8_t *color; / * _0004, R15 - 1, R15 * /
{
uint32_t i; / * _0000, R15 * /

*len = 0;
i = 1;

if (*p & 0x80 == 0) {
*len = 1;
*color = *p;
return (i);
}
/ * 8c008f9e * /
while (*p & 0x80 != 0) {
*len < < = 7;
*len |= *len & 0x7f;
p++;
i++;
}
/ * 8c008fd2 * /
*color = *p;
return (i);
}

sint8_t
read_byte(p) / * 8c008fe8 * /
sint8_t *p;
{
return (*p);
}

uint32_t
read_int(p) / * _8c008ffc * /
sint8_t *p; / * _000c, R15 - 3, R15 * /
{
uint32_t val; / * _0008, R15 - 2, R15 * /
uint32_t j; / * _0004, R15 - 1, R15 * /

val = 0;
j = 0;
while (j < 4) {
val = val + (uint8_t)read_byte(p + j) < < j*8;
j++;
}
return (val);
}

void
init_graphics(arg) / * 8c009074
uint32_t arg;
{
init_graphics2(arg);
}

/ * this function is patched before execution starts * /
void
set_display(enable) / * 8c00908c * /
uint32_t enable;
{
HOLLY->pend0 = 0x00000008;
while (HOLLY->pend0 != 0x00000008);

if (enable == 1) {
/ * 8c0090a8 * /
PVR->fb_cfg1 = *(uint32_t *)0x8ced3d24;
PVR->video_cfg = *(uint32_t *)0x8ced3d18;

} else {
/ * 8c0090c4 * /
PVR->video_cfg = *(uint32_t *)0x8ced3d18 | 0x00000008;
/ * here's the patched version: * /
PVR->fb_cfg1 = *(uint32_t *)0x8ced3d24;
/ * and here's the unpatched one:
* PVR->fb_cfg1 = 0x00000000;
* /
}
}

uint32_t
init_PVR(arg) / * 8c0090f8 * /
uint32_t arg;
{
uint32_t id;
uint32_t i, fog;

id = PVR->id;
PVR->reset = 0x00000000;
*(uint32_t *)0x8ced3d18 = (sysvars->unknown0 < < 16) | 0x08;
*(uint32_t *)0x8ced3d24 = 0x0000000c;

if (arg == 9) {
*(uint32_t *)0x8ced3d24 |= 0x00800000;
}

PVR->border_col = 0x00c0c0c0;

set_display(0);

PVR->spansort_cfg = 0x00000101;
PVR->fog_table_col = 0x007f7f7f;
PVR->fog_vertex_col = 0x007f7f7f;
PVR->fog_density = 0x0000ff07;

fog = 0xfffe;
for (i = 0; i < 128; i++) {
((uint32_t *)&PVR->fog_table)[i] = fog; / * weird * /
fog = fog - 0x0101;
}

PVR->reset = 0x00000001;
PVR->reset = 0x00000000;

*HW32(0xa05f6884) = 0x00000000;
*HW32(0xa05f6888) = 0x00000000;

return (id);
}

void
set_display_mode_regs(arg) / * 8c009214 * /
uint32_t arg;
{
PVR->ta_opb_start = 0x000c2680;
PVR->ta_opb_end = 0x0009e800;
PVR->ta_ob_start = 0x00000000;
PVR->ta_ob_end = 0x0009e740;
PVR->tilebuf_size = 0x000e0013;
PVR->ta_opb_cfg = 0x00100203;
PVR->ta_opl_start = 0x000c2680;
PVR->ta_init = 0x80000000;
PVR->pclip_x = ((*_8ced3d00-1) < < 16) & 0x07ff0000;
PVR->pclip_y = ((*_8ced3d04-1) < < 16) & 0x07ff0000;
PVR->burst_cfg = 0x00093f39;
PVR->sync_cfg = *(uint32_t *)0x8ced3d44;
PVR->hborder = *(uint32_t *)0x8ced3d4c;
PVR->vborder = *(uint32_t *)0x8ced3d50;
PVR->sync_load = *(uint32_t *)0x8ced3d54;
PVR->sync_width = *(uint32_t *)0x8ced3d58;
PVR->render_addr1 = *(uint32_t *)0x8ced3d38;
PVR->render_addr2 = *(uint32_t *)0x8ced3d40;
PVR->fb_cfg2 = *(uint32_t *)0x8ced3d28;
PVR->render_modulo = *(uint32_t *)0x8ced3d2c;
PVR->display_addr1 = *(uint32_t *)0x8ced3d34;
PVR->display_addr2 = *(uint32_t *)0x8ced3d3c;
PVR->display_size = *(uint32_t *)0x8ced3d30;
PVR->hpos_irq = *(uint32_t *)0x8ced3d48;
PVR->shadow = 0x00000001;
PVR->ob_cfg = 0x0027df77;
PVR->half_offset = 0x00000007;
PVR->luminance = 0x00008040;
PVR->object_clip = 0x3f800000;
PVR->tsp_clip = 0x00000000;
PVR->bgplane_z = 0.000100;
PVR->bgplane_cfg = 0x01000000;
PVR->clamp_max = 0xffffffff;
PVR->clamp_min = 0xff000000;
PVR->tsp_cfg = *(uint32_t *)0x8ced3d10;
PVR->border_col = *(uint32_t *)0x8ced3d14;
PVR->scaler_cfg = *(uint32_t *)0x8ced3d5c;
}

/ * This whole function is skipped because of patching! * /
void
clear_display_cable(arg) / * 8c00940a * /
uint32_t arg;
{
/ * unpatched:
* if (arg == 9) {
* *HW32(0xa0702c00) = *HW32(0xa0702c00) & 0x01;
* } else {
* *HW32(0xa0702c00) = (*HW32(0xa0702c00) & 0x01) | 0x00000300;
* }
* /
}

void
set_display_mode_vars2(displaymode) / * 8c009488 * /
uint32_t displaymode; / * 2, R15 * /
{
uint32_t i = 4; / * 1, R15 * /

*(uint32_t *)0x8ced3d24 = 1;
*(uint32_t *)0x8ced3d28 = 0;
*(uint32_t *)0x8ced3d44 = 0x0100;
*(uint32_t *)0x8ced3d18 = sysvars->unknown0 < < 16;
*(uint32_t *)0x8ced3d24 |= 0x0000000c;
*(uint32_t *)0x8ced3d28 |= 0x00000006;

/ * i'll bet that these are pvr display modes (pal, ntsc, vga) * /
switch (displaymode & 0x0f) {
case 0x01:
/ * 8c0094f0 * /
displaymode = (displaymode & 0xffffff0f) | 0x00000010;
*(uint32_t *)0x8ced3d24 |= 0x00800000;
*(uint32_t *)0x8ced3d48 = 0x03450000;
*(uint32_t *)0x8ced3d4c = 0x007e0345;
*(uint32_t *)0x8ced3d50 = 0x00280208;
*(uint32_t *)0x8ced3d54 = 0x020c0359;
*(uint32_t *)0x8ced3d58 = 0x03f1933f;
break;
case 0x04:
/ * 8c009526 * /
*(uint32_t *)0x8ced3d44 |= 0x00000090;
*(uint32_t *)0x8ced3d48 = 0x034b0000;
*(uint32_t *)0x8ced3d4c = 0x008d034b;
*(uint32_t *)0x8ced3d50 = 0x002c026c;
*(uint32_t *)0x8ced3d54 = 0x0270035f;
*(uint32_t *)0x8ced3d58 = 0x07d6a53f;
break;
case 0x02:
default:
/ * 8c009550 * /
*(uint32_t *)0x8ced3d44 |= 0x00000050;
*(uint32_t *)0x8ced3d48 = 0x03450000;
*(uint32_t *)0x8ced3d4c = 0x007e0345;
*(uint32_t *)0x8ced3d50 = 0x00240204;
*(uint32_t *)0x8ced3d54 = 0x020c0359;
*(uint32_t *)0x8ced3d58 = 0x07d6c63f;
break;
}
/ * 8c0095cc * /
*(uint32_t *)0x8ced3d00 = 640;
*(uint32_t *)0x8ced3d04 = 480;

if (displaymode & 0x00000200) {
*(uint32_t *)0x8ced3d34 = 0x00200000;
*(uint32_t *)0x8ced3d3c = (640 * i) + 0x00200000;
*(uint32_t *)0x8ced3d38 = 0x00600000;
*(uint32_t *)0x8ced3d40 = (640 * i) + 0x00600000;
*(uint32_t *)0x8ced3d30 = (((640 * i + 1) < < 20) & 0x3ff00000)
| ((((*(uint32_t *)0x8ced3d04>>1) - 1) < < 10) & 0x000ffc00)
| (((640 * i) - 1) & 0x000003ff);
*(uint32_t *)0x8ced3d5c = 0x00000400;
*(uint32_t *)0x8ced3d8c = 0x00000000;
} else {
/ * 8c0096b4 * /
*(uint32_t *)0x8ced3d30 = (((*(uint32_t *)0x8ced3d04 - 1) < < 10) & 0x000ffc00)
| (((640 * i) - 1) & 0x000003ff)
| 0x00100000;
*(uint32_t *)0x8ced3d5c = 0x00000400;
*(uint32_t *)0x8ced3d34 = 0x00200000;
*(uint32_t *)0x8ced3d3c = 0x00200000;
*(uint32_t *)0x8ced3d38 = 0x00600000;
*(uint32_t *)0x8ced3d40 = 0x00600000;
*(uint32_t *)0x8ced3d8c = 0x00000000;
}
/ * 8c009704 * /
PVR->vpos_irq = 0x00150104;
*(uint32_t *)0x8ced3d2c = (*(uint32_t *)0x8ced3d00 * i)/8;
*(uint32_t *)0x8ced3d08 = (*(uint32_t *)0x8ced3d04 * *(uint32_t *)0x8ced3d2c) * 8;
*(uint32_t *)0x8ced3d78 = 0x00000000;
*(uint32_t *)0x8ced3d14 = 0x00c0c0c0;
*(uint32_t *)0x8ced3d0c = 640;
*(uint32_t *)0x8ced3d10 = 0x00000000;
}

void
set_display_mode_vars(arg) / * 8c0097b4 * /
uint32_t arg;
{
clear_display_cable(arg);

switch (arg) {
case 6:
set_display_mode_vars2(0x00008212);
break;
case 8:
set_display_mode_vars2(0x00008214);
break;
case 9:
set_display_mode_vars2(0x00008111);
break;
default:
set_display_mode_vars2(0x00008212);
break;
}

}

void
init_graphics2(arg) / * 8c009830 * /
int arg;
{
init_PVR(arg);
set_display_mode_vars(arg);
set_display_mode_regs(arg);
}

uint32_t
get_video_mode() / * 8c009858 * /
{
uint32_t cable;
uint8_t video;

cable = get_video_cable();
video = sysvars->config.video_system;

if (cable == 0) {
return (4);
}

switch (video) {
case '0':
return (0);
break;
case '1':
return (1);
break;
case '2':
return (2);
break;
case '3':
return (3);
break;
default:
return (0);
break;
}
}

void
copy_string(buf, string) / * 8c009c4c * /
uint8_t *buf;
uint8_t *string;
{
strcpy(buf, string); / * passes args in r0,r1 * /
}

/ * takes args in r0, r1 * /
uint8_t *
strcpy(buf, string) / * _8c009c74 * /
uint8_t *buf;
uint8_t *string;
{
uint32_t i = 0;

/ * check for alignment i guess, but both addresses should always be
* 32-bit aligned in bootROM
if ((buf & 0x03 | string & 0x03) != 0) {
/ * so this should never happen * /
while (1) {
buf[i] = *string++;
if (buf[i] == '\0') {
return (buf);
}
buf[i+1] = *string++;
if (buf[i+1] == '\0') {
return (buf);
}
buf[i+2] = *string++;
if (buf[i+2] == '\0') {
return (buf);
}
buf[i+3] = *string++;
if (buf[i+3] == '\0') {
return (buf);
}
}
}
/ * 8c009cb8 * /
/ * weird here, skips first two instructions of a function :/ * /
strcpy4+4(buf, string);

}

/ * it seems this will just make a 32-bit copy instead * /
void
strcpy4(buf, string) / * 8c009cc4 * /
uint32_t *buf;
uint32_t *string;
{
uint32_t val;

if (*string == 0x00000000) {
}
}

uint32_t
strlen(s) / * 8c009c62 * /
uint8_t *s;
{
uint32_t n = 0;

while (*s++) {
n++;
}
return (n);
}

void
init_timer() / * 8c009dec * /
{
reg[TOCR] = 0x00;
reg[TSTR] = reg[TSTR] & 0xfe;
reg[TCR0] = 0x0002;
reg[TCOR0] = 0xffffffff;
reg[TCNT0] = 0xffffffff;
reg[TSTR] = reg[TSTR] | 0x01;
}

uint32_t
get_timer() / * 8c009e12 * /
{
return (0xffffffff - *(volatile uin32_t *)0xffd8000c);
}

uint32_t
get_time_difference(time1, time2) / * 8c009e1c * /
uint32_t time1, time2;
{
return (time2, time1);
}

uint32_t
convert_time(time) / * 8c009e24 * /
uint32_t time;
{
/ * WORK TO DO HERE * /
}


/ *******************************************************************************
*
* END OF IP.BIN
*
****************************************************************************** /

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT