mirror of
https://github.com/libretro/snes9x2005.git
synced 2024-11-27 02:20:24 +00:00
1e6f792755
Fix regression introduced in snes9x-1.40.
951 lines
34 KiB
C
951 lines
34 KiB
C
#include "../copyright"
|
|
|
|
#include "snes9x.h"
|
|
#include "dsp1.h"
|
|
#include "memmap.h"
|
|
#include "dsp1emu.c"
|
|
#include "dsp2emu.c"
|
|
|
|
void (*SetDSP)(uint8_t, uint16_t) = &DSP1SetByte;
|
|
uint8_t(*GetDSP)(uint16_t) = &DSP1GetByte;
|
|
|
|
void S9xResetDSP1(void)
|
|
{
|
|
DSP1.waiting4command = true;
|
|
DSP1.in_count = 0;
|
|
DSP1.out_count = 0;
|
|
DSP1.in_index = 0;
|
|
DSP1.out_index = 0;
|
|
DSP1.first_parameter = true;
|
|
}
|
|
|
|
uint8_t S9xGetDSP(uint16_t address)
|
|
{
|
|
return (*GetDSP)(address);
|
|
}
|
|
|
|
void S9xSetDSP(uint8_t byte, uint16_t address)
|
|
{
|
|
(*SetDSP)(byte, address);
|
|
}
|
|
|
|
void DSP1SetByte(uint8_t byte, uint16_t address)
|
|
{
|
|
if ((address & 0xf000) == 0x6000 || (address & 0x7fff) < 0x4000)
|
|
{
|
|
if ((DSP1.command == 0x0A || DSP1.command == 0x1A) && DSP1.out_count != 0)
|
|
{
|
|
DSP1.out_count--;
|
|
DSP1.out_index++;
|
|
return;
|
|
}
|
|
else if (DSP1.waiting4command)
|
|
{
|
|
DSP1.command = byte;
|
|
DSP1.in_index = 0;
|
|
DSP1.waiting4command = false;
|
|
DSP1.first_parameter = true;
|
|
switch (byte) /* Mario Kart uses 0x00, 0x02, 0x06, 0x0c, 0x28, 0x0a */
|
|
{
|
|
case 0x07:
|
|
case 0x0a:
|
|
case 0x0f:
|
|
case 0x1f:
|
|
case 0x27:
|
|
case 0x2f:
|
|
DSP1.in_count = 1;
|
|
break;
|
|
case 0x00:
|
|
case 0x04:
|
|
case 0x0e:
|
|
case 0x10:
|
|
case 0x1e:
|
|
case 0x20:
|
|
case 0x24:
|
|
case 0x2e:
|
|
case 0x30:
|
|
case 0x3e:
|
|
DSP1.in_count = 2;
|
|
break;
|
|
case 0x03:
|
|
case 0x06:
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0b:
|
|
case 0x0c:
|
|
case 0x0d:
|
|
case 0x13:
|
|
case 0x16:
|
|
case 0x19:
|
|
case 0x1b:
|
|
case 0x1d:
|
|
case 0x23:
|
|
case 0x26:
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2b:
|
|
case 0x2c:
|
|
case 0x2d:
|
|
case 0x33:
|
|
case 0x36:
|
|
case 0x39:
|
|
case 0x3b:
|
|
case 0x3d:
|
|
DSP1.in_count = 3;
|
|
break;
|
|
case 0x01:
|
|
case 0x05:
|
|
case 0x11:
|
|
case 0x15:
|
|
case 0x18:
|
|
case 0x21:
|
|
case 0x25:
|
|
case 0x31:
|
|
case 0x35:
|
|
case 0x38:
|
|
DSP1.in_count = 4;
|
|
break;
|
|
case 0x14:
|
|
case 0x1c:
|
|
case 0x34:
|
|
case 0x3c:
|
|
DSP1.in_count = 6;
|
|
break;
|
|
case 0x02:
|
|
case 0x12:
|
|
case 0x22:
|
|
case 0x32:
|
|
DSP1.in_count = 7;
|
|
break;
|
|
case 0x1a:
|
|
case 0x2a:
|
|
case 0x3a:
|
|
DSP1.command = 0x1a;
|
|
DSP1.in_count = 1;
|
|
break;
|
|
case 0x17:
|
|
case 0x37:
|
|
case 0x3F:
|
|
DSP1.command = 0x1f;
|
|
DSP1.in_count = 1;
|
|
break;
|
|
default:
|
|
DSP1.in_count = 0;
|
|
DSP1.waiting4command = true;
|
|
DSP1.first_parameter = true;
|
|
break;
|
|
}
|
|
DSP1.in_count <<= 1;
|
|
}
|
|
else
|
|
{
|
|
DSP1.parameters [DSP1.in_index] = byte;
|
|
DSP1.first_parameter = false;
|
|
DSP1.in_index++;
|
|
}
|
|
|
|
if (DSP1.waiting4command || (DSP1.first_parameter && byte == 0x80))
|
|
{
|
|
DSP1.waiting4command = true;
|
|
DSP1.first_parameter = false;
|
|
}
|
|
else if (!(DSP1.first_parameter && (DSP1.in_count != 0 || (DSP1.in_count == 0 && DSP1.in_index == 0))))
|
|
{
|
|
if (DSP1.in_count)
|
|
{
|
|
if (--DSP1.in_count == 0)
|
|
{
|
|
DSP1.waiting4command = true;
|
|
DSP1.out_index = 0;
|
|
switch (DSP1.command)
|
|
{
|
|
case 0x1f:
|
|
DSP1.out_count = 2048;
|
|
break;
|
|
case 0x00: /* Multiple */
|
|
Op00Multiplicand = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op00Multiplier = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
DSPOp00();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = Op00Result & 0xFF;
|
|
DSP1.output [1] = (Op00Result >> 8) & 0xFF;
|
|
break;
|
|
case 0x20: /* Multiple */
|
|
Op20Multiplicand = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op20Multiplier = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
DSPOp20();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = Op20Result & 0xFF;
|
|
DSP1.output [1] = (Op20Result >> 8) & 0xFF;
|
|
break;
|
|
case 0x30:
|
|
case 0x10: /* Inverse */
|
|
Op10Coefficient = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op10Exponent = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
DSPOp10();
|
|
DSP1.out_count = 4;
|
|
DSP1.output [0] = (uint8_t)(((int16_t) Op10CoefficientR) & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((((int16_t) Op10CoefficientR) >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(((int16_t) Op10ExponentR) & 0xff);
|
|
DSP1.output [3] = (uint8_t)((((int16_t) Op10ExponentR) >> 8) & 0xff);
|
|
break;
|
|
case 0x24:
|
|
case 0x04: /* Sin and Cos of angle */
|
|
Op04Angle = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op04Radius = (uint16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
DSPOp04();
|
|
DSP1.out_count = 4;
|
|
DSP1.output [0] = (uint8_t)(Op04Sin & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op04Sin >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op04Cos & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op04Cos >> 8) & 0xFF);
|
|
break;
|
|
case 0x08: /* Radius */
|
|
Op08X = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op08Y = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op08Z = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp08();
|
|
DSP1.out_count = 4;
|
|
DSP1.output [0] = (uint8_t)(((int16_t) Op08Ll) & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((((int16_t) Op08Ll) >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(((int16_t) Op08Lh) & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((((int16_t) Op08Lh) >> 8) & 0xFF);
|
|
break;
|
|
case 0x18: /* Range */
|
|
Op18X = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op18Y = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op18Z = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op18R = (int16_t)(DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
DSPOp18();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op18D & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op18D >> 8) & 0xFF);
|
|
break;
|
|
case 0x38: /* Range */
|
|
Op38X = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op38Y = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op38Z = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op38R = (int16_t)(DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
DSPOp38();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op38D & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op38D >> 8) & 0xFF);
|
|
break;
|
|
case 0x28: /* Distance (vector length) */
|
|
Op28X = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op28Y = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op28Z = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp28();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op28R & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op28R >> 8) & 0xFF);
|
|
break;
|
|
case 0x2c:
|
|
case 0x0c: /* Rotate (2D rotate) */
|
|
Op0CA = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op0CX1 = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op0CY1 = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp0C();
|
|
DSP1.out_count = 4;
|
|
DSP1.output [0] = (uint8_t)(Op0CX2 & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op0CX2 >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op0CY2 & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op0CY2 >> 8) & 0xFF);
|
|
break;
|
|
case 0x3c:
|
|
case 0x1c: /* Polar (3D rotate) */
|
|
Op1CZ = (DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op1CY = (DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op1CX = (DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op1CXBR = (DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
Op1CYBR = (DSP1.parameters [8] | (DSP1.parameters[9] << 8));
|
|
Op1CZBR = (DSP1.parameters [10] | (DSP1.parameters[11] << 8));
|
|
DSPOp1C();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op1CXAR & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op1CXAR >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op1CYAR & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op1CYAR >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op1CZAR & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op1CZAR >> 8) & 0xFF);
|
|
break;
|
|
case 0x32:
|
|
case 0x22:
|
|
case 0x12:
|
|
case 0x02: /* Parameter (Projection) */
|
|
Op02FX = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op02FY = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op02FZ = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op02LFE = (int16_t)(DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
Op02LES = (int16_t)(DSP1.parameters [8] | (DSP1.parameters[9] << 8));
|
|
Op02AAS = (uint16_t)(DSP1.parameters [10] | (DSP1.parameters[11] << 8));
|
|
Op02AZS = (uint16_t)(DSP1.parameters [12] | (DSP1.parameters[13] << 8));
|
|
DSPOp02();
|
|
DSP1.out_count = 8;
|
|
DSP1.output [0] = (uint8_t)(Op02VOF & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op02VOF >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op02VVA & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op02VVA >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op02CX & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op02CX >> 8) & 0xFF);
|
|
DSP1.output [6] = (uint8_t)(Op02CY & 0xFF);
|
|
DSP1.output [7] = (uint8_t)((Op02CY >> 8) & 0xFF);
|
|
break;
|
|
case 0x3a: /* 1a Mirror */
|
|
case 0x2a: /* 1a Mirror */
|
|
case 0x1a: /* Raster mode 7 matrix data */
|
|
case 0x0a:
|
|
Op0AVS = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
DSPOp0A();
|
|
DSP1.out_count = 8;
|
|
DSP1.output [0] = (uint8_t)(Op0AA & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op0AB & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op0AC & 0xFF);
|
|
DSP1.output [6] = (uint8_t)(Op0AD & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op0AA >> 8) & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op0AB >> 8) & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op0AC >> 8) & 0xFF);
|
|
DSP1.output [7] = (uint8_t)((Op0AD >> 8) & 0xFF);
|
|
DSP1.in_index = 0;
|
|
break;
|
|
case 0x16:
|
|
case 0x26:
|
|
case 0x36:
|
|
case 0x06: /* Project object */
|
|
Op06X = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op06Y = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op06Z = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp06();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op06H & 0xff);
|
|
DSP1.output [1] = (uint8_t)((Op06H >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op06V & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op06V >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op06M & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op06M >> 8) & 0xFF);
|
|
break;
|
|
case 0x1e:
|
|
case 0x2e:
|
|
case 0x3e:
|
|
case 0x0e: /* Target */
|
|
Op0EH = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op0EV = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
DSPOp0E();
|
|
DSP1.out_count = 4;
|
|
DSP1.output [0] = (uint8_t)(Op0EX & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op0EX >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op0EY & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op0EY >> 8) & 0xFF);
|
|
break;
|
|
case 0x05: /* Extra commands used by Pilot Wings */
|
|
case 0x35:
|
|
case 0x31:
|
|
case 0x01: /* Set attitude matrix A */
|
|
Op01m = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op01Zr = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op01Yr = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op01Xr = (int16_t)(DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
DSPOp01();
|
|
break;
|
|
case 0x15:
|
|
case 0x11: /* Set attitude matrix B */
|
|
Op11m = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op11Zr = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op11Yr = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op11Xr = (int16_t)(DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
DSPOp11();
|
|
break;
|
|
case 0x25:
|
|
case 0x21: /* Set attitude matrix C */
|
|
Op21m = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op21Zr = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op21Yr = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op21Xr = (int16_t)(DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
DSPOp21();
|
|
break;
|
|
case 0x09:
|
|
case 0x39:
|
|
case 0x3d:
|
|
case 0x0d: /* Objective matrix A */
|
|
Op0DX = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op0DY = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op0DZ = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp0D();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op0DF & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op0DF >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op0DL & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op0DL >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op0DU & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op0DU >> 8) & 0xFF);
|
|
break;
|
|
case 0x19:
|
|
case 0x1d: /* Objective matrix B */
|
|
Op1DX = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op1DY = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op1DZ = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp1D();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op1DF & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op1DF >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op1DL & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op1DL >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op1DU & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op1DU >> 8) & 0xFF);
|
|
break;
|
|
case 0x29:
|
|
case 0x2d: /* Objective matrix C */
|
|
Op2DX = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op2DY = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op2DZ = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp2D();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op2DF & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op2DF >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op2DL & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op2DL >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op2DU & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op2DU >> 8) & 0xFF);
|
|
break;
|
|
case 0x33:
|
|
case 0x03: /* Subjective matrix A */
|
|
Op03F = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op03L = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op03U = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp03();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op03X & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op03X >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op03Y & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op03Y >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op03Z & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op03Z >> 8) & 0xFF);
|
|
break;
|
|
case 0x13: /* Subjective matrix B */
|
|
Op13F = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op13L = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op13U = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp13();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op13X & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op13X >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op13Y & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op13Y >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op13Z & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op13Z >> 8) & 0xFF);
|
|
break;
|
|
case 0x23: /* Subjective matrix C */
|
|
Op23F = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op23L = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op23U = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp23();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op23X & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op23X >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op23Y & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op23Y >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op23Z & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op23Z >> 8) & 0xFF);
|
|
break;
|
|
case 0x3b:
|
|
case 0x0b:
|
|
Op0BX = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op0BY = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op0BZ = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp0B();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op0BS & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op0BS >> 8) & 0xFF);
|
|
break;
|
|
case 0x1b:
|
|
Op1BX = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op1BY = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op1BZ = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp1B();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op1BS & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op1BS >> 8) & 0xFF);
|
|
break;
|
|
case 0x2b:
|
|
Op2BX = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op2BY = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op2BZ = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
DSPOp2B();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op2BS & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op2BS >> 8) & 0xFF);
|
|
break;
|
|
case 0x34:
|
|
case 0x14:
|
|
Op14Zr = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
Op14Xr = (int16_t)(DSP1.parameters [2] | (DSP1.parameters[3] << 8));
|
|
Op14Yr = (int16_t)(DSP1.parameters [4] | (DSP1.parameters[5] << 8));
|
|
Op14U = (int16_t)(DSP1.parameters [6] | (DSP1.parameters[7] << 8));
|
|
Op14F = (int16_t)(DSP1.parameters [8] | (DSP1.parameters[9] << 8));
|
|
Op14L = (int16_t)(DSP1.parameters [10] | (DSP1.parameters[11] << 8));
|
|
DSPOp14();
|
|
DSP1.out_count = 6;
|
|
DSP1.output [0] = (uint8_t)(Op14Zrr & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op14Zrr >> 8) & 0xFF);
|
|
DSP1.output [2] = (uint8_t)(Op14Xrr & 0xFF);
|
|
DSP1.output [3] = (uint8_t)((Op14Xrr >> 8) & 0xFF);
|
|
DSP1.output [4] = (uint8_t)(Op14Yrr & 0xFF);
|
|
DSP1.output [5] = (uint8_t)((Op14Yrr >> 8) & 0xFF);
|
|
break;
|
|
case 0x27:
|
|
case 0x2F:
|
|
Op2FUnknown = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
DSPOp2F();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op2FSize & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op2FSize >> 8) & 0xFF);
|
|
break;
|
|
case 0x07:
|
|
case 0x0F:
|
|
Op0FRamsize = (int16_t)(DSP1.parameters [0] | (DSP1.parameters[1] << 8));
|
|
DSPOp0F();
|
|
DSP1.out_count = 2;
|
|
DSP1.output [0] = (uint8_t)(Op0FPass & 0xFF);
|
|
DSP1.output [1] = (uint8_t)((Op0FPass >> 8) & 0xFF);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t DSP1GetByte(uint16_t address)
|
|
{
|
|
uint8_t t;
|
|
if ((address & 0xf000) == 0x6000 || (address & 0x7fff) < 0x4000)
|
|
{
|
|
if (DSP1.out_count)
|
|
{
|
|
t = (uint8_t) DSP1.output [DSP1.out_index];
|
|
DSP1.out_index++;
|
|
if (--DSP1.out_count == 0)
|
|
{
|
|
if (DSP1.command == 0x1a || DSP1.command == 0x0a)
|
|
{
|
|
DSPOp0A();
|
|
DSP1.out_count = 8;
|
|
DSP1.out_index = 0;
|
|
DSP1.output [0] = (Op0AA & 0xFF);
|
|
DSP1.output [1] = (Op0AA >> 8) & 0xFF;
|
|
DSP1.output [2] = (Op0AB & 0xFF);
|
|
DSP1.output [3] = (Op0AB >> 8) & 0xFF;
|
|
DSP1.output [4] = (Op0AC & 0xFF);
|
|
DSP1.output [5] = (Op0AC >> 8) & 0xFF;
|
|
DSP1.output [6] = (Op0AD & 0xFF);
|
|
DSP1.output [7] = (Op0AD >> 8) & 0xFF;
|
|
}
|
|
if (DSP1.command == 0x1f)
|
|
{
|
|
if ((DSP1.out_index % 2) != 0)
|
|
t = (uint8_t)DSP1ROM[DSP1.out_index >> 1];
|
|
else
|
|
t = DSP1ROM[DSP1.out_index >> 1] >> 8;
|
|
}
|
|
}
|
|
DSP1.waiting4command = true;
|
|
}
|
|
else
|
|
t = 0xff;
|
|
}
|
|
else
|
|
t = 0x80;
|
|
return t;
|
|
}
|
|
|
|
void DSP2SetByte(uint8_t byte, uint16_t address)
|
|
{
|
|
#ifndef FAST_LSB_WORD_ACCESS
|
|
uint32_t temp;
|
|
#endif
|
|
|
|
if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000))
|
|
{
|
|
if (DSP1.waiting4command)
|
|
{
|
|
DSP1.command = byte;
|
|
DSP1.in_index = 0;
|
|
DSP1.waiting4command = false;
|
|
switch (byte)
|
|
{
|
|
default:
|
|
DSP1.in_count = 0;
|
|
break;
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x06:
|
|
DSP1.in_count = 1;
|
|
break;
|
|
case 0x0d:
|
|
DSP1.in_count = 2;
|
|
break;
|
|
case 0x09:
|
|
DSP1.in_count = 4;
|
|
break;
|
|
case 0x01:
|
|
DSP1.in_count = 32;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DSP1.parameters [DSP1.in_index] = byte;
|
|
DSP1.in_index++;
|
|
}
|
|
|
|
if (DSP1.in_count == DSP1.in_index)
|
|
{
|
|
DSP1.waiting4command = true;
|
|
DSP1.out_index = 0;
|
|
switch (DSP1.command)
|
|
{
|
|
case 0x0D:
|
|
if (DSP2Op0DHasLen)
|
|
{
|
|
DSP2Op0DHasLen = false;
|
|
DSP1.out_count = DSP2Op0DOutLen;
|
|
DSP2_Op0D();
|
|
}
|
|
else
|
|
{
|
|
DSP2Op0DInLen = DSP1.parameters[0];
|
|
DSP2Op0DOutLen = DSP1.parameters[1];
|
|
DSP1.in_index = 0;
|
|
DSP1.in_count = (DSP2Op0DInLen + 1) >> 1;
|
|
DSP2Op0DHasLen = true;
|
|
if (byte)
|
|
DSP1.waiting4command = false;
|
|
}
|
|
break;
|
|
case 0x06:
|
|
if (DSP2Op06HasLen)
|
|
{
|
|
DSP2Op06HasLen = false;
|
|
DSP1.out_count = DSP2Op06Len;
|
|
DSP2_Op06();
|
|
}
|
|
else
|
|
{
|
|
DSP2Op06Len = DSP1.parameters[0];
|
|
DSP1.in_index = 0;
|
|
DSP1.in_count = DSP2Op06Len;
|
|
DSP2Op06HasLen = true;
|
|
if (byte)
|
|
DSP1.waiting4command = false;
|
|
}
|
|
break;
|
|
case 0x01:
|
|
DSP1.out_count = 32;
|
|
DSP2_Op01();
|
|
break;
|
|
case 0x09: /* Multiply - don't yet know if this is signed or unsigned */
|
|
DSP2Op09Word1 = DSP1.parameters[0] | (DSP1.parameters[1] << 8);
|
|
DSP2Op09Word2 = DSP1.parameters[2] | (DSP1.parameters[3] << 8);
|
|
DSP1.out_count = 4;
|
|
#ifdef FAST_LSB_WORD_ACCESS
|
|
*(uint32_t*)DSP1.output = DSP2Op09Word1 * DSP2Op09Word2;
|
|
#else
|
|
temp = DSP2Op09Word1 * DSP2Op09Word2;
|
|
DSP1.output[0] = temp & 0xFF;
|
|
DSP1.output[1] = (temp >> 8) & 0xFF;
|
|
DSP1.output[2] = (temp >> 16) & 0xFF;
|
|
DSP1.output[3] = (temp >> 24) & 0xFF;
|
|
#endif
|
|
break;
|
|
case 0x05:
|
|
if (DSP2Op05HasLen)
|
|
{
|
|
DSP2Op05HasLen = false;
|
|
DSP1.out_count = DSP2Op05Len;
|
|
DSP2_Op05();
|
|
}
|
|
else
|
|
{
|
|
DSP2Op05Len = DSP1.parameters[0];
|
|
DSP1.in_index = 0;
|
|
DSP1.in_count = 2 * DSP2Op05Len;
|
|
DSP2Op05HasLen = true;
|
|
if (byte)
|
|
DSP1.waiting4command = false;
|
|
}
|
|
break;
|
|
|
|
case 0x03:
|
|
DSP2Op05Transparent = DSP1.parameters[0];
|
|
break;
|
|
case 0x0f:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t DSP2GetByte(uint16_t address)
|
|
{
|
|
uint8_t t;
|
|
if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000))
|
|
{
|
|
if (DSP1.out_count)
|
|
{
|
|
t = (uint8_t) DSP1.output [DSP1.out_index];
|
|
DSP1.out_index++;
|
|
if (DSP1.out_count == DSP1.out_index)
|
|
DSP1.out_count = 0;
|
|
}
|
|
else
|
|
t = 0xff;
|
|
}
|
|
else
|
|
t = 0x80;
|
|
return t;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
bool waiting4command;
|
|
bool half_command;
|
|
uint16_t command;
|
|
uint32_t in_count;
|
|
uint32_t in_index;
|
|
uint32_t out_count;
|
|
uint32_t out_index;
|
|
uint8_t parameters [512];
|
|
uint8_t output [512];
|
|
} SDSP4;
|
|
|
|
SDSP4 DSP4;
|
|
|
|
#include "dsp4emu.c"
|
|
|
|
bool DSP4_init = false;
|
|
|
|
void DSP4SetByte(uint8_t byte, uint16_t address)
|
|
{
|
|
if (!DSP4_init) /* bootup */
|
|
{
|
|
DSP4.waiting4command = 1;
|
|
DSP4_init = true;
|
|
}
|
|
|
|
if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000))
|
|
{
|
|
if (DSP4.out_index < DSP4.out_count)
|
|
{
|
|
DSP4.out_index++;
|
|
return;
|
|
}
|
|
|
|
if (DSP4.waiting4command)
|
|
{
|
|
if (DSP4.half_command)
|
|
{
|
|
DSP4.command |= (byte << 8);
|
|
DSP4.in_index = 0;
|
|
DSP4.waiting4command = false;
|
|
DSP4.half_command = false;
|
|
DSP4.out_count = 0;
|
|
DSP4.out_index = 0;
|
|
DSP4_Logic = 0;
|
|
|
|
switch (DSP4.command)
|
|
{
|
|
case 0x0003:
|
|
case 0x0005:
|
|
case 0x0006:
|
|
case 0x000E:
|
|
DSP4.in_count = 0;
|
|
break;
|
|
case 0x0000:
|
|
DSP4.in_count = 4;
|
|
break;
|
|
case 0x000A:
|
|
case 0x000B:
|
|
DSP4.in_count = 6;
|
|
break;
|
|
case 0x0011:
|
|
DSP4.in_count = 8;
|
|
break;
|
|
case 0x0009:
|
|
DSP4.in_count = 14;
|
|
break;
|
|
case 0x0007:
|
|
DSP4.in_count = 22;
|
|
break;
|
|
case 0x000D:
|
|
DSP4.in_count = 34;
|
|
break;
|
|
case 0x0001:
|
|
DSP4.in_count = 36;
|
|
break;
|
|
case 0x0008:
|
|
DSP4.in_count = 72;
|
|
break;
|
|
default:
|
|
DSP4.waiting4command = true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DSP4.command = byte;
|
|
DSP4.half_command = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DSP4.parameters [DSP4.in_index] = byte;
|
|
DSP4.in_index++;
|
|
}
|
|
|
|
if (!DSP4.waiting4command && DSP4.in_count == DSP4.in_index)
|
|
{
|
|
DSP4.waiting4command = true;
|
|
DSP4.out_index = 0;
|
|
DSP4.in_index = 0;
|
|
switch (DSP4.command)
|
|
{
|
|
case 0x0000: /* 16-bit multiplication */
|
|
{
|
|
int16_t multiplier, multiplicand;
|
|
int32_t product;
|
|
multiplier = DSP4_READ_WORD(0);
|
|
multiplicand = DSP4_READ_WORD(2);
|
|
product = DSP4_Multiply(multiplicand, multiplier);
|
|
DSP4.out_count = 4;
|
|
DSP4_WRITE_WORD(0, product);
|
|
DSP4_WRITE_WORD(2, product >> 16);
|
|
break;
|
|
}
|
|
case 0x0011: /* unknown: horizontal mapping command */
|
|
{
|
|
int16_t a, b, c, d, m;
|
|
a = DSP4_READ_WORD(6);
|
|
b = DSP4_READ_WORD(4);
|
|
c = DSP4_READ_WORD(2);
|
|
d = DSP4_READ_WORD(0);
|
|
m = DSP4_UnknownOP11(a, b, c, d);
|
|
DSP4.out_count = 2;
|
|
DSP4_WRITE_WORD(0, m);
|
|
break;
|
|
}
|
|
case 0x0001: /* track projection */
|
|
DSP4_Op01();
|
|
break;
|
|
case 0x0007: /* track projection (pass 2) */
|
|
DSP4_Op07();
|
|
break;
|
|
case 0x0008: /* zone projections (fuel/repair/lap/teleport/...) */
|
|
DSP4_Op08();
|
|
break;
|
|
case 0x0009: /* sprite transformation */
|
|
DSP4_Op09();
|
|
break;
|
|
case 0x000D: /* fast track projection */
|
|
DSP4_Op0D();
|
|
break;
|
|
case 0x0003: /* internal memory management (01) */
|
|
{
|
|
/* reset op09 data */
|
|
op09_mode = false;
|
|
break;
|
|
}
|
|
case 0x0005: /* internal memory management (06) */
|
|
{
|
|
int32_t lcv;
|
|
/* clear OAM tables */
|
|
op06_index = 0;
|
|
op06_offset = 0;
|
|
for (lcv = 0; lcv < 32; lcv++)
|
|
op06_OAM[lcv] = 0;
|
|
break;
|
|
}
|
|
case 0x000E: /* internal memory management (0D) */
|
|
{
|
|
/* reset op09 data */
|
|
op09_mode = true;
|
|
break;
|
|
}
|
|
case 0x0006: /* sprite OAM post-table data */
|
|
{
|
|
int32_t lcv;
|
|
DSP4.out_count = 32;
|
|
for (lcv = 0; lcv < 32; lcv++)
|
|
DSP4.output[lcv] = op06_OAM[lcv];
|
|
break;
|
|
}
|
|
case 0x000A: /* unknown */
|
|
{
|
|
int16_t out1a, out2a;
|
|
out1a = (int16_t)0xff40;
|
|
out2a = (int16_t)0x00c0;
|
|
DSP4.out_count = 8;
|
|
DSP4_WRITE_WORD(0, out1a);
|
|
DSP4_WRITE_WORD(2, out2a);
|
|
DSP4_WRITE_WORD(4, out1a);
|
|
DSP4_WRITE_WORD(6, out2a);
|
|
break;
|
|
}
|
|
case 0x000B: /* render player positions around track */
|
|
{
|
|
int16_t sp_x = DSP4_READ_WORD(0);
|
|
int16_t sp_y = DSP4_READ_WORD(2);
|
|
int16_t oam = DSP4_READ_WORD(4);
|
|
|
|
if (!op09_mode) /* Only allow 1p/1p-split to yield output (???) */
|
|
{
|
|
/* yield OAM output */
|
|
DSP4.out_count = 6;
|
|
DSP4_WRITE_WORD(0, 1);
|
|
|
|
/* pack OAM data: x,y,name,attr */
|
|
DSP4.output[2] = sp_x & 0xff;
|
|
DSP4.output[3] = sp_y & 0xff;
|
|
DSP4_WRITE_WORD(4, oam);
|
|
|
|
/* OAM: size,msb data */
|
|
DSP4_Op06(false, false);
|
|
}
|
|
else /* 4p mode */
|
|
{
|
|
/* no OAM available */
|
|
DSP4.out_count = 0;
|
|
DSP4_WRITE_WORD(0, 0);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t DSP4GetByte(uint16_t address)
|
|
{
|
|
uint8_t t;
|
|
if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000))
|
|
{
|
|
if (DSP4.out_count)
|
|
{
|
|
t = (uint8_t) DSP4.output [DSP4.out_index];
|
|
DSP4.out_index++;
|
|
if (DSP4.out_count == DSP4.out_index)
|
|
DSP4.out_count = 0;
|
|
}
|
|
else
|
|
t = 0xff;
|
|
}
|
|
else
|
|
t = 0x80;
|
|
|
|
return t;
|
|
}
|