diff --git a/Cargo.toml b/Cargo.toml index e22f99c..1fe0ee7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/cpus/m68k/decode.rs b/src/cpus/m68k/decode.rs index c8d451f..2a8ff57 100644 --- a/src/cpus/m68k/decode.rs +++ b/src/cpus/m68k/decode.rs @@ -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 { diff --git a/src/cpus/m68k/execute.rs b/src/cpus/m68k/execute.rs index e561714..c16f408 100644 --- a/src/cpus/m68k/execute.rs +++ b/src/cpus/m68k/execute.rs @@ -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, } } diff --git a/src/cpus/m68k/mod.rs b/src/cpus/m68k/mod.rs index c4f401f..5aa921f 100644 --- a/src/cpus/m68k/mod.rs +++ b/src/cpus/m68k/mod.rs @@ -1,6 +1,7 @@ mod decode; mod execute; +//mod debugger; pub use self::execute::MC68010; diff --git a/src/devices/mc68681.rs b/src/devices/mc68681.rs index 25ee431..d204f9d 100644 --- a/src/devices/mc68681.rs +++ b/src/devices/mc68681.rs @@ -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, 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 { + 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 { + 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 { + 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); }, + } + } +} +*/ diff --git a/src/main.rs b/src/main.rs index 6236087..d09c7c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(); } } diff --git a/src/memory.rs b/src/memory.rs index b60144e..49d358c 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -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; 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 { + 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, 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 { - 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 { + 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 { - 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 { + 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 { - 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 { + 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)))?) }