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)?;
|
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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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("\\\"", "\"")
|
||||||
|
}
|
||||||
|
|||||||
@@ -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(<>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user