Some video work
This commit is contained in:
parent
58473484a0
commit
0474de9605
|
@ -42,24 +42,11 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
public const int R_SYSTEM_CONTROL = 0x26;
|
||||
public const int R_IRQ_STATUS = 0x27;
|
||||
|
||||
/// <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>
|
||||
/// Y offset modifier used with Y_Scroll to determine the VRAM pointer
|
||||
/// </summary>
|
||||
public int Y_OFFSET => _regs[R_LCD_X_SIZE] > 0xC0 ? 0x30 : 0x60;
|
||||
|
||||
/// <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[0x2000];
|
||||
public byte[] Regs => _regs;
|
||||
|
@ -86,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
private int _seqCounter;
|
||||
private int _byteCounter;
|
||||
private int _lineCounter;
|
||||
private int _field;
|
||||
private bool _field;
|
||||
private ushort _vramByteBuffer;
|
||||
private int _vramPointer;
|
||||
private int _vramStartAddress;
|
||||
|
@ -134,13 +121,80 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
AudioClock(ticks);
|
||||
|
||||
// video
|
||||
for (int i = 0; i < lcdCycles; i++)
|
||||
{
|
||||
_byteCounter++;
|
||||
|
||||
if (_byteCounter * 4 <= (_regs[R_LCD_X_SIZE] & 0b1111_1100))
|
||||
{
|
||||
// still sending pixel data to the LCD
|
||||
// 4 pixles (bits) per byte read
|
||||
_vramPointer = (ushort) (_vramStartAddress + (_regs[R_X_SCROLL] >> 2) + _byteCounter - 1);
|
||||
//_vramPointer = (ushort)(_vramPointer + _byteCounter - 1);
|
||||
|
||||
// read a byte of data from VRAM
|
||||
byte data = _sv.ReadVRAM((ushort)_vramPointer);
|
||||
|
||||
// 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);
|
||||
|
||||
// structure the correct bits based on the current field
|
||||
byte lData = !_field
|
||||
? (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));
|
||||
|
||||
Screen.PixelClock(lData);
|
||||
}
|
||||
else if (_byteCounter * 4 > (_regs[R_LCD_X_SIZE] & 0b1111_1100))
|
||||
{
|
||||
// end of scanline
|
||||
_lineCounter++;
|
||||
_byteCounter = 0;
|
||||
|
||||
if (_lineCounter < _regs[R_LCD_Y_SIZE])
|
||||
{
|
||||
// still within the frame
|
||||
// pulse line latch
|
||||
Screen.LineLatch();
|
||||
|
||||
// vstart is updated every scanline
|
||||
// it is incremented based on the X_Size register
|
||||
int inc = _regs[R_LCD_X_SIZE] > 0xC3 ? 0x60 : 0x30;
|
||||
_vramStartAddress = (_vramStartAddress + inc) & 0x1FFFF;
|
||||
if (_vramStartAddress == 0x1FE0)
|
||||
_vramStartAddress = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// end of field
|
||||
_lineCounter = 0;
|
||||
// pulse the frame latch
|
||||
Screen.FrameLatch();
|
||||
// new field
|
||||
_field = !_field;
|
||||
Screen.FramePolarity = _field;
|
||||
|
||||
// setup memory pointer for beginning of field
|
||||
_vramStartAddress = (_regs[R_Y_SCROLL] * 0x30) & 0x1FFF;
|
||||
if (_vramStartAddress == 0x1FE0)
|
||||
{
|
||||
_vramStartAddress = 0;
|
||||
}
|
||||
|
||||
// setup for the next scanline
|
||||
_vramPointer = _vramStartAddress + (_regs[R_X_SCROLL] >> 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_sv.FrameClock += ticks;
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Runs a single clock cycle of the ASIC
|
||||
/// </summary>
|
||||
|
@ -256,7 +310,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
_sv.FrameClock++;
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Interrupt management
|
||||
|
|
|
@ -89,47 +89,50 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
// 9 - Power Control
|
||||
|
||||
/// <summary>
|
||||
/// It takes 6 cycles for each write to the LCD screen (so 1 pixelclock == 6 cpu cycles)
|
||||
/// Pulsed at the end of a field
|
||||
/// Clears the column and row shift registers
|
||||
/// </summary>
|
||||
public void PixelClock(byte data, int framePolarity = 0, bool lineLatch = false, bool frameLatch = false)
|
||||
{
|
||||
// Each scanline is composed of 246 clocks.
|
||||
// There are 40 pixel writes to the LCD, and 1 latch write, for a total of 41 writes.
|
||||
// Each write period lasts 6 clock cycles, so 41*6 = 246 cycles
|
||||
if (frameLatch)
|
||||
{
|
||||
// end of field
|
||||
// write last pixel
|
||||
if (DisplayEnable)
|
||||
WritePixels(data, framePolarity);
|
||||
public void FrameLatch() => ResetPosition();
|
||||
|
||||
// setup for next frame
|
||||
ResetPosition();
|
||||
}
|
||||
else if (lineLatch)
|
||||
{
|
||||
// end of scanline
|
||||
_hPos = 0;
|
||||
_vPos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DisplayEnable)
|
||||
WritePixels(data, framePolarity);
|
||||
}
|
||||
/// <summary>
|
||||
/// When pulsed, data from the column shift register latched into the current LCD glass column
|
||||
/// The row shift register is then clocked
|
||||
/// </summary>
|
||||
public void LineLatch()
|
||||
{
|
||||
_vPos++;
|
||||
_hPos = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This outputs 4 pixels at a time - we only use the first 4 bits of the data
|
||||
/// 2BPP, bit0 is written in the first field, bit1 in the second
|
||||
/// The frame polarity/bright control signal is toggled every field
|
||||
/// This inverts all the driver signals
|
||||
/// It also darkens the display a bit so you can get a true 2 bits per pixel
|
||||
/// The polarity toggling is done to prevent destruction of the LCD display glass via electrolytic plating action
|
||||
/// </summary>
|
||||
private void WritePixels(byte data, int framePolarity)
|
||||
public bool FramePolarity
|
||||
{
|
||||
get { return _framePolarity; }
|
||||
set { _framePolarity = value; }
|
||||
}
|
||||
private bool _framePolarity;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Bit offset when writing to the framebuffer
|
||||
/// </summary>
|
||||
private int _polarityOffset => FramePolarity ? 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// It takes 6 cycles for each write to the LCD screen (so 1 pixelclock == 6 cpu cycles)
|
||||
/// </summary>
|
||||
public void PixelClock(byte data)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (_hPos < PEN_BUFFER_WIDTH && _vPos < PEN_BUFFER_HEIGHT)
|
||||
{
|
||||
_penBuffer[(_vPos * 160 * 2) + (_hPos + framePolarity)] = (data >> i) & 0x01;
|
||||
_penBuffer[(_vPos * 160 * 2) + (_hPos + _polarityOffset)] = (data >> i) & 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -147,7 +150,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
VsyncDenominator = dom;
|
||||
}
|
||||
|
||||
public int VirtualWidth => (int)(BufferWidth * 1.25);
|
||||
public int VirtualWidth => BufferWidth;
|
||||
public int VirtualHeight => BufferHeight;
|
||||
public int BufferWidth => 160;
|
||||
public int BufferHeight => 160;
|
||||
|
@ -174,6 +177,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
ser.Sync(nameof(_hPos), ref _hPos);
|
||||
ser.Sync(nameof(_vPos), ref _vPos);
|
||||
ser.Sync(nameof(DisplayEnable), ref DisplayEnable);
|
||||
ser.Sync(nameof(FramePolarity), ref _framePolarity);
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue