Added PTY terminal for I/O via the MC68681 module

Also fixed a bug where MOVEA needs to behave differently than MOVE,
such that the data is sign extended to a long and the condition flags
are not changed.  I also modifed how Addressable returns data because
I need to return owned data from MC68681, so that the stored data can
be updated (ie. the status flag must be modified after a read)
This commit is contained in:
transistor 2021-10-01 12:25:23 -07:00
parent 01b4bdf859
commit f7529bbb41
7 changed files with 178 additions and 41 deletions

View File

@ -6,3 +6,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nix = "0.23"

View File

@ -115,6 +115,7 @@ pub enum Instruction {
LSd(Target, Target, Size, ShiftDirection),
MOVE(Target, Target, Size),
MOVEA(Target, u8, Size),
MOVEfromSR(Target),
MOVEtoSR(Target),
MOVEtoCCR(Target),
@ -270,12 +271,20 @@ impl MC68010 {
OPCG_MOVE_LONG => {
let src = self.decode_lower_effective_address(space, ins, Some(Size::Long))?;
let dest = self.decode_upper_effective_address(space, ins, Some(Size::Long))?;
Ok(Instruction::MOVE(src, dest, Size::Long))
if let Target::DirectAReg(reg) = dest {
Ok(Instruction::MOVEA(src, reg, Size::Long))
} else {
Ok(Instruction::MOVE(src, dest, Size::Long))
}
},
OPCG_MOVE_WORD => {
let src = self.decode_lower_effective_address(space, ins, Some(Size::Word))?;
let dest = self.decode_upper_effective_address(space, ins, Some(Size::Word))?;
Ok(Instruction::MOVE(src, dest, Size::Word))
if let Target::DirectAReg(reg) = dest {
Ok(Instruction::MOVEA(src, reg, Size::Word))
} else {
Ok(Instruction::MOVE(src, dest, Size::Word))
}
},
OPCG_MISC => {
if (ins & 0b000101000000) == 0b000100000000 {

View File

@ -121,7 +121,7 @@ impl MC68010 {
}
}
pub fn dump_state(&self, space: &AddressSpace) {
pub fn dump_state(&self, space: &mut AddressSpace) {
println!("State: {:?}", self.state);
println!("PC: {:#010x}", self.pc);
println!("SR: {:#06x}", self.sr);
@ -285,8 +285,13 @@ impl MC68010 {
//Instruction::EXG(Target, Target) => {
//},
Instruction::EXT(reg, size) => {
let data: u8 = self.d_reg[reg as usize] as u8;
self.d_reg[reg as usize] = sign_extend_byte(data, size);
let byte = (self.d_reg[reg as usize] as u8) as i8;
let result = match size {
Size::Byte => (byte as u8) as u32,
Size::Word => ((byte as i16) as u16) as u32,
Size::Long => (byte as i32) as u32,
};
self.d_reg[reg as usize] = result;
},
//Instruction::ILLEGAL => {
//},
@ -311,6 +316,11 @@ impl MC68010 {
self.set_compare_flags(value, false, size);
self.set_target_value(space, dest, value, size)?;
},
Instruction::MOVEA(src, reg, size) => {
let value = self.get_target_value(space, src, size)?;
let addr = self.get_a_reg_mut(reg);
*addr = sign_extend_to_long(value, size) as u32;
},
Instruction::MOVEfromSR(target) => {
self.set_target_value(space, target, self.sr as u32, Size::Word)?;
},
@ -374,7 +384,7 @@ impl MC68010 {
}
},
Instruction::MOVEQ(data, reg) => {
let value = sign_extend_byte(data, Size::Long);
let value = sign_extend_to_long(data as u32, Size::Byte) as u32;
self.d_reg[reg as usize] = value;
self.set_compare_flags(value, false, Size::Long);
},
@ -604,11 +614,7 @@ impl MC68010 {
}
fn set_compare_flags(&mut self, value: u32, carry: bool, size: Size) {
let value = match size {
Size::Byte => ((value as u8) as i8) as i32,
Size::Word => ((value as u16) as i16) as i32,
Size::Long => value as i32,
};
let value = sign_extend_to_long(value, size);
let mut flags = 0x0000;
if value < 0 {
@ -704,12 +710,11 @@ fn set_address_sized(space: &mut AddressSpace, addr: Address, value: u32, size:
}
}
fn sign_extend_byte(value: u8, size: Size) -> u32 {
let value = value as i8;
match size {
Size::Byte => (value as u8) as u32,
Size::Word => ((value as i16) as u16) as u32,
Size::Long => (value as i32) as u32,
fn sign_extend_to_long(value: u32, from: Size) -> i32 {
match from {
Size::Byte => ((value as u8) as i8) as i32,
Size::Word => ((value as u16) as i16) as i32,
Size::Long => value as i32,
}
}

View File

@ -1,6 +1,7 @@
mod decode;
mod execute;
//mod debugger;
pub use self::execute::MC68010;

View File

@ -1,6 +1,15 @@
use std::slice::Iter;
use std::process::Command;
use std::io::{Read, Write};
use std::os::unix::io::{RawFd, AsRawFd};
use nix::pty::{self, PtyMaster};
use nix::fcntl::OFlag;
use nix::unistd::sleep;
use nix::poll::{poll, PollFd, PollFlags};
use crate::error::Error;
use crate::memory::{Address, Addressable};
@ -27,9 +36,22 @@ const REG_ISR_RD: Address = 0x0B;
const REG_IMR_WR: Address = 0x0B;
const REG_IVR_WR: Address = 0x19;
// Status Register Bits (SRA/SRB)
const SR_RECEIVED_BREAK: u8 = 0x80;
const SR_FRAMING_ERROR: u8 = 0x40;
const SR_PARITY_ERROR: u8 = 0x20;
const SR_OVERRUN_ERROR: u8 = 0x10;
const SR_TX_EMPTY: u8 = 0x08;
const SR_TX_READY: u8 = 0x04;
const SR_RX_FULL: u8 = 0x02;
const SR_RX_READY: u8 = 0x01;
const DEV_NAME: &'static str = "mc68681";
pub struct MC68681 {
pub tty: Option<PtyMaster>,
pub status: [u8; 1],
pub input: [u8; 1],
}
@ -37,10 +59,57 @@ pub struct MC68681 {
impl MC68681 {
pub fn new() -> Self {
MC68681 {
tty: None,
status: [0x0C],
input: [0],
}
}
pub fn open(&mut self) -> Result<(), Error> {
let result = pty::posix_openpt(OFlag::O_RDWR).and_then(|master| {
pty::grantpt(&master).and_then(|_| pty::unlockpt(&master)).and_then(|_| Ok(master))
});
match result {
Ok(master) => {
let name = unsafe { pty::ptsname(&master).map_err(|_| Error::new("Unable to get pty name"))? };
println!("Open {}", name);
self.tty = Some(master);
Command::new("x-terminal-emulator").arg("-e").arg(&format!("pyserial-miniterm {}", name)).spawn().unwrap();
sleep(1);
Ok(())
},
Err(_) => Err(Error::new("Error opening new pseudoterminal")),
}
}
pub fn step(&mut self) -> Result<(), Error> {
if !self.rx_ready() && self.tty.is_some() {
self.poll_one_byte().map(|byte| {
self.input[0] = byte;
self.status[0] |= SR_RX_READY;
});
}
Ok(())
}
pub fn rx_ready(&self) -> bool {
(self.status[0] & SR_RX_READY) != 0
}
fn poll_one_byte(&mut self) -> Option<u8> {
if self.tty.is_none() {
return None;
}
let tty = self.tty.as_mut().unwrap();
let mut fds = [PollFd::new(tty.as_raw_fd(), PollFlags::POLLIN); 1];
match poll(&mut fds, 0) {
Ok(byte) => Some(byte as u8),
Err(_) => None,
}
}
}
impl Addressable for MC68681 {
@ -48,19 +117,68 @@ impl Addressable for MC68681 {
0x30
}
fn read(&self, addr: Address) -> &[u8] {
fn read(&mut self, addr: Address, count: usize) -> Vec<u8> {
let mut data = vec![0; count];
// TODO this is temporary
self.step();
match addr {
REG_SRA_RD => &self.status,
REG_TBA_RD => &self.input,
_ => { println!("{}: reading from {:0x}", DEV_NAME, addr); &self.input },
REG_SRA_RD => data[0] = self.status[0],
REG_TBA_RD => {
data[0] = self.input[0];
},
_ => { println!("{}: reading from {:0x}", DEV_NAME, addr); data[0] = self.input[0]; },
}
data
}
fn write(&mut self, mut addr: Address, data: &[u8]) {
match addr {
REG_TBA_WR => { println!(">>> {}", data[0] as char); },
REG_TBA_WR => {
println!("{}: {}", DEV_NAME, data[0] as char);
self.tty.as_mut().map(|tty| tty.write_all(&[data[0]]));
},
_ => { println!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr); },
}
}
}
/*
impl Addressable for MC68681 {
fn len(&self) -> usize {
0x30
}
fn read(&mut self, addr: Address, count: usize) -> Vec<u8> {
let mut data = vec![0; count];
// TODO this is temporary
self.step();
match addr {
REG_SRA_RD => { data[0] = self.status },
REG_RBA_RD => {
if self.rx_ready() {
data[0] = self.input;
self.status = self.status & !SR_RX_READY;
}
},
_ => { println!("{}: reading from {:0x}", DEV_NAME, addr); },
}
data
}
fn write(&mut self, mut addr: Address, data: &[u8]) {
match addr {
REG_TBA_WR => {
println!("{}: {}", DEV_NAME, data[0] as char);
self.tty.as_mut().map(|tty| tty.write_all(&[data[0]]));
},
_ => { println!("{}: writing {:0x} to {:0x}", DEV_NAME, data[0], addr); },
}
}
}
*/

View File

@ -21,19 +21,22 @@ fn main() {
space.insert(0x00100000, Box::new(ram));
let mut serial = MC68681::new();
serial.open().unwrap();
space.insert(0x00700000, Box::new(serial));
let mut cpu = MC68010::new();
//cpu.set_breakpoint(0x0838);
//cpu.use_tracing = true;
//cpu.set_breakpoint(0x0224);
cpu.use_tracing = true;
while cpu.is_running() {
match cpu.step(&mut space) {
Ok(()) => { },
Err(err) => {
cpu.dump_state(&space);
cpu.dump_state(&mut space);
panic!("{:?}", err);
},
}
//serial.step();
}
}

View File

@ -9,7 +9,7 @@ pub type Address = u64;
pub trait Addressable {
fn len(&self) -> usize;
fn read(&self, addr: Address) -> &[u8];
fn read(&mut self, addr: Address, count: usize) -> Vec<u8>;
fn write(&mut self, addr: Address, data: &[u8]);
}
@ -38,8 +38,8 @@ impl Addressable for MemoryBlock {
self.contents.len()
}
fn read(&self, addr: Address) -> &[u8] {
&self.contents[(addr) as usize .. ]
fn read(&mut self, addr: Address, count: usize) -> Vec<u8> {
self.contents[(addr as usize) .. (addr as usize + count)].to_vec()
}
fn write(&mut self, mut addr: Address, data: &[u8]) {
@ -107,7 +107,7 @@ impl AddressSpace {
}
pub fn dump_memory(&self, mut addr: Address, mut count: Address) {
pub fn dump_memory(&mut self, mut addr: Address, mut count: Address) {
while count > 0 {
let mut line = format!("{:#010x}: ", addr);
for i in 0..8 {
@ -120,24 +120,24 @@ impl AddressSpace {
}
pub fn read(&self, addr: Address) -> Result<&[u8], Error> {
let seg = self.get_segment(addr)?;
Ok(seg.contents.read(addr - seg.base))
pub fn read(&mut self, addr: Address, count: usize) -> Result<Vec<u8>, Error> {
let mut seg = self.get_segment_mut(addr)?;
Ok(seg.contents.read(addr - seg.base, count))
}
pub fn read_u8(&self, addr: Address) -> Result<u8, Error> {
let seg = self.get_segment(addr)?;
Ok(*seg.contents.read(addr - seg.base).iter().next().ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
pub fn read_u8(&mut self, addr: Address) -> Result<u8, Error> {
let mut seg = self.get_segment_mut(addr)?;
Ok(*seg.contents.read(addr - seg.base, 1).iter().next().ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
}
pub fn read_beu16(&self, addr: Address) -> Result<u16, Error> {
let seg = self.get_segment(addr)?;
Ok(read_beu16(seg.contents.read(addr - seg.base).iter()).ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
pub fn read_beu16(&mut self, addr: Address) -> Result<u16, Error> {
let mut seg = self.get_segment_mut(addr)?;
Ok(read_beu16(seg.contents.read(addr - seg.base, 2).iter()).ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
}
pub fn read_beu32(&self, addr: Address) -> Result<u32, Error> {
let seg = self.get_segment(addr)?;
Ok(read_beu32(seg.contents.read(addr - seg.base).iter()).ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
pub fn read_beu32(&mut self, addr: Address) -> Result<u32, Error> {
let mut seg = self.get_segment_mut(addr)?;
Ok(read_beu32(seg.contents.read(addr - seg.base, 4).iter()).ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
}