Started RL0x device, debugged failures in DZQKA
This commit is contained in:
@@ -7,7 +7,7 @@ import java.io.File
|
|||||||
fun main(args: Array<String>) {
|
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(32768)
|
||||||
var cpu = CPU(mbus)
|
var cpu = CPU(mbus)
|
||||||
val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) }
|
val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) }
|
||||||
try {
|
try {
|
||||||
@@ -17,7 +17,9 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
cpu.loadAbs(File(args[0]))
|
cpu.loadAbs(File(args[0]))
|
||||||
cpu.runState = CPU.RunState.RUNNING
|
cpu.runState = CPU.RunState.RUNNING
|
||||||
|
cpu.pc = 0x80u
|
||||||
cpu.run()
|
cpu.run()
|
||||||
|
System.err.println("Halted at 0${cpu.pc.toString(8)}")
|
||||||
} finally {
|
} finally {
|
||||||
println("Exiting")
|
println("Exiting")
|
||||||
console.stop()
|
console.stop()
|
||||||
|
@@ -44,7 +44,7 @@ fun CPU.loadAbs(infile: File) {
|
|||||||
if (buf[0] != 1.toByte() || buf[1] != 0.toByte()) {
|
if (buf[0] != 1.toByte() || buf[1] != 0.toByte()) {
|
||||||
throw Exception("Invalid block header at $pos: ${buf[0]},${buf[1]}")
|
throw Exception("Invalid block header at $pos: ${buf[0]},${buf[1]}")
|
||||||
}
|
}
|
||||||
len = buf[3].toInt().shl(8) + buf[2].toInt() - 6
|
len = buf[3].toUByte().toInt().shl(8) + buf[2].toUByte().toInt() - 6
|
||||||
addr = (buf[5].toUByte().toUShort().shl(8) + buf[4].toUByte().toUShort()).toUShort()
|
addr = (buf[5].toUByte().toUShort().shl(8) + buf[4].toUByte().toUShort()).toUShort()
|
||||||
cksum = 0
|
cksum = 0
|
||||||
for (i in 0..<6) {
|
for (i in 0..<6) {
|
||||||
@@ -53,6 +53,7 @@ fun CPU.loadAbs(infile: File) {
|
|||||||
if (buf.size < len+1) {
|
if (buf.size < len+1) {
|
||||||
buf = ByteArray(len+1)
|
buf = ByteArray(len+1)
|
||||||
}
|
}
|
||||||
|
System.err.println("Reading ${len+1} bytes into ${buf.size}")
|
||||||
inStream.read(buf, 0, len+1)
|
inStream.read(buf, 0, len+1)
|
||||||
for (i in 0..len) {
|
for (i in 0..len) {
|
||||||
cksum += buf[i]
|
cksum += buf[i]
|
||||||
|
@@ -270,12 +270,13 @@ class CPU(val mbus: MemBus) {
|
|||||||
0x0700 -> br_rel(Z or (N xor V), opcode) // BLE
|
0x0700 -> br_rel(Z or (N xor V), opcode) // BLE
|
||||||
0x0800, 0x0900 -> { // JSR
|
0x0800, 0x0900 -> { // JSR
|
||||||
val r = opcode shr 6 and 0x7
|
val r = opcode shr 6 and 0x7
|
||||||
val dst = opc_dst(r)
|
val dst = opc_dst(opcode)
|
||||||
if (is_paddr_reg(dst)) {
|
if (is_paddr_reg(dst)) {
|
||||||
trap(4u) // illegal opcode
|
trap(4u) // illegal opcode
|
||||||
}
|
}
|
||||||
stack_push(registers[r])
|
stack_push(registers[r])
|
||||||
registers[r] = pc
|
registers[r] = pc
|
||||||
|
System.err.println("JSR to ${dst.toString(16)}: ${opcode.toString(8)}")
|
||||||
pc = dst.toUShort()
|
pc = dst.toUShort()
|
||||||
} // JSR
|
} // JSR
|
||||||
0x0A00 -> when (opcode shr 6 and 3) {
|
0x0A00 -> when (opcode shr 6 and 3) {
|
||||||
@@ -772,7 +773,7 @@ class CPU(val mbus: MemBus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (runState == RunState.WAIT_FOR_INTERRUPT) return
|
if (runState == RunState.WAIT_FOR_INTERRUPT) return
|
||||||
|
// System.err.println("Executing insn at ${pc.toString(8)}")
|
||||||
step_int()
|
step_int()
|
||||||
// TODO: handle T bit
|
// TODO: handle T bit
|
||||||
} catch (error: MemoryError) {
|
} catch (error: MemoryError) {
|
||||||
@@ -803,8 +804,11 @@ class CPU(val mbus: MemBus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setw(addr: UInt, value: UShort) = when (addr) {
|
override fun setw(addr: UInt, value: UShort) = when (addr) {
|
||||||
0x3FFFEu -> psw = value
|
0x3_FFFEu -> psw = value
|
||||||
else -> throw BusTimeoutError(addr)
|
else -> {
|
||||||
|
println("Bus error at ${addr.toString(16)}")
|
||||||
|
throw BusTimeoutError(addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -76,6 +76,13 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setb(addr: UInt, value: UByte) {
|
||||||
|
when (addr.toInt() and 7) {
|
||||||
|
0 -> setw(0u, value.toUShort()) // high bits are unaffected
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun recvByte(data: Int) {
|
private fun recvByte(data: Int) {
|
||||||
val overrun = rcsr bit 7
|
val overrun = rcsr bit 7
|
||||||
rcsr = rcsr and 0xC3FFu
|
rcsr = rcsr and 0xC3FFu
|
||||||
|
@@ -42,7 +42,7 @@ class MemBus(val size: Int) : PAddressSpace {
|
|||||||
throw OddAddressError(addr)
|
throw OddAddressError(addr)
|
||||||
}
|
}
|
||||||
return when (addr.toInt()) {
|
return when (addr.toInt()) {
|
||||||
in 0x3c0000..0x3FFFFF -> unibus.getw(addr)
|
in 0x3c0000..0x3FFFFF -> unibus.getw(addr and 0x3_FFFFu)
|
||||||
in 0..size.dec() -> data[addr.toInt() shr 1]
|
in 0..size.dec() -> data[addr.toInt() shr 1]
|
||||||
else -> throw NonExistentMemoryError(addr)
|
else -> throw NonExistentMemoryError(addr)
|
||||||
}
|
}
|
||||||
@@ -53,9 +53,24 @@ class MemBus(val size: Int) : PAddressSpace {
|
|||||||
throw OddAddressError(addr)
|
throw OddAddressError(addr)
|
||||||
}
|
}
|
||||||
return when (addr.toInt()) {
|
return when (addr.toInt()) {
|
||||||
in 0x3c0000..0x3FFFFF -> unibus.setw(addr, value)
|
in 0x3c0000..0x3FFFFF -> unibus.setw(addr and 0x3_FFFFu, value)
|
||||||
in 0..size.dec() -> data[addr.toInt() shr 1] = value
|
in 0..size.dec() -> data[addr.toInt() shr 1] = value
|
||||||
else -> throw NonExistentMemoryError(addr)
|
else -> throw NonExistentMemoryError(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getb(addr: UInt): UByte {
|
||||||
|
return when (addr.toInt()) {
|
||||||
|
in 0x3c0000..0x3FFFFF -> unibus.getb(addr and 0x3_FFFFu)
|
||||||
|
else -> super.getb(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setb(addr: UInt, value: UByte) {
|
||||||
|
return when (addr.toInt()) {
|
||||||
|
in 0x3c0000..0x3FFFFF -> unibus.setb(addr and 0x3_FFFFu, value)
|
||||||
|
else -> super.setb(addr, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
161
src/main/kotlin/com/thequux/mcpdp/peripheral/RL11.kt
Normal file
161
src/main/kotlin/com/thequux/mcpdp/peripheral/RL11.kt
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
package com.thequux.mcpdp.peripheral
|
||||||
|
|
||||||
|
import com.thequux.mcpdp.core.OddAddressError
|
||||||
|
import com.thequux.mcpdp.core.PAddressSpace
|
||||||
|
import com.thequux.mcpdp.ext.bit.bis
|
||||||
|
import com.thequux.mcpdp.ext.bit.bit
|
||||||
|
import com.thequux.mcpdp.ext.bit.maskSet
|
||||||
|
import com.thequux.mcpdp.ext.bit.shr
|
||||||
|
import java.io.RandomAccessFile
|
||||||
|
|
||||||
|
// Only one can be attached, so no need for configurable addresses
|
||||||
|
class RL11(val unibus: Unibus): PAddressSpace, Peripheral {
|
||||||
|
val reg_base: UInt = 0x3F900u
|
||||||
|
val vector: UShort = 0x70u
|
||||||
|
|
||||||
|
val silo: ArrayDeque<UShort> = ArrayDeque(16)
|
||||||
|
|
||||||
|
// registers
|
||||||
|
var csr: UShort = 0x8080u
|
||||||
|
set(value) {
|
||||||
|
field = value bis 7
|
||||||
|
cur_disk = (value shr 8 and 0x3u).toInt()
|
||||||
|
bus_addr = bus_addr and 0xFFFFu or (value.toUInt() and 0x30u shl 12)
|
||||||
|
}
|
||||||
|
get() {
|
||||||
|
var newf = field.bit(14, disks[cur_disk].error)
|
||||||
|
newf = newf.bit(15, (field and 0x7C00u) != 0.toUShort())
|
||||||
|
return newf
|
||||||
|
}
|
||||||
|
|
||||||
|
var cur_disk: Int = 0
|
||||||
|
var bus_addr: UInt = 0u
|
||||||
|
var disk_addr: UShort = 0u
|
||||||
|
var mpr: UShort = 0u
|
||||||
|
|
||||||
|
private val interruptSource = InterruptSource(unibus, 5, vector, true)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val RLCS_DRDY: UShort = 0x0001u
|
||||||
|
val RLCS_IE: UShort = 0x0040u
|
||||||
|
val RLCS_CRDY: UShort = 0x0080u
|
||||||
|
val RLCS_OPI: UShort = 0x0400u
|
||||||
|
val RLCS_CKE: UShort = 0x0800u // Also called DCRC, HCRC, or WCE
|
||||||
|
val RLCS_DLT: UShort = 0x1000u // also called HNF
|
||||||
|
val RLCS_NXM: UShort = 0x2000u
|
||||||
|
val RLCS_DE: UShort = 0x4000u
|
||||||
|
val RLCS_ERR: UShort = 0x8000u
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Disk {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
}
|
||||||
|
var media: RandomAccessFile? = null
|
||||||
|
var isRL02: Boolean = true
|
||||||
|
|
||||||
|
var cyl: Int = 0 // 0..256/512
|
||||||
|
var sector: Int = 0 // 0..=39
|
||||||
|
var head: Boolean = false
|
||||||
|
var error: Boolean = false
|
||||||
|
|
||||||
|
val status: UShort
|
||||||
|
get() {
|
||||||
|
return 0u
|
||||||
|
}
|
||||||
|
|
||||||
|
fun seek(dar: UShort) {
|
||||||
|
var dcyl = dar.toInt() shr 7
|
||||||
|
if (dar bit 2) {
|
||||||
|
// dir?
|
||||||
|
dcyl = -dcyl
|
||||||
|
}
|
||||||
|
head = dar bit 4
|
||||||
|
cyl = (cyl + dcyl).coerceIn(0..39)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val disks: Array<Disk> = Array(4) { Disk() }
|
||||||
|
override fun getw(addr: UInt): UShort =
|
||||||
|
when (addr.toInt() and 7) {
|
||||||
|
0 -> csr
|
||||||
|
2 -> bus_addr.toUShort()
|
||||||
|
4 -> disk_addr
|
||||||
|
6 -> siloPop()
|
||||||
|
else -> throw OddAddressError(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun setw(addr: UInt, value: UShort) {
|
||||||
|
when (addr.toInt() and 7) {
|
||||||
|
0 -> {
|
||||||
|
// It would be 0x3FE, but we want to always keep crdy set because all commands complete instantly
|
||||||
|
csr = csr.maskSet(value, 0x37Eu)
|
||||||
|
if (value.inv() bit 7) {
|
||||||
|
// go command sent
|
||||||
|
execCommand()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 -> bus_addr = bus_addr and 0x3_0000u or value.toUInt()
|
||||||
|
4 -> disk_addr = value
|
||||||
|
6 -> mpr = value
|
||||||
|
else -> throw OddAddressError(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun mount(bus: Unibus) {
|
||||||
|
unibus.attach(reg_base, 3, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this a general purpose interface
|
||||||
|
override fun service() {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun siloPush(value: UShort) {
|
||||||
|
if (silo.size >= 16) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
silo.addLast(value)
|
||||||
|
}
|
||||||
|
fun siloPop(): UShort {
|
||||||
|
return if (silo.isEmpty()) {
|
||||||
|
0u
|
||||||
|
} else {
|
||||||
|
silo.removeFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute the command in csr
|
||||||
|
private fun execCommand() {
|
||||||
|
val command = csr.toInt() shr 1 and 0x7
|
||||||
|
when (command) {
|
||||||
|
0 -> {} // No-op
|
||||||
|
1 -> {
|
||||||
|
|
||||||
|
} // write check
|
||||||
|
2 -> {
|
||||||
|
|
||||||
|
} // get status
|
||||||
|
3 -> {
|
||||||
|
if (disk_addr and 0x6bu != 1u.toUShort()) {
|
||||||
|
csr = csr or RLCS_OPI
|
||||||
|
}
|
||||||
|
} // seek
|
||||||
|
4 -> {
|
||||||
|
|
||||||
|
} // read header
|
||||||
|
5 -> {
|
||||||
|
|
||||||
|
} // write data
|
||||||
|
6 -> {
|
||||||
|
|
||||||
|
} // read data
|
||||||
|
7 -> {
|
||||||
|
|
||||||
|
} // read data without header check
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user