diff --git a/MAME.Unity/Assets/Plugins/UMAME/Log/EmuLogger.cs b/MAME.Unity/Assets/Plugins/UMAME/Log/EmuLogger.cs index 28acc3a..4d8b2b4 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/Log/EmuLogger.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/Log/EmuLogger.cs @@ -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 } } diff --git a/MAME.Unity/Assets/Plugins/UMAME/ObjectPoolAuto.cs b/MAME.Unity/Assets/Plugins/UMAME/ObjectPoolAuto.cs new file mode 100644 index 0000000..1189454 --- /dev/null +++ b/MAME.Unity/Assets/Plugins/UMAME/ObjectPoolAuto.cs @@ -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 + { + /************************************************************************************************************************/ + + /// + /// 获取或者创建一个新的 + /// + /// Remember to 需要回收参见这个 + public static T Acquire() + where T : class, new() + => ObjectPool.Acquire(); + + /// + /// 获取或者创建一个新的 + /// + /// Remember to 需要回收参见这个 + public static void Acquire(out T item) + where T : class, new() + => item = ObjectPool.Acquire(); + /************************************************************************************************************************/ + + /// + /// 回收对象 + /// + public static void Release(T item) + where T : class, new() + => ObjectPool.Release(item); + + /// + /// 回收对象 + /// + public static void Release(ref T item) where T : class, new() + { + if (item != null) + { + ObjectPool.Release(item); + item = null; + } + } + + /************************************************************************************************************************/ + public const string + NotClearError = " They must be cleared before being released to the pool and not modified after that."; + + /************************************************************************************************************************/ + + /// + /// 获取或创建List + /// + /// Remember to 回收参见此方法 + public static List AcquireList() + { + var list = ObjectPool>.Acquire(); + EmuLogger.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError); + return list; + } + + /// + /// 回收List + /// + public static void Release(List list) + { + list.Clear(); + ObjectPool>.Release(list); + } + /// + /// 回收List内容 + /// + /// + /// + public static void ReleaseListContent(List list) where T : class, new() + { + foreach (var item in list) + { + ObjectPool.Release(item); + } + list.Clear(); + } + + /************************************************************************************************************************/ + + /// + /// 获取或创建HashSet + /// + public static HashSet AcquireSet() + { + var set = ObjectPool>.Acquire(); + EmuLogger.Assert(set.Count == 0, "A pooled set is not empty." + NotClearError); + return set; + } + + /// + /// 释放HashSet + /// + public static void Release(HashSet set) + { + set.Clear(); + ObjectPool>.Release(set); + } + + /************************************************************************************************************************/ + + /// + /// 获取一个字符串StringBuilder + /// + /// Remember to 回收参见这个 + public static StringBuilder AcquireStringBuilder() + { + var builder = ObjectPool.Acquire(); + EmuLogger.Assert(builder.Length == 0, $"A pooled {nameof(StringBuilder)} is not empty." + NotClearError); + return builder; + } + + /// + /// 回收 StringBuilder + /// + public static void Release(StringBuilder builder) + { + builder.Length = 0; + ObjectPool.Release(builder); + } + + /// + /// 回收 StringBuilder + /// + public static string ReleaseToString(this StringBuilder builder) + { + var result = builder.ToString(); + Release(builder); + return result; + } + + /************************************************************************************************************************/ + + private static class Cache + { + public static readonly Dictionary, T>> + Results = new Dictionary, T>>(); + } + + /// + /// 此方法主要用于频繁绘制缓存,比如说GUI绘制 + /// + public static T GetCachedResult(Func function) + { + var method = function.Method; + if (!Cache.Results.TryGetValue(method, out var result)) + { + + result = new KeyValuePair, T>(function, function()); + Cache.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 + { + /************************************************************************************************************************/ + + /// + /// Calls to get a spare if + /// + public static IDisposable Acquire(out T item) + where T : class, new() + => ObjectPool.Disposable.Acquire(out item); + + /************************************************************************************************************************/ + + /// + /// Calls to get a spare if + /// + public static IDisposable AcquireList(out List list) + { + var disposable = ObjectPool>.Disposable.Acquire(out list, onRelease: (l) => l.Clear()); + EmuLogger.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError); + return disposable; + } + + /************************************************************************************************************************/ + + /// + /// Calls to get a spare if + /// + public static IDisposable AcquireSet(out HashSet set) + { + var disposable = ObjectPool>.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 where T : class, new() + { + /************************************************************************************************************************/ + + private static readonly List + Items = new List(); + + /************************************************************************************************************************/ + + /// The number of spare items currently in the pool. + 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); + } + } + } + + /************************************************************************************************************************/ + + /// + /// If the is less than the specified value, this method increases it to that value by + /// creating new objects. + /// + public static void SetMinCount(int count) + { + if (Count < count) + Count = count; + } + + /************************************************************************************************************************/ + + /// The of the internal list of spare items. + public static int Capacity + { + get => Items.Capacity; + set + { + if (Items.Count > value) + Items.RemoveRange(value, Items.Count - value); + Items.Capacity = value; + } + } + + /************************************************************************************************************************/ + + /// Returns a spare item if there are any, or creates a new one. + /// Remember to it when you are done. + 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; + } + } + + /************************************************************************************************************************/ + + /// Adds the `item` to the list of spares so it can be reused. + public static void Release(T item) + { + Items.Add(item); + + } + + /************************************************************************************************************************/ + + /// Returns a description of the state of this pool. + public static string GetDetails() + { + return + $"{typeof(T).Name}" + + $" ({nameof(Count)} = {Items.Count}" + + $", {nameof(Capacity)} = {Items.Capacity}" + + ")"; + } + + /************************************************************************************************************************/ + + /// + /// An system to allow pooled objects to be acquired and released within using + /// statements instead of needing to manually release everything. + /// + public sealed class Disposable : IDisposable + { + /************************************************************************************************************************/ + + private static readonly List LazyStack = new List(); + + private static int _ActiveDisposables; + + private T _Item; + private Action _OnRelease; + + /************************************************************************************************************************/ + + private Disposable() { } + + /// + /// Calls to set the `item` and returns an + /// that will call on the `item` when disposed. + /// + public static IDisposable Acquire(out T item, Action onRelease = null) + { + Disposable disposable; + + if (LazyStack.Count <= _ActiveDisposables) + { + LazyStack.Add(disposable = new Disposable()); + } + else + { + disposable = LazyStack[_ActiveDisposables]; + } + + _ActiveDisposables++; + + disposable._Item = item = ObjectPool.Acquire(); + disposable._OnRelease = onRelease; + return disposable; + } + + /************************************************************************************************************************/ + + void IDisposable.Dispose() + { + _OnRelease?.Invoke(_Item); + Release(_Item); + _ActiveDisposables--; + } + /************************************************************************************************************************/ + } + } + + #region ExtFunctions + public struct PoolHandle : IDisposable + where T : class, new() + { + public T Ins; + internal static PoolHandle Create(T poolIns) + { + return new PoolHandle { Ins = poolIns }; + } + + public void Dispose() + { + ObjectPoolAuto.Release(Ins); + } + } + public struct PoolListHandle : IDisposable + { + public List Ins; + internal static PoolListHandle Create(List poolIns) + { + return new PoolListHandle { Ins = poolIns }; + } + + public void Dispose() + { + ObjectPoolAuto.Release(Ins); + } + } + + public static PoolHandle PoolScope() + where T : class, new() + { + return PoolHandle.Create(ObjectPoolAuto.Acquire()); + } + public static PoolListHandle PoolListScope() + { + return PoolListHandle.Create(ObjectPoolAuto.AcquireList()); + } + #endregion + + } +} + + diff --git a/MAME.Unity/Assets/Plugins/UMAME/ObjectPoolAuto.cs.meta b/MAME.Unity/Assets/Plugins/UMAME/ObjectPoolAuto.cs.meta new file mode 100644 index 0000000..7dc7aae --- /dev/null +++ b/MAME.Unity/Assets/Plugins/UMAME/ObjectPoolAuto.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f22c2fa157c9e6045ad5307124c8a365 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MAME.Unity/Assets/Plugins/UMAME/cpu/nec/Nec.cs b/MAME.Unity/Assets/Plugins/UMAME/cpu/nec/Nec.cs index 3609c9b..e19b5b3 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/cpu/nec/Nec.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/cpu/nec/Nec.cs @@ -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.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) { diff --git a/MAME.Unity/Assets/Plugins/UMAME/emu/Cpuint.cs b/MAME.Unity/Assets/Plugins/UMAME/emu/Cpuint.cs index 6ff6a25..41e2770 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/emu/Cpuint.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/emu/Cpuint.cs @@ -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.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.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 lsirq = new List(); + //List lsirq = new List(); + List lsirq = ObjectPoolAuto.AcquireList(); 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(); for (i = 0; i < n; i++) { - lirq.Add(new irq()); + irq _irq = ObjectPoolAuto.Acquire(); + lirq.Add(_irq); + //lirq.Add(new irq()); lirq[i].cpunum = reader.ReadInt32(); lirq[i].line = reader.ReadInt32(); lirq[i].state = (LineState)reader.ReadInt32(); diff --git a/MAME.Unity/Assets/Plugins/UMAME/emu/EmuTimer.cs b/MAME.Unity/Assets/Plugins/UMAME/emu/EmuTimer.cs index 5fe2437..5bfcf85 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/emu/EmuTimer.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/emu/EmuTimer.cs @@ -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 timer_list_remove_lt1 = new List(); 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 lt1 = new List(); + 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); } diff --git a/MAME.Unity/Assets/Plugins/UMAME/mame/neogeo/Video.cs b/MAME.Unity/Assets/Plugins/UMAME/mame/neogeo/Video.cs index 45d98c0..e65bb3e 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/mame/neogeo/Video.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/mame/neogeo/Video.cs @@ -145,165 +145,533 @@ 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 span_neogeo_videoram = neogeo_videoram.AsSpan(); + // Span span_bitmapbaseN_iBitmap = Video.bitmapbaseN[iBitmap].AsSpan(); + // Span span_sprite_gfx = sprite_gfx.AsSpan(); + // Span 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; + // } + // } + // } + //} + + /// + /// draw_sprites (Unsafa 尝试提升效率) + /// + /// + /// + unsafe 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) + + 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]) { - 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) + 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; + byte sprite_y_and_tile; + bool invert; + y = 0; + x = 0; + rows = 0; + zoom_y = 0; + zoom_x = 0; + if ((scanline & 0x01) != 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; + sprite_list_offset = 0x8680; } 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; + sprite_list_offset = 0x8600; } - if ((x >= 0x140) && (x <= 0x1f0)) + for (max_sprite_index = 95; max_sprite_index >= 0; max_sprite_index--) { - continue; + if (neogeo_videoram[sprite_list_offset + max_sprite_index] != 0) + { + break; + } } - if (sprite_on_scanline(scanline, y, rows)) + if (max_sprite_index != 95) { - sprite_line = (scanline - y) & 0x1ff; - zoom_line = sprite_line & 0xff; - invert = ((sprite_line & 0x100) != 0) ? true : false; - if (invert) + 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]; + + //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) { - 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; + x = (x + zoom_x + 1) & 0x01ff; + zoom_x = (zoom_control >> 8) & 0x0f; } else { - x_inc = 1; + y = 0x200 - (y_control >> 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; } - int pixel_addr_offsetx, pixel_addr_offsety; - if (x <= 0x01f0) + + fixed (int* zoom_x_tablesPtr = &zoom_x_tables[zoom_x, 0]) { - int i; - pixel_addr_offsetx = x + NEOGEO_HBEND; - pixel_addr_offsety = scanline; - for (i = 0; i < 0x10; i++) + int* zoom_x_tables = zoom_x_tablesPtr; + + if ((x >= 0x140) && (x <= 0x1f0)) { - if (zoom_x_tables[zoom_x, zoom_x_table_offset] != 0) + 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) { - 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_line ^= 0xff; } - 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 (rows > 0x20) { - if (x >= 0x200) + zoom_line = zoom_line % ((zoom_y + 1) << 1); + if (zoom_line > zoom_y) { - if (sprite_gfx[gfx_offset] != 0) + 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 (zoom_x_tables[zoom_x_table_offset] != 0) { - Video.bitmapbaseN[iBitmap][pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + sprite_gfx[gfx_offset]]; + //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]]; + bitmapbase[pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + spriteGfx[gfx_offset]]; + } + pixel_addr_offsetx++; } - pixel_addr_offsetx++; + zoom_x_table_offset++; + gfx_offset += x_inc; } - x++; } - 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 (zoom_x_tables[zoom_x_table_offset] != 0) + { + if (x >= 0x200) + { + //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]]; + bitmapbase[pixel_addr_offsety * 384 + pixel_addr_offsetx] = pens[line_pens_offset + spriteGfx[gfx_offset]]; + } + pixel_addr_offsetx++; + } + x++; + } + zoom_x_table_offset++; + gfx_offset += x_inc; + } + x = x_save; + } } - x = x_save; } } } } + + //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; diff --git a/MAME.Unity/Assets/Plugins/UMAME/mame/pgm/Video.cs b/MAME.Unity/Assets/Plugins/UMAME/mame/pgm/Video.cs index 7dc926e..ba98608 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/mame/pgm/Video.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/mame/pgm/Video.cs @@ -199,47 +199,132 @@ namespace MAME.Core ycnt++; } } - private static void draw_sprites(int priority) + unsafe private static void draw_sprites(int priority) { - while (pgm_sprite_source_offset < 0x500) + fixed (ushort* pSpriteBuffer = &pgm_spritebufferram[0]) + fixed (byte* pVideoRegs = &pgm_videoregs[0]) { - 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) + ushort* spritePtr = pSpriteBuffer + pgm_sprite_source_offset; + int offset = 0; + + while (pgm_sprite_source_offset < 0x500) { - xzom = 0x10 - xzom; + // 读取数据 + 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; + } + if (ygrow != 0) + { + yzom = 0x10 - yzom; + } + 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) + 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); + + // 移动到下一个精灵 + spritePtr += 10; // 每个精灵占用5个ushort,即10个字节 + pgm_sprite_source_offset += 5; // 假设pgm_sprite_source_offset是以ushort为单位递增的 + + // 注意:这里我们直接通过指针移动,因此不需要再次访问数组来更新pgm_sprite_source_offset对应的值 } - if (ygrow != 0) - { - 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]); - 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 draw_sprites(int priority) + //{ + // while (pgm_sprite_source_offset < 0x500) + // { + // //用Span优化 + // Span 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 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; diff --git a/MAME.Unity/Assets/Plugins/UMAME/sound/OKI6295.cs b/MAME.Unity/Assets/Plugins/UMAME/sound/OKI6295.cs index 86667ff..2d3c02c 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/sound/OKI6295.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/sound/OKI6295.cs @@ -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) { diff --git a/MAME.Unity/Assets/Plugins/UMAME/sound/YM2151.cs b/MAME.Unity/Assets/Plugins/UMAME/sound/YM2151.cs index e43c318..1b40bb5 100644 --- a/MAME.Unity/Assets/Plugins/UMAME/sound/YM2151.cs +++ b/MAME.Unity/Assets/Plugins/UMAME/sound/YM2151.cs @@ -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) { - 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); - { - 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); + //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 = PSGoper[chan * 4]; /* M1 */ + //op.mem_connect = op.mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ + set_mem(PSGoper, chanout, imem, chan * 4); + if (PSGoper[chan * 4].ams != 0) + { + AM = PSG.lfa << (int)(PSGoper[chan * 4].ams - 1); + } - PSG.oper[chan * 4].fb_out_curr = 0; + env = volume_calc(PSGoper, (chan * 4), AM); + //env = volume_calc_planB(PSGoper[chan * 4], AM); + { + 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(chanout, PSGoper, chan * 4); + + PSGoper[chan * 4].fb_out_curr = 0; + if (env < 13 * 64) + { + if (PSGoper[chan * 4].fb_shift == 0) + { + iout = 0; + } + PSGoper[chan * 4].fb_out_curr = op_calc1(PSGoper, (chan * 4), env, (iout << (int)PSGoper[chan * 4].fb_shift)); + } + } + env = volume_calc(PSGoper, (chan * 4 + 1), AM); /* M2 */ + //env = volume_calc_planB(PSGoper[chan * 4 + 1], AM);/* M2 */ 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)); + //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(PSGoper, (chan * 4 + 2), AM); /* C1 */ + //env = volume_calc_planB(PSGoper[chan * 4 + 2], AM); /* C1 */ + if (env < 13 * 64) + { + //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(PSGoper, (chan * 4 + 3), AM); /* C2 */ + //env = volume_calc_planB(PSGoper[chan * 4 + 3], AM); /* C2 */ + if (env < 13 * 64) + { + chanout[chan] += op_calc(PSGoper, (chan * 4 + 3), env, chanout[10]);// c2); + } + /* M1 */ + PSGoper[chan * 4].mem_value = chanout[11];//mem; } - env = volume_calc((int)(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 */ - 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 */ - 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; + } - 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,66 +1625,297 @@ 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) { - int i; - int outl, outr; - for (i = 0; i < length; i++) + 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]) { - 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) + 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++) { - outl = 32767; + advance_eg(PSGoper); + 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(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; + } + else if (outl < -32768) + { + outl = -32768; + } + if (outr > 32767) + { + outr = 32767; + } + else if (outr < -32768) + { + outr = -32768; + } + streamoutput0[offset + i] = outl; + streamoutput1[offset + i] = outr; + advance(PSGoper, PSGfreq); } - 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 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;