Refactored mc68681 to make a common port struct and fixed a bug in DIV

This commit is contained in:
transistor 2021-10-09 17:35:23 -07:00
parent f0637e81f1
commit fbb5153121
5 changed files with 162 additions and 114 deletions

Binary file not shown.

View File

@ -261,8 +261,11 @@ impl MC68010 {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, Size::Long)?;
let result = match sign {
Sign::Signed => ((existing as i16 % value as i16) as u32) << 16 | (0xFFFF & (existing as i16 / value as i16) as u32),
Sign::Unsigned => ((existing as u16 % value as u16) as u32) << 16 | (0xFFFF & (existing as u16 / value as u16) as u32),
Sign::Signed => {
let value = sign_extend_to_long(value, size) as u32;
((existing % value) << 16) | (0xFFFF & (existing / value))
},
Sign::Unsigned => ((existing % value) << 16) | (0xFFFF & (existing / value)),
};
self.set_target_value(system, dest, result, Size::Long)?;
},

View File

@ -34,7 +34,8 @@ fn main() {
system.add_addressable_device(0x00600000, wrap_addressable(ata)).unwrap();
let mut serial = MC68681::new();
serial.open().unwrap();
launch_terminal_emulator(serial.port_a.open().unwrap());
launch_slip_connection(serial.port_b.open().unwrap());
system.add_addressable_device(0x00700000, wrap_addressable(serial)).unwrap();
@ -44,6 +45,7 @@ fn main() {
//cpu.add_breakpoint(0x10781a);
//cpu.add_breakpoint(0x10bc9c);
//cpu.add_breakpoint(0x106a94);
//cpu.add_breakpoint(0x10d0c6);
system.add_interruptable_device(wrap_interruptable(cpu)).unwrap();
loop {
@ -72,3 +74,38 @@ fn main() {
*/
}
pub fn launch_terminal_emulator(name: String) {
use nix::unistd::sleep;
use std::process::Command;
Command::new("x-terminal-emulator").arg("-e").arg(&format!("pyserial-miniterm {}", name)).spawn().unwrap();
sleep(1);
}
pub fn launch_slip_connection(name: String) {
use nix::unistd::sleep;
use std::process::Command;
//Command::new("x-terminal-emulator").arg("-e").arg(&format!("pyserial-miniterm {}", name)).spawn().unwrap();
Command::new("sudo").args(["slattach", "-s", "38400", "-p", "slip", &name]).spawn().unwrap();
Command::new("sudo").args(["ifconfig", "sl0", "192.168.1.2", "pointopoint", "192.168.1.200", "up"]).status().unwrap();
Command::new("sudo").args(["arp", "-Ds", "192.168.1.200", "enp4s0", "pub"]).status().unwrap();
Command::new("sudo").args(["iptables", "-A", "FORWARD", "-i", "sl0", "-j", "ACCEPT"]).status().unwrap();
Command::new("sudo").args(["iptables", "-A", "FORWARD", "-o", "sl0", "-j", "ACCEPT"]).status().unwrap();
Command::new("sudo").args(["sh", "-c", "echo 1 > /proc/sys/net/ipv4/ip_forward"]).status().unwrap();
/*
*/
/*
sudo slattach -s 38400 -p slip /dev/ttyUSB1
sudo ifconfig sl0 192.168.1.2 pointopoint 192.168.1.200 up
// (this is automatically added on my machine) >> sudo route add -host 192.168.1.200 sl0
sudo arp -Ds 192.168.1.200 enp3s0 pub
sudo iptables -A FORWARD -i sl0 -j ACCEPT
sudo iptables -A FORWARD -o sl0 -j ACCEPT
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
*/
sleep(1);
}

View File

@ -1,10 +1,8 @@
use std::process::Command;
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use nix::fcntl::OFlag;
use nix::unistd::sleep;
use nix::pty::{self, PtyMaster};
use nix::fcntl::{fcntl, FcntlArg};
@ -21,12 +19,12 @@ const REG_CRA_WR: Address = 0x05;
const REG_TBA_WR: Address = 0x07;
const REG_RBA_RD: Address = 0x07;
const REG_MR1B_MR2B: Address = 0x700011;
const REG_SRB_RD: Address = 0x700013;
const REG_CSRB_WR: Address = 0x700013;
const REG_CRB_WR: Address = 0x700015;
const REG_TBB_WR: Address = 0x700017;
const REG_RBB_RD: Address = 0x700017;
const REG_MR1B_MR2B: Address = 0x11;
const REG_SRB_RD: Address = 0x13;
const REG_CSRB_WR: Address = 0x13;
const REG_CRB_WR: Address = 0x15;
const REG_TBB_WR: Address = 0x17;
const REG_RBB_RD: Address = 0x17;
const REG_ACR_WR: Address = 0x09;
@ -70,21 +68,95 @@ const ISR_CH_A_TX_READY: u8 = 0x01;
const DEV_NAME: &'static str = "mc68681";
pub struct MC68681 {
pub struct MC68681Port {
pub tty: Option<PtyMaster>,
pub status: u8,
pub input: u8,
pub tx_enabled: bool,
pub rx_enabled: bool,
}
impl MC68681Port {
pub fn new() -> MC68681Port {
MC68681Port {
tty: None,
status: 0,
input: 0,
tx_enabled: false,
rx_enabled: false,
}
}
pub fn open(&mut self) -> Result<String, Error> {
let master = pty::posix_openpt(OFlag::O_RDWR).and_then(|master| {
pty::grantpt(&master)?;
pty::unlockpt(&master)?;
fcntl(master.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?;
Ok(master)
}).map_err(|_| Error::new("Error opening new pseudoterminal"))?;
let name = unsafe { pty::ptsname(&master).map_err(|_| Error::new("Unable to get pty name"))? };
println!("{}: opening pts {}", DEV_NAME, name);
self.tty = Some(master);
Ok(name)
}
pub fn rx_ready(&self) -> bool {
(self.status & SR_RX_READY) != 0
}
pub fn check_read(&mut self) -> Result<bool, Error> {
if self.rx_enabled && !self.rx_ready() && self.tty.is_some() {
let mut buf = [0; 1];
let tty = self.tty.as_mut().unwrap();
match tty.read(&mut buf) {
Ok(count) => {
println!("READ {:?}", count);
self.input = buf[0];
self.status |= SR_RX_READY;
return Ok(true);
},
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { },
Err(err) => {
println!("ERROR: {:?}", err);
}
}
}
Ok(false)
}
pub fn handle_command(&mut self, data: u8) -> Option<bool> {
let rx_cmd = data& 0x03;
if rx_cmd == 0b01 {
self.rx_enabled = true;
} else if rx_cmd == 0b10 {
self.rx_enabled = false;
}
let tx_cmd = (data & 0x0C) >> 2;
if tx_cmd == 0b01 {
self.tx_enabled = true;
self.status |= SR_TX_READY | SR_TX_EMPTY;
return Some(true);
} else if tx_cmd == 0b10 {
self.tx_enabled = false;
self.status &= !(SR_TX_READY | SR_TX_EMPTY);
return Some(false);
}
None
}
}
pub struct MC68681 {
pub acr: u8,
pub status_a: u8,
pub input_a: u8,
pub tx_a_enabled: bool,
pub rx_a_enabled: bool,
pub status_b: u8,
pub input_b: u8,
pub tx_b_enabled: bool,
pub rx_b_enabled: bool,
pub port_a: MC68681Port,
pub port_b: MC68681Port,
pub int_mask: u8,
pub int_status: u8,
pub int_vector: u8,
pub is_interrupt: bool,
pub timer_preload: u16,
pub timer_count: u16,
pub is_timing: bool,
@ -93,22 +165,13 @@ pub struct MC68681 {
impl MC68681 {
pub fn new() -> Self {
MC68681 {
tty: None,
acr: 0,
status_a: 0,
input_a: 0,
tx_a_enabled: false,
rx_a_enabled: false,
status_b: 0,
input_b: 0,
tx_b_enabled: false,
rx_b_enabled: false,
port_a: MC68681Port::new(),
port_b: MC68681Port::new(),
int_mask: 0,
int_status: 0,
int_vector: 0,
is_interrupt: false,
timer_preload: 0,
timer_count: 0,
@ -116,46 +179,13 @@ impl MC68681 {
}
}
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);
fcntl(master.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).unwrap();
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 rx_ready(&self) -> bool {
(self.status_a & SR_RX_READY) != 0
}
pub fn step_internal(&mut self, system: &System) -> Result<(), Error> {
if self.rx_a_enabled && !self.rx_ready() && self.tty.is_some() {
let mut buf = [0; 1];
let tty = self.tty.as_mut().unwrap();
match tty.read(&mut buf) {
Ok(count) => {
println!("READ {:?}", count);
self.input_a = buf[0];
self.status_a |= SR_RX_READY;
self.int_status |= ISR_CH_A_RX_READY_FULL;
},
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { },
Err(err) => {
println!("ERROR: {:?}", err);
}
}
if self.port_a.check_read()? {
self.int_status |= ISR_CH_A_RX_READY_FULL;
}
if self.port_b.check_read()? {
self.int_status |= ISR_CH_B_RX_READY_FULL;
}
if self.is_timing {
@ -176,6 +206,10 @@ impl MC68681 {
Ok(())
}
fn set_interrupt_flag(&mut self, flag: u8, value: bool) {
self.int_status = (self.int_status & !flag) | (if value { flag } else { 0 });
}
fn check_interrupt_state(&mut self, system: &System) -> Result<(), Error> {
system.get_interrupt_controller().set((self.int_status & self.int_mask) != 0, 4, self.int_vector)
}
@ -195,19 +229,19 @@ impl Addressable for MC68681 {
match addr {
REG_SRA_RD => {
data[0] = self.status_a
data[0] = self.port_a.status
},
REG_RBA_RD => {
data[0] = self.input_a;
self.status_a &= !SR_RX_READY;
data[0] = self.port_a.input;
self.port_a.status &= !SR_RX_READY;
self.int_status &= !ISR_CH_A_RX_READY_FULL;
},
REG_SRB_RD => {
data[0] = self.status_b
data[0] = self.port_b.status
},
REG_RBB_RD => {
data[0] = self.input_b;
self.status_b &= !SR_RX_READY;
data[0] = self.port_b.input;
self.port_b.status &= !SR_RX_READY;
self.int_status &= !ISR_CH_B_RX_READY_FULL;
},
REG_ISR_RD => {
@ -245,47 +279,22 @@ impl Addressable for MC68681 {
}
REG_TBA_WR => {
println!("{}a: write {}", DEV_NAME, data[0] as char);
self.tty.as_mut().map(|tty| tty.write_all(&[data[0]]));
self.port_a.tty.as_mut().map(|tty| tty.write_all(&[data[0]]));
},
REG_CRA_WR => {
let rx_cmd = (data[0] & 0x03);
if rx_cmd == 0b01 {
self.rx_a_enabled = true;
} else if rx_cmd == 0b10 {
self.rx_a_enabled = false;
}
let tx_cmd = ((data[0] & 0x0C) >> 2);
if tx_cmd == 0b01 {
self.tx_a_enabled = true;
self.status_a |= SR_TX_READY | SR_TX_EMPTY;
self.int_status |= ISR_CH_A_TX_READY;
} else if tx_cmd == 0b10 {
self.tx_a_enabled = false;
self.status_a &= !(SR_TX_READY | SR_TX_EMPTY);
self.int_status &= !ISR_CH_A_TX_READY;
match self.port_a.handle_command(data[0]) {
Some(value) => self.set_interrupt_flag(ISR_CH_A_TX_READY, value),
None => { },
}
},
REG_TBB_WR => {
println!("{}b: write {:x}", DEV_NAME, data[0]);
self.port_b.tty.as_mut().map(|tty| tty.write_all(&[data[0]]));
},
REG_CRB_WR => {
let rx_cmd = (data[0] & 0x03);
if rx_cmd == 0b01 {
self.rx_b_enabled = true;
} else if rx_cmd == 0b10 {
self.rx_b_enabled = false;
}
let tx_cmd = ((data[0] & 0x0C) >> 2);
if tx_cmd == 0b01 {
self.tx_b_enabled = true;
self.status_b |= SR_TX_READY | SR_TX_EMPTY;
self.int_status |= ISR_CH_B_TX_READY;
} else if tx_cmd == 0b10 {
self.tx_b_enabled = false;
self.status_b &= !(SR_TX_READY | SR_TX_EMPTY);
self.int_status &= !ISR_CH_B_TX_READY;
match self.port_b.handle_command(data[0]) {
Some(value) => self.set_interrupt_flag(ISR_CH_B_TX_READY, value),
None => { },
}
},
REG_CTUR_WR => {

View File

@ -1,11 +1,10 @@
use std::rc::Rc;
use std::cell::{RefCell, RefMut};
use crate::error::Error;
use crate::interrupts::InterruptController;
use crate::memory::{Address, Addressable, Bus};
use crate::devices::{Device, Steppable, AddressableDeviceBox, InterruptableDeviceBox, Clock};
use crate::memory::{Address, Bus};
use crate::devices::{Device, AddressableDeviceBox, InterruptableDeviceBox, Clock};
pub struct System {
@ -42,7 +41,7 @@ impl System {
}
pub fn add_interruptable_device(&mut self, device: InterruptableDeviceBox) -> Result<(), Error> {
self.interrupt_controller.borrow_mut().set_target(device.clone());
self.interrupt_controller.borrow_mut().set_target(device.clone())?;
self.devices.push(Device::Interruptable(device));
Ok(())
}