452 lines
20 KiB
Rust
452 lines
20 KiB
Rust
use crate::{Machine, MEMORY};
|
|
use image::io::Reader;
|
|
use image::png::PngDecoder;
|
|
use image::GenericImageView;
|
|
use std::collections::HashMap;
|
|
use std::fs::read_to_string;
|
|
|
|
pub struct ImageAssembler {
|
|
memory: Vec<u32>,
|
|
ptr: usize,
|
|
labels: HashMap<String, usize>,
|
|
}
|
|
|
|
impl ImageAssembler {
|
|
pub fn new() -> ImageAssembler {
|
|
ImageAssembler {
|
|
memory: vec![0; MEMORY],
|
|
ptr: 0,
|
|
labels: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
pub fn extract(self) -> Machine {
|
|
let mut machine = Machine::new();
|
|
machine.memory = self.memory;
|
|
return machine;
|
|
}
|
|
|
|
pub fn assemble(&mut self, filename: &str) {
|
|
let asm = read_to_string(filename).unwrap_or_default();
|
|
let lines = asm.split('\n');
|
|
for line in lines {
|
|
let parts = line.split_once(';');
|
|
|
|
let mut command = match parts {
|
|
Some((command, _comment)) => command.trim(),
|
|
_ => line.trim(),
|
|
};
|
|
|
|
if command.starts_with("data") {
|
|
command = line.trim();
|
|
}
|
|
|
|
let command_parts = command.split_whitespace().collect::<Vec<&str>>();
|
|
|
|
if command_parts.is_empty() {
|
|
continue;
|
|
}
|
|
|
|
if command_parts.len() == 1 {
|
|
match command_parts[0] {
|
|
"meta" => {
|
|
println!("Headers + Imports Stop at {:x}", self.ptr);
|
|
}
|
|
"nop" => {
|
|
self.memory[self.ptr] = 0x00000000;
|
|
self.ptr += 1;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
}
|
|
"ret" => {
|
|
self.memory[self.ptr] = 0xC0000000;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"hlt" => {
|
|
self.memory[self.ptr] = 0x0F000000;
|
|
self.ptr += 1;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
}
|
|
"clr" => {
|
|
self.memory[self.ptr] = 0x04000000;
|
|
self.ptr += 1;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
}
|
|
"updsp" => {
|
|
self.memory[self.ptr] = 0x01000000;
|
|
self.ptr += 1;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
}
|
|
_ => {
|
|
let data = self.parse_addr(command_parts[0]);
|
|
self.memory[self.ptr] = data;
|
|
self.ptr += 1;
|
|
}
|
|
}
|
|
} else if command_parts.len() == 2 && command_parts[0] != "data" {
|
|
match command_parts[0] {
|
|
"label" => {
|
|
self.labels
|
|
.insert(command_parts[1].replace(":", ""), self.ptr);
|
|
}
|
|
"@" => {
|
|
self.ptr = self.parse_addr(command_parts[1]) as usize;
|
|
println!("Setting addr to ${:X}", self.ptr);
|
|
}
|
|
"inc" => {
|
|
let num = self.parse_addr(command_parts[1]);
|
|
let inst = 0x40 + num;
|
|
self.memory[self.ptr] = inst << 24;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"dec" => {
|
|
let num = self.parse_addr(command_parts[1]);
|
|
let inst = 0x50 + num;
|
|
self.memory[self.ptr] = inst << 24;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"jmp" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xE0000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"jeq" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xE1000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"jneq" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xE2000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"jlt" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xE4000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"jgt" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xE3000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"call" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xC1000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"bzero" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xB0000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"ijmp" => {
|
|
let addr = self.parse_addr(command_parts[1]);
|
|
self.memory[self.ptr] = 0xEF000000 + addr;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"import" => {
|
|
self.assemble(command_parts[1]);
|
|
}
|
|
_ => {
|
|
panic!("Unknown Instruction: {:?}", command_parts)
|
|
}
|
|
}
|
|
} else if command_parts.len() == 3 && command_parts[0] != "data" {
|
|
match command_parts[0] {
|
|
"rload" => {
|
|
// Load Immediate
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0x70 + target_reg) << 24;
|
|
let imm = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + imm;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"loadi" => {
|
|
// Load Immediate
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0x30 + target_reg) << 24;
|
|
let imm = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + imm;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"load" => {
|
|
// Load Immediate
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0x20 + target_reg) << 24;
|
|
let reg = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"store" => {
|
|
// Load Immediate
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0x10 + target_reg) << 24;
|
|
let reg = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"rstore" => {
|
|
// Load Immediate
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0x60 + target_reg) << 24;
|
|
let reg = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"tx" => {
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0x80 + target_reg) << 24;
|
|
let reg = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"bappend" => {
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0xB0 + target_reg) << 24;
|
|
let reg = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"bcopy" => {
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0xD0 + target_reg) << 24;
|
|
let reg = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"bdelete" => {
|
|
let target_reg = self.parse_addr(command_parts[1]);
|
|
let inst = (0x03 + target_reg) << 24;
|
|
let reg = self.parse_addr(command_parts[2]);
|
|
self.memory[self.ptr] = inst + reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
_ => {
|
|
panic!("unknown opcopde {}", command_parts[0])
|
|
}
|
|
}
|
|
} else if command_parts.len() == 4 && command_parts[0] != "data" {
|
|
// Every Instruction with 3 is [INST] [Source Reg] [Target Addr / Reg]
|
|
let a_reg = self.parse_addr(command_parts[1]);
|
|
let b_reg = self.parse_addr(command_parts[2]);
|
|
let result_reg = self.parse_addr(command_parts[3]);
|
|
match command_parts[0] {
|
|
"add" => {
|
|
self.memory[self.ptr] =
|
|
(0xa1 << 24) + (a_reg << 16) + (b_reg << 8) + result_reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"sub" => {
|
|
self.memory[self.ptr] =
|
|
(0xa2 << 24) + (a_reg << 16) + (b_reg << 8) + result_reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"mul" => {
|
|
self.memory[self.ptr] =
|
|
(0xa3 << 24) + (a_reg << 16) + (b_reg << 8) + result_reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"lshift" => {
|
|
self.memory[self.ptr] =
|
|
(0xa7 << 24) + (a_reg << 16) + (b_reg << 8) + result_reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"shift" => {
|
|
self.memory[self.ptr] =
|
|
(0xa5 << 24) + (a_reg << 16) + (b_reg << 8) + result_reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
"and" => {
|
|
self.memory[self.ptr] =
|
|
(0xa6 << 24) + (a_reg << 16) + (b_reg << 8) + result_reg;
|
|
println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]);
|
|
self.ptr += 1;
|
|
}
|
|
_ => {
|
|
panic!("Unknown Instruction: {:?}", command_parts)
|
|
}
|
|
}
|
|
} else {
|
|
match command_parts[0] {
|
|
"data" => match command_parts[1] {
|
|
"ascii" => {
|
|
self.labels
|
|
.insert(command_parts[2].replace(":", ""), self.ptr);
|
|
let data = command_parts
|
|
.iter()
|
|
.skip(3)
|
|
.map(|x| String::from(*x))
|
|
.collect::<Vec<String>>()
|
|
.join(" ");
|
|
for char in data.chars() {
|
|
self.memory[self.ptr] = char as u32;
|
|
self.ptr += 1;
|
|
}
|
|
self.memory[self.ptr] = 0x00;
|
|
self.ptr += 1;
|
|
}
|
|
"image" => {
|
|
if command_parts.len() != 4 {
|
|
panic!("data buffer label len")
|
|
}
|
|
self.labels
|
|
.insert(command_parts[2].replace(":", ""), self.ptr);
|
|
let img = Reader::open(command_parts[3]).unwrap().decode().unwrap();
|
|
self.memory[self.ptr] = img.width();
|
|
self.ptr += 1;
|
|
self.memory[self.ptr] = img.height();
|
|
self.ptr += 1;
|
|
for h in 0..img.height() {
|
|
for w in 0..img.width() {
|
|
let pixel = img.get_pixel(w, h).0;
|
|
let a = (pixel[3] as u32) << 24;
|
|
let r = (pixel[0] as u32) << 16;
|
|
let g = (pixel[1] as u32) << 8;
|
|
let b = (pixel[2] as u32);
|
|
self.memory[self.ptr] = a + r + g + b;
|
|
self.ptr += 1;
|
|
}
|
|
}
|
|
self.memory[self.ptr] = 0x00;
|
|
self.ptr += 1;
|
|
}
|
|
"buffer" => {
|
|
if command_parts.len() != 4 {
|
|
panic!("data buffer label len")
|
|
}
|
|
self.labels
|
|
.insert(command_parts[2].replace(":", ""), self.ptr);
|
|
let len = command_parts[3].parse().unwrap_or_default();
|
|
self.memory[self.ptr] = len;
|
|
self.ptr += 1;
|
|
self.memory[self.ptr] = 0x00;
|
|
self.ptr += 1;
|
|
// Pad with 0's
|
|
for i in 0..=len {
|
|
self.memory[self.ptr] = 0x00;
|
|
self.ptr += 1
|
|
}
|
|
}
|
|
"buffers" => {
|
|
if command_parts.len() != 5 {
|
|
panic!("data buffers length label buffer_len")
|
|
}
|
|
|
|
let len = command_parts[2].parse().unwrap_or_default();
|
|
let buffer_len = command_parts[4].parse().unwrap_or_default();
|
|
for i in 0..len {
|
|
self.labels.insert(
|
|
format!("{}[{}]", command_parts[3].replace(":", ""), i),
|
|
self.ptr,
|
|
);
|
|
self.memory[self.ptr] = buffer_len;
|
|
self.ptr += 1;
|
|
self.memory[self.ptr] = 0x00;
|
|
self.ptr += 1;
|
|
// Pad with 0's
|
|
for _x in 0..=buffer_len {
|
|
self.memory[self.ptr] = 0x00;
|
|
self.ptr += 1
|
|
}
|
|
}
|
|
}
|
|
"ptr" => {
|
|
if command_parts.len() != 4 {
|
|
panic!("data ptr label init")
|
|
}
|
|
self.labels
|
|
.insert(command_parts[2].replace(":", ""), self.ptr);
|
|
self.memory[self.ptr] = self.parse_addr(command_parts[3]);
|
|
self.ptr += 1;
|
|
}
|
|
_ => {
|
|
panic!("unknown type {}", command_parts[1])
|
|
}
|
|
},
|
|
_ => {
|
|
panic!("unknown command {}", command_parts[0])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn parse_addr(&self, input: &str) -> u32 {
|
|
if input.starts_with('@') {
|
|
match self.labels.get(input.replace("@", "").as_str()) {
|
|
Some(addr) => {
|
|
return addr.clone() as u32 + 2;
|
|
}
|
|
None => {}
|
|
}
|
|
}
|
|
|
|
if input.starts_with('+') {
|
|
match usize::from_str_radix(input.replace("+", "").as_str(), 10) {
|
|
Ok(offeset) => {
|
|
return (self.ptr + offeset) as u32;
|
|
}
|
|
_ => {
|
|
panic!("Not a Relative Address {:?}", input)
|
|
}
|
|
}
|
|
}
|
|
|
|
match u32::from_str_radix(input.replace("$", "").replace(":", "").as_str(), 16) {
|
|
Ok(addr) => {
|
|
return addr;
|
|
}
|
|
_ => match input.split_once("+") {
|
|
Some((input, offset)) => match self.labels.get(input) {
|
|
Some(addr) => {
|
|
match usize::from_str_radix(offset.replace("+", "").as_str(), 10) {
|
|
Ok(offset) => {
|
|
return addr.clone() as u32 + offset as u32;
|
|
}
|
|
_ => {
|
|
panic!("Not a Hex Encoded Address {:?}", input)
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
panic!("Not a Hex Encoded Address {:?}", input)
|
|
}
|
|
},
|
|
_ => match self.labels.get(input) {
|
|
Some(addr) => {
|
|
return addr.clone() as u32;
|
|
}
|
|
_ => {
|
|
panic!("Not a Hex Encoded Address {:?}", input)
|
|
}
|
|
},
|
|
},
|
|
}
|
|
}
|
|
}
|