[CPCHawk] New CRTC1 impl.
This commit is contained in:
parent
aac3da9e0d
commit
95cf257d96
|
@ -15,12 +15,13 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
/// </summary>
|
||||
public override int CrtcType => 0;
|
||||
|
||||
/// <summary>
|
||||
/// CRTC is clocked at 1MHz (16 GA cycles)
|
||||
/// </summary>
|
||||
public override void Clock() => throw new InvalidOperationException("CRTC Type 0 not implemented yet");
|
||||
|
||||
|
||||
/*
|
||||
public override void Clock()
|
||||
{
|
||||
base.Clock();
|
||||
CheckReset();
|
||||
|
||||
int maxScanLine;
|
||||
|
||||
|
@ -130,7 +131,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
hhclock = true;
|
||||
}
|
||||
|
||||
/* Hor active video */
|
||||
if (HCC == 0)
|
||||
{
|
||||
// active display
|
||||
|
@ -143,7 +143,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
latch_hdisp = false;
|
||||
}
|
||||
|
||||
/* Hor sync */
|
||||
if (hssstart || // start of horizontal sync
|
||||
HSYNC) // already in horizontal sync
|
||||
{
|
||||
|
@ -163,7 +162,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
HSYNC = false;
|
||||
}
|
||||
|
||||
/* Ver active video */
|
||||
if (VCC == 0)
|
||||
{
|
||||
// active display
|
||||
|
@ -203,7 +201,6 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
}
|
||||
|
||||
|
||||
/* Address Generation */
|
||||
int line = VLC;
|
||||
|
||||
if (R8_Interlace == 3)
|
||||
|
@ -222,7 +219,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
_RA = VLC;
|
||||
}
|
||||
|
||||
_LA = _vma;
|
||||
ma = _vma;
|
||||
|
||||
// DISPTMG Generation
|
||||
if (!latch_hdisp || !latch_vdisp)
|
||||
|
@ -238,7 +235,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
DISPTMG = true;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// R3l: CRTC-type horizontal sync width independent helper function
|
||||
|
|
|
@ -14,13 +14,277 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
/// </summary>
|
||||
public override int CrtcType => 1;
|
||||
|
||||
private int cnt;
|
||||
|
||||
/// <summary>
|
||||
/// CRTC is clocked at 1MHz (16 GA cycles)
|
||||
/// </summary>
|
||||
public override void Clock()
|
||||
{
|
||||
CheckReset();
|
||||
cnt++;
|
||||
|
||||
// linear address generator clocked
|
||||
ma = (ma + 1) & 0x3FFF;
|
||||
|
||||
// horizontal character counter clocked
|
||||
HCC++;
|
||||
|
||||
if (HCC == R0_HorizontalTotal + 1) // C0 == R0
|
||||
{
|
||||
// new scanline
|
||||
// increment raster counter
|
||||
VLC++;
|
||||
|
||||
if (VLC == R9_MaxScanline + 1) // C9 == R9
|
||||
{
|
||||
// new character row
|
||||
// vertical character counter reset
|
||||
VLC = 0;
|
||||
|
||||
// incremement vertical character counter
|
||||
VCC++;
|
||||
|
||||
if (VCC == R6_VerticalDisplayed) // C4 == R6
|
||||
{
|
||||
// vertical display is disabled
|
||||
latch_vdisp = false;
|
||||
}
|
||||
|
||||
if (VCC == R4_VerticalTotal + 1) // C4 == R4
|
||||
{
|
||||
// new CRTC frame
|
||||
// vertical character counter reset
|
||||
VCC = 0;
|
||||
|
||||
// vertical display enabled
|
||||
latch_vdisp = true;
|
||||
|
||||
// cached VMA loaded with register start address
|
||||
ma_store = (Register[R12_START_ADDR_H] << 8) | Register[R13_START_ADDR_L];
|
||||
}
|
||||
|
||||
if (VCC == R7_VerticalSyncPosition) // C4 == R7
|
||||
{
|
||||
// VSYNC enabled
|
||||
VSYNC = true;
|
||||
|
||||
// reset vertical sync counter
|
||||
VSC = 0;
|
||||
}
|
||||
|
||||
ma_row_start = ma_store;
|
||||
}
|
||||
|
||||
if (VSYNC)
|
||||
{
|
||||
// increment vertical sync counter
|
||||
VSC++;
|
||||
|
||||
if (VSC == R3_VerticalSyncWidth // C3h == R3h
|
||||
|| VSC == 0) // VSC counter wrap-around
|
||||
{
|
||||
// VSYNC disabled
|
||||
VSYNC = false;
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// H display is enabled
|
||||
latch_hdisp = true;
|
||||
|
||||
// horizontal character counter reset
|
||||
HCC = 0;
|
||||
|
||||
// VMA updated with row start address
|
||||
ma = ma_row_start;
|
||||
}
|
||||
|
||||
if (HCC == R1_HorizontalDisplayed) // CO == R1
|
||||
{
|
||||
// H display is disabled
|
||||
latch_hdisp = false;
|
||||
|
||||
// current VMA is copied into memory
|
||||
ma_store = ma;
|
||||
}
|
||||
|
||||
if (HCC == R2_HorizontalSyncPosition) // C0 == R2
|
||||
{
|
||||
// HSYNC is enabled
|
||||
HSYNC = true;
|
||||
|
||||
// reset horizontal sync counter
|
||||
HSC = 0;
|
||||
}
|
||||
|
||||
if (HSYNC)
|
||||
{
|
||||
// HSYNC still enabled - increment counter
|
||||
HSC++;
|
||||
|
||||
if (HSC == R3_HorizontalSyncWidth // C3l == R3l
|
||||
|| HSC == 0) // HSC counter wrap-around
|
||||
{
|
||||
// disable HSYNC
|
||||
HSYNC = false;
|
||||
}
|
||||
}
|
||||
|
||||
// outputs
|
||||
if (!latch_hdisp || !latch_vdisp)
|
||||
{
|
||||
// HSYNC output pin is fed through a NOR gate with either 2 or 3 inputs
|
||||
// - H Display
|
||||
// - V Display
|
||||
DISPTMG = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DISPTMG = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clock2()
|
||||
{
|
||||
base.Clock();
|
||||
|
||||
ma = (ma + 1) & 0x3FFF;
|
||||
HCC++;
|
||||
|
||||
// C0 == R0
|
||||
if (HCC == R0_HorizontalTotal + 1)
|
||||
{
|
||||
// new scanline
|
||||
HCC = 0;
|
||||
|
||||
// C9 == R9
|
||||
if (++VLC == R9_MaxScanline + 1 || latch_vadjust)
|
||||
{
|
||||
VLC = 0;
|
||||
|
||||
// C4 == R4
|
||||
if (++VCC == R4_VerticalTotal + 1)
|
||||
{
|
||||
latch_vadjust = true;
|
||||
|
||||
_vmaRowStart = (Register[R12_START_ADDR_H] << 8) | Register[R13_START_ADDR_L];
|
||||
|
||||
// C5 == R5
|
||||
if (VTAC == R5_VerticalTotalAdjust)
|
||||
{
|
||||
latch_vadjust = false;
|
||||
VCC = 0;
|
||||
VTAC = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
VTAC++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// MA set to row start at the beginning of each line
|
||||
_vmaRowStart += R1_HorizontalDisplayed;
|
||||
}
|
||||
|
||||
// C4 == 0
|
||||
if (VCC == 0)
|
||||
{
|
||||
latch_vdisp = true;
|
||||
}
|
||||
|
||||
if (VCC == R6_VerticalDisplayed)
|
||||
{
|
||||
latch_vdisp = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!latch_vadjust)
|
||||
{
|
||||
// C4 == R7
|
||||
if (VCC == R7_VerticalSyncPosition && VLC == 0)
|
||||
{
|
||||
VSYNC = true;
|
||||
VSC = 0;
|
||||
}
|
||||
|
||||
if (VSYNC)
|
||||
{
|
||||
VSC++;
|
||||
|
||||
// C3h == R3h
|
||||
if (VSC == R3_VerticalSyncWidth || VSC == 0)
|
||||
{
|
||||
VSYNC = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (HCC == 0)
|
||||
{
|
||||
ma = _vmaRowStart;
|
||||
}
|
||||
|
||||
// C0 == R2
|
||||
if (HCC == R2_HorizontalSyncPosition)
|
||||
{
|
||||
HSYNC = true;
|
||||
HSC = 0;
|
||||
}
|
||||
if (HSYNC)
|
||||
{
|
||||
if (R3_HorizontalSyncWidth > 0)
|
||||
{
|
||||
HSC++;
|
||||
}
|
||||
|
||||
// C3l == R3l
|
||||
if (HSC == R3_HorizontalSyncWidth)
|
||||
{
|
||||
HSYNC = false;
|
||||
}
|
||||
}
|
||||
|
||||
int dSkew = R8_Skew_CUDISP > 2 ? -1 : R8_Skew_CUDISP;
|
||||
|
||||
// C0 == 0
|
||||
if (dSkew >= 0 && HCC == dSkew)
|
||||
{
|
||||
latch_hdisp = true;
|
||||
}
|
||||
|
||||
// C0 == R1
|
||||
if (dSkew >= 0 && HCC == R1_HorizontalDisplayed + dSkew)
|
||||
{
|
||||
latch_hdisp = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// outputs
|
||||
if (!latch_hdisp || !latch_vdisp)
|
||||
{
|
||||
// HSYNC output pin is fed through a NOR gate with either 2 or 3 inputs
|
||||
// - H Display
|
||||
// - V Display
|
||||
DISPTMG = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DISPTMG = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Clocko()
|
||||
{
|
||||
CheckReset();
|
||||
|
||||
int maxScanLine;
|
||||
|
||||
if (HCC == R0_HorizontalTotal)
|
||||
|
@ -227,7 +491,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
_RA = VLC;
|
||||
}
|
||||
|
||||
_LA = _vma;
|
||||
ma = _vma;
|
||||
|
||||
// DISPTMG Generation
|
||||
if (!latch_hdisp || !latch_vdisp)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -16,231 +15,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
/// </summary>
|
||||
public override int CrtcType => 2;
|
||||
|
||||
/// <summary>
|
||||
/// CRTC is clocked at 1MHz (16 GA cycles)
|
||||
/// </summary>
|
||||
public override void Clock()
|
||||
{
|
||||
base.Clock();
|
||||
|
||||
int maxScanLine;
|
||||
|
||||
if (HCC == R0_HorizontalTotal)
|
||||
{
|
||||
// end of displayable area reached
|
||||
// set up for the next line
|
||||
HCC = 0;
|
||||
|
||||
// TODO: handle interlace setup
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// in interlace sync and video mask off bit 0 of the max scanline address
|
||||
maxScanLine = R9_MaxScanline & 0b11110;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxScanLine = R9_MaxScanline;
|
||||
}
|
||||
|
||||
if (VLC == maxScanLine)
|
||||
{
|
||||
// we have reached the final scanline within this vertical character row
|
||||
// move to next character
|
||||
VLC = 0;
|
||||
|
||||
// TODO: implement vertical adjust
|
||||
|
||||
|
||||
if (VCC == R4_VerticalTotal)
|
||||
{
|
||||
// check the interlace mode
|
||||
if (R8_Interlace.Bit(0))
|
||||
{
|
||||
// toggle the field
|
||||
_field = !_field;
|
||||
}
|
||||
else
|
||||
{
|
||||
// stay on the even field
|
||||
_field = false;
|
||||
}
|
||||
|
||||
// we have reached the end of the vertical display area
|
||||
// address loaded from start address register at the top of each field
|
||||
_vmaRowStart = (Register[R12_START_ADDR_H] << 8) | Register[R13_START_ADDR_L];
|
||||
|
||||
// reset the vertical character counter
|
||||
VCC = 0;
|
||||
|
||||
// increment field counter
|
||||
CFC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// row start address is increased by Horiztonal Displayed
|
||||
_vmaRowStart += R1_HorizontalDisplayed;
|
||||
|
||||
// increment vertical character counter
|
||||
VCC++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// next scanline
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// interlace sync+video mode
|
||||
// vertical line counter increments by 2
|
||||
VLC += 2;
|
||||
|
||||
// ensure vertical line counter is an even value
|
||||
VLC &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-interlace mode
|
||||
// increment vertical line counter
|
||||
VLC++;
|
||||
}
|
||||
}
|
||||
|
||||
// MA set to row start at the beginning of each line
|
||||
_vma = _vmaRowStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
// next horizontal character (1us)
|
||||
// increment horizontal character counter
|
||||
HCC++;
|
||||
|
||||
// increment VMA
|
||||
_vma++;
|
||||
}
|
||||
|
||||
hssstart = false;
|
||||
hhclock = false;
|
||||
|
||||
if (HCC == R2_HorizontalSyncPosition)
|
||||
{
|
||||
// start of horizontal sync
|
||||
hssstart = true;
|
||||
}
|
||||
|
||||
if (HCC == R2_HorizontalSyncPosition / 2)
|
||||
{
|
||||
// we are half way through the line
|
||||
hhclock = true;
|
||||
}
|
||||
|
||||
/* Hor active video */
|
||||
if (HCC == 0)
|
||||
{
|
||||
// active display
|
||||
latch_hdisp = true;
|
||||
}
|
||||
|
||||
if (HCC == R1_HorizontalDisplayed)
|
||||
{
|
||||
// inactive display
|
||||
latch_hdisp = false;
|
||||
}
|
||||
|
||||
/* Hor sync */
|
||||
if (hssstart || // start of horizontal sync
|
||||
HSYNC) // already in horizontal sync
|
||||
{
|
||||
// start of horizontal sync
|
||||
HSYNC = true;
|
||||
HSC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset hsync counter
|
||||
HSC = 0;
|
||||
}
|
||||
|
||||
if (HSC == R3_HorizontalSyncWidth)
|
||||
{
|
||||
// end of horizontal sync
|
||||
HSYNC = false;
|
||||
}
|
||||
|
||||
/* Ver active video */
|
||||
if (VCC == 0)
|
||||
{
|
||||
// active display
|
||||
latch_vdisp = true;
|
||||
}
|
||||
|
||||
if (VCC == R6_VerticalDisplayed)
|
||||
{
|
||||
// inactive display
|
||||
latch_vdisp = false;
|
||||
}
|
||||
|
||||
// vertical sync occurs at different times depending on the interlace field
|
||||
// even field: the same time as HSYNC
|
||||
// odd field: half a line later than HSYNC
|
||||
if ((!_field && hssstart) || (_field && hhclock))
|
||||
{
|
||||
if ((VCC == R7_VerticalSyncPosition && VLC == 0) // vsync starts on the first line
|
||||
|| VSYNC) // vsync is already in progress
|
||||
{
|
||||
// start of vertical sync
|
||||
VSYNC = true;
|
||||
// increment vertical sync counter
|
||||
VSC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset vsync counter
|
||||
VSC = 0;
|
||||
}
|
||||
|
||||
if (VSYNC && VSC == R3_VerticalSyncWidth - 1)
|
||||
{
|
||||
// end of vertical sync
|
||||
VSYNC = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Address Generation */
|
||||
int line = VLC;
|
||||
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// interlace sync+video mode
|
||||
// the least significant bit is based on the current field number
|
||||
int fNum = _field ? 1 : 0;
|
||||
int lNum = VLC.Bit(0) ? 1 : 0;
|
||||
line &= ~1;
|
||||
|
||||
_RA = line & (fNum | lNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// raster address is just the VLC
|
||||
_RA = VLC;
|
||||
}
|
||||
|
||||
_LA = _vma;
|
||||
|
||||
// DISPTMG Generation
|
||||
if (!latch_hdisp || !latch_vdisp)
|
||||
{
|
||||
// HSYNC output pin is fed through a NOR gate with either 2 or 3 inputs
|
||||
// - H Display
|
||||
// - V Display
|
||||
// - TODO: R8 DISPTMG Skew (only on certain CRTC types)
|
||||
DISPTMG = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DISPTMG = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clock() => throw new InvalidOperationException("CRTC Type 2 not implemented yet");
|
||||
|
||||
/// <summary>
|
||||
/// R3l: CRTC-type horizontal sync width independent helper function
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -14,231 +13,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
/// </summary>
|
||||
public override int CrtcType => 3;
|
||||
|
||||
/// <summary>
|
||||
/// CRTC is clocked at 1MHz (16 GA cycles)
|
||||
/// </summary>
|
||||
public override void Clock()
|
||||
{
|
||||
base.Clock();
|
||||
|
||||
int maxScanLine;
|
||||
|
||||
if (HCC == R0_HorizontalTotal)
|
||||
{
|
||||
// end of displayable area reached
|
||||
// set up for the next line
|
||||
HCC = 0;
|
||||
|
||||
// TODO: handle interlace setup
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// in interlace sync and video mask off bit 0 of the max scanline address
|
||||
maxScanLine = R9_MaxScanline & 0b11110;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxScanLine = R9_MaxScanline;
|
||||
}
|
||||
|
||||
if (VLC == maxScanLine)
|
||||
{
|
||||
// we have reached the final scanline within this vertical character row
|
||||
// move to next character
|
||||
VLC = 0;
|
||||
|
||||
// TODO: implement vertical adjust
|
||||
|
||||
|
||||
if (VCC == R4_VerticalTotal)
|
||||
{
|
||||
// check the interlace mode
|
||||
if (R8_Interlace.Bit(0))
|
||||
{
|
||||
// toggle the field
|
||||
_field = !_field;
|
||||
}
|
||||
else
|
||||
{
|
||||
// stay on the even field
|
||||
_field = false;
|
||||
}
|
||||
|
||||
// we have reached the end of the vertical display area
|
||||
// address loaded from start address register at the top of each field
|
||||
_vmaRowStart = (Register[R12_START_ADDR_H] << 8) | Register[R13_START_ADDR_L];
|
||||
|
||||
// reset the vertical character counter
|
||||
VCC = 0;
|
||||
|
||||
// increment field counter
|
||||
CFC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// row start address is increased by Horiztonal Displayed
|
||||
_vmaRowStart += R1_HorizontalDisplayed;
|
||||
|
||||
// increment vertical character counter
|
||||
VCC++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// next scanline
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// interlace sync+video mode
|
||||
// vertical line counter increments by 2
|
||||
VLC += 2;
|
||||
|
||||
// ensure vertical line counter is an even value
|
||||
VLC &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-interlace mode
|
||||
// increment vertical line counter
|
||||
VLC++;
|
||||
}
|
||||
}
|
||||
|
||||
// MA set to row start at the beginning of each line
|
||||
_vma = _vmaRowStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
// next horizontal character (1us)
|
||||
// increment horizontal character counter
|
||||
HCC++;
|
||||
|
||||
// increment VMA
|
||||
_vma++;
|
||||
}
|
||||
|
||||
hssstart = false;
|
||||
hhclock = false;
|
||||
|
||||
if (HCC == R2_HorizontalSyncPosition)
|
||||
{
|
||||
// start of horizontal sync
|
||||
hssstart = true;
|
||||
}
|
||||
|
||||
if (HCC == R2_HorizontalSyncPosition / 2)
|
||||
{
|
||||
// we are half way through the line
|
||||
hhclock = true;
|
||||
}
|
||||
|
||||
/* Hor active video */
|
||||
if (HCC == 0)
|
||||
{
|
||||
// active display
|
||||
latch_hdisp = true;
|
||||
}
|
||||
|
||||
if (HCC == R1_HorizontalDisplayed)
|
||||
{
|
||||
// inactive display
|
||||
latch_hdisp = false;
|
||||
}
|
||||
|
||||
/* Hor sync */
|
||||
if (hssstart || // start of horizontal sync
|
||||
HSYNC) // already in horizontal sync
|
||||
{
|
||||
// start of horizontal sync
|
||||
HSYNC = true;
|
||||
HSC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset hsync counter
|
||||
HSC = 0;
|
||||
}
|
||||
|
||||
if (HSC == R3_HorizontalSyncWidth)
|
||||
{
|
||||
// end of horizontal sync
|
||||
HSYNC = false;
|
||||
}
|
||||
|
||||
/* Ver active video */
|
||||
if (VCC == 0)
|
||||
{
|
||||
// active display
|
||||
latch_vdisp = true;
|
||||
}
|
||||
|
||||
if (VCC == R6_VerticalDisplayed)
|
||||
{
|
||||
// inactive display
|
||||
latch_vdisp = false;
|
||||
}
|
||||
|
||||
// vertical sync occurs at different times depending on the interlace field
|
||||
// even field: the same time as HSYNC
|
||||
// odd field: half a line later than HSYNC
|
||||
if ((!_field && hssstart) || (_field && hhclock))
|
||||
{
|
||||
if ((VCC == R7_VerticalSyncPosition && VLC == 0) // vsync starts on the first line
|
||||
|| VSYNC) // vsync is already in progress
|
||||
{
|
||||
// start of vertical sync
|
||||
VSYNC = true;
|
||||
// increment vertical sync counter
|
||||
VSC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset vsync counter
|
||||
VSC = 0;
|
||||
}
|
||||
|
||||
if (VSYNC && VSC == R3_VerticalSyncWidth - 1)
|
||||
{
|
||||
// end of vertical sync
|
||||
VSYNC = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Address Generation */
|
||||
int line = VLC;
|
||||
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// interlace sync+video mode
|
||||
// the least significant bit is based on the current field number
|
||||
int fNum = _field ? 1 : 0;
|
||||
int lNum = VLC.Bit(0) ? 1 : 0;
|
||||
line &= ~1;
|
||||
|
||||
_RA = line & (fNum | lNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// raster address is just the VLC
|
||||
_RA = VLC;
|
||||
}
|
||||
|
||||
_LA = _vma;
|
||||
|
||||
// DISPTMG Generation
|
||||
if (!latch_hdisp || !latch_vdisp)
|
||||
{
|
||||
// HSYNC output pin is fed through a NOR gate with either 2 or 3 inputs
|
||||
// - H Display
|
||||
// - V Display
|
||||
// - TODO: R8 DISPTMG Skew (only on certain CRTC types)
|
||||
DISPTMG = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DISPTMG = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clock() => throw new InvalidOperationException("CRTC Type 3 not implemented yet");
|
||||
|
||||
/// <summary>
|
||||
/// R3l: CRTC-type horizontal sync width independent helper function
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -15,231 +14,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
/// </summary>
|
||||
public override int CrtcType => 4;
|
||||
|
||||
/// <summary>
|
||||
/// CRTC is clocked at 1MHz (16 GA cycles)
|
||||
/// </summary>
|
||||
public override void Clock()
|
||||
{
|
||||
base.Clock();
|
||||
|
||||
int maxScanLine;
|
||||
|
||||
if (HCC == R0_HorizontalTotal)
|
||||
{
|
||||
// end of displayable area reached
|
||||
// set up for the next line
|
||||
HCC = 0;
|
||||
|
||||
// TODO: handle interlace setup
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// in interlace sync and video mask off bit 0 of the max scanline address
|
||||
maxScanLine = R9_MaxScanline & 0b11110;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxScanLine = R9_MaxScanline;
|
||||
}
|
||||
|
||||
if (VLC == maxScanLine)
|
||||
{
|
||||
// we have reached the final scanline within this vertical character row
|
||||
// move to next character
|
||||
VLC = 0;
|
||||
|
||||
// TODO: implement vertical adjust
|
||||
|
||||
|
||||
if (VCC == R4_VerticalTotal)
|
||||
{
|
||||
// check the interlace mode
|
||||
if (R8_Interlace.Bit(0))
|
||||
{
|
||||
// toggle the field
|
||||
_field = !_field;
|
||||
}
|
||||
else
|
||||
{
|
||||
// stay on the even field
|
||||
_field = false;
|
||||
}
|
||||
|
||||
// we have reached the end of the vertical display area
|
||||
// address loaded from start address register at the top of each field
|
||||
_vmaRowStart = (Register[R12_START_ADDR_H] << 8) | Register[R13_START_ADDR_L];
|
||||
|
||||
// reset the vertical character counter
|
||||
VCC = 0;
|
||||
|
||||
// increment field counter
|
||||
CFC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// row start address is increased by Horiztonal Displayed
|
||||
_vmaRowStart += R1_HorizontalDisplayed;
|
||||
|
||||
// increment vertical character counter
|
||||
VCC++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// next scanline
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// interlace sync+video mode
|
||||
// vertical line counter increments by 2
|
||||
VLC += 2;
|
||||
|
||||
// ensure vertical line counter is an even value
|
||||
VLC &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-interlace mode
|
||||
// increment vertical line counter
|
||||
VLC++;
|
||||
}
|
||||
}
|
||||
|
||||
// MA set to row start at the beginning of each line
|
||||
_vma = _vmaRowStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
// next horizontal character (1us)
|
||||
// increment horizontal character counter
|
||||
HCC++;
|
||||
|
||||
// increment VMA
|
||||
_vma++;
|
||||
}
|
||||
|
||||
hssstart = false;
|
||||
hhclock = false;
|
||||
|
||||
if (HCC == R2_HorizontalSyncPosition)
|
||||
{
|
||||
// start of horizontal sync
|
||||
hssstart = true;
|
||||
}
|
||||
|
||||
if (HCC == R2_HorizontalSyncPosition / 2)
|
||||
{
|
||||
// we are half way through the line
|
||||
hhclock = true;
|
||||
}
|
||||
|
||||
/* Hor active video */
|
||||
if (HCC == 0)
|
||||
{
|
||||
// active display
|
||||
latch_hdisp = true;
|
||||
}
|
||||
|
||||
if (HCC == R1_HorizontalDisplayed)
|
||||
{
|
||||
// inactive display
|
||||
latch_hdisp = false;
|
||||
}
|
||||
|
||||
/* Hor sync */
|
||||
if (hssstart || // start of horizontal sync
|
||||
HSYNC) // already in horizontal sync
|
||||
{
|
||||
// start of horizontal sync
|
||||
HSYNC = true;
|
||||
HSC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset hsync counter
|
||||
HSC = 0;
|
||||
}
|
||||
|
||||
if (HSC == R3_HorizontalSyncWidth)
|
||||
{
|
||||
// end of horizontal sync
|
||||
HSYNC = false;
|
||||
}
|
||||
|
||||
/* Ver active video */
|
||||
if (VCC == 0)
|
||||
{
|
||||
// active display
|
||||
latch_vdisp = true;
|
||||
}
|
||||
|
||||
if (VCC == R6_VerticalDisplayed)
|
||||
{
|
||||
// inactive display
|
||||
latch_vdisp = false;
|
||||
}
|
||||
|
||||
// vertical sync occurs at different times depending on the interlace field
|
||||
// even field: the same time as HSYNC
|
||||
// odd field: half a line later than HSYNC
|
||||
if ((!_field && hssstart) || (_field && hhclock))
|
||||
{
|
||||
if ((VCC == R7_VerticalSyncPosition && VLC == 0) // vsync starts on the first line
|
||||
|| VSYNC) // vsync is already in progress
|
||||
{
|
||||
// start of vertical sync
|
||||
VSYNC = true;
|
||||
// increment vertical sync counter
|
||||
VSC++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset vsync counter
|
||||
VSC = 0;
|
||||
}
|
||||
|
||||
if (VSYNC && VSC == R3_VerticalSyncWidth - 1)
|
||||
{
|
||||
// end of vertical sync
|
||||
VSYNC = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Address Generation */
|
||||
int line = VLC;
|
||||
|
||||
if (R8_Interlace == 3)
|
||||
{
|
||||
// interlace sync+video mode
|
||||
// the least significant bit is based on the current field number
|
||||
int fNum = _field ? 1 : 0;
|
||||
int lNum = VLC.Bit(0) ? 1 : 0;
|
||||
line &= ~1;
|
||||
|
||||
_RA = line & (fNum | lNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// raster address is just the VLC
|
||||
_RA = VLC;
|
||||
}
|
||||
|
||||
_LA = _vma;
|
||||
|
||||
// DISPTMG Generation
|
||||
if (!latch_hdisp || !latch_vdisp)
|
||||
{
|
||||
// HSYNC output pin is fed through a NOR gate with either 2 or 3 inputs
|
||||
// - H Display
|
||||
// - V Display
|
||||
// - TODO: R8 DISPTMG Skew (only on certain CRTC types)
|
||||
DISPTMG = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DISPTMG = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clock() => throw new InvalidOperationException("CRTC Type 4 not implemented yet");
|
||||
|
||||
/// <summary>
|
||||
/// R3l: CRTC-type horizontal sync width independent helper function
|
||||
|
|
|
@ -137,7 +137,17 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
/// Character pos address (0 index).
|
||||
/// Feeds the MA lines
|
||||
/// </summary>
|
||||
protected int _LA;
|
||||
protected int ma;
|
||||
|
||||
/// <summary>
|
||||
/// Memory address reset latch
|
||||
/// </summary>
|
||||
protected int ma_row_start;
|
||||
|
||||
/// <summary>
|
||||
/// Internal latch for storing intermediate MA values
|
||||
/// </summary>
|
||||
protected int ma_store;
|
||||
|
||||
/// <summary>
|
||||
/// Generated by the Vertical Control Raster Counter
|
||||
|
@ -173,21 +183,21 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
{
|
||||
var MA = new BitArray(16);
|
||||
MA[0] = CLK;
|
||||
MA[1] = _LA.Bit(0);
|
||||
MA[2] = _LA.Bit(1);
|
||||
MA[3] = _LA.Bit(2);
|
||||
MA[4] = _LA.Bit(3);
|
||||
MA[5] = _LA.Bit(4);
|
||||
MA[6] = _LA.Bit(5);
|
||||
MA[7] = _LA.Bit(6);
|
||||
MA[8] = _LA.Bit(7);
|
||||
MA[9] = _LA.Bit(8);
|
||||
MA[10] = _LA.Bit(9);
|
||||
MA[11] = _RA.Bit(0);
|
||||
MA[12] = _RA.Bit(1);
|
||||
MA[13] = _RA.Bit(2);
|
||||
MA[14] = _LA.Bit(12);
|
||||
MA[15] = _LA.Bit(13);
|
||||
MA[1] = ma.Bit(0);
|
||||
MA[2] = ma.Bit(1);
|
||||
MA[3] = ma.Bit(2);
|
||||
MA[4] = ma.Bit(3);
|
||||
MA[5] = ma.Bit(4);
|
||||
MA[6] = ma.Bit(5);
|
||||
MA[7] = ma.Bit(6);
|
||||
MA[8] = ma.Bit(7);
|
||||
MA[9] = ma.Bit(8);
|
||||
MA[10] = ma.Bit(9);
|
||||
MA[11] = VLC.Bit(0);
|
||||
MA[12] = VLC.Bit(1);
|
||||
MA[13] = VLC.Bit(2);
|
||||
MA[14] = ma.Bit(12);
|
||||
MA[15] = ma.Bit(13);
|
||||
int[] array = new int[1];
|
||||
MA.CopyTo(array, 0);
|
||||
return (ushort)array[0];
|
||||
|
@ -616,7 +626,10 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
/// <summary>
|
||||
/// CRTC is clocked at 1MHz (16 GA cycles)
|
||||
/// </summary>
|
||||
public virtual void Clock()
|
||||
public virtual void Clock() { }
|
||||
|
||||
|
||||
public virtual void CheckReset()
|
||||
{
|
||||
if (_inReset > 0)
|
||||
{
|
||||
|
@ -633,7 +646,9 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
_field = false;
|
||||
_vmaRowStart = 0;
|
||||
_vma = 0;
|
||||
_LA = 0;
|
||||
ma = 0;
|
||||
ma_row_start = 0;
|
||||
ma_store = 0;
|
||||
_RA = 0;
|
||||
latch_hdisp = false;
|
||||
latch_vdisp = false;
|
||||
|
@ -755,7 +770,9 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
ser.Sync(nameof(_HSYNC), ref _HSYNC);
|
||||
ser.Sync(nameof(_DISPTMG), ref _DISPTMG);
|
||||
ser.Sync(nameof(_CUDISP), ref _CUDISP);
|
||||
ser.Sync(nameof(_LA), ref _LA);
|
||||
ser.Sync(nameof(ma), ref ma);
|
||||
ser.Sync(nameof(ma_row_start), ref ma_row_start);
|
||||
ser.Sync(nameof(ma_store), ref ma_store);
|
||||
ser.Sync(nameof(_RA), ref _RA);
|
||||
ser.Sync(nameof(_addressRegister), ref _addressRegister);
|
||||
ser.Sync(nameof(Register), ref Register, false);
|
||||
|
|
|
@ -51,6 +51,9 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
}
|
||||
private int _GAClockCounter;
|
||||
|
||||
public double CRTCClockCounter => (double)GAClockCounter / 16;
|
||||
public double CPUClockClounter => (double)GAClockCounter / 4;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Previous frame clock count. Latched at the end of the frame (VSYNC off)
|
||||
|
@ -514,6 +517,9 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
}
|
||||
}
|
||||
|
||||
private int GAClockCounterOriginVSYNC;
|
||||
private double GACunlockCounterOriginVSYNCCRTC => (double)GAClockCounterOriginVSYNC / 16;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when CRTC VSYNC active signal is detected
|
||||
/// </summary>
|
||||
|
@ -525,6 +531,10 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
GA_VSYNC = true;
|
||||
// black colour enabled for vsync
|
||||
C_VSYNC_Black = true;
|
||||
|
||||
// signal start of new frame
|
||||
GAClockCounterOriginVSYNC = 0;
|
||||
FrameEnd = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -609,6 +619,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
// We will do this for now to get the accuracy right, but will probably need to optimise this down the line
|
||||
//OutputPixel(0);
|
||||
GAClockCounter++;
|
||||
GAClockCounterOriginVSYNC++;
|
||||
|
||||
|
||||
// Based on timing oscilloscope traces from
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
CPC = cpc;
|
||||
CPU = cpu;
|
||||
|
||||
CRTC = CRTC.Create(0);
|
||||
CRTC = CRTC.Create(1);
|
||||
GateArray = new GateArray(this, GateArrayType.Amstrad40010);
|
||||
CRTScreen = new CRTScreen(ScreenType.CTM064x, borderType);
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
GateArray.GAClockCounter = 0;
|
||||
GateArray.FrameEnd = false;
|
||||
|
||||
while (!CRTScreen.FrameEnd)
|
||||
while (!GateArray.FrameEnd)
|
||||
{
|
||||
GateArray.Clock();
|
||||
|
||||
|
@ -157,7 +157,7 @@ namespace BizHawk.Emulation.Cores.Computers.AmstradCPC
|
|||
TapeDevice.TapeCycle();
|
||||
}
|
||||
|
||||
CRTScreen.FrameEnd = false;
|
||||
GateArray.FrameEnd = false;
|
||||
|
||||
var ipf = GateArray.interruptsPerFrame;
|
||||
GateArray.interruptsPerFrame = 0;
|
||||
|
|
Loading…
Reference in New Issue