Add address deref, syntax, and deref sizes

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-02-25 12:07:24 -05:00
parent bdd08c6c5b
commit 5619c9dc87
11 changed files with 308 additions and 99 deletions

View File

@@ -1,31 +1,32 @@
code $0x0 { .section data $0x1000 {
beef: .u16 $0xBEEF
; TODO(syntax)
; bytes: .u8 [
; $0xEF,
; $0xBE,
; $0xAD,
; $0xDE,
; ]
.export beef
}
.section code $0x0 {
main: main:
storeimm32 %r00, $0xDEAD mov %r0, $0xDEAD
storeimm64 %r01, $16 shl %r0, $16
; move 32 bits at 'beef' to %r01
shl %r00, %r01 ; TODO(syntax)
mov %r1, (beef)u32
storeimm32 %r01, $0xBEEF or %r0, %r01
or %r00, %r01 cmpeq %r0, $0xDEADBEEF
; jump to the address 'end'
storeimm64 %r01, $0xDEADBEEF jz end
mov %status, $1
cmpeq %r00, %r01 end:
storeimm32 %r00, failure halt
storeimm64 %r01, ok
jz %r00
jmp %r01
failure:
storeimm32 %status, $1
ok: halt
.export main .export main
} }
meta { .meta {
entry: main entry: main
} }

View File

@@ -1,45 +1,30 @@
data $0x1000 .. $0x1100 { .section data $0x1000 .. $0x1100 {
zstr: .zstring "This is a zero-terminated string" zstr: .zstring "This is a string"
str: .string "This is a string"
.export zstr .export zstr
.export str
} }
code $0x0 { .section code $0x0 {
zstr_len: ; Take the length of a zstr without those fancy "function calls" and "stack frames"
storeimm32 %r15, $0xFF ; %r0: the input string (in)
storeimm32 %r16, $1 ; %r1: the return address (in)
storeimm64 %r20, zstr_next ; %r2: the length of the string (out)
storeimm64 %r21, exit_zstr
regcopy %r10, %r00 zstrlen:
mov %r2, %r0
zstr_next: ztrlen_loop:
load %r11, %r10 cmpeq (%r2)u8, $0
and %r11, %r15 zstrlen_end:
cmpeq %r11, %null jmp %r1
jnz %r21
add %r10, %r16
jmp %r20
main: main:
storeimm64 %r05, zstr_len
storeimm64 %r00, zstr
jmp %r05
exit_zstr:
regcopy %status, %r10
halt halt
ineg %r00
add %r10, %r00
regcopy %status, %r10
end:
halt
.export main .export main
} }
meta { .meta {
entry: main entry: main
} }

View File

@@ -44,6 +44,6 @@ fn main() -> Result<()> {
let mut state = State::new(); let mut state = State::new();
state.load_object(object, 64 * 1024 * 1024)?; state.load_object(object, 64 * 1024 * 1024)?;
let status = state.exec()?; let status = state.exec()?;
println!("exit status: {}", status); println!("exit status: {:#04x}", status);
Ok(()) Ok(())
} }

View File

