29static constexpr int R07_RESET = 0x01;
30static constexpr int R07_SP_OFF = 0x08;
31static constexpr int R07_REPEAT = 0x10;
32static constexpr int R07_MEMORY_DATA = 0x20;
33static constexpr int R07_REC = 0x40;
34static constexpr int R07_START = 0x80;
35static constexpr int R07_MODE = 0xE0;
38static constexpr int R08_ROM = 0x01;
39static constexpr int R08_64K = 0x02;
40static constexpr int R08_DA_AD = 0x04;
41static constexpr int R08_SAMPL = 0x08;
42static constexpr int R08_NOTE_SET = 0x40;
43static constexpr int R08_CSM = 0x80;
45static constexpr int DIFF_MAX = 0x6000;
46static constexpr int DIFF_MIN = 0x7F;
47static constexpr int DIFF_DEFAULT = 0x7F;
49static constexpr int STEP_BITS = 16;
50static constexpr int STEP_MASK = (1 << STEP_BITS) -1;
54 const std::string& name,
unsigned sampleRam)
57 , ram(config, name +
" RAM",
"Y8950 sample RAM", sampleRam)
58 , clock(config.getMotherBoard().getCurrentTime())
77 addrMask = (1 << 18) - 1;
90bool Y8950Adpcm::isPlaying()
const
92 return (reg7 & 0xC0) == 0x80;
96 return !isPlaying() || (reg7 & R07_SP_OFF);
99void Y8950Adpcm::restart(PlayData& pd)
const
101 pd.memPtr = startAddr;
102 pd.nowStep = (1 << STEP_BITS) - delta;
105 pd.diff = DIFF_DEFAULT;
115 for (
unsigned i = 0; isPlaying() && (i < ticks); ++i) {
122void Y8950Adpcm::schedule()
125 if ((stopAddr > startAddr) && (delta != 0)) {
129 if (reg7 & R07_MEMORY_DATA) {
132 uint64_t samples = stopAddr - emu.memPtr + 1;
133 uint64_t length = (samples << STEP_BITS) +
134 ((1 << STEP_BITS) - emu.nowStep) +
136 stop += unsigned(length / delta);
146void Y8950Adpcm::executeUntil(EmuTime::param time)
151 if (isPlaying() && (reg7 & R07_REPEAT)) {
162 if (reg7 & R07_START) {
167 if (reg7 & R07_RESET) {
170 if (reg7 & R07_START) {
175 if (reg7 & R07_MEMORY_DATA) {
177 emu.memPtr = startAddr;
178 aud.memPtr = startAddr;
180 if ((reg7 & 0xA0) == 0x20) {
196 romBank = data & R08_ROM;
197 addrMask = data & R08_64K ? (1 << 16) - 1 : (1 << 18) - 1;
201 startAddr = (startAddr & 0x7F807) | (data << 3);
204 startAddr = (startAddr & 0x007FF) | (data << 11);
208 stopAddr = (stopAddr & 0x7F807) | (data << 3);
215 stopAddr = (stopAddr & 0x007FF) | (data << 11);
227 delta = (delta & 0xFF00) | data;
228 volumeWStep = (volume * delta) >> STEP_BITS;
235 delta = (delta & 0x00FF) | (data << 8);
236 volumeWStep = (volume * delta) >> STEP_BITS;
245 volumeWStep = (volume * delta) >> STEP_BITS;
259void Y8950Adpcm::writeData(
byte data)
262 if ((reg7 & R07_MODE) == 0x60) {
264 assert(!isPlaying());
266 emu.memPtr = startAddr;
269 if (emu.memPtr <= stopAddr) {
270 writeMemory(emu.memPtr, data);
286 if (emu.memPtr > stopAddr) {
293 emu.memPtr = startAddr;
297 }
else if ((reg7 & R07_MODE) == 0x80) {
309 byte result = (rg == 0x0F)
330 return narrow_cast<byte>((emu.output >> 8) & 0xFF);
332 return narrow_cast<byte>((emu.output >> 16) & 0xFF);
356 if (((reg7 & R07_MODE & ~R07_REC) == R07_MEMORY_DATA) ||
357 ((reg7 & R07_MODE) == 0)){
363byte Y8950Adpcm::readData()
365 if ((reg7 & R07_MODE) == R07_MEMORY_DATA) {
367 assert(!isPlaying());
369 emu.memPtr = startAddr;
372 byte result = peekData();
373 if ((reg7 & R07_MODE) == R07_MEMORY_DATA) {
374 assert(!isPlaying());
379 }
else if (emu.memPtr > stopAddr) {
402byte Y8950Adpcm::peekData()
const
404 if ((reg7 & R07_MODE) == R07_MEMORY_DATA) {
406 assert(!isPlaying());
409 }
else if (emu.memPtr > stopAddr) {
412 return readMemory(emu.memPtr);
419void Y8950Adpcm::writeMemory(
unsigned memPtr,
byte value)
421 unsigned addr = (memPtr / 2) & addrMask;
422 if ((addr < ram.
size()) && !romBank) {
423 ram.
write(addr, value);
426byte Y8950Adpcm::readMemory(
unsigned memPtr)
const
428 unsigned addr = (memPtr / 2) & addrMask;
429 if (romBank || (addr >= ram.
size())) {
439 if (!isPlaying())
return 0;
441 return (reg7 & R07_SP_OFF) ? 0 : output;
447 static constexpr std::array<int, 16> F1 = {
448 1, 3, 5, 7, 9, 11, 13, 15,
449 -1, -3, -5, -7, -9, -11, -13, -15
451 static constexpr std::array<int, 16> F2 = {
452 57, 57, 57, 57, 77, 102, 128, 153,
453 57, 57, 57, 57, 77, 102, 128, 153
458 PlayData& pd = doEmu ? emu : aud;
460 if (pd.nowStep & ~STEP_MASK) {
461 pd.nowStep &= STEP_MASK;
463 if (!(pd.memPtr & 1)) {
465 if (reg7 & R07_MEMORY_DATA) {
466 pd.adpcm_data = readMemory(pd.memPtr);
468 pd.adpcm_data = reg15;
474 return byte(pd.adpcm_data >> 4);
477 return byte(pd.adpcm_data & 0x0F);
480 int prevOut = pd.out;
482 pd.diff = std::clamp((pd.diff * F2[val]) / 64, DIFF_MIN, DIFF_MAX);
484 int prevLeveling = pd.nextLeveling;
485 pd.nextLeveling = (prevOut + pd.out) / 2;
486 int deltaLeveling = pd.nextLeveling - prevLeveling;
487 pd.sampleStep = deltaLeveling * volumeWStep;
488 int tmp = deltaLeveling * ((volume * narrow<int>(pd.nowStep)) >> STEP_BITS);
489 pd.output = prevLeveling * volume + tmp;
492 if ((reg7 & R07_MEMORY_DATA) &&
493 (pd.memPtr > stopAddr)) {
503 if (reg7 & R07_REPEAT) {
513 pd.output += pd.sampleStep;
515 return pd.output >> 12;
525template<
typename Archive>
528 ar.template serializeBase<Schedulable>(*
this);
529 ar.serialize(
"ram", ram,
530 "startAddr", startAddr,
531 "stopAddr", stopAddr,
532 "addrMask", addrMask,
534 "volumeWStep", volumeWStep,
535 "readDelay", readDelay,
541 "memPntr", emu.memPtr,
542 "nowStep", emu.nowStep,
544 "output", emu.output,
546 "nextLeveling", emu.nextLeveling,
547 "sampleStep", emu.sampleStep,
548 "adpcm_data", emu.adpcm_data);
549 if constexpr (Archive::IS_LOADER) {
555 if (ar.versionBelow(version, 2)) {
565 ar.serialize(
"clock", clock);
Represents a clock with a fixed frequency.
constexpr void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
constexpr void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past the given time.
constexpr unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Every class that wants to get scheduled at some point must inherit from this class.
void setSyncPoint(EmuTime::param timestamp)
EmuTime::param getCurrentTime() const
Convenience method: This is the same as getScheduler().getCurrentTime().
void write(size_t addr, byte value)
void sync(EmuTime::param time)
byte readReg(byte rg, EmuTime::param time)
byte peekReg(byte rg, EmuTime::param time) const
Y8950Adpcm(Y8950 &y8950, const DeviceConfig &config, const std::string &name, unsigned sampleRam)
void writeReg(byte rg, byte data, EmuTime::param time)
void serialize(Archive &ar, unsigned version)
void reset(EmuTime::param time)
static constexpr int STATUS_BUF_RDY
void setStatus(uint8_t flags)
static constexpr int STATUS_PCM_BSY
void resetStatus(uint8_t flags)
static constexpr int STATUS_EOS
uint8_t peekRawStatus() const
int16_t clipToInt16(T x)
Clip x to range [-32768,32767].
This file implemented 3 utility functions:
uint8_t byte
8 bit unsigned integer
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)