Skip to content

Commit

Permalink
Fix TX enable
Browse files Browse the repository at this point in the history
TX Enable should only set the TxRDY bit if there is no character
currently in the TX holding register. Likewise, the TxEMT bit should
only be set if there is no character in the shift register.
  • Loading branch information
sethm committed Sep 11, 2022
1 parent 8ba2b44 commit a7e13a7
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 76 deletions.
6 changes: 3 additions & 3 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::bus::{AccessCode, Bus};
use crate::err::*;
use crate::instr::*;

use log::{debug, trace};
use log::trace;
use std::fmt;

///
Expand Down Expand Up @@ -1032,7 +1032,7 @@ impl Cpu {
if let Some(val) = bus.get_interrupts() {
let cpu_ipl = (self.r[R_PSW]) >> 13 & 0xf;
if cpu_ipl < IPL_TABLE[(val & 0x3f) as usize] {
debug!(
trace!(
"[PC={:08x} PSW={:08x}] INTERRUPT 0x{:04x}",
&self.r[R_PC],
&self.r[R_PSW],
Expand Down Expand Up @@ -2002,7 +2002,7 @@ impl Cpu {
match self.dispatch(bus) {
Ok(i) => {
// We should have the necessary information to trace after dispatch.
trace!("[PC={:08x} PSW={:08x}] {}", &self.r[R_PC], &self.r[R_PSW], &self.ir);
// trace!("[PC={:08x} PSW={:08x}] {}", &self.r[R_PC], &self.r[R_PSW], &self.ir);
self.r[R_PC] = (self.r[R_PC] as i32 + i) as u32
}
Err(CpuError::Bus(BusError::NoDevice(_)))
Expand Down
140 changes: 69 additions & 71 deletions src/duart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
use crate::bus::{AccessCode, Device};
use crate::err::BusError;

use log::debug;
use log::{debug, trace};
use ringbuffer::{
ConstGenericRingBuffer, RingBuffer, RingBufferExt, RingBufferRead, RingBufferWrite,
};
Expand Down Expand Up @@ -73,12 +73,14 @@ const MR12A: u8 = 0x03;
const CSRA: u8 = 0x07;
const CRA: u8 = 0x0b;
const THRA: u8 = 0x0f;
const RHRA: u8 = 0x0f;
const IPCR_ACR: u8 = 0x13;
const ISR_MASK: u8 = 0x17;
const MR12B: u8 = 0x23;
const CSRB: u8 = 0x27;
const CRB: u8 = 0x2b;
const THRB: u8 = 0x2f;
const RHRB: u8 = 0x2f;
const IP_OPCR: u8 = 0x37;
const OPBITS_SET: u8 = 0x3b;
const OPBITS_RESET: u8 = 0x3f;
Expand Down Expand Up @@ -230,11 +232,11 @@ impl Port {
/// room becomes available. The shift register is overwitten if a
/// new character is received while the FIFO is full.
fn rx_char(&mut self, c: u8) {
debug!("rx_char: {:02x}", c);
trace!("rx_char: {:02x}, fifo_len={}", c, self.rx_fifo.len());
if self.rx_fifo.len() < RX_FIFO_LEN {
self.rx_fifo.push(c);
if self.rx_fifo.len() >= RX_FIFO_LEN {
debug!("FIFO FULL.");
trace!("FIFO FULL.");
self.stat |= STS_FFL;
}
} else {
Expand Down Expand Up @@ -277,51 +279,50 @@ impl Port {

/// Move the transmitter state machine.
fn tx_service(&mut self, keyboard: bool) {
let tx_service_needed = self.tx_enabled()
&& (self.tx_holding_reg.is_some() || self.tx_shift_reg.is_some())
&& Instant::now() >= self.next_tx_service;

if !tx_service_needed {
if self.tx_holding_reg.is_none() && self.tx_shift_reg.is_none() {
// Nothing to do
return;
}

// Check for data in the transmitter shift register that's
// ready to go out to the RS232 output buffer
if let Some(c) = self.tx_shift_reg {
debug!("RS232 TX: {:02x}", c);
if self.loopback() {
debug!("RS232 TX: Port is in loopback.");
self.rx_char(c);
} else {
if keyboard && c == 0x02 {
self.stat |= STS_PER;
if Instant::now() >= self.next_tx_service {
// Check for data in the transmitter shift register that's
// ready to go out to the RS232 output buffer
if let Some(c) = self.tx_shift_reg {
trace!("RS232 TX: {:02x}", c);
if self.loopback() {
debug!("RS232 TX: LOOPBACK: Finish transmit character {:02x}", c);
self.rx_char(c);
} else {
if keyboard && c == 0x02 {
self.stat |= STS_PER;
}
debug!("RS232 TX: Finish transmit character {:02x}", c);
self.tx_deque.push_front(c);
}
self.tx_deque.push_front(c);
}

self.tx_shift_reg = None;
self.stat |= STS_TXR | STS_TXE;
}
self.tx_shift_reg = None;
if self.tx_holding_reg.is_none() {
self.stat |= STS_TXR;
self.stat |= STS_TXE;
}
}

// Check for data in the transmitter holding register that's
// ready to go out to the transmitter shift register.
if let Some(c) = self.tx_holding_reg {
self.tx_shift_reg = Some(c);
// Clear the holding register
self.tx_holding_reg = None;
self.next_tx_service = Instant::now() + self.char_delay;
// Check for data in the holding register that's ready to go
// out to the shift register.
if let Some(c) = self.tx_holding_reg {
self.tx_shift_reg = Some(c);
// Clear the holding register
self.tx_holding_reg = None;
// Ready for a new character
self.next_tx_service = Instant::now() + self.char_delay;
}
}
}

fn loopback(&self) -> bool {
(self.mode[1] & 0xc0) == 0x80
}

fn tx_enabled(&self) -> bool {
(self.conf & CNF_ETX) != 0
}

fn rx_enabled(&self) -> bool {
(self.conf & CNF_ERX) != 0
}
Expand All @@ -330,20 +331,20 @@ impl Port {
self.conf |= CNF_ETX;
if self.tx_holding_reg.is_none() {
self.stat |= STS_TXR;
}
if self.tx_shift_reg.is_none() {
self.stat |= STS_TXE;
}
}

fn disable_tx(&mut self) {
self.conf &= !CNF_ETX;
self.stat &= !(STS_TXR | STS_TXE);
self.next_rx_service = Instant::now() + Duration::new(0, 10_000_000);
}

fn enable_rx(&mut self) {
self.conf |= CNF_ERX;
self.stat &= !STS_RXR;
self.next_rx_service = Instant::now() + Duration::new(0, 10_000_000);
}

fn disable_rx(&mut self) {
Expand Down Expand Up @@ -376,7 +377,7 @@ impl Default for Duart {
/// Compute the delay rate to wait for the next transmit or receive
fn delay_rate(csr_bits: u8, acr_bits: u8) -> Duration {
const NS_PER_SEC: u32 = 1_000_000_000;
const BITS_PER_CHAR: u32 = 7;
const BITS_PER_CHAR: u32 = 10;

let baud_bits: usize = ((csr_bits >> 4) & 0xf) as usize;
let baud_rate = if acr_bits & 0x80 == 0 {
Expand All @@ -385,7 +386,7 @@ fn delay_rate(csr_bits: u8, acr_bits: u8) -> Duration {
BAUD_RATES_B[baud_bits]
};

Duration::new(0, (NS_PER_SEC / (baud_rate / BITS_PER_CHAR)) / 2)
Duration::new(0, NS_PER_SEC / (baud_rate / BITS_PER_CHAR))
}

impl Duart {
Expand Down Expand Up @@ -455,6 +456,7 @@ impl Duart {

pub fn output_port(&self) -> u8 {
// The output port always returns a complement of the bits
debug!("READ: Output Port: {:02x}", !self.outprt);
!self.outprt
}

Expand Down Expand Up @@ -645,15 +647,15 @@ impl Device for Duart {
let mut ctx = &mut self.ports[PORT_0];
let val = ctx.mode[ctx.mode_ptr];
ctx.mode_ptr = (ctx.mode_ptr + 1) % 2;
debug!("READ : MR12A val={:02x}", val);
trace!("READ : MR12A, val={:02x}", val);
Ok(val)
}
CSRA => {
let val = self.ports[PORT_0].stat;
debug!("READ : CSRA val={:02x}", val);
trace!("READ : CSRA, val={:02x}", val);
Ok(val)
}
THRA => {
RHRA => {
let ctx = &mut self.ports[PORT_0];
self.isr &= !ISTS_RAI;
self.ivec &= !RX_INT;
Expand All @@ -662,35 +664,35 @@ impl Device for Duart {
} else {
0
};
debug!("READ : RHRA val={:02x}", val);
debug!("READ : RHRA, val={:02x}", val);
Ok(val)
}
IPCR_ACR => {
let val = self.ipcr;
self.ipcr &= !0x0f;
self.ivec = 0;
self.isr &= !ISTS_IPC;
debug!("READ : IPCR_ACR val={:02x}", val);
trace!("READ : IPCR_ACR, val={:02x}", val);
Ok(val)
}
ISR_MASK => {
let val = self.isr;
debug!("READ : ISR_MASK val={:02x}", val);
trace!("READ : ISR_MASK, val={:02x}", val);
Ok(val)
}
MR12B => {
let mut ctx = &mut self.ports[PORT_1];
let val = ctx.mode[ctx.mode_ptr];
ctx.mode_ptr = (ctx.mode_ptr + 1) % 2;
debug!("READ : MR12B val={:02x}", val);
trace!("READ : MR12B, val={:02x}", val);
Ok(val)
}
CSRB => {
let val = self.ports[PORT_1].stat;
debug!("READ : CSRB val={:02x}", val);
trace!("READ : CSRB, val={:02x}", val);
Ok(val)
}
THRB => {
RHRB => {
let ctx = &mut self.ports[PORT_1];
self.isr &= !ISTS_RAI;
self.ivec &= !KEYBOARD_INT;
Expand All @@ -699,16 +701,16 @@ impl Device for Duart {
} else {
0
};
debug!("READ : RHRB val={:02x}", val);
debug!("READ : RHRB, val={:02x}", val);
Ok(val)
}
IP_OPCR => {
let val = self.inprt;
debug!("READ : IP_OPCR val={:02x}", val);
trace!("READ : IP_OPCR val={:02x}", val);
Ok(val)
}
_ => {
debug!("READ : UNHANDLED. ADDRESS={:08x}", address);
trace!("READ : UNHANDLED. ADDRESS={:08x}", address);
Err(BusError::NoDevice(address))
}
}
Expand All @@ -727,54 +729,50 @@ impl Device for Duart {
fn write_byte(&mut self, address: usize, val: u8, _access: AccessCode) -> Result<(), BusError> {
match (address - START_ADDR) as u8 {
MR12A => {
debug!("WRITE: MR12A, val={:02x}", val);
trace!("WRITE: MR12A, val={:02x}", val);
let mut ctx = &mut self.ports[PORT_0];
ctx.mode[ctx.mode_ptr] = val;
ctx.mode_ptr = (ctx.mode_ptr + 1) % 2;
}
CSRA => {
debug!("WRITE: CSRA, val={:02x}", val);
trace!("WRITE: CSRA, val={:02x}", val);
let mut ctx = &mut self.ports[PORT_0];
ctx.char_delay = delay_rate(val, self.acr);
}
CRA => {
debug!("WRITE: CRA, val={:02x}", val);
trace!("WRITE: CRA, val={:02x}", val);
self.handle_command(val, PORT_0);
}
THRA => {
debug!("WRITE: THRA, val={:02x}", val);
let mut ctx = &mut self.ports[PORT_0];
debug!("WRITE: THRA, val={:02x}", val);
ctx.tx_holding_reg = Some(val);
// Update state. Since we're transmitting, the
// transmitter buffer is not empty. The actual
// transmit will happen in the 'service' function.
ctx.next_tx_service = Instant::now() + ctx.char_delay;
ctx.stat &= !(STS_TXE | STS_TXR);
// TxRDY and TxEMT are both de-asserted on load.
ctx.stat &= !(STS_TXR | STS_TXE);
self.isr &= !ISTS_TAI;
self.ivec &= !TX_INT;
}
IPCR_ACR => {
debug!("WRITE: IPCR_ACR, val={:02x}", val);
trace!("WRITE: IPCR_ACR, val={:02x}", val);
self.acr = val;
// TODO: Update baud rate generator
}
ISR_MASK => {
debug!("WRITE: ISR_MASK, val={:02x}", val);
trace!("WRITE: ISR_MASK, val={:02x}", val);
self.imr = val;
}
MR12B => {
debug!("WRITE: MR12B, val={:02x}", val);
trace!("WRITE: MR12B, val={:02x}", val);
let mut ctx = &mut self.ports[PORT_1];
ctx.mode[ctx.mode_ptr] = val;
ctx.mode_ptr = (ctx.mode_ptr + 1) % 2;
}
CSRB => {
debug!("WRITE: CSRB, val={:02x}", val);
trace!("WRITE: CSRB, val={:02x}", val);
let mut ctx = &mut self.ports[PORT_1];
ctx.char_delay = delay_rate(val, self.acr);
}
CRB => {
debug!("WRITE: CRB, val={:02x}", val);
trace!("WRITE: CRB, val={:02x}", val);
self.handle_command(val, PORT_1);
}
THRB => {
Expand All @@ -783,24 +781,24 @@ impl Device for Duart {
// the keyboard! It's meant for the printer.
let mut ctx = &mut self.ports[PORT_1];
ctx.tx_holding_reg = Some(val);
ctx.next_tx_service = Instant::now() + ctx.char_delay;
ctx.stat &= !(STS_TXE | STS_TXR);
// TxRDY and TxEMT are both de-asserted on load.
ctx.stat &= !(STS_TXR | STS_TXE);
self.isr &= !ISTS_TBI;
}
IP_OPCR => {
debug!("WRITE: IP_OPCR, val={:02x}", val);
trace!("WRITE: IP_OPCR, val={:02x}", val);
// Not implemented
}
OPBITS_SET => {
debug!("WRITE: OPBITS_SET, val={:02x}", val);
trace!("WRITE: OPBITS_SET, val={:02x}", val);
self.outprt |= val;
}
OPBITS_RESET => {
debug!("WRITE: OPBITS_RESET, val={:02x}", val);
trace!("WRITE: OPBITS_RESET, val={:02x}", val);
self.outprt &= !val;
}
_ => {
debug!("WRITE: UNHANDLED. ADDRESS={:08x}", address);
trace!("WRITE: UNHANDLED. ADDRESS={:08x}", address);
}
};

Expand Down
4 changes: 2 additions & 2 deletions src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::bus::Device;
use crate::err::BusError;
use std::ops::Range;

use log::debug;
use log::trace;

const START_ADDRESS: usize = 0x400000;
const END_ADDRESS: usize = 0x4000004;
Expand Down Expand Up @@ -50,7 +50,7 @@ impl Device for Mouse {
}

fn read_half(&mut self, address: usize, _access: AccessCode) -> Result<u16, BusError> {
debug!("Mouse Read, address={:08x}", address);
trace!("Mouse Read, address={:08x}", address);
match address - START_ADDRESS {
0 => Ok(self.y),
2 => Ok(self.x),
Expand Down

0 comments on commit a7e13a7

Please sign in to comment.