Tại sao x86 lại xấu? Tại sao nó bị coi là kém hơn khi so sánh với những người khác? [đóng cửa]


105

Gần đây tôi đã đọc một số kho lưu trữ SO và gặp các câu lệnh chống lại kiến ​​trúc x86.

và nhiều bình luận khác như

Tôi đã thử tìm kiếm nhưng không tìm thấy bất kỳ lý do nào. Tôi thấy x86 không tệ có lẽ vì đây là kiến ​​trúc duy nhất tôi quen thuộc.

Ai đó có thể vui lòng cho tôi lý do để xem xét x86 xấu / xấu / kém hơn so với những người khác.


1
Tôi sẽ xem xét S&A trên cơ sở các câu trả lời cho đến nay, nhưng tôi sẽ lưu ý rằng CISC không phải là vấn đề đối với tập lệnh m68k. x86 là cái gì và bạn có thể giữ nó.
dmckee --- cựu điều hành kitten

"S&A" là gì? "CISC không phải là vấn đề đối với tập lệnh m68k." -- Tại sao không?
vuốt

5
Các chip motorala 68000 series có kiến ​​trúc CISC cao, nhưng chúng có tập lệnh thống nhất, khá trực giao và rất dễ dàng. Tại sao lại có sự khác biệt so với x86? Tôi không biết. Nhưng lưu ý rằng có sự khác biệt lớn giữa độ phức tạp trong chip và độ phức tạp trong tập lệnh (tức là trong giao diện mà một lập trình viên lắp ráp nhìn thấy).
dmckee --- cựu điều hành kitten

4
+1 cho một câu hỏi rất thú vị.
Turing Complete vào

1
Nghiên cứu gần đây về hiệu quả năng lượng của các bộ xử lý khác nhau được tìm thấy ở đây, với một cuộc thảo luận tốt về điều gì đã thúc đẩy các thiết kế CISC & RISC. extremetech.com/extreme/...

Câu trả lời:


93

Một số lý do có thể cho nó:

  1. x86 là ISA tương đối cũ (tiền thân của nó là những năm 8086)
  2. x86 đã phát triển đáng kể nhiều lần, nhưng cần phải có phần cứng để duy trì khả năng tương thích ngược với các tệp nhị phân cũ. Ví dụ, phần cứng x86 hiện đại vẫn hỗ trợ chạy mã 16 bit nguyên bản. Ngoài ra, tồn tại một số mô hình định địa chỉ bộ nhớ để cho phép mã cũ hơn hoạt động với nhau trên cùng một bộ xử lý, chẳng hạn như chế độ thực, chế độ được bảo vệ, chế độ 8086 ảo và chế độ dài (amd64). Điều này có thể gây nhầm lẫn cho một số người.
  3. x86 là một máy CISC. Trong một thời gian dài, điều này có nghĩa là nó chậm hơn so với các máy RISC như MIPS hoặc ARM, bởi vì các lệnh có sự phụ thuộc lẫn nhau về dữ liệu và cờ làm cho hầu hết các dạng song song mức lệnh khó thực hiện. Các triển khai hiện đại chuyển các hướng dẫn x86 thành các hướng dẫn giống RISC được gọi là " micro-ops " dưới vỏ bọc để làm cho các loại tối ưu hóa này trở nên thực tế để triển khai trong phần cứng.
  4. Ở một số khía cạnh, x86 không thua kém, nó chỉ khác. Ví dụ: đầu vào / đầu ra được xử lý dưới dạng ánh xạ bộ nhớ trên đại đa số các kiến ​​trúc, nhưng không phải trên x86. (NB: Các máy x86 hiện đại thường có một số dạng hỗ trợ DMA và giao tiếp với phần cứng khác thông qua ánh xạ bộ nhớ; nhưng ISA vẫn có các lệnh I / O như INOUT)
  5. ISA x86 có rất ít thanh ghi kiến ​​trúc, điều này có thể buộc các chương trình quay vòng qua bộ nhớ thường xuyên hơn mức cần thiết. Các hướng dẫn bổ sung cần thiết để thực hiện việc này lấy tài nguyên thực thi có thể được chi cho công việc hữu ích, mặc dù chuyển tiếp cửa hàng hiệu quảgiữ độ trễ thấp. Các triển khai hiện đại với việc đổi tên thanh ghi thành một tệp thanh ghi vật lý lớn có thể giữ nhiều lệnh trong quá trình hoạt động, nhưng việc thiếu thanh ghi kiến ​​trúc vẫn là một điểm yếu đáng kể của x86 32-bit. Sự gia tăng của x86-64 từ 8 lên 16 số nguyên và thanh ghi vectơ là một trong những yếu tố lớn nhất khiến mã 64bit nhanh hơn 32-bit (cùng với lệnh gọi thanh ghi ABI hiệu quả hơn), chứ không phải tăng chiều rộng của mỗi thanh ghi. Việc tăng thêm từ 16 đến 32 thanh ghi số nguyên sẽ giúp một số, nhưng không nhiều. (Tuy nhiên, AVX512 tăng lên 32 thanh ghi vectơ vì mã dấu phẩy động có độ trễ cao hơn và thường cần nhiều hằng số hơn.) ( Xem nhận xét )
  6. Mã lắp ráp x86 phức tạp vì x86 là một kiến ​​trúc phức tạp với nhiều tính năng. Danh sách hướng dẫn cho một máy MIPS điển hình nằm gọn trên một tờ giấy có kích thước bằng chữ cái. Danh sách tương đương cho x86 lấp đầy một số trang và các hướng dẫn chỉ làm được nhiều hơn, vì vậy bạn thường cần giải thích nhiều hơn về những gì họ làm hơn là một danh sách có thể cung cấp. Ví dụ: MOVSBlệnh cần một khối mã C tương đối lớn để mô tả những gì nó làm:

    if (DF==0) 
      *(byte*)DI++ = *(byte*)SI++; 
    else 
      *(byte*)DI-- = *(byte*)SI--;
    

    Đó là một lệnh duy nhất thực hiện một tải, một lưu trữ và hai lệnh cộng hoặc trừ (được điều khiển bởi đầu vào cờ), mỗi lệnh sẽ là các lệnh riêng biệt trên máy RISC.

    Mặc dù sự đơn giản của MIPS (và các kiến ​​trúc tương tự) không nhất thiết khiến chúng trở nên vượt trội, nhưng để dạy phần giới thiệu về lớp hợp ngữ, bạn nên bắt đầu với một ISA đơn giản hơn . Một số lớp hợp ngữ dạy một tập con cực kỳ đơn giản của x86 được gọi là y86 , được đơn giản hóa đến mức không hữu ích cho việc sử dụng thực tế (ví dụ: không có lệnh shift) hoặc một số chỉ dạy các lệnh x86 cơ bản.

  7. X86 sử dụng các mã opcodes có độ dài thay đổi, làm tăng thêm độ phức tạp của phần cứng đối với việc phân tích cú pháp các lệnh. Trong kỷ nguyên hiện đại, chi phí này ngày càng trở nên nhỏ bé khi CPU ngày càng bị giới hạn bởi băng thông bộ nhớ hơn là tính toán thô, nhưng nhiều bài báo và quan điểm "dựa trên x86" đến từ thời đại mà chi phí này tương đối lớn hơn nhiều.
    Cập nhật 2016: Anandtech đã đăng một cuộc thảo luận về kích thước opcode dưới x64 và AArch64 .

