forked from MightyPork/crsn
AMAZING NEW FEATURES ldn, bfio
This commit is contained in:
@@ -275,6 +275,8 @@ Jumping to a label is always safer than a manual skip.
|
|||||||
|
|
||||||
## Built-in Instructions
|
## Built-in Instructions
|
||||||
|
|
||||||
|
...and pseudo-instructions
|
||||||
|
|
||||||
```
|
```
|
||||||
; Do nothing
|
; Do nothing
|
||||||
(nop)
|
(nop)
|
||||||
@@ -282,6 +284,15 @@ Jumping to a label is always safer than a manual skip.
|
|||||||
; Stop execution
|
; Stop execution
|
||||||
(halt)
|
(halt)
|
||||||
|
|
||||||
|
; Define a register alias.
|
||||||
|
; The alias is only valid in the current routine or in the root of the program.
|
||||||
|
; However, if the register is a global register, then the alias is valid everywhere.
|
||||||
|
(sym SYM REG)
|
||||||
|
|
||||||
|
; Define a constant. These are valid in the whole program.
|
||||||
|
; Value must be known at compile time.
|
||||||
|
(def CONST VALUE)
|
||||||
|
|
||||||
; Mark a jump target.
|
; Mark a jump target.
|
||||||
(:LABEL)
|
(:LABEL)
|
||||||
; Numbered labels
|
; Numbered labels
|
||||||
@@ -300,6 +311,21 @@ Jumping to a label is always safer than a manual skip.
|
|||||||
; Skip backward or forward
|
; Skip backward or forward
|
||||||
(s Rd)
|
(s Rd)
|
||||||
|
|
||||||
|
; Copy value
|
||||||
|
(ld Wr Rd)
|
||||||
|
|
||||||
|
; Copy N values. This is especially useful when used with stream handles or buffers.
|
||||||
|
(ldn Wr Rd Rd:count)
|
||||||
|
|
||||||
|
; Swap values
|
||||||
|
(swap RW RW)
|
||||||
|
|
||||||
|
; Store status flags to a register
|
||||||
|
(stf Wr)
|
||||||
|
|
||||||
|
; Load status flags from a register
|
||||||
|
(ldf Rd)
|
||||||
|
|
||||||
; Mark a routine entry point (call target).
|
; Mark a routine entry point (call target).
|
||||||
(routine PROC)
|
(routine PROC)
|
||||||
(routine PROC/A)
|
(routine PROC/A)
|
||||||
@@ -311,6 +337,11 @@ Jumping to a label is always safer than a manual skip.
|
|||||||
; Exit the current routine with return values
|
; Exit the current routine with return values
|
||||||
(ret Rd...)
|
(ret Rd...)
|
||||||
|
|
||||||
|
; Generate a run-time fault with a debugger message
|
||||||
|
(fault)
|
||||||
|
(fault message)
|
||||||
|
(fault "message text")
|
||||||
|
|
||||||
; Deny jumps, skips and run across this address, producing a run-time fault with a message.
|
; Deny jumps, skips and run across this address, producing a run-time fault with a message.
|
||||||
(barrier)
|
(barrier)
|
||||||
(barrier message)
|
(barrier message)
|
||||||
@@ -321,32 +352,6 @@ Jumping to a label is always safer than a manual skip.
|
|||||||
; The label can be a numeric or string label, its sole purpose is tying the two together. They must be unique in the program.
|
; The label can be a numeric or string label, its sole purpose is tying the two together. They must be unique in the program.
|
||||||
(barrier-open LABEL)
|
(barrier-open LABEL)
|
||||||
(barrier-close LABEL)
|
(barrier-close LABEL)
|
||||||
|
|
||||||
; Generate a run-time fault with a debugger message
|
|
||||||
(fault)
|
|
||||||
(fault message)
|
|
||||||
(fault "message text")
|
|
||||||
|
|
||||||
; Copy value
|
|
||||||
(ld Wr Rd)
|
|
||||||
|
|
||||||
; Swap values
|
|
||||||
(swap RW RW)
|
|
||||||
|
|
||||||
; Store status flags to a register
|
|
||||||
(stf Wr)
|
|
||||||
|
|
||||||
; Load status flags from a register
|
|
||||||
(ldf Rd)
|
|
||||||
|
|
||||||
; Define a register alias.
|
|
||||||
; The alias is only valid in the current routine or in the root of the program.
|
|
||||||
; However, if the register is a global register, then the alias is valid everywhere.
|
|
||||||
(sym SYM REG)
|
|
||||||
|
|
||||||
; Define a constant. These are valid in the whole program.
|
|
||||||
; Value must be known at compile time.
|
|
||||||
(def CONST VALUE)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Arithmetic Module
|
## Arithmetic Module
|
||||||
@@ -460,6 +465,24 @@ A buffer needs to be created using one of the init instructions:
|
|||||||
(mkbf Wr (Rd...))
|
(mkbf Wr (Rd...))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Buffers can be as stacks or queues by reading and writing the handle (e.g. `(ld @buf 123)`).
|
||||||
|
The behavior of reads and writes is configurable per stack, and can be changed at any time.
|
||||||
|
The default mode is forward queue.
|
||||||
|
|
||||||
|
This feature may be a bit confusing at first, but it is extremely powerful.
|
||||||
|
One consequence of this feature is that `(ld @buf @buf)` will move items from one end to the other
|
||||||
|
in one or the other direction (queue mode), or do nothing at all (stack mode).
|
||||||
|
|
||||||
|
```list
|
||||||
|
; Set buffer IO mode
|
||||||
|
; Mode is one of:
|
||||||
|
; - BFIO_QUEUE (1)
|
||||||
|
; - BFIO_RQUEUE (2)
|
||||||
|
; - BFIO_STACK (3)
|
||||||
|
; - BFIO_RSTACK (4)
|
||||||
|
(bfio @Obj MODE)
|
||||||
|
```
|
||||||
|
|
||||||
Primitive buffer ops (position is always 0-based)
|
Primitive buffer ops (position is always 0-based)
|
||||||
|
|
||||||
```lisp
|
```lisp
|
||||||
@@ -540,9 +563,9 @@ such as animations.
|
|||||||
; Set pixel color
|
; Set pixel color
|
||||||
(sc-px X Y COLOR)
|
(sc-px X Y COLOR)
|
||||||
|
|
||||||
; Set screen option
|
; Set screen option. Constants are pre-defined.
|
||||||
; 1 ... auto-blit (blit automatically on pixel write when needed to achieve the target FPS)
|
; SCREEN_AUTO_BLIT (1) ... auto-blit (blit automatically on pixel write when needed to achieve the target FPS)
|
||||||
; 2 ... frame rate
|
; SCREEN_FPS (2) ... frame rate
|
||||||
(sc-opt OPTION VALUE)
|
(sc-opt OPTION VALUE)
|
||||||
|
|
||||||
; Blit (render the pixel buffer).
|
; Blit (render the pixel buffer).
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ use sexp::{Sexp, SourcePosition};
|
|||||||
|
|
||||||
use crate::asm::data::{Rd, RdData, RdObj, Wr, RdWr};
|
use crate::asm::data::{Rd, RdData, RdObj, Wr, RdWr};
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
|
use crate::asm::parse::parse_data::{parse_rd, parse_wr, parse_value};
|
||||||
use crate::asm::parse::ParserContext;
|
use crate::asm::parse::ParserContext;
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
|
use crate::asm::data::literal::Value;
|
||||||
|
|
||||||
/// Utility for argument parsing
|
/// Utility for argument parsing
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -85,6 +86,12 @@ impl<'a> TokenParser<'a> {
|
|||||||
Ok(esa)
|
Ok(esa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the next value entry
|
||||||
|
pub fn next_value(&mut self) -> Result<(Value, SourcePosition), CrsnError> {
|
||||||
|
let next = self.next_or_err()?;
|
||||||
|
parse_value(next, self.pcx)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next entry as read location
|
/// Get the next entry as read location
|
||||||
pub fn next_rd(&mut self) -> Result<Rd, CrsnError> {
|
pub fn next_rd(&mut self) -> Result<Rd, CrsnError> {
|
||||||
let next = self.next_or_err()?;
|
let next = self.next_or_err()?;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::asm::patches::ErrWithPos;
|
|||||||
|
|
||||||
fn is_valid_identifier(name: &str) -> bool {
|
fn is_valid_identifier(name: &str) -> bool {
|
||||||
// ascii symbols "!\"#$_&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
// ascii symbols "!\"#$_&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||||
const BLACKLIST : &str = "!\"#$&'()*+,-./:;<=>?@[\\]^`{|}~";
|
const BLACKLIST : &str = "!\"#$&'()*+,./;<=>?@[\\]^`{|}~";
|
||||||
name != "_"
|
name != "_"
|
||||||
&& !name.starts_with(|c: char| c.is_ascii_digit() || BLACKLIST.contains(c))
|
&& !name.starts_with(|c: char| c.is_ascii_digit() || BLACKLIST.contains(c))
|
||||||
&& !name.contains(|c : char| c.is_whitespace() || BLACKLIST.contains(c))
|
&& !name.contains(|c : char| c.is_whitespace() || BLACKLIST.contains(c))
|
||||||
@@ -161,27 +161,34 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse immediate value
|
/// Parse immediate value
|
||||||
pub fn parse_value(tok: Sexp, pcx: &ParserContext) -> Result<Value, CrsnError> {
|
pub fn parse_value(tok: Sexp, pcx: &ParserContext) -> Result<(Value, SourcePosition), CrsnError> {
|
||||||
match tok {
|
match tok {
|
||||||
Sexp::Atom(Atom::I(val), _pos) => {
|
Sexp::Atom(Atom::I(val), pos) => {
|
||||||
Ok(unsafe { std::mem::transmute(val) })
|
Ok((unsafe { std::mem::transmute(val) }, pos))
|
||||||
}
|
}
|
||||||
Sexp::Atom(Atom::U(val), _pos) => {
|
Sexp::Atom(Atom::U(val), pos) => {
|
||||||
Ok(val)
|
Ok((val, pos))
|
||||||
}
|
}
|
||||||
Sexp::Atom(Atom::C(val), _pos) => {
|
Sexp::Atom(Atom::C(val), pos) => {
|
||||||
Ok(val as u64)
|
Ok((val as u64, pos))
|
||||||
}
|
}
|
||||||
Sexp::Atom(Atom::QS(_), pos) => {
|
Sexp::Atom(Atom::QS(_), pos) => {
|
||||||
Err(CrsnError::Parse("quoted string not expected here".into(), pos))
|
Err(CrsnError::Parse("quoted string not expected here".into(), pos))
|
||||||
}
|
}
|
||||||
Sexp::Atom(Atom::F(val), _) => {
|
Sexp::Atom(Atom::F(val), pos) => {
|
||||||
Ok(unsafe { std::mem::transmute(val) })
|
Ok((unsafe { std::mem::transmute(val) }, pos))
|
||||||
}
|
}
|
||||||
Sexp::Atom(Atom::S(s), pos) => {
|
Sexp::Atom(Atom::S(s), pos) => {
|
||||||
let pstate = pcx.state.borrow();
|
let pstate = pcx.state.borrow();
|
||||||
if let Some(val) = pstate.constants.get(&s) {
|
if let Some(val) = pstate.constants.get(&s) {
|
||||||
return Ok(*val);
|
return Ok((*val, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extension constants */
|
||||||
|
for p in pcx.parsers {
|
||||||
|
if let Some(val) = p.get_constant_value(&s) {
|
||||||
|
return Ok((val, pos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(CrsnError::Parse(format!("unknown constant: {}", s).into(), pos))
|
Err(CrsnError::Parse(format!("unknown constant: {}", s).into(), pos))
|
||||||
|
|||||||
@@ -70,8 +70,10 @@ pub enum BuiltinOp {
|
|||||||
/// Deallocate an extension object.
|
/// Deallocate an extension object.
|
||||||
/// The object is released and the handle becomes invalid.
|
/// The object is released and the handle becomes invalid.
|
||||||
Delete(RdObj),
|
Delete(RdObj),
|
||||||
/// Copy value
|
/// Move a value
|
||||||
MoveValue { dst: Wr, src: Rd },
|
MoveValue { dst: Wr, src: Rd },
|
||||||
|
/// Move N values
|
||||||
|
MoveMultipleValues { dst: Wr, src: Rd, count: Rd },
|
||||||
/// Swap two registers
|
/// Swap two registers
|
||||||
SwapValues { a: RdWr, b: RdWr },
|
SwapValues { a: RdWr, b: RdWr },
|
||||||
/// Store runtime status to a register
|
/// Store runtime status to a register
|
||||||
|
|||||||
@@ -109,6 +109,17 @@ impl OpTrait for BuiltinOp {
|
|||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
}
|
}
|
||||||
|
BuiltinOp::MoveMultipleValues { dst, src, count } => {
|
||||||
|
state.clear_status();
|
||||||
|
let mut count = state.read(count)?;
|
||||||
|
let mut last = 0;
|
||||||
|
while count > 0 {
|
||||||
|
last = state.read(src)?;
|
||||||
|
state.write(dst, last)?;
|
||||||
|
count -= 1;
|
||||||
|
}
|
||||||
|
state.update_status(last);
|
||||||
|
}
|
||||||
BuiltinOp::SwapValues { a, b } => {
|
BuiltinOp::SwapValues { a, b } => {
|
||||||
let aa = state.read(a)?;
|
let aa = state.read(a)?;
|
||||||
let bb = state.read(b)?;
|
let bb = state.read(b)?;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
|
|||||||
|
|
||||||
"def" => {
|
"def" => {
|
||||||
let (name, namepos) = parse_constant_name(args.next_or_err()?)?;
|
let (name, namepos) = parse_constant_name(args.next_or_err()?)?;
|
||||||
let value = parse_value(args.next_or_err()?, pcx)?;
|
let (value, _valuepos) = parse_value(args.next_or_err()?, pcx)?;
|
||||||
|
|
||||||
let mut pstate = pcx.state.borrow_mut();
|
let mut pstate = pcx.state.borrow_mut();
|
||||||
if pstate.constants.contains_key(&name) {
|
if pstate.constants.contains_key(&name) {
|
||||||
@@ -189,6 +189,14 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"ldn" => {
|
||||||
|
BuiltinOp::MoveMultipleValues {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
src: args.next_rd()?,
|
||||||
|
count: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"swap" => {
|
"swap" => {
|
||||||
BuiltinOp::SwapValues {
|
BuiltinOp::SwapValues {
|
||||||
a: args.next_rdwr()?,
|
a: args.next_rdwr()?,
|
||||||
@@ -309,7 +317,8 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp {
|
|||||||
}
|
}
|
||||||
BuiltinOp::Delete(obj) => sexp::list(&[A("del"), A(obj)]),
|
BuiltinOp::Delete(obj) => sexp::list(&[A("del"), A(obj)]),
|
||||||
BuiltinOp::MoveValue { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]),
|
BuiltinOp::MoveValue { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]),
|
||||||
BuiltinOp::SwapValues { a, b } => sexp::list(&[A("swp"), A(a), A(b)]),
|
BuiltinOp::MoveMultipleValues { dst, src, count } => sexp::list(&[A("ldn"), A(dst), A(src), A(count)]),
|
||||||
|
BuiltinOp::SwapValues { a, b } => sexp::list(&[A("swap"), A(a), A(b)]),
|
||||||
BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]),
|
BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]),
|
||||||
BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)])
|
BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)])
|
||||||
}
|
}
|
||||||
@@ -382,6 +391,7 @@ mod test {
|
|||||||
("(ld r0 r0)", "(ld r0 r0)"),
|
("(ld r0 r0)", "(ld r0 r0)"),
|
||||||
("(ld r0 156)", "(ld r0 156)"),
|
("(ld r0 156)", "(ld r0 156)"),
|
||||||
("(ld _ -32767)", "(ld _ -32767)"),
|
("(ld _ -32767)", "(ld _ -32767)"),
|
||||||
|
("(ldn _ @r0 7)", "(ldn _ @r0 7)"),
|
||||||
("(stf r0)", "(stf r0)"),
|
("(stf r0)", "(stf r0)"),
|
||||||
("(ldf r0)", "(ldf r0)"),
|
("(ldf r0)", "(ldf r0)"),
|
||||||
("(far :label)", "(far :label)"),
|
("(far :label)", "(far :label)"),
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use crsn::asm::data::{Rd, RdObj, Wr};
|
use crsn::asm::data::{Rd, RdObj, Wr};
|
||||||
|
use crsn::asm::data::literal::Value;
|
||||||
|
use crate::parse::{BUF_IOMODE_QUEUE, BUF_IOMODE_REVERSE_QUEUE, BUF_IOMODE_STACK, BUF_IOMODE_REVERSE_STACK};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum BufValue {
|
pub enum BufValue {
|
||||||
@@ -7,9 +9,35 @@ pub enum BufValue {
|
|||||||
Chars(String),
|
Chars(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum BufIoMode {
|
||||||
|
Queue,
|
||||||
|
ReverseQueue,
|
||||||
|
Stack,
|
||||||
|
ReverseStack,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BufIoMode {
|
||||||
|
pub fn to_value(self) -> Value {
|
||||||
|
match self {
|
||||||
|
BufIoMode::Queue => BUF_IOMODE_QUEUE,
|
||||||
|
BufIoMode::ReverseQueue => BUF_IOMODE_REVERSE_QUEUE,
|
||||||
|
BufIoMode::Stack => BUF_IOMODE_STACK,
|
||||||
|
BufIoMode::ReverseStack => BUF_IOMODE_REVERSE_STACK,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BufIoMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Queue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum BufOps {
|
pub enum BufOps {
|
||||||
New { dst: Wr, value: BufValue },
|
New { dst: Wr, value: BufValue },
|
||||||
|
SetIoMode { obj: RdObj, mode: BufIoMode },
|
||||||
|
|
||||||
// Elementary ops
|
// Elementary ops
|
||||||
Read { dst: Wr, obj: RdObj, idx: Rd },
|
Read { dst: Wr, obj: RdObj, idx: Rd },
|
||||||
|
|||||||
+122
-53
@@ -1,19 +1,25 @@
|
|||||||
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::Flag;
|
||||||
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};
|
||||||
use crsn::sexp;
|
use crsn::sexp;
|
||||||
use crsn::sexp::{Sexp, atom_qs};
|
use crsn::sexp::{atom_qs, Sexp};
|
||||||
use crsn::utils::A;
|
use crsn::utils::A;
|
||||||
|
|
||||||
use crate::defs::{BufOps, BufValue};
|
use crate::defs::{BufIoMode, BufOps, BufValue};
|
||||||
use crsn::asm::instr::cond::Flag;
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
struct Buffer {
|
||||||
|
data: VecDeque<Value>,
|
||||||
|
iomode: BufIoMode,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct ExtData {
|
struct ExtData {
|
||||||
store: HashMap<Value, VecDeque<Value>>,
|
buffers: HashMap<Value, Buffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO optimize and DRY
|
// TODO optimize and DRY
|
||||||
@@ -49,26 +55,38 @@ impl OpTrait for BufOps {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let data: &mut ExtData = state.ext_mut();
|
let data: &mut ExtData = state.ext_mut();
|
||||||
data.store.insert(id, que);
|
data.buffers.insert(id, Buffer {
|
||||||
|
data: que,
|
||||||
|
iomode: Default::default()
|
||||||
|
});
|
||||||
state.write(dst, id)?;
|
state.write(dst, id)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BufOps::SetIoMode { obj, mode } => {
|
||||||
|
state.clear_status();
|
||||||
|
let handle = state.read_obj(obj)?;
|
||||||
|
let store: &mut ExtData = state.ext_mut();
|
||||||
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
|
|
||||||
|
buf.iomode = *mode;
|
||||||
|
}
|
||||||
|
|
||||||
BufOps::Push { obj, src } => {
|
BufOps::Push { obj, src } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let val = state.read(src)?;
|
let val = state.read(src)?;
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
stack.push_back(val);
|
buf.data.push_back(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufOps::Pop { dst, obj } => {
|
BufOps::Pop { dst, obj } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
if let Some(val) = stack.pop_back() {
|
if let Some(val) = buf.data.pop_back() {
|
||||||
let empty = stack.is_empty();
|
let empty = buf.data.is_empty();
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.set_flag(Flag::Empty, empty);
|
state.set_flag(Flag::Empty, empty);
|
||||||
@@ -82,9 +100,9 @@ impl OpTrait for BufOps {
|
|||||||
state.clear_status();
|
state.clear_status();
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let idx = state.read(idx)?;
|
let idx = state.read(idx)?;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
if let Some(val) = stack.get(idx as usize) {
|
if let Some(val) = buf.data.get(idx as usize) {
|
||||||
let val = *val;
|
let val = *val;
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
@@ -96,9 +114,9 @@ impl OpTrait for BufOps {
|
|||||||
BufOps::GetLen { dst, obj } => {
|
BufOps::GetLen { dst, obj } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
let val = stack.len() as Value;
|
let val = buf.data.len() as Value;
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
}
|
}
|
||||||
@@ -108,12 +126,12 @@ impl OpTrait for BufOps {
|
|||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let val = state.read(value)?;
|
let val = state.read(value)?;
|
||||||
let idx = state.read(idx)? as usize;
|
let idx = state.read(idx)? as usize;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
if idx < stack.len() {
|
if idx < buf.data.len() {
|
||||||
stack[idx] = val;
|
buf.data[idx] = val;
|
||||||
} else if idx == stack.len() {
|
} else if idx == buf.data.len() {
|
||||||
stack.push_back(val);
|
buf.data.push_back(val);
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Flag::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
@@ -124,12 +142,12 @@ impl OpTrait for BufOps {
|
|||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let val = state.read(value)?;
|
let val = state.read(value)?;
|
||||||
let idx = state.read(idx)? as usize;
|
let idx = state.read(idx)? as usize;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
if idx < stack.len() {
|
if idx < buf.data.len() {
|
||||||
stack.insert(idx, val);
|
buf.data.insert(idx, val);
|
||||||
} else if idx == stack.len() {
|
} else if idx == buf.data.len() {
|
||||||
stack.push_back(val);
|
buf.data.push_back(val);
|
||||||
} else {
|
} else {
|
||||||
state.set_flag(Flag::Overflow, true);
|
state.set_flag(Flag::Overflow, true);
|
||||||
}
|
}
|
||||||
@@ -139,11 +157,11 @@ impl OpTrait for BufOps {
|
|||||||
state.clear_status();
|
state.clear_status();
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let idx = state.read(idx)? as usize;
|
let idx = state.read(idx)? as usize;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
if idx < stack.len() {
|
if idx < buf.data.len() {
|
||||||
let val = stack.remove(idx).unwrap();
|
let val = buf.data.remove(idx).unwrap();
|
||||||
let empty = stack.is_empty();
|
let empty = buf.data.is_empty();
|
||||||
state.update_status(val);
|
state.update_status(val);
|
||||||
state.write(dst, val)?;
|
state.write(dst, val)?;
|
||||||
state.set_flag(Flag::Empty, empty);
|
state.set_flag(Flag::Empty, empty);
|
||||||
@@ -155,21 +173,21 @@ impl OpTrait for BufOps {
|
|||||||
BufOps::Resize { obj, len } => {
|
BufOps::Resize { obj, len } => {
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let len = state.read(len)? as usize;
|
let len = state.read(len)? as usize;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
stack.resize(len, 0);
|
buf.data.resize(len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufOps::Reverse { obj } => {
|
BufOps::Reverse { obj } => {
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
let len = stack.len();
|
let len = buf.data.len();
|
||||||
if len > 1 {
|
if len > 1 {
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
let mut end = len - 1;
|
let mut end = len - 1;
|
||||||
while start < end {
|
while start < end {
|
||||||
stack.swap(start, end);
|
buf.data.swap(start, end);
|
||||||
start += 1;
|
start += 1;
|
||||||
end -= 1;
|
end -= 1;
|
||||||
}
|
}
|
||||||
@@ -179,20 +197,22 @@ impl OpTrait for BufOps {
|
|||||||
BufOps::AppendBuf { obj, obj2 } => {
|
BufOps::AppendBuf { obj, obj2 } => {
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let handle2 = state.read_obj(obj2)?;
|
let handle2 = state.read_obj(obj2)?;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack2 = stacks.store.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.clone();
|
// TODO figure out how to avoid cloning
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf2 = store.buffers.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.data.clone();
|
||||||
stack.extend(stack2);
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
|
buf.data.extend(buf2);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufOps::PrependBuf { obj, obj2 } => {
|
BufOps::PrependBuf { obj, obj2 } => {
|
||||||
let handle = state.read_obj(obj)?;
|
let handle = state.read_obj(obj)?;
|
||||||
let handle2 = state.read_obj(obj2)?;
|
let handle2 = state.read_obj(obj2)?;
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
let stack2 = stacks.store.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.clone();
|
// TODO figure out how to avoid cloning
|
||||||
let stack = stacks.store.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
let buf2 = store.buffers.get(&handle2).ok_or_else(|| Fault::ObjectNotExist(handle))?.data.clone();
|
||||||
for v in stack2.into_iter().rev() {
|
let buf = store.buffers.get_mut(&handle).ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
stack.push_front(v);
|
for v in buf2.into_iter().rev() {
|
||||||
|
buf.data.push_front(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,12 +277,61 @@ impl OpTrait for BufOps {
|
|||||||
BufOps::PrependBuf { obj, obj2 } => {
|
BufOps::PrependBuf { obj, obj2 } => {
|
||||||
sexp::list(&[A("bfprep"), A(obj), A(obj2)])
|
sexp::list(&[A("bfprep"), A(obj), A(obj2)])
|
||||||
}
|
}
|
||||||
|
BufOps::SetIoMode { obj, mode } => {
|
||||||
|
sexp::list(&[A("bfio"), A(obj), A(mode.to_value())])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
||||||
let stacks: &mut ExtData = state.ext_mut();
|
let store: &mut ExtData = state.ext_mut();
|
||||||
Ok(stacks.store.remove(&handle).map(|_| ()))
|
Ok(store.buffers.remove(&handle).map(|_| ()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run-time method called to read an object (using the object handle syntax)
|
||||||
|
pub(crate) fn read_obj(state: &mut RunState, handle: Value)
|
||||||
|
-> Result<Option<Value>, Fault>
|
||||||
|
{
|
||||||
|
let store: &mut ExtData = state.ext_mut();
|
||||||
|
if let Some(buf) = store.buffers.get_mut(&handle) {
|
||||||
|
match match buf.iomode {
|
||||||
|
BufIoMode::Queue => buf.data.pop_front(),
|
||||||
|
BufIoMode::ReverseQueue => buf.data.pop_back(),
|
||||||
|
BufIoMode::Stack => buf.data.pop_back(),
|
||||||
|
BufIoMode::ReverseStack => buf.data.pop_front()
|
||||||
|
} {
|
||||||
|
None => {
|
||||||
|
state.set_flag(Flag::Overflow, true);
|
||||||
|
state.set_flag(Flag::Empty, true);
|
||||||
|
Ok(Some(0))
|
||||||
|
}
|
||||||
|
Some(val) => {
|
||||||
|
let em = buf.data.is_empty();
|
||||||
|
state.set_flag(Flag::Empty, em);
|
||||||
|
Ok(Some(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run-time method called to write an object (using the object handle syntax)
|
||||||
|
pub(crate) fn write_obj(state: &mut RunState, handle: Value, value: Value) -> Result<Option<()>, Fault>
|
||||||
|
{
|
||||||
|
let store: &mut ExtData = state.ext_mut();
|
||||||
|
if let Some(buf) = store.buffers.get_mut(&handle) {
|
||||||
|
match buf.iomode {
|
||||||
|
BufIoMode::Queue => buf.data.push_back(value),
|
||||||
|
BufIoMode::ReverseQueue => buf.data.push_front(value),
|
||||||
|
BufIoMode::Stack => buf.data.push_back(value),
|
||||||
|
BufIoMode::ReverseStack => buf.data.push_front(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crsn::module::{CrsnExtension, ParseRes};
|
|||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
||||||
use crsn::sexp::SourcePosition;
|
use crsn::sexp::SourcePosition;
|
||||||
|
use crate::parse::{BUF_IOMODE_STACK, BUF_IOMODE_REVERSE_STACK, BUF_IOMODE_QUEUE, BUF_IOMODE_REVERSE_QUEUE};
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -32,4 +33,30 @@ impl CrsnExtension for BufOps {
|
|||||||
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
||||||
exec::drop_obj(state, handle)
|
exec::drop_obj(state, handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run-time method called to read an object (using the object handle syntax)
|
||||||
|
fn read_obj(&self, state: &mut RunState, handle: Value)
|
||||||
|
-> Result<Option<Value>, Fault>
|
||||||
|
{
|
||||||
|
exec::read_obj(state, handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run-time method called to write an object (using the object handle syntax)
|
||||||
|
fn write_obj(&self, state: &mut RunState, handle: Value, value: Value) -> Result<Option<()>, Fault>
|
||||||
|
{
|
||||||
|
exec::write_obj(state, handle, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get value of an extension-provided constant.
|
||||||
|
/// This constant may be an object handle, or a constant value used as argument in some other instruction.
|
||||||
|
fn get_constant_value<'a>(&self, name: &str) -> Option<Value>
|
||||||
|
{
|
||||||
|
match name {
|
||||||
|
"BFIO_STACK" => Some(BUF_IOMODE_STACK),
|
||||||
|
"BFIO_RSTACK" => Some(BUF_IOMODE_REVERSE_STACK),
|
||||||
|
"BFIO_QUEUE" => Some(BUF_IOMODE_QUEUE),
|
||||||
|
"BFIO_RQUEUE" => Some(BUF_IOMODE_REVERSE_QUEUE),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-1
@@ -4,9 +4,15 @@ use crsn::asm::parse::arg_parser::TokenParser;
|
|||||||
use crsn::module::ParseRes;
|
use crsn::module::ParseRes;
|
||||||
use crsn::sexp::{SourcePosition, Sexp, Atom};
|
use crsn::sexp::{SourcePosition, Sexp, Atom};
|
||||||
|
|
||||||
use crate::defs::{BufOps, BufValue};
|
use crate::defs::{BufOps, BufValue, BufIoMode};
|
||||||
use crsn::asm::data::Rd;
|
use crsn::asm::data::Rd;
|
||||||
use crsn::asm::parse::parse_data::parse_rd;
|
use crsn::asm::parse::parse_data::parse_rd;
|
||||||
|
use crsn::asm::data::literal::Value;
|
||||||
|
|
||||||
|
pub const BUF_IOMODE_STACK : Value = 1;
|
||||||
|
pub const BUF_IOMODE_REVERSE_STACK : Value = 2;
|
||||||
|
pub const BUF_IOMODE_QUEUE : Value = 3;
|
||||||
|
pub const BUF_IOMODE_REVERSE_QUEUE : Value = 4;
|
||||||
|
|
||||||
pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
Ok(ParseRes::ext(match keyword {
|
Ok(ParseRes::ext(match keyword {
|
||||||
@@ -40,6 +46,21 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
|
|||||||
BufOps::New { dst, value }
|
BufOps::New { dst, value }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"bfio" => {
|
||||||
|
let obj = args.next_rdobj()?;
|
||||||
|
let (mode, modepos) = args.next_value()?;
|
||||||
|
BufOps::SetIoMode {
|
||||||
|
obj,
|
||||||
|
mode: match mode {
|
||||||
|
BUF_IOMODE_STACK => BufIoMode::Stack,
|
||||||
|
BUF_IOMODE_REVERSE_STACK => BufIoMode::ReverseStack,
|
||||||
|
BUF_IOMODE_QUEUE => BufIoMode::Queue,
|
||||||
|
BUF_IOMODE_REVERSE_QUEUE => BufIoMode::ReverseQueue,
|
||||||
|
_ => return Err(CrsnError::Parse("Bad buffer iomode".into(), modepos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"bfrd" => {
|
"bfrd" => {
|
||||||
let dst = args.next_wr()?;
|
let dst = args.next_wr()?;
|
||||||
let obj = args.next_rdobj()?;
|
let obj = args.next_rdobj()?;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crsn::asm::data::{Rd, Wr};
|
use crsn::asm::data::{Rd, Wr};
|
||||||
|
use crsn::asm::data::literal::Value;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum ScreenOp {
|
pub enum ScreenOp {
|
||||||
@@ -31,7 +32,7 @@ pub enum ScreenOp {
|
|||||||
force: Rd,
|
force: Rd,
|
||||||
},
|
},
|
||||||
SetOpt {
|
SetOpt {
|
||||||
opt: Rd,
|
opt: Value,
|
||||||
val: Rd,
|
val: Rd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ impl Default for Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const OPT_AUTO_BLIT: u64 = 1;
|
pub const OPT_AUTO_BLIT: u64 = 1;
|
||||||
const OPT_FRAME_RATE: u64 = 2;
|
pub const OPT_FRAME_RATE: u64 = 2;
|
||||||
|
|
||||||
// Hack for Window
|
// Hack for Window
|
||||||
unsafe impl std::marker::Send for Backend {}
|
unsafe impl std::marker::Send for Backend {}
|
||||||
@@ -72,11 +72,10 @@ impl OpTrait for ScreenOp {
|
|||||||
|
|
||||||
ScreenOp::SetOpt { opt, val } => {
|
ScreenOp::SetOpt { opt, val } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let opt = state.read(opt)?;
|
|
||||||
let val = state.read(val)?;
|
let val = state.read(val)?;
|
||||||
let backend: &mut Backend = state.ext_mut();
|
let backend: &mut Backend = state.ext_mut();
|
||||||
|
|
||||||
match opt {
|
match *opt {
|
||||||
OPT_AUTO_BLIT => {
|
OPT_AUTO_BLIT => {
|
||||||
backend.opts.auto_blit = val != 0;
|
backend.opts.auto_blit = val != 0;
|
||||||
debug!("Set auto blit to {:?}", backend.opts.auto_blit);
|
debug!("Set auto blit to {:?}", backend.opts.auto_blit);
|
||||||
@@ -85,9 +84,8 @@ impl OpTrait for ScreenOp {
|
|||||||
backend.opts.frame_rate = Duration::from_micros(1_000_000 as u64 / val);
|
backend.opts.frame_rate = Duration::from_micros(1_000_000 as u64 / val);
|
||||||
debug!("Set frame rate to {:?}", backend.opts.frame_rate);
|
debug!("Set frame rate to {:?}", backend.opts.frame_rate);
|
||||||
}
|
}
|
||||||
other => {
|
_other => {
|
||||||
warn!("Bad screen opt: {}", other);
|
unreachable!()
|
||||||
state.set_flag(Flag::Invalid, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use crsn::asm::instr::op::OpKind;
|
|||||||
use crsn::asm::parse::arg_parser::TokenParser;
|
use crsn::asm::parse::arg_parser::TokenParser;
|
||||||
use crsn::module::{CrsnExtension, ParseRes};
|
use crsn::module::{CrsnExtension, ParseRes};
|
||||||
use crsn::sexp::SourcePosition;
|
use crsn::sexp::SourcePosition;
|
||||||
|
use crsn::asm::data::literal::Value;
|
||||||
|
use crate::exec::{OPT_AUTO_BLIT, OPT_FRAME_RATE};
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -28,4 +30,15 @@ impl CrsnExtension for ScreenOps {
|
|||||||
fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
parse::parse(pos, keyword, args)
|
parse::parse(pos, keyword, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get value of an extension-provided constant.
|
||||||
|
/// This constant may be an object handle, or a constant value used as argument in some other instruction.
|
||||||
|
fn get_constant_value<'a>(&self, name: &str) -> Option<Value>
|
||||||
|
{
|
||||||
|
match name {
|
||||||
|
"SCREEN_AUTO_BLIT" => Some(OPT_AUTO_BLIT),
|
||||||
|
"SCREEN_FPS" => Some(OPT_FRAME_RATE),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ use crsn::sexp::SourcePosition;
|
|||||||
|
|
||||||
use crate::defs::ScreenOp;
|
use crate::defs::ScreenOp;
|
||||||
|
|
||||||
|
use super::exec::OPT_AUTO_BLIT;
|
||||||
|
use super::exec::OPT_FRAME_RATE;
|
||||||
|
|
||||||
pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
Ok(ParseRes::ext(match keyword {
|
Ok(ParseRes::ext(match keyword {
|
||||||
"sc-init" => {
|
"sc-init" => {
|
||||||
@@ -35,8 +38,19 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
|
|||||||
}
|
}
|
||||||
|
|
||||||
"sc-opt" => {
|
"sc-opt" => {
|
||||||
|
let (val, valopt) = args.next_value()?;
|
||||||
ScreenOp::SetOpt {
|
ScreenOp::SetOpt {
|
||||||
opt: args.next_rd()?,
|
opt: match val {
|
||||||
|
OPT_AUTO_BLIT => {
|
||||||
|
OPT_AUTO_BLIT // TODO use enum
|
||||||
|
}
|
||||||
|
OPT_FRAME_RATE => {
|
||||||
|
OPT_FRAME_RATE
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Bad screen option".into(), valopt));
|
||||||
|
}
|
||||||
|
},
|
||||||
val: args.next_rd()?,
|
val: args.next_rd()?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
(
|
||||||
|
(mkbf r0)
|
||||||
|
|
||||||
|
; Default mode - queue
|
||||||
|
(ld @r0 1)
|
||||||
|
(ld @r0 2)
|
||||||
|
(ld @r0 3)
|
||||||
|
(bfrd r1 @r0 2) (cmp r1 3 (ne? (fault))) ; last is 3
|
||||||
|
(ld r1 @r0) (cmp r1 1 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 2 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 3 (ne? (fault)))
|
||||||
|
|
||||||
|
(bfio @r0 BFIO_QUEUE)
|
||||||
|
(ld @r0 1)
|
||||||
|
(ld @r0 2)
|
||||||
|
(ld @r0 3)
|
||||||
|
(bfrd r1 @r0 2) (cmp r1 3 (ne? (fault))) ; last is 3
|
||||||
|
(ld r1 @r0) (cmp r1 1 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 2 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 3 (ne? (fault)))
|
||||||
|
|
||||||
|
(bfio @r0 BFIO_RQUEUE)
|
||||||
|
(ld @r0 1)
|
||||||
|
(ld @r0 2)
|
||||||
|
(ld @r0 3)
|
||||||
|
(bfrd r1 @r0 0) (cmp r1 3 (ne? (fault)))
|
||||||
|
(bfrd r1 @r0 2) (cmp r1 1 (ne? (fault))) ; last is 1
|
||||||
|
(ld r1 @r0) (cmp r1 1 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 2 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 3 (ne? (fault)))
|
||||||
|
|
||||||
|
(bfio @r0 BFIO_STACK)
|
||||||
|
(ld @r0 1)
|
||||||
|
(ld @r0 2)
|
||||||
|
(ld @r0 3)
|
||||||
|
(bfrd r1 @r0 0) (cmp r1 1 (ne? (fault)))
|
||||||
|
(bfrd r1 @r0 2) (cmp r1 3 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 3 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 2 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 1 (ne? (fault)))
|
||||||
|
|
||||||
|
(bfio @r0 BFIO_RSTACK)
|
||||||
|
(ld @r0 1)
|
||||||
|
(ld @r0 2)
|
||||||
|
(ld @r0 3)
|
||||||
|
(bfrd r1 @r0 0) (cmp r1 3 (ne? (fault)))
|
||||||
|
(bfrd r1 @r0 2) (cmp r1 1 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 3 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 2 (ne? (fault)))
|
||||||
|
(ld r1 @r0) (cmp r1 1 (ne? (fault)))
|
||||||
|
|
||||||
|
(del @r0)
|
||||||
|
)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
(
|
||||||
|
(mkbf r0)
|
||||||
|
(ldn @r0 @cin 5)
|
||||||
|
(bfrev @r0)
|
||||||
|
(ldn @cout @r0 5)
|
||||||
|
(del @r0)
|
||||||
|
)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
; Set log level to "info" or above for the best results!
|
; Set log level to "info" or above for the best results!
|
||||||
(
|
(
|
||||||
(sc-init 800 600)
|
(sc-init 800 600)
|
||||||
(sc-opt 1 1) ; auto blit
|
(sc-opt SCREEN_AUTO_BLIT 1)
|
||||||
(sc-opt 2 25) ; frame rate
|
(sc-opt SCREEN_FPS 25)
|
||||||
|
|
||||||
(sym x r0) (sym y r1) (sym dx r2) (sym dy r3) (sym color r5)
|
(sym x r0) (sym y r1) (sym dx r2) (sym dy r3) (sym color r5)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user