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)?;
//dump(&obj)?;
dump(&obj)?;
let mut vm = vm::vm::Vm::new();
vm.load_object(obj, 1024 * 1024 * 64)?; // 64mb
let status = vm.run()?;
@@ -45,16 +45,31 @@ fn dump(obj: &vm::obj::obj::Object) -> Result<()> {
use vm::visit::VisitInst;
let mut stdout = io::stdout();
for section in &obj.sections {
let mut disasm = match section {
Section::Code { start, contents, .. } => {
vm::disassemble::Disassemble::new(&mut stdout, contents, *start)
match section {
Section::Data { start, contents, .. } => {
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));
}
Section::Meta { .. } | Section::Data { .. } => continue,
};
print!("{:02x} ", b);
if i % WIDTH == (WIDTH - 1) {
println!();
}
}
println!();
}
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,
};
}
Ok(())
}

View File

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

View File

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

View File

@@ -25,7 +25,7 @@ pub enum SectionOrg {
pub enum Line {
Inst(Inst),
LabelDef(String),
ImmValue(ImmValue),
ValueDecl(ValueDecl),
Export(String),
}
@@ -35,6 +35,53 @@ pub enum ImmValue {
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)]
pub enum Inst {
Add(Reg, Reg),

View File

@@ -3,3 +3,14 @@ use lalrpop_util::lalrpop_mod;
lalrpop_mod!(pub parser, "/vm/obj/syn/parser.rs");
pub mod ast;
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 crate::vm::{
obj::syn::ast::*,
obj::syn::{unescape_string, ast::*},
reg::*,
};
@@ -10,15 +10,13 @@ LabelDef: String = {
<Label> ":" => <>
}
// TODO : Value (ImmValue, String)
ImmValue: ImmValue = {
<Label> => ImmValue::Label(<>),
<Number> => ImmValue::Number(<>),
}
Label: String = {
r"[a-zA-Z]+" => String::from(<>),
r"[a-zA-Z_][a-zA-Z0-9_]*" => String::from(<>),
}
Number: u64 = {
@@ -27,11 +25,19 @@ Number: u64 = {
<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 = {
r"%ip" => IP,
r"%sp" => SP,
r"%fp" => FP,
r"%flags" => FLAGS,
r"%null" => NULL,
r"%status" => STATUS,
r"%r[0-9]{2}" => {
let offset = (&<>[2..]).parse::<u8>().unwrap();
@@ -68,10 +74,19 @@ Inst: Inst = {
"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 = {
<Inst> => Line::Inst(<>),
<LabelDef> => Line::LabelDef(<>),
<ImmValue> => Line::ImmValue(<>),
<ValueDecl> => Line::ValueDecl(<>),
r"\.export" <Label> => Line::Export(<>),
}

View File

@@ -153,6 +153,9 @@ impl Vm {
}
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)
}