@@ -134,6 +134,10 @@ pub enum Source {
Addr32(Addr), Addr32(Addr),
Addr16(Addr), Addr16(Addr),
Addr8(Addr), Addr8(Addr),
RegAddr64(Reg),
RegAddr32(Reg),
RegAddr16(Reg),
RegAddr8(Reg),
Reg(Reg), Reg(Reg),
Imm(u64), Imm(u64),
} }
@@ -142,6 +146,7 @@ impl Source {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { match self {
Source::Addr64(_) | Source::Addr32(_) | Source::Addr16(_) | Source::Addr8(_) => 8, Source::Addr64(_) | Source::Addr32(_) | Source::Addr16(_) | Source::Addr8(_) => 8,
Source::RegAddr64(_) | Source::RegAddr32(_) | Source::RegAddr16(_) | Source::RegAddr8(_) => 1,
Source::Reg(_) => 1, Source::Reg(_) => 1,
Source::Imm(_) => 8, Source::Imm(_) => 8,
} }
@@ -154,6 +159,10 @@ pub enum Dest {
Addr32(Addr), Addr32(Addr),
Addr16(Addr), Addr16(Addr),
Addr8(Addr), Addr8(Addr),
RegAddr64(Reg),
RegAddr32(Reg),
RegAddr16(Reg),
RegAddr8(Reg),
Reg(Reg), Reg(Reg),
} }
@@ -161,23 +170,35 @@ impl Dest {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { match self {
Dest::Addr64(_) | Dest::Addr32(_) | Dest::Addr16(_) | Dest::Addr8(_) => 8, Dest::Addr64(_) | Dest::Addr32(_) | Dest::Addr16(_) | Dest::Addr8(_) => 8,
Dest::RegAddr64(_) | Dest::RegAddr32(_) | Dest::RegAddr16(_) | Dest::RegAddr8(_) => 1,
Dest::Reg(_) => 1, Dest::Reg(_) => 1,
} }
} }
} }
// TODO : make this an enum
pub const DEST_ADDR64: u8 = 0b0000; pub const DEST_ADDR64: u8 = 0b0000;
pub const DEST_ADDR32: u8 = 0b0001; pub const DEST_ADDR32: u8 = 0b0001;
pub const DEST_ADDR16: u8 = 0b0010; pub const DEST_ADDR16: u8 = 0b0010;
pub const DEST_ADDR8: u8 = 0b0011; pub const DEST_ADDR8: u8 = 0b0011;
pub const DEST_REG: u8 = 0b0100; pub const DEST_REG_ADDR64: u8 = 0b0100;
pub const DEST_REG_ADDR32: u8 = 0b0101;
pub const DEST_REG_ADDR16: u8 = 0b0110;
pub const DEST_REG_ADDR8: u8 = 0b0111;
/* immediates - not used, invalid */
pub const DEST_REG: u8 = 0b1100;
pub const SOURCE_ADDR64: u8 = 0b0000; pub const SOURCE_ADDR64: u8 = 0b0000;
pub const SOURCE_ADDR32: u8 = 0b0001; pub const SOURCE_ADDR32: u8 = 0b0001;
pub const SOURCE_ADDR16: u8 = 0b0010; pub const SOURCE_ADDR16: u8 = 0b0010;
pub const SOURCE_ADDR8: u8 = 0b0011; pub const SOURCE_ADDR8: u8 = 0b0011;
pub const SOURCE_REG: u8 = 0b0100; pub const SOURCE_REG_ADDR64: u8 = 0b0100;
pub const SOURCE_IMM64: u8 = 0b0101; pub const SOURCE_REG_ADDR32: u8 = 0b0101;
pub const SOURCE_IMM32: u8 = 0b0110; pub const SOURCE_REG_ADDR16: u8 = 0b0110;
pub const SOURCE_IMM16: u8 = 0b0111; pub const SOURCE_REG_ADDR8: u8 = 0b0111;
pub const SOURCE_IMM8: u8 = 0b1000; pub const SOURCE_IMM64: u8 = 0b1000;
pub const SOURCE_IMM32: u8 = 0b1001;
pub const SOURCE_IMM16: u8 = 0b1010;
pub const SOURCE_IMM8: u8 = 0b1011;
pub const SOURCE_REG: u8 = 0b1100;

View File

@@ -145,6 +145,10 @@ impl<T> MemCursor<T>
DEST_ADDR32 => Ok(Dest::Addr32(self.next_addr()?)), DEST_ADDR32 => Ok(Dest::Addr32(self.next_addr()?)),
DEST_ADDR16 => Ok(Dest::Addr16(self.next_addr()?)), DEST_ADDR16 => Ok(Dest::Addr16(self.next_addr()?)),
DEST_ADDR8 => Ok(Dest::Addr8(self.next_addr()?)), DEST_ADDR8 => Ok(Dest::Addr8(self.next_addr()?)),
DEST_REG_ADDR64 => Ok(Dest::RegAddr64(self.next_reg()?)),
DEST_REG_ADDR32 => Ok(Dest::RegAddr32(self.next_reg()?)),
DEST_REG_ADDR16 => Ok(Dest::RegAddr16(self.next_reg()?)),
DEST_REG_ADDR8 => Ok(Dest::RegAddr8(self.next_reg()?)),
DEST_REG => Ok(Dest::Reg(self.next_reg()?)), DEST_REG => Ok(Dest::Reg(self.next_reg()?)),
_ => Err(VmError::IllegalDestSpec { spec }), _ => Err(VmError::IllegalDestSpec { spec }),
} }
@@ -156,6 +160,10 @@ impl<T> MemCursor<T>
SOURCE_ADDR32 => Ok(Source::Addr32(self.next_addr()?)), SOURCE_ADDR32 => Ok(Source::Addr32(self.next_addr()?)),
SOURCE_ADDR16 => Ok(Source::Addr16(self.next_addr()?)), SOURCE_ADDR16 => Ok(Source::Addr16(self.next_addr()?)),
SOURCE_ADDR8 => Ok(Source::Addr8(self.next_addr()?)), SOURCE_ADDR8 => Ok(Source::Addr8(self.next_addr()?)),
SOURCE_REG_ADDR64 => Ok(Source::RegAddr64(self.next_reg()?)),
SOURCE_REG_ADDR32 => Ok(Source::RegAddr32(self.next_reg()?)),
SOURCE_REG_ADDR16 => Ok(Source::RegAddr16(self.next_reg()?)),
SOURCE_REG_ADDR8 => Ok(Source::RegAddr8(self.next_reg()?)),
SOURCE_REG => Ok(Source::Reg(self.next_reg()?)), SOURCE_REG => Ok(Source::Reg(self.next_reg()?)),
SOURCE_IMM64 => Ok(Source::Imm(self.next_u64()?)), SOURCE_IMM64 => Ok(Source::Imm(self.next_u64()?)),
SOURCE_IMM32 => Ok(Source::Imm(self.next_u32()? as u64)), SOURCE_IMM32 => Ok(Source::Imm(self.next_u32()? as u64)),

