Giải mã vi mã của chip xử lý dấu phẩy động Intel 8087: Lệnh FSCALE

Công nghệ12 tháng 9, 2026·8 phút đọc

Intel 8087 ra đời năm 1980 đã đặt nền móng cho chuẩn dấu phẩy động IEEE 754 ngày nay. Bài viết phân tích cách lệnh FSCALE tưởng chừng đơn giản lại được hiện thực bằng hơn 140 vi lệnh và ba tầng gọi chương trình con, hé lộ nhiều chi tiết thú vị về kiến trúc bên trong con chip huyền thoại này.

Giải mã vi mã của chip xử lý dấu phẩy động Intel 8087: Lệnh FSCALE

Bên trong vi mã của chip dấu phẩy động Intel 8087: Câu chuyện về lệnh FSCALE

Vào thập niên 1970, số học dấu phẩy động là một mớ hỗn độn với hàng chục tiêu chuẩn xung đột giữa các hãng máy tính. Intel 8087 ra đời năm 1980 đã thay đổi cuộc chơi, trở thành nền tảng cho chuẩn IEEE 754 mà gần như mọi máy tính ngày nay đều sử dụng.

Bài viết này mổ xẻ vi mã của một lệnh tưởng chừng đơn giản là FSCALE — lệnh dùng để nhân một số với lũy thừa của 2. Kết quả cho thấy nó cần tới hơn 140 vi lệnhba tầng gọi chương trình con, đồng thời tiết lộ một tính năng ẩn của con chip.

Bối cảnh: Khi dấu phẩy động còn là "vùng đất hoang"

Trước thập niên 1980, mỗi nhà sản xuất máy tính lại có một chuẩn số học dấu phẩy động riêng. Các hệ thống được thiết kế để phần cứng đơn giản thay vì đảm bảo độ chính xác toán học, dẫn đến nhiều vấn đề về ổn định số.

Intel 8087 xuất hiện với mục tiêu ngược lại: chính xác nhất có thể, kể cả trong những trường hợp biên hiếm gặp. Nhờ lắp được vào IBM PC, con chip này giúp các phép tính dấu phẩy động nhanh hơn tới 100 lần trong các ứng dụng từ bảng tính đến CAD.

Điều quan trọng hơn cả tốc độ: 8087 trở thành tiêu chuẩn dấu phẩy động mà hầu hết máy tính ngày nay vẫn kế thừa.

Khuôn chip Intel 8087 với các khối chức năng chính được chú thíchKhuôn chip Intel 8087 với các khối chức năng chính được chú thích

Kiến trúc bên trong chip

Khi mở chip 8087 ra và chụp ảnh độ phân giải cao bằng kính hiển vi, có thể thấy rõ bố cục:

  • ROM vi mã nằm ở trung tâm, chứa 1648 vi lệnh điều khiển toàn bộ hoạt động của chip
  • Bộ máy vi mã bên trái đảm nhiệm việc duyệt tuần tự các vi lệnh, xử lý nhảy và gọi chương trình con
  • Datapath ở nửa dưới — nơi thực hiện tính toán — được chia làm hai phần: datapath 16 bit cho số mũ và datapath 64 bit cho phần định trị

Các khối quan trọng trong datapath gồm:

  • ROM số mũ lưu các hằng số
  • Bộ chuyển đổi số mũ (exponent converter) — mạch chuyên dụng kiểm tra số mũ, phát hiện giá trị đặc biệt và chuyển đổi giữa các định dạng
  • Bộ dịch (shifter) 64 bit, cho phép dịch trái hoặc phải một giá trị với số lượng bit tùy ý
  • Bộ cộng (adder) — trái tim của mọi phép tính, được dùng trong vòng lặp cho phép nhân, chia và căn bậc hai
  • Thanh ghi B giữ một đầu vào của bộ cộng, còn thanh ghi tổng lưu kết quả đầu ra

Sơ đồ datapath của 8087 với các khối chức năng được dùng bởi FSCALESơ đồ datapath của 8087 với các khối chức năng được dùng bởi FSCALE

Số dấu phẩy động trong 8087 được biểu diễn thế nào?

8087 tổ chức tám thanh ghi nội bộ thành một ngăn xếp, mỗi thanh ghi lưu một số dấu phẩy động 80 bit. Mỗi giá trị đi kèm một thẻ (tag) mà lập trình viên thường không nhìn thấy, phân loại giá trị đó là hợp lệ, đặc biệt, bằng không, hay rỗng.

Một số "temporary real" gồm ba phần:

  • Bit dấu
  • Số mũ 15 bit (trải từ -16382 đến 16383, được lưu với độ lệch 16383)
  • Phần định trị 64 bit dạng 1.bbb... với bit 1 dẫn đầu

8087 hỗ trợ nhiều loại giá trị đặc biệt như vô cực, NaN (Not a Number), số phi chuẩn hóa (denormalized) và chưa chuẩn hóa (unnormalized). Chính sự phong phú này khiến vi mã trở nên phức tạp, vì mọi tổ hợp trường hợp đặc biệt đều phải được xử lý đúng.

FSCALE: Ý tưởng đơn giản, hiện thực phức tạp

