summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/compile.c6
-rw-r--r--py/mpz.c73
-rw-r--r--py/obj.h4
-rw-r--r--py/objint.c3
-rw-r--r--py/objint_longlong.c3
-rw-r--r--py/objint_mpz.c3
-rw-r--r--py/parse.c20
-rw-r--r--py/parse.h7
-rw-r--r--py/parsenum.c17
-rw-r--r--py/runtime.c2
-rw-r--r--py/smallint.c1
-rw-r--r--py/smallint.h5
-rw-r--r--qemu-arm/README.md23
-rw-r--r--tests/basics/int-big-and.py24
14 files changed, 138 insertions, 53 deletions
diff --git a/py/compile.c b/py/compile.c
index f925c8c1ff..31ecbf0b91 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -249,7 +249,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
// shouldn't happen
assert(0);
}
- if (MP_PARSE_FITS_SMALL_INT(arg0)) {
+ if (MP_SMALL_INT_FITS(arg0)) {
//printf("%ld + %ld\n", arg0, arg1);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
}
@@ -264,7 +264,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
// int * int
if (!mp_small_int_mul_overflow(arg0, arg1)) {
arg0 *= arg1;
- if (MP_PARSE_FITS_SMALL_INT(arg0)) {
+ if (MP_SMALL_INT_FITS(arg0)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
}
}
@@ -337,7 +337,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
mp_load_method_maybe(elem->value, q_attr, dest);
if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
- if (MP_PARSE_FITS_SMALL_INT(val)) {
+ if (MP_SMALL_INT_FITS(val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
}
}
diff --git a/py/mpz.c b/py/mpz.c
index 9e60fc50d0..9c42878ff8 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -218,6 +218,38 @@ STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz
return idig + 1 - oidig;
}
+/* computes i = j & -k = j & (~k + 1)
+ returns number of digits in i
+ assumes enough memory in i; assumes normalised j, k
+ can have i, j, k pointing to same memory
+*/
+STATIC uint mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
+ mpz_dig_t *oidig = idig;
+ mpz_dbl_dig_t carry = 1;
+
+ for (; jlen > 0 && klen > 0; --jlen, --klen, ++idig, ++jdig, ++kdig) {
+ carry += *kdig ^ DIG_MASK;
+ *idig = (*jdig & carry) & DIG_MASK;
+ carry >>= DIG_SIZE;
+ }
+
+ for (; jlen > 0; --jlen, ++idig, ++jdig) {
+ carry += DIG_MASK;
+ *idig = (*jdig & carry) & DIG_MASK;
+ carry >>= DIG_SIZE;
+ }
+
+ if (carry != 0) {
+ *idig = carry;
+ } else {
+ // remove trailing zeros
+ for (--idig; idig >= oidig && *idig == 0; --idig) {
+ }
+ }
+
+ return idig + 1 - oidig;
+}
+
/* computes i = j | k
returns number of digits in i
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
@@ -896,24 +928,35 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
can have dest, lhs, rhs the same
*/
void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
- // make sure lhs has the most digits
- if (lhs->len < rhs->len) {
- const mpz_t *temp = lhs;
- lhs = rhs;
- rhs = temp;
- }
-
if (lhs->neg == rhs->neg) {
- mpz_need_dig(dest, rhs->len);
- dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
+ if (lhs->neg == 0) {
+ // make sure lhs has the most digits
+ if (lhs->len < rhs->len) {
+ const mpz_t *temp = lhs;
+ lhs = rhs;
+ rhs = temp;
+ }
+ // do the and'ing
+ mpz_need_dig(dest, rhs->len);
+ dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
+ dest->neg = 0;
+ } else {
+ // TODO both args are negative
+ assert(0);
+ }
} else {
- mpz_need_dig(dest, lhs->len);
- // TODO
- assert(0);
-// dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
+ // args have different sign
+ // make sure lhs is the positive arg
+ if (rhs->neg == 0) {
+ const mpz_t *temp = lhs;
+ lhs = rhs;
+ rhs = temp;
+ }
+ mpz_need_dig(dest, lhs->len + 1);
+ dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
+ assert(dest->len <= dest->alloc);
+ dest->neg = 0;
}
-
- dest->neg = lhs->neg;
}
/* computes dest = lhs | rhs
diff --git a/py/obj.h b/py/obj.h
index 74bdc79774..185fe14db0 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -72,10 +72,6 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
// These macros check for small int, qstr or object, and access small int and qstr values
-// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
-#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1))
-#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN)))
-#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
// these macros have now become inline functions; see below
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
//#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
diff --git a/py/objint.c b/py/objint.c
index 7d6258b7d4..f631d698f3 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -35,6 +35,7 @@
#include "qstr.h"
#include "obj.h"
#include "parsenum.h"
+#include "smallint.h"
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
@@ -251,7 +252,7 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
- if (MP_OBJ_FITS_SMALL_INT(value)) {
+ if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index 381246dfe4..82db9e6608 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -34,6 +34,7 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
+#include "smallint.h"
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
@@ -140,7 +141,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
- if (MP_OBJ_FITS_SMALL_INT(value)) {
+ if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
return mp_obj_new_int_from_ll(value);
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 733dc096a6..9cdbb71688 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -35,6 +35,7 @@
#include "qstr.h"
#include "parsenumbase.h"
#include "obj.h"
+#include "smallint.h"
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
@@ -239,7 +240,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
- if (MP_OBJ_FITS_SMALL_INT(value)) {
+ if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
return mp_obj_new_int_from_ll(value);
diff --git a/py/parse.c b/py/parse.c
index 93bced843b..af09c335f2 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -36,6 +36,7 @@
#include "lexer.h"
#include "parsenumbase.h"
#include "parse.h"
+#include "smallint.h"
#define RULE_ACT_KIND_MASK (0xf0)
#define RULE_ACT_ARG_MASK (0x0f)
@@ -311,13 +312,13 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
int i = mp_parse_num_base(str, len, &base);
bool overflow = false;
for (; i < len; i++) {
- machine_int_t old_val = int_val;
+ int dig;
if (unichar_isdigit(str[i]) && str[i] - '0' < base) {
- int_val = base * int_val + str[i] - '0';
+ dig = str[i] - '0';
} else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') {
- int_val = base * int_val + str[i] - 'a' + 10;
+ dig = str[i] - 'a' + 10;
} else if (base == 16 && 'A' <= str[i] && str[i] <= 'F') {
- int_val = base * int_val + str[i] - 'A' + 10;
+ dig = str[i] - 'A' + 10;
} else if (str[i] == '.' || str[i] == 'e' || str[i] == 'E' || str[i] == 'j' || str[i] == 'J') {
dec = true;
break;
@@ -325,17 +326,18 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
small_int = false;
break;
}
- if (int_val < old_val) {
- // If new value became less than previous, it's overflow
+ // add next digi and check for overflow
+ if (mp_small_int_mul_overflow(int_val, base)) {
overflow = true;
- } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
- // If signed number changed sign - it's overflow
+ }
+ int_val = int_val * base + dig;
+ if (!MP_SMALL_INT_FITS(int_val)) {
overflow = true;
}
}
if (dec) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_DECIMAL, qstr_from_strn(str, len));
- } else if (small_int && !overflow && MP_PARSE_FITS_SMALL_INT(int_val)) {
+ } else if (small_int && !overflow && MP_SMALL_INT_FITS(int_val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, int_val);
} else {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_INTEGER, qstr_from_strn(str, len));
diff --git a/py/parse.h b/py/parse.h
index 43c74e73b8..6950139e7b 100644
--- a/py/parse.h
+++ b/py/parse.h
@@ -37,13 +37,6 @@ struct _mp_lexer_t;
// - xx...x10010: a string of bytes; bits 5 and above are the qstr holding the value
// - xx...x10110: a token; bits 5 and above are mp_token_kind_t
-// TODO: these can now be unified with MP_OBJ_FITS_SMALL_INT(x)
-// makes sure the top 2 bits of x are all cleared (positive number) or all set (negavite number)
-// these macros can probably go somewhere else because they are used more than just in the parser
-#define MP_UINT_HIGH_2_BITS (~((~((machine_uint_t)0)) >> 2))
-// parser's small ints are different from VM small int
-#define MP_PARSE_FITS_SMALL_INT(x) (((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == 0) || ((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == MP_UINT_HIGH_2_BITS))
-
#define MP_PARSE_NODE_NULL (0)
#define MP_PARSE_NODE_SMALL_INT (0x1)
#define MP_PARSE_NODE_ID (0x02)
diff --git a/py/parsenum.c b/py/parsenum.c
index 842a9e9599..9729ffe64a 100644
--- a/py/parsenum.c
+++ b/py/parsenum.c
@@ -34,6 +34,7 @@
#include "obj.h"
#include "parsenumbase.h"
#include "parsenum.h"
+#include "smallint.h"
#if MICROPY_ENABLE_FLOAT
#include <math.h>
@@ -70,16 +71,16 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
machine_int_t int_val = 0;
const char *restrict str_val_start = str;
for (; str < top; str++) {
- machine_int_t old_val = int_val;
+ // get next digit as a value
int dig = *str;
if (unichar_isdigit(dig) && dig - '0' < base) {
// 0-9 digit
- int_val = base * int_val + dig - '0';
+ dig = dig - '0';
} else if (base == 16) {
dig |= 0x20;
if ('a' <= dig && dig <= 'f') {
// a-f hex digit
- int_val = base * int_val + dig - 'a' + 10;
+ dig = dig - 'a' + 10;
} else {
// unknown character
break;
@@ -88,11 +89,13 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
// unknown character
break;
}
- if (int_val < old_val) {
- // If new value became less than previous, it's overflow
+
+ // add next digi and check for overflow
+ if (mp_small_int_mul_overflow(int_val, base)) {
goto overflow;
- } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
- // If signed number changed sign - it's overflow
+ }
+ int_val = int_val * base + dig;
+ if (!MP_SMALL_INT_FITS(int_val)) {
goto overflow;
}
}
diff --git a/py/runtime.c b/py/runtime.c
index f487807256..a9d57460ac 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -413,7 +413,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
goto unsupported_op;
}
// TODO: We just should make mp_obj_new_int() inline and use that
- if (MP_OBJ_FITS_SMALL_INT(lhs_val)) {
+ if (MP_SMALL_INT_FITS(lhs_val)) {
return MP_OBJ_NEW_SMALL_INT(lhs_val);
} else {
return mp_obj_new_int(lhs_val);
diff --git a/py/smallint.c b/py/smallint.c
index 186c9c754f..5543f126c3 100644
--- a/py/smallint.c
+++ b/py/smallint.c
@@ -28,6 +28,7 @@
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
+#include "smallint.h"
bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y) {
// Check for multiply overflow; see CERT INT32-C
diff --git a/py/smallint.h b/py/smallint.h
index 9c1de42ad0..36b55f9197 100644
--- a/py/smallint.h
+++ b/py/smallint.h
@@ -26,6 +26,11 @@
// Functions for small integer arithmetic
+// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
+#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1))
+#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN)))
+#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
+
bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y);
machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor);
machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom);
diff --git a/qemu-arm/README.md b/qemu-arm/README.md
new file mode 100644
index 0000000000..a1d389d164
--- /dev/null
+++ b/qemu-arm/README.md
@@ -0,0 +1,23 @@
+This is experimental, community-supported port for Cortex-M emulation as
+provided my QEMU (http://qemu.org).
+
+The purposes of this port are to enable:
+
+1. Continuous integration
+ - run tests agains architecture-specific parts of code base
+2. Experimentation
+ - simulation & prototyping of anything that has architecture-specific
+ code
+ - exploring instruction set in terms of optimising some part of
+ MicroPython or a module
+3. Streamlined debugging
+ - no need for JTAG or even an MCU chip itself
+ - no need to use OpenOCD or anything else that might slow down the
+ process in terms of plugging things together, pressing buttons, etc.
+
+This port will only work with with [GCC ARM Embedded](launchpad.net/gcc-arm-embedded)
+toolchain and not with CodeSourcery toolchain. You will need to modify
+`LDFLAGS` if you want to use CodeSourcery's version of `arm-none-eabi`.
+The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while
+ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be
+passed to the linker.
diff --git a/tests/basics/int-big-and.py b/tests/basics/int-big-and.py
index 75fbd52884..a48848dbf0 100644
--- a/tests/basics/int-big-and.py
+++ b/tests/basics/int-big-and.py
@@ -2,7 +2,23 @@ print(0 & (1 << 80))
print(0 & (1 << 80) == 0)
print(bool(0 & (1 << 80)))
-#a = 0xfffffffffffffffffffffffffffff
-#print(a & (1 << 80))
-#print((a & (1 << 80)) >> 80)
-#print((a & (1 << 80)) >> 80 == 1)
+a = 0xfffffffffffffffffffffffffffff
+print(a & (1 << 80))
+print((a & (1 << 80)) >> 80)
+print((a & (1 << 80)) >> 80 == 1)
+
+# test negative on rhs
+a = 123456789012345678901234567890
+print(a & -1)
+print(a & -2)
+print(a & -2345678901234567890123456789)
+print(a & (-a))
+
+# test negative on lhs
+a = 123456789012345678901234567890
+print(-1 & a)
+print(-2 & a)
+print(-2345678901234567890123456789 & a)
+print((-a) & a)
+print((-a) & 0xffffffff)
+print((-a) & 0xffffffffffffffffffffffffffffffff)