Supermodel/core/r3d.c
Ville Linde b4f2c7d9fe
2006-07-12 16:18:04 +00:00

938 lines
25 KiB
C

/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* r3d.c
*
* Real3D Model 3 graphics system emulation. The 3D hardware in Model 3 is
* supposedly based on the Pro-1000.
*
* To-Do List:
* -----------
* - In VS2_98, in the attract mode, when the camera zooms in on the score
* board for South Africa vs. Nigeria, the "Nigeria" text texture is
* garbage.
* - RAM texture uploading is too weird to be true.
*/
/*
* RAM Size:
* ---------
*
* It appears that there is 2MB total of "culling RAM." 1MB appears at
* 0x8C000000 and the other at 0x8E000000. Step 1.0 and 1.5 appear to have
* 1MB of polygon RAM, but Step 2.0 (and probably 2.1) clearly uses 2MB.
*/
#include "model3.h"
extern UINT8 *ram;
/******************************************************************/
/* Privates */
/******************************************************************/
static UINT8 *culling_ram_8e; // culling RAM at 0x8E000000
static UINT8 *culling_ram_8c; // culling RAM at 0x8C000000
static UINT8 *polygon_ram; // polygon RAM at 0x98000000
static UINT8 *texture_ram; // texture RAM
static UINT8 *vrom;
static UINT8 texture_buffer_ram[1*1024*1024];
static UINT32 vrom_texture_address;
static UINT32 vrom_texture_header;
static UINT32 texture_last_addr = 0;
static UINT32 texture_header = 0;
/******************************************************************/
/* Interface */
/******************************************************************/
/*
* void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
* UINT8 *polygon_ram_ptr, UINT8 *texture_ram, UINT8 *vrom_ptr);
*
* Initializes the Real3D graphics emulation.
*
* Parameters:
* culling_ram_8e_ptr = Pointer to 0x8E000000 culling RAM.
* culling_ram_8c_ptr = Pointer to 0x8C000000 culling RAM.
* polygon_ram_ptr = Pointer to polygon RAM.
* texture_ram = Pointer to texture RAM.
* vrom_ptr = Pointer to VROM.
*/
void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr,
UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr, UINT8 *vrom_ptr)
{
culling_ram_8e = culling_ram_8e_ptr;
culling_ram_8c = culling_ram_8c_ptr;
polygon_ram = polygon_ram_ptr;
texture_ram = texture_ram_ptr;
vrom = vrom_ptr;
LOG_INIT("texture.log");
}
/*
* void r3d_shutdown(void);
*
* Shuts down the Real3D emulation.
*/
void r3d_shutdown(void)
{
}
/*
* void r3d_reset(void);
*
* Resets the Real3D graphics hardware. RAM is cleared in order to prevent
* the renderer from drawing garbage and possibly locking up as a result.
*/
void r3d_reset(void)
{
memset(culling_ram_8e, 0, 1*1024*1024);
memset(culling_ram_8c, 0, 4*1024*1024);
memset(polygon_ram, 0, 2*1024*1024);
memset(texture_ram, 0, 2048*2048*2);
tap_reset();
}
/*
* void r3d_save_state(FILE *fp);
*
* Saves the state of the Real3D graphics hardware to a file.
*
* Parameters:
* fp = File to save to.
*/
void r3d_save_state(FILE *fp)
{
fwrite(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp);
fwrite(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp);
fwrite(polygon_ram, sizeof(UINT8), 2*1024*1024, fp);
fwrite(texture_ram, sizeof(UINT8), 2048*2048*2, fp);
}
/*
* void r3d_load_state(FILE *fp);
*
* Loads the state of the Real3D graphics hardware from a file.
*
* Parameters:
* fp = File to load from.
*/
void r3d_load_state(FILE *fp)
{
fread(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp);
fread(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp);
fread(polygon_ram, sizeof(UINT8), 2*1024*1024, fp);
fread(texture_ram, sizeof(UINT8), 2048*2048*2, fp);
osd_renderer_invalidate_textures(0, 0, 0, 0, 2048, 2048, texture_ram, 0);
}
/******************************************************************/
/* Texture Memory Management */
/******************************************************************/
static const INT decode[64] =
{
0, 1, 4, 5, 8, 9,12,13,
2, 3, 6, 7,10,11,14,15,
16,17,20,21,24,25,28,29,
18,19,22,23,26,27,30,31,
32,33,36,37,40,41,44,45,
34,35,38,39,42,43,46,47,
48,49,52,53,56,57,60,61,
50,51,54,55,58,59,62,63
};
/*
* store_texture_tile():
*
* Writes a single 8x8 texture tile into the appropriate part of the texture
* sheet.
*/
static void store_texture_tile(UINT x, UINT y, UINT8 *src, UINT bpp, BOOL little_endian)
{
UINT xi, yi, pixel_offs;
UINT16 rgb16;
UINT8 gray8;
for (yi = 0; yi < 8; yi++)
{
for (xi = 0; xi < 8; xi++)
{
/*
* Grab the pixel offset from the decode[] array and fetch the
* pixel word
*/
if (little_endian)
{
if (bpp == 2)
{
/*
* XOR with 1 in little endian mode -- every word contains
* 2 16-bit pixels, thus they are swapped
*/
pixel_offs = decode[(yi * 8 + xi) ^ 1] * 2;
rgb16 = *(UINT16 *) &src[pixel_offs];
}
else
{
pixel_offs = decode[((yi ^ 1) * 8 + (xi ^ 1))];
gray8 = src[pixel_offs];
}
}
else
{
if (bpp == 2)
{
pixel_offs = decode[yi * 8 + xi] * 2;
rgb16 = (src[pixel_offs + 0] << 8) | src[pixel_offs + 1];
}
else
{
pixel_offs = decode[yi * 8 + xi];
gray8 = src[pixel_offs + 0];
}
}
/*
* Store within the texture sheet
*/
if (bpp == 2)
*(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2] = rgb16;
else
texture_ram[(((y + yi) * 2048 + x) * 2) + xi] = gray8;
}
}
}
/*
* store_texture():
*
* Writes a texture into the texture sheet. The pixel words are not decoded,
* but the 16-bit pixels are converted into a common endianness (little.)
* 8-bit pixels are not expanded into 16-bits.
*
* bpp (bytes per pixel) must be 1 or 2.
*/
static void store_texture(UINT x, UINT y, UINT w, UINT h, UINT8 *src, UINT bpp, BOOL little_endian)
{
UINT xi, yi;
UINT bw;
if(bpp == 2)
bw = 1;
else
bw = 2;
for (yi = 0; yi < h; yi += 8)
{
for (xi = 0; xi < w; xi += 8)
{
store_texture_tile(x + (xi / bw), y + yi, src, bpp, little_endian);
src += 8 * 8 * bpp; // each texture tile is 8x8 and 16-bit color
}
}
}
/*
* upload_texture():
*
* Uploads a texture to texture memory.
*/
// Mipmap starting positions for each level
static const int mipmap_xpos[11] =
{ 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
static const int mipmap_ypos[11] =
{ 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023, 0 };
// Mipmap size dividers
static const int mipmap_size[9] =
{ 2, 4, 8, 16, 32, 64, 128, 256, 512 };
static void upload_texture(UINT32 header, UINT8 *src, BOOL little_endian)
{
UINT size_x, size_y, xpos, ypos, bit_depth, mip_ypos, page;
int mipmap_num = 0;
int mxpos, mypos, msize_x, msize_y;
PROFILE_SECT_ENTRY("real3d");
/*
* Model 3 texture RAM appears as 2 2048x1024 textures. When textures are
* uploaded, their size and position within a sheet is given. I treat the
* texture sheet selection bit as an additional bit to the Y coordinate.
*/
size_x = (header >> 14) & 7;
size_y = (header >> 17) & 7;
size_x = (32 << size_x); // width in pixels
size_y = (32 << size_y); // height
ypos = (((header >> 7) & 0x1F) | ((header >> 15) & 0x20)) * 32;
xpos = ((header >> 0) & 0x3F) * 32;
mip_ypos = ((header >> 7) & 0x1F) * 32;
page = (header >> 15 & 0x20) ? 1 : 0;
if( header & 0x00800000 )
bit_depth = 2; // 16-bit texture
else
bit_depth = 1; // 8-bit texture
LOG("texture.log", "%08X %d,%d\t%dx%d\n", header, xpos, ypos, size_x, size_y);
/*
* Render the texture into the texture buffer
*/
switch( (header >> 24) & 0xF )
{
case 0: // Texture with mipmaps
store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian);
osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0);
msize_x = size_x;
msize_y = size_y;
// Store mipmaps
while( msize_y > 8 && msize_x > 8 ) {
src += (msize_x * msize_y * bit_depth);
msize_x /= 2;
msize_y /= 2;
mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]);
mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]);
if(page)
mypos += 1024;
mipmap_num++;
store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian);
//osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num);
}
break;
case 1: // Texture without mipmaps
store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian);
osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0);
break;
case 2: // Only mipmaps
msize_x = size_x;
msize_y = size_y;
while( msize_y > 8 && msize_x > 8 ) {
msize_x /= 2;
msize_y /= 2;
mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]);
mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]);
if(page)
mypos += 1024;
mipmap_num++;
store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian);
//osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num);
src += (msize_x * msize_y * bit_depth);
}
break;
}
/*
* Remove any existing textures that may have been overwritten
*/
//osd_renderer_invalidate_textures(xpos, ypos, size_x, size_y);
PROFILE_SECT_EXIT("real3d");
}
/******************************************************************/
/* Access */
/******************************************************************/
static BOOL trigger = 0;
static UINT64 trigger_time;
/*
* UINT32 r3d_read_32(UINT32 a);
*
* Reads a 32-bit word from the Real3D regions.
*
* Parameters:
* a = Address.
*
* Returns:
* Data read.
*/
UINT32 r3d_read_32(UINT32 a)
{
static UINT32 _84000000 = 0;
// message(0, "%08X (%08X): Real3D read32 to %08X", PPC_PC, PPC_LR, a);
switch (a)
{
/*
* In Lost World, routine at 0x1174E0 reads all the 0x840000XX status
* registers and at 0x117A30, bit 0x02000000 is checked for.
*/
case 0x84000000:
return (_84000000 ^= 0xFFFFFFFF);
case 0x84000004: // unknown
case 0x84000008:
case 0x8400000C:
case 0x84000010:
case 0x84000014:
case 0x84000018:
case 0x8400001C:
case 0x84000020:
return 0xFFFFFFFF;
}
error("Unknown R3D read: %08X: %08X\n", ppc_get_pc(), a);
return(0);
}
/*
* void r3d_write_32(UINT32 a, UINT32 d);
*
* Writes a 32-bit word to the Real3D regions.
*
* Parameters:
* a = Address.
* d = Data to write.
*/
UINT32 _9C000000, _9C000004, _9C000008;
static int texture_start_pos = 8;
static int texture_ram_ptr = 0;
void r3d_write_32(UINT32 a, UINT32 d)
{
static UINT32 last_addr;
if (a >= 0x8E000000 && a <= 0x8E0FFFFF) // culling RAM
{
*(UINT32 *) &culling_ram_8e[a & 0xFFFFF] = BSWAP32(d);
return;
}
else if (a >= 0x8C000000 && a <= 0x8C3FFFFF) // culling RAM
{
*(UINT32 *) &culling_ram_8c[a & 0x3FFFFF] = BSWAP32(d);
return;
}
else if (a >= 0x98000000 && a <= 0x981FFFFF) // polygon RAM
{
// if(a >= 0x98001000 && a < 0x98002000)
// message(1, "color table: %08X = %08X", a, BSWAP32(d));
*(UINT32 *) &polygon_ram[a & 0x1FFFFF] = BSWAP32(d);
return;
}
else if (a >= 0x94000000 && a <= 0x940FFFFF) // texture buffer
{
d = BSWAP32(d);
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
texture_ram_ptr += 4;
return;
}
switch (a)
{
case 0x88000000: // trigger?
//message(0, "%08X (%08X): 88000000 = %08X", PPC_PC, PPC_LR, BSWAP32(d));
if( texture_ram_ptr > 0 ) {
int i=0;
while( i < texture_ram_ptr ) {
UINT32 length = (*(UINT32*)&texture_buffer_ram[i+0] / 2) + 2;
UINT32 header = *(UINT32*)&texture_buffer_ram[i+4];
upload_texture( header, &texture_buffer_ram[i+8], 1 );
i += length;
};
}
texture_ram_ptr = 0;
return;
case 0x90000000: // VROM texture address
vrom_texture_address = BSWAP32(d);
LOG("model3.log", "VROM1 ADDR = %08X\n", BSWAP32(d));
//message(0, "VROM texture address = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
return;
case 0x90000004:
vrom_texture_header = BSWAP32(d);
LOG("model3.log", "VROM1 HEAD = %08X\n", BSWAP32(d));
//message(0, "VROM texture header = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
return;
case 0x90000008:
upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1);
LOG("model3.log", "VROM1 SIZE = %08X\n", BSWAP32(d));
//message(0, "VROM texture length = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR);
return;
case 0x9000000C: // ? Virtual On 2: These are almost certainly for VROM textures as well (I was too lazy to check :P)
vrom_texture_address = BSWAP32(d);
LOG("model3.log", "VROM2 ADDR = %08X\n", BSWAP32(d));
//message(0, "90000000C = %08X", BSWAP32(d));
return;
case 0x90000010: // ?
vrom_texture_header = BSWAP32(d);
LOG("model3.log", "VROM2 HEAD = %08X\n", BSWAP32(d));
//message(0, "900000010 = %08X", BSWAP32(d));
return;
case 0x90000014: // ?
upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1);
LOG("model3.log", "VROM2 SIZE = %08X\n", BSWAP32(d));
//message(0, "900000014 = %08X", BSWAP32(d));
return;
case 0x9C000000: // ?
//message(0, "9C000000 = %08X", BSWAP32(d));
LOG("model3.log", "%08X = %08X\n", a, d);
_9C000000 = BSWAP32(d);
return;
case 0x9C000004: // ?
//message(0, "9C000004 = %08X", BSWAP32(d));
LOG("model3.log", "%08X = %08X\n", a, d);
_9C000004 = BSWAP32(d);
return;
case 0x9C000008: // ?
//message(0, "9C000008 = %08X", BSWAP32(d));
LOG("model3.log", "%08X = %08X\n", a, d);
_9C000008 = BSWAP32(d);
return;
}
error("Unknown R3D write: %08X: %08X = %08X\n", ppc_get_pc(), a, d);
}
void r3d_dma_culling_ram_8c(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *)&culling_ram_8c[dst] = d;
dst += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *)&culling_ram_8c[dst] = d;
dst += 4;
}
}
}
void r3d_dma_culling_ram_8e(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *)&culling_ram_8e[dst] = d;
dst += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *)&culling_ram_8e[dst] = d;
dst += 4;
}
}
}
void r3d_dma_polygon_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *) &polygon_ram[dst] = d;
dst += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *) &polygon_ram[dst] = d;
dst += 4;
}
}
}
void r3d_dma_texture_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words)
{
int i;
dst &= 0xffffff;
if (swap_words)
{
for (i=0; i < length; i+=4)
{
UINT32 d = BSWAP32(*src++);
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
texture_ram_ptr += 4;
}
}
else
{
for (i=0; i < length; i+=4)
{
UINT32 d = (*src++);
*(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d;
texture_ram_ptr += 4;
}
}
}
/******************************************************************/
/* Real3D TAP Port */
/******************************************************************/
/*
* State (corresponding to fsm[][] Y) and Instruction Names
*/
static char *state_name[] = { "Test-Logic/Reset", "Run-Test/Idle", "Select-DR-Scan",
"Capture-DR", "Shift-DR", "Exit1-DR", "Pause-DR",
"Exit2-DR", "Update-DR", "Select-IR-Scan",
"Capture-IR", "Shift-IR", "Exit1-IR", "Pause-IR",
"Exit2-IR", "Update-IR"
};
/*
* TAP Finite State Machine
*
* Y are states and X are outgoing paths. Constructed from information on page
* 167 of the 3D-RAM manual.
*/
#define NEXT(new_state) fsm[state][new_state]
static INT state; // current state
static INT fsm[][2] = {
{ 1, 0 }, // 0 Test-Logic/Reset
{ 1, 2 }, // 1 Run-Test/Idle
{ 3, 9 }, // 2 Select-DR-Scan
{ 4, 5 }, // 3 Capture-DR
{ 4, 5 }, // 4 Shift-DR
{ 6, 8 }, // 5 Exit1-DR
{ 6, 7 }, // 6 Pause-DR
{ 4, 8 }, // 7 Exit2-DR
{ 1, 2 }, // 8 Update-DR
{ 10, 0 }, // 9 Select-IR-Scan
{ 11, 12 }, // 10 Capture-IR
{ 11, 12 }, // 11 Shift-IR
{ 13, 15 }, // 12 Exit1-IR
{ 13, 14 }, // 13 Pause-IR
{ 11, 15 }, // 14 Exit2-IR
{ 1, 2 } // 15 Update-IR
};
/*
* TAP Registers
*/
static UINT64 current_instruction; // latched IR (not always equal to IR)
static UINT64 ir; // instruction register (46 bits)
static UINT8 id_data[32]; // ASIC ID code data buffer
static INT id_size; // size of ID data in bits
static INT ptr; // current bit ptr for data
static BOOL tdo; // bit shifted out to TDO
/*
* insert_bit():
*
* Inserts a bit into an arbitrarily long bit field. Bit 0 is assumed to be
* the MSB of the first byte in the buffer.
*/
static void insert_bit(UINT8 *buf, INT bit_num, INT bit)
{
INT bit_in_byte;
bit_in_byte = 7 - (bit_num & 7);
buf[bit_num / 8] &= ~(1 << bit_in_byte);
buf[bit_num / 8] |= (bit << bit_in_byte);
}
/*
* insert_id():
*
* Inserts a 32-bit ID code into the ID bit field.
*/
static void insert_id(UINT32 id, INT start_bit)
{
INT i;
for (i = 31; i >= 0; i--)
insert_bit(id_data, start_bit++, (id >> i) & 1);
}
/*
* shift():
*
* Shifts the data buffer right (towards LSB at byte 0) by 1 bit. The size of
* the number of bits must be specified. The bit shifted out of the LSB is
* returned.
*/
static BOOL shift(UINT8 *data, INT num_bits)
{
INT i;
BOOL shift_out, shift_in;
/*
* This loop takes care of all the fully-filled bytes
*/
shift_in = 0;
for (i = 0; i < num_bits / 8; i++)
{
shift_out = data[i] & 1;
data[i] >>= 1;
data[i] |= (shift_in << 7);
shift_in = shift_out; // carry over to next element's MSB
}
/*
* Take care of the last partial byte (if there is one)
*/
if ((num_bits & 7) != 0)
{
shift_out = (data[i] >> (8 - (num_bits & 7))) & 1;
data[i] >>= 1;
data[i] |= (shift_in << 7);
}
return shift_out;
}
/*
* BOOL tap_read(void);
*
* Reads TDO.
*
* Returns:
* TDO.
*/
BOOL tap_read(void)
{
return tdo;
}
/*
* void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst);
*
* Writes to the TAP. State changes only occur on the rising edge of the clock
* (tck = 1.)
*
* Parameters:
* tck = Clock.
* tms = Test mode select.
* tdi = Serial data input. Must be 0 or 1 only!
* trst = Reset.
*/
void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst)
{
if (!tck)
return;
state = NEXT(tms);
switch (state)
{
case 3: // Capture-DR
/*
* Read ASIC IDs.
*
* The ID Sequence is:
* - Jupiter
* - Mercury
* - Venus
* - Earth
* - Mars
* - Mars (again)
*
* Note that different Model 3 steps have different chip
* revisions, hence the different IDs returned below.
*
* On Step 1.5 and 1.0, instruction 0x0C631F8C7FFE is used to retrieve
* the ID codes but Step 2.0 is a little weirder. It seems to use this
* and either the state of the TAP after reset or other instructions
* to read the IDs as well. This can be emulated in one of 2 ways:
* Ignore the instruction and always load up the data or load the
* data on TAP reset and when the instruction is issued.
*/
if (m3_config.step == 0x10)
{
insert_id(0x116C7057, 1 + 0 * 32);
insert_id(0x216C3057, 1 + 1 * 32);
insert_id(0x116C4057, 1 + 2 * 32);
insert_id(0x216C5057, 1 + 3 * 32);
insert_id(0x116C6057, 1 + 4 * 32 + 1);
insert_id(0x116C6057, 1 + 5 * 32 + 1);
}
else if (m3_config.step == 0x15)
{
insert_id(0x316C7057, 1 + 0 * 32);
insert_id(0x316C3057, 1 + 1 * 32);
insert_id(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057
insert_id(0x316C5057, 1 + 3 * 32);
insert_id(0x216C6057, 1 + 4 * 32 + 1);
insert_id(0x216C6057, 1 + 5 * 32 + 1);
}
else if (m3_config.step >= 0x20)
{
insert_id(0x416C7057, 1 + 0 * 32);
insert_id(0x416C3057, 1 + 1 * 32);
insert_id(0x316C4057, 1 + 2 * 32);
insert_id(0x416C5057, 1 + 3 * 32);
insert_id(0x316C6057, 1 + 4 * 32 + 1);
insert_id(0x316C6057, 1 + 5 * 32 + 1);
}
break;
case 4: // Shift-DR
tdo = shift(id_data, id_size);
break;
case 10: // Capture-IR
/*
* Load lower 2 bits with 01 as per IEEE 1149.1-1990
*/
ir = 1;
break;
case 11: // Shift-IR
/*
* Shift IR towards output and load in new data from TDI
*/
tdo = ir & 1; // shift LSB to output
ir >>= 1;
ir |= ((UINT64) tdi << 45);
break;
case 15: // Update-IR
/*
* Latch IR (technically, this should occur on the falling edge of
* TCK)
*/
ir &= 0x3fffffffffff;
current_instruction = ir;
#if 0
{
UINT8 *i = (UINT8 *) &ir;
LOG("tap.log", "current instruction set: %02X%02X%02X%02X%02X%02X\n", i[5], i[4], i[3], i[2], i[1], i[0]);
}
#endif
break;
default:
break;
}
#if 0
if (state == 4)
LOG("tap.log", "state: Shift-DR %d\n", tdi);
else if (state == 11)
LOG("tap.log", "state: Shift-IR %d\n", tdi);
else
LOG("tap.log", "state: %s\n", state_name[state]);
#endif
}
/*
* void tap_reset(void);
*
* Resets the TAP (simulating a power up or SCAN_RST signal.)
*/
void tap_reset(void)
{
id_size = 197; // 197 bits
state = 0; // test-logic/reset
}