summaryrefslogtreecommitdiff
path: root/src/devices/memory_device.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/memory_device.rs')
-rw-r--r--src/devices/memory_device.rs210
1 files changed, 115 insertions, 95 deletions
diff --git a/src/devices/memory_device.rs b/src/devices/memory_device.rs
index 0128d55..8efb12a 100644
--- a/src/devices/memory_device.rs
+++ b/src/devices/memory_device.rs
@@ -1,53 +1,73 @@
-use bedrock_core::*;
+use crate::*;
-type Page = [u8; 256];
-
-macro_rules! fn_read_head {
- ($fn_name:ident($offset:ident, $address:ident)) => {
- pub fn $fn_name(&mut self) -> u8 {
- let page_i = (self.$offset + (self.$address / 256)) as usize;
- let byte_i = (self.$address % 256) as usize;
- self.$address = self.$address.wrapping_add(1);
- match self.pages.get(page_i) {
- Some(page) => page[byte_i],
- None => 0,
- }
- }
- };
-}
+use std::cmp::min;
-macro_rules! fn_write_head {
- ($fn_name:ident($offset:ident, $address:ident)) => {
- pub fn $fn_name(&mut self, byte: u8) {
- let page_i = (self.$offset + (self.$address / 256)) as usize;
- let byte_i = (self.$address % 256) as usize;
- self.$address = self.$address.wrapping_add(1);
- match self.pages.get_mut(page_i) {
- Some(page) => page[byte_i] = byte,
- None => if page_i < self.provisioned {
- self.pages.resize(page_i + 1, [0; 256]);
- self.pages[page_i][byte_i] = byte;
- }
- }
- }
- };
-}
+type Page = [u8; 256];
pub struct MemoryDevice {
pub limit: u16, // maximum provisionable number of pages
pub requested: u16, // number of pages requested by program
pub provisioned: usize, // number of pages provisioned for use
pub pages: Vec<Page>, // all allocated pages
+ pub head_1: HeadAddress,
+ pub head_2: HeadAddress,
+ pub copy_length: u16,
+}
- pub offset_1: u16,
- pub address_1: u16,
- pub offset_2: u16,
- pub address_2: u16,
- pub copy_length: u16,
+impl Device for MemoryDevice {
+ fn read(&mut self, port: u8) -> u8 {
+ match port {
+ 0x0 => self.read_head_1(),
+ 0x1 => self.read_head_1(),
+ 0x2 => read_h!(self.head_1.offset),
+ 0x3 => read_l!(self.head_1.offset),
+ 0x4 => read_h!(self.head_1.address),
+ 0x5 => read_l!(self.head_1.address),
+ 0x6 => read_h!(self.provisioned),
+ 0x7 => read_l!(self.provisioned),
+ 0x8 => self.read_head_2(),
+ 0x9 => self.read_head_2(),
+ 0xa => read_h!(self.head_2.offset),
+ 0xb => read_l!(self.head_2.offset),
+ 0xc => read_h!(self.head_2.address),
+ 0xd => read_l!(self.head_2.address),
+ 0xe => 0x00,
+ 0xf => 0x00,
+ _ => unreachable!(),
+ }
+ }
+
+ fn write(&mut self, port: u8, value: u8) -> Option<Signal> {
+ match port {
+ 0x0 => self.write_head_1(value),
+ 0x1 => self.write_head_1(value),
+ 0x2 => write_h!(self.head_1.offset, value),
+ 0x3 => write_l!(self.head_1.offset, value),
+ 0x4 => write_h!(self.head_1.address, value),
+ 0x5 => write_l!(self.head_1.address, value),
+ 0x6 => write_h!(self.requested, value),
+ 0x7 => { write_l!(self.requested, value); self.provision(); },
+ 0x8 => self.write_head_2(value),
+ 0x9 => self.write_head_2(value),
+ 0xa => write_h!(self.head_2.offset, value),
+ 0xb => write_l!(self.head_2.offset, value),
+ 0xc => write_h!(self.head_2.address, value),
+ 0xd => write_l!(self.head_2.address, value),
+ 0xe => write_h!(self.copy_length, value),
+ 0xf => { write_l!(self.copy_length, value); self.copy(); },
+ _ => unreachable!(),
+ };
+ return None;
+ }
+
+ fn wake(&mut self) -> bool {
+ false
+ }
}
+
impl MemoryDevice {
pub fn new() -> Self {
Self {
@@ -55,34 +75,63 @@ impl MemoryDevice {
requested: 0,
provisioned: 0,
pages: Vec::new(),
+ head_1: HeadAddress::new(),
+ head_2: HeadAddress::new(),
+ copy_length: 0,
+ }
+ }
+
+ pub fn read_head_1(&mut self) -> u8 {
+ let (page_i, byte_i) = self.head_1.get_page_address();
+ self.read_byte(page_i, byte_i)
+ }
- offset_1: 0,
- address_1: 0,
- offset_2: 0,
- address_2: 0,
+ pub fn read_head_2(&mut self) -> u8 {
+ let (page_i, byte_i) = self.head_2.get_page_address();
+ self.read_byte(page_i, byte_i)
+ }
- copy_length: 0,
+ fn read_byte(&self, page_i: usize, byte_i: usize) -> u8 {
+ match self.pages.get(page_i) {
+ Some(page) => page[byte_i],
+ None => 0,
}
}
- fn_read_head! { read_head_1( offset_1, address_1) }
- fn_read_head! { read_head_2( offset_2, address_2) }
- fn_write_head!{ write_head_1(offset_1, address_1) }
- fn_write_head!{ write_head_2(offset_2, address_2) }
+ pub fn write_head_1(&mut self, value: u8) {
+ let (page_i, byte_i) = self.head_1.get_page_address();
+ self.write_byte(page_i, byte_i, value);
+ }
+
+ pub fn write_head_2(&mut self, value: u8) {
+ let (page_i, byte_i) = self.head_2.get_page_address();
+ self.write_byte(page_i, byte_i, value);
+ }
+
+ // Write a byte to a page of memory.
+ fn write_byte(&mut self, page_i: usize, byte_i: usize, value: u8) {
+ match self.pages.get_mut(page_i) {
+ Some(page) => page[byte_i] = value,
+ None => if page_i < self.provisioned {
+ self.pages.resize(page_i + 1, [0; 256]);
+ self.pages[page_i][byte_i] = value;
+ }
+ }
+ }
pub fn provision(&mut self) {
- self.provisioned = std::cmp::min(self.requested, self.limit) as usize;
+ self.provisioned = min(self.requested, self.limit) as usize;
// Defer allocation of new pages.
self.pages.truncate(self.provisioned as usize);
}
pub fn copy(&mut self) {
- let src = self.offset_2 as usize;
- let dest = self.offset_1 as usize;
+ let src = self.head_2.offset as usize;
+ let dest = self.head_1.offset as usize;
let count = self.copy_length as usize;
// Pre-allocate destination pages as needed.
- let pages_needed = std::cmp::min(dest + count, self.provisioned);
+ let pages_needed = min(dest + count, self.provisioned);
if pages_needed > self.pages.len() {
self.pages.resize(pages_needed, [0; 256]);
}
@@ -100,53 +149,24 @@ impl MemoryDevice {
}
}
-impl Device for MemoryDevice {
- fn read(&mut self, port: u8) -> u8 {
- match port {
- 0x0 => self.read_head_1(),
- 0x1 => self.read_head_1(),
- 0x2 => read_h!(self.offset_1),
- 0x3 => read_l!(self.offset_1),
- 0x4 => read_h!(self.address_1),
- 0x5 => read_l!(self.address_1),
- 0x6 => read_h!(self.provisioned),
- 0x7 => read_l!(self.provisioned),
- 0x8 => self.read_head_2(),
- 0x9 => self.read_head_2(),
- 0xa => read_h!(self.offset_2),
- 0xb => read_l!(self.offset_2),
- 0xc => read_h!(self.address_2),
- 0xd => read_l!(self.address_2),
- 0xe => 0x00,
- 0xf => 0x00,
- _ => unreachable!(),
- }
- }
- fn write(&mut self, port: u8, value: u8) -> Option<Signal> {
- match port {
- 0x0 => self.write_head_1(value),
- 0x1 => self.write_head_1(value),
- 0x2 => write_h!(self.offset_1, value),
- 0x3 => write_l!(self.offset_1, value),
- 0x4 => write_h!(self.address_1, value),
- 0x5 => write_l!(self.address_1, value),
- 0x6 => write_h!(self.requested, value),
- 0x7 => { write_l!(self.requested, value); self.provision(); },
- 0x8 => self.write_head_2(value),
- 0x9 => self.write_head_2(value),
- 0xa => write_h!(self.offset_2, value),
- 0xb => write_l!(self.offset_2, value),
- 0xc => write_h!(self.address_2, value),
- 0xd => write_l!(self.address_2, value),
- 0xe => write_h!(self.copy_length, value),
- 0xf => { write_l!(self.copy_length, value); self.copy(); },
- _ => unreachable!(),
- };
- return None;
+pub struct HeadAddress {
+ pub offset: u16,
+ pub address: u16,
+}
+
+impl HeadAddress {
+ pub fn new() -> Self {
+ Self {
+ offset: 0,
+ address: 0,
+ }
}
- fn wake(&mut self) -> bool {
- false
+ fn get_page_address(&mut self) -> (usize, usize) {
+ let page_i = (self.offset + (self.address / 256)) as usize;
+ let byte_i = (self.address % 256) as usize;
+ self.address = self.address.wrapping_add(1);
+ (page_i, byte_i)
}
}