From 0d3dfb5a379e0c97642b5e7de5abca36e6948bf5 Mon Sep 17 00:00:00 2001 From: TQ Hirsch Date: Sun, 10 Sep 2023 20:53:10 +0200 Subject: [PATCH] Many changes --- .idea/kotlinc.xml | 2 +- build.gradle.kts | 5 + src/main/kotlin/Main.kt | 4 - .../kotlin/com/thequux/mcpdp/RT11Loader.kt | 22 ++++ src/main/kotlin/com/thequux/mcpdp/core/CPU.kt | 4 +- .../com/thequux/mcpdp/core/PagingUnit.kt | 54 ++++++---- .../com/thequux/mcpdp/ext/bit/bitext.kt | 100 +++++++++--------- .../com/thequux/mcpdp/peripheral/DL11.kt | 92 ++++++++++++++++ .../thequux/mcpdp/peripheral/Peripheral.kt | 14 +++ .../com/thequux/mcpdp/peripheral/Unibus.kt | 7 +- .../kotlin/com/thequux/mcpdp/tools/Link11.kt | 62 +++++++++++ test/echo.mac | 16 +++ 12 files changed, 307 insertions(+), 75 deletions(-) create mode 100644 src/main/kotlin/com/thequux/mcpdp/RT11Loader.kt create mode 100644 src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt create mode 100644 src/main/kotlin/com/thequux/mcpdp/peripheral/Peripheral.kt create mode 100644 src/main/kotlin/com/thequux/mcpdp/tools/Link11.kt create mode 100644 test/echo.mac diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index fdf8d99..f8467b4 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 55f1c4d..1a4ebcf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("jvm") version "1.9.0" application + kotlin("kapt") version "1.9.10" } group = "com.thequux" @@ -12,6 +13,10 @@ repositories { dependencies { testImplementation(kotlin("test")) + + // For the utilities classes + kapt("info.picocli:picocli-codegen:4.7.5") + implementation("info.picocli:picocli:4.7.5") } tasks.test { diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index f2a59b6..adb5b33 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,7 +1,3 @@ fun main(args: Array) { - println("Hello World!") - // Try adding program arguments via Run/Debug configuration. - // Learn more about running applications: https://www.jetbrains.com/help/idea/running-applications.html. - println("Program arguments: ${args.joinToString()}") } \ No newline at end of file diff --git a/src/main/kotlin/com/thequux/mcpdp/RT11Loader.kt b/src/main/kotlin/com/thequux/mcpdp/RT11Loader.kt new file mode 100644 index 0000000..e766a74 --- /dev/null +++ b/src/main/kotlin/com/thequux/mcpdp/RT11Loader.kt @@ -0,0 +1,22 @@ +package com.thequux.mcpdp + +import com.thequux.mcpdp.core.CPU +import com.thequux.mcpdp.core.PAddressSpace +import java.io.File + +/// Loads an RT-11 object file into memory +fun CPU.loadAbs(infile: File) { + val core = this.core.modeSpace + val inStream = infile.inputStream().buffered() + val buf = ByteArray(6) + val + while (true) { + var read = inStream.read(buf, 0, 6) + if (read == 0) { + return + } else if (read < 6) { + + } + if (hdr[0] != 0) + } +} \ 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 c5a2cb8..e008d64 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -11,11 +11,11 @@ import com.thequux.mcpdp.util.ProgrammerError /// Exxx: ROM /// xxxx: rest @OptIn(ExperimentalUnsignedTypes::class) -class CPU(private val mbus: MemBus) { +class CPU(val mbus: MemBus) { private val registers = UShortArray(8) private val general_registers = Array(2) { UShortArray(5) } private val shadow_r6 = UShortArray(4) // - private val core = PagingUnit(mbus) + val core = PagingUnit(mbus) var runState: RunState = RunState.HALTED var psw: UShort diff --git a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt index cd2e7fe..3a6855a 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt @@ -57,7 +57,6 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { private var mmr = UShortArray(4) private var enableUnibusMap: Boolean = false private var enable22bit: Boolean = false - private var enableDSpaceByMode = BooleanArray(4) /// The 18-bit address space exposed to peripherals val unibusMap: PAddressSpace = UnibusMap() @@ -108,36 +107,53 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { } var mode: Int = 0 + set(value) { + field = value + modeSpace = modeVTabs[if (field == 3) 2 else field] + } private val itabs: Array = Array(3) { PageTable(if (it == 2) 3 else it, dspace = false) } private val dtabs: Array = Array(3) { PageTable(if (it == 2) 3 else it, dspace = true) } - private var curIspace: PageTable = itabs[0] - private var curDspace: PageTable = dtabs[0] + private val modeVTabs: Array = Array(3) { ModeVSpace(itabs[it], dtabs[it], false) } + var modeSpace: VAddressSpace = modeVTabs[0] + private set private val unibusTable = UIntArray(32) - private fun getSpace(dspace: Boolean): PageTable = if (dspace) curDspace else curIspace - override fun getw(addr: UShort, dspace: Boolean): UShort = pspace.getw(getSpace(dspace).map(addr, write = false)) - override fun getb(addr: UShort): UByte = pspace.getb(curDspace.map(addr, write = false)) + private inner class ModeVSpace(private val iSpace: PageTable, private val dSpace: PageTable, var useDSpace: Boolean): VAddressSpace { + private fun getSpace(dspace: Boolean): PageTable = if (dspace) dSpace else iSpace + override fun getw(addr: UShort, dspace: Boolean): UShort = pspace.getw(getSpace(dspace).map(addr, write = false)) - override fun setw(addr: UShort, value: UShort, dspace: Boolean) { - pspace.setw(getSpace(dspace).map(addr, write = true), value) - } + override fun getb(addr: UShort): UByte = pspace.getb(dSpace.map(addr, write = false)) - override fun setb(addr: UShort, value: UByte) { - pspace.setb(curDspace.map(addr, write = true), value) + override fun setw(addr: UShort, value: UShort, dspace: Boolean) { + pspace.setw(getSpace(dspace).map(addr, write = true), value) + } + + override fun setb(addr: UShort, value: UByte) { + pspace.setb(dSpace.map(addr, write = true), value) + } } companion object { private val MMR3: UInt = 0x3F54Eu } + + override fun getw(addr: UShort, dspace: Boolean): UShort = modeSpace.getw(addr, dspace) + + override fun getb(addr: UShort): UByte = modeSpace.getb(addr) + + override fun setw(addr: UShort, value: UShort, dspace: Boolean) = modeSpace.setw(addr, value, dspace) + + override fun setb(addr: UShort, value: UByte) = modeSpace.setb(addr, value) + private inner class ConfigRegisters: PAddressSpace { override fun getw(addr: UInt): UShort = when (addr) { MMR3 -> { - (0U.bit(0, enableDSpaceByMode[3]) - .bit(1, enableDSpaceByMode[1]) - .bit(2, enableDSpaceByMode[0]) + (0U.bit(0, modeVTabs[2].useDSpace) + .bit(1, modeVTabs[1].useDSpace) + .bit(2, modeVTabs[0].useDSpace) .bit(4, enable22bit) .bit(5, enableUnibusMap) .toUShort()) @@ -149,9 +165,9 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { MMR3 -> { enableUnibusMap = value bit 5 enable22bit = value bit 4 - enableDSpaceByMode[0] = value bit 2 - enableDSpaceByMode[1] = value bit 1 - enableDSpaceByMode[3] = value bit 0 + modeVTabs[0].useDSpace = value bit 2 + modeVTabs[1].useDSpace = value bit 1 + modeVTabs[2].useDSpace = value bit 0 } in 0x3F080u..0x3F0FFu -> { val uaddr = (addr shr 1 and 31u).toInt() @@ -178,10 +194,10 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { attach(0x3_F4C0u, 6, regs) // Kernal PAR/PDF attach(0x3_F480u, 6, regs) // Supervisor PAR/PDR attach(0x3_F080u, 7, regs) // Unibus map - } - } + + private inner class UnibusMap: PAddressSpace { // This implements an *18-bit* address space, for the view of unibus peripherals diff --git a/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt b/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt index 20e126f..9ff3a93 100644 --- a/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt +++ b/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt @@ -1,82 +1,86 @@ +@file:Suppress("NOTHING_TO_INLINE") + package com.thequux.mcpdp.ext.bit import kotlin.experimental.and import kotlin.math.max -infix fun Byte.shr(qty: Int): Byte = this.toInt().shr(max(qty, 7)).toByte() -infix fun Byte.shl(qty: Int): Byte = if (qty > 7) 0 else this.toInt().shl(qty).toByte() -infix fun Byte.bit(n: Int): Boolean = this.toInt() shr n and 1 != 0 -fun Byte.bit(n: Int, v: Boolean): Byte = if (v) this bis n else this bic n -infix fun Byte.bis(n: Int): Byte = this.toInt().or(1 shl n).toByte() -infix fun Byte.bic(n: Int): Byte = this.toInt().and(1.shl(n).inv()).toByte() -infix fun Byte.sex(n: Int): Byte { +inline infix fun Byte.shr(qty: Int): Byte = this.toInt().shr(max(qty, 7)).toByte() +inline infix fun Byte.shl(qty: Int): Byte = if (qty > 7) 0 else this.toInt().shl(qty).toByte() +inline infix fun Byte.bit(n: Int): Boolean = this.toInt() shr n and 1 != 0 +inline fun Byte.bit(n: Int, v: Boolean): Byte = if (v) this bis n else this bic n +inline infix fun Byte.bis(n: Int): Byte = this.toInt().or(1 shl n).toByte() +inline infix fun Byte.bic(n: Int): Byte = this.toInt().and(1.shl(n).inv()).toByte() +inline infix fun Byte.sex(n: Int): Byte { val sign = 1.toByte() shl n+1 return ((this and sign.dec()) - (this and sign)).toByte() } -infix fun UByte.shr(qty: Int): UByte = this.toUInt().shr(max(qty, 7)).toUByte() -infix fun UByte.shl(qty: Int): UByte = if (qty > 7) 0U else this.toInt().shl(qty).toUByte() -infix fun UByte.bit(n: Int): Boolean = this.toUInt() shr n and 1U != 0U -fun UByte.bit(n: Int, v: Boolean): UByte = if (v) this bis n else this bic n -infix fun UByte.bis(n: Int): UByte = this.toUInt().or(1U shl n).toUByte() -infix fun UByte.bic(n: Int): UByte = this.toUInt().and(1U.shl(n).inv()).toUByte() -infix fun UByte.sex(n: Int): UByte { +inline infix fun UByte.shr(qty: Int): UByte = this.toUInt().shr(max(qty, 7)).toUByte() +inline infix fun UByte.shl(qty: Int): UByte = if (qty > 7) 0U else this.toInt().shl(qty).toUByte() +inline infix fun UByte.bit(n: Int): Boolean = this.toUInt() shr n and 1U != 0U +inline fun UByte.bit(n: Int, v: Boolean): UByte = if (v) this bis n else this bic n +inline infix fun UByte.bis(n: Int): UByte = this.toUInt().or(1U shl n).toUByte() +inline infix fun UByte.bic(n: Int): UByte = this.toUInt().and(1U.shl(n).inv()).toUByte() +inline infix fun UByte.sex(n: Int): UByte { val sign = 1.toUByte() shl n+1 return ((this and sign.dec()) - (this and sign)).toUByte() } -infix fun Short.shr(qty: Int): Short = this.toInt().shr(max(qty, 15)).toShort() -infix fun Short.shl(qty: Int): Short = if (qty > 15) 0 else this.toInt().shl(qty).toShort() -infix fun Short.bit(n: Int): Boolean = this.toInt() shr n and 1 != 0 -fun Short.bit(n: Int, v: Boolean): Short = if (v) this bis n else this bic n -infix fun Short.bis(n: Int): Short = this.toInt().or(1 shl n).toShort() -infix fun Short.bic(n: Int): Short = this.toInt().and(1.shl(n).inv()).toShort() -infix fun Short.sex(n: Int): Short { +inline infix fun Short.shr(qty: Int): Short = this.toInt().shr(max(qty, 15)).toShort() +inline infix fun Short.shl(qty: Int): Short = if (qty > 15) 0 else this.toInt().shl(qty).toShort() +inline infix fun Short.bit(n: Int): Boolean = this.toInt() shr n and 1 != 0 +inline fun Short.bit(n: Int, v: Boolean): Short = if (v) this bis n else this bic n +inline infix fun Short.bis(n: Int): Short = this.toInt().or(1 shl n).toShort() +inline infix fun Short.bic(n: Int): Short = this.toInt().and(1.shl(n).inv()).toShort() +inline infix fun Short.sex(n: Int): Short { val sign = 1.toShort() shl n+1 return ((this and sign.dec()) - (this and sign)).toShort() } -infix fun UShort.shr(qty: Int): UShort = this.toUInt().shr(max(qty, 15)).toUShort() -infix fun UShort.shl(qty: Int): UShort = if (qty > 15) 0U else this.toInt().shl(qty).toUShort() -infix fun UShort.bit(n: Int): Boolean = this.toUInt() shr n and 1U != 0U -fun UShort.bit(n: Int, v: Boolean): UShort = if (v) this bis n else this bic n -infix fun UShort.bis(n: Int): UShort = this.toUInt().or(1U shl n).toUShort() -infix fun UShort.bic(n: Int): UShort = this.toUInt().and(1U.shl(n).inv()).toUShort() -infix fun UShort.sex(n: Int): UShort { +inline infix fun UShort.shr(qty: Int): UShort = this.toUInt().shr(max(qty, 15)).toUShort() +inline infix fun UShort.shl(qty: Int): UShort = if (qty > 15) 0U else this.toInt().shl(qty).toUShort() +inline infix fun UShort.bit(n: Int): Boolean = this.toUInt() shr n and 1U != 0U +inline fun UShort.bit(n: Int, v: Boolean): UShort = if (v) this bis n else this bic n +inline infix fun UShort.bis(n: Int): UShort = this.toUInt().or(1U shl n).toUShort() +inline infix fun UShort.bic(n: Int): UShort = this.toUInt().and(1U.shl(n).inv()).toUShort() +inline infix fun UShort.sex(n: Int): UShort { val sign = 1.toUShort() shl n+1 return ((this and sign.dec()) - (this and sign)).toUShort() } -infix fun Int.bit(n: Int): Boolean = this shr n and 1 != 0 -fun Int.bit(n: Int, v: Boolean): Int = if (v) this bis n else this bic n -infix fun Int.bis(n: Int): Int = this.or(1 shl n) -infix fun Int.bic(n: Int): Int = this and (1 shl n).inv() -infix fun Int.sex(n: Int): Int { +inline fun UShort.maskSet(v: UShort, mask: UShort) = this and mask.inv() or (v and mask) + +inline infix fun Int.bit(n: Int): Boolean = this shr n and 1 != 0 +inline fun Int.bit(n: Int, v: Boolean): Int = if (v) this bis n else this bic n +inline infix fun Int.bis(n: Int): Int = this.or(1 shl n) +inline infix fun Int.bic(n: Int): Int = this and (1 shl n).inv() +inline infix fun Int.sex(n: Int): Int { val sign = 1 shl n+1 return ((this and sign.dec()) - (this and sign)) } -infix fun UInt.bit(n: Int): Boolean = this shr n and 1U != 0U -fun UInt.bit(n: Int, v: Boolean): UInt = if (v) this bis n else this bic n -infix fun UInt.bis(n: Int): UInt = this.or(1U shl n) -infix fun UInt.bic(n: Int): UInt = this.and(1U.shl(n).inv()) -infix fun UInt.sex(n: Int): UInt { +inline infix fun UInt.bit(n: Int): Boolean = this shr n and 1U != 0U +inline fun UInt.bit(n: Int, v: Boolean): UInt = if (v) this bis n else this bic n +inline infix fun UInt.bis(n: Int): UInt = this.or(1U shl n) +inline infix fun UInt.bic(n: Int): UInt = this.and(1U.shl(n).inv()) +inline infix fun UInt.sex(n: Int): UInt { val sign = 1U shl n+1 return ((this and sign.dec()) - (this and sign)) } -infix fun Long.bit(n: Int): Boolean = this shr n and 1L != 0L -fun Long.bit(n: Int, v: Boolean): Long = if (v) this bis n else this bic n -infix fun Long.bis(n: Int): Long = this.or(1L shl n) -infix fun Long.bic(n: Int): Long = this and (1L shl n).inv() -infix fun Long.sex(n: Int): Long { +inline infix fun Long.bit(n: Int): Boolean = this shr n and 1L != 0L +inline fun Long.bit(n: Int, v: Boolean): Long = if (v) this bis n else this bic n +inline infix fun Long.bis(n: Int): Long = this.or(1L shl n) +inline infix fun Long.bic(n: Int): Long = this and (1L shl n).inv() +inline infix fun Long.sex(n: Int): Long { val sign = 1.toLong() shl n+1 return (this and sign.dec()) - (this and sign) } -infix fun ULong.bit(n: Int): Boolean = this shr n and 1UL != 0UL -fun ULong.bit(n: Int, v: Boolean): ULong = if (v) this bis n else this bic n -infix fun ULong.bis(n: Int): ULong = this.or(1UL shl n) -infix fun ULong.bic(n: Int): ULong = this.and(1UL.shl(n).inv()) -infix fun ULong.sex(n: Int): ULong { +inline infix fun ULong.bit(n: Int): Boolean = this shr n and 1UL != 0UL +inline fun ULong.bit(n: Int, v: Boolean): ULong = if (v) this bis n else this bic n +inline infix fun ULong.bis(n: Int): ULong = this.or(1UL shl n) +inline infix fun ULong.bic(n: Int): ULong = this.and(1UL.shl(n).inv()) +inline infix fun ULong.sex(n: Int): ULong { val sign = 1UL shl n+1 return ((this and (sign.dec())) - (this and sign)) } diff --git a/src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt b/src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt new file mode 100644 index 0000000..ab97645 --- /dev/null +++ b/src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt @@ -0,0 +1,92 @@ +package com.thequux.mcpdp.peripheral + +import com.thequux.mcpdp.core.MemoryError +import com.thequux.mcpdp.core.MemoryErrorType +import com.thequux.mcpdp.core.PAddressSpace +import com.thequux.mcpdp.ext.bit.bic +import com.thequux.mcpdp.ext.bit.bis +import com.thequux.mcpdp.ext.bit.bit +import com.thequux.mcpdp.ext.bit.maskSet +import java.io.InputStream +import java.io.OutputStream +import java.util.concurrent.Semaphore +import kotlin.concurrent.thread + + +class DL11(private var istr: InputStream, private val ostr: OutputStream, val reg_base: UInt, val vector: UShort): PAddressSpace, Peripheral { + private var reader: Thread? = null + private var rcsr: UShort = 0x0u + private var rbuf: UShort = 0u + private var xcsr: UShort = 0u + + constructor(istr: InputStream, ostr: OutputStream): this(istr, ostr, 0x3FF70u, 0x30u) + + override fun mount(bus: Unibus) { + bus.attach(reg_base, 3, this) + } + + override fun service() { } + + override fun getw(addr: UInt): UShort = synchronized(this) { + when (addr.toInt() and 7) { + 0 -> rcsr + 2 -> { rcsr = rcsr bic 7; rbuf } + 4 -> xcsr + 6 -> 0u + else -> throw MemoryError(MemoryErrorType.OddAddress, addr) + } + } + + override fun setw(addr: UInt, value: UShort): Unit = synchronized(this) { + when (addr.toInt() and 7) { + 0 -> { + rcsr = rcsr.maskSet(value, 0x009Eu) + if (value bit 0) {rcsr = rcsr bic 7 } + } + 2 -> { rcsr = rcsr bic 7 } + 4 -> xcsr = xcsr.maskSet(value, 0x0045u) + 6 -> { + val b = value.toInt() and 0xFF + if (xcsr bit 1) { + recvByte(b) + } + ostr.write(b) + } + else -> throw MemoryError(MemoryErrorType.OddAddress, addr) + } + } + + private fun recvByte(data: Int) { + val overrun = rcsr bit 7 + rcsr = rcsr and 0xC3FFu + if (data < 0) { + rcsr = rcsr bis 12 + } else { + rcsr = rcsr bis 7 + rbuf = (data and 0xFF).bit(14, overrun).bit(15, overrun).toUShort() + } + } + private fun readThread() { + try { + while (true) { + val data = istr.read() + synchronized(this) { + // receive if not in maintenance mode + // TODO: block until receiver ready + if (!(xcsr bit 1)) recvByte(data) + } + if (data < 0) { + break + } + } + } catch (_: InterruptedException) { + // Nothing to do; time to shut down + } + } + override fun start() { + super.start() + reader = thread(block = this::readThread) + + reader?.interrupt() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/thequux/mcpdp/peripheral/Peripheral.kt b/src/main/kotlin/com/thequux/mcpdp/peripheral/Peripheral.kt new file mode 100644 index 0000000..b76a9e3 --- /dev/null +++ b/src/main/kotlin/com/thequux/mcpdp/peripheral/Peripheral.kt @@ -0,0 +1,14 @@ +package com.thequux.mcpdp.peripheral + +interface Peripheral { + fun mount(bus: Unibus) + fun reset() {} + + /// Check if the device needs to do something + fun service() + + /// Called when the device starts up + fun start() {} + /// Called when the device stops + fun stop() {} +} \ No newline at end of file diff --git a/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt b/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt index ff53ed8..40b8241 100644 --- a/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt +++ b/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt @@ -13,7 +13,8 @@ interface Region { fun map(address: UInt): PAddressSpace? } -private class MappedDevice(val device: PAddressSpace): Region { +@JvmInline +private value class MappedDevice(val device: PAddressSpace): Region { override fun attach(address: UInt, suffix: Int, device: PAddressSpace) { throw ConfigurationError("Attempted to map one device over another at ${address.toString(8)}") } @@ -68,4 +69,8 @@ class Unibus: PAddressSpace, Subregion(12, 6) { override fun getb(addr: UInt): UByte = map(addr).getb(addr) override fun setw(addr: UInt, value: UShort) = map(addr).setw(addr, value) override fun setb(addr: UInt, value: UByte) = map(addr).setb(addr, value) + + fun interrupt(vector: UShort) { + throw NotImplementedError("Interrupts not yet implemented") + } } diff --git a/src/main/kotlin/com/thequux/mcpdp/tools/Link11.kt b/src/main/kotlin/com/thequux/mcpdp/tools/Link11.kt new file mode 100644 index 0000000..8530687 --- /dev/null +++ b/src/main/kotlin/com/thequux/mcpdp/tools/Link11.kt @@ -0,0 +1,62 @@ +@file:OptIn(ExperimentalUnsignedTypes::class) + +package com.thequux.mcpdp.tools + +import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream +import picocli.CommandLine +import picocli.CommandLine.Option +import picocli.CommandLine.Parameters +import java.io.File +import java.util.Hashtable +import java.util.concurrent.Callable +import java.util.function.Consumer + + +@CommandLine.Command(name = "link", description = ["Link together multiple object files into something loadable"]) +class Link11: Callable { + + @Parameters() + lateinit var objects: Array + + @Option(names = ["-o", "--out"], required = true, description = ["Output file"]) + lateinit var outFile: File + + @Option(names = ["-l", "--load"], description = ["Load address"]) + var loadAddr: Int = 1024 + + companion object { + val R40Chars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789".toCharArray() + fun decodeRadix50(word: UShort): String { + val buf = CharArray(3) + var value = word.toInt() + for (i in 0..2) { + buf[2-i] = (value % 40).toChar() + value /= 40 + } + return String(buf) + } + + fun main(args: Array) { + + } + } + + // symbols are always 4 bytes of radix-50, so we can just treat it as a uint + private val symbols: HashMap = HashMap() + private val pendingReloc: HashMap>> = HashMap() + private val mem = UByteArray(65536) + + private val prog_start_addr: UShort = 1u + private val prog_start_value: UShort = 1u + private val prog_start_psect: UInt = 0xF94AF01u // ". ABS." + + + + override fun call(): Int { + return 0 + } + + private fun load_rt11() { + + } +} \ No newline at end of file diff --git a/test/echo.mac b/test/echo.mac new file mode 100644 index 0000000..14669e8 --- /dev/null +++ b/test/echo.mac @@ -0,0 +1,16 @@ +rcsr = 177560 +rbuf = 177562 +xcsr = 177564 +xbuf = 177566 + + .psect .txt + .title echo +start: + tstb @#rcsr + bmi start + mov @#rbuf,r1 + xor r1,#40 + mov r1,@#xbuf + br start +.byte 123 +.end start