forked from MightyPork/crsn
rewrite the stdio module to be less broken. also add sehbang support
This commit is contained in:
Generated
+3
-45
@@ -168,23 +168,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "console"
|
|
||||||
version = "0.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c0b1aacfaffdbff75be81c15a399b4bedf78aaefe840e8af1d299ac2ade885d2"
|
|
||||||
dependencies = [
|
|
||||||
"encode_unicode",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"regex",
|
|
||||||
"terminal_size",
|
|
||||||
"termios",
|
|
||||||
"unicode-width",
|
|
||||||
"winapi",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crsn"
|
name = "crsn"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -228,8 +211,8 @@ dependencies = [
|
|||||||
name = "crsn_stdio"
|
name = "crsn_stdio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
|
||||||
"crsn",
|
"crsn",
|
||||||
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -274,12 +257,6 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82"
|
checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "encode_unicode"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -394,9 +371,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.77"
|
version = "0.2.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
|
checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -996,25 +973,6 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "terminal_size"
|
|
||||||
version = "0.1.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termios"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f0fcee7b24a25675de40d5bb4de6e41b0df07bc9856295e7e2b3a3600c400c2"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|||||||
@@ -15,10 +15,16 @@ It's probably faster than you need for most things, actually.
|
|||||||
|
|
||||||
You can slow it down using the `-C` argument, or using sleep instructions.
|
You can slow it down using the `-C` argument, or using sleep instructions.
|
||||||
|
|
||||||
#### What if I don't enjoy writing assembly that looks like weird Lisp?
|
### What if I don't enjoy writing assembly that looks like weird Lisp?
|
||||||
|
|
||||||
Maybe this is not for you
|
Maybe this is not for you
|
||||||
|
|
||||||
|
### Shebang?
|
||||||
|
|
||||||
|
Yes! You can use crsn as a scripting language!
|
||||||
|
|
||||||
|
The first line from a source file is skipped if it starts with `#!`
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
Yup, go ahead. You can also develop your own private *crsn* extensions, they work like plugins.
|
Yup, go ahead. You can also develop your own private *crsn* extensions, they work like plugins.
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ fn atom_of_string(s: String) -> Atom {
|
|||||||
|
|
||||||
// returns the char it found, and the new pos if you wish to consume that char
|
// returns the char it found, and the new pos if you wish to consume that char
|
||||||
fn peek(s: &str, pos: usize) -> ERes<(char, usize)> {
|
fn peek(s: &str, pos: usize) -> ERes<(char, usize)> {
|
||||||
trace!("peek {}", pos);
|
//trace!("peek {}", pos);
|
||||||
if pos == s.len() { return err("unexpected eof", s, pos); }
|
if pos == s.len() { return err("unexpected eof", s, pos); }
|
||||||
if s.is_char_boundary(pos) {
|
if s.is_char_boundary(pos) {
|
||||||
let ch = s[pos..].chars().next().unwrap();
|
let ch = s[pos..].chars().next().unwrap();
|
||||||
@@ -158,7 +158,7 @@ fn peek(s: &str, pos: usize) -> ERes<(char, usize)> {
|
|||||||
|
|
||||||
// returns the char it found, and the new pos if you wish to consume that char
|
// returns the char it found, and the new pos if you wish to consume that char
|
||||||
fn peekn(s: &str, nth: usize, pos: usize) -> Option<(char, usize)> {
|
fn peekn(s: &str, nth: usize, pos: usize) -> Option<(char, usize)> {
|
||||||
trace!("peekn {}", pos);
|
//trace!("peekn {}", pos);
|
||||||
if nth == 0 {
|
if nth == 0 {
|
||||||
panic!("peekn with nth=0");
|
panic!("peekn with nth=0");
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ fn peekn(s: &str, nth: usize, pos: usize) -> Option<(char, usize)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expect(s: &str, pos: &mut usize, c: char) -> ERes<()> {
|
fn expect(s: &str, pos: &mut usize, c: char) -> ERes<()> {
|
||||||
trace!("expect {}", pos);
|
//trace!("expect {}", pos);
|
||||||
let (ch, next) = peek(s, *pos)?;
|
let (ch, next) = peek(s, *pos)?;
|
||||||
*pos = next;
|
*pos = next;
|
||||||
if ch == c {
|
if ch == c {
|
||||||
@@ -208,7 +208,7 @@ fn consume_until_newline(s: &str, pos: &mut usize) -> ERes<()> {
|
|||||||
|
|
||||||
// zero or more spaces
|
// zero or more spaces
|
||||||
fn zspace(s: &str, pos: &mut usize) -> ERes<()> {
|
fn zspace(s: &str, pos: &mut usize) -> ERes<()> {
|
||||||
trace!("zspace {}", pos);
|
//trace!("zspace {}", pos);
|
||||||
loop {
|
loop {
|
||||||
if *pos == s.len() {
|
if *pos == s.len() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -226,7 +226,7 @@ fn zspace(s: &str, pos: &mut usize) -> ERes<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_quoted_atom(s: &str, quote: char, pos: &mut usize) -> ERes<Atom> {
|
fn parse_quoted_atom(s: &str, quote: char, pos: &mut usize) -> ERes<Atom> {
|
||||||
trace!("parse_quoted_atom {}", pos);
|
//trace!("parse_quoted_atom {}", pos);
|
||||||
let pos0 = *pos;
|
let pos0 = *pos;
|
||||||
let mut cs: String = String::new();
|
let mut cs: String = String::new();
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ fn parse_quoted_atom(s: &str, quote: char, pos: &mut usize) -> ERes<Atom> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unquoted_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
|
fn parse_unquoted_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
|
||||||
trace!("parse_unquoted_atom {}", pos);
|
//trace!("parse_unquoted_atom {}", pos);
|
||||||
let mut cs: String = String::new();
|
let mut cs: String = String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -288,7 +288,7 @@ fn parse_unquoted_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
|
fn parse_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
|
||||||
trace!("parse_atom {}", pos);
|
//trace!("parse_atom {}", pos);
|
||||||
let (ch, _) = peek(s, *pos)?;
|
let (ch, _) = peek(s, *pos)?;
|
||||||
|
|
||||||
if ch == '"' {
|
if ch == '"' {
|
||||||
@@ -309,7 +309,7 @@ fn parse_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_list(s: &str, pos: &mut usize) -> ERes<Vec<Sexp>> {
|
fn parse_list(s: &str, pos: &mut usize) -> ERes<Vec<Sexp>> {
|
||||||
trace!("parse_list {}", pos);
|
//trace!("parse_list {}", pos);
|
||||||
zspace(s, pos)?;
|
zspace(s, pos)?;
|
||||||
expect(s, pos, '(')?;
|
expect(s, pos, '(')?;
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ fn parse_list(s: &str, pos: &mut usize) -> ERes<Vec<Sexp>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_sexp(s: &str, pos: &mut usize) -> ERes<Sexp> {
|
fn parse_sexp(s: &str, pos: &mut usize) -> ERes<Sexp> {
|
||||||
trace!("parse_sexp {}", pos);
|
//trace!("parse_sexp {}", pos);
|
||||||
zspace(s, pos)?;
|
zspace(s, pos)?;
|
||||||
let (c, _) = peek(s, *pos)?;
|
let (c, _) = peek(s, *pos)?;
|
||||||
let r = if c == '(' {
|
let r = if c == '(' {
|
||||||
|
|||||||
@@ -5,6 +5,55 @@ use sexp::SourcePosition;
|
|||||||
|
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
|
|
||||||
|
/// Condition flag
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub enum Flag {
|
||||||
|
/// Equality
|
||||||
|
Equal,
|
||||||
|
/// Equal to zero
|
||||||
|
Zero,
|
||||||
|
/// A < B
|
||||||
|
Lower,
|
||||||
|
/// A > B
|
||||||
|
Greater,
|
||||||
|
/// A > 0
|
||||||
|
Positive,
|
||||||
|
/// A < 0
|
||||||
|
Negative,
|
||||||
|
/// Arithmetic operation caused an integer operand to overflow
|
||||||
|
Overflow,
|
||||||
|
/// Arithmetic (or other) operation was invalid.
|
||||||
|
/// Example: division by zero
|
||||||
|
Invalid,
|
||||||
|
/// Arithmetic carry
|
||||||
|
Carry,
|
||||||
|
// Full
|
||||||
|
Full,
|
||||||
|
// Empty
|
||||||
|
Empty,
|
||||||
|
// Empty
|
||||||
|
Eof,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Flag> for Cond {
|
||||||
|
fn from(flag: Flag) -> Self {
|
||||||
|
match flag {
|
||||||
|
Flag::Equal => Cond::Equal,
|
||||||
|
Flag::Zero => Cond::Zero,
|
||||||
|
Flag::Lower => Cond::Lower,
|
||||||
|
Flag::Greater => Cond::Greater,
|
||||||
|
Flag::Positive => Cond::Positive,
|
||||||
|
Flag::Negative => Cond::Negative,
|
||||||
|
Flag::Overflow => Cond::Overflow,
|
||||||
|
Flag::Invalid => Cond::Invalid,
|
||||||
|
Flag::Carry => Cond::Carry,
|
||||||
|
Flag::Full => Cond::Full,
|
||||||
|
Flag::Empty => Cond::Empty,
|
||||||
|
Flag::Eof => Cond::Eof,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Condition flag
|
/// Condition flag
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum Cond {
|
pub enum Cond {
|
||||||
@@ -53,6 +102,10 @@ pub enum Cond {
|
|||||||
Empty,
|
Empty,
|
||||||
/// Not empty
|
/// Not empty
|
||||||
NotEmpty,
|
NotEmpty,
|
||||||
|
// Empty
|
||||||
|
Eof,
|
||||||
|
/// Not empty
|
||||||
|
NotEof,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
||||||
@@ -77,6 +130,8 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
|||||||
"nf" | "nfull" => Cond::NotFull,
|
"nf" | "nfull" => Cond::NotFull,
|
||||||
"ok" | "val" | "valid" => Cond::Valid,
|
"ok" | "val" | "valid" => Cond::Valid,
|
||||||
"inval" | "invalid" | "nval" | "nok" => Cond::Invalid,
|
"inval" | "invalid" | "nval" | "nok" => Cond::Invalid,
|
||||||
|
"eof" => Cond::Eof,
|
||||||
|
"neof" => Cond::NotEof,
|
||||||
"ov" => Cond::Overflow,
|
"ov" => Cond::Overflow,
|
||||||
"nov" => Cond::NotOverflow,
|
"nov" => Cond::NotOverflow,
|
||||||
_ => {
|
_ => {
|
||||||
@@ -85,6 +140,13 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Flag {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
let cond : Cond = (*self).into();
|
||||||
|
write!(f, "{}", cond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Cond {
|
impl Display for Cond {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
f.write_str(match self {
|
f.write_str(match self {
|
||||||
@@ -110,6 +172,8 @@ impl Display for Cond {
|
|||||||
Cond::NotCarry => "nc",
|
Cond::NotCarry => "nc",
|
||||||
Cond::Invalid => "inval",
|
Cond::Invalid => "inval",
|
||||||
Cond::Valid => "valid",
|
Cond::Valid => "valid",
|
||||||
|
Cond::Eof => "eof",
|
||||||
|
Cond::NotEof => "neof",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,6 +211,9 @@ impl Not for Cond {
|
|||||||
|
|
||||||
Cond::Invalid => Cond::Valid,
|
Cond::Invalid => Cond::Valid,
|
||||||
Cond::Valid => Cond::Invalid,
|
Cond::Valid => Cond::Invalid,
|
||||||
|
|
||||||
|
Cond::NotEof => Cond::Eof,
|
||||||
|
Cond::Eof => Cond::NotEof,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ impl Flatten for InstrWithBranches {
|
|||||||
let parent_pos = self.pos;
|
let parent_pos = self.pos;
|
||||||
|
|
||||||
if let Some(branches) = self.branches {
|
if let Some(branches) = self.branches {
|
||||||
|
// trace!("Branches {:?}", branches);
|
||||||
|
|
||||||
let labels = HashMap::<Cond, u32>::new();
|
let labels = HashMap::<Cond, u32>::new();
|
||||||
let branch_count = branches.len();
|
let branch_count = branches.len();
|
||||||
let end_lbl = Label::unique(label_num);
|
let end_lbl = Label::unique(label_num);
|
||||||
|
|||||||
@@ -23,6 +23,17 @@ pub fn assemble(source: &str, uniq : &CrsnUniq, mut parsers: Vec<Box<dyn CrsnExt
|
|||||||
p.init(uniq);
|
p.init(uniq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove first line if it looks like a shebang
|
||||||
|
let source = if source.starts_with("#!") {
|
||||||
|
if let Some(nl) = source.find('\n') {
|
||||||
|
&source[nl + 1..]
|
||||||
|
} else {
|
||||||
|
source
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
source
|
||||||
|
};
|
||||||
|
|
||||||
let pcx = ParserContext {
|
let pcx = ParserContext {
|
||||||
parsers: &parsers,
|
parsers: &parsers,
|
||||||
state: RefCell::new(ParserState {
|
state: RefCell::new(ParserState {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crate::asm::parse::ParserContext;
|
|||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
|
|
||||||
/// Utility for argument parsing
|
/// Utility for argument parsing
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TokenParser<'a> {
|
pub struct TokenParser<'a> {
|
||||||
orig_len: usize,
|
orig_len: usize,
|
||||||
args: Vec<Sexp>,
|
args: Vec<Sexp>,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub mod parse_op;
|
|||||||
pub mod arg_parser;
|
pub mod arg_parser;
|
||||||
pub mod parse_routine;
|
pub mod parse_routine;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ParserContext<'a> {
|
pub struct ParserContext<'a> {
|
||||||
/// Extension modules
|
/// Extension modules
|
||||||
pub parsers: &'a [Box<dyn CrsnExtension>],
|
pub parsers: &'a [Box<dyn CrsnExtension>],
|
||||||
@@ -27,7 +28,7 @@ pub struct ParserContext<'a> {
|
|||||||
pub state: RefCell<ParserState>,
|
pub state: RefCell<ParserState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ParserState {
|
pub struct ParserState {
|
||||||
/// Register aliases within the routine
|
/// Register aliases within the routine
|
||||||
pub reg_aliases: HashMap<RegisterAlias, Register>,
|
pub reg_aliases: HashMap<RegisterAlias, Register>,
|
||||||
|
|||||||
@@ -63,10 +63,11 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pos: &SourcePosition,
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let arg_tokens = TokenParser::new(toki.take(token_count - branch_tokens.len()).collect(), &listpos, pcx);
|
let arg_tokens = TokenParser::new(toki.take(token_count - branch_tokens.len()).collect(), &listpos, pcx);
|
||||||
|
// debug!("branch_tokens: {:#?}", branch_tokens);
|
||||||
|
|
||||||
let branches = {
|
let branches = {
|
||||||
let mut branches = vec![];
|
let mut branches = vec![];
|
||||||
for t in branch_tokens {
|
for t in branch_tokens.into_iter().rev() {
|
||||||
branches.push(parse_cond_branch(t, pcx)?);
|
branches.push(parse_cond_branch(t, pcx)?);
|
||||||
}
|
}
|
||||||
if branches.is_empty() {
|
if branches.is_empty() {
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ use sexp::Sexp;
|
|||||||
|
|
||||||
use crate::asm::data::{Rd, RdData};
|
use crate::asm::data::{Rd, RdData};
|
||||||
use crate::asm::data::literal::Addr;
|
use crate::asm::data::literal::Addr;
|
||||||
use crate::asm::instr::Cond;
|
|
||||||
use crate::builtin::defs::{Barrier, BuiltinOp};
|
use crate::builtin::defs::{Barrier, BuiltinOp};
|
||||||
use crate::module::{EvalRes, OpTrait};
|
use crate::module::{EvalRes, OpTrait};
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::runtime::frame::StackFrame;
|
use crate::runtime::frame::StackFrame;
|
||||||
use crate::runtime::run_thread::{state::RunState, ThreadInfo};
|
use crate::runtime::run_thread::{state::RunState, ThreadInfo};
|
||||||
|
use crate::asm::instr::cond::Flag;
|
||||||
|
|
||||||
impl OpTrait for BuiltinOp {
|
impl OpTrait for BuiltinOp {
|
||||||
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||||
@@ -138,7 +138,7 @@ impl OpTrait for BuiltinOp {
|
|||||||
}
|
}
|
||||||
if !dropped {
|
if !dropped {
|
||||||
warn!("Object {:#x} to del does not exist!", x);
|
warn!("Object {:#x} to del does not exist!", x);
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::fmt;
|
|||||||
|
|
||||||
use crate::asm::data::literal::{is_negative, is_positive, Value};
|
use crate::asm::data::literal::{is_negative, is_positive, Value};
|
||||||
use crate::asm::instr::Cond;
|
use crate::asm::instr::Cond;
|
||||||
|
use crate::asm::instr::cond::Flag;
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct StatusFlags {
|
pub struct StatusFlags {
|
||||||
@@ -28,6 +29,8 @@ pub struct StatusFlags {
|
|||||||
pub full: bool,
|
pub full: bool,
|
||||||
/// Buffer empty
|
/// Buffer empty
|
||||||
pub empty: bool,
|
pub empty: bool,
|
||||||
|
/// Stream ended
|
||||||
|
pub eof: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatusFlags {
|
impl StatusFlags {
|
||||||
@@ -49,6 +52,7 @@ impl StatusFlags {
|
|||||||
if self.carry { val |= 0x100; }
|
if self.carry { val |= 0x100; }
|
||||||
if self.full { val |= 0x200; }
|
if self.full { val |= 0x200; }
|
||||||
if self.empty { val |= 0x400; }
|
if self.empty { val |= 0x400; }
|
||||||
|
if self.eof { val |= 0x800; }
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +68,7 @@ impl StatusFlags {
|
|||||||
if val & 0x100 != 0 { self.carry = true; }
|
if val & 0x100 != 0 { self.carry = true; }
|
||||||
if val & 0x200 != 0 { self.full = true; }
|
if val & 0x200 != 0 { self.full = true; }
|
||||||
if val & 0x400 != 0 { self.empty = true; }
|
if val & 0x400 != 0 { self.empty = true; }
|
||||||
|
if val & 0x800 != 0 { self.eof = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -98,50 +103,49 @@ impl StatusFlags {
|
|||||||
Cond::NotFull => !self.full,
|
Cond::NotFull => !self.full,
|
||||||
Cond::Empty => self.empty,
|
Cond::Empty => self.empty,
|
||||||
Cond::NotEmpty => !self.empty,
|
Cond::NotEmpty => !self.empty,
|
||||||
|
Cond::Eof => self.eof,
|
||||||
|
Cond::NotEof => !self.eof,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set(&mut self, cond: Cond) {
|
pub fn set(&mut self, cond: Flag, val : bool) {
|
||||||
match cond {
|
match cond {
|
||||||
Cond::Equal => {
|
Flag::Equal => {
|
||||||
self.equal = true;
|
self.equal = val;
|
||||||
}
|
}
|
||||||
Cond::Zero => {
|
Flag::Zero => {
|
||||||
self.zero = true;
|
self.zero = val;
|
||||||
}
|
}
|
||||||
Cond::Lower => {
|
Flag::Lower => {
|
||||||
self.lower = true;
|
self.lower = val;
|
||||||
}
|
}
|
||||||
Cond::Greater => {
|
Flag::Greater => {
|
||||||
self.lower = false;
|
self.greater = val;
|
||||||
self.equal = false;
|
|
||||||
self.greater = true;
|
|
||||||
}
|
}
|
||||||
Cond::Positive => {
|
Flag::Positive => {
|
||||||
self.positive = true;
|
self.positive = val;
|
||||||
}
|
}
|
||||||
Cond::Negative => {
|
Flag::Negative => {
|
||||||
self.negative = true;
|
self.negative = val;
|
||||||
}
|
}
|
||||||
Cond::Overflow => {
|
Flag::Overflow => {
|
||||||
self.overflow = true;
|
self.overflow = val;
|
||||||
}
|
}
|
||||||
Cond::Invalid => {
|
Flag::Invalid => {
|
||||||
self.invalid = true;
|
self.invalid = val;
|
||||||
}
|
}
|
||||||
Cond::Carry => {
|
Flag::Carry => {
|
||||||
self.carry = true;
|
self.carry = val;
|
||||||
}
|
}
|
||||||
Cond::Empty => {
|
Flag::Empty => {
|
||||||
self.empty = true;
|
self.empty = val;
|
||||||
}
|
}
|
||||||
Cond::Full => {
|
Flag::Full => {
|
||||||
self.full = true;
|
self.full = val;
|
||||||
}
|
}
|
||||||
other => {
|
Flag::Eof => {
|
||||||
error!("Cannot set cond by {:?}", other);
|
self.eof = val;
|
||||||
// ...and do nothing. Don't panic, we don't want to crash the runtime!
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,6 +187,9 @@ impl Display for StatusFlags {
|
|||||||
if self.empty {
|
if self.empty {
|
||||||
f.write_str(" Emp")?;
|
f.write_str(" Emp")?;
|
||||||
}
|
}
|
||||||
|
if self.eof {
|
||||||
|
f.write_str(" Eof")?;
|
||||||
|
}
|
||||||
f.write_str(" ]")?;
|
f.write_str(" ]")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::runtime::run_thread::ThreadInfo;
|
use crate::runtime::run_thread::ThreadInfo;
|
||||||
use nudge::{likely};
|
use nudge::{likely};
|
||||||
|
use crate::asm::instr::cond::Flag;
|
||||||
|
|
||||||
pub struct RunState {
|
pub struct RunState {
|
||||||
pub thread_info: Arc<ThreadInfo>,
|
pub thread_info: Arc<ThreadInfo>,
|
||||||
@@ -51,10 +52,9 @@ impl RunState {
|
|||||||
|
|
||||||
/// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual)
|
/// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual)
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_flag(&mut self, cond: Cond, set: bool) {
|
pub fn set_flag(&mut self, flag: Flag, set: bool) {
|
||||||
if set {
|
trace!("Flag {} = {:?}", flag, set);
|
||||||
self.frame.status.set(cond);
|
self.frame.status.set(flag, set);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check status flags for a condition
|
/// Check status flags for a condition
|
||||||
|
|||||||
+17
-17
@@ -3,7 +3,6 @@ use std::ops::Rem;
|
|||||||
use num_traits::PrimInt;
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
use crsn::asm::data::{Rd, Wr};
|
use crsn::asm::data::{Rd, Wr};
|
||||||
use crsn::asm::instr::Cond;
|
|
||||||
use crsn::module::{EvalRes, OpTrait};
|
use crsn::module::{EvalRes, OpTrait};
|
||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
||||||
@@ -12,6 +11,7 @@ use crsn::sexp::Sexp;
|
|||||||
use crsn::utils::A;
|
use crsn::utils::A;
|
||||||
|
|
||||||
use crate::defs::ArithOp;
|
use crate::defs::ArithOp;
|
||||||
|
use crsn::asm::instr::cond::Flag;
|
||||||
|
|
||||||
impl OpTrait for ArithOp {
|
impl OpTrait for ArithOp {
|
||||||
fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||||
@@ -26,9 +26,9 @@ impl OpTrait for ArithOp {
|
|||||||
state.clear_status();
|
state.clear_status();
|
||||||
let x = state.read(a)?;
|
let x = state.read(a)?;
|
||||||
let y = state.read(b)?;
|
let y = state.read(b)?;
|
||||||
state.set_flag(Cond::Equal, x == y);
|
state.set_flag(Flag::Equal, x == y);
|
||||||
state.set_flag(Cond::Lower, x < y);
|
state.set_flag(Flag::Lower, x < y);
|
||||||
state.set_flag(Cond::Greater, x > y);
|
state.set_flag(Flag::Greater, x > y);
|
||||||
// Test flags are set when both arguments have the property
|
// Test flags are set when both arguments have the property
|
||||||
if x == y {
|
if x == y {
|
||||||
state.update_status(x);
|
state.update_status(x);
|
||||||
@@ -39,9 +39,9 @@ impl OpTrait for ArithOp {
|
|||||||
let val = state.read(val)?;
|
let val = state.read(val)?;
|
||||||
let a = state.read(a)?;
|
let a = state.read(a)?;
|
||||||
let b = state.read(b)?;
|
let b = state.read(b)?;
|
||||||
state.set_flag(Cond::Equal, val >= a && val <= b);
|
state.set_flag(Flag::Equal, val >= a && val <= b);
|
||||||
state.set_flag(Cond::Lower, val < a);
|
state.set_flag(Flag::Lower, val < a);
|
||||||
state.set_flag(Cond::Greater, val > b);
|
state.set_flag(Flag::Greater, val > b);
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
}
|
}
|
||||||
ArithOp::Add { dst, a, b } => {
|
ArithOp::Add { dst, a, b } => {
|
||||||
@@ -54,7 +54,7 @@ impl OpTrait for ArithOp {
|
|||||||
(x.wrapping_add(y), true)
|
(x.wrapping_add(y), true)
|
||||||
};
|
};
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
state.set_flag(Cond::Overflow, ov);
|
state.set_flag(Flag::Overflow, ov);
|
||||||
state.write(dst, res)?;
|
state.write(dst, res)?;
|
||||||
}
|
}
|
||||||
ArithOp::Sub { dst, a, b } => {
|
ArithOp::Sub { dst, a, b } => {
|
||||||
@@ -67,7 +67,7 @@ impl OpTrait for ArithOp {
|
|||||||
(x.wrapping_sub(y), true)
|
(x.wrapping_sub(y), true)
|
||||||
};
|
};
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
state.set_flag(Cond::Overflow, ov);
|
state.set_flag(Flag::Overflow, ov);
|
||||||
state.write(dst, res)?;
|
state.write(dst, res)?;
|
||||||
}
|
}
|
||||||
ArithOp::Mul { dst, a, b } => {
|
ArithOp::Mul { dst, a, b } => {
|
||||||
@@ -77,7 +77,7 @@ impl OpTrait for ArithOp {
|
|||||||
let res = if let Some(v) = x.checked_mul(y) {
|
let res = if let Some(v) = x.checked_mul(y) {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
x.wrapping_mul(y)
|
x.wrapping_mul(y)
|
||||||
};
|
};
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
@@ -88,7 +88,7 @@ impl OpTrait for ArithOp {
|
|||||||
let x = state.read(a)?;
|
let x = state.read(a)?;
|
||||||
let d = state.read(div)?;
|
let d = state.read(div)?;
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
} else {
|
} else {
|
||||||
let (res, remainder, ov) = if let Some(v) = x.checked_div(d) {
|
let (res, remainder, ov) = if let Some(v) = x.checked_div(d) {
|
||||||
(v, x.rem(d), false)
|
(v, x.rem(d), false)
|
||||||
@@ -96,7 +96,7 @@ impl OpTrait for ArithOp {
|
|||||||
(x.wrapping_div(d), x.wrapping_rem(d), true)
|
(x.wrapping_div(d), x.wrapping_rem(d), true)
|
||||||
};
|
};
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
state.set_flag(Cond::Overflow, ov);
|
state.set_flag(Flag::Overflow, ov);
|
||||||
state.write(dst, res)?;
|
state.write(dst, res)?;
|
||||||
state.write(rem, remainder)?;
|
state.write(rem, remainder)?;
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ impl OpTrait for ArithOp {
|
|||||||
let x = state.read(a)?;
|
let x = state.read(a)?;
|
||||||
let d = state.read(div)?;
|
let d = state.read(div)?;
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
} else {
|
} else {
|
||||||
let (remainder, ov) = if let Some(v) = x.checked_rem(d) {
|
let (remainder, ov) = if let Some(v) = x.checked_rem(d) {
|
||||||
(v, false)
|
(v, false)
|
||||||
@@ -114,7 +114,7 @@ impl OpTrait for ArithOp {
|
|||||||
(x.wrapping_rem(d), true)
|
(x.wrapping_rem(d), true)
|
||||||
};
|
};
|
||||||
state.update_status(remainder);
|
state.update_status(remainder);
|
||||||
state.set_flag(Cond::Overflow, ov);
|
state.set_flag(Flag::Overflow, ov);
|
||||||
state.write(dst, remainder)?;
|
state.write(dst, remainder)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ impl OpTrait for ArithOp {
|
|||||||
let x = state.read(a)?;
|
let x = state.read(a)?;
|
||||||
let y = state.read(n)?;
|
let y = state.read(n)?;
|
||||||
if y > u32::MAX as u64 {
|
if y > u32::MAX as u64 {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
} else {
|
} else {
|
||||||
let res = x.rotate_left(y as u32);
|
let res = x.rotate_left(y as u32);
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
@@ -166,7 +166,7 @@ impl OpTrait for ArithOp {
|
|||||||
let x = state.read(a)?;
|
let x = state.read(a)?;
|
||||||
let y = state.read(n)?;
|
let y = state.read(n)?;
|
||||||
if y > u32::MAX as u64 {
|
if y > u32::MAX as u64 {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
} else {
|
} else {
|
||||||
let res = x.rotate_right(y as u32);
|
let res = x.rotate_right(y as u32);
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
@@ -194,7 +194,7 @@ impl OpTrait for ArithOp {
|
|||||||
let x = state.read(a)?;
|
let x = state.read(a)?;
|
||||||
let y = state.read(n)?;
|
let y = state.read(n)?;
|
||||||
if y > u32::MAX as u64 {
|
if y > u32::MAX as u64 {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
} else {
|
} else {
|
||||||
let res = x.signed_shr(y as u32);
|
let res = x.signed_shr(y as u32);
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
use crsn::asm::data::literal::Value;
|
use crsn::asm::data::literal::Value;
|
||||||
use crsn::asm::instr::Cond;
|
|
||||||
use crsn::module::{EvalRes, OpTrait};
|
use crsn::module::{EvalRes, OpTrait};
|
||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
||||||
@@ -10,6 +9,7 @@ use crsn::sexp::{Sexp, atom_qs};
|
|||||||
use crsn::utils::A;
|
use crsn::utils::A;
|
||||||
|
|
||||||
use crate::defs::{BufOps, BufValue};
|
use crate::defs::{BufOps, BufValue};
|
||||||
|
use crsn::asm::instr::cond::Flag;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct ExtData {
|
struct ExtData {
|
||||||
@@ -71,10 +71,10 @@ impl OpTrait for BufOps {
|
|||||||
let empty = stack.is_empty();
|
let empty = stack.is_empty();
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.set_flag(Cond::Empty, empty);
|
state.set_flag(Flag::Empty, empty);
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Cond::Empty, true);
|
state.set_flag(Flag::Empty, true);
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ impl OpTrait for BufOps {
|
|||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ impl OpTrait for BufOps {
|
|||||||
} else if idx == stack.len() {
|
} else if idx == stack.len() {
|
||||||
stack.push_back(val);
|
stack.push_back(val);
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ impl OpTrait for BufOps {
|
|||||||
} else if idx == stack.len() {
|
} else if idx == stack.len() {
|
||||||
stack.push_back(val);
|
stack.push_back(val);
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,9 +146,9 @@ impl OpTrait for BufOps {
|
|||||||
let empty = stack.is_empty();
|
let empty = stack.is_empty();
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
state.set_flag(Cond::Empty, empty);
|
state.set_flag(Flag::Empty, empty);
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -4,7 +4,6 @@ use std::time::{Duration, Instant};
|
|||||||
use minifb::{Key, MouseButton, MouseMode, ScaleMode, Window, WindowOptions};
|
use minifb::{Key, MouseButton, MouseMode, ScaleMode, Window, WindowOptions};
|
||||||
|
|
||||||
use crsn::asm::data::literal::Value;
|
use crsn::asm::data::literal::Value;
|
||||||
use crsn::asm::instr::Cond;
|
|
||||||
use crsn::module::{EvalRes, OpTrait};
|
use crsn::module::{EvalRes, OpTrait};
|
||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
||||||
@@ -13,6 +12,7 @@ use crsn::sexp::Sexp;
|
|||||||
use crsn::utils::A;
|
use crsn::utils::A;
|
||||||
|
|
||||||
use crate::defs::ScreenOp;
|
use crate::defs::ScreenOp;
|
||||||
|
use crsn::asm::instr::cond::Flag;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Opts {
|
struct Opts {
|
||||||
@@ -87,7 +87,7 @@ impl OpTrait for ScreenOp {
|
|||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
warn!("Bad screen opt: {}", other);
|
warn!("Bad screen opt: {}", other);
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ impl OpTrait for ScreenOp {
|
|||||||
w.update();
|
w.update();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ impl OpTrait for ScreenOp {
|
|||||||
let backend: &mut Backend = state.ext_mut();
|
let backend: &mut Backend = state.ext_mut();
|
||||||
|
|
||||||
if x >= backend.width as u64 || y >= backend.height as u64 {
|
if x >= backend.width as u64 || y >= backend.height as u64 {
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
return Ok(eres);
|
return Ok(eres);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ impl OpTrait for ScreenOp {
|
|||||||
let index = y * backend.width as u64 + x;
|
let index = y * backend.width as u64 + x;
|
||||||
if index as usize > backend.buffer.len() {
|
if index as usize > backend.buffer.len() {
|
||||||
warn!("Screen set pixel out of bounds");
|
warn!("Screen set pixel out of bounds");
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
} else {
|
} else {
|
||||||
backend.buffer[index as usize] = color as u32;
|
backend.buffer[index as usize] = color as u32;
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ impl OpTrait for ScreenOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ impl OpTrait for ScreenOp {
|
|||||||
debug!("mp = {:?}", mp);
|
debug!("mp = {:?}", mp);
|
||||||
match mp {
|
match mp {
|
||||||
None => {
|
None => {
|
||||||
state.set_flag(Cond::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
Some((xf, yf)) => {
|
Some((xf, yf)) => {
|
||||||
let xval = xf.round() as u64;
|
let xval = xf.round() as u64;
|
||||||
@@ -174,7 +174,7 @@ impl OpTrait for ScreenOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,7 +187,7 @@ impl OpTrait for ScreenOp {
|
|||||||
Some(w) => {
|
Some(w) => {
|
||||||
match num {
|
match num {
|
||||||
None => {
|
None => {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
Some(kn) => {
|
Some(kn) => {
|
||||||
let down = w.is_key_down(kn) as u64;
|
let down = w.is_key_down(kn) as u64;
|
||||||
@@ -197,7 +197,7 @@ impl OpTrait for ScreenOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ impl OpTrait for ScreenOp {
|
|||||||
1 => Some(MouseButton::Right),
|
1 => Some(MouseButton::Right),
|
||||||
2 => Some(MouseButton::Middle),
|
2 => Some(MouseButton::Middle),
|
||||||
_ => {
|
_ => {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -225,7 +225,7 @@ impl OpTrait for ScreenOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crsn = { path = "../crsn" }
|
crsn = { path = "../crsn" }
|
||||||
console = "0.12.0"
|
libc = "0.2.79"
|
||||||
|
|||||||
+159
-30
@@ -6,43 +6,139 @@ use crsn::module::{CrsnExtension, ParseRes, CrsnUniq};
|
|||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::run_thread::{RunState};
|
use crsn::runtime::run_thread::{RunState};
|
||||||
use crsn::sexp::SourcePosition;
|
use crsn::sexp::SourcePosition;
|
||||||
use std::io::{Write};
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use crsn::asm::instr::Cond;
|
use std::io;
|
||||||
use console::Term;
|
use crsn::asm::instr::cond::Flag;
|
||||||
|
|
||||||
|
mod console {
|
||||||
|
use std::{io};
|
||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::mem::{self, MaybeUninit};
|
||||||
|
|
||||||
|
fn setup_fd(fd: RawFd) -> io::Result<libc::termios> {
|
||||||
|
use libc::*;
|
||||||
|
|
||||||
|
let mut tio = MaybeUninit::uninit();
|
||||||
|
if 0 != unsafe { tcgetattr(fd, tio.as_mut_ptr()) } {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
let mut tio = unsafe { MaybeUninit::assume_init(tio) };
|
||||||
|
let old_tio : termios = unsafe { mem::transmute_copy(&tio) };
|
||||||
|
|
||||||
|
tio.c_iflag &= !(/*BRKINT |*/ /*ICRNL |*/ INPCK | ISTRIP | IXON);
|
||||||
|
tio.c_oflag |= ONLCR;
|
||||||
|
tio.c_cflag |= CS8;
|
||||||
|
tio.c_lflag &= !(ECHO | ICANON | IEXTEN /*| ISIG*/);
|
||||||
|
tio.c_cc[VMIN] = 1;
|
||||||
|
tio.c_cc[VTIME] = 0;
|
||||||
|
if 0 != unsafe { tcsetattr(fd, TCSANOW, &tio) } {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(old_tio)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_io() -> io::Result<libc::termios> {
|
||||||
|
setup_fd(libc::STDIN_FILENO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_byte() -> io::Result<u8> {
|
||||||
|
let mut buf = 0u8;
|
||||||
|
let len = unsafe { libc::read(libc::STDIN_FILENO, &mut buf as *mut u8 as *mut c_void, 1) };
|
||||||
|
if len <= 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(buf as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_byte(b : u8) -> io::Result<()> {
|
||||||
|
let len = unsafe { libc::write(libc::STDOUT_FILENO, &b as *const u8 as *const c_void, 1) };
|
||||||
|
if len <= 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_char(c : char) -> io::Result<()> {
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
for b in c.encode_utf8(&mut buf).as_bytes() {
|
||||||
|
write_byte(*b)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_char() -> io::Result<char> {
|
||||||
|
let first = read_byte()?;
|
||||||
|
|
||||||
|
if first & 0x80 == 0 {
|
||||||
|
return Ok(first as char);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bytes = [first, 0, 0, 0];
|
||||||
|
|
||||||
|
let remain = if first & 0b1110_0000 == 0b1100_0000 {
|
||||||
|
1
|
||||||
|
} else if first & 0b1111_0000 == 0b1110_0000 {
|
||||||
|
2
|
||||||
|
} else /*if first & 0b1111_1000 == 0b1111_0000*/ {
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
|
for n in 1..=remain {
|
||||||
|
bytes[n] = read_byte()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::str::from_utf8(&bytes[..=remain])
|
||||||
|
.map(|s| s.chars().nth(0).unwrap())
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StdioOps {
|
pub struct StdioOps {
|
||||||
|
old_tio: Option<libc::termios>,
|
||||||
hdl_stdin : Value,
|
hdl_stdin : Value,
|
||||||
|
hdl_stdin_raw : Value,
|
||||||
hdl_stdout : Value,
|
hdl_stdout : Value,
|
||||||
}
|
hdl_stdout_raw : Value,
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct StdioData {
|
|
||||||
console: Term,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for StdioData {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
console : Term::stdout()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdioOps {
|
impl StdioOps {
|
||||||
pub fn new() -> Box<dyn CrsnExtension> {
|
pub fn new() -> Box<dyn CrsnExtension> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
|
old_tio: None,
|
||||||
hdl_stdin: 0,
|
hdl_stdin: 0,
|
||||||
hdl_stdout: 0
|
hdl_stdin_raw: 0,
|
||||||
|
hdl_stdout: 0,
|
||||||
|
hdl_stdout_raw: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for StdioOps {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Un-break the terminal
|
||||||
|
if let Some(tio) = self.old_tio.take() {
|
||||||
|
let _ = unsafe { libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &tio) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CrsnExtension for StdioOps {
|
impl CrsnExtension for StdioOps {
|
||||||
fn init(&mut self, uniq: &CrsnUniq) {
|
fn init(&mut self, uniq: &CrsnUniq) {
|
||||||
self.hdl_stdin = uniq.unique_handle();
|
self.hdl_stdin = uniq.unique_handle();
|
||||||
|
self.hdl_stdin_raw = uniq.unique_handle();
|
||||||
self.hdl_stdout = uniq.unique_handle();
|
self.hdl_stdout = uniq.unique_handle();
|
||||||
|
self.hdl_stdout_raw = uniq.unique_handle();
|
||||||
|
|
||||||
|
// This can fail if the input is not a tty
|
||||||
|
if let Ok(tio) = console::init_io() {
|
||||||
|
self.old_tio = Some(tio);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get value of an extension-provided constant.
|
/// Get value of an extension-provided constant.
|
||||||
@@ -50,8 +146,10 @@ impl CrsnExtension for StdioOps {
|
|||||||
fn get_constant_value<'a>(&self, name: &str) -> Option<Value>
|
fn get_constant_value<'a>(&self, name: &str) -> Option<Value>
|
||||||
{
|
{
|
||||||
match name {
|
match name {
|
||||||
"stdin" => Some(self.hdl_stdin),
|
"cin" => Some(self.hdl_stdin),
|
||||||
"stdout" => Some(self.hdl_stdout),
|
"cin_r" => Some(self.hdl_stdin_raw),
|
||||||
|
"cout" => Some(self.hdl_stdout),
|
||||||
|
"cout_r" => Some(self.hdl_stdout_raw),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,12 +167,36 @@ impl CrsnExtension for StdioOps {
|
|||||||
-> Result<Option<Value>, Fault>
|
-> Result<Option<Value>, Fault>
|
||||||
{
|
{
|
||||||
if handle == self.hdl_stdin {
|
if handle == self.hdl_stdin {
|
||||||
let data = state.ext_mut::<StdioData>();
|
match console::read_char() {
|
||||||
return Ok(Some(data.console.read_char().expect("stdin read") as u64));
|
Ok(c) => {
|
||||||
|
return Ok(Some(c as Value));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
state.set_flag(Flag::Invalid, true);
|
||||||
|
if e.kind() != io::ErrorKind::InvalidData {
|
||||||
|
state.set_flag(Flag::Eof, true);
|
||||||
|
}
|
||||||
|
return Ok(Some(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle == self.hdl_stdout {
|
if handle == self.hdl_stdin_raw {
|
||||||
return Err(Fault::NotAllowed("Cannot read stdout".into()));
|
match console::read_byte() {
|
||||||
|
Ok(b) => {
|
||||||
|
return Ok(Some(b as Value));
|
||||||
|
}
|
||||||
|
Err(_e) => {
|
||||||
|
state.set_flag(Flag::Invalid, true);
|
||||||
|
state.set_flag(Flag::Eof, true);
|
||||||
|
return Ok(Some(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle == self.hdl_stdout || handle == self.hdl_stdout_raw {
|
||||||
|
state.set_flag(Flag::Invalid, true);
|
||||||
|
return Ok(Some(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -87,18 +209,25 @@ impl CrsnExtension for StdioOps {
|
|||||||
|
|
||||||
if handle == self.hdl_stdout {
|
if handle == self.hdl_stdout {
|
||||||
if let Ok(a_char) = char::try_from((value & 0xFFFF_FFFF) as u32) {
|
if let Ok(a_char) = char::try_from((value & 0xFFFF_FFFF) as u32) {
|
||||||
let data = state.ext_mut::<StdioData>();
|
if console::write_char(a_char).is_err() {
|
||||||
|
state.set_flag(Flag::Eof, true);
|
||||||
let mut b = [0; 4];
|
}
|
||||||
data.console.write(a_char.encode_utf8(&mut b).as_bytes()).expect("stdout write");
|
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Cond::Invalid, true);
|
state.set_flag(Flag::Invalid, true);
|
||||||
}
|
}
|
||||||
return Ok(Some(()));
|
return Ok(Some(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle == self.hdl_stdin {
|
if handle == self.hdl_stdout_raw {
|
||||||
return Err(Fault::NotAllowed("Cannot write stdin".into()));
|
if console::write_byte((value & 0xFF) as u8).is_err() {
|
||||||
|
state.set_flag(Flag::Eof, true);
|
||||||
|
}
|
||||||
|
return Ok(Some(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle == self.hdl_stdin || handle == self.hdl_stdin_raw {
|
||||||
|
state.set_flag(Flag::Invalid, true);
|
||||||
|
return Ok(Some(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
(sym buf r7)
|
(sym buf r7)
|
||||||
(mkbf buf (r0 66 67 68 '\n'))
|
(mkbf buf (r0 66 67 68 '\n'))
|
||||||
|
|
||||||
(bfrpop @stdout @buf)
|
(bfrpop @cout @buf)
|
||||||
(s.nem -1)
|
(s.nem -1)
|
||||||
)
|
)
|
||||||
|
|||||||
+5
-5
@@ -20,27 +20,27 @@
|
|||||||
(:next)
|
(:next)
|
||||||
(bfrd ch @str pos)
|
(bfrd ch @str pos)
|
||||||
(ret.ov)
|
(ret.ov)
|
||||||
(ld @stdout ch)
|
(ld @cout ch)
|
||||||
(inc pos)
|
(inc pos)
|
||||||
(j :next)
|
(j :next)
|
||||||
)
|
)
|
||||||
|
|
||||||
(:loop)
|
(:loop)
|
||||||
(ld r0 @stdin)
|
(ld r0 @cin)
|
||||||
|
|
||||||
(cmp r0 'q'
|
(cmp r0 'q'
|
||||||
(eq? (ld @stdout '\n')
|
(eq? (ld @cout '\n')
|
||||||
(halt)))
|
(halt)))
|
||||||
|
|
||||||
; uppercase ASCII
|
; uppercase ASCII
|
||||||
(cmp r0 'a' (<? (j :badchar)))
|
(cmp r0 'a' (<? (j :badchar)))
|
||||||
(cmp r0 'z' (>? (j :badchar)))
|
(cmp r0 'z' (>? (j :badchar)))
|
||||||
(sub r0 ' ')
|
(sub r0 ' ')
|
||||||
(ld @stdout r0)
|
(ld @cout r0)
|
||||||
(j :loop)
|
(j :loop)
|
||||||
|
|
||||||
(:badchar)
|
(:badchar)
|
||||||
(ld @stdout r0)
|
(ld @cout r0)
|
||||||
(bfrd r0 @TXT T_UNK)
|
(bfrd r0 @TXT T_UNK)
|
||||||
(call print r0)
|
(call print r0)
|
||||||
(j :loop)
|
(j :loop)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
(
|
(
|
||||||
(mkbf r7)
|
(mkbf r7)
|
||||||
(:r)(ld r0 @stdin)
|
(:r)(ld r0 @cin)
|
||||||
(cmp r0 '\n' (eq? (j :q)))
|
(cmp r0 '\n' (eq? (j :q)))
|
||||||
(bfpush @r7 r0)
|
(bfpush @r7 r0)
|
||||||
(j :r)
|
(j :r)
|
||||||
(:q)(bfpop @stdout @r7 (nem? (j :q)))
|
(:q)(bfpop @cout @r7 (nem? (j :q)))
|
||||||
(ld @stdout '\n')
|
(ld @cout '\n')
|
||||||
)
|
)
|
||||||
|
|||||||
Regular → Executable
+5
-2
@@ -1,6 +1,9 @@
|
|||||||
|
#!/usr/bin/env crsn
|
||||||
(
|
(
|
||||||
(:again)
|
(:again)
|
||||||
(ld r0 @stdin (inval? (halt)))
|
(ld r0 @cin
|
||||||
|
(eof? (halt))
|
||||||
|
(inval? (j :again)))
|
||||||
(rcmp r0 'A' 'Z'
|
(rcmp r0 'A' 'Z'
|
||||||
(eq? (ld r1 'A'))
|
(eq? (ld r1 'A'))
|
||||||
(ne? (rcmp r0 'a' 'z'
|
(ne? (rcmp r0 'a' 'z'
|
||||||
@@ -11,6 +14,6 @@
|
|||||||
(mod r0 26)
|
(mod r0 26)
|
||||||
(add r0 r1)
|
(add r0 r1)
|
||||||
(:print)
|
(:print)
|
||||||
(ld @stdout r0)
|
(ld @cout r0)
|
||||||
(j :again)
|
(j :again)
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user