Hướng dẫn micropython unsigned int - int không dấu micropython

Sau đây là một số ví dụ về việc sử dụng trình biên dịch nội tuyến và một số thông tin về cách làm việc xung quanh các hạn chế của nó. Trong tài liệu này, thuật ngữ chức năng trình biên dịch của người dùng, đề cập đến một hàm được khai báo trong Python với trình trang trí @micropython.asm_thumb, trong khi đó, chương trình con của Hồi giáo đề cập đến mã trình biên dịch được gọi từ trong một hàm trình biên dịch.

1.1. Code và chương trình con

Điều quan trọng là phải đánh giá cao rằng các nhãn là cục bộ cho một chức năng trình biên dịch. Hiện tại không có cách nào để một chương trình con được xác định trong một chức năng được gọi từ một chức năng khác.

Để gọi một chương trình con, hướng dẫn

@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
0 được ban hành. Điều này chuyển kiểm soát sang hướng dẫn theo chỉ thị
@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
1 và lưu trữ địa chỉ trả lại trong thanh ghi liên kết (
@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
2 hoặc
@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
3). Để trả về hướng dẫn
@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
4 được ban hành, điều này khiến việc thực thi tiếp tục với hướng dẫn theo cuộc gọi chương trình con. Cơ chế này ngụ ý rằng, nếu một chương trình con là gọi một chương trình khác, nó phải lưu thanh ghi liên kết trước khi gọi và khôi phục nó trước khi chấm dứt.

Ví dụ khá rõ ràng sau đây minh họa một cuộc gọi chức năng. Lưu ý rằng nó cần thiết khi bắt đầu phân nhánh xung quanh tất cả các cuộc gọi chương trình con: Chương trình con kết thúc thực thi với

@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
4 trong khi chức năng bên ngoài chỉ đơn giản là bỏ rơi kết thúc theo phong cách của các chức năng Python.

@micropython.asm_thumb
def quad(r0):
    b(START)
    label(DOUBLE)
    add(r0, r0, r0)
    bx(lr)
    label(START)
    bl(DOUBLE)
    bl(DOUBLE)

print(quad(10))

Ví dụ về mã sau đây cho thấy một cuộc gọi lồng nhau (đệ quy): chuỗi Fibonacci cổ điển. Ở đây, trước một cuộc gọi đệ quy, thanh ghi liên kết được lưu cùng với các thanh ghi khác mà logic chương trình yêu cầu phải được bảo tồn.

@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))

1.2. Đối số vượt qua và trở lại

Hướng dẫn chi tiết thực tế là các chức năng của trình biên dịch có thể hỗ trợ từ 0 đến ba đối số, phải (nếu được sử dụng) được đặt tên là

@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
6,
@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
7 và
@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
8. Khi mã thực thi các thanh ghi sẽ được khởi tạo cho các giá trị đó.

Các loại dữ liệu có thể được truyền theo cách này là số nguyên và địa chỉ bộ nhớ. Với phần sụn hiện tại, tất cả các giá trị 32 bit có thể được truyền và trả về. Nếu giá trị trả về có thể có bit đáng kể nhất, một gợi ý loại python nên được sử dụng để cho phép micropython để xác định xem giá trị có nên được hiểu là số nguyên được ký hay không dấu hay không: các loại là

@micropython.asm_thumb
def fib(r0):
    b(START)
    label(DOFIB)
    push({r1, r2, lr})
    cmp(r0, 1)
    ble(FIBDONE)
    sub(r0, 1)
    mov(r2, r0) # r2 = n -1
    bl(DOFIB)
    mov(r1, r0) # r1 = fib(n -1)
    sub(r0, r2, 1)
    bl(DOFIB)   # r0 = fib(n -2)
    add(r0, r0, r1)
    label(FIBDONE)
    pop({r1, r2, lr})
    bx(lr)
    label(START)
    bl(DOFIB)

for n in range(10):
    print(fib(n))
9 hoặc
@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)
0.

@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)

@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)
1 sẽ trả về 0x80000000, thể hiện sự vượt qua và lợi nhuận của các số nguyên trong đó các bit 30 và 31 khác nhau.

Các giới hạn về số lượng đối số và giá trị trả về có thể được khắc phục bằng mô -đun

@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)
2 cho phép truy cập bất kỳ số lượng giá trị nào của bất kỳ loại nào.

1.2.1. Nhiều đối số

Nếu một mảng Python của các số nguyên được truyền như một đối số cho hàm trình biên dịch, hàm sẽ nhận được địa chỉ của một tập hợp các số nguyên tiếp giáp. Do đó, nhiều đối số có thể được truyền dưới dạng các yếu tố của một mảng duy nhất. Tương tự, một hàm có thể trả về nhiều giá trị bằng cách gán chúng cho các thành phần mảng. Các chức năng của trình biên dịch không có phương tiện xác định độ dài của một mảng: điều này sẽ cần được truyền đến hàm.

