@@ -1,6 +1,6 @@
|
||||
use cfgrammar::yacc::YaccKind;
|
||||
use lrlex::LexerBuilder;
|
||||
use lrpar::{CTParserBuilder};
|
||||
use lrpar::CTParserBuilder;
|
||||
use rerun_except::rerun_except;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -10,9 +10,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
LexerBuilder::new()
|
||||
.rule_ids_map(lex_rule_ids_map)
|
||||
.process_file_in_src("obj/syn/lexer.l")?;
|
||||
rerun_except(&[
|
||||
"examples/*.asm",
|
||||
"tests/*.asm",
|
||||
]).unwrap();
|
||||
rerun_except(&["examples/*.asm", "tests/*.asm"]).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ macro_rules! impl_add_assign {
|
||||
self.0 = self.0 + (rhs as u64);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_add_assign!(usize);
|
||||
@@ -53,7 +53,7 @@ macro_rules! impl_cmp {
|
||||
self.0.partial_cmp(&other)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_cmp!(usize);
|
||||
@@ -66,7 +66,7 @@ macro_rules! impl_from {
|
||||
Addr(other as u64)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from!(usize);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{inst::InstOp, reg::Reg, addr::*,};
|
||||
use crate::{addr::*, inst::InstOp, reg::Reg};
|
||||
use snafu::Snafu;
|
||||
|
||||
#[derive(Snafu, Debug, Clone)]
|
||||
|
||||
@@ -125,34 +125,28 @@ impl Inst {
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Inst::Add(dest, source)
|
||||
| Inst::Sub(dest, source)
|
||||
| Inst::Mul(dest, source)
|
||||
| Inst::Div(dest, source)
|
||||
| Inst::IDiv(dest, source)
|
||||
| Inst::Mod(dest, source)
|
||||
| Inst::And(dest, source)
|
||||
| Inst::Or(dest, source)
|
||||
| Inst::Xor(dest, source)
|
||||
| Inst::Shl(dest, source)
|
||||
| Inst::Shr(dest, source)
|
||||
| Inst::INeg(dest, source)
|
||||
| Inst::Inv(dest, source)
|
||||
| Inst::Not(dest, source)
|
||||
| Inst::Mov(dest, source) => { 3 + dest.len() + source.len() }
|
||||
Inst::CmpEq(s1, s2)
|
||||
| Inst::CmpLt(s1, s2)
|
||||
| Inst::Int(s1, s2) => { 3 + s1.len() + s2.len() }
|
||||
Inst::Jmp(v)
|
||||
| Inst::Jz(v)
|
||||
| Inst::Jnz(v)
|
||||
| Inst::Call(v)
|
||||
| Inst::Push(v) => { 3 + v.len() }
|
||||
Inst::Pop(v) => { 3 + v.len() }
|
||||
Inst::Ret
|
||||
| Inst::Halt
|
||||
| Inst::Nop
|
||||
| Inst::Dump
|
||||
| Inst::IRet => { 2 }
|
||||
| Inst::Sub(dest, source)
|
||||
| Inst::Mul(dest, source)
|
||||
| Inst::Div(dest, source)
|
||||
| Inst::IDiv(dest, source)
|
||||
| Inst::Mod(dest, source)
|
||||
| Inst::And(dest, source)
|
||||
| Inst::Or(dest, source)
|
||||
| Inst::Xor(dest, source)
|
||||
| Inst::Shl(dest, source)
|
||||
| Inst::Shr(dest, source)
|
||||
| Inst::INeg(dest, source)
|
||||
| Inst::Inv(dest, source)
|
||||
| Inst::Not(dest, source)
|
||||
| Inst::Mov(dest, source) => 3 + dest.len() + source.len(),
|
||||
Inst::CmpEq(s1, s2) | Inst::CmpLt(s1, s2) | Inst::Int(s1, s2) => {
|
||||
3 + s1.len() + s2.len()
|
||||
}
|
||||
Inst::Jmp(v) | Inst::Jz(v) | Inst::Jnz(v) | Inst::Call(v) | Inst::Push(v) => {
|
||||
3 + v.len()
|
||||
}
|
||||
Inst::Pop(v) => 3 + v.len(),
|
||||
Inst::Ret | Inst::Halt | Inst::Nop | Inst::Dump | Inst::IRet => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +170,10 @@ impl Source {
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Source::Addr64(_) | Source::Addr32(_) | Source::Addr16(_) | Source::Addr8(_) => 8,
|
||||
Source::RegAddr64(_) | Source::RegAddr32(_) | Source::RegAddr16(_) | Source::RegAddr8(_) => 1,
|
||||
Source::RegAddr64(_)
|
||||
| Source::RegAddr32(_)
|
||||
| Source::RegAddr16(_)
|
||||
| Source::RegAddr8(_) => 1,
|
||||
Source::Reg(_) => 1,
|
||||
Source::Imm(_) => 8,
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ pub const IVT_LENGTH: usize = 512;
|
||||
pub struct Interrupt(u64);
|
||||
|
||||
const ENABLED_MASK: u64 = 0x8000_0000_0000_0000;
|
||||
const ADDR_MASK: u64 = 0x07ff_ffff_ffff_ffff;
|
||||
const ADDR_MASK: u64 = 0x07ff_ffff_ffff_ffff;
|
||||
|
||||
impl Interrupt {
|
||||
pub fn enabled(&self) -> bool {
|
||||
@@ -37,7 +37,7 @@ impl Interrupt {
|
||||
let enabled = (enabled as u64) << 63;
|
||||
self.0 |= enabled;
|
||||
}
|
||||
|
||||
|
||||
pub fn addr(&self) -> Addr {
|
||||
Addr((self.0 & ADDR_MASK) << 5)
|
||||
}
|
||||
|
||||
@@ -8,11 +8,14 @@ pub struct MemCursor<T> {
|
||||
}
|
||||
|
||||
impl<T> MemCursor<T>
|
||||
where Cursor<T>: ReadBytesExt,
|
||||
T: AsRef<[u8]>
|
||||
where
|
||||
Cursor<T>: ReadBytesExt,
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
pub fn new(mem: T) -> Self {
|
||||
MemCursor { cursor: Cursor::new(mem) }
|
||||
MemCursor {
|
||||
cursor: Cursor::new(mem),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> u64 {
|
||||
@@ -32,7 +35,7 @@ impl<T> MemCursor<T>
|
||||
let end = start + count;
|
||||
self.check_addr(end as u64 - 1)?;
|
||||
self.cursor.set_position(end as u64);
|
||||
Ok(&self.cursor.get_ref().as_ref()[start .. end])
|
||||
Ok(&self.cursor.get_ref().as_ref()[start..end])
|
||||
}
|
||||
|
||||
pub fn next_u8_unchecked(&mut self) -> u8 {
|
||||
@@ -61,7 +64,7 @@ impl<T> MemCursor<T>
|
||||
self.check_addr(self.position() + 3)
|
||||
.map(|_| self.next_u32_unchecked())
|
||||
}
|
||||
|
||||
|
||||
pub fn next_u64_unchecked(&mut self) -> u64 {
|
||||
self.cursor.read_u64::<LE>().unwrap()
|
||||
}
|
||||
@@ -220,7 +223,8 @@ impl<T> MemCursor<T>
|
||||
}
|
||||
|
||||
impl<T> MemCursor<T>
|
||||
where T: AsRef<[u8]>
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
fn check_addr(&self, addr: u64) -> Result<()> {
|
||||
if addr >= (self.cursor.get_ref().as_ref().len() as u64) {
|
||||
@@ -232,8 +236,9 @@ impl<T> MemCursor<T>
|
||||
}
|
||||
|
||||
impl<T> MemCursor<T>
|
||||
where Cursor<T>: WriteBytesExt,
|
||||
T: AsRef<[u8]>
|
||||
where
|
||||
Cursor<T>: WriteBytesExt,
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
pub fn write_u8_unchecked(&mut self, value: u8) {
|
||||
self.cursor.write_u8(value).unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pub mod error;
|
||||
pub mod session;
|
||||
mod includes;
|
||||
mod names;
|
||||
pub mod session;
|
||||
|
||||
use self::{error::*, session::AsmSession};
|
||||
use crate::{
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
obj::{
|
||||
obj::{self, Object},
|
||||
syn::ast::*,
|
||||
}
|
||||
},
|
||||
};
|
||||
use byteorder::{WriteBytesExt, LE};
|
||||
use std::{collections::HashMap, path::Path};
|
||||
@@ -48,7 +48,7 @@ impl Asm for Directive {
|
||||
match self {
|
||||
Directive::Data(section) => Ok(Some(obj::Section::Data(section.assemble(asm)?))),
|
||||
Directive::Meta(section) => section.assemble(asm).map(Some),
|
||||
Directive::Include(_) => { Ok(None) }
|
||||
Directive::Include(_) => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,10 @@ impl Asm for DataSection {
|
||||
let mut contents = Vec::with_capacity(content_len as usize);
|
||||
for (pos, line) in self.lines(start) {
|
||||
let expected_len = pos - (start as usize);
|
||||
assert!(expected_len >= contents.len(), "next line size would cause section to shrink");
|
||||
assert!(
|
||||
expected_len >= contents.len(),
|
||||
"next line size would cause section to shrink"
|
||||
);
|
||||
// resize contents if necessary, this pads out aligned values
|
||||
contents.resize(expected_len, 0);
|
||||
contents.extend(line.assemble(session)?);
|
||||
@@ -93,11 +96,7 @@ impl Asm for DataSection {
|
||||
"in section {}",
|
||||
self.name
|
||||
);
|
||||
assert_eq!(
|
||||
session.pos - start, content_len,
|
||||
"in section {}",
|
||||
self.name
|
||||
);
|
||||
assert_eq!(session.pos - start, content_len, "in section {}", self.name);
|
||||
|
||||
session.name_stack.pop();
|
||||
Ok(obj::DataSection {
|
||||
@@ -122,8 +121,15 @@ impl Asm for MetaSection {
|
||||
}
|
||||
let value = match &line.value {
|
||||
Value::Int(i) => *i,
|
||||
Value::Name(s) => session.lookup_name(s.as_str())
|
||||
.ok_or_else(|| AsmError::UnknownName { name: s.to_string() })?.addr.0,
|
||||
Value::Name(s) => {
|
||||
session
|
||||
.lookup_name(s.as_str())
|
||||
.ok_or_else(|| AsmError::UnknownName {
|
||||
name: s.to_string(),
|
||||
})?
|
||||
.addr
|
||||
.0
|
||||
}
|
||||
Value::Reg(_) | Value::Here | Value::Addr(_, _) => {
|
||||
return Err(AsmError::IllegalMetaValue {
|
||||
name: line.name.to_string(),
|
||||
@@ -218,10 +224,7 @@ impl Asm for Inst {
|
||||
let dest_encoding = dest.source_encoding() << 4;
|
||||
bytes.write_u8(dest_encoding).unwrap();
|
||||
bytes.extend(dest.assemble(session)?);
|
||||
assert_eq!(
|
||||
len,
|
||||
bytes.len(),
|
||||
);
|
||||
assert_eq!(len, bytes.len(),);
|
||||
Ok(bytes)
|
||||
}
|
||||
Inst::Int(v1, v2) => self.map_source_source(session, inst::INT, v1, v2),
|
||||
@@ -235,47 +238,56 @@ impl Asm for Inst {
|
||||
}
|
||||
|
||||
impl Inst {
|
||||
fn map_dest_source(&self, session: &mut AsmSession, op: inst::InstOp, dest: &Value, source: &Value) -> Result<Vec<u8>> {
|
||||
fn map_dest_source(
|
||||
&self,
|
||||
session: &mut AsmSession,
|
||||
op: inst::InstOp,
|
||||
dest: &Value,
|
||||
source: &Value,
|
||||
) -> Result<Vec<u8>> {
|
||||
let len = self.len();
|
||||
let mut bytes = Vec::with_capacity(len);
|
||||
bytes.write_u16::<LE>(op).unwrap();
|
||||
let dest_encoding =
|
||||
dest.dest_encoding()
|
||||
.ok_or_else(|| AsmError::IllegalDestValue {
|
||||
value: dest.clone(),
|
||||
})?;
|
||||
let dest_encoding = dest
|
||||
.dest_encoding()
|
||||
.ok_or_else(|| AsmError::IllegalDestValue {
|
||||
value: dest.clone(),
|
||||
})?;
|
||||
let source_encoding = source.source_encoding();
|
||||
bytes
|
||||
.write_u8((dest_encoding << 4) | source_encoding)
|
||||
.unwrap();
|
||||
bytes.extend(dest.assemble(session)?);
|
||||
bytes.extend(source.assemble(session)?);
|
||||
assert_eq!(
|
||||
len,
|
||||
bytes.len(),
|
||||
);
|
||||
assert_eq!(len, bytes.len(),);
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
fn map_source_source(&self, session: &mut AsmSession, op: inst::InstOp, s1: &Value, s2: &Value) -> Result<Vec<u8>> {
|
||||
fn map_source_source(
|
||||
&self,
|
||||
session: &mut AsmSession,
|
||||
op: inst::InstOp,
|
||||
s1: &Value,
|
||||
s2: &Value,
|
||||
) -> Result<Vec<u8>> {
|
||||
let len = self.len();
|
||||
let mut bytes = Vec::with_capacity(len);
|
||||
bytes.write_u16::<LE>(op).unwrap();
|
||||
let s1_encoding = s1.source_encoding();
|
||||
let s2_encoding = s2.source_encoding();
|
||||
bytes
|
||||
.write_u8((s1_encoding << 4) | s2_encoding)
|
||||
.unwrap();
|
||||
bytes.write_u8((s1_encoding << 4) | s2_encoding).unwrap();
|
||||
bytes.extend(s1.assemble(session)?);
|
||||
bytes.extend(s2.assemble(session)?);
|
||||
assert_eq!(
|
||||
len,
|
||||
bytes.len(),
|
||||
);
|
||||
assert_eq!(len, bytes.len(),);
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
fn map_source(&self, session: &mut AsmSession, op: inst::InstOp, source: &Value) -> Result<Vec<u8>> {
|
||||
fn map_source(
|
||||
&self,
|
||||
session: &mut AsmSession,
|
||||
op: inst::InstOp,
|
||||
source: &Value,
|
||||
) -> Result<Vec<u8>> {
|
||||
let len = self.len();
|
||||
let mut bytes = Vec::with_capacity(len);
|
||||
bytes.write_u16::<LE>(op).unwrap();
|
||||
@@ -290,10 +302,7 @@ impl Inst {
|
||||
let len = self.len();
|
||||
let mut bytes = Vec::with_capacity(len);
|
||||
bytes.write_u16::<LE>(op).unwrap();
|
||||
assert_eq!(
|
||||
len,
|
||||
bytes.len(),
|
||||
);
|
||||
assert_eq!(len, bytes.len(),);
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
||||
@@ -306,8 +315,12 @@ impl Asm for Value {
|
||||
Value::Int(i) => Ok(i.to_le_bytes().to_vec()),
|
||||
Value::Reg(r) => Ok(vec![*r]),
|
||||
Value::Name(name) => {
|
||||
let value = session.lookup_name(name.as_str())
|
||||
.ok_or_else(|| AsmError::UnknownName { name: name.to_string() })?;
|
||||
let value =
|
||||
session
|
||||
.lookup_name(name.as_str())
|
||||
.ok_or_else(|| AsmError::UnknownName {
|
||||
name: name.to_string(),
|
||||
})?;
|
||||
Ok(value.addr.0.to_le_bytes().to_vec())
|
||||
}
|
||||
Value::Here => Ok(session.pos.to_le_bytes().to_vec()),
|
||||
@@ -331,7 +344,7 @@ mod test {
|
||||
fn test_inst_len() {
|
||||
let mut session = AsmSession::default();
|
||||
//asm.names
|
||||
//.push(vec![("test".to_string(), Addr(0u64))].into_iter().collect());
|
||||
//.push(vec![("test".to_string(), Addr(0u64))].into_iter().collect());
|
||||
|
||||
macro_rules! assert_len {
|
||||
($inst:expr) => {{
|
||||
|
||||
@@ -112,4 +112,3 @@ impl From<LexParseError> for SyntaxError {
|
||||
}
|
||||
|
||||
pub type Result<T, E = AsmError> = std::result::Result<T, E>;
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use crate::{
|
||||
addr::Addr,
|
||||
obj::{
|
||||
assemble::{
|
||||
session::AsmSession,
|
||||
error::*,
|
||||
},
|
||||
syn::ast::{DataSection, DataLine, Directive},
|
||||
assemble::{error::*, session::AsmSession},
|
||||
syn::ast::{DataLine, DataSection, Directive},
|
||||
},
|
||||
};
|
||||
use std::{collections::{HashMap, HashSet}, rc::Rc};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
// TODO(asm) make custom Names type that has "merge" that will catch errors with duplicate names
|
||||
pub type Names = HashMap<String, Name>;
|
||||
@@ -53,12 +53,15 @@ pub fn get_section_names(section: &DataSection) -> Result<Names> {
|
||||
return Err(AsmError::DuplicateLabel { name: name.clone() });
|
||||
}
|
||||
let export = exports.remove(name);
|
||||
|
||||
names.insert(name.clone(), Name {
|
||||
name: name.clone(),
|
||||
addr: Addr(pos as u64),
|
||||
export,
|
||||
});
|
||||
|
||||
names.insert(
|
||||
name.clone(),
|
||||
Name {
|
||||
name: name.clone(),
|
||||
addr: Addr(pos as u64),
|
||||
export,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +69,9 @@ pub fn get_section_names(section: &DataSection) -> Result<Names> {
|
||||
if exports.is_empty() {
|
||||
Ok(names)
|
||||
} else {
|
||||
Err(AsmError::UnknownExport { name: exports.iter().next().unwrap().to_string() })
|
||||
Err(AsmError::UnknownExport {
|
||||
name: exports.iter().next().unwrap().to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,12 +98,16 @@ pub fn get_exports(session: &mut AsmSession) -> Result<Names> {
|
||||
for name_map in all_exports.iter() {
|
||||
let names_set: HashSet<_> = name_map.keys().collect();
|
||||
if let Some(dupe) = exports.intersection(&names_set).next() {
|
||||
return Err(AsmError::DuplicateExport { name: dupe.to_string() });
|
||||
return Err(AsmError::DuplicateExport {
|
||||
name: dupe.to_string(),
|
||||
});
|
||||
}
|
||||
exports.extend(names_set);
|
||||
}
|
||||
|
||||
// NOTE: this can probably be done with a fancy combinator chain
|
||||
Ok(all_exports.into_iter()
|
||||
.fold(Names::new(), |mut acc, val| { acc.extend(val); acc }))
|
||||
Ok(all_exports.into_iter().fold(Names::new(), |mut acc, val| {
|
||||
acc.extend(val);
|
||||
acc
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
use crate::{
|
||||
obj::{
|
||||
assemble::{
|
||||
Asm,
|
||||
includes::GetIncludes,
|
||||
names::{self, Name, Names},
|
||||
error::*,
|
||||
},
|
||||
obj::Object,
|
||||
syn::ast::Ast,
|
||||
use crate::obj::{
|
||||
assemble::{
|
||||
error::*,
|
||||
includes::GetIncludes,
|
||||
names::{self, Name, Names},
|
||||
Asm,
|
||||
},
|
||||
obj::Object,
|
||||
syn::ast::Ast,
|
||||
};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
@@ -19,19 +17,17 @@ use std::{
|
||||
/// A shared session for the assembler.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AsmSession {
|
||||
pub (in super) includes: Rc<BTreeMap<PathBuf, Ast>>,
|
||||
pub (in super) include_search_paths: Vec<PathBuf>,
|
||||
pub (in super) include_stack: Vec<PathBuf>,
|
||||
pub (in super) name_stack: Vec<Names>,
|
||||
pub (in super) pos: u64,
|
||||
pub(super) includes: Rc<BTreeMap<PathBuf, Ast>>,
|
||||
pub(super) include_search_paths: Vec<PathBuf>,
|
||||
pub(super) include_stack: Vec<PathBuf>,
|
||||
pub(super) name_stack: Vec<Names>,
|
||||
pub(super) pos: u64,
|
||||
}
|
||||
|
||||
impl AsmSession {
|
||||
pub fn assemble(&mut self) -> Result<Object> {
|
||||
let includes = Rc::clone(&self.includes);
|
||||
let sections: Vec<_> = includes.iter()
|
||||
.flat_map(|(_, ast)| ast)
|
||||
.collect();
|
||||
let sections: Vec<_> = includes.iter().flat_map(|(_, ast)| ast).collect();
|
||||
sections.assemble(self)
|
||||
}
|
||||
|
||||
@@ -46,19 +42,21 @@ impl AsmSession {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub (in super) fn current_include_path(&self) -> Option<&Path> {
|
||||
pub(super) fn current_include_path(&self) -> Option<&Path> {
|
||||
self.include_stack.last().map(PathBuf::as_path)
|
||||
}
|
||||
|
||||
pub (in super) fn resolve_include_path(&self, path: impl AsRef<Path>) -> Option<PathBuf> {
|
||||
pub(super) fn resolve_include_path(&self, path: impl AsRef<Path>) -> Option<PathBuf> {
|
||||
let path = path.as_ref();
|
||||
self.current_include_path()
|
||||
.and_then(|last_path| last_path.parent())
|
||||
.map(|last_dir| last_dir.join(path))
|
||||
.or_else(|| self.include_search_paths
|
||||
.iter()
|
||||
.filter_map(|include| include.join(path).canonicalize().ok())
|
||||
.next())
|
||||
.or_else(|| {
|
||||
self.include_search_paths
|
||||
.iter()
|
||||
.filter_map(|include| include.join(path).canonicalize().ok())
|
||||
.next()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lookup_name(&self, name: &str) -> Option<&Name> {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::{mem::MemCursor, obj::obj::*};
|
||||
use prettytable::{Table, row, cell};
|
||||
use std::io::{self, Write as Write};
|
||||
use prettytable::{cell, row, Table};
|
||||
use std::io::{self, Write};
|
||||
|
||||
const SEP: &str = "================================================================================";
|
||||
const SEP: &str =
|
||||
"================================================================================";
|
||||
|
||||
pub trait Disasm {
|
||||
fn disasm(&self, writer: &mut dyn Write) -> io::Result<()>;
|
||||
@@ -61,8 +62,8 @@ impl Disasm for DataSection {
|
||||
if let Ok(inst) = cursor.next_inst() {
|
||||
let start = cursor_pos as usize;
|
||||
let end = start + inst.len();
|
||||
let data = &self.contents.as_slice()[start .. end];
|
||||
table.add_row(row! [
|
||||
let data = &self.contents.as_slice()[start..end];
|
||||
table.add_row(row![
|
||||
format!("{:016x} <{}+{:x}>", pos, self.name, cursor_pos),
|
||||
bytes_hex(data),
|
||||
format!("{:?}", inst),
|
||||
|
||||
@@ -42,4 +42,3 @@ into_parse_error! {
|
||||
}
|
||||
|
||||
pub type Result<T, E = ParseError> = std::result::Result<T, E>;
|
||||
|
||||
|
||||
@@ -114,8 +114,8 @@ pub enum Section {
|
||||
impl Section {
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Section::Data(s) => { 1 + 8 + s.len() },
|
||||
Section::Meta(s) => { 1 + 8 + s.len() },
|
||||
Section::Data(s) => 1 + 8 + s.len(),
|
||||
Section::Meta(s) => 1 + 8 + s.len(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ impl Section {
|
||||
Section::Meta(s) => {
|
||||
cursor.write_u8(SectionKind::Meta.into()).unwrap();
|
||||
s.to_bytes()
|
||||
},
|
||||
}
|
||||
};
|
||||
cursor.write_u64::<LE>(bytes.len() as u64).unwrap();
|
||||
cursor.write(&bytes).unwrap();
|
||||
@@ -181,7 +181,7 @@ impl DataSection {
|
||||
let name_len = cursor.read_u16::<LE>()? as usize;
|
||||
let name_start = cursor.position() as usize;
|
||||
let name_end = name_start + name_len;
|
||||
let name_bytes = &bytes[name_start .. name_end];
|
||||
let name_bytes = &bytes[name_start..name_end];
|
||||
let name_string = String::from_utf8(name_bytes.to_vec())?;
|
||||
cursor.set_position(name_end as u64);
|
||||
|
||||
@@ -205,7 +205,9 @@ pub struct MetaSection {
|
||||
|
||||
impl MetaSection {
|
||||
pub fn len(&self) -> usize {
|
||||
8 + self.entries.iter()
|
||||
8 + self
|
||||
.entries
|
||||
.iter()
|
||||
.map(|(k, _)| 8 + k.as_bytes().len() + 8)
|
||||
.sum::<usize>()
|
||||
}
|
||||
@@ -254,11 +256,11 @@ mod test {
|
||||
name: "data".to_string(),
|
||||
start: 0,
|
||||
len: 16,
|
||||
contents: vec!(0u8; 16),
|
||||
contents: vec![0u8; 16],
|
||||
}),
|
||||
Section::Meta(MetaSection {
|
||||
entries: Default::default(),
|
||||
})
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
use crate::{
|
||||
interrupt::Interrupt,
|
||||
inst,
|
||||
reg::Reg,
|
||||
};
|
||||
use crate::{inst, interrupt::Interrupt, reg::Reg};
|
||||
|
||||
pub type Ast = Vec<Directive>;
|
||||
|
||||
@@ -182,7 +178,7 @@ impl Value {
|
||||
Value::Addr(v, _) => v.len(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn dest_encoding(&self) -> Option<u8> {
|
||||
match self {
|
||||
Value::Int(_) | Value::Name(_) | Value::Here => None,
|
||||
@@ -291,34 +287,30 @@ impl Inst {
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Inst::Add(v1, v2)
|
||||
| Inst::Sub(v1, v2)
|
||||
| Inst::Mul(v1, v2)
|
||||
| Inst::Div(v1, v2)
|
||||
| Inst::IDiv(v1, v2)
|
||||
| Inst::Mod(v1, v2)
|
||||
| Inst::And(v1, v2)
|
||||
| Inst::Or(v1, v2)
|
||||
| Inst::Xor(v1, v2)
|
||||
| Inst::Shl(v1, v2)
|
||||
| Inst::Shr(v1, v2)
|
||||
| Inst::INeg(v1, v2)
|
||||
| Inst::Inv(v1, v2)
|
||||
| Inst::Not(v1, v2)
|
||||
| Inst::CmpEq(v1, v2)
|
||||
| Inst::CmpLt(v1, v2)
|
||||
| Inst::Int(v1, v2)
|
||||
| Inst::Mov(v1, v2) => { 3 + v1.len() + v2.len() }
|
||||
| Inst::Sub(v1, v2)
|
||||
| Inst::Mul(v1, v2)
|
||||
| Inst::Div(v1, v2)
|
||||
| Inst::IDiv(v1, v2)
|
||||
| Inst::Mod(v1, v2)
|
||||
| Inst::And(v1, v2)
|
||||
| Inst::Or(v1, v2)
|
||||
| Inst::Xor(v1, v2)
|
||||
| Inst::Shl(v1, v2)
|
||||
| Inst::Shr(v1, v2)
|
||||
| Inst::INeg(v1, v2)
|
||||
| Inst::Inv(v1, v2)
|
||||
| Inst::Not(v1, v2)
|
||||
| Inst::CmpEq(v1, v2)
|
||||
| Inst::CmpLt(v1, v2)
|
||||
| Inst::Int(v1, v2)
|
||||
| Inst::Mov(v1, v2) => 3 + v1.len() + v2.len(),
|
||||
Inst::Jmp(v)
|
||||
| Inst::Jz(v)
|
||||
| Inst::Jnz(v)
|
||||
| Inst::Call(v)
|
||||
| Inst::Push(v)
|
||||
| Inst::Pop(v) => { 3 + v.len() }
|
||||
Inst::Ret
|
||||
| Inst::IRet
|
||||
| Inst::Halt
|
||||
| Inst::Nop
|
||||
| Inst::Dump => { 2 }
|
||||
| Inst::Jz(v)
|
||||
| Inst::Jnz(v)
|
||||
| Inst::Call(v)
|
||||
| Inst::Push(v)
|
||||
| Inst::Pop(v) => 3 + v.len(),
|
||||
Inst::Ret | Inst::IRet | Inst::Halt | Inst::Nop | Inst::Dump => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,21 +146,25 @@ impl State {
|
||||
pub fn ivt(&self) -> Result<&[Interrupt]> {
|
||||
let ivt_addr = self.get_reg_unchecked(IVT);
|
||||
if ivt_addr % 64 != 0 {
|
||||
panic!("illegal IVT address {:#x}; must be divisible by 64", ivt_addr);
|
||||
panic!(
|
||||
"illegal IVT address {:#x}; must be divisible by 64",
|
||||
ivt_addr
|
||||
);
|
||||
}
|
||||
|
||||
let start = ivt_addr as usize;
|
||||
let end = start + (IVT_LENGTH * mem::size_of::<Interrupt>());
|
||||
|
||||
if end > self.mem.len() {
|
||||
return Err(VmError::MemOutOfBounds { addr: Addr(ivt_addr) });
|
||||
return Err(VmError::MemOutOfBounds {
|
||||
addr: Addr(ivt_addr),
|
||||
});
|
||||
}
|
||||
|
||||
// This is safe because we check the bounds above
|
||||
let slice_ptr = (&self.mem[start..]).as_ptr();
|
||||
let slice = unsafe {
|
||||
std::slice::from_raw_parts(slice_ptr as *const Interrupt, IVT_LENGTH)
|
||||
};
|
||||
let slice =
|
||||
unsafe { std::slice::from_raw_parts(slice_ptr as *const Interrupt, IVT_LENGTH) };
|
||||
|
||||
Ok(slice)
|
||||
}
|
||||
@@ -383,10 +387,12 @@ impl State {
|
||||
fn push(&mut self, source: Source) -> Result<()> {
|
||||
let value = self.load_source(source)?;
|
||||
let mut stack_addr = self.sp();
|
||||
|
||||
|
||||
// create a destination based on the size of the source
|
||||
let dest = match source {
|
||||
Source::Addr64(_) | Source::RegAddr64(_) | Source::Reg(_) | Source::Imm(_) => Dest::Addr64(Addr(stack_addr)),
|
||||
Source::Addr64(_) | Source::RegAddr64(_) | Source::Reg(_) | Source::Imm(_) => {
|
||||
Dest::Addr64(Addr(stack_addr))
|
||||
}
|
||||
Source::Addr32(_) | Source::RegAddr32(_) => Dest::Addr32(Addr(stack_addr)),
|
||||
Source::Addr16(_) | Source::RegAddr16(_) => Dest::Addr16(Addr(stack_addr)),
|
||||
Source::Addr8(_) | Source::RegAddr8(_) => Dest::Addr8(Addr(stack_addr)),
|
||||
|
||||
Reference in New Issue
Block a user