More video, DMA and interrupt work

This commit is contained in:
Asnivor 2024-10-31 19:16:30 +00:00
parent 875a7d808c
commit e8a2093a74
8 changed files with 330 additions and 145 deletions

View File

@ -84,6 +84,8 @@ namespace BizHawk.Client.Common
["ChannelF"] = 234375.0 / 3872.0, // (NTSCCarrier * 8 / 7) / (256 * 264) ["ChannelF"] = 234375.0 / 3872.0, // (NTSCCarrier * 8 / 7) / (256 * 264)
// note: ChannelF II PAL timings might be slightly different... // note: ChannelF II PAL timings might be slightly different...
["ChannelF_PAL"] = 15625.0 / 312.0, // 4000000 / (256 * 312) ["ChannelF_PAL"] = 15625.0 / 312.0, // 4000000 / (256 * 312)
["SuperVision"] = 50.08012820512821
}; };
public static double GetFrameRate(string systemId, bool pal) public static double GetFrameRate(string systemId, bool pal)

View File

@ -34,7 +34,8 @@ namespace BizHawk.Emulation.Common
new(VSystemID.Raw.O2, "Odyssey2"), new(VSystemID.Raw.O2, "Odyssey2"),
new(VSystemID.Raw.VEC, "Vectrex"), new(VSystemID.Raw.VEC, "Vectrex"),
new(VSystemID.Raw.MSX, "MSX"), new(VSystemID.Raw.MSX, "MSX"),
new(VSystemID.Raw.NDS, "Nintendo DS") new(VSystemID.Raw.NDS, "Nintendo DS"),
new(VSystemID.Raw.SuperVision, "Watara SuperVision")
}; };
public SystemInfo this[string systemId] public SystemInfo this[string systemId]

View File

@ -1,63 +0,0 @@
namespace BizHawk.Emulation.Cores.Consoles.SuperVision
{
public partial class ASIC
{
/// <summary>
/// The inbuilt LCD screen
/// </summary>
private LCD _screen;
/// <summary>
/// The current field being drawn (0 or 1)
/// </summary>
private int _field;
/// <summary>
/// VRAM byte read every 6 CPU cycles
/// </summary>
private byte _latchedVRAM;
/// <summary>
/// The current VRAM pointer - latched every 6 cpu cycles
/// </summary>
private int _currentVRAMPointer;
private int _currY;
private int _currX;
private void SetupScreen(SuperVision.SuperVisionSyncSettings superVisionSyncSettings)
{
_screen = new LCD(superVisionSyncSettings.ScreenType);
}
private void VideoClock()
{
if (FrameStart)
{
// initial V start value (limit to 8k size)
_currentVRAMPointer = (_regs[R_Y_SCROLL] * 0x30) * 0x1FFF;
}
else
{
_currentVRAMPointer++;
if (_currentVRAMPointer == 0x1FE0)
{
// wrap around
_currentVRAMPointer = 0;
}
}
if (_sv.FrameClock % 6 == 0)
{
// address lines are updated with a new VRAM address
_latchedVRAM = _sv.VRAM[_currentVRAMPointer];
}
}
}
}

View File

