Hiểu sâu về Floating Point và ABI trên bộ vi xử lý Cortex-M
Bài viết phân tích chi tiết về các tùy chọn giao diện nhị phân ứng dụng (ABI) cho điểm nổi trên Arm Cortex-M, giải thích nguyên nhân gây ra lỗi trình liên kết và cách cấu hình FPU trong hệ điều hành thời gian thực Zephyr.

Trong bài viết gần đây về PSA Crypto API, tôi đã giới thiệu cách sử dụng API này trên hai vi điều khiển (MCU) khác nhau: nRF52840 và ESP32-S3. Đối với nRF52840, thao tác ký số ECDSA cuối cùng được thực hiện trong một thư viện mã nguồn đóng quản lý việc giao tiếp giữa bộ vi xử lý Arm Cortex-M4 và hệ thống con bảo mật Arm TrustZone CryptoCell 310.
Những độc giả đã đi sâu vào các liên kết trong bài viết có thể đã nhận thấy rằng có các biến thể của thư viện nrf_cc310_mbedcrypto cho hard-float và soft-float. Nếu bạn từng gặp lỗi từ trình liên kết (linker) giống như dưới đây, bạn sẽ hiểu ngay lý do:
ld.bfd: error: X uses VFP register arguments, Y does not
ld.bfd: failed to merge target specific data of file
Ba tùy chọn Floating Point ABI của Arm
Arm định nghĩa ba tùy chọn Giao diện Nhị phân Ứng dụng (ABI) cho điểm nổi, được kiểm soát bởi cờ trình biên dịch -mfloat-abi:
- soft: ABI mềm không có phần cứng FPU. Tất cả các thao tác điểm nổi được xử lý bởi các hàm thư viện thời gian chạy. Các giá trị được truyền qua thanh ghi đa năng (integer register bank).
- softfp: ABI mềm có phần cứng FPU. Điều này cho phép mã đã biên dịch tạo ra các lệnh truy cập trực tiếp FPU. Tuy nhiên, nếu một phép tính cần sử dụng hàm thư viện thời gian chạy, quy ước gọi soft-float sẽ được sử dụng. Các giá trị được truyền qua thanh ghi đa năng.
- hard: ABI cứng. Điều này cho phép mã đã biên dịch tạo ra các lệnh truy cập trực tiếp FPU và sử dụng các quy ước gọi dành riêng cho FPU khi gọi các hàm thư viện thời gian chạy.
Cơ chế truyền tham số và Thanh ghi
Giống như hầu hết các Kiến trúc Bộ tập lệnh (ISA), Arm chuyển các đối số cho các chương trình con trong các thanh ghi mục đích chung (GPR), cụ thể là r0-r3. Khi số lượng hoặc kích thước của đối số vượt quá các GPR có sẵn, các đối số còn lại sẽ bị "tràn" vào ngăn xếp (stack).
Tuy nhiên, khi bộ xử lý bao gồm Đơn vị Điểm nổi (FPU) — cụ thể hơn là đối với bộ xử lý Armv7-M như Cortex-M4, các coprocessor C10 và C11 — và có phần mở rộng điểm nổi, sẽ có một ngân hàng thanh ghi bổ sung với 32 thanh ghi điểm nổi (s0-s31).
Lưu ý phụ: Bạn có thể thấy thuật ngữ Vector Floating Point (VFP) khi đề cập đến điểm nổi trên bộ xử lý Armv7-M. Sổ tay hướng dẫn giải thích rằng Armv7-M giữ các mã lệnh này nhưng thường mô tả chúng là các lệnh điểm nổi (FP instructions).
Khi sử dụng hard ABI, các thanh ghi s0-s15 có thể được sử dụng để truyền đối số cho các chương trình con. Việc sử dụng hard cũng chỉ ra rằng các lệnh điểm nổi (tải, lưu, chuyển thanh ghi, xử lý dữ liệu) có thể được sử dụng bên trong các quy trình.
Khi sử dụng softfp, các lệnh điểm nổi được phép bên trong các quy trình, nhưng đối số không thể được truyền trong các thanh ghi điểm nổi. soft sử dụng quy ước gọi giống như softfp và do đó tương thích, nhưng không cho phép sử dụng các lệnh điểm nổi. Khi các thao tác điểm nổi được thực hiện mà không có hỗ trợ lệnh điểm nổi, chúng phải được mô phỏng bằng phần mềm.
Khi bạn thấy lỗi được mô tả ở đầu bài viết, bạn đang trộn lẫn soft/softfp với hard, điều mà trình liên kết sẽ từ chối. Nó có thể xác định ABI của tệp đối tượng đang được liên kết bằng cách xem phần thuộc tính Arm, phần này khác nhau đối với từng biến thể.
Floating Point ABIs trong thực tế
Đầu ra của việc biên dịch với mỗi ABI có thể được quan sát với một hàm đơn giản như addf sau đây, với tính năng tối ưu hóa bị tắt để đảm bảo rằng nó không được nội tuyến (inline) hay loại bỏ hoàn toàn.
float __attribute__((optimize("O0"))) addf(float a, float b)
{
return a + b;
}
Nếu bạn đang sử dụng hệ thống xây dựng như Zephyr, FPU được bật bằng cách đặt CONFIG_FPU=y. Tùy chọn này phụ thuộc vào CONFIG_CPU_HAS_FPU, nhưng mặc định là false ngay cả khi FPU có mặt.
Soft ABI
Với FPU bị tắt theo mặc định, west build sẽ dẫn đến việc sử dụng soft ABI. Các đối số được truyền trong GPR, và thao tác cộng điểm nổi sẽ thực hiện cuộc gọi đến hàm thư viện thời gian chạy __addsf3, hàm này thực hiện thao tác trong phần mềm.
Hard ABI
Khi đặt CONFIG_FPU=y và xây dựng lại, hard float ABI sẽ được sử dụng theo mặc định. Các đối số điểm nổi sẽ được truyền cho addf trong các thanh ghi điểm nổi, sau đó vadd.f32 sẽ được sử dụng để thực hiện phép cộng.
Softfp ABI
Đặt CONFIG_FP_SOFTABI=y sẽ thay đổi kết quả thành softfp. Đầu ra quan sát được bao gồm quy ước gọi mềm (đối số được truyền trong GPR), nhưng vẫn sử dụng các thanh ghi và lệnh điểm nổi bên trong quy trình.
Vòng thưởng: Kích hoạt FPU một cách động
Nếu bạn đọc mô tả của CONFIG_FPU ở trên, bạn sẽ nhận thấy rằng nó không chỉ cho phép cấu hình softfp và hard ABI, mà còn bật FPU khi khởi động lại. Hàm z_arm_floating_point_init() được gọi từ z_prep_c() bất cứ khi nào bộ xử lý có FPU.
Tùy thuộc vào giá trị của CONFIG_FPU cũng như các cấu hình khác, z_arm_floating_point_init() sẽ thiết lập FPU tương ứng. Điều này được thực hiện bằng cách xóa Thanh ghi Kiểm soát Truy cập Coprocessor (CPACR), sau đó, nếu CONFIG_FPU=y, đặt cờ CP10 và CP11 để bật coprocessor điểm nổi.
Tuy nhiên, không có lý do cụ thể nào bắt buộc FPU phải được bật khi khởi động lại, hay thậm chí được bật liên tục. Cùng một chuỗi thao tác có thể được thêm vào hàm addf để "kịp thời" (just-in-time) bật FPU.
float __attribute__((optimize("O0"))) addf(float a, float b)
{
SCB->CPACR &= (~(CPACR_CP10_Msk | CPACR_CP11_Msk));
SCB->CPACR |= CPACR_CP10_PRIV_ACCESS | CPACR_CP11_PRIV_ACCESS;
FPU->FPCCR = FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk;
barrier_dsync_fence_full();
barrier_isync_fence_full();
__set_FPSCR(0);
return a + b;
}
Biên dịch lại và flash nRF52840 dẫn đến việc thực thi thành công các thao tác điểm nổi trong hàm. Một hành vi tương tự cũng có thể đạt được bằng cách điều chỉnh trình xử lý lỗi sử dụng (usage fault handler) để bật FPU nếu bit NOCP được đặt, sau đó trả lại thực thi cho lệnh đã tạo ra lỗi.
Mặc dù có nhiều lý do khiến việc bật và tắt FPU theo cách này có thể dẫn đến các vấn đề và nên được sử dụng một cách thận trọng, nhưng có những trường hợp sử dụng hợp lý để giới hạn thời gian phần cứng điểm nổi được bật. Chúng ta sẽ khám phá các kịch bản này và một số sự đánh đổi giữa điểm nổi phần cứng và phần mềm trong một bài viết sau.
Bài viết liên quan

Công nghệ
Louis Zocchi, người phát minh ra viên xúc xắc d100, qua đời ở tuổi 87
21 tháng 4, 2026

Công nghệ
Sony yêu cầu xác minh độ tuổi bắt buộc cho người dùng PlayStation tại Anh và Ireland
21 tháng 4, 2026

Công nghệ
Dyson ra mắt máy sấy tóc Supersonic Travel: Nhỏ gọn, nhẹ hơn cho dân di chuyển
21 tháng 4, 2026
