Implement Step-Over functionality

This change adds a new "Step Over" button, which is enabled
when a "JSR" (Jump to Subroutine) instruction is encountered
while stepping through execution one instruction at a time.

Pressing "Step Over" will continue running instructions until a
corresponding "RTS" (Return from Subroutine) is encountered.
While stepping over a subroutine, the call stack depth is tracked
in an attempt to halt only when the *correct* RTS is encountered.
In other words, it should skip over other subroutines nested
inside the call you want to step over:

```
     JSR A # Step over here...
     ...
     JSR B
     ...
     RTS   # Returns from 'B', doesn't halt
     ...
     RTS   # Returns from 'A', halts after return
```

Implements feature request #18.
This commit is contained in:
Seth Morabito committed 2025-03-30 15:18:00 -07:00
1 parent 2284535b7f
commit 7268766cd6
39 files changed
+162 -56

No files matched your search

+1 -1
View File
@@ -377,7 +377,7 @@ running.
## 8.0 Copyright and Acknowledgements ## 8.0 Copyright and Acknowledgements
**Copyright (c) 2014 Seth J. Morabito <web@loomcom.com>** **Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>**
- Portions Copyright (c) 2014 Maik Merten - Portions Copyright (c) 2014 Maik Merten
<maikmerten@googlemail.com> <maikmerten@googlemail.com>
@@ -1,3 +1,26 @@
/*
* Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.loomcom.symon; package com.loomcom.symon;
import com.loomcom.symon.exceptions.MemoryAccessException; import com.loomcom.symon.exceptions.MemoryAccessException;
+1 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
+5 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1699,6 +1699,10 @@ public class Cpu implements InstructionTable {
return state.ir; return state.ir;
} }
public int getNextIr() {
return state.nextIr;
}
/** /**
* @value The value of the Process Status Register bits to be set. * @value The value of the Process Status Register bits to be set.
*/ */
@@ -1,3 +1,26 @@
/*
* Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.loomcom.symon; package com.loomcom.symon;
import com.loomcom.symon.util.Utils; import com.loomcom.symon.util.Utils;
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -25,6 +25,10 @@ package com.loomcom.symon;
public interface InstructionTable { public interface InstructionTable {
int BRK = 0x00;
int JSR = 0x20;
int RTS = 0x60;
/** /**
* Enumeration of valid CPU behaviors. These determine what behavior and instruction * Enumeration of valid CPU behaviors. These determine what behavior and instruction
* set will be simulated, depending on desired version of 6502. * set will be simulated, depending on desired version of 6502.
+2 -3
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -22,7 +22,6 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package com.loomcom.symon; package com.loomcom.symon;
import com.loomcom.symon.machines.*; import com.loomcom.symon.machines.*;
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
+62 -9
View File
@@ -1,5 +1,5 @@
/* /*
* Copyrighi (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -37,6 +37,8 @@ import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.io.*; import java.io.*;
import static com.loomcom.symon.InstructionTable.*;
/** /**
* Symon Simulator Interface and Control. * Symon Simulator Interface and Control.
* <p/> * <p/>
@@ -112,6 +114,7 @@ public class Simulator {
private JButton runStopButton; private JButton runStopButton;
private JButton stepButton; private JButton stepButton;
private JButton stepOverButton;
private JComboBox<String> stepCountBox; private JComboBox<String> stepCountBox;
private JFileChooser fileChooser; private JFileChooser fileChooser;
@@ -188,6 +191,8 @@ public class Simulator {
runStopButton = new JButton("Run"); runStopButton = new JButton("Run");
stepButton = new JButton("Step"); stepButton = new JButton("Step");
stepOverButton = new JButton("Step Over");
stepOverButton.setEnabled(false);
JButton softResetButton = new JButton("Soft Reset"); JButton softResetButton = new JButton("Soft Reset");
JButton hardResetButton = new JButton("Hard Reset"); JButton hardResetButton = new JButton("Hard Reset");
@@ -209,6 +214,7 @@ public class Simulator {
buttonContainer.add(runStopButton); buttonContainer.add(runStopButton);
buttonContainer.add(stepButton); buttonContainer.add(stepButton);
buttonContainer.add(stepOverButton);
buttonContainer.add(stepCountBox); buttonContainer.add(stepCountBox);
buttonContainer.add(softResetButton); buttonContainer.add(softResetButton);
buttonContainer.add(hardResetButton); buttonContainer.add(hardResetButton);
@@ -232,6 +238,7 @@ public class Simulator {
}); });
stepButton.addActionListener(actionEvent -> Simulator.this.handleStep(stepsPerClick)); stepButton.addActionListener(actionEvent -> Simulator.this.handleStep(stepsPerClick));
stepOverButton.addActionListener(actionEvent -> Simulator.this.handleStepOver());
softResetButton.addActionListener(actionEvent -> { softResetButton.addActionListener(actionEvent -> {
// If this was a CTRL-click, do a hard reset. // If this was a CTRL-click, do a hard reset.
@@ -325,11 +332,28 @@ public class Simulator {
step(); step();
} }
updateVisibleState(); updateVisibleState();
stepOverButton.setEnabled(machine.getCpu().getNextIr() == JSR);
} catch (SymonException ex) { } catch (SymonException ex) {
logger.error("Exception during simulator step", ex); logger.error("Exception during simulator step", ex);
} }
} }
/**
* Step over a JSR / RTS function. This function is much more like a "run()"
* than a "step()", and may enter an infinite loop if no RTS is encountered.
*/
private void handleStepOver() {
if (runLoop != null && runLoop.isRunning()) {
// This should really never happen...
logger.error("Can't step over when the simulator is already running!");
return;
}
runLoop = new RunLoop();
runLoop.haltOnRts(true);
runLoop.start();
}
/** /**
* Perform a single step of the simulated system. * Perform a single step of the simulated system.
*/ */
@@ -398,22 +422,36 @@ public class Simulator {
*/ */
class RunLoop extends Thread { class RunLoop extends Thread {
private boolean isRunning = false; private boolean isRunning = false;
private boolean haltOnRts = false;
// The number of JSR instructions we've seen since being asked to
// step over a subroutine. While stepping over, this is incremented
// on RTS instructions, and decremented on JSR instructions.
private int callStackDepth = 0;
public boolean isRunning() { public boolean isRunning() {
return isRunning; return this.isRunning;
} }
public void requestStop() { public void requestStop() {
isRunning = false; this.isRunning = false;
}
public void haltOnRts(boolean value) {
this.haltOnRts = value;
} }
public void run() { public void run() {
logger.debug("Starting main run loop."); if (this.haltOnRts) {
isRunning = true; logger.debug("Running until next RTS instruction");
} else {
logger.debug("Running");
}
this.isRunning = true;
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
// Don't allow step while the simulator is running // Don't allow step while the simulator is running
stepButton.setEnabled(false); stepButton.setEnabled(false);
stepOverButton.setEnabled(false);
stepCountBox.setEnabled(false); stepCountBox.setEnabled(false);
menuBar.simulatorDidStart(); menuBar.simulatorDidStart();
// Toggle the state of the run button // Toggle the state of the run button
@@ -423,6 +461,17 @@ public class Simulator {
try { try {
do { do {
step(); step();
if (this.haltOnRts) {
var instruction = machine.getCpu().getInstruction();
if (instruction == JSR) {
this.callStackDepth++;
logger.trace("Step-over call stack increased to {}", this.callStackDepth);
} else if (this.callStackDepth > 0 && instruction == RTS) {
this.callStackDepth--;
logger.trace("Step-over call stack decreased to {}", this.callStackDepth);
}
}
} while (shouldContinue()); } while (shouldContinue());
} catch (SymonException ex) { } catch (SymonException ex) {
logger.error("Exception in main simulator run thread. Exiting run.", ex); logger.error("Exception in main simulator run thread. Exiting run.", ex);
@@ -433,6 +482,7 @@ public class Simulator {
memoryWindow.updateState(); memoryWindow.updateState();
runStopButton.setText("Run"); runStopButton.setText("Run");
stepButton.setEnabled(true); stepButton.setEnabled(true);
stepOverButton.setEnabled(machine.getCpu().getNextIr() == JSR);
stepCountBox.setEnabled(true); stepCountBox.setEnabled(true);
if (traceLog.isVisible()) { if (traceLog.isVisible()) {
traceLog.refresh(); traceLog.refresh();
@@ -448,9 +498,13 @@ public class Simulator {
* @return True if the run loop should proceed to the next step. * @return True if the run loop should proceed to the next step.
*/ */
private boolean shouldContinue() { private boolean shouldContinue() {
return !breakpoints.contains(machine.getCpu().getProgramCounter()) && var instruction = machine.getCpu().getInstruction();
isRunning &&
!(preferences.getHaltOnBreak() && machine.getCpu().getInstruction() == 0x00); var stepOverHalt = this.haltOnRts && this.callStackDepth == 0 && instruction == RTS;
var breakpointHalt = breakpoints.contains(machine.getCpu().getProgramCounter());
var brkHalt = preferences.getHaltOnBreak() && instruction == BRK;
return isRunning && !(stepOverHalt || breakpointHalt || brkHalt);
} }
} }
@@ -924,7 +978,6 @@ public class Simulator {
private void updateVisibleState() { private void updateVisibleState() {
// Immediately update the UI. // Immediately update the UI.
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
// Now update the state
statusPane.updateState(); statusPane.updateState();
memoryWindow.updateState(); memoryWindow.updateState();
if (traceLog.shouldUpdate()) { if (traceLog.shouldUpdate()) {
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Portions Copyright (c) 2009-2011 Graham Edgecombe * Portions Copyright (c) 2009-2011 Graham Edgecombe
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
@@ -1,7 +1,7 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* Chelsea Wilkinson <mail@chelseawilkinson.me> * Chelsea Wilkinson <mail@chelseawilkinson.me>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com> * Maik Merten <maikmerten@googlemail.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com> * Copyright (c) 2008-2025 Seth J. Morabito <web@loomcom.com>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the