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>) {
|
||||
|
||||
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()
|
||||
|
@@ -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]
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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