From cdd8206756b9aede2f972b211da08f1489446525 Mon Sep 17 00:00:00 2001 From: Isabelle L Date: Sun, 21 Jun 2020 16:10:23 -0500 Subject: [PATCH] lots of work on ceres-asm (not working yet) --- Cargo.lock | 13 +-- README.md | 17 +++- ceres-asm/Cargo.toml | 1 + ceres-asm/src/lib.rs | 205 ++++++++++++++++++++++++++++++++++++----- ceres-sys/src/video.rs | 10 ++ justfile | 10 ++ src/main.rs | 38 +++----- test.asm | 7 +- 8 files changed, 243 insertions(+), 58 deletions(-) create mode 100644 justfile diff --git a/Cargo.lock b/Cargo.lock index 2e8ba37..de3cb2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,7 @@ name = "ceres-asm" version = "0.1.0" dependencies = [ "logos 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -428,7 +429,7 @@ version = "0.1.0" dependencies = [ "image 0.23.5 (registry+https://github.com/rust-lang/crates.io-index)", "minifb 0.16.0 (git+https://github.com/emoon/rust_minifb)", - "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -829,15 +830,15 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1109,8 +1110,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344" -"checksum thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" +"checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" +"checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" "checksum tiff 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f3b8a87c4da944c3f27e5943289171ac71a6150a79ff6bacfff06d159dfff2f" "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" diff --git a/README.md b/README.md index 3d6ee60..2fdb97b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ a shitty fantasy console written in rust using a proprietary MIPS based asm instruction set. a lot of inspiration from PICO-8. ceres is structured of these crates: - ceres-sys: the core system structure of ceres-16 +- ceres-asm: the assembler for ceres-16 ### Graphics @@ -24,4 +25,18 @@ all registers are unsigned 16 bit ### Memory map and info -god oh fuck what am i even doing \ No newline at end of file +god oh fuck what am i even doing + +### instructions + +##### load - ld:signifier + +can be vram/cram/imed + +- immediate `ld:immd $dest immediate` + + | opcode | signifier | destination | padding | immediate | + | ------- | --------- | ----------- | ------- | ------------------ | + | `00001` | `100` | `0000` | `0000` | `0000000000000000` | + + \ No newline at end of file diff --git a/ceres-asm/Cargo.toml b/ceres-asm/Cargo.toml index cacfe2e..d619ad7 100644 --- a/ceres-asm/Cargo.toml +++ b/ceres-asm/Cargo.toml @@ -8,3 +8,4 @@ edition = "2018" [dependencies] logos = "0.11.4" +thiserror = "1.0.20" diff --git a/ceres-asm/src/lib.rs b/ceres-asm/src/lib.rs index 9688617..3bff54d 100644 --- a/ceres-asm/src/lib.rs +++ b/ceres-asm/src/lib.rs @@ -1,14 +1,107 @@ -use logos::Logos; +// izzy do not forget to remove these later dummy +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(unused_variables)] +// namespacing +use logos::{Lexer, Logos}; + +/// ceres-asm result type +pub type Result = std::result::Result; + +/// ceres-asm error type +#[derive(Debug, thiserror::Error)] +pub enum CeresAsmError { + #[error("wrong token found:\nexpected: {expected:?}\n found: {found:?}")] + BadToken { expected: Token, found: Token }, + #[error("bad token: {token:?}")] + LazyBadToken { token: Token }, + #[error("was looking for token, found nothing ???")] + NoToken, +} + +/// assembler struct +pub struct Assembler<'a> { + lexer: Lexer<'a, Token>, +} + +impl<'a> Assembler<'a> { + /// create a new assembler + pub fn new(data: &'a str) -> Assembler<'a> { + let lexer = Token::lexer(data); + Assembler { lexer } + } + + /// assemble + pub fn assemble(&mut self) -> Result> { + let mut machine_code: Vec = Vec::new(); + + while let Some(token) = self.lexer.next() { + match token { + // cases that should continue + Token::Comment => continue, + Token::Newline => continue, + // cases that like, actually make sense to process + Token::Load => { + if let Some(new_token) = self.lexer.next() { + let signifier = Signifier::from_token(new_token)?; + machine_code.push(self.load(signifier)?); + } else { + return Err(CeresAsmError::NoToken); + } + } + // cases that should straight up not happen + _ => return Err(CeresAsmError::LazyBadToken { token }), + } + } + + Ok(machine_code) + } + + // load instruction assembly + fn load(&mut self, signifier: Signifier) -> Result { + let opcode: u32 = 0b00001; + let signifier: u32 = signifier.as_bits() as u32; + let instruction: u32 = (opcode << 27) | (signifier << 24); + Ok(instruction) + } +} + +enum Signifier { + VideoMemory, + CartMemory, + Immediate, +} + +impl Signifier { + fn from_token(token: Token) -> Result { + match token { + Token::VideoMemory => Ok(Self::VideoMemory), + Token::CartMemory => Ok(Self::CartMemory), + Token::Immediate => Ok(Self::Immediate), + _ => Err(CeresAsmError::LazyBadToken { token }), + } + } + + // returns the signifier as bits stored in a u8 + fn as_bits(self) -> u8 { + match self { + Self::VideoMemory => 0b010, + Self::CartMemory => 0b001, + Self::Immediate => 0b100, + } + } +} + +/// token #[derive(Logos, Debug, PartialEq)] pub enum Token { // general stuff #[regex(";.+")] Comment, - #[token("@")] - At, - #[regex("/[a-z-_]+:/g")] - Label, + #[token("\n")] + Newline, + // registers #[token("$t0")] ZeroRegister, @@ -25,13 +118,21 @@ pub enum Token { #[token("$a2")] ArgumentTwo, #[token("$v0")] - ReturnOne, + ReturnZero, #[token("$v1")] - ReturnTwo, - #[regex("\\$t[0-6]")] - TemoraryRegister, - #[regex("\\$[0-9]+")] - RegisterIndex, + ReturnOne, + #[regex("\\$t[0-6]", |lex| lex.slice()[2..].parse::())] + TemporaryRegister(u16), + #[regex("\\$[0-9]+", |lex| lex.slice()[1..].parse::())] + RegisterIndex(u16), + + // types + #[token("immd")] + Immediate, + #[token("vram")] + VideoMemory, + #[token("cram")] + CartMemory, // literals #[regex("0x[a-fA-F0-9]+", |lex| u16::from_str_radix(&lex.slice()[2..], 16).unwrap() )] @@ -42,18 +143,80 @@ pub enum Token { DecimalLiteral(u16), // instructions - #[token("add")] - Add, - #[token("sub")] - Sub, - #[token("mul")] - Mul, - #[token("div")] - Div, - #[token("jmp")] - Jmp, + #[token("ld:")] + Load, // logos error #[error] + #[regex(" +", logos::skip)] Error, } + +impl Token { + // returns the token as a str + fn as_str(&self) -> String { + match self { + // general stuff + Self::Comment => "a comment".to_owned(), + Self::Newline => "\\n".to_owned(), + // registers + Self::ZeroRegister => "$z0".to_owned(), + Self::ProgramCounter => "$pc".to_owned(), + Self::StackPointer => "$sp".to_owned(), + Self::ReturnAddress => "$ra".to_owned(), + Self::ArgumentZero => "$a0".to_owned(), + Self::ArgumentOne => "$z1".to_owned(), + Self::ArgumentTwo => "$a2".to_owned(), + Self::ReturnZero => "$v0".to_owned(), + Self::ReturnOne => "$v1".to_owned(), + Self::TemporaryRegister(idx) => format!("$t{}", idx), + Self::RegisterIndex(idx) => format!("${}", idx), + // types + Self::Immediate => "immd".to_owned(), + Self::VideoMemory => "vram".to_owned(), + Self::CartMemory => "cram".to_owned(), + // literals + Self::HexLiteral(_) => "hex lit".to_owned(), + Self::BinaryLiteral(_) => "bin lit".to_owned(), + Self::DecimalLiteral(_) => "dec lit".to_owned(), + // instructions + Self::Load => "ld:".to_owned(), + // errors + Self::Error => "ERR".to_owned(), + } + } + + // returns true if given token is a register + fn is_register(&self) -> bool { + match self { + Self::ZeroRegister + | Self::ProgramCounter + | Self::StackPointer + | Self::ReturnAddress + | Self::ArgumentZero + | Self::ArgumentOne + | Self::ArgumentTwo + | Self::ReturnZero + | Self::ReturnOne + | Self::TemporaryRegister(_) + | Self::RegisterIndex(_) => true, + _ => false, + } + } + + // returns true if given token is a literal + fn is_literal(&self) -> bool { + match self { + Self::HexLiteral(_) | Self::BinaryLiteral(_) | Self::DecimalLiteral(_) => true, + _ => false, + } + } + + // returns true if it's a valid memory location or immediate + fn is_signifier(&self) -> bool { + match self { + Self::VideoMemory | Self::CartMemory | Self::Immediate => true, + _ => false, + } + } +} diff --git a/ceres-sys/src/video.rs b/ceres-sys/src/video.rs index a833e90..ee9e7ea 100644 --- a/ceres-sys/src/video.rs +++ b/ceres-sys/src/video.rs @@ -8,6 +8,16 @@ impl VideoMemory { pub fn init() -> VideoMemory { VideoMemory { data: [0x0000; crate::VIDEO_MEMORY_LEN] } } + + /// an iterator + pub fn iter(&self) -> impl Iterator { + self.data.iter() + } + + /// mutable iterator + pub fn iter_mut(&mut self) -> impl Iterator { + self.data.iter_mut() + } } impl std::ops::Index for VideoMemory { diff --git a/justfile b/justfile new file mode 100644 index 0000000..5f40da1 --- /dev/null +++ b/justfile @@ -0,0 +1,10 @@ +alias r := run +alias b := build + +build: + clear + cargo build + +run: + clear + cargo run diff --git a/src/main.rs b/src/main.rs index 19735ee..ade010a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,12 +6,18 @@ use structopt::StructOpt; struct Opt { /// times the screen should be scaled by #[structopt(short = "s", long = "scale", default_value = "4")] - scale_factor: usize, + _scale_factor: usize, } fn wrapper() -> Result<()> { - let opt = Opt::from_args(); + // load options + let _opt = Opt::from_args(); + // initialize the system + let _sys = ceres_sys::System::init(); + + /* + // create a new graphics context let mut ctx = offbrand::Context::new( ceres_sys::SCREEN_WIDTH, ceres_sys::SCREEN_HEIGHT, @@ -19,25 +25,12 @@ fn wrapper() -> Result<()> { Some(opt.scale_factor), )?; - let mut sys = ceres_sys::System::init(); - - let mut colors: Vec = Vec::new(); - - for r in 0x0..0xf { - for g in 0x0..0xf { - for b in 0x0..0xf { - colors.push((r << 8) | (g << 4) | b); - } - } - } - - colors.iter().enumerate().for_each(|(addr, color)| { - sys.video_memory[addr as u16] = *color; - }); - + // loop while the context window is open while ctx.is_open() { + // clear the context ctx.clear(None); + // print a pixel for ever word in the video memory buffer for x in 0..ceres_sys::SCREEN_WIDTH { for y in 0..ceres_sys::SCREEN_HEIGHT { let color = @@ -46,19 +39,14 @@ fn wrapper() -> Result<()> { } } + // render the context ctx.present()?; } + */ Ok(()) } -fn color_from_u16(color: u16) -> Color { - let r = (((color >> 8) & 0x000f) as u8) * 17; - let g = (((color >> 4) & 0x000f) as u8) * 17; - let b = ((color & 0x000f) as u8) * 17; - Color { r, g, b } -} - fn main() { if let Err(err) = wrapper() { eprintln!("error: {:?}", err); diff --git a/test.asm b/test.asm index 61f4257..8795a95 100644 --- a/test.asm +++ b/test.asm @@ -1,5 +1,2 @@ -; a simple test application -main: - load $t0 0xcccc - load $t1 0xaaaa - sub $t0 $t1 $t3 \ No newline at end of file +; a simple test +ld:immd $t0 0x5a5a