CHỈNH SỬA: Đây không phải là một bash x86! buổi tiệc. Tôi không có lựa chọn nào khác ngoài việc thực hiện một số đánh giá dựa trên cách diễn đạt câu hỏi. Nhưng ngoại trừ (1), tất cả những điều này đã được thực hiện vì những lý do chính đáng (xem phần bình luận). Các nhà thiết kế của Intel không hề ngu ngốc - họ muốn đạt được một số điều với kiến ​​trúc của mình và đây là một số khoản thuế họ phải trả để biến những điều đó thành hiện thực.


17
Đó là một sự đánh đổi. Đó là điểm mạnh ở chỗ kích thước nhị phân có thể nhỏ hơn, nhưng điểm yếu là bạn cần phải có phần cứng rất phức tạp để triển khai trình phân tích cú pháp cho các hướng dẫn này. Dù sao thì đại đa số các hướng dẫn đều có cùng kích thước - hầu hết lý do cho các mã opcode có độ dài thay đổi trên x86 là vì khi họ quyết định thêm các tính năng và nhận thấy rằng chúng không thể đại diện cho những gì họ muốn trong số bit mà họ phải làm việc . Đại đa số mọi người không quan tâm đến kích thước nhị phân gần như độ phức tạp của phần cứng hoặc mức tiêu thụ điện năng.
Billy ONeal

