mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-15 17:25:06 +00:00
Add AY-3-8914 support as configurable in AY-3-8910
Previous PR (https://github.com/tildearrow/furnace/pull/278) is closed due this, but archived for info. It's AY with 4 level envelope volume per channel and different register format.
This commit is contained in:
parent
74a23b3ec5
commit
3ac1dce3fe
5 changed files with 79 additions and 13 deletions
|
@ -4,6 +4,8 @@ this chip was used in several home computers (ZX Spectrum, MSX, Amstrad CPC, Ata
|
|||
|
||||
the chip's powerful sound comes from the envelope...
|
||||
|
||||
AY-3-8914 variant was used in Intellivision, it's basically original AY with 4 level envelope volume per channel and different register format.
|
||||
|
||||
# effects
|
||||
|
||||
- `20xx`: set channel mode. `xx` may be one of the following:
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <math.h>
|
||||
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
|
||||
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(regRemap(a),v); if (dumpWrites) {addWrite(regRemap(a),v);} }
|
||||
|
||||
#define CHIP_DIVIDER 8
|
||||
|
||||
|
@ -48,8 +48,28 @@ const char* regCheatSheetAY[]={
|
|||
NULL
|
||||
};
|
||||
|
||||
const char* regCheatSheetAY8914[]={
|
||||
"FreqL_A", "0",
|
||||
"FreqL_B", "1",
|
||||
"FreqL_C", "2",
|
||||
"FreqL_Env", "3",
|
||||
"FreqH_A", "4",
|
||||
"FreqH_B", "5",
|
||||
"FreqH_C", "6",
|
||||
"FreqH_Env", "7",
|
||||
"Enable", "8",
|
||||
"FreqNoise", "9",
|
||||
"Control_Env", "A",
|
||||
"Volume_A", "B",
|
||||
"Volume_B", "C",
|
||||
"Volume_C", "D",
|
||||
"PortA", "E",
|
||||
"PortB", "F",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformAY8910::getRegisterSheet() {
|
||||
return regCheatSheetAY;
|
||||
return intellivision?regCheatSheetAY8914:regCheatSheetAY;
|
||||
}
|
||||
|
||||
const char* DivPlatformAY8910::getEffectName(unsigned char effect) {
|
||||
|
@ -92,8 +112,13 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
}
|
||||
while (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
ay->address_w(w.addr);
|
||||
ay->data_w(w.val);
|
||||
if (intellivision) {
|
||||
ay8914_device* ay8914=(ay8914_device*)ay;
|
||||
ay8914->write(w.addr,w.val);
|
||||
} else {
|
||||
ay->address_w(w.addr);
|
||||
ay->data_w(w.val);
|
||||
}
|
||||
regPool[w.addr&0x0f]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
@ -125,6 +150,8 @@ void DivPlatformAY8910::tick() {
|
|||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else if (intellivision && (chan[i].psgMode&4)) {
|
||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
||||
}
|
||||
|
@ -151,6 +178,8 @@ void DivPlatformAY8910::tick() {
|
|||
chan[i].psgMode=(chan[i].std.wave+1)&7;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else if (intellivision && (chan[i].psgMode&4)) {
|
||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
||||
}
|
||||
|
@ -242,6 +271,8 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
chan[c.chan].std.init(ins);
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
}
|
||||
|
@ -264,7 +295,13 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
if (chan[c.chan].active) {
|
||||
if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -317,7 +354,11 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (chan[c.chan].active) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -334,6 +375,8 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
}
|
||||
|
@ -383,6 +426,8 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) {
|
|||
isMuted[ch]=mute;
|
||||
if (isMuted[ch]) {
|
||||
rWrite(0x08+ch,0);
|
||||
} else if (intellivision && (chan[ch].psgMode&4)) {
|
||||
rWrite(0x08+ch,(chan[ch].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode&4)<<2));
|
||||
}
|
||||
|
@ -508,14 +553,22 @@ void DivPlatformAY8910::setFlags(unsigned int flags) {
|
|||
case 1:
|
||||
ay=new ym2149_device(rate);
|
||||
sunsoft=false;
|
||||
intellivision=false;
|
||||
break;
|
||||
case 2:
|
||||
ay=new sunsoft_5b_sound_device(rate);
|
||||
sunsoft=true;
|
||||
intellivision=false;
|
||||
break;
|
||||
case 3:
|
||||
ay=new ay8914_device(rate);
|
||||
sunsoft=false;
|
||||
intellivision=true;
|
||||
break;
|
||||
default:
|
||||
ay=new ay8910_device(rate);
|
||||
sunsoft=false;
|
||||
intellivision=false;
|
||||
break;
|
||||
}
|
||||
ay->device_start();
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
|
||||
class DivPlatformAY8910: public DivDispatch {
|
||||
protected:
|
||||
const unsigned char AY8914RegRemap[16]={
|
||||
0,4,1,5,2,6,9,8,11,12,13,3,7,10,14,15
|
||||
};
|
||||
inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
|
||||
struct Channel {
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, note, pitch;
|
||||
|
@ -60,7 +64,7 @@ class DivPlatformAY8910: public DivDispatch {
|
|||
int delay;
|
||||
|
||||
bool extMode;
|
||||
bool stereo, sunsoft;
|
||||
bool stereo, sunsoft, intellivision;
|
||||
|
||||
short oldWrites[16];
|
||||
short pendingWrites[16];
|
||||
|
|
|
@ -419,10 +419,6 @@ const char* DivEngine::getSongSystemName() {
|
|||
return "Vectrex";
|
||||
case 5: // AY-3-8910, 1MHz
|
||||
return "Amstrad CPC";
|
||||
case 6: // AY-3-8910, 0.somethingMhz
|
||||
return "Intellivision";
|
||||
case 8: // AY-3-8910, 0.somethingMhz
|
||||
return "Intellivision (PAL)";
|
||||
|
||||
case 0x10: // YM2149, 1.79MHz
|
||||
return "MSX";
|
||||
|
@ -432,7 +428,12 @@ const char* DivEngine::getSongSystemName() {
|
|||
return "Sunsoft 5B standalone";
|
||||
case 0x28: // 5B PAL
|
||||
return "Sunsoft 5B standalone (PAL)";
|
||||
|
||||
|
||||
case 0x30: // AY-3-8914, 1.79MHz
|
||||
return "Intellivision";
|
||||
case 0x33: // AY-3-8914, 2MHz
|
||||
return "Intellivision (PAL)";
|
||||
|
||||
default:
|
||||
if ((song.systemFlags[0]&0x30)==0x00) {
|
||||
return "AY-3-8910";
|
||||
|
@ -440,6 +441,8 @@ const char* DivEngine::getSongSystemName() {
|
|||
return "Yamaha YM2149";
|
||||
} else if ((song.systemFlags[0]&0x30)==0x20) {
|
||||
return "Overclocked Sunsoft 5B";
|
||||
} else if ((song.systemFlags[0]&0x30)==0x30) {
|
||||
return "Intellivision";
|
||||
}
|
||||
}
|
||||
} else if (song.system[0]==DIV_SYSTEM_SMS) {
|
||||
|
|
|
@ -5116,6 +5116,10 @@ bool FurnaceGUI::loop() {
|
|||
e->setSysFlags(i,(flags&(~0x30))|32,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
if (ImGui::RadioButton("AY-3-8914",(flags&0x30)==48)) {
|
||||
e->setSysFlags(i,(flags&(~0x30))|48,restart);
|
||||
updateWindowTitle();
|
||||
}
|
||||
}
|
||||
bool stereo=flags&0x40;
|
||||
ImGui::BeginDisabled((flags&0x30)==32);
|
||||
|
@ -6684,7 +6688,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"Mattel Intellivision", {
|
||||
DIV_SYSTEM_AY8910, 64, 0, 6,
|
||||
DIV_SYSTEM_AY8910, 64, 0, 48,
|
||||
0
|
||||
}
|
||||
));
|
||||
|
|
Loading…
Reference in a new issue