Added CLI
This commit is contained in:
@@ -33,5 +33,5 @@ kotlin {
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("MainKt")
|
||||
mainClass.set("com.thequux.mcpdp.cli.Cli")
|
||||
}
|
||||
|
104
src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt
Normal file
104
src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt
Normal file
@@ -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<Int> {
|
||||
@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<String>) {
|
||||
exitProcess(CommandLine(Cli()).execute(*args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OctalParamConverter: ITypeConverter<Int> {
|
||||
override fun convert(value: String): Int {
|
||||
return value.toInt(8)
|
||||
}
|
||||
}
|
@@ -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),
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user