8
@Joey Adams: Đối chiếu các hướng dẫn về độ dài thay đổi của x86 với Chế độ Ngón tay cái của ARM ( en.wikipedia.org/wiki/ARM_architecture#Thumb ). Chế độ Ngón tay cái dẫn đến mã đối tượng nhỏ hơn đáng kể cho ARM vì các hướng dẫn ngắn hơn ánh xạ trực tiếp đến các lệnh bình thường. Nhưng vì có một ánh xạ 1: 1 giữa các lệnh lớn hơn và các lệnh nhỏ hơn, phần cứng phân tích cú pháp rất đơn giản để thực hiện. Các lệnh có độ dài thay đổi của x86 không có những lợi ích này vì ngay từ đầu chúng đã không được thiết kế theo cách đó.
Billy ONeal

7
(6) Không phải mọi chương trình đều cần phải sử dụng mã op, nhưng chết tiệt, khi tôi cần SSE3, tôi rất vui vì đã có nó.
Chris K

4
@Chris Kaminski: Làm thế nào để điều đó không ảnh hưởng đến phần cứng? Chắc chắn, trên một chiếc máy tính có kích thước đầy đủ hiện đại sẽ không ai quan tâm, nhưng nếu tôi đang làm một cái gì đó như điện thoại di động, tôi quan tâm đến mức tiêu thụ điện năng hơn hầu hết mọi thứ khác. Các mã opcodes có độ dài thay đổi không làm tăng thời gian thực thi nhưng phần cứng giải mã vẫn yêu cầu nguồn điện để hoạt động.
Billy ONeal

5
Đó là một trong những điều khiến tập lệnh x86 trở nên xấu xí, vì nó không thể quyết định xem đó là bộ tích lũy hay kiến ​​trúc dựa trên tệp đăng ký (mặc dù điều này hầu hết đã được sửa với 386, điều này làm cho tập lệnh trực giao hơn nhiều , bất kể điều gì mà 68k người hâm mộ nói với bạn).
ninjalj

25

Cú hích chính chống lại x86 trong tâm trí tôi là nguồn gốc CISC của nó - tập lệnh chứa rất nhiều phụ thuộc lẫn nhau. Những sự phụ thuộc lẫn nhau này gây khó khăn khi thực hiện những việc như sắp xếp lại thứ tự lệnh trên chip, bởi vì các tạo tác và ngữ nghĩa của những sự phụ thuộc lẫn nhau đó phải được bảo toàn cho mỗi lệnh.

Ví dụ, hầu hết các lệnh cộng và trừ số nguyên x86 đều sửa đổi thanh ghi cờ. Sau khi thực hiện một phép cộng hoặc phép trừ, thao tác tiếp theo thường là xem các thanh ghi cờ để kiểm tra lỗi tràn, bit dấu, v.v. Nếu có một phép cộng khác sau đó, rất khó để biết liệu có an toàn để bắt đầu thực hiện phép cộng thứ hai hay không. trước khi kết quả của lần bổ sung đầu tiên được biết.

Trên kiến ​​trúc RISC, lệnh add sẽ chỉ định các toán hạng đầu vào và (các) thanh ghi đầu ra, và mọi thứ về hoạt động sẽ diễn ra chỉ khi sử dụng các thanh ghi đó. Điều này làm cho việc tách các thao tác bổ sung gần nhau dễ dàng hơn nhiều vì không có thanh ghi cờ nào buộc mọi thứ phải xếp hàng và thực thi một tệp duy nhất.

Chip DEC Alpha AXP, một thiết kế RISC theo phong cách MIPS, khá khó khăn trong các hướng dẫn có sẵn, nhưng tập lệnh được thiết kế để tránh các phụ thuộc thanh ghi ngầm giữa các lệnh. Không có thanh ghi ngăn xếp do phần cứng xác định. Không có thanh ghi cờ do phần cứng xác định. Ngay cả con trỏ hướng dẫn cũng đã được OS định nghĩa - nếu bạn muốn quay lại người gọi, bạn phải tìm cách người gọi sẽ cho bạn biết địa chỉ nào để quay lại. Điều này thường được xác định bởi quy ước gọi hệ điều hành. Tuy nhiên, trên x86, nó được xác định bởi phần cứng chip.

Dù sao, qua 3 hoặc 4 thế hệ thiết kế chip Alpha AXP, phần cứng đã từ chỗ thực thi tập lệnh spartan theo nghĩa đen với 32 thanh ghi int và 32 thanh ghi float thành một công cụ thực thi không theo thứ tự khổng lồ với 80 thanh ghi bên trong, đổi tên thanh ghi, chuyển tiếp kết quả (trong đó kết quả của một lệnh trước được chuyển tiếp đến một lệnh sau phụ thuộc vào giá trị) và tất cả các loại công cụ tăng hiệu suất hoang dã và điên rồ. Và với tất cả những tiếng chuông và tiếng còi đó, chip AXP vẫn nhỏ hơn đáng kể so với chip Pentium tương đương vào thời điểm đó, và AXP nhanh hơn rất nhiều.

Bạn không thấy những thứ tăng hiệu suất bùng nổ đó trong cây họ x86 phần lớn là do độ phức tạp của tập lệnh x86 khiến nhiều loại tối ưu hóa thực thi trở nên đắt đỏ nếu không muốn nói là không thể. Thiên tài của Intel là đã từ bỏ việc triển khai tập lệnh x86 trong phần cứng nữa - tất cả các chip x86 hiện đại thực sự là lõi RISC ở một mức độ nhất định sẽ diễn giải các lệnh x86, dịch chúng thành vi mã bên trong bảo toàn tất cả ngữ nghĩa của x86 gốc. nhưng cho phép một chút RISC không theo thứ tự và các tối ưu hóa khác trên vi mã.

Tôi đã viết rất nhiều trình biên dịch x86 và hoàn toàn có thể đánh giá cao sự tiện lợi của gốc CISC của nó. Nhưng tôi không hoàn toàn đánh giá được x86 phức tạp như thế nào cho đến khi tôi dành một chút thời gian để viết trình hợp dịch Alpha AXP. Tôi đã bị thu hút bởi sự đơn giản và đồng nhất của AXP. Sự khác biệt là rất lớn và sâu sắc.


6
Tôi sẽ lắng nghe không bashing của CISC cho mỗi gia nhập trừ khi và cho đến khi bạn có thể giải thích m68k.
dmckee --- cựu điều hành kitten

2
Mình không rành về m68k nên không phê bình được.
dthorpe

4
Tôi không nghĩ câu trả lời này đủ tệ để phản đối, nhưng tôi nghĩ toàn bộ lập luận "RISC nhỏ hơn và nhanh hơn CISC" không thực sự phù hợp trong kỷ nguyên hiện đại. Chắc chắn, AXP có thể nhanh hơn rất nhiều so với thời điểm hiện tại, nhưng thực tế của vấn đề là các RISC hiện đại và CISC hiện đại đều giống nhau về hiệu suất. Như tôi đã nói trong câu trả lời của mình, hình phạt điện năng nhẹ đối với giải mã x86 là lý do để không sử dụng x86 cho một thứ gì đó như điện thoại di động, nhưng đó là lý do nhỏ đối với máy tính để bàn hoặc máy tính xách tay có kích thước đầy đủ.
Billy ONeal

4
@Billy: kích thước không chỉ là kích thước mã hoặc kích thước hướng dẫn. Intel trả một khoản tiền khá lớn trong diện tích bề mặt chip để thực hiện logic phần cứng cho tất cả các lệnh đặc biệt đó, lõi vi mã RISC có nằm dưới mui xe hay không. Kích thước của khuôn ảnh hưởng trực tiếp đến chi phí sản xuất, vì vậy nó vẫn là mối quan tâm hợp lệ với các thiết kế hệ thống hiện đại.
dthorpe

1
@dthorpe: Tôi không đồng ý với hầu hết nếu không phải là tất cả những gì bạn đã viết. Kể từ năm 8086, bạn không phải lo lắng liệu có an toàn khi thực thi một lệnh addkhác hay không add. Các quy tắc rõ ràng. Bạn cũng không cần phải đối phó với việc sắp xếp lại hướng dẫn. Kể từ Pentium Pro vào giữa những năm 90, CPU đã làm điều đó cho bạn. Những gì bạn đang đề cập có thể là một vấn đề cách đây 20 năm, nhưng tôi không thấy có lý do gì để chống lại kiến ​​trúc x86 ngày nay.
Nathan Fellman

21

Kiến trúc x86 bắt nguồn từ thiết kế của bộ vi xử lý 8008 và họ hàng. Các CPU này được thiết kế trong thời kỳ bộ nhớ chậm và nếu bạn có thể làm điều đó trên CPU chết, nó thường nhanh hơn rất nhiều . Tuy nhiên, không gian chết của CPU cũng rất đắt. Hai lý do này là lý do tại sao chỉ có một số ít thanh ghi có xu hướng có các mục đích đặc biệt và một tập lệnh phức tạp với đủ loại lỗi và hạn chế.

Các bộ vi xử lý khác từ cùng thời đại (ví dụ như dòng 6502) cũng có những hạn chế và khó khăn tương tự. Điều thú vị là cả dòng 8008 và dòng 6502 đều được dùng làm bộ điều khiển nhúng. Thậm chí vào thời điểm đó, các bộ điều khiển nhúng được cho là sẽ được lập trình trong trình hợp dịch và theo nhiều cách được phục vụ cho người lập trình hợp ngữ hơn là người viết trình biên dịch. (Hãy nhìn vào chip VAX để biết điều gì sẽ xảy ra khi bạn phục vụ cho việc viết trình biên dịch.) Các nhà thiết kế không mong đợi chúng trở thành nền tảng máy tính có mục đích chung; đó là những thứ giống như những người tiền nhiệm của POWER archicture dành cho. Tất nhiên, cuộc cách mạng Máy tính gia đình đã thay đổi điều đó.


4
+1 cho câu trả lời duy nhất ở đây từ một người thực sự dường như có kiến ​​thức lịch sử về vấn đề này.
Billy ONeal

3
Bộ nhớ luôn chậm. Ngày nay có thể (nói một cách tương đối) chậm hơn so với khi tôi bắt đầu với Z80 và CP / M vào năm 1982. Tuyệt chủng không phải là con đường tiến hóa duy nhất bởi vì với sự tuyệt chủng, hướng tiến hóa cụ thể sẽ dừng lại. Tôi có thể nói rằng x86 đã thích nghi tốt trong 28 năm (tồn tại cho đến nay).
Olof Forshell

4
Tốc độ bộ nhớ nhanh chóng đạt gần ngang bằng với các CPU vào khoảng thời gian 8086. 9900 của Texas Instruments có thiết kế chỉ hoạt động vì điều này đã xảy ra. Nhưng sau đó CPU lại chạy trước và vẫn ở đó. Chỉ bây giờ, có bộ nhớ cache để giúp quản lý điều này.
staticsan

3
@Olof Forshell: Nó tương thích với trình hợp dịch trong đó mã lắp ráp 8080 có thể dịch thành mã 8086. Theo quan điểm đó, đó là 8080 cộng với tiện ích mở rộng, giống như bạn có thể xem 8080 là 8008 cộng với tiện ích mở rộng.
David Thornley,

3
@Olof Forshell: Ngoại trừ việc 8086 được thiết kế để điều đó xảy ra. Nó là một phần mở rộng của 8080, và hầu hết (có thể là tất cả) các lệnh 8080 được ánh xạ 1-1, với ngữ nghĩa rõ ràng là tương tự. Điều đó không đúng với kiến ​​trúc IBM 360, bất kể bạn muốn đẩy nó theo cách nào.
David Thornley

13

Tôi có một số khía cạnh bổ sung ở đây:

Hãy xem xét hoạt động "a = b / c" x86 sẽ thực hiện điều này như

  mov eax,b
  xor edx,edx
  div dword ptr c
  mov a,eax

Như một phần thưởng bổ sung của lệnh div edx sẽ chứa phần còn lại.

Một bộ xử lý RISC sẽ yêu cầu đầu tiên tải địa chỉ của b và c, tải b và c từ bộ nhớ đến các thanh ghi, thực hiện phép chia và tải địa chỉ của a rồi lưu trữ kết quả. Cú pháp Dst, src:

  mov r5,addr b
  mov r5,[r5]
  mov r6,addr c
  mov r6,[r6]
  div r7,r5,r6
  mov r5,addr a
  mov [r5],r7

Ở đây thường sẽ không có phần còn lại.

Nếu bất kỳ biến nào được tải qua con trỏ thì cả hai chuỗi có thể dài hơn mặc dù điều này ít xảy ra hơn đối với RISC vì nó có thể có một hoặc nhiều con trỏ đã được tải trong một thanh ghi khác. x86 có ít thanh ghi hơn nên khả năng con trỏ nằm trong một trong số chúng là nhỏ hơn.

Ưu và nhược điểm:

Các lệnh RISC có thể được trộn với mã xung quanh để cải thiện việc lập lịch lệnh, điều này ít xảy ra với x86 mà thay vào đó, x86 thực hiện điều này (nhiều hoặc ít tùy thuộc vào trình tự) bên trong chính CPU. Chuỗi RISC ở trên thường sẽ dài 28 byte (7 lệnh có độ rộng 32 bit / 4 byte mỗi lệnh) trên kiến ​​trúc 32 bit. Điều này sẽ khiến bộ nhớ ngoài chip hoạt động nhiều hơn khi tìm nạp các hướng dẫn (bảy lần tìm nạp). Chuỗi x86 dày đặc hơn chứa ít lệnh hơn và mặc dù độ rộng của chúng khác nhau, có thể bạn cũng đang xem trung bình 4 byte / lệnh ở đó. Ngay cả khi bạn có bộ nhớ đệm hướng dẫn để tăng tốc bảy lần tìm nạp này có nghĩa là bạn sẽ có ba lần thiếu hụt ở nơi khác để bù đắp so với x86.

Kiến trúc x86 với ít thanh ghi hơn để lưu / khôi phục có nghĩa là nó có thể sẽ thực hiện chuyển mạch luồng và xử lý ngắt nhanh hơn RISC. Nhiều thanh ghi hơn để lưu và khôi phục đòi hỏi nhiều không gian ngăn xếp RAM tạm thời hơn để thực hiện ngắt và nhiều không gian ngăn xếp cố định hơn để lưu trữ trạng thái luồng. Những khía cạnh này sẽ làm cho x86 trở thành ứng cử viên tốt hơn để chạy RTOS thuần túy.

Trên một lưu ý cá nhân hơn, tôi thấy việc viết RISC assembly khó hơn x86. Tôi giải quyết vấn đề này bằng cách viết quy trình RISC trong C, biên dịch và sửa đổi mã đã tạo. Điều này hiệu quả hơn từ quan điểm sản xuất mã và có lẽ kém hiệu quả hơn từ quan điểm thực thi. Tất cả 32 đăng ký để theo dõi. Với x86 thì ngược lại: 6-8 thanh ghi có tên "thật" làm cho vấn đề dễ quản lý hơn và tạo thêm niềm tin rằng mã được tạo ra sẽ hoạt động như mong đợi.

Xấu xí? Đó là trong mắt của người xử lý. Tôi thích "khác biệt".


a, b và c trong các ví dụ của tôi nên được xem như các biến dựa trên bộ nhớ chứ không phải các giá trị tức thì.
Olof Forshell

... "dword ptr" được sử dụng để xác định kích thước của một biến mà kích thước của nó không được biết, ví dụ: nó chỉ được khai báo là bên ngoài hoặc nếu bạn đã lười biếng.
Olof Forshell

2
Đó không phải là lần đầu tiên tôi nghe thấy đề xuất viết nó bằng C trước, sau đó chắt lọc nó thành trình hợp ngữ. Điều đó chắc chắn có ích
Joe Plante

Trong những ngày đầu, tất cả các bộ xử lý đều là RISC. CISC ra đời như một chiến lược giảm thiểu đối với các hệ thống bộ nhớ lõi sắt RẤT chậm, do đó CISC, với ít lệnh hơn, mạnh hơn, gây ít căng thẳng hơn cho hệ thống con bộ nhớ và sử dụng băng thông tốt hơn. Tương tự như vậy, ban đầu các thanh ghi được coi là vị trí bộ nhớ trên chip, trong CPU để thực hiện tích lũy. Lần cuối cùng tôi đánh giá nghiêm túc một máy RISC là năm 1993 - SPARC và HP Prisim. SPARC rất kinh khủng trên diện rộng. Prisim nhanh gấp 20 lần so với 486 trên add / sub / mul nhưng bị hút vào siêu việt. CISC tốt hơn.

@OlofForshell Bạn nói there typically won't be a remindernhưng wiki nói rằng mips có nó: en.wikipedia.org/wiki/MIPS_instruction_set#Integer
Alex Zhukovskiy

10

Tôi nghĩ câu hỏi này có một giả định sai. Nó chủ yếu chỉ là những học giả bị ám ảnh bởi RISC gọi x86 là xấu xí. Trên thực tế, ISA x86 có thể thực hiện trong một hoạt động lệnh đơn lẻ sẽ cần đến 5-6 lệnh trên RISC ISA. Người hâm mộ RISC có thể phản đối rằng các CPU x86 hiện đại phá vỡ các lệnh "phức tạp" này thành các microops; Tuy nhiên:

  1. Trong nhiều trường hợp, điều đó chỉ đúng một phần hoặc hoàn toàn không đúng. Các hướng dẫn "phức tạp" hữu ích nhất trong x86 là những thứ như mov %eax, 0x1c(%esp,%edi,4)chế độ định địa chỉ, và chúng không được chia nhỏ.
  2. Điều thường quan trọng hơn trên các máy hiện đại không phải là số chu kỳ được sử dụng (vì hầu hết các tác vụ không bị ràng buộc bởi cpu) mà là tác động của bộ đệm lệnh của mã. 5-6 lệnh kích thước cố định (thường là 32bit) sẽ ảnh hưởng đến bộ nhớ cache nhiều hơn một lệnh phức tạp hiếm khi nhiều hơn 5 byte.

x86 thực sự hấp thụ tất cả các khía cạnh tốt của RISC khoảng 10-15 năm trước, và những phẩm chất còn lại của RISC (thực sự là định nghĩa - tập lệnh tối thiểu) là có hại và không mong muốn.

Ngoài chi phí và độ phức tạp của việc sản xuất CPU và yêu cầu năng lượng của chúng, x86 là ISA tốt nhất . Bất kỳ ai nói với bạn theo cách khác đều đang để cho hệ tư tưởng hoặc chương trình nghị sự cản trở lý luận của họ.

Mặt khác, nếu bạn đang nhắm mục tiêu các thiết bị nhúng mà chi phí của CPU được tính, hoặc các thiết bị nhúng / di động nơi tiêu thụ năng lượng là mối quan tâm hàng đầu, ARM hoặc MIPS có thể có ý nghĩa hơn. Hãy nhớ rằng mặc dù bạn vẫn phải xử lý thêm ram và kích thước nhị phân cần thiết để xử lý mã dễ dàng lớn hơn 3-4 lần và bạn sẽ không thể đạt được gần hiệu suất. Điều này có quan trọng hay không phụ thuộc rất nhiều vào những gì bạn sẽ chạy trên nó.


3
nơi tiêu thụ năng lượng là mối quan tâm hàng đầu, ARM hoặc MIPS có lẽ có ý nghĩa hơn ... vì vậy, nếu có ít nhất một khía cạnh mà ARM hoặc MIPS có ý nghĩa hơn, nó không làm cho x86 không nhất thiết phải là ISA tốt nhất?
Shahbaz

Đó là lý do tại sao tôi đủ tiêu chuẩn "tốt nhất" với "ngoài chi phí ... và yêu cầu năng lượng của họ".
R .. GitHub NGỪNG TRỢ GIÚP LÚC NỮA,

1
Tôi nghĩ rằng việc Intel giảm tốc độ CPU và kích thước khuôn nhỏ hơn đã loại bỏ phần lớn sự khác biệt về công suất. CPU Celeron kép 64 bit mới với bộ nhớ đệm 64k L1 và 1MB L2 là chip 7,5 watt. Đó là máy hangout "Starbucks" của tôi và thời lượng pin dài đến mức nực cười và sẽ chạy vòng quanh máy P6. Là một chàng trai làm phần lớn các phép tính dấu phẩy động, tôi đã từ bỏ RISC từ lâu. Nó chỉ bò. SPARC đặc biệt là băng hà tàn bạo. Ví dụ hoàn hảo về lý do tại sao RISC tệ là CPU Intel i860. Intel không bao giờ đi đến đó một lần nữa.

@RocketRoy: 7,5 watt không thực sự chấp nhận được đối với một thiết bị được cung cấp năng lượng 24/7 (và không thực hiện các phép tính hữu ích suốt thời gian) hoặc hết pin 3.7v / 2000mAh.
R .. GitHub NGỪNG TRỢ GIÚP ICE

2
@RocketRoy "CPU Intel i860. Intel không bao giờ đi đến ĐÓ nữa." Sau một nghiên cứu nhỏ, i860 âm thanh một nhiều như Itanium: VLIW, biên dịch theo lệnh hướng dẫn xử lý song song ....
Jonathon Reinhart

9

ngôn ngữ trình hợp dịch x86 không quá tệ. Đó là khi bạn truy cập vào mã máy, nó bắt đầu trở nên thực sự xấu xí. Mã hóa lệnh, chế độ định địa chỉ, v.v. phức tạp hơn nhiều so với mã hóa đối với hầu hết các CPU RISC. Và có thêm nhiều điều thú vị được tích hợp cho các mục đích tương thích ngược - thứ chỉ phát huy tác dụng khi bộ xử lý ở một trạng thái nhất định.

Ví dụ, trong các chế độ 16-bit, việc định địa chỉ có vẻ rất kỳ lạ; có một chế độ địa chỉ cho [BX+SI], nhưng không có một cho [AX+BX]. Những thứ như vậy có xu hướng phức tạp hóa việc sử dụng sổ đăng ký, vì bạn cần đảm bảo giá trị của mình trong một sổ đăng ký mà bạn có thể sử dụng khi cần.

(May mắn thay, chế độ 32-bit tốt hơn nhiều (mặc dù bản thân nó vẫn hơi kỳ lạ - ví dụ như phân đoạn) và mã x86 16-bit phần lớn không còn liên quan nữa ngoài bộ tải khởi động và một số môi trường nhúng.)

Ngoài ra còn có những thứ còn sót lại từ những ngày xa xưa, khi Intel đang cố gắng biến x86 trở thành bộ xử lý tối ưu. Các hướng dẫn dài một vài byte đã thực hiện các tác vụ mà không ai thực sự làm được nữa, vì chúng thực sự quá chậm hoặc phức tạp. ENTER vàHướng dẫn LOOP , đối với hai ví dụ - lưu ý rằng mã khung ngăn xếp C giống như "push ebp; mov ebp, esp" và không phải "enter" đối với hầu hết các trình biên dịch.


2
Tôi tin rằng vấn đề "enter" so với "push / mov" đã phát sinh vì trên một số bộ xử lý, "push / mov" nhanh hơn. Trên một số bộ xử lý, "enter" nhanh hơn. C'est la vie.
Dietrich Epp

4
Khi tôi buộc phải sử dụng một máy dựa trên x86 và bắt đầu xem xét nó (có nền m68k), tôi bắt đầu cảm thấy lập trình asm bực bội, ... như thể tôi đã học lập trình với một ngôn ngữ như C, và sau đó buộc phải liên lạc với asm ... bạn "cảm thấy" mình mất đi khả năng diễn đạt, dễ dàng, rõ ràng, "mạch lạc", "khả năng trực giác". Tôi chắc chắn rằng nếu tôi bắt đầu lập trình asm với x86, tôi sẽ nghĩ nó không quá tệ ... có lẽ ... tôi cũng đã làm MMIX và MIPS, và "asm lang" của họ tốt hơn nhiều so với x86 (nếu đây là PoV phù hợp cho Q, nhưng có lẽ nó không phải)
ShinTakezou

Vấn đề chế độ địa chỉ đã được khắc phục trong 80386. Chỉ mã 16 bit có các chế độ địa chỉ hạn chế, mã 32 bit tốt hơn nhiều. Bạn có thể nhận các chế độ địa chỉ 32 bit trong mã 16 bit bằng cách sử dụng tiền tố đặc biệt và ngược lại.
fuz

@FUZxxl: Vâng ... tôi có lẽ nên đề cập rằng độ xấu chủ yếu chỉ giới hạn ở mã 16 bit. Đã sửa (tôi nghĩ). :)
cHao

