diff --git a/src/asm/68k/amigatest/Makefile b/src/asm/68k/amigatest/Makefile new file mode 100644 index 000000000..19f1cdc15 --- /dev/null +++ b/src/asm/68k/amigatest/Makefile @@ -0,0 +1,4 @@ +all: player + +player: player.s + vasmm68k_mot -Fhunkexe -kick1hunks -o player player.s diff --git a/src/asm/68k/amigatest/README.md b/src/asm/68k/amigatest/README.md index 7cb5b0cdb..20ae10b84 100644 --- a/src/asm/68k/amigatest/README.md +++ b/src/asm/68k/amigatest/README.md @@ -26,24 +26,23 @@ run a.out on Amiga. it should play the exported song. # sequence format -## 00-0F: global +## 00-0F: per-channel (00, 10, 20, 30) -- 00: do nothing -- 01: next tick -- 02 xx: wait -- 03 xxxx: wait -- 06 xxxx: write to DMACON -- 0a xxxx: write to INTENA -- 0e xxxx: write to ADKCON - -## 10-1F: per-channel (10, 20, 30, 40) - -- 10 xxxxxx yyyy zzzzzz wwww: set loc/len +- 00 xxxxxx yyyy: set loc/len - x: loc - y: len - - z: loc after interrupt - - w: len after interrupt -- 12 xxxx yy: initialize wavetable (xxxx: pos; yy: length) -- 16 xxxx: set period -- 18 xx: set volume -- 1a xxxx: set data +- 01 xxxx yy: initialize wavetable (xxxx: pos; yy: length) +- 06 xxxx: set period +- 08 xx: set volume +- 0a xxxx: set data + +## F0-FF: global + +- f0: do nothing +- f1: next tick +- f2 xx: wait +- f3 xxxx: wait +- f6 xxxx: write to DMACON +- fa xxxx: write to INTENA +- fe xxxx: write to ADKCON +- ff: end of song diff --git a/src/asm/68k/amigatest/player.s b/src/asm/68k/amigatest/player.s index b382a77f6..3b36284e4 100644 --- a/src/asm/68k/amigatest/player.s +++ b/src/asm/68k/amigatest/player.s @@ -5,9 +5,34 @@ VPOSR = $dff004 COLOR00 = $dff180 +DMACONR = $dff002 +DMACON = $dff096 +AUD0LCH = $dff0a0 +AUD0LCL = $dff0a2 +AUD0LEN = $dff0a4 +AUD0PER = $dff0a6 +AUD0VOL = $dff0a8 +AUD0DAT = $dff0aa cseg - move.l #0,d0 + move.w #15,d0 + move.w d0,DMACON + +testDMACon: + move.w DMACON,d0 + btst #0,d0 + bne testDMACon + + lea sampleData(pc),a0 + move.l a0,AUD0LCH + move.w #$2000,d0 + move.w d0,AUD0LEN + move.w #$a0,d0 + move.w d0,AUD0PER + move.w #$40,d0 + move.w d0,AUD0VOL + move.l #$8201,d0 + move.w d0,DMACON main: jsr waitVBlank @@ -30,3 +55,14 @@ data_c curColor: dc.w 0 + +sampleData: + incbin "sample.bin" + +data_f + +sequence: + incbin "seq.bin" + +wavetable: + incbin "wave.bin" diff --git a/src/engine/engine.h b/src/engine/engine.h index e5deb7ace..7b84f5da2 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -48,6 +48,10 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; +#define EXTERN_BUSY_BEGIN e->softLocked=false; e->isBusy.lock(); +#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock(); +#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; + #define DIV_VERSION "dev145" #define DIV_ENGINE_VERSION 145 // for imports diff --git a/src/engine/export/amigaValidation.cpp b/src/engine/export/amigaValidation.cpp index 7552350e1..02811d753 100644 --- a/src/engine/export/amigaValidation.cpp +++ b/src/engine/export/amigaValidation.cpp @@ -19,9 +19,135 @@ #include "amigaValidation.h" #include "../engine.h" +#include "../platform/amiga.h" std::vector DivExportAmigaValidation::go(DivEngine* e) { - e->testFunction(); + std::vector ret; + DivPlatformAmiga* amiga=(DivPlatformAmiga*)e->getDispatch(0); - return std::vector(); + e->stop(); + e->repeatPattern=false; + e->setOrder(0); + EXTERN_BUSY_BEGIN_SOFT; + + // determine loop point + int loopOrder=0; + int loopRow=0; + int loopEnd=0; + e->walkSong(loopOrder,loopRow,loopEnd); + + e->curOrder=0; + e->freelance=false; + e->playing=false; + e->extValuePresent=false; + e->remainingLoops=-1; + + // play the song ourselves + bool done=false; + + // sample.bin + SafeWriter* sample=new SafeWriter; + sample->init(); + for (int i=0; i<256; i++) { + sample->writeI(0); + } + sample->write(&((const unsigned char*)amiga->getSampleMem(0))[0x400],amiga->getSampleMemUsage(0)-0x400); + if (sample->tell()&1) sample->writeC(0); + + // wave.bin + SafeWriter* wave=new SafeWriter; + wave->init(); + for (int i=0; i<32; i++) { + sample->writeC(i<<3); + } + + // seq.bin + SafeWriter* seq=new SafeWriter; + seq->init(); + + amiga->toggleRegisterDump(true); + + // write song data + e->playSub(false); + size_t songTick=0; + size_t lastTick=0; + bool writeLoop=false; + int loopPos=-1; + for (int i=0; ichans; i++) { + e->chan[i].wentThroughNote=false; + e->chan[i].goneThroughNote=false; + } + while (!done) { + if (loopPos==-1) { + if (loopOrder==e->curOrder && loopRow==e->curRow && e->ticks==1) { + writeLoop=true; + } + } + if (e->nextTick(false,true)) { + done=true; + amiga->getRegisterWrites().clear(); + break; + } + // get register writes + std::vector& writes=amiga->getRegisterWrites(); + for (DivRegWrite& j: writes) { + if (lastTick!=songTick) { + int delta=songTick-lastTick; + if (delta==1) { + seq->writeC(0xf1); + } else if (delta<256) { + seq->writeC(0xf2); + seq->writeC(delta); + } else if (delta<65536) { + seq->writeC(0xf3); + seq->writeS_BE(delta); + } + lastTick=songTick; + } + if (j.addr>=0x200) { // direct loc/len change + if (j.addr&4) { // len + seq->writeS_BE(j.val); + } else { // loc + seq->writeC((j.addr&3)<<4); + seq->writeC(j.val>>16); + seq->writeC(j.val>>8); + seq->writeC(j.val); + } + } else if (j.addr<0xa0) { + // don't write INTENA + if ((j.addr&15)!=10) { + seq->writeC(0xf0|(j.addr&15)); + seq->writeS_BE(j.val); + } + } else if ((j.addr&15)!=0 && (j.addr&15)!=2 && (j.addr&15)!=4) { + seq->writeC(j.addr-0xa0); + if ((j.addr&15)==8) { + seq->writeC(j.val); + } else { + seq->writeS_BE(j.val); + } + } + } + writes.clear(); + + songTick++; + } + // end of song + seq->writeC(0xff); + + amiga->toggleRegisterDump(false); + + e->remainingLoops=-1; + e->playing=false; + e->freelance=false; + e->extValuePresent=false; + + EXTERN_BUSY_END; + + // finish + ret.push_back(DivROMExportOutput("sample.bin",sample)); + ret.push_back(DivROMExportOutput("wave.bin",wave)); + ret.push_back(DivROMExportOutput("seq.bin",seq)); + + return ret; } diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 2a5e9729b..ac67460b3 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -419,6 +419,10 @@ void DivPlatformAmiga::tick(bool sysTick) { chWrite(i,0,0); chWrite(i,2,i<<8); chWrite(i,4,chan[i].audLen); + if (dumpWrites) { + addWrite(0x200+i,i<<8); + addWrite(0x204+i,chan[i].audLen); + } rWrite(0x96,0x8000|(1<=0 && chan[i].samplesong.sampleLen) { @@ -436,10 +440,18 @@ void DivPlatformAmiga::tick(bool sysTick) { chWrite(i,0,0); chWrite(i,2,0x400); chWrite(i,4,1); + if (dumpWrites) { + addWrite(0x200+i,0x400); + addWrite(0x204+i,1); + } } else { chWrite(i,0,start>>16); chWrite(i,2,start); chWrite(i,4,len); + if (dumpWrites) { + addWrite(0x200+i,start); + addWrite(0x204+i,len); + } } rWrite(0x96,0x8000|(1< // 0: all directions @@ -575,6 +577,40 @@ void FurnaceGUI::drawMobileControls() { if (ImGui::Button("Switch to Desktop Mode")) { toggleMobileUI(!mobileUI); } + + int numAmiga=0; + for (int i=0; isong.systemLen; i++) { + if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++; + } + + if (numAmiga) { + ImGui::Text( + "this is NOT ROM export! only use for making sure the\n" + "Furnace Amiga emulator is working properly by\n" + "comparing it with real Amiga output." + ); + ImGui::Text("Directory"); + ImGui::SameLine(); + ImGui::InputText("##AVDPath",&workingDirROMExport); + if (ImGui::Button("Bake Data")) { + std::vector out=e->buildROM(DIV_ROM_AMIGA_VALIDATION); + if (workingDirROMExport.size()>0) { + if (workingDirROMExport[workingDirROMExport.size()-1]!=DIR_SEPARATOR) workingDirROMExport+=DIR_SEPARATOR_STR; + } + for (DivROMExportOutput& i: out) { + String path=workingDirROMExport+i.name; + FILE* outFile=ps_fopen(path.c_str(),"wb"); + if (outFile!=NULL) { + fwrite(i.data->getFinalBuf(),1,i.data->size(),outFile); + fclose(outFile); + } + i.data->finish(); + delete i.data; + } + showError(fmt::sprintf("Done! Baked %d files.",(int)out.size())); + } + } + break; } } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 010e9f16c..ff530fa89 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3697,6 +3697,7 @@ bool FurnaceGUI::loop() { ImGui::SameLine(); ImGui::InputText("##AVDPath",&workingDirROMExport); if (ImGui::Button("Bake Data")) { + std::vector out=e->buildROM(DIV_ROM_AMIGA_VALIDATION); ImGui::CloseCurrentPopup(); } ImGui::EndMenu();