cc! assembler and examples

This commit is contained in:
c0repwn3r 2023-05-08 18:01:50 -04:00
parent 6c1cf0f620
commit 596254394f
Signed by: core
GPG key ID: FDBF740DADDCEECF
7 changed files with 298 additions and 169 deletions

View file

@ -1,7 +1,7 @@
use crate::opt_sim_asm::SimpleAssemblySimulator;
use std::error::Error; use std::error::Error;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use crate::opt_sim_asm::SimpleAssemblySimulator;
pub fn assemble(processed: String, out: PathBuf) -> Result<(), Box<dyn Error>> { pub fn assemble(processed: String, out: PathBuf) -> Result<(), Box<dyn Error>> {
let mut simple_sim = SimpleAssemblySimulator { let mut simple_sim = SimpleAssemblySimulator {

View file

@ -1,6 +1,8 @@
use std::error::Error; use std::error::Error;
use std::path::PathBuf; use std::path::PathBuf;
pub fn disassemble(file: PathBuf, out: PathBuf) -> Result<(), Box<dyn Error>> { // TODO
pub fn disassemble(_file: PathBuf, _out: PathBuf) -> Result<(), Box<dyn Error>> {
Ok(()) Ok(())
} }

View file

@ -1,16 +1,16 @@
use std::path::PathBuf;
use clap::{Parser, ArgAction};
use crate::asm::assemble; use crate::asm::assemble;
use crate::disasm::disassemble; use crate::disasm::disassemble;
use crate::normalizer::normalize; use crate::normalizer::normalize;
use crate::preprocessor::preprocess; use crate::preprocessor::preprocess;
use clap::{ArgAction, Parser};
use std::path::PathBuf;
pub mod ops; pub mod asm;
pub mod disasm; pub mod disasm;
pub mod normalizer; pub mod normalizer;
pub mod asm; pub mod ops;
pub mod preprocessor;
pub mod opt_sim_asm; pub mod opt_sim_asm;
pub mod preprocessor;
#[derive(Parser)] #[derive(Parser)]
pub struct Cli { pub struct Cli {
@ -25,7 +25,7 @@ pub struct Cli {
#[clap(short, long, action = ArgAction::SetTrue)] #[clap(short, long, action = ArgAction::SetTrue)]
pub preprocess_only: bool, pub preprocess_only: bool,
#[clap(short, long, action = ArgAction::SetTrue)] #[clap(short, long, action = ArgAction::SetTrue)]
pub disassemble: bool pub disassemble: bool,
} }
fn main() { fn main() {

View file

@ -14,30 +14,47 @@ pub fn normalize(file: PathBuf) -> Result<String, Box<dyn Error>> {
match line_split[0] { match line_split[0] {
"lsh" => { "lsh" => {
if line_split.len() != 3 { if line_split.len() != 3 {
return Err(format!("line {}: expected exactly 2 arguments to 'lsh', instead got {}", line_num, line_split.len() - 1).into()); return Err(format!(
"line {}: expected exactly 2 arguments to 'lsh', instead got {}",
line_num,
line_split.len() - 1
)
.into());
} }
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { if !dest.ends_with(',') {
return Err(format!("line {}: arg 1 to 'lsh' must end in ','", line_num).into()); return Err(format!("line {}: arg 1 to 'lsh' must end in ','", line_num).into());
} }
let dest = &dest[..dest.len()-1]; let dest = &dest[..dest.len() - 1];
let rg = line_split[2]; let rg = line_split[2];
normalized += &format!("add {}, {} {} ; normalizer: originally '{}'\n", dest, rg, rg, line); normalized += &format!(
"add {}, {} {} ; normalizer: originally '{}'\n",
}, dest, rg, rg, line
);
}
"cmp" => { "cmp" => {
if line_split.len() != 3 { if line_split.len() != 3 {
return Err(format!("line {}: expected exactly 2 arguments to 'cmp', instead got {}", line_num, line_split.len() - 1).into()); return Err(format!(
"line {}: expected exactly 2 arguments to 'cmp', instead got {}",
line_num,
line_split.len() - 1
)
.into());
} }
let a = line_split[1]; let a = line_split[1];
let b = line_split[2]; let b = line_split[2];
normalized += &format!("sub r0, {} {} ; normalizer: originally '{}'\n", a, b, line); normalized += &format!("sub r0, {} {} ; normalizer: originally '{}'\n", a, b, line);
}, }
"cpy" => { "cpy" => {
if line_split.len() != 3 { if line_split.len() != 3 {
return Err(format!("line {}: expected exactly 2 arguments to 'cpy', instead got {}", line_num, line_split.len() - 1).into()); return Err(format!(
"line {}: expected exactly 2 arguments to 'cpy', instead got {}",
line_num,
line_split.len() - 1
)
.into());
} }
let dest = line_split[1]; let dest = line_split[1];
let a = line_split[2]; let a = line_split[2];
@ -47,11 +64,21 @@ pub fn normalize(file: PathBuf) -> Result<String, Box<dyn Error>> {
} }
normalized += "ldi r0, 0 ; normalizer: originally below\n"; normalized += "ldi r0, 0 ; normalizer: originally below\n";
normalized += &format!("add {}, {} r0 ; normalizer: originally '{}'\n", &dest[..dest.len()-1], a, line); normalized += &format!(
}, "add {}, {} r0 ; normalizer: originally '{}'\n",
&dest[..dest.len() - 1],
a,
line
);
}
"not" => { "not" => {
if line_split.len() != 3 { if line_split.len() != 3 {
return Err(format!("line {}: expected exactly 2 arguments to 'not', instead got {}", line_num, line_split.len() - 1).into()); return Err(format!(
"line {}: expected exactly 2 arguments to 'not', instead got {}",
line_num,
line_split.len() - 1
)
.into());
} }
let dest = line_split[1]; let dest = line_split[1];
let a = line_split[2]; let a = line_split[2];
@ -61,7 +88,12 @@ pub fn normalize(file: PathBuf) -> Result<String, Box<dyn Error>> {
} }
normalized += "ldi r0, 0 ; normalizer: originally below\n"; normalized += "ldi r0, 0 ; normalizer: originally below\n";
normalized += &format!("nor {}, {} r0 ; normalizer: originally '{}'\n", &dest[..dest.len()-1], a, line); normalized += &format!(
"nor {}, {} r0 ; normalizer: originally '{}'\n",
&dest[..dest.len() - 1],
a,
line
);
} }
_ => { _ => {
normalized += line; normalized += line;

View file

@ -13,7 +13,7 @@ pub enum Register {
RD, RD,
RE, RE,
PC, PC,
FLG FLG,
} }
impl Register { impl Register {
fn byte(&self) -> u8 { fn byte(&self) -> u8 {
@ -32,73 +32,73 @@ impl Register {
pub fn add(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> { pub fn add(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> {
vec![ vec![
0b1111_1101, // opcode 0b1111_1101, // opcode
reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1 reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1
reg_b.byte() << 5, // operands 2, reg_b.byte() << 5, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
pub fn sub(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> { pub fn sub(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> {
vec![ vec![
0b1111_1100, // opcode 0b1111_1100, // opcode
reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1 reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1
reg_b.byte() << 5, // operands 2, reg_b.byte() << 5, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
pub fn or(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> { pub fn or(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> {
vec![ vec![
0b1111_1011, // opcode 0b1111_1011, // opcode
reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1 reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1
reg_b.byte() << 5, // operands 2, reg_b.byte() << 5, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
pub fn nor(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> { pub fn nor(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> {
vec![ vec![
0b1111_1010, // opcode 0b1111_1010, // opcode
reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1 reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1
reg_b.byte() << 5, // operands 2, reg_b.byte() << 5, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
pub fn and(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> { pub fn and(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> {
vec![ vec![
0b1111_1001, // opcode 0b1111_1001, // opcode
reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1 reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1
reg_b.byte() << 5, // operands 2, reg_b.byte() << 5, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
pub fn xor(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> { pub fn xor(reg_dest: Register, reg_a: Register, reg_b: Register) -> Vec<u8> {
vec![ vec![
0b1111_1000, // opcode 0b1111_1000, // opcode
reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1 reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1
reg_b.byte() << 5, // operands 2, reg_b.byte() << 5, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
pub fn rsh(reg_dest: Register, reg_a: Register) -> Vec<u8> { pub fn rsh(reg_dest: Register, reg_a: Register) -> Vec<u8> {
vec![ vec![
0b1111_0111, // opcode 0b1111_0111, // opcode
reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1 reg_dest.byte() << 5 | reg_a.byte() << 2, // operands 1
0b0000_0000, // operands 2, 0b0000_0000, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
pub fn ldi(reg_dest: Register, immediate: u8) -> Vec<u8> { pub fn ldi(reg_dest: Register, immediate: u8) -> Vec<u8> {
vec![ vec![
0b1111_0110, // opcode 0b1111_0110, // opcode
reg_dest.byte() << 5, // operands 1 reg_dest.byte() << 5, // operands 1
immediate, // operands 2, immediate, // operands 2,
0b0000_0000 // operands 3 0b0000_0000, // operands 3
] ]
} }
@ -108,65 +108,55 @@ pub fn mmr(reg_dest: Register, address: u16) -> Vec<u8> {
// &0000 1111 1111 0000, >> 4 // &0000 1111 1111 0000, >> 4
// &0000 0000 0000 1111, << 4 // &0000 0000 0000 1111, << 4
vec![ vec![
0b1111_0101, // opcode, 0b1111_0101, // opcode,
reg_dest.byte() << 5, // operands 1 reg_dest.byte() << 5, // operands 1
address_higher_half(address), // operands 2 address_higher_half(address), // operands 2
address_lower_half(address), // operands 3 address_lower_half(address), // operands 3
] ]
} }
pub fn mrm(reg_src: Register, address: u16) -> Vec<u8> { pub fn mrm(reg_src: Register, address: u16) -> Vec<u8> {
vec![ vec![
0b1111_0100, // opcode 0b1111_0100, // opcode
reg_src.byte() << 5, // operands 1 reg_src.byte() << 5, // operands 1
address_higher_half(address), // operands 2 address_higher_half(address), // operands 2
address_lower_half(address), // operands 3 address_lower_half(address), // operands 3
] ]
} }
pub fn jmp(address: u16) -> Vec<u8> { pub fn jmp(address: u16) -> Vec<u8> {
vec![ vec![
0b1111_0011, // opcode 0b1111_0011, // opcode
address_higher_half(address), // operands 1 address_higher_half(address), // operands 1
address_lower_half(address), // operands 2, address_lower_half(address), // operands 2,
0b0000_0000 0b0000_0000,
] ]
} }
pub fn jez(address: u16) -> Vec<u8> { pub fn jez(address: u16) -> Vec<u8> {
vec![ vec![
0b1111_0010, // opcode 0b1111_0010, // opcode
address_higher_half(address), // operands 1 address_higher_half(address), // operands 1
address_lower_half(address), // operands 2, address_lower_half(address), // operands 2,
0b0000_0000 0b0000_0000,
] ]
} }
pub fn rmmr(reg_dest: Register, address: u16) -> Vec<u8> { pub fn rmmr(reg_dest: Register, address: u16) -> Vec<u8> {
vec![ vec![
0b1111_0001, // opcode, 0b1111_0001, // opcode,
reg_dest.byte() << 5, // operands 1 reg_dest.byte() << 5, // operands 1
address_higher_half(address), // operands 2 address_higher_half(address), // operands 2
address_lower_half(address), // operands 3 address_lower_half(address), // operands 3
] ]
} }
pub fn r#in(reg_dest: Register, port: u8) -> Vec<u8> { pub fn r#in(reg_dest: Register, port: u8) -> Vec<u8> {
vec![ vec![0b1111_0000, reg_dest.byte() << 5, port, 0b0000_0000]
0b1111_0000,
reg_dest.byte() << 5,
port,
0b0000_0000
]
} }
pub fn out(reg_src: Register, port: u8) -> Vec<u8> { pub fn out(reg_src: Register, port: u8) -> Vec<u8> {
vec![ vec![0b1110_1111, reg_src.byte() << 5, port, 0b0000_0000]
0b1110_1111,
reg_src.byte() << 5,
port,
0b0000_0000
]
} }
// See `mmr` for how these values are calculated // See `mmr` for how these values are calculated
@ -178,8 +168,12 @@ fn address_lower_half(address: u16) -> u8 {
((address & 0b0000_0000_0000_1111) << 4).try_into().unwrap() ((address & 0b0000_0000_0000_1111) << 4).try_into().unwrap()
} }
#[cfg(test)]
mod tests { mod tests {
use crate::ops::{add, and, hcf, jez, jmp, ldi, mmr, mrm, nop, nor, or, out, r#in, Register, rmmr, rsh, sub, xor}; use crate::ops::{
add, and, hcf, jez, jmp, ldi, mmr, mrm, nop, nor, or, out, r#in, rmmr, rsh, sub, xor,
Register,
};
#[test] #[test]
fn test_nop() { fn test_nop() {
@ -193,76 +187,121 @@ mod tests {
#[test] #[test]
fn test_add() { fn test_add() {
assert_eq!(add(Register::R0, Register::RA, Register::RB), vec![0b1111_1101, 0b0000_0100, 0b0100_0000, 0b0000_0000]) assert_eq!(
add(Register::R0, Register::RA, Register::RB),
vec![0b1111_1101, 0b0000_0100, 0b0100_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_sub() { fn test_sub() {
assert_eq!(sub(Register::R0, Register::RA, Register::RB), vec![0b1111_1100, 0b0000_0100, 0b0100_0000, 0b0000_0000]) assert_eq!(
sub(Register::R0, Register::RA, Register::RB),
vec![0b1111_1100, 0b0000_0100, 0b0100_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_or() { fn test_or() {
assert_eq!(or(Register::R0, Register::RA, Register::RB), vec![0b1111_1011, 0b0000_0100, 0b0100_0000, 0b0000_0000]) assert_eq!(
or(Register::R0, Register::RA, Register::RB),
vec![0b1111_1011, 0b0000_0100, 0b0100_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_nor() { fn test_nor() {
assert_eq!(nor(Register::R0, Register::RA, Register::RB), vec![0b1111_1010, 0b0000_0100, 0b0100_0000, 0b0000_0000]) assert_eq!(
nor(Register::R0, Register::RA, Register::RB),
vec![0b1111_1010, 0b0000_0100, 0b0100_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_and() { fn test_and() {
assert_eq!(and(Register::R0, Register::RA, Register::RB), vec![0b1111_1001, 0b0000_0100, 0b0100_0000, 0b0000_0000]) assert_eq!(
and(Register::R0, Register::RA, Register::RB),
vec![0b1111_1001, 0b0000_0100, 0b0100_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_xor() { fn test_xor() {
assert_eq!(xor(Register::R0, Register::RA, Register::RB), vec![0b1111_1000, 0b0000_0100, 0b0100_0000, 0b0000_0000]) assert_eq!(
xor(Register::R0, Register::RA, Register::RB),
vec![0b1111_1000, 0b0000_0100, 0b0100_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_rsh() { fn test_rsh() {
assert_eq!(rsh(Register::R0, Register::RA), vec![0b1111_0111, 0b0000_0100, 0b0000_0000, 0b0000_0000]) assert_eq!(
rsh(Register::R0, Register::RA),
vec![0b1111_0111, 0b0000_0100, 0b0000_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_ldi() { fn test_ldi() {
assert_eq!(ldi(Register::R0, 0b0101_1010), vec![0b1111_0110, 0b0000_0000, 0b0101_1010, 0b0000_0000]) assert_eq!(
ldi(Register::R0, 0b0101_1010),
vec![0b1111_0110, 0b0000_0000, 0b0101_1010, 0b0000_0000]
)
} }
#[test] #[test]
fn test_mmr() { fn test_mmr() {
assert_eq!(mmr(Register::R0, 0b0000_0101_1010_0110), vec![0b1111_0101, 0b0000_0000, 0b0101_1010, 0b0110_0000]) assert_eq!(
mmr(Register::R0, 0b0000_0101_1010_0110),
vec![0b1111_0101, 0b0000_0000, 0b0101_1010, 0b0110_0000]
)
} }
#[test] #[test]
fn test_mrm() { fn test_mrm() {
assert_eq!(mrm(Register::R0, 0b0000_0101_1010_0110), vec![0b1111_0100, 0b0000_0000, 0b0101_1010, 0b0110_0000]) assert_eq!(
mrm(Register::R0, 0b0000_0101_1010_0110),
vec![0b1111_0100, 0b0000_0000, 0b0101_1010, 0b0110_0000]
)
} }
#[test] #[test]
fn test_jmp() { fn test_jmp() {
assert_eq!(jmp(0b0000_0101_1010_0110), vec![0b1111_0011, 0b0101_1010, 0b0110_0000, 0b0000_0000]) assert_eq!(
jmp(0b0000_0101_1010_0110),
vec![0b1111_0011, 0b0101_1010, 0b0110_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_jez() { fn test_jez() {
assert_eq!(jez(0b0000_0101_1010_0110), vec![0b1111_0010, 0b0101_1010, 0b0110_0000, 0b0000_0000]) assert_eq!(
jez(0b0000_0101_1010_0110),
vec![0b1111_0010, 0b0101_1010, 0b0110_0000, 0b0000_0000]
)
} }
#[test] #[test]
fn test_rmmr() { fn test_rmmr() {
assert_eq!(rmmr(Register::R0, 0b0000_0101_1010_0110), vec![0b1111_0001, 0b0000_0000, 0b0101_1010, 0b0110_0000]) assert_eq!(
rmmr(Register::R0, 0b0000_0101_1010_0110),
vec![0b1111_0001, 0b0000_0000, 0b0101_1010, 0b0110_0000]
)
} }
#[test] #[test]
fn test_in() { fn test_in() {
assert_eq!(r#in(Register::R0, 0b0101_1010), vec![0b1111_0000, 0b0000_0000, 0b0101_1010, 0b0000_0000]) assert_eq!(
r#in(Register::R0, 0b0101_1010),
vec![0b1111_0000, 0b0000_0000, 0b0101_1010, 0b0000_0000]
)
} }
#[test] #[test]
fn test_out() { fn test_out() {
assert_eq!(out(Register::R0, 0b0101_1010), vec![0b1110_1111, 0b0000_0000, 0b0101_1010, 0b0000_0000]) assert_eq!(
out(Register::R0, 0b0101_1010),
vec![0b1110_1111, 0b0000_0000, 0b0101_1010, 0b0000_0000]
)
} }
} }

View file

@ -1,5 +1,7 @@
use crate::ops::{
add, and, hcf, ldi, mmr, mrm, nop, nor, or, out, r#in, rmmr, rsh, sub, xor, Register,
};
use std::error::Error; use std::error::Error;
use crate::ops::{add, and, hcf, ldi, mmr, mrm, nop, nor, or, out, r#in, Register, rmmr, rsh, sub, xor};
#[derive(Clone, Eq, PartialEq, Debug)] #[derive(Clone, Eq, PartialEq, Debug)]
pub struct SimpleAssemblySimulator { pub struct SimpleAssemblySimulator {
@ -13,7 +15,7 @@ pub struct SimpleAssemblySimulator {
pub rd: u8, pub rd: u8,
pub re: u8, pub re: u8,
pub pc: u16, pub pc: u16,
pub flg: u8 pub flg: u8,
} }
impl SimpleAssemblySimulator { impl SimpleAssemblySimulator {
pub fn line(&mut self, line: &str) -> Result<Vec<u8>, Box<dyn Error>> { pub fn line(&mut self, line: &str) -> Result<Vec<u8>, Box<dyn Error>> {
@ -23,10 +25,14 @@ impl SimpleAssemblySimulator {
"nop" => Ok(nop()), "nop" => Ok(nop()),
"hcf" => Ok(hcf()), // ignored for the simulator "hcf" => Ok(hcf()), // ignored for the simulator
"add" => { "add" => {
if line_split.len() != 4 { return Err("add requires exactly 3 arguments".into()) } if line_split.len() != 4 {
return Err("add requires exactly 3 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of add must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of add must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let a = to_reg(line_split[2])?; let a = to_reg(line_split[2])?;
@ -38,7 +44,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let b = to_reg(line_split[3])?; let b = to_reg(line_split[3])?;
@ -51,7 +57,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let mut val = (a_val as u16) + (b_val as u16); let mut val = (a_val as u16) + (b_val as u16);
@ -67,16 +73,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = val as u8, Register::RD => self.rd = val as u8,
Register::RE => self.re = val as u8, Register::RE => self.re = val as u8,
Register::PC => self.pc = (val as u8) as u16, Register::PC => self.pc = (val as u8) as u16,
Register::FLG => self.flg = val as u8 Register::FLG => self.flg = val as u8,
} }
Ok(add(dest, a, b)) Ok(add(dest, a, b))
}, }
"sub" => { "sub" => {
if line_split.len() != 4 { return Err("sub requires exactly 3 arguments".into()) } if line_split.len() != 4 {
return Err("sub requires exactly 3 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of sub must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of sub must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let a = to_reg(line_split[2])?; let a = to_reg(line_split[2])?;
@ -88,7 +98,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let b = to_reg(line_split[3])?; let b = to_reg(line_split[3])?;
@ -101,15 +111,15 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let val;
if b_val > a_val { let val = if b_val > a_val {
val = 0; 0
} else { } else {
val = a_val - b_val; a_val - b_val
} };
match dest { match dest {
Register::R0 => self.r0 = val, Register::R0 => self.r0 = val,
@ -119,16 +129,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = val, Register::RD => self.rd = val,
Register::RE => self.re = val, Register::RE => self.re = val,
Register::PC => self.pc = (val) as u16, Register::PC => self.pc = (val) as u16,
Register::FLG => self.flg = val Register::FLG => self.flg = val,
} }
Ok(sub(dest, a, b)) Ok(sub(dest, a, b))
}, }
"or" => { "or" => {
if line_split.len() != 4 { return Err("or requires exactly 3 arguments".into()) } if line_split.len() != 4 {
return Err("or requires exactly 3 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of or must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of or must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let a = to_reg(line_split[2])?; let a = to_reg(line_split[2])?;
@ -140,7 +154,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let b = to_reg(line_split[3])?; let b = to_reg(line_split[3])?;
@ -153,7 +167,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
match dest { match dest {
@ -164,16 +178,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = a_val | b_val, Register::RD => self.rd = a_val | b_val,
Register::RE => self.re = a_val | b_val, Register::RE => self.re = a_val | b_val,
Register::PC => self.pc = (a_val | b_val) as u16, Register::PC => self.pc = (a_val | b_val) as u16,
Register::FLG => self.flg = a_val | b_val Register::FLG => self.flg = a_val | b_val,
} }
Ok(or(dest, a, b)) Ok(or(dest, a, b))
}, }
"nor" => { "nor" => {
if line_split.len() != 4 { return Err("nor requires exactly 3 arguments".into()) } if line_split.len() != 4 {
return Err("nor requires exactly 3 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of nor must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of nor must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let a = to_reg(line_split[2])?; let a = to_reg(line_split[2])?;
@ -185,7 +203,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let b = to_reg(line_split[3])?; let b = to_reg(line_split[3])?;
@ -198,7 +216,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
match dest { match dest {
@ -209,16 +227,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = !(a_val | b_val), Register::RD => self.rd = !(a_val | b_val),
Register::RE => self.re = !(a_val | b_val), Register::RE => self.re = !(a_val | b_val),
Register::PC => self.pc = !(a_val | b_val) as u16, Register::PC => self.pc = !(a_val | b_val) as u16,
Register::FLG => self.flg = !(a_val | b_val) Register::FLG => self.flg = !(a_val | b_val),
} }
Ok(nor(dest, a, b)) Ok(nor(dest, a, b))
}, }
"and" => { "and" => {
if line_split.len() != 4 { return Err("and requires exactly 3 arguments".into()) } if line_split.len() != 4 {
return Err("and requires exactly 3 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of and must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of and must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let a = to_reg(line_split[2])?; let a = to_reg(line_split[2])?;
@ -230,7 +252,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let b = to_reg(line_split[3])?; let b = to_reg(line_split[3])?;
@ -243,7 +265,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
match dest { match dest {
@ -254,16 +276,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = a_val & b_val, Register::RD => self.rd = a_val & b_val,
Register::RE => self.re = a_val & b_val, Register::RE => self.re = a_val & b_val,
Register::PC => self.pc = (a_val & b_val) as u16, Register::PC => self.pc = (a_val & b_val) as u16,
Register::FLG => self.flg = a_val & b_val Register::FLG => self.flg = a_val & b_val,
} }
Ok(and(dest, a, b)) Ok(and(dest, a, b))
}, }
"xor" => { "xor" => {
if line_split.len() != 4 { return Err("xor requires exactly 3 arguments".into()) } if line_split.len() != 4 {
return Err("xor requires exactly 3 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of xor must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of xor must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let a = to_reg(line_split[2])?; let a = to_reg(line_split[2])?;
@ -275,7 +301,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
let b = to_reg(line_split[3])?; let b = to_reg(line_split[3])?;
@ -288,7 +314,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
match dest { match dest {
@ -299,16 +325,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = a_val ^ b_val, Register::RD => self.rd = a_val ^ b_val,
Register::RE => self.re = a_val ^ b_val, Register::RE => self.re = a_val ^ b_val,
Register::PC => self.pc = (a_val ^ b_val) as u16, Register::PC => self.pc = (a_val ^ b_val) as u16,
Register::FLG => self.flg = a_val ^ b_val Register::FLG => self.flg = a_val ^ b_val,
} }
Ok(xor(dest, a, b)) Ok(xor(dest, a, b))
}, }
"rsh" => { "rsh" => {
if line_split.len() != 3 { return Err("rsh requires exactly 2 arguments".into()) } if line_split.len() != 3 {
return Err("rsh requires exactly 2 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of rsh must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of rsh must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let a = to_reg(line_split[2])?; let a = to_reg(line_split[2])?;
@ -320,7 +350,7 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd, Register::RD => self.rd,
Register::RE => self.re, Register::RE => self.re,
Register::PC => return Err("Cannot use program counter as a register".into()), Register::PC => return Err("Cannot use program counter as a register".into()),
Register::FLG => self.flg Register::FLG => self.flg,
}; };
match dest { match dest {
@ -331,16 +361,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = a_val >> 1, Register::RD => self.rd = a_val >> 1,
Register::RE => self.re = a_val >> 1, Register::RE => self.re = a_val >> 1,
Register::PC => self.pc = (a_val >> 1) as u16, Register::PC => self.pc = (a_val >> 1) as u16,
Register::FLG => self.flg = a_val >> 1 Register::FLG => self.flg = a_val >> 1,
} }
Ok(rsh(dest, a)) Ok(rsh(dest, a))
}, }
"ldi" => { "ldi" => {
if line_split.len() != 3 { return Err("rsh requires exactly 2 arguments".into()) } if line_split.len() != 3 {
return Err("rsh requires exactly 2 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of rsh must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of rsh must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let data: u8 = parse_int::parse(line_split[2])?; let data: u8 = parse_int::parse(line_split[2])?;
@ -352,16 +386,20 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = data, Register::RD => self.rd = data,
Register::RE => self.re = data, Register::RE => self.re = data,
Register::PC => self.pc = data as u16, Register::PC => self.pc = data as u16,
Register::FLG => self.flg = data Register::FLG => self.flg = data,
} }
Ok(ldi(dest, data)) Ok(ldi(dest, data))
}, }
"mmr" => { "mmr" => {
if line_split.len() != 3 { return Err("mmr requires exactly 2 arguments".into()) } if line_split.len() != 3 {
return Err("mmr requires exactly 2 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of mmr must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of mmr must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let address: u16 = parse_int::parse(line_split[2])?; let address: u16 = parse_int::parse(line_split[2])?;
@ -373,21 +411,25 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = self.ram[address as usize], Register::RD => self.rd = self.ram[address as usize],
Register::RE => self.re = self.ram[address as usize], Register::RE => self.re = self.ram[address as usize],
Register::PC => self.pc = self.ram[address as usize] as u16, Register::PC => self.pc = self.ram[address as usize] as u16,
Register::FLG => self.flg = self.ram[address as usize] Register::FLG => self.flg = self.ram[address as usize],
} }
Ok(mmr(dest, address)) Ok(mmr(dest, address))
}, }
"mrm" => { "mrm" => {
if line_split.len() != 3 { return Err("mrm requires exactly 2 arguments".into()) } if line_split.len() != 3 {
return Err("mrm requires exactly 2 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of mrm must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of mrm must end in , ".into());
}
let src = line_split[2]; let src = line_split[2];
let src = to_reg(src)?; let src = to_reg(src)?;
let address: u16 = parse_int::parse(&line_split[1][..line_split[1].len()-1])?; let address: u16 = parse_int::parse(&line_split[1][..line_split[1].len() - 1])?;
match src { match src {
Register::R0 => self.ram[address as usize] = self.r0, Register::R0 => self.ram[address as usize] = self.r0,
@ -397,39 +439,51 @@ impl SimpleAssemblySimulator {
Register::RD => self.ram[address as usize] = self.rd, Register::RD => self.ram[address as usize] = self.rd,
Register::RE => self.ram[address as usize] = self.re, Register::RE => self.ram[address as usize] = self.re,
Register::PC => self.ram[address as usize] = self.pc.try_into().unwrap(), Register::PC => self.ram[address as usize] = self.pc.try_into().unwrap(),
Register::FLG => self.ram[address as usize] = self.flg Register::FLG => self.ram[address as usize] = self.flg,
} }
Ok(mrm(src, address)) Ok(mrm(src, address))
}, }
"in" => { "in" => {
if line_split.len() != 3 { return Err("in requires exactly 2 arguments".into()) } if line_split.len() != 3 {
return Err("in requires exactly 2 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of in must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of in must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let port: u8 = parse_int::parse(line_split[2])?; let port: u8 = parse_int::parse(line_split[2])?;
Ok(r#in(dest, port)) Ok(r#in(dest, port))
}, }
"out" => { "out" => {
if line_split.len() != 3 { return Err("in requires exactly 2 arguments".into()) } if line_split.len() != 3 {
return Err("in requires exactly 2 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of in must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of in must end in , ".into());
}
let src = line_split[2]; let src = line_split[2];
let src = to_reg(src)?; let src = to_reg(src)?;
let port: u8 = parse_int::parse(&line_split[1][..line_split[1].len()-1])?; let port: u8 = parse_int::parse(&line_split[1][..line_split[1].len() - 1])?;
Ok(out(src, port)) Ok(out(src, port))
}, }
"rmmr" => { "rmmr" => {
if line_split.len() != 3 { return Err("rmmr requires exactly 2 arguments".into()) } if line_split.len() != 3 {
return Err("rmmr requires exactly 2 arguments".into());
}
let dest = line_split[1]; let dest = line_split[1];
if !dest.ends_with(',') { return Err("1st argument of rmmr must end in , ".into()) } if !dest.ends_with(',') {
return Err("1st argument of rmmr must end in , ".into());
}
let dest = to_reg(&dest[..dest.len() - 1])?; let dest = to_reg(&dest[..dest.len() - 1])?;
let address: u16 = parse_int::parse(line_split[2])?; let address: u16 = parse_int::parse(line_split[2])?;
@ -441,12 +495,12 @@ impl SimpleAssemblySimulator {
Register::RD => self.rd = self.ram[address as usize], Register::RD => self.rd = self.ram[address as usize],
Register::RE => self.re = self.ram[address as usize], Register::RE => self.re = self.ram[address as usize],
Register::PC => self.pc = self.ram[address as usize] as u16, Register::PC => self.pc = self.ram[address as usize] as u16,
Register::FLG => self.flg = self.ram[address as usize] Register::FLG => self.flg = self.ram[address as usize],
} }
Ok(rmmr(dest, address)) Ok(rmmr(dest, address))
} }
_ => Err(format!("Unknown instruction {}", line_split[0]).into()) _ => Err(format!("Unknown instruction {}", line_split[0]).into()),
} }
} }
} }
@ -461,6 +515,6 @@ fn to_reg(s: &str) -> Result<Register, Box<dyn Error>> {
"re" => Ok(Register::RE), "re" => Ok(Register::RE),
"pc" => Ok(Register::PC), "pc" => Ok(Register::PC),
"flg" => Ok(Register::FLG), "flg" => Ok(Register::FLG),
_ => Err(format!("Unknown register {}", s).into()) _ => Err(format!("Unknown register {}", s).into()),
} }
} }

View file

@ -14,7 +14,9 @@ pub fn preprocess(normalized: String) -> Result<String, Box<dyn Error>> {
} }
if !line_comments_removed.is_empty() { if !line_comments_removed.is_empty() {
processed += line_comments_removed.trim_start_matches(' ').trim_end_matches(' '); processed += line_comments_removed
.trim_start_matches(' ')
.trim_end_matches(' ');
processed += "\n"; processed += "\n";
} }
} }