diff --git a/src/main/java/jace/core/CPU.java b/src/main/java/jace/core/CPU.java index 2635551..2815ee1 100644 --- a/src/main/java/jace/core/CPU.java +++ b/src/main/java/jace/core/CPU.java @@ -1,46 +1,38 @@ -/** -* Copyright 2024 Brendan Robert -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - package jace.core; -import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; - import jace.config.ConfigurableField; /** * CPU is a vague abstraction of a CPU. It is defined as something which can be * debugged or traced. It has a program counter which can be incremented or - * change. Most importantly, it is a device which does something on every clock tick. + * changed. Most importantly, it is a device which does something on every clock tick. * Subclasses should implement "executeOpcode" rather than override the tick method. * Created on January 4, 2007, 7:27 PM * - * @author Brendan Robert (BLuRry) brendan.robert@gmail.com + * @author Brendan Robert (BLuRry) brendan.robert@gmail.com */ public abstract class CPU extends Device { private static final Logger LOG = Logger.getLogger(CPU.class.getName()); + private Debugger debugger = null; + + @ConfigurableField(name = "Enable trace to STDOUT", shortName = "trace") + public boolean trace = false; + + @ConfigurableField(name = "Trace length", shortName = "traceSize", description = "Number of most recent trace lines to keep for debugging errors. Zero == disabled") + public int traceLength = 0; + + private final TraceLog traceLog; + + public CPU() { + traceLog = new TraceLog(); + } @Override public String getShortName() { return "cpu"; } - private Debugger debugger = null; - @ConfigurableField(name = "Enable trace to STDOUT", shortName = "trace") - public boolean trace = false; public boolean isTraceEnabled() { return trace; @@ -49,33 +41,22 @@ public abstract class CPU extends Device { public void setTraceEnabled(boolean t) { trace = t; } - @ConfigurableField(name = "Trace length", shortName = "traceSize", description = "Number of most recent trace lines to keep for debugging errors. Zero == disabled") - public int traceLength = 0; - private ArrayList traceLog = new ArrayList<>(); public boolean isLogEnabled() { return (traceLength > 0); } public void log(String line) { - if (!isLogEnabled()) { - return; + if (isLogEnabled()) { + traceLog.log(line, traceLength); } - while (traceLog.size() >= traceLength) { - traceLog.remove(0); - } - traceLog.add(line); } - + public void dumpTrace() { - whileSuspended(()->{ - ArrayList newLog = new ArrayList<>(); - ArrayList oldLog = traceLog; - traceLog = newLog; + whileSuspended(() -> { LOG.log(Level.INFO, "Most recent {0} instructions:", traceLength); - oldLog.forEach(LOG::info); - oldLog.clear(); - }); + traceLog.dumpAndClear(LOG); + }); } public void setDebug(Debugger d) { @@ -87,6 +68,7 @@ public abstract class CPU extends Device { debugger = null; resume(); } + //@ConfigurableField(name="Program Counter") public int programCounter = 0; @@ -112,16 +94,13 @@ public abstract class CPU extends Device { try { if (debugger != null) { if (!debugger.isActive() && debugger.hasBreakpoints()) { - if (debugger.getBreakpoints().contains(getProgramCounter())){ + if (debugger.getBreakpoints().contains(getProgramCounter())) { debugger.setActive(true); } } if (debugger.isActive()) { debugger.updateStatus(); if (!debugger.takeStep()) { - // If the debugger is active and we aren't ready for the next step, sleep and exit - // Without the sleep, this would constitute a very rapid-fire loop and would eat - // an unnecessary amount of CPU. Thread.onSpinWait(); return; } @@ -132,10 +111,6 @@ public abstract class CPU extends Device { } executeOpcode(); } - /* - * Execute the current opcode at the current program counter - *@return number of cycles to wait until next command can be executed - */ protected abstract void executeOpcode(); @@ -153,19 +128,23 @@ public abstract class CPU extends Device { boolean singleTraceEnabled = false; public String lastTrace = "START"; + public void performSingleTrace() { singleTraceEnabled = true; } + public boolean isSingleTraceEnabled() { return singleTraceEnabled; } + public String getLastTrace() { return lastTrace; } + public void captureSingleTrace(String trace) { lastTrace = trace; singleTraceEnabled = false; } abstract public void clearState(); -} \ No newline at end of file +} diff --git a/src/main/java/jace/core/Media.java b/src/main/java/jace/core/Media.java index fea353d..104874f 100644 --- a/src/main/java/jace/core/Media.java +++ b/src/main/java/jace/core/Media.java @@ -28,7 +28,7 @@ public class Media { try (InputStream oggStream = getClass().getResourceAsStream(resourcePath)) { oggFile = oggStream.readAllBytes(); } - + ByteBuffer oggBuffer = null; STBVorbisInfo info = null; ShortBuffer tempSampleBuffer = null; @@ -97,7 +97,7 @@ public class Media { return "VORBIS_seek_without_length"; case STBVorbis.VORBIS_unexpected_eof: return "VORBIS_unexpected_eof"; - case STBVorbis.VORBIS_seek_invalid: + case STBVorbis.VORBIS_seek_invalid: return "VORBIS_seek_invalid"; case STBVorbis.VORBIS_invalid_setup: return "VORBIS_invalid_setup"; @@ -175,7 +175,7 @@ public class Media { public float getTotalDuration() { return totalDuration; - } + } public int getTotalSamples() { return totalSamples; diff --git a/src/main/java/jace/core/TraceLog.java b/src/main/java/jace/core/TraceLog.java new file mode 100644 index 0000000..b400e8e --- /dev/null +++ b/src/main/java/jace/core/TraceLog.java @@ -0,0 +1,30 @@ +package jace.core; + +import java.util.ArrayList; +import java.util.logging.Logger; + +/** + * TraceLog manages the trace log functionality for recording recent instructions or events. + * It is used in conjunction with the CPU class to provide traceable debugging output. + */ +public class TraceLog { + private ArrayList logEntries; + + public TraceLog() { + this.logEntries = new ArrayList<>(); + } + + public void log(String line, int maxEntries) { + while (logEntries.size() >= maxEntries) { + logEntries.remove(0); + } + logEntries.add(line); + } + + public void dumpAndClear(Logger logger) { + ArrayList oldLog = logEntries; + logEntries = new ArrayList<>(); + oldLog.forEach(logger::info); + oldLog.clear(); + } +}