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()
|
val tb = org.jline.terminal.TerminalBuilder.terminal()
|
||||||
var mbus = MemBus(65536)
|
var mbus = MemBus(65536)
|
||||||
var cpu = CPU(mbus)
|
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 {
|
try {
|
||||||
|
|
||||||
tb.enterRawMode()
|
tb.enterRawMode()
|
||||||
|
@@ -35,7 +35,7 @@ class CPU(val mbus: MemBus) {
|
|||||||
if (Z) res = res or 0x0004
|
if (Z) res = res or 0x0004
|
||||||
if (N) res = res or 0x0008
|
if (N) res = res or 0x0008
|
||||||
if (T) res = res or 0x0010
|
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 (cur_mode shl 14) or (prv_mode shl 12)
|
||||||
res = res or (registerSet shl 11)
|
res = res or (registerSet shl 11)
|
||||||
return res.toUShort()
|
return res.toUShort()
|
||||||
@@ -47,7 +47,7 @@ class CPU(val mbus: MemBus) {
|
|||||||
Z = value bit 3
|
Z = value bit 3
|
||||||
N = value bit 4
|
N = value bit 4
|
||||||
T = value bit 5 // TODO: handle suspended trap
|
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
|
registerSet = newpsw shr 11 and 1
|
||||||
cur_mode = newpsw shr 14
|
cur_mode = newpsw shr 14
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ class CPU(val mbus: MemBus) {
|
|||||||
core.mode = value
|
core.mode = value
|
||||||
}
|
}
|
||||||
private var prv_mode: Int = 0
|
private var prv_mode: Int = 0
|
||||||
private var psw_pl: Int = 0
|
private var psw_priority: Int = 0
|
||||||
var pc: UShort
|
var pc: UShort
|
||||||
get() = registers[7]
|
get() = registers[7]
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -240,7 +240,7 @@ class CPU(val mbus: MemBus) {
|
|||||||
registers[reg] = stack_pop()
|
registers[reg] = stack_pop()
|
||||||
} // RTS
|
} // RTS
|
||||||
in 0x98..0x9F -> {
|
in 0x98..0x9F -> {
|
||||||
psw_pl = opcode and 0x7
|
psw_priority = opcode and 0x7
|
||||||
} // SPL
|
} // SPL
|
||||||
in 0xA0..0xBF -> {
|
in 0xA0..0xBF -> {
|
||||||
val flag = opcode bit 4
|
val flag = opcode bit 4
|
||||||
@@ -756,11 +756,23 @@ class CPU(val mbus: MemBus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun step() {
|
fun step() {
|
||||||
if (runState == RunState.HALTED) return
|
|
||||||
// TODO: check for interrupts
|
|
||||||
if (runState == RunState.WAIT_FOR_INTERRUPT) return
|
|
||||||
|
|
||||||
try {
|
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()
|
step_int()
|
||||||
// TODO: handle T bit
|
// TODO: handle T bit
|
||||||
} catch (error: MemoryError) {
|
} catch (error: MemoryError) {
|
||||||
|
@@ -14,13 +14,25 @@ import java.util.concurrent.Semaphore
|
|||||||
import kotlin.concurrent.thread
|
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 reader: Thread? = null
|
||||||
private var rcsr: UShort = 0x0u
|
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 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) {
|
override fun mount(bus: Unibus) {
|
||||||
bus.attach(reg_base, 3, this)
|
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) {
|
override fun getw(addr: UInt): UShort = synchronized(this) {
|
||||||
when (addr.toInt() and 7) {
|
when (addr.toInt() and 7) {
|
||||||
0 -> rcsr
|
0 -> {
|
||||||
|
val oldRcsr = rcsr
|
||||||
|
rcsr = rcsr bic 15
|
||||||
|
oldRcsr
|
||||||
|
}
|
||||||
2 -> { rcsr = rcsr bic 7; rbuf }
|
2 -> { rcsr = rcsr bic 7; rbuf }
|
||||||
4 -> xcsr
|
4 -> xcsr
|
||||||
6 -> 0u
|
6 -> 0u
|
||||||
@@ -48,9 +64,10 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
|
|||||||
4 -> xcsr = xcsr.maskSet(value, 0x0045u)
|
4 -> xcsr = xcsr.maskSet(value, 0x0045u)
|
||||||
6 -> {
|
6 -> {
|
||||||
val b = value.toInt() and 0xFF
|
val b = value.toInt() and 0xFF
|
||||||
if (xcsr bit 1) {
|
if (xcsr bit 2) {
|
||||||
recvByte(b)
|
recvByte(b)
|
||||||
}
|
}
|
||||||
|
if (xcsr bit 6) intrXmit.level = true
|
||||||
ostr.write(b)
|
ostr.write(b)
|
||||||
}
|
}
|
||||||
else -> throw OddAddressError(addr)
|
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.ConfigurationError
|
||||||
import com.thequux.mcpdp.util.ProgrammerError
|
import com.thequux.mcpdp.util.ProgrammerError
|
||||||
import java.lang.Integer.min
|
import java.lang.Integer.min
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.LinkedList
|
||||||
|
import java.util.Vector
|
||||||
|
|
||||||
interface Region {
|
interface Region {
|
||||||
fun attach(address: UInt, suffix: Int, device: PAddressSpace)
|
fun attach(address: UInt, suffix: Int, device: PAddressSpace)
|
||||||
@@ -14,6 +17,11 @@ interface Region {
|
|||||||
fun map(address: UInt): PAddressSpace?
|
fun map(address: UInt): PAddressSpace?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Device {
|
||||||
|
// TODO: Add runtime config interface
|
||||||
|
val vector: UShort
|
||||||
|
}
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
private value class MappedDevice(val device: PAddressSpace): Region {
|
private value class MappedDevice(val device: PAddressSpace): Region {
|
||||||
override fun attach(address: UInt, suffix: Int, device: PAddressSpace) {
|
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
|
/// The view of the unibus from a device
|
||||||
var deviceView: PAddressSpace = this
|
var deviceView: PAddressSpace = this
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
|
private val queue: Array<MutableList<InterruptSource>> = Array(8) { Vector(4) }
|
||||||
|
|
||||||
override fun map(address: UInt): PAddressSpace =
|
override fun map(address: UInt): PAddressSpace =
|
||||||
super.map(address) ?: throw BusTimeoutError(address)
|
super.map(address) ?: throw BusTimeoutError(address)
|
||||||
override fun getw(addr: UInt): UShort = map(addr).getw(addr)
|
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 setw(addr: UInt, value: UShort) = map(addr).setw(addr, value)
|
||||||
override fun setb(addr: UInt, value: UByte) = map(addr).setb(addr, value)
|
override fun setb(addr: UInt, value: UByte) = map(addr).setb(addr, value)
|
||||||
|
|
||||||
fun interrupt(vector: UShort) {
|
/// Request that the processor service an interrupt. When the interrupt is handled, calls getVector() on the device
|
||||||
throw NotImplementedError("Interrupts not yet implemented")
|
/// 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