Làm thế nào ALU trong bộ vi xử lý sẽ phân biệt giữa một số đã ký, -7 được ký hiệu là 1111 và số 15 không dấu, cũng được ký hiệu là 1111?
Làm thế nào ALU trong bộ vi xử lý sẽ phân biệt giữa một số đã ký, -7 được ký hiệu là 1111 và số 15 không dấu, cũng được ký hiệu là 1111?
Câu trả lời:
Câu trả lời ngắn gọn và đơn giản là: không. Không có CPU CPU CPU hiện đại nào hoạt động theo cách bạn nghĩ.
Đối với CPU, nó chỉ là một mẫu bit. Tùy thuộc vào bạn, lập trình viên, để theo dõi ý nghĩa của mẫu bit đó.
Nói chung, ISAs không phân biệt giữa các loại dữ liệu khác nhau, khi nói đến lưu trữ. (Bỏ qua các thanh ghi có mục đích đặc biệt như các thanh ghi nổi trong một FPU.) Nó chỉ là một mẫu bit vô nghĩa đối với CPU. Tuy nhiên, ISA làm có các loại khác nhau của các hướng dẫn mà có thể giải thích các mẫu bit theo những cách khác nhau. Ví dụ, hướng dẫn số học như MUL
, DIV
, ADD
, SUB
giải thích các mẫu bit như một số loại số, trong khi hướng dẫn logic như AND
, OR
, XOR
giải thích nó như một mảng các phép toán. Vì vậy, tùy thuộc vào, lập trình viên, (hoặc tác giả của trình thông dịch hoặc trình biên dịch nếu bạn sử dụng ngôn ngữ cấp cao hơn) để chọn hướng dẫn chính xác.
Ví dụ, rất có thể có các hướng dẫn riêng cho các số được ký so với số không dấu. Một số ISA cũng có hướng dẫn về số học với số thập phân được mã hóa nhị phân.
Tuy nhiên, lưu ý rằng tôi đã viết "ISA chính thống hiện đại" ở trên. Trên thực tế, có những ISA không chính thống hoặc lịch sử hoạt động khác nhau. Ví dụ, cả ISA CISC 48 bit gốc của IBM AS / 400 cũng như ISA RISC 64 bit dựa trên POWER hiện tại của hệ thống hiện được gọi là IBM i, phân biệt giữa các con trỏ và các giá trị khác. Con trỏ luôn được gắn thẻ và chúng bao gồm thông tin loại và quản lý quyền. CPU biết liệu một giá trị có phải là con trỏ hay không và chỉ hạt nhân i / OS đặc quyền mới được phép thao tác con trỏ một cách tự do. Các ứng dụng người dùng chỉ có thể thao tác các con trỏ mà họ sở hữu để trỏ vào bộ nhớ mà họ sở hữu bằng một số lượng nhỏ các hướng dẫn an toàn.
Ngoài ra còn có một số thiết kế ISA lịch sử bao gồm ít nhất một số hình thức nhận thức hạn chế.
char
, mà là một unsigned loại 16-bit. Tất nhiên, vẫn không có hướng dẫn số học không dấu trong mã byte Java, vì mọi char
giá trị được tự động thăng cấp lên int
(ký 32 bit) cho số học.
Phiên bản ngắn: không biết. Không có cách nào để nói.
Nếu 1111
đại diện cho -7, thì bạn có biểu diễn cường độ ký hiệu , trong đó bit đầu tiên là dấu hiệu và phần còn lại của các bit là độ lớn. Trong trường hợp này, số học có phần phức tạp, vì một phép cộng không dấu và một phép cộng được ký sử dụng logic khác nhau. Vì vậy, bạn có thể có một SADD
và một UADD
opcode, và nếu bạn chọn sai, bạn sẽ nhận được kết quả vô nghĩa.
Tuy nhiên, thường xuyên hơn, 1111
đại diện cho -1, trong cái được gọi là đại diện bổ sung của hai . Trong trường hợp này, ALU đơn giản là không quan tâm nếu các số được ký hoặc không dấu! Ví dụ: hãy thực hiện các hoạt động của 1110 + 0001
. Trong số học đã ký, điều này có nghĩa là "-2 + 1" và kết quả sẽ là -1 ( 1111
). Trong số học không dấu, điều này có nghĩa là "14 + 1" và kết quả sẽ là 15 ( 1111
). Vì vậy, ALU không biết bạn muốn có kết quả đã ký hay chưa ký và điều đó không quan tâm. Nó chỉ thực hiện bổ sung như thể nó không được ký và nếu bạn muốn coi đó là số nguyên đã ký sau đó, điều đó tùy thuộc vào bạn.
EDIT: Do Ruslan và Daniel Schepler hoàn toàn chỉ ra trong các bình luận, một số toán hạng vẫn cần các phiên bản được ký và không dấu riêng biệt, ngay cả trên máy hai phần bù. Phép cộng, phép trừ, phép nhân, đẳng thức và tất cả đều hoạt động tốt mà không cần biết các số có được ký hay không. Nhưng sự phân chia và bất kỳ so sánh lớn hơn / ít hơn so với phải có các phiên bản riêng biệt.
EDIT EDIT: Cũng có một số đại diện khác, như bổ sung của một người , nhưng về cơ bản chúng không bao giờ được sử dụng nữa nên bạn không cần phải lo lắng về chúng.
<
<=
>=
>
khác nhau đối với các toán hạng được ký so với không dấu trong khi đó ==
và !=
là tính không xác định.
Một trong những lợi thế lớn của toán học bổ sung hai, mà tất cả các kiến trúc hiện đại sử dụng, là các hướng dẫn cộng và trừ hoàn toàn giống nhau cho cả hai toán hạng đã ký và không dấu.
Nhiều CPU thậm chí không có các lệnh nhân, chia hoặc mô đun. Nếu họ làm như vậy, họ phải có các hình thức hướng dẫn được ký và không dấu riêng biệt, và trình biên dịch (hoặc lập trình viên ngôn ngữ lắp ráp) chọn một hình thức phù hợp.
CPU cũng thường có các hướng dẫn khác nhau để so sánh có chữ ký hoặc không dấu. Ví dụ: x86 có thể theo a CMP
với JL
(Nhảy nếu nhỏ hơn) nếu so sánh được ký hoặc JB
(Nhảy nếu dưới) nếu so sánh không được ký. Một lần nữa, trình biên dịch hoặc lập trình viên sẽ chọn đúng hướng dẫn cho kiểu dữ liệu.
Một vài hướng dẫn khác thường có các biến thể được ký và không dấu, chẳng hạn như dịch chuyển phải hoặc tải một giá trị vào một thanh ghi rộng hơn, có hoặc không có phần mở rộng ký.
smulh
và umulh
lợi nhuận mà chỉ có các bit trên của phép nhân và hướng dẫn signed và unsigned mà trả về kết quả trong một thanh ghi rộng gấp đôi các toán hạng nguồn.
Nó không. Bộ xử lý dựa vào tập lệnh để cho nó biết loại dữ liệu nào đang xem và nơi gửi nó. Không có gì về 1 và 0 trong toán hạng vốn có thể báo hiệu cho ALU xem dữ liệu có phải là char, float, int, đã ký int hay không, v.v ... Nếu 1111 đó sẽ chuyển sang mạch điện dự kiến sẽ bổ sung 2s, nó sẽ đi được giải thích như là một bổ sung 2s.
char
ở cấp độ phần cứng. Có thể ngày xửa ngày xưa, trở lại thời của máy điện báo. Nhưng ngày hôm nay, một char
là chỉ một số xa như phần cứng là có liên quan. Lý do tại sao các số khác nhau tương ứng với các hình dạng chữ cái khác nhau trên màn hình của bạn là vì các số đó được sử dụng để chọn các bitmap khác nhau hoặc các thói quen vẽ khác nhau từ một bảng lớn (nghĩa là từ "phông chữ").
Tôi muốn đưa ra một bổ sung cho các câu trả lời đã được thực hiện:
Trong hầu hết các câu trả lời khác, lưu ý rằng trong số học bổ sung twos, kết quả là giống nhau cho các số có chữ ký và không dấu:
-2 + 1 = -1 1110 + 0001 = 1111
14 + 1 = 15 1110 + 0001 = 1111
Tuy nhiên , có những trường hợp ngoại lệ:
Division:
-2 / 2 = -1 1110 / 0010 = 1111
14 / 2 = 7 1110 / 0010 = 0111
Comparison:
-2 < 2 = TRUE 1110 < 0010 = TRUE
14 < 2 = FALSE 1110 < 0010 = FALSE
"Typical" (*) multiplication:
-2 * 2 = -4 1110 * 0010 = 11111100
14 * 2 = 28 1110 * 0010 = 00011100
(*) Trên nhiều CPU, kết quả của phép nhân hai số n bit là (2 * n) bit.
Đối với các hoạt động như vậy, CPU có các hướng dẫn khác nhau cho số học đã ký và không dấu.
Điều này có nghĩa là lập trình viên (hoặc trình biên dịch) phải sử dụng các hướng dẫn khác để ký và số học không dấu.
Ví dụ, CPU x86 có một lệnh được đặt tên div
để thực hiện phân chia không dấu và một lệnh được đặt tên idiv
để thực hiện phân chia đã ký.
Ngoài ra còn có các hướng dẫn "có điều kiện" khác nhau (nhảy có điều kiện, set-bit-on-condition) cũng như các hướng dẫn nhân cho số học đã ký và không dấu.