CHƯƠNG 4: NGÔN NGỮ MÁY VÀ HỢP NGỮ
4.1. Các thành phần cứng của cấu trúc tập lệnh
Một máy tính theo mô hình ISA dưới cái nhìn của một lập trình viên bao gồm tất cả các phần cứng, các lệnh và các dữ liệu mà chúng ta có thể truy cập được.
Trong phần này, chúng ta sẽ xem xét cấu trúc phần cứng của máy tính dưới con mắt của một lập trình viên. Chúng ta sẽ bắt đầu bằng việc thảo luận về cấu trúc của máy tính, đó là CPU và tương tác của nó với bộ nhớ chính, đó là sự xuất nhập dữ liệu của máy tính với bên ngoài
4.1.1. Nhắc lại về mô hình cấu trúc bus
Hình 4.1. Mô hình cấu trúc bus
Hình 4.1. nhắc lại cho chúng ta cấu trúc của mô hình cấu trúc bus mà chúng ta đã xem xét trong chương 1. Mục đích của hệ thống bus là giảm thiểu các liên kết giữa CPU và các thành phần của nó. Thay vì việc sử dụng các mối liên kết riêng rẽ giữa bộ nhớ và cổng ngoại vi I/O, CPU được kết nối với các thành phần đó bằng hệ thống bus. Trong một vài cấu trúc khác phức tạp hơn, CPU sẽ sử dụng các hệ thống bus riêng biệt để kết nối các thành phần đó
Không phải là tất cả các thành phần hệ thống được kết nối với nhau theo cùng một phương thức. CPU tạo ra các địa chỉ và được đưa lên bus địa chỉ, và bộ nhớ nhận tín hiệu địa chỉ này từ bus địa chỉ đó. Bộ nhớ không tạo ra các tín hiệu địa chỉ và CPU không bao giờ nhận các tín hiệu địa chỉ, và do đó không có một sự tương ứng trong các đường bus đó
Thông thường, người sử dụng sẽ viết các chương trình bằng ngôn ngữ cấp cao, sau đó được chuyển sang hợp ngữ. Chương trình biên dịch sẽ chuyển tiếp chương trình hợp ngữ này thành mã máy được lưu trữ trên ổ đĩa. Trước khi thực thi chương trình, mã máy sẽ được nạp từ ổ đĩa lên bộ nhớ chính dưới sự điều khiển của hệ điều hành
Trong quá trình thực thi các lệnh của chương trình, từng lệnh sẽ được nạp vào ALU từ bộ nhớ một cách lần lượt cùng với dữ liệu tương ứng cần được xử lý của lệnh đó. Kết quả của chương trình sẽ được đưa đến các thiết bị như màn hình hay ổ đĩa. Tất cả các hoạt động đó được phối hợp bởi bộ điều khiển mà chúng ta sẽ nói kỹ hơn trong chương 6.
Điều quan trọng chúng ta cần nhớ rằng các lệnh được xử lý bởi ALU mặc dù tất cả các lệnh và dữ liệu của nó được lưu trữ trên bộ nhớ. Điều đó có nghĩa là các lệnh và dữ liệu cần được nạp từ bộ nhớ vào các thanh ghi của ALU, và kết quả sẽ được lưu ngược trở lại vào bộ nhớ.
4.1.2. Bộ nhớ
Bộ nhớ của máy tính bao gồm một tập hợp một số các thanh ghi được đánh số thứ tự hay còn gọi là đánh địa chỉ, mỗi địa chỉ có thể lưu trữ 1 byte có độ lớn 8 bit. Một nibble hay đôi khi còn được gọi là nybble được định nghĩa là 4 bit liền kề nhau. Ý nghĩa của các khái niệm bit, byte, và nibble nói chung không phụ thuộc và cấu trúc của máy tính nhưng ý nghĩa của word sẽ phụ thuộc vào từng cấu trúc cụ thể. Một word thông thường có thể là 16, 32, 64 và 128 bit, với word 32 bit được xem là dạng chuẩn của máy tính. Hình 4.2 liệt kê các dạng dữ liệu của máy tính
Hình 4.2. Các dạng dữ liệu máy tính
Trong máy tính đánh địa chỉ theo byte, dữ liệu nhỏ nhất mà nó có thể tác động trực tiếp trong bộ nhớ là byte. Tuy nhiên, thông thường các lệnh sẽ đọc và ghi một vài byte liên tiếp. Những cụm byte như vậy sẽ được lưu trữ liên tiếp trong bộ nhớ, được đánh địa chỉ bởi byte có địa chỉ thấp nhất. Hầu hết các máy tính ngày nay có thể truy cập theo byte, half word, và double word.
Khi sử dụng cụm byte, có 2 phương pháp chính để lưu dữ liệu vào trong bộ nhớ:
byte có trọng số lớn được lưu vào địa chỉ thấp, được gọi là big-endian, hoặc là byte có trọng số nhỏ được lưu vào địa chỉ thấp, được gọi là little-endian.
Hình 4.3. Phương pháp lưu dữ liệu trong bộ nhớ
Các ô nhớ trong bộ nhớ được đánh địa chỉ tuyến tính như thể hiện trên hình 4.3.
Mỗi địa chỉ duy nhất tương ứng với một từ đặc biệt gồm 4 byte. Các địa chỉ được đánh tăng dần bắt đầu từ 0 và địa chỉ cao nhất được xác định là dung lượng của bộ nhớ trừ 1 đơn vị. Địa chỉ cao nhất của bộ nhớ 232 byte là 232-1.
Hình 4.4. Tổ chức bộ nhớ trên máy tính
Hình 4.4. mô tả tổ chức bộ nhớ trên máy tính. Máy tính trong ví dụ này có không gian địa chỉ 32 bit, có nghĩa là chương trình có thể truy cập vào bất cứ ô nhớ nào trong không gian địa chỉ từ 0 đến 232-1. Không gian địa chỉ trong máy tính sẽ được chia thành các vùng có chức năng riêng biệt đó là các vùng dành cho hệ điều hành, các cổng ngoại vi I/O, người sử dụng và stack. Cách phân vùng giữa các máy tính khác nhau cũng khác nhau. Điều đó lý giải tại sao chương trình thích hợp cho những dạng vi xử lý này lại không thích hợp đối với những dạng vi xử lý khác.
4.1.3. CPU
Chúng ta vừa tìm hiểu cấu trúc cơ bản nhất của máy tính là hệ thống bus, bộ nhớ, bây giờ chúng ta sẽ tìm hiểu cấu trúc bên trong của CPU. Một cách đơn giản nhất, CPU bao gồm khối dữ liệu bao gồm các thanh ghi chứa và bộ ALU, và một khối điều khiển được sử dụng để biên dịch các lệnh và tác động đến các thanh ghi dịch chuyển
Hình 4.5. Cấu trúc đơn giản của CPU
Khối điều khiển của máy tính có trách nhiệm thực thi các lệnh của chương trình được lưu trên bộ nhớ (ta sẽ tìm hiểu kỹ hơn trong chương 9). Có 2 thanh ghi liên kết giữa khối điều khiển và khối dữ liệu là thanh ghi đếm chương trình PC (Program Counter) và thanh ghi lệnh IR (Instruction Register). Thanh ghi PC chứa địa chỉ của lệnh đang được thực thi trong ALU. Lệnh này sẽ được nạp từ bộ nhớ, được lưu trong thanh ghi IR và được biên dịch tại đó. Các bước thực thi 1 lệnh được chỉ ra bởi các bước dưới đây
1. Nạp lệnh kế tiếp sẽ được thực thi từ bộ nhớ 2. Giải mã lệnh
3. Đọc các toán hạng từ bộ nhớ chính nếu cần 4. Thực thi lệnh và lưu trữ kết quả
5. Quay về bước đầu tiên
Quá trình thực hiện trên được biết đến bằng cái tên chu kỳ lệnh.
Ngoài ra, khối điều khiển còn có trách nhiệm phối hợp các thành phần khác nhau để thực thi lệnh. Có thể coi rằng có một “máy tính” nhỏ bên trong máy tính lớn để đảm nhiệm mọi hoạt động của CPU. Chúng ta sẽ tìm hiểu kỹ hơn vấn đề này trong chương 6
Mô hình điều khiển luồng dữ liệu
Hình 4.6. Một mô hình luồng dữ liệu
Luồng dữ liệu là mối liên kết giữa các thanh ghi trong CPU và khối ALU. Hình 4.6. là một mô hình luồng dữ liệu của máy tính. Các thanh ghi trong mô hình này có thể được coi là một vùng nhớ truy cập nhanh, độc lập với vùng nhớ của hệ thống, được sử dụng để lưu trữ tạm thời trong quá trình tính toán. Kích cỡ của hệ thống thanh ghi này có thể từ vài thanh ghi cho tới vài nghìn thanh ghi.
Cũng giống như bộ nhớ, các thanh ghi được đánh địa chỉ tăng dần bắt đầu từ 0, tuy nhiên không gian địa chỉ của các thanh ghi nhỏ hơn nhiều so với không gian bộ nhớ. Sự khác biệt lớn nhất giữa hệ thống thanh ghi và bộ nhớ hệ thống là hệ thống thanh ghi nằm trên CPU, nên hoạt động của nó nhanh hơn. Dữ liệu dịch chuyển giữa các thanh ghi nhanh hơn khoảng 10 lần so với dịch chuyển dữ liệu với bộ nhớ hệ thống.
Khối ALU có thể thực thi các lệnh có 1 hoặc 2 toán hạng. Các toán hạng được sử dụng sẽ được lựa chọn bởi khối điều khiển. Các toán hạng này được nạp từ các luồng dữ liệu được đánh dấu bởi nhãn “Register Source 1 (rs1)” và
“Register Source 2 (rs2)”. Đầu ra từ ALU là luồng dữ liệu được đánh nhãn
“Register Destination (rd)” được đưa ngược trở về hệ thống các thanh ghi.
Trong hầu hết các hệ thống, các liên kết bao gồm cả các luồng dữ liệu đều có thể truy cập được
Tập lệnh
Tập lệnh là tập hợp các câu lệnh mà vi xử lý có thể thực thi được, do đó nó phải được định nghĩa bởi vi xử lý. Tập lệnh cho mỗi họ vi xử lý là hoàn toàn khác nhau. Chúng khác nhau ở số lượng các câu lệnh, các toán tử, toán hạng, thậm chí cả kết quả thu được từ vi xử lý cũng khác nhau. Sự không tương thích này lại hoàn toàn trái ngược với khả năng tương thích của các ngôn ngữ bậc cao như C, Pascal,...Chương trình viết bằng ngôn ngữ cấp cao có thể chạy được trên hầu hết các hệ thống vi xử lý khác nhau nếu được biên dịch lại cho phù hợp với hệ vi xử lý tương ứng.
Chúng ta sẽ xem xét một tập lệnh cụ thể trong chương này
Phần mềm tạo ra ngôn ngữ máy
Trình biên dịch (Compiler) là một chương trình máy tính được sử dụng để chuyển một chương trình được viết bằng ngôn ngữ cấp cao như C, Pascal, hay Fortran sang ngôn ngữ máy. Các trình biên dịch ở cùng một mức ngôn ngữ có cùng một dạng đầu vào nhưng chúng sẽ có những đầu ra khác biệt phụ thuộc vào chủng loại vi điều khiển. Ngoài ra, khi biên dịch cùng một chương trình cho cùng một loại vi xử lý, ta sẽ nhận được các kết quả khác nhau phụ thuộc vào các trình biên dịch khác nhau.
Việc sử dụng các trình biên dịch đã tạo thuận lợi lớn cho các lập trình viên. Đó là việc lập trình trở nên dễ dàng vì ngôn ngữ sử dụng gân với ngôn ngữ đời thường, không phải là chuỗi các con số 0 và 1 dễ nhầm lẫn. Tuy nhiên, khi lập trình bằng ngôn ngữ cấp cao, tốc độ xử lý của hệ thống bị ảnh hưởng do hệ thống tốn thời gian chuyển chương trình từ ngôn ngữ cấp cao thành ngôn ngữ hợp ngữ, sau đó lại phải chuyển tiếp sang ngôn ngữ máy. Các ngôn ngữ lập trình hiện nay cũng hỗ trợ việc lập trình kết hợp cả ngôn ngữ cấp cao và ngôn ngữ máy trong cùng một chương trình để tận dụng những ưu điểm của cả 2 loại ngôn ngữ cấp cao và cấp thấp.
Ngôn ngữ cấp cao cho phép chúng ta không cần quan tâm đến cấu trúc của máy tính trong quá trình lập trình. Ở cấp độ ngôn ngữ máy, để lập trình, sự hiểu biết về cấu trúc máy tính là điều thiết yếu. Nhưng nếu ta lập trình bằng ngôn ngữ cấp cao như C, Pascal, hay Fortran, chúng ta không cần quan tâm đến điều đó vì đã có trình biên dịch chuyển các chương trình đó thành các chương trình tương ứng với mỗi một hệ thống vi xử lý.