Add value directives and strings

.string, .zstring, .u64, .u32, .u16, .u8 are used before an ImmValue to
determine how the memory should be laid out for that value.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-02-11 17:49:17 -05:00
parent 95d4eb0a60
commit cf9ba376aa
8 changed files with 158 additions and 24 deletions

45
examples/strings.asm Normal file
View File

@@ -0,0 +1,45 @@
data $0x1000 .. $0x1100 {
zstr: .zstring "This is a zero-terminated string"
.export zstr
}
code $0x0 {
zstr_len:
storeimm32 %r15, $0xFF
storeimm32 %r16, $1
storeimm64 %r20, zstr_next
storeimm64 %r21, exit_zstr
regcopy %r10, %r00
zstr_next:
load %r11, %r10
and %r11, %r15
cmpeq %r11, %null
jnz %r21
add %r10, %r16
jmp %r20
main:
storeimm64 %r05, zstr_len
storeimm64 %r00, zstr
jmp %r05
exit_zstr:
regcopy %status, %r10
halt
ineg %r00
add %r10, %r00
regcopy %status, %r10
end:
halt
.export main
}
meta {
entry: main
}

View File

@@ -31,7 +31,7 @@ fn main() -> Result<()> {
} }
}; };
let obj = vm::obj::obj::Object::try_from(&ast)?; let obj = vm::obj::obj::Object::try_from(&ast)?;
//dump(&obj)?; dump(&obj)?;
let mut vm = vm::vm::Vm::new(); let mut vm = vm::vm::Vm::new();
vm.load_object(obj, 1024 * 1024 * 64)?; // 64mb vm.load_object(obj, 1024 * 1024 * 64)?; // 64mb
let status = vm.run()?; let status = vm.run()?;
@@ -45,16 +45,31 @@ fn dump(obj: &vm::obj::obj::Object) -> Result<()> {
use vm::visit::VisitInst; use vm::visit::VisitInst;
let mut stdout = io::stdout(); let mut stdout = io::stdout();
for section in &obj.sections { for section in &obj.sections {
let mut disasm = match section { match section {
Section::Code { start, contents, .. } => { Section::Data { start, contents, .. } => {
vm::disassemble::Disassemble::new(&mut stdout, contents, *start) const WIDTH: usize = 4;
println!("data section at 0x{:08x}", start);
for (i, b) in contents.iter().enumerate() {
if i % WIDTH == 0 {
print!("{:08x} | ", ((*start as usize) + i));
}
print!("{:02x} ", b);
if i % WIDTH == (WIDTH - 1) {
println!();
}
}
println!();
} }
Section::Meta { .. } | Section::Data { .. } => continue, Section::Code { start, contents, .. } => {
println!("code section at 0x{:08x}", start);
let mut disasm = vm::disassemble::Disassemble::new(&mut stdout, contents, *start);
while !disasm.is_done() {
disasm.visit_inst()?;
}
println!();
}
Section::Meta { .. } => continue,
}; };
while !disasm.is_done() {
disasm.visit_inst()?;
}
println!();
} }
Ok(()) Ok(())
} }

View File

