Got it to the point that it can run a simple echo test
This commit is contained in:
@@ -17,6 +17,9 @@ dependencies {
|
||||
// For the utilities classes
|
||||
kapt("info.picocli:picocli-codegen:4.7.5")
|
||||
implementation("info.picocli:picocli:4.7.5")
|
||||
implementation("org.jline:jline-terminal:3.23.0")
|
||||
implementation("org.jline:jline-terminal-jansi:3.23.0")
|
||||
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
|
@@ -1,3 +1,22 @@
|
||||
import com.thequux.mcpdp.core.CPU
|
||||
import com.thequux.mcpdp.loadAbs
|
||||
import com.thequux.mcpdp.peripheral.DL11
|
||||
import com.thequux.mcpdp.peripheral.MemBus
|
||||
import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
val tb = org.jline.terminal.TerminalBuilder.terminal()
|
||||
try {
|
||||
tb.enterRawMode()
|
||||
var mbus = MemBus(65536)
|
||||
var cpu = CPU(mbus)
|
||||
val console = DL11(tb.input(), tb.output()).apply { mount(mbus.unibus) }
|
||||
console.start()
|
||||
|
||||
cpu.loadAbs(File(args[0]))
|
||||
cpu.runState = CPU.RunState.RUNNING
|
||||
cpu.run()
|
||||
} finally {
|
||||
}
|
||||
}
|
@@ -2,21 +2,56 @@ package com.thequux.mcpdp
|
||||
|
||||
import com.thequux.mcpdp.core.CPU
|
||||
import com.thequux.mcpdp.core.PAddressSpace
|
||||
import com.thequux.mcpdp.ext.bit.bit
|
||||
import com.thequux.mcpdp.ext.bit.shl
|
||||
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
|
||||
var buf = ByteArray(6)
|
||||
var offset = 0
|
||||
var addr: UShort = 0u
|
||||
var len: Int = 0
|
||||
var cksum: Int = 0
|
||||
while (true) {
|
||||
var read = inStream.read(buf, 0, 6)
|
||||
if (read == 0) {
|
||||
if (read == -1) {
|
||||
return
|
||||
} else if (read < 6) {
|
||||
|
||||
}
|
||||
if (hdr[0] != 0)
|
||||
if (read < 6) {
|
||||
// TODO: report the error
|
||||
throw Exception("Short record: $read bytes")
|
||||
}
|
||||
if (buf[0] != 1.toByte() || buf[1] != 0.toByte()) {
|
||||
throw Exception("Invalid block header")
|
||||
}
|
||||
len = buf[3].toInt().shl(8) + buf[2].toInt() - 6
|
||||
addr = (buf[5].toUByte().toUShort().shl(8) + buf[4].toUByte().toUShort()).toUShort()
|
||||
cksum = 0
|
||||
for (i in 0..<6) {
|
||||
cksum += buf[i]
|
||||
}
|
||||
if (buf.size < len+1) {
|
||||
buf = ByteArray(len+1)
|
||||
}
|
||||
inStream.read(buf, 0, len+1)
|
||||
for (i in 0..len) {
|
||||
cksum += buf[i]
|
||||
}
|
||||
cksum = cksum and 0xFF
|
||||
// TODO: validate checksum == 0
|
||||
if (len == 0) {
|
||||
// end of file
|
||||
if (!(addr bit 0)) this.pc = addr
|
||||
return
|
||||
} else {
|
||||
// copy data to memory
|
||||
// TODO: copy a word at a time
|
||||
for (i in 0..<len) {
|
||||
core.setb(addr++, buf[i].toUByte())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,9 +22,9 @@ interface PAddressSpace {
|
||||
val waddr = addr bic 0
|
||||
val load = getw(waddr)
|
||||
val store = if (addr bit 0) {
|
||||
load and 0xFF00u or value.toUShort()
|
||||
} else {
|
||||
load and 0x00FFu or (value.toUShort() shl 8)
|
||||
} else {
|
||||
load and 0xFF00u or value.toUShort()
|
||||
}
|
||||
setw(waddr, store)
|
||||
}
|
||||
|
@@ -12,8 +12,17 @@ import com.thequux.mcpdp.util.ProgrammerError
|
||||
/// xxxx: rest
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
class CPU(val mbus: MemBus) {
|
||||
private val flagStr: String
|
||||
get() {
|
||||
val chars = CharArray(4) { '-' }
|
||||
if (N) chars[0] = 'N'
|
||||
if (Z) chars[1] = 'Z'
|
||||
if (V) chars[2] = 'V'
|
||||
if (C) chars[3] = 'C'
|
||||
return String(chars)
|
||||
}
|
||||
private val registers = UShortArray(8)
|
||||
private val general_registers = Array<UShortArray>(2) { UShortArray(5) }
|
||||
private val general_registers = Array<UShortArray>(2) { UShortArray(6) }
|
||||
private val shadow_r6 = UShortArray(4) //
|
||||
val core = PagingUnit(mbus)
|
||||
|
||||
@@ -54,7 +63,7 @@ class CPU(val mbus: MemBus) {
|
||||
}
|
||||
private var prv_mode: Int = 0
|
||||
private var psw_pl: Int = 0
|
||||
private var pc: UShort
|
||||
var pc: UShort
|
||||
get() = registers[7]
|
||||
set(value) {
|
||||
registers[7] = value
|
||||
@@ -181,8 +190,8 @@ class CPU(val mbus: MemBus) {
|
||||
|
||||
private fun opc_dst(opcode: Int): UInt = op_resolve(opcode and 0x3F)
|
||||
private fun opc_dstb(opcode: Int): UInt = op_resolve(opcode and 0x3F, byte_mode = true)
|
||||
private fun opc_src(opcode: Int): UInt = op_resolve(opcode shr 6 and 0xFC0)
|
||||
private fun opc_srcb(opcode: Int): UInt = op_resolve(opcode shr 6 and 0xFC0, byte_mode = true)
|
||||
private fun opc_src(opcode: Int): UInt = op_resolve(opcode shr 6 and 0x3F)
|
||||
private fun opc_srcb(opcode: Int): UInt = op_resolve(opcode shr 6 and 0x3F, byte_mode = true)
|
||||
|
||||
private fun stack_pop(): UShort = core.getw(sp).also { sp = (sp + 2u).toUShort() }
|
||||
private fun stack_push(value: UShort) {
|
||||
@@ -195,7 +204,9 @@ class CPU(val mbus: MemBus) {
|
||||
pc = (pc + 2u * (opcode and 0xFF).toByte().toShort().toUShort()).toUShort()
|
||||
}
|
||||
}
|
||||
fun step() {
|
||||
|
||||
/// Internal step; evaluates one opcode, but does not handle errors, interrupts, or updating system registers
|
||||
fun step_int() {
|
||||
val opcode = core.getw(pc).toInt()
|
||||
pc = (pc + 2u).toUShort()
|
||||
when (opcode and 0xF000) {
|
||||
@@ -219,7 +230,7 @@ class CPU(val mbus: MemBus) {
|
||||
// jmp
|
||||
val dst = opc_dst(opcode)
|
||||
if (is_paddr_reg(dst)) {
|
||||
throw InvalidOpcodeException()
|
||||
trap(4u); // Illegal instruction
|
||||
}
|
||||
pc = dst.toUShort()
|
||||
} // JMP
|
||||
@@ -259,10 +270,13 @@ class CPU(val mbus: MemBus) {
|
||||
0x0700 -> br_rel(Z or (N xor V), opcode) // BLE
|
||||
0x0800, 0x0900 -> { // JSR
|
||||
val r = opcode shr 6 and 0x7
|
||||
val dst = op_loadw(opc_dst(r))
|
||||
val dst = opc_dst(r)
|
||||
if (is_paddr_reg(dst)) {
|
||||
trap(4u) // illegal opcode
|
||||
}
|
||||
stack_push(registers[r])
|
||||
registers[r] = pc
|
||||
pc = dst
|
||||
pc = dst.toUShort()
|
||||
} // JSR
|
||||
0x0A00 -> when (opcode shr 6 and 3) {
|
||||
0 -> { // CLR
|
||||
@@ -541,7 +555,7 @@ class CPU(val mbus: MemBus) {
|
||||
0x3000 -> { // BIT
|
||||
val src = opc_src(opcode)
|
||||
val dst = opc_dst(opcode)
|
||||
val res = op_loadw(dst) and op_loadw(src).inv()
|
||||
val res = op_loadw(dst) and op_loadw(src)
|
||||
N = res bit 15
|
||||
Z = res != 0u.toUShort()
|
||||
V = false
|
||||
@@ -660,13 +674,13 @@ class CPU(val mbus: MemBus) {
|
||||
} // ASHC
|
||||
4 -> {
|
||||
val r = opcode shr 6 and 7
|
||||
val dst = opc_dst(r)
|
||||
val dst = opc_dst(opcode)
|
||||
val res = op_loadw(dst) xor registers[r]
|
||||
op_storw(dst, res)
|
||||
N = res bit 15
|
||||
Z = res == 0.toUShort()
|
||||
V = false
|
||||
}
|
||||
} // XOR
|
||||
5,6 -> throw InvalidOpcodeException()
|
||||
7 -> {
|
||||
val reg = opcode shr 6 and 7
|
||||
@@ -695,7 +709,7 @@ class CPU(val mbus: MemBus) {
|
||||
val src = op_loadb(opc_srcb(opcode))
|
||||
val src2 = op_loadb(opc_dstb(opcode))
|
||||
val res = (src - src2) and 0xFFu
|
||||
N = res bit 8
|
||||
N = res bit 7
|
||||
Z = res == 0U
|
||||
C = src < src2 // unsigned lt
|
||||
V = ((src bit 8) xor (src2 bit 8)) and ((src2 bit 8) == (res bit 8))
|
||||
@@ -703,9 +717,9 @@ class CPU(val mbus: MemBus) {
|
||||
0xB000 -> { // BITB
|
||||
val src = opc_srcb(opcode)
|
||||
val dst = opc_dstb(opcode)
|
||||
val res = op_loadb(dst) and op_loadb(src).inv()
|
||||
val res = op_loadb(dst) and op_loadb(src)
|
||||
N = res bit 7
|
||||
Z = res != 0u.toUByte()
|
||||
Z = res == 0u.toUByte()
|
||||
V = false
|
||||
} // BITB
|
||||
0xC000 -> { // BICB
|
||||
@@ -741,6 +755,28 @@ class CPU(val mbus: MemBus) {
|
||||
}
|
||||
}
|
||||
|
||||
fun step() {
|
||||
if (runState == RunState.HALTED) return
|
||||
// TODO: check for interrupts
|
||||
if (runState == RunState.WAIT_FOR_INTERRUPT) return
|
||||
|
||||
try {
|
||||
step_int()
|
||||
// TODO: handle T bit
|
||||
} catch (error: MemoryError) {
|
||||
// TODO: fill in memory manager fields
|
||||
trap(4u)
|
||||
} catch (_: InvalidOpcodeException) {
|
||||
trap(10u)
|
||||
}
|
||||
}
|
||||
|
||||
fun run() {
|
||||
while (runState == RunState.RUNNING) {
|
||||
step()
|
||||
}
|
||||
}
|
||||
|
||||
fun trap(vector: UShort) {
|
||||
stack_push(psw)
|
||||
stack_push(pc)
|
||||
@@ -751,12 +787,12 @@ class CPU(val mbus: MemBus) {
|
||||
private inner class Registers: PAddressSpace {
|
||||
override fun getw(addr: UInt): UShort = when (addr) {
|
||||
0x3FFFEu -> psw
|
||||
else -> throw MemoryError(MemoryErrorType.BusTimeout, addr)
|
||||
else -> throw BusTimeoutError(addr)
|
||||
}
|
||||
|
||||
override fun setw(addr: UInt, value: UShort) = when (addr) {
|
||||
0x3FFFEu -> psw = value
|
||||
else -> throw MemoryError(MemoryErrorType.BusTimeout, addr)
|
||||
else -> throw BusTimeoutError(addr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,9 @@
|
||||
package com.thequux.mcpdp.core
|
||||
|
||||
class MemoryError(val type: MemoryErrorType, var addr: UInt): Exception("Memory error $type at ${addr.toString(8)}")
|
||||
sealed class MemoryError(val type: MemoryErrorType, var addr: UInt): Exception("Memory error: $type at ${addr.toString(8)}")
|
||||
class BusTimeoutError(addr: UInt): MemoryError(MemoryErrorType.BusTimeout, addr)
|
||||
class OddAddressError(addr: UInt): MemoryError(MemoryErrorType.OddAddress, addr)
|
||||
class NonExistentMemoryError(addr: UInt): MemoryError(MemoryErrorType.NonExistent, addr)
|
||||
|
||||
enum class MemoryErrorType {
|
||||
BusTimeout,
|
||||
|
@@ -109,13 +109,18 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
|
||||
var mode: Int = 0
|
||||
set(value) {
|
||||
field = value
|
||||
modeSpace = modeVTabs[if (field == 3) 2 else field]
|
||||
modeSpace = if (mmr[0] bit 0) {
|
||||
modeVTabs[if (field == 3) 2 else field]
|
||||
} else {
|
||||
noMmanSpace
|
||||
}
|
||||
}
|
||||
|
||||
private val itabs: Array<PageTable> = Array(3) { PageTable(if (it == 2) 3 else it, dspace = false) }
|
||||
private val dtabs: Array<PageTable> = Array(3) { PageTable(if (it == 2) 3 else it, dspace = true) }
|
||||
private val modeVTabs: Array<ModeVSpace> = Array(3) { ModeVSpace(itabs[it], dtabs[it], false) }
|
||||
var modeSpace: VAddressSpace = modeVTabs[0]
|
||||
private var noMmanSpace = NoMmanSpace()
|
||||
var modeSpace: VAddressSpace = noMmanSpace
|
||||
private set
|
||||
private val unibusTable = UIntArray(32)
|
||||
|
||||
@@ -135,6 +140,14 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
|
||||
}
|
||||
}
|
||||
|
||||
private inner class NoMmanSpace: VAddressSpace {
|
||||
private fun map(addr: UShort): UInt = if ((addr shr 13) == 7u.toUShort()) addr.toUInt().or(0x3F0000u) else addr.toUInt()
|
||||
override fun getb(addr: UShort): UByte = pspace.getb(map(addr))
|
||||
override fun getw(addr: UShort, dspace: Boolean): UShort = pspace.getw(map(addr))
|
||||
override fun setb(addr: UShort, value: UByte) = pspace.setb(map(addr), value)
|
||||
override fun setw(addr: UShort, value: UShort, dspace: Boolean) = pspace.setw(map(addr), value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MMR3: UInt = 0x3F54Eu
|
||||
}
|
||||
@@ -158,7 +171,7 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
|
||||
.bit(5, enableUnibusMap)
|
||||
.toUShort())
|
||||
} // 772516 MMR3
|
||||
else -> throw MemoryError(MemoryErrorType.BusTimeout, addr)
|
||||
else -> throw BusTimeoutError(addr)
|
||||
}
|
||||
|
||||
override fun setw(addr: UInt, value: UShort): Unit = when(addr) {
|
||||
@@ -178,7 +191,7 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
|
||||
unibusTable[uaddr] = unibusTable[uaddr] and 0xFFFF_0000u or (value.toUInt() bic 0)
|
||||
}
|
||||
} // 770200..770377 Unibus map
|
||||
else -> throw MemoryError(MemoryErrorType.BusTimeout, addr)
|
||||
else -> throw BusTimeoutError(addr)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -204,10 +217,12 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
|
||||
private fun map(addr: UInt): UInt {
|
||||
val uaddr = addr and 0x3_FFFFu
|
||||
return if (uaddr > 0x3_0000u) {
|
||||
// I/O page is always mapped as follows
|
||||
addr or 0x3FC000u
|
||||
} else {
|
||||
unibusTable[(uaddr shr 13).toInt()] + (uaddr and 0x1FFFu) or 0x3C0000U
|
||||
// I/O page is always mapped as follows
|
||||
addr or 0x3FC000u
|
||||
} else if (mmr[3] bit 5) {
|
||||
unibusTable[(uaddr shr 13).toInt()] + (uaddr and 0x1FFFu) or 0x3C0000U
|
||||
} else {
|
||||
addr
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,8 +4,9 @@ package com.thequux.mcpdp.ext.bit
|
||||
|
||||
import kotlin.experimental.and
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
inline infix fun Byte.shr(qty: Int): Byte = this.toInt().shr(max(qty, 7)).toByte()
|
||||
inline infix fun Byte.shr(qty: Int): Byte = this.toInt().shr(min(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
|
||||
@@ -16,7 +17,7 @@ inline infix fun Byte.sex(n: Int): Byte {
|
||||
return ((this and sign.dec()) - (this and sign)).toByte()
|
||||
}
|
||||
|
||||
inline infix fun UByte.shr(qty: Int): UByte = this.toUInt().shr(max(qty, 7)).toUByte()
|
||||
inline infix fun UByte.shr(qty: Int): UByte = this.toUInt().shr(min(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
|
||||
@@ -27,7 +28,7 @@ inline infix fun UByte.sex(n: Int): UByte {
|
||||
return ((this and sign.dec()) - (this and sign)).toUByte()
|
||||
}
|
||||
|
||||
inline infix fun Short.shr(qty: Int): Short = this.toInt().shr(max(qty, 15)).toShort()
|
||||
inline infix fun Short.shr(qty: Int): Short = this.toInt().shr(min(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
|
||||
@@ -38,7 +39,7 @@ inline infix fun Short.sex(n: Int): Short {
|
||||
return ((this and sign.dec()) - (this and sign)).toShort()
|
||||
}
|
||||
|
||||
inline infix fun UShort.shr(qty: Int): UShort = this.toUInt().shr(max(qty, 15)).toUShort()
|
||||
inline infix fun UShort.shr(qty: Int): UShort = this.toUInt().shr(min(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
|
||||
|
@@ -2,6 +2,7 @@ package com.thequux.mcpdp.peripheral
|
||||
|
||||
import com.thequux.mcpdp.core.MemoryError
|
||||
import com.thequux.mcpdp.core.MemoryErrorType
|
||||
import com.thequux.mcpdp.core.OddAddressError
|
||||
import com.thequux.mcpdp.core.PAddressSpace
|
||||
import com.thequux.mcpdp.ext.bit.bic
|
||||
import com.thequux.mcpdp.ext.bit.bis
|
||||
@@ -33,7 +34,7 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
|
||||
2 -> { rcsr = rcsr bic 7; rbuf }
|
||||
4 -> xcsr
|
||||
6 -> 0u
|
||||
else -> throw MemoryError(MemoryErrorType.OddAddress, addr)
|
||||
else -> throw OddAddressError(addr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
|
||||
}
|
||||
ostr.write(b)
|
||||
}
|
||||
else -> throw MemoryError(MemoryErrorType.OddAddress, addr)
|
||||
else -> throw OddAddressError(addr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +88,6 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
|
||||
super.start()
|
||||
reader = thread(block = this::readThread)
|
||||
|
||||
reader?.interrupt()
|
||||
// reader?.interrupt()
|
||||
}
|
||||
}
|
@@ -1,8 +1,6 @@
|
||||
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.core.*
|
||||
import com.thequux.mcpdp.ext.bit.bit
|
||||
import com.thequux.mcpdp.util.ConfigurationError
|
||||
|
||||
@@ -32,7 +30,7 @@ class MemBus(val size: Int) : PAddressSpace {
|
||||
override fun getw(addr: UInt): UShort = when (addr) {
|
||||
0x3FFF2u -> 0u // upper size
|
||||
0x3FFF0u -> (size shr 6).toUShort()
|
||||
else -> throw MemoryError(MemoryErrorType.BusTimeout, addr)
|
||||
else -> throw BusTimeoutError(addr)
|
||||
}
|
||||
|
||||
// Both registers are write-only
|
||||
@@ -41,18 +39,23 @@ class MemBus(val size: Int) : PAddressSpace {
|
||||
|
||||
override fun getw(addr: UInt): UShort {
|
||||
if (size bit 0) {
|
||||
throw MemoryError(MemoryErrorType.OddAddress, addr)
|
||||
throw OddAddressError(addr)
|
||||
}
|
||||
return when (addr.toInt()) {
|
||||
in 0..size.dec() -> data[addr.toInt() shr 1]
|
||||
in 0x3c0000..0x3FFFFF -> unibus.getw(addr)
|
||||
else -> throw MemoryError(MemoryErrorType.NonExistent, addr)
|
||||
in 0..size.dec() -> data[addr.toInt() shr 1]
|
||||
else -> throw NonExistentMemoryError(addr)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setw(addr: UInt, value: UShort) {
|
||||
if (size bit 0) {
|
||||
throw MemoryError(MemoryErrorType.OddAddress, addr)
|
||||
throw OddAddressError(addr)
|
||||
}
|
||||
return when (addr.toInt()) {
|
||||
in 0x3c0000..0x3FFFFF -> unibus.setw(addr, value)
|
||||
in 0..size.dec() -> data[addr.toInt() shr 1] = value
|
||||
else -> throw NonExistentMemoryError(addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.thequux.mcpdp.peripheral
|
||||
|
||||
import com.thequux.mcpdp.core.BusTimeoutError
|
||||
import com.thequux.mcpdp.core.MemoryError
|
||||
import com.thequux.mcpdp.core.MemoryErrorType
|
||||
import com.thequux.mcpdp.core.PAddressSpace
|
||||
@@ -35,7 +36,7 @@ open class Subregion(private val suffix: Int, private val size: Int): Region {
|
||||
}
|
||||
|
||||
override fun attach(address: UInt, suffix: Int, device: PAddressSpace) {
|
||||
val loc = (address shr suffix and mask).toInt()
|
||||
val loc = (address shr this.suffix and mask).toInt()
|
||||
if (suffix <= 0) throw ProgrammerError("Suffix must be positive")
|
||||
if (suffix < this.suffix) {
|
||||
// needs a submap
|
||||
@@ -64,7 +65,7 @@ class Unibus: PAddressSpace, Subregion(12, 6) {
|
||||
var deviceView: PAddressSpace = this
|
||||
internal set
|
||||
override fun map(address: UInt): PAddressSpace =
|
||||
super.map(address) ?: throw MemoryError(MemoryErrorType.BusTimeout, address)
|
||||
super.map(address) ?: throw BusTimeoutError(address)
|
||||
override fun getw(addr: UInt): UShort = map(addr).getw(addr)
|
||||
override fun getb(addr: UInt): UByte = map(addr).getb(addr)
|
||||
override fun setw(addr: UInt, value: UShort) = map(addr).setw(addr, value)
|
||||
|
@@ -6,11 +6,14 @@ xbuf = 177566
|
||||
.psect .txt
|
||||
.title echo
|
||||
start:
|
||||
mov #40,r3
|
||||
tstb @#rcsr
|
||||
bmi start
|
||||
bge start
|
||||
mov @#rbuf,r1
|
||||
xor r1,#40
|
||||
mov r1,@#xbuf
|
||||
cmpb r1,#40
|
||||
ble noxor
|
||||
xor r3,r1
|
||||
noxor: mov r1,@#xbuf
|
||||
br start
|
||||
.byte 123
|
||||
.end start
|
||||
|
Reference in New Issue
Block a user