From ea8be373a975356808a19a79f1dd20383bec82ba Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Thu, 7 Jan 2016 14:54:13 +0000
Subject: [PATCH] py/inlinethumb: Remove 30-bit restriction on movwt
 instruction.

movwt can now move a full 32-bit constant into a register.
---
 docs/reference/asm_thumb2_mov.rst | 7 +++----
 py/emitinlinethumb.c              | 5 ++---
 tests/inlineasm/asmconst.py       | 8 ++++++++
 tests/inlineasm/asmconst.py.exp   | 1 +
 4 files changed, 14 insertions(+), 7 deletions(-)
 create mode 100644 tests/inlineasm/asmconst.py
 create mode 100644 tests/inlineasm/asmconst.py.exp

diff --git a/docs/reference/asm_thumb2_mov.rst b/docs/reference/asm_thumb2_mov.rst
index e42460881..900bf957b 100644
--- a/docs/reference/asm_thumb2_mov.rst
+++ b/docs/reference/asm_thumb2_mov.rst
@@ -21,8 +21,7 @@ Where immediate values are used, these are zero-extended to 32 bits. Thus
 movt writes an immediate value to the top halfword of the destination register.
 It does not affect the contents of the bottom halfword.
 
-* movwt(Rd, imm30) ``Rd = imm30``
+* movwt(Rd, imm32) ``Rd = imm32``
 
-movwt is a pseudo-instruction: the MicroPython assembler emits a ``movw`` and a ``movt``
-to move a zero extended 30 bit value into Rd. Where the full 32 bits are required a
-workround is to use the movw and movt operations.
+movwt is a pseudo-instruction: the MicroPython assembler emits a ``movw`` followed
+by a ``movt`` to move a 32-bit value into Rd.
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c
index 854b1460d..317febe92 100644
--- a/py/emitinlinethumb.c
+++ b/py/emitinlinethumb.c
@@ -703,11 +703,10 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
                 goto op_movw_movt;
             } else if (ARMV7M && strcmp(op_str, "movwt") == 0) {
                 // this is a convenience instruction
-                // we clear the MSB since it might be set from extracting the small int value
                 mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
-                int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff);
+                uint32_t i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff);
                 asm_thumb_mov_reg_i16(emit->as, ASM_THUMB_OP_MOVW, reg_dest, i_src & 0xffff);
-                asm_thumb_mov_reg_i16(emit->as, ASM_THUMB_OP_MOVT, reg_dest, (i_src >> 16) & 0x7fff);
+                asm_thumb_mov_reg_i16(emit->as, ASM_THUMB_OP_MOVT, reg_dest, (i_src >> 16) & 0xffff);
             } else if (ARMV7M && strcmp(op_str, "ldrex") == 0) {
                 mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
                 mp_parse_node_t pn_base, pn_offset;
diff --git a/tests/inlineasm/asmconst.py b/tests/inlineasm/asmconst.py
new file mode 100644
index 000000000..299a25093
--- /dev/null
+++ b/tests/inlineasm/asmconst.py
@@ -0,0 +1,8 @@
+# test constants in assembler
+
+@micropython.asm_thumb
+def c1():
+    movwt(r0, 0xffffffff)
+    movwt(r1, 0xf0000000)
+    sub(r0, r0, r1)
+print(hex(c1()))
diff --git a/tests/inlineasm/asmconst.py.exp b/tests/inlineasm/asmconst.py.exp
new file mode 100644
index 000000000..3ef9fcabd
--- /dev/null
+++ b/tests/inlineasm/asmconst.py.exp
@@ -0,0 +1 @@
+0xfffffff
-- 
GitLab