File Hex (Part 2)
🌱 Lời mở đầu
Chào mọi người, trong bài viết trước mặc dù đã nghiên cứu hầu hết các khía cạnh của tệp HEX, tôi nhận thấy phần Record Type chưa được trình bày chi tiết. Vì vậy, bài viết này sẽ tập trung giải thích rõ ràng về Record Type trong định dạng tệp HEX.
Series File Hex gồm:
Định dạng và phân tích sâu về File Hex
Trước khi đi vào phần Record type, ta sẽ tổng ôn sơ qua phần format của File Hex
1. Định dạng File Hex
RECORD MASK
: Mỗi dòng trong tệp HEX bắt đầu bằng ký tự dấu hai chấm (:), đây là ký hiệu xác định điểm bắt đầu của một record.RECLEN (Record Length)
: Trường này cho biết số byte dữ liệu (INFO OR DATA) có trong record.LOAD OFFSET
: Địa chỉ offset, xác định nơi dữ liệu sẽ được ghi vào bộ nhớ.RECTYPE (Record Type)
: Trường này biểu thị loại record, giúp xác định ý nghĩa của dòng dữ liệu.0x00
: Record chứa dữ liệu (INFO OR DATA), thường là nội dung chính của file nhị phân.0x01
: Record kết thúc tệp HEX, thường xuất hiện ở dòng cuối cùng của tệp.0x02
: Record chỉ định địa chỉ phân đoạn mở rộng (Extended Segment Address).0x03
: Record chỉ định địa chỉ phân đoạn bắt đầu (Start Segment Address).0x04
: Record chỉ định địa chỉ tuyến tính mở rộng (Extended Linear Address).0x05
: Record chỉ định địa chỉ tuyến tính bắt đầu (Start Linear Address), thường được sử dụng làm địa chỉ mục nhập cho chức năng chính của chương trình. (Tôi sẽ đưa ra ví dụ sau).
INFO OR DATA
: Trường này chứa dữ liệu thực tế hoặc thông tin địa chỉ liên quan đến record.CHEKSUM
: Đây là tổng kiểm tra của record, được tính bằng công thức:
Checksum=(0x100
− S) & 0xFF
Trong đó:
- S là tổng của tất cả các byte trong record (ngoại trừ byte cuối cùng - checksum).
- Kết quả giúp phát hiện lỗi trong quá trình truyền dữ liệu.
Lưu ý: Các loại RECTYPE
phổ biến là 0x00
, 0x01
, 0x04
, 0x05
.
2. Record type 0x00
Example: :04 2000 00 FECACEFA 4C
04
: Số bytes dữ liệu, ở đây là 4 bytes data.2000
: địa chỉ offset, tức là0x2000
.00
: Loại bản ghi (RECTYPE), với00
biểu thị bản ghi dữ liệu.FECACEFA
: Dữ liệu sẽ được ghi vào bộ nhớ, bao gồm các byte:0xFE
,0xCA
,0xCE
,0xFA
.0x4C
: Checksum, được tính để kiểm tra tính toàn vẹn của dòng.- Tổng tích lũy S = (
0x04
+0x20
+0x00
+0x00
+0xFE
+0xCA
+0xCE
+0xFA
) =0x3B4
. (chỉ lấy byte cuối cùng của kết quả) - Tổng kiểm tra CHEKSUM = (
0x100
- S) &0xFF
=0x4C
.
- Tổng tích lũy S = (
3. Record type 0x01
Example: :00 0000 01 FF
00
: Số bytes dữ liệu, ở đây là 0 bytes data. (Bạn có thể thấy hình bên trên không có phần data)0000
: địa chỉ offset, tức là0x0000
.00
: Loại bản ghi (RECTYPE), với0x01
biểu thị kết thúc của File Hex.0xFF
: Checksum, được tính để kiểm tra tính toàn vẹn của dòng.- Tổng tích lũy S = (
0x00
+0x00
+0x00
+0x01
) =0x01
. (Chỉ lấy byte cuối cùng của kết quả) - Tổng kiểm tra CHEKSUM = (
0x100
- S) &0xFF
=0xFF
.
- Tổng tích lũy S = (
4. Record type 0x02
USBA (Upper Segment Base Address)
là một phần trong bản ghi mở rộng địa chỉ đoạn (Extended Segment Address Record). Đây là một giá trị 16-bit được sử dụng để ghi lại địa chỉ cơ sở của phân đoạn mở rộng, áp dụng trong các định dạng địa chỉ 16-bit hoặc 32-bit.
Cách hoạt động của USBA:
USBA ghi lại các bit từ 4 - 19 của địa chỉ đoạn mở rộng (Segment Base Address - SBA), trong khi các bit từ 0 - 3 được đặt bằng 0.
Khi cần tính địa chỉ vật lí (Physical address - địa chỉ thực tế mà dữ liệu sẽ được ghi vào) của một dữ liệu trong đoạn này, ta cộng USBA
với LOAD OFFSET
.
Công thức: Physical Address=(USBA « 4) + LOAD OFFSET
Example: Nếu USBA
= 0x1F02
và LOAD OFFSET
= 0x1005
, thì địa chỉ vật lí sẽ là: (0x1F02
« 4) + 0x1005
= 0x1F020
+ 0x1005
= 0x20025
.
Trong định dạng Intel HEX, việc sử dụng record type = 0x02 có tác dụng gì?.
Để giải thích cho việc sử dụng record type = 0x02, ta cần xét đến cấu trúc bộ nhớ trong vi xử lý 8086. Trong 8086, không gian bộ nhớ được tổ chức thành 4 segment chính:
- ES: Extra Segment
- CS: Code Segment
- SS: Stack Segment
- DS: Data Segment.
Mỗi segment được quản lý bởi một thanh ghi 16-bit, giới hạn kích thước mỗi segment là 64KB. Khi chương trình sử dụng hết 64KB của một segment, chúng ta sẽ không thể viết thêm dữ liệu vào đó nữa. Để khắc phục vấn đề này, cần mở rộng không gian địa chỉ từ 16-bit lên 20-bit, cho phép truy cập vào tối đa 1MB bộ nhớ.
Trong định dạng Intel HEX, record type = 0x02 được sử dụng để lưu trữ thông tin Extended Segment Address (ESA). Giá trị ESA này kết hợp với giá trị offset 16-bit sẽ tạo ra địa chỉ 20-bit đầy đủ, cho phép CPU truy cập vào toàn bộ 1MB không gian bộ nhớ. Đây là cách mà record type = 0x02 giải quyết vấn đề hết dung lượng của 64KB. “Đây là giải thích sơ bộ, chi tiết thì sẽ được viết trong loạt bài về 8086.”
5. Record type 0x03
Đối với các vi xử lý 80x86, chỉ định địa chỉ bắt đầu thực thi. Số byte luôn là 04, trường địa chỉ là 0000 và hai byte đầu tiên là giá trị CS, hai byte sau là giá trị IP. Việc thực thi sẽ bắt đầu từ địa chỉ này.
Example: :04 0000 03 0000 3800 C1
Địa chỉ của chương trình bắt đầu tại vị trí 0x3800.
6. Record type 0x04
Mở rộng địa chỉ lên 32 bit (4 GB). Số byte luôn là 02 và trường địa chỉ sẽ bị bỏ qua (thường là 0000). Hai byte dữ liệu (theo định dạng big endian) chỉ định 16 bit cao của địa chỉ tuyệt đối 32 bit, áp dụng cho tất cả các bản ghi loại 00 tiếp theo. Các bit địa chỉ cao này sẽ được giữ nguyên cho đến khi gặp một bản ghi loại 04. Địa chỉ tuyệt đối của một bản ghi loại 00 được tạo thành bằng cách kết hợp 16 bit địa chỉ cao của bản ghi loại 04 gần nhất và 16 bit địa chỉ thấp của bản ghi loại 00. Nếu không có bản ghi loại 04 trước đó, thì các bit địa chỉ cao của bản ghi loại 00 sẽ mặc định là 0000.
Trong bài viết File Hex (Part 1), đã có ví dụ về phần record type = 0x04 này ở mục IV. Lưu trữ data trong Memory.
7.Record type 0x05
Số byte luôn là 04, trường địa chỉ là 0000. Bốn byte dữ liệu đại diện cho một giá trị địa chỉ 32-bit (theo định dạng big endian). Đối với các CPU hỗ trợ tính năng này, địa chỉ 32-bit này chính là địa chỉ mà chương trình sẽ bắt đầu thực thi.
Example: :04 0000 05 00008411 62
04
: Số bytes dữ liệu, ở đây là 4 bytes data.0000
: địa chỉ offset, tức là0x0000
.05
: Loại bản ghi (RECTYPE), với0x05
biểu thị Start Linear Address.00008411
: địa chỉ bắt đầu hàmmain()
.0x62
: Checksum, được tính để kiểm tra tính toàn vẹn của dòng.- Tổng tích lũy S = (
0x04
+0x00
+0x00
+0x05
+0x00
+0x00
+0x84
+0x11
) =0x9E
. - Tổng kiểm tra CHEKSUM = (
0x100
- S) &0xFF
=0x62
.
- Tổng tích lũy S = (