boo-os/src/assembler.rs

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)
}
},
},
}
}
}