Skip to content

Commit

Permalink
Partial bit deleting and marking now works. #118
Browse files Browse the repository at this point in the history
  • Loading branch information
travisgoodspeed committed Aug 1, 2024
1 parent 67508ab commit fa4d2c3
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 45 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ now sets the home position. Zooming and movement keys now work in the
second view. Perfectly duplicates lines are now culled during DRC by
the `V` key. Rows and columns are now stored as sorted lists intead
of sets. Rows and columns are now in a consistent order in the file
export. 30% speed-up on bit marking.
export. Performance boosts in bit marking, background bit marking
and alignment.

2024-07-14 -- Fixes crash when deleting a double-selected item. Delete
and backspace now delete objects like `D`. Multiple disassemblers.
Expand Down
12 changes: 7 additions & 5 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ int main(int argc, char *argv[]){
//Don't print anything because the function takes care of it for us.
mrt.enableVerbose();
}
a.processEvents();

mrt.show();
for(int i=0; i<args.count(); i++)
Expand Down Expand Up @@ -215,12 +216,13 @@ int main(int argc, char *argv[]){
qDebug()<<"Stressing the loaded project.";
for(int i=0; i<10; i++){
qDebug()<<"Round"<<i<<"of bit clearing.";
mrt.clearBits();
a.processEvents();
mrt.clearBits(true);
//a.processEvents();
assert(mrt.bitcount==0);
qDebug()<<"Round"<<i<<"of bit marking.";
mrt.markBits();
a.processEvents();
qDebug()<<"Round"<<i<<"of bit aligning.";

while(!mrt.markBits(false))
a.processEvents();
mrt.markBitTable();
a.processEvents();
}
Expand Down
90 changes: 60 additions & 30 deletions maskromtool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ void MaskRomTool::keyPressEvent(QKeyEvent *event){
case Qt::Key_F:
if(shift && !ctrl && !alt){ //Force a Bit
markUndoPoint();
fixBit(scene->scenepos);
statusBar()->showMessage(tr("Forced a bit."));
}
break;
Expand Down Expand Up @@ -706,8 +707,7 @@ void MaskRomTool::keyPressEvent(QKeyEvent *event){
duplicateItem(item);
}
}
//Update bits when done.
markBits(false);
//Don't bother forcing an update. That can come later.
}else if(none){ //Delete
foreach(QGraphicsItem* item, scene->selection){
removeItem(item);
Expand Down Expand Up @@ -770,13 +770,10 @@ void MaskRomTool::keyPressEvent(QKeyEvent *event){

//These operate on the loaded data.
case Qt::Key_M: //Mark Bits.
markBits(true);
if(asciiDialog.isVisible())
on_asciiButton_triggered();
statusBar()->showMessage(tr("Marked bits."));
//This kicks off the state machine to redraw all bits.
clearBits(false);
if(shift){
on_actionHexView_triggered();
statusBar()->showMessage(tr("Decoded bits."));
}
break;
}
Expand Down Expand Up @@ -1422,7 +1419,7 @@ void MaskRomTool::markLine(RomLineItem* line){
* rather than just one type.
*/

foreach(QGraphicsItem* item, scene->collidingItems(line)){
if(!line->marked) foreach(QGraphicsItem* item, scene->collidingItems(line)){
//We are only looking for columns that collide with rows here. All other collisions are irrelevant.
if(line->linetype==RomLineItem::LINEROW
&& item->type()==item->UserType+1 //Is the colliding item a column?
Expand All @@ -1437,6 +1434,8 @@ void MaskRomTool::markLine(RomLineItem* line){
}
}

line->marked=true;

updateCrosshairAngle(line);
}

Expand Down Expand Up @@ -1518,35 +1517,39 @@ void MaskRomTool::moveList(QList<QGraphicsItem*> list, QPointF offset){
}

//Mark up all of the bits where rows and columns collide.
void MaskRomTool::markBits(bool full){
bool MaskRomTool::markBits(bool full){
bool bitswerevisible=bitsVisible;
bool lineswerevisible=linesVisible;
uint64_t count=0;

state=STATE_MARKING;

//Exit early if there's nothing to do.
if(!markingdirty) return;
//Exit quick and early if there's nothing to do.
//This is needed because partial updates are called in rendering loop.
if(!markingdirty) return true;

if(!lineswerevisible)
setLinesVisible(true);

//We're blowing away the alignment here, will need to rebuild it later.
alignmentdirty=true;

//First we remove all the old bits. This is very slow.
if(verbose) qDebug()<<"Clearing bits.";
clearBits();

bitcount=0;
setBitsVisible(false);

//Mark every line collision.
if(verbose) qDebug()<<"Marking bits.";
foreach (RomLineItem* line, cols)
foreach (RomLineItem* line, cols){
if(!line->marked && count++>50 && !full){
//Show the bits if--and only if--we've set that style.
setBitsVisible(bitswerevisible);
//Same for the lines.
setLinesVisible(lineswerevisible);
return false;
}
if(!line->marked) alignmentdirty=true;
markLine(line);
if(verbose) qDebug()<<"Sorting bits.";
sortBits();
}

//Now our marking is clean, if unsorted.
markingdirty=false;
sortBits();
//Mark all the fixes.
if(verbose) qDebug()<<"Marking fixes.";
markFixes();

if(verbose) qDebug()<<"Restoring visibility.";
Expand All @@ -1555,37 +1558,54 @@ void MaskRomTool::markBits(bool full){
//Same for the lines.
setLinesVisible(lineswerevisible);

if(verbose)
qDebug()<<"Marked"<<bitcount<<"bits.";

markingdirty=false;
state=STATE_IDLE;
return true;
}



//Mark up all of the bits where rows and columns collide.
void MaskRomTool::clearBits(){
void MaskRomTool::clearBits(bool full){
uint64_t count=0;
state=STATE_CLEARING;

/* FIXME: This leaves behind some unhandled events. If calling
* this from the CLI, be sure to call QApplication.processEvents()
* to clear them or processing will become progressively slower
* as the count rises.
*
* In the GUI, we'll call this with full=false to opportunistically
* wipe away bits without hogging the redraw thread. Like markBits(),
* it might take a few frames to finish on large projects.
*/
foreach (QGraphicsItem* item, bits){
scene->removeItem(item);
delete item;
bitcount--;
if(!full)
//For partial work, we need to remove the items.
bits.removeOne(item);
if(!full && count++>10000)
//We'll finish this off later.
return;
}

//For a full erase, we eliminate items in bulk.
bits.clear();
assert(bits.isEmpty());


//Reset the markers so we can start again.
foreach (RomLineItem* line, rows)
line->marked=false;
foreach (RomLineItem* line, cols)
line->marked=false;

//Next step is to mark the bits.
bitcount=0;
markingdirty=true;
alignmentdirty=true;
state=STATE_MARKING;
}

//Marks the bit fixes.
Expand All @@ -1595,13 +1615,16 @@ void MaskRomTool::markFixes(){
* overlaps a fix than every fix that overlaps a bit.
*/
bool bitswerevisible=bitsVisible;

setBitsVisible(true);
foreach (RomBitFix* fix, bitfixes){
RomBitItem* bit=getBit(fix->pos());
if(bit) // Apply the fix.
bit->setFix(fix);
else // Destroy fixes that don't match bits.
else if(!markingdirty)
// Destroy fixes that don't match bits.
removeItem(fix);

}
setBitsVisible(bitswerevisible);
}
Expand All @@ -1621,6 +1644,11 @@ void MaskRomTool::remarkBits(){
RomBitItem* MaskRomTool::markBitTable(){
static RomBitItem* firstbit=0;

//qDebug()<<"Aligning table of"<<bitcount<<"bits.";
foreach (RomLineItem* line, cols){
assert(line->marked);
}

//Make sure all the bits are ready.
if(alignmentdirty || markingdirty){
markBits(true);
Expand All @@ -1633,6 +1661,7 @@ RomBitItem* MaskRomTool::markBitTable(){
if(!firstbit)
alignmentdirty=true;

//qDebug()<<"Updating counts.";
//If we have a bit, update the counts.
rowcount=colcount=0;
RomBitItem* bit=firstbit;
Expand All @@ -1646,6 +1675,7 @@ RomBitItem* MaskRomTool::markBitTable(){
bit=bit->nexttoright;
}

state=STATE_IDLE;
return firstbit;
}

Expand Down
10 changes: 8 additions & 2 deletions maskromtool.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,18 @@ class MaskRomTool : public QMainWindow{
void setBitsVisible(bool b=true); //Show or hide the bits.
void setViolationsVisible(bool b=true); //Show or hide the DRC violations.

/* The state of GUI is whether it is marking bits, clearing them,
* or aligning them. This lets us mark bits in the background without
* hogging the rendering thread.
*/
enum {STATE_IDLE, STATE_CLEARING, STATE_MARKING} state=STATE_IDLE;

//Marks all of the bit positions, but not their connections.
void markBits(bool full=true);
bool markBits(bool full=true);
//Sorts the bits from the left. Fast if already sorted.
void sortBits();
//Clears all bits. Useful when we want them out of the way for a bit.
void clearBits();
void clearBits(bool full=true);
//Re-marks bits at all of the old positions, but new samples.
void remarkBits();
//Marks one bit.
Expand Down
30 changes: 23 additions & 7 deletions romscene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,19 +148,32 @@ void RomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent){

updateCrosshairs(mouseEvent->buttons()==Qt::LeftButton);

/* Whenever the mouse moves, we also update the status bar
* to show our position and size.
*/
updateStatus();

//here instead of on release so we can have preview
if(mouseEvent->buttons()==Qt::RightButton){
QPointF dpos = mouseEvent->scenePos() - presspos;
maskRomTool->moveList(selection, dpos);

// update because we already moved it
presspos = scenepos;
}else{
//Update some of the bits if they aren't finished.

switch(maskRomTool->state){
case MaskRomTool::STATE_MARKING:
maskRomTool->markBits(false);
break;
case MaskRomTool::STATE_CLEARING:
maskRomTool->clearBits(false);
break;
case MaskRomTool::STATE_IDLE:
break;
}
}

/* Whenever the mouse moves, we also update the status bar
* to show our position and size.
*/
updateStatus();
}

void RomScene::setRowAngle(qreal angle){
Expand Down Expand Up @@ -264,8 +277,11 @@ void RomScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent){
* arrangement. As a workaround, we remark the bits after releasing the
* button from a moving drag.
*/
if(maskRomTool->bitsVisible)
maskRomTool->markBits();
if(maskRomTool->bitsVisible){
//Clear the old bits in the background.
//This will continue until redrawing them.
maskRomTool->clearBits(false);
}
}
}

Expand Down

0 comments on commit fa4d2c3

Please sign in to comment.