Compare commits
4 Commits
d5de189af6
...
d19c4e5bea
Author | SHA1 | Date |
---|---|---|
Ondřej Hruška | d19c4e5bea | 4 years ago |
Ondřej Hruška | b7345144e0 | 4 years ago |
Ondřej Hruška | 2269d759c6 | 4 years ago |
Ondřej Hruška | 3599cb46c4 | 4 years ago |
@ -1,6 +1,27 @@ |
||||
pub use parse::ArithOps; |
||||
use crsn::module::{CrsnExtension, ParseOpRes}; |
||||
use crsn::asm::parse::arg_parser::ArgParser; |
||||
use crsn::asm::error::CrsnError; |
||||
use crsn::asm::instr::Op; |
||||
|
||||
mod defs; |
||||
mod parse; |
||||
mod exec; |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct ArithOps; |
||||
|
||||
impl ArithOps { |
||||
pub fn new() -> Box<dyn CrsnExtension> { |
||||
Box::new(Self) |
||||
} |
||||
} |
||||
|
||||
impl CrsnExtension for ArithOps { |
||||
fn name(&self) -> &'static str { |
||||
"arith" |
||||
} |
||||
|
||||
fn parse_op(&self, keyword: &str, args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||
parse::parse(keyword, args) |
||||
} |
||||
} |
||||
|
@ -1,455 +1,437 @@ |
||||
use crsn::asm::data::{Rd, Wr}; |
||||
use crsn::asm::error::Error; |
||||
use crsn::asm::error::CrsnError; |
||||
use crsn::asm::instr::Op; |
||||
use crsn::asm::parse::arg_parser::ArgParser; |
||||
use crsn::module::{CrsnExtension, ParseOpRes}; |
||||
use crsn::module::{ParseOpRes}; |
||||
|
||||
use crate::defs::ArithOp; |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct ArithOps { |
||||
_internal: () |
||||
} |
||||
|
||||
impl ArithOps { |
||||
pub fn new() -> Box<dyn CrsnExtension> { |
||||
Box::new(Self { |
||||
_internal: () |
||||
}) |
||||
} |
||||
} |
||||
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||
Ok(ParseOpRes::ext(match keyword { |
||||
"cmp" => { |
||||
ArithOp::Compare { |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
|
||||
impl CrsnExtension for ArithOps { |
||||
fn name(&self) -> &'static str { |
||||
"arith" |
||||
} |
||||
"tst" => { |
||||
let arg = args.next_rd()?; |
||||
ArithOp::Test { a: arg } |
||||
} |
||||
|
||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes, Error> { |
||||
Ok(ParseOpRes::Parsed(Op::Ext(Box::new(match keyword { |
||||
"cmp" => { |
||||
ArithOp::Compare { |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
"inc" => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Add { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: Rd::immediate(1), |
||||
} |
||||
} |
||||
|
||||
"tst" => { |
||||
let arg = args.next_rd()?; |
||||
ArithOp::Test { a: arg } |
||||
"dec" => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Sub { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: Rd::immediate(1), |
||||
} |
||||
} |
||||
|
||||
"inc" => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Add { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: Rd::immediate(1), |
||||
"add" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Add { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
} |
||||
|
||||
"dec" => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Sub { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: Rd::immediate(1), |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Add { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"add" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Add { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Add { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Add requires 2 or 3 arguments".into())); |
||||
"sub" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Sub { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Sub { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"sub" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Sub { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Sub { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Sub requires 2 or 3 arguments".into())); |
||||
"mul" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Mul { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Mul { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"mul" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Mul { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Mul { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Mul requires 2 or 3 arguments".into())); |
||||
"divr" => { |
||||
match args.len() { |
||||
3 => { |
||||
let dst = args.next_wr()?; |
||||
let rem = args.next_wr()?; |
||||
let div = args.next_rd()?; |
||||
ArithOp::Div { |
||||
dst, |
||||
rem, |
||||
a: dst.as_rd(), |
||||
div, |
||||
} |
||||
} |
||||
4 => { |
||||
ArithOp::Div { |
||||
dst: args.next_wr()?, |
||||
rem: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
div: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("DivR requires 3 or 4 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"divr" => { |
||||
match args.len() { |
||||
3 => { |
||||
let dst = args.next_wr()?; |
||||
let rem = args.next_wr()?; |
||||
let div = args.next_rd()?; |
||||
ArithOp::Div { |
||||
dst, |
||||
rem, |
||||
a: dst.as_rd(), |
||||
div, |
||||
} |
||||
} |
||||
4 => { |
||||
ArithOp::Div { |
||||
dst: args.next_wr()?, |
||||
rem: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
div: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("DivR requires 3 or 4 arguments".into())); |
||||
"div" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Div { |
||||
dst: args.next_wr()?, |
||||
rem: Wr::discard(), |
||||
a: args.next_rd()?, |
||||
div: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
let div = args.next_rd()?; |
||||
ArithOp::Div { |
||||
dst, |
||||
rem: Wr::discard(), |
||||
a: dst.as_rd(), |
||||
div, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"div" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Div { |
||||
dst: args.next_wr()?, |
||||
rem: Wr::discard(), |
||||
a: args.next_rd()?, |
||||
div: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
let div = args.next_rd()?; |
||||
ArithOp::Div { |
||||
dst, |
||||
rem: Wr::discard(), |
||||
a: dst.as_rd(), |
||||
div, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Div requires 2 or 3 arguments".into())); |
||||
"mod" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Mod { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
div: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
let div = args.next_rd()?; |
||||
ArithOp::Mod { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
div, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"mod" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Mod { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
div: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
let div = args.next_rd()?; |
||||
ArithOp::Mod { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
div, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Mod requires 2 or 3 arguments".into())); |
||||
"and" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::And { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::And { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("And requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"and" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::And { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::And { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("And requires 2 or 3 arguments".into())); |
||||
"or" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Or { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Or { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"or" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Or { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Or { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Or requires 2 or 3 arguments".into())); |
||||
"xor" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Xor { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Xor { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"xor" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Xor { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Xor { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
b: args.next_rd()?, |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Xor requires 2 or 3 arguments".into())); |
||||
"cpl" => { |
||||
match args.len() { |
||||
2 => { |
||||
ArithOp::Cpl { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Cpl { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"cpl" => { |
||||
match args.len() { |
||||
2 => { |
||||
ArithOp::Cpl { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
} |
||||
"rol" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Rol { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Cpl { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Rol { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Cpl requires 1 or 2 arguments".into())); |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Rol { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"rol" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Rol { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Rol { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Rol { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Rol requires 1, 2 or 3 arguments".into())); |
||||
"ror" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Ror { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
} |
||||
|
||||
"ror" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Ror { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Ror { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Ror { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Ror requires 1, 2 or 3 arguments".into())); |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Ror { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Ror { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"lsl" | "asl" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Lsl { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsl { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsl { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Lsl requires 1, 2 or 3 arguments".into())); |
||||
"lsl" | "asl" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Lsl { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsl { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsl { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"lsr" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Lsr { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Lsr requires 1, 2 or 3 arguments".into())); |
||||
"lsr" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Lsr { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Lsr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
"asr" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Asr { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Asr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Asr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(Error::Parse("Asr requires 1, 2 or 3 arguments".into())); |
||||
"asr" => { |
||||
match args.len() { |
||||
3 => { |
||||
ArithOp::Asr { |
||||
dst: args.next_wr()?, |
||||
a: args.next_rd()?, |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
2 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Asr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: args.next_rd()?, |
||||
} |
||||
} |
||||
1 => { |
||||
let dst = args.next_wr()?; |
||||
ArithOp::Asr { |
||||
dst, |
||||
a: dst.as_rd(), |
||||
n: Rd::immediate(1), |
||||
} |
||||
} |
||||
_ => { |
||||
return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
_other => { |
||||
return Ok(ParseOpRes::Unknown(args)); |
||||
} |
||||
})))) |
||||
} |
||||
_other => { |
||||
return Ok(ParseOpRes::Unknown(args)); |
||||
} |
||||
})) |
||||
} |
||||
|
||||
|
@ -0,0 +1,13 @@ |
||||
[package] |
||||
name = "crsn_screen" |
||||
version = "0.1.0" |
||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"] |
||||
edition = "2018" |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
|
||||
[dependencies] |
||||
crsn = { path = "../crsn" } |
||||
minifb = "0.19.1" |
||||
parking_lot = "0.11.0" |
||||
log = "0.4.11" |
@ -0,0 +1,14 @@ |
||||
use crsn::asm::data::{Rd, RdObj, Wr}; |
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)] |
||||
pub enum ScreenOp { |
||||
ScreenInit { |
||||
width: Rd, |
||||
height: Rd, |
||||
}, |
||||
SetPixel { |
||||
x: Rd, |
||||
y: Rd, |
||||
color: Rd, |
||||
} |
||||
} |
@ -0,0 +1,99 @@ |
||||
use std::collections::{HashMap, VecDeque}; |
||||
|
||||
use crsn::asm::data::literal::Value; |
||||
use crsn::asm::instr::Cond; |
||||
use crsn::module::{CrsnExtension, EvalRes, OpTrait}; |
||||
use crsn::runtime::fault::Fault; |
||||
use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; |
||||
|
||||
use crate::defs::ScreenOp; |
||||
use minifb::{Window, WindowOptions, ScaleMode}; |
||||
use parking_lot::Mutex; |
||||
use std::sync::Arc; |
||||
|
||||
#[derive(Debug, Default)] |
||||
struct Backend { |
||||
width: usize, |
||||
height: usize, |
||||
buffer: Vec<u32>, |
||||
window: Option<Window>, |
||||
} |
||||
|
||||
// Hack for Window
|
||||
unsafe impl std::marker::Send for Backend { } |
||||
|
||||
impl OpTrait for ScreenOp { |
||||
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> { |
||||
let eres = EvalRes::default(); |
||||
match self { |
||||
ScreenOp::ScreenInit { width, height } => { |
||||
let w = state.read(*width)?; |
||||
let h = state.read(*height)?; |
||||
init(state, w, h)?; |
||||
} |
||||
ScreenOp::SetPixel { x, y, color } => { |
||||
let x = state.read(*x)?; |
||||
let y = state.read(*y)?; |
||||
let color = state.read(*color)?; |
||||
|
||||
let backend : &mut Backend = state.ext_mut(); |
||||
match &mut backend.window { |
||||
Some(w) => { |
||||
let index = y * backend.width as u64 + x; |
||||
if index as usize > backend.buffer.len() { |
||||
warn!("Screen set pixel out of bounds"); |
||||
state.set_flag(Cond::Invalid, true); |
||||
} else { |
||||
backend.buffer[index as usize] = color as u32; |
||||
|
||||
w |
||||
.update_with_buffer(&backend.buffer, backend.width, backend.height) |
||||
.expect("Update screen"); // TODO fault
|
||||
} |
||||
} |
||||
None => { |
||||
state.set_flag(Cond::Invalid, true); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
Ok(eres) |
||||
} |
||||
//
|
||||
} |
||||
|
||||
fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault> { |
||||
let mut window = Window::new( |
||||
"Croissant", |
||||
width as usize, |
||||
height as usize, |
||||
WindowOptions { |
||||
resize: true, |
||||
scale_mode: ScaleMode::AspectRatioStretch, |
||||
..WindowOptions::default() |
||||
}, |
||||
).expect("Unable to create window"); // TODO fault
|
||||
|
||||
|
||||
let backend : &mut Backend = state.ext_mut(); |
||||
|
||||
if backend.window.is_some() { |
||||
return Err(Fault::NotAllowed("Screen already initialized".into())); |
||||
} |
||||
|
||||
backend.width = width as usize; |
||||
backend.height = height as usize; |
||||
backend.buffer = vec![0; (width * height) as usize]; |
||||
|
||||
// window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
|
||||
window.limit_update_rate(None); |
||||
|
||||
window |
||||
.update_with_buffer(&backend.buffer, backend.width, backend.height) |
||||
.expect("Update screen"); // TODO fault
|
||||
|
||||
backend.window = Some(window); |
||||
|
||||
Ok(()) |
||||
} |
@ -0,0 +1,30 @@ |
||||
#[macro_use] |
||||
extern crate log; |
||||
|
||||
use crsn::module::{CrsnExtension, ParseOpRes}; |
||||
use crsn::asm::parse::arg_parser::ArgParser; |
||||
use crsn::asm::instr::Op; |
||||
use crsn::asm::error::CrsnError; |
||||
|
||||
mod defs; |
||||
mod parse; |
||||
mod exec; |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct ScreenOps; |
||||
|
||||
impl ScreenOps { |
||||
pub fn new() -> Box<dyn CrsnExtension> { |
||||
Box::new(Self) |
||||
} |
||||
} |
||||
|
||||
impl CrsnExtension for ScreenOps { |
||||
fn name(&self) -> &'static str { |
||||
"screen" |
||||
} |
||||
|
||||
fn parse_op(&self, keyword: &str, args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||
parse::parse(keyword, args) |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
|
||||
use crsn::asm::error::CrsnError; |
||||
use crsn::asm::instr::Op; |
||||
use crsn::asm::parse::arg_parser::ArgParser; |
||||
use crsn::module::{ParseOpRes}; |
||||
|
||||
use crate::defs::ScreenOp; |
||||
|
||||
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||
Ok(ParseOpRes::ext(match keyword { |
||||
"sc-init" => { |
||||
ScreenOp::ScreenInit { |
||||
width: args.next_rd()?, |
||||
height: args.next_rd()?, |
||||
} |
||||
} |
||||
|
||||
"sc-px" => { |
||||
ScreenOp::SetPixel { |
||||
x: args.next_rd()?, |
||||
y: args.next_rd()?, |
||||
color: args.next_rd()?, |
||||
} |
||||
} |
||||
|
||||
_other => { |
||||
return Ok(ParseOpRes::Unknown(args)); |
||||
} |
||||
})) |
||||
} |
@ -1,6 +1,34 @@ |
||||
pub use parse::StackOps; |
||||
use crsn::module::{CrsnExtension, ParseOpRes}; |
||||
use crsn::asm::parse::arg_parser::ArgParser; |
||||
use crsn::asm::instr::Op; |
||||
use crsn::asm::error::CrsnError; |
||||
use crsn::runtime::run_thread::{ThreadInfo, RunState}; |
||||
use crsn::asm::data::literal::Value; |
||||
use crsn::runtime::fault::Fault; |
||||
|
||||
mod defs; |
||||
mod parse; |
||||
mod exec; |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct StackOps; |
||||
|
||||
impl StackOps { |
||||
pub fn new() -> Box<dyn CrsnExtension> { |
||||
Box::new(Self) |
||||
} |
||||
} |
||||
|
||||
impl CrsnExtension for StackOps { |
||||
fn name(&self) -> &'static str { |
||||
"stacks" |
||||
} |
||||
|
||||
fn parse_op(&self, keyword: &str, args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||
parse::parse(keyword, args) |
||||
} |
||||
|
||||
fn drop_obj(&self, ti: &ThreadInfo, state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> { |
||||
exec::drop_obj(state, handle) |
||||
} |
||||
} |
||||
|
@ -1,61 +1,37 @@ |
||||
use crsn::asm::error::Error; |
||||
|
||||
use crsn::asm::error::CrsnError; |
||||
use crsn::asm::instr::Op; |
||||
use crsn::asm::parse::arg_parser::ArgParser; |
||||
use crsn::module::{CrsnExtension, ParseOpRes}; |
||||
use crsn::module::{ParseOpRes}; |
||||
|
||||
use crate::defs::StackOp; |
||||
use crsn::runtime::run_thread::{ThreadInfo, RunState}; |
||||
use crsn::asm::data::literal::Value; |
||||
use crsn::runtime::fault::Fault; |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct StackOps { |
||||
_internal: () |
||||
} |
||||
|
||||
impl StackOps { |
||||
pub fn new() -> Box<dyn CrsnExtension> { |
||||
Box::new(Self { |
||||
_internal: () |
||||
}) |
||||
} |
||||
} |
||||
|
||||
impl CrsnExtension for StackOps { |
||||
fn name(&self) -> &'static str { |
||||
"stacks" |
||||
} |
||||
|
||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes, Error> { |
||||
Ok(ParseOpRes::Parsed(Op::Ext(Box::new(match keyword { |
||||
"stack" => { |
||||
StackOp::NewStack { |
||||
dst: args.next_wr()?, |
||||
} |
||||
} |
||||
use crate::defs::StackOp; |
||||
|
||||
"push" => { |
||||
StackOp::Push { |
||||
obj: args.next_rdobj()?, |
||||
src: args.next_rd()?, |
||||
} |
||||
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||
Ok(ParseOpRes::ext(match keyword { |
||||
"stack" => { |
||||
StackOp::NewStack { |
||||
dst: args.next_wr()?, |
||||
} |
||||
} |
||||
|
||||
"pop" => { |
||||
StackOp::Pop { |
||||
dst: args.next_wr()?, |
||||
obj: args.next_rdobj()?, |
||||
} |
||||
"push" => { |
||||
StackOp::Push { |
||||
obj: args.next_rdobj()?, |
||||
src: args.next_rd()?, |
||||
} |
||||
} |
||||
|
||||
_other => { |
||||
return Ok(ParseOpRes::Unknown(args)); |
||||
"pop" => { |
||||
StackOp::Pop { |
||||
dst: args.next_wr()?, |
||||
obj: args.next_rdobj()?, |
||||
} |
||||
})))) |
||||
} |
||||
} |
||||
|
||||
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle : Value) -> Result<Option<()>, Fault> |
||||
{ |
||||
crate::exec::drop_stack(state, handle) |
||||
} |
||||
_other => { |
||||
return Ok(ParseOpRes::Unknown(args)); |
||||
} |
||||
})) |
||||
} |
||||
|
Loading…
Reference in new issue