Revert "Provide dirty flag on devices"

This reverts commit 4131b2262c.
This commit is contained in:
Seth Morabito 2021-04-21 12:40:29 -07:00
parent 4131b2262c
commit c9161324b5
7 changed files with 112 additions and 141 deletions

View File

@ -1,7 +1,7 @@
[package]
name = "dmd_core"
description = "AT&T / Teletype DMD 5620 Terminal Emulator - Core Library"
version = "0.7.0"
version = "0.6.5"
authors = ["Seth Morabito <web@loomcom.com>"]
homepage = "https://github.com/sethm/dmd_core"
repository = "https://github.com/sethm/dmd_core"

View File

@ -41,10 +41,6 @@ pub trait Device: Send + Sync + Debug {
fn write_half(&mut self, address: usize, val: u16, access: AccessCode) -> Result<(), BusError>;
fn write_word(&mut self, address: usize, val: u32, access: AccessCode) -> Result<(), BusError>;
fn load(&mut self, address: usize, data: &[u8]) -> Result<(), BusError>;
fn dirty(&self) -> bool {
false
}
fn clear_dirty(&mut self) {}
}
//
@ -171,14 +167,6 @@ impl Bus {
self.ram.as_slice(start..end)
}
pub fn video_ram_dirty(&self) -> bool {
self.vid.dirty()
}
pub fn video_ram_clear_dirty(&mut self) {
self.vid.clear_dirty()
}
pub fn service(&mut self) {
self.duart.service();
}

View File

