sub-blocks, part 1
currently awful
This commit is contained in:
parent
c110f87548
commit
d5f1d3c25c
|
@ -72,6 +72,7 @@ hex | description
|
||||||
f0 | UNUSED - placeholder used during optimization passes (3-byte nonce follows)
|
f0 | UNUSED - placeholder used during optimization passes (3-byte nonce follows)
|
||||||
f1 | no operation
|
f1 | no operation
|
||||||
f2 | UNUSED - unoptimized extended command
|
f2 | UNUSED - unoptimized extended command
|
||||||
|
f3 | loop (negative offset and count follow... both are 8-bit)
|
||||||
f4 | call symbol (16-bit index follows; only used internally)
|
f4 | call symbol (16-bit index follows; only used internally)
|
||||||
f5 | jump to sub-block (address follows)
|
f5 | jump to sub-block (address follows)
|
||||||
f6 | go to sub-block (32-bit offset follows)
|
f6 | go to sub-block (32-bit offset follows)
|
||||||
|
|
|
@ -122,6 +122,23 @@ bool DivCSPlayer::tick() {
|
||||||
break;
|
break;
|
||||||
case 0xf1: // nop
|
case 0xf1: // nop
|
||||||
break;
|
break;
|
||||||
|
case 0xf3: { // loop
|
||||||
|
unsigned char loopOff=stream.readC();
|
||||||
|
if (chan[i].loopCount>0) {
|
||||||
|
stream.readC();
|
||||||
|
if (--chan[i].loopCount) {
|
||||||
|
// jump
|
||||||
|
chan[i].readPos-=loopOff;
|
||||||
|
mustTell=false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[i].loopCount=stream.readC();
|
||||||
|
// jump
|
||||||
|
chan[i].readPos-=loopOff;
|
||||||
|
mustTell=false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 0xf7:
|
case 0xf7:
|
||||||
command=stream.readC();
|
command=stream.readC();
|
||||||
break;
|
break;
|
||||||
|
@ -130,6 +147,7 @@ bool DivCSPlayer::tick() {
|
||||||
if (!chan[i].doCall(callAddr)) {
|
if (!chan[i].doCall(callAddr)) {
|
||||||
logE("%d: (callb16) stack error!",i);
|
logE("%d: (callb16) stack error!",i);
|
||||||
}
|
}
|
||||||
|
mustTell=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xf6: {
|
case 0xf6: {
|
||||||
|
@ -137,6 +155,7 @@ bool DivCSPlayer::tick() {
|
||||||
if (!chan[i].doCall(callAddr)) {
|
if (!chan[i].doCall(callAddr)) {
|
||||||
logE("%d: (callb32) stack error!",i);
|
logE("%d: (callb32) stack error!",i);
|
||||||
}
|
}
|
||||||
|
mustTell=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xf5: {
|
case 0xf5: {
|
||||||
|
@ -144,6 +163,7 @@ bool DivCSPlayer::tick() {
|
||||||
if (!chan[i].doCall(callAddr)) {
|
if (!chan[i].doCall(callAddr)) {
|
||||||
logE("%d: (call) stack error!",i);
|
logE("%d: (call) stack error!",i);
|
||||||
}
|
}
|
||||||
|
mustTell=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xf4: {
|
case 0xf4: {
|
||||||
|
|
|
@ -37,7 +37,7 @@ struct DivCSChannelState {
|
||||||
int volume, volMax, volSpeed, volSpeedTarget;
|
int volume, volMax, volSpeed, volSpeedTarget;
|
||||||
int vibratoDepth, vibratoRate, vibratoPos;
|
int vibratoDepth, vibratoRate, vibratoPos;
|
||||||
int portaTarget, portaSpeed;
|
int portaTarget, portaSpeed;
|
||||||
unsigned char arp, arpStage, arpTicks;
|
unsigned char arp, arpStage, arpTicks, loopCount;
|
||||||
|
|
||||||
unsigned int callStack[8];
|
unsigned int callStack[8];
|
||||||
unsigned char callStackPos;
|
unsigned char callStackPos;
|
||||||
|
@ -65,6 +65,7 @@ struct DivCSChannelState {
|
||||||
arp(0),
|
arp(0),
|
||||||
arpStage(0),
|
arpStage(0),
|
||||||
arpTicks(0),
|
arpTicks(0),
|
||||||
|
loopCount(0),
|
||||||
callStackPos(0),
|
callStackPos(0),
|
||||||
tracePos(0) {
|
tracePos(0) {
|
||||||
for (int i=0; i<DIV_MAX_CSTRACE; i++) {
|
for (int i=0; i<DIV_MAX_CSTRACE; i++) {
|
||||||
|
|
|
@ -269,6 +269,61 @@ void reloc(unsigned char* buf, size_t len, unsigned int sourceAddr, unsigned int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SafeWriter* stripNops(SafeWriter* s) {
|
||||||
|
std::unordered_map<unsigned int,unsigned int> addrTable;
|
||||||
|
SafeWriter* oldStream=s;
|
||||||
|
unsigned char* buf=oldStream->getFinalBuf();
|
||||||
|
s=new SafeWriter;
|
||||||
|
s->init();
|
||||||
|
|
||||||
|
// prepare address map
|
||||||
|
size_t addr=0;
|
||||||
|
for (size_t i=0; i<oldStream->size();) {
|
||||||
|
int insLen=getInsLength(buf[i]);
|
||||||
|
if (insLen<1) {
|
||||||
|
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
addrTable[i]=addr;
|
||||||
|
if (buf[i]!=0xf1) addr+=insLen;
|
||||||
|
i+=insLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate addresses
|
||||||
|
for (size_t i=0; i<oldStream->size();) {
|
||||||
|
int insLen=getInsLength(buf[i]);
|
||||||
|
if (insLen<1) {
|
||||||
|
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (buf[i]) {
|
||||||
|
case 0xf5: // call
|
||||||
|
case 0xfa: { // jmp
|
||||||
|
unsigned int addr=buf[i+1]|(buf[i+2]<<8)|(buf[i+3]<<8)|(buf[i+4]<<24);
|
||||||
|
try {
|
||||||
|
addr=addrTable[addr];
|
||||||
|
buf[i+1]=addr&0xff;
|
||||||
|
buf[i+2]=(addr>>8)&0xff;
|
||||||
|
buf[i+3]=(addr>>16)&0xff;
|
||||||
|
buf[i+4]=(addr>>24)&0xff;
|
||||||
|
} catch (std::out_of_range& e) {
|
||||||
|
logW("address %x is not mappable!",addr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf[i]!=0xf1) {
|
||||||
|
s->write(&buf[i],insLen);
|
||||||
|
}
|
||||||
|
i+=insLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
oldStream->finish();
|
||||||
|
delete oldStream;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
SafeWriter* DivEngine::saveCommand() {
|
SafeWriter* DivEngine::saveCommand() {
|
||||||
stop();
|
stop();
|
||||||
repeatPattern=false;
|
repeatPattern=false;
|
||||||
|
@ -406,34 +461,7 @@ SafeWriter* DivEngine::saveCommand() {
|
||||||
logV("%d",tick);
|
logV("%d",tick);
|
||||||
cmdStreamEnabled=oldCmdStreamEnabled;
|
cmdStreamEnabled=oldCmdStreamEnabled;
|
||||||
|
|
||||||
// PASS 1: find sub-blocks and isolate them
|
// PASS 1: condense delays
|
||||||
|
|
||||||
// PASS 2: find loops
|
|
||||||
|
|
||||||
// PASS 3: optimize command calls
|
|
||||||
/*
|
|
||||||
int sortCand=-1;
|
|
||||||
int sortPos=0;
|
|
||||||
while (sortPos<16) {
|
|
||||||
sortCand=-1;
|
|
||||||
for (int i=DIV_CMD_SAMPLE_MODE; i<256; i++) {
|
|
||||||
if (cmdPopularity[i]) {
|
|
||||||
if (sortCand==-1) {
|
|
||||||
sortCand=i;
|
|
||||||
} else if (cmdPopularity[sortCand]<cmdPopularity[i]) {
|
|
||||||
sortCand=i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sortCand==-1) break;
|
|
||||||
|
|
||||||
sortedCmdPopularity[sortPos]=cmdPopularity[sortCand];
|
|
||||||
sortedCmd[sortPos]=sortCand;
|
|
||||||
cmdPopularity[sortCand]=0;
|
|
||||||
sortPos++;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// PASS 4: condense delays
|
|
||||||
// calculate delay usage
|
// calculate delay usage
|
||||||
for (int h=0; h<chans; h++) {
|
for (int h=0; h<chans; h++) {
|
||||||
unsigned char* buf=chanStream[h]->getFinalBuf();
|
unsigned char* buf=chanStream[h]->getFinalBuf();
|
||||||
|
@ -535,62 +563,119 @@ SafeWriter* DivEngine::saveCommand() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PASS 5: remove all remaining nop's
|
// PASS 2: remove nop's
|
||||||
// this includes modifying call addresses to compensate
|
// this includes modifying call addresses to compensate
|
||||||
for (int h=0; h<chans; h++) {
|
for (int h=0; h<chans; h++) {
|
||||||
std::unordered_map<unsigned int,unsigned int> addrTable;
|
chanStream[h]=stripNops(chanStream[h]);
|
||||||
SafeWriter* oldStream=chanStream[h];
|
}
|
||||||
unsigned char* buf=oldStream->getFinalBuf();
|
|
||||||
chanStream[h]=new SafeWriter;
|
|
||||||
chanStream[h]->init();
|
|
||||||
|
|
||||||
// prepare address map
|
// PASS 2: find sub-blocks and isolate them (TODO: THIS!)
|
||||||
size_t addr=0;
|
for (int h=0; h<chans; h++) {
|
||||||
for (size_t i=0; i<oldStream->size();) {
|
unsigned char* buf=chanStream[h]->getFinalBuf();
|
||||||
int insLen=getInsLength(buf[i]);
|
unsigned char group[256]; // max offset is -255
|
||||||
if (insLen<1) {
|
size_t groupLen=0;
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
addrTable[i]=addr;
|
|
||||||
if (buf[i]!=0xf1) addr+=insLen;
|
|
||||||
i+=insLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
// translate addresses
|
memset(group,0,256);
|
||||||
for (size_t i=0; i<oldStream->size();) {
|
|
||||||
int insLen=getInsLength(buf[i]);
|
// 3 is the minimum loop size that can be reliably optimized
|
||||||
if (insLen<1) {
|
logI("finding loop in chan %d",h);
|
||||||
logE("INS %x NOT IMPLEMENTED...",buf[i]);
|
for (int groupSize=3; groupSize<256; groupSize++) {
|
||||||
break;
|
bool foundSomething=false;
|
||||||
}
|
//logD("...try size %d",groupSize);
|
||||||
switch (buf[i]) {
|
for (size_t searchPos=0; searchPos<chanStream[h]->size();) {
|
||||||
case 0xf5: // call
|
int insLen=getInsLength(buf[searchPos]);
|
||||||
case 0xfa: { // jmp
|
groupLen=0;
|
||||||
unsigned int addr=buf[i+1]|(buf[i+2]<<8)|(buf[i+3]<<8)|(buf[i+4]<<24);
|
|
||||||
try {
|
if (insLen<1) {
|
||||||
addr=addrTable[addr];
|
logE("INS %x NOT IMPLEMENTED...",buf[searchPos]);
|
||||||
buf[i+1]=addr&0xff;
|
|
||||||
buf[i+2]=(addr>>8)&0xff;
|
|
||||||
buf[i+3]=(addr>>16)&0xff;
|
|
||||||
buf[i+4]=(addr>>24)&0xff;
|
|
||||||
} catch (std::out_of_range& e) {
|
|
||||||
logW("address %x is not mappable!",addr);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (buf[i]!=0xf1) {
|
|
||||||
chanStream[h]->write(&buf[i],insLen);
|
|
||||||
}
|
|
||||||
i+=insLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
oldStream->finish();
|
// copy a block
|
||||||
delete oldStream;
|
for (int i=0; i<groupSize && searchPos+i<chanStream[h]->size();) {
|
||||||
|
int insLenI=getInsLength(buf[searchPos+i]);
|
||||||
|
if (insLenI<1) {
|
||||||
|
logE("INS %x NOT IMPLEMENTED...",buf[searchPos+i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i+=insLenI;
|
||||||
|
if ((int)groupLen+insLenI>groupSize) break;
|
||||||
|
groupLen+=insLenI;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't do anything if we don't have a block
|
||||||
|
if (!groupLen) {
|
||||||
|
searchPos+=insLen;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(group,&buf[searchPos],groupLen);
|
||||||
|
|
||||||
|
// find contiguous blocks
|
||||||
|
size_t searchPos1=searchPos+groupLen;
|
||||||
|
size_t posOfFirstBlock=searchPos1;
|
||||||
|
int loopCount=0;
|
||||||
|
while (true) {
|
||||||
|
// stop if we're near the end
|
||||||
|
if (searchPos1>=chanStream[h]->size()) break;
|
||||||
|
// compare next block to group
|
||||||
|
if (memcmp(&buf[searchPos1],group,groupLen)!=0) break;
|
||||||
|
|
||||||
|
// if we're here, we found a contiguous block
|
||||||
|
searchPos1+=groupLen;
|
||||||
|
loopCount++;
|
||||||
|
// don't loop more than 255 times
|
||||||
|
if (loopCount>=255) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopCount>0) {
|
||||||
|
// write loop command
|
||||||
|
logD("- LOOP: %x (size %d, %d times)",searchPos,groupLen,loopCount);
|
||||||
|
buf[posOfFirstBlock++]=0xf3;
|
||||||
|
buf[posOfFirstBlock++]=groupLen;
|
||||||
|
buf[posOfFirstBlock++]=loopCount;
|
||||||
|
// set the rest to nop
|
||||||
|
while (posOfFirstBlock<searchPos1) {
|
||||||
|
buf[posOfFirstBlock++]=0xf1;
|
||||||
|
}
|
||||||
|
// skip contiguous blocks
|
||||||
|
searchPos=searchPos1;
|
||||||
|
foundSomething=true;
|
||||||
|
} else {
|
||||||
|
// try again somewhere else
|
||||||
|
searchPos+=insLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundSomething) {
|
||||||
|
chanStream[h]=stripNops(chanStream[h]);
|
||||||
|
buf=chanStream[h]->getFinalBuf();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PASS 3: optimize command calls
|
||||||
|
/*
|
||||||
|
int sortCand=-1;
|
||||||
|
int sortPos=0;
|
||||||
|
while (sortPos<16) {
|
||||||
|
sortCand=-1;
|
||||||
|
for (int i=DIV_CMD_SAMPLE_MODE; i<256; i++) {
|
||||||
|
if (cmdPopularity[i]) {
|
||||||
|
if (sortCand==-1) {
|
||||||
|
sortCand=i;
|
||||||
|
} else if (cmdPopularity[sortCand]<cmdPopularity[i]) {
|
||||||
|
sortCand=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sortCand==-1) break;
|
||||||
|
|
||||||
|
sortedCmdPopularity[sortPos]=cmdPopularity[sortCand];
|
||||||
|
sortedCmd[sortPos]=sortCand;
|
||||||
|
cmdPopularity[sortCand]=0;
|
||||||
|
sortPos++;
|
||||||
|
}*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
// optimize stream
|
// optimize stream
|
||||||
|
|
|
@ -101,6 +101,9 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr) {
|
||||||
case 0xf1:
|
case 0xf1:
|
||||||
return "nop";
|
return "nop";
|
||||||
break;
|
break;
|
||||||
|
case 0xf3:
|
||||||
|
return fmt::sprintf("loop (-%d), %d",(int)buf[addr+1],(int)buf[addr+2]);
|
||||||
|
break;
|
||||||
case 0xf4:
|
case 0xf4:
|
||||||
if (addr+2>=bufLen) return "???";
|
if (addr+2>=bufLen) return "???";
|
||||||
return fmt::sprintf("callsym %.4x",(int)(buf[addr+1]|(buf[addr+2]<<8)));
|
return fmt::sprintf("callsym %.4x",(int)(buf[addr+1]|(buf[addr+2]<<8)));
|
||||||
|
@ -367,7 +370,6 @@ void FurnaceGUI::drawCSPlayer() {
|
||||||
}
|
}
|
||||||
if (!highlights.empty()) nextHighlight=highlights[0];
|
if (!highlights.empty()) nextHighlight=highlights[0];
|
||||||
|
|
||||||
|
|
||||||
for (int i=csClipper.DisplayStart; i<csClipper.DisplayEnd; i++) {
|
for (int i=csClipper.DisplayStart; i<csClipper.DisplayEnd; i++) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
Loading…
Reference in a new issue