diff --git a/.idea/dsa2.iml b/.idea/dsa2.iml
index 40aec87..433611a 100644
--- a/.idea/dsa2.iml
+++ b/.idea/dsa2.iml
@@ -5,9 +5,11 @@
-
-
+
+
+
+
diff --git a/Cargo.toml b/Cargo.toml
index f9d7779..1b5ed0a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[workspace]
-members = ["dsa/common", "dsa/assembler", "dsa/emulator", "dsa/linker", "dsa/compiler"]
+members = ["dsa/common", "dsa/assembler", "dsa/emulator/frontend", "dsa/linker", "dsa/compiler", "dsa/emulator/backend"]
resolver = "3"
[workspace.package]
diff --git a/dsa/assembler/src/disassembler.rs b/dsa/assembler/src/disassembler.rs
new file mode 100644
index 0000000..457489a
--- /dev/null
+++ b/dsa/assembler/src/disassembler.rs
@@ -0,0 +1,158 @@
+use std::fs;
+use std::path::PathBuf;
+use std::io::{Cursor, Read, Seek, SeekFrom, Write};
+use std::fs::File;
+use binrw::{binrw, BinRead, binwrite, NullString, BinReaderExt, BinWriterExt, BinWrite};
+
+use common::prelude::Instruction;
+use crate::assembler::Symbol;
+
+pub fn disassemble(in_path: PathBuf, out_path: PathBuf) -> Result<(), String> {
+
+ let Ok(content) = fs::read(in_path) else {
+ return Err(String::new())
+ };
+
+ for (line_num, chunk) in content.chunks(4).enumerate() {
+ let address = line_num * 4;
+
+ let value = u32::from_le_bytes(*chunk.as_array().unwrap());
+ println!("{:#?}", Instruction(value));
+ }
+ Ok(())
+}
+
+
+#[binrw]
+#[brw(magic = b"DSAX", little)]
+#[derive(Debug, Clone)]
+struct DseHeader {
+ version: u16,
+ flags: u16,
+ entry_point: u32,
+
+ symbol_table_offset: u32,
+ symbol_table_size: u32,
+
+ string_table_offset: u32,
+ string_table_size: u32,
+
+ data_offset: u32,
+ data_size: u32,
+
+ text_offset: u32,
+ text_size: u32
+}
+
+#[binrw]
+#[brw(little)]
+#[derive(Debug, Clone)]
+struct SymbolEntry {
+ name_offset: u32,
+ value: u32,
+ section: u8,
+ binding: u8,
+ _pad: u16
+}
+
+#[derive(Debug, Clone)]
+struct DseExecutable {
+ header: DseHeader,
+ symbols: Vec,
+ string_table: Vec,
+ data: Vec,
+ text: Vec
+}
+
+impl DseExecutable {
+ fn load(path: PathBuf) -> binrw::BinResult {
+ let mut file = File::open(path).map_err(|e| binrw::Error::Io(e))?;
+ Self::read(&mut file)
+ }
+
+ fn read(reader: &mut R) -> binrw::BinResult {
+ let header = DseHeader::read(reader)?;
+
+ reader.seek(SeekFrom::Start(header.symbol_table_offset as u64))?;
+ let symbols: Vec = (0..header.symbol_table_size)
+ .map(|_| SymbolEntry::read(reader))
+ .collect::>()?;
+
+ reader.seek(SeekFrom::Start(header.string_table_offset as u64))?;
+ let mut string_table = vec![0u8; header.string_table_size as usize];
+ reader.read_exact(&mut string_table).map_err(|e| binrw::Error::Io(e))?;
+
+ reader.seek(SeekFrom::Start(header.data_offset as u64))?;
+ let mut data = vec![0u8; header.data_size as usize];
+ reader.read_exact(&mut data).map_err(|e| binrw::Error::Io(e))?;
+
+ reader.seek(SeekFrom::Start(header.text_offset as u64))?;
+ let text: Vec = (0..header.text_size)
+ .map(|_| reader.read_le::())
+ .collect::>()?;
+
+ Ok(DseExecutable { header, symbols, string_table, data, text })
+ }
+
+ fn save(&self, path: PathBuf) -> binrw::BinResult<()> {
+ let mut file = File::create(path)
+ .map_err(|e| binrw::Error::Io(e))?;
+ self.write(&mut file)
+ }
+
+ fn write(&self, writer: &mut W) -> binrw::BinResult<()> {
+ self.header.write(writer)?;
+
+ for symbol in &self.symbols {
+ symbol.write(writer)?;
+ }
+
+ writer.write_all(&self.string_table)?;
+ writer.write_all(&self.data)?;
+
+ for word in &self.text {
+ writer.write_le(word)?;
+ }
+
+ Ok(())
+ }
+
+ fn new(
+ symbols: &[SymbolEntry],
+ string_table: &[u8],
+ data: &[u8],
+ text: &[u32],
+ entry_point: u32,
+ ) -> DseExecutable {
+ const HEADER_SIZE: u32 = 4 + 2 + 2 + 4 + 4*2 + 4*2 + 4*2 + 4*2; // adjust to actual packed size
+
+ let symbol_table_offset = HEADER_SIZE;
+ let symbol_table_size = symbols.len() as u32 * 8; // 4+4+1+1+2 padded = 8 bytes each
+ let string_table_offset = symbol_table_offset + symbol_table_size;
+ let data_offset = string_table_offset + string_table.len() as u32;
+ let text_offset = data_offset + data.len() as u32;
+
+ let header = DseHeader {
+ version: 1,
+ flags: 0,
+ entry_point,
+ symbol_table_offset,
+ symbol_table_size: symbols.len() as u32,
+ string_table_offset,
+ string_table_size: string_table.len() as u32,
+ data_offset,
+ data_size: data.len() as u32,
+ text_offset,
+ text_size: text.len() as u32,
+ };
+
+ DseExecutable {
+ header,
+ symbols: symbols.to_vec(),
+ string_table: string_table.to_vec(),
+ data: data.to_vec(),
+ text: text.to_vec(),
+ }
+ }
+}
+
diff --git a/dsa/common/src/isa/register.rs b/dsa/common/src/isa/register.rs
index 113b7ce..1b653f6 100644
--- a/dsa/common/src/isa/register.rs
+++ b/dsa/common/src/isa/register.rs
@@ -56,7 +56,7 @@ impl std::fmt::Display for Register {
impl Register {
/// Total number of registers, not counting Null as it's not a real register.
- /// reading or writing to Null is undefined behaviour.
+ /// reading or writing to Null is undefined behaviour!!
pub const COUNT: u8 = Self::Null as u8;
/// # Safety
diff --git a/dsa/emulator/backend/Cargo.toml b/dsa/emulator/backend/Cargo.toml
new file mode 100644
index 0000000..a19d96d
--- /dev/null
+++ b/dsa/emulator/backend/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "emu_core"
+edition.workspace = true
+version.workspace = true
+authors.workspace = true
+
+[lib]
+name = "emu_core"
+path = "src/lib.rs"
+
+[dependencies]
+arc-swap = "1.9.2"
+common = { version = "0.1.0", path = "../../common" }
+serde = { version = "1.0.228", features = ["derive"] }
+ron = "0.12.2"
diff --git a/dsa/emulator/backend/src/config/default/dsa.iomap.ron b/dsa/emulator/backend/src/config/default/dsa.iomap.ron
new file mode 100644
index 0000000..c5772d3
--- /dev/null
+++ b/dsa/emulator/backend/src/config/default/dsa.iomap.ron
@@ -0,0 +1,10 @@
+/* @[crate::config::IoMap] */
+IoMap(
+ items: [
+ IoMapping(
+ device: "Display",
+ base: 0x0002_0000,
+ size: 0x0000_07D0, // 2000 bytes (80x25)
+ ),
+ ]
+)
diff --git a/dsa/emulator/src/config/default/dsa.mmap.ron b/dsa/emulator/backend/src/config/default/dsa.mmap.ron
similarity index 96%
rename from dsa/emulator/src/config/default/dsa.mmap.ron
rename to dsa/emulator/backend/src/config/default/dsa.mmap.ron
index defd625..d80b68e 100644
--- a/dsa/emulator/src/config/default/dsa.mmap.ron
+++ b/dsa/emulator/backend/src/config/default/dsa.mmap.ron
@@ -1,3 +1,4 @@
+/* @[crate::config::MemoryMap] */
MemoryMap(
table_addr: 0x1000,
regions: [
diff --git a/dsa/emulator/backend/src/config/default/mod.rs b/dsa/emulator/backend/src/config/default/mod.rs
new file mode 100644
index 0000000..fd36e72
--- /dev/null
+++ b/dsa/emulator/backend/src/config/default/mod.rs
@@ -0,0 +1,2 @@
+pub const DEFAULT_MEMORY_MAP: &'static str = include_str!("./dsa.mmap.ron");
+pub const DEFAULT_IO_MAP: &'static str = include_str!("./dsa.iomap.ron");
\ No newline at end of file
diff --git a/dsa/emulator/src/config/mod.rs b/dsa/emulator/backend/src/config/mod.rs
similarity index 77%
rename from dsa/emulator/src/config/mod.rs
rename to dsa/emulator/backend/src/config/mod.rs
index 76f440f..b86b866 100644
--- a/dsa/emulator/src/config/mod.rs
+++ b/dsa/emulator/backend/src/config/mod.rs
@@ -1,10 +1,10 @@
use serde::{Deserialize, Serialize};
+use crate::config::default::{DEFAULT_IO_MAP, DEFAULT_MEMORY_MAP};
+use crate::memory::mmu::MMU;
+use crate::memory::PhysAddr;
+use crate::processor::processor::Emulator;
-use crate::{
- Emulator,
- backend::memory::{PhysAddr, mmu::MMU},
- // io::DeviceId,
-};
+mod default;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -25,7 +25,7 @@ pub struct Region {
pub size: u32,
pub region_type: RegionType,
- // flags for the emulator
+ // flags for the ui
#[serde(default)]
pub identity_map_on_boot: bool,
}
@@ -38,11 +38,26 @@ pub struct MemoryMap {
#[derive(Serialize, Deserialize)]
pub struct IoMapping {
- // pub device: DeviceId,
+ pub device: String,
pub base: u32,
pub size: u32,
}
+#[derive(Serialize, Deserialize)]
+pub struct IoMap { items: Vec }
+
+impl Default for IoMap {
+ fn default() -> Self {
+ ron::from_str(DEFAULT_IO_MAP).unwrap()
+ }
+}
+
+impl Default for MemoryMap {
+ fn default() -> Self {
+ ron::from_str(DEFAULT_MEMORY_MAP).unwrap()
+ }
+}
+
impl MemoryMap {
pub const DEFAULT_MEMORY_MAP_ADDR: PhysAddr = 0x1000;
diff --git a/dsa/emulator/backend/src/lib.rs b/dsa/emulator/backend/src/lib.rs
new file mode 100644
index 0000000..330a163
--- /dev/null
+++ b/dsa/emulator/backend/src/lib.rs
@@ -0,0 +1,5 @@
+#![feature(likely_unlikely)]
+
+pub mod processor;
+pub mod memory;
+pub mod config;
\ No newline at end of file
diff --git a/dsa/emulator/src/backend/memory/cache.rs b/dsa/emulator/backend/src/memory/cache.rs
similarity index 100%
rename from dsa/emulator/src/backend/memory/cache.rs
rename to dsa/emulator/backend/src/memory/cache.rs
diff --git a/dsa/emulator/src/backend/memory/mmu.rs b/dsa/emulator/backend/src/memory/mmu.rs
similarity index 97%
rename from dsa/emulator/src/backend/memory/mmu.rs
rename to dsa/emulator/backend/src/memory/mmu.rs
index 6afe4af..761634d 100644
--- a/dsa/emulator/src/backend/memory/mmu.rs
+++ b/dsa/emulator/backend/src/memory/mmu.rs
@@ -1,4 +1,4 @@
-use crate::backend::memory::{FaultInfo, PhysAddr, VirtAddr, tlb::TLB};
+use crate::memory::{FaultInfo, PhysAddr, VirtAddr, tlb::TLB};
pub struct MMU {
buffer: TLB,
diff --git a/dsa/emulator/src/backend/memory/mod.rs b/dsa/emulator/backend/src/memory/mod.rs
similarity index 100%
rename from dsa/emulator/src/backend/memory/mod.rs
rename to dsa/emulator/backend/src/memory/mod.rs
diff --git a/dsa/emulator/src/backend/memory/ram.rs b/dsa/emulator/backend/src/memory/ram.rs
similarity index 99%
rename from dsa/emulator/src/backend/memory/ram.rs
rename to dsa/emulator/backend/src/memory/ram.rs
index 3a7dea9..96890d8 100644
--- a/dsa/emulator/src/backend/memory/ram.rs
+++ b/dsa/emulator/backend/src/memory/ram.rs
@@ -28,7 +28,7 @@ pub use bulkalloc::BulkAllocStore;
// #[cfg(feature = "mainstore-prealloc")]
// pub use prealloc::PreAllocStore;
-use crate::backend::memory::PhysAddr;
+use crate::memory::PhysAddr;
#[repr(transparent)]
#[derive(Clone)]
diff --git a/dsa/emulator/src/backend/memory/tlb.rs b/dsa/emulator/backend/src/memory/tlb.rs
similarity index 96%
rename from dsa/emulator/src/backend/memory/tlb.rs
rename to dsa/emulator/backend/src/memory/tlb.rs
index f6d6da4..2a04745 100644
--- a/dsa/emulator/src/backend/memory/tlb.rs
+++ b/dsa/emulator/backend/src/memory/tlb.rs
@@ -1,4 +1,4 @@
-use crate::backend::memory::{PhysAddr, VirtAddr};
+use crate::memory::{PhysAddr, VirtAddr};
const TLB_SIZE: usize = 256;
const TLB_MASK: u32 = (TLB_SIZE - 1) as u32;
diff --git a/dsa/emulator/src/backend/processor/interrupts.rs b/dsa/emulator/backend/src/processor/interrupts.rs
similarity index 100%
rename from dsa/emulator/src/backend/processor/interrupts.rs
rename to dsa/emulator/backend/src/processor/interrupts.rs
diff --git a/dsa/emulator/src/backend/processor/mod.rs b/dsa/emulator/backend/src/processor/mod.rs
similarity index 100%
rename from dsa/emulator/src/backend/processor/mod.rs
rename to dsa/emulator/backend/src/processor/mod.rs
diff --git a/dsa/emulator/src/backend/processor/processor.rs b/dsa/emulator/backend/src/processor/processor.rs
similarity index 95%
rename from dsa/emulator/src/backend/processor/processor.rs
rename to dsa/emulator/backend/src/processor/processor.rs
index f9a0b37..f2c75b5 100644
--- a/dsa/emulator/src/backend/processor/processor.rs
+++ b/dsa/emulator/backend/src/processor/processor.rs
@@ -10,13 +10,22 @@ use std::{
time::{Duration, Instant},
};
-use crate::{
- MemoryBank, Page, SharedState,
- backend::{memory::mmu::MMU, processor::interrupts::Interrupt},
- config::{MemoryMap, RegionType},
+use common::{
+ isa::instructions::{Instruction, Opcode},
+ isa::register::Register
};
-use common::isa::instructions::{Instruction, Opcode};
-use common::isa::register::Register;
+use crate::{
+ memory::{
+ mmu::MMU,
+ ram::MemoryBank
+ },
+ processor::{
+ interrupts::Interrupt,
+ state::SharedState
+ }
+};
+use crate::config::{MemoryMap, RegionType};
+use crate::memory::ram::Page;
pub struct Emulator {
internal_state: ProcessorSnapshot,
@@ -197,13 +206,13 @@ impl Emulator {
return;
}
- // UI is resetting the emulator
+ // UI is resetting the ui
self.check_update();
}
}
pub fn run(&mut self) -> Result<(), String> {
- // wait for UI to initialise emulator.
+ // wait for UI to initialise ui.
if self.shared_state.paused.load(Ordering::Relaxed) {
self.wait_for_instructions();
}
@@ -324,9 +333,15 @@ impl Emulator {
)
}
Some(Opcode::Ldh) => {
- *self.mut_reg(word.dest_uc()) = u32::from(
- self.mem_read_word(self.reg(word.src1_uc()) + word.imm16() as u32) >> 16,
- )
+ let addr = self.reg(word.src1_uc()) + word.imm16() as u32;
+
+ let hi = self.mem_read_byte(addr) as u32;
+ let lo = self.mem_read_byte(addr + 1) as u32;
+ *self.mut_reg(word.dest_uc()) = (hi << 8) | lo;
+
+ // *self.mut_reg(word.dest_uc()) = u32::from(
+ // self.mem_read_word(self.reg(word.src1_uc()) + word.imm16() as u32) >> 16,
+ // )
}
Some(Opcode::Ldw) => {
*self.mut_reg(word.dest_uc()) = u32::from(
@@ -515,7 +530,7 @@ impl Emulator {
#[inline]
fn mem_write_byte(&mut self, addr: u32, val: u8) {
if addr == 0x40000 || addr == 0x40001 || addr == 0x40002 || addr == 0x40003 {
- eprintln!("emulator wrote 0x{:08x} to uart + {}", val, addr - 0x40000);
+ eprintln!("ui wrote 0x{:08x} to uart + {}", val, addr - 0x40000);
if addr == 0x40001 || addr == 0x40003 {
eprintln!("writing char {} to uart + {}", val as char, addr - 0x40000);
diff --git a/dsa/emulator/src/backend/processor/state.rs b/dsa/emulator/backend/src/processor/state.rs
similarity index 91%
rename from dsa/emulator/src/backend/processor/state.rs
rename to dsa/emulator/backend/src/processor/state.rs
index c34f1a0..839a15e 100644
--- a/dsa/emulator/src/backend/processor/state.rs
+++ b/dsa/emulator/backend/src/processor/state.rs
@@ -2,7 +2,7 @@ use std::sync::{Arc, atomic::AtomicBool, mpsc};
use arc_swap::ArcSwap;
-use crate::backend::processor::processor::ProcessorSnapshot;
+use crate::processor::processor::ProcessorSnapshot;
use super::interrupts::Interrupt;
diff --git a/dsa/emulator/Cargo.toml b/dsa/emulator/frontend/Cargo.toml
similarity index 87%
rename from dsa/emulator/Cargo.toml
rename to dsa/emulator/frontend/Cargo.toml
index cf12517..7bbcac8 100644
--- a/dsa/emulator/Cargo.toml
+++ b/dsa/emulator/frontend/Cargo.toml
@@ -22,15 +22,16 @@ fxhash = "0.2.1"
ron = "0.12.0"
serde = { version = "1.0.228", features = ["derive"] }
-common = { path = "../common" }
+common = { path = "../../common" }
egui = "0.33.3"
eframe = "0.33.3"
egui_tiles = "0.14.1"
egui_code_editor = "0.2.21"
egui_file = "0.25.0"
dirs = "6.0.0"
-assembler = { path = "../assembler" }
+assembler = { path = "../../assembler" }
egui_extras = "0.33.3"
+emu_core = { version = "0.3.0", path = "../backend" }
[features]
default = ["mainstore-prealloc"]
diff --git a/dsa/emulator/font/JetBrainsMonoNerdFontMono_Regular.ttf b/dsa/emulator/frontend/font/JetBrainsMonoNerdFontMono_Regular.ttf
similarity index 100%
rename from dsa/emulator/font/JetBrainsMonoNerdFontMono_Regular.ttf
rename to dsa/emulator/frontend/font/JetBrainsMonoNerdFontMono_Regular.ttf
diff --git a/dsa/emulator/src/args.rs b/dsa/emulator/frontend/src/args.rs
similarity index 82%
rename from dsa/emulator/src/args.rs
rename to dsa/emulator/frontend/src/args.rs
index a35ecfd..a1f3f41 100644
--- a/dsa/emulator/src/args.rs
+++ b/dsa/emulator/frontend/src/args.rs
@@ -2,7 +2,7 @@ use std::{fs, path::PathBuf};
use clap::Parser;
-use crate::config::{IoMapping, MemoryMap};
+use emu_core::config::{IoMap, IoMapping, MemoryMap};
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
@@ -36,7 +36,7 @@ impl DsaArgs {
.and_then(|map| ron::from_str(&map).ok())
})
.unwrap_or_else(|| {
- ron::from_str(include_str!("./config/default/dsa.mmap.ron")).unwrap()
+ MemoryMap::default()
})
}
@@ -46,7 +46,7 @@ impl DsaArgs {
.and_then(|path| Some(fs::read(path).unwrap()))
}
- pub fn get_io_map(&self) -> Vec {
+ pub fn get_io_map(&self) -> IoMap {
self.io_map
.as_ref()
.and_then(|m| {
@@ -55,7 +55,7 @@ impl DsaArgs {
.and_then(|map| ron::from_str(&map).ok())
})
.unwrap_or_else(|| {
- ron::from_str(include_str!("./config/default/dsa.iomap.ron")).unwrap()
+ IoMap::default()
})
}
}
diff --git a/dsa/emulator/frontend/src/lib.rs b/dsa/emulator/frontend/src/lib.rs
new file mode 100644
index 0000000..b0cb793
--- /dev/null
+++ b/dsa/emulator/frontend/src/lib.rs
@@ -0,0 +1,7 @@
+#![feature(likely_unlikely)]
+#![feature(inherent_associated_types)]
+#![feature(str_as_str)]
+
+pub mod ui;
+pub mod args;
+
diff --git a/dsa/emulator/src/main.rs b/dsa/emulator/frontend/src/main.rs
similarity index 93%
rename from dsa/emulator/src/main.rs
rename to dsa/emulator/frontend/src/main.rs
index 1d9e154..fec9a96 100644
--- a/dsa/emulator/src/main.rs
+++ b/dsa/emulator/frontend/src/main.rs
@@ -1,8 +1,11 @@
use clap::Parser;
use common::prelude::Instruction;
-use dsa::{Emulator, Page, args::DsaArgs, frontend::run_app};
use std::thread;
+use dsa::args::DsaArgs;
+use dsa::ui::run_app;
+use emu_core::memory::ram::Page;
+use emu_core::processor::processor::Emulator;
const STACK_SIZE: usize = 1024 * 1024 * 16;
diff --git a/dsa/emulator/src/frontend/components/controller.rs b/dsa/emulator/frontend/src/ui/components/controller.rs
similarity index 95%
rename from dsa/emulator/src/frontend/components/controller.rs
rename to dsa/emulator/frontend/src/ui/components/controller.rs
index 254a775..4a17b3e 100644
--- a/dsa/emulator/src/frontend/components/controller.rs
+++ b/dsa/emulator/frontend/src/ui/components/controller.rs
@@ -1,9 +1,9 @@
use std::sync::{Arc, atomic::Ordering};
use super::Component;
-use crate::{MemoryBank, SharedState};
-
use common::prelude::Register;
+use emu_core::memory::ram::MemoryBank;
+use emu_core::processor::state::SharedState;
pub struct Controller {
state: Arc,
@@ -57,7 +57,7 @@ impl Component for Controller {
// });
// }
- // Resets the emulator and all attached devices
+ // Resets the ui and all attached devices
if ui.button("Reset All").clicked() {
self.state.reseting.store(true, Ordering::Relaxed);
self.mem.clear();
diff --git a/dsa/emulator/src/frontend/components/display.rs b/dsa/emulator/frontend/src/ui/components/display.rs
similarity index 97%
rename from dsa/emulator/src/frontend/components/display.rs
rename to dsa/emulator/frontend/src/ui/components/display.rs
index bad05ae..d303c95 100644
--- a/dsa/emulator/src/frontend/components/display.rs
+++ b/dsa/emulator/frontend/src/ui/components/display.rs
@@ -1,7 +1,6 @@
use egui::{Color32, FontId, Vec2};
-
-use crate::{MemoryBank, Page, backend::memory::PhysAddr};
-
+use emu_core::memory::PhysAddr;
+use emu_core::memory::ram::{MemoryBank, Page};
use super::Component;
pub struct Display {
diff --git a/dsa/emulator/src/frontend/components/editor/mod.rs b/dsa/emulator/frontend/src/ui/components/editor/mod.rs
similarity index 99%
rename from dsa/emulator/src/frontend/components/editor/mod.rs
rename to dsa/emulator/frontend/src/ui/components/editor/mod.rs
index 6d36e45..db5e7e4 100644
--- a/dsa/emulator/src/frontend/components/editor/mod.rs
+++ b/dsa/emulator/frontend/src/ui/components/editor/mod.rs
@@ -15,9 +15,8 @@ use egui::{Align, Context, Key, Layout, Ui};
use egui_code_editor::{CodeEditor, ColorTheme, Completer, Syntax};
use egui_extras::{Column, TableBuilder};
use egui_file::FileDialog;
-
-use crate::{MemoryBank, Page, SharedState};
-
+use emu_core::memory::ram::{MemoryBank, Page};
+use emu_core::processor::state::SharedState;
use super::Component;
pub struct Editor {
@@ -86,7 +85,7 @@ impl Component for Editor {
Layout::left_to_right(Align::Min),
|ui| {
if self.show_output {
- egui::SidePanel::right("Editor Output").show_inside(ui, |ui| {
+ egui::SidePanel::right("Editor Output").resizable(false).show_inside(ui, |ui| {
self.output.ui(ui, ctx);
});
}
@@ -327,7 +326,7 @@ impl Editor {
fn render_editor(&mut self, ui: &mut Ui, _ctx: &Context) {
let available_width = ui.available_width();
- let mut editor = self.editor.clone().desired_width(available_width - 500.0);
+ let mut editor = self.editor.clone().desired_width(available_width);
editor.show_with_completer(ui, &mut self.text, &mut self.completer);
}
diff --git a/dsa/emulator/src/frontend/components/editor/syntax/mod.rs b/dsa/emulator/frontend/src/ui/components/editor/syntax/mod.rs
similarity index 100%
rename from dsa/emulator/src/frontend/components/editor/syntax/mod.rs
rename to dsa/emulator/frontend/src/ui/components/editor/syntax/mod.rs
diff --git a/dsa/emulator/src/frontend/components/framebuffer.rs b/dsa/emulator/frontend/src/ui/components/framebuffer.rs
similarity index 97%
rename from dsa/emulator/src/frontend/components/framebuffer.rs
rename to dsa/emulator/frontend/src/ui/components/framebuffer.rs
index 5d9a91a..c916a91 100644
--- a/dsa/emulator/src/frontend/components/framebuffer.rs
+++ b/dsa/emulator/frontend/src/ui/components/framebuffer.rs
@@ -1,7 +1,6 @@
use egui::Vec2;
-
-use crate::{MemoryBank, Page, backend::memory::PhysAddr};
-
+use emu_core::memory::PhysAddr;
+use emu_core::memory::ram::{MemoryBank, Page};
use super::Component;
pub struct FrameBuffer {
diff --git a/dsa/emulator/src/frontend/components/memory.rs b/dsa/emulator/frontend/src/ui/components/memory.rs
similarity index 98%
rename from dsa/emulator/src/frontend/components/memory.rs
rename to dsa/emulator/frontend/src/ui/components/memory.rs
index f290062..557f18d 100644
--- a/dsa/emulator/src/frontend/components/memory.rs
+++ b/dsa/emulator/frontend/src/ui/components/memory.rs
@@ -1,8 +1,8 @@
use std::num::ParseIntError;
use common::prelude::Instruction;
-
-use crate::{MemoryBank, frontend::components::Component};
+use emu_core::memory::ram::MemoryBank;
+use super::Component;
pub struct MemoryInspector {
memory: MemoryBank,
diff --git a/dsa/emulator/src/frontend/components.rs b/dsa/emulator/frontend/src/ui/components/mod.rs
similarity index 100%
rename from dsa/emulator/src/frontend/components.rs
rename to dsa/emulator/frontend/src/ui/components/mod.rs
diff --git a/dsa/emulator/src/frontend/components/registers.rs b/dsa/emulator/frontend/src/ui/components/registers.rs
similarity index 99%
rename from dsa/emulator/src/frontend/components/registers.rs
rename to dsa/emulator/frontend/src/ui/components/registers.rs
index 59c3a9d..fe71745 100644
--- a/dsa/emulator/src/frontend/components/registers.rs
+++ b/dsa/emulator/frontend/src/ui/components/registers.rs
@@ -1,8 +1,7 @@
use std::{f32, sync::Arc};
use common::prelude::Register;
-
-use crate::SharedState;
+use emu_core::processor::state::SharedState;
use super::Component;
diff --git a/dsa/emulator/src/frontend/components/serial.rs b/dsa/emulator/frontend/src/ui/components/serial.rs
similarity index 88%
rename from dsa/emulator/src/frontend/components/serial.rs
rename to dsa/emulator/frontend/src/ui/components/serial.rs
index 2f5f024..6bffda7 100644
--- a/dsa/emulator/src/frontend/components/serial.rs
+++ b/dsa/emulator/frontend/src/ui/components/serial.rs
@@ -6,17 +6,16 @@ use std::{
mpsc::{Receiver, Sender},
},
};
-
+use emu_core::memory::PhysAddr;
+use emu_core::memory::ram::MemoryBank;
+use emu_core::processor::interrupts::Interrupt;
+use emu_core::processor::state::SharedState;
use super::Component;
-use crate::{
- MemoryBank, SharedState,
- backend::{memory::PhysAddr, processor::interrupts::Interrupt},
-};
-/// ## SERIAL LAYOUT: (from the perspective of code inside the emulator)
+/// ## SERIAL LAYOUT: (from the perspective of code inside the ui)
/// - [base+0x00]: ser_out valid flag - set by kernel after writing a byte to serial
-/// - [base+0x01]: ser_out byte - data payload for emulator to read
-/// - [base+0x02]: ser_in valid flag - set by emulator after writing a byte to serial
+/// - [base+0x01]: ser_out byte - data payload for ui to read
+/// - [base+0x02]: ser_in valid flag - set by ui after writing a byte to serial
/// - [base+0x03]: ser_in byte - data payload for kernel to read
pub struct Serial {
pub read_rx: Receiver,
@@ -43,7 +42,7 @@ impl Serial {
}
let ser_out_valid = mem.read_byte(uart_base + 0);
- // Kernel => emulator: valid flag in byte 0, data in byte 1
+ // Kernel => ui: valid flag in byte 0, data in byte 1
if ser_out_valid == 0x01 {
let ser_out = mem.read_byte(uart_base + 1);
let _ = tx.send(ser_out);
diff --git a/dsa/emulator/src/frontend/mod.rs b/dsa/emulator/frontend/src/ui/mod.rs
similarity index 93%
rename from dsa/emulator/src/frontend/mod.rs
rename to dsa/emulator/frontend/src/ui/mod.rs
index 5333261..b898655 100644
--- a/dsa/emulator/src/frontend/mod.rs
+++ b/dsa/emulator/frontend/src/ui/mod.rs
@@ -1,16 +1,16 @@
use eframe::NativeOptions;
use eframe::egui;
-use std::mem;
use std::sync::Arc;
use std::sync::atomic::Ordering;
mod components;
use components::{
- Component, controller::Controller, display::Display, editor::Editor, framebuffer::FrameBuffer,
- memory::MemoryInspector, registers::Registers, serial::Serial,
+ controller::Controller, display::Display, editor::Editor, framebuffer::FrameBuffer, memory::MemoryInspector,
+ registers::Registers, serial::Serial, Component,
};
-
-use crate::{MemoryBank, SharedState, config::VERSION};
+use emu_core::config::VERSION;
+use emu_core::memory::ram::MemoryBank;
+use emu_core::processor::state::SharedState;
pub fn run_app(state: Arc, mem_handle: MemoryBank) -> eframe::Result<()> {
eframe::run_native(
@@ -22,7 +22,7 @@ pub fn run_app(state: Arc, mem_handle: MemoryBank) -> eframe::Resul
impl eframe::App for DsaUi {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
- // request an update from emulator every cycle
+ // request an update from ui every cycle
self.state.update_req.store(true, Ordering::Relaxed);
// title panel with dsa title
diff --git a/dsa/emulator/src/backend/mod.rs b/dsa/emulator/src/backend/mod.rs
deleted file mode 100644
index af5b873..0000000
--- a/dsa/emulator/src/backend/mod.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-pub mod memory;
-pub mod processor;
diff --git a/dsa/emulator/src/bin/bench_emu.rs b/dsa/emulator/src/bin/bench_emu.rs
deleted file mode 100644
index 9604f5d..0000000
--- a/dsa/emulator/src/bin/bench_emu.rs
+++ /dev/null
@@ -1,332 +0,0 @@
-// use common::isa::instructions::Instruction;
-// use dsa::{Emulator, MemoryBank, Page};
-// /// DSA Emulator Benchmark
-// ///
-// /// Place this in `dsa/src/bin/bench.rs` and run with:
-// /// cargo run --bin bench --release
-// ///
-// /// Three workloads are tested:
-// /// 1. ALU-heavy — tight arithmetic loop, no memory, no branches
-// /// 2. Memory-heavy — repeated load/store to a working set of addresses
-// /// 3. Branch-heavy — the bf.dsa dispatch pattern (ieq + jnz chains)
-// ///
-// /// Each workload is a hand-assembled flat binary loaded directly into
-// /// the emulator, bypassing all the args/display/IO plumbing.
-// use std::{
-// thread,
-// time::{Duration, Instant},
-// u16,
-// };
-
-// // ---------------------------------------------------------------------------
-// // Minimal no-op memory map + IO so the emulator boots without a config file.
-// // ---------------------------------------------------------------------------
-
-// fn make_emulator() -> Emulator {
-// use dsa::{
-// config::{MemoryMap, Region, RegionType},
-// io::display::Display,
-// };
-
-// let mmap = MemoryMap {
-// table_addr: 0x40000,
-// regions: vec![
-// Region {
-// base: 0x0000_0000,
-// size: 0x0010_0000, // 1 MiB RAM
-// region_type: RegionType::Usable,
-// identity_map_on_boot: true,
-// },
-// Region {
-// base: 0x0020_0000,
-// size: 0x0002_0000, // 128 KiB MMIO (display)
-// region_type: RegionType::MMIO,
-// identity_map_on_boot: false,
-// },
-// ],
-// };
-
-// // let iomap = vec![dsa::config::IoMapping {
-// // device: dsa::io::DeviceId::Display,
-// // base: 0x0020_0000,
-// // size: 0x0000_07D0,
-// // }];
-
-// // let (display, _handle) = Display::new(80, 25);
-// // Emulator::new(MemoryBank::new())
-// // .with_device(display)
-// // .apply_memory_map(mmap)
-// // .apply_io_map(iomap)
-// // .unwrap()
-// }
-
-// // ---------------------------------------------------------------------------
-// // Instruction encoding helpers (little-endian words)
-// // ---------------------------------------------------------------------------
-
-// /// Encode an I-type instruction: [op:6][src:5][dst:5][imm:16]
-// fn enc_i(op: u8, src: u8, dst: u8, imm: u16) -> u32 {
-// ((op as u32 & 0x3F) << 26)
-// | ((src as u32 & 0x1F) << 21)
-// | ((dst as u32 & 0x1F) << 16)
-// | imm as u32
-// }
-
-// /// Encode an R-type instruction: [op:6][r1:5][r2:5][r3:5][r4:5][u6:6]
-// fn enc_r(op: u8, r1: u8, r2: u8, r3: u8, r4: u8, u6: u8) -> u32 {
-// ((op as u32 & 0x3F) << 26)
-// | ((r1 as u32 & 0x1F) << 21)
-// | ((r2 as u32 & 0x1F) << 16)
-// | ((r3 as u32 & 0x1F) << 11)
-// | ((r4 as u32 & 0x1F) << 6)
-// | (u6 as u32 & 0x3F)
-// }
-
-// // Register indices — must match your Register enum discriminants
-// const RG0: u8 = 0;
-// const RG1: u8 = 1;
-// const RG2: u8 = 2;
-// const RG3: u8 = 3;
-// const RG4: u8 = 4;
-// const RG5: u8 = 5;
-// const ZERO: u8 = 16;
-
-// // Opcodes — must match your Opcode enum discriminants.
-// // Fill these in from your ISA.md / encode.rs.
-// const OP_NOP: u8 = 0x0D; // adjust to match your actual opcode values
-// const OP_HLT: u8 = 0x2B;
-// const OP_ADD: u8 = 0x22;
-// const OP_ADDI: u8 = 0x23;
-// const OP_SUBI: u8 = 0x24;
-// const OP_LDW: u8 = 0x07;
-// const OP_STW: u8 = 0x0A;
-// const OP_LLI: u8 = 0x0B;
-// const OP_LUI: u8 = 0x0C;
-// const OP_IEQ: u8 = 0x0E;
-// const OP_JNZ: u8 = 0x15;
-// const OP_JMP: u8 = 0x12;
-
-// // ---------------------------------------------------------------------------
-// // Workload 1: ALU-heavy
-// //
-// // Counts down from 10_000_000 using subi, jumps back to top.
-// // Pure register arithmetic, no memory accesses after init.
-// // Instruction mix: lli, subi, ieq, jnz, hlt
-// //
-// // Layout (each word at address = index * 4):
-// // 0: lli rg0, 0 (upper half of count) [lui follows]
-// // 4: lui rg0,
-// // 8: loop: subi rg0, 1, rg0
-// // 12: ieq rg0, zero, rg1
-// // 16: jnz rg1, zero, 8 [jump to loop]
-// // 20: hlt
-// // ---------------------------------------------------------------------------
-// fn alu_workload() -> Vec {
-// let count: u32 = 10_000_000;
-// let lo = (count & 0xFFFF) as u16;
-// let hi = ((count >> 16) & 0xFFFF) as u16;
-
-// let words: &[u32] = &[
-// enc_i(OP_LLI, 0, RG0, lo), // 0x00: lli rg0, lo(count)
-// enc_i(OP_LUI, 0, RG0, hi), // 0x04: lui rg0, hi(count)
-// // loop @ 0x08:
-// enc_i(OP_SUBI, RG0, RG0, 1), // 0x08: subi rg0, rg0, 1
-// enc_r(OP_IEQ, RG0, ZERO, RG1, 0, 0), // 0x0C: ieq rg0, zero, rg1
-// enc_i(OP_JNZ, RG1, ZERO, 0x0008), // 0x10: jnz rg1, zero, 0x08 <- BUG: jnz jumps when rg1!=0
-// // rg1=1 when rg0==0, so we want jez here to keep looping
-// // fix: use jez (jump when rg1==0, i.e. rg0!=0)
-// enc_i(OP_HLT, 0, 0, 0), // 0x14: hlt
-// ];
-// // Note: replace OP_JNZ above with your JEZ opcode so the loop continues
-// // while rg0 != 0. JNZ exits when rg1 != 0, i.e. when rg0 == 0 (done).
-// // The ieq sets rg1=1 only when rg0==0, so jnz rg1 exits the loop correctly.
-// // Actually this IS correct: loop while ieq returns 0 (rg0 != 0),
-// // exit when ieq returns 1 (rg0 == 0). jnz rg1 = jump when rg1 != 0 = jump when done.
-// // We want to jump BACK while not done, so we need jez:
-// // jez rg1, zero, 0x08 = jump back when rg1==0 (rg0 != 0, not done yet)
-// // Swap OP_JNZ for your JEZ opcode.
-// words_to_bytes(words)
-// }
-
-// // ---------------------------------------------------------------------------
-// // Workload 2: Memory-heavy
-// //
-// // Repeatedly writes and reads a 64-word working set.
-// // Tests page table lookup performance under repeated memory access.
-// //
-// // rg0 = base address (0x1000, well within RAM, page-aligned)
-// // rg1 = loop counter (1000 outer iterations)
-// // rg2 = inner counter (64 words per pass)
-// // rg3 = scratch for store value
-// // ---------------------------------------------------------------------------
-// fn memory_workload() -> Vec {
-// let base: u32 = 0x1000;
-// let outer: u16 = 1000;
-// let inner: u16 = 64;
-
-// let words: &[u32] = &[
-// // init
-// enc_i(OP_LLI, 0, RG0, (base & 0xFFFF) as u16), // rg0 = base
-// enc_i(OP_LLI, 0, RG1, outer), // rg1 = outer count
-// // outer_loop @ 0x08:
-// enc_i(OP_LLI, 0, RG2, inner), // rg2 = inner count
-// enc_i(OP_LLI, 0, RG3, 0xABCD), // rg3 = value to write
-// // inner_loop @ 0x10:
-// enc_i(OP_STW, RG3, RG0, 0), // stw rg3, rg0, 0
-// enc_i(OP_LDW, RG0, RG3, 0), // ldw rg0, rg3, 0 (read back)
-// enc_i(OP_ADDI, RG0, RG0, 4), // rg0 += 4
-// enc_i(OP_SUBI, RG2, RG2, 1), // rg2 -= 1
-// enc_r(OP_IEQ, RG2, ZERO, RG4, 0, 0), // ieq rg2, zero, rg4
-// enc_i(OP_JNZ, RG4, ZERO, 0x0010), // jez rg4 -> inner_loop (swap opcode)
-// // restore base, dec outer
-// enc_i(OP_LLI, 0, RG0, (base & 0xFFFF) as u16),
-// enc_i(OP_SUBI, RG1, RG1, 1),
-// enc_r(OP_IEQ, RG1, ZERO, RG4, 0, 0),
-// enc_i(OP_JNZ, RG4, ZERO, 0x0008), // jez rg4 -> outer_loop (swap opcode)
-// enc_i(OP_HLT, 0, 0, 0),
-// ];
-// words_to_bytes(words)
-// }
-
-// // ---------------------------------------------------------------------------
-// // Workload 3: Branch-heavy
-// //
-// // Mimics the bf.dsa dispatch pattern: compare a value against 8 constants,
-// // branch on each. Worst case for branch predictor.
-// // rg0 = current "instruction" (cycles through 8 values)
-// // rg8-rgf = the 8 bf opcode constants
-// // ---------------------------------------------------------------------------
-// fn branch_workload() -> Vec {
-// // 8 bf opcodes: + - > < . , [ ]
-// let opcodes: [u16; 8] = [43, 45, 62, 60, 46, 44, 91, 93];
-// // We'll cycle rg0 through these values and do the full dispatch chain.
-// // To keep it self-contained: load opcodes, set outer loop counter,
-// // inner loop cycles rg0 through all 8 values doing ieq+jnz for each.
-// let outer: u16 = u16::MAX;
-
-// let mut w: Vec = Vec::new();
-
-// // Load 8 opcode constants into rg8-rgf (regs 8-15)
-// for (i, &op) in opcodes.iter().enumerate() {
-// w.push(enc_i(OP_LLI, 0, 8 + i as u8, op));
-// }
-// // rg1 = outer counter
-// w.push(enc_i(OP_LLI, 0, RG1, outer));
-
-// // outer_loop:
-// let outer_loop_addr = (w.len() * 4) as u16;
-
-// // rg5 = inner counter (8 opcodes)
-// w.push(enc_i(OP_LLI, 0, RG5, 8));
-// // rg2 = pointer into opcode table (we'll use addi to step rg0 through values)
-// // For simplicity: just set rg0 to each opcode in sequence via lli each iteration
-// // This is branch-heavy, not arithmetic-heavy, so the lli overhead is fine.
-// for (i, &op) in opcodes.iter().enumerate() {
-// let next_offset = ((w.len() + 4) * 4) as u16; // addr after the jnz
-// w.push(enc_i(OP_LLI, 0, RG0, op)); // rg0 = opcode
-// w.push(enc_r(OP_IEQ, RG0, 8 + i as u8, RG4, 0, 0)); // ieq rg0, rgX, rg4
-// w.push(enc_i(OP_JNZ, RG4, ZERO, next_offset)); // jnz rg4 (jez to skip)
-// w.push(enc_i(OP_NOP, 0, 0, 0)); // "handler" nop
-// }
-// // dec outer, loop
-// let after_dispatch = (w.len() * 4) as u16;
-// w.push(enc_i(OP_SUBI, RG1, RG1, 1));
-// w.push(enc_r(OP_IEQ, RG1, ZERO, RG4, 0, 0));
-// w.push(enc_i(OP_JNZ, RG4, ZERO, outer_loop_addr)); // jez -> outer_loop
-// w.push(enc_i(OP_HLT, 0, 0, 0));
-
-// words_to_bytes(&w)
-// }
-
-// fn words_to_bytes(words: &[u32]) -> Vec {
-// words.iter().flat_map(|w| w.to_le_bytes()).collect()
-// }
-
-// // ---------------------------------------------------------------------------
-// // Runner
-// // ---------------------------------------------------------------------------
-
-// struct BenchResult {
-// name: &'static str,
-// instructions: u64,
-// elapsed: Duration,
-// mips: f64,
-// }
-
-// fn run_bench(name: &'static str, binary: Vec) -> BenchResult {
-// let mut emu = make_emulator();
-// let handle = emu.state_handle();
-
-// let pages: Vec = Page::paginate(&binary).collect();
-// for (i, page) in pages.iter().enumerate() {
-// emu.memory_mut().write_page(i as u32 * 4096, page);
-// }
-
-// let start = Instant::now();
-// // run() blocks until HLT
-// emu.run().expect("emulator run failed");
-// let elapsed = start.elapsed();
-
-// // read clock from emulator — we need to expose it.
-// // For now, estimate from elapsed + target MIPS.
-// // TODO: expose emulator.clock() -> u64 and use that directly.
-// let instructions = handle.proc.load().clock as u64;
-// let mips = instructions as f64 / elapsed.as_micros() as f64;
-
-// BenchResult {
-// name,
-// instructions,
-// elapsed,
-// mips,
-// }
-// }
-
-// fn main() {
-// println!("DSA Emulator Benchmark");
-// println!("======================");
-// println!();
-
-// // NOTE: you need to expose `pub fn clock(&self) -> usize` on Emulator
-// // and ensure `run()` returns normally on HLT without blocking in idle_wait.
-// // The idle_wait loop currently spins forever after HLT — for benchmarking,
-// // you want run() to return when the program halts. Add a flag or check:
-// // if !self.internal_state.running { break 'emu; }
-// // after the HLT handler sets running=false.
-
-// let workloads: &[(&'static str, fn() -> Vec)] = &[
-// ("ALU-heavy (10M countdown)", alu_workload),
-// ("Memory-heavy (64K rw ops)", memory_workload),
-// ("Branch-heavy (bf dispatch)", branch_workload),
-// ];
-
-// let mut results = Vec::new();
-// for &(name, build) in workloads {
-// print!("Running {}... ", name);
-// let binary = build();
-// let result = run_bench(name, binary);
-// println!("done ({:.1}ms)", result.elapsed.as_secs_f64() * 1000.0);
-// results.push(result);
-// }
-
-// println!();
-// println!(
-// "{:<35} {:>12} {:>12} {:>10}",
-// "Workload", "Instructions", "Time", "MIPS"
-// );
-// println!("{}", "-".repeat(72));
-// for r in &results {
-// println!(
-// "{:<35} {:>12} {:>10.1}ms {:>10.1}",
-// r.name,
-// r.instructions,
-// r.elapsed.as_secs_f64() * 1000.0,
-// r.mips,
-// );
-// }
-
-// let avg_mips: f64 = results.iter().map(|r| r.mips).sum::() / results.len() as f64;
-// println!("{}", "-".repeat(72));
-// println!("{:<35} {:>35.1} MIPS avg", "Overall", avg_mips);
-// }
-
-fn main() {}
diff --git a/dsa/emulator/src/config/default/dsa.iomap.ron b/dsa/emulator/src/config/default/dsa.iomap.ron
deleted file mode 100644
index 6575514..0000000
--- a/dsa/emulator/src/config/default/dsa.iomap.ron
+++ /dev/null
@@ -1,7 +0,0 @@
-[
- IoMapping(
- device: Display,
- base: 0x0002_0000,
- size: 0x0000_07D0, // 2000 bytes (80x25)
- ),
-]
diff --git a/dsa/emulator/src/lib.rs b/dsa/emulator/src/lib.rs
deleted file mode 100644
index ef240a7..0000000
--- a/dsa/emulator/src/lib.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(likely_unlikely)]
-#![feature(inherent_associated_types)]
-#![feature(str_as_str)]
-
-pub mod args;
-pub mod backend;
-pub mod config;
-pub mod frontend;
-
-pub use backend::memory::ram::*;
-pub use backend::{processor::processor::Emulator, processor::state::SharedState};