Câu trả lời của @ jalf bao gồm hầu hết các lý do, nhưng có một chi tiết thú vị mà nó không đề cập đến: Lõi giống RISC bên trong không được thiết kế để chạy một tập lệnh bất kỳ thứ gì như ARM / PPC / MIPS. Thuế x86 không chỉ được trả trong các bộ giải mã ngốn điện, mà ở một mức độ nào đó trong toàn bộ lõi. tức là nó không chỉ là mã hóa lệnh x86; đó là mọi hướng dẫn với ngữ nghĩa kỳ lạ.
Hãy giả sử rằng Intel đã tạo ra một chế độ hoạt động trong đó luồng lệnh là một thứ gì đó khác với x86, với các lệnh ánh xạ trực tiếp hơn tới các uops. Cũng giả sử rằng mỗi kiểu CPU có ISA riêng cho chế độ này, vì vậy chúng vẫn có thể tự do thay đổi bên trong khi chúng muốn và để lộ chúng với một lượng bóng bán dẫn tối thiểu để giải mã lệnh của định dạng thay thế này.
Có lẽ bạn vẫn chỉ có cùng một số lượng thanh ghi, được ánh xạ tới trạng thái kiến trúc x86, vì vậy hệ điều hành x86 có thể lưu / khôi phục nó trên các công tắc ngữ cảnh mà không cần sử dụng tập lệnh dành riêng cho CPU. Nhưng nếu chúng ta loại bỏ hạn chế thực tế đó, vâng chúng ta có thể có thêm một vài thanh ghi vì chúng ta có thể sử dụng các thanh ghi tạm thời ẩn thường được dành cho vi mã 1 .
Nếu chúng ta chỉ có các bộ giải mã thay thế mà không có thay đổi đối với các giai đoạn đường ống sau này (đơn vị thực thi), ISA này sẽ vẫn có nhiều điểm lệch tâm x86. Nó sẽ không phải là một kiến trúc RISC rất đẹp. Không có hướng dẫn đơn lẻ nào sẽ rất phức tạp, nhưng một số sự điên rồ khác của x86 vẫn sẽ ở đó.
Ví dụ: dịch chuyển trái / phải để lại cờ Tràn không xác định, trừ khi số dịch chuyển là một, trong trường hợp đó OF = phát hiện tràn có dấu thông thường. Sự điên rồ tương tự cho các vòng quay. Tuy nhiên, các hướng dẫn RISC tiếp xúc có thể cung cấp các thay đổi không gắn cờ, v.v. (cho phép chỉ sử dụng một hoặc hai trong số nhiều uops thường đi vào một số lệnh x86 phức tạp). Vì vậy, đây không thực sự được coi là lập luận phản bác chính.
Nếu bạn định tạo một bộ giải mã hoàn toàn mới cho RISC ISA, bạn có thể yêu cầu nó chọn và chọn các phần của lệnh x86 sẽ được hiển thị dưới dạng hướng dẫn RISC. Điều này làm giảm bớt phần nào sự chuyên môn hóa x86 của lõi.
Mã hóa lệnh có thể sẽ không có kích thước cố định, vì các uops đơn lẻ có thể chứa rất nhiều dữ liệu. Nhiều dữ liệu hơn là có ý nghĩa nếu tất cả các phần trong có cùng kích thước. Một uop hợp nhất vi mô duy nhất có thể thêm một toán hạng bộ nhớ và ngay lập tức 32 bit sử dụng chế độ định địa chỉ với 2 thanh ghi và sự dịch chuyển 32 bit. (Trong SnB trở lên, chỉ các chế độ định địa chỉ thanh ghi đơn mới có thể kết hợp vi mô với các hoạt động ALU).
uops rất lớn và không giống với các lệnh ARM có chiều rộng cố định. Tập lệnh 32bit có độ rộng cố định chỉ có thể tải 16bit ngay lập tức tại một thời điểm, do đó, việc tải một địa chỉ 32bit yêu cầu một cặp nửa thấp / tải cao-tức thì tải ngay lập tức. x86 không cần phải làm điều đó, điều này giúp nó không quá tệ với chỉ 15 thanh ghi GP hạn chế khả năng giữ các hằng số xung quanh trong các thanh ghi. (15 là một trợ giúp lớn hơn 7 thanh ghi, nhưng tăng gấp đôi một lần nữa lên 31 sẽ giúp ít hơn nhiều, tôi nghĩ rằng một số mô phỏng đã tìm thấy. RSP thường không phải là mục đích chung, vì vậy nó giống như 15 thanh ghi GP và một ngăn xếp.)
Tóm tắt TL; DR:
Dù sao, câu trả lời này tóm gọn lại thành "tập lệnh x86 có lẽ là cách tốt nhất để lập trình một CPU có thể chạy các lệnh x86 một cách nhanh chóng", nhưng hy vọng sẽ làm sáng tỏ lý do.
Định dạng uop nội bộ trong front-end so với back-end
Xem thêm Chế độ kết hợp vi mô và chế độ địa chỉ để biết một trường hợp khác biệt về những gì định dạng uop front-end so với back-end có thể thể hiện trên CPU Intel.
Chú thích chân trang 1 : Có một số thanh ghi "ẩn" để sử dụng làm mã tạm thời bằng vi mã. Các thanh ghi này được đổi tên giống như các thanh ghi kiến trúc x86, vì vậy các lệnh multi-uop có thể thực thi không theo thứ tự.
ví dụ: xchg eax, ecx
trên CPU Intel giải mã dưới dạng 3 uops ( tại sao? ), và dự đoán tốt nhất của chúng tôi là đây là những uops giống MOV tmp = eax; ecx=eax ; eax=tmp;
. Theo thứ tự đó, bởi vì tôi đo độ trễ của hướng dst-> src ở ~ 1 chu kỳ, so với 2 đối với cách khác. Và những bước di chuyển này không giống như những mov
hướng dẫn thông thường ; chúng dường như không phải là ứng cử viên để loại bỏ mov độ trễ bằng 0.
Xem thêm http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ để biết về việc cố gắng đo kích thước PRF bằng thực nghiệm và phải tính đến các thanh ghi vật lý được sử dụng để giữ trạng thái kiến trúc, bao gồm cả thanh ghi ẩn.
Trong giao diện người dùng sau bộ giải mã, nhưng trước giai đoạn vấn đề / đổi tên đổi tên các đăng ký vào tệp đăng ký vật lý, định dạng uop nội bộ sử dụng số đăng ký tương tự như số reg x86, nhưng có chỗ để giải quyết các thanh ghi ẩn này.
Định dạng uop hơi khác bên trong lõi không theo thứ tự (ROB và RS), hay còn gọi là back-end (sau giai đoạn vấn đề / đổi tên). Mỗi tệp thanh ghi vật lý int / FP có 168 mục nhập trong Haswell , vì vậy mỗi trường đăng ký trong một uop cần phải đủ rộng để giải quyết nhiều trường đó.
Vì bộ đổi tên có trong HW, nên chúng ta có lẽ tốt hơn nên sử dụng nó, thay vì cung cấp các hướng dẫn được lập lịch tĩnh trực tiếp cho back-end. Vì vậy, chúng tôi sẽ làm việc với một tập hợp các thanh ghi lớn như các thanh ghi kiến trúc x86 + thời gian tạm thời vi mã, không nhiều hơn thế.
Back-end được thiết kế để hoạt động với bộ đổi tên front-end để tránh các nguy cơ WAW / WAR, vì vậy chúng tôi không thể sử dụng nó như một CPU đặt hàng ngay cả khi chúng tôi muốn. Nó không có khóa liên động để phát hiện những phụ thuộc đó; được xử lý bởi sự cố / đổi tên.
Có thể rất gọn gàng nếu chúng ta có thể đưa các uops vào back-end mà không bị tắc nghẽn ở giai đoạn vấn đề / đổi tên (điểm hẹp nhất trong các đường ống Intel hiện đại, ví dụ: 4-wide trên Skylake so với 4 ALU + 2 tải + 1 cổng lưu trữ trong phía sau). Nhưng nếu bạn đã làm điều đó, tôi không nghĩ rằng bạn có thể lên lịch tĩnh mã để tránh việc sử dụng lại đăng ký và bước vào kết quả vẫn cần thiết nếu lỗi bộ nhớ cache làm ngừng tải trong một thời gian dài.
Vì vậy, chúng tôi cần phải cung cấp rất nhiều uops cho giai đoạn vấn đề / đổi tên, có thể chỉ bỏ qua giải mã, không phải bộ nhớ cache uop hoặc IDQ. Sau đó, chúng tôi nhận được trình điều hành OoO bình thường với phát hiện nguy cơ lành mạnh. Bảng phân bổ thanh ghi chỉ được thiết kế để đổi tên 16 + một số thanh ghi số nguyên thành số nguyên 168 mục nhập PRF. Chúng tôi không thể mong đợi HW đổi tên một tập hợp các thanh ghi logic lớn hơn thành cùng một số thanh ghi vật lý; điều đó sẽ mất RAT lớn hơn.