Sự kém cỏi được nhận thức chủ yếu đến từ quan niệm sai lầm rằng các thanh ghi của 8086 là các thanh ghi cho mục đích chung; điều đó không chính xác. Mỗi người trong số họ có một mục đích đặc biệt và nếu bạn không tuân theo mục đích của họ, bạn sẽ có một khoảng thời gian tồi tệ.
fuz

3

Tôi không phải là một chuyên gia, nhưng có vẻ như nhiều tính năng khiến mọi người không thích nó có thể là lý do nó hoạt động tốt. Vài năm trước, có các thanh ghi (thay vì một ngăn xếp), các khung thanh ghi, v.v. được coi là những giải pháp tốt để làm cho kiến ​​trúc có vẻ đơn giản hơn đối với con người. Tuy nhiên, hiện nay, điều quan trọng là hiệu suất bộ nhớ cache và các từ có độ dài thay đổi của x86 cho phép nó lưu trữ nhiều lệnh hơn trong bộ nhớ cache. "Giải mã hướng dẫn", mà tôi tin rằng các đối thủ đã chỉ ra từng chiếm một nửa chip, gần như không còn nhiều như vậy nữa.

Tôi nghĩ tính song song là một trong những yếu tố quan trọng nhất hiện nay - ít nhất là đối với các thuật toán đã chạy đủ nhanh để có thể sử dụng được. Việc thể hiện tính song song cao trong phần mềm cho phép phần cứng giảm bớt (hoặc thường ẩn hoàn toàn) độ trễ bộ nhớ. Tất nhiên, tương lai kiến ​​trúc vươn xa hơn có lẽ là trong một lĩnh vực như điện toán lượng tử.