View File

@@ -22,7 +22,7 @@ impl Asm {
/// Gets all names defined in a data section, their positions, and puts them into a hashmap. /// 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>> { fn gather_names(&self, section: &DataSection) -> Result<HashMap<String, Addr>> {
let mut names = HashMap::new(); let mut names = HashMap::new();
let mut addr = Addr(0); let mut addr = Addr(section.org.start());
for line in section.lines.iter() { for line in section.lines.iter() {
match line { match line {
DataLine::ValueDef(v) => addr += v.len(), 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) Ok(names)
} }
@@ -48,7 +48,9 @@ impl Asm {
.rev() .rev()
.filter_map(|names| names.get(name).copied()) .filter_map(|names| names.get(name).copied())
.next() .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.clear();
asm.names.push(globals); asm.names.push(globals);
let sections = self.iter() let sections = self
.iter()
.map(|section| section.assemble(asm)) .map(|section| section.assemble(asm))
.collect::<Result<_>>()?; .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> { fn assemble(&self, asm: &mut Asm) -> Result<Self::Out> {
let names = asm.gather_names(self)?; let names = asm.gather_names(self)?;
asm.names.push(names); asm.names.push(names);
asm.pos = Addr(0);
let section_len = self.len() as u64; let section_len = self.len() as u64;
let (start, end) = match self.org { let (start, end) = match self.org {
SectionOrg::Start(start) => (start, start + (section_len as u64)), SectionOrg::Start(start) => (start, start + (section_len as u64)),
SectionOrg::StartEnd(start, end) => (start, end), SectionOrg::StartEnd(start, end) => (start, end),
}; };
asm.pos = Addr(start);
if start > end { if start > end {
return Err(AssembleError::StartGreaterThanEnd { start, end, }); return Err(AssembleError::StartGreaterThanEnd { start, end });
} }
let len = end - start - 1; let len = end - start - 1;
if len > section_len { if len > section_len {
@@ -129,7 +135,12 @@ impl Assemble for DataSection {
contents.extend(line.assemble(asm)?); contents.extend(line.assemble(asm)?);
asm.pos += line.len(); 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(); asm.names.pop();
Ok(Section::Data { Ok(Section::Data {
start, start,
@@ -146,15 +157,21 @@ impl Assemble for MetaSection {
let mut entries = HashMap::new(); let mut entries = HashMap::new();
for line in self.lines.iter() { for line in self.lines.iter() {
if entries.contains_key(&line.name) { 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 { let value = match &line.value {
Value::Int(i) => *i, Value::Int(i) => *i,
Value::Name(s) => asm.lookup_name(s.as_str())?.0, Value::Name(s) => asm.lookup_name(s.as_str())?.0,
Value::Reg(_) | Value::Here => return Err(AssembleError::IllegalMetaValue { Value::Reg(_) | Value::Here | Value::Addr(_, _) => {
name: line.name.to_string(), return Err(AssembleError::IllegalMetaValue {
value: line.value.clone(), name: line.name.to_string(),
}), value: line.value.clone(),
})
} // TODO :
// * deref constexpr?
// * pre-startup static init?
}; };
entries.insert(line.name.to_string(), value); entries.insert(line.name.to_string(), value);
} }
@@ -207,17 +224,25 @@ impl Assemble for Inst {
let mut bytes = Vec::with_capacity(len); let mut bytes = Vec::with_capacity(len);
bytes.write_u16::<LE>($op).unwrap(); bytes.write_u16::<LE>($op).unwrap();
let dest = $dest; let dest = $dest;
let dest_encoding = dest.dest_encoding() let dest_encoding =
.ok_or_else(|| AssembleError::IllegalDestValue { value: dest.clone(), })?; dest.dest_encoding()
.ok_or_else(|| AssembleError::IllegalDestValue {
value: dest.clone(),
})?;
let source = $source; let source = $source;
let source_encoding = source.source_encoding(); 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(dest.assemble(asm)?);
bytes.extend(source.assemble(asm)?); bytes.extend(source.assemble(asm)?);
assert_eq!( assert_eq!(
self.len(), bytes.len(), self.len(),
bytes.len(),
"instruction size mismatch in {} instruction - {:?} produces these bytes {:?}", "instruction size mismatch in {} instruction - {:?} produces these bytes {:?}",
stringify!($op), self, bytes stringify!($op),
self,
bytes
); );
Ok(bytes) Ok(bytes)
}}; }};
@@ -244,9 +269,12 @@ impl Assemble for Inst {
let mut bytes = Vec::with_capacity(len); let mut bytes = Vec::with_capacity(len);
bytes.write_u16::<LE>($op).unwrap(); bytes.write_u16::<LE>($op).unwrap();
assert_eq!( assert_eq!(
self.len(), bytes.len(), self.len(),
bytes.len(),
"instruction size mismatch in {} instruction - {:?} produces these bytes {:?}", "instruction size mismatch in {} instruction - {:?} produces these bytes {:?}",
stringify!($op), self, bytes stringify!($op),
self,
bytes
); );
Ok(bytes) Ok(bytes)
}}; }};
@@ -291,6 +319,12 @@ impl Assemble for Value {
Ok(value.0.to_le_bytes().to_vec()) Ok(value.0.to_le_bytes().to_vec())
} }
Value::Here => Ok(asm.pos.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))] #[snafu(display("section start ({:#x}) is greater than end ({:#x})", start, end))]
StartGreaterThanEnd { start: u64, end: u64 }, 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 }, SectionTooShort { section_end: u64, section_size: u64 },
#[snafu(display("illegal instruction destination value: {:?}", value))] #[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>; 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
}
}
}
}

