mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-16 15:29:30 +00:00
Refactored mc68681 to make a common port struct and fixed a bug in DIV
This commit is contained in:
parent
f0637e81f1
commit
fbb5153121
Binary file not shown.
|
@ -261,8 +261,11 @@ impl MC68010 {
|
||||||
let value = self.get_target_value(system, src, size)?;
|
let value = self.get_target_value(system, src, size)?;
|
||||||
let existing = self.get_target_value(system, dest, Size::Long)?;
|
let existing = self.get_target_value(system, dest, Size::Long)?;
|
||||||
let result = match sign {
|
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::Signed => {
|
||||||
Sign::Unsigned => ((existing as u16 % value as u16) as u32) << 16 | (0xFFFF & (existing as u16 / value as u16) as u32),
|
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)?;
|
self.set_target_value(system, dest, result, Size::Long)?;
|
||||||
},
|
},
|
||||||
|
|
39
src/main.rs
39
src/main.rs
|
@ -34,7 +34,8 @@ fn main() {
|
||||||
system.add_addressable_device(0x00600000, wrap_addressable(ata)).unwrap();
|
system.add_addressable_device(0x00600000, wrap_addressable(ata)).unwrap();
|
||||||
|
|
||||||
let mut serial = MC68681::new();
|
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();
|
system.add_addressable_device(0x00700000, wrap_addressable(serial)).unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ fn main() {
|
||||||
//cpu.add_breakpoint(0x10781a);
|
//cpu.add_breakpoint(0x10781a);
|
||||||
//cpu.add_breakpoint(0x10bc9c);
|
//cpu.add_breakpoint(0x10bc9c);
|
||||||
//cpu.add_breakpoint(0x106a94);
|
//cpu.add_breakpoint(0x106a94);
|
||||||
|
//cpu.add_breakpoint(0x10d0c6);
|
||||||
|
|
||||||
system.add_interruptable_device(wrap_interruptable(cpu)).unwrap();
|
system.add_interruptable_device(wrap_interruptable(cpu)).unwrap();
|
||||||
loop {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
|
|
||||||
use std::process::Command;
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use nix::unistd::sleep;
|
|
||||||
use nix::pty::{self, PtyMaster};
|
use nix::pty::{self, PtyMaster};
|
||||||
use nix::fcntl::{fcntl, FcntlArg};
|
use nix::fcntl::{fcntl, FcntlArg};
|
||||||
|
|
||||||
|
@ -21,12 +19,12 @@ const REG_CRA_WR: Address = 0x05;
|
||||||
const REG_TBA_WR: Address = 0x07;
|
const REG_TBA_WR: Address = 0x07;
|
||||||
const REG_RBA_RD: Address = 0x07;
|
const REG_RBA_RD: Address = 0x07;
|
||||||
|
|
||||||
const REG_MR1B_MR2B: Address = 0x700011;
|
const REG_MR1B_MR2B: Address = 0x11;
|
||||||
const REG_SRB_RD: Address = 0x700013;
|
const REG_SRB_RD: Address = 0x13;
|
||||||
const REG_CSRB_WR: Address = 0x700013;
|
const REG_CSRB_WR: Address = 0x13;
|
||||||
const REG_CRB_WR: Address = 0x700015;
|
const REG_CRB_WR: Address = 0x15;
|
||||||
const REG_TBB_WR: Address = 0x700017;
|
const REG_TBB_WR: Address = 0x17;
|
||||||
const REG_RBB_RD: Address = 0x700017;
|
const REG_RBB_RD: Address = 0x17;
|
||||||
|
|
||||||
const REG_ACR_WR: Address = 0x09;
|
const REG_ACR_WR: Address = 0x09;
|
||||||
|
|
||||||
|
@ -70,21 +68,95 @@ const ISR_CH_A_TX_READY: u8 = 0x01;
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "mc68681";
|
const DEV_NAME: &'static str = "mc68681";
|
||||||
|
|
||||||
pub struct MC68681 {
|
pub struct MC68681Port {
|
||||||
pub tty: Option<PtyMaster>,
|
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 acr: u8,
|
||||||
pub status_a: u8,
|
pub port_a: MC68681Port,
|
||||||
pub input_a: u8,
|
pub port_b: MC68681Port,
|
||||||
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 int_mask: u8,
|
pub int_mask: u8,
|
||||||
pub int_status: u8,
|
pub int_status: u8,
|
||||||
pub int_vector: u8,
|
pub int_vector: u8,
|
||||||
pub is_interrupt: bool,
|
|
||||||
pub timer_preload: u16,
|
pub timer_preload: u16,
|
||||||
pub timer_count: u16,
|
pub timer_count: u16,
|
||||||
pub is_timing: bool,
|
pub is_timing: bool,
|
||||||
|
@ -93,22 +165,13 @@ pub struct MC68681 {
|
||||||
impl MC68681 {
|
impl MC68681 {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
MC68681 {
|
MC68681 {
|
||||||
tty: None,
|
|
||||||
acr: 0,
|
acr: 0,
|
||||||
|
port_a: MC68681Port::new(),
|
||||||
status_a: 0,
|
port_b: MC68681Port::new(),
|
||||||
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,
|
|
||||||
|
|
||||||
int_mask: 0,
|
int_mask: 0,
|
||||||
int_status: 0,
|
int_status: 0,
|
||||||
int_vector: 0,
|
int_vector: 0,
|
||||||
is_interrupt: false,
|
|
||||||
|
|
||||||
timer_preload: 0,
|
timer_preload: 0,
|
||||||
timer_count: 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> {
|
pub fn step_internal(&mut self, system: &System) -> Result<(), Error> {
|
||||||
if self.rx_a_enabled && !self.rx_ready() && self.tty.is_some() {
|
if self.port_a.check_read()? {
|
||||||
let mut buf = [0; 1];
|
self.int_status |= ISR_CH_A_RX_READY_FULL;
|
||||||
let tty = self.tty.as_mut().unwrap();
|
}
|
||||||
match tty.read(&mut buf) {
|
|
||||||
Ok(count) => {
|
if self.port_b.check_read()? {
|
||||||
println!("READ {:?}", count);
|
self.int_status |= ISR_CH_B_RX_READY_FULL;
|
||||||
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.is_timing {
|
if self.is_timing {
|
||||||
|
@ -176,6 +206,10 @@ impl MC68681 {
|
||||||
Ok(())
|
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> {
|
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)
|
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 {
|
match addr {
|
||||||
REG_SRA_RD => {
|
REG_SRA_RD => {
|
||||||
data[0] = self.status_a
|
data[0] = self.port_a.status
|
||||||
},
|
},
|
||||||
REG_RBA_RD => {
|
REG_RBA_RD => {
|
||||||
data[0] = self.input_a;
|
data[0] = self.port_a.input;
|
||||||
self.status_a &= !SR_RX_READY;
|
self.port_a.status &= !SR_RX_READY;
|
||||||
self.int_status &= !ISR_CH_A_RX_READY_FULL;
|
self.int_status &= !ISR_CH_A_RX_READY_FULL;
|
||||||
},
|
},
|
||||||
REG_SRB_RD => {
|
REG_SRB_RD => {
|
||||||
data[0] = self.status_b
|
data[0] = self.port_b.status
|
||||||
},
|
},
|
||||||
REG_RBB_RD => {
|
REG_RBB_RD => {
|
||||||
data[0] = self.input_b;
|
data[0] = self.port_b.input;
|
||||||
self.status_b &= !SR_RX_READY;
|
self.port_b.status &= !SR_RX_READY;
|
||||||
self.int_status &= !ISR_CH_B_RX_READY_FULL;
|
self.int_status &= !ISR_CH_B_RX_READY_FULL;
|
||||||
},
|
},
|
||||||
REG_ISR_RD => {
|
REG_ISR_RD => {
|
||||||
|
@ -245,47 +279,22 @@ impl Addressable for MC68681 {
|
||||||
}
|
}
|
||||||
REG_TBA_WR => {
|
REG_TBA_WR => {
|
||||||
println!("{}a: write {}", DEV_NAME, data[0] as char);
|
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 => {
|
REG_CRA_WR => {
|
||||||
let rx_cmd = (data[0] & 0x03);
|
match self.port_a.handle_command(data[0]) {
|
||||||
if rx_cmd == 0b01 {
|
Some(value) => self.set_interrupt_flag(ISR_CH_A_TX_READY, value),
|
||||||
self.rx_a_enabled = true;
|
None => { },
|
||||||
} 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;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
REG_TBB_WR => {
|
REG_TBB_WR => {
|
||||||
println!("{}b: write {:x}", DEV_NAME, data[0]);
|
println!("{}b: write {:x}", DEV_NAME, data[0]);
|
||||||
|
self.port_b.tty.as_mut().map(|tty| tty.write_all(&[data[0]]));
|
||||||
},
|
},
|
||||||
REG_CRB_WR => {
|
REG_CRB_WR => {
|
||||||
let rx_cmd = (data[0] & 0x03);
|
match self.port_b.handle_command(data[0]) {
|
||||||
if rx_cmd == 0b01 {
|
Some(value) => self.set_interrupt_flag(ISR_CH_B_TX_READY, value),
|
||||||
self.rx_b_enabled = true;
|
None => { },
|
||||||
} 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;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
REG_CTUR_WR => {
|
REG_CTUR_WR => {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::{RefCell, RefMut};
|
use std::cell::{RefCell, RefMut};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::interrupts::InterruptController;
|
use crate::interrupts::InterruptController;
|
||||||
use crate::memory::{Address, Addressable, Bus};
|
use crate::memory::{Address, Bus};
|
||||||
use crate::devices::{Device, Steppable, AddressableDeviceBox, InterruptableDeviceBox, Clock};
|
use crate::devices::{Device, AddressableDeviceBox, InterruptableDeviceBox, Clock};
|
||||||
|
|
||||||
|
|
||||||
pub struct System {
|
pub struct System {
|
||||||
|
@ -42,7 +41,7 @@ impl System {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_interruptable_device(&mut self, device: InterruptableDeviceBox) -> Result<(), Error> {
|
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));
|
self.devices.push(Device::Interruptable(device));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user