input/output instructions

This commit is contained in:
Martin Löffler 2023-01-29 00:33:18 +01:00
parent a97824b26e
commit 6955ca49ee
Signed by: FatalErrorCoded
GPG key ID: FFEF368AC076566A
3 changed files with 57 additions and 0 deletions

View file

@ -39,6 +39,16 @@ fn tick<M: MemoryMapper>(state: &mut EmulatorState<M>) {
0x00 => {} // NOP 0x00 => {} // NOP
/* Special */ /* Special */
0xd3 => {
// OUT
let port = state.next_byte();
state.write_io(port, state.a);
}
0xdb => {
// IN
let port = state.next_byte();
state.a = state.read_io(port);
}
0xfb => state.ei = true, // EI 0xfb => state.ei = true, // EI
0xf3 => state.ei = false, // DI 0xf3 => state.ei = false, // DI
0x76 => { 0x76 => {

View file

@ -1,6 +1,19 @@
pub trait MemoryMapper { pub trait MemoryMapper {
/// Read a byte at the specified address through the memory mapper
fn read(&mut self, address: u16) -> u8; fn read(&mut self, address: u16) -> u8;
/// Write a byte to the specified address through the memory mapper
fn write(&mut self, address: u16, value: u8); fn write(&mut self, address: u16, value: u8);
/// Receive a byte from a device on the I/O bus through the memory mapper
#[allow(unused_variables)]
fn read_io(&mut self, port: u8) -> u8 {
0
}
/// Send a byte to a device on the I/O bus through the memory mapper
#[allow(unused_variables)]
fn write_io(&mut self, port: u8, value: u8) {}
} }
//#[cfg(test)] //#[cfg(test)]

View file

@ -47,12 +47,20 @@ impl<M: MemoryMapper> EmulatorState<M> {
} }
/// Read a byte at a specific address /// Read a byte at a specific address
///
/// May return an indeterminate value if an invalid region is accessed.
/// May cause internal mapper state (eg. interrupts, emulated shift
/// registers) to be updated. Subsequent reads from the same address may
/// yield different values.
#[inline] #[inline]
pub fn read_byte(&mut self, address: u16) -> u8 { pub fn read_byte(&mut self, address: u16) -> u8 {
self.mapper.read(address) self.mapper.read(address)
} }
/// Write a byte at a specific address /// Write a byte at a specific address
///
/// May do nothing if an invalid region is accessed. Subsequent reads
/// from the same address may yield different values.
#[inline] #[inline]
pub fn write_byte(&mut self, address: u16, value: u8) { pub fn write_byte(&mut self, address: u16, value: u8) {
self.mapper.write(address, value); self.mapper.write(address, value);
@ -67,6 +75,11 @@ impl<M: MemoryMapper> EmulatorState<M> {
} }
/// Read a 16-bit word at a specific address /// Read a 16-bit word at a specific address
///
/// May return an indeterminate value if an invalid region is accessed.
/// May cause internal mapper state (eg. interrupts, emulated shift
/// registers) to be updated. Subsequent reads from the same address may
/// yield different values.
#[inline] #[inline]
pub fn read_word(&mut self, address: u16) -> u16 { pub fn read_word(&mut self, address: u16) -> u16 {
u16::from_le_bytes([ u16::from_le_bytes([
@ -76,6 +89,9 @@ impl<M: MemoryMapper> EmulatorState<M> {
} }
/// Write a 16-bit word at a specific address /// Write a 16-bit word at a specific address
///
/// May do nothing if an invalid region is accessed. Subsequent reads
/// from the same address may yield different values.
#[inline] #[inline]
pub fn write_word(&mut self, address: u16, value: u16) { pub fn write_word(&mut self, address: u16, value: u16) {
let [low, high] = u16::to_le_bytes(value); let [low, high] = u16::to_le_bytes(value);
@ -90,6 +106,24 @@ impl<M: MemoryMapper> EmulatorState<M> {
(self.pc, ..) = self.pc.overflowing_add(2); (self.pc, ..) = self.pc.overflowing_add(2);
value value
} }
/// Receive a byte from a device on the I/O bus
///
/// May return an indeterminate value if an invalid device is accessed.
/// May (and usually will) cause internal mapper state (eg. interrupts)
/// to be updated.
#[inline]
pub fn read_io(&mut self, port: u8) -> u8 {
self.mapper.read_io(port)
}
/// Send a byte to a device on the I/O bus
///
/// May do nothing if an invalid device is accessed.
#[inline]
pub fn write_io(&mut self, port: u8, value: u8) {
self.mapper.write_io(port, value);
}
} }
impl<M: MemoryMapper + Default> Default for EmulatorState<M> { impl<M: MemoryMapper + Default> Default for EmulatorState<M> {