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:
45
examples/strings.asm
Normal file
45
examples/strings.asm
Normal 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
|
||||
}
|
||||
33
src/main.rs
33
src/main.rs
@@ -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));
|
||||
}
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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("\\\"", "\"")
|
||||
}
|
||||
|
||||
@@ -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(<>),
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user