mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-07 18:29:32 +00:00
Fixed all clippy warnings
This commit is contained in:
parent
0ac3f48b64
commit
7bdd63bc76
1
.clippy.toml
Normal file
1
.clippy.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
msrv = "1.60.0"
|
|
@ -6,6 +6,7 @@ use crate::system::System;
|
||||||
use crate::devices::{Address, Addressable, Debuggable, TransmutableBox};
|
use crate::devices::{Address, Addressable, Debuggable, TransmutableBox};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Debugger {
|
pub struct Debugger {
|
||||||
last_command: Option<String>,
|
last_command: Option<String>,
|
||||||
repeat: u32,
|
repeat: u32,
|
||||||
|
@ -14,14 +15,6 @@ pub struct Debugger {
|
||||||
|
|
||||||
|
|
||||||
impl Debugger {
|
impl Debugger {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
last_command: None,
|
|
||||||
repeat: 0,
|
|
||||||
trace_only: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breakpoint_occurred(&mut self) {
|
pub fn breakpoint_occurred(&mut self) {
|
||||||
self.trace_only = false;
|
self.trace_only = false;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +53,7 @@ impl Debugger {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_debugger_command(&mut self, system: &System, debug_obj: &mut dyn Debuggable, args: &[&str]) -> Result<bool, Error> {
|
pub fn run_debugger_command(&mut self, system: &System, debug_obj: &mut dyn Debuggable, args: &[&str]) -> Result<bool, Error> {
|
||||||
if args.len() == 0 {
|
if args.is_empty() {
|
||||||
// The Default Command
|
// The Default Command
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
@ -202,7 +195,7 @@ impl Debugger {
|
||||||
|
|
||||||
fn check_repeat_arg(&mut self, args: &[&str]) -> Result<(), Error> {
|
fn check_repeat_arg(&mut self, args: &[&str]) -> Result<(), Error> {
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
self.repeat = u32::from_str_radix(args[1], 10).map_err(|_| Error::new("Unable to parse repeat number"))?;
|
self.repeat = args[1].parse::<u32>().map_err(|_| Error::new("Unable to parse repeat number"))?;
|
||||||
self.last_command = Some(args[0].to_string());
|
self.last_command = Some(args[0].to_string());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub trait Interruptable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A device that can be addressed to read data from or write data to the device.
|
/// A device that can be addressed to read data from or write data to the device.
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
pub trait Addressable {
|
pub trait Addressable {
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error>;
|
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ErrorType {
|
pub enum ErrorType {
|
||||||
Assertion,
|
Assertion,
|
||||||
Emulator,
|
Emulator,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ControllerDevice {
|
pub enum ControllerDevice {
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
|
@ -7,7 +7,7 @@ pub enum ControllerDevice {
|
||||||
D,
|
D,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ControllerEvent {
|
pub enum ControllerEvent {
|
||||||
DpadUp(bool),
|
DpadUp(bool),
|
||||||
DpadDown(bool),
|
DpadDown(bool),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::Error;
|
||||||
|
|
||||||
pub const MASK_COLOUR: u32 = 0xFFFFFFFF;
|
pub const MASK_COLOUR: u32 = 0xFFFFFFFF;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
|
@ -131,7 +131,7 @@ impl FrameQueue {
|
||||||
pub fn new(width: u32, height: u32) -> Self {
|
pub fn new(width: u32, height: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
max_size: (width, height),
|
max_size: (width, height),
|
||||||
queue: ClockedQueue::new(),
|
queue: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
|
|
|
@ -106,14 +106,10 @@ impl<T: Copy> HostData<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct ClockedQueue<T>(Arc<Mutex<VecDeque<(Clock, T)>>>);
|
pub struct ClockedQueue<T>(Arc<Mutex<VecDeque<(Clock, T)>>>);
|
||||||
|
|
||||||
impl<T: Clone> ClockedQueue<T> {
|
impl<T: Clone> ClockedQueue<T> {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self(Arc::new(Mutex::new(VecDeque::new())))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&self, clock: Clock, data: T) {
|
pub fn push(&self, clock: Clock, data: T) {
|
||||||
self.0.lock().unwrap().push_back((clock, data));
|
self.0.lock().unwrap().push_back((clock, data));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,17 @@ pub struct InterruptController {
|
||||||
highest: u8,
|
highest: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InterruptController {
|
impl Default for InterruptController {
|
||||||
pub fn new() -> InterruptController {
|
fn default() -> InterruptController {
|
||||||
InterruptController {
|
InterruptController {
|
||||||
target: None,
|
target: None,
|
||||||
interrupts: vec![(false, 0); 7],
|
interrupts: vec![(false, 0); 7],
|
||||||
highest: 0,
|
highest: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptController {
|
||||||
pub fn set_target(&mut self, dev: TransmutableBox) -> Result<(), Error> {
|
pub fn set_target(&mut self, dev: TransmutableBox) -> Result<(), Error> {
|
||||||
if self.target.is_some() {
|
if self.target.is_some() {
|
||||||
return Err(Error::new("Interruptable device already set, and interrupt controller only supports one receiver"));
|
return Err(Error::new("Interruptable device already set, and interrupt controller only supports one receiver"));
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
use crate::info;
|
use crate::info;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
@ -31,9 +32,7 @@ impl MemoryBlock {
|
||||||
pub fn load_at(&mut self, addr: Address, filename: &str) -> Result<(), Error> {
|
pub fn load_at(&mut self, addr: Address, filename: &str) -> Result<(), Error> {
|
||||||
match fs::read(filename) {
|
match fs::read(filename) {
|
||||||
Ok(contents) => {
|
Ok(contents) => {
|
||||||
for i in 0..contents.len() {
|
self.contents[(addr as usize)..(addr as usize) + contents.len()].copy_from_slice(&contents);
|
||||||
self.contents[(addr as usize) + i] = contents[i];
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Err(_) => Err(Error::new(&format!("Error reading contents of {}", filename))),
|
Err(_) => Err(Error::new(&format!("Error reading contents of {}", filename))),
|
||||||
|
@ -55,9 +54,7 @@ impl Addressable for MemoryBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
||||||
for i in 0..data.len() {
|
data.copy_from_slice(&self.contents[(addr as usize)..(addr as usize) + data.len()]);
|
||||||
data[i] = self.contents[(addr as usize) + i];
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,9 +63,7 @@ impl Addressable for MemoryBlock {
|
||||||
return Err(Error::breakpoint(&format!("Attempt to write to read-only memory at {:x} with data {:?}", addr, data)));
|
return Err(Error::breakpoint(&format!("Attempt to write to read-only memory at {:x} with data {:?}", addr, data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..data.len() {
|
self.contents[(addr as usize) .. (addr as usize) + data.len()].copy_from_slice(data);
|
||||||
self.contents[(addr as usize) + i] = data[i];
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +155,7 @@ pub struct Block {
|
||||||
pub dev: TransmutableBox,
|
pub dev: TransmutableBox,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Bus {
|
pub struct Bus {
|
||||||
blocks: Vec<Block>,
|
blocks: Vec<Block>,
|
||||||
ignore_unmapped: bool,
|
ignore_unmapped: bool,
|
||||||
|
@ -169,15 +164,6 @@ pub struct Bus {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
pub fn new() -> Bus {
|
|
||||||
Bus {
|
|
||||||
ignore_unmapped: false,
|
|
||||||
blocks: vec!(),
|
|
||||||
watchers: vec!(),
|
|
||||||
watcher_modified: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_ignore_unmapped(&mut self, ignore_unmapped: bool) {
|
pub fn set_ignore_unmapped(&mut self, ignore_unmapped: bool) {
|
||||||
self.ignore_unmapped = ignore_unmapped;
|
self.ignore_unmapped = ignore_unmapped;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +190,7 @@ impl Bus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(Error::new(&format!("No segment found at {:#010x}", addr)));
|
Err(Error::new(&format!("No segment found at {:#010x}", addr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_memory(&mut self, mut addr: Address, mut count: Address) {
|
pub fn dump_memory(&mut self, mut addr: Address, mut count: Address) {
|
||||||
|
@ -218,7 +204,7 @@ impl Bus {
|
||||||
println!("{}", line);
|
println!("{}", line);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
line += &format!("{:#06x} ", word.unwrap());
|
write!(line, "{:#06x} ", word.unwrap()).unwrap();
|
||||||
addr += 2;
|
addr += 2;
|
||||||
count -= 2;
|
count -= 2;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +250,7 @@ impl Addressable for Bus {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
||||||
if let Some(_) = self.watchers.iter().position(|a| *a == addr) {
|
if self.watchers.iter().any(|a| *a == addr) {
|
||||||
println!("watch: writing to address {:#06x} with {:?}", addr, data);
|
println!("watch: writing to address {:#06x} with {:?}", addr, data);
|
||||||
self.watcher_modified = true;
|
self.watcher_modified = true;
|
||||||
}
|
}
|
||||||
|
@ -352,7 +338,7 @@ pub fn dump_slice(data: &[u8], mut count: usize) {
|
||||||
let to = if count < 16 { count / 2 } else { 8 };
|
let to = if count < 16 { count / 2 } else { 8 };
|
||||||
for _ in 0..to {
|
for _ in 0..to {
|
||||||
let word = read_beu16(&data[addr..]);
|
let word = read_beu16(&data[addr..]);
|
||||||
line += &format!("{:#06x} ", word);
|
write!(line, "{:#06x} ", word).unwrap();
|
||||||
addr += 2;
|
addr += 2;
|
||||||
count -= 2;
|
count -= 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl<'input> AssemblyParser<'input> {
|
||||||
let list = self.parse_list_of_words()?;
|
let list = self.parse_list_of_words()?;
|
||||||
AssemblyLine::Directive(name, list)
|
AssemblyLine::Directive(name, list)
|
||||||
},
|
},
|
||||||
word if word.chars().nth(0).map(|ch| is_word(ch)).unwrap_or(false) => {
|
word if word.chars().next().map(is_word).unwrap_or(false) => {
|
||||||
let next = self.lexer.peek();
|
let next = self.lexer.peek();
|
||||||
if next.is_some() && next.as_ref().unwrap() == ":" {
|
if next.is_some() && next.as_ref().unwrap() == ":" {
|
||||||
self.lexer.expect_next()?;
|
self.lexer.expect_next()?;
|
||||||
|
@ -152,7 +152,7 @@ impl<'input> AssemblyParser<'input> {
|
||||||
Ok(AssemblyOperand::Immediate(number))
|
Ok(AssemblyOperand::Immediate(number))
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
if is_digit(token.chars().nth(0).unwrap()) {
|
if is_digit(token.chars().next().unwrap()) {
|
||||||
let number = parse_any_number(self.lexer.lineno(), &token)?;
|
let number = parse_any_number(self.lexer.lineno(), &token)?;
|
||||||
Ok(AssemblyOperand::Immediate(number))
|
Ok(AssemblyOperand::Immediate(number))
|
||||||
} else {
|
} else {
|
||||||
|
@ -164,12 +164,12 @@ impl<'input> AssemblyParser<'input> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_any_number(lineno: usize, string: &str) -> Result<usize, Error> {
|
fn parse_any_number(lineno: usize, string: &str) -> Result<usize, Error> {
|
||||||
let (radix, numeric) = if string.starts_with("0x") {
|
let (radix, numeric) = if let Some(s) = string.strip_prefix("0x") {
|
||||||
(16, &string[2..])
|
(16, s)
|
||||||
} else if string.starts_with("0b") {
|
} else if let Some(s) = string.strip_prefix("0b") {
|
||||||
(2, &string[2..])
|
(2, s)
|
||||||
} else if string.starts_with("0o") {
|
} else if let Some(s) = string.strip_prefix("0o") {
|
||||||
(8, &string[2..])
|
(8, s)
|
||||||
} else {
|
} else {
|
||||||
(10, string)
|
(10, string)
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,11 +37,13 @@ impl<T: Copy> Signal<T> {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EdgeSignal(Signal<bool>);
|
pub struct EdgeSignal(Signal<bool>);
|
||||||
|
|
||||||
impl EdgeSignal {
|
impl Default for EdgeSignal {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
EdgeSignal(Signal::new(false))
|
EdgeSignal(Signal::new(false))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EdgeSignal {
|
||||||
pub fn signal(&mut self) {
|
pub fn signal(&mut self) {
|
||||||
self.0.set(true);
|
self.0.set(true);
|
||||||
}
|
}
|
||||||
|
@ -53,8 +55,10 @@ impl EdgeSignal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ObservableCallback<T> = Box<dyn Fn(&T)>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ObservableSignal<T>(Rc<RefCell<(T, Option<Box<dyn Fn(&T)>>)>>);
|
pub struct ObservableSignal<T>(Rc<RefCell<(T, Option<ObservableCallback<T>>)>>);
|
||||||
|
|
||||||
impl<T> ObservableSignal<T> {
|
impl<T> ObservableSignal<T> {
|
||||||
pub fn new(init: T) -> ObservableSignal<T> {
|
pub fn new(init: T) -> ObservableSignal<T> {
|
||||||
|
@ -84,11 +88,13 @@ impl<T> Observable<T> for ObservableSignal<T> {
|
||||||
|
|
||||||
pub struct ObservableEdgeSignal(ObservableSignal<bool>);
|
pub struct ObservableEdgeSignal(ObservableSignal<bool>);
|
||||||
|
|
||||||
impl ObservableEdgeSignal {
|
impl Default for ObservableEdgeSignal {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
ObservableEdgeSignal(ObservableSignal::new(false))
|
ObservableEdgeSignal(ObservableSignal::new(false))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObservableEdgeSignal {
|
||||||
pub fn set(&mut self) {
|
pub fn set(&mut self) {
|
||||||
*self.0.borrow_mut() = true;
|
*self.0.borrow_mut() = true;
|
||||||
self.0.notify();
|
self.0.notify();
|
||||||
|
|
|
@ -25,23 +25,25 @@ pub struct System {
|
||||||
pub break_signal: Option<EdgeSignal>,
|
pub break_signal: Option<EdgeSignal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl System {
|
impl Default for System {
|
||||||
pub fn new() -> System {
|
fn default() -> Self {
|
||||||
System {
|
Self {
|
||||||
clock: 0,
|
clock: 0,
|
||||||
devices: HashMap::new(),
|
devices: HashMap::new(),
|
||||||
event_queue: vec![],
|
event_queue: vec![],
|
||||||
|
|
||||||
debug_enabled: Cell::new(false),
|
debug_enabled: Cell::new(false),
|
||||||
debugger: RefCell::new(Debugger::new()),
|
debugger: RefCell::new(Debugger::default()),
|
||||||
|
|
||||||
bus: Rc::new(RefCell::new(Bus::new())),
|
bus: Rc::new(RefCell::new(Bus::default())),
|
||||||
interrupt_controller: RefCell::new(InterruptController::new()),
|
interrupt_controller: RefCell::new(InterruptController::default()),
|
||||||
|
|
||||||
break_signal: None,
|
break_signal: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
pub fn get_bus(&self) -> RefMut<'_, Bus> {
|
pub fn get_bus(&self) -> RefMut<'_, Bus> {
|
||||||
self.bus.borrow_mut()
|
self.bus.borrow_mut()
|
||||||
}
|
}
|
||||||
|
@ -91,7 +93,7 @@ impl System {
|
||||||
fn process_one_event(&mut self) -> Result<(), Error> {
|
fn process_one_event(&mut self) -> Result<(), Error> {
|
||||||
let mut event_device = self.event_queue.pop().unwrap();
|
let mut event_device = self.event_queue.pop().unwrap();
|
||||||
self.clock = event_device.next_clock;
|
self.clock = event_device.next_clock;
|
||||||
let result = match event_device.device.borrow_mut().as_steppable().unwrap().step(&self) {
|
let result = match event_device.device.borrow_mut().as_steppable().unwrap().step(self) {
|
||||||
Ok(diff) => {
|
Ok(diff) => {
|
||||||
event_device.next_clock = self.clock + diff;
|
event_device.next_clock = self.clock + diff;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -152,7 +154,7 @@ impl System {
|
||||||
pub fn exit_error(&mut self) {
|
pub fn exit_error(&mut self) {
|
||||||
for (_, dev) in self.devices.iter() {
|
for (_, dev) in self.devices.iter() {
|
||||||
match dev.borrow_mut().as_steppable() {
|
match dev.borrow_mut().as_steppable() {
|
||||||
Some(dev) => dev.on_error(&self),
|
Some(dev) => dev.on_error(self),
|
||||||
None => { },
|
None => { },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +164,7 @@ impl System {
|
||||||
if self.debug_enabled.get() {
|
if self.debug_enabled.get() {
|
||||||
let top = self.event_queue[self.event_queue.len() - 1].device.clone();
|
let top = self.event_queue[self.event_queue.len() - 1].device.clone();
|
||||||
if top.borrow_mut().as_debuggable().map(|debug| debug.debugging_enabled()).unwrap_or(false) {
|
if top.borrow_mut().as_debuggable().map(|debug| debug.debugging_enabled()).unwrap_or(false) {
|
||||||
if let Err(err) = self.debugger.borrow_mut().run_debugger(&self, top.clone()) {
|
if let Err(err) = self.debugger.borrow_mut().run_debugger(self, top.clone()) {
|
||||||
println!("Error: {:?}", err);
|
println!("Error: {:?}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ pub struct AverageTimer {
|
||||||
pub start: Option<Instant>,
|
pub start: Option<Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AverageTimer {
|
impl Default for AverageTimer {
|
||||||
pub fn new() -> AverageTimer {
|
fn default() -> AverageTimer {
|
||||||
AverageTimer {
|
AverageTimer {
|
||||||
high: 0,
|
high: 0,
|
||||||
average: 0.0,
|
average: 0.0,
|
||||||
|
@ -21,7 +21,9 @@ impl AverageTimer {
|
||||||
start: None,
|
start: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AverageTimer {
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
//self.start = Some(Instant::now())
|
//self.start = Some(Instant::now())
|
||||||
}
|
}
|
||||||
|
@ -47,28 +49,18 @@ impl fmt::Display for AverageTimer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct CpuTimer {
|
pub struct CpuTimer {
|
||||||
pub decode: AverageTimer,
|
pub decode: AverageTimer,
|
||||||
pub execute: AverageTimer,
|
pub execute: AverageTimer,
|
||||||
pub cycle: AverageTimer,
|
pub cycle: AverageTimer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuTimer {
|
|
||||||
pub fn new() -> CpuTimer {
|
|
||||||
CpuTimer {
|
|
||||||
decode: AverageTimer::new(),
|
|
||||||
execute: AverageTimer::new(),
|
|
||||||
cycle: AverageTimer::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for CpuTimer {
|
impl fmt::Display for CpuTimer {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "Decode: {}\n", self.decode)?;
|
writeln!(f, "Decode: {}", self.decode)?;
|
||||||
write!(f, "Execute: {}\n", self.execute)?;
|
writeln!(f, "Execute: {}", self.execute)?;
|
||||||
write!(f, "Cycle: {}\n", self.cycle)?;
|
writeln!(f, "Cycle: {}", self.cycle)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ impl M68kAssembler {
|
||||||
self.labels.insert(label.clone(), self.output.len() - 1);
|
self.labels.insert(label.clone(), self.output.len() - 1);
|
||||||
},
|
},
|
||||||
AssemblyLine::Instruction(name, list) => {
|
AssemblyLine::Instruction(name, list) => {
|
||||||
self.convert_instruction(lineno, &name, &list)?;
|
self.convert_instruction(lineno, name, list)?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -255,7 +255,7 @@ impl M68kAssembler {
|
||||||
let (effective_address_left, additional_words_left) = convert_target(lineno, &args[0], operation_size, Disallow::None)?;
|
let (effective_address_left, additional_words_left) = convert_target(lineno, &args[0], operation_size, Disallow::None)?;
|
||||||
let (effective_address_right, additional_words_right) = convert_target(lineno, &args[1], operation_size, Disallow::None)?;
|
let (effective_address_right, additional_words_right) = convert_target(lineno, &args[1], operation_size, Disallow::None)?;
|
||||||
let effective_address_left = (effective_address_left >> 3) | (effective_address_left << 3);
|
let effective_address_left = (effective_address_left >> 3) | (effective_address_left << 3);
|
||||||
self.output.push(0x0000 | encode_size_for_move(operation_size) | effective_address_left | effective_address_right);
|
self.output.push(encode_size_for_move(operation_size) | effective_address_left | effective_address_right);
|
||||||
self.output.extend(additional_words_left);
|
self.output.extend(additional_words_left);
|
||||||
self.output.extend(additional_words_right);
|
self.output.extend(additional_words_right);
|
||||||
},
|
},
|
||||||
|
@ -371,23 +371,23 @@ impl M68kAssembler {
|
||||||
};
|
};
|
||||||
|
|
||||||
match &args {
|
match &args {
|
||||||
&[AssemblyOperand::Immediate(_), AssemblyOperand::Register(_)] => {
|
[AssemblyOperand::Immediate(_), AssemblyOperand::Register(_)] => {
|
||||||
let mut immediate = parser::expect_immediate(lineno, &args[0])?;
|
let mut immediate = parser::expect_immediate(lineno, &args[0])?;
|
||||||
if immediate < 1 || immediate > 8 {
|
if !(1..=8).contains(&immediate) {
|
||||||
return Err(Error::new(&format!("error at line {}: immediate value must be between 1 and 8, found {:?}", lineno, args)));
|
return Err(Error::new(&format!("error at line {}: immediate value must be between 1 and 8, found {:?}", lineno, args)));
|
||||||
} else if immediate == 8 {
|
} else if immediate == 8 {
|
||||||
immediate = 0;
|
immediate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let reg = expect_data_register(lineno, &args[1])?;
|
let reg = expect_data_register(lineno, &args[1])?;
|
||||||
self.output.push(opcode | ((immediate as u16) << 9) | direction | encode_size(operation_size) | (0b0 << 5) | reg);
|
self.output.push(opcode | ((immediate as u16) << 9) | direction | encode_size(operation_size) /*(0b0 << 5)*/ | reg);
|
||||||
},
|
},
|
||||||
&[AssemblyOperand::Register(_), AssemblyOperand::Register(_)] => {
|
[AssemblyOperand::Register(_), AssemblyOperand::Register(_)] => {
|
||||||
let bit_reg = expect_data_register(lineno, &args[0])?;
|
let bit_reg = expect_data_register(lineno, &args[0])?;
|
||||||
let reg = expect_data_register(lineno, &args[1])?;
|
let reg = expect_data_register(lineno, &args[1])?;
|
||||||
self.output.push(opcode | ((bit_reg as u16) << 9) | direction | encode_size(operation_size) | (0b1 << 5) | reg);
|
self.output.push(opcode | ((bit_reg as u16) << 9) | direction | encode_size(operation_size) | (0b1 << 5) | reg);
|
||||||
},
|
},
|
||||||
//&[_] => {
|
//[_] => {
|
||||||
// let (effective_address, additional_words) = convert_target(lineno, &args[0], Size::Word, Disallow::NoRegsImmediateOrPC)?;
|
// let (effective_address, additional_words) = convert_target(lineno, &args[0], Size::Word, Disallow::NoRegsImmediateOrPC)?;
|
||||||
// self.output.push(opcode | effective_address);
|
// self.output.push(opcode | effective_address);
|
||||||
// self.output.extend(additional_words);
|
// self.output.extend(additional_words);
|
||||||
|
@ -414,7 +414,7 @@ fn convert_target(lineno: usize, operand: &AssemblyOperand, size: Size, disallow
|
||||||
disallow.check(lineno, Disallow::NoIndirectPost)?;
|
disallow.check(lineno, Disallow::NoIndirectPost)?;
|
||||||
if args.len() == 1 && operator == "+" {
|
if args.len() == 1 && operator == "+" {
|
||||||
if let AssemblyOperand::Register(name) = &args[0] {
|
if let AssemblyOperand::Register(name) = &args[0] {
|
||||||
if name.starts_with("a") {
|
if name.starts_with('a') {
|
||||||
let reg = expect_reg_num(lineno, name)?;
|
let reg = expect_reg_num(lineno, name)?;
|
||||||
return Ok(((0b011 << 3) | reg, vec![]));
|
return Ok(((0b011 << 3) | reg, vec![]));
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@ fn convert_target(lineno: usize, operand: &AssemblyOperand, size: Size, disallow
|
||||||
disallow.check(lineno, Disallow::NoIndirectPre)?;
|
disallow.check(lineno, Disallow::NoIndirectPre)?;
|
||||||
if args.len() == 1 && operator == "-" {
|
if args.len() == 1 && operator == "-" {
|
||||||
if let AssemblyOperand::Register(name) = &args[0] {
|
if let AssemblyOperand::Register(name) = &args[0] {
|
||||||
if name.starts_with("a") {
|
if name.starts_with('a') {
|
||||||
let reg = expect_reg_num(lineno, name)?;
|
let reg = expect_reg_num(lineno, name)?;
|
||||||
return Ok(((0b100 << 3) | reg, vec![]));
|
return Ok(((0b100 << 3) | reg, vec![]));
|
||||||
} else if name == "sp" {
|
} else if name == "sp" {
|
||||||
|
@ -442,12 +442,12 @@ fn convert_target(lineno: usize, operand: &AssemblyOperand, size: Size, disallow
|
||||||
|
|
||||||
fn convert_register(lineno: usize, name: &str, disallow: Disallow) -> Result<(u16, Vec<u16>), Error> {
|
fn convert_register(lineno: usize, name: &str, disallow: Disallow) -> Result<(u16, Vec<u16>), Error> {
|
||||||
match name {
|
match name {
|
||||||
name if name.starts_with("d") => {
|
name if name.starts_with('d') => {
|
||||||
disallow.check(lineno, Disallow::NoDReg)?;
|
disallow.check(lineno, Disallow::NoDReg)?;
|
||||||
let reg = expect_reg_num(lineno, name)?;
|
let reg = expect_reg_num(lineno, name)?;
|
||||||
Ok(((0b000 << 3) | reg, vec![]))
|
Ok((/*(0b000 << 3)*/ reg, vec![]))
|
||||||
},
|
},
|
||||||
name if name.starts_with("a") => {
|
name if name.starts_with('a') => {
|
||||||
disallow.check(lineno, Disallow::NoAReg)?;
|
disallow.check(lineno, Disallow::NoAReg)?;
|
||||||
let reg = expect_reg_num(lineno, name)?;
|
let reg = expect_reg_num(lineno, name)?;
|
||||||
Ok(((0b001 << 3) | reg, vec![]))
|
Ok(((0b001 << 3) | reg, vec![]))
|
||||||
|
@ -462,12 +462,12 @@ fn convert_register(lineno: usize, name: &str, disallow: Disallow) -> Result<(u1
|
||||||
|
|
||||||
fn convert_indirect(lineno: usize, args: &[AssemblyOperand], disallow: Disallow) -> Result<(u16, Vec<u16>), Error> {
|
fn convert_indirect(lineno: usize, args: &[AssemblyOperand], disallow: Disallow) -> Result<(u16, Vec<u16>), Error> {
|
||||||
match &args {
|
match &args {
|
||||||
&[AssemblyOperand::Register(name)] => {
|
[AssemblyOperand::Register(name)] => {
|
||||||
disallow.check(lineno, Disallow::NoIndirect)?;
|
disallow.check(lineno, Disallow::NoIndirect)?;
|
||||||
let reg = expect_address_reg_num(lineno, name)?;
|
let reg = expect_address_reg_num(lineno, name)?;
|
||||||
Ok(((0b010 << 3) | reg, vec![]))
|
Ok(((0b010 << 3) | reg, vec![]))
|
||||||
},
|
},
|
||||||
&[AssemblyOperand::Immediate(address)] => {
|
[AssemblyOperand::Immediate(address)] => {
|
||||||
disallow.check(lineno, Disallow::NoIndirectImmediate)?;
|
disallow.check(lineno, Disallow::NoIndirectImmediate)?;
|
||||||
if *address < u16::MAX as usize {
|
if *address < u16::MAX as usize {
|
||||||
Ok((0b111000, convert_immediate(lineno, *address, Size::Word)?))
|
Ok((0b111000, convert_immediate(lineno, *address, Size::Word)?))
|
||||||
|
@ -475,7 +475,7 @@ fn convert_indirect(lineno: usize, args: &[AssemblyOperand], disallow: Disallow)
|
||||||
Ok((0b111001, convert_immediate(lineno, *address, Size::Long)?))
|
Ok((0b111001, convert_immediate(lineno, *address, Size::Long)?))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&[AssemblyOperand::Immediate(offset), AssemblyOperand::Register(name)] => {
|
[AssemblyOperand::Immediate(offset), AssemblyOperand::Register(name)] => {
|
||||||
if name == "pc" {
|
if name == "pc" {
|
||||||
disallow.check(lineno, Disallow::NoPCRelative)?;
|
disallow.check(lineno, Disallow::NoPCRelative)?;
|
||||||
Ok((0b111010, convert_immediate(lineno, *offset, Size::Word)?))
|
Ok((0b111010, convert_immediate(lineno, *offset, Size::Word)?))
|
||||||
|
@ -485,9 +485,9 @@ fn convert_indirect(lineno: usize, args: &[AssemblyOperand], disallow: Disallow)
|
||||||
Ok(((0b101 << 3) | reg, convert_immediate(lineno, *offset, Size::Word)?))
|
Ok(((0b101 << 3) | reg, convert_immediate(lineno, *offset, Size::Word)?))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&[AssemblyOperand::Immediate(offset), AssemblyOperand::Register(name), AssemblyOperand::Register(index)] => {
|
[AssemblyOperand::Immediate(offset), AssemblyOperand::Register(name), AssemblyOperand::Register(index)] => {
|
||||||
let index_reg = expect_reg_num(lineno, index)?;
|
let index_reg = expect_reg_num(lineno, index)?;
|
||||||
let da_select = if index.starts_with("a") { 1 << 15 } else { 0 };
|
let da_select = if index.starts_with('a') { 1 << 15 } else { 0 };
|
||||||
if name == "pc" {
|
if name == "pc" {
|
||||||
disallow.check(lineno, Disallow::NoPCRelativeIndex)?;
|
disallow.check(lineno, Disallow::NoPCRelativeIndex)?;
|
||||||
Ok((0b111011, vec![da_select | (index_reg << 12) | ((*offset as u16) & 0xff)]))
|
Ok((0b111011, vec![da_select | (index_reg << 12) | ((*offset as u16) & 0xff)]))
|
||||||
|
@ -504,13 +504,13 @@ fn convert_indirect(lineno: usize, args: &[AssemblyOperand], disallow: Disallow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_reg_and_other<'a>(lineno: usize, args: &'a [AssemblyOperand], _disallow: Disallow) -> Result<(u16, u16, &'a AssemblyOperand), Error> {
|
fn convert_reg_and_other(lineno: usize, args: &[AssemblyOperand], _disallow: Disallow) -> Result<(u16, u16, &AssemblyOperand), Error> {
|
||||||
match &args {
|
match &args {
|
||||||
&[AssemblyOperand::Register(reg), effective_address] => {
|
[AssemblyOperand::Register(reg), effective_address] => {
|
||||||
Ok(((0b1 << 8), expect_reg_num(lineno, ®)?, effective_address))
|
Ok(((0b1 << 8), expect_reg_num(lineno, reg)?, effective_address))
|
||||||
},
|
},
|
||||||
&[effective_address, AssemblyOperand::Register(reg)] => {
|
[effective_address, AssemblyOperand::Register(reg)] => {
|
||||||
Ok(((0b0 << 8), expect_reg_num(lineno, ®)?, effective_address))
|
Ok(((0b0 << 8), expect_reg_num(lineno, reg)?, effective_address))
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
Err(Error::new(&format!("error at line {}: expected register and effective address, but found {:?}", lineno, args)))
|
Err(Error::new(&format!("error at line {}: expected register and effective address, but found {:?}", lineno, args)))
|
||||||
|
@ -540,7 +540,7 @@ fn convert_immediate(lineno: usize, value: usize, size: Size) -> Result<Vec<u16>
|
||||||
|
|
||||||
fn expect_data_register(lineno: usize, operand: &AssemblyOperand) -> Result<u16, Error> {
|
fn expect_data_register(lineno: usize, operand: &AssemblyOperand) -> Result<u16, Error> {
|
||||||
if let AssemblyOperand::Register(name) = operand {
|
if let AssemblyOperand::Register(name) = operand {
|
||||||
if name.starts_with("d") {
|
if name.starts_with('d') {
|
||||||
return expect_reg_num(lineno, name);
|
return expect_reg_num(lineno, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -549,7 +549,7 @@ fn expect_data_register(lineno: usize, operand: &AssemblyOperand) -> Result<u16,
|
||||||
|
|
||||||
fn expect_address_register(lineno: usize, operand: &AssemblyOperand) -> Result<u16, Error> {
|
fn expect_address_register(lineno: usize, operand: &AssemblyOperand) -> Result<u16, Error> {
|
||||||
if let AssemblyOperand::Register(name) = operand {
|
if let AssemblyOperand::Register(name) = operand {
|
||||||
if name.starts_with("d") {
|
if name.starts_with('d') {
|
||||||
return expect_reg_num(lineno, name);
|
return expect_reg_num(lineno, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,7 +557,7 @@ fn expect_address_register(lineno: usize, operand: &AssemblyOperand) -> Result<u
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_address_reg_num(lineno: usize, name: &str) -> Result<u16, Error> {
|
fn expect_address_reg_num(lineno: usize, name: &str) -> Result<u16, Error> {
|
||||||
if name.starts_with("a") {
|
if name.starts_with('a') {
|
||||||
return expect_reg_num(lineno, name);
|
return expect_reg_num(lineno, name);
|
||||||
}
|
}
|
||||||
Err(Error::new(&format!("error at line {}: expected an address register, but found {:?}", lineno, name)))
|
Err(Error::new(&format!("error at line {}: expected an address register, but found {:?}", lineno, name)))
|
||||||
|
|
|
@ -4,18 +4,12 @@ use moa_core::{System, Error, Address, Addressable, Debuggable};
|
||||||
use super::state::M68k;
|
use super::state::M68k;
|
||||||
use super::decode::M68kDecoder;
|
use super::decode::M68kDecoder;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct StackTracer {
|
pub struct StackTracer {
|
||||||
pub calls: Vec<u32>,
|
pub calls: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackTracer {
|
impl StackTracer {
|
||||||
pub fn new() -> StackTracer {
|
|
||||||
StackTracer {
|
|
||||||
calls: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_return(&mut self, addr: u32) {
|
pub fn push_return(&mut self, addr: u32) {
|
||||||
self.calls.push(addr);
|
self.calls.push(addr);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +20,7 @@ impl StackTracer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct M68kDebugger {
|
pub struct M68kDebugger {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub breakpoints: Vec<u32>,
|
pub breakpoints: Vec<u32>,
|
||||||
|
@ -35,18 +29,6 @@ pub struct M68kDebugger {
|
||||||
pub stack_tracer: StackTracer,
|
pub stack_tracer: StackTracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl M68kDebugger {
|
|
||||||
pub fn new() -> M68kDebugger {
|
|
||||||
M68kDebugger {
|
|
||||||
enabled: false,
|
|
||||||
breakpoints: vec!(),
|
|
||||||
use_tracing: false,
|
|
||||||
step_until_return: None,
|
|
||||||
stack_tracer: StackTracer::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debuggable for M68k {
|
impl Debuggable for M68k {
|
||||||
fn debugging_enabled(&mut self) -> bool {
|
fn debugging_enabled(&mut self) -> bool {
|
||||||
self.debugger.enabled
|
self.debugger.enabled
|
||||||
|
|
|
@ -50,7 +50,7 @@ impl M68kDecoder {
|
||||||
pub fn new(cputype: M68kType, start: u32) -> M68kDecoder {
|
pub fn new(cputype: M68kType, start: u32) -> M68kDecoder {
|
||||||
M68kDecoder {
|
M68kDecoder {
|
||||||
cputype,
|
cputype,
|
||||||
start: start,
|
start,
|
||||||
end: start,
|
end: start,
|
||||||
instruction_word: 0,
|
instruction_word: 0,
|
||||||
instruction: Instruction::NOP,
|
instruction: Instruction::NOP,
|
||||||
|
@ -85,7 +85,7 @@ impl M68kDecoder {
|
||||||
0b0000 => Ok(Instruction::ORtoCCR(data as u8)),
|
0b0000 => Ok(Instruction::ORtoCCR(data as u8)),
|
||||||
0b0010 => Ok(Instruction::ANDtoCCR(data as u8)),
|
0b0010 => Ok(Instruction::ANDtoCCR(data as u8)),
|
||||||
0b1010 => Ok(Instruction::EORtoCCR(data as u8)),
|
0b1010 => Ok(Instruction::EORtoCCR(data as u8)),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
0b01 => {
|
0b01 => {
|
||||||
|
@ -94,10 +94,10 @@ impl M68kDecoder {
|
||||||
0b0000 => Ok(Instruction::ORtoSR(data)),
|
0b0000 => Ok(Instruction::ORtoSR(data)),
|
||||||
0b0010 => Ok(Instruction::ANDtoSR(data)),
|
0b0010 => Ok(Instruction::ANDtoSR(data)),
|
||||||
0b1010 => Ok(Instruction::EORtoSR(data)),
|
0b1010 => Ok(Instruction::EORtoSR(data)),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
} else if (ins & 0x138) == 0x108 {
|
} else if (ins & 0x138) == 0x108 {
|
||||||
let dreg = get_high_reg(ins);
|
let dreg = get_high_reg(ins);
|
||||||
|
@ -124,7 +124,7 @@ impl M68kDecoder {
|
||||||
0b01 => Ok(Instruction::BCHG(bitnum, target, size)),
|
0b01 => Ok(Instruction::BCHG(bitnum, target, size)),
|
||||||
0b10 => Ok(Instruction::BCLR(bitnum, target, size)),
|
0b10 => Ok(Instruction::BCLR(bitnum, target, size)),
|
||||||
0b11 => Ok(Instruction::BSET(bitnum, target, size)),
|
0b11 => Ok(Instruction::BSET(bitnum, target, size)),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
|
@ -143,7 +143,7 @@ impl M68kDecoder {
|
||||||
0b0110 => Ok(Instruction::ADD(Target::Immediate(data), target, size.unwrap())),
|
0b0110 => Ok(Instruction::ADD(Target::Immediate(data), target, size.unwrap())),
|
||||||
0b1010 => Ok(Instruction::EOR(Target::Immediate(data), target, size.unwrap())),
|
0b1010 => Ok(Instruction::EOR(Target::Immediate(data), target, size.unwrap())),
|
||||||
0b1100 => Ok(Instruction::CMP(Target::Immediate(data), target, size.unwrap())),
|
0b1100 => Ok(Instruction::CMP(Target::Immediate(data), target, size.unwrap())),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -221,7 +221,7 @@ impl M68kDecoder {
|
||||||
match get_size(ins) {
|
match get_size(ins) {
|
||||||
Some(size) => Ok(Instruction::CLR(target, size)),
|
Some(size) => Ok(Instruction::CLR(target, size)),
|
||||||
None if self.cputype >= M68kType::MC68010 => Ok(Instruction::MOVEfromCCR(target)),
|
None if self.cputype >= M68kType::MC68010 => Ok(Instruction::MOVEfromCCR(target)),
|
||||||
None => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
None => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
0b100 => {
|
0b100 => {
|
||||||
|
@ -236,7 +236,7 @@ impl M68kDecoder {
|
||||||
None => Ok(Instruction::MOVEtoSR(target)),
|
None => Ok(Instruction::MOVEtoSR(target)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
} else if ins_0f00 == 0x800 || ins_0f00 == 0x900 {
|
} else if ins_0f00 == 0x800 || ins_0f00 == 0x900 {
|
||||||
let opmode = (ins & 0x01C0) >> 6;
|
let opmode = (ins & 0x01C0) >> 6;
|
||||||
|
@ -269,7 +269,7 @@ impl M68kDecoder {
|
||||||
(0b111, 0b000) => {
|
(0b111, 0b000) => {
|
||||||
Ok(Instruction::EXT(get_low_reg(ins), Size::Byte, Size::Long))
|
Ok(Instruction::EXT(get_low_reg(ins), Size::Byte, Size::Long))
|
||||||
},
|
},
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
} else if ins_0f00 == 0xA00 {
|
} else if ins_0f00 == 0xA00 {
|
||||||
if (ins & 0x0FF) == 0xFC {
|
if (ins & 0x0FF) == 0xFC {
|
||||||
|
@ -332,11 +332,11 @@ impl M68kDecoder {
|
||||||
};
|
};
|
||||||
Ok(Instruction::MOVEC(target, creg, dir))
|
Ok(Instruction::MOVEC(target, creg, dir))
|
||||||
},
|
},
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::processor(Exceptions::IllegalInstruction as u32));
|
Err(Error::processor(Exceptions::IllegalInstruction as u32))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OPCG_ADDQ_SUBQ => {
|
OPCG_ADDQ_SUBQ => {
|
||||||
|
@ -354,13 +354,11 @@ impl M68kDecoder {
|
||||||
} else {
|
} else {
|
||||||
Ok(Instruction::SUBA(Target::Immediate(data), reg, size))
|
Ok(Instruction::SUBA(Target::Immediate(data), reg, size))
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ins & 0x0100) == 0 {
|
||||||
if (ins & 0x0100) == 0 {
|
|
||||||
Ok(Instruction::ADD(Target::Immediate(data), target, size))
|
Ok(Instruction::ADD(Target::Immediate(data), target, size))
|
||||||
} else {
|
} else {
|
||||||
Ok(Instruction::SUB(Target::Immediate(data), target, size))
|
Ok(Instruction::SUB(Target::Immediate(data), target, size))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let mode = get_low_mode(ins);
|
let mode = get_low_mode(ins);
|
||||||
|
@ -402,11 +400,7 @@ impl M68kDecoder {
|
||||||
OPCG_DIV_OR => {
|
OPCG_DIV_OR => {
|
||||||
let size = get_size(ins);
|
let size = get_size(ins);
|
||||||
|
|
||||||
if size.is_none() {
|
if (ins & 0x1F0) == 0x100 {
|
||||||
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
|
||||||
Ok(Instruction::DIVW(effective_addr, get_high_reg(ins), sign))
|
|
||||||
} else if (ins & 0x1F0) == 0x100 {
|
|
||||||
let regx = get_high_reg(ins);
|
let regx = get_high_reg(ins);
|
||||||
let regy = get_low_reg(ins);
|
let regy = get_low_reg(ins);
|
||||||
|
|
||||||
|
@ -414,11 +408,15 @@ impl M68kDecoder {
|
||||||
false => Ok(Instruction::SBCD(Target::DirectDReg(regy), Target::DirectDReg(regx))),
|
false => Ok(Instruction::SBCD(Target::DirectDReg(regy), Target::DirectDReg(regx))),
|
||||||
true => Ok(Instruction::SBCD(Target::IndirectARegDec(regy), Target::IndirectARegDec(regx))),
|
true => Ok(Instruction::SBCD(Target::IndirectARegDec(regy), Target::IndirectARegDec(regx))),
|
||||||
}
|
}
|
||||||
} else {
|
} else if let Some(size) = size {
|
||||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, size)?;
|
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
||||||
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
||||||
Ok(Instruction::OR(from, to, size.unwrap()))
|
Ok(Instruction::OR(from, to, size))
|
||||||
|
} else {
|
||||||
|
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
||||||
|
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
||||||
|
Ok(Instruction::DIVW(effective_addr, get_high_reg(ins), sign))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OPCG_SUB => {
|
OPCG_SUB => {
|
||||||
|
@ -472,7 +470,7 @@ impl M68kDecoder {
|
||||||
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
let target = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
||||||
Ok(Instruction::CMPA(target, reg, size))
|
Ok(Instruction::CMPA(target, reg, size))
|
||||||
},
|
},
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OPCG_MUL_AND => {
|
OPCG_MUL_AND => {
|
||||||
|
@ -486,24 +484,24 @@ impl M68kDecoder {
|
||||||
false => Ok(Instruction::ABCD(Target::DirectDReg(regy), Target::DirectDReg(regx))),
|
false => Ok(Instruction::ABCD(Target::DirectDReg(regy), Target::DirectDReg(regx))),
|
||||||
true => Ok(Instruction::ABCD(Target::IndirectARegDec(regy), Target::IndirectARegDec(regx))),
|
true => Ok(Instruction::ABCD(Target::IndirectARegDec(regy), Target::IndirectARegDec(regx))),
|
||||||
}
|
}
|
||||||
} else if (ins & 0b0001_0011_0000) == 0b0001_0000_0000 && !size.is_none() {
|
} else if (ins & 0b0001_0011_0000) == 0b0001_0000_0000 && size.is_some() {
|
||||||
let regx = get_high_reg(ins);
|
let regx = get_high_reg(ins);
|
||||||
let regy = get_low_reg(ins);
|
let regy = get_low_reg(ins);
|
||||||
match (ins & 0x00F8) >> 3 {
|
match (ins & 0x00F8) >> 3 {
|
||||||
0b01000 => Ok(Instruction::EXG(Target::DirectDReg(regx), Target::DirectDReg(regy))),
|
0b01000 => Ok(Instruction::EXG(Target::DirectDReg(regx), Target::DirectDReg(regy))),
|
||||||
0b01001 => Ok(Instruction::EXG(Target::DirectAReg(regx), Target::DirectAReg(regy))),
|
0b01001 => Ok(Instruction::EXG(Target::DirectAReg(regx), Target::DirectAReg(regy))),
|
||||||
0b10001 => Ok(Instruction::EXG(Target::DirectDReg(regx), Target::DirectAReg(regy))),
|
0b10001 => Ok(Instruction::EXG(Target::DirectDReg(regx), Target::DirectAReg(regy))),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
} else if size.is_none() {
|
} else if let Some(size) = size {
|
||||||
|
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
||||||
|
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(size))?;
|
||||||
|
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
||||||
|
Ok(Instruction::AND(from, to, size))
|
||||||
|
} else {
|
||||||
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
let sign = if (ins & 0x0100) == 0 { Sign::Unsigned } else { Sign::Signed };
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
let effective_addr = self.decode_lower_effective_address(memory, ins, Some(Size::Word))?;
|
||||||
Ok(Instruction::MULW(effective_addr, get_high_reg(ins), sign))
|
Ok(Instruction::MULW(effective_addr, get_high_reg(ins), sign))
|
||||||
} else {
|
|
||||||
let data_reg = Target::DirectDReg(get_high_reg(ins));
|
|
||||||
let effective_addr = self.decode_lower_effective_address(memory, ins, size)?;
|
|
||||||
let (from, to) = if (ins & 0x0100) == 0 { (effective_addr, data_reg) } else { (data_reg, effective_addr) };
|
|
||||||
Ok(Instruction::AND(from, to, size.unwrap()))
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OPCG_ADD => {
|
OPCG_ADD => {
|
||||||
|
@ -552,7 +550,7 @@ impl M68kDecoder {
|
||||||
0b01 => Ok(Instruction::LSd(count, Target::DirectDReg(reg), size, dir)),
|
0b01 => Ok(Instruction::LSd(count, Target::DirectDReg(reg), size, dir)),
|
||||||
0b10 => Ok(Instruction::ROXd(count, Target::DirectDReg(reg), size, dir)),
|
0b10 => Ok(Instruction::ROXd(count, Target::DirectDReg(reg), size, dir)),
|
||||||
0b11 => Ok(Instruction::ROd(count, Target::DirectDReg(reg), size, dir)),
|
0b11 => Ok(Instruction::ROd(count, Target::DirectDReg(reg), size, dir)),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -564,7 +562,7 @@ impl M68kDecoder {
|
||||||
0b01 => Ok(Instruction::LSd(count, target, Size::Word, dir)),
|
0b01 => Ok(Instruction::LSd(count, target, Size::Word, dir)),
|
||||||
0b10 => Ok(Instruction::ROXd(count, target, Size::Word, dir)),
|
0b10 => Ok(Instruction::ROXd(count, target, Size::Word, dir)),
|
||||||
0b11 => Ok(Instruction::ROd(count, target, Size::Word, dir)),
|
0b11 => Ok(Instruction::ROd(count, target, Size::Word, dir)),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
} else if self.cputype > M68kType::MC68020 {
|
} else if self.cputype > M68kType::MC68020 {
|
||||||
// Bitfield instructions (MC68020+)
|
// Bitfield instructions (MC68020+)
|
||||||
|
@ -591,10 +589,10 @@ impl M68kDecoder {
|
||||||
0b111 => Ok(Instruction::BFINS(reg, target, offset, width)),
|
0b111 => Ok(Instruction::BFINS(reg, target, offset, width)),
|
||||||
0b110 => Ok(Instruction::BFSET(target, offset, width)),
|
0b110 => Ok(Instruction::BFSET(target, offset, width)),
|
||||||
0b000 => Ok(Instruction::BFTST(target, offset, width)),
|
0b000 => Ok(Instruction::BFTST(target, offset, width)),
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::processor(Exceptions::IllegalInstruction as u32));
|
Err(Error::processor(Exceptions::IllegalInstruction as u32))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -605,7 +603,7 @@ impl M68kDecoder {
|
||||||
OPCG_FLINE => {
|
OPCG_FLINE => {
|
||||||
Ok(Instruction::UnimplementedF(ins))
|
Ok(Instruction::UnimplementedF(ins))
|
||||||
},
|
},
|
||||||
_ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
_ => Err(Error::processor(Exceptions::IllegalInstruction as u32)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::instructions::{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "m68k-cpu";
|
const DEV_NAME: &str = "m68k-cpu";
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum Used {
|
pub enum Used {
|
||||||
|
@ -358,14 +358,14 @@ impl M68k {
|
||||||
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
||||||
let mut src_val = self.get_target_value(target, size, Used::Twice)?;
|
let mut src_val = self.get_target_value(target, size, Used::Twice)?;
|
||||||
let mask = self.set_bit_test_flags(src_val, bitnum, size);
|
let mask = self.set_bit_test_flags(src_val, bitnum, size);
|
||||||
src_val = src_val & !mask;
|
src_val &= !mask;
|
||||||
self.set_target_value(target, src_val, size, Used::Twice)?;
|
self.set_target_value(target, src_val, size, Used::Twice)?;
|
||||||
},
|
},
|
||||||
Instruction::BSET(bitnum, target, size) => {
|
Instruction::BSET(bitnum, target, size) => {
|
||||||
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?;
|
||||||
let mut value = self.get_target_value(target, size, Used::Twice)?;
|
let mut value = self.get_target_value(target, size, Used::Twice)?;
|
||||||
let mask = self.set_bit_test_flags(value, bitnum, size);
|
let mask = self.set_bit_test_flags(value, bitnum, size);
|
||||||
value = value | mask;
|
value |= mask;
|
||||||
self.set_target_value(target, value, size, Used::Twice)?;
|
self.set_target_value(target, value, size, Used::Twice)?;
|
||||||
},
|
},
|
||||||
Instruction::BTST(bitnum, target, size) => {
|
Instruction::BTST(bitnum, target, size) => {
|
||||||
|
@ -1562,7 +1562,7 @@ fn rotate_operation(value: u32, size: Size, dir: ShiftDirection, use_extend: Opt
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ShiftDirection::Right => {
|
ShiftDirection::Right => {
|
||||||
let bit = if (value & 0x01) != 0 { true } else { false };
|
let bit = (value & 0x01) != 0;
|
||||||
let mask = if use_extend.unwrap_or(bit) { get_msb_mask(0xffffffff, size) } else { 0x0 };
|
let mask = if use_extend.unwrap_or(bit) { get_msb_mask(0xffffffff, size) } else { 0x0 };
|
||||||
((value >> 1) | mask, bit)
|
((value >> 1) | mask, bit)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,66 +1,66 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
|
|
||||||
pub type Register = u8;
|
pub type Register = u8;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Size {
|
pub enum Size {
|
||||||
Byte,
|
Byte,
|
||||||
Word,
|
Word,
|
||||||
Long,
|
Long,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Sign {
|
pub enum Sign {
|
||||||
Signed,
|
Signed,
|
||||||
Unsigned,
|
Unsigned,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
FromTarget,
|
FromTarget,
|
||||||
ToTarget,
|
ToTarget,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ShiftDirection {
|
pub enum ShiftDirection {
|
||||||
Right,
|
Right,
|
||||||
Left,
|
Left,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum XRegister {
|
pub enum XRegister {
|
||||||
DReg(u8),
|
DReg(u8),
|
||||||
AReg(u8),
|
AReg(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum BaseRegister {
|
pub enum BaseRegister {
|
||||||
None,
|
None,
|
||||||
PC,
|
PC,
|
||||||
AReg(u8),
|
AReg(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct IndexRegister {
|
pub struct IndexRegister {
|
||||||
pub xreg: XRegister,
|
pub xreg: XRegister,
|
||||||
pub scale: u8,
|
pub scale: u8,
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum RegOrImmediate {
|
pub enum RegOrImmediate {
|
||||||
DReg(u8),
|
DReg(u8),
|
||||||
Immediate(u8),
|
Immediate(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ControlRegister {
|
pub enum ControlRegister {
|
||||||
VBR,
|
VBR,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Condition {
|
pub enum Condition {
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
|
@ -80,7 +80,7 @@ pub enum Condition {
|
||||||
LessThanOrEqual,
|
LessThanOrEqual,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
Immediate(u32),
|
Immediate(u32),
|
||||||
DirectDReg(Register),
|
DirectDReg(Register),
|
||||||
|
@ -94,7 +94,7 @@ pub enum Target {
|
||||||
IndirectMemory(u32, Size),
|
IndirectMemory(u32, Size),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
ABCD(Target, Target),
|
ABCD(Target, Target),
|
||||||
ADD(Target, Target, Size),
|
ADD(Target, Target, Size),
|
||||||
|
@ -318,7 +318,7 @@ fn fmt_index_disp(index: &Option<IndexRegister>) -> String {
|
||||||
Some(index) => {
|
Some(index) => {
|
||||||
let mut result = format!(", %{}", index.xreg);
|
let mut result = format!(", %{}", index.xreg);
|
||||||
if index.scale != 0 {
|
if index.scale != 0 {
|
||||||
result += &format!("<< {}", index.scale);
|
write!(result, "<< {}", index.scale).unwrap();
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
},
|
},
|
||||||
|
@ -433,7 +433,7 @@ impl fmt::Display for Instruction {
|
||||||
Instruction::DBcc(cond, reg, offset) => write!(f, "db{}\t%d{}, {}", cond, reg, offset),
|
Instruction::DBcc(cond, reg, offset) => write!(f, "db{}\t%d{}, {}", cond, reg, offset),
|
||||||
Instruction::DIVW(src, dest, sign) => write!(f, "div{}w\t{}, %d{}", sign, src, dest),
|
Instruction::DIVW(src, dest, sign) => write!(f, "div{}w\t{}, %d{}", sign, src, dest),
|
||||||
Instruction::DIVL(src, desth, destl, sign) => {
|
Instruction::DIVL(src, desth, destl, sign) => {
|
||||||
let opt_reg = desth.map(|reg| format!("%d{}:", reg)).unwrap_or("".to_string());
|
let opt_reg = desth.map(|reg| format!("%d{}:", reg)).unwrap_or_else(|| "".to_string());
|
||||||
write!(f, "div{}l\t{}, {}%d{}", sign, src, opt_reg, destl)
|
write!(f, "div{}l\t{}, {}%d{}", sign, src, opt_reg, destl)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ impl fmt::Display for Instruction {
|
||||||
},
|
},
|
||||||
Instruction::MULW(src, dest, sign) => write!(f, "mul{}w\t{}, %d{}", sign, src, dest),
|
Instruction::MULW(src, dest, sign) => write!(f, "mul{}w\t{}, %d{}", sign, src, dest),
|
||||||
Instruction::MULL(src, desth, destl, sign) => {
|
Instruction::MULL(src, desth, destl, sign) => {
|
||||||
let opt_reg = desth.map(|reg| format!("%d{}:", reg)).unwrap_or("".to_string());
|
let opt_reg = desth.map(|reg| format!("%d{}:", reg)).unwrap_or_else(|| "".to_string());
|
||||||
write!(f, "mul{}l\t{}, {}%d{}", sign, src, opt_reg, destl)
|
write!(f, "mul{}l\t{}, {}%d{}", sign, src, opt_reg, destl)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ const FLAGS_ON_RESET: u16 = 0x2700;
|
||||||
|
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Flags {
|
pub enum Flags {
|
||||||
Carry = 0x0001,
|
Carry = 0x0001,
|
||||||
Overflow = 0x0002,
|
Overflow = 0x0002,
|
||||||
|
@ -36,7 +36,7 @@ pub enum Flags {
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Exceptions {
|
pub enum Exceptions {
|
||||||
BusError = 2,
|
BusError = 2,
|
||||||
AddressError = 3,
|
AddressError = 3,
|
||||||
|
@ -52,7 +52,7 @@ pub enum Exceptions {
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum FunctionCode {
|
pub enum FunctionCode {
|
||||||
Reserved0 = 0,
|
Reserved0 = 0,
|
||||||
UserData = 1,
|
UserData = 1,
|
||||||
|
@ -64,7 +64,7 @@ pub enum FunctionCode {
|
||||||
CpuSpace = 7,
|
CpuSpace = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Init,
|
Init,
|
||||||
Running,
|
Running,
|
||||||
|
@ -72,7 +72,7 @@ pub enum Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum InterruptPriority {
|
pub enum InterruptPriority {
|
||||||
NoInterrupt = 0,
|
NoInterrupt = 0,
|
||||||
Level1 = 1,
|
Level1 = 1,
|
||||||
|
@ -84,19 +84,19 @@ pub enum InterruptPriority {
|
||||||
Level7 = 7,
|
Level7 = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum MemType {
|
pub enum MemType {
|
||||||
Program,
|
Program,
|
||||||
Data,
|
Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum MemAccess {
|
pub enum MemAccess {
|
||||||
Read,
|
Read,
|
||||||
Write,
|
Write,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct MemoryRequest {
|
pub struct MemoryRequest {
|
||||||
pub i_n_bit: bool,
|
pub i_n_bit: bool,
|
||||||
pub access: MemAccess,
|
pub access: MemAccess,
|
||||||
|
@ -105,7 +105,7 @@ pub struct MemoryRequest {
|
||||||
pub address: u32,
|
pub address: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct M68kState {
|
pub struct M68kState {
|
||||||
pub status: Status,
|
pub status: Status,
|
||||||
pub request: MemoryRequest,
|
pub request: MemoryRequest,
|
||||||
|
@ -134,11 +134,11 @@ pub struct M68k {
|
||||||
pub timer: CpuTimer,
|
pub timer: CpuTimer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl M68kState {
|
impl Default for M68kState {
|
||||||
pub fn new() -> M68kState {
|
fn default() -> M68kState {
|
||||||
M68kState {
|
M68kState {
|
||||||
status: Status::Init,
|
status: Status::Init,
|
||||||
request: MemoryRequest::new(),
|
request: MemoryRequest::default(),
|
||||||
current_ipl: InterruptPriority::NoInterrupt,
|
current_ipl: InterruptPriority::NoInterrupt,
|
||||||
pending_ipl: InterruptPriority::NoInterrupt,
|
pending_ipl: InterruptPriority::NoInterrupt,
|
||||||
|
|
||||||
|
@ -159,21 +159,21 @@ impl M68k {
|
||||||
M68k {
|
M68k {
|
||||||
cputype,
|
cputype,
|
||||||
frequency,
|
frequency,
|
||||||
state: M68kState::new(),
|
state: M68kState::default(),
|
||||||
decoder: M68kDecoder::new(cputype, 0),
|
decoder: M68kDecoder::new(cputype, 0),
|
||||||
timing: M68kInstructionTiming::new(cputype, port.data_width()),
|
timing: M68kInstructionTiming::new(cputype, port.data_width()),
|
||||||
debugger: M68kDebugger::new(),
|
debugger: M68kDebugger::default(),
|
||||||
port: port,
|
port,
|
||||||
timer: CpuTimer::new(),
|
timer: CpuTimer::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.state = M68kState::new();
|
self.state = M68kState::default();
|
||||||
self.decoder = M68kDecoder::new(self.cputype, 0);
|
self.decoder = M68kDecoder::new(self.cputype, 0);
|
||||||
self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
|
self.timing = M68kInstructionTiming::new(self.cputype, self.port.data_width());
|
||||||
self.debugger = M68kDebugger::new();
|
self.debugger = M68kDebugger::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_state(&mut self) {
|
pub fn dump_state(&mut self) {
|
||||||
|
@ -187,9 +187,9 @@ impl M68k {
|
||||||
println!(" SSP: {:#010x}", self.state.ssp);
|
println!(" SSP: {:#010x}", self.state.ssp);
|
||||||
|
|
||||||
println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
|
println!("Current Instruction: {:#010x} {:?}", self.decoder.start, self.decoder.instruction);
|
||||||
println!("");
|
println!();
|
||||||
self.port.dump_memory(self.state.ssp as Address, 0x40);
|
self.port.dump_memory(self.state.ssp as Address, 0x40);
|
||||||
println!("");
|
println!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,8 +226,8 @@ impl FunctionCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryRequest {
|
impl Default for MemoryRequest {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
i_n_bit: false,
|
i_n_bit: false,
|
||||||
access: MemAccess::Read,
|
access: MemAccess::Read,
|
||||||
|
@ -236,7 +236,9 @@ impl MemoryRequest {
|
||||||
address: 0,
|
address: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryRequest {
|
||||||
pub fn get_type_code(&self) -> u16 {
|
pub fn get_type_code(&self) -> u16 {
|
||||||
let ins = match self.i_n_bit {
|
let ins = match self.i_n_bit {
|
||||||
false => 0x0000,
|
false => 0x0000,
|
||||||
|
|
|
@ -143,7 +143,7 @@ mod decode_tests {
|
||||||
print!("FAILED");
|
print!("FAILED");
|
||||||
print!("\nleft: {:?}, right: {:?}", data, case.data);
|
print!("\nleft: {:?}, right: {:?}", data, case.data);
|
||||||
}
|
}
|
||||||
println!("");
|
println!();
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("FAILED\n{:?}", err);
|
println!("FAILED\n{:?}", err);
|
||||||
|
@ -181,7 +181,7 @@ mod decode_tests {
|
||||||
print!("FAILED");
|
print!("FAILED");
|
||||||
print!("\nleft: {:#06x}, right: {:#06x}", data[0], case.data[0]);
|
print!("\nleft: {:#06x}, right: {:#06x}", data[0], case.data[0]);
|
||||||
}
|
}
|
||||||
println!("");
|
println!();
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("FAILED\n{:?}", err);
|
println!("FAILED\n{:?}", err);
|
||||||
|
@ -619,7 +619,7 @@ mod execute_tests {
|
||||||
print!("FAILED");
|
print!("FAILED");
|
||||||
print!("\nleft: {:?}, right: {:?}", data, case.data);
|
print!("\nleft: {:?}, right: {:?}", data, case.data);
|
||||||
}
|
}
|
||||||
println!("");
|
println!();
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("FAILED\n{:?}", err);
|
println!("FAILED\n{:?}", err);
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::M68kType;
|
||||||
use crate::instructions::{Size, Sign, Direction, Target, Instruction};
|
use crate::instructions::{Size, Sign, Direction, Target, Instruction};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct M68kInstructionTiming {
|
pub struct M68kInstructionTiming {
|
||||||
pub cputype: M68kType,
|
pub cputype: M68kType,
|
||||||
pub bus_size: Size,
|
pub bus_size: Size,
|
||||||
|
@ -325,11 +325,12 @@ impl M68kInstructionTiming {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_instruction_68020(&mut self, instruction: &Instruction) -> &mut Self {
|
pub fn add_instruction_68020(&mut self, _instruction: &Instruction) -> &mut Self {
|
||||||
match instruction {
|
//match instruction {
|
||||||
// TODO implement
|
// // TODO implement
|
||||||
_ => self.add_internal(4),
|
// _ => self.add_internal(4),
|
||||||
}
|
//}
|
||||||
|
self.add_internal(4)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_clocks(&self, branched: bool, reps: u16) -> u16 {
|
pub fn calculate_clocks(&self, branched: bool, reps: u16) -> u16 {
|
||||||
|
|
|
@ -5,20 +5,12 @@ use crate::state::Z80;
|
||||||
use crate::decode::Z80Decoder;
|
use crate::decode::Z80Decoder;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Z80Debugger {
|
pub struct Z80Debugger {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub breakpoints: Vec<u16>,
|
pub breakpoints: Vec<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Z80Debugger {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
enabled: false,
|
|
||||||
breakpoints: vec!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debuggable for Z80 {
|
impl Debuggable for Z80 {
|
||||||
fn debugging_enabled(&mut self) -> bool {
|
fn debugging_enabled(&mut self) -> bool {
|
||||||
self.debugger.enabled
|
self.debugger.enabled
|
||||||
|
@ -48,7 +40,7 @@ impl Debuggable for Z80 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
||||||
let mut decoder = Z80Decoder::new();
|
let mut decoder = Z80Decoder::default();
|
||||||
decoder.dump_disassembly(&mut self.port, addr as u16, count as u16);
|
decoder.dump_disassembly(&mut self.port, addr as u16, count as u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,19 +4,19 @@ use moa_core::{Error, Address, Addressable};
|
||||||
use crate::state::{Register, InterruptMode};
|
use crate::state::{Register, InterruptMode};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
ToAcc,
|
ToAcc,
|
||||||
FromAcc,
|
FromAcc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Size {
|
pub enum Size {
|
||||||
Byte,
|
Byte,
|
||||||
Word,
|
Word,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Condition {
|
pub enum Condition {
|
||||||
NotZero,
|
NotZero,
|
||||||
Zero,
|
Zero,
|
||||||
|
@ -28,7 +28,7 @@ pub enum Condition {
|
||||||
Negative,
|
Negative,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum RegisterPair {
|
pub enum RegisterPair {
|
||||||
BC,
|
BC,
|
||||||
DE,
|
DE,
|
||||||
|
@ -39,13 +39,13 @@ pub enum RegisterPair {
|
||||||
IY,
|
IY,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum IndexRegister {
|
pub enum IndexRegister {
|
||||||
IX,
|
IX,
|
||||||
IY,
|
IY,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum IndexRegisterHalf {
|
pub enum IndexRegisterHalf {
|
||||||
IXH,
|
IXH,
|
||||||
IXL,
|
IXL,
|
||||||
|
@ -53,13 +53,13 @@ pub enum IndexRegisterHalf {
|
||||||
IYL,
|
IYL,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum SpecialRegister {
|
pub enum SpecialRegister {
|
||||||
I,
|
I,
|
||||||
R,
|
R,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
DirectReg(Register),
|
DirectReg(Register),
|
||||||
DirectRegHalf(IndexRegisterHalf),
|
DirectRegHalf(IndexRegisterHalf),
|
||||||
|
@ -68,7 +68,7 @@ pub enum Target {
|
||||||
Immediate(u8),
|
Immediate(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum LoadTarget {
|
pub enum LoadTarget {
|
||||||
DirectRegByte(Register),
|
DirectRegByte(Register),
|
||||||
DirectRegHalfByte(IndexRegisterHalf),
|
DirectRegHalfByte(IndexRegisterHalf),
|
||||||
|
@ -85,7 +85,7 @@ pub enum LoadTarget {
|
||||||
|
|
||||||
pub type UndocumentedCopy = Option<Target>;
|
pub type UndocumentedCopy = Option<Target>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
ADCa(Target),
|
ADCa(Target),
|
||||||
ADC16(RegisterPair, RegisterPair),
|
ADC16(RegisterPair, RegisterPair),
|
||||||
|
@ -179,8 +179,8 @@ pub struct Z80Decoder {
|
||||||
pub execution_time: u16,
|
pub execution_time: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Z80Decoder {
|
impl Default for Z80Decoder {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::decode::{Condition, Instruction, LoadTarget, Target, RegisterPair, In
|
||||||
use crate::state::{Z80, Status, Flags, Register};
|
use crate::state::{Z80, Status, Flags, Register};
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "z80-cpu";
|
const DEV_NAME: &str = "z80-cpu";
|
||||||
|
|
||||||
const FLAGS_NUMERIC: u8 = 0xC0;
|
const FLAGS_NUMERIC: u8 = 0xC0;
|
||||||
const FLAGS_ARITHMETIC: u8 = 0x17;
|
const FLAGS_ARITHMETIC: u8 = 0x17;
|
||||||
|
@ -337,11 +337,11 @@ impl Z80 {
|
||||||
let parity = if count != 0 { Flags::Parity as u8 } else { 0 };
|
let parity = if count != 0 { Flags::Parity as u8 } else { 0 };
|
||||||
self.set_flags(mask, parity);
|
self.set_flags(mask, parity);
|
||||||
|
|
||||||
if self.decoder.instruction == Instruction::LDIR || self.decoder.instruction == Instruction::LDDR {
|
if (self.decoder.instruction == Instruction::LDIR || self.decoder.instruction == Instruction::LDDR)
|
||||||
if count != 0 {
|
&& count != 0
|
||||||
|
{
|
||||||
self.state.pc -= 2;
|
self.state.pc -= 2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Instruction::NEG => {
|
Instruction::NEG => {
|
||||||
let acc = self.get_register_value(Register::A);
|
let acc = self.get_register_value(Register::A);
|
||||||
|
@ -383,7 +383,7 @@ impl Z80 {
|
||||||
},
|
},
|
||||||
Instruction::RES(bit, target, opt_copy) => {
|
Instruction::RES(bit, target, opt_copy) => {
|
||||||
let mut value = self.get_target_value(target)?;
|
let mut value = self.get_target_value(target)?;
|
||||||
value = value & !(1 << bit);
|
value &= !(1 << bit);
|
||||||
self.set_target_value(target, value)?;
|
self.set_target_value(target, value)?;
|
||||||
if let Some(target) = opt_copy {
|
if let Some(target) = opt_copy {
|
||||||
self.set_target_value(target, value)?;
|
self.set_target_value(target, value)?;
|
||||||
|
@ -504,7 +504,7 @@ impl Z80 {
|
||||||
},
|
},
|
||||||
Instruction::SET(bit, target, opt_copy) => {
|
Instruction::SET(bit, target, opt_copy) => {
|
||||||
let mut value = self.get_target_value(target)?;
|
let mut value = self.get_target_value(target)?;
|
||||||
value = value | (1 << bit);
|
value |= 1 << bit;
|
||||||
self.set_target_value(target, value)?;
|
self.set_target_value(target, value)?;
|
||||||
if let Some(target) = opt_copy {
|
if let Some(target) = opt_copy {
|
||||||
self.set_target_value(target, value)?;
|
self.set_target_value(target, value)?;
|
||||||
|
@ -836,7 +836,7 @@ impl Z80 {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_flag(&mut self, flag: Flags, value: bool) {
|
fn set_flag(&mut self, flag: Flags, value: bool) {
|
||||||
self.state.reg[Register::F as usize] = self.state.reg[Register::F as usize] & !(flag as u8);
|
self.state.reg[Register::F as usize] &= !(flag as u8);
|
||||||
if value {
|
if value {
|
||||||
self.state.reg[Register::F as usize] |= flag as u8;
|
self.state.reg[Register::F as usize] |= flag as u8;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub enum Z80Type {
|
||||||
Z80,
|
Z80,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Init,
|
Init,
|
||||||
Running,
|
Running,
|
||||||
|
@ -19,7 +19,7 @@ pub enum Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum InterruptMode {
|
pub enum InterruptMode {
|
||||||
Mode0,
|
Mode0,
|
||||||
Mode01,
|
Mode01,
|
||||||
|
@ -29,7 +29,7 @@ pub enum InterruptMode {
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Flags {
|
pub enum Flags {
|
||||||
Carry = 0x01,
|
Carry = 0x01,
|
||||||
AddSubtract = 0x02,
|
AddSubtract = 0x02,
|
||||||
|
@ -42,7 +42,7 @@ pub enum Flags {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Register {
|
pub enum Register {
|
||||||
B = 0,
|
B = 0,
|
||||||
C = 1,
|
C = 1,
|
||||||
|
@ -55,7 +55,7 @@ pub enum Register {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Z80State {
|
pub struct Z80State {
|
||||||
pub status: Status,
|
pub status: Status,
|
||||||
pub interrupts_enabled: bool,
|
pub interrupts_enabled: bool,
|
||||||
|
@ -73,8 +73,8 @@ pub struct Z80State {
|
||||||
pub r: u8,
|
pub r: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Z80State {
|
impl Default for Z80State {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
status: Status::Init,
|
status: Status::Init,
|
||||||
interrupts_enabled: false,
|
interrupts_enabled: false,
|
||||||
|
@ -92,7 +92,9 @@ impl Z80State {
|
||||||
r: 0,
|
r: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Z80State {
|
||||||
pub fn get_register(&mut self, reg: Register) -> u8 {
|
pub fn get_register(&mut self, reg: Register) -> u8 {
|
||||||
self.reg[reg as usize]
|
self.reg[reg as usize]
|
||||||
}
|
}
|
||||||
|
@ -118,10 +120,10 @@ impl Z80 {
|
||||||
Self {
|
Self {
|
||||||
cputype,
|
cputype,
|
||||||
frequency,
|
frequency,
|
||||||
state: Z80State::new(),
|
state: Z80State::default(),
|
||||||
decoder: Z80Decoder::new(),
|
decoder: Z80Decoder::default(),
|
||||||
debugger: Z80Debugger::new(),
|
debugger: Z80Debugger::default(),
|
||||||
port: port,
|
port,
|
||||||
reset: Signal::new(false),
|
reset: Signal::new(false),
|
||||||
bus_request: Signal::new(false),
|
bus_request: Signal::new(false),
|
||||||
}
|
}
|
||||||
|
@ -129,9 +131,9 @@ impl Z80 {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn clear_state(&mut self) {
|
pub fn clear_state(&mut self) {
|
||||||
self.state = Z80State::new();
|
self.state = Z80State::default();
|
||||||
self.decoder = Z80Decoder::new();
|
self.decoder = Z80Decoder::default();
|
||||||
self.debugger = Z80Debugger::new();
|
self.debugger = Z80Debugger::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_state(&mut self) {
|
pub fn dump_state(&mut self) {
|
||||||
|
@ -147,9 +149,9 @@ impl Z80 {
|
||||||
println!("H: {:#04x} L: {:#04x} H': {:#04x} L': {:#04x}", self.state.reg[Register::H as usize], self.state.reg[Register::L as usize], self.state.shadow_reg[Register::H as usize], self.state.shadow_reg[Register::L as usize]);
|
println!("H: {:#04x} L: {:#04x} H': {:#04x} L': {:#04x}", self.state.reg[Register::H as usize], self.state.reg[Register::L as usize], self.state.shadow_reg[Register::H as usize], self.state.shadow_reg[Register::L as usize]);
|
||||||
|
|
||||||
println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction);
|
println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction);
|
||||||
println!("");
|
println!();
|
||||||
self.port.dump_memory(self.state.sp as Address, 0x40);
|
self.port.dump_memory(self.state.sp as Address, 0x40);
|
||||||
println!("");
|
println!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use moa_core::host::{Audio, ClockedQueue};
|
||||||
const SAMPLE_RATE: usize = 48000;
|
const SAMPLE_RATE: usize = 48000;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct AudioFrame {
|
pub struct AudioFrame {
|
||||||
data: Vec<(f32, f32)>,
|
data: Vec<(f32, f32)>,
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ pub struct AudioSource {
|
||||||
|
|
||||||
impl AudioSource {
|
impl AudioSource {
|
||||||
pub fn new(mixer: Arc<Mutex<AudioMixer>>) -> Self {
|
pub fn new(mixer: Arc<Mutex<AudioMixer>>) -> Self {
|
||||||
let queue = ClockedQueue::new();
|
let queue = ClockedQueue::default();
|
||||||
let (id, sample_rate, frame_size) = {
|
let (id, sample_rate, frame_size) = {
|
||||||
let mut mixer = mixer.lock().unwrap();
|
let mut mixer = mixer.lock().unwrap();
|
||||||
let id = mixer.add_source(queue.clone());
|
let id = mixer.add_source(queue.clone());
|
||||||
|
@ -283,7 +283,7 @@ impl CpalAudioOutput {
|
||||||
|
|
||||||
if let Some(frame) = result {
|
if let Some(frame) = result {
|
||||||
let (start, middle, end) = unsafe { frame.data.align_to::<f32>() };
|
let (start, middle, end) = unsafe { frame.data.align_to::<f32>() };
|
||||||
if start.len() != 0 || end.len() != 0 {
|
if !start.is_empty() || !end.is_empty() {
|
||||||
warn!("audio: frame wasn't aligned");
|
warn!("audio: frame wasn't aligned");
|
||||||
}
|
}
|
||||||
let length = middle.len().min(data.len());
|
let length = middle.len().min(data.len());
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CircularBuffer<T> {
|
|
||||||
pub inp: usize,
|
|
||||||
pub out: usize,
|
|
||||||
pub init: T,
|
|
||||||
pub buffer: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Copy> CircularBuffer<T> {
|
|
||||||
pub fn new(size: usize, init: T) -> Self {
|
|
||||||
Self {
|
|
||||||
inp: 0,
|
|
||||||
out: 0,
|
|
||||||
init,
|
|
||||||
buffer: vec![init; size],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.buffer.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.inp = 0;
|
|
||||||
self.out = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resize(&mut self, newlen: usize) {
|
|
||||||
if self.buffer.len() != newlen {
|
|
||||||
self.buffer = vec![self.init; newlen];
|
|
||||||
self.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, item: T) {
|
|
||||||
let next = self.next_in();
|
|
||||||
if next != self.out {
|
|
||||||
self.buffer[self.inp] = item;
|
|
||||||
self.inp = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drop_next(&mut self, mut count: usize) {
|
|
||||||
let avail = self.used_space();
|
|
||||||
if count > avail {
|
|
||||||
count = avail;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.out += count;
|
|
||||||
if self.out >= self.buffer.len() {
|
|
||||||
self.out -= self.buffer.len();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_full(&self) -> bool {
|
|
||||||
self.next_in() == self.out
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn used_space(&self) -> usize {
|
|
||||||
if self.inp >= self.out {
|
|
||||||
self.inp - self.out
|
|
||||||
} else {
|
|
||||||
self.buffer.len() - self.out + self.inp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free_space(&self) -> usize {
|
|
||||||
if self.out > self.inp {
|
|
||||||
self.out - self.inp - 1
|
|
||||||
} else {
|
|
||||||
self.buffer.len() - self.inp + self.out - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_in(&self) -> usize {
|
|
||||||
if self.inp + 1 < self.buffer.len() {
|
|
||||||
self.inp + 1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Copy> Iterator for CircularBuffer<T> {
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<T> {
|
|
||||||
if self.out == self.inp {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let value = self.buffer[self.out];
|
|
||||||
self.out += 1;
|
|
||||||
if self.out >= self.buffer.len() {
|
|
||||||
self.out = 0;
|
|
||||||
}
|
|
||||||
Some(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
pub mod circularbuf;
|
|
||||||
|
|
||||||
#[cfg(feature = "tty")]
|
#[cfg(feature = "tty")]
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
use clap::Arg;
|
use clap::Arg;
|
||||||
|
|
||||||
use moa_minifb;
|
|
||||||
use moa_genesis::{build_genesis, SegaGenesisOptions};
|
use moa_genesis::{build_genesis, SegaGenesisOptions};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -10,7 +9,7 @@ fn main() {
|
||||||
.help("ROM file to load (must be flat binary)"))
|
.help("ROM file to load (must be flat binary)"))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let mut options = SegaGenesisOptions::new();
|
let mut options = SegaGenesisOptions::default();
|
||||||
if let Some(filename) = matches.value_of("ROM") {
|
if let Some(filename) = matches.value_of("ROM") {
|
||||||
options.rom = filename.to_string();
|
options.rom = filename.to_string();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
|
|
||||||
use moa_minifb;
|
|
||||||
use moa_macintosh::build_macintosh_512k;
|
use moa_macintosh::build_macintosh_512k;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
|
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
|
||||||
use moa_minifb;
|
|
||||||
use moa_peripherals_yamaha::{Ym2612, Sn76489};
|
use moa_peripherals_yamaha::{Ym2612, Sn76489};
|
||||||
|
|
||||||
use moa_core::host::gfx::{Frame, FrameQueue};
|
use moa_core::host::gfx::{Frame, FrameQueue};
|
||||||
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key, KeyEvent, MouseUpdater, MouseState, MouseEvent};
|
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key, KeyEvent /*, MouseUpdater, MouseState, MouseEvent*/};
|
||||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
|
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +97,7 @@ fn main() {
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
moa_minifb::run(matches, |host| {
|
moa_minifb::run(matches, |host| {
|
||||||
let mut system = System::new();
|
let mut system = System::default();
|
||||||
|
|
||||||
let queue = FrameQueue::new(384, 128);
|
let queue = FrameQueue::new(384, 128);
|
||||||
let (sender, receiver) = mpsc::channel();
|
let (sender, receiver) = mpsc::channel();
|
||||||
|
@ -112,7 +111,7 @@ fn main() {
|
||||||
let sn_sound = wrap_transmutable(Sn76489::create(host)?);
|
let sn_sound = wrap_transmutable(Sn76489::create(host)?);
|
||||||
system.add_addressable_device(0x10, sn_sound)?;
|
system.add_addressable_device(0x10, sn_sound)?;
|
||||||
|
|
||||||
host.add_window(Box::new(queue.clone()))?;
|
host.add_window(Box::new(queue))?;
|
||||||
host.register_keyboard(Box::new(SynthControlsUpdater(sender)))?;
|
host.register_keyboard(Box::new(SynthControlsUpdater(sender)))?;
|
||||||
//host.register_mouse(Box::new(SynthControlsUpdater(sender)))?;
|
//host.register_mouse(Box::new(SynthControlsUpdater(sender)))?;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
use clap::Arg;
|
use clap::Arg;
|
||||||
|
|
||||||
use moa_minifb;
|
|
||||||
use moa_trs80::{build_trs80, Trs80Options};
|
use moa_trs80::{build_trs80, Trs80Options};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -14,7 +13,7 @@ fn main() {
|
||||||
.help("ROM file to load at the start of memory"))
|
.help("ROM file to load at the start of memory"))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let mut options = Trs80Options::new();
|
let mut options = Trs80Options::default();
|
||||||
if let Some(filename) = matches.value_of("rom") {
|
if let Some(filename) = matches.value_of("rom") {
|
||||||
options.rom = filename.to_string();
|
options.rom = filename.to_string();
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub fn run<I>(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBui
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_inline<I>(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBuilder) -> Result<System, Error> {
|
pub fn run_inline<I>(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBuilder) -> Result<System, Error> {
|
||||||
let mut frontend = MiniFrontendBuilder::new();
|
let mut frontend = MiniFrontendBuilder::default();
|
||||||
let system = init(&mut frontend).unwrap();
|
let system = init(&mut frontend).unwrap();
|
||||||
|
|
||||||
frontend
|
frontend
|
||||||
|
@ -68,7 +68,7 @@ pub fn run_inline<I>(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFron
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_threaded<I>(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBuilder) -> Result<System, Error> + Send + 'static {
|
pub fn run_threaded<I>(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFrontendBuilder) -> Result<System, Error> + Send + 'static {
|
||||||
let frontend = Arc::new(Mutex::new(MiniFrontendBuilder::new()));
|
let frontend = Arc::new(Mutex::new(MiniFrontendBuilder::default()));
|
||||||
|
|
||||||
{
|
{
|
||||||
let frontend = frontend.clone();
|
let frontend = frontend.clone();
|
||||||
|
@ -88,7 +88,7 @@ pub fn run_threaded<I>(matches: ArgMatches, init: I) where I: FnOnce(&mut MiniFr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_until_initialized(frontend: Arc<Mutex<MiniFrontendBuilder>>) {
|
fn wait_until_initialized(frontend: Arc<Mutex<MiniFrontendBuilder>>) {
|
||||||
while frontend.lock().unwrap().finalized == false {
|
while !frontend.lock().unwrap().finalized {
|
||||||
thread::sleep(Duration::from_millis(10));
|
thread::sleep(Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,8 +103,8 @@ pub struct MiniFrontendBuilder {
|
||||||
pub finalized: bool,
|
pub finalized: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MiniFrontendBuilder {
|
impl Default for MiniFrontendBuilder {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
window: None,
|
window: None,
|
||||||
controller: None,
|
controller: None,
|
||||||
|
@ -114,7 +114,9 @@ impl MiniFrontendBuilder {
|
||||||
finalized: false,
|
finalized: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MiniFrontendBuilder {
|
||||||
pub fn finalize(&mut self) {
|
pub fn finalize(&mut self) {
|
||||||
self.finalized = true;
|
self.finalized = true;
|
||||||
}
|
}
|
||||||
|
@ -211,20 +213,24 @@ impl MiniFrontend {
|
||||||
.init().unwrap();
|
.init().unwrap();
|
||||||
|
|
||||||
if matches.occurrences_of("debugger") > 0 {
|
if matches.occurrences_of("debugger") > 0 {
|
||||||
system.as_mut().map(|system| system.enable_debugging());
|
if let Some(system) = system.as_mut() {
|
||||||
|
system.enable_debugging();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.occurrences_of("disable-audio") <= 0 {
|
if matches.occurrences_of("disable-audio") == 0 {
|
||||||
self.audio = Some(CpalAudioOutput::create_audio_output(self.mixer.lock().unwrap().get_sink()));
|
self.audio = Some(CpalAudioOutput::create_audio_output(self.mixer.lock().unwrap().get_sink()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut options = minifb::WindowOptions::default();
|
let options = minifb::WindowOptions {
|
||||||
options.scale = match matches.value_of("scale").map(|s| u8::from_str_radix(s, 10).unwrap()) {
|
scale: match matches.value_of("scale").map(|s| s.parse::<u8>().unwrap()) {
|
||||||
Some(1) => minifb::Scale::X1,
|
Some(1) => minifb::Scale::X1,
|
||||||
Some(2) => minifb::Scale::X2,
|
Some(2) => minifb::Scale::X2,
|
||||||
Some(4) => minifb::Scale::X4,
|
Some(4) => minifb::Scale::X4,
|
||||||
Some(8) => minifb::Scale::X8,
|
Some(8) => minifb::Scale::X8,
|
||||||
_ => minifb::Scale::X2,
|
_ => minifb::Scale::X2,
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let speed = match matches.value_of("speed") {
|
let speed = match matches.value_of("speed") {
|
||||||
|
@ -271,9 +277,10 @@ impl MiniFrontend {
|
||||||
self.check_key(key, true);
|
self.check_key(key, true);
|
||||||
|
|
||||||
// Process special keys
|
// Process special keys
|
||||||
match key {
|
if let Key::D = key {
|
||||||
Key::D => { system.as_ref().map(|s| s.enable_debugging()); },
|
if let Some(system) = system.as_ref() {
|
||||||
_ => { },
|
system.enable_debugging();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,9 @@ const ATA_ST_ERROR: u8 = 0x01;
|
||||||
|
|
||||||
const ATA_SECTOR_SIZE: u32 = 512;
|
const ATA_SECTOR_SIZE: u32 = 512;
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "ata";
|
const DEV_NAME: &str = "ata";
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct AtaDevice {
|
pub struct AtaDevice {
|
||||||
selected_sector: u32,
|
selected_sector: u32,
|
||||||
selected_count: u32,
|
selected_count: u32,
|
||||||
|
@ -39,17 +40,7 @@ pub struct AtaDevice {
|
||||||
contents: Vec<u8>,
|
contents: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl AtaDevice {
|
impl AtaDevice {
|
||||||
pub fn new() -> Self {
|
|
||||||
AtaDevice {
|
|
||||||
selected_sector: 0,
|
|
||||||
selected_count: 0,
|
|
||||||
last_error: 0,
|
|
||||||
contents: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(&mut self, filename: &str) -> Result<(), Error> {
|
pub fn load(&mut self, filename: &str) -> Result<(), Error> {
|
||||||
match fs::read(filename) {
|
match fs::read(filename) {
|
||||||
Ok(contents) => {
|
Ok(contents) => {
|
||||||
|
|
|
@ -12,7 +12,7 @@ const REG_INT_ENABLE: Address = 0x0E;
|
||||||
const REG_OUTPUT_A_NHS: Address = 0x0F;
|
const REG_OUTPUT_A_NHS: Address = 0x0F;
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "mos6522";
|
const DEV_NAME: &str = "mos6522";
|
||||||
|
|
||||||
|
|
||||||
pub struct Port {
|
pub struct Port {
|
||||||
|
@ -20,8 +20,8 @@ pub struct Port {
|
||||||
pub ddr: u8,
|
pub ddr: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Port {
|
impl Default for Port {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: 0xff,
|
data: 0xff,
|
||||||
ddr: 0,
|
ddr: 0,
|
||||||
|
@ -39,11 +39,11 @@ pub struct Mos6522 {
|
||||||
pub interrupt_enable: u8,
|
pub interrupt_enable: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mos6522 {
|
impl Default for Mos6522 {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
port_a: ObservableSignal::new(Port::new()),
|
port_a: ObservableSignal::new(Port::default()),
|
||||||
port_b: ObservableSignal::new(Port::new()),
|
port_b: ObservableSignal::new(Port::default()),
|
||||||
peripheral_ctrl: 0,
|
peripheral_ctrl: 0,
|
||||||
interrupt: Signal::new(false),
|
interrupt: Signal::new(false),
|
||||||
interrupt_flags: 0,
|
interrupt_flags: 0,
|
||||||
|
|
|
@ -65,8 +65,9 @@ const ISR_CH_A_RX_READY_FULL: u8 = 0x02;
|
||||||
const ISR_CH_A_TX_READY: u8 = 0x01;
|
const ISR_CH_A_TX_READY: u8 = 0x01;
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "mc68681";
|
const DEV_NAME: &str = "mc68681";
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct MC68681Port {
|
pub struct MC68681Port {
|
||||||
tty: Option<Box<dyn Tty>>,
|
tty: Option<Box<dyn Tty>>,
|
||||||
status: u8,
|
status: u8,
|
||||||
|
@ -78,18 +79,6 @@ pub struct MC68681Port {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MC68681Port {
|
impl MC68681Port {
|
||||||
pub fn new() -> MC68681Port {
|
|
||||||
MC68681Port {
|
|
||||||
tty: None,
|
|
||||||
status: 0,
|
|
||||||
|
|
||||||
tx_enabled: false,
|
|
||||||
|
|
||||||
rx_enabled: false,
|
|
||||||
input: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn connect(&mut self, pty: Box<dyn Tty>) -> Result<String, Error> {
|
pub fn connect(&mut self, pty: Box<dyn Tty>) -> Result<String, Error> {
|
||||||
let name = pty.device_name();
|
let name = pty.device_name();
|
||||||
println!("{}: opening pts {}", DEV_NAME, name);
|
println!("{}: opening pts {}", DEV_NAME, name);
|
||||||
|
@ -180,12 +169,12 @@ pub struct MC68681 {
|
||||||
output_state: u8,
|
output_state: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MC68681 {
|
impl Default for MC68681 {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
MC68681 {
|
MC68681 {
|
||||||
acr: 0,
|
acr: 0,
|
||||||
port_a: MC68681Port::new(),
|
port_a: MC68681Port::default(),
|
||||||
port_b: MC68681Port::new(),
|
port_b: MC68681Port::default(),
|
||||||
|
|
||||||
int_mask: 0,
|
int_mask: 0,
|
||||||
int_status: 0,
|
int_status: 0,
|
||||||
|
@ -202,7 +191,9 @@ impl MC68681 {
|
||||||
output_state: 0,
|
output_state: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MC68681 {
|
||||||
fn set_interrupt_flag(&mut self, flag: u8, value: bool) {
|
fn set_interrupt_flag(&mut self, flag: u8, value: bool) {
|
||||||
self.int_status = (self.int_status & !flag) | (if value { flag } else { 0 });
|
self.int_status = (self.int_status & !flag) | (if value { flag } else { 0 });
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use moa_core::host::{Host, Audio};
|
||||||
use moa_core::host::audio::{SquareWave};
|
use moa_core::host::audio::{SquareWave};
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "sn76489";
|
const DEV_NAME: &str = "sn76489";
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ToneGenerator {
|
pub struct ToneGenerator {
|
||||||
|
@ -51,14 +51,16 @@ pub struct NoiseGenerator {
|
||||||
attenuation: f32,
|
attenuation: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoiseGenerator {
|
impl Default for NoiseGenerator {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
on: false,
|
on: false,
|
||||||
attenuation: 0.0,
|
attenuation: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoiseGenerator {
|
||||||
pub fn set_attenuation(&mut self, attenuation: u8) {
|
pub fn set_attenuation(&mut self, attenuation: u8) {
|
||||||
if attenuation == 0x0F {
|
if attenuation == 0x0F {
|
||||||
self.on = false;
|
self.on = false;
|
||||||
|
@ -99,7 +101,7 @@ impl Sn76489 {
|
||||||
first_byte: None,
|
first_byte: None,
|
||||||
source,
|
source,
|
||||||
tones: vec![ToneGenerator::new(sample_rate); 3],
|
tones: vec![ToneGenerator::new(sample_rate); 3],
|
||||||
noise: NoiseGenerator::new(),
|
noise: NoiseGenerator::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +115,7 @@ impl Steppable for Sn76489 {
|
||||||
if samples > 0 {
|
if samples > 0 {
|
||||||
//if available >= rate / 1000 {
|
//if available >= rate / 1000 {
|
||||||
let mut buffer = vec![0.0; samples];
|
let mut buffer = vec![0.0; samples];
|
||||||
for i in 0..samples {
|
for buffered_sample in buffer.iter_mut().take(samples) {
|
||||||
let mut sample = 0.0;
|
let mut sample = 0.0;
|
||||||
|
|
||||||
for ch in 0..3 {
|
for ch in 0..3 {
|
||||||
|
@ -126,7 +128,7 @@ impl Steppable for Sn76489 {
|
||||||
sample += self.noise.get_sample();
|
sample += self.noise.get_sample();
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[i] = sample.clamp(-1.0, 1.0);
|
*buffered_sample = sample.clamp(-1.0, 1.0);
|
||||||
}
|
}
|
||||||
self.source.write_samples(system.clock, &buffer);
|
self.source.write_samples(system.clock, &buffer);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Tra
|
||||||
use moa_core::host::{Host, Audio};
|
use moa_core::host::{Host, Audio};
|
||||||
use moa_core::host::audio::{SineWave};
|
use moa_core::host::audio::{SineWave};
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "ym2612";
|
const DEV_NAME: &str = "ym2612";
|
||||||
|
|
||||||
const CHANNELS: usize = 8;
|
const CHANNELS: usize = 8;
|
||||||
|
|
||||||
|
@ -101,22 +101,19 @@ impl Channel {
|
||||||
OperatorAlgorithm::A1 => {
|
OperatorAlgorithm::A1 => {
|
||||||
let sample1 = self.operators[0].get_sample(0.0) + self.operators[1].get_sample(0.0);
|
let sample1 = self.operators[0].get_sample(0.0) + self.operators[1].get_sample(0.0);
|
||||||
let sample2 = self.operators[2].get_sample(sample1);
|
let sample2 = self.operators[2].get_sample(sample1);
|
||||||
let sample3 = self.operators[3].get_sample(sample2);
|
self.operators[3].get_sample(sample2)
|
||||||
sample3
|
|
||||||
},
|
},
|
||||||
OperatorAlgorithm::A2 => {
|
OperatorAlgorithm::A2 => {
|
||||||
let sample1 = self.operators[1].get_sample(0.0);
|
let sample1 = self.operators[1].get_sample(0.0);
|
||||||
let sample2 = self.operators[2].get_sample(sample1);
|
let sample2 = self.operators[2].get_sample(sample1);
|
||||||
let sample3 = self.operators[0].get_sample(0.0) + sample2;
|
let sample3 = self.operators[0].get_sample(0.0) + sample2;
|
||||||
let sample4 = self.operators[3].get_sample(sample3);
|
self.operators[3].get_sample(sample3)
|
||||||
sample4
|
|
||||||
},
|
},
|
||||||
OperatorAlgorithm::A3 => {
|
OperatorAlgorithm::A3 => {
|
||||||
let sample1 = self.operators[0].get_sample(0.0);
|
let sample1 = self.operators[0].get_sample(0.0);
|
||||||
let sample2 = self.operators[1].get_sample(sample1);
|
let sample2 = self.operators[1].get_sample(sample1);
|
||||||
let sample3 = self.operators[2].get_sample(0.0);
|
let sample3 = self.operators[2].get_sample(0.0);
|
||||||
let sample4 = self.operators[3].get_sample(sample2 + sample3);
|
self.operators[3].get_sample(sample2 + sample3)
|
||||||
sample4
|
|
||||||
},
|
},
|
||||||
OperatorAlgorithm::A4 => {
|
OperatorAlgorithm::A4 => {
|
||||||
let sample1 = self.operators[0].get_sample(0.0);
|
let sample1 = self.operators[0].get_sample(0.0);
|
||||||
|
@ -127,8 +124,7 @@ impl Channel {
|
||||||
},
|
},
|
||||||
OperatorAlgorithm::A5 => {
|
OperatorAlgorithm::A5 => {
|
||||||
let sample1 = self.operators[0].get_sample(0.0);
|
let sample1 = self.operators[0].get_sample(0.0);
|
||||||
let sample2 = self.operators[1].get_sample(sample1) + self.operators[2].get_sample(sample1) + self.operators[3].get_sample(sample1);
|
self.operators[1].get_sample(sample1) + self.operators[2].get_sample(sample1) + self.operators[3].get_sample(sample1)
|
||||||
sample2
|
|
||||||
},
|
},
|
||||||
OperatorAlgorithm::A6 => {
|
OperatorAlgorithm::A6 => {
|
||||||
let sample1 = self.operators[0].get_sample(0.0);
|
let sample1 = self.operators[0].get_sample(0.0);
|
||||||
|
@ -136,11 +132,10 @@ impl Channel {
|
||||||
sample2 + self.operators[2].get_sample(0.0) + self.operators[3].get_sample(0.0)
|
sample2 + self.operators[2].get_sample(0.0) + self.operators[3].get_sample(0.0)
|
||||||
},
|
},
|
||||||
OperatorAlgorithm::A7 => {
|
OperatorAlgorithm::A7 => {
|
||||||
let sample = self.operators[0].get_sample(0.0)
|
self.operators[0].get_sample(0.0)
|
||||||
+ self.operators[1].get_sample(0.0)
|
+ self.operators[1].get_sample(0.0)
|
||||||
+ self.operators[2].get_sample(0.0)
|
+ self.operators[2].get_sample(0.0)
|
||||||
+ self.operators[3].get_sample(0.0);
|
+ self.operators[3].get_sample(0.0)
|
||||||
sample
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +235,7 @@ impl Ym2612 {
|
||||||
self.channels[ch].operators[op].set_multiplier(frequency, multiplier)
|
self.channels[ch].operators[op].set_multiplier(frequency, multiplier)
|
||||||
},
|
},
|
||||||
|
|
||||||
reg if reg >= 0xA0 && reg <= 0xA2 => {
|
reg if (0xA0..=0xA2).contains(®) => {
|
||||||
let ch = (reg & 0x07) + (bank * 3);
|
let ch = (reg & 0x07) + (bank * 3);
|
||||||
self.channel_frequencies[ch].1 = (self.channel_frequencies[ch].1 & 0xFF00) | data as u16;
|
self.channel_frequencies[ch].1 = (self.channel_frequencies[ch].1 & 0xFF00) | data as u16;
|
||||||
|
|
||||||
|
@ -249,13 +244,13 @@ impl Ym2612 {
|
||||||
self.channels[ch].set_frequency(frequency);
|
self.channels[ch].set_frequency(frequency);
|
||||||
},
|
},
|
||||||
|
|
||||||
reg if reg >= 0xA4 && reg <= 0xA6 => {
|
reg if (0xA4..=0xA6).contains(®) => {
|
||||||
let ch = (reg & 0x07) - 4 + (bank * 3);
|
let ch = (reg & 0x07) - 4 + (bank * 3);
|
||||||
self.channel_frequencies[ch].1 = (self.channel_frequencies[ch].1 & 0xFF) | ((data as u16) & 0x07) << 8;
|
self.channel_frequencies[ch].1 = (self.channel_frequencies[ch].1 & 0xFF) | ((data as u16) & 0x07) << 8;
|
||||||
self.channel_frequencies[ch].0 = (data & 0x38) >> 3;
|
self.channel_frequencies[ch].0 = (data & 0x38) >> 3;
|
||||||
},
|
},
|
||||||
|
|
||||||
reg if reg >= 0xB0 && reg <= 0xB2 => {
|
reg if (0xB0..=0xB2).contains(®) => {
|
||||||
let ch = (reg & 0x07) + (bank * 3);
|
let ch = (reg & 0x07) + (bank * 3);
|
||||||
self.channels[ch].algorithm = match data & 0x07 {
|
self.channels[ch].algorithm = match data & 0x07 {
|
||||||
0 => OperatorAlgorithm::A0,
|
0 => OperatorAlgorithm::A0,
|
||||||
|
@ -279,7 +274,7 @@ impl Ym2612 {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fnumber_to_frequency(fnumber: (u8, u16)) -> f32 {
|
pub fn fnumber_to_frequency(fnumber: (u8, u16)) -> f32 {
|
||||||
(fnumber.1 as f32 * 0.0264) * (2 as u32).pow(fnumber.0 as u32) as f32
|
(fnumber.1 as f32 * 0.0264) * 2_u32.pow(fnumber.0 as u32) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -313,7 +308,7 @@ impl Steppable for Ym2612 {
|
||||||
let samples = if available < rate / 1000 { available } else { rate / 1000 };
|
let samples = if available < rate / 1000 { available } else { rate / 1000 };
|
||||||
//if self.source.space_available() >= samples {
|
//if self.source.space_available() >= samples {
|
||||||
let mut buffer = vec![0.0; samples];
|
let mut buffer = vec![0.0; samples];
|
||||||
for i in 0..samples {
|
for buffered_sample in buffer.iter_mut().take(samples) {
|
||||||
let mut sample = 0.0;
|
let mut sample = 0.0;
|
||||||
|
|
||||||
for ch in 0..6 {
|
for ch in 0..6 {
|
||||||
|
@ -330,9 +325,8 @@ impl Steppable for Ym2612 {
|
||||||
sample += self.channels[6].get_sample();
|
sample += self.channels[6].get_sample();
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[i] = sample.clamp(-1.0, 1.0);
|
*buffered_sample = sample.clamp(-1.0, 1.0);
|
||||||
}
|
}
|
||||||
//println!("synthesized: {:?}", buffer);
|
|
||||||
self.source.write_samples(system.clock, &buffer);
|
self.source.write_samples(system.clock, &buffer);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
@ -349,7 +343,7 @@ impl Addressable for Ym2612 {
|
||||||
match addr {
|
match addr {
|
||||||
0 | 1 | 2 | 3 => {
|
0 | 1 | 2 | 3 => {
|
||||||
// Read the status byte (busy/overflow)
|
// Read the status byte (busy/overflow)
|
||||||
data[0] = 0 | ((self.timer_a_overflow as u8) << 1) | (self.timer_b_overflow as u8);
|
data[0] = ((self.timer_a_overflow as u8) << 1) | (self.timer_b_overflow as u8);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
|
warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
|
||||||
|
|
|
@ -1,42 +1,27 @@
|
||||||
|
|
||||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, warn, debug};
|
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, warn, debug};
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "z8530";
|
const DEV_NAME: &str = "z8530";
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Z8530 {
|
pub struct Z8530 {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Z8530 {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Addressable for Z8530 {
|
impl Addressable for Z8530 {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
0x10
|
0x10
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
||||||
match addr {
|
|
||||||
_ => {
|
|
||||||
warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
|
warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
|
||||||
},
|
|
||||||
}
|
|
||||||
debug!("{}: read from register {:x} of {:?}", DEV_NAME, addr, data);
|
debug!("{}: read from register {:x} of {:?}", DEV_NAME, addr, data);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
||||||
debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
||||||
match addr {
|
|
||||||
_ => {
|
|
||||||
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
|
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +29,7 @@ impl Addressable for Z8530 {
|
||||||
impl Steppable for Z8530 {
|
impl Steppable for Z8530 {
|
||||||
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
||||||
|
|
||||||
Ok(1_000_000_00)
|
Ok(1_000_000_000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use moa_peripherals_motorola::MC68681;
|
||||||
|
|
||||||
|
|
||||||
pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
||||||
let mut system = System::new();
|
let mut system = System::default();
|
||||||
|
|
||||||
let monitor = MemoryBlock::load("binaries/computie/monitor.bin")?;
|
let monitor = MemoryBlock::load("binaries/computie/monitor.bin")?;
|
||||||
system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?;
|
system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?;
|
||||||
|
@ -17,11 +17,11 @@ pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
||||||
ram.load_at(0, "binaries/computie/kernel.bin")?;
|
ram.load_at(0, "binaries/computie/kernel.bin")?;
|
||||||
system.add_addressable_device(0x00100000, wrap_transmutable(ram))?;
|
system.add_addressable_device(0x00100000, wrap_transmutable(ram))?;
|
||||||
|
|
||||||
let mut ata = AtaDevice::new();
|
let mut ata = AtaDevice::default();
|
||||||
ata.load("binaries/computie/disk-with-partition-table.img")?;
|
ata.load("binaries/computie/disk-with-partition-table.img")?;
|
||||||
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
|
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
|
||||||
|
|
||||||
let mut serial = MC68681::new();
|
let mut serial = MC68681::default();
|
||||||
launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?);
|
launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?);
|
||||||
launch_slip_connection(serial.port_b.connect(host.create_pty()?)?);
|
launch_slip_connection(serial.port_b.connect(host.create_pty()?)?);
|
||||||
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
||||||
|
@ -46,7 +46,7 @@ pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
|
pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
|
||||||
let mut system = System::new();
|
let mut system = System::default();
|
||||||
|
|
||||||
let monitor = MemoryBlock::load("binaries/computie/monitor-68030.bin")?;
|
let monitor = MemoryBlock::load("binaries/computie/monitor-68030.bin")?;
|
||||||
system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?;
|
system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?;
|
||||||
|
@ -55,11 +55,11 @@ pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
|
||||||
ram.load_at(0, "binaries/computie/kernel-68030.bin")?;
|
ram.load_at(0, "binaries/computie/kernel-68030.bin")?;
|
||||||
system.add_addressable_device(0x00100000, wrap_transmutable(ram))?;
|
system.add_addressable_device(0x00100000, wrap_transmutable(ram))?;
|
||||||
|
|
||||||
let mut ata = AtaDevice::new();
|
let mut ata = AtaDevice::default();
|
||||||
ata.load("binaries/computie/disk-with-partition-table.img")?;
|
ata.load("binaries/computie/disk-with-partition-table.img")?;
|
||||||
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
|
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
|
||||||
|
|
||||||
let mut serial = MC68681::new();
|
let mut serial = MC68681::default();
|
||||||
launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?);
|
launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?);
|
||||||
//launch_slip_connection(serial.port_b.connect(host.create_pty()?)?);
|
//launch_slip_connection(serial.port_b.connect(host.create_pty()?)?);
|
||||||
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
||||||
|
|
|
@ -16,7 +16,7 @@ const REG_S_CTRL2: Address = 0x19;
|
||||||
const REG_S_CTRL3: Address = 0x1F;
|
const REG_S_CTRL3: Address = 0x1F;
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "genesis_controller";
|
const DEV_NAME: &str = "genesis_controller";
|
||||||
|
|
||||||
pub struct GenesisControllerPort {
|
pub struct GenesisControllerPort {
|
||||||
/// Data contains bits:
|
/// Data contains bits:
|
||||||
|
@ -31,8 +31,8 @@ pub struct GenesisControllerPort {
|
||||||
s_ctrl: u8,
|
s_ctrl: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenesisControllerPort {
|
impl Default for GenesisControllerPort {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
buttons: HostData::new(0xffff),
|
buttons: HostData::new(0xffff),
|
||||||
ctrl: 0,
|
ctrl: 0,
|
||||||
|
@ -41,7 +41,9 @@ impl GenesisControllerPort {
|
||||||
s_ctrl: 0,
|
s_ctrl: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenesisControllerPort {
|
||||||
pub fn get_data(&mut self) -> u8 {
|
pub fn get_data(&mut self) -> u8 {
|
||||||
let inputs = self.buttons.get();
|
let inputs = self.buttons.get();
|
||||||
let th_state = (self.outputs & 0x40) != 0;
|
let th_state = (self.outputs & 0x40) != 0;
|
||||||
|
@ -118,19 +120,21 @@ pub struct GenesisControllers {
|
||||||
reset_timer: Clock,
|
reset_timer: Clock,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenesisControllers {
|
impl Default for GenesisControllers {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
port_1: GenesisControllerPort::new(),
|
port_1: GenesisControllerPort::default(),
|
||||||
port_2: GenesisControllerPort::new(),
|
port_2: GenesisControllerPort::default(),
|
||||||
expansion: GenesisControllerPort::new(),
|
expansion: GenesisControllerPort::default(),
|
||||||
interrupt: HostData::new(false),
|
interrupt: HostData::new(false),
|
||||||
reset_timer: 0,
|
reset_timer: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenesisControllers {
|
||||||
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> {
|
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> {
|
||||||
let controller = GenesisControllers::new();
|
let controller = GenesisControllers::default();
|
||||||
|
|
||||||
let controller1 = Box::new(GenesisControllersUpdater(controller.port_1.buttons.clone(), controller.interrupt.clone()));
|
let controller1 = Box::new(GenesisControllersUpdater(controller.port_1.buttons.clone(), controller.interrupt.clone()));
|
||||||
host.register_controller(ControllerDevice::A, controller1)?;
|
host.register_controller(ControllerDevice::A, controller1)?;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use moa_core::{warn, info};
|
||||||
use moa_core::{Bus, Signal, Error, Address, Addressable, Transmutable};
|
use moa_core::{Bus, Signal, Error, Address, Addressable, Transmutable};
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "coprocessor";
|
const DEV_NAME: &str = "coprocessor";
|
||||||
|
|
||||||
pub struct CoprocessorCoordinator {
|
pub struct CoprocessorCoordinator {
|
||||||
bus_request: Signal<bool>,
|
bus_request: Signal<bool>,
|
||||||
|
|
|
@ -59,10 +59,10 @@ const MODE4_BF_SHADOW_HIGHLIGHT: u8 = 0x08;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "ym7101";
|
const DEV_NAME: &str = "ym7101";
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum DmaType {
|
pub enum DmaType {
|
||||||
None,
|
None,
|
||||||
Memory,
|
Memory,
|
||||||
|
@ -70,7 +70,7 @@ pub enum DmaType {
|
||||||
Copy,
|
Copy,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Memory {
|
pub enum Memory {
|
||||||
Vram,
|
Vram,
|
||||||
Cram,
|
Cram,
|
||||||
|
@ -97,8 +97,8 @@ pub struct Ym7101Memory {
|
||||||
pub ctrl_port_buffer: Option<u16>,
|
pub ctrl_port_buffer: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ym7101Memory {
|
impl Default for Ym7101Memory {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
vram: [0; 0x10000],
|
vram: [0; 0x10000],
|
||||||
cram: [0; 128],
|
cram: [0; 128],
|
||||||
|
@ -119,8 +119,9 @@ impl Ym7101Memory {
|
||||||
ctrl_port_buffer: None,
|
ctrl_port_buffer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ym7101Memory {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_beu16(&self, target: Memory, addr: usize) -> u16 {
|
fn read_beu16(&self, target: Memory, addr: usize) -> u16 {
|
||||||
let addr = match target {
|
let addr = match target {
|
||||||
|
@ -148,7 +149,7 @@ impl Ym7101Memory {
|
||||||
|
|
||||||
pub fn setup_transfer(&mut self, first: u16, second: u16) {
|
pub fn setup_transfer(&mut self, first: u16, second: u16) {
|
||||||
self.ctrl_port_buffer = None;
|
self.ctrl_port_buffer = None;
|
||||||
self.transfer_type = ((((first & 0xC000) >> 14) | ((second & 0x00F0) >> 2))) as u8;
|
self.transfer_type = (((first & 0xC000) >> 14) | ((second & 0x00F0) >> 2)) as u8;
|
||||||
self.transfer_dest_addr = ((first & 0x3FFF) | ((second & 0x0003) << 14)) as u32;
|
self.transfer_dest_addr = ((first & 0x3FFF) | ((second & 0x0003) << 14)) as u32;
|
||||||
self.transfer_target = match self.transfer_type & 0x0E {
|
self.transfer_target = match self.transfer_type & 0x0E {
|
||||||
0 => Memory::Vram,
|
0 => Memory::Vram,
|
||||||
|
@ -268,14 +269,14 @@ impl Ym7101Memory {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ColourMode {
|
pub enum ColourMode {
|
||||||
Normal,
|
Normal,
|
||||||
Shadow,
|
Shadow,
|
||||||
Highlight,
|
Highlight,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Scroll {
|
pub enum Scroll {
|
||||||
ScrollA,
|
ScrollA,
|
||||||
ScrollB,
|
ScrollB,
|
||||||
|
@ -314,11 +315,11 @@ pub struct Ym7101State {
|
||||||
pub current_y: i32,
|
pub current_y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ym7101State {
|
impl Default for Ym7101State {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
status: 0x3400 | STATUS_FIFO_EMPTY,
|
status: 0x3400 | STATUS_FIFO_EMPTY,
|
||||||
memory: Ym7101Memory::new(),
|
memory: Ym7101Memory::default(),
|
||||||
|
|
||||||
mode_1: 0,
|
mode_1: 0,
|
||||||
mode_2: 0,
|
mode_2: 0,
|
||||||
|
@ -349,7 +350,9 @@ impl Ym7101State {
|
||||||
current_y: 0,
|
current_y: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ym7101State {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hsync_int_enabled(&self) -> bool {
|
fn hsync_int_enabled(&self) -> bool {
|
||||||
(self.mode_1 & MODE1_BF_HSYNC_INTERRUPT) != 0
|
(self.mode_1 & MODE1_BF_HSYNC_INTERRUPT) != 0
|
||||||
|
@ -470,13 +473,11 @@ impl Ym7101State {
|
||||||
|
|
||||||
let offset = pattern_addr as usize + line * 4 + column;
|
let offset = pattern_addr as usize + line * 4 + column;
|
||||||
let second = x % 2 == 1;
|
let second = x % 2 == 1;
|
||||||
let value = if (!h_rev && !second) || (h_rev && second) {
|
if (!h_rev && !second) || (h_rev && second) {
|
||||||
(palette, self.memory.vram[offset] >> 4)
|
(palette, self.memory.vram[offset] >> 4)
|
||||||
} else {
|
} else {
|
||||||
(palette, self.memory.vram[offset] & 0x0f)
|
(palette, self.memory.vram[offset] & 0x0f)
|
||||||
};
|
}
|
||||||
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_frame(&mut self, frame: &mut Frame) {
|
pub fn draw_frame(&mut self, frame: &mut Frame) {
|
||||||
|
@ -685,10 +686,10 @@ impl Ym7101 {
|
||||||
|
|
||||||
Ym7101 {
|
Ym7101 {
|
||||||
queue,
|
queue,
|
||||||
state: Ym7101State::new(),
|
state: Ym7101State::default(),
|
||||||
sn_sound,
|
sn_sound,
|
||||||
external_interrupt,
|
external_interrupt,
|
||||||
frame_complete: EdgeSignal::new(),
|
frame_complete: EdgeSignal::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,8 +780,8 @@ impl Addressable for Ym7101 {
|
||||||
// Read from Control Port
|
// Read from Control Port
|
||||||
0x04 | 0x05 | 0x06 | 0x07 => {
|
0x04 | 0x05 | 0x06 | 0x07 => {
|
||||||
debug!("{}: read status byte {:x}", DEV_NAME, self.state.status);
|
debug!("{}: read status byte {:x}", DEV_NAME, self.state.status);
|
||||||
for i in 0..data.len() {
|
for item in data {
|
||||||
data[i] = if (addr % 2) == 0 {
|
*item = if (addr % 2) == 0 {
|
||||||
(self.state.status >> 8) as u8
|
(self.state.status >> 8) as u8
|
||||||
} else {
|
} else {
|
||||||
(self.state.status & 0x00FF) as u8
|
(self.state.status & 0x00FF) as u8
|
||||||
|
@ -873,18 +874,18 @@ impl Inspectable for Ym7101 {
|
||||||
|
|
||||||
impl Ym7101State {
|
impl Ym7101State {
|
||||||
pub fn dump_state(&self) {
|
pub fn dump_state(&self) {
|
||||||
println!("");
|
println!();
|
||||||
println!("Mode1: {:#04x}", self.mode_1);
|
println!("Mode1: {:#04x}", self.mode_1);
|
||||||
println!("Mode2: {:#04x}", self.mode_2);
|
println!("Mode2: {:#04x}", self.mode_2);
|
||||||
println!("Mode3: {:#04x}", self.mode_3);
|
println!("Mode3: {:#04x}", self.mode_3);
|
||||||
println!("Mode4: {:#04x}", self.mode_4);
|
println!("Mode4: {:#04x}", self.mode_4);
|
||||||
println!("");
|
println!();
|
||||||
println!("Scroll A : {:#06x}", self.scroll_a_addr);
|
println!("Scroll A : {:#06x}", self.scroll_a_addr);
|
||||||
println!("Window : {:#06x}", self.window_addr);
|
println!("Window : {:#06x}", self.window_addr);
|
||||||
println!("Scroll B : {:#06x}", self.scroll_b_addr);
|
println!("Scroll B : {:#06x}", self.scroll_b_addr);
|
||||||
println!("HScroll : {:#06x}", self.hscroll_addr);
|
println!("HScroll : {:#06x}", self.hscroll_addr);
|
||||||
println!("Sprites : {:#06x}", self.sprites_addr);
|
println!("Sprites : {:#06x}", self.sprites_addr);
|
||||||
println!("");
|
println!();
|
||||||
println!("DMA type : {:?}", self.memory.transfer_type);
|
println!("DMA type : {:?}", self.memory.transfer_type);
|
||||||
println!("DMA Source: {:#06x}", self.memory.transfer_src_addr);
|
println!("DMA Source: {:#06x}", self.memory.transfer_src_addr);
|
||||||
println!("DMA Dest : {:#06x}", self.memory.transfer_dest_addr);
|
println!("DMA Dest : {:#06x}", self.memory.transfer_dest_addr);
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use moa_core::{System, Error, Signal, MemoryBlock, AddressRepeater, Bus, BusPort, Address, Addressable, Debuggable, wrap_transmutable};
|
use moa_core::{System, Error, Signal, MemoryBlock, Bus, BusPort, Address, Addressable, Debuggable, wrap_transmutable};
|
||||||
use moa_core::host::Host;
|
use moa_core::host::Host;
|
||||||
|
|
||||||
use moa_m68k::{M68k, M68kType};
|
use moa_m68k::{M68k, M68kType};
|
||||||
|
@ -22,8 +22,8 @@ pub struct SegaGenesisOptions {
|
||||||
pub rom_data: Option<Vec<u8>>,
|
pub rom_data: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SegaGenesisOptions {
|
impl Default for SegaGenesisOptions {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rom: "".to_string(),
|
rom: "".to_string(),
|
||||||
rom_data: None,
|
rom_data: None,
|
||||||
|
@ -32,7 +32,7 @@ impl SegaGenesisOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) -> Result<System, Error> {
|
pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) -> Result<System, Error> {
|
||||||
let mut system = System::new();
|
let mut system = System::default();
|
||||||
|
|
||||||
let rom_data = if options.rom_data.is_some() {
|
let rom_data = if options.rom_data.is_some() {
|
||||||
mem::take(&mut options.rom_data).unwrap()
|
mem::take(&mut options.rom_data).unwrap()
|
||||||
|
@ -75,14 +75,14 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
|
||||||
let coproc_register = wrap_transmutable(CoprocessorBankRegister::new(bank_register.clone()));
|
let coproc_register = wrap_transmutable(CoprocessorBankRegister::new(bank_register.clone()));
|
||||||
let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone()));
|
let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone()));
|
||||||
|
|
||||||
let coproc_bus = Rc::new(RefCell::new(Bus::new()));
|
let coproc_bus = Rc::new(RefCell::new(Bus::default()));
|
||||||
coproc_bus.borrow_mut().set_ignore_unmapped(true);
|
coproc_bus.borrow_mut().set_ignore_unmapped(true);
|
||||||
coproc_bus.borrow_mut().insert(0x0000, coproc_ram.clone());
|
coproc_bus.borrow_mut().insert(0x0000, coproc_ram.clone());
|
||||||
coproc_bus.borrow_mut().insert(0x4000, coproc_ym_sound.clone());
|
coproc_bus.borrow_mut().insert(0x4000, coproc_ym_sound.clone());
|
||||||
coproc_bus.borrow_mut().insert(0x6000, coproc_register.clone());
|
coproc_bus.borrow_mut().insert(0x6000, coproc_register.clone());
|
||||||
coproc_bus.borrow_mut().insert(0x7f11, coproc_sn_sound.clone());
|
coproc_bus.borrow_mut().insert(0x7f11, coproc_sn_sound.clone());
|
||||||
coproc_bus.borrow_mut().insert(0x8000, coproc_area);
|
coproc_bus.borrow_mut().insert(0x8000, coproc_area);
|
||||||
let mut coproc = Z80::new(Z80Type::Z80, 3_579_545, BusPort::new(0, 16, 8, coproc_bus.clone()));
|
let mut coproc = Z80::new(Z80Type::Z80, 3_579_545, BusPort::new(0, 16, 8, coproc_bus));
|
||||||
coproc.set_debugging(true);
|
coproc.set_debugging(true);
|
||||||
let mut reset = coproc.reset.clone();
|
let mut reset = coproc.reset.clone();
|
||||||
let mut bus_request = coproc.bus_request.clone();
|
let mut bus_request = coproc.bus_request.clone();
|
||||||
|
|
|
@ -11,8 +11,9 @@ const ENABLE: u8 = 0x10;
|
||||||
const Q6: u8 = 0x40;
|
const Q6: u8 = 0x40;
|
||||||
const Q7: u8 = 0x80;
|
const Q7: u8 = 0x80;
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "iwm";
|
const DEV_NAME: &str = "iwm";
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct IWM {
|
pub struct IWM {
|
||||||
state: u8,
|
state: u8,
|
||||||
mode: u8,
|
mode: u8,
|
||||||
|
@ -20,14 +21,6 @@ pub struct IWM {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IWM {
|
impl IWM {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
state: 0,
|
|
||||||
mode: 0,
|
|
||||||
handshake: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flip_switches(&mut self, addr: Address) {
|
pub fn flip_switches(&mut self, addr: Address) {
|
||||||
let mask = 1 << (addr >> 1);
|
let mask = 1 << (addr >> 1);
|
||||||
|
|
||||||
|
@ -102,8 +95,8 @@ impl Addressable for IWM {
|
||||||
|
|
||||||
impl Steppable for IWM {
|
impl Steppable for IWM {
|
||||||
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
|
||||||
|
// TODO implement
|
||||||
Ok(1_000_000_00)
|
Ok(1_000_000_000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use moa_peripherals_mos::Mos6522;
|
||||||
use moa_peripherals_zilog::Z8530;
|
use moa_peripherals_zilog::Z8530;
|
||||||
use crate::peripherals::iwm::IWM;
|
use crate::peripherals::iwm::IWM;
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "mac";
|
const DEV_NAME: &str = "mac";
|
||||||
|
|
||||||
|
|
||||||
pub struct Mainboard {
|
pub struct Mainboard {
|
||||||
|
@ -23,13 +23,13 @@ pub struct Mainboard {
|
||||||
|
|
||||||
impl Mainboard {
|
impl Mainboard {
|
||||||
pub fn create(ram: TransmutableBox, rom: TransmutableBox) -> Result<Self, Error> {
|
pub fn create(ram: TransmutableBox, rom: TransmutableBox) -> Result<Self, Error> {
|
||||||
let scc1 = Z8530::new();
|
let scc1 = Z8530::default();
|
||||||
let scc2 = Z8530::new();
|
let scc2 = Z8530::default();
|
||||||
let iwm = IWM::new();
|
let iwm = IWM::default();
|
||||||
let via = Mos6522::new();
|
let via = Mos6522::default();
|
||||||
let phase_read = PhaseRead::new();
|
let phase_read = PhaseRead::default();
|
||||||
|
|
||||||
let lower_bus = Rc::new(RefCell::new(Bus::new()));
|
let lower_bus = Rc::new(RefCell::new(Bus::default()));
|
||||||
|
|
||||||
let mainboard = Self {
|
let mainboard = Self {
|
||||||
lower_bus: lower_bus.clone(),
|
lower_bus: lower_bus.clone(),
|
||||||
|
@ -72,17 +72,17 @@ impl Addressable for Mainboard {
|
||||||
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
||||||
if addr < 0x800000 {
|
if addr < 0x800000 {
|
||||||
self.lower_bus.borrow_mut().read(addr, data)
|
self.lower_bus.borrow_mut().read(addr, data)
|
||||||
} else if addr >= 0x900000 && addr < 0xA00000 {
|
} else if (0x900000..0xA00000).contains(&addr) {
|
||||||
self.scc1.read((addr >> 9) & 0x0F, data)
|
self.scc1.read((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xB00000 && addr < 0xC00000 {
|
} else if (0xB00000..0xC00000).contains(&addr) {
|
||||||
self.scc2.read((addr >> 9) & 0x0F, data)
|
self.scc2.read((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xD00000 && addr < 0xE00000 {
|
} else if (0xD00000..0xE00000).contains(&addr) {
|
||||||
self.iwm.read((addr >> 9) & 0x0F, data)
|
self.iwm.read((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xE80000 && addr < 0xF00000 {
|
} else if (0xE80000..0xF00000).contains(&addr) {
|
||||||
self.via.read((addr >> 9) & 0x0F, data)
|
self.via.read((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xF00000 && addr < 0xF80000 {
|
} else if (0xF00000..0xF80000).contains(&addr) {
|
||||||
self.phase_read.read(addr, data)
|
self.phase_read.read(addr, data)
|
||||||
} else if addr >= 0xF80000 && addr < 0xF80010 {
|
} else if (0xF80000..0xF80010).contains(&addr) {
|
||||||
// Debugger
|
// Debugger
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,15 +93,15 @@ impl Addressable for Mainboard {
|
||||||
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
||||||
if addr < 0x800000 {
|
if addr < 0x800000 {
|
||||||
self.lower_bus.borrow_mut().write(addr, data)
|
self.lower_bus.borrow_mut().write(addr, data)
|
||||||
} else if addr >= 0x900000 && addr < 0xA00000 {
|
} else if (0x900000..0xA00000).contains(&addr) {
|
||||||
self.scc1.write((addr >> 9) & 0x0F, data)
|
self.scc1.write((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xB00000 && addr < 0xC00000 {
|
} else if (0xB00000..0xC00000).contains(&addr) {
|
||||||
self.scc2.write((addr >> 9) & 0x0F, data)
|
self.scc2.write((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xD00000 && addr < 0xE00000 {
|
} else if (0xD00000..0xE00000).contains(&addr) {
|
||||||
self.iwm.write((addr >> 9) & 0x0F, data)
|
self.iwm.write((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xE80000 && addr < 0xF00000 {
|
} else if (0xE80000..0xF00000).contains(&addr) {
|
||||||
self.via.write((addr >> 9) & 0x0F, data)
|
self.via.write((addr >> 9) & 0x0F, data)
|
||||||
} else if addr >= 0xF00000 && addr < 0xF80000 {
|
} else if (0xF00000..0xF80000).contains(&addr) {
|
||||||
self.phase_read.write(addr, data)
|
self.phase_read.write(addr, data)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new(&format!("Error writing address {:#010x}", addr)))
|
Err(Error::new(&format!("Error writing address {:#010x}", addr)))
|
||||||
|
@ -136,17 +136,11 @@ impl Transmutable for Mainboard {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct PhaseRead {
|
pub struct PhaseRead {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PhaseRead {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Addressable for PhaseRead {
|
impl Addressable for PhaseRead {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
0x80000
|
0x80000
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::peripherals::mainboard::Mainboard;
|
||||||
|
|
||||||
|
|
||||||
pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
|
pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
|
||||||
let mut system = System::new();
|
let mut system = System::default();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
use crate::peripherals::mos6522::Mos6522;
|
use crate::peripherals::mos6522::Mos6522;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use super::keymap;
|
||||||
use super::charset::CharacterGenerator;
|
use super::charset::CharacterGenerator;
|
||||||
|
|
||||||
|
|
||||||
const DEV_NAME: &'static str = "model1";
|
const DEV_NAME: &str = "model1";
|
||||||
const SCREEN_SIZE: (u32, u32) = (384, 128);
|
const SCREEN_SIZE: (u32, u32) = (384, 128);
|
||||||
|
|
||||||
pub struct Model1Peripherals {
|
pub struct Model1Peripherals {
|
||||||
|
@ -65,7 +65,7 @@ impl Addressable for Model1Peripherals {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
||||||
if addr >= 0x20 && addr <= 0xA0 {
|
if (0x20..=0xA0).contains(&addr) {
|
||||||
let offset = addr - 0x20;
|
let offset = addr - 0x20;
|
||||||
data[0] = 0;
|
data[0] = 0;
|
||||||
if (offset & 0x01) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[0]; }
|
if (offset & 0x01) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[0]; }
|
||||||
|
@ -77,7 +77,7 @@ impl Addressable for Model1Peripherals {
|
||||||
if (offset & 0x40) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[6]; }
|
if (offset & 0x40) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[6]; }
|
||||||
if (offset & 0x80) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[7]; }
|
if (offset & 0x80) != 0 { data[0] |= self.keyboard_mem.lock().unwrap()[7]; }
|
||||||
//info!("{}: read from keyboard {:x} of {:?}", DEV_NAME, addr, data);
|
//info!("{}: read from keyboard {:x} of {:?}", DEV_NAME, addr, data);
|
||||||
} else if addr >= 0x420 && addr <= 0x820 {
|
} else if (0x420..=0x820).contains(&addr) {
|
||||||
data[0] = self.video_mem[addr as usize - 0x420];
|
data[0] = self.video_mem[addr as usize - 0x420];
|
||||||
} else {
|
} else {
|
||||||
warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
|
warn!("{}: !!! unhandled read from {:0x}", DEV_NAME, addr);
|
||||||
|
@ -88,7 +88,7 @@ impl Addressable for Model1Peripherals {
|
||||||
|
|
||||||
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
||||||
debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
||||||
if addr >= 0x420 && addr < 0x820 {
|
if (0x420..0x820).contains(&addr) {
|
||||||
self.video_mem[addr as usize - 0x420] = data[0];
|
self.video_mem[addr as usize - 0x420] = data[0];
|
||||||
} else {
|
} else {
|
||||||
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
|
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
|
||||||
|
|
|
@ -13,8 +13,8 @@ pub struct Trs80Options {
|
||||||
pub frequency: u32,
|
pub frequency: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trs80Options {
|
impl Default for Trs80Options {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rom: "binaries/trs80/level2.rom".to_string(),
|
rom: "binaries/trs80/level2.rom".to_string(),
|
||||||
memory: 0xC000,
|
memory: 0xC000,
|
||||||
|
@ -25,7 +25,7 @@ impl Trs80Options {
|
||||||
|
|
||||||
|
|
||||||
pub fn build_trs80<H: Host>(host: &mut H, options: Trs80Options) -> Result<System, Error> {
|
pub fn build_trs80<H: Host>(host: &mut H, options: Trs80Options) -> Result<System, Error> {
|
||||||
let mut system = System::new();
|
let mut system = System::default();
|
||||||
|
|
||||||
let mut rom = MemoryBlock::new(vec![0; 0x3000]);
|
let mut rom = MemoryBlock::new(vec![0; 0x3000]);
|
||||||
//rom.load_at(0x0000, "binaries/trs80/level1.rom")?;
|
//rom.load_at(0x0000, "binaries/trs80/level1.rom")?;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user