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 defs; |
||||||
mod parse; |
mod parse; |
||||||
mod exec; |
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::data::{Rd, Wr}; |
||||||
use crsn::asm::error::Error; |
use crsn::asm::error::CrsnError; |
||||||
use crsn::asm::instr::Op; |
use crsn::asm::instr::Op; |
||||||
use crsn::asm::parse::arg_parser::ArgParser; |
use crsn::asm::parse::arg_parser::ArgParser; |
||||||
use crsn::module::{CrsnExtension, ParseOpRes}; |
use crsn::module::{ParseOpRes}; |
||||||
|
|
||||||
use crate::defs::ArithOp; |
use crate::defs::ArithOp; |
||||||
|
|
||||||
#[derive(Debug, Clone)] |
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||||
pub struct ArithOps { |
Ok(ParseOpRes::ext(match keyword { |
||||||
_internal: () |
"cmp" => { |
||||||
} |
ArithOp::Compare { |
||||||
|
a: args.next_rd()?, |
||||||
impl ArithOps { |
b: args.next_rd()?, |
||||||
pub fn new() -> Box<dyn CrsnExtension> { |
} |
||||||
Box::new(Self { |
} |
||||||
_internal: () |
|
||||||
}) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl CrsnExtension for ArithOps { |
"tst" => { |
||||||
fn name(&self) -> &'static str { |
let arg = args.next_rd()?; |
||||||
"arith" |
ArithOp::Test { a: arg } |
||||||
} |
} |
||||||
|
|
||||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes, Error> { |
"inc" => { |
||||||
Ok(ParseOpRes::Parsed(Op::Ext(Box::new(match keyword { |
let dst = args.next_wr()?; |
||||||
"cmp" => { |
ArithOp::Add { |
||||||
ArithOp::Compare { |
dst, |
||||||
a: args.next_rd()?, |
a: dst.as_rd(), |
||||||
b: args.next_rd()?, |
b: Rd::immediate(1), |
||||||
} |
|
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"tst" => { |
"dec" => { |
||||||
let arg = args.next_rd()?; |
let dst = args.next_wr()?; |
||||||
ArithOp::Test { a: arg } |
ArithOp::Sub { |
||||||
|
dst, |
||||||
|
a: dst.as_rd(), |
||||||
|
b: Rd::immediate(1), |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"inc" => { |
"add" => { |
||||||
let dst = args.next_wr()?; |
match args.len() { |
||||||
ArithOp::Add { |
3 => { |
||||||
dst, |
ArithOp::Add { |
||||||
a: dst.as_rd(), |
dst: args.next_wr()?, |
||||||
b: Rd::immediate(1), |
a: args.next_rd()?, |
||||||
|
b: args.next_rd()?, |
||||||
|
} |
||||||
} |
} |
||||||
} |
2 => { |
||||||
|
let dst = args.next_wr()?; |
||||||
"dec" => { |
ArithOp::Add { |
||||||
let dst = args.next_wr()?; |
dst, |
||||||
ArithOp::Sub { |
a: dst.as_rd(), |
||||||
dst, |
b: args.next_rd()?, |
||||||
a: dst.as_rd(), |
} |
||||||
b: Rd::immediate(1), |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into())); |
||||||
} |
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"add" => { |
"sub" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Add { |
ArithOp::Sub { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
b: args.next_rd()?, |
b: args.next_rd()?, |
||||||
} |
} |
||||||
} |
} |
||||||
2 => { |
2 => { |
||||||
let dst = args.next_wr()?; |
let dst = args.next_wr()?; |
||||||
ArithOp::Add { |
ArithOp::Sub { |
||||||
dst, |
dst, |
||||||
a: dst.as_rd(), |
a: dst.as_rd(), |
||||||
b: args.next_rd()?, |
b: args.next_rd()?, |
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("Add requires 2 or 3 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"sub" => { |
"mul" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Sub { |
ArithOp::Mul { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
b: args.next_rd()?, |
b: args.next_rd()?, |
||||||
} |
} |
||||||
} |
} |
||||||
2 => { |
2 => { |
||||||
let dst = args.next_wr()?; |
let dst = args.next_wr()?; |
||||||
ArithOp::Sub { |
ArithOp::Mul { |
||||||
dst, |
dst, |
||||||
a: dst.as_rd(), |
a: dst.as_rd(), |
||||||
b: args.next_rd()?, |
b: args.next_rd()?, |
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("Sub requires 2 or 3 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"mul" => { |
"divr" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Mul { |
let dst = args.next_wr()?; |
||||||
dst: args.next_wr()?, |
let rem = args.next_wr()?; |
||||||
a: args.next_rd()?, |
let div = args.next_rd()?; |
||||||
b: args.next_rd()?, |
ArithOp::Div { |
||||||
} |
dst, |
||||||
} |
rem, |
||||||
2 => { |
a: dst.as_rd(), |
||||||
let dst = args.next_wr()?; |
div, |
||||||
ArithOp::Mul { |
|
||||||
dst, |
|
||||||
a: dst.as_rd(), |
|
||||||
b: args.next_rd()?, |
|
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("Mul requires 2 or 3 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
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" => { |
"div" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
let dst = args.next_wr()?; |
ArithOp::Div { |
||||||
let rem = args.next_wr()?; |
dst: args.next_wr()?, |
||||||
let div = args.next_rd()?; |
rem: Wr::discard(), |
||||||
ArithOp::Div { |
a: args.next_rd()?, |
||||||
dst, |
div: args.next_rd()?, |
||||||
rem, |
} |
||||||
a: dst.as_rd(), |
} |
||||||
div, |
2 => { |
||||||
} |
let dst = args.next_wr()?; |
||||||
} |
let div = args.next_rd()?; |
||||||
4 => { |
ArithOp::Div { |
||||||
ArithOp::Div { |
dst, |
||||||
dst: args.next_wr()?, |
rem: Wr::discard(), |
||||||
rem: args.next_wr()?, |
a: dst.as_rd(), |
||||||
a: args.next_rd()?, |
div, |
||||||
div: args.next_rd()?, |
|
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("DivR requires 3 or 4 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"div" => { |
"mod" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Div { |
ArithOp::Mod { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
rem: Wr::discard(), |
a: args.next_rd()?, |
||||||
a: args.next_rd()?, |
div: args.next_rd()?, |
||||||
div: args.next_rd()?, |
} |
||||||
} |
} |
||||||
} |
2 => { |
||||||
2 => { |
let dst = args.next_wr()?; |
||||||
let dst = args.next_wr()?; |
let div = args.next_rd()?; |
||||||
let div = args.next_rd()?; |
ArithOp::Mod { |
||||||
ArithOp::Div { |
dst, |
||||||
dst, |
a: dst.as_rd(), |
||||||
rem: Wr::discard(), |
div, |
||||||
a: dst.as_rd(), |
|
||||||
div, |
|
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("Div requires 2 or 3 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"mod" => { |
"and" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Mod { |
ArithOp::And { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
div: args.next_rd()?, |
b: args.next_rd()?, |
||||||
} |
} |
||||||
} |
} |
||||||
2 => { |
2 => { |
||||||
let dst = args.next_wr()?; |
let dst = args.next_wr()?; |
||||||
let div = args.next_rd()?; |
ArithOp::And { |
||||||
ArithOp::Mod { |
dst, |
||||||
dst, |
a: dst.as_rd(), |
||||||
a: dst.as_rd(), |
b: args.next_rd()?, |
||||||
div, |
|
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("Mod requires 2 or 3 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("And requires 2 or 3 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"and" => { |
"or" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::And { |
ArithOp::Or { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
b: 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())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
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" => { |
"xor" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Or { |
ArithOp::Xor { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
b: 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())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
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" => { |
"cpl" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
2 => { |
||||||
ArithOp::Xor { |
ArithOp::Cpl { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
b: args.next_rd()?, |
} |
||||||
} |
} |
||||||
} |
1 => { |
||||||
2 => { |
let dst = args.next_wr()?; |
||||||
let dst = args.next_wr()?; |
ArithOp::Cpl { |
||||||
ArithOp::Xor { |
dst, |
||||||
dst, |
a: dst.as_rd(), |
||||||
a: dst.as_rd(), |
|
||||||
b: args.next_rd()?, |
|
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("Xor requires 2 or 3 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"cpl" => { |
"rol" => { |
||||||
match args.len() { |
match args.len() { |
||||||
2 => { |
3 => { |
||||||
ArithOp::Cpl { |
ArithOp::Rol { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
} |
n: args.next_rd()?, |
||||||
} |
} |
||||||
1 => { |
} |
||||||
let dst = args.next_wr()?; |
2 => { |
||||||
ArithOp::Cpl { |
let dst = args.next_wr()?; |
||||||
dst, |
ArithOp::Rol { |
||||||
a: dst.as_rd(), |
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" => { |
"ror" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Rol { |
ArithOp::Ror { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
n: 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())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
} |
2 => { |
||||||
|
let dst = args.next_wr()?; |
||||||
"ror" => { |
ArithOp::Ror { |
||||||
match args.len() { |
dst, |
||||||
3 => { |
a: dst.as_rd(), |
||||||
ArithOp::Ror { |
n: args.next_rd()?, |
||||||
dst: args.next_wr()?, |
} |
||||||
a: args.next_rd()?, |
} |
||||||
n: args.next_rd()?, |
1 => { |
||||||
} |
let dst = args.next_wr()?; |
||||||
} |
ArithOp::Ror { |
||||||
2 => { |
dst, |
||||||
let dst = args.next_wr()?; |
a: dst.as_rd(), |
||||||
ArithOp::Ror { |
n: Rd::immediate(1), |
||||||
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())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"lsl" | "asl" => { |
"lsl" | "asl" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Lsl { |
ArithOp::Lsl { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
n: args.next_rd()?, |
n: args.next_rd()?, |
||||||
} |
} |
||||||
} |
} |
||||||
2 => { |
2 => { |
||||||
let dst = args.next_wr()?; |
let dst = args.next_wr()?; |
||||||
ArithOp::Lsl { |
ArithOp::Lsl { |
||||||
dst, |
dst, |
||||||
a: dst.as_rd(), |
a: dst.as_rd(), |
||||||
n: args.next_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())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
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" => { |
"lsr" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Lsr { |
ArithOp::Lsr { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
n: args.next_rd()?, |
n: args.next_rd()?, |
||||||
} |
} |
||||||
} |
} |
||||||
2 => { |
2 => { |
||||||
let dst = args.next_wr()?; |
let dst = args.next_wr()?; |
||||||
ArithOp::Lsr { |
ArithOp::Lsr { |
||||||
dst, |
dst, |
||||||
a: dst.as_rd(), |
a: dst.as_rd(), |
||||||
n: args.next_rd()?, |
n: args.next_rd()?, |
||||||
} |
} |
||||||
} |
} |
||||||
1 => { |
1 => { |
||||||
let dst = args.next_wr()?; |
let dst = args.next_wr()?; |
||||||
ArithOp::Lsr { |
ArithOp::Lsr { |
||||||
dst, |
dst, |
||||||
a: dst.as_rd(), |
a: dst.as_rd(), |
||||||
n: Rd::immediate(1), |
n: Rd::immediate(1), |
||||||
} |
|
||||||
} |
|
||||||
_ => { |
|
||||||
return Err(Error::Parse("Lsr requires 1, 2 or 3 arguments".into())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
_ => { |
||||||
|
return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into())); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"asr" => { |
"asr" => { |
||||||
match args.len() { |
match args.len() { |
||||||
3 => { |
3 => { |
||||||
ArithOp::Asr { |
ArithOp::Asr { |
||||||
dst: args.next_wr()?, |
dst: args.next_wr()?, |
||||||
a: args.next_rd()?, |
a: args.next_rd()?, |
||||||
n: 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())); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
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 => { |
_other => { |
||||||
return Ok(ParseOpRes::Unknown(args)); |
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 defs; |
||||||
mod parse; |
mod parse; |
||||||
mod exec; |
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::instr::Op; |
||||||
use crsn::asm::parse::arg_parser::ArgParser; |
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 { |
use crate::defs::StackOp; |
||||||
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()?, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
"push" => { |
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> { |
||||||
StackOp::Push { |
Ok(ParseOpRes::ext(match keyword { |
||||||
obj: args.next_rdobj()?, |
"stack" => { |
||||||
src: args.next_rd()?, |
StackOp::NewStack { |
||||||
} |
dst: args.next_wr()?, |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
"pop" => { |
"push" => { |
||||||
StackOp::Pop { |
StackOp::Push { |
||||||
dst: args.next_wr()?, |
obj: args.next_rdobj()?, |
||||||
obj: args.next_rdobj()?, |
src: args.next_rd()?, |
||||||
} |
|
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
_other => { |
"pop" => { |
||||||
return Ok(ParseOpRes::Unknown(args)); |
StackOp::Pop { |
||||||
|
dst: args.next_wr()?, |
||||||
|
obj: args.next_rdobj()?, |
||||||
} |
} |
||||||
})))) |
} |
||||||
} |
|
||||||
|
|
||||||
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle : Value) -> Result<Option<()>, Fault> |
_other => { |
||||||
{ |
return Ok(ParseOpRes::Unknown(args)); |
||||||
crate::exec::drop_stack(state, handle) |
} |
||||||
} |
})) |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue