First try at allowing interrupts

This commit is contained in:
2023-09-13 23:38:32 +02:00
parent 79efc4e8d3
commit d546b0c28e
4 changed files with 81 additions and 15 deletions

View File

@@ -9,7 +9,7 @@ fun main(args: Array<String>) {
val tb = org.jline.terminal.TerminalBuilder.terminal()
var mbus = MemBus(65536)
var cpu = CPU(mbus)
val console = DL11(tb.input(), tb.output()).apply { mount(mbus.unibus) }
val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) }
try {
tb.enterRawMode()

View File

@@ -35,7 +35,7 @@ class CPU(val mbus: MemBus) {
if (Z) res = res or 0x0004
if (N) res = res or 0x0008
if (T) res = res or 0x0010
res = res or (psw_pl shl 5)
res = res or (psw_priority shl 5)
res = res or (cur_mode shl 14) or (prv_mode shl 12)
res = res or (registerSet shl 11)
return res.toUShort()
@@ -47,7 +47,7 @@ class CPU(val mbus: MemBus) {
Z = value bit 3
N = value bit 4
T = value bit 5 // TODO: handle suspended trap
psw_pl = newpsw shr 5 and 7
psw_priority = newpsw shr 5 and 7
registerSet = newpsw shr 11 and 1
cur_mode = newpsw shr 14
@@ -62,7 +62,7 @@ class CPU(val mbus: MemBus) {
core.mode = value
}
private var prv_mode: Int = 0
private var psw_pl: Int = 0
private var psw_priority: Int = 0
var pc: UShort
get() = registers[7]
set(value) {
@@ -240,7 +240,7 @@ class CPU(val mbus: MemBus) {
registers[reg] = stack_pop()
} // RTS
in 0x98..0x9F -> {
psw_pl = opcode and 0x7
psw_priority = opcode and 0x7
} // SPL
in 0xA0..0xBF -> {
val flag = opcode bit 4
@@ -756,11 +756,23 @@ class CPU(val mbus: MemBus) {
}
fun step() {
if (runState == RunState.HALTED) return
// TODO: check for interrupts
if (runState == RunState.WAIT_FOR_INTERRUPT) return
try {
if (runState == RunState.HALTED) return
// TODO: handle PIRQ
for (i in (psw_priority + 1..<7).reversed()) {
val source = mbus.unibus.checkInterrupt(i)
if (source != null) {
// we might have been waiting for an interrupt
runState = RunState.RUNNING
trap(source.vector)
source.handled()
break
}
}
if (runState == RunState.WAIT_FOR_INTERRUPT) return
step_int()
// TODO: handle T bit
} catch (error: MemoryError) {

View File

@@ -14,13 +14,25 @@ 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 {
class DL11(private var istr: InputStream, private val ostr: OutputStream, val reg_base: UInt, val vector: UShort, val unibus: Unibus): PAddressSpace, Peripheral {
private var reader: Thread? = null
private var rcsr: UShort = 0x0u
set(value) {
/// Propagate status bits
val setBits = field.inv().and(value).toInt()
val changedBits = (field xor value).toInt()
val datasetStatusChanged = (setBits.and(0x4000) or changedBits.and(0x3400)) != 0
val newValue = value.bit(15, datasetStatusChanged)
intrRcv.level = intrRcv.level || (newValue bit 5 && datasetStatusChanged && !(field bit 15)) || (newValue bit 6 && setBits bit 7)
field = newValue
}
private var rbuf: UShort = 0u
private var xcsr: UShort = 0u
private var xcsr: UShort = 0x80u
constructor(istr: InputStream, ostr: OutputStream): this(istr, ostr, 0x3FF70u, 0x30u)
private var intrRcv = InterruptSource(unibus, 4, vector, edgeTriggered = true)
private var intrXmit = InterruptSource(unibus, 4, (vector+4u).toUShort(), edgeTriggered = true)
constructor(unibus: Unibus, istr: InputStream, ostr: OutputStream): this(istr, ostr, 0x3FF70u, 0x30u, unibus)
override fun mount(bus: Unibus) {
bus.attach(reg_base, 3, this)
@@ -30,7 +42,11 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
override fun getw(addr: UInt): UShort = synchronized(this) {
when (addr.toInt() and 7) {
0 -> rcsr
0 -> {
val oldRcsr = rcsr
rcsr = rcsr bic 15
oldRcsr
}
2 -> { rcsr = rcsr bic 7; rbuf }
4 -> xcsr
6 -> 0u
@@ -48,9 +64,10 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
4 -> xcsr = xcsr.maskSet(value, 0x0045u)
6 -> {
val b = value.toInt() and 0xFF
if (xcsr bit 1) {
if (xcsr bit 2) {
recvByte(b)
}
if (xcsr bit 6) intrXmit.level = true
ostr.write(b)
}
else -> throw OddAddressError(addr)

View File

@@ -7,6 +7,9 @@ import com.thequux.mcpdp.core.PAddressSpace
import com.thequux.mcpdp.util.ConfigurationError
import com.thequux.mcpdp.util.ProgrammerError
import java.lang.Integer.min
import java.util.Collections
import java.util.LinkedList
import java.util.Vector
interface Region {
fun attach(address: UInt, suffix: Int, device: PAddressSpace)
@@ -14,6 +17,11 @@ interface Region {
fun map(address: UInt): PAddressSpace?
}
interface Device {
// TODO: Add runtime config interface
val vector: UShort
}
@JvmInline
private value class MappedDevice(val device: PAddressSpace): Region {
override fun attach(address: UInt, suffix: Int, device: PAddressSpace) {
@@ -64,6 +72,9 @@ class Unibus: PAddressSpace, Subregion(12, 6) {
/// The view of the unibus from a device
var deviceView: PAddressSpace = this
internal set
private val queue: Array<MutableList<InterruptSource>> = Array(8) { Vector(4) }
override fun map(address: UInt): PAddressSpace =
super.map(address) ?: throw BusTimeoutError(address)
override fun getw(addr: UInt): UShort = map(addr).getw(addr)
@@ -71,7 +82,33 @@ class Unibus: PAddressSpace, Subregion(12, 6) {
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")
/// Request that the processor service an interrupt. When the interrupt is handled, calls getVector() on the device
/// to fetch the currently desired interrupt vector
fun assertInterrupt(priority: Int, device: InterruptSource) {
val list = queue[priority]
if (!list.contains(device)) list.add(device)
}
fun deassertInterrupt(priority: Int, device: InterruptSource) {
queue[priority].remove(device)
}
// Checks for an interrupt. The handler receives (priority, device)
fun checkInterrupt(priority: Int): InterruptSource? = queue[priority].firstOrNull()
}
class InterruptSource(val unibus: Unibus, val priority: Int, val vector: UShort, val edgeTriggered: Boolean = false) {
fun handled() {
if (edgeTriggered) level = false
}
var level: Boolean = false
set(value) {
when(value) {
field -> {}
true -> unibus.assertInterrupt(priority, this)
false -> unibus.deassertInterrupt(priority, this)
}
field = value
}
}