Tôi đã nghe từ nVidia rằng một trong những sai lầm của Intel là họ giữ các định dạng nhị phân gần với phần cứng. CUDA's PTX thực hiện một số tính toán sử dụng thanh ghi nhanh (tô màu đồ thị), vì vậy nVidia có thể sử dụng máy đăng ký thay vì máy ngăn xếp, nhưng vẫn có đường dẫn nâng cấp không phá vỡ tất cả phần mềm cũ.


9
RISC không được thiết kế cho các nhà phát triển con người. Một trong những ý tưởng đằng sau RISC là giảm tải một số độ phức tạp của chip cho bất kỳ ai viết assembly, lý tưởng nhất là trình biên dịch. Nhiều thanh ghi hơn có nghĩa là sử dụng ít bộ nhớ hơn và ít phụ thuộc hơn giữa các lệnh, cho phép đường ống sâu hơn và hiệu suất cao hơn. Lưu ý rằng x86-64 có số lượng thanh ghi chung nhiều gấp đôi so với x86 và chỉ điều này là nguyên nhân dẫn đến tăng hiệu suất đáng kể. Và các hướng dẫn trên hầu hết các chip x86 được giải mã trước khi chúng được lưu vào bộ nhớ cache, không phải sau (vì vậy kích thước không quan trọng ở đây).
Dietrich Epp

