Làm thế nào để các dòng mã được thực thi bởi CPU?


11

Tôi đang cố gắng thực sự hiểu chính xác một ngôn ngữ cấp cao được chuyển đổi thành mã máy như thế nào và sau đó được cpu thực thi.

Tôi hiểu rằng mã được biên dịch thành mã máy, đây là mã cấp thấp mà CPU có thể sử dụng. Nếu tôi có một tuyên bố chuyển nhượng nói:

x = x + 5;
y = x - 3;

CPU có thực thi từng dòng một không? Vì vậy, đầu tiên nó sẽ thực hiện x = x + 5; lệnh và sau đó lệnh tiếp theo CPU sẽ thực thi là y = x- 3; Tôi thực sự đang cố gắng để hiểu quá trình thực thi và cách mã tôi viết thực sự được thực thi bởi CPU.


Bạn có thể muốn thử thiết kế một trong những CPU nguồn mở, có một số triển khai dựa trên ngăn xếp thực sự đơn giản như excamera.com/sphinx/fpga-j1.html - chúng đơn giản hơn nhiều so với kiến ​​trúc 3 địa chỉ như trong ví dụ của bạn.
SK-logic

3
Khi tôi tham gia vào công việc kinh doanh này, điều này sẽ có những câu trả lời đơn giản và được xác định rõ ràng. Ngày nay, CPU cực kỳ phức tạp và làm đủ mọi cách để tăng sức mạnh xử lý.
David Thornley

Câu trả lời:


12

Các dòng mã không liên quan gì đến cách CPU thực thi nó. Tôi khuyên bạn nên đọc về trình biên dịch chương trình, bởi vì điều đó sẽ dạy cho bạn rất nhiều về cách phần cứng thực sự làm mọi thứ. Bạn cũng có thể nhận được đầu ra của trình biên dịch từ nhiều trình biên dịch.

Mã đó có thể biên dịch thành một cái gì đó như (bằng ngôn ngữ lắp ráp tạo thành):

load R1, [x] ; meaning load the data stored at memory location x into register 1
add R1, 5
store [x], R1 ; store the modified value into the memory location x
sub R1, 3
store R1, [y]

Tuy nhiên, nếu trình biên dịch biết rằng một biến không được sử dụng lại, thì thao tác lưu trữ có thể không được phát ra.

Bây giờ để trình gỡ lỗi biết mã máy nào tương ứng với một dòng nguồn chương trình, các chú thích được trình biên dịch thêm vào để hiển thị dòng nào tương ứng với vị trí trong mã máy.


Tại sao không? Kiến trúc 3 địa chỉ sẽ có các hướng dẫn như ADD Rx, Rx, $5SUB Ry, Rx, $3(giả sử rằng các biến x và y đã được ánh xạ vào các thanh ghi). Bạn đang mô tả một cách tiếp cận RISC tải / lưu trữ.
SK-logic

1
@ SK-logic: Mặc dù điều đó có thể xảy ra đối với các dòng mã rất đơn giản trong các ngôn ngữ lập trình rất đơn giản với các kiểu dữ liệu và hoạt động mà CPU xảy ra để hỗ trợ đủ tốt, nhưng đây không phải là trường hợp chung. Nó thuận tiện cho các chuyên gia, nhưng trước tiên, điều quan trọng là phải nhận ra các hướng dẫn mã máy nói chung có chút giống với các dòng mã trong một làn đường cấp cao.

@ SK-Logic: chỉ hoạt động cho ví dụ cụ thể này. Nói chung, tuy nhiên, maxpolun là đúng. Các câu lệnh ngôn ngữ cấp cao phải được dịch sang ngôn ngữ cấp thấp hơn, với nhiều "băng đỏ" cần thiết hơn để thực hiện các công cụ đơn giản về mặt khái niệm. Tôi đoán OP đã yêu cầu một ví dụ về sự chuyển đổi này.
Andres F.

1
@ SK-Logic: OP bắt đầu câu hỏi của mình với "Tôi đang cố gắng thực sự hiểu chính xác một ngôn ngữ cấp cao [...]" như thế nào
Andres F.

1
@ SK-logic Ngữ cảnh là "Nếu tôi có câu lệnh gán nói: [đoạn mã] CPU có thực thi từng dòng một không?" - có vẻ như tôi dự định là mã nguồn trong ngôn ngữ không phải trình biên dịch. Tổng quát hơn, tôi thấy không có chỉ số nào về sự hiểu biết về mã máy cấp thấp như thế nào và một số cụm từ (chẳng hạn như nói về các dòng) chỉ ra một số quan niệm sai lầm. Điều đó không phải là không thể như bạn ngụ ý, không phải ai cũng có được niềm vui khi được ném đầu vào một số bộ vi điều khiển đơn giản (như tôi và rõ ràng là những người khác). Có lẽ Frankie nên làm rõ.

2

Nó phụ thuộc.

Trong những ngày đầu của các máy thực sự đơn giản, vâng, mã đã thực thi một dòng tại một thời điểm. Khi các máy trở nên lớn hơn, nhanh hơn và phức tạp hơn, bạn bắt đầu thấy cả khả năng thực thi đồng thời nhiều lệnh và bộ nhớ đọc và ghi mất nhiều thời gian hơn so với thao tác trên các thanh ghi.

Tối ưu hóa trình biên dịch phải tính đến điều này và các dòng bạn đưa ra có thể được thực thi song song "ít nhiều", với một phần của bộ xử lý làm việc trên tính toán của y, trong khi một phần khác đang lưu trữ giá trị mới được tính toán trước đó của x (và tính toán của y đã sử dụng giá trị mới đó từ thanh ghi).

