cog/Frameworks/libsidplay/sidplay-residfp-code/.svn/pristine/62/622a8a92c5e2d467b166bbcc484...

255 lines
7.0 KiB
Plaintext

// ---------------------------------------------------------------------------
// This file is part of reSID, a MOS6581 SID emulator engine.
// Copyright (C) 2010 Dag Lem <resid@nimrod.no>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// ---------------------------------------------------------------------------
#define RESID_WAVE_CC
#include "wave.h"
#include "dac.h"
namespace reSID
{
// Waveform lookup tables.
unsigned short WaveformGenerator::model_wave[2][8][1 << 12] = {
{
{0},
{0},
{0},
#include "wave6581__ST.h"
{0},
#include "wave6581_P_T.h"
#include "wave6581_PS_.h"
#include "wave6581_PST.h"
},
{
{0},
{0},
{0},
#include "wave8580__ST.h"
{0},
#include "wave8580_P_T.h"
#include "wave8580_PS_.h"
#include "wave8580_PST.h"
}
};
// DAC lookup tables.
unsigned short WaveformGenerator::model_dac[2][1 << 12] = {
{0},
{0},
};
// ----------------------------------------------------------------------------
// Constructor.
// ----------------------------------------------------------------------------
WaveformGenerator::WaveformGenerator()
{
static bool class_init;
if (!class_init) {
// Calculate tables for normal waveforms.
accumulator = 0;
for (int i = 0; i < (1 << 12); i++) {
reg24 msb = accumulator & 0x800000;
// Noise mask, triangle, sawtooth, pulse mask.
// The triangle calculation is made branch-free, just for the hell of it.
model_wave[0][0][i] = model_wave[1][0][i] = 0xfff;
model_wave[0][1][i] = model_wave[1][1][i] =
((accumulator ^ -!!msb) >> 11) & 0xffe;
model_wave[0][2][i] = model_wave[1][2][i] = accumulator >> 12;
model_wave[0][4][i] = model_wave[1][4][i] = 0xfff;
accumulator += 0x1000;
}
// Build DAC lookup tables for 12-bit DACs.
// MOS 6581: 2R/R ~ 2.20, missing termination resistor.
build_dac_table(model_dac[0], 12, 2.20, false);
// MOS 8580: 2R/R ~ 2.00, correct termination.
build_dac_table(model_dac[1], 12, 2.00, true);
class_init = true;
}
sync_source = this;
sid_model = MOS6581;
reset();
}
// ----------------------------------------------------------------------------
// Set sync source.
// ----------------------------------------------------------------------------
void WaveformGenerator::set_sync_source(WaveformGenerator* source)
{
sync_source = source;
source->sync_dest = this;
}
// ----------------------------------------------------------------------------
// Set chip model.
// ----------------------------------------------------------------------------
void WaveformGenerator::set_chip_model(chip_model model)
{
sid_model = model;
wave = model_wave[model][waveform & 0x7];
}
// ----------------------------------------------------------------------------
// Register functions.
// ----------------------------------------------------------------------------
void WaveformGenerator::writeFREQ_LO(reg8 freq_lo)
{
freq = (freq & 0xff00) | (freq_lo & 0x00ff);
}
void WaveformGenerator::writeFREQ_HI(reg8 freq_hi)
{
freq = ((freq_hi << 8) & 0xff00) | (freq & 0x00ff);
}
void WaveformGenerator::writePW_LO(reg8 pw_lo)
{
pw = (pw & 0xf00) | (pw_lo & 0x0ff);
// Push next pulse level into pulse level pipeline.
pulse_output = (accumulator >> 12) >= pw ? 0xfff : 0x000;
}
void WaveformGenerator::writePW_HI(reg8 pw_hi)
{
pw = ((pw_hi << 8) & 0xf00) | (pw & 0x0ff);
// Push next pulse level into pulse level pipeline.
pulse_output = (accumulator >> 12) >= pw ? 0xfff : 0x000;
}
void WaveformGenerator::writeCONTROL_REG(reg8 control)
{
reg8 waveform_prev = waveform;
reg8 test_prev = test;
waveform = (control >> 4) & 0x0f;
test = control & 0x08;
ring_mod = control & 0x04;
sync = control & 0x02;
// Set up waveform table.
wave = model_wave[sid_model][waveform & 0x7];
// Substitution of accumulator MSB when sawtooth = 0, ring_mod = 1.
ring_msb_mask = ((~control >> 5) & (control >> 2) & 0x1) << 23;
// no_noise and no_pulse are used in set_waveform_output() as bitmasks to
// only let the noise or pulse influence the output when the noise or pulse
// waveforms are selected.
no_noise = waveform & 0x8 ? 0x000 : 0xfff;
no_noise_or_noise_output = no_noise | noise_output;
no_pulse = waveform & 0x4 ? 0x000 : 0xfff;
// Test bit rising.
// The accumulator is cleared, while the the shift register is prepared for
// shifting by interconnecting the register bits. The internal SRAM cells
// start to slowly rise up towards one. The SRAM cells reach one within
// approximately $8000 cycles, yielding a shift register value of
// 0x7fffff.
if (!test_prev && test) {
// Reset accumulator.
accumulator = 0;
// Flush shift pipeline.
shift_pipeline = 0;
// Set reset time for shift register.
shift_register_reset = 0x8000;
// The test bit sets pulse high.
pulse_output = 0xfff;
}
else if (test_prev && !test) {
// When the test bit is falling, the second phase of the shift is
// completed by enabling SRAM write.
// bit0 = (bit22 | test) ^ bit17 = 1 ^ bit17 = ~bit17
reg24 bit0 = (~shift_register >> 17) & 0x1;
shift_register = ((shift_register << 1) | bit0) & 0x7fffff;
// Set new noise waveform output.
set_noise_output();
}
if (waveform) {
// Set new waveform output.
set_waveform_output();
}
else if (waveform_prev) {
// Change to floating DAC input.
// Reset fading time for floating DAC input.
//
// We have two SOAS/C samplings showing that floating DAC
// keeps its state for at least 0x14000 cycles.
//
// This can't be found via sampling OSC3, it seems that
// the actual analog output must be sampled and timed.
floating_output_ttl = 0x14000;
}
// The gate bit is handled by the EnvelopeGenerator.
}
reg8 WaveformGenerator::readOSC()
{
return waveform_output >> 4;
}
// ----------------------------------------------------------------------------
// SID reset.
// ----------------------------------------------------------------------------
void WaveformGenerator::reset()
{
accumulator = 0;
freq = 0;
pw = 0;
msb_rising = false;
waveform = 0;
test = 0;
ring_mod = 0;
sync = 0;
wave = model_wave[sid_model][0];
ring_msb_mask = 0;
no_noise = 0xfff;
no_pulse = 0xfff;
pulse_output = 0xfff;
reset_shift_register();
shift_pipeline = 0;
waveform_output = 0;
floating_output_ttl = 0;
}
} // namespace reSID