3
@Dietrich Epp: Điều đó không hoàn toàn đúng. X86-64 có nhiều thanh ghi hơn hiển thị trong ISA, nhưng các triển khai x86 hiện đại thường có tệp thanh ghi kiểu RISC được ánh xạ tới các thanh ghi của ISA theo yêu cầu để tăng tốc độ thực thi.
Billy ONeal

"Tôi đã nghe từ nVidia rằng một trong những sai lầm của Intel là họ giữ các định dạng nhị phân gần với phần cứng." - Tôi không hiểu cái này và phần PTX của CUDA.
vuốt

1
@Dietrech Epp: "Và hướng dẫn trên hầu hết các chip x86 được giải mã trước khi chúng được lưu vào bộ nhớ cache, không phải sau" Điều đó không đúng. Chúng được lưu vào bộ nhớ đệm trước khi chúng được giải mã. Tôi tin rằng Pentium 4 có một bộ nhớ cache theo dõi bổ sung được lưu vào bộ nhớ cache sau khi giải mã, nhưng điều đó đã bị ngừng.
Nathan Fellman

điều đó không đúng, các bộ vi xử lý "cầu cát" mới nhất sử dụng một loại bộ nhớ đệm theo dõi (giống như cho pentium 4, oh cậu bé cũ: D), vì vậy các công nghệ sẽ biến mất và quay trở lại ...
Quonux

3