Control Data 6600 là cỗ máy đầu tiên tôi biết đã làm điều này. Bổ sung số nguyên mất 300 nsec, tham chiếu bộ nhớ (đọc hoặc ghi) mất 1000 nsec, nhân và chia mất nhiều thời gian hơn. Tối đa khoảng mười hướng dẫn có thể được thực thi song song, tùy thuộc vào đơn vị chức năng nào được yêu cầu. Trình biên dịch CDC 6600 FORTRAN RẤT giỏi trong việc lên lịch tất cả những điều này.


Trong trường hợp này, đầu vào của lệnh tiếp theo phụ thuộc vào kết quả lệnh đầu tiên, do đó nó phải được thực hiện tuần tự.
SK-logic

@ SK-logic: Không hoàn toàn. Đầu vào của dòng thứ hai phụ thuộc vào kết quả của phía bên phải của dòng đầu tiên, nhưng, chỉ dựa trên những gì chúng ta có thể thấy trong mã ví dụ ban đầu, nó có thể KHÔNG phụ thuộc vào cửa hàng vào bộ nhớ của kết quả dòng đầu tiên. Nếu x đã được khai báo là không ổn định (trong C / C ++), thì trình biên dịch sẽ được yêu cầu lưu trữ kết quả trước, VÀ THÌ LIÊN QUAN ĐẾN TỪ NHỚ, trước khi bắt đầu tính giá trị mới của y, vì "dễ bay hơi" có nghĩa là một cái gì đó (một trình xử lý ngắt, giả sử) có thể đi vào và zap x giữa hai dòng.
John R. Strohm

Tôi giả sử x và y là các thanh ghi (và mã bằng ngôn ngữ giả 3 địa chỉ thay vì giống như C). Trong trường hợp này cả hai hướng dẫn là không thể tránh khỏi tuần tự. Nếu không, OP đã phải hỏi hai hoặc nhiều câu hỏi khác nhau thay vì câu hỏi này.
SK-logic

Tôi tự hỏi nếu bộ xử lý sẽ cố gắng "suy đoán" giá trị của xnó là gì? Bằng cách này, nó đã thực thi mã và được lưu trữ trong bộ đệm.
Hẻm núi Kolob

Ngay cả khi chúng là các thanh ghi, GỬI TRÊN MÁY, bạn không thể cho rằng các hướng dẫn thực hiện hoàn toàn tuần tự. 6600 có logic lập lịch ("bảng điểm") sẽ buộc các ngữ nghĩa tuần tự, dựa trên giả định rằng lập trình viên muốn làm điều hiển nhiên. Các máy sau này đã bỏ qua phần cứng đó, thay vào đó dựa vào trình biên dịch để lên lịch hướng dẫn cẩn thận. Các lập trình viên con người thực hiện lập trình ngôn ngữ lắp ráp trên những con thú đó đã TRÊN SỞ HỮU.
John R. Strohm

1

Không, không có ánh xạ một-một giữa các dòng mã / hướng dẫn trong các ngôn ngữ cấp cao hơn và cấp thấp hơn. Trong thực tế, cả hai dòng trên được dịch thành nhiều hướng dẫn mã máy , như

  1. tải một giá trị từ một địa chỉ bộ nhớ nhất định vào một thanh ghi
  2. sửa đổi giá trị
  3. ghi lại vào bộ nhớ

Các chi tiết thực tế của các hướng dẫn này khác nhau giữa các nền tảng.

Đây là quan điểm cơ bản của sự vật. Tuy nhiên, để làm phức tạp thêm các vấn đề, các CPU hiện đại áp dụng các kỹ thuật như đường ống thực thi , thực thi không theo thứ tựnhiều lõi , trong số các lõi khác. Những kết quả này khiến CPU thực hiện nhiều việc cùng một lúc, ví dụ: các đường ống xử lý các pha khác nhau của các lệnh tiếp theo song song trong cùng một đơn vị xử lý, trong khi nhiều lõi có thể xử lý song song các lệnh độc lập.


0

Bạn nên xem chi tiết tuyệt vời trong một cuốn sách để tìm thêm chi tiết về cách thức hoạt động của nó, có thể là một lớp trình biên dịch.

Về cơ bản, câu hỏi của bạn đang tập trung vào 2 khía cạnh khác nhau.

1) Mã được dịch thành mã máy như thế nào?

2) Khi nào / làm thế nào mã được tính bằng cách sử dụng song song?

Câu trả lời cho 1) phụ thuộc vào ngôn ngữ bạn sử dụng (mặc dù ví dụ của bạn là tầm thường nên đầu ra sẽ giống nhau). Cách trình biên dịch thực hiện dịch mã sang mã máy là một trong những lực của ngôn ngữ. Ngoài ra, có một số mối quan tâm cần được tính đến trong ví dụ của bạn, mã sẽ tải dữ liệu vào bộ nhớ, lưu trữ, v.v.

Cuối cùng, song song hóa là một tính năng mà bạn có thể ép buộc từ quan điểm lập trình, nhưng tóm lại, một số bộ xử lý có thể cố gắng nghĩ rằng một số phần mã có thể được chạy cùng một lúc, vì chúng độc lập. Trong trường hợp của bạn, rõ ràng, không phải vậy, vì bạn cần thực hiện các câu lệnh một cách tuần tự, vì vậy không, nó sẽ không chạy cùng một lúc.

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.