Skip to content

Commit

Permalink
Merge pull request #204 from emu-russia/167-add-pal-ppu-support-ppusim
Browse files Browse the repository at this point in the history
PAL VideoProcessing + UMC UA6538 Support
  • Loading branch information
ogamespec authored Jun 22, 2022
2 parents 29ffa4c + 4cbdf70 commit adcf7d7
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 21 deletions.
20 changes: 15 additions & 5 deletions BreaksPPU/PPUPlayer/FormCompositeViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ void ProcessScanComposite()

// Detect Color Burst Phase (simulate TV PLL)

int cb_phase = PLL();
bool odd = (CurrentScan % 2) != 0 && ppu_features.PhaseAlteration != 0;
int cb_phase = PLL(odd, ppu_features.PhaseAlteration != 0 ? 10 : 0);

ReadPtr += ppu_features.BackPorchSize * ppu_features.SamplesPerPCLK;

Expand Down Expand Up @@ -169,7 +170,7 @@ void ProcessScanComposite()
float level = ((batch[n].composite - ppu_features.BurstLevel) * normalize_factor) / num_phases;
Y += level;
I += level * (float)Math.Cos((cb_phase + n + ofs) * (2 * Math.PI / num_phases) + hue_adj);
Q += level * (float)Math.Sin((cb_phase + n + ofs) * (2 * Math.PI / num_phases) + hue_adj);
Q += level * (float)Math.Sin((cb_phase + n + ofs) * (2 * Math.PI / num_phases) + hue_adj) * (odd ? -1.0f : +1.0f);
}

// 6500K color temperature
Expand All @@ -195,12 +196,19 @@ void ProcessScanComposite()
}
}

int PLL()
int prev_cb_shift = 0;

int PLL(bool odd, int cb)
{
int ReadPtr = SyncPos;
int num_phases = 12;
int samples = ppu_features.BackPorchSize * ppu_features.SamplesPerPCLK;

if (odd)
{
return Math.Abs((prev_cb_shift + 5) % num_phases);
}

// Skip HSync

while (ScanBuffer[ReadPtr].composite <= ppu_features.SyncLevel)
Expand All @@ -217,7 +225,7 @@ int PLL()

// Get phase shift

int cb_shift = 0;
int cb_shift = cb;

if (ScanBuffer[ReadPtr].composite < ppu_features.BurstLevel)
{
Expand All @@ -238,7 +246,9 @@ int PLL()
}
}

return cb_shift % num_phases;
int res = cb_shift % num_phases;
prev_cb_shift = res;
return res;
}

float Clamp(float val, float min, float max)
Expand Down
6 changes: 3 additions & 3 deletions BreaksPPU/PPUPlayer/FormMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,17 @@ void RunPPU()
return;
}

FormSettings.PPUPlayerSettings settings = FormSettings.LoadSettings();

// If the user did not select anything, but just clicked the `Play` button - notify him that he is in free flight.

if (ppu_dump == null && nes_file == null)
{
string text = DefaultTitle;
text += " - Free Flight";
text += " - Free Flight (" + settings.PPU_Revision + ")";
this.Text = text;
}

FormSettings.PPUPlayerSettings settings = FormSettings.LoadSettings();

// If the user has specified RegDump - use it. Otherwise, create a dummy RegDump with an `infinite` wait to read register $2002.

if (ppu_dump != null)
Expand Down
2 changes: 2 additions & 0 deletions BreaksPPU/PPUPlayer/PPUPlayerInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public struct VideoSignalFeatures
public float WhiteLevel; // IRE = 100
[FieldOffset(28)]
public float SyncLevel;
[FieldOffset(32)]
public int PhaseAlteration; // 1: PAL
}

[DllImport("PPUPlayerInterop.dll", CallingConvention = CallingConvention.Cdecl)]
Expand Down
21 changes: 15 additions & 6 deletions BreaksPPU/PPUPlayer/VideoProcessing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ void ProcessScanComposite()

// Detect Color Burst Phase (simulate TV PLL)

int cb_phase = PLL();
bool odd = (CurrentScan % 2) != 0 && ppu_features.PhaseAlteration != 0;
int cb_phase = PLL(odd, ppu_features.PhaseAlteration != 0 ? 10 : 0);

ReadPtr += ppu_features.BackPorchSize * ppu_features.SamplesPerPCLK;

Expand Down Expand Up @@ -273,7 +274,7 @@ void ProcessScanComposite()
float level = ((batch[n].composite - ppu_features.BurstLevel) * normalize_factor) / num_phases;
Y += level;
I += level * (float)Math.Cos((cb_phase + n + ofs) * (2 * Math.PI / num_phases) + hue_adj);
Q += level * (float)Math.Sin((cb_phase + n + ofs) * (2 * Math.PI / num_phases) + hue_adj);
Q += level * (float)Math.Sin((cb_phase + n + ofs) * (2 * Math.PI / num_phases) + hue_adj) * (odd ? -1.0f : +1.0f);
}

