First try at allowing interrupts
This commit is contained in:
@@ -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()
|
||||
|
@@ -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) {
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user