Add address deref, syntax, and deref sizes
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -22,7 +22,7 @@ impl Asm {
|
||||
/// Gets all names defined in a data section, their positions, and puts them into a hashmap.
|
||||
fn gather_names(&self, section: &DataSection) -> Result<HashMap<String, Addr>> {
|
||||
let mut names = HashMap::new();
|
||||
let mut addr = Addr(0);
|
||||
let mut addr = Addr(section.org.start());
|
||||
for line in section.lines.iter() {
|
||||
match line {
|
||||
DataLine::ValueDef(v) => addr += v.len(),
|
||||
@@ -37,7 +37,7 @@ impl Asm {
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_eq!(addr, section.len());
|
||||
assert_eq!(addr, Addr(section.org.start() + (section.len() as u64)));
|
||||
Ok(names)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,9 @@ impl Asm {
|
||||
.rev()
|
||||
.filter_map(|names| names.get(name).copied())
|
||||
.next()
|
||||
.ok_or_else(|| AssembleError::UnknownName { name: name.to_string() })
|
||||
.ok_or_else(|| AssembleError::UnknownName {
|
||||
name: name.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +85,14 @@ impl Assemble for Vec<SectionDef> {
|
||||
asm.names.clear();
|
||||
asm.names.push(globals);
|
||||
|
||||
let sections = self.iter()
|
||||
let sections = self
|
||||
.iter()
|
||||
.map(|section| section.assemble(asm))
|
||||
.collect::<Result<_>>()?;
|
||||
Ok(Object { version: OBJ_VERSION, sections, })
|
||||
Ok(Object {
|
||||
version: OBJ_VERSION,
|
||||
sections,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,14 +113,14 @@ impl Assemble for DataSection {
|
||||
fn assemble(&self, asm: &mut Asm) -> Result<Self::Out> {
|
||||
let names = asm.gather_names(self)?;
|
||||
asm.names.push(names);
|
||||
asm.pos = Addr(0);
|
||||
let section_len = self.len() as u64;
|
||||
let (start, end) = match self.org {
|
||||
SectionOrg::Start(start) => (start, start + (section_len as u64)),
|
||||
SectionOrg::StartEnd(start, end) => (start, end),
|
||||
};
|
||||
asm.pos = Addr(start);
|
||||
if start > end {
|
||||
return Err(AssembleError::StartGreaterThanEnd { start, end, });
|
||||
return Err(AssembleError::StartGreaterThanEnd { start, end });
|
||||
}
|
||||
let len = end - start - 1;
|
||||
if len > section_len {
|
||||
@@ -129,7 +135,12 @@ impl Assemble for DataSection {
|
||||
contents.extend(line.assemble(asm)?);
|
||||
asm.pos += line.len();
|
||||
}
|
||||
assert_eq!(contents.len() as u64, section_len, "in section {}", self.name);
|
||||
assert_eq!(
|
||||
contents.len() as u64,
|
||||
section_len,
|
||||
"in section {}",
|
||||
self.name
|
||||
);
|
||||
asm.names.pop();
|
||||
Ok(Section::Data {
|
||||
start,
|
||||
@@ -146,15 +157,21 @@ impl Assemble for MetaSection {
|
||||
let mut entries = HashMap::new();
|
||||
for line in self.lines.iter() {
|
||||
if entries.contains_key(&line.name) {
|
||||
return Err(AssembleError::DuplicateMetaName { name: line.name.to_string() });
|
||||
return Err(AssembleError::DuplicateMetaName {
|
||||
name: line.name.to_string(),
|
||||
});
|
||||
}
|
||||
let value = match &line.value {
|
||||
Value::Int(i) => *i,
|
||||
Value::Name(s) => asm.lookup_name(s.as_str())?.0,
|
||||
Value::Reg(_) | Value::Here => return Err(AssembleError::IllegalMetaValue {
|
||||
name: line.name.to_string(),
|
||||
value: line.value.clone(),
|
||||
}),
|
||||
Value::Reg(_) | Value::Here | Value::Addr(_, _) => {
|
||||
return Err(AssembleError::IllegalMetaValue {
|
||||
name: line.name.to_string(),
|
||||
value: line.value.clone(),
|
||||
})
|
||||
} // TODO :
|
||||
// * deref constexpr?
|
||||
// * pre-startup static init?
|
||||
};
|
||||
entries.insert(line.name.to_string(), value);
|
||||
}
|
||||
@@ -207,17 +224,25 @@ impl Assemble for Inst {
|
||||
let mut bytes = Vec::with_capacity(len);
|
||||
bytes.write_u16::<LE>($op).unwrap();
|
||||
let dest = $dest;
|
||||
let dest_encoding = dest.dest_encoding()
|
||||
.ok_or_else(|| AssembleError::IllegalDestValue { value: dest.clone(), })?;
|
||||
let dest_encoding =
|
||||
dest.dest_encoding()
|
||||
.ok_or_else(|| AssembleError::IllegalDestValue {
|
||||
value: dest.clone(),
|
||||
})?;
|
||||
let source = $source;
|
||||
let source_encoding = source.source_encoding();
|
||||
bytes.write_u8((dest_encoding << 4) | source_encoding).unwrap();
|
||||
bytes
|
||||
.write_u8((dest_encoding << 4) | source_encoding)
|
||||
.unwrap();
|
||||
bytes.extend(dest.assemble(asm)?);
|
||||
bytes.extend(source.assemble(asm)?);
|
||||
assert_eq!(
|
||||
self.len(), bytes.len(),
|
||||
self.len(),
|
||||
bytes.len(),
|
||||
"instruction size mismatch in {} instruction - {:?} produces these bytes {:?}",
|
||||
stringify!($op), self, bytes
|
||||
stringify!($op),
|
||||
self,
|
||||
bytes
|
||||
);
|
||||
Ok(bytes)
|
||||
}};
|
||||
@@ -244,9 +269,12 @@ impl Assemble for Inst {
|
||||
let mut bytes = Vec::with_capacity(len);
|
||||
bytes.write_u16::<LE>($op).unwrap();
|
||||
assert_eq!(
|
||||
self.len(), bytes.len(),
|
||||
self.len(),
|
||||
bytes.len(),
|
||||
"instruction size mismatch in {} instruction - {:?} produces these bytes {:?}",
|
||||
stringify!($op), self, bytes
|
||||
stringify!($op),
|
||||
self,
|
||||
bytes
|
||||
);
|
||||
Ok(bytes)
|
||||
}};
|
||||
@@ -291,6 +319,12 @@ impl Assemble for Value {
|
||||
Ok(value.0.to_le_bytes().to_vec())
|
||||
}
|
||||
Value::Here => Ok(asm.pos.0.to_le_bytes().to_vec()),
|
||||
Value::Addr(v, _) => if let Value::Addr(_, _) = &**v {
|
||||
// double deref is not allowed
|
||||
todo!()
|
||||
} else {
|
||||
v.assemble(asm)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,11 +352,78 @@ pub enum AssembleError {
|
||||
#[snafu(display("section start ({:#x}) is greater than end ({:#x})", start, end))]
|
||||
StartGreaterThanEnd { start: u64, end: u64 },
|
||||
|
||||
#[snafu(display("section end ({:#x}) too short for section content size ({:#x})", section_end, section_size))]
|
||||
#[snafu(display(
|
||||
"section end ({:#x}) too short for section content size ({:#x})",
|
||||
section_end,
|
||||
section_size
|
||||
))]
|
||||
SectionTooShort { section_end: u64, section_size: u64 },
|
||||
|
||||
#[snafu(display("illegal instruction destination value: {:?}", value))]
|
||||
IllegalDestValue { value: Value, },
|
||||
IllegalDestValue { value: Value },
|
||||
|
||||
#[snafu(display("deref of a deref value is not allowed"))]
|
||||
DoubleDeref { value: Value },
|
||||
}
|
||||
|
||||
pub type Result<T, E = AssembleError> = std::result::Result<T, E>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_inst_len() {
|
||||
let mut asm = Asm::default();
|
||||
asm.names.push(vec![("test".to_string(), Addr(0u64))].into_iter().collect());
|
||||
|
||||
macro_rules! assert_len {
|
||||
($inst:expr) => {{
|
||||
let inst = $inst;
|
||||
let asm_size = $inst.assemble(&mut asm).unwrap().len();
|
||||
assert_eq!(inst.len(), asm_size, "Instruction {:?}.len() indicates it should be {} bytes long but was assembled as {} bytes", inst, inst.len(), asm_size);
|
||||
}}
|
||||
}
|
||||
|
||||
use Inst::*;
|
||||
|
||||
let dummy_dests = &[
|
||||
Value::Reg(0),
|
||||
Value::Addr(Box::new(Value::Reg(0)), IntSize::U8),
|
||||
Value::Addr(Box::new(Value::Here), IntSize::U16),
|
||||
Value::Addr(Box::new(Value::Name("test".to_string())), IntSize::U32),
|
||||
Value::Addr(Box::new(Value::Int(0)), IntSize::U64),
|
||||
];
|
||||
|
||||
let dummy_sources = &[
|
||||
Value::Int(0),
|
||||
Value::Reg(0),
|
||||
Value::Name("test".to_string()),
|
||||
Value::Here,
|
||||
Value::Addr(Box::new(Value::Reg(0)), IntSize::U8),
|
||||
Value::Addr(Box::new(Value::Here), IntSize::U16),
|
||||
Value::Addr(Box::new(Value::Name("test".to_string())), IntSize::U32),
|
||||
Value::Addr(Box::new(Value::Int(0)), IntSize::U32),
|
||||
];
|
||||
|
||||
for v1 in dummy_dests {
|
||||
for v2 in dummy_sources {
|
||||
assert_len!(Add(v1.clone(), v2.clone()));
|
||||
assert_len!(Sub(v1.clone(), v2.clone()));
|
||||
assert_len!(Mul(v1.clone(), v2.clone()));
|
||||
assert_len!(Div(v1.clone(), v2.clone()));
|
||||
assert_len!(Mod(v1.clone(), v2.clone()));
|
||||
assert_len!(And(v1.clone(), v2.clone()));
|
||||
assert_len!(Or(v1.clone(), v2.clone()));
|
||||
assert_len!(Xor(v1.clone(), v2.clone()));
|
||||
assert_len!(Shl(v1.clone(), v2.clone()));
|
||||
assert_len!(Shr(v1.clone(), v2.clone()));
|
||||
assert_len!(INeg(v1.clone(), v2.clone()));
|
||||
assert_len!(Inv(v1.clone(), v2.clone()));
|
||||
assert_len!(Not(v1.clone(), v2.clone()));
|
||||
assert_len!(Mov(v1.clone(), v2.clone()));
|
||||
// TODO more length tests
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user