@@ -50,10 +50,10 @@ instructions! {
pub fn inst_len(op: InstOp) -> usize { pub fn inst_len(op: InstOp) -> usize {
match op { match op {
// 2 bytes // 2 bytes
INEG | INV | NOT | HALT | NOP => 2, HALT | NOP => 2,
// 4 bytes // 4 bytes
ADD | MUL | DIV | MOD | AND | OR | XOR | SHL | SHR | CMPEQ | CMPLT | JMP | JZ | JNZ ADD | MUL | DIV | INEG | INV | NOT | MOD | AND | OR | XOR | SHL | SHR | CMPEQ | CMPLT
| LOAD | REGCOPY | MEMCOPY | STORE => 4, | JMP | JZ | JNZ | LOAD | REGCOPY | MEMCOPY | STORE => 4,
// Immediates - 4+ bytes // Immediates - 4+ bytes
STOREIMM64 => 16, STOREIMM64 => 16,
STOREIMM32 => 8, STOREIMM32 => 8,

View File

@@ -68,10 +68,8 @@ impl<'a> Assemble<'a> {
bytes.extend(self.assemble_inst(inst)); bytes.extend(self.assemble_inst(inst));
} }
Line::LabelDef(_) => { /* no-op */ } Line::LabelDef(_) => { /* no-op */ }
Line::ImmValue(value) => { Line::ValueDecl(decl) => {
let value = bytes.extend(decl.to_bytes());
self.get_value(value).expect("TODO : value label not found");
bytes.extend(&value.to_le_bytes());
} }
Line::Export(_) => { /* no-op */ } Line::Export(_) => { /* no-op */ }
} }
@@ -138,8 +136,8 @@ impl<'a> Assemble<'a> {
labels.insert(label.to_string(), pos as u64); labels.insert(label.to_string(), pos as u64);
} }
} }
Line::ImmValue(_) => { Line::ValueDecl(decl) => {
pos += 8; pos += decl.len();
} }
Line::Export(name) => { Line::Export(name) => {
if export { if export {

View File

@@ -25,7 +25,7 @@ pub enum SectionOrg {
pub enum Line { pub enum Line {
Inst(Inst), Inst(Inst),
LabelDef(String), LabelDef(String),
ImmValue(ImmValue), ValueDecl(ValueDecl),
Export(String), Export(String),
} }
@@ -35,6 +35,53 @@ pub enum ImmValue {
Label(String), Label(String),
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValueDecl {
U64(u64),
U32(u64),
U16(u64),
U8(u64),
String(String),
ZString(String),
}
impl ValueDecl {
pub fn len(&self) -> usize {
match self {
ValueDecl::U64(_) => 8,
ValueDecl::U32(_) => 4,
ValueDecl::U16(_) => 2,
ValueDecl::U8(_) => 1,
ValueDecl::String(s) => s.as_bytes().len() + 8,
ValueDecl::ZString(s) => s.as_bytes().len() + 1,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let len = self.len();
let bytes = match self {
ValueDecl::U64(v) => v.to_le_bytes().to_vec(),
ValueDecl::U32(v) => v.to_le_bytes()[0..4].to_vec(),
ValueDecl::U16(v) => v.to_le_bytes()[0..2].to_vec(),
ValueDecl::U8(v) => vec![(v & 0xff) as u8],
ValueDecl::String(s) => {
let mut bytes = Vec::with_capacity(self.len());
bytes.extend(&(s.len() as u64).to_le_bytes());
bytes.extend(s.as_bytes());
bytes
}
ValueDecl::ZString(s) => {
let mut bytes = Vec::with_capacity(self.len());
bytes.extend(s.as_bytes());
bytes.push(0);
bytes
}
};
assert_eq!(bytes.len(), len);
bytes
}
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Inst { pub enum Inst {
Add(Reg, Reg), Add(Reg, Reg),

View File

@@ -3,3 +3,14 @@ use lalrpop_util::lalrpop_mod;
lalrpop_mod!(pub parser, "/vm/obj/syn/parser.rs"); lalrpop_mod!(pub parser, "/vm/obj/syn/parser.rs");
pub mod ast; pub mod ast;
pub mod error; pub mod error;
pub fn unescape_string(s: impl AsRef<str>) -> String {
let s = s.as_ref();
s.replace(r"\\", "\\")
.replace("\\n", "\n")
.replace("\\r", "\r")
.replace("\\t", "\t")
.replace("\\t", "\t")
.replace("\\0", "\0")
.replace("\\\"", "\"")
}

View File

@@ -1,6 +1,6 @@
use std::str::FromStr; use std::str::FromStr;
use crate::vm::{ use crate::vm::{
obj::syn::ast::*, obj::syn::{unescape_string, ast::*},
reg::*, reg::*,
}; };
@@ -10,15 +10,13 @@ LabelDef: String = {
<Label> ":" => <> <Label> ":" => <>
} }
// TODO : Value (ImmValue, String)
ImmValue: ImmValue = { ImmValue: ImmValue = {
<Label> => ImmValue::Label(<>), <Label> => ImmValue::Label(<>),
<Number> => ImmValue::Number(<>), <Number> => ImmValue::Number(<>),
} }
Label: String = { Label: String = {
r"[a-zA-Z]+" => String::from(<>), r"[a-zA-Z_][a-zA-Z0-9_]*" => String::from(<>),
} }
Number: u64 = { Number: u64 = {
@@ -27,11 +25,19 @@ Number: u64 = {
<s:r"\$0b[01]+"> => u64::from_str_radix(&s[3..], 2).unwrap(), <s:r"\$0b[01]+"> => u64::from_str_radix(&s[3..], 2).unwrap(),
} }
String: String = {
<s:r#""([^"\\]|\\[\\nrt0"])*""#> => {
let len = s.len();
unescape_string(&s[1..len-1])
}
}
Reg: Reg = { Reg: Reg = {
r"%ip" => IP, r"%ip" => IP,
r"%sp" => SP, r"%sp" => SP,
r"%fp" => FP, r"%fp" => FP,
r"%flags" => FLAGS, r"%flags" => FLAGS,
r"%null" => NULL,
r"%status" => STATUS, r"%status" => STATUS,
r"%r[0-9]{2}" => { r"%r[0-9]{2}" => {
let offset = (&<>[2..]).parse::<u8>().unwrap(); let offset = (&<>[2..]).parse::<u8>().unwrap();
@@ -68,10 +74,19 @@ Inst: Inst = {
"halt" => Inst::Halt, "halt" => Inst::Halt,
} }
ValueDecl: ValueDecl = {
r"\.u64" <Number> => ValueDecl::U64(<>),
r"\.u32" <Number> => ValueDecl::U32(<>),
r"\.u16" <Number> => ValueDecl::U16(<>),
r"\.u8" <Number> => ValueDecl::U8(<>),
r"\.string" <String> => ValueDecl::String(<>),
r"\.zstring" <String> => ValueDecl::ZString(<>),
}
Line: Line = { Line: Line = {
<Inst> => Line::Inst(<>), <Inst> => Line::Inst(<>),
<LabelDef> => Line::LabelDef(<>), <LabelDef> => Line::LabelDef(<>),
<ImmValue> => Line::ImmValue(<>), <ValueDecl> => Line::ValueDecl(<>),
r"\.export" <Label> => Line::Export(<>), r"\.export" <Label> => Line::Export(<>),
} }

View File

@@ -153,6 +153,9 @@ impl Vm {
} }
pub fn set_reg(&mut self, reg: Reg, value: Word) -> Word { pub fn set_reg(&mut self, reg: Reg, value: Word) -> Word {
if reg == NULL {
return 0;
}
mem::replace(&mut self.registers[reg as usize], value) mem::replace(&mut self.registers[reg as usize], value)
} }