cc! assembler and examples
This commit is contained in:
parent
6c1cf0f620
commit
596254394f
7 changed files with 298 additions and 169 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
12
src/main.rs
12
src/main.rs
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
175
src/ops.rs
175
src/ops.rs
|
@ -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]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue