|
| 1 | +try: |
| 2 | + import sys, io, vfs |
| 3 | + |
| 4 | + sys.implementation._mpy |
| 5 | + io.IOBase |
| 6 | +except (ImportError, AttributeError): |
| 7 | + print("SKIP") |
| 8 | + raise SystemExit |
| 9 | + |
| 10 | +sys_implementation_mpy = sys.implementation._mpy |
| 11 | +arch = (sys_implementation_mpy >> 10) & 0x0F |
| 12 | + |
| 13 | +# RV32-only for now. |
| 14 | +if arch != 11: |
| 15 | + print("SKIP") |
| 16 | + raise SystemExit |
| 17 | + |
| 18 | + |
| 19 | +class UserFile(io.IOBase): |
| 20 | + def __init__(self, data): |
| 21 | + self.data = memoryview(data) |
| 22 | + self.pos = 0 |
| 23 | + |
| 24 | + def readinto(self, buf): |
| 25 | + n = min(len(buf), len(self.data) - self.pos) |
| 26 | + buf[:n] = self.data[self.pos : self.pos + n] |
| 27 | + self.pos += n |
| 28 | + return n |
| 29 | + |
| 30 | + def ioctl(self, req, arg): |
| 31 | + if req == 4: # MP_STREAM_CLOSE |
| 32 | + return 0 |
| 33 | + return -1 |
| 34 | + |
| 35 | + |
| 36 | +class UserFS: |
| 37 | + def __init__(self, files): |
| 38 | + self.files = files |
| 39 | + |
| 40 | + def mount(self, readonly, mksfs): |
| 41 | + pass |
| 42 | + |
| 43 | + def umount(self): |
| 44 | + pass |
| 45 | + |
| 46 | + def stat(self, path): |
| 47 | + if path in self.files: |
| 48 | + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
| 49 | + raise OSError |
| 50 | + |
| 51 | + def open(self, path, mode): |
| 52 | + return UserFile(self.files[path]) |
| 53 | + |
| 54 | + |
| 55 | +def mp_encode_uint(val): |
| 56 | + encoded = [val & 0x7F] |
| 57 | + val >>= 7 |
| 58 | + while val != 0: |
| 59 | + encoded.insert(0, 0x80 | (val & 0x7F)) |
| 60 | + val >>= 7 |
| 61 | + return bytes(encoded) |
| 62 | + |
| 63 | + |
| 64 | +def add_flags(module, flags): |
| 65 | + output = bytearray() |
| 66 | + output.extend(module[:4]) |
| 67 | + output[2] |= 0x40 |
| 68 | + output.extend(mp_encode_uint(flags)) |
| 69 | + output.extend(module[4:]) |
| 70 | + return output |
| 71 | + |
| 72 | + |
| 73 | +arch_flags = sys_implementation_mpy >> 16 |
| 74 | +can_test_partial_flags = arch_flags not in [1 << i for i in range(16)] |
| 75 | + |
| 76 | +# To recreate this string run: |
| 77 | +# echo "hello=1" | mpy-cross -s module.py - | python -c 'import sys; print(sys.stdin.buffer.read())' |
| 78 | +MPY_FILE_BASE = b"M\x06\x00\x1f\x03\x00\x12module.py\x00\x0f\nhello\x00@\x00\x02\x01\x81\x16\x02Qc" |
| 79 | + |
| 80 | +user_files = { |
| 81 | + "/matching_flags.mpy": add_flags(MPY_FILE_BASE, arch_flags), |
| 82 | + "/invalid_flags.mpy": add_flags(MPY_FILE_BASE, (~arch_flags & 0xFFFF)), |
| 83 | + "/explicit_no_flags.mpy": add_flags(MPY_FILE_BASE, 0), |
| 84 | +} |
| 85 | +if can_test_partial_flags: |
| 86 | + user_files["/partial_flags_more.mpy"] = add_flags( |
| 87 | + MPY_FILE_BASE, (arch_flags | (arch_flags << 1)) & 0xFFFF |
| 88 | + ) |
| 89 | + user_files["/partial_flags_less.mpy"] = add_flags( |
| 90 | + MPY_FILE_BASE, (arch_flags >> 1) & arch_flags |
| 91 | + ) |
| 92 | + |
| 93 | +vfs.mount(UserFS(user_files), "/userfs") |
| 94 | +sys.path.append("/userfs") |
| 95 | + |
| 96 | +import matching_flags |
| 97 | + |
| 98 | +if not hasattr(matching_flags, "hello"): |
| 99 | + print("Improper matching_flags import") |
| 100 | + |
| 101 | +import explicit_no_flags |
| 102 | + |
| 103 | +if not hasattr(explicit_no_flags, "hello"): |
| 104 | + print("Improper explicit_no_flags import") |
| 105 | + |
| 106 | +try: |
| 107 | + import invalid_flags |
| 108 | + |
| 109 | + print("Unexpected invalid_flags import") |
| 110 | +except ValueError as e: |
| 111 | + if str(e) != "incompatible .mpy file": |
| 112 | + print("Unexpected invalid_flags import error:", str(e)) |
| 113 | + |
| 114 | +if can_test_partial_flags: |
| 115 | + import partial_flags_less |
| 116 | + |
| 117 | + if not hasattr(partial_flags_less, "hello"): |
| 118 | + print("Improper partial_flags_less import") |
| 119 | + |
| 120 | + try: |
| 121 | + import partial_flags_more |
| 122 | + |
| 123 | + print("Unexpected partial_flags_more import") |
| 124 | + except ValueError as e: |
| 125 | + if str(e) != "incompatible .mpy file": |
| 126 | + print("Unexpected partial_flags_more import error:", str(e)) |
| 127 | + |
| 128 | +print("OK") |
0 commit comments