Quản lý phân trang bộ nhớ trên kiến trúc C166 và cách khắc phục lỗi Warning 23

Cơ chế phân trang bộ nhớ và nguyên nhân Warning 23

Khi làm việc với bộ công cụ lập trình C166 (phiên bản 4.03 trở lên), lập trình viên thường gặp cảnh báo: Warning 23: NDATA/NDATA0 or NCONST must fit in one 16kb page. Đây không đơn thuần là lỗi cú pháp mà liên quan trực tiếp đến kiến trúc phần cứng của dòng vi điều khiển C166.

Bộ nhớ dữ liệu của C166 được quản lý thông qua các thanh ghi con trỏ trang dữ liệu (DPP - Data Page Pointers). Các quy tắc cốt lõi bao gồm:

  • Mỗi trang dữ liệu có kích thước tối đa là 16KB (tương ứng với dải địa chỉ 0x0000 - 0x3FFF).
  • Hệ thống sử dụng 4 thanh ghi DPP (DPP0 đến DPP3) để ánh xạ vào các trang vật lý khác nhau.
  • Các vùng nhớ thuộc phân đoạn NDATA (Near Data) hoặc NCONST (Near Constant) bắt buộc phải nằm trọn trong một trang 16KB duy nhất.

Phân tích các tình huống gây lỗi

Cảnh báo sẽ xuất hiện nếu định nghĩa vùng nhớ vi phạm một trong các điều kiện về biên giới hoặc kích thước. Dưới đây là các ví dụ điển hình:

// Trường hợp 1: Tổng kích thước vượt quá giới hạn 16KB
NDATA(0x4000 - 0x8001) // Độ dài là 16KB + 2 byte, vượt mức cho phép

// Trường hợp 2: Vùng nhớ nằm đè lên ranh giới giữa hai trang
// Giả sử ranh giới trang nằm tại 0x8000
NDATA(0x7000 - 0x9000) // Vùng này trải dài qua cả trang 1 và trang 2

// Trường hợp 3: Khai báo địa chỉ bắt đầu nhưng không giới hạn kết thúc
NDATA(0x8000) // Trình liên kết có thể hiểu nhầm là cố gắng chiếm dụng toàn bộ không gian còn lại

Giải pháp cấu hình trình liên kết (Linker)

1. Định nghĩa dải địa chỉ hợp lệ

Để đảm bảo tính đúng đắn, các phân đoạn phải được giới hạn trong phạm vi 16KB và không được cắt ngang qua các mốc địa chỉ chia hết cho 0x4000.

// Định nghĩa một phân đoạn 16KB chuẩn
NDATA(0x4000 - 0x7FFF) 

// Chia nhỏ thành nhiều phân đoạn nhưng tổng không quá 16KB
NDATA(0x8000 - 0x9FFF, 0xB000 - 0xBFFF)

2. Sử dụng chỉ thị DPPUSE để mở rộng vùng NDATA

Nếu ứng dụng yêu cầu vùng nhớ Near lớn hơn 16KB, bạn cần sử dụng lệnh DPPUSE trong tập lệnh của Linker L166 để gộp nhiều trang dữ liệu lại với nhau.

/* Cấu hình trong file điều khiển linker */
DPPUSE (
    0 = NDATA(0x100000 - 0x10BFFF), // Gán DPP0 quản lý vùng 48KB
    3 = NCONST(0xC000 - 0xFFFF)     // DPP3 mặc định cho hằng số vùng hệ thống
)

3. Thao tác trên giao diện µVision IDE

Nếu bạn không muốn chỉnh sửa file script thủ công, có thể cấu hình trực tiếp qua giao diện đồ họa:

  1. Mở Options for Target, chọn tab L166 Locate.
  2. Kích hoạt tùy chọn Use DPPUSE.
  3. Trong mục nhập liệu DPP, ánh xạ DPP0 tới vùng NDATA mong muốn (ví dụ: 0x100000-0x10BFFF).
  4. Sử dụng chỉ thị CLASSES để phân tách các vùng nhớ con nếu cần thiết:
    CLASSES(NDATA(0x100000 - 0x103FFF, 0x108000 - 0x10BFFF))

Kỹ thuật quản lý bộ nhớ tối ưu

Trong các dự án thực tế, việc sắp xếp dữ liệu hợp lý sẽ giúp tăng hiệu năng truy cập:

  • Dữ liệu tần suất cao: Ưu tiên đặt trong vùng được ánh xạ bởi DPP0 vì trình biên dịch thường coi đây là trang mặc định, giúp giảm thiểu lệnh chuyển đổi trang (SEL DPPx).
  • Quản lý bảng tra cứu (Lookup Tables): Các bảng dữ liệu lớn nên được khai báo là NCONST và đặt vào vùng do DPP3 quản lý để tách biệt với dữ liệu biến động.
  • Kiểm tra file Map: Sau khi build, luôn kiểm tra file .map để xác nhận kích thước thực tế của từng phân đoạn:
    Size = End_Address - Start_Address + 1

Xử lý trong môi trường thời gian thực (RTOS)

Khi chạy đa nhiệm trên C166, cần lưu ý đặc biệt đến các thanh ghi DPP:

  • Context Switch (Chuyển đổi ngữ cảnh) phải lưu trữ và khôi phục giá trị của các thanh ghi DPP nếu các tác vụ khác nhau sử dụng sơ đồ phân trang khác nhau.
  • Stack của mỗi tác vụ nên được nằm trọn trong một trang để tránh lỗi truy xuất địa chỉ khi thực hiện các lệnh Push/Pop.

Lưu ý về phần cứng

Kiến trúc C166 tạo địa chỉ vật lý bằng cách kết hợp 14 bit thấp của địa chỉ 16 bit với giá trị trong thanh ghi DPP được chọn bởi 2 bit cao. Điều này giới hạn mỗi "cửa sổ" truy cập là 16KB. Việc hiểu rõ ranh giới phần cứng này giúp lập trình viên tránh được các lỗi Runtime khó phát hiện như dữ liệu bị ghi đè do nhầm trang.

Thẻ: C166 embedded-systems microcontroller memory-management Keil-Compiler

Đăng vào ngày 1 tháng 8 lúc 09:48