mirror of
https://github.com/transistorfet/moa.git
synced 2025-02-17 18:30:33 +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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
nix = "0.23"
|
||||||
|
@ -115,6 +115,7 @@ pub enum Instruction {
|
|||||||
LSd(Target, Target, Size, ShiftDirection),
|
LSd(Target, Target, Size, ShiftDirection),
|
||||||
|
|
||||||
MOVE(Target, Target, Size),
|
MOVE(Target, Target, Size),
|
||||||
|
MOVEA(Target, u8, Size),
|
||||||
MOVEfromSR(Target),
|
MOVEfromSR(Target),
|
||||||
MOVEtoSR(Target),
|
MOVEtoSR(Target),
|
||||||
MOVEtoCCR(Target),
|
MOVEtoCCR(Target),
|
||||||
@ -270,12 +271,20 @@ impl MC68010 {
|
|||||||
OPCG_MOVE_LONG => {
|
OPCG_MOVE_LONG => {
|
||||||
let src = self.decode_lower_effective_address(space, ins, Some(Size::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))?;
|
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 => {
|
OPCG_MOVE_WORD => {
|
||||||
let src = self.decode_lower_effective_address(space, ins, Some(Size::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))?;
|
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 => {
|
OPCG_MISC => {
|
||||||
if (ins & 0b000101000000) == 0b000100000000 {
|
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!("State: {:?}", self.state);
|
||||||
println!("PC: {:#010x}", self.pc);
|
println!("PC: {:#010x}", self.pc);
|
||||||
println!("SR: {:#06x}", self.sr);
|
println!("SR: {:#06x}", self.sr);
|
||||||
@ -285,8 +285,13 @@ impl MC68010 {
|
|||||||
//Instruction::EXG(Target, Target) => {
|
//Instruction::EXG(Target, Target) => {
|
||||||
//},
|
//},
|
||||||
Instruction::EXT(reg, size) => {
|
Instruction::EXT(reg, size) => {
|
||||||
let data: u8 = self.d_reg[reg as usize] as u8;
|
let byte = (self.d_reg[reg as usize] as u8) as i8;
|
||||||
self.d_reg[reg as usize] = sign_extend_byte(data, size);
|
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 => {
|
//Instruction::ILLEGAL => {
|
||||||
//},
|
//},
|
||||||
@ -311,6 +316,11 @@ impl MC68010 {
|
|||||||
self.set_compare_flags(value, false, size);
|
self.set_compare_flags(value, false, size);
|
||||||
self.set_target_value(space, dest, value, 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) => {
|
Instruction::MOVEfromSR(target) => {
|
||||||
self.set_target_value(space, target, self.sr as u32, Size::Word)?;
|
self.set_target_value(space, target, self.sr as u32, Size::Word)?;
|
||||||
},
|
},
|
||||||
@ -374,7 +384,7 @@ impl MC68010 {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::MOVEQ(data, reg) => {
|
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.d_reg[reg as usize] = value;
|
||||||
self.set_compare_flags(value, false, Size::Long);
|
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) {
|
fn set_compare_flags(&mut self, value: u32, carry: bool, size: Size) {
|
||||||
let value = match size {
|
let value = sign_extend_to_long(value, 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 mut flags = 0x0000;
|
let mut flags = 0x0000;
|
||||||
if value < 0 {
|
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 {
|
fn sign_extend_to_long(value: u32, from: Size) -> i32 {
|
||||||
let value = value as i8;
|
match from {
|
||||||
match size {
|
Size::Byte => ((value as u8) as i8) as i32,
|
||||||
Size::Byte => (value as u8) as u32,
|
Size::Word => ((value as u16) as i16) as i32,
|
||||||
Size::Word => ((value as i16) as u16) as u32,
|
Size::Long => value as i32,
|
||||||
Size::Long => (value as i32) as u32,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
mod decode;
|
mod decode;
|
||||||
mod execute;
|
mod execute;
|
||||||
|
//mod debugger;
|
||||||
|
|
||||||
pub use self::execute::MC68010;
|
pub use self::execute::MC68010;
|
||||||
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
|
|
||||||
use std::slice::Iter;
|
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};
|
use crate::memory::{Address, Addressable};
|
||||||
|
|
||||||
|
|
||||||
@ -27,9 +36,22 @@ const REG_ISR_RD: Address = 0x0B;
|
|||||||
const REG_IMR_WR: Address = 0x0B;
|
const REG_IMR_WR: Address = 0x0B;
|
||||||
const REG_IVR_WR: Address = 0x19;
|
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";
|
const DEV_NAME: &'static str = "mc68681";
|
||||||
|
|
||||||
pub struct MC68681 {
|
pub struct MC68681 {
|
||||||
|
pub tty: Option<PtyMaster>,
|
||||||
pub status: [u8; 1],
|
pub status: [u8; 1],
|
||||||
pub input: [u8; 1],
|
pub input: [u8; 1],
|
||||||
}
|
}
|
||||||
@ -37,10 +59,57 @@ pub struct MC68681 {
|
|||||||
impl MC68681 {
|
impl MC68681 {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
MC68681 {
|
MC68681 {
|
||||||
|
tty: None,
|
||||||
status: [0x0C],
|
status: [0x0C],
|
||||||
input: [0],
|
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 {
|
impl Addressable for MC68681 {
|
||||||
@ -48,19 +117,68 @@ impl Addressable for MC68681 {
|
|||||||
0x30
|
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 {
|
match addr {
|
||||||
REG_SRA_RD => &self.status,
|
REG_SRA_RD => data[0] = self.status[0],
|
||||||
REG_TBA_RD => &self.input,
|
REG_TBA_RD => {
|
||||||
_ => { println!("{}: reading from {:0x}", DEV_NAME, addr); &self.input },
|
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]) {
|
fn write(&mut self, mut addr: Address, data: &[u8]) {
|
||||||
match addr {
|
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); },
|
_ => { 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));
|
space.insert(0x00100000, Box::new(ram));
|
||||||
|
|
||||||
let mut serial = MC68681::new();
|
let mut serial = MC68681::new();
|
||||||
|
serial.open().unwrap();
|
||||||
space.insert(0x00700000, Box::new(serial));
|
space.insert(0x00700000, Box::new(serial));
|
||||||
|
|
||||||
let mut cpu = MC68010::new();
|
let mut cpu = MC68010::new();
|
||||||
//cpu.set_breakpoint(0x0838);
|
//cpu.set_breakpoint(0x0224);
|
||||||
//cpu.use_tracing = true;
|
cpu.use_tracing = true;
|
||||||
while cpu.is_running() {
|
while cpu.is_running() {
|
||||||
match cpu.step(&mut space) {
|
match cpu.step(&mut space) {
|
||||||
Ok(()) => { },
|
Ok(()) => { },
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
cpu.dump_state(&space);
|
cpu.dump_state(&mut space);
|
||||||
panic!("{:?}", err);
|
panic!("{:?}", err);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//serial.step();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ pub type Address = u64;
|
|||||||
|
|
||||||
pub trait Addressable {
|
pub trait Addressable {
|
||||||
fn len(&self) -> usize;
|
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]);
|
fn write(&mut self, addr: Address, data: &[u8]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ impl Addressable for MemoryBlock {
|
|||||||
self.contents.len()
|
self.contents.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&self, addr: Address) -> &[u8] {
|
fn read(&mut self, addr: Address, count: usize) -> Vec<u8> {
|
||||||
&self.contents[(addr) as usize .. ]
|
self.contents[(addr as usize) .. (addr as usize + count)].to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, mut addr: Address, data: &[u8]) {
|
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 {
|
while count > 0 {
|
||||||
let mut line = format!("{:#010x}: ", addr);
|
let mut line = format!("{:#010x}: ", addr);
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
@ -120,24 +120,24 @@ impl AddressSpace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn read(&self, addr: Address) -> Result<&[u8], Error> {
|
pub fn read(&mut self, addr: Address, count: usize) -> Result<Vec<u8>, Error> {
|
||||||
let seg = self.get_segment(addr)?;
|
let mut seg = self.get_segment_mut(addr)?;
|
||||||
Ok(seg.contents.read(addr - seg.base))
|
Ok(seg.contents.read(addr - seg.base, count))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_u8(&self, addr: Address) -> Result<u8, Error> {
|
pub fn read_u8(&mut self, addr: Address) -> Result<u8, Error> {
|
||||||
let seg = self.get_segment(addr)?;
|
let mut seg = self.get_segment_mut(addr)?;
|
||||||
Ok(*seg.contents.read(addr - seg.base).iter().next().ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", 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> {
|
pub fn read_beu16(&mut self, addr: Address) -> Result<u16, Error> {
|
||||||
let seg = self.get_segment(addr)?;
|
let mut seg = self.get_segment_mut(addr)?;
|
||||||
Ok(read_beu16(seg.contents.read(addr - seg.base).iter()).ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", 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> {
|
pub fn read_beu32(&mut self, addr: Address) -> Result<u32, Error> {
|
||||||
let seg = self.get_segment(addr)?;
|
let mut seg = self.get_segment_mut(addr)?;
|
||||||
Ok(read_beu32(seg.contents.read(addr - seg.base).iter()).ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
|
Ok(read_beu32(seg.contents.read(addr - seg.base, 4).iter()).ok_or_else(|| Error::new(&format!("Error reading address {:#010x}", addr)))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user