initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+143
@@ -0,0 +1,143 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arc-swap"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5"
|
||||||
|
dependencies = [
|
||||||
|
"rustversion",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dsa-emu"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
|
"fxhash",
|
||||||
|
"ron",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fxhash"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ron"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"once_cell",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"typeid",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typeid"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "dsa-emu"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
arc-swap = "1.8.2"
|
||||||
|
fxhash = "0.2.1"
|
||||||
|
ron = "0.12.0"
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
LoadConfig(
|
||||||
|
// defined as the bootloader in dsa.mmap.ron
|
||||||
|
start_address: 0x1000,
|
||||||
|
|
||||||
|
// maximum allowed bootloader size (as to not overlap MMIO)
|
||||||
|
max_size: 0x4000,
|
||||||
|
)
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
MemoryMap(
|
||||||
|
table_addr: 0x1000,
|
||||||
|
regions: [
|
||||||
|
// 0000-1000 = reserved
|
||||||
|
Region(
|
||||||
|
base: 0x0,
|
||||||
|
size: 0x1000,
|
||||||
|
region_type: Reserved
|
||||||
|
),
|
||||||
|
// 1000-4000 = bootloader
|
||||||
|
Region(
|
||||||
|
base: 0x1000,
|
||||||
|
size: 0x3000,
|
||||||
|
region_type: Bootloader
|
||||||
|
),
|
||||||
|
// 5000-0FFFFFFF = MMIO
|
||||||
|
Region(
|
||||||
|
base: 0x5000,
|
||||||
|
size: 0x0FFF_FFFF,
|
||||||
|
region_type: MMIO
|
||||||
|
),
|
||||||
|
// 10000000-BFFFFFFF = userspace
|
||||||
|
Region(
|
||||||
|
base: 0x1000_0000,
|
||||||
|
size: 0xBFFF_FFFF,
|
||||||
|
region_type: Usable
|
||||||
|
),
|
||||||
|
// C0000000-C0FFFFFF = kernel page tables
|
||||||
|
Region(
|
||||||
|
base: 0xC000_0000,
|
||||||
|
size: 0x100_0000,
|
||||||
|
region_type: KernelTables
|
||||||
|
),
|
||||||
|
// C1000000-FFFFFFFF = kernel
|
||||||
|
Region(
|
||||||
|
base: 0xC100_0000,
|
||||||
|
size: 0x3EFF_FFFF,
|
||||||
|
region_type: Kernel
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
use arc_swap::ArcSwap;
|
||||||
|
use std::{
|
||||||
|
sync::{
|
||||||
|
Arc,
|
||||||
|
atomic::{AtomicBool, AtomicU8},
|
||||||
|
},
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::processor::{processor::Emulator, state::SharedState};
|
||||||
|
|
||||||
|
mod memory;
|
||||||
|
mod processor;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut emulator = Emulator::new();
|
||||||
|
let state = emulator.state_handle();
|
||||||
|
let runner = thread::spawn(move || emulator.run());
|
||||||
|
let observer = thread::spawn(|| observe(state));
|
||||||
|
|
||||||
|
runner.join().unwrap();
|
||||||
|
observer.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn observe(state: Arc<SharedState>) {
|
||||||
|
loop {
|
||||||
|
thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
let state = state.proc.load();
|
||||||
|
println!("GP Registers: {:?}", state.gp_registers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
use fxhash::FxHashMap;
|
||||||
|
|
||||||
|
use crate::memory::PhysAddr;
|
||||||
|
|
||||||
|
type Page = [u8; 4096];
|
||||||
|
|
||||||
|
pub struct MainStore {
|
||||||
|
pages: FxHashMap<PhysAddr, Page>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MainStore {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
pages: FxHashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
const fn segment_addr(addr: PhysAddr) -> (PhysAddr, usize) {
|
||||||
|
(addr & !(0xFFF), (addr & 0xFFF) as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_byte(&self, addr: PhysAddr) -> u8 {
|
||||||
|
let (page, offset) = Self::segment_addr(addr);
|
||||||
|
self.pages.get(&page).map(|p| p[offset]).unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_word(&self, addr: PhysAddr) -> u32 {
|
||||||
|
let (page, offset) = Self::segment_addr(addr);
|
||||||
|
let page = self.pages.get(&page).unwrap_or(&[0; 4096]);
|
||||||
|
u32::from_be_bytes(page[offset..=offset + 3].try_into().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_page(&self, addr: PhysAddr) -> &[u8] {
|
||||||
|
self.pages.get(&addr).unwrap_or(&[0; 4096])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_byte(&mut self, addr: PhysAddr, value: u8) {
|
||||||
|
let (page, offset) = Self::segment_addr(addr);
|
||||||
|
self.pages.entry(page).or_insert_with(|| [0; 4096])[offset] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_word(&mut self, addr: PhysAddr, value: u32) {
|
||||||
|
let (page, offset) = Self::segment_addr(addr);
|
||||||
|
let page = self.pages.entry(page).or_insert_with(|| [0; 4096]);
|
||||||
|
page[offset..=offset + 3].copy_from_slice(&value.to_be_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]) {
|
||||||
|
let (page, offset) = Self::segment_addr(addr);
|
||||||
|
let page = self.pages.entry(page).or_insert_with(|| [0; 4096]);
|
||||||
|
page[offset..offset + value.len()].copy_from_slice(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
use crate::memory::{FaultInfo, PhysAddr, VirtAddr, tlb::TLB};
|
||||||
|
|
||||||
|
pub struct MMU {
|
||||||
|
buffer: TLB,
|
||||||
|
enable_paging: bool,
|
||||||
|
|
||||||
|
// Memory Management Register (MMR) Tells MMU where to find page tables
|
||||||
|
mmr_value: u32,
|
||||||
|
|
||||||
|
page_table: Box<[Option<PageTable>; 1024]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MMU {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
MMU {
|
||||||
|
buffer: TLB::new(),
|
||||||
|
enable_paging: false,
|
||||||
|
mmr_value: 0,
|
||||||
|
page_table: Box::new([const { None }; 1024]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paging_enabled(&mut self, enable: bool) {
|
||||||
|
self.enable_paging = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tlb_insert(&mut self, virtual_address: VirtAddr, physical_address: PhysAddr) {
|
||||||
|
self.buffer.insert(virtual_address, physical_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_mapping(&mut self, virtual_address: VirtAddr, physical_address: PhysAddr) {
|
||||||
|
let table = (virtual_address >> 22) as usize;
|
||||||
|
let page = ((virtual_address >> 12) & 0x3FF) as usize;
|
||||||
|
|
||||||
|
self.page_table[table].get_or_insert_default().entries[page] =
|
||||||
|
Some(PageTableEntry::new(physical_address, true, true, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn lookup(&mut self, virtual_address: VirtAddr) -> Result<PhysAddr, FaultInfo> {
|
||||||
|
if !self.enable_paging {
|
||||||
|
return Ok(virtual_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(addr) = self.buffer.lookup(virtual_address) {
|
||||||
|
return Ok(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.walk(virtual_address)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[inline(never)]
|
||||||
|
fn walk(&mut self, virtual_address: VirtAddr) -> Result<PhysAddr, FaultInfo> {
|
||||||
|
let phys_addr = self.walk_page_table(virtual_address)?;
|
||||||
|
self.buffer.insert(virtual_address, phys_addr);
|
||||||
|
Ok(phys_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_page_table(&mut self, virtual_address: VirtAddr) -> Result<PhysAddr, FaultInfo> {
|
||||||
|
let table = (virtual_address >> 22) as usize;
|
||||||
|
let page = ((virtual_address >> 12) & 0x3FF) as usize;
|
||||||
|
|
||||||
|
if let Some(table) = &self.page_table[table] {
|
||||||
|
return table.entries[page]
|
||||||
|
.map(|entry| entry.physical_addr)
|
||||||
|
.ok_or(FaultInfo::PageFault);
|
||||||
|
} else {
|
||||||
|
Err(FaultInfo::PageFault)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct PageDir {
|
||||||
|
entries: Box<[PageTable; 1024]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct PageTable {
|
||||||
|
entries: Box<[Option<PageTableEntry>; 1024]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PageTable {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
entries: Box::new([None; 1024]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct PageTableEntry {
|
||||||
|
physical_addr: PhysAddr,
|
||||||
|
writable: bool,
|
||||||
|
present: bool,
|
||||||
|
user: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTableEntry {
|
||||||
|
fn new(physical_addr: PhysAddr, writable: bool, present: bool, user: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
physical_addr,
|
||||||
|
writable,
|
||||||
|
present,
|
||||||
|
user,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::memory::mmu::MMU;
|
||||||
|
|
||||||
|
mod cache;
|
||||||
|
pub mod mainstore;
|
||||||
|
pub mod mmu;
|
||||||
|
mod tlb;
|
||||||
|
|
||||||
|
pub type VirtAddr = u32;
|
||||||
|
pub type PhysAddr = u32;
|
||||||
|
|
||||||
|
pub enum FaultInfo {
|
||||||
|
PageFault,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
|
enum RegionType {
|
||||||
|
Reserved,
|
||||||
|
Bootloader,
|
||||||
|
Kernel,
|
||||||
|
KernelTables,
|
||||||
|
Usable,
|
||||||
|
MMIO,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
|
pub struct Region {
|
||||||
|
base: PhysAddr,
|
||||||
|
size: usize,
|
||||||
|
region_type: RegionType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct MemoryMap {
|
||||||
|
table_addr: PhysAddr,
|
||||||
|
pub regions: Vec<Region>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryMap {
|
||||||
|
pub const DEFAULT_MEMORY_MAP_ADDR: PhysAddr = 0x1000;
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
MemoryMap {
|
||||||
|
table_addr: Self::DEFAULT_MEMORY_MAP_ADDR,
|
||||||
|
regions: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn identity_map(mmu: &mut MMU, region: &Region) {
|
||||||
|
let first_page = region.base >> 12;
|
||||||
|
let page_count = (region.size >> 12) as u32;
|
||||||
|
|
||||||
|
for page in (first_page..first_page + page_count).map(|p| p << 12) {
|
||||||
|
mmu.create_mapping(page, page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MemoryMap {
|
||||||
|
fn default() -> Self {
|
||||||
|
ron::from_str(include_str!("../../config/dsa.mmap.ron")).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
use crate::memory::{PhysAddr, VirtAddr};
|
||||||
|
|
||||||
|
const TLB_SIZE: usize = 256;
|
||||||
|
const TLB_MASK: u32 = (TLB_SIZE - 1) as u32;
|
||||||
|
|
||||||
|
pub struct TLB {
|
||||||
|
entries: [TlbEntry; TLB_SIZE],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct TlbEntry {
|
||||||
|
virtual_address: VirtAddr,
|
||||||
|
physical_address: PhysAddr,
|
||||||
|
valid: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TLB {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TLB {
|
||||||
|
entries: [TlbEntry {
|
||||||
|
virtual_address: 0,
|
||||||
|
physical_address: 0,
|
||||||
|
valid: false,
|
||||||
|
}; TLB_SIZE],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn index(page: u32) -> usize {
|
||||||
|
let hash = page ^ (page >> 12);
|
||||||
|
(hash & TLB_MASK) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn lookup(&self, virtual_address: VirtAddr) -> Option<PhysAddr> {
|
||||||
|
let page = virtual_address >> 12; // for 4KB pages
|
||||||
|
let entry = self.entries[Self::index(page)];
|
||||||
|
if entry.valid && entry.virtual_address == virtual_address {
|
||||||
|
Some(entry.physical_address)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn insert(&mut self, virt: VirtAddr, phys: PhysAddr) {
|
||||||
|
let idx = Self::index(virt) as usize;
|
||||||
|
self.entries[idx] = TlbEntry {
|
||||||
|
virtual_address: virt,
|
||||||
|
physical_address: phys,
|
||||||
|
valid: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
pub enum Interrupt {
|
||||||
|
PageFault,
|
||||||
|
ProtectionFault,
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mod interrupts;
|
||||||
|
pub mod processor;
|
||||||
|
pub mod state;
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
use std::{sync::Arc, thread, time::Duration};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
memory::{FaultInfo, MemoryMap, mainstore::MainStore, mmu::MMU},
|
||||||
|
processor::{
|
||||||
|
interrupts::Interrupt,
|
||||||
|
state::{ProcessorSnapshot, SharedState},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Emulator {
|
||||||
|
internal_state: ProcessorSnapshot,
|
||||||
|
shared_state: Arc<SharedState>,
|
||||||
|
|
||||||
|
mmu: MMU,
|
||||||
|
mainstore: MainStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Emulator {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
internal_state: ProcessorSnapshot::default(),
|
||||||
|
shared_state: Arc::new(SharedState::new()),
|
||||||
|
mmu: MMU::new(),
|
||||||
|
mainstore: MainStore::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn state_handle(&self) -> Arc<SharedState> {
|
||||||
|
self.shared_state.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
let mut clock = 0;
|
||||||
|
|
||||||
|
let regions = MemoryMap::default();
|
||||||
|
|
||||||
|
self.mmu.paging_enabled(true);
|
||||||
|
MemoryMap::identity_map(&mut self.mmu, regions.regions.get(0).unwrap());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
thread::sleep(Duration::from_micros(1000));
|
||||||
|
|
||||||
|
match self.mmu.lookup(clock) {
|
||||||
|
Ok(addr) => {
|
||||||
|
let x = self.mainstore.read_word(addr);
|
||||||
|
println!("{}", x);
|
||||||
|
self.mainstore.write_word(addr, x + 1);
|
||||||
|
}
|
||||||
|
Err(FaultInfo::PageFault) => self.interrupt(Interrupt::PageFault),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.internal_state.gp_registers[0] += 10;
|
||||||
|
|
||||||
|
if clock % 1000 == 0 {
|
||||||
|
self.shared_state
|
||||||
|
.proc
|
||||||
|
.store(Arc::new(self.internal_state.clone()));
|
||||||
|
}
|
||||||
|
clock += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupt(&mut self, int: Interrupt) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
use std::sync::{
|
||||||
|
Arc,
|
||||||
|
atomic::{AtomicBool, AtomicU8},
|
||||||
|
};
|
||||||
|
|
||||||
|
use arc_swap::ArcSwap;
|
||||||
|
|
||||||
|
pub struct SharedState {
|
||||||
|
pub proc: ArcSwap<ProcessorSnapshot>,
|
||||||
|
|
||||||
|
pub running: AtomicBool,
|
||||||
|
pub interrupt: AtomicU8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
proc: ArcSwap::new(Arc::new(ProcessorSnapshot::default())),
|
||||||
|
|
||||||
|
running: AtomicBool::new(true),
|
||||||
|
interrupt: AtomicU8::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ProcessorSnapshot {
|
||||||
|
pub gp_registers: [u32; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ProcessorSnapshot {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
gp_registers: [0; 16],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user