@ -1,6 +1,6 @@
#![allow(clippy::unreadable_literal)]
use crate::bus::{AccessCode, Bus};
use crate::bus::{Bus, AccessCode};
use crate::cpu::Cpu;
use crate::err::BusError;
use crate::rom_hi::HI_ROM;
@ -52,14 +52,6 @@ impl Dmd {
self.bus.video_ram()
}
pub fn video_ram_dirty(&self) -> bool {
self.bus.video_ram_dirty()
}
pub fn video_ram_clear_dirty(&mut self) {
self.bus.video_ram_clear_dirty()
}
pub fn get_pc(&self) -> u32 {
self.cpu.get_pc()
}
@ -148,34 +140,23 @@ impl Dmd {
#[no_mangle]
fn dmd_reset() -> c_int {
match DMD.lock() {
Ok(mut dmd) => match dmd.reset() {
Ok(()) => SUCCESS,
Err(_) => ERROR,
},
Err(_) => ERROR,
Ok(mut dmd) => {
match dmd.reset() {
Ok(()) => SUCCESS,
Err(_) => ERROR
}
}
Err(_) => ERROR
}
}
#[no_mangle]
fn dmd_video_ram() -> *const u8 {
match DMD.lock() {
Ok(dmd) => dmd.video_ram().as_ptr(),
Err(_) => ptr::null(),
}
}
#[no_mangle]
fn dmd_video_ram_dirty() -> bool {
match DMD.lock() {
Ok(dmd) => dmd.video_ram_dirty(),
Err(_) => false,
}
}
#[no_mangle]
fn dmd_video_ram_clear_dirty() {
if let Ok(mut dmd) = DMD.lock() {
dmd.video_ram_clear_dirty();
Ok(dmd) => {
dmd.video_ram().as_ptr()
}
Err(_) => ptr::null()
}
}
@ -186,7 +167,7 @@ fn dmd_step() -> c_int {
dmd.step();
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -196,8 +177,8 @@ fn dmd_step_loop(steps: usize) -> c_int {
Ok(mut dmd) => {
dmd.run(steps);
SUCCESS
}
Err(_) => ERROR,
},
Err(_) => ERROR
}
}
@ -207,8 +188,8 @@ fn dmd_get_pc(pc: &mut u32) -> c_int {
Ok(dmd) => {
*pc = dmd.get_pc();
SUCCESS
}
Err(_) => ERROR,
},
Err(_) => ERROR
}
}
@ -218,36 +199,40 @@ fn dmd_get_register(reg: u8, val: &mut u32) -> c_int {
Ok(dmd) => {
*val = dmd.get_register(reg);
SUCCESS
}
Err(_) => ERROR,
},
Err(_) => ERROR
}
}
#[no_mangle]
fn dmd_read_word(addr: u32, val: &mut u32) -> c_int {
match DMD.lock() {
Ok(mut dmd) => match dmd.read_word(addr as usize) {
Some(word) => {
*val = word;
SUCCESS
Ok(mut dmd) => {
match dmd.read_word(addr as usize) {
Some(word) => {
*val = word;
SUCCESS
},
None => ERROR
}
None => ERROR,
},
Err(_) => ERROR,
Err(_) => ERROR
}
}
#[no_mangle]
fn dmd_read_byte(addr: u32, val: &mut u8) -> c_int {
match DMD.lock() {
Ok(mut dmd) => match dmd.read_byte(addr as usize) {
Some(byte) => {
*val = byte;
SUCCESS
Ok(mut dmd) => {
match dmd.read_byte(addr as usize) {
Some(byte) => {
*val = byte;
SUCCESS
},
None => ERROR
}
None => ERROR,
},
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -258,7 +243,7 @@ fn dmd_get_duart_output_port(oport: &mut u8) -> c_int {
*oport = dmd.duart_output();
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -269,7 +254,7 @@ fn dmd_rx_char(c: u8) -> c_int {
dmd.rx_char(c as u8);
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -280,7 +265,7 @@ fn dmd_rx_keyboard(c: u8) -> c_int {
dmd.rx_keyboard(c);
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -291,7 +276,7 @@ fn dmd_mouse_move(x: u16, y: u16) -> c_int {
dmd.mouse_move(x, y);
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -302,7 +287,7 @@ fn dmd_mouse_down(button: u8) -> c_int {
dmd.mouse_down(button);
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -313,35 +298,39 @@ fn dmd_mouse_up(button: u8) -> c_int {
dmd.mouse_up(button);
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
#[no_mangle]
fn dmd_rs232_tx_poll(tx_char: &mut u8) -> c_int {
match DMD.lock() {
Ok(mut dmd) => match dmd.rs232_tx_poll() {
Some(c) => {
*tx_char = c;
SUCCESS
Ok(mut dmd) => {
match dmd.rs232_tx_poll() {
Some(c) => {
*tx_char = c;
SUCCESS
}
None => BUSY
}
None => BUSY,
},
Err(_) => ERROR,
}
Err(_) => ERROR
}
}
#[no_mangle]
fn dmd_kb_tx_poll(tx_char: &mut u8) -> c_int {
match DMD.lock() {
Ok(mut dmd) => match dmd.kb_tx_poll() {
Some(c) => {
*tx_char = c;
SUCCESS
Ok(mut dmd) => {
match dmd.kb_tx_poll() {
Some(c) => {
*tx_char = c;
SUCCESS
}
None => BUSY
}
None => BUSY,
},
Err(_) => ERROR,
}
Err(_) => ERROR
}
}
@ -352,7 +341,7 @@ fn dmd_set_nvram(nvram: &[u8; 8192]) -> c_int {
dmd.set_nvram(nvram);
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}
@ -363,7 +352,7 @@ fn dmd_get_nvram(nvram: &mut [u8; 8192]) -> c_int {
nvram.clone_from_slice(dmd.get_nvram());
SUCCESS
}
Err(_) => ERROR,
Err(_) => ERROR
}
}

View File

@ -4,28 +4,34 @@ use crate::bus::AccessCode;
use crate::bus::Device;
use crate::err::BusError;
use std::collections::VecDeque;
use std::fmt::Debug;
use std::fmt::Error;
use std::fmt::Formatter;
use std::ops::Range;
use std::time::Duration;
use std::time::Instant;
use std::collections::VecDeque;
const START_ADDR: usize = 0x200000;
const END_ADDR: usize = 0x2000040;
const ADDRESS_RANGE: Range<usize> = START_ADDR..END_ADDR;
// Vertical blanks should occur at 60Hz. This value is in nanoseconds
const VERTICAL_BLANK_DELAY: u32 = 16_666_666; // 60 Hz
const VERTICAL_BLANK_DELAY: u32 = 16_666_666; // 60 Hz
// Delay rates, in nanoseconds, selected when ACR[7] = 0
const DELAY_RATES_A: [u32; 13] =
[160000000, 72727272, 59259260, 40000000, 26666668, 13333334, 6666667, 7619047, 3333333, 1666666, 1111111, 833333, 208333];
const DELAY_RATES_A: [u32;13] = [
160000000, 72727272, 59259260, 40000000,
26666668, 13333334, 6666667, 7619047,
3333333, 1666666, 1111111, 833333, 208333
];
// Delay rates, in nanoseconds, selected when ACR[7] = 1
const DELAY_RATES_B: [u32; 13] =
[106666672, 72727272, 59259260, 53333336, 26666668, 13333334, 6666667, 4000000, 3333333, 1666666, 4444444, 833333, 416666];
const DELAY_RATES_B: [u32;13] = [
106666672, 72727272, 59259260, 53333336,
26666668, 13333334, 6666667, 4000000,
3333333, 1666666, 4444444, 833333, 416666
];
const PORT_0: usize = 0;
const PORT_1: usize = 1;
@ -47,6 +53,7 @@ const IP_OPCR: u8 = 0x37;
const OPBITS_SET: u8 = 0x3b;
const OPBITS_RESET: u8 = 0x3f;
//
// Port Configuration Bits
//
@ -89,7 +96,7 @@ const TX_INT: u8 = 0x10;
const RX_INT: u8 = 0x20;
struct Port {
mode: [u8; 2],
mode: [u8;2],
stat: u8,
conf: u8,
rx_data: u8,
@ -135,7 +142,7 @@ pub struct Duart {
istat: u8,
imr: u8,
ivec: u8,
next_vblank: Instant,
next_vblank: Instant
}
impl Default for Duart {
@ -147,7 +154,10 @@ impl Default for Duart {
impl Duart {
pub fn new() -> Duart {
Duart {
ports: [Port::new(), Port::new()],
ports: [
Port::new(),
Port::new(),
],
acr: 0,
ipcr: 0x40,
inprt: 0xb,
@ -206,7 +216,10 @@ impl Duart {
_ => (ISTS_TBI, ISTS_RBI),
};
if (ctx.conf & CNF_ETX) != 0 && (ctx.stat & STS_TXR) == 0 && (ctx.stat & STS_TXE) == 0 && Instant::now() >= ctx.next_tx {
if (ctx.conf & CNF_ETX) != 0 &&
(ctx.stat & STS_TXR) == 0 &&
(ctx.stat & STS_TXE) == 0 && Instant::now() >= ctx.next_tx
{
let c = ctx.tx_data;
ctx.stat |= STS_TXR;
ctx.stat |= STS_TXE;
@ -382,7 +395,7 @@ impl Duart {
ctx.stat |= STS_TXE;
ctx.conf &= !CNF_ETX;
}
4 => ctx.stat &= !(STS_FER | STS_PER | STS_OER),
4 => ctx.stat &= !(STS_FER|STS_PER|STS_OER),
_ => {}
}
}
@ -415,7 +428,9 @@ impl Device for Duart {
ctx.mode_ptr = (ctx.mode_ptr + 1) % 2;
Ok(val)
}
CSRA => Ok(self.ports[PORT_0].stat),
CSRA => {
Ok(self.ports[PORT_0].stat)
}
THRA => {
let mut ctx = &mut self.ports[PORT_0];
ctx.stat &= !STS_RXR;
@ -430,14 +445,18 @@ impl Device for Duart {
self.istat &= !ISTS_IPC;
Ok(result)
}
ISR_MASK => Ok(self.istat),
ISR_MASK => {
Ok(self.istat)
}
MR12B => {
let mut ctx = &mut self.ports[PORT_1];
let val = ctx.mode[ctx.mode_ptr];
ctx.mode_ptr = (ctx.mode_ptr + 1) % 2;
Ok(val)
}
CSRB => Ok(self.ports[PORT_1].stat),
CSRB => {
Ok(self.ports[PORT_1].stat)
}
THRB => {
let mut ctx = &mut self.ports[PORT_1];
ctx.stat &= !STS_RXR;
@ -445,7 +464,9 @@ impl Device for Duart {
self.ivec &= !KEYBOARD_INT;
Ok(ctx.rx_data)
}
IP_OPCR => Ok(self.inprt),
IP_OPCR => {
Ok(self.inprt)
}
_ => Ok(0),
}
}

View File

@ -1,14 +1,14 @@
pub mod bus;
pub mod cpu;
pub mod dmd;
pub mod duart;
pub mod err;
pub mod instr;
pub mod mem;
pub mod duart;
pub mod mouse;
pub mod rom_hi;
pub mod rom_lo;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate libc;

View File

@ -6,27 +6,25 @@ use crate::err::BusError;
use std::fmt::Debug;
use std::fmt::Error;
use std::fmt::Formatter;
use std::ops::Range;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
use std::ops::Range;
pub struct Mem {
address_range: Range<usize>,
len: usize,
ram: Vec<u8>,
is_read_only: bool,
dirty: bool,
}
/// Memory is a Device with a single address range.
impl Mem {
pub fn new(start_address: usize, len: usize, is_read_only: bool) -> Mem {
Mem {
address_range: start_address..start_address + len,
address_range: start_address..start_address+len,
len,
ram: vec![0; len],
is_read_only,
dirty: false,
}
}
@ -93,7 +91,7 @@ impl Device for Mem {
u32::from(self.ram[offset]).wrapping_shl(24)
| u32::from(self.ram[offset + 1]).wrapping_shl(16)
| u32::from(self.ram[offset + 2]).wrapping_shl(8)
| u32::from(self.ram[offset + 3]),
| u32::from(self.ram[offset + 3])
)
}
}
@ -109,9 +107,6 @@ impl Device for Mem {
if address >= self.address_range().end {
Err(BusError::Range)
} else {
if self.ram[offset] != val {
self.dirty = true;
}
self.ram[offset] = val;
Ok(())
}
@ -127,13 +122,8 @@ impl Device for Mem {
if address >= self.address_range().end {
Err(BusError::Range)
} else {
let b1 = (val.wrapping_shr(8) & 0xff) as u8;
let b2 = (val & 0xff) as u8;
if self.ram[offset] != b1 || self.ram[offset + 1] != b2 {
self.dirty = true;
}
self.ram[offset] = b1;
self.ram[offset + 1] = b2;
self.ram[offset] = (val.wrapping_shr(8) & 0xff) as u8;
self.ram[offset + 1] = (val & 0xff) as u8;
Ok(())
}
}
@ -148,19 +138,10 @@ impl Device for Mem {
if address >= self.address_range().end {
Err(BusError::Range)
} else {
let b1 = (val.wrapping_shr(24) & 0xff) as u8;
let b2 = (val.wrapping_shr(16) & 0xff) as u8;
let b3 = (val.wrapping_shr(8) & 0xff) as u8;
let b4 = (val & 0xff) as u8;
if self.ram[offset] != b1 || self.ram[offset + 1] != b2 || self.ram[offset + 2] != b3 || self.ram[offset + 3] != b4 {
self.dirty = true;
}
self.ram[offset] = b1;
self.ram[offset + 1] = b2;
self.ram[offset + 2] = b3;
self.ram[offset + 3] = b4;
self.ram[offset] = (val.wrapping_shr(24) & 0xff) as u8;
self.ram[offset + 1] = (val.wrapping_shr(16) & 0xff) as u8;
self.ram[offset + 2] = (val.wrapping_shr(8) & 0xff) as u8;
self.ram[offset + 3] = (val & 0xff) as u8;
Ok(())
}
}
@ -179,14 +160,6 @@ impl Device for Mem {
Ok(())
}
}
fn dirty(&self) -> bool {
self.dirty
}
fn clear_dirty(&mut self) {
self.dirty = false;
}
}
impl Index<usize> for Mem {

View File

@ -1,7 +1,7 @@
#![allow(clippy::unreadable_literal)]
use crate::bus::AccessCode;
use crate::bus::Device;
use crate::bus::AccessCode;
use crate::err::BusError;
use std::ops::Range;
@ -48,7 +48,7 @@ impl Device for Mouse {
}
fn read_half(&mut self, address: usize, _access: AccessCode) -> Result<u16, BusError> {
match address - START_ADDRESS {
match address-START_ADDRESS {
0 => Ok(self.y),
2 => Ok(self.x),
_ => Err(BusError::NoDevice(address as u32)),
@ -74,4 +74,4 @@ impl Device for Mouse {
fn load(&mut self, _address: usize, _data: &[u8]) -> Result<(), BusError> {
unimplemented!()
}
}
}