more command stream work
including a disassembler, large stack, and some other things
This commit is contained in:
parent
39ea7e6da0
commit
f7c2fce461
|
@ -24,7 +24,7 @@
|
||||||
#include "../ta-log.h"
|
#include "../ta-log.h"
|
||||||
|
|
||||||
bool DivCSChannelState::doCall(unsigned int addr) {
|
bool DivCSChannelState::doCall(unsigned int addr) {
|
||||||
if (callStackPos>=8) {
|
if (callStackPos>=16) {
|
||||||
readPos=0;
|
readPos=0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,10 @@ DivCSChannelState* DivCSPlayer::getChanState(int ch) {
|
||||||
return &chan[ch];
|
return &chan[ch];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int DivCSPlayer::getFileChans() {
|
||||||
|
return fileChans;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char* DivCSPlayer::getFastDelays() {
|
unsigned char* DivCSPlayer::getFastDelays() {
|
||||||
return fastDelays;
|
return fastDelays;
|
||||||
}
|
}
|
||||||
|
@ -471,9 +475,9 @@ bool DivCSPlayer::init() {
|
||||||
|
|
||||||
if (memcmp(magic,"FCS",4)!=0) return false;
|
if (memcmp(magic,"FCS",4)!=0) return false;
|
||||||
|
|
||||||
unsigned int chans=stream.readI();
|
fileChans=stream.readI();
|
||||||
|
|
||||||
for (unsigned int i=0; i<chans; i++) {
|
for (unsigned int i=0; i<fileChans; i++) {
|
||||||
if (i>=DIV_MAX_CHANS) {
|
if (i>=DIV_MAX_CHANS) {
|
||||||
stream.readI();
|
stream.readI();
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct DivCSChannelState {
|
||||||
int portaTarget, portaSpeed;
|
int portaTarget, portaSpeed;
|
||||||
unsigned char arp, arpStage, arpTicks, loopCount;
|
unsigned char arp, arpStage, arpTicks, loopCount;
|
||||||
|
|
||||||
unsigned int callStack[8];
|
unsigned int callStack[16];
|
||||||
unsigned char callStackPos;
|
unsigned char callStackPos;
|
||||||
|
|
||||||
unsigned int trace[DIV_MAX_CSTRACE];
|
unsigned int trace[DIV_MAX_CSTRACE];
|
||||||
|
@ -83,12 +83,14 @@ class DivCSPlayer {
|
||||||
unsigned char fastDelays[16];
|
unsigned char fastDelays[16];
|
||||||
unsigned char fastCmds[16];
|
unsigned char fastCmds[16];
|
||||||
unsigned char arpSpeed;
|
unsigned char arpSpeed;
|
||||||
|
unsigned int fileChans;
|
||||||
|
|
||||||
short vibTable[64];
|
short vibTable[64];
|
||||||
public:
|
public:
|
||||||
unsigned char* getData();
|
unsigned char* getData();
|
||||||
size_t getDataLen();
|
size_t getDataLen();
|
||||||
DivCSChannelState* getChanState(int ch);
|
DivCSChannelState* getChanState(int ch);
|
||||||
|
unsigned int getFileChans();
|
||||||
unsigned char* getFastDelays();
|
unsigned char* getFastDelays();
|
||||||
unsigned char* getFastCmds();
|
unsigned char* getFastCmds();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
@ -101,4 +103,9 @@ class DivCSPlayer {
|
||||||
stream(buf,len) {}
|
stream(buf,len) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// command stream utilities
|
||||||
|
namespace DivCS {
|
||||||
|
int getInsLength(unsigned char ins, unsigned char ext=0);
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
//#define DISABLE_BLOCK_SEARCH
|
//#define DISABLE_BLOCK_SEARCH
|
||||||
|
|
||||||
int getInsLength(unsigned char ins) {
|
int DivCS::getInsLength(unsigned char ins, unsigned char ext) {
|
||||||
switch (ins) {
|
switch (ins) {
|
||||||
case 0xb8: // ins
|
case 0xb8: // ins
|
||||||
case 0xc0: // pre porta
|
case 0xc0: // pre porta
|
||||||
|
@ -49,8 +49,11 @@ int getInsLength(unsigned char ins) {
|
||||||
case 0xf0: // opt
|
case 0xf0: // opt
|
||||||
return 4;
|
return 4;
|
||||||
case 0xf2: // opt command
|
case 0xf2: // opt command
|
||||||
case 0xf7: // cmd
|
case 0xf7: { // cmd
|
||||||
|
// determine length from secondary
|
||||||
|
if (ext==0) return 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
case 0xf8: // callb16
|
case 0xf8: // callb16
|
||||||
case 0xfc: // waits
|
case 0xfc: // waits
|
||||||
return 3;
|
return 3;
|
||||||
|
@ -232,6 +235,8 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using namespace DivCS;
|
||||||
|
|
||||||
void reloc(unsigned char* buf, size_t len, unsigned int sourceAddr, unsigned int destAddr) {
|
void reloc(unsigned char* buf, size_t len, unsigned int sourceAddr, unsigned int destAddr) {
|
||||||
unsigned int delta=destAddr-sourceAddr;
|
unsigned int delta=destAddr-sourceAddr;
|
||||||
for (size_t i=0; i<len;) {
|
for (size_t i=0; i<len;) {
|
||||||
|
@ -325,6 +330,7 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlock
|
||||||
size_t subBlockID=subBlocks.size();
|
size_t subBlockID=subBlocks.size();
|
||||||
int insLen=getInsLength(buf[searchPos]);
|
int insLen=getInsLength(buf[searchPos]);
|
||||||
bool haveSub=false;
|
bool haveSub=false;
|
||||||
|
bool onlyCalls=true;
|
||||||
|
|
||||||
if (insLen<1) {
|
if (insLen<1) {
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[searchPos]);
|
logE("INS %x NOT IMPLEMENTED...",buf[searchPos]);
|
||||||
|
@ -333,6 +339,7 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlock
|
||||||
|
|
||||||
// register this block
|
// register this block
|
||||||
for (size_t i=0; i<groupSize && i<stream->size();) {
|
for (size_t i=0; i<groupSize && i<stream->size();) {
|
||||||
|
if (buf[searchPos+i]!=0xf4) onlyCalls=false;
|
||||||
int insLenI=getInsLength(buf[searchPos+i]);
|
int insLenI=getInsLength(buf[searchPos+i]);
|
||||||
if (insLenI<1) {
|
if (insLenI<1) {
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[searchPos+i]);
|
logE("INS %x NOT IMPLEMENTED...",buf[searchPos+i]);
|
||||||
|
@ -356,6 +363,13 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector<SafeWriter*>& subBlock
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't do anything if this block only consists of calls
|
||||||
|
if (onlyCalls) {
|
||||||
|
logW("nothing but calls.");
|
||||||
|
searchPos+=insLen;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// find identical blocks
|
// find identical blocks
|
||||||
for (size_t i=searchPos+groupLen; i+groupLen<stream->size();) {
|
for (size_t i=searchPos+groupLen; i+groupLen<stream->size();) {
|
||||||
int insLenI=getInsLength(buf[i]);
|
int insLenI=getInsLength(buf[i]);
|
||||||
|
@ -564,6 +578,12 @@ SafeWriter* DivEngine::saveCommand() {
|
||||||
logV("%d",tick);
|
logV("%d",tick);
|
||||||
cmdStreamEnabled=oldCmdStreamEnabled;
|
cmdStreamEnabled=oldCmdStreamEnabled;
|
||||||
|
|
||||||
|
remainingLoops=-1;
|
||||||
|
playing=false;
|
||||||
|
freelance=false;
|
||||||
|
extValuePresent=false;
|
||||||
|
BUSY_END;
|
||||||
|
|
||||||
// PASS 1: condense delays
|
// PASS 1: condense delays
|
||||||
// calculate delay usage
|
// calculate delay usage
|
||||||
for (int h=0; h<chans; h++) {
|
for (int h=0; h<chans; h++) {
|
||||||
|
@ -928,11 +948,5 @@ SafeWriter* DivEngine::saveCommand() {
|
||||||
if (sortedCmdPopularity[i]) logD("- %s: %d",cmdName[sortedCmd[i]],sortedCmdPopularity[i]);
|
if (sortedCmdPopularity[i]) logD("- %s: %d",cmdName[sortedCmd[i]],sortedCmdPopularity[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingLoops=-1;
|
|
||||||
playing=false;
|
|
||||||
freelance=false;
|
|
||||||
extValuePresent=false;
|
|
||||||
BUSY_END;
|
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,7 +273,7 @@ void FurnaceGUI::drawCSPlayer() {
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
DivCSChannelState* state=cs->getChanState(i);
|
DivCSChannelState* state=cs->getChanState(i);
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("%d: $%.4x",i,state->readPos);
|
ImGui::Text("%d: $%.4x (>>%d)",i,state->readPos,state->callStackPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
@ -303,6 +303,90 @@ void FurnaceGUI::drawCSPlayer() {
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginTabItem(_("Disassemble"))) {
|
if (ImGui::BeginTabItem(_("Disassemble"))) {
|
||||||
|
bool mustProceed=false;
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Address");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::InputScalar("##DisAsmAddr",ImGuiDataType_U32,&csDisAsmAddr,0,0,"%.8X",ImGuiInputTextFlags_CharsHexadecimal);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Go")) {
|
||||||
|
mustProceed=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mustProceed) {
|
||||||
|
csDisAsm.clear();
|
||||||
|
unsigned char* buf=cs->getData();
|
||||||
|
for (size_t i=csDisAsmAddr; i<cs->getDataLen();) {
|
||||||
|
int insLen=DivCS::getInsLength(buf[i]);
|
||||||
|
if (insLen<1) {
|
||||||
|
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSDisAsmIns ins;
|
||||||
|
ins.addr=i;
|
||||||
|
memcpy(ins.data,&buf[i],insLen);
|
||||||
|
ins.len=insLen;
|
||||||
|
csDisAsm.push_back(ins);
|
||||||
|
|
||||||
|
i+=insLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!csDisAsm.empty()) {
|
||||||
|
ImGui::PushFont(patFont);
|
||||||
|
if (ImGui::BeginTable("CSDisAsm",chans,ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_ScrollY)) {
|
||||||
|
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,oneChar.x*2.0f);
|
||||||
|
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,oneChar.x*9.0f);
|
||||||
|
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,oneChar.x*3.0f*6.0f);
|
||||||
|
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("pc");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("addr");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("hex");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("ins");
|
||||||
|
|
||||||
|
for (CSDisAsmIns& i: csDisAsm) {
|
||||||
|
ImGui::TableNextRow(0,oneChar.y);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
// this is the "PC is here row"...
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%.8x",i.addr);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
for (int j=0; j<i.len; j++) {
|
||||||
|
ImGui::Text("%.2x",i.data[j]);
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
String dis=disasmCmd(i.data,8,0);
|
||||||
|
ImGui::Text("%s",dis.c_str());
|
||||||
|
|
||||||
|
// jmp/ret separator
|
||||||
|
if (i.data[0]==0xf9 || i.data[0]==0xfa) {
|
||||||
|
ImGui::TableNextRow(0,oneChar.y);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Separator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
ImGui::PopFont();
|
||||||
|
}
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginTabItem(_("Hex"))) {
|
if (ImGui::BeginTabItem(_("Hex"))) {
|
||||||
|
@ -422,6 +506,21 @@ void FurnaceGUI::drawCSPlayer() {
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
if (ImGui::BeginTabItem(_("Stream Info"))) {
|
||||||
|
ImGui::Text("%d bytes",(int)cs->getDataLen());
|
||||||
|
ImGui::Text("%u channels",cs->getFileChans());
|
||||||
|
ImGui::Text("preset delays:");
|
||||||
|
for (int i=0; i<16; i++) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("%d",cs->getFastDelays()[i]);
|
||||||
|
}
|
||||||
|
ImGui::Text("speed dial commands:");
|
||||||
|
for (int i=0; i<16; i++) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("%d",cs->getFastCmds()[i]);
|
||||||
|
}
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
ImGui::EndTabBar();
|
ImGui::EndTabBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1613,6 +1613,17 @@ struct MappedInput {
|
||||||
scan(s), val(v) {}
|
scan(s), val(v) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CSDisAsmIns {
|
||||||
|
unsigned int addr;
|
||||||
|
unsigned char data[8];
|
||||||
|
unsigned char len;
|
||||||
|
CSDisAsmIns():
|
||||||
|
addr(0),
|
||||||
|
len(0) {
|
||||||
|
memset(data,0,8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct FurnaceCV;
|
struct FurnaceCV;
|
||||||
|
|
||||||
class FurnaceGUI {
|
class FurnaceGUI {
|
||||||
|
@ -2743,6 +2754,8 @@ class FurnaceGUI {
|
||||||
|
|
||||||
// command stream player
|
// command stream player
|
||||||
ImGuiListClipper csClipper;
|
ImGuiListClipper csClipper;
|
||||||
|
unsigned int csDisAsmAddr;
|
||||||
|
std::vector<CSDisAsmIns> csDisAsm;
|
||||||
|
|
||||||
// export options
|
// export options
|
||||||
DivAudioExportOptions audioExportOptions;
|
DivAudioExportOptions audioExportOptions;
|
||||||
|
|
Loading…
Reference in a new issue