From 308e3a9efac6433e19ef952dfdc0e5730fd5dba6 Mon Sep 17 00:00:00 2001 From: TQ Hirsch Date: Sat, 30 Sep 2023 12:33:16 +0200 Subject: [PATCH] Added CLI --- build.gradle.kts | 2 +- src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt | 104 ++++++++++++++++++ src/main/kotlin/com/thequux/mcpdp/core/CPU.kt | 17 +-- 3 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt diff --git a/build.gradle.kts b/build.gradle.kts index 4e91771..0b76328 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,5 +33,5 @@ kotlin { } application { - mainClass.set("MainKt") + mainClass.set("com.thequux.mcpdp.cli.Cli") } diff --git a/src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt b/src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt new file mode 100644 index 0000000..7654cc0 --- /dev/null +++ b/src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt @@ -0,0 +1,104 @@ +package com.thequux.mcpdp.cli + +import ch.qos.logback.classic.LoggerContext +import com.thequux.mcpdp.core.CPU +import com.thequux.mcpdp.debug.FlightRecorder +import com.thequux.mcpdp.debug.LoggingCollector +import com.thequux.mcpdp.debug.NullTracer +import com.thequux.mcpdp.debug.Tracer +import com.thequux.mcpdp.loadAbs +import com.thequux.mcpdp.peripheral.DL11 +import com.thequux.mcpdp.peripheral.MemBus +import org.jline.utils.Log +import org.slf4j.LoggerFactory +import picocli.CommandLine +import picocli.CommandLine.Command +import picocli.CommandLine.ITypeConverter +import picocli.CommandLine.Option +import picocli.CommandLine.Parameters +import java.io.File +import java.util.concurrent.Callable +import kotlin.system.exitProcess + +@Command(name="jdp11", mixinStandardHelpOptions = true) +class Cli: Callable { + @Option(names = ["-l", "--load"], description = ["The paper tape image to load"]) + private var load: File? = null + + @Option(names = ["-t", "--trace"]) + private var traceLength: Int = 0 + + @Option(names = ["-g", "--go"], description = ["Start address in octal. Ignored if odd"], converter = [ OctalParamConverter::class ]) + private var startAddress: Int = 1 + + @Option(names = ["-b", "--break"], description = ["Breakpoint address"], converter = [ OctalParamConverter::class ]) + private var breakpoint: Int = 1 + + @Option(names = ["-c", "--count"], description = ["Max number of instructions to run. 0 is infinite"]) + private var maxInsns: Long = 0 + + override fun call(): Int { + val tb = org.jline.terminal.TerminalBuilder.terminal() + var mbus = MemBus(65536) + val tracer = Tracer() + if (CPU.debugMode) + tracer.addCollector(LoggingCollector()) + val recorder = FlightRecorder(traceLength) + if (traceLength > 0) { + tracer.addCollector(recorder) + } + var cpu = CPU(mbus, if (traceLength > 0 || CPU.debugMode) tracer else NullTracer()) + val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) } + try { + + + tb.enterRawMode() + console.start() + + if (load != null) { + cpu.loadAbs(load!!) + } +// cpu.core.setw(0x3C78u, 0u) // halt instead of restart + if (startAddress % 2 == 0) { + cpu.pc = startAddress.toUShort() + cpu.runState = CPU.RunState.RUNNING + } + + cpu.breakpoint = breakpoint.toUShort() +// var ninsn = cpu.run(60000000) + if (cpu.runState == CPU.RunState.RUNNING) { + val start = System.nanoTime() + + var ninsn = if (maxInsns > 0) cpu.run(maxInsns) else cpu.run() +// var ninsn = cpu.run(13300) +// ninsn += cpu.run(10) + recorder.dump(System.out) + cpu.dumpReg() + val end = System.nanoTime() + System.err.println("Halted at 0${cpu.pc.toString(8)}") + val time = (end - start).toDouble() / 1_000_000_000.0 + System.err.println("Executed ${ninsn} in ${time}s: ${ninsn / time / 1_000_000} MIPS") + } + + } finally { + println("Exiting") + console.stop() + } + val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext + loggerContext.stop() + return 0 + } + + companion object { + @JvmStatic + fun main(args: Array) { + exitProcess(CommandLine(Cli()).execute(*args)) + } + } +} + +class OctalParamConverter: ITypeConverter { + override fun convert(value: String): Int { + return value.toInt(8) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt index 06ad605..f85c6cb 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -747,6 +747,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { } } + private var atBreakpoint: Boolean = false private var allowT: Boolean = true private var control_reg: UShort = 0u val logger: Logger = LoggerFactory.getLogger(this.javaClass) @@ -765,6 +766,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { private var stack_limit: UShort = 0u private var handlingStackRed: Boolean = false private var trapReq: Int = 0 + var breakpoint: UShort = 1u val core = PagingUnit(mbus, this) var runState: RunState = RunState.HALTED @@ -1145,21 +1147,22 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { fun run(): Long { var ninsn: Long = 0 - while (runState == RunState.RUNNING) { + atBreakpoint = false + while (runState == RunState.RUNNING && !atBreakpoint) { ninsn += run(Long.MAX_VALUE) } return ninsn } fun run(nstep: Long): Long { + atBreakpoint = false var ninsn: Long = 0 - while (runState == RunState.RUNNING && ninsn < nstep) { + while (runState == RunState.RUNNING && ninsn < nstep && !atBreakpoint) { ninsn++ - if (pc == 0x3224.toUShort()) { - runState = runState - runState = RunState.HALTED - } step() + if (pc == breakpoint) { + atBreakpoint = true + } } return ninsn } @@ -1233,7 +1236,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { enum class RunState(val handleInterrupt: Boolean) { RUNNING(handleInterrupt = true), HALTED(handleInterrupt = false), - WAIT_FOR_INTERRUPT(handleInterrupt = true) + WAIT_FOR_INTERRUPT(handleInterrupt = true), } }