Việc sử dụng các mảng này có thể được mở rộng để cho phép sử dụng nhiều hơn ba mảng. Điều này được thực hiện bằng cách sử dụng Indirection: Mô -đun

@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)
3 hỗ trợ
@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)
4 sẽ trả về địa chỉ của một mảng được truyền dưới dạng đối số của nó. Do đó, bạn có thể điền một mảng số nguyên với địa chỉ của các mảng khác:

from uctypes import addressof
@micropython.asm_thumb
def getindirect(r0):
    ldr(r0, [r0, 0]) # Address of array loaded from passed array
    ldr(r0, [r0, 4]) # Return element 1 of indirect array (24)

def testindirect():
    a = array.array('i',[23, 24])
    b = array.array('i',[0,0])
    b[0] = addressof(a)
    print(getindirect(b))

1.2.2. Các loại dữ liệu không phải là số nguyên

Chúng có thể được xử lý bằng các mảng của loại dữ liệu thích hợp. Ví dụ, dữ liệu điểm nổi chính xác duy nhất có thể được xử lý như sau. Ví dụ mã này lấy một mảng phao và thay thế nội dung của nó bằng hình vuông của chúng.

from array import array

@micropython.asm_thumb
def square(r0, r1):
    label(LOOP)
    vldr(s0, [r0, 0])
    vmul(s0, s0, s0)
    vstr(s0, [r0, 0])
    add(r0, 4)
    sub(r1, 1)
    bgt(LOOP)

a = array('f', (x for x in range(10)))
square(a, len(a))
print(a)

Mô -đun UCTYPES hỗ trợ việc sử dụng các cấu trúc dữ liệu ngoài các mảng đơn giản. Nó cho phép cấu trúc dữ liệu Python được ánh xạ vào một thể hiện bytearray sau đó có thể được chuyển đến hàm trình biên dịch.

1.3. Hằng số được đặt tên

Mã trình biên dịch có thể được làm cho dễ đọc hơn và có thể duy trì bằng cách sử dụng các hằng số được đặt tên thay vì xả rác với các số. Điều này có thể đạt được như vậy:

MYDATA = const(33)

@micropython.asm_thumb
def foo():
    mov(r0, MYDATA)

Cấu trúc const () khiến micropython thay thế tên biến bằng giá trị của nó tại thời điểm biên dịch. Nếu các hằng số được khai báo trong phạm vi Python bên ngoài, chúng có thể được chia sẻ giữa nhiều chức năng của trình biên dịch và với mã Python.

1.4. Mã trình biên dịch là Phương thức lớp

Micropython chuyển địa chỉ của thể hiện đối tượng là đối số đầu tiên cho các phương thức lớp. Điều này thường ít sử dụng cho một chức năng trình biên dịch. Có thể tránh được bằng cách khai báo chức năng như một phương pháp tĩnh, do đó:

class foo:
  @staticmethod
  @micropython.asm_thumb
  def bar(r0):
    add(r0, r0, r0)

1.5. Sử dụng các hướng dẫn không được hỗ trợ

Chúng có thể được mã hóa bằng cách sử dụng câu lệnh dữ liệu như hình dưới đây. Trong khi

@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)
5 và
@micropython.asm_thumb
def uadd(r0, r1) -> uint:
    add(r0, r0, r1)
6 được hỗ trợ ví dụ dưới đây minh họa nguyên tắc. Mã máy cần thiết có thể được tìm thấy trong Hướng dẫn tham khảo kiến ​​trúc ARM V7-M. Lưu ý rằng đối số đầu tiên của các cuộc gọi dữ liệu như

data(2, 0xe92d, 0x0f00) # push r8,r9,r10,r11

chỉ ra rằng mỗi đối số tiếp theo là một số lượng hai byte.

1.6.Vượt qua giới hạn số nguyên của Micropython từ

Chip Pyboard bao gồm một máy phát CRC.Việc sử dụng của nó thể hiện một vấn đề trong micropython vì các giá trị được trả về bao gồm toàn bộ số lượng 32 bit trong khi các số nguyên nhỏ trong micropython không thể có các giá trị khác nhau trong bit 30 và 31. Giới hạn này được khắc phục với mã sau đây, sử dụng trình biên dịch để đưa kết quả kết quảvào một mảng và mã python để ép buộc kết quả thành một số nguyên không chính xác tùy ý.

from array import array
import stm

def enable_crc():
    stm.mem32[stm.RCC + stm.RCC_AHB1ENR] |= 0x1000

def reset_crc():
    stm.mem32[stm.CRC+stm.CRC_CR] = 1

@micropython.asm_thumb
def getval(r0, r1):
    movwt(r3, stm.CRC + stm.CRC_DR)
    str(r1, [r3, 0])
    ldr(r2, [r3, 0])
    str(r2, [r0, 0])

def getcrc(value):
    a = array('i', [0])
    getval(a, value)
    return a[0] & 0xffffffff # coerce to arbitrary precision

enable_crc()
reset_crc()
for x in range(20):
    print(hex(getcrc(0)))