Bên cạnh những lý do mà mọi người đã đề cập:

  • x86-16 có một sơ đồ đánh địa chỉ bộ nhớ khá lạ cho phép một vị trí bộ nhớ duy nhất được đánh địa chỉ theo 4096 cách khác nhau, RAM giới hạn ở 1 MB và buộc các lập trình viên phải xử lý hai kích thước con trỏ khác nhau. May mắn thay, việc chuyển sang 32-bit đã làm cho tính năng này trở nên không cần thiết, nhưng các chip x86 vẫn mang trong mình các thanh ghi phân đoạn.
  • Trong khi không phải là một lỗi của x86 cho mỗi gia nhập , x86 ước gọi không được tiêu chuẩn hóa như MIPS là (chủ yếu là vì MS-DOS không đi kèm với bất kỳ trình biên dịch), để lại cho chúng ta sự lộn xộn của __cdecl, __stdcall, __fastcallvv

Hmm .. khi tôi nghĩ về các đối thủ cạnh tranh x86, tôi không nghĩ đến MIPS. ARM hoặc PowerPC có thể ....
Billy ONeal

@Billy: x86 đã tồn tại gần như mãi mãi. Đã có lúc MIPS là đối thủ cạnh tranh của x86. Như tôi nhớ x86 đã phải cắt bỏ công việc của nó để đạt đến một cấp độ mà nó có thể cạnh tranh với MIPS. (Quay lại khi MIPS và SPARC đã chiến đấu nó ra trong lĩnh vực máy trạm.)
Shannon Severance

@Shannon Từ chức: Chỉ vì một cái gì đó đã từng là không có nghĩa là một cái gì đó.
Billy ONeal

2
@supercat: những gì mọi người trong thời đại của mô hình bộ nhớ phẳng x86-32 có xu hướng quên là 16 bit có nghĩa là 64k bộ nhớ (bất kỳ ai bận tâm làm toán sẽ hiểu rằng phép thuật là không thể, rằng 8086 không phải là hình phạt khó chịu cho các lập trình viên không nghi ngờ). Có một số cách để đạt được khoảng 64k nhưng giải pháp 8086 là một sự thỏa hiệp tốt.
Olof Forshell

2
@OlofForshell: Tôi nghĩ nhiều người đã than phiền rằng 8086 không đẹp bằng 68000 (có không gian địa chỉ tuyến tính 16MB và đường dẫn rõ ràng đến 4 hợp đồng biểu diễn). Chắc chắn việc chuyển sang bộ xử lý 32-bit sẽ giúp truy cập dễ dàng hơn 64K, nhưng 8086 là một kiến ​​trúc 16-bit được thiết kế để cải thiện một bước so với 8080 8-bit. Tôi thấy không có lý do gì Intel nên nhảy vọt trực tiếp từ 8-bit sang 32-bit.
supercat

3

Tôi nghĩ rằng bạn sẽ đi đến một phần của câu trả lời nếu bạn cố gắng viết một trình biên dịch nhắm mục tiêu x86 hoặc nếu bạn viết một trình giả lập máy x86 hoặc thậm chí nếu bạn cố gắng triển khai ISA trong một thiết kế phần cứng.

Mặc dù tôi hiểu "x86 là xấu xí!" tranh luận, tôi vẫn nghĩ nó vui hơn việc viết assembly x86 hơn MIPS (ví dụ) - cái sau chỉ đơn giản là tẻ nhạt. Nó luôn luôn tốt cho các trình biên dịch hơn là cho con người. Tôi không chắc một con chip có thể thù địch hơn với người viết trình biên dịch nếu nó cố gắng ...

Phần xấu nhất đối với tôi là cách thức hoạt động của phân đoạn (chế độ thực) - rằng bất kỳ địa chỉ vật lý nào cũng có 4096 phân đoạn: bí danh offset. Lần cuối cùng bạn cần điều đó là khi nào? Mọi thứ sẽ đơn giản hơn rất nhiều nếu phần phân đoạn là các bit bậc cao hơn của địa chỉ 32 bit.


m68k vui nhộn hơn rất nhiều và tốt với con người hơn nhiều so với x86 (điều này có vẻ không giống với con người đối với nhiều lập trình viên m68k), nếu PoV phù hợp là cách con người có thể viết mã trong các assembly đó.
ShinTakezou

Phân khúc: địa chỉ bù đắp là một nỗ lực để duy trì sự tương thích ở một mức độ nào đó với thế giới CP / M. Một trong những quyết định tồi tệ nhất từ ​​trước đến nay.
Turing Complete vào

@Turing Complete: segment: offset chủ yếu KHÔNG phải là nỗ lực để duy trì tương thích với thế giới CP / M. Đó là một nỗ lực rất thành công khi cho phép bộ xử lý 16 bit xử lý hơn 64 KByte bằng cách đặt mã, dữ liệu, ngăn xếp và các vùng bộ nhớ khác trong các phân đoạn khác nhau.
Olof Forshell

1
Trong thực tế, việc đặt dữ liệu và ngăn xếp trong các phân đoạn khác nhau là hoàn toàn vô ích đối với C; nó chỉ có thể sử dụng được cho asm. Trong C, một con trỏ có thể trỏ đến dữ liệu với thời lượng lưu trữ tĩnh, tự động hoặc được phân bổ động, vì vậy không có cách nào để lướt qua phân đoạn. Có lẽ nó là hữu ích cho Pascal hoặc Fortran hoặc một cái gì đó, nhưng không phải cho C, mà đã là ngôn ngữ chi phối vào thời điểm đó ...
R .. GitHub DỪNG GIÚP ICE

2
@Bernd: Lý do fs / gs được chọn để lưu trữ cục bộ luồng không phải là thanh ghi phân đoạn tốt cho việc này. Chỉ là x86 bị ​​bỏ đói nghiêm trọng cho các thanh ghi và các thanh ghi phân đoạn không được sử dụng. Một thanh ghi có mục đích chung trỏ đến cấu trúc luồng cũng sẽ hoạt động tốt và trên thực tế, nhiều hệ thống RISC với nhiều thanh ghi hơn sử dụng một thanh ghi làm con trỏ luồng.
R .. GitHub NGỪNG TRỢ GIÚP LÚC NỮA,

