extracted emulator backend into independent crate
This commit is contained in:
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user