303 lines
7.3 KiB
Rust
303 lines
7.3 KiB
Rust
|
|
use femtos::Instant;
|
|
|
|
use moa_core::{Error, Address, Addressable, BusPort};
|
|
|
|
use crate::state::{M68k, M68kError, Exceptions};
|
|
use crate::instructions::Size;
|
|
|
|
#[repr(u8)]
|
|
#[allow(dead_code)]
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub enum FunctionCode {
|
|
Reserved0 = 0,
|
|
UserData = 1,
|
|
UserProgram = 2,
|
|
Reserved3 = 3,
|
|
Reserved4 = 4,
|
|
SupervisorData = 5,
|
|
SupervisorProgram = 6,
|
|
CpuSpace = 7,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub enum MemType {
|
|
Program,
|
|
Data,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub enum MemAccess {
|
|
Read,
|
|
Write,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
// TODO change to MemoryState or RequestState or AccessState or maybe even BusState
|
|
pub struct MemoryRequest {
|
|
pub i_n_bit: bool,
|
|
pub access: MemAccess,
|
|
pub code: FunctionCode,
|
|
pub size: Size,
|
|
pub address: u32,
|
|
}
|
|
|
|
impl FunctionCode {
|
|
pub fn program(is_supervisor: bool) -> Self {
|
|
if is_supervisor {
|
|
FunctionCode::SupervisorProgram
|
|
} else {
|
|
FunctionCode::UserProgram
|
|
}
|
|
}
|
|
|
|
pub fn data(is_supervisor: bool) -> Self {
|
|
if is_supervisor {
|
|
FunctionCode::SupervisorData
|
|
} else {
|
|
FunctionCode::UserData
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for MemoryRequest {
|
|
fn default() -> Self {
|
|
Self {
|
|
i_n_bit: false,
|
|
access: MemAccess::Read,
|
|
code: FunctionCode::Reserved0,
|
|
size: Size::Word,
|
|
address: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MemoryRequest {
|
|
pub fn get_type_code(&self) -> u16 {
|
|
let ins = match self.i_n_bit {
|
|
false => 0x0000,
|
|
true => 0x0008,
|
|
};
|
|
|
|
let rw = match self.access {
|
|
MemAccess::Write => 0x0000,
|
|
MemAccess::Read => 0x0010,
|
|
};
|
|
|
|
ins | rw | (self.code as u16)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct M68kBusPort {
|
|
pub port: BusPort,
|
|
pub request: MemoryRequest,
|
|
pub cycle_start_clock: Instant,
|
|
pub current_clock: Instant,
|
|
}
|
|
|
|
|
|
impl M68k {
|
|
// TODO should some of the ones from execute.rs move here
|
|
}
|
|
|
|
impl M68kBusPort {
|
|
pub fn new(port: BusPort) -> Self {
|
|
Self {
|
|
port,
|
|
request: Default::default(),
|
|
cycle_start_clock: Instant::START,
|
|
current_clock: Instant::START,
|
|
}
|
|
}
|
|
|
|
pub fn data_width(&self) -> u8 {
|
|
self.port.data_width()
|
|
}
|
|
|
|
pub fn init_cycle(&mut self, clock: Instant) {
|
|
self.cycle_start_clock = clock;
|
|
self.current_clock = clock;
|
|
}
|
|
|
|
pub(crate) fn read_instruction_word(&mut self, is_supervisor: bool, addr: u32) -> Result<u16, M68kError> {
|
|
self.start_instruction_request(is_supervisor, addr)?;
|
|
Ok(self.port.read_beu16(self.current_clock, addr as Address)?)
|
|
}
|
|
|
|
pub(crate) fn read_instruction_long(&mut self, is_supervisor: bool, addr: u32) -> Result<u32, M68kError> {
|
|
self.start_instruction_request(is_supervisor, addr)?;
|
|
Ok(self.port.read_beu32(self.current_clock, addr as Address)?)
|
|
}
|
|
|
|
pub(crate) fn read_data_sized(&mut self, is_supervisor: bool, addr: Address, size: Size) -> Result<u32, M68kError> {
|
|
self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?;
|
|
Ok(match size {
|
|
Size::Byte => self.port.read_u8(self.current_clock, addr).map(|value| value as u32),
|
|
Size::Word => self.port.read_beu16(self.current_clock, addr).map(|value| value as u32),
|
|
Size::Long => self.port.read_beu32(self.current_clock, addr),
|
|
}?)
|
|
}
|
|
|
|
pub(crate) fn write_data_sized(&mut self, is_supervisor: bool, addr: Address, value: u32, size: Size) -> Result<(), M68kError> {
|
|
self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?;
|
|
Ok(match size {
|
|
Size::Byte => self.port.write_u8(self.current_clock, addr, value as u8),
|
|
Size::Word => self.port.write_beu16(self.current_clock, addr, value as u16),
|
|
Size::Long => self.port.write_beu32(self.current_clock, addr, value),
|
|
}?)
|
|
}
|
|
|
|
pub(crate) fn start_instruction_request(&mut self, is_supervisor: bool, addr: u32) -> Result<u32, M68kError> {
|
|
self.request.i_n_bit = false;
|
|
self.request.code = FunctionCode::program(is_supervisor);
|
|
self.request.access = MemAccess::Read;
|
|
self.request.address = addr;
|
|
|
|
validate_address(addr)
|
|
}
|
|
|
|
pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, M68kError> {
|
|
self.request.i_n_bit = i_n_bit;
|
|
self.request.code = match mtype {
|
|
MemType::Program => FunctionCode::program(is_supervisor),
|
|
MemType::Data => FunctionCode::data(is_supervisor),
|
|
};
|
|
|
|
self.request.access = access;
|
|
self.request.address = addr;
|
|
|
|
if size == Size::Byte {
|
|
Ok(addr)
|
|
} else {
|
|
validate_address(addr)
|
|
}
|
|
}
|
|
|
|
pub(crate) fn dump_memory(&mut self, addr: u32, length: usize) {
|
|
self.port.dump_memory(self.current_clock, addr as Address, length as u64);
|
|
}
|
|
}
|
|
|
|
fn validate_address(addr: u32) -> Result<u32, M68kError> {
|
|
if addr & 0x1 == 0 {
|
|
Ok(addr)
|
|
} else {
|
|
Err(M68kError::Exception(Exceptions::AddressError))
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
pub(crate) struct TargetAccess {
|
|
must_read: bool,
|
|
must_write: bool,
|
|
size: Size,
|
|
target: Target,
|
|
}
|
|
|
|
impl TargetAccess {
|
|
pub(crate) fn read_only(size: Size) -> Self {
|
|
|
|
}
|
|
|
|
pub(crate) fn read_update(size: Size) -> Self {
|
|
|
|
}
|
|
|
|
pub(crate) fn updated_only(size: Size) -> Self {
|
|
|
|
}
|
|
|
|
pub(crate) fn get(&mut self, cpu: &M68k) -> Result<u32, M68kError> {
|
|
|
|
}
|
|
|
|
pub(crate) fn set(&mut self, cpu: &M68k, value: u32) -> Result<(), M68kError> {
|
|
|
|
}
|
|
|
|
pub(crate) fn complete(&self) -> Result<Self, M68kError> {
|
|
|
|
}
|
|
}
|
|
|
|
|
|
impl Target {
|
|
pub(crate) fn read_once(self, size: Size) -> ReadOnceAccess {
|
|
ReadOnceAccess {
|
|
size,
|
|
target: self,
|
|
accessed: false,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn read_update(self, size: Size) -> ReadUpdateAccess {
|
|
ReadUpdateAccess {
|
|
size,
|
|
target: self,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn write_once(self, size: Size) -> WriteOnceAccess {
|
|
WriteOnceAccess {
|
|
size,
|
|
target: self,
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct ReadOnceAccess {
|
|
size: Size,
|
|
target: Target,
|
|
accessed: bool,
|
|
}
|
|
|
|
impl ReadOnceAccess {
|
|
pub(crate) fn get(&mut self, cpu: &M68k) -> Result<u32, M68kError> {
|
|
|
|
}
|
|
|
|
pub(crate) fn complete(&self) -> Result<Self, M68kError> {
|
|
|
|
}
|
|
}
|
|
|
|
pub(crate) struct ReadUpdateAccess {
|
|
size: Size,
|
|
target: Target,
|
|
}
|
|
|
|
impl ReadUpdateAccess {
|
|
pub(crate) fn get(&mut self, cpu: &M68k) -> Result<u32, M68kError> {
|
|
|
|
}
|
|
|
|
pub(crate) fn set(&mut self, cpu: &M68k, value: u32) -> Result<(), M68kError> {
|
|
|
|
}
|
|
|
|
pub(crate) fn complete(&self) -> Result<Self, M68kError> {
|
|
|
|
}
|
|
}
|
|
|
|
pub(crate) struct WriteOnceAccess {
|
|
size: Size,
|
|
target: Target,
|
|
}
|
|
|
|
impl WriteOnceAccess {
|
|
pub(crate) fn set(&mut self, cpu: &M68k, value: u32) -> Result<(), M68kError> {
|
|
|
|
}
|
|
|
|
pub(crate) fn complete(&self) -> Result<Self, M68kError> {
|
|
|
|
}
|
|
}
|
|
*/
|