Browse Source

cleanup. remove conditional jumps, replaced by condition embedded in the enum

Ondřej Hruška 11 months ago
parent
commit
986f3be6a2
Signed by: Ondřej Hruška <ondra@ondrovo.com> GPG key ID: 2C5FD5035250423D

+ 1 - 0
_stash/README.txt View File

@@ -0,0 +1 @@
1
+Files in this folder were developed for crsn but are not currently used by core or any extension.

crsn/src/runtime/mlock.rs → _stash/mlock.rs View File


crsn/src/runtime/span.rs → _stash/span.rs View File


crsn/src/runtime/sparse.rs → _stash/sparse.rs View File


+ 3 - 3
crsn/src/asm/data/reg.rs View File

@@ -26,19 +26,19 @@ impl Display for Register {
26 26
 pub fn parse_reg(name: &str) -> anyhow::Result<Register> {
27 27
     // TODO deduplicate code
28 28
     if let Some(rn) = name.strip_prefix("arg") {
29
-        if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
29
+        if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
30 30
             Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
31 31
         }
32 32
         let val: u8 = rn.parse()?;
33 33
         Ok(Register::Arg(val))
34 34
     } else if let Some(rn) = name.strip_prefix("res") {
35
-        if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
35
+        if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
36 36
             Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
37 37
         }
38 38
         let val: u8 = rn.parse()?;
39 39
         Ok(Register::Res(val))
40 40
     } else if let Some(rn) = name.strip_prefix("r") {
41
-        if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
41
+        if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
42 42
             Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
43 43
         }
44 44
         let val: u8 = rn.parse()?;

+ 1 - 1
crsn/src/asm/error.rs View File

@@ -1,11 +1,11 @@
1 1
 use std::borrow::Cow;
2
+use std::num::ParseIntError;
2 3
 
3 4
 use thiserror::Error;
4 5
 
5 6
 use crate::asm::data::{Mask, Register};
6 7
 use crate::asm::data::literal::Label;
7 8
 use crate::asm::instr::Cond;
8
-use std::num::ParseIntError;
9 9
 
10 10
 /// csn_asm unified error type
11 11
 #[derive(Error, Debug)]

+ 33 - 25
crsn/src/asm/instr/flatten.rs View File

@@ -4,9 +4,10 @@ use std::sync::atomic::{AtomicU32, Ordering};
4 4
 use crate::asm::data::{Rd, RdData};
5 5
 use crate::asm::data::literal::{Label, Value};
6 6
 use crate::asm::error::{AsmError, CrsnError};
7
-use crate::asm::instr::{Cond, Instr, Op, Routine};
8
-use crate::builtin::defs::BuiltinOp;
7
+use crate::asm::instr::{Cond, InstrWithBranches, Op, Routine};
8
+use crate::asm::instr::op::OpKind;
9 9
 use crate::builtin::defs::Barrier;
10
+use crate::builtin::defs::BuiltinOp;
10 11
 
11 12
 /// A trait for something that can turn into multiple instructions
12 13
 pub trait Flatten {
@@ -19,7 +20,7 @@ impl Flatten for () {
19 20
     }
20 21
 }
21 22
 
