421 lines
16 KiB
C#
421 lines
16 KiB
C#
using System.IO;
|
|
|
|
namespace MAME.Core
|
|
{
|
|
public unsafe class Upd7759
|
|
{
|
|
public struct upd7759_chip
|
|
{
|
|
public uint pos;
|
|
public uint step;
|
|
public Atime clock_period;
|
|
public EmuTimer.emu_timer timer;
|
|
|
|
public byte fifo_in;
|
|
public byte reset;
|
|
public byte start;
|
|
public byte drq;
|
|
public drqcallback drqcallback;
|
|
|
|
public sbyte state;
|
|
public int clocks_left;
|
|
public ushort nibbles_left;
|
|
public byte repeat_count;
|
|
public sbyte post_drq_state;
|
|
public int post_drq_clocks;
|
|
public byte req_sample;
|
|
public byte last_sample;
|
|
public byte block_header;
|
|
public byte sample_rate;
|
|
public byte first_valid_header;
|
|
public uint offset;
|
|
public uint repeat_offset;
|
|
|
|
public sbyte adpcm_state;
|
|
public byte adpcm_data;
|
|
public short sample;
|
|
|
|
public int rombase;
|
|
public uint romoffset;
|
|
}
|
|
public static int[,] upd7759_step = new int[16, 16]
|
|
{
|
|
{ 0, 0, 1, 2, 3, 5, 7, 10, 0, 0, -1, -2, -3, -5, -7, -10 },
|
|
{ 0, 1, 2, 3, 4, 6, 8, 13, 0, -1, -2, -3, -4, -6, -8, -13 },
|
|
{ 0, 1, 2, 4, 5, 7, 10, 15, 0, -1, -2, -4, -5, -7, -10, -15 },
|
|
{ 0, 1, 3, 4, 6, 9, 13, 19, 0, -1, -3, -4, -6, -9, -13, -19 },
|
|
{ 0, 2, 3, 5, 8, 11, 15, 23, 0, -2, -3, -5, -8, -11, -15, -23 },
|
|
{ 0, 2, 4, 7, 10, 14, 19, 29, 0, -2, -4, -7, -10, -14, -19, -29 },
|
|
{ 0, 3, 5, 8, 12, 16, 22, 33, 0, -3, -5, -8, -12, -16, -22, -33 },
|
|
{ 1, 4, 7, 10, 15, 20, 29, 43, -1, -4, -7, -10, -15, -20, -29, -43 },
|
|
{ 1, 4, 8, 13, 18, 25, 35, 53, -1, -4, -8, -13, -18, -25, -35, -53 },
|
|
{ 1, 6, 10, 16, 22, 31, 43, 64, -1, -6, -10, -16, -22, -31, -43, -64 },
|
|
{ 2, 7, 12, 19, 27, 37, 51, 76, -2, -7, -12, -19, -27, -37, -51, -76 },
|
|
{ 2, 9, 16, 24, 34, 46, 64, 96, -2, -9, -16, -24, -34, -46, -64, -96 },
|
|
{ 3, 11, 19, 29, 41, 57, 79, 117, -3, -11, -19, -29, -41, -57, -79, -117 },
|
|
{ 4, 13, 24, 36, 50, 69, 96, 143, -4, -13, -24, -36, -50, -69, -96, -143 },
|
|
{ 4, 16, 29, 44, 62, 85, 118, 175, -4, -16, -29, -44, -62, -85, -118, -175 },
|
|
{ 6, 20, 36, 54, 76, 104, 144, 214, -6, -20, -36, -54, -76, -104, -144, -214 },
|
|
};
|
|
public static int[] upd7759_state = new int[16] { -1, -1, 0, 0, 1, 2, 2, 3, -1, -1, 0, 0, 1, 2, 2, 3 };
|
|
public static upd7759_chip chip;
|
|
public static byte[] updrom;
|
|
public delegate void drqcallback(int irq);
|
|
|
|
|
|
public static void update_adpcm(int data)
|
|
{
|
|
chip.sample += (short)upd7759_step[chip.adpcm_state, data];
|
|
chip.adpcm_state += (sbyte)upd7759_state[data];
|
|
if (chip.adpcm_state < 0)
|
|
{
|
|
chip.adpcm_state = 0;
|
|
}
|
|
else if (chip.adpcm_state > 15)
|
|
{
|
|
chip.adpcm_state = 15;
|
|
}
|
|
}
|
|
public static void advance_state()
|
|
{
|
|
switch (chip.state)
|
|
{
|
|
case 0:
|
|
chip.clocks_left = 4;
|
|
break;
|
|
case 1:
|
|
chip.drq = 0;
|
|
chip.clocks_left = chip.post_drq_clocks;
|
|
chip.state = chip.post_drq_state;
|
|
break;
|
|
case 2:
|
|
chip.req_sample = (byte)(updrom != null ? chip.fifo_in : 0x10);
|
|
chip.clocks_left = 70;
|
|
chip.state = 3;
|
|
break;
|
|
case 3:
|
|
chip.drq = 1;
|
|
chip.clocks_left = 44;
|
|
chip.state = 4;
|
|
break;
|
|
case 4:
|
|
chip.last_sample = updrom != null ? updrom[0] : chip.fifo_in;
|
|
chip.drq = 1;
|
|
chip.clocks_left = 28;
|
|
chip.state = (sbyte)((chip.req_sample > chip.last_sample) ? 0 : 5);
|
|
break;
|
|
case 5:
|
|
chip.drq = 1;
|
|
chip.clocks_left = 32;
|
|
chip.state = 6;
|
|
break;
|
|
case 6:
|
|
chip.offset = (uint)((updrom != null ? updrom[chip.req_sample * 2 + 5] : chip.fifo_in) << 9);
|
|
chip.drq = 1;
|
|
chip.clocks_left = 44;
|
|
chip.state = 7;
|
|
break;
|
|
case 7:
|
|
chip.offset |= (uint)((updrom != null ? updrom[chip.req_sample * 2 + 6] : chip.fifo_in) << 1);
|
|
chip.drq = 1;
|
|
chip.clocks_left = 36;
|
|
chip.state = 8;
|
|
break;
|
|
case 8:
|
|
chip.offset++;
|
|
chip.first_valid_header = 0;
|
|
chip.drq = 1;
|
|
chip.clocks_left = 36;
|
|
chip.state = 9;
|
|
break;
|
|
case 9:
|
|
if (chip.repeat_count != 0)
|
|
{
|
|
chip.repeat_count--;
|
|
chip.offset = chip.repeat_offset;
|
|
}
|
|
chip.block_header = updrom != null ? updrom[chip.offset++ & 0x1ffff] : chip.fifo_in;
|
|
chip.drq = 1;
|
|
switch (chip.block_header & 0xc0)
|
|
{
|
|
case 0x00:
|
|
chip.clocks_left = 1024 * ((chip.block_header & 0x3f) + 1);
|
|
chip.state = (sbyte)((chip.block_header == 0 && chip.first_valid_header != 0) ? 0 : 9);
|
|
chip.sample = 0;
|
|
chip.adpcm_state = 0;
|
|
break;
|
|
case 0x40:
|
|
chip.sample_rate = (byte)((chip.block_header & 0x3f) + 1);
|
|
chip.nibbles_left = 256;
|
|
chip.clocks_left = 36;
|
|
chip.state = 11;
|
|
break;
|
|
case 0x80:
|
|
chip.sample_rate = (byte)((chip.block_header & 0x3f) + 1);
|
|
chip.clocks_left = 36;
|
|
chip.state = 10;
|
|
break;
|
|
case 0xc0:
|
|
chip.repeat_count = (byte)((chip.block_header & 7) + 1);
|
|
chip.repeat_offset = chip.offset;
|
|
chip.clocks_left = 36;
|
|
chip.state = 9;
|
|
break;
|
|
}
|
|
if (chip.block_header != 0)
|
|
{
|
|
chip.first_valid_header = 1;
|
|
}
|
|
break;
|
|
case 10:
|
|
chip.nibbles_left = (ushort)((updrom != null ? updrom[chip.offset++ & 0x1ffff] : chip.fifo_in) + 1);
|
|
chip.drq = 1;
|
|
chip.clocks_left = 36;
|
|
chip.state = 11;
|
|
break;
|
|
case 11:
|
|
chip.adpcm_data = updrom != null ? updrom[chip.offset++ & 0x1ffff] : chip.fifo_in;
|
|
update_adpcm(chip.adpcm_data >> 4);
|
|
chip.drq = 1;
|
|
chip.clocks_left = chip.sample_rate * 4;
|
|
if (--chip.nibbles_left == 0)
|
|
{
|
|
chip.state = 9;
|
|
}
|
|
else
|
|
{
|
|
chip.state = 12;
|
|
}
|
|
break;
|
|
case 12:
|
|
update_adpcm(chip.adpcm_data & 15);
|
|
chip.clocks_left = chip.sample_rate * 4;
|
|
if (--chip.nibbles_left == 0)
|
|
{
|
|
chip.state = 9;
|
|
}
|
|
else
|
|
{
|
|
chip.state = 11;
|
|
}
|
|
break;
|
|
}
|
|
if (chip.drq != 0)
|
|
{
|
|
chip.post_drq_state = chip.state;
|
|
chip.post_drq_clocks = chip.clocks_left - 21;
|
|
chip.state = 1;
|
|
chip.clocks_left = 21;
|
|
}
|
|
}
|
|
public static void upd7759_update(int offset, int length)
|
|
{
|
|
int clocks_left = chip.clocks_left;
|
|
short sample = chip.sample;
|
|
uint step = chip.step;
|
|
uint pos = chip.pos;
|
|
int i = 0, j;
|
|
if (chip.state != 0)
|
|
{
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
Sound.upd7759stream.streamoutput_Ptrs[0][offset + i] = sample << 7;
|
|
pos += step;
|
|
while (updrom != null && pos >= 0x100000)
|
|
{
|
|
int clocks_this_time = (int)(pos >> 20);
|
|
if (clocks_this_time > clocks_left)
|
|
{
|
|
clocks_this_time = clocks_left;
|
|
}
|
|
pos -= (uint)(clocks_this_time * 0x100000);
|
|
clocks_left -= clocks_this_time;
|
|
if (clocks_left == 0)
|
|
{
|
|
advance_state();
|
|
if (chip.state == 0)
|
|
{
|
|
break;
|
|
}
|
|
clocks_left = chip.clocks_left;
|
|
sample = chip.sample;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (i < length - 1)
|
|
{
|
|
for (j = i; j < length; j++)
|
|
{
|
|
Sound.upd7759stream.streamoutput_Ptrs[0][offset + j] = 0;
|
|
}
|
|
}
|
|
chip.clocks_left = clocks_left;
|
|
chip.pos = pos;
|
|
}
|
|
public static void upd7759_slave_update()
|
|
{
|
|
byte olddrq = chip.drq;
|
|
Sound.upd7759stream.stream_update();
|
|
//stream_update(chip.channel);
|
|
advance_state();
|
|
if (olddrq != chip.drq && chip.drqcallback != null)
|
|
{
|
|
chip.drqcallback(chip.drq);
|
|
}
|
|
if (chip.state != 0)
|
|
{
|
|
EmuTimer.timer_adjust_periodic(chip.timer, Attotime.attotime_mul(chip.clock_period, (uint)chip.clocks_left), Attotime.ATTOTIME_NEVER);
|
|
}
|
|
}
|
|
public static void upd7759_reset()
|
|
{
|
|
chip.pos = 0;
|
|
chip.fifo_in = 0;
|
|
chip.drq = 0;
|
|
chip.state = 0;
|
|
chip.clocks_left = 0;
|
|
chip.nibbles_left = 0;
|
|
chip.repeat_count = 0;
|
|
chip.post_drq_state = 0;
|
|
chip.post_drq_clocks = 0;
|
|
chip.req_sample = 0;
|
|
chip.last_sample = 0;
|
|
chip.block_header = 0;
|
|
chip.sample_rate = 0;
|
|
chip.first_valid_header = 0;
|
|
chip.offset = 0;
|
|
chip.repeat_offset = 0;
|
|
chip.adpcm_state = 0;
|
|
chip.adpcm_data = 0;
|
|
chip.sample = 0;
|
|
if (chip.timer != null)
|
|
{
|
|
EmuTimer.timer_adjust_periodic(chip.timer, Attotime.ATTOTIME_NEVER, Attotime.ATTOTIME_NEVER);
|
|
}
|
|
}
|
|
public static void upd7759_start(int clock)
|
|
{
|
|
chip = new upd7759_chip();
|
|
chip.step = 4 * 0x100000;
|
|
chip.clock_period = new Atime(0, (long)(1e18 / clock));
|
|
chip.state = 0;
|
|
chip.rombase = 0;
|
|
if (updrom == null)
|
|
{
|
|
chip.timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Upd7759_upd7759_slave_update, false);
|
|
}
|
|
chip.reset = 1;
|
|
chip.start = 1;
|
|
upd7759_reset();
|
|
}
|
|
public static void upd7759_reset_w(int which, byte data)
|
|
{
|
|
byte oldreset = chip.reset;
|
|
chip.reset = (byte)((data != 0) ? 1 : 0);
|
|
Sound.upd7759stream.stream_update();
|
|
if (oldreset != 0 && chip.reset == 0)
|
|
{
|
|
upd7759_reset();
|
|
}
|
|
}
|
|
public static void upd7759_start_w(int which, byte data)
|
|
{
|
|
byte oldstart = chip.start;
|
|
chip.start = (byte)((data != 0) ? 1 : 0);
|
|
Sound.upd7759stream.stream_update();
|
|
if (chip.state == 0 && oldstart == 0 && chip.start != 0 && chip.reset != 0)
|
|
{
|
|
chip.state = 2;
|
|
if (chip.timer != null)
|
|
{
|
|
EmuTimer.timer_adjust_periodic(chip.timer, Attotime.ATTOTIME_ZERO, Attotime.ATTOTIME_NEVER);
|
|
}
|
|
}
|
|
}
|
|
public static void upd7759_port_w(int which, byte data)
|
|
{
|
|
chip.fifo_in = data;
|
|
}
|
|
public static int upd7759_busy_r(int which)
|
|
{
|
|
return (chip.state == 0) ? 1 : 0;
|
|
}
|
|
public static void upd7759_set_bank_base(int which, uint base1)
|
|
{
|
|
//chip.rom = chip.rombase + base1;
|
|
chip.romoffset = base1;
|
|
}
|
|
public static void upd7759_0_start_w(byte data)
|
|
{
|
|
upd7759_start_w(0, data);
|
|
}
|
|
public static void upd7759_0_reset_w(byte data)
|
|
{
|
|
upd7759_reset_w(0, data);
|
|
}
|
|
public static void upd7759_0_port_w(byte data)
|
|
{
|
|
upd7759_port_w(0, data);
|
|
}
|
|
public static byte upd7759_0_busy_r()
|
|
{
|
|
return (byte)upd7759_busy_r(0);
|
|
}
|
|
public static void SaveStateBinary(BinaryWriter writer)
|
|
{
|
|
writer.Write(chip.pos);
|
|
writer.Write(chip.step);
|
|
writer.Write(chip.fifo_in);
|
|
writer.Write(chip.reset);
|
|
writer.Write(chip.start);
|
|
writer.Write(chip.drq);
|
|
writer.Write(chip.state);
|
|
writer.Write(chip.clocks_left);
|
|
writer.Write(chip.nibbles_left);
|
|
writer.Write(chip.repeat_count);
|
|
writer.Write(chip.post_drq_state);
|
|
writer.Write(chip.post_drq_clocks);
|
|
writer.Write(chip.req_sample);
|
|
writer.Write(chip.last_sample);
|
|
writer.Write(chip.block_header);
|
|
writer.Write(chip.sample_rate);
|
|
writer.Write(chip.first_valid_header);
|
|
writer.Write(chip.offset);
|
|
writer.Write(chip.repeat_offset);
|
|
writer.Write(chip.adpcm_state);
|
|
writer.Write(chip.adpcm_data);
|
|
writer.Write(chip.sample);
|
|
writer.Write(chip.romoffset);
|
|
writer.Write(chip.rombase);
|
|
}
|
|
public static void LoadStateBinary(BinaryReader reader)
|
|
{
|
|
chip.pos = reader.ReadUInt32();
|
|
chip.step = reader.ReadUInt32();
|
|
chip.fifo_in = reader.ReadByte();
|
|
chip.reset = reader.ReadByte();
|
|
chip.start = reader.ReadByte();
|
|
chip.drq = reader.ReadByte();
|
|
chip.state = reader.ReadSByte();
|
|
chip.clocks_left = reader.ReadInt32();
|
|
chip.nibbles_left = reader.ReadUInt16();
|
|
chip.repeat_count = reader.ReadByte();
|
|
chip.post_drq_state = reader.ReadSByte();
|
|
chip.post_drq_clocks = reader.ReadInt32();
|
|
chip.req_sample = reader.ReadByte();
|
|
chip.last_sample = reader.ReadByte();
|
|
chip.block_header = reader.ReadByte();
|
|
chip.sample_rate = reader.ReadByte();
|
|
chip.first_valid_header = reader.ReadByte();
|
|
chip.offset = reader.ReadUInt32();
|
|
chip.repeat_offset = reader.ReadUInt32();
|
|
chip.adpcm_state = reader.ReadSByte();
|
|
chip.adpcm_data = reader.ReadByte();
|
|
chip.sample = reader.ReadInt16();
|
|
chip.romoffset = reader.ReadUInt32();
|
|
chip.rombase = reader.ReadInt32();
|
|
}
|
|
}
|
|
}
|