mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-24 23:32:46 +00:00
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:
parent
01b4bdf859
commit
f7529bbb41
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
mod decode;
|
||||
mod execute;
|
||||
//mod debugger;
|
||||
|
||||
pub use self::execute::MC68010;
|
||||
|
||||
|
@ -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); },
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)))?)
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user