// 6500K color temperature
Expand All @@ -298,12 +299,19 @@ void ProcessScanComposite()
}
}

int PLL()
int prev_cb_shift = 0;

int PLL(bool odd, int cb)
{
int ReadPtr = SyncPos;
int num_phases = 12;
int samples = ppu_features.BackPorchSize * ppu_features.SamplesPerPCLK;

if (odd)
{
return Math.Abs((prev_cb_shift + 5) % num_phases);
}

// Skip HSync

while (ScanBuffer[ReadPtr].composite <= ppu_features.SyncLevel)
Expand All @@ -320,7 +328,7 @@ int PLL()

// Get phase shift

int cb_shift = 0;
int cb_shift = cb;

if (ScanBuffer[ReadPtr].composite < ppu_features.BurstLevel)
{
Expand All @@ -339,10 +347,11 @@ int PLL()
cb_shift++;
ReadPtr++;
}

}

return cb_shift % num_phases;
int res = cb_shift % num_phases;
prev_cb_shift = res;
return res;
}

float Clamp(float val, float min, float max)
Expand Down
7 changes: 7 additions & 0 deletions BreaksPPU/PPUSim/fsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ namespace PPUSim
ppu->wire.EvenOddOut = TriState::Zero;
break;
}

case Revision::UMC_UA6538:
{
ppu->wire.EvenOddOut = TriState::Zero;
break;
}
}
}

Expand All @@ -273,6 +279,7 @@ namespace PPUSim
// PAL PPU does not use EvenOddOut.

case Revision::RP2C07_0:
case Revision::UMC_UA6538:
{
ctrl_latch1.set(NOT(HPLA[23]), n_PCLK);
ctrl_latch2.set(VPLA[8], n_PCLK);
Expand Down
48 changes: 48 additions & 0 deletions BreaksPPU/PPUSim/hv_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace PPUSim
vpla_outputs = 9;
break;
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
// An additional output is used for modified EVEN/ODD logic.
vpla_outputs = 10;
break;
Expand Down Expand Up @@ -138,6 +139,53 @@ namespace PPUSim
}
break;

case Revision::UMC_UA6538:
{
size_t UMC_UA6538_HDecoder[] = { // Same as PAL PPU
0b01101010011001100100,
0b01101010101010101000,
0b10100110101010100101,
0b00101010101000000000,
0b10000000000000000010,
0b01100110011010010101,
0b10101001010101010101,
0b00010101010101010101,
0b10101000000000000001,
0b01101000000000000001,
0b10000000000000000011,
0b00000000000010100001,
0b00000000000001010000,
0b00000000000001100000,
0b01000110100000000001,
0b10000000000000000001,
0b00000000000010010000,
0b01101010101010101000,
0b10101010101001101000,
0b01101010011001100100,
0b01101001100101011000,
0b01100110101010100100,
0b01101001011010011000,
0b01100110011001101000,
};

size_t UMC_UA6538_VDecoder[] = {
0b011010100110101010,
0b011010101001011001,
0b101010101010101001,
0b000101010110101010,
0b011010011010100101, // triggered 50 lines later
0b101010101010101010,
0b000101010110101010,
0b011010010110010101,
0b011010010110010101,
0b011010101001101001,
};

h_bitmask = UMC_UA6538_HDecoder;
v_bitmask = UMC_UA6538_VDecoder;
}
break;

// TBD: Add PLA for the rest of the PPU studied.
}

Expand Down
1 change: 1 addition & 0 deletions BreaksPPU/PPUSim/pclk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace PPUSim
break;

