CAPCOM YM2151 主要高频函数 unsafe 指针优化 | CPS NeoGeo PGS draw 函数 指针优化

This commit is contained in:
sin365 2025-01-18 19:06:19 +08:00
parent 0fc5acac4c
commit 0634207bf0
10 changed files with 1756 additions and 350 deletions

View File

@ -20,6 +20,14 @@ namespace MAME.Core
{
Act_Log?.Invoke(msg);
}
public static void Assert(bool conditional, string msg)
{
if (conditional)
return;
Act_Log?.Invoke(msg);
}
#endregion
}
}

View File

@ -0,0 +1,417 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using UnityEngine;
namespace MAME.Core
{
internal static class ObjectPoolAuto
{
/************************************************************************************************************************/
/// <summary>
/// 获取或者创建一个新的
/// </summary>
/// <remarks>Remember to <see cref="Release{T}(T)"/> 需要回收参见这个</remarks>
public static T Acquire<T>()
where T : class, new()
=> ObjectPool<T>.Acquire();
/// <summary>
/// 获取或者创建一个新的
/// </summary>
/// <remarks>Remember to <see cref="Release{T}(T)"/> 需要回收参见这个</remarks>
public static void Acquire<T>(out T item)
where T : class, new()
=> item = ObjectPool<T>.Acquire();
/************************************************************************************************************************/
/// <summary>
/// 回收对象
/// </summary>
public static void Release<T>(T item)
where T : class, new()
=> ObjectPool<T>.Release(item);
/// <summary>
/// 回收对象
/// </summary>
public static void Release<T>(ref T item) where T : class, new()
{
if (item != null)
{
ObjectPool<T>.Release(item);
item = null;
}
}
/************************************************************************************************************************/
public const string
NotClearError = " They must be cleared before being released to the pool and not modified after that.";
/************************************************************************************************************************/
/// <summary>
/// 获取或创建List
/// </summary>
/// <remarks>Remember to <see cref="Release{T}(List{T})"/> 回收参见此方法</remarks>
public static List<T> AcquireList<T>()
{
var list = ObjectPool<List<T>>.Acquire();
EmuLogger.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError);
return list;
}
/// <summary>
/// 回收List
/// </summary>
public static void Release<T>(List<T> list)
{
list.Clear();
ObjectPool<List<T>>.Release(list);
}
/// <summary>
/// 回收List内容
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
public static void ReleaseListContent<T>(List<T> list) where T : class, new()
{
foreach (var item in list)
{
ObjectPool<T>.Release(item);
}
list.Clear();
}
/************************************************************************************************************************/
/// <summary>
/// 获取或创建HashSet
/// </summary>
public static HashSet<T> AcquireSet<T>()
{
var set = ObjectPool<HashSet<T>>.Acquire();
EmuLogger.Assert(set.Count == 0, "A pooled set is not empty." + NotClearError);
return set;
}
/// <summary>
/// 释放HashSet
/// </summary>
public static void Release<T>(HashSet<T> set)
{
set.Clear();
ObjectPool<HashSet<T>>.Release(set);
}
/************************************************************************************************************************/
/// <summary>
/// 获取一个字符串StringBuilder
/// </summary>
/// <remarks>Remember to <see cref="Release(StringBuilder)"/>回收参见这个</remarks>
public static StringBuilder AcquireStringBuilder()
{
var builder = ObjectPool<StringBuilder>.Acquire();
EmuLogger.Assert(builder.Length == 0, $"A pooled {nameof(StringBuilder)} is not empty." + NotClearError);
return builder;
}
/// <summary>
/// 回收 StringBuilder
/// </summary>
public static void Release(StringBuilder builder)
{
builder.Length = 0;
ObjectPool<StringBuilder>.Release(builder);
}
/// <summary>
/// 回收 StringBuilder
/// </summary>
public static string ReleaseToString(this StringBuilder builder)
{
var result = builder.ToString();
Release(builder);
return result;
}
/************************************************************************************************************************/
private static class Cache<T>
{
public static readonly Dictionary<MethodInfo, KeyValuePair<Func<T>, T>>
Results = new Dictionary<MethodInfo, KeyValuePair<Func<T>, T>>();
}
/// <summary>
/// 此方法主要用于频繁绘制缓存比如说GUI绘制
/// </summary>
public static T GetCachedResult<T>(Func<T> function)
{
var method = function.Method;
if (!Cache<T>.Results.TryGetValue(method, out var result))
{
result = new KeyValuePair<Func<T>, T>(function, function());
Cache<T>.Results.Add(method, result);
}
else if (result.Key != function)
{
EmuLogger.Log(
$"{nameof(GetCachedResult)}<{typeof(T).Name}>" +
$" was previously called on {method.Name} with a different target." +
" This likely means that a new delegate is being passed into every call" +
" so it can't actually return the same cached object.");
}
return result.Value;
}
/************************************************************************************************************************/
public static class Disposable
{
/************************************************************************************************************************/
/// <summary>
/// Calls <see cref="ObjectPool{T}.Disposable.Acquire"/> to get a spare <see cref="List{T}"/> if
/// </summary>
public static IDisposable Acquire<T>(out T item)
where T : class, new()
=> ObjectPool<T>.Disposable.Acquire(out item);
/************************************************************************************************************************/
/// <summary>
/// Calls <see cref="ObjectPool{T}.Disposable.Acquire"/> to get a spare <see cref="List{T}"/> if
/// </summary>
public static IDisposable AcquireList<T>(out List<T> list)
{
var disposable = ObjectPool<List<T>>.Disposable.Acquire(out list, onRelease: (l) => l.Clear());
EmuLogger.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError);
return disposable;
}
/************************************************************************************************************************/
/// <summary>
/// Calls <see cref="ObjectPool{T}.Disposable.Acquire"/> to get a spare <see cref="HashSet{T}"/> if
/// </summary>
public static IDisposable AcquireSet<T>(out HashSet<T> set)
{
var disposable = ObjectPool<HashSet<T>>.Disposable.Acquire(out set, onRelease: (s) => s.Clear());
EmuLogger.Assert(set.Count == 0, "A pooled set is not empty." + NotClearError);
return disposable;
}
/************************************************************************************************************************/
}
/************************************************************************************************************************/
public static class ObjectPool<T> where T : class, new()
{
/************************************************************************************************************************/
private static readonly List<T>
Items = new List<T>();
/************************************************************************************************************************/
/// <summary>The number of spare items currently in the pool.</summary>
public static int Count
{
get => Items.Count;
set
{
var count = Items.Count;
if (count < value)
{
if (Items.Capacity < value)
Items.Capacity = Mathf.NextPowerOfTwo(value);
do
{
Items.Add(new T());
count++;
}
while (count < value);
}
else if (count > value)
{
Items.RemoveRange(value, count - value);
}
}
}
/************************************************************************************************************************/
/// <summary>
/// If the <see cref="Count"/> is less than the specified value, this method increases it to that value by
/// creating new objects.
/// </summary>
public static void SetMinCount(int count)
{
if (Count < count)
Count = count;
}
/************************************************************************************************************************/
/// <summary>The <see cref="List{T}.Capacity"/> of the internal list of spare items.</summary>
public static int Capacity
{
get => Items.Capacity;
set
{
if (Items.Count > value)
Items.RemoveRange(value, Items.Count - value);
Items.Capacity = value;
}
}
/************************************************************************************************************************/
/// <summary>Returns a spare item if there are any, or creates a new one.</summary>
/// <remarks>Remember to <see cref="Release(T)"/> it when you are done.</remarks>
public static T Acquire()
{
var count = Items.Count;
if (count == 0)
{
return new T();
}
else
{
count--;
var item = Items[count];
Items.RemoveAt(count);
return item;
}
}
/************************************************************************************************************************/
/// <summary>Adds the `item` to the list of spares so it can be reused.</summary>
public static void Release(T item)
{
Items.Add(item);
}
/************************************************************************************************************************/
/// <summary>Returns a description of the state of this pool.</summary>
public static string GetDetails()
{
return
$"{typeof(T).Name}" +
$" ({nameof(Count)} = {Items.Count}" +
$", {nameof(Capacity)} = {Items.Capacity}" +
")";
}
/************************************************************************************************************************/
/// <summary>
/// An <see cref="IDisposable"/> system to allow pooled objects to be acquired and released within <c>using</c>
/// statements instead of needing to manually release everything.
/// </summary>
public sealed class Disposable : IDisposable
{
/************************************************************************************************************************/
private static readonly List<Disposable> LazyStack = new List<Disposable>();
private static int _ActiveDisposables;
private T _Item;
private Action<T> _OnRelease;
/************************************************************************************************************************/
private Disposable() { }
/// <summary>
/// Calls <see cref="ObjectPool{T}.Acquire"/> to set the `item` and returns an <see cref="IDisposable"/>
/// that will call <see cref="Release(T)"/> on the `item` when disposed.
/// </summary>
public static IDisposable Acquire(out T item, Action<T> onRelease = null)
{
Disposable disposable;
if (LazyStack.Count <= _ActiveDisposables)
{
LazyStack.Add(disposable = new Disposable());
}
else
{
disposable = LazyStack[_ActiveDisposables];
}
_ActiveDisposables++;
disposable._Item = item = ObjectPool<T>.Acquire();
disposable._OnRelease = onRelease;
return disposable;
}
/************************************************************************************************************************/
void IDisposable.Dispose()
{
_OnRelease?.Invoke(_Item);
Release(_Item);
_ActiveDisposables--;
}
/************************************************************************************************************************/
}
}
#region ExtFunctions
public struct PoolHandle<T> : IDisposable
where T : class, new()
{
public T Ins;
internal static PoolHandle<T> Create(T poolIns)
{
return new PoolHandle<T> { Ins = poolIns };
}
public void Dispose()
{
ObjectPoolAuto.Release<T>(Ins);
}
}
public struct PoolListHandle<T> : IDisposable
{
public List<T> Ins;
internal static PoolListHandle<T> Create(List<T> poolIns)
{
return new PoolListHandle<T> { Ins = poolIns };
}
public void Dispose()
{
ObjectPoolAuto.Release<T>(Ins);
}
}
public static PoolHandle<T> PoolScope<T>()
where T : class, new()
{
return PoolHandle<T>.Create(ObjectPoolAuto.Acquire<T>());
}
public static PoolListHandle<T> PoolListScope<T>()
{
return PoolListHandle<T>.Create(ObjectPoolAuto.AcquireList<T>());
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f22c2fa157c9e6045ad5307124c8a365
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -61,7 +61,10 @@ namespace cpu.nec
{
if (line >= 0 && line < 35)
{
Cpuint.lirq.Add(new irq(cpunum, line, state, vector, EmuTimer.get_current_time()));
irq _irq = ObjectPoolAuto.Acquire<irq>();
_irq.Init(cpunum, line, state, vector, EmuTimer.get_current_time());
Cpuint.lirq.Add(_irq);
//Cpuint.lirq.Add(new irq(cpunum, line, state, vector, EmuTimer.get_current_time()));
int event_index = Cpuint.input_event_index[cpunum, line]++;
if (event_index >= 35)
{

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Runtime.InteropServices;
namespace MAME.Core
@ -57,7 +58,7 @@ namespace MAME.Core
{
}
public irq(int _cpunum, int _line, LineState _state, int _vector, Atime _time)
public void Init(int _cpunum, int _line, LineState _state, int _vector, Atime _time)
{
cpunum = _cpunum;
line = _line;
@ -134,7 +135,10 @@ namespace MAME.Core
public static void cpunum_set_input_line(int cpunum, int line, LineState state)
{
int vector = (line >= 0 && line < 35) ? interrupt_vector[cpunum, line] : 0xff;
lirq.Add(new irq(cpunum, line, state, vector, EmuTimer.get_current_time()));
irq _irq = ObjectPoolAuto.Acquire<irq>();
_irq.Init(cpunum, line, state, vector, EmuTimer.get_current_time());
lirq.Add(_irq);
//lirq.Add(new irq(cpunum, line, state, vector, EmuTimer.get_current_time()));
Cpuexec.cpu[cpunum].cpunum_set_input_line_and_vector(cpunum, line, state, vector);
}
public static void cpunum_set_input_line_vector(int cpunum, int line, int vector)
@ -149,13 +153,17 @@ namespace MAME.Core
{
if (line >= 0 && line < 35)
{
lirq.Add(new irq(cpunum, line, state, vector, EmuTimer.get_current_time()));
irq _irq = ObjectPoolAuto.Acquire<irq>();
_irq.Init(cpunum, line, state, vector, EmuTimer.get_current_time());
lirq.Add(_irq);
//lirq.Add(new irq(cpunum, line, state, vector, EmuTimer.get_current_time()));
EmuTimer.timer_set_internal(EmuTimer.TIME_ACT.Cpuint_cpunum_empty_event_queue);
}
}
public static void cpunum_empty_event_queue()
{
List<irq> lsirq = new List<irq>();
//List<irq> lsirq = new List<irq>();
List<irq> lsirq = ObjectPoolAuto.AcquireList<irq>();
if (lirq.Count == 0)
{
int i1 = 1;
@ -219,12 +227,14 @@ namespace MAME.Core
foreach (irq irq1 in lsirq)
{
input_event_index[irq1.cpunum, irq1.line] = 0;
ObjectPoolAuto.Release(irq1);
lirq.Remove(irq1);
}
if (lirq.Count > 0)
{
int i1 = 1;
}
ObjectPoolAuto.Release(lsirq);
}
public static int cpu_irq_callback(int cpunum, int line)
{
@ -348,7 +358,9 @@ namespace MAME.Core
lirq = new List<irq>();
for (i = 0; i < n; i++)
{
lirq.Add(new irq());
irq _irq = ObjectPoolAuto.Acquire<irq>();
lirq.Add(_irq);
//lirq.Add(new irq());
lirq[i].cpunum = reader.ReadInt32();
lirq[i].line = reader.ReadInt32();
lirq[i].state = (LineState)reader.ReadInt32();

View File

@ -25,10 +25,6 @@ namespace MAME.Core
public Atime period;
public Atime start;
public Atime expire;
public emu_timer()
{
}
}
public class emu_timer2
{
@ -502,16 +498,18 @@ namespace MAME.Core
lt.Insert(i, timer1);
}
}
static List<emu_timer> timer_list_remove_lt1 = new List<emu_timer>();
public static void timer_list_remove(emu_timer timer1)
{
if (timer1.action == TIME_ACT.Cpuint_cpunum_empty_event_queue || timer1.action == TIME_ACT.setvector)
{
List<emu_timer> lt1 = new List<emu_timer>();
timer_list_remove_lt1.Clear();
foreach (emu_timer et in lt)
{
if (et.action == timer1.action && Attotime.attotime_compare(et.expire, timer1.expire) == 0)
{
lt1.Add(et);
timer_list_remove_lt1.Add(et);
//lt.Remove(et);
//break;
}
@ -524,7 +522,7 @@ namespace MAME.Core
int i1 = 1;
}
}
foreach (emu_timer et1 in lt1)
foreach (emu_timer et1 in timer_list_remove_lt1)
{
lt.Remove(et1);
}

View File

@ -145,8 +145,195 @@ namespace MAME.Core
return (((max_y >= y) && (scanline >= y) && (scanline <= max_y)) ||
((max_y < y) && ((scanline >= y) || (scanline <= max_y))));
}
private static void draw_sprites(int iBitmap, int scanline)
//private static void draw_sprites(int iBitmap, int scanline)
//{
// int x_2, code_2;
// int x, y, rows, zoom_x, zoom_y, sprite_list_offset, sprite_index, max_sprite_index, sprite_number, sprite_y, tile, attr_and_code_offs, code, zoom_x_table_offset, gfx_offset, line_pens_offset, x_inc, sprite_line, zoom_line;
// ushort y_control, zoom_control, attr;
// byte sprite_y_and_tile;
// bool invert;
// y = 0;
// x = 0;
// rows = 0;
// zoom_y = 0;
// zoom_x = 0;
// if ((scanline & 0x01) != 0)
// {
// sprite_list_offset = 0x8680;
// }
// else
// {
// sprite_list_offset = 0x8600;
// }
// Span<ushort> span_neogeo_videoram = neogeo_videoram.AsSpan();
// Span<int> span_bitmapbaseN_iBitmap = Video.bitmapbaseN[iBitmap].AsSpan();
// Span<byte> span_sprite_gfx = sprite_gfx.AsSpan();
// Span<int> span_pens = pens.AsSpan();
// for (max_sprite_index = 95; max_sprite_index >= 0; max_sprite_index--)
// {
// if (span_neogeo_videoram[sprite_list_offset + max_sprite_index] != 0)
// {
// break;
// }
// }
// if (max_sprite_index != 95)
// {
// max_sprite_index = max_sprite_index + 1;
// }
// for (sprite_index = 0; sprite_index < max_sprite_index; sprite_index++)
// {
// sprite_number = span_neogeo_videoram[sprite_list_offset + sprite_index] & 0x1ff;
// y_control = span_neogeo_videoram[0x8200 | sprite_number];
// zoom_control = span_neogeo_videoram[0x8000 | sprite_number];
// x_2 = span_neogeo_videoram[0x8400 | sprite_number];
// code_2 = span_neogeo_videoram[sprite_number << 6];
// if ((y_control & 0x40) != 0)
// {
// x = (x + zoom_x + 1) & 0x01ff;
// zoom_x = (zoom_control >> 8) & 0x0f;
// }
// else
// {
// y = 0x200 - (y_control >> 7);
// x = span_neogeo_videoram[0x8400 | sprite_number] >> 7;
// zoom_y = zoom_control & 0xff;
// zoom_x = (zoom_control >> 8) & 0x0f;
// rows = y_control & 0x3f;
// }
// if ((x >= 0x140) && (x <= 0x1f0))
// {
// continue;
// }
// if (sprite_on_scanline(scanline, y, rows))
// {
// sprite_line = (scanline - y) & 0x1ff;
// zoom_line = sprite_line & 0xff;
// invert = ((sprite_line & 0x100) != 0) ? true : false;
// if (invert)
// {
// zoom_line ^= 0xff;
// }
// if (rows > 0x20)
// {
// zoom_line = zoom_line % ((zoom_y + 1) << 1);
// if (zoom_line > zoom_y)
// {
// zoom_line = ((zoom_y + 1) << 1) - 1 - zoom_line;
// invert = !invert;
// }
// }
// sprite_y_and_tile = zoomyrom[(zoom_y << 8) | zoom_line];
// sprite_y = sprite_y_and_tile & 0x0f;
// tile = sprite_y_and_tile >> 4;
// if (invert)
// {
// sprite_y ^= 0x0f;
// tile ^= 0x1f;
// }
// attr_and_code_offs = (sprite_number << 6) | (tile << 1);
// attr = span_neogeo_videoram[attr_and_code_offs + 1];
// code = ((attr << 12) & 0x70000) | span_neogeo_videoram[attr_and_code_offs];
// if (auto_animation_disabled == 0)
// {
// if ((attr & 0x0008) != 0)
// {
// code = (code & ~0x07) | (auto_animation_counter & 0x07);
// }
// else if ((attr & 0x0004) != 0)
// {
// code = (code & ~0x03) | (auto_animation_counter & 0x03);
// }
// }
// if ((attr & 0x0002) != 0)
// {
// sprite_y ^= 0x0f;
// }
// zoom_x_table_offset = 0;
// gfx_offset = (int)(((code << 8) | (sprite_y << 4)) & sprite_gfx_address_mask);
// line_pens_offset = attr >> 8 << 4;
// if ((attr & 0x0001) != 0)
// {
// gfx_offset = gfx_offset + 0x0f;
// x_inc = -1;
// }
// else
// {
// x_inc = 1;
// }
// int pixel_addr_offsetx, pixel_addr_offsety;
// if (x <= 0x01f0)
// {
// int i;
// pixel_addr_offsetx = x + NEOGEO_HBEND;
// pixel_addr_offsety = scanline;
// for (i = 0; i < 0x10; i++)
// {
// if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
// {
// //if (sprite_gfx[gfx_offset] != 0)
// if (span_sprite_gfx[gfx_offset] != 0)
// {
// //Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
// span_bitmapbaseN_iBitmap[pixel_addr_offsety * 384 + pixel_addr_offsetx] = span_pens[line_pens_offset + span_sprite_gfx[gfx_offset]];
// }
// pixel_addr_offsetx++;
// }
// zoom_x_table_offset++;
// gfx_offset += x_inc;
// }
// }
// else
// {
// int i;
// int x_save = x;
// pixel_addr_offsetx = NEOGEO_HBEND;
// pixel_addr_offsety = scanline;
// for (i = 0; i < 0x10; i++)
// {
// if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
// {
// if (x >= 0x200)
// {
// //if (sprite_gfx[gfx_offset] != 0)
// if (span_sprite_gfx[gfx_offset] != 0)
// {
// //Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
// span_bitmapbaseN_iBitmap[pixel_addr_offsety * 384 + pixel_addr_offsetx] = span_pens[line_pens_offset + span_sprite_gfx[gfx_offset]];
// }
// pixel_addr_offsetx++;
// }
// x++;
// }
// zoom_x_table_offset++;
// gfx_offset += x_inc;
// }
// x = x_save;
// }
// }
// }
//}
/// <summary>
/// draw_sprites (Unsafa 尝试提升效率)
/// </summary>
/// <param name="iBitmap"></param>
/// <param name="scanline"></param>
unsafe private static void draw_sprites(int iBitmap, int scanline)
{
fixed (ushort* videoramPtr = &neogeo_videoram[0])
fixed (int* bitmapbasePtr = &Video.bitmapbaseN[iBitmap][0])
fixed (byte* spriteGfxPtr = &sprite_gfx[0])
fixed (int* pensPtr = &pens[0])
fixed (byte* zoomyromPtr = &zoomyrom[0])
{
ushort* neogeo_videoram = videoramPtr;
int* bitmapbase = bitmapbasePtr;
byte* spriteGfx = spriteGfxPtr;
int* pens = pensPtr;
byte* zoomyrom = zoomyromPtr;
int x_2, code_2;
int x, y, rows, zoom_x, zoom_y, sprite_list_offset, sprite_index, max_sprite_index, sprite_number, sprite_y, tile, attr_and_code_offs, code, zoom_x_table_offset, gfx_offset, line_pens_offset, x_inc, sprite_line, zoom_line;
ushort y_control, zoom_control, attr;
@ -183,6 +370,13 @@ namespace MAME.Core
zoom_control = neogeo_videoram[0x8000 | sprite_number];
x_2 = neogeo_videoram[0x8400 | sprite_number];
code_2 = neogeo_videoram[sprite_number << 6];
//sprite_number = (*(videoram + sprite_list_offset + sprite_index) & 0x1ff);
//y_control = (ushort)(*(videoram + 0x8200) | sprite_number);
//zoom_control = (ushort)(*(videoram + 0x8000) | sprite_number);
//x_2 = (ushort)(*(videoram + 0x8400) | sprite_number);
//code_2 = *(videoram + (sprite_number << 6));
if ((y_control & 0x40) != 0)
{
x = (x + zoom_x + 1) & 0x01ff;
@ -191,11 +385,17 @@ namespace MAME.Core
else
{
y = 0x200 - (y_control >> 7);
x = neogeo_videoram[0x8400 | sprite_number] >> 7;
//x = neogeo_videoram[0x8400 | sprite_number] >> 7;
x = x_2 >> 7;
zoom_y = zoom_control & 0xff;
zoom_x = (zoom_control >> 8) & 0x0f;
rows = y_control & 0x3f;
}
fixed (int* zoom_x_tablesPtr = &zoom_x_tables[zoom_x, 0])
{
int* zoom_x_tables = zoom_x_tablesPtr;
if ((x >= 0x140) && (x <= 0x1f0))
{
continue;
@ -264,11 +464,14 @@ namespace MAME.Core
pixel_addr_offsety = scanline;
for (i = 0; i < 0x10; i++)
{
if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
//if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
if (zoom_x_tables[zoom_x_table_offset] != 0)
{
if (sprite_gfx[gfx_offset] != 0)
//if (sprite_gfx[gfx_offset] != 0)
if (spriteGfx[gfx_offset] != 0)
{
Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
//Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
bitmapbase[pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + spriteGfx[gfx_offset]];
}
pixel_addr_offsetx++;
}
@ -284,13 +487,16 @@ namespace MAME.Core
pixel_addr_offsety = scanline;
for (i = 0; i < 0x10; i++)
{
if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
//if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
if (zoom_x_tables[zoom_x_table_offset] != 0)
{
if (x >= 0x200)
{
if (sprite_gfx[gfx_offset] != 0)
//if (sprite_gfx[gfx_offset] != 0)
if (spriteGfx[gfx_offset] != 0)
{
Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
//Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
bitmapbase[pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + spriteGfx[gfx_offset]];
}
pixel_addr_offsetx++;
}
@ -304,6 +510,168 @@ namespace MAME.Core
}
}
}
}
}
//private static void draw_sprites(int iBitmap, int scanline)
//{
// int x_2, code_2;
// int x, y, rows, zoom_x, zoom_y, sprite_list_offset, sprite_index, max_sprite_index, sprite_number, sprite_y, tile, attr_and_code_offs, code, zoom_x_table_offset, gfx_offset, line_pens_offset, x_inc, sprite_line, zoom_line;
// ushort y_control, zoom_control, attr;
// byte sprite_y_and_tile;
// bool invert;
// y = 0;
// x = 0;
// rows = 0;
// zoom_y = 0;
// zoom_x = 0;
// if ((scanline & 0x01) != 0)
// {
// sprite_list_offset = 0x8680;
// }
// else
// {
// sprite_list_offset = 0x8600;
// }
// for (max_sprite_index = 95; max_sprite_index >= 0; max_sprite_index--)
// {
// if (neogeo_videoram[sprite_list_offset + max_sprite_index] != 0)
// {
// break;
// }
// }
// if (max_sprite_index != 95)
// {
// max_sprite_index = max_sprite_index + 1;
// }
// for (sprite_index = 0; sprite_index < max_sprite_index; sprite_index++)
// {
// sprite_number = neogeo_videoram[sprite_list_offset + sprite_index] & 0x1ff;
// y_control = neogeo_videoram[0x8200 | sprite_number];
// zoom_control = neogeo_videoram[0x8000 | sprite_number];
// x_2 = neogeo_videoram[0x8400 | sprite_number];
// code_2 = neogeo_videoram[sprite_number << 6];
// if ((y_control & 0x40) != 0)
// {
// x = (x + zoom_x + 1) & 0x01ff;
// zoom_x = (zoom_control >> 8) & 0x0f;
// }
// else
// {
// y = 0x200 - (y_control >> 7);
// x = neogeo_videoram[0x8400 | sprite_number] >> 7;
// zoom_y = zoom_control & 0xff;
// zoom_x = (zoom_control >> 8) & 0x0f;
// rows = y_control & 0x3f;
// }
// if ((x >= 0x140) && (x <= 0x1f0))
// {
// continue;
// }
// if (sprite_on_scanline(scanline, y, rows))
// {
// sprite_line = (scanline - y) & 0x1ff;
// zoom_line = sprite_line & 0xff;
// invert = ((sprite_line & 0x100) != 0) ? true : false;
// if (invert)
// {
// zoom_line ^= 0xff;
// }
// if (rows > 0x20)
// {
// zoom_line = zoom_line % ((zoom_y + 1) << 1);
// if (zoom_line > zoom_y)
// {
// zoom_line = ((zoom_y + 1) << 1) - 1 - zoom_line;
// invert = !invert;
// }
// }
// sprite_y_and_tile = zoomyrom[(zoom_y << 8) | zoom_line];
// sprite_y = sprite_y_and_tile & 0x0f;
// tile = sprite_y_and_tile >> 4;
// if (invert)
// {
// sprite_y ^= 0x0f;
// tile ^= 0x1f;
// }
// attr_and_code_offs = (sprite_number << 6) | (tile << 1);
// attr = neogeo_videoram[attr_and_code_offs + 1];
// code = ((attr << 12) & 0x70000) | neogeo_videoram[attr_and_code_offs];
// if (auto_animation_disabled == 0)
// {
// if ((attr & 0x0008) != 0)
// {
// code = (code & ~0x07) | (auto_animation_counter & 0x07);
// }
// else if ((attr & 0x0004) != 0)
// {
// code = (code & ~0x03) | (auto_animation_counter & 0x03);
// }
// }
// if ((attr & 0x0002) != 0)
// {
// sprite_y ^= 0x0f;
// }
// zoom_x_table_offset = 0;
// gfx_offset = (int)(((code << 8) | (sprite_y << 4)) & sprite_gfx_address_mask);
// line_pens_offset = attr >> 8 << 4;
// if ((attr & 0x0001) != 0)
// {
// gfx_offset = gfx_offset + 0x0f;
// x_inc = -1;
// }
// else
// {
// x_inc = 1;
// }
// int pixel_addr_offsetx, pixel_addr_offsety;
// if (x <= 0x01f0)
// {
// int i;
// pixel_addr_offsetx = x + NEOGEO_HBEND;
// pixel_addr_offsety = scanline;
// for (i = 0; i < 0x10; i++)
// {
// if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
// {
// if (sprite_gfx[gfx_offset] != 0)
// {
// Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
// }
// pixel_addr_offsetx++;
// }
// zoom_x_table_offset++;
// gfx_offset += x_inc;
// }
// }
// else
// {
// int i;
// int x_save = x;
// pixel_addr_offsetx = NEOGEO_HBEND;
// pixel_addr_offsety = scanline;
// for (i = 0; i < 0x10; i++)
// {
// if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0)
// {
// if (x >= 0x200)
// {
// if (sprite_gfx[gfx_offset] != 0)
// {
// Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]];
// }
// pixel_addr_offsetx++;
// }
// x++;
// }
// zoom_x_table_offset++;
// gfx_offset += x_inc;
// }
// x = x_save;
// }
// }
// }
//}
private static void parse_sprites(int scanline)
{
ushort sprite_number, y_control;

View File

@ -199,24 +199,36 @@ namespace MAME.Core
ycnt++;
}
}
private static void draw_sprites(int priority)
unsafe private static void draw_sprites(int priority)
{
fixed (ushort* pSpriteBuffer = &pgm_spritebufferram[0])
fixed (byte* pVideoRegs = &pgm_videoregs[0])
{
ushort* spritePtr = pSpriteBuffer + pgm_sprite_source_offset;
int offset = 0;
while (pgm_sprite_source_offset < 0x500)
{
int xpos = pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x07ff;
int ypos = pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x03ff;
int xzom = (pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x7800) >> 11;
int xgrow = (pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x8000) >> 15;
int yzom = (pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x7800) >> 11;
int ygrow = (pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x8000) >> 15;
int palt = (pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x1f00) >> 8;
int flip = (pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x6000) >> 13;
int boff = ((pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x007f) << 16) | (pgm_spritebufferram[pgm_sprite_source_offset + 3] & 0xffff);
int wide = (pgm_spritebufferram[pgm_sprite_source_offset + 4] & 0x7e00) >> 9;
int high = pgm_spritebufferram[pgm_sprite_source_offset + 4] & 0x01ff;
int pri = (pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x0080) >> 7;
int xzoom, yzoom;
// 读取数据
ushort* spriteData = (ushort*)spritePtr;
int xpos = spriteData[0] & 0x07FF;
int ypos = spriteData[1] & 0x03FF;
int xzom = (spriteData[0] & 0x7800) >> 11;
int xgrow = (spriteData[0] & 0x8000) >> 15;
int yzom = (spriteData[1] & 0x7800) >> 11;
int ygrow = (spriteData[1] & 0x8000) >> 15;
ushort* spriteData2 = (ushort*)(spritePtr + 4);
int palt = (spriteData2[0] & 0x1F00) >> 8;
int flip = (spriteData2[0] & 0x6000) >> 13;
int boff = ((spriteData2[0] & 0x007F) << 16) | spriteData2[1];
ushort* spriteData3 = (ushort*)(spritePtr + 6);
int wide = (spriteData3[0] & 0x7E00) >> 9;
int high = spriteData3[0] & 0x01FF;
int pri = (spriteData2[0] & 0x0080) >> 7;
int pgm_sprite_zoomtable_offset = 0x1000;
// 处理缩放
int xzoom, yzoom;
int* zoomTablePtr = (int*)(pVideoRegs + pgm_sprite_zoomtable_offset);
if (xgrow != 0)
{
xzom = 0x10 - xzom;
@ -225,21 +237,94 @@ namespace MAME.Core
{
yzom = 0x10 - yzom;
}
xzoom = ((pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 1]) << 16) | (pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 2] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 3]);
yzoom = ((pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 1]) << 16) | (pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 2] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 3]);
xzoom = zoomTablePtr[xzom * 4] * 0x10000 + zoomTablePtr[xzom * 4 + 1] * 0x100 + zoomTablePtr[xzom * 4 + 2];
yzoom = zoomTablePtr[yzom * 4] * 0x10000 + zoomTablePtr[yzom * 4 + 1] * 0x100 + zoomTablePtr[yzom * 4 + 2];
// 调整偏移和边界检查
boff *= 2;
if (xpos > 0x3ff)
if (xpos > 0x3FF)
xpos -= 0x800;
if (ypos > 0x1ff)
if (ypos > 0x1FF)
ypos -= 0x400;
if (high == 0)
break;
if ((priority == 1) && (pri == 0))
break;
// 调用绘制函数(注意:这个函数也需要被修改为接受指针或适当的参数类型)
draw_sprite_new_zoomed(wide, high, xpos, ypos, palt, boff, flip, xzoom, xgrow, yzoom, ygrow);
pgm_sprite_source_offset += 5;
// 移动到下一个精灵
spritePtr += 10; // 每个精灵占用5个ushort即10个字节
pgm_sprite_source_offset += 5; // 假设pgm_sprite_source_offset是以ushort为单位递增的
// 注意这里我们直接通过指针移动因此不需要再次访问数组来更新pgm_sprite_source_offset对应的值
}
}
}
//private static void draw_sprites(int priority)
//{
// while (pgm_sprite_source_offset < 0x500)
// {
// //用Span优化
// Span<ushort> span_pgm_spritebufferram = pgm_spritebufferram.AsSpan();
// int xpos = span_pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x07ff;
// int ypos = span_pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x03ff;
// int xzom = (span_pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x7800) >> 11;
// int xgrow = (span_pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x8000) >> 15;
// int yzom = (span_pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x7800) >> 11;
// int ygrow = (span_pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x8000) >> 15;
// int palt = (span_pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x1f00) >> 8;
// int flip = (span_pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x6000) >> 13;
// int boff = ((span_pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x007f) << 16) | (span_pgm_spritebufferram[pgm_sprite_source_offset + 3] & 0xffff);
// int wide = (span_pgm_spritebufferram[pgm_sprite_source_offset + 4] & 0x7e00) >> 9;
// int high = span_pgm_spritebufferram[pgm_sprite_source_offset + 4] & 0x01ff;
// int pri = (span_pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x0080) >> 7;
// //int xpos = pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x07ff;
// //int ypos = pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x03ff;
// //int xzom = (pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x7800) >> 11;
// //int xgrow = (pgm_spritebufferram[pgm_sprite_source_offset + 0] & 0x8000) >> 15;
// //int yzom = (pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x7800) >> 11;
// //int ygrow = (pgm_spritebufferram[pgm_sprite_source_offset + 1] & 0x8000) >> 15;
// //int palt = (pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x1f00) >> 8;
// //int flip = (pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x6000) >> 13;
// //int boff = ((pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x007f) << 16) | (pgm_spritebufferram[pgm_sprite_source_offset + 3] & 0xffff);
// //int wide = (pgm_spritebufferram[pgm_sprite_source_offset + 4] & 0x7e00) >> 9;
// //int high = pgm_spritebufferram[pgm_sprite_source_offset + 4] & 0x01ff;
// //int pri = (pgm_spritebufferram[pgm_sprite_source_offset + 2] & 0x0080) >> 7;
// int xzoom, yzoom;
// int pgm_sprite_zoomtable_offset = 0x1000;
// if (xgrow != 0)
// {
// xzom = 0x10 - xzom;
// }
// if (ygrow != 0)
// {
// yzom = 0x10 - yzom;
// }
// Span<byte> span_pgm_videoregs = pgm_videoregs.AsSpan();
// xzoom = ((span_pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4] * 0x100 + span_pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 1]) << 16) | (span_pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 2] * 0x100 + span_pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 3]);
// yzoom = ((span_pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4] * 0x100 + span_pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 1]) << 16) | (span_pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 2] * 0x100 + span_pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 3]);
// //xzoom = ((pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 1]) << 16) | (pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 2] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + xzom * 4 + 3]);
// //yzoom = ((pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 1]) << 16) | (pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 2] * 0x100 + pgm_videoregs[pgm_sprite_zoomtable_offset + yzom * 4 + 3]);
// boff *= 2;
// if (xpos > 0x3ff)
// xpos -= 0x800;
// if (ypos > 0x1ff)
// ypos -= 0x400;
// if (high == 0)
// break;
// if ((priority == 1) && (pri == 0))
// break;
// draw_sprite_new_zoomed(wide, high, xpos, ypos, palt, boff, flip, xzoom, xgrow, yzoom, ygrow);
// pgm_sprite_source_offset += 5;
// }
//}
private static void pgm_tx_videoram_w(int offset, byte data)
{
int col, row;

View File

@ -115,6 +115,8 @@ namespace MAME.Core
i1++;
}
}
//TODO 移动到这里,但是大小,还需要考虑
static short[] sample_data = new short[10000];
public static void okim6295_update(int offset, int length)
{
int i;
@ -124,7 +126,8 @@ namespace MAME.Core
}
for (i = 0; i < 4; i++)
{
short[] sample_data = new short[10000];
//不每次new避免GC排除问题。待验证影响
//short[] sample_data = new short[10000];
int remaining = length;
while (remaining != 0)
{

View File

@ -1032,21 +1032,35 @@ namespace MAME.Core
ym2151_write_reg(i, 0);
}
}
private static int op_calc(int i1, uint env, int pm)
unsafe static int op_calc(YM2151Operator* PSGoper, int i1, uint env, int pm)
{
uint p;
p = (env << 3) + sin_tab[(((int)((PSG.oper[i1].phase & 0xffff0000) + (pm << 15))) >> 16) & 0x3ff];
p = (env << 3) + sin_tab[(((int)((PSGoper[i1].phase & 0xffff0000) + (pm << 15))) >> 16) & 0x3ff];
if (p >= 13 * 2 * 0x100)
{
return 0;
}
return tl_tab[p];
}
private static int op_calc1(int i1, uint env, int pm)
//private static int op_calc(int i1, uint env, int pm)
//{
// uint p;
// p = (env << 3) + sin_tab[(((int)((PSG.oper[i1].phase & 0xffff0000) + (pm << 15))) >> 16) & 0x3ff];
// if (p >= 13 * 2 * 0x100)
// {
// return 0;
// }
// return tl_tab[p];
//}
unsafe static int op_calc1(YM2151Operator* PSGoper, int i1, uint env, int pm)
{
uint p;
int i;
i = (int)((PSG.oper[i1].phase & 0xffff0000) + pm);
i = (int)((PSGoper[i1].phase & 0xffff0000) + pm);
p = (env << 3) + sin_tab[(i >> 16) & 0x3ff];
if (p >= 13 * 2 * 0x100)
{
@ -1054,63 +1068,155 @@ namespace MAME.Core
}
return tl_tab[p];
}
private static uint volume_calc(int i1, uint AM)
//private static int op_calc1_src(int i1, uint env, int pm)
//{
// uint p;
// int i;
// i = (int)((PSG.oper[i1].phase & 0xffff0000) + pm);
// p = (env << 3) + sin_tab[(i >> 16) & 0x3ff];
// if (p >= 13 * 2 * 0x100)
// {
// return 0;
// }
// return tl_tab[p];
//}
unsafe static uint volume_calc(YM2151Operator* PSGoper, int i1, uint AM)
{
uint i11;
i11 = PSG.oper[i1].tl + ((uint)PSG.oper[i1].volume) + (AM & PSG.oper[i1].AMmask);
i11 = PSGoper[i1].tl + ((uint)PSGoper[i1].volume) + (AM & PSGoper[i1].AMmask);
return i11;
}
private static void chan_calc(int chan)
//private static uint volume_calc_old(int i1, uint AM)
//{
// uint i11;
// i11 = PSG.oper[i1].tl + ((uint)PSG.oper[i1].volume) + (AM & PSG.oper[i1].AMmask);
// return i11;
//}
//chan_calc高频调用 单次Update 5467次 左右下级堆栈volume_calc 20000+次 op_calc 10000+次
unsafe static void chan_calc(YM2151Operator* PSGoper, int* chanout, int* imem, int chan)
{
//fixed (YM2151Operator* PSGoperPtr = &PSG.oper[0])
{
//YM2151Operator* PSGoper = PSGoperPtr;
uint env;
uint AM = 0;
//m2 = c1 = c2 = mem = 0;
chanout[8] = chanout[9] = chanout[10] = chanout[11] = 0;
//op = PSG.oper[chan * 4]; /* M1 */
//op = PSGoper[chan * 4]; /* M1 */
//op.mem_connect = op.mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
set_mem(chan * 4);
if (PSG.oper[chan * 4].ams != 0)
set_mem(PSGoper, chanout, imem, chan * 4);
if (PSGoper[chan * 4].ams != 0)
{
AM = PSG.lfa << (int)(PSG.oper[chan * 4].ams - 1);
AM = PSG.lfa << (int)(PSGoper[chan * 4].ams - 1);
}
env = volume_calc((int)(chan * 4), AM);
env = volume_calc(PSGoper, (chan * 4), AM);
//env = volume_calc_planB(PSGoper[chan * 4], AM);
{
int iout = PSG.oper[chan * 4].fb_out_prev + PSG.oper[chan * 4].fb_out_curr;
PSG.oper[chan * 4].fb_out_prev = PSG.oper[chan * 4].fb_out_curr;
int iout = PSGoper[chan * 4].fb_out_prev + PSGoper[chan * 4].fb_out_curr;
PSGoper[chan * 4].fb_out_prev = PSGoper[chan * 4].fb_out_curr;
set_value1(chan * 4);
set_value1(chanout, PSGoper, chan * 4);
PSG.oper[chan * 4].fb_out_curr = 0;
PSGoper[chan * 4].fb_out_curr = 0;
if (env < 13 * 64)
{
if (PSG.oper[chan * 4].fb_shift == 0)
if (PSGoper[chan * 4].fb_shift == 0)
{
iout = 0;
}
PSG.oper[chan * 4].fb_out_curr = op_calc1((int)(chan * 4), env, (int)(iout << (int)PSG.oper[chan * 4].fb_shift));
PSGoper[chan * 4].fb_out_curr = op_calc1(PSGoper, (chan * 4), env, (iout << (int)PSGoper[chan * 4].fb_shift));
}
}
env = volume_calc((int)(chan * 4 + 1), AM); /* M2 */
env = volume_calc(PSGoper, (chan * 4 + 1), AM); /* M2 */
//env = volume_calc_planB(PSGoper[chan * 4 + 1], AM);/* M2 */
if (env < 13 * 64)
{
//PSG.oper[chan * 4 + 1].connect += op_calc((int)(chan * 4 + 1), env, m2);
set_value2(chan * 4 + 1, op_calc((int)(chan * 4 + 1), env, chanout[8]));// m2));
//PSGoper[chan * 4 + 1].connect += op_calc((int)(chan * 4 + 1), env, m2);
set_value2(chanout, chan * 4 + 1, op_calc(PSGoper, (chan * 4 + 1), env, chanout[8]));// m2));
}
env = volume_calc((int)(chan * 4 + 2), AM); /* C1 */
env = volume_calc(PSGoper, (chan * 4 + 2), AM); /* C1 */
//env = volume_calc_planB(PSGoper[chan * 4 + 2], AM); /* C1 */
if (env < 13 * 64)
{
//PSG.oper[chan * 4 + 2].connect += op_calc((int)(chan * 4 + 2), env, c1);
set_value2(chan * 4 + 2, op_calc((int)(chan * 4 + 2), env, chanout[9]));// c1));
//PSGoper[chan * 4 + 2].connect += op_calc((int)(chan * 4 + 2), env, c1);
set_value2(chanout, chan * 4 + 2, op_calc(PSGoper, (chan * 4 + 2), env, chanout[9]));// c1));
}
env = volume_calc((int)(chan * 4 + 3), AM); /* C2 */
env = volume_calc(PSGoper, (chan * 4 + 3), AM); /* C2 */
//env = volume_calc_planB(PSGoper[chan * 4 + 3], AM); /* C2 */
if (env < 13 * 64)
{
chanout[chan] += op_calc((int)(chan * 4 + 3), env, chanout[10]);// c2);
chanout[chan] += op_calc(PSGoper, (chan * 4 + 3), env, chanout[10]);// c2);
}
/* M1 */
PSG.oper[chan * 4].mem_value = chanout[11];//mem;
PSGoper[chan * 4].mem_value = chanout[11];//mem;
}
private static void chan7_calc()
}
//private static void chan_calc_src(int chan)
//{
// uint env;
// uint AM = 0;
// //m2 = c1 = c2 = mem = 0;
// chanout[8] = chanout[9] = chanout[10] = chanout[11] = 0;
// //op = PSG.oper[chan * 4]; /* M1 */
// //op.mem_connect = op.mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
// set_mem(chan * 4);
// if (PSG.oper[chan * 4].ams != 0)
// {
// AM = PSG.lfa << (int)(PSG.oper[chan * 4].ams - 1);
// }
// env = volume_calc((int)(chan * 4), AM);
// //env = volume_calc_planB(PSG.oper[chan * 4], AM);
// {
// int iout = PSG.oper[chan * 4].fb_out_prev + PSG.oper[chan * 4].fb_out_curr;
// PSG.oper[chan * 4].fb_out_prev = PSG.oper[chan * 4].fb_out_curr;
// set_value1(chan * 4);
// PSG.oper[chan * 4].fb_out_curr = 0;
// if (env < 13 * 64)
// {
// if (PSG.oper[chan * 4].fb_shift == 0)
// {
// iout = 0;
// }
// PSG.oper[chan * 4].fb_out_curr = op_calc1((int)(chan * 4), env, (int)(iout << (int)PSG.oper[chan * 4].fb_shift));
// }
// }
// env = volume_calc((int)(chan * 4 + 1), AM); /* M2 */
// //env = volume_calc_planB(PSG.oper[chan * 4 + 1], AM);/* M2 */
// if (env < 13 * 64)
// {
// //PSG.oper[chan * 4 + 1].connect += op_calc((int)(chan * 4 + 1), env, m2);
// set_value2(chan * 4 + 1, op_calc((int)(chan * 4 + 1), env, chanout[8]));// m2));
// }
// env = volume_calc((int)(chan * 4 + 2), AM); /* C1 */
// //env = volume_calc_planB(PSG.oper[chan * 4 + 2], AM); /* C1 */
// if (env < 13 * 64)
// {
// //PSG.oper[chan * 4 + 2].connect += op_calc((int)(chan * 4 + 2), env, c1);
// set_value2(chan * 4 + 2, op_calc((int)(chan * 4 + 2), env, chanout[9]));// c1));
// }
// env = volume_calc((int)(chan * 4 + 3), AM); /* C2 */
// //env = volume_calc_planB(PSG.oper[chan * 4 + 3], AM); /* C2 */
// if (env < 13 * 64)
// {
// chanout[chan] += op_calc((int)(chan * 4 + 3), env, chanout[10]);// c2);
// }
// /* M1 */
// PSG.oper[chan * 4].mem_value = chanout[11];//mem;
//}
unsafe static void chan7_calc(YM2151Operator* PSGoper, int* chanout, int* imem)
{
uint env;
uint AM = 0;
@ -1118,37 +1224,41 @@ namespace MAME.Core
chanout[8] = chanout[9] = chanout[10] = chanout[11] = 0;
//op = PSG.oper[7 * 4]; /* M1 */
//op.mem_connect = op.mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
set_mem(7 * 4);
if (PSG.oper[7 * 4].ams != 0)
set_mem(PSGoper, chanout, imem, 7 * 4);
if (PSGoper[7 * 4].ams != 0)
{
AM = PSG.lfa << (int)(PSG.oper[7 * 4].ams - 1);
AM = PSG.lfa << (int)(PSGoper[7 * 4].ams - 1);
}
env = volume_calc(7 * 4, AM);
int iout = PSG.oper[7 * 4].fb_out_prev + PSG.oper[7 * 4].fb_out_curr;
PSG.oper[7 * 4].fb_out_prev = PSG.oper[7 * 4].fb_out_curr;
set_value1(7 * 4);
PSG.oper[7 * 4].fb_out_curr = 0;
env = volume_calc(PSGoper, 7 * 4, AM);
//env = volume_calc_planB(PSGoper[7*4], AM);
int iout = PSGoper[7 * 4].fb_out_prev + PSGoper[7 * 4].fb_out_curr;
PSGoper[7 * 4].fb_out_prev = PSGoper[7 * 4].fb_out_curr;
set_value1(chanout, PSGoper, 7 * 4);
PSGoper[7 * 4].fb_out_curr = 0;
if (env < 13 * 64)
{
if (PSG.oper[7 * 4].fb_shift == 0)
if (PSGoper[7 * 4].fb_shift == 0)
{
iout = 0;
}
PSG.oper[7 * 4].fb_out_curr = op_calc1(7 * 4, env, (iout << (int)PSG.oper[7 * 4].fb_shift));
PSGoper[7 * 4].fb_out_curr = op_calc1(PSGoper, 7 * 4, env, (iout << (int)PSGoper[7 * 4].fb_shift));
}
env = volume_calc(7 * 4 + 1, AM); /* M2 */
env = volume_calc(PSGoper, 7 * 4 + 1, AM); /* M2 */
//env = volume_calc_planB(PSGoper[7 * 4 + 1], AM);/* M2 */
if (env < 13 * 64)
{
//PSG.oper[7 * 4 + 1].connect += op_calc(7 * 4 + 1, env, m2);
set_value2(7 * 4 + 1, op_calc(7 * 4 + 1, env, chanout[8]));// m2));
//PSGoper[7 * 4 + 1].connect += op_calc(7 * 4 + 1, env, m2);
set_value2(chanout, 7 * 4 + 1, op_calc(PSGoper, 7 * 4 + 1, env, chanout[8]));// m2));
}
env = volume_calc(7 * 4 + 2, AM); /* C1 */
env = volume_calc(PSGoper, 7 * 4 + 2, AM); /* C1 */
//env = volume_calc_planB(PSGoper[7 * 4 + 2], AM);/* C1 */
if (env < 13 * 64)
{
//PSG.oper[7 * 4 + 2].connect += op_calc(7 * 4 + 2, env, c1);
set_value2(7 * 4 + 2, op_calc(7 * 4 + 2, env, chanout[9]));// c1));
//PSGoper[7 * 4 + 2].connect += op_calc(7 * 4 + 2, env, c1);
set_value2(chanout, 7 * 4 + 2, op_calc(PSGoper, 7 * 4 + 2, env, chanout[9]));// c1));
}
env = volume_calc(7 * 4 + 3, AM); /* C2 */
env = volume_calc(PSGoper, 7 * 4 + 3, AM); /* C2 */
//env = volume_calc_planB(PSGoper[7 * 4 + 3], AM);/* C2 */
if ((PSG.noise & 0x80) != 0)
{
uint noiseout;
@ -1161,12 +1271,74 @@ namespace MAME.Core
else
{
if (env < 13 * 64)
chanout[7] += op_calc(7 * 4 + 3, env, chanout[10]);// c2);
chanout[7] += op_calc(PSGoper, 7 * 4 + 3, env, chanout[10]);// c2);
}
/* M1 */
PSG.oper[7 * 4].mem_value = chanout[11];//mem;
PSGoper[7 * 4].mem_value = chanout[11];//mem;
}
private static void advance_eg()
//private static void chan7_calc_src()
//{
// uint env;
// uint AM = 0;
// //m2 = c1 = c2 = mem = 0;
// chanout[8] = chanout[9] = chanout[10] = chanout[11] = 0;
// //op = PSG.oper[7 * 4]; /* M1 */
// //op.mem_connect = op.mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
// set_mem(7 * 4);
// if (PSG.oper[7 * 4].ams != 0)
// {
// AM = PSG.lfa << (int)(PSG.oper[7 * 4].ams - 1);
// }
// env = volume_calc(7 * 4, AM);
// //env = volume_calc_planB(PSG.oper[7*4], AM);
// int iout = PSG.oper[7 * 4].fb_out_prev + PSG.oper[7 * 4].fb_out_curr;
// PSG.oper[7 * 4].fb_out_prev = PSG.oper[7 * 4].fb_out_curr;
// set_value1(7 * 4);
// PSG.oper[7 * 4].fb_out_curr = 0;
// if (env < 13 * 64)
// {
// if (PSG.oper[7 * 4].fb_shift == 0)
// {
// iout = 0;
// }
// PSG.oper[7 * 4].fb_out_curr = op_calc1(7 * 4, env, (iout << (int)PSG.oper[7 * 4].fb_shift));
// }
// env = volume_calc(7 * 4 + 1, AM); /* M2 */
// //env = volume_calc_planB(PSG.oper[7 * 4 + 1], AM);/* M2 */
// if (env < 13 * 64)
// {
// //PSG.oper[7 * 4 + 1].connect += op_calc(7 * 4 + 1, env, m2);
// set_value2(7 * 4 + 1, op_calc(7 * 4 + 1, env, chanout[8]));// m2));
// }
// env = volume_calc(7 * 4 + 2, AM); /* C1 */
// //env = volume_calc_planB(PSG.oper[7 * 4 + 2], AM);/* C1 */
// if (env < 13 * 64)
// {
// //PSG.oper[7 * 4 + 2].connect += op_calc(7 * 4 + 2, env, c1);
// set_value2(7 * 4 + 2, op_calc(7 * 4 + 2, env, chanout[9]));// c1));
// }
// env = volume_calc(7 * 4 + 3, AM); /* C2 */
// //env = volume_calc_planB(PSG.oper[7 * 4 + 3], AM);/* C2 */
// if ((PSG.noise & 0x80) != 0)
// {
// uint noiseout;
// noiseout = 0;
// if (env < 0x3ff)
// noiseout = (env ^ 0x3ff) * 2; /* range of the YM2151 noise output is -2044 to 2040 */
// chanout[7] += (int)(((PSG.noise_rng & 0x10000) != 0) ? noiseout : -noiseout); /* bit 16 -> output */
// }
// else
// {
// if (env < 13 * 64)
// chanout[7] += op_calc(7 * 4 + 3, env, chanout[10]);// c2);
// }
// /* M1 */
// PSG.oper[7 * 4].mem_value = chanout[11];//mem;
//}
unsafe static void advance_eg(YM2151Operator* PSGoper)
{
uint i;
int i1 = 0;
@ -1176,53 +1348,53 @@ namespace MAME.Core
PSG.eg_timer -= PSG.eg_timer_overflow;
PSG.eg_cnt++;
/* envelope generator */
//op = PSG.oper[i1]; /* CH 0 M1 */
//op = PSGoper[i1]; /* CH 0 M1 */
i = 32;
do
{
switch (PSG.oper[i1].state)
switch (PSGoper[i1].state)
{
case 4: /* attack phase */
if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_ar) - 1)) == 0)
if ((PSG.eg_cnt & ((1 << PSGoper[i1].eg_sh_ar) - 1)) == 0)
{
PSG.oper[i1].volume += (~PSG.oper[i1].volume *
(eg_inc[PSG.oper[i1].eg_sel_ar + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_ar) & 7)])
PSGoper[i1].volume += (~PSGoper[i1].volume *
(eg_inc[PSGoper[i1].eg_sel_ar + ((PSG.eg_cnt >> PSGoper[i1].eg_sh_ar) & 7)])
) >> 4;
if (PSG.oper[i1].volume <= 0)
if (PSGoper[i1].volume <= 0)
{
PSG.oper[i1].volume = 0;
PSG.oper[i1].state = 3;
PSGoper[i1].volume = 0;
PSGoper[i1].state = 3;
}
}
break;
case 3: /* decay phase */
if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_d1r) - 1)) == 0)
if ((PSG.eg_cnt & ((1 << PSGoper[i1].eg_sh_d1r) - 1)) == 0)
{
PSG.oper[i1].volume += eg_inc[PSG.oper[i1].eg_sel_d1r + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_d1r) & 7)];
if (PSG.oper[i1].volume >= PSG.oper[i1].d1l)
PSG.oper[i1].state = 2;
PSGoper[i1].volume += eg_inc[PSGoper[i1].eg_sel_d1r + ((PSG.eg_cnt >> PSGoper[i1].eg_sh_d1r) & 7)];
if (PSGoper[i1].volume >= PSGoper[i1].d1l)
PSGoper[i1].state = 2;
}
break;
case 2: /* sustain phase */
if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_d2r) - 1)) == 0)
if ((PSG.eg_cnt & ((1 << PSGoper[i1].eg_sh_d2r) - 1)) == 0)
{
PSG.oper[i1].volume += eg_inc[PSG.oper[i1].eg_sel_d2r + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_d2r) & 7)];
if (PSG.oper[i1].volume >= 0x3ff)
PSGoper[i1].volume += eg_inc[PSGoper[i1].eg_sel_d2r + ((PSG.eg_cnt >> PSGoper[i1].eg_sh_d2r) & 7)];
if (PSGoper[i1].volume >= 0x3ff)
{
PSG.oper[i1].volume = 0x3ff;
PSG.oper[i1].state = 0;
PSGoper[i1].volume = 0x3ff;
PSGoper[i1].state = 0;
}
}
break;
case 1: /* release phase */
if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_rr) - 1)) == 0)
if ((PSG.eg_cnt & ((1 << PSGoper[i1].eg_sh_rr) - 1)) == 0)
{
PSG.oper[i1].volume += eg_inc[PSG.oper[i1].eg_sel_rr + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_rr) & 7)];
if (PSG.oper[i1].volume >= 0x3ff)
PSGoper[i1].volume += eg_inc[PSGoper[i1].eg_sel_rr + ((PSG.eg_cnt >> PSGoper[i1].eg_sh_rr) & 7)];
if (PSGoper[i1].volume >= 0x3ff)
{
PSG.oper[i1].volume = 0x3ff;
PSG.oper[i1].state = 0;
PSGoper[i1].volume = 0x3ff;
PSGoper[i1].state = 0;
}
}
break;
@ -1232,7 +1404,74 @@ namespace MAME.Core
} while (i != 0);
}
}
private static void advance()
//private static void advance_eg()
//{
// uint i;
// int i1 = 0;
// PSG.eg_timer += PSG.eg_timer_add;
// while (PSG.eg_timer >= PSG.eg_timer_overflow)
// {
// PSG.eg_timer -= PSG.eg_timer_overflow;
// PSG.eg_cnt++;
// /* envelope generator */
// //op = PSG.oper[i1]; /* CH 0 M1 */
// i = 32;
// do
// {
// switch (PSG.oper[i1].state)
// {
// case 4: /* attack phase */
// if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_ar) - 1)) == 0)
// {
// PSG.oper[i1].volume += (~PSG.oper[i1].volume *
// (eg_inc[PSG.oper[i1].eg_sel_ar + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_ar) & 7)])
// ) >> 4;
// if (PSG.oper[i1].volume <= 0)
// {
// PSG.oper[i1].volume = 0;
// PSG.oper[i1].state = 3;
// }
// }
// break;
// case 3: /* decay phase */
// if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_d1r) - 1)) == 0)
// {
// PSG.oper[i1].volume += eg_inc[PSG.oper[i1].eg_sel_d1r + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_d1r) & 7)];
// if (PSG.oper[i1].volume >= PSG.oper[i1].d1l)
// PSG.oper[i1].state = 2;
// }
// break;
// case 2: /* sustain phase */
// if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_d2r) - 1)) == 0)
// {
// PSG.oper[i1].volume += eg_inc[PSG.oper[i1].eg_sel_d2r + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_d2r) & 7)];
// if (PSG.oper[i1].volume >= 0x3ff)
// {
// PSG.oper[i1].volume = 0x3ff;
// PSG.oper[i1].state = 0;
// }
// }
// break;
// case 1: /* release phase */
// if ((PSG.eg_cnt & ((1 << PSG.oper[i1].eg_sh_rr) - 1)) == 0)
// {
// PSG.oper[i1].volume += eg_inc[PSG.oper[i1].eg_sel_rr + ((PSG.eg_cnt >> PSG.oper[i1].eg_sh_rr) & 7)];
// if (PSG.oper[i1].volume >= 0x3ff)
// {
// PSG.oper[i1].volume = 0x3ff;
// PSG.oper[i1].state = 0;
// }
// }
// break;
// }
// i1++;
// i--;
// } while (i != 0);
// }
//}
unsafe static void advance(YM2151Operator* PSGoper, uint* PSGfreq)
{
uint i;
int a, p;
@ -1319,39 +1558,39 @@ namespace MAME.Core
}
/* phase generator */
uint i1 = 0;
//op = PSG.oper[i1]; /* CH 0 M1 */
//op = PSGoper[i1]; /* CH 0 M1 */
i = 8;
do
{
if (PSG.oper[i1].pms != 0) /* only when phase modulation from LFO is enabled for this channel */
if (PSGoper[i1].pms != 0) /* only when phase modulation from LFO is enabled for this channel */
{
int mod_ind = PSG.lfp; /* -128..+127 (8bits signed) */
if (PSG.oper[i1].pms < 6)
mod_ind >>= (int)(6 - PSG.oper[i1].pms);
if (PSGoper[i1].pms < 6)
mod_ind >>= (int)(6 - PSGoper[i1].pms);
else
mod_ind <<= (int)(PSG.oper[i1].pms - 5);
mod_ind <<= (int)(PSGoper[i1].pms - 5);
if (mod_ind != 0)
{
uint kc_channel = (uint)(PSG.oper[i1].kc_i + mod_ind);
PSG.oper[i1].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1].dt2] + PSG.oper[i1].dt1) * PSG.oper[i1].mul) >> 1);
PSG.oper[i1 + 1].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1 + 1].dt2] + PSG.oper[i1 + 1].dt1) * PSG.oper[i1 + 1].mul) >> 1);
PSG.oper[i1 + 2].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1 + 2].dt2] + PSG.oper[i1 + 2].dt1) * PSG.oper[i1 + 2].mul) >> 1);
PSG.oper[i1 + 3].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1 + 3].dt2] + PSG.oper[i1 + 3].dt1) * PSG.oper[i1 + 3].mul) >> 1);
uint kc_channel = (uint)(PSGoper[i1].kc_i + mod_ind);
PSGoper[i1].phase += (uint)(((PSGfreq[kc_channel + PSGoper[i1].dt2] + PSGoper[i1].dt1) * PSGoper[i1].mul) >> 1);
PSGoper[i1 + 1].phase += (uint)(((PSGfreq[kc_channel + PSGoper[i1 + 1].dt2] + PSGoper[i1 + 1].dt1) * PSGoper[i1 + 1].mul) >> 1);
PSGoper[i1 + 2].phase += (uint)(((PSGfreq[kc_channel + PSGoper[i1 + 2].dt2] + PSGoper[i1 + 2].dt1) * PSGoper[i1 + 2].mul) >> 1);
PSGoper[i1 + 3].phase += (uint)(((PSGfreq[kc_channel + PSGoper[i1 + 3].dt2] + PSGoper[i1 + 3].dt1) * PSGoper[i1 + 3].mul) >> 1);
}
else /* phase modulation from LFO is equal to zero */
{
PSG.oper[i1].phase += PSG.oper[i1].freq;
PSG.oper[i1 + 1].phase += PSG.oper[i1 + 1].freq;
PSG.oper[i1 + 2].phase += PSG.oper[i1 + 2].freq;
PSG.oper[i1 + 3].phase += PSG.oper[i1 + 3].freq;
PSGoper[i1].phase += PSGoper[i1].freq;
PSGoper[i1 + 1].phase += PSGoper[i1 + 1].freq;
PSGoper[i1 + 2].phase += PSGoper[i1 + 2].freq;
PSGoper[i1 + 3].phase += PSGoper[i1 + 3].freq;
}
}
else /* phase modulation from LFO is disabled */
{
PSG.oper[i1].phase += PSG.oper[i1].freq;
PSG.oper[i1 + 1].phase += PSG.oper[i1 + 1].freq;
PSG.oper[i1 + 2].phase += PSG.oper[i1 + 2].freq;
PSG.oper[i1 + 3].phase += PSG.oper[i1 + 3].freq;
PSGoper[i1].phase += PSGoper[i1].freq;
PSGoper[i1 + 1].phase += PSGoper[i1 + 1].freq;
PSGoper[i1 + 2].phase += PSGoper[i1 + 2].freq;
PSGoper[i1 + 3].phase += PSGoper[i1 + 3].freq;
}
i1 += 4;
i--;
@ -1361,7 +1600,7 @@ namespace MAME.Core
if (PSG.csm_req == 2) /* KEY ON */
{
i1 = 0;
PSG.oper[i1] = PSG.oper[i1]; /* CH 0 M1 */
PSGoper[i1] = PSGoper[i1]; /* CH 0 M1 */
i = 32;
do
{
@ -1374,7 +1613,7 @@ namespace MAME.Core
else /* KEY OFF */
{
i1 = 0;
PSG.oper[i1] = PSG.oper[i1]; /* CH 0 M1 */
PSGoper[i1] = PSGoper[i1]; /* CH 0 M1 */
i = 32;
do
{
@ -1386,13 +1625,183 @@ namespace MAME.Core
}
}
}
public static void ym2151_update_one(int offset, int length)
//private static void advance()
//{
// uint i;
// int a, p;
// /* LFO */
// if ((PSG.test & 2) != 0)
// {
// PSG.lfo_phase = 0;
// }
// else
// {
// PSG.lfo_timer += PSG.lfo_timer_add;
// if (PSG.lfo_timer >= PSG.lfo_overflow)
// {
// PSG.lfo_timer -= PSG.lfo_overflow;
// PSG.lfo_counter += PSG.lfo_counter_add;
// PSG.lfo_phase += (PSG.lfo_counter >> 4);
// PSG.lfo_phase &= 255;
// PSG.lfo_counter &= 15;
// }
// }
// i = PSG.lfo_phase;
// /* calculate LFO AM and PM waveform value (all verified on real chip, except for noise algorithm which is impossible to analyse)*/
// switch (PSG.lfo_wsel)
// {
// case 0:
// /* saw */
// /* AM: 255 down to 0 */
// /* PM: 0 to 127, -127 to 0 (at PMD=127: LFP = 0 to 126, -126 to 0) */
// a = (int)(255 - i);
// if (i < 128)
// p = (int)i;
// else
// p = (int)(i - 255);
// break;
// case 1:
// /* square */
// /* AM: 255, 0 */
// /* PM: 128,-128 (LFP = exactly +PMD, -PMD) */
// if (i < 128)
// {
// a = 255;
// p = 128;
// }
// else
// {
// a = 0;
// p = -128;
// }
// break;
// case 2:
// /* triangle */
// /* AM: 255 down to 1 step -2; 0 up to 254 step +2 */
// /* PM: 0 to 126 step +2, 127 to 1 step -2, 0 to -126 step -2, -127 to -1 step +2*/
// if (i < 128)
// a = (int)(255 - (i * 2));
// else
// a = (int)((i * 2) - 256);
// if (i < 64) /* i = 0..63 */
// p = (int)(i * 2); /* 0 to 126 step +2 */
// else if (i < 128) /* i = 64..127 */
// p = (int)(255 - i * 2); /* 127 to 1 step -2 */
// else if (i < 192) /* i = 128..191 */
// p = (int)(256 - i * 2); /* 0 to -126 step -2*/
// else /* i = 192..255 */
// p = (int)(i * 2 - 511); /*-127 to -1 step +2*/
// break;
// case 3:
// default: /*keep the compiler happy*/
// a = lfo_noise_waveform[i];
// p = a - 128;
// break;
// }
// PSG.lfa = (uint)(a * PSG.amd / 128);
// PSG.lfp = p * PSG.pmd / 128;
// PSG.noise_p += PSG.noise_f;
// i = (PSG.noise_p >> 16); /* number of events (shifts of the shift register) */
// PSG.noise_p &= 0xffff;
// while (i != 0)
// {
// uint j;
// j = ((PSG.noise_rng ^ (PSG.noise_rng >> 3)) & 1) ^ 1;
// PSG.noise_rng = (j << 16) | (PSG.noise_rng >> 1);
// i--;
// }
// /* phase generator */
// uint i1 = 0;
// //op = PSG.oper[i1]; /* CH 0 M1 */
// i = 8;
// do
// {
// if (PSG.oper[i1].pms != 0) /* only when phase modulation from LFO is enabled for this channel */
// {
// int mod_ind = PSG.lfp; /* -128..+127 (8bits signed) */
// if (PSG.oper[i1].pms < 6)
// mod_ind >>= (int)(6 - PSG.oper[i1].pms);
// else
// mod_ind <<= (int)(PSG.oper[i1].pms - 5);
// if (mod_ind != 0)
// {
// uint kc_channel = (uint)(PSG.oper[i1].kc_i + mod_ind);
// PSG.oper[i1].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1].dt2] + PSG.oper[i1].dt1) * PSG.oper[i1].mul) >> 1);
// PSG.oper[i1 + 1].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1 + 1].dt2] + PSG.oper[i1 + 1].dt1) * PSG.oper[i1 + 1].mul) >> 1);
// PSG.oper[i1 + 2].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1 + 2].dt2] + PSG.oper[i1 + 2].dt1) * PSG.oper[i1 + 2].mul) >> 1);
// PSG.oper[i1 + 3].phase += (uint)(((PSG.freq[kc_channel + PSG.oper[i1 + 3].dt2] + PSG.oper[i1 + 3].dt1) * PSG.oper[i1 + 3].mul) >> 1);
// }
// else /* phase modulation from LFO is equal to zero */
// {
// PSG.oper[i1].phase += PSG.oper[i1].freq;
// PSG.oper[i1 + 1].phase += PSG.oper[i1 + 1].freq;
// PSG.oper[i1 + 2].phase += PSG.oper[i1 + 2].freq;
// PSG.oper[i1 + 3].phase += PSG.oper[i1 + 3].freq;
// }
// }
// else /* phase modulation from LFO is disabled */
// {
// PSG.oper[i1].phase += PSG.oper[i1].freq;
// PSG.oper[i1 + 1].phase += PSG.oper[i1 + 1].freq;
// PSG.oper[i1 + 2].phase += PSG.oper[i1 + 2].freq;
// PSG.oper[i1 + 3].phase += PSG.oper[i1 + 3].freq;
// }
// i1 += 4;
// i--;
// } while (i != 0);
// if (PSG.csm_req != 0) /* CSM KEYON/KEYOFF seqeunce request */
// {
// if (PSG.csm_req == 2) /* KEY ON */
// {
// i1 = 0;
// PSG.oper[i1] = PSG.oper[i1]; /* CH 0 M1 */
// i = 32;
// do
// {
// KEY_ON(i1, 2);
// i1++;
// i--;
// } while (i != 0);
// PSG.csm_req = 1;
// }
// else /* KEY OFF */
// {
// i1 = 0;
// PSG.oper[i1] = PSG.oper[i1]; /* CH 0 M1 */
// i = 32;
// do
// {
// KEY_OFF(i1, 0xfffffffe);
// i1++;
// i--;
// } while (i != 0);
// PSG.csm_req = 0;
// }
// }
//}
public unsafe static void ym2151_update_one(int offset, int length)
{
fixed (uint* PSGpanPtr = &PSG.pan[0])
fixed (uint* PSGfreqPtr = &PSG.freq[0])
fixed (YM2151Operator* PSGoperPtr = &PSG.oper[0])
fixed (int* chanoutPtr = &chanout[0])
fixed (int* streamoutput0Ptr = &Sound.ym2151stream.streamoutput[0][0])
fixed (int* streamoutput1Ptr = &Sound.ym2151stream.streamoutput[0][1])
fixed (int* imemPtr = &imem[0])
{
YM2151Operator* PSGoper = PSGoperPtr;
uint* PSGpan = PSGpanPtr;
uint* PSGfreq = PSGfreqPtr;
int* chanout = chanoutPtr;
int* streamoutput0 = streamoutput0Ptr;
int* streamoutput1 = streamoutput1Ptr;
int* imem = imemPtr;
int i;
int outl, outr;
for (i = 0; i < length; i++)
{
advance_eg();
advance_eg(PSGoper);
chanout[0] = 0;
chanout[1] = 0;
chanout[2] = 0;
@ -1401,30 +1810,30 @@ namespace MAME.Core
chanout[5] = 0;
chanout[6] = 0;
chanout[7] = 0;
chan_calc(0);
chan_calc(1);
chan_calc(2);
chan_calc(3);
chan_calc(4);
chan_calc(5);
chan_calc(6);
chan7_calc();
outl = (int)(chanout[0] & PSG.pan[0]);
outr = (int)(chanout[0] & PSG.pan[1]);
outl += (int)(chanout[1] & PSG.pan[2]);
outr += (int)(chanout[1] & PSG.pan[3]);
outl += (int)(chanout[2] & PSG.pan[4]);
outr += (int)(chanout[2] & PSG.pan[5]);
outl += (int)(chanout[3] & PSG.pan[6]);
outr += (int)(chanout[3] & PSG.pan[7]);
outl += (int)(chanout[4] & PSG.pan[8]);
outr += (int)(chanout[4] & PSG.pan[9]);
outl += (int)(chanout[5] & PSG.pan[10]);
outr += (int)(chanout[5] & PSG.pan[11]);
outl += (int)(chanout[6] & PSG.pan[12]);
outr += (int)(chanout[6] & PSG.pan[13]);
outl += (int)(chanout[7] & PSG.pan[14]);
outr += (int)(chanout[7] & PSG.pan[15]);
chan_calc(PSGoper, chanout, imem, 0);
chan_calc(PSGoper, chanout, imem, 1);
chan_calc(PSGoper, chanout, imem, 2);
chan_calc(PSGoper, chanout, imem, 3);
chan_calc(PSGoper, chanout, imem, 4);
chan_calc(PSGoper, chanout, imem, 5);
chan_calc(PSGoper, chanout, imem, 6);
chan7_calc(PSGoper, chanout, imem);
outl = (int)(chanout[0] & PSGpan[0]);
outr = (int)(chanout[0] & PSGpan[1]);
outl += (int)(chanout[1] & PSGpan[2]);
outr += (int)(chanout[1] & PSGpan[3]);
outl += (int)(chanout[2] & PSGpan[4]);
outr += (int)(chanout[2] & PSGpan[5]);
outl += (int)(chanout[3] & PSGpan[6]);
outr += (int)(chanout[3] & PSGpan[7]);
outl += (int)(chanout[4] & PSGpan[8]);
outr += (int)(chanout[4] & PSGpan[9]);
outl += (int)(chanout[5] & PSGpan[10]);
outr += (int)(chanout[5] & PSGpan[11]);
outl += (int)(chanout[6] & PSGpan[12]);
outr += (int)(chanout[6] & PSGpan[13]);
outl += (int)(chanout[7] & PSGpan[14]);
outr += (int)(chanout[7] & PSGpan[15]);
if (outl > 32767)
{
outl = 32767;
@ -1441,11 +1850,72 @@ namespace MAME.Core
{
outr = -32768;
}
Sound.ym2151stream.streamoutput[0][offset + i] = outl;
Sound.ym2151stream.streamoutput[1][offset + i] = outr;
advance();
streamoutput0[offset + i] = outl;
streamoutput1[offset + i] = outr;
advance(PSGoper, PSGfreq);
}
}
}
//public static void ym2151_update_one(int offset, int length)
//{
// int i;
// int outl, outr;
// for (i = 0; i < length; i++)
// {
// advance_eg();
// chanout[0] = 0;
// chanout[1] = 0;
// chanout[2] = 0;
// chanout[3] = 0;
// chanout[4] = 0;
// chanout[5] = 0;
// chanout[6] = 0;
// chanout[7] = 0;
// chan_calc(0);
// chan_calc(1);
// chan_calc(2);
// chan_calc(3);
// chan_calc(4);
// chan_calc(5);
// chan_calc(6);
// chan7_calc();
// outl = (int)(chanout[0] & PSG.pan[0]);
// outr = (int)(chanout[0] & PSG.pan[1]);
// outl += (int)(chanout[1] & PSG.pan[2]);
// outr += (int)(chanout[1] & PSG.pan[3]);
// outl += (int)(chanout[2] & PSG.pan[4]);
// outr += (int)(chanout[2] & PSG.pan[5]);
// outl += (int)(chanout[3] & PSG.pan[6]);
// outr += (int)(chanout[3] & PSG.pan[7]);
// outl += (int)(chanout[4] & PSG.pan[8]);
// outr += (int)(chanout[4] & PSG.pan[9]);
// outl += (int)(chanout[5] & PSG.pan[10]);
// outr += (int)(chanout[5] & PSG.pan[11]);
// outl += (int)(chanout[6] & PSG.pan[12]);
// outr += (int)(chanout[6] & PSG.pan[13]);
// outl += (int)(chanout[7] & PSG.pan[14]);
// outr += (int)(chanout[7] & PSG.pan[15]);
// if (outl > 32767)
// {
// outl = 32767;
// }
// else if (outl < -32768)
// {
// outl = -32768;
// }
// if (outr > 32767)
// {
// outr = 32767;
// }
// else if (outr < -32768)
// {
// outr = -32768;
// }
// Sound.ym2151stream.streamoutput[0][offset + i] = outl;
// Sound.ym2151stream.streamoutput[1][offset + i] = outr;
// advance();
// }
//}
public static byte ym2151_status_port_0_r()
{
Sound.ym2151stream.stream_update();
@ -1460,18 +1930,30 @@ namespace MAME.Core
Sound.ym2151stream.stream_update();
ym2151_write_reg(PSG.lastreg0, data);
}
private static void set_value1(int op1)
unsafe static void set_value1(int* chanout, YM2151Operator* PSGoper, int op1)
{
if (iconnect[op1] == 12)
{
chanout[9] = chanout[10] = chanout[11] = PSG.oper[op1].fb_out_prev;
chanout[9] = chanout[10] = chanout[11] = PSGoper[op1].fb_out_prev;
}
else
{
chanout[iconnect[op1]] = PSG.oper[op1].fb_out_prev;
chanout[iconnect[op1]] = PSGoper[op1].fb_out_prev;
}
}
private static void set_value2(int op1, int i)
//private static void set_value1(int op1)
//{
// if (iconnect[op1] == 12)
// {
// chanout[9] = chanout[10] = chanout[11] = PSG.oper[op1].fb_out_prev;
// }
// else
// {
// chanout[iconnect[op1]] = PSG.oper[op1].fb_out_prev;
// }
//}
unsafe static void set_value2(int* chanout, int op1, int i)
{
if (iconnect[op1] == 12)
{
@ -1482,13 +1964,32 @@ namespace MAME.Core
chanout[iconnect[op1]] += i;
}
}
private static void set_mem(int op1)
//private static void set_value2(int op1, int i)
//{
// if (iconnect[op1] == 12)
// {
// return;
// }
// else
// {
// chanout[iconnect[op1]] += i;
// }
//}
unsafe static void set_mem(YM2151Operator* PSGoper, int* chanout, int* imem, int op1)
{
if (imem[op1] == 8 || imem[op1] == 10 || imem[op1] == 11)
{
chanout[imem[op1]] = PSG.oper[op1].mem_value;
chanout[imem[op1]] = PSGoper[op1].mem_value;
}
}
//private static void set_mem(int op1)
//{
// if (imem[op1] == 8 || imem[op1] == 10 || imem[op1] == 11)
// {
// chanout[imem[op1]] = PSG.oper[op1].mem_value;
// }
//}
public static void SaveStateBinary(BinaryWriter writer)
{
int i;