Tác giả

Mô phỏng CPU x86-64 trên ARM64

Chia sẻ các bước cài đặt trình mô phỏng Kiến trúc CPU x86-64 trên hệ thống ARM64/aarch64. Ở đây mình dùng termux + proot distro trên Android

Yêu cầu

Cài đặt các gói phụ thuộc cần thiết:

  • flex, bison, cmake, g++, git

Phiên bản yêu cầu:

  • flex >= 2.6.4
  • bison >= 3.3.2
  • cmake >= 3.8
  • Trình biên dịch C++17 (g++)

Sao chép Repository

bash
git clone https://github.com/AnisBdz/CPU
cd CPU

Các bản vá tương thích ARM64

Dự án sử dụng SSE intrinsics của x86 cần được điều chỉnh cho ARM. Áp dụng các bản vá sau:

1. Sửa nhánh Git của FTXUI

Chỉnh sửa CMakeLists.txt và cập nhật khai báo FTXUI (khoảng dòng 30):

cmake
FetchContent_Declare(ftxui
  GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
  GIT_TAG main
)

2. Thêm hỗ trợ SSE2NEON

Thêm sau phần FTXUI trong CMakeLists.txt:

cmake
# Thêm SSE2NEON để tương thích ARM
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64")
  FetchContent_Declare(sse2neon
    GIT_REPOSITORY https://github.com/DLTcollab/sse2neon
    GIT_TAG master
  )
  FetchContent_MakeAvailable(sse2neon)
endif()

Thêm vào phần include của thư viện core (khoảng dòng 125):

cmake
# Thêm đường dẫn include SSE2NEON cho hệ thống ARM
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64")
  target_include_directories(core PUBLIC ${sse2neon_SOURCE_DIR})
endif()

3. Tạo Header tương thích SSE

Tạo file src/core/headers/sse_compat.hh:

cpp
#pragma once

#if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
    #include "sse2neon.h"
#else
    #include <emmintrin.h>
#endif

4. Cập nhật các file Header

Thay thế #include <emmintrin.h>
bằng #include "sse_compat.hh"
trong:

  • src/core/headers/vector_register.hh
  • src/core/headers/sse.hh

5. Sửa tương thích kiểu dữ liệu

Trong src/core/headers/vector_register.hh, thay đổi:

__m128i_u * value_dq();

thành:

cpp
__m128i * value_dq();

Trong src/core/vector_register.cc, thay thế tất cả __m128i_u bằng __m128i:

bash
sed -i 's/__m128i_u/__m128i/g' src/core/vector_register.cc

6. Sửa header cxxopts

Thêm #include <cstdint> vào lib/cxxopts.hpp sau dòng 28:

cpp
#include <cstring>
#include <cctype>
#include <cstdint>
#include <exception>

Build

bash
mkdir build
cd build
cmake ..
make -j$(nproc)

Quá trình build sẽ tạo ra:

  • app - File thực thi chính của trình mô phỏng CPU
  • Các bài kiểm tra trong mã nguồn có thể không biên dịch được (vấn đề Catch2/glibc) nhưng ứng dụng chính vẫn hoạt động

Sử dụng

bash
./app --help

Chạy chương trình ví dụ:

bash
./app -f ../examples/add_loop.asm

Chế độ tương tác:

bash
./app -f ../examples/add_loop.asm -i

Script xây dựng tự động

Để thiết lập nhanh, sử dụng lệnh một dòng này:

bash
cd CPU && \
wget https://raw.githubusercontent.com/DLTcollab/sse2neon/master/sse2neon.h -O src/core/headers/sse2neon.h && \
# Áp dụng tất cả các bản vá ở trên, sau đó:
mkdir build && cd build && cmake .. && make -j$(nproc)

Khắc phục sự cố

Vấn đề: emmintrin.h: No such file or directory

  • Giải pháp: Đảm bảo SSE2NEON được cấu hình đúng và sse_compat.hh đã được tạo

Vấn đề: __m128i_u does not name a type

  • Giải pháp: Thay thế tất cả __m128i_u bằng __m128i

Vấn đề: Các bài kiểm tra đơn vị không biên dịch được

  • Giải pháp: Đây là điều bình thường do tương thích Catch2. Ứng dụng chính vẫn hoạt động.

Ghi chú

  • Trình mô phỏng chạy mã assembly x86-64 ở chế độ giả lập trên ARM
  • SSE2NEON chuyển đổi các SSE intrinsics của x86 sang các lệnh tương đương NEON của ARM
  • Hiệu suất có thể khác so với thực thi x86 gốc