diff --git a/src/engine/cmdStream.cpp b/src/engine/cmdStream.cpp index 489b16b61..d8c77030f 100644 --- a/src/engine/cmdStream.cpp +++ b/src/engine/cmdStream.cpp @@ -77,6 +77,12 @@ bool DivCSPlayer::tick() { chan[i].readPos=0; break; } + + chan[i].trace[chan[i].tracePos++]=chan[i].readPos; + if (chan[i].tracePos>=DIV_MAX_CSTRACE) { + chan[i].tracePos=0; + } + unsigned char next=stream.readC(); unsigned char command=0; bool mustTell=true; diff --git a/src/gui/csPlayer.cpp b/src/gui/csPlayer.cpp index 7402fa5d7..825f65acb 100644 --- a/src/gui/csPlayer.cpp +++ b/src/gui/csPlayer.cpp @@ -20,8 +20,85 @@ #include "gui.h" #include #include "imgui.h" +#include "guiConst.h" +// TODO: memory safety String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr) { + if (addr>=bufLen) return "???"; + + if (buf[addr]<0xb4) { + return fmt::sprintf("note %s",noteNames[buf[addr]]); + } else switch (buf[addr]) { + case 0xb4: + return "note null"; + break; + case 0xb5: + return "off"; + break; + case 0xb6: + return "offrel"; + break; + case 0xb7: + return "mrel"; + break; + case 0xb8: + return fmt::sprintf("ins $%.2x",(int)buf[addr+1]); + break; + case 0xbe: + return fmt::sprintf("pan $%x, $%x",(int)buf[addr+1],(int)buf[addr+2]); + break; + case 0xc0: + return fmt::sprintf("preporta $%.2x",(int)buf[addr+1]); + break; + case 0xc2: + return fmt::sprintf("vib %d, %d",(int)buf[addr+1],(int)buf[addr+2]); + break; + case 0xc3: + return fmt::sprintf("vibrange %d",(int)buf[addr+1]); + break; + case 0xc4: + return fmt::sprintf("vibshape %d",(int)buf[addr+1]); + break; + case 0xc5: + return fmt::sprintf("pitch $%.2x",(int)buf[addr+1]); + break; + case 0xc6: + return fmt::sprintf("arp %d, %d",(int)buf[addr+1],(int)buf[addr+2]); + break; + case 0xc7: + return fmt::sprintf("vol $%.2x",(int)buf[addr+1]); + break; + case 0xc8: + return fmt::sprintf("volslide %d",(int)((short)(buf[addr+1]|(buf[addr+2]<<8)))); + break; + case 0xc9: + return fmt::sprintf("porta %d, %d",(int)buf[addr+1],(int)buf[addr+2]); + break; + case 0xca: + return fmt::sprintf("legato %d",(int)buf[addr+1]); + break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + return fmt::sprintf("qwait (%d)",(int)(buf[addr]-0xe0)); + break; + case 0xfc: + return fmt::sprintf("waits %d",(int)(buf[addr+1]|(buf[addr+2]<<8))); + break; + case 0xfd: + return fmt::sprintf("waitc %d",(int)buf[addr+1]); + break; + case 0xfe: + return "wait 1"; + break; + case 0xff: + return "stop"; + break; + default: + return "ill"; + break; + } return "TODO"; } @@ -124,6 +201,44 @@ void FurnaceGUI::drawCSPlayer() { ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Trace")) { + ImGui::PushFont(patFont); + if (ImGui::BeginTable("CSTrace",chans,ImGuiTableFlags_SizingFixedSame|ImGuiTableFlags_Borders|ImGuiTableFlags_ScrollX)) { + char tempID[32]; + for (int i=0; igetChanState(i); + ImGui::TableNextColumn(); + ImGui::Text("%d: $%.4x",i,state->readPos); + } + + ImGui::TableNextRow(); + unsigned char* buf=cs->getData(); + size_t bufSize=cs->getDataLen(); + for (int i=0; igetChanState(i); + ImGui::TableNextColumn(); + int maxItems=(ImGui::GetContentRegionAvail().y/MAX(ImGui::GetTextLineHeightWithSpacing(),1.0f)); + if (maxItems>=DIV_MAX_CSTRACE) maxItems=DIV_MAX_CSTRACE-1; + + int tracePos=state->tracePos; + + for (int j=(tracePos-maxItems)&(DIV_MAX_CSTRACE-1); j!=tracePos; j=(j+1)&(DIV_MAX_CSTRACE-1)) { + if (state->trace[j]==0) { + ImGui::TextUnformatted("..."); + } else { + String dis=disasmCmd(buf,bufSize,state->trace[j]); + ImGui::Text("%.4x: %s",state->trace[j],dis.c_str()); + } + } + } + + ImGui::EndTable(); + } + ImGui::PopFont(); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Disassemble")) {