@ -41,37 +41,141 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
public const int R_SYSTEM_CONTROL = 0x26; public const int R_SYSTEM_CONTROL = 0x26;
public const int R_IRQ_STATUS = 0x27; public const int R_IRQ_STATUS = 0x27;
private SuperVision _sv; /// <summary>
/// Scanline length in cpu clocks
/// </summary>
public int CLOCK_WIDTH =>
((_regs[R_LCD_X_SIZE] & 0xFC) // topmost 6 bits of the X Size register
+ 4) // line latch pulse
* 6; // 6 clocks per pixel
/// <summary>
/// Number of scanlines in a field
/// </summary>
public int LINE_HEIGHT => _regs[R_LCD_Y_SIZE];
private SuperVision _sv;
private byte[] _regs = new byte[0x30]; private byte[] _regs = new byte[0x30];
/// <summary>
/// The inbuilt LCD screen
/// </summary>
public LCD Screen;
public ASIC(SuperVision sv, SuperVision.SuperVisionSyncSettings ss) public ASIC(SuperVision sv, SuperVision.SuperVisionSyncSettings ss)
{ {
_sv = sv; _sv = sv;
_screen = new LCD(ss.ScreenType); Screen = new LCD(ss.ScreenType);
} }
public bool FrameStart; public bool FrameStart;
private int _intTimer; private int _intTimer;
private bool _intTimerEnabled;
private bool _intTimerChanged;
private int _nmiTimer; private int _nmiTimer;
private bool _intFlag; private bool _intFlag;
private bool _dmaInProgress; private bool _dmaInProgress;
private int _dmaCounter; private int _dmaCounter;
private int _seqCounter;
private int _byteCounter;
private int _lineCounter;
private int _field;
private ushort _vramByteBuffer;
/// <summary> /// <summary>
/// ASIC is clocked at the same rate as the CPU /// ASIC is clocked at the same rate as the CPU
/// </summary> /// </summary>
public void Clock() public void Clock()
{ {
CheckInterrupt(); // According to the information presented in https://github.com/GrenderG/supervision_reveng_notes/blob/master/Supervision_Tech.txt
// it can be surmised that the ASIC rigidly sticks to a 6-phase sequencer, which is as follows:
// 0: CPU RDY line true / PixelCLK to LCD / Output 1/2 byte to LCD
// 1: DMA byte transfer to VRAM (if DMA is active) / CPU RDY line false (if DMA is active)
// 2: DMA byte transfer to VRAM (if DMA is active) / CPU RDY line false (if DMA is active)
// 3: DMA byte transfer to VRAM (if DMA is active) / CPU RDY line false (if DMA is active)
// 4: DMA byte transfer to VRAM (if DMA is active) / CPU RDY line false (if DMA is active)
// 5: DMA byte transfer to VRAM (if DMA is active) / CPU RDY line false (if DMA is active)
CheckDMA(); CheckDMA();
VideoClock();
// so DMA can transfer 5 bytes to VRAM every 6 clocks, the 6th clock being the 1/2 byte transfer to the LCD
switch (_seqCounter)
{
case 0:
// there is no DMA on this cycle so CPU can run freely
_sv._cpu.RDY = true;
// ASIC reads a byte from VRAM
byte data = 0xff; //todo
// shift the last read byte in the buffer and add the new byte to the start
_vramByteBuffer = (ushort) ((_vramByteBuffer << 8) | data);
// get the correct byte data based on the X Scroll register lower 2 bits
// this simulates a delay in the bits sent to the LCD
byte b = (byte) ((_vramByteBuffer >> (_regs[R_X_SCROLL] & 0b0000_0011)) & 0xff);
// depending on the field, a 4 bit sequence is sent to the LCD
// Field0: bits 0-2-4-6
// Field1: bits 1-3-5-7
byte lData = _field == 0
? (byte) ((b & 0b0000_0001) | ((b & 0b0000_0100) >> 1) | ((b & 0b0001_0000) >> 2) | ((b & 0b0100_0000) >> 3))
: (byte) ((b & 0b0000_0010) >> 1 | ((b & 0b0000_1000) >> 2) | ((b & 0b0010_0000) >> 3) | ((b & 0b1000_0000) >> 4));
bool lineEnd = _byteCounter == CLOCK_WIDTH - 1;
bool frameEnd = _lineCounter == LINE_HEIGHT && lineEnd && _field == 1;
// send 1/2 byte to the LCD
Screen.PixelClock(lData, _field, lineEnd, frameEnd);
_byteCounter++;
if (_byteCounter == CLOCK_WIDTH)
{
// end of scanline
_byteCounter = 0;
_lineCounter++;
if (_lineCounter == LINE_HEIGHT)
{
// end of field
_lineCounter = 0;
_field++;
if (_field == 2)
_field = 0; // wraparound
}
}
break;
default:
if (_dmaInProgress)
{
// perform DMA transfer
DoDMA();
_sv._cpu.RDY = !_dmaInProgress;
}
break;
}
_seqCounter++;
if (_seqCounter == 7)
_seqCounter = 0; // wraparound
CheckInterrupt();
AudioClock(); AudioClock();
if (FrameStart) if (FrameStart)
FrameStart = false; FrameStart = false;
_sv.FrameClock++;
} }
/// <summary>
/// The current prescaler value for the IRQ timer
/// </summary>
private int IntPrescaler => _regs[R_SYSTEM_CONTROL].Bit(4) ? 16384 : 256; private int IntPrescaler => _regs[R_SYSTEM_CONTROL].Bit(4) ? 16384 : 256;
/// <summary> /// <summary>
@ -88,16 +192,63 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_sv._cpu.NMI = true; _sv._cpu.NMI = true;
} }
_intTimer--; if (_intTimerChanged)
if (_intTimer <= 0)
{ {
// IRQ timer register has just been modified
_intTimerChanged = false;
_intTimerEnabled = true;
// prescaler reset
_intTimer = 0;
if (_regs[R_IRQ_TIMER] == 0)
{
if (_regs[R_SYSTEM_CONTROL].Bit(1))
{
// instant IRQ
_intFlag = true;
_intTimerEnabled = false;
// set IRQ Timer expired bit
_regs[R_IRQ_STATUS] = (byte) (_regs[R_IRQ_STATUS] | 2);
}
}
}
else if (_regs[R_IRQ_TIMER] > 0)
{
// timer will be counting down clocked by the prescaler
if (_intTimer++ == IntPrescaler)
{
// prescaler clock
_intTimer = 0;
// decrement timer
_regs[R_IRQ_TIMER]--;
}
}
else
{
// timer has expired
if (_intTimerEnabled)
{
_intFlag = true;
_intTimerEnabled = false;
// set IRQ Timer expired bit
_regs[R_IRQ_STATUS] = (byte) (_regs[R_IRQ_STATUS] | 2);
}
}
if (_intFlag && _regs[R_SYSTEM_CONTROL].Bit(1))
{
// IRQ enabled
_sv._cpu.IRQ = true;
_intFlag = false;
} }
} }
/// <summary> /// <summary>
/// DMA Control /// Check whether DMA needs to start
/// </summary> /// </summary>
private void CheckDMA() private void CheckDMA()
{ {
@ -105,22 +256,46 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
{ {
// DMA start requested // DMA start requested
_dmaInProgress = true; _dmaInProgress = true;
// Unset the DMA start bit
_regs[R_DMA_CONTROL] = (byte) (_regs[R_DMA_CONTROL] & ~(1 << 7));
}
} }
/// <summary>
/// Perform a DMA transfer
/// </summary>
private void DoDMA()
{
if (_dmaInProgress) if (_dmaInProgress)
{
_dmaCounter++;
if (_dmaCounter == 4096 || _dmaCounter == _regs[R_DMA_LENGTH] * 16)
{
// wraparound or length reached
_dmaCounter = 0;
_dmaInProgress = false;
}
else
{ {
ushort source = (ushort) (_regs[R_DMA_SOURCE_HIGH] << 8 | _regs[R_DMA_SOURCE_LOW]); ushort source = (ushort) (_regs[R_DMA_SOURCE_HIGH] << 8 | _regs[R_DMA_SOURCE_LOW]);
ushort dest = (ushort) (_regs[R_DMA_DEST_HIGH] << 8 | _regs[R_DMA_DEST_LOW]); ushort dest = (ushort) (_regs[R_DMA_DEST_HIGH] << 8 | _regs[R_DMA_DEST_LOW]);
_dmaCounter++; // transfer a byte from source to dest using DMA
_sv.WriteMemory(dest, _sv.ReadMemory(source));
if (_dmaCounter == 4096) // source registers incremented
{ source++;
// wrap around _regs[R_DMA_SOURCE_HIGH] = (byte) (source >> 8);
_dmaCounter = 0; _regs[R_DMA_SOURCE_LOW] = (byte) source;
// destination registers incremeneted
dest++;
_regs[R_DMA_DEST_HIGH] = (byte) (dest >> 8);
_regs[R_DMA_DEST_LOW] = (byte) dest;
} }
} }
} }
/// <summary> /// <summary>
@ -135,45 +310,83 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
// LCD_X_Size // LCD_X_Size
case 0x00: case 0x00:
case 0x04: case 0x04:
// Only the upper 6 bits of LCD_X_Size are usable. The lower 2 bits are ignored.
// the LCD size can only be changed in 4 pixel increments
_regs[R_LCD_X_SIZE] = value;
break; break;
// LCD_Y_Size // LCD_Y_Size
case 0x01: case 0x01:
case 0x05: case 0x05:
// LCD_Y_Size controls how many scanlines are shown in the field
// After the requisite number of scanlines, the LCD frame latch signal is output and the frame polarity line is toggled
_regs[R_LCD_Y_SIZE] = value;
break; break;
// X_Scroll // X_Scroll
case 0x02: case 0x02:
case 0x06: case 0x06:
_regs[R_X_SCROLL] = value;
break; break;
// Y_Scroll // Y_Scroll
case 0x03: case 0x03:
case 0x07: case 0x07:
_regs[R_Y_SCROLL] = value;
break; break;
// DMA Source low // DMA Source low
case 0x08: case 0x08:
_regs[R_DMA_SOURCE_LOW] = value;
break; break;
// DMA Source high // DMA Source high
case 0x09: case 0x09:
_regs[R_DMA_SOURCE_HIGH] = value;
break; break;
// DMA Destination low // DMA Destination low
case 0x0A: case 0x0A:
_regs[R_DMA_DEST_LOW] = value;
break; break;
// DMA Destination high // DMA Destination high
case 0x0B: case 0x0B:
_regs[R_DMA_DEST_HIGH] = value;
break; break;
// DMA Length // DMA Length
case 0x0C: case 0x0C:
// 8bit register
// This register selects how many bytes of data to move. The actual number of bytes to move is (L * 16).
// If the register is loaded with 0, a full 4096 bytes is moved.
_regs[R_DMA_LENGTH] = value;
break; break;
// DMA Control // DMA Control
case 0x0D: case 0x0D:
// Start DMA when written with bit7 set
_regs[R_DMA_CONTROL] = value;
break; break;
// CH1_Flow (right only) // CH1_Flow (right only)
@ -244,9 +457,12 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
// This timer is clocked by a prescaler, which is reset when the timer is written to. // This timer is clocked by a prescaler, which is reset when the timer is written to.
// This prescaler can divide the system clock by 256 or 16384. // This prescaler can divide the system clock by 256 or 16384.
// 8bits // 8bits
_regs[R_IRQ_TIMER] = value;
_intTimerEnabled = true;
// reset prescaler? // reset prescaler?
_regs[R_SYSTEM_CONTROL] = (byte)(_regs[R_SYSTEM_CONTROL] & ~(1 << 4)); // Reset bit 4 //_regs[R_SYSTEM_CONTROL] = (byte)(_regs[R_SYSTEM_CONTROL] & ~(1 << 4)); // Reset bit 4
_intTimer = value * IntPrescaler; _intTimer = value * IntPrescaler;
@ -274,20 +490,16 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_regs[regIndex] = value; _regs[regIndex] = value;
// lcd displayenable // lcd displayenable
_screen.DisplayEnable = value.Bit(3); Screen.DisplayEnable = value.Bit(3);
// banking // banking
_sv.BankSelect = value >> 5; _sv.BankSelect = value >> 5;
// writing to this register resets the LCD rendering system and makes it start rendering from the upper left corner, regardless of the bit pattern. // writing to this register resets the LCD rendering system and makes it start rendering from the upper left corner, regardless of the bit pattern.
_screen.ResetPosition(); Screen.ResetPosition();
break; break;
// IRQ status
case 0x27:
break;
// CH4_Freq_Vol (left and right) // CH4_Freq_Vol (left and right)
case 0x28: case 0x28:
case 0x2C: case 0x2C:
@ -306,6 +518,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
// READONLY // READONLY
case 0x20: // Controller case 0x20: // Controller
case 0x27: // IRQ status
break; break;
// UNKNOWN // UNKNOWN
@ -440,6 +653,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
// IRQ timer // IRQ timer
case 0x23: case 0x23:
result = _regs[R_IRQ_TIMER];
break; break;
// Reset IRQ timer flag // Reset IRQ timer flag
@ -457,6 +671,11 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
// IRQ status // IRQ status
case 0x27: case 0x27:
// bit0: DMA Audio System (1 == DMA audio finished)
// bit1: IRQ Timer expired (1 == expired)
result = _regs[regIndex];
break; break;
// CH4_Freq_Vol (left and right) // CH4_Freq_Vol (left and right)
@ -500,18 +719,18 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
ser.Sync(nameof(_regs), ref _regs, false); ser.Sync(nameof(_regs), ref _regs, false);
ser.Sync(nameof(FrameStart), ref FrameStart); ser.Sync(nameof(FrameStart), ref FrameStart);
ser.Sync(nameof(_intTimer), ref _intTimer); ser.Sync(nameof(_intTimer), ref _intTimer);
ser.Sync(nameof(_intTimerEnabled), ref _intTimerEnabled);
ser.Sync(nameof(_intTimerChanged), ref _intTimerChanged);
ser.Sync(nameof(_nmiTimer), ref _nmiTimer); ser.Sync(nameof(_nmiTimer), ref _nmiTimer);
ser.Sync(nameof(_intFlag), ref _intFlag); ser.Sync(nameof(_intFlag), ref _intFlag);
ser.Sync(nameof(_dmaInProgress), ref _dmaInProgress); ser.Sync(nameof(_dmaInProgress), ref _dmaInProgress);
ser.Sync(nameof(_dmaCounter), ref _dmaCounter); ser.Sync(nameof(_dmaCounter), ref _dmaCounter);
ser.Sync(nameof(_seqCounter), ref _seqCounter);
ser.Sync(nameof(_byteCounter), ref _byteCounter);
ser.Sync(nameof(_lineCounter), ref _lineCounter);
ser.Sync(nameof(_field), ref _field); ser.Sync(nameof(_field), ref _field);
ser.Sync(nameof(_latchedVRAM), ref _latchedVRAM); ser.Sync(nameof(_vramByteBuffer), ref _vramByteBuffer);
ser.Sync(nameof(_currentVRAMPointer), ref _currentVRAMPointer); Screen.SyncState(ser);
ser.Sync(nameof(_currY), ref _currY);
ser.Sync(nameof(_currX), ref _currX);
_screen.SyncState(ser);
ser.EndSection(); ser.EndSection();
} }

