Support keyboard transmit (bell) requests

Bumping version to 0.4.0, because this is a breaking change.
This commit is contained in:
Seth Morabito 2018-12-19 21:47:25 -08:00
parent 5fd15da4ae
commit 17b81b71da
6 changed files with 67 additions and 22 deletions

View File

@ -1,7 +1,7 @@
[package]
name = "dmd_core"
description = "AT&T / Teletype DMD 5620 Terminal Emulator - Core Library"
version = "0.3.1"
version = "0.4.0"
authors = ["Seth Morabito <web@loomcom.com>"]
homepage = "https://github.com/sethm/dmd_core"
repository = "https://github.com/sethm/dmd_core"
@ -16,4 +16,4 @@ lazy_static = "^1.2.0"
[badges]
travis-ci = { repository = "https://github.com/sethm/dmd_core", branch = "master" }
maintenance = { status = "actively-developed" }
maintenance = { status = "actively-developed" }

View File

@ -27,6 +27,10 @@ however.
## Changelog
0.4.0: Breaking change. TX to the keyboard from the terminal is
now supported, so that clients can use it to detect when
a bell (^G) request has been sent.
0.3.1: Added exception handling for memory errors, and a `run` function
to free-run the CPU for a given number of steps.

View File

@ -184,8 +184,12 @@ impl Bus {
self.duart.mouse_up(button);
}
pub fn tx_poll(&mut self) -> Option<u8> {
self.duart.tx_poll()
pub fn rs232_tx_poll(&mut self) -> Option<u8> {
self.duart.rs232_tx_poll()
}
pub fn kb_tx_poll(&mut self) -> Option<u8> {
self.duart.kb_tx_poll()
}
pub fn rx_char(&mut self, char: u8) {

View File

@ -1315,7 +1315,7 @@ impl Cpu {
}
MNEGW | MNEGH | MNEGB => {
let a = self.read_op(bus, 0)?;
let result = !a + 1;
let result = (!a).wrapping_add(1);
self.write_op(bus, 1, result)?;
self.set_nz_flags(result, 1);
self.set_c_flag(false);

View File

@ -107,8 +107,15 @@ impl Dmd {
///
/// Poll for a character to transmit from the terminal to the host.
///
pub fn tx_poll(&mut self) -> Option<u8> {
self.bus.tx_poll()
pub fn rs232_tx_poll(&mut self) -> Option<u8> {
self.bus.rs232_tx_poll()
}
///
/// Poll for a character to transmit from the terminal to the keyboard.
///
pub fn kb_tx_poll(&mut self) -> Option<u8> {
self.bus.kb_tx_poll()
}
///

View File

@ -81,6 +81,7 @@ const CMD_DTX: u8 = 0x08;
//
const ISTS_TAI: u8 = 0x01;
const ISTS_RAI: u8 = 0x02;
const ISTS_TBI: u8 = 0x10;
const ISTS_RBI: u8 = 0x20;
const ISTS_IPC: u8 = 0x80;
@ -210,34 +211,49 @@ impl Duart {
}
}
pub fn service(&mut self) {
let mut ctx = &mut self.ports[PORT_0];
fn handle_tx(&mut self, port: usize) {
let mut ctx = &mut self.ports[port];
let (tx_istat, rx_istat) = match port {
0 => (ISTS_TAI, ISTS_RAI),
_ => (ISTS_TBI, ISTS_RBI),
};
// Deal with RS-232 Transmit
if (ctx.conf & CNF_ETX) != 0 &&
(ctx.stat & STS_TXR) == 0 &&
(ctx.stat & STS_TXE) == 0 && Instant::now() >= ctx.next_tx {
(ctx.stat & STS_TXE) == 0 && Instant::now() >= ctx.next_tx
{
let c = ctx.tx_data;
ctx.stat |= STS_TXR;
ctx.stat |= STS_TXE;
self.istat |= ISTS_TAI;
self.ivec |= TX_INT;
self.istat |= tx_istat;
// Only RS232 transmit generates an interrupt.
if port == 0 {
self.ivec |= TX_INT;
}
if (ctx.mode[1] >> 6) & 3 == 0x2 {
// Loopback Mode.
ctx.rx_data = c;
ctx.stat |= STS_RXR;
self.istat |= ISTS_RAI;
self.istat |= rx_istat;
self.ivec |= RX_INT;
} else {
ctx.tx_queue.push_front(c);
}
// ctx.next_tx = Instant::now() + ctx.char_delay;
}
}
pub fn service(&mut self) {
// Deal with RS-232 Transmit
self.handle_tx(PORT_0);
// Deal with RS-232 Receive
self.handle_rx(PORT_0);
// Deal with Keyboard Transmit
// (note: This is used only for keyboard beeps!)
self.handle_tx(PORT_1);
// Deal with Keyboard Receive
self.handle_rx(PORT_1);
}
@ -259,10 +275,14 @@ impl Duart {
!self.outprt
}
pub fn tx_poll(&mut self) -> Option<u8> {
pub fn rs232_tx_poll(&mut self) -> Option<u8> {
self.ports[PORT_0].tx_queue.pop_back()
}
pub fn kb_tx_poll(&mut self) -> Option<u8> {
self.ports[PORT_1].tx_queue.pop_back()
}
pub fn mouse_down(&mut self, button: u8) {
self.ipcr = 0;
self.inprt |= 0xb;
@ -491,8 +511,8 @@ impl Device for Duart {
// transmit will happen in the 'service' function.
ctx.next_tx = Instant::now() + ctx.char_delay;
ctx.stat &= !(STS_TXE | STS_TXR);
self.ivec &= !TX_INT;
self.istat &= !ISTS_TAI;
self.ivec &= !TX_INT;
}
IPCR_ACR => {
self.acr = val;
@ -509,11 +529,21 @@ impl Device for Duart {
self.handle_command(val, PORT_1);
}
THRB => {
// TODO: When OP3 is low, do not send data to
// the keyboard! It's meant for the printer.
// Keyboard transmit requires special handling,
// because the only things the terminal transmits to
// the keyboard are status requests, or keyboard beep
// requests. We ignore status requests, and only
// put beep requests into the queue.
let mut ctx = &mut self.ports[PORT_1];
ctx.tx_data = val;
// Special case for status requests from the keyboard
if val == 0x02 {
ctx.stat = STS_RXR | STS_PER;
if (val & 0x08) != 0 {
ctx.tx_data = val;
ctx.next_tx = Instant::now() + ctx.char_delay;
ctx.stat &= !(STS_TXE | STS_TXR);
self.istat &= !ISTS_TBI;
}
}
IP_OPCR => {