View File

@@ -50,6 +50,14 @@ pub enum SectionOrg {
StartEnd(u64, u64), StartEnd(u64, u64),
} }
impl SectionOrg {
pub fn start(&self) -> u64 {
match self {
SectionOrg::Start(start) | SectionOrg::StartEnd(start, _) => *start,
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum DataLine { pub enum DataLine {
ValueDef(ValueDef), ValueDef(ValueDef),
@@ -87,22 +95,24 @@ impl ValueDef {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Value { pub enum Value {
// TODO : immediate int sizes
// Int(u64, IntSize)
Int(u64), Int(u64),
Reg(Reg), Reg(Reg),
Name(String), Name(String),
Here, Here,
Addr(Box<Value>, IntSize),
//Array(Vec<Value>), //Array(Vec<Value>),
//Deref(Value, IntSize),
} }
impl Value { impl Value {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { match self {
// TODO : immediate int sizes
Value::Int(_) => 8, Value::Int(_) => 8,
Value::Reg(_) => 1, Value::Reg(_) => 1,
Value::Name(_) => 8, Value::Name(_) => 8,
Value::Here => 8, Value::Here => 8,
Value::Addr(v, _) => v.len(),
} }
} }
@@ -110,6 +120,24 @@ impl Value {
match self { match self {
Value::Int(_) | Value::Name(_) | Value::Here => None, Value::Int(_) | Value::Name(_) | Value::Here => None,
Value::Reg(_) => Some(inst::DEST_REG), Value::Reg(_) => Some(inst::DEST_REG),
// TODO : check reg vs int value, and use dest_reg_addr8/16/32/64 values
Value::Addr(v, size) => {
if let Value::Reg(_) = &**v {
match size {
IntSize::U64 => Some(inst::DEST_REG_ADDR64),
IntSize::U32 => Some(inst::DEST_REG_ADDR32),
IntSize::U16 => Some(inst::DEST_REG_ADDR16),
IntSize::U8 => Some(inst::DEST_REG_ADDR8),
}
} else {
match size {
IntSize::U64 => Some(inst::DEST_ADDR64),
IntSize::U32 => Some(inst::DEST_ADDR32),
IntSize::U16 => Some(inst::DEST_ADDR16),
IntSize::U8 => Some(inst::DEST_ADDR8),
}
}
}
} }
} }
@@ -117,11 +145,37 @@ impl Value {
match self { match self {
Value::Int(_) => inst::SOURCE_IMM64, Value::Int(_) => inst::SOURCE_IMM64,
Value::Reg(_) => inst::SOURCE_REG, Value::Reg(_) => inst::SOURCE_REG,
// TODO : check reg vs int value, and use source_reg_addr8/16/32/64 values
Value::Name(_) | Value::Here => inst::SOURCE_IMM64, Value::Name(_) | Value::Here => inst::SOURCE_IMM64,
Value::Addr(v, size) => {
if let Value::Reg(_) = &**v {
match size {
IntSize::U64 => inst::SOURCE_REG_ADDR64,
IntSize::U32 => inst::SOURCE_REG_ADDR32,
IntSize::U16 => inst::SOURCE_REG_ADDR16,
IntSize::U8 => inst::SOURCE_REG_ADDR8,
}
} else {
match size {
IntSize::U64 => inst::SOURCE_ADDR64,
IntSize::U32 => inst::SOURCE_ADDR32,
IntSize::U16 => inst::SOURCE_ADDR16,
IntSize::U8 => inst::SOURCE_ADDR8,
}
}
}
} }
} }
} }
#[derive(Debug, Clone)]
pub enum IntSize {
U8,
U16,
U32,
U64,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Inst { pub enum Inst {
Add(Value, Value), Add(Value, Value),

View File

@@ -5,13 +5,18 @@
\.meta "DIR_META" \.meta "DIR_META"
\.section "DIR_SECTION" \.section "DIR_SECTION"
\.export "DIR_EXPORT" \.export "DIR_EXPORT"
\( "LPAREN"
\) "RPAREN"
\{ "LBRACE" \{ "LBRACE"
\} "RBRACE" \} "RBRACE"
\.\. "DOTDOT" \.\. "DOTDOT"
: "COLON" : "COLON"
, "COMMA" , "COMMA"
\$\$ "BUCKBUCK" \$\$ "BUCKBUCK"
[iu](8|16|32|64) "INT_TYPE" u8 "U8"
u16 "U16"
u32 "U32"
u64 "U64"
\.[iu](8|16|32|64) "INT_DEF" \.[iu](8|16|32|64) "INT_DEF"
\.string "STR_DEF" \.string "STR_DEF"
\.zstring "ZSTR_DEF" \.zstring "ZSTR_DEF"

View File

@@ -57,6 +57,11 @@ Value -> Value:
| Reg { Value::Reg($1) } | Reg { Value::Reg($1) }
| Name { Value::Name($1) } | Name { Value::Name($1) }
| 'BUCKBUCK' { Value::Here } | 'BUCKBUCK' { Value::Here }
| 'LPAREN' Value 'RPAREN' { Value::Addr(Box::new($2), IntSize::U64) }
| 'LPAREN' Value 'RPAREN' 'U8' { Value::Addr(Box::new($2), IntSize::U8) }
| 'LPAREN' Value 'RPAREN' 'U16' { Value::Addr(Box::new($2), IntSize::U16) }
| 'LPAREN' Value 'RPAREN' 'U32' { Value::Addr(Box::new($2), IntSize::U32) }
| 'LPAREN' Value 'RPAREN' 'U64' { Value::Addr(Box::new($2), IntSize::U64) }
; ;
Inst -> Inst: Inst -> Inst:

View File

@@ -232,6 +232,9 @@ impl State {
// TODO - dump // TODO - dump
} }
} }
if next_ip > 100 {
panic!("{:?}", next_ip);
}
self.set_reg_unchecked(IP, next_ip); self.set_reg_unchecked(IP, next_ip);
Ok(()) Ok(())
} }
@@ -244,6 +247,23 @@ impl State {
.write_u32((value & 0xffff_ffff) as u32), .write_u32((value & 0xffff_ffff) as u32),
Dest::Addr16(a) => self.mem_cursor_mut(a).write_u16((value & 0xffff) as u16), Dest::Addr16(a) => self.mem_cursor_mut(a).write_u16((value & 0xffff) as u16),
Dest::Addr8(a) => self.mem_cursor_mut(a).write_u8((value & 0xff) as u8), Dest::Addr8(a) => self.mem_cursor_mut(a).write_u8((value & 0xff) as u8),
Dest::RegAddr64(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr).write_u64(value)
}
Dest::RegAddr32(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr)
.write_u32((value & 0xffff_ffff) as u32)
}
Dest::RegAddr16(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr).write_u16((value & 0xffff) as u16)
}
Dest::RegAddr8(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr).write_u8((value & 0xff) as u8)
}
Dest::Reg(reg) => self.set_reg(reg, value), Dest::Reg(reg) => self.set_reg(reg, value),
} }
} }
@@ -254,6 +274,10 @@ impl State {
Source::Addr32(a) => self.mem_cursor(a).next_u32()? as u64, Source::Addr32(a) => self.mem_cursor(a).next_u32()? as u64,
Source::Addr16(a) => self.mem_cursor(a).next_u16()? as u64, Source::Addr16(a) => self.mem_cursor(a).next_u16()? as u64,
Source::Addr8(a) => self.mem_cursor(a).next_u8()? as u64, Source::Addr8(a) => self.mem_cursor(a).next_u8()? as u64,
Source::RegAddr64(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u64()?,
Source::RegAddr32(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u32()? as u64,
Source::RegAddr16(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u16()? as u64,
Source::RegAddr8(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u8()? as u64,
Source::Reg(reg) => self.get_reg(reg)?, Source::Reg(reg) => self.get_reg(reg)?,
Source::Imm(u) => u, Source::Imm(u) => u,
}; };
@@ -266,6 +290,10 @@ impl State {
Dest::Addr32(a) => self.mem_cursor(a).next_u32()? as u64, Dest::Addr32(a) => self.mem_cursor(a).next_u32()? as u64,
Dest::Addr16(a) => self.mem_cursor(a).next_u16()? as u64, Dest::Addr16(a) => self.mem_cursor(a).next_u16()? as u64,
Dest::Addr8(a) => self.mem_cursor(a).next_u8()? as u64, Dest::Addr8(a) => self.mem_cursor(a).next_u8()? as u64,
Dest::RegAddr64(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u64()?,
Dest::RegAddr32(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u32()? as u64,
Dest::RegAddr16(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u16()? as u64,
Dest::RegAddr8(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u8()? as u64,
Dest::Reg(reg) => self.get_reg(reg)?, Dest::Reg(reg) => self.get_reg(reg)?,
}; };
Ok(value) Ok(value)

21
vm.md
View File

@@ -228,7 +228,6 @@ the section contents.
* 8 bits - Section kind * 8 bits - Section kind
* 0x00 - Data * 0x00 - Data
* 0x10 - Code
* 0xFF - Meta * 0xFF - Meta
* 64 bits - Length of the section * 64 bits - Length of the section
@@ -239,15 +238,6 @@ The data section contains static data that is initialized to some known value.
* 64 bits - section load start - where in memory the content of this section begins * 64 bits - section load start - where in memory the content of this section begins
* 64 bits - section length - how long the memory content is * 64 bits - section length - how long the memory content is
### Code section
The code section contains executable code.
* 64 bits - section load start - where in memory the content of this section begins
* 64 bits - section load end - where in memory the content of this section ends
The remaining length of the section is the code itself.
### Meta section ### Meta section
The meta section holds a table of metadata about the binary in a key-value format of strings mapping The meta section holds a table of metadata about the binary in a key-value format of strings mapping
@@ -273,3 +263,14 @@ A VM must provide support for the following meta-values:
* Interrupts * Interrupts
* MMIO regions * MMIO regions
* Paging? * Paging?
* Determine how address sizes are determined
* source size <= dest size - zero extend source and copy
* mov %r0, (label)u32
* source size > dest size - truncate to dest size
* mov (label)u32, %r0
* source size with unknown dest size - use dest size == source size
* mov %r0, (label)
* unknown source size with dest size - use dest size == source size
* mov (label), %r0
* unknown source size with unknown dest size - 64 bits
* mov (label), (%r0)