Amiga: better emulation, part 1

prepare to actually emulate DMA operation
eventually poke() and register view will work
This commit is contained in:
tildearrow 2023-03-09 17:46:45 -05:00
parent 0f08c6e702
commit c0b4cc0d63
4 changed files with 109 additions and 3 deletions

View file

@ -20,6 +20,7 @@
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "amiga.h" #include "amiga.h"
#include "../engine.h" #include "../engine.h"
#include "../../ta-log.h"
#include <math.h> #include <math.h>
#define AMIGA_DIVIDER 8 #define AMIGA_DIVIDER 8
@ -81,6 +82,10 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) {
for (size_t h=0; h<len; h++) { for (size_t h=0; h<len; h++) {
outL=0; outL=0;
outR=0; outR=0;
// NEW CODE
// OLD CODE
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].volPos=(chan[i].volPos+1)&AMIGA_VPMASK; chan[i].volPos=(chan[i].volPos+1)&AMIGA_VPMASK;
if (!chan[i].active) { if (!chan[i].active) {
@ -457,6 +462,9 @@ void DivPlatformAmiga::setFlags(const DivConfig& flags) {
sep1=sep+127; sep1=sep+127;
sep2=127-sep; sep2=127-sep;
amigaModel=flags.getInt("chipType",0); amigaModel=flags.getInt("chipType",0);
chipMem=flags.getInt("chipMem",21);
if (chipMem<18) chipMem=18;
if (chipMem>21) chipMem=21;
bypassLimits=flags.getBool("bypassLimits",false); bypassLimits=flags.getBool("bypassLimits",false);
if (amigaModel) { if (amigaModel) {
filtConstOff=4000; filtConstOff=4000;
@ -467,6 +475,56 @@ void DivPlatformAmiga::setFlags(const DivConfig& flags) {
} }
} }
const void* DivPlatformAmiga::getSampleMem(int index) {
return index == 0 ? sampleMem : NULL;
}
size_t DivPlatformAmiga::getSampleMemCapacity(int index) {
return index == 0 ? (1<<chipMem) : 0;
}
size_t DivPlatformAmiga::getSampleMemUsage(int index) {
return index == 0 ? sampleMemLen : 0;
}
bool DivPlatformAmiga::isSampleLoaded(int index, int sample) {
if (index!=0) return false;
if (sample<0 || sample>255) return false;
return sampleLoaded[sample];
}
void DivPlatformAmiga::renderSamples(int sysID) {
memset(sampleMem,0,2097152);
memset(sampleOff,0,256*sizeof(unsigned int));
memset(sampleLoaded,0,256*sizeof(bool));
size_t memPos=0;
for (int i=0; i<parent->song.sampleLen; i++) {
DivSample* s=parent->song.sample[i];
if (!s->renderOn[0][sysID]) {
sampleOff[i]=0;
continue;
}
if (memPos>=getSampleMemCapacity()) {
logW("out of Amiga memory for sample %d!",i);
break;
}
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
int actualLength=MIN((int)(getSampleMemCapacity()-memPos),length);
if (actualLength>0) {
sampleOff[i]=memPos;
memcpy(&sampleMem[memPos],s->data8,actualLength);
memPos+=actualLength;
}
// align memPos to short
if (memPos&1) memPos++;
sampleLoaded[i]=true;
}
sampleMemLen=memPos;
}
int DivPlatformAmiga::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { int DivPlatformAmiga::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p; parent=p;
dumpWrites=false; dumpWrites=false;
@ -487,12 +545,16 @@ int DivPlatformAmiga::init(DivEngine* p, int channels, int sugRate, const DivCon
} }
} }
sampleMem=new unsigned char[2097152];
sampleMemLen=0;
setFlags(flags); setFlags(flags);
reset(); reset();
return 6; return 6;
} }
void DivPlatformAmiga::quit() { void DivPlatformAmiga::quit() {
delete[] sampleMem;
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
delete oscBuf[i]; delete oscBuf[i];
} }

View file

