From b282c9368992d107edf660282ee235e3e5c05c12 Mon Sep 17 00:00:00 2001 From: Sam Boling Date: Fri, 15 Nov 2019 20:25:26 -0700 Subject: [PATCH] circular shift ops --- CHANGELOG.md | 3 ++ docs/ops/maths.toml | 15 +++++++- module/help_mode.c | 6 +++- src/match_token.rl | 5 +++ src/ops/maths.c | 86 +++++++++++++++++++++++++++++++++++---------- src/ops/maths.h | 5 +++ src/ops/op.c | 6 ++-- src/ops/op_enum.h | 5 +++ 8 files changed, 108 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 190d9eff..0d8878d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - **FIX**: improve DAC latency when using `CV` ops - **NEW**: call metro / init with `SCRIPT 9` / `SCRIPT 10` - **NEW**: forward (C-f or C-s) and reverse (C-r) search in help mode +- **NEW**: new ops: `LROT` (alias `<<<`), `RROT` (alias `>>>`) +- **NEW**: `LSH` and `RSH` shift the opposite direction when passed a negative shift amount +- **NEW**: new op: `SGN` (sign of argument) ## v3.1.0 diff --git a/docs/ops/maths.toml b/docs/ops/maths.toml index efd86df3..fafcac6d 100644 --- a/docs/ops/maths.toml +++ b/docs/ops/maths.toml @@ -116,6 +116,16 @@ prototype = "RSH x y" aliases = [">>"] short = "right shift `x` by `y` bits, in effect divide `x` by `2` to the power of `y`" +[LROT] +prototype = "LROT x y" +aliases = ["<<<"] +short = "circular left shift `x` by `y` bits, wrapping around when bits fall off the end" + +[RROT] +prototype = "RROT x y" +aliases = [">>>"] +short = "circular right shift `x` by `y` bits, wrapping around when bits fall off the end" + ["|"] prototype = "| x y" short = "bitwise or `x` | `y`" @@ -228,6 +238,10 @@ short = "converts a voltage to a value usable by the CV outputs (`x` between `0` prototype = "EXP x" short = "exponentiation table lookup. `0-16383` range (V `0-10`)" +[SGN] +prototype = "SGN x" +short = "sign function: 1 for positive, -1 for negative, 0 for 0" + [CHAOS] prototype = "CHAOS x" short = "get next value from chaos generator, or set the current value" @@ -251,4 +265,3 @@ short = "set the lower end of the range from 0 – 32767" ["R.MAX"] prototype = "R.MAX x" short = "set the upper end of the range from 0 – 32767" - diff --git a/module/help_mode.c b/module/help_mode.c index ca6bb106..5867e1a2 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -143,7 +143,7 @@ const char* help4[HELP4_LENGTH] = { "4/13 DATA AND TABLES", "BPM 2-MAX|MS PER BPM", "EXP X|EXPO LOOKUP" }; -#define HELP5_LENGTH 64 +#define HELP5_LENGTH 68 const char* help5[HELP5_LENGTH] = { "5/13 OPERATORS", " ", "RAND A|RANDOM 0 - A", @@ -157,6 +157,8 @@ const char* help5[HELP5_LENGTH] = { "5/13 OPERATORS", "AVG A B|AVERAGE OF INS", "MIN A B|LESSER OF INS", "MAX A B|GREATER OF INS", + "ABS X|ABSOLUTE VALUE", + "SGN X|SIGN FUNCTION", " ", "ADD A B|A + B", "SUB A B|A - B", @@ -176,6 +178,8 @@ const char* help5[HELP5_LENGTH] = { "5/13 OPERATORS", " ", "RSH A B|BITSHIFT A RIGHT B", "LSH A B|BITSHIFT A LEFT B", + "RROT A B|BITROTATE A >> B", + "LROT A B|BITROTATE A << B", "| A B|BITWISE A OR B", "& A B|BITWISE A AND B", "^ A B|BITWISE A XOR B", diff --git a/src/match_token.rl b/src/match_token.rl index 229e6f4c..24ef605c 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -188,8 +188,11 @@ "EZ" => { MATCH_OP(E_OP_EZ); }; "RSH" => { MATCH_OP(E_OP_RSH); }; "LSH" => { MATCH_OP(E_OP_LSH); }; + "RROT" => { MATCH_OP(E_OP_RROT); }; + "LROT" => { MATCH_OP(E_OP_LROT); }; "EXP" => { MATCH_OP(E_OP_EXP); }; "ABS" => { MATCH_OP(E_OP_ABS); }; + "SGN" => { MATCH_OP(E_OP_SGN); }; "AND" => { MATCH_OP(E_OP_AND); }; "OR" => { MATCH_OP(E_OP_OR); }; "JI" => { MATCH_OP(E_OP_JI); }; @@ -226,6 +229,8 @@ "!" => { MATCH_OP(E_OP_SYM_EXCLAMATION); }; "<<" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_x2); }; ">>" => { MATCH_OP(E_OP_SYM_RIGHT_ANGLED_x2); }; + "<<<" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_x3); }; + ">>>" => { MATCH_OP(E_OP_SYM_RIGHT_ANGLED_x3); }; "&&" => { MATCH_OP(E_OP_SYM_AMPERSAND_x2); }; "||" => { MATCH_OP(E_OP_SYM_PIPE_x2); }; diff --git a/src/ops/maths.c b/src/ops/maths.c index c4cf95f0..ee463b2d 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -66,10 +66,16 @@ static void op_RSH_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_LSH_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_RROT_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_LROT_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); static void op_EXP_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_ABS_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_SGN_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); static void op_AND_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_OR_get(const void *data, scene_state_t *ss, exec_state_t *es, @@ -148,8 +154,11 @@ const tele_op_t op_NZ = MAKE_GET_OP(NZ , op_NZ_get , 1, true); const tele_op_t op_EZ = MAKE_GET_OP(EZ , op_EZ_get , 1, true); const tele_op_t op_RSH = MAKE_GET_OP(RSH , op_RSH_get , 2, true); const tele_op_t op_LSH = MAKE_GET_OP(LSH , op_LSH_get , 2, true); +const tele_op_t op_RROT = MAKE_GET_OP(RROT , op_RROT_get , 2, true); +const tele_op_t op_LROT = MAKE_GET_OP(LROT , op_LROT_get , 2, true); const tele_op_t op_EXP = MAKE_GET_OP(EXP , op_EXP_get , 1, true); const tele_op_t op_ABS = MAKE_GET_OP(ABS , op_ABS_get , 1, true); +const tele_op_t op_SGN = MAKE_GET_OP(SGN , op_SGN_get , 1, true); const tele_op_t op_AND = MAKE_GET_OP(AND , op_AND_get , 2, true); const tele_op_t op_OR = MAKE_GET_OP(OR , op_OR_get , 2, true); const tele_op_t op_JI = MAKE_GET_OP(JI , op_JI_get , 2, true); @@ -174,22 +183,24 @@ const tele_op_t op_TIF = MAKE_GET_OP(?, op_TIF_get, 3, true); const tele_op_t op_XOR = MAKE_ALIAS_OP(XOR, op_NE_get, NULL, 2, true); -const tele_op_t op_SYM_PLUS = MAKE_ALIAS_OP(+ , op_ADD_get, NULL, 2, true); -const tele_op_t op_SYM_DASH = MAKE_ALIAS_OP(- , op_SUB_get, NULL, 2, true); -const tele_op_t op_SYM_STAR = MAKE_ALIAS_OP(* , op_MUL_get, NULL, 2, true); -const tele_op_t op_SYM_FORWARD_SLASH = MAKE_ALIAS_OP(/ , op_DIV_get, NULL, 2, true); -const tele_op_t op_SYM_PERCENTAGE = MAKE_ALIAS_OP(% , op_MOD_get, NULL, 2, true); -const tele_op_t op_SYM_EQUAL_x2 = MAKE_ALIAS_OP(==, op_EQ_get , NULL, 2, true); -const tele_op_t op_SYM_EXCLAMATION_EQUAL = MAKE_ALIAS_OP(!=, op_NE_get , NULL, 2, true); -const tele_op_t op_SYM_LEFT_ANGLED = MAKE_ALIAS_OP(< , op_LT_get , NULL, 2, true); -const tele_op_t op_SYM_RIGHT_ANGLED = MAKE_ALIAS_OP(> , op_GT_get , NULL, 2, true); -const tele_op_t op_SYM_LEFT_ANGLED_EQUAL = MAKE_ALIAS_OP(<=, op_LTE_get, NULL, 2, true); -const tele_op_t op_SYM_RIGHT_ANGLED_EQUAL = MAKE_ALIAS_OP(>=, op_GTE_get, NULL, 2, true); -const tele_op_t op_SYM_EXCLAMATION = MAKE_ALIAS_OP(! , op_EZ_get , NULL, 1, true); -const tele_op_t op_SYM_LEFT_ANGLED_x2 = MAKE_ALIAS_OP(<<, op_LSH_get, NULL, 2, true); -const tele_op_t op_SYM_RIGHT_ANGLED_x2 = MAKE_ALIAS_OP(>>, op_RSH_get, NULL, 2, true); -const tele_op_t op_SYM_AMPERSAND_x2 = MAKE_ALIAS_OP(&&, op_AND_get, NULL, 2, true); -const tele_op_t op_SYM_PIPE_x2 = MAKE_ALIAS_OP(||, op_OR_get , NULL, 2, true); +const tele_op_t op_SYM_PLUS = MAKE_ALIAS_OP(+ , op_ADD_get, NULL, 2, true); +const tele_op_t op_SYM_DASH = MAKE_ALIAS_OP(- , op_SUB_get, NULL, 2, true); +const tele_op_t op_SYM_STAR = MAKE_ALIAS_OP(* , op_MUL_get, NULL, 2, true); +const tele_op_t op_SYM_FORWARD_SLASH = MAKE_ALIAS_OP(/ , op_DIV_get, NULL, 2, true); +const tele_op_t op_SYM_PERCENTAGE = MAKE_ALIAS_OP(% , op_MOD_get, NULL, 2, true); +const tele_op_t op_SYM_EQUAL_x2 = MAKE_ALIAS_OP(==, op_EQ_get , NULL, 2, true); +const tele_op_t op_SYM_EXCLAMATION_EQUAL = MAKE_ALIAS_OP(!=, op_NE_get , NULL, 2, true); +const tele_op_t op_SYM_LEFT_ANGLED = MAKE_ALIAS_OP(< , op_LT_get , NULL, 2, true); +const tele_op_t op_SYM_RIGHT_ANGLED = MAKE_ALIAS_OP(> , op_GT_get , NULL, 2, true); +const tele_op_t op_SYM_LEFT_ANGLED_EQUAL = MAKE_ALIAS_OP(<=, op_LTE_get, NULL, 2, true); +const tele_op_t op_SYM_RIGHT_ANGLED_EQUAL = MAKE_ALIAS_OP(>=, op_GTE_get, NULL, 2, true); +const tele_op_t op_SYM_EXCLAMATION = MAKE_ALIAS_OP(! , op_EZ_get , NULL, 1, true); +const tele_op_t op_SYM_LEFT_ANGLED_x2 = MAKE_ALIAS_OP(<<, op_LSH_get, NULL, 2, true); +const tele_op_t op_SYM_RIGHT_ANGLED_x2 = MAKE_ALIAS_OP(>>, op_RSH_get, NULL, 2, true); +const tele_op_t op_SYM_LEFT_ANGLED_x3 = MAKE_ALIAS_OP(<<<, op_LROT_get, NULL, 2, true); +const tele_op_t op_SYM_RIGHT_ANGLED_x3 = MAKE_ALIAS_OP(>>>, op_RROT_get, NULL, 2, true); +const tele_op_t op_SYM_AMPERSAND_x2 = MAKE_ALIAS_OP(&&, op_AND_get, NULL, 2, true); +const tele_op_t op_SYM_PIPE_x2 = MAKE_ALIAS_OP(||, op_OR_get , NULL, 2, true); // clang-format on @@ -427,12 +438,44 @@ static void op_EZ_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), static void op_RSH_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, cs_pop(cs) >> cs_pop(cs)); + int16_t x = cs_pop(cs); + int16_t n = cs_pop(cs); + cs_push(cs, (n > 0) ? (x >> n) : (x << -n)); } static void op_LSH_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, cs_pop(cs) << cs_pop(cs)); + int16_t x = cs_pop(cs); + int16_t n = cs_pop(cs); + cs_push(cs, (n > 0) ? (x << n) : (x >> -n)); +} + +static uint16_t rrot(uint16_t x, uint8_t n) { + return (x >> n) | (x << (16 - n)); +} + +static uint16_t lrot(uint16_t x, uint8_t n) { + return (x << n) | (x >> (16 - n)); +} + +typedef union { int16_t si; uint16_t ui; } bits16; + +static void op_RROT_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + bits16 u; + u.si = cs_pop(cs); + int16_t n = cs_pop(cs) % 16; + u.ui = (n > 0) ? rrot(u.ui, n) : lrot(u.ui, -n); + cs_push(cs, u.si); +} + +static void op_LROT_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + bits16 u; + u.si = cs_pop(cs); + int16_t n = cs_pop(cs) % 16; + u.ui = (n > 0) ? lrot(u.ui, n) : rrot(u.ui, -n); + cs_push(cs, u.si); } static void op_EXP_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), @@ -463,6 +506,12 @@ static void op_ABS_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), cs_push(cs, a); } +static void op_SGN_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a = cs_pop(cs); + cs_push(cs, (a > 0) ? 1 : ((a < 0) ? -1 : 0)); +} + static void op_AND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); @@ -703,4 +752,3 @@ static void op_TIF_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), s16 b = cs_pop(cs); cs_push(cs, condition ? a : b); } - diff --git a/src/ops/maths.h b/src/ops/maths.h index c595f7bc..8f472af2 100644 --- a/src/ops/maths.h +++ b/src/ops/maths.h @@ -33,8 +33,11 @@ extern const tele_op_t op_NZ; extern const tele_op_t op_EZ; extern const tele_op_t op_RSH; extern const tele_op_t op_LSH; +extern const tele_op_t op_RROT; +extern const tele_op_t op_LROT; extern const tele_op_t op_EXP; extern const tele_op_t op_ABS; +extern const tele_op_t op_SGN; extern const tele_op_t op_AND; extern const tele_op_t op_OR; extern const tele_op_t op_JI; @@ -73,6 +76,8 @@ extern const tele_op_t op_SYM_RIGHT_ANGLED_EQUAL; // >= alias GT extern const tele_op_t op_SYM_EXCLAMATION; // ! alias NZ extern const tele_op_t op_SYM_LEFT_ANGLED_x2; // << alias LSH extern const tele_op_t op_SYM_RIGHT_ANGLED_x2; // >> alias RSH +extern const tele_op_t op_SYM_LEFT_ANGLED_x3; // <<< alias LROT +extern const tele_op_t op_SYM_RIGHT_ANGLED_x3; // >>> alias RROT extern const tele_op_t op_SYM_AMPERSAND_x2; // && alias AND extern const tele_op_t op_SYM_PIPE_x2; // || alias OR diff --git a/src/ops/op.c b/src/ops/op.c index 09571b4f..778579ac 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -80,14 +80,16 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_ADD, &op_SUB, &op_MUL, &op_DIV, &op_MOD, &op_RAND, &op_RND, &op_RRAND, &op_RRND, &op_R, &op_R_MIN, &op_R_MAX, &op_TOSS, &op_MIN, &op_MAX, &op_LIM, &op_WRAP, &op_WRP, &op_QT, &op_AVG, &op_EQ, &op_NE, &op_LT, &op_GT, &op_LTE, - &op_GTE, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_EXP, &op_ABS, &op_AND, - &op_OR, &op_JI, &op_SCALE, &op_SCL, &op_N, &op_V, &op_VV, &op_ER, &op_BPM, + &op_GTE, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_LROT, &op_RROT, + &op_EXP, &op_ABS, &op_SGN, &op_AND, &op_OR, + &op_JI, &op_SCALE, &op_SCL, &op_N, &op_V, &op_VV, &op_ER, &op_BPM, &op_BIT_OR, &op_BIT_AND, &op_BIT_NOT, &op_BIT_XOR, &op_BSET, &op_BGET, &op_BCLR, &op_XOR, &op_CHAOS, &op_CHAOS_R, &op_CHAOS_ALG, &op_SYM_PLUS, &op_SYM_DASH, &op_SYM_STAR, &op_SYM_FORWARD_SLASH, &op_SYM_PERCENTAGE, &op_SYM_EQUAL_x2, &op_SYM_EXCLAMATION_EQUAL, &op_SYM_LEFT_ANGLED, &op_SYM_RIGHT_ANGLED, &op_SYM_LEFT_ANGLED_EQUAL, &op_SYM_RIGHT_ANGLED_EQUAL, &op_SYM_EXCLAMATION, &op_SYM_LEFT_ANGLED_x2, &op_SYM_RIGHT_ANGLED_x2, + &op_SYM_LEFT_ANGLED_x3, &op_SYM_RIGHT_ANGLED_x3, &op_SYM_AMPERSAND_x2, &op_SYM_PIPE_x2, &op_TIF, // stack diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index 6815b580..81a367ff 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -161,8 +161,11 @@ typedef enum { E_OP_EZ, E_OP_RSH, E_OP_LSH, + E_OP_LROT, + E_OP_RROT, E_OP_EXP, E_OP_ABS, + E_OP_SGN, E_OP_AND, E_OP_OR, E_OP_JI, @@ -198,6 +201,8 @@ typedef enum { E_OP_SYM_EXCLAMATION, E_OP_SYM_LEFT_ANGLED_x2, E_OP_SYM_RIGHT_ANGLED_x2, + E_OP_SYM_LEFT_ANGLED_x3, + E_OP_SYM_RIGHT_ANGLED_x3, E_OP_SYM_AMPERSAND_x2, E_OP_SYM_PIPE_x2, E_OP_TIF,