case Revision::RP2C07_0:
case Revision::UMC_UA6538:
{
pclk_1.set(NOR(pclk_6.get(), wire.RES), CLK);
pclk_2.set(pclk_1.nget(), n_CLK);
Expand Down
2 changes: 2 additions & 0 deletions BreaksPPU/PPUSim/ppu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ namespace PPUSim
case Revision::RP2C02G:
case Revision::RP2C02H:
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
{
TriState nSLAVE = regs->get_nSLAVE();

Expand Down Expand Up @@ -202,6 +203,7 @@ namespace PPUSim
case Revision::RP2C02G:
case Revision::RP2C02H:
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
{
for (size_t n = 0; n < 4; n++)
{
Expand Down
1 change: 1 addition & 0 deletions BreaksPPU/PPUSim/ppu.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ namespace PPUSim
float BurstLevel; // IRE = 0
float WhiteLevel; // IRE = 100
float SyncLevel;
int32_t PhaseAlteration; // 1: PAL
};

/// <summary>
Expand Down
8 changes: 6 additions & 2 deletions BreaksPPU/PPUSim/regs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ namespace PPUSim

sim_RegFFs();

if (ppu->rev == Revision::RP2C07_0)
switch (ppu->rev)
{
sim_PalBLACK();
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
sim_PalBLACK();
break;
}
}

Expand Down Expand Up @@ -213,6 +216,7 @@ namespace PPUSim
// The PAL PPU uses a hidden latch for the VBL signal, which is stored between the open transistor and the inverter in the VBlank INT circuit.

case Revision::RP2C07_0:
case Revision::UMC_UA6538:
vbl_latch.set(PPU_CTRL0[7].get(), NOT(W0_Enable));
ppu->wire.VBL = vbl_latch.get();
break;
Expand Down
2 changes: 2 additions & 0 deletions BreaksPPU/PPUSim/sprite_eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ namespace PPUSim
// For the PAL PPU, the $2003 write delay is screwed on. This is most likely how they fight OAM Corruption.

case Revision::RP2C07_0:
case Revision::UMC_UA6538:
{
auto W3 = NOR(n_W3, n_DBE);
W3_FF1.set(NOR(NOR(W3, W3_FF1.get()), w3_latch3.nget()));
Expand Down Expand Up @@ -322,6 +323,7 @@ namespace PPUSim
switch (ppu->rev)
{
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
{
TriState n_PCLK = ppu->wire.n_PCLK;
blnk_latch.set(BLNK, n_PCLK);
Expand Down
36 changes: 31 additions & 5 deletions BreaksPPU/PPUSim/video_out.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace PPUSim
case Revision::RP2C02G:
case Revision::RP2C02H:
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
LToV[0] = 0.781f; // Synch
LToV[1] = 1.000f; // Colorburst L
LToV[2] = 1.131f; // Color 0D
Expand Down Expand Up @@ -43,6 +44,7 @@ namespace PPUSim
switch (ppu->rev)
{
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
SetupChromaDecoderPAL();
break;
}
Expand Down Expand Up @@ -168,6 +170,7 @@ namespace PPUSim
break;

case Revision::RP2C07_0:
case Revision::UMC_UA6538:
{
TriState n_PCLK = ppu->wire.n_PCLK;
if (ppu->v != nullptr)
Expand Down Expand Up @@ -488,11 +491,14 @@ namespace PPUSim
TriState n_PCLK = ppu->wire.n_PCLK;
TriState n_PICTURE = ppu->fsm.n_PICTURE;

if (ppu->rev == Revision::RP2C07_0)
switch (ppu->rev)
{
npicture_latch1.set(NOT(n_PICTURE), n_PCLK);
npicture_latch2.set(npicture_latch1.nget(), PCLK);
n_PICTURE = npicture_latch2.get();
case Revision::RP2C07_0:
case Revision::UMC_UA6538:
npicture_latch1.set(NOT(n_PICTURE), n_PCLK);
npicture_latch2.set(npicture_latch1.nget(), PCLK);
n_PICTURE = npicture_latch2.get();
break;
}

VidOut_n_PICTURE = n_PICTURE;
Expand All @@ -511,6 +517,7 @@ namespace PPUSim
features.BurstLevel = 1.3f;
features.WhiteLevel = 1.6f;
features.SyncLevel = 0.781f;
features.PhaseAlteration = false;
break;

case Revision::RP2C07_0:
Expand All @@ -521,6 +528,21 @@ namespace PPUSim
features.BurstLevel = 1.3f;
features.WhiteLevel = 1.6f;
features.SyncLevel = 0.781f;
features.PhaseAlteration = true;
break;

// TBD: Technically the DAC should not differ from the PAL PPU, but there are reports that the colors are brighter.
// Apparently this is due to the slight difference in the crystal area.

case Revision::UMC_UA6538:
features.SamplesPerPCLK = 10;
features.PixelsPerScan = 341;
features.ScansPerField = 312;
features.BackPorchSize = 42;
features.BurstLevel = 1.3f;
features.WhiteLevel = 1.6f;
features.SyncLevel = 0.781f;
features.PhaseAlteration = true;
break;

case Revision::RP2C04_0003:
Expand Down Expand Up @@ -626,9 +648,13 @@ namespace PPUSim
float level = ((batch[n].composite - features.BurstLevel) * normalize_factor) / num_phases;
Y += level;
I += level * cos((cb_phase + n) * (2 * π / num_phases));
Q += level * sin((cb_phase + n) * (2 * π / num_phases));
Q += level * sin((cb_phase + n) * (2 * π / num_phases)) * +1.0f;
}

// Note to PAL researchers. Read math behind PAL, or just use these:
// cb_phase = 1
// Q += level * sin((cb_phase + n) * (2 * π / num_phases)) * -1.0f; <---- Minus

delete[] batch;

// 6500K color temperature
Expand Down

0 comments on commit adcf7d7

Please sign in to comment.