use crate::*;
use std::cmp::min;
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,
}
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 {
limit: u16::MAX,
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)
}
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)
}
fn read_byte(&self, page_i: usize, byte_i: usize) -> u8 {
match self.pages.get(page_i) {
Some(page) => page[byte_i],
None => 0,
}
}
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 = 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.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 = min(dest + count, self.provisioned);
if pages_needed > self.pages.len() {
self.pages.resize(pages_needed, [0; 256]);
}
for i in 0..count {
let src_page = match self.pages.get(src + i) {
Some(src_page) => src_page.to_owned(),
None => [0; 256],
};
match self.pages.get_mut(dest + i) {
Some(dest) => *dest = src_page,
None => break,
};
}
}
}
pub struct HeadAddress {
pub offset: u16,
pub address: u16,
}
impl HeadAddress {
pub fn new() -> Self {
Self {
offset: 0,
address: 0,
}
}
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)
}
}