Started RL0x device, debugged failures in DZQKA

This commit is contained in:
2023-09-16 14:17:56 +02:00
parent 3bbc842277
commit 9d2397d809
6 changed files with 198 additions and 8 deletions

View File

@@ -7,7 +7,7 @@ import java.io.File
fun main(args: Array<String>) {
val tb = org.jline.terminal.TerminalBuilder.terminal()
var mbus = MemBus(65536)
var mbus = MemBus(32768)
var cpu = CPU(mbus)
val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) }
try {
@@ -17,7 +17,9 @@ fun main(args: Array<String>) {
cpu.loadAbs(File(args[0]))
cpu.runState = CPU.RunState.RUNNING
cpu.pc = 0x80u
cpu.run()
System.err.println("Halted at 0${cpu.pc.toString(8)}")
} finally {
println("Exiting")
console.stop()

View File

@@ -44,7 +44,7 @@ fun CPU.loadAbs(infile: File) {
if (buf[0] != 1.toByte() || buf[1] != 0.toByte()) {
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()
cksum = 0
for (i in 0..<6) {
@@ -53,6 +53,7 @@ fun CPU.loadAbs(infile: File) {
if (buf.size < len+1) {
buf = ByteArray(len+1)
}
System.err.println("Reading ${len+1} bytes into ${buf.size}")
inStream.read(buf, 0, len+1)
for (i in 0..len) {
cksum += buf[i]

View File

@@ -270,12 +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 = opc_dst(r)
val dst = opc_dst(opcode)
if (is_paddr_reg(dst)) {
trap(4u) // illegal opcode
}
stack_push(registers[r])
registers[r] = pc
System.err.println("JSR to ${dst.toString(16)}: ${opcode.toString(8)}")
pc = dst.toUShort()
} // JSR
0x0A00 -> when (opcode shr 6 and 3) {
@@ -772,7 +773,7 @@ class CPU(val mbus: MemBus) {
}
}
if (runState == RunState.WAIT_FOR_INTERRUPT) return
// System.err.println("Executing insn at ${pc.toString(8)}")
step_int()
// TODO: handle T bit
} catch (error: MemoryError) {
@@ -803,8 +804,11 @@ class CPU(val mbus: MemBus) {
}
override fun setw(addr: UInt, value: UShort) = when (addr) {
0x3FFFEu -> psw = value
else -> throw BusTimeoutError(addr)
0x3_FFFEu -> psw = value
else -> {
println("Bus error at ${addr.toString(16)}")
throw BusTimeoutError(addr)
}
}
}

View File

@@ -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) {
val overrun = rcsr bit 7
rcsr = rcsr and 0xC3FFu

View File

@@ -42,7 +42,7 @@ class MemBus(val size: Int) : PAddressSpace {
throw OddAddressError(addr)
}
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]
else -> throw NonExistentMemoryError(addr)
}
@@ -53,9 +53,24 @@ class MemBus(val size: Int) : PAddressSpace {
throw OddAddressError(addr)
}
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
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)
}
}
}

View 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
}
}
}