View File

@ -27,10 +27,13 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
private readonly int[] _palette = new int[4]; private readonly int[] _palette = new int[4];
public const int PEN_BUFFER_WIDTH = 160 * 2;
public const int PEN_BUFFER_HEIGHT = 160;
/// <summary> /// <summary>
/// The inbuilt screen is a 160*160 dot 2bpp monochrome LCD /// The inbuilt screen is a 160*160 dot 2bpp monochrome LCD
/// </summary> /// </summary>
private int[] _penBuffer = new int[160 * 160 * 2]; private int[] _penBuffer = new int[PEN_BUFFER_WIDTH * PEN_BUFFER_HEIGHT];
/// <summary> /// <summary>
/// The output framebuffer /// The output framebuffer
@ -90,13 +93,11 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
WritePixels(data, framePolarity); WritePixels(data, framePolarity);
// setup for next frame // setup for next frame
_vPos = 0; ResetPosition();
_hPos = 0;
} }
else if (lineLatch) else if (lineLatch)
{ {
// end of scanline // end of scanline
//
_hPos = 0; _hPos = 0;
_vPos++; _vPos++;
} }
@ -115,13 +116,27 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
_frameBuffer[(_vPos * 160 * 2) + (_hPos + framePolarity)] = (data >> i) & 0x01; if (_hPos < PEN_BUFFER_WIDTH && _vPos < PEN_BUFFER_HEIGHT)
{
_penBuffer[(_vPos * 160 * 2) + (_hPos + framePolarity)] = (data >> i) & 0x01;
}
else
{
// bits out of bounds of the LCD screen
// data is discarded
}
_hPos += 2; _hPos += 2;
} }
} }
public void SetRates(int num, int dom)
{
VsyncNumerator = num;
VsyncDenominator = dom;
}
public int VirtualWidth => BufferWidth; public int VirtualWidth => (int)(BufferWidth * 1.25);
public int VirtualHeight => BufferHeight; public int VirtualHeight => BufferHeight;
public int BufferWidth => 160; public int BufferWidth => 160;
public int BufferHeight => 160; public int BufferHeight => 160;
@ -144,6 +159,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
{ {
ser.BeginSection("LCD"); ser.BeginSection("LCD");
ser.Sync(nameof(_frameBuffer), ref _frameBuffer, false); ser.Sync(nameof(_frameBuffer), ref _frameBuffer, false);
ser.Sync(nameof(_penBuffer), ref _penBuffer, false);
ser.Sync(nameof(_hPos), ref _hPos); ser.Sync(nameof(_hPos), ref _hPos);
ser.Sync(nameof(_vPos), ref _vPos); ser.Sync(nameof(_vPos), ref _vPos);
ser.Sync(nameof(DisplayEnable), ref DisplayEnable); ser.Sync(nameof(DisplayEnable), ref DisplayEnable);

View File

@ -13,8 +13,6 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
/// </summary> /// </summary>
public byte[] VRAM = new byte[0x2000]; public byte[] VRAM = new byte[0x2000];
/// <summary> /// <summary>
/// Bank select index /// Bank select index
/// </summary> /// </summary>
@ -30,53 +28,54 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_cpuMemoryAccess = true; _cpuMemoryAccess = true;
byte result = 0xFF; byte result = 0xFF;
if (address < 0x2000) var divider = address / 0x2000;
{
// RAM
return WRAM[address];
}
if (address < 0x4000) switch (divider)
{ {
// port access case 0:
return ReadHardware(address); // WRAM
} result = WRAM[address];
break;
if (address < 0x6000) case 1:
{ // IO address space
break;
case 2:
// VRAM // VRAM
return VRAM[address - 0x4000]; result = VRAM[address - 0x4000];
} break;
if (address < 0x8000) case 3:
{
// nothing here // nothing here
} break;
if (address < 0xC000) case 4:
{
// cartridge rom banking // cartridge rom banking
// 0x8000 - 0xBFFF is selectable using the 3 bits from the SystemControl register // 0x8000 - 0xBFFF is selectable using the 3 bits from the SystemControl register
switch (BankSelect) switch (BankSelect)
{ {
// first 16k // first 16k
case 0: case 0:
return _cartridge.ReadByte((ushort)(address % 0x2000)); result = _cartridge.ReadByte((ushort) (address % 0x2000));
break;
// second 16k // second 16k
case 1: case 1:
return _cartridge.ReadByte((ushort)((address % 0x2000) + 0x2000)); result = _cartridge.ReadByte((ushort) ((address % 0x2000) + 0x2000));
break;
// third 16k // third 16k
case 2: case 2:
return _cartridge.ReadByte((ushort)((address % 0x2000) + 0x4000)); result = _cartridge.ReadByte((ushort) ((address % 0x2000) + 0x4000));
} break;
} }
break;
if (address < 0xFFFF) case 5:
{
// fixed to the last 16K in the cart address space // fixed to the last 16K in the cart address space
return _cartridge.ReadByte((ushort)((address % 0x2000) + 0x6000)); result = _cartridge.ReadByte(address);
break;
} }
return result; return result;

View File

@ -18,7 +18,11 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
private int _frameClock; private int _frameClock;
private int _frame; private int _frame;
public int FrameClock => _frameClock; public int FrameClock
{
get => _frameClock;
set => _frameClock = value;
}
public int Frame => _frame; public int Frame => _frame;
private void CalcClock() private void CalcClock()
@ -31,6 +35,10 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
2; // fields per frame 2; // fields per frame
double refreshRate = _cpuClocksPerSecond / _cpuClocksPerFrame; // 50.8130081300813 double refreshRate = _cpuClocksPerSecond / _cpuClocksPerFrame; // 50.8130081300813
_asic.Screen.SetRates(
(int) _cpuClocksPerSecond,
(int) _cpuClocksPerFrame);
} }
public bool FrameAdvance(IController controller, bool render, bool renderSound) public bool FrameAdvance(IController controller, bool render, bool renderSound)

View File

@ -28,6 +28,9 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_tracer = new TraceBuffer(_cpu.TraceHeader); _tracer = new TraceBuffer(_cpu.TraceHeader);
_asic = new ASIC(this, _syncSettings); _asic = new ASIC(this, _syncSettings);
CalcClock();
ser.Register<IVideoProvider>(_asic.Screen);
ser.Register<ITraceable>(_tracer); ser.Register<ITraceable>(_tracer);
ser.Register<IDisassemblable>(_cpu); ser.Register<IDisassemblable>(_cpu);
ser.Register<IStatable>(new StateSerializer(SyncState)); ser.Register<IStatable>(new StateSerializer(SyncState));