added a create-project system to assembler, and fixed a couple of parsing bugs
This commit is contained in:
@@ -7,6 +7,7 @@ pub fn codegen(nodes: Vec<Node>) -> Result<Vec<Instruction>, AssembleError> {
|
|||||||
let mut instructions = vec![];
|
let mut instructions = vec![];
|
||||||
|
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
|
println!("node {node}");
|
||||||
instructions.push(build_instruction(node)?);
|
instructions.push(build_instruction(node)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +170,9 @@ fn build_instruction(node: Node) -> Result<Instruction, AssembleError> {
|
|||||||
let immediate = expect_token!(args.first().unwrap(), Immediate)?;
|
let immediate = expect_token!(args.first().unwrap(), Immediate)?;
|
||||||
Ok(Instruction::Segment(immediate))
|
Ok(Instruction::Segment(immediate))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These pseudo-instructions should have been expanded!
|
||||||
|
// this case being activated suggests the wrong syntax was given, and indicates a bug in the parser
|
||||||
Opcode::Db
|
Opcode::Db
|
||||||
| Opcode::Dh
|
| Opcode::Dh
|
||||||
| Opcode::Dw
|
| Opcode::Dw
|
||||||
@@ -178,6 +182,10 @@ fn build_instruction(node: Node) -> Result<Instruction, AssembleError> {
|
|||||||
| Opcode::Push
|
| Opcode::Push
|
||||||
| Opcode::Pop
|
| Opcode::Pop
|
||||||
| Opcode::Lwi
|
| Opcode::Lwi
|
||||||
| Opcode::Include => todo!(),
|
| Opcode::Include
|
||||||
|
| Opcode::Call
|
||||||
|
| Opcode::Return
|
||||||
|
| Opcode::Pusha
|
||||||
|
| Opcode::Popa => Err(AssembleError::InvalidArg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ fn try_expand(
|
|||||||
match node.opcode() {
|
match node.opcode() {
|
||||||
Opcode::Push => expand_push(node.clone(), result)?,
|
Opcode::Push => expand_push(node.clone(), result)?,
|
||||||
Opcode::Pop => expand_pop(node.clone(), result)?,
|
Opcode::Pop => expand_pop(node.clone(), result)?,
|
||||||
|
Opcode::Pusha => expand_pusha(node.clone(), result)?,
|
||||||
|
Opcode::Popa => expand_popa(node.clone(), result)?,
|
||||||
|
Opcode::Call => expand_call(node.clone(), result)?,
|
||||||
|
Opcode::Return => expand_return(node.clone(), result)?,
|
||||||
Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw => {
|
Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw => {
|
||||||
expand_ldx(node.clone(), result)?
|
expand_ldx(node.clone(), result)?
|
||||||
}
|
}
|
||||||
@@ -42,22 +46,105 @@ fn try_expand(
|
|||||||
fn expand_push(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
fn expand_push(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
||||||
let label = current.label();
|
let label = current.label();
|
||||||
let reg = expect_type!(current.arg(0).unwrap(), Register)?;
|
let reg = expect_type!(current.arg(0).unwrap(), Register)?;
|
||||||
|
let spr = Token::Register(Register::Spr);
|
||||||
|
|
||||||
nodes.extend(vec![
|
nodes.extend(vec![
|
||||||
node!(
|
node!(label, Opcode::SubI, spr, 4, spr),
|
||||||
|
node!(None, Opcode::Stw, reg, spr, 0),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_pusha(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
||||||
|
let label = current.label();
|
||||||
|
let count = expect_token!(current.arg(0).unwrap(), Immediate)?;
|
||||||
|
let spr = Token::Register(Register::Spr);
|
||||||
|
let registers: Vec<Register> = Register::general();
|
||||||
|
|
||||||
|
nodes.push(node!(
|
||||||
label,
|
label,
|
||||||
Opcode::SubI,
|
Opcode::SubI,
|
||||||
Token::Register(Register::Spr),
|
spr,
|
||||||
Token::Immediate(4),
|
Token::Immediate(count * 4),
|
||||||
Token::Register(Register::Spr)
|
spr
|
||||||
),
|
));
|
||||||
|
|
||||||
|
nodes.extend(
|
||||||
|
(0..count)
|
||||||
|
.rev()
|
||||||
|
.map(|i| {
|
||||||
node!(
|
node!(
|
||||||
None,
|
None,
|
||||||
Opcode::Stw,
|
Opcode::Stw,
|
||||||
reg,
|
Token::Register(registers[i as usize]),
|
||||||
Token::Register(Register::Spr),
|
spr,
|
||||||
Token::Immediate(0)
|
Token::Immediate(i * 4)
|
||||||
),
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Node>>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_popa(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
||||||
|
let label = current.label();
|
||||||
|
let count = expect_token!(current.arg(0).unwrap(), Immediate)?;
|
||||||
|
let spr = Token::Register(Register::Spr);
|
||||||
|
let registers: Vec<Register> = Register::general();
|
||||||
|
|
||||||
|
nodes.extend(
|
||||||
|
(0..count)
|
||||||
|
.rev()
|
||||||
|
.map(|i| {
|
||||||
|
node!(
|
||||||
|
{ if i == 0 { label.clone() } else { None } },
|
||||||
|
Opcode::Ldw,
|
||||||
|
spr,
|
||||||
|
Token::Register(registers[i as usize]),
|
||||||
|
Token::Immediate(i * 4)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Node>>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
nodes.push(node!(
|
||||||
|
None,
|
||||||
|
Opcode::AddI,
|
||||||
|
spr,
|
||||||
|
Token::Immediate(count * 4),
|
||||||
|
spr
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_call(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
||||||
|
let label = current.label();
|
||||||
|
let addr = expect_type!(current.arg(0).unwrap(), Symbol)?;
|
||||||
|
let spr = Token::Register(Register::Spr);
|
||||||
|
let pcx = Token::Register(Register::Pcx);
|
||||||
|
let zero = Token::Register(Register::Zero);
|
||||||
|
|
||||||
|
nodes.extend(vec![
|
||||||
|
node!(label, Opcode::SubI, spr, 4, spr),
|
||||||
|
node!(None, Opcode::Stw, pcx, spr, 0),
|
||||||
|
node!(None, Opcode::Jmp, addr, zero),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_return(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
||||||
|
let label = current.label();
|
||||||
|
let spr = Token::Register(Register::Spr);
|
||||||
|
let ret = Token::Register(Register::Ret);
|
||||||
|
|
||||||
|
nodes.extend(vec![
|
||||||
|
node!(label, Opcode::Ldw, spr, ret, 0),
|
||||||
|
node!(None, Opcode::AddI, spr, 4, spr),
|
||||||
|
node!(None, Opcode::Jmp, 4, ret),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -66,22 +153,11 @@ fn expand_push(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError
|
|||||||
fn expand_pop(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
fn expand_pop(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError> {
|
||||||
let label = current.label();
|
let label = current.label();
|
||||||
let reg = expect_type!(current.arg(0).unwrap(), Register)?;
|
let reg = expect_type!(current.arg(0).unwrap(), Register)?;
|
||||||
|
let spr = Token::Register(Register::Spr);
|
||||||
|
|
||||||
nodes.extend(vec![
|
nodes.extend(vec![
|
||||||
node!(
|
node!(label, Opcode::Ldw, spr, reg, 0),
|
||||||
label,
|
node!(None, Opcode::AddI, spr, 4, spr),
|
||||||
Opcode::Ldw,
|
|
||||||
Token::Register(Register::Spr),
|
|
||||||
reg,
|
|
||||||
Token::Immediate(0)
|
|
||||||
),
|
|
||||||
node!(
|
|
||||||
None,
|
|
||||||
Opcode::AddI,
|
|
||||||
Token::Register(Register::Spr),
|
|
||||||
Token::Immediate(4),
|
|
||||||
Token::Register(Register::Spr)
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -94,9 +170,9 @@ fn expand_ldx(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError>
|
|||||||
let offset = expect_type!(current.arg(2).unwrap(), Immediate)?;
|
let offset = expect_type!(current.arg(2).unwrap(), Immediate)?;
|
||||||
|
|
||||||
nodes.extend(vec![
|
nodes.extend(vec![
|
||||||
node!(current.label(), Opcode::Lli, name.clone(), reg.clone()),
|
node!(current.label(), Opcode::Lli, name, reg),
|
||||||
node!(None, Opcode::Lui, name.clone(), reg.clone()),
|
node!(None, Opcode::Lui, name, reg),
|
||||||
node!(None, opcode, reg.clone(), reg, offset),
|
node!(None, opcode, reg, reg, offset),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -107,20 +183,12 @@ fn expand_stx(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError>
|
|||||||
let base = expect_type!(current.arg(0).unwrap(), Register)?;
|
let base = expect_type!(current.arg(0).unwrap(), Register)?;
|
||||||
let dest = expect_type!(current.arg(1).unwrap(), Symbol)?;
|
let dest = expect_type!(current.arg(1).unwrap(), Symbol)?;
|
||||||
let offset = expect_type!(current.arg(2).unwrap(), Immediate)?;
|
let offset = expect_type!(current.arg(2).unwrap(), Immediate)?;
|
||||||
|
let temp = Token::Register(Register::Rgf);
|
||||||
|
|
||||||
nodes.extend(vec![
|
nodes.extend(vec![
|
||||||
node!(
|
node!(current.label(), Opcode::Lli, dest, temp),
|
||||||
current.label(),
|
node!(None, Opcode::Lui, dest, temp),
|
||||||
Opcode::Lli,
|
node!(None, opcode, base, temp, offset),
|
||||||
dest.clone(),
|
|
||||||
Token::Register(Register::Rgf)
|
|
||||||
),
|
|
||||||
node!(
|
|
||||||
None,
|
|
||||||
Opcode::Lui,
|
|
||||||
dest.clone(),
|
|
||||||
Token::Register(Register::Rgf)
|
|
||||||
),
|
|
||||||
node!(None, opcode, base, Token::Register(Register::Rgf), offset),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -131,8 +199,8 @@ fn expand_lwi(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError>
|
|||||||
let reg = expect_type!(current.arg(1).unwrap(), Register)?;
|
let reg = expect_type!(current.arg(1).unwrap(), Register)?;
|
||||||
|
|
||||||
nodes.extend(vec![
|
nodes.extend(vec![
|
||||||
node!(current.label(), Opcode::Lli, val.clone(), reg.clone()),
|
node!(current.label(), Opcode::Lli, val, reg),
|
||||||
node!(None, Opcode::Lui, val.clone(), reg.clone()),
|
node!(None, Opcode::Lui, val, reg),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -153,7 +221,7 @@ fn expand_resx(current: Node, nodes: &mut Vec<Node>) -> Result<(), AssembleError
|
|||||||
// push the inital node with the label
|
// push the inital node with the label
|
||||||
for _ in 0..size.div_ceil(units_per) {
|
for _ in 0..size.div_ceil(units_per) {
|
||||||
// push the rest of the nodes
|
// push the rest of the nodes
|
||||||
buffer.push(node!(None, Opcode::Data, Token::Immediate(0)));
|
buffer.push(node!(None, Opcode::Data, 0));
|
||||||
}
|
}
|
||||||
buffer[0].symbol = Some(region_label);
|
buffer[0].symbol = Some(region_label);
|
||||||
nodes.extend(buffer);
|
nodes.extend(buffer);
|
||||||
|
|||||||
@@ -18,7 +18,19 @@ macro_rules! node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
($symbol: expr, $opcode: expr, $($tokens: expr),+) => {
|
($symbol: expr, $opcode: expr, $($tokens: expr),+) => {
|
||||||
Node::new($symbol.clone(), $opcode.clone(), vec![$($tokens.clone()),+])
|
Node::new(
|
||||||
|
$symbol.clone(),
|
||||||
|
$opcode.clone(),
|
||||||
|
vec![$(node!(@convert_token $tokens)),+]
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
(@convert_token $token: literal) => {
|
||||||
|
Token::Immediate($token)
|
||||||
|
};
|
||||||
|
|
||||||
|
(@convert_token $token: expr) => {
|
||||||
|
$token.clone()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +48,7 @@ impl Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn opcode(&self) -> Opcode {
|
pub fn opcode(&self) -> Opcode {
|
||||||
self.opcode.clone()
|
self.opcode
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn args(&self) -> Vec<Token> {
|
pub fn args(&self) -> Vec<Token> {
|
||||||
@@ -134,11 +146,13 @@ impl fmt::Display for Opcode {
|
|||||||
Opcode::Push => write!(f, "push"),
|
Opcode::Push => write!(f, "push"),
|
||||||
Opcode::Pop => write!(f, "pop"),
|
Opcode::Pop => write!(f, "pop"),
|
||||||
Opcode::Lwi => write!(f, "lwi"),
|
Opcode::Lwi => write!(f, "lwi"),
|
||||||
|
Opcode::Call => write!(f, "call"),
|
||||||
|
Opcode::Return => write!(f, "return"),
|
||||||
|
Opcode::Pusha => write!(f, "pusha"),
|
||||||
|
Opcode::Popa => write!(f, "popa"),
|
||||||
|
|
||||||
// utility - removed at compile time
|
// meta instructions
|
||||||
Opcode::Include => write!(f, "include"),
|
Opcode::Include => write!(f, "include"),
|
||||||
|
|
||||||
// special - generated by assembler
|
|
||||||
Opcode::Data => write!(f, "data"),
|
Opcode::Data => write!(f, "data"),
|
||||||
Opcode::Segment => write!(f, "[SEGMENT]"),
|
Opcode::Segment => write!(f, "[SEGMENT]"),
|
||||||
}
|
}
|
||||||
@@ -200,7 +214,7 @@ impl TokenType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum Opcode {
|
pub enum Opcode {
|
||||||
// Real instructions (0x00-0x26)
|
// Real instructions (0x00-0x26)
|
||||||
Nop,
|
Nop,
|
||||||
@@ -242,6 +256,7 @@ pub enum Opcode {
|
|||||||
Hlt,
|
Hlt,
|
||||||
AddI,
|
AddI,
|
||||||
SubI,
|
SubI,
|
||||||
|
|
||||||
// Pseudo-instructions
|
// Pseudo-instructions
|
||||||
Db,
|
Db,
|
||||||
Dh,
|
Dh,
|
||||||
@@ -251,10 +266,14 @@ pub enum Opcode {
|
|||||||
Resw,
|
Resw,
|
||||||
Push,
|
Push,
|
||||||
Pop,
|
Pop,
|
||||||
|
Pusha,
|
||||||
|
Popa,
|
||||||
Lwi,
|
Lwi,
|
||||||
Include,
|
Call,
|
||||||
|
Return,
|
||||||
|
|
||||||
// fake instructions (these aren't present in the binary as instructions)
|
// meta instructions (these aren't present in the binary as instructions)
|
||||||
|
Include,
|
||||||
Data,
|
Data,
|
||||||
Segment,
|
Segment,
|
||||||
}
|
}
|
||||||
@@ -328,6 +347,10 @@ impl FromStr for Opcode {
|
|||||||
"pop" => Ok(Self::Pop),
|
"pop" => Ok(Self::Pop),
|
||||||
"lwi" => Ok(Self::Lwi),
|
"lwi" => Ok(Self::Lwi),
|
||||||
"include" => Ok(Self::Include),
|
"include" => Ok(Self::Include),
|
||||||
|
"call" => Ok(Self::Call),
|
||||||
|
"return" => Ok(Self::Return),
|
||||||
|
"pusha" => Ok(Self::Push),
|
||||||
|
"popa" => Ok(Self::Pop),
|
||||||
_ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")),
|
_ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,7 +363,9 @@ impl Opcode {
|
|||||||
"lli", "lui", "jmp", "jeq", "jne", "jgt", "jge", "jlt", "jle", "cmp", "inc",
|
"lli", "lui", "jmp", "jeq", "jne", "jgt", "jge", "jlt", "jle", "cmp", "inc",
|
||||||
"dec", "shl", "shr", "add", "sub", "and", "or", "not", "xor", "nand", "nor",
|
"dec", "shl", "shr", "add", "sub", "and", "or", "not", "xor", "nand", "nor",
|
||||||
"xnor", "int", "irt", "hlt", "addi", "subi", // Pseudo-instructions
|
"xnor", "int", "irt", "hlt", "addi", "subi", // Pseudo-instructions
|
||||||
"db", "dh", "dw", "resb", "resh", "resw", "push", "pop", "lwi", "include",
|
"db", "dh", "dw", "resb", "resh", "resw", "push", "pop", "lwi", "call", "return",
|
||||||
|
"pusha", "popa", // meta instructions
|
||||||
|
"include",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn to_opcode_value(&self) -> Option<u8> {
|
pub fn to_opcode_value(&self) -> Option<u8> {
|
||||||
@@ -385,6 +410,7 @@ impl Opcode {
|
|||||||
Self::AddI => Some(0x25),
|
Self::AddI => Some(0x25),
|
||||||
Self::SubI => Some(0x26),
|
Self::SubI => Some(0x26),
|
||||||
Self::Segment => Some(0x27),
|
Self::Segment => Some(0x27),
|
||||||
|
|
||||||
// Pseudo-instructions don't have opcode values
|
// Pseudo-instructions don't have opcode values
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,10 +40,12 @@ impl Default for Program {
|
|||||||
impl Parser {
|
impl Parser {
|
||||||
pub fn parse_nodes(tokens: Vec<Token>) -> Result<Vec<Node>, AssembleError> {
|
pub fn parse_nodes(tokens: Vec<Token>) -> Result<Vec<Node>, AssembleError> {
|
||||||
let mut self_ = Parser {
|
let mut self_ = Parser {
|
||||||
tokens: tokens.into_iter().rev().collect(),
|
tokens: tokens.clone().into_iter().rev().collect(),
|
||||||
nodes: vec![],
|
nodes: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("{:#?}", tokens);
|
||||||
|
|
||||||
while !self_.tokens.is_empty() {
|
while !self_.tokens.is_empty() {
|
||||||
let ins = self_.parse_instruction()?;
|
let ins = self_.parse_instruction()?;
|
||||||
self_.nodes.push(ins);
|
self_.nodes.push(ins);
|
||||||
@@ -68,8 +70,6 @@ impl Parser {
|
|||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{:?}", self.peek_next()?);
|
|
||||||
|
|
||||||
// check if the Node starts with a label
|
// check if the Node starts with a label
|
||||||
let label = expect_token!(self.peek_next()?, Symbol).ok();
|
let label = expect_token!(self.peek_next()?, Symbol).ok();
|
||||||
if label.is_some() {
|
if label.is_some() {
|
||||||
@@ -158,14 +158,24 @@ impl Parser {
|
|||||||
| Opcode::Jlt
|
| Opcode::Jlt
|
||||||
| Opcode::Jle => {
|
| Opcode::Jle => {
|
||||||
let imm = expect_type!(self.next()?, Immediate, Symbol)?;
|
let imm = expect_type!(self.next()?, Immediate, Symbol)?;
|
||||||
let offset = if expect_type!(self.peek_next()?, Register).is_ok() {
|
let offset = match self.peek_next() {
|
||||||
|
Ok(token) => {
|
||||||
|
if expect_type!(token, Register).is_ok() {
|
||||||
self.next()?
|
self.next()?
|
||||||
} else {
|
} else {
|
||||||
Token::Register(Register::Zero)
|
Token::Register(Register::Zero)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => Token::Register(Register::Zero),
|
||||||
};
|
};
|
||||||
args = vec![imm, offset];
|
args = vec![imm, offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opcode::Call => {
|
||||||
|
let addr = expect_type!(self.next()?, Symbol)?;
|
||||||
|
args = vec![addr];
|
||||||
|
}
|
||||||
|
|
||||||
// I-type instructions
|
// I-type instructions
|
||||||
Opcode::Lui | Opcode::Lli | Opcode::Lwi => {
|
Opcode::Lui | Opcode::Lli | Opcode::Lwi => {
|
||||||
let imm = expect_type!(self.next()?, Immediate, Symbol)?;
|
let imm = expect_type!(self.next()?, Immediate, Symbol)?;
|
||||||
@@ -193,18 +203,19 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Db | Opcode::Dh | Opcode::Dw => {
|
Opcode::Db | Opcode::Dh | Opcode::Dw => {
|
||||||
args = self.parse_data_definition(opcode.clone())?;
|
args = self.parse_data_definition(opcode)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// E-type pseudoinstructions (stack operations)
|
// E-type pseudoinstructions (stack operations)
|
||||||
Opcode::Push => {
|
Opcode::Push | Opcode::Pop => {
|
||||||
let reg = expect_type!(self.next()?, Register, Symbol)?;
|
let reg = expect_type!(self.next()?, Register, Symbol)?;
|
||||||
args = vec![reg];
|
args = vec![reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Pop => {
|
Opcode::Pusha | Opcode::Popa => {
|
||||||
let reg = expect_type!(self.next()?, Register, Symbol)?;
|
let count =
|
||||||
args = vec![reg];
|
expect_type!(self.next()?, Immediate).unwrap_or(Token::Immediate(8));
|
||||||
|
args = vec![count];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special instructions
|
// Special instructions
|
||||||
@@ -214,7 +225,7 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Instructions with no arguments
|
// Instructions with no arguments
|
||||||
Opcode::Hlt | Opcode::Nop | Opcode::Irt => {
|
Opcode::Hlt | Opcode::Nop | Opcode::Irt | Opcode::Return => {
|
||||||
args = vec![];
|
args = vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
use assembler::codegen::codegen;
|
use assembler::codegen::codegen;
|
||||||
use assembler::expand::expand_pseudo_ops;
|
|
||||||
use assembler::model::{Node, Opcode, Symbol, Token, TokenType};
|
|
||||||
use assembler::parser::{Parser, Program};
|
|
||||||
use assembler::resolver::{create_sections, resolve_dependencies, resolve_symbols};
|
|
||||||
use common::prelude::*;
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
pub mod assembler;
|
pub mod assembler;
|
||||||
|
pub mod tooling;
|
||||||
use crate::assembler::lexer;
|
mod util;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::assembler::assemble;
|
pub use crate::assembler::assemble;
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ use std::{fs, io::Write, path::PathBuf};
|
|||||||
fn main() {
|
fn main() {
|
||||||
// parse args:
|
// parse args:
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
|
||||||
|
if args.len() == 2 && args[1] == "init" {
|
||||||
|
assembler::tooling::project::tool_libcreate();
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if args.len() != 5 || args[1] != "-i" || args[3] != "-o" {
|
if args.len() != 5 || args[1] != "-i" || args[3] != "-o" {
|
||||||
eprintln!("Usage: binary_name -i input_path -o output_path");
|
eprintln!("Usage: binary_name -i input_path -o output_path");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod project;
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
use crate::util::input;
|
||||||
|
|
||||||
|
pub fn tool_libcreate() {
|
||||||
|
let mut ptype: String;
|
||||||
|
loop {
|
||||||
|
ptype = input("Enter project type (bin|lib)");
|
||||||
|
if ptype == "bin" || ptype == "lib" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let project_name = input("Enter project name");
|
||||||
|
let project_path = input("Enter Directory to create project in");
|
||||||
|
|
||||||
|
println!("[ Creating new {ptype} project {project_name} in {project_path} ]");
|
||||||
|
|
||||||
|
let template = match ptype.as_str() {
|
||||||
|
"bin" => generate_bin_template(&project_name),
|
||||||
|
"lib" => generate_lib_template(&project_name),
|
||||||
|
_ => panic!("Invalid project type"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = format!("{}/{}.dsa", project_path, project_name);
|
||||||
|
std::fs::write(path, template).expect("Unable to write file");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_lib_template(module_name: &str) -> String {
|
||||||
|
format!(
|
||||||
|
r#"// {module_name}.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include {module_name} "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for {module_name}_main:
|
||||||
|
// push (arg1)
|
||||||
|
// push (arg0)
|
||||||
|
// call {module_name}::{module_name}_main
|
||||||
|
// pop (arg0)
|
||||||
|
// pop (arg1)
|
||||||
|
|
||||||
|
// Example data declarations
|
||||||
|
// dw example_data: 0x0000
|
||||||
|
|
||||||
|
// Main function template
|
||||||
|
{module_name}_main:
|
||||||
|
// the correct way to start a function as defined by the calling convention
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// explanation of how to access args
|
||||||
|
ldw bpr, rg0, 8 // arg 0
|
||||||
|
ldw bpr, rg0, 12 // arg 1
|
||||||
|
|
||||||
|
// your code goes here
|
||||||
|
// Example: load example_data into rg1
|
||||||
|
// ldw example_data, rg1
|
||||||
|
|
||||||
|
// the correct way to end a function as defined by the calling convention
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_bin_template(project_name: &str) -> String {
|
||||||
|
format!(
|
||||||
|
r#"// {project_name}.dsa
|
||||||
|
// Binary executable project
|
||||||
|
|
||||||
|
// Example Dependencies
|
||||||
|
// include math "libs/math/math.dsa"
|
||||||
|
include print "../resources/dsa/print.dsa"
|
||||||
|
|
||||||
|
// Data declarations - It is best practice to include these before any code!
|
||||||
|
dw message: "Hello from {project_name}.dsa!" // strings are automatically null terminated!
|
||||||
|
|
||||||
|
// Program entry point - execution starts at the first non-definition line
|
||||||
|
{project_name}:
|
||||||
|
// Getting started: Calling external functions
|
||||||
|
// Syntax: push (arg1), push (arg0), call namespace::function, pop (arg0), pop (arg1)
|
||||||
|
|
||||||
|
// Example: Print a string (if print library is included)
|
||||||
|
ldw message, rg0 // load address of message
|
||||||
|
push rg0 // push argument
|
||||||
|
call print::print // call the print function
|
||||||
|
pop rg0 // clean up stack
|
||||||
|
|
||||||
|
// Program must end with halt instruction
|
||||||
|
halt
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
pub fn input(prompt: &str) -> String {
|
||||||
|
print!("{}\n > ", prompt);
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
let mut input = String::new();
|
||||||
|
std::io::stdin().read_line(&mut input).unwrap();
|
||||||
|
input.trim().to_string()
|
||||||
|
}
|
||||||
@@ -71,6 +71,30 @@ pub enum Register {
|
|||||||
Pcx,
|
Pcx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Register {
|
||||||
|
#[must_use]
|
||||||
|
pub fn general() -> Vec<Self> {
|
||||||
|
vec![
|
||||||
|
Self::Rg0,
|
||||||
|
Self::Rg1,
|
||||||
|
Self::Rg2,
|
||||||
|
Self::Rg3,
|
||||||
|
Self::Rg4,
|
||||||
|
Self::Rg5,
|
||||||
|
Self::Rg6,
|
||||||
|
Self::Rg7,
|
||||||
|
Self::Rg8,
|
||||||
|
Self::Rg9,
|
||||||
|
Self::Rga,
|
||||||
|
Self::Rgb,
|
||||||
|
Self::Rgc,
|
||||||
|
Self::Rgd,
|
||||||
|
Self::Rge,
|
||||||
|
Self::Rgf,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Register {
|
impl Default for Register {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::NoReg
|
Self::NoReg
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ use crate::emulator::{
|
|||||||
ui::interface::Component,
|
ui::interface::Component,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use assembler::prelude::*;
|
||||||
|
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
// editor state
|
// editor state
|
||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
@@ -344,10 +346,10 @@ impl Editor {
|
|||||||
// builds the current file
|
// builds the current file
|
||||||
if ui.button("Build").clicked() && !self.unsaved {
|
if ui.button("Build").clicked() && !self.unsaved {
|
||||||
if let Some(path) = &self.path {
|
if let Some(path) = &self.path {
|
||||||
let instructions = match assembler::assemble(path) {
|
let instructions = match assemble(path) {
|
||||||
Ok(instructions) => instructions,
|
Ok(instructions) => instructions,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
self.error = Some(error.to_string());
|
self.error = Some(format!("Failed to assemble: {error:?}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// multiply.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include multiply "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for multiply:
|
||||||
|
// push (arg1)
|
||||||
|
// push (arg0)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop (arg0)
|
||||||
|
// pop (arg1)
|
||||||
|
|
||||||
|
multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load op 1
|
||||||
|
ldw bpr, rg1, 12 // load op 2
|
||||||
|
|
||||||
|
start:
|
||||||
|
add acc, rg0, acc
|
||||||
|
dec rg1
|
||||||
|
|
||||||
|
cmp rg1, zero
|
||||||
|
jgt start
|
||||||
|
|
||||||
|
end:
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
+34
-12
@@ -17,18 +17,15 @@
|
|||||||
dw display: 0x20000
|
dw display: 0x20000
|
||||||
dw current: 0x20000
|
dw current: 0x20000
|
||||||
|
|
||||||
reset:
|
// prints the given text to the screen.
|
||||||
pop ret
|
|
||||||
ldw display, rg1
|
|
||||||
stw rg1, current
|
|
||||||
jmp 4, ret
|
|
||||||
|
|
||||||
print:
|
print:
|
||||||
pop ret // return address
|
push bpr
|
||||||
pop rg0 // string
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
ldw current, rg1
|
ldw current, rg1
|
||||||
|
|
||||||
loop:
|
print_loop:
|
||||||
ldb rg0, acc
|
ldb rg0, acc
|
||||||
stb acc, rg1
|
stb acc, rg1
|
||||||
|
|
||||||
@@ -36,10 +33,35 @@ loop:
|
|||||||
addi rg1, 1
|
addi rg1, 1
|
||||||
|
|
||||||
cmp acc, zero
|
cmp acc, zero
|
||||||
jne loop
|
jne print_loop
|
||||||
|
jmp end
|
||||||
|
|
||||||
// return
|
// return
|
||||||
end:
|
end:
|
||||||
// set current to
|
|
||||||
stw rg1, current
|
stw rg1, current
|
||||||
jmp 4, ret
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
// resets the cursor position on the screen
|
||||||
|
reset:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
ldw display, rg1
|
||||||
|
jmp end
|
||||||
|
|
||||||
|
clear:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
// display size = 2000 bytes / 500 words
|
||||||
|
lli 500 rg0
|
||||||
|
ldw display, rg1
|
||||||
|
|
||||||
|
clear_loop:
|
||||||
|
dec rg0
|
||||||
|
stw zero, rg1
|
||||||
|
addi rg1, 4
|
||||||
|
cmp rg0, zero
|
||||||
|
jgt clear_loop
|
||||||
|
jmp end
|
||||||
+4
-13
@@ -1,5 +1,4 @@
|
|||||||
include print "./print.dsa"
|
include print "./print.dsa"
|
||||||
include fib "./fib.dsa"
|
|
||||||
|
|
||||||
dw stack: 0x10000
|
dw stack: 0x10000
|
||||||
db string: "An idiot admires complexity, a genius admires simplicity,
|
db string: "An idiot admires complexity, a genius admires simplicity,
|
||||||
@@ -9,23 +8,15 @@ gonna think you're a god cause you made it so complicated nobody can understand
|
|||||||
That's how they write journals in Academics, they try to make it so complicated people think you're a genius"
|
That's how they write journals in Academics, they try to make it so complicated people think you're a genius"
|
||||||
|
|
||||||
init:
|
init:
|
||||||
|
// set up a stack.
|
||||||
ldw stack, bpr
|
ldw stack, bpr
|
||||||
mov bpr, spr
|
mov bpr, spr
|
||||||
|
|
||||||
start:
|
start:
|
||||||
lwi string, rg1
|
lwi string, rg1
|
||||||
|
|
||||||
// push variables
|
push rg1
|
||||||
push rg1 // string address.
|
call print::print
|
||||||
push pcx // return address.
|
pop rg1
|
||||||
|
|
||||||
// call
|
|
||||||
jmp print::print
|
|
||||||
|
|
||||||
|
|
||||||
lli 25, rg0
|
|
||||||
push rg0
|
|
||||||
push pcx
|
|
||||||
jmp fib::fib_n
|
|
||||||
|
|
||||||
hlt
|
hlt
|
||||||
Binary file not shown.
Reference in New Issue
Block a user