@ -29,20 +29,26 @@ class DivPlatformAmiga: public DivDispatch {
unsigned int audLoc; unsigned int audLoc;
unsigned short audLen; unsigned short audLen;
unsigned int audPos; unsigned int audPos;
unsigned int dmaLoc;
unsigned short dmaLen;
int audSub; int audSub;
signed char audDat; signed char audDat;
signed char audDat2;
unsigned char volPos; unsigned char volPos;
int sample, wave; int sample, wave;
int busClock; int busClock;
bool useWave, setPos, useV, useP; bool useWave, setPos, useV, useP, dmaOn, audDatClock;
DivWaveSynth ws; DivWaveSynth ws;
Channel(): Channel():
SharedChannel<signed char>(64), SharedChannel<signed char>(64),
audLoc(0), audLoc(0),
audLen(0), audLen(0),
audPos(0), audPos(0),
dmaLoc(0),
dmaLen(0),
audSub(0), audSub(0),
audDat(0), audDat(0),
audDat2(0),
volPos(0), volPos(0),
sample(-1), sample(-1),
wave(-1), wave(-1),
@ -50,7 +56,9 @@ class DivPlatformAmiga: public DivDispatch {
useWave(false), useWave(false),
setPos(false), setPos(false),
useV(false), useV(false),
useP(false) {} useP(false),
dmaOn(false),
audDatClock(false) {}
}; };
Channel chan[4]; Channel chan[4];
DivDispatchOscBuffer* oscBuf[4]; DivDispatchOscBuffer* oscBuf[4];
@ -62,9 +70,16 @@ class DivPlatformAmiga: public DivDispatch {
int filter[2][4]; int filter[2][4];
int filtConst; int filtConst;
int filtConstOff, filtConstOn; int filtConstOff, filtConstOn;
int chipMem;
unsigned char volTable[64][64]; unsigned char volTable[64][64];
unsigned int sampleOff[256];
bool sampleLoaded[256];
unsigned char* sampleMem;
size_t sampleMemLen;
int sep1, sep2; int sep1, sep2;
friend void putDispatchChip(void*,int); friend void putDispatchChip(void*,int);
@ -86,7 +101,12 @@ class DivPlatformAmiga: public DivDispatch {
void notifyInsChange(int ins); void notifyInsChange(int ins);
void notifyWaveChange(int wave); void notifyWaveChange(int wave);
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);
void renderSamples(int chipID);
const char** getRegisterSheet(); const char** getRegisterSheet();
const void* getSampleMem(int index=0);
size_t getSampleMemCapacity(int index=0);
size_t getSampleMemUsage(int index=0);
bool isSampleLoaded(int index, int sample);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void quit(); void quit();
}; };

View file

@ -446,7 +446,7 @@ void DivPlatformSegaPCM::reset() {
} }
} }
void DivPlatformSegaPCM::renderSamples(int sysID) { void DivPlatformSegaPCM::renderSamples(int sysID) {
size_t memPos=0; size_t memPos=0;
memset(sampleMem,0,16777216); memset(sampleMem,0,16777216);

View file

@ -681,6 +681,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
case DIV_SYSTEM_AMIGA: { case DIV_SYSTEM_AMIGA: {
bool clockSel=flags.getInt("clockSel",0); bool clockSel=flags.getInt("clockSel",0);
int chipType=flags.getInt("chipType",0); int chipType=flags.getInt("chipType",0);
int chipMem=flags.getInt("chipMem",21);
int stereoSep=flags.getInt("stereoSep",0); int stereoSep=flags.getInt("stereoSep",0);
bool bypassLimits=flags.getBool("bypassLimits",false); bool bypassLimits=flags.getBool("bypassLimits",false);
@ -690,6 +691,8 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
if (stereoSep>127) stereoSep=127; if (stereoSep>127) stereoSep=127;
altered=true; altered=true;
} rightClickable } rightClickable
ImGui::Text("Model:");
if (ImGui::RadioButton("Amiga 500 (OCS)",chipType==0)) { if (ImGui::RadioButton("Amiga 500 (OCS)",chipType==0)) {
chipType=0; chipType=0;
altered=true; altered=true;
@ -698,6 +701,26 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
chipType=1; chipType=1;
altered=true; altered=true;
} }
ImGui::Text("Chip memory:");
if (ImGui::RadioButton("2MB (ECS/AGA max)",chipMem==21)) {
chipMem=21;
altered=true;
}
if (ImGui::RadioButton("1MB",chipMem==20)) {
chipMem=20;
altered=true;
}
if (ImGui::RadioButton("512KB (OCS max)",chipMem==19)) {
chipMem=19;
altered=true;
}
if (ImGui::RadioButton("256KB",chipMem==18)) {
chipMem=18;
altered=true;
}
if (ImGui::Checkbox("PAL",&clockSel)) { if (ImGui::Checkbox("PAL",&clockSel)) {
altered=true; altered=true;
} }
@ -709,6 +732,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
e->lockSave([&]() { e->lockSave([&]() {
flags.set("clockSel",(int)clockSel); flags.set("clockSel",(int)clockSel);
flags.set("chipType",chipType); flags.set("chipType",chipType);
flags.set("chipMem",chipMem);
flags.set("stereoSep",stereoSep); flags.set("stereoSep",stereoSep);
flags.set("bypassLimits",bypassLimits); flags.set("bypassLimits",bypassLimits);
}); });