Ý tưởng của FSCALE rất trực tiếp: muốn nhân một số với 2^N, chỉ cần cộng N vào số mũ của số đó. Cách này nhanh hơn nhiều so với phép nhân dấu phẩy động đầy đủ.

Nhưng vi mã thực tế lại phức tạp đến bất ngờ. Quy trình gồm các bước:

  1. Kiểm tra đối số bằng không, thoát sớm nếu có
  2. Xử lý các đối số đặc biệt qua chương trình con SPECIAL_TMPS
  3. Chuyển đối số tỉ lệ từ số thực sang số nguyên bằng cách dịch bit
  4. Cộng (hoặc trừ) giá trị đó vào số mũ
  5. Kiểm tra tràn trên/tràn dưới và xử lý kết quả bất thường

Ở trường hợp thông thường nhất, FSCALE cũng cần khoảng 22 vi lệnh. Để chuyển đổi từ số thực sang số nguyên, vi mã phải dịch phần định trị sang phải đúng 0x403e - exp bit — lý do hằng số 0x403e xuất hiện ngay từ đầu đoạn vi mã.

Cấu trúc một vi lệnh của 8087Cấu trúc một vi lệnh của 8087

Tính năng ẩn: Khi cả hai đối số đều là NaN

Điểm thú vị nhất mà quá trình giải mã hé lộ nằm ở chương trình con SPECIAL_TMPS. Khi phát hiện cả hai đối số đều là NaN, vi mã không trả về một NaN bất kỳ — nó so sánh hai giá trị NaN và trả về giá trị lớn hơn.

Nghe có vẻ kỳ quặc, nhưng đây là hành vi được tài liệu hóa. Ý tưởng của các nhà thiết kế là lập trình viên có thể gán những NaN khác nhau vào từng vị trí trong một mảng chưa khởi tạo, để biết chính xác phần tử nào đã bị truy cập.

Một chi tiết phần cứng đáng chú ý khác: vi lệnh hoán đổi tmpA và tmpB không thực sự di chuyển dữ liệu, mà chỉ lật một flip-flop để đảo ngược ý nghĩa của hai thanh ghi. Đây là thủ thuật quen thuộc — Intel 8080 dùng cách tương tự cho lệnh XCHG, và Z80 cũng vậy với EX/EXX.

Làm tròn: Guard, Round và Sticky

8087 nổi tiếng vì làm tròn chính xác, và điều này khó hơn vẻ ngoài. Để quyết định làm tròn lên hay xuống, bạn cần theo dõi một lượng bit khổng lồ. Ví dụ: 1 + 0 làm tròn lên vẫn là 1, nhưng 1 + 2^-10000 làm tròn lên lại cho một số lớn hơn 1.

Giải pháp là ba bit đặc biệt:

  • Guard — bit có ý nghĩa cao nhất của phần đuôi
  • Round — bit kế tiếp
  • Sticky — phép OR của toàn bộ các bit còn lại, cho biết có bit nào bằng 1 hay không

8087 tạo bit Sticky bằng một cổng NOR 64 bit khổng lồ, kiểm tra song song toàn bộ phần đuôi.

Cách tính ba bit làm tròn từ phép dịch phảiCách tính ba bit làm tròn từ phép dịch phải

Một chi tiết kỳ lạ khác: lệnh nhảy có điều kiện "làm tròn lên" lại có tác dụng phụ cập nhật thanh ghi mã điều kiện (CC1) mà lập trình viên có thể đọc được. Intel không ghi lại hành vi này trong tài liệu cho đến tận chip 387SX năm 1987.

Vì sao 8087 quan trọng đến vậy?

8087 đánh dấu bước ngoặt nhờ được thiết kế cẩn thận để đạt độ chính xác toán học cao nhất có thể, phần lớn nhờ công của chuyên gia số học William Kahan. Chính con chip này dẫn tới chuẩn IEEE 754 — chuẩn mà gần như mọi máy tính ngày nay sử dụng, chấm dứt tình trạng hỗn loạn của các chuẩn dấu phẩy động không tương thích.

Mức độ phức tạp của 8087 có thể đo bằng một con số: với người dùng không có chip, Intel bán kèm thư viện mô phỏng 8087 chiếm tới 16K byte mã 8086 — trong khi cả trình thông dịch BASIC chỉ cần 8K.

Phần cứng của 8087 đã giảm mạnh lượng phần mềm cần thiết: bản thân chip dùng 3,3K vi mã, so với 16K của trình mô phỏng.

Với người đọc quan tâm đến lịch sử máy tính cá nhân, 8087 là mắt xích then chốt: nó xuất hiện trên IBM PC, mở đường cho các ứng dụng tính toán nặng mà trước đó gần như bất khả thi trên máy để bàn.

Kết luận

Lệnh FSCALE là một minh chứng tuyệt vời cho nguyên tắc: độ chính xác luôn đi kèm với độ phức tạp. Một phép tính tưởng như chỉ cần cộng số mũ lại phải gánh trên vai cả hệ thống xử lý ngoại lệ, số phi chuẩn hóa, bốn chế độ làm tròn và một gia đình NaN khổng lồ.

Công trình giải mã vi mã 8087 vẫn đang tiếp tục trong cộng đồng Opcode Collective, với hy vọng làm sáng tỏ thêm những góc khuất của con chip đã định hình nên toàn bộ nền tảng tính toán hiện đại.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