commit
94f6597e86
11 changed files with 161 additions and 61 deletions
|
@ -14,7 +14,7 @@
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
|
|
||||||
void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
|
void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
|
||||||
void BaseMapper::WriteEPSM(uint16_t addr, uint8_t value) { _epsmaudio->WriteRegister(addr, value); }
|
void BaseMapper::WriteEPSM(uint16_t addr, uint8_t value) {_epsmaudio->WriteRegister(addr, value); }
|
||||||
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
|
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
|
||||||
void BaseMapper::InitMapper(RomData &romData) { }
|
void BaseMapper::InitMapper(RomData &romData) { }
|
||||||
void BaseMapper::Reset(bool softReset) { }
|
void BaseMapper::Reset(bool softReset) { }
|
||||||
|
@ -787,7 +787,7 @@ uint8_t BaseMapper::DebugReadRAM(uint16_t addr)
|
||||||
void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
if((addr == 0x4016) & (_console->GetCpu()->GetCycleCount() % 2 == 1)){ WriteEPSM(addr, value); }
|
if((addr == 0x4016) & (_console->GetCpu()->GetCycleCount() % 2 == 1)){ WriteEPSM(addr, value); }
|
||||||
if ((addr >= 0x401c && addr <= 0x401f)) { WriteEPSM(addr, value); }
|
if ((addr >= 0x401c && addr <= 0x401f)) {WriteEPSM(addr, value); }
|
||||||
if(_isWriteRegisterAddr[addr]) {
|
if(_isWriteRegisterAddr[addr]) {
|
||||||
if(_hasBusConflicts) {
|
if(_hasBusConflicts) {
|
||||||
uint8_t prgValue = _prgPages[addr >> 8][(uint8_t)addr];
|
uint8_t prgValue = _prgPages[addr >> 8][(uint8_t)addr];
|
||||||
|
|
|
@ -473,10 +473,10 @@ void Console::ProcessCpuClock()
|
||||||
|
|
||||||
void Console::ProcessInterferenceAudio()
|
void Console::ProcessInterferenceAudio()
|
||||||
{
|
{
|
||||||
_InvA13 = (_ppu->_A13pinLow == 1) ? 0 : 1; // invert relative to 2A03
|
_InvA13 = _ppu->_A13pinLowSum;
|
||||||
|
_ppu->_A13pinLowSum = 0;
|
||||||
|
|
||||||
_controlManager->GetInvOE1(_controlManager->_address);
|
_InvOE1 = !_controlManager->GetInvOE1(_controlManager->_address); // invert relative to 2A03
|
||||||
_InvOE1 = (_controlManager->_OE1pinLow == 1) ? 0 : 1; // invert relative to 2A03
|
|
||||||
|
|
||||||
if (_controlManager->_strobed == true)
|
if (_controlManager->_strobed == true)
|
||||||
_controlManager->_strobed = false;
|
_controlManager->_strobed = false;
|
||||||
|
|
|
@ -351,11 +351,12 @@ void ControlManager::WriteRAM(uint16_t addr, uint8_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlManager::GetInvOE1(uint16_t addr)
|
bool ControlManager::GetInvOE1(uint16_t addr)
|
||||||
{
|
{
|
||||||
// pull low for only one clock
|
// pull low for only one clock
|
||||||
if (addr == 0x4016)
|
if (addr == 0x4016)
|
||||||
_OE1pinLow = (_strobed) ? 0 : 1;
|
_OE1pinLow = !_strobed;
|
||||||
|
return _OE1pinLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlManager::Reset(bool softReset)
|
void ControlManager::Reset(bool softReset)
|
||||||
|
|
|
@ -43,7 +43,7 @@ protected:
|
||||||
virtual uint8_t GetOpenBusMask(uint8_t port);
|
virtual uint8_t GetOpenBusMask(uint8_t port);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint8_t _OE1pinLow;
|
bool _OE1pinLow;
|
||||||
uint16_t _address;
|
uint16_t _address;
|
||||||
bool _strobed;
|
bool _strobed;
|
||||||
|
|
||||||
|
@ -85,5 +85,5 @@ public:
|
||||||
virtual uint8_t ReadRAM(uint16_t addr) override;
|
virtual uint8_t ReadRAM(uint16_t addr) override;
|
||||||
virtual void WriteRAM(uint16_t addr, uint8_t value) override;
|
virtual void WriteRAM(uint16_t addr, uint8_t value) override;
|
||||||
|
|
||||||
void GetInvOE1(uint16_t addr);
|
bool GetInvOE1(uint16_t addr);
|
||||||
};
|
};
|
||||||
|
|
189
Core/EPSMAudio.h
189
Core/EPSMAudio.h
|
@ -5,6 +5,7 @@
|
||||||
#include "BaseExpansionAudio.h"
|
#include "BaseExpansionAudio.h"
|
||||||
#include "SSGAudio.h"
|
#include "SSGAudio.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
#include "CPU.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "ym3438.h"
|
#include "ym3438.h"
|
||||||
|
@ -19,9 +20,22 @@ private:
|
||||||
int16_t _lastOutputs[2];
|
int16_t _lastOutputs[2];
|
||||||
int16_t _currentOutputs[2];
|
int16_t _currentOutputs[2];
|
||||||
uint8_t writeValue;
|
uint8_t writeValue;
|
||||||
int16_t writeAddr;
|
uint16_t writeAddr;
|
||||||
|
uint16_t irqATimer;
|
||||||
|
uint16_t irqBTimer;
|
||||||
|
uint16_t irqACurrentTimer;
|
||||||
|
uint16_t irqBCurrentTimer;
|
||||||
|
uint8_t irqATimerEnable;
|
||||||
|
uint8_t irqBTimerEnable;
|
||||||
|
uint8_t irqAHighValue;
|
||||||
|
uint8_t irqALowValue;
|
||||||
|
uint8_t irqBValue;
|
||||||
|
uint16_t currentRegister;
|
||||||
|
|
||||||
|
|
||||||
double _clock;
|
double _clock;
|
||||||
|
double _clockIRQ;
|
||||||
|
double _cycleCountIRQ = 0;
|
||||||
|
|
||||||
static constexpr uint8_t cycleCount = 24;
|
static constexpr uint8_t cycleCount = 24;
|
||||||
|
|
||||||
|
@ -39,7 +53,6 @@ private:
|
||||||
|
|
||||||
void UpdateOutputLevel()
|
void UpdateOutputLevel()
|
||||||
{
|
{
|
||||||
int16_t summedOutput = 0;
|
|
||||||
for (size_t x = 0; x < 2; x++)
|
for (size_t x = 0; x < 2; x++)
|
||||||
{
|
{
|
||||||
_console->GetApu()->AddExpansionAudioDelta(x == 0 ? AudioChannel::EPSM_L : AudioChannel::EPSM_R, _currentOutputs[x] - _lastOutputs[x]);
|
_console->GetApu()->AddExpansionAudioDelta(x == 0 ? AudioChannel::EPSM_L : AudioChannel::EPSM_R, _currentOutputs[x] - _lastOutputs[x]);
|
||||||
|
@ -69,6 +82,71 @@ private:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WriteToChipIRQ(uint16_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
switch (addr) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x2:
|
||||||
|
currentRegister = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1:
|
||||||
|
if (currentRegister == 0x24) {
|
||||||
|
//Timer A High 8 bits
|
||||||
|
//std::cout << "Timer A High 8 bits" << std::endl;
|
||||||
|
irqAHighValue = value;
|
||||||
|
}
|
||||||
|
if (currentRegister == 0x25) {
|
||||||
|
//Timer A Low 2 bits
|
||||||
|
//std::cout << "Timer A Low 2 bits" << std::endl;
|
||||||
|
irqALowValue = (value & 0x3);
|
||||||
|
}
|
||||||
|
if (currentRegister == 0x26) {
|
||||||
|
//Timer B 8 bits
|
||||||
|
//std::cout << "Timer B 8 bits" << std::endl;
|
||||||
|
irqBValue = value;
|
||||||
|
}
|
||||||
|
if ((currentRegister == 0x27) && ((value & 0x5)|(value & 0xA))) {
|
||||||
|
//Load+Enable IRQ (0xA = TimerB, 0x5 = TimerA)
|
||||||
|
//std::cout << "Load+Enable IRQ" << std::endl;
|
||||||
|
if ((currentRegister == 0x27) && (value & 0x5)) {
|
||||||
|
irqATimer = (uint16_t(irqAHighValue) << 2) | irqALowValue;
|
||||||
|
irqACurrentTimer = 72 * (1024 - irqATimer) * 2;
|
||||||
|
irqATimerEnable = 1;
|
||||||
|
//std::cout << "Load+Enable IRQ A" << std::endl;
|
||||||
|
}
|
||||||
|
if ((currentRegister == 0x27) && (value & 0xA)) {
|
||||||
|
irqBTimer = 1152 * (256 - irqBValue) * 2;
|
||||||
|
irqBCurrentTimer = irqBTimer;
|
||||||
|
irqBTimerEnable = 1;
|
||||||
|
//std::cout << "Load+Enable IRQ B " << irqBCurrentTimer << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((currentRegister == 0x27) && (value & 0x30)) {
|
||||||
|
//Enable/Reset IRQ
|
||||||
|
//std::cout << std::hex << uint16_t(value) << "Reset IRQ" << std::endl;
|
||||||
|
_console->GetCpu()->ClearIrqSource(IRQSource::EPSM);
|
||||||
|
irqATimerEnable = 0;
|
||||||
|
irqBTimerEnable = 0;
|
||||||
|
}
|
||||||
|
if ((currentRegister == 0x29) && (value & 0x3)) {
|
||||||
|
//enable IRQ's
|
||||||
|
//std::cout << "enable IRQ's" << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
/*if (currentRegister == 0x10) {
|
||||||
|
std::cout << "0x10" << std::endl;
|
||||||
|
}*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//irqBValue = value;
|
||||||
|
//std::cout << std::hex << irqBValue << std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t getClockFrequency()
|
uint32_t getClockFrequency()
|
||||||
{
|
{
|
||||||
return _console->GetSettings()->GetEPSMClockFrequency() / 6;
|
return _console->GetSettings()->GetEPSMClockFrequency() / 6;
|
||||||
|
@ -92,6 +170,26 @@ protected:
|
||||||
EPSMSSGAudio::ClockAudio();
|
EPSMSSGAudio::ClockAudio();
|
||||||
|
|
||||||
_clock += getClockFrequency() / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
|
_clock += getClockFrequency() / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
|
||||||
|
_clockIRQ += (getClockFrequency()*6) / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
|
||||||
|
while (_clockIRQ >= _cycleCountIRQ) {
|
||||||
|
_cycleCountIRQ++;
|
||||||
|
if (irqATimerEnable) {
|
||||||
|
irqACurrentTimer--;
|
||||||
|
if (!irqACurrentTimer) {
|
||||||
|
irqATimerEnable = 0;
|
||||||
|
_console->GetCpu()->SetIrqSource(IRQSource::EPSM);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (irqBTimerEnable) {
|
||||||
|
irqBCurrentTimer--;
|
||||||
|
if (!irqBCurrentTimer) {
|
||||||
|
irqBTimerEnable = 0;
|
||||||
|
_console->GetCpu()->SetIrqSource(IRQSource::EPSM);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (_clock >= cycleCount)
|
while (_clock >= cycleCount)
|
||||||
{
|
{
|
||||||
|
@ -117,7 +215,6 @@ protected:
|
||||||
if(input.wrote)
|
if(input.wrote)
|
||||||
{
|
{
|
||||||
input.wrote = false;
|
input.wrote = false;
|
||||||
|
|
||||||
OPN2_Write(&_chip, input.addr, input.data);
|
OPN2_Write(&_chip, input.addr, input.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,9 +228,9 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual uint32_t GetSSGClockFrequency()
|
virtual uint32_t GetSSGClockFrequency() override
|
||||||
{
|
{
|
||||||
return EPSMSSGAudio::GetSSGClockFrequency() * (_console->GetSettings()->GetEPSMClockFrequency() / 3579545.0 );
|
return EPSMSSGAudio::GetSSGClockFrequency() * (_console->GetSettings()->GetEPSMClockFrequency() / 3579545 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -144,57 +241,59 @@ public:
|
||||||
_inputBuffer = {};
|
_inputBuffer = {};
|
||||||
|
|
||||||
_clock = 0;
|
_clock = 0;
|
||||||
|
_clockIRQ = 0;
|
||||||
|
|
||||||
|
irqATimerEnable = 0;
|
||||||
|
irqBTimerEnable = 0;
|
||||||
OPN2_Reset(&_chip);
|
OPN2_Reset(&_chip);
|
||||||
OPN2_SetChipType(0);
|
OPN2_SetChipType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteRegister(uint16_t addr, uint8_t value)
|
void WriteRegister(uint16_t addr, uint8_t value, uint8_t custom = 0, uint8_t epsmA0 = 0, uint8_t epsmA1 = 0)
|
||||||
{
|
{
|
||||||
|
if (!custom) {
|
||||||
|
switch (addr) {
|
||||||
|
case 0x4016:
|
||||||
|
if ((value & 0x0F) == 0x02) {writeAddr = 0x0;} //A0 = 0, A1 = 0
|
||||||
|
if ((value & 0x0F) == 0x0A) {writeAddr = 0x1;} //A0 = 1, A1 = 0
|
||||||
|
if ((value & 0x0F) == 0x06) {writeAddr = 0x2;} //A0 = 0, A1 = 1
|
||||||
|
if ((value & 0x0F) == 0x0E) {writeAddr = 0x3;} //A0 = 1, A1 = 1
|
||||||
|
if (value & 0x0E) {writeValue = value;}
|
||||||
|
if ((value & 0x0F) == 0x00) {
|
||||||
|
writeValue = (writeValue & 0xF0) | (value >> 4);
|
||||||
|
|
||||||
if (addr == 0x4016) {
|
const uint8_t a0 = !!(writeAddr & 0x1);
|
||||||
if ((value & 0x0F) == 0x02) {
|
const uint8_t a1 = !!(writeAddr & 0x2);
|
||||||
writeValue = value;
|
if (a0 == 0x0) { writeAddr = 0xC000; }
|
||||||
writeAddr = 0xC000;
|
if (a0 == 0x1) { writeAddr = 0xE000; }
|
||||||
}
|
if (a1 == 0x0) { EPSMSSGAudio::WriteRegister(writeAddr, value); }
|
||||||
if ((value & 0x0F) == 0x0A) {
|
WriteToChip(a0 | (a1 << 1), writeValue);
|
||||||
writeValue = value;
|
WriteToChipIRQ(a0 | (a1 << 1), value);
|
||||||
writeAddr = 0xE000;
|
}
|
||||||
}
|
break;
|
||||||
if ((value & 0x0F) == 0x06) {
|
case 0x401c: //0xC000 A0 = 0, A1 = 0
|
||||||
writeValue = value;
|
case 0x401d: //0xE000 A0 = 1, A1 = 0
|
||||||
writeAddr = 0xC002;
|
case 0x401e: //0xC002 A0 = 0, A1 = 1
|
||||||
}
|
case 0x401f: //0xE002 A0 = 1, A1 = 1
|
||||||
if ((value & 0x0F) == 0x0E) {
|
|
||||||
writeValue = value;
|
|
||||||
writeAddr = 0xE002;
|
|
||||||
}
|
|
||||||
if ((value & 0x0F) == 0x00) {
|
|
||||||
writeValue = (writeValue & 0xF0) | (value >> 4);
|
|
||||||
|
|
||||||
const uint8_t a04016 = (writeAddr & 0xF000) == 0xE000;
|
const uint8_t a0 = !!(addr & 0x1); //const uint8_t a0 = (addr & 0xF000) == 0xE000;
|
||||||
const uint8_t a14016 = !!(writeAddr & 0xF);
|
const uint8_t a1 = !!(addr & 0x2); //const uint8_t a1 = !!(addr & 0xF);
|
||||||
EPSMSSGAudio::WriteRegister(writeAddr, writeValue);
|
if (a0 == 0x0) { addr = 0xC000; }
|
||||||
WriteToChip(a04016 | (a14016 << 1), writeValue);
|
if (a0 == 0x1) { addr = 0xE000; }
|
||||||
}
|
if (a1 == 0x0) { EPSMSSGAudio::WriteRegister(addr, value); }
|
||||||
}
|
|
||||||
if (addr == 0x401c) { addr = 0xC000; }
|
|
||||||
if (addr == 0x401d) { addr = 0xE000; }
|
|
||||||
if (addr == 0x401e) { addr = 0xC002; }
|
|
||||||
if (addr == 0x401f) { addr = 0xE002; }
|
|
||||||
|
|
||||||
switch(addr) {
|
|
||||||
case 0xC000:
|
|
||||||
case 0xE000:
|
|
||||||
case 0xC002:
|
|
||||||
case 0xE002:
|
|
||||||
|
|
||||||
const uint8_t a0 = (addr & 0xF000) == 0xE000;
|
|
||||||
const uint8_t a1 = !!(addr & 0xF);
|
|
||||||
EPSMSSGAudio::WriteRegister(addr, value);
|
|
||||||
WriteToChip(a0 | (a1 << 1), value);
|
WriteToChip(a0 | (a1 << 1), value);
|
||||||
|
WriteToChipIRQ(a0 | (a1 << 1), value);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
if (epsmA0 == 0x0) { addr = 0xC000; }
|
||||||
|
if (epsmA0 == 0x1) { addr = 0xE000; }
|
||||||
|
if (epsmA1 == 0x0) { EPSMSSGAudio::WriteRegister(addr, value); }
|
||||||
|
WriteToChip(epsmA0 | (epsmA1 << 1), value);
|
||||||
|
WriteToChipIRQ(epsmA0 | (epsmA1 << 1), value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -133,7 +133,7 @@ void MemoryManager::Write(uint16_t addr, uint8_t value, MemoryOperationType oper
|
||||||
{
|
{
|
||||||
if(_console->DebugProcessRamOperation(operationType, addr, value)) {
|
if(_console->DebugProcessRamOperation(operationType, addr, value)) {
|
||||||
_ramWriteHandlers[addr]->WriteRAM(addr, value);
|
_ramWriteHandlers[addr]->WriteRAM(addr, value);
|
||||||
if ((addr == 0x4016) | (addr >= 0x401c && addr <= 0x401f)) {
|
if ((addr == 0x4016) /*| (addr >= 0x401c && addr <= 0x401f)*/) {
|
||||||
_ramWriteHandlers[0xE000]->WriteRAM(addr, value);
|
_ramWriteHandlers[0xE000]->WriteRAM(addr, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -466,7 +466,7 @@ void PPU::WriteRAM(uint16_t addr, uint8_t value)
|
||||||
void PPU::GetInvA13()
|
void PPU::GetInvA13()
|
||||||
{
|
{
|
||||||
// pull level high when PPU/VRAM addr bit 13 is low
|
// pull level high when PPU/VRAM addr bit 13 is low
|
||||||
_A13pinLow = (_ppuBusAddress & 0x2000) ? 0 : 1;
|
_A13pinLowSum += (bool)(_ppuBusAddress & 0x2000); // invert relative to 2A03
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t PPU::ReadPaletteRAM(uint16_t addr)
|
uint8_t PPU::ReadPaletteRAM(uint16_t addr)
|
||||||
|
|
|
@ -180,7 +180,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
static constexpr int32_t OutputBufferSize = 256*240*2;
|
static constexpr int32_t OutputBufferSize = 256*240*2;
|
||||||
static constexpr int32_t OamDecayCycleCount = 3000;
|
static constexpr int32_t OamDecayCycleCount = 3000;
|
||||||
|
|
||||||
uint8_t _A13pinLow;
|
uint8_t _A13pinLowSum;
|
||||||
|
|
||||||
PPU(shared_ptr<Console> console);
|
PPU(shared_ptr<Console> console);
|
||||||
virtual ~PPU();
|
virtual ~PPU();
|
||||||
|
|
|
@ -277,8 +277,8 @@ int16_t SoundMixer::GetOutputVolume(bool forRightChannel)
|
||||||
#endif
|
#endif
|
||||||
GetChannelOutput(AudioChannel::EPSM_L, forRightChannel) * 4 +
|
GetChannelOutput(AudioChannel::EPSM_L, forRightChannel) * 4 +
|
||||||
GetChannelOutput(AudioChannel::EPSM_R, forRightChannel) * 4 +
|
GetChannelOutput(AudioChannel::EPSM_R, forRightChannel) * 4 +
|
||||||
GetChannelOutput(AudioChannel::InvA13, forRightChannel) * 20 +
|
(GetChannelOutput(AudioChannel::InvA13, forRightChannel) * 20) / 3.0 + // 3 PPU samples per CPU clock
|
||||||
GetChannelOutput(AudioChannel::InvOE1, forRightChannel) * 1000
|
GetChannelOutput(AudioChannel::InvOE1, forRightChannel) * 100
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ enum class IRQSource
|
||||||
FrameCounter = 2,
|
FrameCounter = 2,
|
||||||
DMC = 4,
|
DMC = 4,
|
||||||
FdsDisk = 8,
|
FdsDisk = 8,
|
||||||
|
EPSM = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MemoryOperation
|
enum class MemoryOperation
|
||||||
|
|
|
@ -41,7 +41,6 @@ private:
|
||||||
|
|
||||||
void UpdateOutputLevel()
|
void UpdateOutputLevel()
|
||||||
{
|
{
|
||||||
int16_t summedOutput = 0;
|
|
||||||
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _currentOutput - _lastOutput);
|
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _currentOutput - _lastOutput);
|
||||||
_lastOutput = _currentOutput;
|
_lastOutput = _currentOutput;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue