added asm project
This commit is contained in:
2394
Cargo.lock
generated
2394
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
3
Cargo.toml
Normal file
3
Cargo.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["simu","asm"]
|
||||
8
asm/Cargo.toml
Normal file
8
asm/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "asm"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
parse_int = "0.9.0"
|
||||
regex = "1.12.3"
|
||||
2
asm/rust-toolchain.toml
Normal file
2
asm/rust-toolchain.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
672
asm/src/main.rs
Normal file
672
asm/src/main.rs
Normal file
@@ -0,0 +1,672 @@
|
||||
#![feature(file_buffered)]
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
env::args,
|
||||
io::{BufRead, BufReader, Write, stdin},
|
||||
ops::Index,
|
||||
process::exit,
|
||||
};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Op2 {
|
||||
Direct(i32),
|
||||
Register(u8),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Reg(u8);
|
||||
|
||||
impl Into<u32> for Reg {
|
||||
fn into(self) -> u32 {
|
||||
self.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u32> for &Reg {
|
||||
fn into(self) -> u32 {
|
||||
self.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Cond {
|
||||
Ifeq,
|
||||
Ifne,
|
||||
Iflt,
|
||||
Ifge,
|
||||
Ifgt,
|
||||
Ifle,
|
||||
Ifult,
|
||||
Ifuge,
|
||||
Ifugt,
|
||||
Ifule,
|
||||
}
|
||||
|
||||
impl From<Cond> for u32 {
|
||||
fn from(value: Cond) -> Self {
|
||||
match value {
|
||||
Cond::Ifeq => 0b0000,
|
||||
Cond::Ifne => 0b0001,
|
||||
Cond::Iflt => 0b1000,
|
||||
Cond::Ifge => 0b1001,
|
||||
Cond::Ifgt => 0b1010,
|
||||
Cond::Ifle => 0b1011,
|
||||
Cond::Ifult => 0b1100,
|
||||
Cond::Ifuge => 0b1101,
|
||||
Cond::Ifugt => 0b1110,
|
||||
Cond::Ifule => 0b1111,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Cond> for u32 {
|
||||
fn from(value: &Cond) -> Self {
|
||||
(*value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Cond {
|
||||
type Error = ();
|
||||
fn try_from(value: &str) -> Result<Self, ()> {
|
||||
Ok(match value {
|
||||
"ifeq" => Cond::Ifeq,
|
||||
"ifne" => Cond::Ifne,
|
||||
"iflt" => Cond::Iflt,
|
||||
"ifge" => Cond::Ifge,
|
||||
"ifgt" => Cond::Ifgt,
|
||||
"ifle" => Cond::Ifle,
|
||||
"ifult" => Cond::Ifult,
|
||||
"ifuge" => Cond::Ifuge,
|
||||
"ifugt" => Cond::Ifugt,
|
||||
"ifule" => Cond::Ifule,
|
||||
s => {
|
||||
println!("unrecognised condition: {s}");
|
||||
return Err(());
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
enum Labeli32 {
|
||||
Value(i32),
|
||||
Label(String),
|
||||
}
|
||||
|
||||
enum Labeli17 {
|
||||
Register(Reg),
|
||||
Value(i32),
|
||||
LabelLow(String),
|
||||
LabelHigh(String),
|
||||
}
|
||||
|
||||
enum Instruction {
|
||||
Copy(Reg, Labeli17),
|
||||
Add(Reg, Reg, Labeli17),
|
||||
Sub(Reg, Reg, Op2),
|
||||
Or(Reg, Reg, Op2),
|
||||
And(Reg, Reg, Op2),
|
||||
Xor(Reg, Reg, Op2),
|
||||
Lsl(Reg, Reg, Op2),
|
||||
Lsr(Reg, Reg, Op2),
|
||||
Asr(Reg, Reg, Op2),
|
||||
Smull(Reg, Reg, Op2),
|
||||
Smulh(Reg, Reg, Op2),
|
||||
Umull(Reg, Reg, Op2),
|
||||
Umulh(Reg, Reg, Op2),
|
||||
Div(Reg, Reg, Op2),
|
||||
Mod(Reg, Reg, Op2),
|
||||
Store(Reg, Op2, Reg),
|
||||
Load(Reg, Reg, Op2),
|
||||
Push(Op2),
|
||||
Pop(Reg),
|
||||
Skip(Labeli32, Cond, Reg, Op2),
|
||||
Jump(Labeli32), //address / 4
|
||||
Call(Labeli32), //address / 4
|
||||
Ret(),
|
||||
GetStack(Reg),
|
||||
SetStack(Op2),
|
||||
Data(Labeli32),
|
||||
}
|
||||
|
||||
fn encode_reg(fmt: u32, function: u32, d: u32, x: u32, y: u32) -> u32 {
|
||||
(fmt << 30) | (function << 24) | (d << 20) | (x << 16) | (y << 12)
|
||||
}
|
||||
fn encode_imm(fmt: u32, function: u32, d: u32, x: u32, c: i32) -> u32 {
|
||||
let c_sign = if c < 0 { 1 } else { 0 };
|
||||
let c_mask = c as u32 & 0xFFFF;
|
||||
(fmt << 30)
|
||||
| (c_sign << 29)
|
||||
| (1 << 28)
|
||||
| (function << 24)
|
||||
| (d << 20)
|
||||
| (x << 16)
|
||||
| (c_mask << 0)
|
||||
}
|
||||
|
||||
fn encode_op2(fmt: u32, function: u32, d: u32, x: u32, y_or_c: Op2) -> u32 {
|
||||
match y_or_c {
|
||||
Op2::Direct(c) => encode_imm(fmt, function, d, x, c),
|
||||
Op2::Register(y) => encode_reg(fmt, function, d, x, y as u32),
|
||||
}
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
fn encode(&self, prgm: &Program, self_addr: u32) -> Result<u32, ()> {
|
||||
Ok(match self {
|
||||
Instruction::Copy(dest, value) => match value {
|
||||
Labeli17::Value(v) => encode_imm(1, 0, dest.into(), 0, *v),
|
||||
Labeli17::LabelLow(label) => {
|
||||
encode_imm(1, 0, dest.into(), 0, (prgm[label] & 0xFFFF) as i32)
|
||||
}
|
||||
Labeli17::LabelHigh(label) => {
|
||||
encode_imm(1, 0, dest.into(), 0, (prgm[label] as u32 >> 16) as i32)
|
||||
}
|
||||
Labeli17::Register(reg) => encode_reg(1, 0, dest.into(), 0, reg.into()),
|
||||
},
|
||||
Instruction::Add(reg, reg1, value) => match value {
|
||||
Labeli17::Register(regy) => encode_reg(1, 1, reg.into(), reg1.into(), regy.into()),
|
||||
|
||||
Labeli17::Value(v) => encode_imm(1, 1, reg.into(), reg1.into(), *v),
|
||||
Labeli17::LabelLow(l) => {
|
||||
encode_imm(1, 1, reg.into(), reg1.into(), (prgm[l] & 0xFFFF) as i32)
|
||||
}
|
||||
Labeli17::LabelHigh(l) => encode_imm(
|
||||
1,
|
||||
1,
|
||||
reg.into(),
|
||||
reg1.into(),
|
||||
(prgm[l] as u32 >> 16) as i32,
|
||||
),
|
||||
},
|
||||
Instruction::Sub(reg, reg1, op2) => encode_op2(01, 2, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Or(reg, reg1, op2) => encode_op2(01, 3, reg.into(), reg1.into(), *op2),
|
||||
Instruction::And(reg, reg1, op2) => encode_op2(01, 4, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Xor(reg, reg1, op2) => encode_op2(01, 5, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Lsl(reg, reg1, op2) => encode_op2(01, 6, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Lsr(reg, reg1, op2) => encode_op2(01, 7, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Asr(reg, reg1, op2) => encode_op2(01, 8, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Smull(reg, reg1, op2) => encode_op2(01, 9, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Smulh(reg, reg1, op2) => encode_op2(01, 10, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Umull(reg, reg1, op2) => encode_op2(01, 11, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Umulh(reg, reg1, op2) => encode_op2(01, 12, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Div(reg, reg1, op2) => encode_op2(01, 13, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Mod(reg, reg1, op2) => encode_op2(01, 14, reg.into(), reg1.into(), *op2),
|
||||
Instruction::Store(addr, op2, val) => encode_op2(2, 0, val.into(), addr.into(), *op2),
|
||||
Instruction::Load(dest, addr, op2) => encode_op2(2, 1, dest.into(), addr.into(), *op2),
|
||||
Instruction::Push(op2) => encode_op2(2, 2, 0, 0, *op2),
|
||||
Instruction::Pop(reg) => encode_reg(2, 3, reg.into(), 0, 0),
|
||||
Instruction::Skip(labeli32, cond, reg, op2) => {
|
||||
let jump_distance = match labeli32 {
|
||||
Labeli32::Value(v) => *v as u32,
|
||||
Labeli32::Label(label) => {
|
||||
let dest = prgm[label];
|
||||
dest.wrapping_sub(self_addr + 4) / 4
|
||||
}
|
||||
};
|
||||
if jump_distance > 15 {
|
||||
println!("Error, cannot skip more than 15 instructions");
|
||||
return Err(());
|
||||
}
|
||||
encode_op2(11, cond.into(), jump_distance, reg.into(), *op2)
|
||||
}
|
||||
Instruction::Jump(labeli32) => {
|
||||
let dest = match labeli32 {
|
||||
Labeli32::Value(v) => *v as u32,
|
||||
Labeli32::Label(label) => {
|
||||
let dest = prgm[label];
|
||||
dest.wrapping_sub(self_addr) >> 2
|
||||
}
|
||||
};
|
||||
dest & 0x1FFF_FFFF
|
||||
}
|
||||
Instruction::Call(labeli32) => {
|
||||
let dest = match labeli32 {
|
||||
Labeli32::Value(v) => *v as u32,
|
||||
Labeli32::Label(label) => {
|
||||
let dest = prgm[label];
|
||||
dest.wrapping_sub(self_addr) >> 2
|
||||
}
|
||||
};
|
||||
(dest & 0x1FFF_FFFF) | (1 << 29)
|
||||
}
|
||||
Instruction::Ret() => encode_reg(2, 0b1000, 0, 0, 0),
|
||||
Instruction::GetStack(reg) => encode_reg(2, 0b1101, reg.into(), 0, 0),
|
||||
Instruction::SetStack(op2) => encode_op2(2, 0b1110, 0, 0, *op2),
|
||||
Instruction::Data(labeli32) => match labeli32 {
|
||||
Labeli32::Value(v) => *v as u32,
|
||||
Labeli32::Label(label) => prgm[label],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct Program {
|
||||
locations: HashMap<String, u32>,
|
||||
instructions: Vec<(Instruction, usize)>,
|
||||
}
|
||||
|
||||
impl Index<&String> for &Program {
|
||||
type Output = u32;
|
||||
|
||||
fn index(&self, index: &String) -> &Self::Output {
|
||||
match self.locations.get(index) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
println!("Could not resolve label {index}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reg(s: &str, n: usize, l: &str) -> Reg {
|
||||
match s {
|
||||
"r0" => Reg(0),
|
||||
"r1" => Reg(1),
|
||||
"r2" => Reg(2),
|
||||
"r3" => Reg(3),
|
||||
"r4" => Reg(4),
|
||||
"r5" => Reg(5),
|
||||
"r6" => Reg(6),
|
||||
"r7" => Reg(7),
|
||||
"r8" => Reg(8),
|
||||
"r9" => Reg(9),
|
||||
"r10" => Reg(10),
|
||||
"r11" => Reg(11),
|
||||
"r12" => Reg(12),
|
||||
"r13" => Reg(13),
|
||||
"r14" => Reg(14),
|
||||
"r15" => Reg(15),
|
||||
_ => {
|
||||
println!("Error: illegal register name: {s}. Error in {l} at line {n}");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn _reg(s: &str, n: usize, l: &str) -> Reg {
|
||||
reg(s, n, l)
|
||||
}
|
||||
fn op2(s: &str, n: usize, l: &str) -> Op2 {
|
||||
Op2::Register(match s {
|
||||
"r0" => 0,
|
||||
"r1" => 1,
|
||||
"r2" => 2,
|
||||
"r3" => 3,
|
||||
"r4" => 4,
|
||||
"r5" => 5,
|
||||
"r6" => 6,
|
||||
"r7" => 7,
|
||||
"r8" => 8,
|
||||
"r9" => 9,
|
||||
"r10" => 10,
|
||||
"r11" => 11,
|
||||
"r12" => 12,
|
||||
"r13" => 13,
|
||||
"r14" => 14,
|
||||
"r15" => 15,
|
||||
_ => match parse_int::parse::<i64>(s) {
|
||||
Ok(v) => {
|
||||
if -0xFFFF <= v && v <= 0xFFFF {
|
||||
return Op2::Direct(v as i32);
|
||||
} else {
|
||||
println!("Error: constant {s} is too large to fit in {l} at line {n}");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
println!(
|
||||
"Error: neither a register name nor a constant: {s}. Error in {l} at line {n}"
|
||||
);
|
||||
exit(1)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn memaddr<'a>(n: usize, l: &'a str, rgx: &RegexCollection) -> (Reg, Op2, Cow<'a, str>) {
|
||||
let f = || {
|
||||
println!("invalid memory operand in {l} at line {n}");
|
||||
exit(1);
|
||||
};
|
||||
let (rx, op) = match rgx.memop.captures(l) {
|
||||
Some(c) => {
|
||||
let rx = reg(c.get(1).unwrap().as_str(), n, l);
|
||||
let sign = c.get(2);
|
||||
match sign {
|
||||
Some(s) => {
|
||||
let sign = s.as_str();
|
||||
|
||||
let op = op2(c.get(3).unwrap().as_str(), n, l);
|
||||
match (sign, op) {
|
||||
("+", o) => (rx, o),
|
||||
("-", Op2::Direct(v)) => (rx, Op2::Direct(-v)),
|
||||
_ => f(),
|
||||
}
|
||||
}
|
||||
None => (rx, Op2::Direct(0)),
|
||||
}
|
||||
}
|
||||
None => f(),
|
||||
};
|
||||
let replace = rgx.memop.replace(l, "0");
|
||||
(rx, op, replace)
|
||||
}
|
||||
|
||||
struct RegexCollection {
|
||||
label: Regex,
|
||||
memop: Regex,
|
||||
}
|
||||
|
||||
fn process_line(prgm: &mut Program, (linenum, line): (usize, String), rgx: &RegexCollection) {
|
||||
let mut no_comment = line.split(';').next().unwrap_or("");
|
||||
let binding = no_comment.to_ascii_lowercase();
|
||||
no_comment = binding.as_str();
|
||||
let comma = no_comment.find(':');
|
||||
match comma {
|
||||
Some(index) => {
|
||||
let (label, next) = no_comment.split_at(index);
|
||||
let label = label.trim();
|
||||
if !rgx.label.is_match(label) {
|
||||
println!("The label {label} on line {linenum} is illegal")
|
||||
}
|
||||
prgm.locations
|
||||
.insert(label.to_string(), (prgm.instructions.len() * 4) as u32);
|
||||
no_comment = &next[1..]
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
let mut words = no_comment.split_ascii_whitespace();
|
||||
let mnemonic = words.next();
|
||||
let args: Vec<&str> = words.collect();
|
||||
if mnemonic.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let reg = |i| reg(args[i], linenum, &line);
|
||||
let op2 = |i| op2(args[i], linenum, &line);
|
||||
let labi32 = |i| {
|
||||
if rgx.label.is_match(args[i]) {
|
||||
Labeli32::Label((args[i] as &str).to_string())
|
||||
} else {
|
||||
Labeli32::Value(parse_int::parse::<i64>(args[i]).unwrap_or_else(|e| {
|
||||
println!(
|
||||
"Malformated lable/constant: '{}' in {line} at line {linenum}: {e}",
|
||||
args[i]
|
||||
);
|
||||
exit(1);
|
||||
}) as i32)
|
||||
}
|
||||
};
|
||||
let chk = |n| {
|
||||
if args.len() != n {
|
||||
println!(
|
||||
"Wrong number of argument for {} in {line} at line {linenum}",
|
||||
mnemonic.unwrap()
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let next = match mnemonic.unwrap() {
|
||||
"copy" => {
|
||||
chk(2);
|
||||
if args[0] == "sp" {
|
||||
Instruction::SetStack(op2(1))
|
||||
} else if args[1] == "sp" {
|
||||
Instruction::GetStack(reg(0))
|
||||
} else {
|
||||
Instruction::Copy(
|
||||
reg(0),
|
||||
match op2(1) {
|
||||
Op2::Direct(v) => Labeli17::Value(v),
|
||||
Op2::Register(r) => Labeli17::Register(Reg(r)),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
"add" => {
|
||||
chk(3);
|
||||
Instruction::Add(
|
||||
reg(0),
|
||||
reg(1),
|
||||
match op2(2) {
|
||||
Op2::Direct(v) => Labeli17::Value(v),
|
||||
Op2::Register(r) => Labeli17::Register(Reg(r)),
|
||||
},
|
||||
)
|
||||
}
|
||||
"sub" => {
|
||||
chk(3);
|
||||
Instruction::Sub(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"or" => {
|
||||
chk(3);
|
||||
Instruction::Or(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"and" => {
|
||||
chk(3);
|
||||
Instruction::And(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"xor" => {
|
||||
chk(3);
|
||||
Instruction::Xor(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"lsl" => {
|
||||
chk(3);
|
||||
Instruction::Lsl(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"lsr" => {
|
||||
chk(3);
|
||||
Instruction::Lsr(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"smull" => {
|
||||
chk(3);
|
||||
Instruction::Smull(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"smulh" => {
|
||||
chk(3);
|
||||
Instruction::Smulh(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"umull" => {
|
||||
chk(3);
|
||||
Instruction::Umull(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"umulh" => {
|
||||
chk(3);
|
||||
Instruction::Umulh(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"mod" => {
|
||||
chk(3);
|
||||
Instruction::Mod(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"div" => {
|
||||
chk(3);
|
||||
Instruction::Div(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"asr" => {
|
||||
chk(3);
|
||||
Instruction::Asr(reg(0), reg(1), op2(2))
|
||||
}
|
||||
"load" => {
|
||||
let (rx, op2, new_line) = memaddr(linenum, no_comment, rgx);
|
||||
let args: Vec<_> = new_line.split_ascii_whitespace().collect();
|
||||
if args.len() != 3 {
|
||||
println!("wrong number of args in {line} at line {linenum}");
|
||||
exit(1);
|
||||
}
|
||||
Instruction::Load(_reg(args[1], linenum, &line), rx, op2)
|
||||
}
|
||||
"store" => {
|
||||
let (rx, op2, new_line) = memaddr(linenum, no_comment, rgx);
|
||||
let args: Vec<_> = new_line.split_ascii_whitespace().collect();
|
||||
if args.len() != 3 {
|
||||
println!("wrong number of args in {line} at line {linenum}");
|
||||
exit(1);
|
||||
}
|
||||
Instruction::Store(rx, op2, _reg(args[2], linenum, &line))
|
||||
}
|
||||
"push" => {
|
||||
chk(1);
|
||||
Instruction::Push(op2(0))
|
||||
}
|
||||
"pop" => {
|
||||
chk(1);
|
||||
Instruction::Pop(reg(0))
|
||||
}
|
||||
"skip" => {
|
||||
chk(4);
|
||||
let d = labi32(0);
|
||||
match args[1].try_into() {
|
||||
Ok(c) => Instruction::Skip(d, c, reg(2), op2(3)),
|
||||
Err(_) => {
|
||||
println!("in {line} at line {linenum}");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
"skipto" => {
|
||||
chk(4);
|
||||
let d = labi32(0);
|
||||
match args[1].try_into() {
|
||||
Ok(c) => Instruction::Skip(d, c, reg(2), op2(3)),
|
||||
Err(_) => {
|
||||
println!("in {line} at line {linenum}");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
"jump" => {
|
||||
chk(1);
|
||||
Instruction::Jump(labi32(0))
|
||||
}
|
||||
"call" => {
|
||||
chk(1);
|
||||
Instruction::Call(labi32(0))
|
||||
}
|
||||
"ret" => {
|
||||
chk(0);
|
||||
Instruction::Ret()
|
||||
}
|
||||
"halt" => {
|
||||
chk(0);
|
||||
Instruction::Jump(Labeli32::Value(0))
|
||||
}
|
||||
"nop" => {
|
||||
chk(0);
|
||||
Instruction::Add(Reg(0), Reg(0), Labeli17::Value(0))
|
||||
}
|
||||
"let" => {
|
||||
chk(2);
|
||||
let r = reg(0);
|
||||
match labi32(1) {
|
||||
Labeli32::Label(l) => {
|
||||
prgm.instructions.push((
|
||||
Instruction::Copy(r, Labeli17::LabelHigh(l.clone())),
|
||||
linenum,
|
||||
));
|
||||
prgm.instructions
|
||||
.push((Instruction::Lsl(r, r, Op2::Direct(16)), linenum));
|
||||
Instruction::Add(r, r, Labeli17::LabelLow(l))
|
||||
}
|
||||
Labeli32::Value(v) => {
|
||||
if -0xFFFF <= v && v <= 0xFFFF {
|
||||
Instruction::Copy(r, Labeli17::Value(v))
|
||||
} else {
|
||||
prgm.instructions.push((
|
||||
Instruction::Copy(r, Labeli17::Value((v as u32 >> 16) as i32)),
|
||||
linenum,
|
||||
));
|
||||
prgm.instructions
|
||||
.push((Instruction::Lsl(r, r, Op2::Direct(16)), linenum));
|
||||
Instruction::Add(r, r, Labeli17::Value(v & 0xFFFF))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"d" => {
|
||||
chk(1);
|
||||
Instruction::Data(labi32(0))
|
||||
}
|
||||
m => {
|
||||
println!("Unknown mnemnonic {m} in {line} at line {linenum}");
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
prgm.instructions.push((next, linenum));
|
||||
}
|
||||
|
||||
const HELP: &str = "usage: cargo run --release INPUT [OUTPUT]
|
||||
where INPUT is a file name or - for stdin
|
||||
and the optional OUTPUT is a output file name
|
||||
|
||||
if stdin is used and no output is used, out.bin is used";
|
||||
|
||||
fn main() {
|
||||
let progname = args().nth(1).expect(HELP);
|
||||
let outname = args().nth(2);
|
||||
|
||||
let mut prgm = Program {
|
||||
locations: HashMap::new(),
|
||||
instructions: Vec::new(),
|
||||
};
|
||||
let rgx = RegexCollection {
|
||||
label: Regex::new("^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap(),
|
||||
memop: Regex::new(r"\[ *(r[0-9]{1,2}) *(?:(\+|-) *(r[0-9]{1,2}|0x[0-9a-f]*|[0-9]*) *)?\]")
|
||||
.unwrap(),
|
||||
};
|
||||
if progname == "-" {
|
||||
for line in stdin()
|
||||
.lines()
|
||||
.map(|x| x.expect("error while reading stdin"))
|
||||
.enumerate()
|
||||
{
|
||||
process_line(&mut prgm, line, &rgx);
|
||||
}
|
||||
} else {
|
||||
let infile = std::fs::File::open(progname.as_str()).expect("Cannot open input file");
|
||||
for line in BufReader::new(infile)
|
||||
.lines()
|
||||
.map(|x| x.expect("Erro while reading input file"))
|
||||
.enumerate()
|
||||
{
|
||||
process_line(&mut prgm, line, &rgx);
|
||||
}
|
||||
}
|
||||
|
||||
let outname = match outname {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
if progname == "-" {
|
||||
"out.bin".to_string()
|
||||
} else {
|
||||
progname
|
||||
.strip_suffix(".asm")
|
||||
.unwrap_or(progname.as_str())
|
||||
.to_string()
|
||||
+ ".bin"
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut outfile = std::fs::File::create_buffered(outname).expect("could not open out file");
|
||||
for (num, (instruction, linenum)) in prgm.instructions.iter().enumerate() {
|
||||
let v = instruction.encode(&prgm, num as u32 * 4);
|
||||
match v {
|
||||
Ok(v) => writeln!(outfile, "{v:08x}").expect("error writing"),
|
||||
Err(_) => {
|
||||
println!("in source at line {linenum}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if prgm.locations.len() != 0 {
|
||||
writeln!(outfile, "SYMBOL TABLE:").expect("error writing");
|
||||
}
|
||||
let mut assocs: Vec<_> = prgm.locations.iter().collect();
|
||||
assocs.sort_by_key(|(_, v)| **v);
|
||||
for (s, v) in assocs {
|
||||
writeln!(outfile, "{v:08x} {s}").expect("error writing");
|
||||
}
|
||||
}
|
||||
BIN
sim_rs.tar.xz
BIN
sim_rs.tar.xz
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "sim"
|
||||
name = "simu"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
|
||||
2
simu/rust-toolchain.toml
Normal file
2
simu/rust-toolchain.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
Reference in New Issue
Block a user