1
  1. x86 có một bộ thanh ghi đa năng rất, rất hạn chế

  2. nó thúc đẩy một phong cách phát triển rất kém hiệu quả ở cấp độ thấp nhất (địa ngục CISC) thay vì một phương pháp luận tải / lưu trữ hiệu quả

  3. Intel đã đưa ra quyết định kinh hoàng khi giới thiệu mô hình phân đoạn / bù đắp - bộ nhớ hoàn toàn ngu ngốc để duy trì khả năng tương thích với công nghệ lỗi thời (tại thời điểm này!)

  4. Vào thời điểm mà tất cả mọi người đều sử dụng 32 bit, x86 đã kìm hãm thế giới PC chính thống bằng một con số 16 bit ít ỏi (hầu hết trong số họ - 8088 - thậm chí chỉ có đường dẫn dữ liệu ngoài 8 bit, thậm chí còn đáng sợ hơn!)


Đối với tôi (và tôi là một cựu chiến binh DOS đã từng chứng kiến ​​mọi thế hệ PC từ góc độ nhà phát triển!) Thì điểm 3 là tệ nhất.

Hãy tưởng tượng tình huống sau đây mà chúng ta đã có vào đầu những năm 90 (chính thống!):

a) Hệ điều hành có những hạn chế điên cuồng vì những lý do cũ (640kB RAM dễ truy cập) - DOS

b) Một phần mở rộng của hệ điều hành (Windows) có thể làm được nhiều hơn về RAM, nhưng bị hạn chế khi nói đến những thứ như trò chơi, v.v. và không phải là thứ ổn định nhất trên Trái đất (may mắn là điều này đã thay đổi sau đó, nhưng tôi Tôi đang nói về đầu những năm 90 ở đây)

c) Hầu hết phần mềm vẫn là DOS và chúng tôi phải tạo đĩa khởi động thường xuyên cho phần mềm đặc biệt, bởi vì có EMM386.exe này mà một số chương trình thích, một số chương trình khác lại ghét (đặc biệt là các game thủ - và tôi là một game thủ AVID vào thời điểm này - biết gì không? tôi đang nói về đây)

d) Chúng tôi bị giới hạn ở MCGA 320x200x8 bit (ok, có nhiều hơn một chút với các thủ thuật đặc biệt, 360x480x8 là có thể, nhưng chỉ khi không có hỗ trợ thư viện thời gian chạy), mọi thứ khác lộn xộn và kinh khủng ("VESA" - lol)

e) Nhưng về phần cứng, chúng tôi có máy 32 bit với khá nhiều megabyte RAM và card VGA hỗ trợ lên đến 1024x768

Lý do của tình trạng tồi tệ này?

Một quyết định thiết kế đơn giản của Intel. Mức độ tương thích của máy (KHÔNG phải mức nhị phân!) Với thứ gì đó đã chết, tôi nghĩ đó là 8085. Các vấn đề khác, dường như không liên quan (chế độ đồ họa, v.v.) có liên quan vì lý do kỹ thuật và vì phạm vi rất hẹp kiến trúc tâm trí mà nền tảng x86 mang theo.

Ngày nay, tình hình đã khác, nhưng hãy hỏi bất kỳ nhà phát triển trình hợp ngữ nào hoặc những người xây dựng chương trình phụ trợ trình biên dịch cho x86. Số lượng đăng ký mục đích chung thấp đến mức điên cuồng không gì khác ngoài một kẻ giết người hiệu suất khủng khiếp.


Các vấn đề lớn duy nhất với kiến ​​trúc phân đoạn 8086 là chỉ có một thanh ghi phân đoạn không chuyên dụng (ES) và các ngôn ngữ lập trình không được thiết kế để hoạt động hiệu quả với nó. Phong cách định địa chỉ theo tỷ lệ mà nó sử dụng sẽ hoạt động rất tốt trong một ngôn ngữ hướng đối tượng mà không mong đợi các đối tượng có thể bắt đầu tại các địa chỉ tùy ý (nếu một người căn chỉnh các đối tượng trên ranh giới đoạn, tham chiếu đối tượng sẽ chỉ cần có hai byte thay vì bốn). Nếu người ta so sánh mã Macintosh đời đầu với mã PC, 8086 thực sự trông khá đẹp so với 68000.
supercat

@supercat: trên thực tế, các es đăng ký WAS dành riêng cho một cái gì đó, cụ thể là cho những hướng dẫn chuỗi yêu cầu lưu trữ (mov, stos) hoặc quét (cmps và scas). Với địa chỉ 64KiB từ mọi thanh ghi phân đoạn cũng cung cấp "liên kết bị thiếu" tới bộ nhớ ngoài mã, dữ liệu và bộ nhớ ngăn xếp (cs, ds, ss). Các thanh ghi phân đoạn cung cấp một loại sơ đồ bảo vệ bộ nhớ trong đó bạn không thể giải quyết bên ngoài các khối bộ nhớ 64Kib của thanh ghi. Bạn đề xuất giải pháp nào tốt hơn khi x86 là kiến ​​trúc 16-bit và những hạn chế về kỹ thuật in thạch bản trong ngày?
Olof Forshell

@OlofForshell: ES được sử dụng cho các lệnh chuỗi, nhưng có thể được sử dụng như một thanh ghi không cam kết cho mã không sử dụng chúng. Một cách để giảm nút thắt cổ chai seg-reg mà không yêu cầu quá nhiều không gian opcode là có tiền tố "rseg" sẽ chỉ định rằng đối với lệnh định dạng r / m sau đây, trường "r" sẽ chọn từ CS / SS / DS / ES / FS / GS / ?? / ?? thay vì AX / BX / CX / DX / SI / DI / SP / BP và có tiền tố cho FS / GS và hướng dẫn cho LFS và LGS (như LDS và LES). Tôi không biết kiến ​​trúc vi mô cho 8086 đã được hình thành như thế nào, nhưng tôi nghĩ một thứ như vậy có thể hoạt động được.
supercat

@supercat: như tôi đã viết, "register es cũng cung cấp liên kết bị thiếu đến bộ nhớ ngoài ..." Fs và gs đã không đến cho đến năm 386 như tôi nhớ lại.
Olof Forshell

1
@OlofForshell: Họ không làm vậy, điều này làm cho kiến ​​trúc 80286 thậm chí còn tệ hơn kiến ​​trúc 8086 về hầu hết các phương diện. Quan điểm của tôi là việc thêm một vài thanh ghi phân đoạn (hoặc thậm chí một thanh ghi, đối với vấn đề đó) sẽ làm cho kiến ​​trúc 8086 hữu ích hơn rất nhiều và tập lệnh có thể sạch hơn và hữu ích hơn nếu các thanh ghi phân đoạn có thể được truy cập giống như những cái khác.
supercat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.