wrote new "ContextTree" system, emulator filetree is kind of broken for now. next commit will fix this.
This commit is contained in:
@@ -4,17 +4,11 @@ use crate::{assembler::AssembleError, expect_token};
|
||||
use common::prelude::*;
|
||||
use dsa_tasks::ProcessAgent;
|
||||
|
||||
pub fn codegen(nodes: Vec<Node>, ctx: &ProcessAgent) -> Result<Vec<Instruction>, AssembleError> {
|
||||
let mut instructions = vec![];
|
||||
|
||||
for node in nodes {
|
||||
ctx.log(format!("{}", node));
|
||||
instructions.push(build_instruction(&node)?);
|
||||
}
|
||||
|
||||
ctx.log("Assembly Successful ✅");
|
||||
|
||||
Ok(instructions)
|
||||
pub fn codegen(nodes: &[Node], ctx: &ProcessAgent) -> Result<Vec<Instruction>, AssembleError> {
|
||||
nodes
|
||||
.iter()
|
||||
.map(build_instruction)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
fn build_instruction(node: &Node) -> Result<Instruction, AssembleError> {
|
||||
@@ -41,6 +35,7 @@ fn build_instruction(node: &Node) -> Result<Instruction, AssembleError> {
|
||||
Opcode::Jmp | Opcode::Call | Opcode::Jic | Opcode::Jnc => {
|
||||
ins_jump_unconditional(opcode, &args)
|
||||
}
|
||||
|
||||
Opcode::Jez | Opcode::Jnz => ins_jump_conditional(opcode, &args),
|
||||
Opcode::Shl | Opcode::Shr => ins_bitshift(opcode, &args),
|
||||
Opcode::Add
|
||||
@@ -72,10 +67,7 @@ fn build_instruction(node: &Node) -> Result<Instruction, AssembleError> {
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_mov(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_mov(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(src_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -92,10 +84,7 @@ fn ins_mov(
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_cmov(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_cmov(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(src_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -116,10 +105,7 @@ fn ins_cmov(
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_ldx_stx(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_ldx_stx(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(src_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -147,10 +133,7 @@ fn ins_ldx_stx(
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_stack(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_stack(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(reg_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -163,10 +146,7 @@ fn ins_stack(
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_load_imm(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_load_imm(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(value_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -184,10 +164,7 @@ fn ins_load_imm(
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_jump_unconditional(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_jump_unconditional(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(addr_imm_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -206,21 +183,16 @@ fn ins_jump_unconditional(
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_jump_conditional(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_jump_conditional(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(condition_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
let Some(addr_imm_token) = args.get(1) else {
|
||||
return Err(AssembleError::MissingArgument(1));
|
||||
};
|
||||
let addr_reg_token = if let Some(token) = args.get(2) {
|
||||
token
|
||||
} else {
|
||||
&Token::Register(Register::Zero)
|
||||
};
|
||||
let addr_reg_token = args
|
||||
.get(2)
|
||||
.map_or(&Token::Register(Register::Zero), |token| token);
|
||||
|
||||
let condition = expect_token!(condition_token, Register)?;
|
||||
let addr_imm = expect_token!(addr_imm_token, Immediate)?;
|
||||
@@ -233,10 +205,7 @@ fn ins_jump_conditional(
|
||||
})
|
||||
}
|
||||
|
||||
fn ins_comparison(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_comparison(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(left_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -261,10 +230,7 @@ fn ins_comparison(
|
||||
})
|
||||
}
|
||||
|
||||
fn ins_bitshift(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_bitshift(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(src_reg) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -290,10 +256,7 @@ fn ins_bitshift(
|
||||
})
|
||||
}
|
||||
|
||||
fn ins_arithmetic(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_arithmetic(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(left_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -321,10 +284,7 @@ fn ins_arithmetic(
|
||||
})
|
||||
}
|
||||
|
||||
fn ins_imm_arithmetic(
|
||||
opcode: Opcode,
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn ins_imm_arithmetic(opcode: Opcode, args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(reg_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -368,9 +328,7 @@ fn ins_interrupt(args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
Ok(Instruction::int(code))
|
||||
}
|
||||
|
||||
fn build_data_instruction(
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn build_data_instruction(args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(immediate_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -379,9 +337,7 @@ fn build_data_instruction(
|
||||
Ok(Instruction::data(immediate))
|
||||
}
|
||||
|
||||
fn build_segment_instruction(
|
||||
args: &[Token],
|
||||
) -> Result<Instruction, AssembleError> {
|
||||
fn build_segment_instruction(args: &[Token]) -> Result<Instruction, AssembleError> {
|
||||
let Some(immediate_token) = args.first() else {
|
||||
return Err(AssembleError::MissingArgument(0));
|
||||
};
|
||||
@@ -390,6 +346,6 @@ fn build_segment_instruction(
|
||||
Ok(Instruction::data(
|
||||
// mask the first 6 bits for the opcode
|
||||
// this is really deprecated tbh. may remove in future.
|
||||
Opcode::Segment as u32 | (immediate & 0x05FFFFFF),
|
||||
Opcode::Segment as u32 | (immediate & 0x05FF_FFFF),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
#![allow(dead_code, unused)]
|
||||
|
||||
use dsa_tasks::{ProcessAgent, TraceableProcess};
|
||||
use crate::assembler::resolver2::{SectionId, resolve_address, resolve_dependencies, resolve_symbols, split_sections};
|
||||
use crate::assembler::resolver2::{
|
||||
SectionId, resolve_address, resolve_dependencies, resolve_symbols, split_sections,
|
||||
};
|
||||
use dsa_formats::binary_dse::{DseExecutable, SymbolEntry};
|
||||
use dsa_tasks::{ProcessAgent, TraceableProcess};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
fmt, fs,
|
||||
hash::{DefaultHasher, Hash, Hasher},
|
||||
path::{Path, PathBuf},
|
||||
sync::
|
||||
mpsc::{self},
|
||||
sync::mpsc::{self},
|
||||
};
|
||||
|
||||
// Module declarations
|
||||
@@ -64,6 +65,16 @@ impl TraceableProcess for Assembler {
|
||||
fn run(mut self: Box<Self>, ctx: ProcessAgent) -> Result<Self::Output, Self::Error> {
|
||||
assemble(&self.src_path, &ctx)
|
||||
}
|
||||
|
||||
fn label(&self) -> String {
|
||||
format!(
|
||||
"Assembling {}",
|
||||
self.src_path
|
||||
.file_name()
|
||||
.expect("a valid path must have a file name")
|
||||
.to_string_lossy()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble(src: &Path, ctx: &ProcessAgent) -> Result<DseExecutable, AssembleError> {
|
||||
@@ -74,21 +85,14 @@ fn assemble(src: &Path, ctx: &ProcessAgent) -> Result<DseExecutable, AssembleErr
|
||||
|
||||
let nodes = program.nodes.clone();
|
||||
|
||||
// for node in &nodes {
|
||||
// ctx.log(format!("{:?}", node));
|
||||
// }
|
||||
|
||||
let (data_nodes, mut text_nodes) = split_sections(nodes);
|
||||
let symbol_table = resolve_symbols(&data_nodes, &mut text_nodes)?;
|
||||
let text_len = text_nodes.len() as u32;
|
||||
|
||||
ctx.log("Generating assembly output...");
|
||||
ctx.log("Generating Instructions...");
|
||||
|
||||
// println!("Generating assembly output...");
|
||||
let instructions = codegen(text_nodes, ctx)?;
|
||||
let text: Vec<u32> = instructions
|
||||
.iter()
|
||||
.map(|i| i.0).collect();
|
||||
let instructions = codegen(&text_nodes, ctx)?;
|
||||
let text: Vec<u32> = instructions.iter().map(|i| i.0).collect();
|
||||
|
||||
let data = build_data_bytes(&data_nodes)?;
|
||||
|
||||
@@ -117,20 +121,16 @@ fn assemble(src: &Path, ctx: &ProcessAgent) -> Result<DseExecutable, AssembleErr
|
||||
.iter()
|
||||
.find(|(sym, _)| sym.name == "_init")
|
||||
.map(|(_, entry)| resolve_address(*entry, text_len))
|
||||
.ok_or(AssembleError::UndefinedSymbol(Symbol {
|
||||
name: "_init".to_string(),
|
||||
module: Module::Resolved(0),
|
||||
}))?;
|
||||
.ok_or_else(|| {
|
||||
AssembleError::UndefinedSymbol(Symbol {
|
||||
name: "_init".to_string(),
|
||||
module: Module::Resolved(0),
|
||||
})
|
||||
})?;
|
||||
|
||||
ctx.log("Compilation Successful");
|
||||
|
||||
Ok(DseExecutable::new(
|
||||
symbols.as_slice(),
|
||||
&string_table,
|
||||
&data,
|
||||
&text,
|
||||
entry_point,
|
||||
).unwrap())
|
||||
Ok(DseExecutable::new(symbols.as_slice(), &string_table, &data, &text, entry_point).unwrap())
|
||||
}
|
||||
|
||||
fn build_data_bytes(data_nodes: &[Node]) -> Result<Vec<u8>, AssembleError> {
|
||||
@@ -144,7 +144,6 @@ fn build_data_bytes(data_nodes: &[Node]) -> Result<Vec<u8>, AssembleError> {
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
|
||||
fn prepare_dependency(
|
||||
path: &Path,
|
||||
modules: &mut HashSet<u64>,
|
||||
@@ -157,21 +156,26 @@ fn prepare_dependency(
|
||||
.expect("Failed to get file name from path");
|
||||
|
||||
if let Ok(path) = path.canonicalize() {
|
||||
ctx.log(format!("{:20} {:20} [{}]", "Building", filename, path.display()));
|
||||
ctx.log(format!(
|
||||
"{:30} {:20} [{}]",
|
||||
"Building",
|
||||
filename,
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
|
||||
let src =
|
||||
fs::read_to_string(path).map_err(|_| AssembleError::InvalidFile(path.to_path_buf()))?;
|
||||
let file_hash = quick_hash(path);
|
||||
|
||||
ctx.log(format!("{:20} {:20}", "Tokenising", filename));
|
||||
ctx.log(format!("{:30} {:20}", "Lexing", filename));
|
||||
let tokens = lexer::lexer(src, file_hash)?;
|
||||
// let tokens = Lexer::new(src, file_hash).run()?;
|
||||
|
||||
ctx.log(format!("{:20} {:20}", "Parsing", filename));
|
||||
ctx.log(format!("{:30} {:20}", "Parsing", filename));
|
||||
let parsed = Parser::parse_nodes(tokens)?;
|
||||
|
||||
ctx.log(format!("{:20} {:20}", "Resolving Deps", filename));
|
||||
ctx.log(format!("{:30} {:20}", "Resolving Dependencies", filename));
|
||||
// Get the parent directory of the source file to use as the base directory
|
||||
let base_dir = path
|
||||
.parent()
|
||||
@@ -181,20 +185,20 @@ fn prepare_dependency(
|
||||
|
||||
let deps = Parser::get_dependencies(&nodes, path)?;
|
||||
|
||||
ctx.log(format!("{:20} {:20}", "Expanding Pseudo-ops", filename));
|
||||
ctx.log(format!("{:30} {:20}", "Expanding Macros", filename));
|
||||
|
||||
// add a section instruction
|
||||
nodes.insert(
|
||||
0,
|
||||
node!(None, Opcode::Segment, Token::Immediate(file_hash as u32)),
|
||||
);
|
||||
|
||||
|
||||
program.add_module(nodes);
|
||||
|
||||
for dep in deps {
|
||||
ctx.log(format!(
|
||||
"{:20} {:20}",
|
||||
"Including",
|
||||
"Including Dependency",
|
||||
dep.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.expect("Dependency path has no file name or is not valid UTF-8")
|
||||
@@ -202,7 +206,7 @@ fn prepare_dependency(
|
||||
|
||||
let dep_hash = quick_hash(&dep);
|
||||
if modules.insert(dep_hash) {
|
||||
prepare_dependency(dep.as_path(), modules, program, &ctx)?;
|
||||
prepare_dependency(dep.as_path(), modules, program, ctx)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user