22
-impl Flatten for Instr {
23
+impl Flatten for InstrWithBranches {
23 24
     fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
24 25
         let mut ops = vec![self.op];
25 26
 
@@ -37,8 +38,21 @@ impl Flatten for Instr {
37 38
                 } else {
38 39
                     Label::unique(label_num)
39 40
                 };
40
-                ops.push(BuiltinOp::JumpIf(!cond, next_lbl.clone()).into());
41
-                ops.extend(branch.flatten(label_num)?);
41
+
42
+                let mut flattened = branch.flatten(label_num)?;
43
+
44
+                if flattened.len() == 0 {
45
+                    ops.push(Op { cond: Some(cond), kind: BuiltinOp::Jump(end_lbl.clone()).into() });
46
+                } else if flattened.len() == 1 && flattened[0].cond.is_none() && branch_count == 1 {
47
+                    // optimization for single-branch conditionals with a single instruction
48
+                    ops.push(Op { cond: Some(cond), kind: flattened.remove(0).kind });
49
+                } else {
50
+                    ops.push(Op {
51
+                        kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
52
+                        cond: Some(!cond),
53
+                    });
54
+                    ops.extend(flattened);
55
+                }
42 56
 
43 57
                 if cnt != branch_count - 1 {
44 58
                     ops.push(BuiltinOp::Jump(end_lbl.clone()).into());
@@ -64,14 +78,13 @@ impl Flatten for Vec<Box<dyn Flatten>> {
64 78
 
65 79
 impl Flatten for Routine {
66 80
     fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
67
-        let skip_label = Label::Numbered(label_num.fetch_add(1, Ordering::Relaxed));
81
+        let skip_label = Label::unique(label_num);
68 82
 
69
-        let mut ops : Vec<Op> = vec![
83
+        let mut ops: Vec<Op> = vec![
70 84
             BuiltinOp::Barrier {
71 85
                 kind: Barrier::Open(skip_label.clone()),
72
-                msg: Some(format!("proc {} start", self.name).into())
86
+                msg: Some(format!("proc {} start", self.name).into()),
73 87
             }.into(),
74
-
75 88
             BuiltinOp::Routine(self.name.clone()).into(),
76 89
         ];
77 90
 
@@ -80,7 +93,7 @@ impl Flatten for Routine {
80 93
         ops.push(
81 94
             BuiltinOp::Barrier {
82 95
                 kind: Barrier::Close(skip_label.clone()),
83
-                msg: Some(format!("proc {} end", self.name).into())
96
+                msg: Some(format!("proc {} end", self.name).into()),
84 97
             }.into()
85 98
         );
86 99
 
@@ -92,7 +105,7 @@ impl Flatten for Routine {
92 105
 pub fn labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> {
93 106
     let mut label_positions = HashMap::<Label, usize>::new();
94 107
     for (n, op) in ops.iter().enumerate() {
95
-        if let Op::BuiltIn(BuiltinOp::Label(name)) = op {
108
+        if let OpKind::BuiltIn(BuiltinOp::Label(name)) = &op.kind {
96 109
             label_positions.insert(name.clone(), n - label_positions.len());
97 110
         }
98 111
     }
@@ -100,28 +113,23 @@ pub fn labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> {
100 113
     let mut cleaned = vec![];
101 114
     let mut skipped = 0;
102 115
     for (n, op) in ops.into_iter().enumerate() {
103
-        match op {
104
-            Op::BuiltIn(BuiltinOp::Label(_)) => {
116
+        match op.kind {
117
+            OpKind::BuiltIn(BuiltinOp::Label(_)) => {
105 118
                 skipped += 1;
106 119
             }
107
-            Op::BuiltIn(BuiltinOp::Jump(target)) => {
108
-                if let Some(dest) = label_positions.get(&target) {
109
-                    let skip = *dest as isize - n as isize + skipped;
110
-                    cleaned.push(Op::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))));
111
-                } else {
112
-                    return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
113
-                }
114
-            }
115
-            Op::BuiltIn(BuiltinOp::JumpIf(cond, target)) => {
120
+            OpKind::BuiltIn(BuiltinOp::Jump(target)) => {
116 121
                 if let Some(dest) = label_positions.get(&target) {
117 122
                     let skip = *dest as isize - n as isize + skipped;
118
-                    cleaned.push(Op::BuiltIn(BuiltinOp::SkipIf(cond, Rd::new(RdData::Immediate(skip as Value)))));
123
+                    cleaned.push(Op {
124
+                        cond: op.cond,
125
+                        kind: OpKind::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))),
126
+                    });
119 127
                 } else {
120 128
                     return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
121 129
                 }
122 130
             }
123
-            other => {
124
-                cleaned.push(other);
131
+            _ => {
132
+                cleaned.push(op);
125 133
             }
126 134
         }
127 135
     }

+ 1 - 1
crsn/src/asm/instr/mod.rs View File

@@ -9,7 +9,7 @@ pub mod cond;
9 9
 mod flatten;
10 10
 
11 11
 /// A higher-level instruction
12
-pub struct Instr {
12
+pub struct InstrWithBranches {
13 13
     pub op: Op,
14 14
     pub branches: Option<Vec<(Cond, Box<dyn Flatten>)>>,
15 15
 }

+ 20 - 4
crsn/src/asm/instr/op.rs View File

@@ -1,5 +1,6 @@
1 1
 use std::fmt::Debug;
2 2
 
3
+use crate::asm::instr::Cond;
3 4
 use crate::builtin::defs::BuiltinOp;
4 5
 use crate::module::{EvalRes, OpTrait};
5 6
 use crate::runtime::fault::Fault;
@@ -7,19 +8,34 @@ use crate::runtime::run_thread::{info::ThreadInfo, state::RunState};
7 8
 
8 9
 /// A higher level simple opration
9 10
 #[derive(Debug)]
10
-pub enum Op {
11
+pub enum OpKind {
11 12
     BuiltIn(BuiltinOp),
12 13
     /// Instruction added by an extension
13 14
     Ext(Box<dyn OpTrait>),
14 15
 }
15 16
 
17
+#[derive(Debug)]
18
+pub struct Op {
19
+    pub cond: Option<Cond>,
20
+    pub kind: OpKind,
21
+}
22
+
16 23
 impl OpTrait for Op {
17 24
     fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
18
-        match self {
19
-            Op::BuiltIn(op) => {
25
+        if let Some(cond) = self.cond {
26
+            if !state.test_cond(cond) {
27
+                return Ok(EvalRes {
28
+                    cycles: 0,
29
+                    advance: 1,
30
+                });
31
+            }
32
+        }
33
+
34
+        match &self.kind {
35
+            OpKind::BuiltIn(op) => {
20 36
                 op.execute(ti, state)
21 37
             }
22
-            Op::Ext(op) => {
38
+            OpKind::Ext(op) => {
23 39
                 op.execute(ti, state)
24 40
             }
25 41
         }

+ 0 - 6
crsn/src/asm/mod.rs View File

@@ -24,11 +24,5 @@ pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Resu
24 24
 
25 25
     let ops = parse::parse(source, &pcx)?;
26 26
 
27
-    trace!("--- Compiled program ---");
28
-    for (n, op) in ops.iter().enumerate() {
29
-        trace!("{:04} : {:?}", n, op);
30
-    }
31
-    trace!("------------------------");
32
-
33 27
     Ok(Program::new(ops, parsers)?)
34 28
 }

+ 7 - 7
crsn/src/asm/parse/parse_data.rs View File

@@ -16,7 +16,7 @@ fn is_valid_identifier(name: &str) -> bool {
16 16
 
17 17
 /// Parse register alias
18 18
 pub fn parse_reg_alias(name: Option<Sexp>) -> Result<RegisterAlias, CrsnError> {
19
-    trace!("parse reg alias: {:?}", name);
19
+    // trace!("parse reg alias: {:?}", name);
20 20
 
21 21
     let name = expect_string_atom(name)?;
22 22
 
@@ -29,7 +29,7 @@ pub fn parse_reg_alias(name: Option<Sexp>) -> Result<RegisterAlias, CrsnError> {
29 29
 
30 30
 /// Parse constant name
31 31
 pub fn parse_constant_name(name: Option<Sexp>) -> Result<ConstantName, CrsnError> {
32
-    trace!("parse const name: {:?}", name);
32
+    // trace!("parse const name: {:?}", name);
33 33
 
34 34
     let name = expect_string_atom(name)?;
35 35
 
@@ -42,7 +42,7 @@ pub fn parse_constant_name(name: Option<Sexp>) -> Result<ConstantName, CrsnError
42 42
 
43 43
 /// Parse a label
44 44
 pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> {
45
-    trace!("parse label: {:?}", name);
45
+    // trace!("parse label: {:?}", name);
46 46
 
47 47
     let name = expect_string_atom(name)?;
48 48
     Ok(Label::Named(name.trim_start_matches(':').into()))
@@ -50,7 +50,7 @@ pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> {
50 50
 
51 51
 /// Parse data disposition (address/value, without the read/write restriction)
52 52
 pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDisp, CrsnError> {
53
-    trace!("parse data: {:?}", tok);
53
+    // trace!("parse data: {:?}", tok);
54 54
 
55 55
     let tok = if let Some(tok) = tok {
56 56
         tok
@@ -103,7 +103,7 @@ pub fn parse_value(tok: Option<Sexp>) -> Result<Value, CrsnError> {
103 103
         return Err(CrsnError::Parse("Expected value token".into()));
104 104
     };
105 105
 
106
-    trace!("parse value: {:?}", tok);
106
+    // trace!("parse value: {:?}", tok);
107 107
 
108 108
     match &tok {
109 109
         Sexp::Atom(Atom::I(val)) => {
@@ -120,7 +120,7 @@ pub fn parse_value(tok: Option<Sexp>) -> Result<Value, CrsnError> {
120 120
 
121 121
 
122 122
 pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
123
-    trace!("parse u64 from {}", literal);
123
+    // trace!("parse u64 from {}", literal);
124 124
     let mut without_underscores = Cow::Borrowed(literal);
125 125
     if without_underscores.contains('_') {
126 126
         without_underscores = without_underscores.replace('_', "").into();
@@ -136,7 +136,7 @@ pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
136 136
 }
137 137
 
138 138
 pub fn parse_i64(literal: &str) -> anyhow::Result<i64> {
139
-    trace!("parse i64 from {}", literal);
139
+    // trace!("parse i64 from {}", literal);
140 140
     if let Some(_value) = literal.strip_prefix("-") {
141 141
         Ok(-1 * i64::try_from(parse_u64(literal)?)?)
142 142
     } else {

+ 3 - 6
crsn/src/asm/parse/parse_instr.rs View File

@@ -1,19 +1,16 @@
1 1
 use sexp::Sexp;
2 2
 
3
-use crate::asm::data::literal::RoutineName;
4
-use crate::asm::data::Register;
5 3
 use crate::asm::error::CrsnError;
6
-use crate::asm::instr::{Flatten, Instr, Routine};
4
+use crate::asm::instr::{Flatten, InstrWithBranches};
7 5
 use crate::asm::parse::arg_parser::TokenParser;
8 6
 use crate::asm::parse::parse_cond::parse_cond_branch;
9
-use crate::asm::parse::parse_data::parse_reg_alias;
7
+use crate::asm::parse::parse_routine::parse_routine;
10 8
 use crate::asm::parse::ParserContext;
11 9
 use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
12 10
 use crate::asm::patches::SexpIsA;
13 11
 use crate::module::ParseRes;
14 12
 
15 13
 use super::parse_op::parse_op;
16
-use crate::asm::parse::parse_routine::parse_routine;
17 14
 
18 15
 pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
19 16
     let mut parsed = vec![];
@@ -66,7 +63,7 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext)
66 63
         };
67 64
 
68 65
         if let Some(op) = parse_op(name.as_str(), arg_tokens)? {
69
-            parsed.push(Box::new(Instr {
66
+            parsed.push(Box::new(InstrWithBranches {
70 67
                 op,
71 68
                 branches,
72 69
             }));

+ 12 - 2
crsn/src/asm/parse/parse_op.rs View File

@@ -1,16 +1,26 @@
1 1
 use crate::asm::error::CrsnError;
2
+use crate::asm::instr::cond::parse_cond;
2 3
 use crate::asm::instr::Op;
3 4
 use crate::asm::parse::arg_parser::TokenParser;
4 5
 use crate::builtin::parse::BuiltinOps;
5 6
 use crate::module::ParseRes;
6 7
 
7
-pub fn parse_op<'a>(keyword: &str, mut arg_tokens: TokenParser<'a>) -> Result<Option<Op>, CrsnError> {
8
+pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>) -> Result<Option<Op>, CrsnError> {
8 9
     // Include built-in instructions
9 10
     let builtins = [BuiltinOps::new()];
11
+    let mut cond = None;
12
+
13
+    if let Some(pos) = keyword.find('.') {
14
+        cond = Some(parse_cond(&keyword[(pos + 1)..])?);
15
+        keyword = &keyword[..pos];
16
+    }
10 17
 
11 18
     for p in builtins.iter().chain(arg_tokens.pcx.parsers) {
12 19
         arg_tokens = match p.parse_op(keyword, arg_tokens) {
13
-            Ok(ParseRes::Parsed(op)) => return Ok(Some(op)),
20
+            Ok(ParseRes::Parsed(kind)) => return Ok(Some(Op {
21
+                cond,
22
+                kind,
23
+            })),
14 24
             Ok(ParseRes::ParsedNone) => return Ok(None),
15 25
             Ok(ParseRes::Unknown(to_reuse)) => {
16 26
                 if to_reuse.parsing_started() {

+ 6 - 6
crsn/src/asm/parse/parse_routine.rs View File

@@ -1,13 +1,13 @@
1 1
 use sexp::Sexp;
2
-use crate::asm::parse::{ParserContext, parse_instructions};
3
-use crate::asm::instr::{Flatten, Routine};
2
+
3
+use crate::asm::data::Register;
4 4
 use crate::asm::error::CrsnError;
5
-use crate::asm::parse::sexp_expect::expect_string_atom;
5
+use crate::asm::instr::{Flatten, Routine};
6
+use crate::asm::parse::{parse_instructions, ParserContext};
6 7
 use crate::asm::parse::arg_parser::TokenParser;
7
-use crate::asm::patches::SexpIsA;
8 8
 use crate::asm::parse::parse_data::parse_reg_alias;
9
-use crate::asm::data::Register;
10
-use crate::asm::data::literal::RoutineName;
9
+use crate::asm::parse::sexp_expect::expect_string_atom;
10
+use crate::asm::patches::SexpIsA;
11 11
 use crate::builtin::parse::parse_routine_name;
12 12
 
13 13
 pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {

+ 14 - 10
crsn/src/builtin/defs.rs View File

@@ -1,6 +1,7 @@
1 1
 use crate::asm::data::{Rd, RdObj, Wr};
2 2
 use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
3
-use crate::asm::instr::{Cond, Op};
3
+use crate::asm::instr::Op;
4
+use crate::asm::instr::op::OpKind;
4 5
 
5 6
 #[derive(Debug)]
6 7
 pub enum Barrier {
@@ -9,7 +10,7 @@ pub enum Barrier {
9 10
     /// Closing counterpart to the Open barrier
10 11
     Close(Label),
11 12
     /// Stand-alone barrier
12
-    Standalone
13
+    Standalone,
13 14
 }
14 15
 
15 16
 #[derive(Debug)]
@@ -26,10 +27,6 @@ pub enum BuiltinOp {
26 27
     Label(Label),
27 28
     /// Jump to a label
28 29
     Jump(Label),
29
-    /// Jump to a label if a flag is set
30
-    JumpIf(Cond, Label),
31
-    /// Far jump to a label if a flag is set
32
-    FarJumpIf(Cond, Label),
33 30
     /// Mark a far jump target (can be jumped to from another routine).
34 31
     /// This label is preserved in optimized code.
35 32
     FarLabel(Label),
@@ -45,12 +42,10 @@ pub enum BuiltinOp {
45 42
     Routine(RoutineName),
46 43
     /// Skip backward or forward. The skip count can be defined by an argument.
47 44
     Skip(Rd),
48
-    /// Skip if a flag is set
49
-    SkipIf(Cond, Rd),
50 45
     /// Deny jumps, skips and run across this address, producing a run-time fault.
51 46
     Barrier {
52 47
         kind: Barrier,
53
-        msg: Option<DebugMsg>
48
+        msg: Option<DebugMsg>,
54 49
     },
55 50
     /// Generate a run-time fault with a debugger message
56 51
     Fault(Option<DebugMsg>),
@@ -67,6 +62,15 @@ pub enum BuiltinOp {
67 62
 
68 63
 impl From<BuiltinOp> for Op {
69 64
     fn from(bo: BuiltinOp) -> Self {
70
-        Op::BuiltIn(bo)
65
+        Op {
66
+            kind: bo.into(),
67
+            cond: None,
68
+        }
69
+    }
70
+}
71
+
72
+impl From<BuiltinOp> for OpKind {
73
+    fn from(bo: BuiltinOp) -> Self {
74
+        OpKind::BuiltIn(bo)
71 75
     }
72 76
 }

+ 3 - 45
crsn/src/builtin/exec.rs View File

@@ -3,7 +3,7 @@ use std::time::Duration;
3 3
 use crate::asm::data::{Rd, RdData};
4 4
 use crate::asm::data::literal::Addr;
5 5
 use crate::asm::instr::Cond;
6
-use crate::builtin::defs::{BuiltinOp, Barrier};
6
+use crate::builtin::defs::{Barrier, BuiltinOp};
7 7
 use crate::module::{EvalRes, OpTrait};
8 8
 use crate::runtime::fault::Fault;
9 9
 use crate::runtime::frame::StackFrame;
@@ -59,41 +59,8 @@ impl OpTrait for BuiltinOp {
59 59
                     }
60 60
                 }
61 61
             }
62
-            BuiltinOp::Jump(name) => {
63
-                unimplemented!()
64
-                // match program.find_local_label(state.get_pc(), name) {
65
-                //     Ok(pos) => {
66
-                //         state.set_pc(pos);
67
-                //     }
68
-                //     Err(e) => {
69
-                //         return Err(e);
70
-                //     }
71
-                // }
72
-            }
73
-            BuiltinOp::JumpIf(cond, name) => {
74
-                unimplemented!()
75
-                // if state.test_cond(*cond) {
76
-                //     match program.find_local_label(state.get_pc(), name) {
77
-                //         Ok(pos) => {
78
-                //             state.set_pc(pos);
79
-                //         }
80
-                //         Err(e) => {
81
-                //             return Err(e);
82
-                //         }
83
-                //     }
84
-                // }
85
-            }
86
-            BuiltinOp::FarJumpIf(cond, name) => {
87
-                if state.test_cond(*cond) {
88
-                    match program.find_far_label(name) {
89
-                        Ok(pos) => {
90
-                            state.set_pc(pos);
91
-                        }
92
-                        Err(e) => {
93
-                            return Err(e);
94
-                        }
95
-                    }
96
-                }
62
+            BuiltinOp::Jump(_name) => {
63
+                panic!("jump not translated to skip by assembler!");
97 64
             }
98 65
             BuiltinOp::Call(name, args) => {
99 66
                 match program.find_routine(&name) {
@@ -134,15 +101,6 @@ impl OpTrait for BuiltinOp {
134 101
                 let pc = state.get_pc();
135 102
                 program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?;
136 103
             }
137
-            BuiltinOp::SkipIf(cond, val) => {
138
-                if state.test_cond(*cond) {
139
-                    debug!("Skipping");
140
-                    let steps = state.read(*val)?;
141
-                    res.advance = i64::from_ne_bytes(steps.to_ne_bytes());
142
-                    let pc = state.get_pc();
143
-                    program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?;
144
-                }
145
-            }
146 104
             BuiltinOp::Move { dst, src } => {
147 105
                 state.clear_status();
148 106
                 let val = state.read(*src)?;

+ 8 - 29
crsn/src/builtin/parse.rs View File

@@ -3,12 +3,11 @@ use sexp::{Atom, Sexp};
3 3
 use crate::asm::data::literal::{Label, RoutineName};
4 4
 use crate::asm::data::reg::parse_reg;
5 5
 use crate::asm::error::CrsnError;
6
-use crate::asm::instr::cond::parse_cond;
7
-use crate::asm::instr::Op;
6
+use crate::asm::instr::op::OpKind;
8 7
 use crate::asm::parse::arg_parser::TokenParser;
9 8
 use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_rd, parse_reg_alias, parse_value};
10 9
 use crate::asm::parse::sexp_expect::expect_string_atom;
11
-use crate::builtin::defs::{BuiltinOp, Barrier};
10
+use crate::builtin::defs::{Barrier, BuiltinOp};
12 11
 use crate::module::{CrsnExtension, ParseRes};
13 12
 
14 13
 #[derive(Debug, Clone)]
@@ -29,10 +28,10 @@ impl CrsnExtension for BuiltinOps {
29 28
         "builtin"
30 29
     }
31 30
 
32
-    fn parse_op<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
31
+    fn parse_op<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
33 32
         let pcx = args.pcx;
34 33
 
35
-        Ok(ParseRes::Parsed(Op::BuiltIn(match keyword {
34
+        Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword {
36 35
             "nop" => {
37 36
                 BuiltinOp::Nop
38 37
             }
@@ -142,37 +141,17 @@ impl CrsnExtension for BuiltinOps {
142 141
                 BuiltinOp::Routine(parse_routine_name(name)?)
143 142
             }
144 143
 
145
-            "sk" => {
144
+            "skip" => {
146 145
                 BuiltinOp::Skip(args.next_rd()?)
147 146
             }
148 147
 
149
-            // TODO add jne-style names for jif ne ...
150
-
151
-            "skif" => {
152
-                let cond = parse_cond(&args.next_string()?)?;
153
-                let offs = args.next_rd()?;
154
-                BuiltinOp::SkipIf(cond, offs)
155
-            }
156
-
157
-            "jif" => {
158
-                let cond = parse_cond(&args.next_string()?)?;
159
-                let dest = parse_label(args.next())?;
160
-                BuiltinOp::JumpIf(cond, dest)
161
-            }
162
-
163
-            "fjif" => {
164
-                let cond = parse_cond(&args.next_string()?)?;
165
-                let dest = parse_label(args.next())?;
166
-                BuiltinOp::FarJumpIf(cond, dest)
167
-            }
168
-
169 148
             "barrier" => {
170 149
                 BuiltinOp::Barrier {
171 150
                     kind: Barrier::Standalone,
172 151
                     msg: match args.next() {
173 152
                         None => None,
174 153
                         Some(s) => Some(expect_string_atom(Some(s))?.into()),
175
-                    }
154
+                    },
176 155
                 }
177 156
             }
178 157
 
@@ -231,11 +210,11 @@ impl CrsnExtension for BuiltinOps {
231 210
     }
232 211
 }
233 212
 
234
-pub(crate) fn parse_routine_name(name : String) -> Result<RoutineName, CrsnError> {
213
+pub(crate) fn parse_routine_name(name: String) -> Result<RoutineName, CrsnError> {
235 214
     let (name, arity) = if let Some(n) = name.find('/') {
236 215
         (
237 216
             (&name[0..n]).to_string(),
238
-            (&name[(n+1)..]).parse::<u8>()?
217
+            (&name[(n + 1)..]).parse::<u8>()?
239 218
         )
240 219
     } else {
241 220
         (name, 0)

+ 5 - 4
crsn/src/module/mod.rs View File

@@ -7,7 +7,8 @@ pub use eval_res::EvalRes;
7 7
 use crate::asm::data::literal::Value;
8 8
 use crate::asm::data::Mask;
9 9
 use crate::asm::error::CrsnError;
10
-use crate::asm::instr::{Flatten, Op};
10
+use crate::asm::instr::Flatten;
11
+use crate::asm::instr::op::OpKind;
11 12
 use crate::asm::parse::arg_parser::TokenParser;
12 13
 use crate::runtime::fault::Fault;
13 14
 use crate::runtime::run_thread::state::RunState;
@@ -25,10 +26,10 @@ pub enum ParseRes<'a, T> {
25 26
     Unknown(TokenParser<'a>),
26 27
 }
27 28
 
28
-impl<'a> ParseRes<'a, Op> {
29
+impl<'a> ParseRes<'a, OpKind> {
29 30
     /// Helper to construct an extension op
30 31
     pub fn ext(op: impl OpTrait) -> Self {
31
-        Self::Parsed(Op::Ext(Box::new(op)))
32
+        Self::Parsed(OpKind::Ext(Box::new(op)))
32 33
     }
33 34
 }
34 35
 
@@ -47,7 +48,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
47 48
     /// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
48 49
     ///
49 50
     /// pcx is available on the arg_tokens parser
50
-    fn parse_op<'a>(&self, keyword: &str, arg_tokens: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError>;
51
+    fn parse_op<'a>(&self, keyword: &str, arg_tokens: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError>;
51 52
 
52 53
     /// Parse a generic S-expression (non-op)
53 54
     ///

+ 1 - 1
crsn/src/runtime/mod.rs View File

@@ -2,7 +2,7 @@ pub mod run_thread;
2 2
 // pub mod mlock;
3 3
 // pub mod sparse;
4 4
 pub mod fault;
5
-pub mod span;
5
+// pub mod span;
6 6
 pub mod exec;
7 7
 pub mod frame;
8 8
 pub mod program;

+ 13 - 14
crsn/src/runtime/program.rs View File

@@ -3,7 +3,8 @@ use std::sync::Arc;
3 3
 
4 4
 use crate::asm::data::literal::{Addr, Label, RoutineName};
5 5
 use crate::asm::instr::Op;
6
-use crate::builtin::defs::{BuiltinOp, Barrier};
6
+use crate::asm::instr::op::OpKind;
7
+use crate::builtin::defs::{Barrier, BuiltinOp};
7 8
 use crate::module::CrsnExtension;
8 9
 use crate::runtime::fault::Fault;
9 10
 
@@ -12,7 +13,6 @@ pub struct Program {
12 13
     pub ops: Vec<Op>,
13 14
     pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>,
14 15
     routines: HashMap<RoutineName, Addr>,
15
-    local_labels: HashMap<Label, Addr>,
16 16
     far_labels: HashMap<Label, Addr>,
17 17
     /// Barriers from-to (inclusive).
18 18
     /// Standalone barriers have both addresses the same.
@@ -25,7 +25,6 @@ impl Program {
25 25
             ops,
26 26
             extensions,
27 27
             routines: Default::default(),
28
-            local_labels: Default::default(),
29 28
             far_labels: Default::default(),
30 29
             barriers: Default::default(),
31 30
         };
@@ -35,23 +34,23 @@ impl Program {
35 34
 
36 35
     /// Find all the named things
37 36
     fn scan(&mut self) -> anyhow::Result<()> {
38
-        let mut barrier_starts : HashMap<&Label, Addr> = HashMap::new();
37
+        let mut barrier_starts: HashMap<&Label, Addr> = HashMap::new();
39 38
         for (pos, op) in self.ops.iter().enumerate() {
40
-            match op {
41
-                Op::BuiltIn(BuiltinOp::FarLabel(name)) => {
39
+            match &op.kind {
40
+                OpKind::BuiltIn(BuiltinOp::FarLabel(name)) => {
42 41
                     self.far_labels.insert(name.clone(), pos.into());
43 42
                 }
44
-                Op::BuiltIn(BuiltinOp::Routine(name)) => {
43
+                OpKind::BuiltIn(BuiltinOp::Routine(name)) => {
45 44
                     self.routines.insert(name.clone(), pos.into());
46 45
                 }
47
-                Op::BuiltIn(
46
+                OpKind::BuiltIn(
48 47
                     BuiltinOp::Barrier {
49 48
                         kind: Barrier::Open(lbl), ..
50 49
                     }
51 50
                 ) => {
52 51
                     barrier_starts.insert(lbl, pos.into());
53 52
                 }
54
-                Op::BuiltIn(
53
+                OpKind::BuiltIn(
55 54
                     BuiltinOp::Barrier {
56 55
                         kind: Barrier::Close(lbl),
57 56
                         msg,
@@ -64,7 +63,7 @@ impl Program {
64 63
                         anyhow::bail!("Block barrier \"{:?}\" closed without being open!", msg);
65 64
                     }
66 65
                 }
67
-                Op::BuiltIn(
66
+                OpKind::BuiltIn(
68 67
                     BuiltinOp::Barrier {
69 68
                         kind: Barrier::Standalone,
70 69
                         ..
@@ -80,7 +79,7 @@ impl Program {
80 79
             anyhow::bail!("Some block barriers open without being closed!");
81 80
         }
82 81
 
83
-        debug!("Program scanned: {:?}", self);
82
+        trace!("Program scanned: {:?}", self);
84 83
 
85 84
         Ok(())
86 85
     }
@@ -88,7 +87,7 @@ impl Program {
88 87
     /// Read a program instruction at address
89 88
     pub fn read(&self, addr: Addr) -> &Op {
90 89
         if addr.0 >= self.ops.len() as u64 {
91
-            &Op::BuiltIn(BuiltinOp::Halt)
90
+            &Op { kind: OpKind::BuiltIn(BuiltinOp::Halt), cond: None }
92 91
         } else {
93 92
             &self.ops[addr.0 as usize]
94 93
         }
@@ -104,7 +103,7 @@ impl Program {
104 103
             if b0 != b1 {
105 104
                 // block barrier that only partially intersects the jump
106 105
                 if (*b0 >= from && *b0 <= to) != (*b1 >= from && *b1 <= to) {
107
-                    if let Op::BuiltIn(BuiltinOp::Barrier { msg, .. }) = self.read(*b0) {
106
+                    if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind {
108 107
                         return Err(Fault::JumpThroughBarrier {
109 108
                             msg: msg.clone().unwrap_or("BLOCK BARRIER".into())
110 109
                         });
@@ -115,7 +114,7 @@ impl Program {
115 114
             } else {
116 115
                 // point barrier
117 116
                 if *b0 >= from && *b0 <= to {
118
-                    if let Op::BuiltIn(BuiltinOp::Barrier { msg, .. }) = self.read(*b0) {
117
+                    if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind {
119 118
                         return Err(Fault::JumpThroughBarrier {
120 119
                             msg: msg.clone().unwrap_or("POINT BARRIER".into())
121 120
                         });

+ 2 - 2
crsn_arith/src/lib.rs View File

@@ -1,5 +1,5 @@
1 1
 use crsn::asm::error::CrsnError;
2
-use crsn::asm::instr::Op;
2
+use crsn::asm::instr::op::OpKind;
3 3
 use crsn::asm::parse::arg_parser::TokenParser;
4 4
 use crsn::module::{CrsnExtension, ParseRes};
5 5
 
@@ -21,7 +21,7 @@ impl CrsnExtension for ArithOps {
21 21
         "arith"
22 22
     }
23 23
 
24
-    fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
24
+    fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
25 25
         parse::parse(keyword, args)
26 26
     }
27 27
 }

+ 2 - 2
crsn_arith/src/parse.rs View File

@@ -1,12 +1,12 @@
1 1
 use crsn::asm::data::{Rd, Wr};
2 2
 use crsn::asm::error::CrsnError;
3
-use crsn::asm::instr::Op;
3
+use crsn::asm::instr::op::OpKind;
4 4
 use crsn::asm::parse::arg_parser::TokenParser;
5 5
 use crsn::module::ParseRes;
6 6
 
7 7
 use crate::defs::ArithOp;
8 8
 
9
-pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
9
+pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
10 10
     Ok(ParseRes::ext(match keyword {
11 11
         "cmp" => {
12 12
             ArithOp::Compare {

+ 2 - 2
crsn_screen/src/lib.rs View File

@@ -2,7 +2,7 @@
2 2
 extern crate log;
3 3
 
4 4
 use crsn::asm::error::CrsnError;
5
-use crsn::asm::instr::Op;
5
+use crsn::asm::instr::op::OpKind;
6 6
 use crsn::asm::parse::arg_parser::TokenParser;
7 7
 use crsn::module::{CrsnExtension, ParseRes};
8 8
 
@@ -24,7 +24,7 @@ impl CrsnExtension for ScreenOps {
24 24
         "screen"
25 25
     }
26 26
 
27
-    fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
27
+    fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
28 28
         parse::parse(keyword, args)
29 29
     }
30 30
 }

+ 2 - 2
crsn_screen/src/parse.rs View File

@@ -1,12 +1,12 @@
1 1
 use crsn::asm::data::Rd;
2 2
 use crsn::asm::error::CrsnError;
3
-use crsn::asm::instr::Op;
3
+use crsn::asm::instr::op::OpKind;
4 4
 use crsn::asm::parse::arg_parser::TokenParser;
5 5
 use crsn::module::ParseRes;
6 6
 
7 7
 use crate::defs::ScreenOp;
8 8
 
9
-pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
9
+pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
10 10
     Ok(ParseRes::ext(match keyword {
11 11
         "sc-init" => {
12 12
             ScreenOp::ScreenInit {

+ 2 - 2
crsn_stacks/src/lib.rs View File

@@ -1,6 +1,6 @@
1 1
 use crsn::asm::data::literal::Value;
2 2
 use crsn::asm::error::CrsnError;
3
-use crsn::asm::instr::Op;
3
+use crsn::asm::instr::op::OpKind;
4 4
 use crsn::asm::parse::arg_parser::TokenParser;
5 5
 use crsn::module::{CrsnExtension, ParseRes};
6 6
 use crsn::runtime::fault::Fault;
@@ -24,7 +24,7 @@ impl CrsnExtension for StackOps {
24 24
         "stacks"
25 25
     }
26 26
 
27
-    fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
27
+    fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
28 28
         parse::parse(keyword, args)
29 29
     }
30 30
 

+ 2 - 2
crsn_stacks/src/parse.rs View File

@@ -1,11 +1,11 @@
1 1
 use crsn::asm::error::CrsnError;
2
-use crsn::asm::instr::Op;
2
+use crsn::asm::instr::op::OpKind;
3 3
 use crsn::asm::parse::arg_parser::TokenParser;
4 4
 use crsn::module::ParseRes;
5 5
 
6 6
 use crate::defs::StackOp;
7 7
 
8
-pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
8
+pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
9 9
     Ok(ParseRes::ext(match keyword {
10 10
         "stack" => {
11 11
             StackOp::NewStack {

+ 25 - 2
launcher/src/main.rs View File

@@ -3,6 +3,7 @@ extern crate log;
3 3
 
4 4
 use std::collections::HashMap;
5 5
 use std::sync::Arc;
6
+use std::time::Duration;
6 7
 
7 8
 use clappconfig::{AppConfig, clap};
8 9
 use clappconfig::clap::ArgMatches;
@@ -13,7 +14,6 @@ use crsn::runtime::run_thread::{RunThread, ThreadToken};
13 14
 use crsn_arith::ArithOps;
14 15
 use crsn_screen::ScreenOps;
15 16
 use crsn_stacks::StackOps;
16
-use std::time::Duration;
17 17
 
18 18
 mod read_file;
19 19
 mod serde_duration_millis;
@@ -30,7 +30,9 @@ struct Config {
30 30
     log: LogConfig,
31 31
     #[serde(skip)]
32 32
     program_file: String,
33
-    #[serde(with="serde_duration_millis")]
33
+    #[serde(skip)]
34
+    asm_only: bool,
35
+    #[serde(with = "serde_duration_millis")]
34 36
     cycle_time: Duration,
35 37
 }
36 38
 
@@ -42,6 +44,7 @@ impl Default for Config {
42 44
                 modules: Default::default(),
43 45
             },
44 46
             program_file: "".to_string(),
47
+            asm_only: false,
45 48
             cycle_time: Duration::default(),
46 49
         }
47 50
     }
@@ -70,6 +73,12 @@ impl AppConfig for Config {
70 73
                     .takes_value(true),
71 74
             )
72 75
             .arg(
76
+                clap::Arg::with_name("asm-only")
77
+                    .short("P")
78
+                    .long("asm")
79
+                    .help("Only assemble, do not run."),
80
+            )
81
+            .arg(
73 82
                 clap::Arg::with_name("cycle")
74 83
                     .long("cycle")
75 84
                     .short("C")
@@ -95,6 +104,7 @@ impl AppConfig for Config {
95 104
 
96 105
     fn configure(mut self, clap: &ArgMatches) -> anyhow::Result<Self> {
97 106
         self.program_file = clap.value_of("input").unwrap().to_string();
107
+        self.asm_only = clap.is_present("asm-only");
98 108
         if let Some(c) = clap.value_of("cycle") {
99 109
             self.cycle_time = Duration::from_millis(c.parse().unwrap());
100 110
         }
@@ -118,6 +128,19 @@ fn main() -> anyhow::Result<()> {
118 128
 
119 129
     let parsed = crsn::asm::assemble(&source, parsers)?;
120 130
 
131
+    if config.asm_only {
132
+        for (n, op) in parsed.ops.iter().enumerate() {
133
+            println!("{:04} : {:?}", n, op);
134
+        }
135
+        return Ok(());
136
+    } else {
137
+        trace!("--- Compiled program ---");
138
+        for (n, op) in parsed.ops.iter().enumerate() {
139
+            trace!("{:04} : {:?}", n, op);
140
+        }
141
+        trace!("------------------------");
142
+    }
143
+
121 144
     info!("Start runtime");
122 145
 
123 146
     let args = &[];

+ 2 - 1
launcher/src/serde_duration_millis.rs View File

@@ -1,6 +1,7 @@
1
-use serde::{self, Deserialize, Deserializer, Serializer};
2 1
 use std::time::Duration;
3 2
 
3
+use serde::{self, Deserialize, Deserializer, Serializer};
4
+
4 5
 pub fn serialize<S>(value: &Duration, se: S) -> Result<S::Ok, S::Error>
5 6
     where
6 7
         S: Serializer,