extracted emulator backend into independent crate

This commit is contained in:
2026-07-14 22:13:11 +01:00
parent b9d0f4fdd4
commit 7a84073bc4
38 changed files with 296 additions and 419 deletions
+158
View File
@@ -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<SymbolEntry>,
string_table: Vec<u8>,
data: Vec<u8>,
text: Vec<u32>
}
impl DseExecutable {
fn load(path: PathBuf) -> binrw::BinResult<Self> {
let mut file = File::open(path).map_err(|e| binrw::Error::Io(e))?;
Self::read(&mut file)
}
fn read<R: Read + Seek>(reader: &mut R) -> binrw::BinResult<Self> {
let header = DseHeader::read(reader)?;
reader.seek(SeekFrom::Start(header.symbol_table_offset as u64))?;
let symbols: Vec<SymbolEntry> = (0..header.symbol_table_size)
.map(|_| SymbolEntry::read(reader))
.collect::<binrw::BinResult<_>>()?;
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<u32> = (0..header.text_size)
.map(|_| reader.read_le::<u32>())
.collect::<binrw::BinResult<_>>()?;
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<W: Write + Seek>(&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(),
}
}
}