Ở trên ta ựã ựưa ra các tiêu chắ thiết kế dạng thức lệnh, mà một trong các tiêu chắ là lệnh càng ngắn càng tốt ựể tiết kiệm thời gian của CPU và tiết kiệm bộ nhớ. Giới hạn cuối cùng của việc giảm chiều dài ựịa chỉ là làm cho lệnh không còn trường ựịa chỉ nữa, chỉ có opcode thôi. Thật ựáng ngạc nhiên là ựiều này có thể thực hiện ựược bằng cách sử dụng một cấu trúc dữ liệu có tên là Stack.
Stack chứa các phần tử dữ liệu (words, characters,Ầ) theo trật tự liên tiếp trong bộ nhớ. Phần tử ựầu tiên ựược ựẩy lên Stack ựược gọi là nằm ở ựáy của Stack, phần tử sau cùng vừa mới ựẩy lên Stack ựược gọi là nằm ở ựỉnh của Stack. Dữ liệu ựược ựưa vào và lấy ra theo phương thức vào ựầu tiên thì ra sau cùng FILO (first in last out). Mỗi Stack ựược gắn với một thanh ghi hay word bộ nhớ chứa ựịa chỉ ựỉnh Stack và ựược gọi là con trỏ Stack.
Hình 6.9 cho ta thấy các chế ựộ lập ựịa chỉ của dữ liệu trong các máy tắnh mới nhất và các vắ dụ tương ứng với nó. Trong hình này và trong cuốn sách này chúng ta dùng phần mở rộng của ngôn ngữ lập trình C ựể biểu diễn các câu lệnh. Ở ựây chúng ta dùng mảng Mem như là tên của bộ nhớ chắnh và Regs ựể chỉ Registers. Vắ dụ chúng ta ghi Mem[Regs[R1]] ựể chỉ một ô nhớ có ựịa chỉ ựược ghi trong thanh ghi tên là R1. Trong bảng này mỗi chế ựộ lập
ựịa chỉ sẽ có một vắ dụ minh họa ựược ựưa ra, ựồng thời giải thắch ý nghĩa của nó và cho biết nó ựược dùng khi nào.
Hình 6.9. Các chế ựộ lập ựịa chỉ thông dụng
Vắ dụ ở chế ựộ lập ựịa chỉ Ộthanh ghiỢ (Register) ựể làm phép toán cộng hai số ta dùng câu lệnh:
Add R4, R3.
Câu lệnh này cho thấy ở chế ựộ thanh ghi các toán hạng ựều là các thanh ghi. Ở ựây R3 và R4 là hai toán hạng của phép toán cộng. Ý nghĩa của câu lệnh này có nghĩa là:
Regs[R4]Regs[R4] + Regs[R3]
Tức là toán hạng thứ nhất nằm trên thanh ghi có tên R4 và toán hạng thứ hai nằm trên thanh ghi có tên là R3 sẽ ựược cộng lại
quả sẽ ựược lưu vào ựâu. đặc biệt trong câu lệnh với tham chiếu bộ nhớ (Memory indirect) hay trong C ta gọi là với con trỏ ta thấy ở toán hạng thứ hai có thêm dấu Ộ@Ợ ựể chỉ toán hạng ựó là một ựịa chỉ và ở ựịa chỉ ựó chứa một ựịa chỉ khác, mà ở ựịa chỉ cuối này mới chứa giá trị thật của toán hạng này. Giả sử trong câu lệnh
Add R1, @(R3)
R1 chứa giá trị 5, R3 chứa giá trị 16 thì lệnh này có thể ựược diễn giải rõ hơn như hình 6.9. Trong R3 chứa giá trị 16 là một ựịa chỉ, mà trong ựịa chỉ này chứa giá trị 4 là một ựịa chỉ khác, mà trong ựịa chỉ 4 này mới chứa giá trị thật 7 của toán hạng thứ hai. Giá trị toán hạng thứ nhất là 5 cộng với giá trị toán hạng thứ hai là 7, ựược 12 và giá trị này lại ghi trở lại vào R1.
0 4 7 8 12 16 4 20 R1 = 5 R3 = 16 5 7 + 12
6.4. Bộ lệnh
Trong phần này chúng ta sẽ xem xét các loại lệnh cơ bản của các kiến trúc phần mềm ựược dùng nhiều nhất, ựể cho thấy các kỹ thuật ở mức ngôn ngữ máy dùng ựể thi hành các cấu trúc trong các ngôn ngữ cấp cao. đa số ngày nay, ựể viết các chương trình cho máy tắnh, người ta dùng các ngôn ngữ cấp cao dễ hiểu va tiên lợi hơn như C, Pascal, C#,.. Quá trình biên dịch từ một ngôn gữ cấp cao sang ngôn ngữ máy tiến hành như trong hình 6.10.
Do mỗi lệnh trong máy tắnh là tổ hợp các con số nhị phân 0, 1 nên rất khó nhớ. để khắc phục ựiểm yếu này người ta dùng hợp ngữ Assembly ựể mô tả các mã lệnh nhị phân bằng các từ ngắn gọn mà ta gọi là từ gợi nhớ mã lệnh. Ngoài ra trong quá trình diễn giải chúng ta còn dùng các khái niệm thanh ghi ựắch, thanh ghi nguồn 1, thanh ghi nguồn 2.
Chương trình bằng ngôn ngữ cấp cao Chương trình bằng hợp ngữ Chương trình bằng ngôn ngữ máy Trình biên dịch ( Compiler) Bộ dịch hợp ngữ (Assempler)
Từ gợi nhớ mã lệnh mô tả ngắn gọn tác vụ phải thi hành trên các thanh ghi nguồn, kết quả ựược lưu giữ trong thanh ghi ựắch.
Mỗi lệnh của ngôn ngữ cấp cao ựược xây dựng bằng một lệnh mã máy hoặc một chuỗi nhiều lệnh mã máy. Lệnh nhảy (GOTO) ựược thực hiện bằng các lệnh hợp ngữ về nhảy (JUMP) hoặc lệnh hợp ngữ về vòng. Chúng ta phân biệt lệnh nhảy làm cho bộ ựếm chương trình ựược nạp vào ựịa chỉ tuyệt ựối nơi phải nhảy ựến (PC ← ựịa chỉ tuyệt ựối nơi phải nhảy tới), với lệnh vòng theo ựó ta chỉ cần cộng thêm một ựộ dời vào bộ ựếm chương trình (PC ← PC + ựộ dời).
Ngoài ra do mỗi kiểu kiến trúc máy tắnh có cách mã hóa lệnh và tên các câu lệnh khác nhau, do ựó trong phần này chúng ta chỉ ựể ý ựến kiểu cấu trúc RISC.
6.4.1. Nhóm lệnh truyền dữ liệu
Nhóm lệnh này nhằm truyền dữ liệu (a word or a block) từ một nguồn có thể là thanh ghi hoặc bộ nhớ ựến một ựắch. Phần lớn trong nhóm này là những lệnh truyền dữ liệu giữa các thanh ghi khác nhau trong CPU. Việc truyền dữ liệu từ một thanh ghi ựến một thanh ghi khác có thể thông qua lệnh sau:
MOVE Ri, Rj // truyền dữ liệu từ thanh ghi Rj ựến thanh ghi Ri
Ở ựây dữ liệu từ thanh ghi nguồn Rj ựược ghi ựè lên thanh ghi ựắch Ri, còn dữ liệu của Rj thì không thay ựổi.
đắch Nguồn Vắ dụ Giải thắch
Bộ nhớ Thanh
ghi
MOVE 100H, AX Chuyển nội dung trong
AX vao vị trắ nhớ 100H Thanh
ghi
Bộ nhớ MOVE AX,MEM1 Chuyển nội dung trong vị
trắ nhớ MEM1 chỉ ra vào thanh ghi AX Thanh ghi Thanh ghi
MOVE AX, BX Chuyển nội dung trong
thanh ghi BX vào thanh ghi AX Thanh ghi Hằng số MOVE AX, 0FFFFH Chuyển giá trị hằng số ở hệ 16: FFFF vào thanh ghi AX, số 0 ở ựầu ựể chỉ rõ FFFFH là một giá trị hằng chứ không phải là một nhãn
Bảng 6.4. Một số vắ dụ lệnh MOVE
để nạp một giá trị từ bộ nhớ vào thanh ghi hoặc lưu một giá trị từ thanh ghi vào bộ nhớ ta dùng các lệnh sau:
LOAD ựắch, nguồn
vắ dụ: LOAD Ri, M (ựịa chỉ) // RiM[ựịa chỉ] STORE ựắch, nguồn
vắ dụ: STORE M(ựịa chỉ), Ri // M[ựịa chỉ] ←Ri Trong bảng 6.5 cho ta thấy một số các lệnh và ý nghĩa của nó
6.4.2. Nhóm lệnh tắnh toán số học:
Các lệnh số học bao gồm bốn phép tắnh số học cơ bản là cộng, trừ, nhân, chia và ựảo dấu toán hạng.
ADD/SUB
Dạng tổng quát của các lệnh cộng (add) và trừ (subtract) như sau:
ADD ựắch, nguồn // ựắch ựắch + nguồn SUB ựắch, nguồn // ựắch ựắch Ờ nguồn
trong ựó các toán hạng ựắch và nguồn có thể tắm ựược theo các ựịa chỉ khác nhau, nhưng phải chứa dữ liệu có cùng ựộ dài và không ựược phép ựồng thời là hai ô nhớ và cũng không ựược là thanh ghi ựoạn
Vắ dụ 1:
ADD AX, BX // AX AX + BX
ADD AL,74H // AL AL + 74H
SUB CL, AL // CL CL Ờ AL
SUB AX, 0405H // AX AX Ờ 0405H
Vắ dụ 2: Viết ựoạn chương trình bằng ngôn ngữ Assembly ựể cộng 5H với 3H, dùng các thanh ghi AL và BL. Kết quả của phép cộng lưu vào bộ nhớ tại ựịa chỉ 100H.
MOV AL, 05H // AL 05H
MOV BL, 03H // BL 03H
ADD AL, BL // AL AL + BL
MOV 100H, AL // MEM[100H]AL: di
// chuyển kết quả từ AL vào // vị trắ nhớ DS:100H
Bảng 6.6 cho ta tóm tắt các lệnh tắnh toán số học và ý nghĩa tương ứng của nó
Tên lệnh Ý nghĩa ADD Cộng ADDD Cộng số có dấu chấm ựộng, chắnh xác kép SUB Trừ SUBD Trừ số có dấu chấm ựộng, chắnh xác kép MUL Nhân DIV Chia
INC Tăng lên 1
DEC Giảm ựi 1
NEG đảo dấu toán hạng
Bảng 6.6. Các lệnh tắnh toán số học cơ bản
6.4.3. Nhóm lệnh logic:
Tthực hiện phép tắnh logic NOT, AND và OR cho từng bit một. Lệnh NOT ựảo tất cả các bit trong toán hạng, các lệnh
AND/OR thực hiện các phép tắnh AND/OR ựối với một ựôi bit trong toán hạng nguồn và toán hạng ựắch.
AND/OR
Dạng tổng quát của lệnh AND/OR như sau: AND ựắch, nguồn
OR ựắch, nguồn
AND/OR thực hiện phép toán Boolean ựối với các toán hạng nguồn và ựắch. Phép AND thường dùng ựể che ựi hoặc giữ lại một vài bit nào ựó của một toán hạng bằng cách nhân logic toán hạng ựó với toán hạng tức thời có các bit 0/1 tại các vị trắ cần che/ giữ lại tương ứng. Phép OR thường dùng ựể lập một vài bit nào ựó của toán hạng bằng cách cộng logic toán hạng ựó với toán hạng tức thời có các bit 1 tại các vị trắ tương ứng cần thiết lập (toán hạng tức thời trong những trường hợp này còn ựược gọi là mặt nạ)
Vắ dụ:
AND AL, BL // Nội dung thanh ghi BL ựược giao // với nội dung trong thanh ghi AL
// và kết quả ựược lưu lại vào trong // thanh gh AL. Nếu con số trong // AL là 00001101B và trong BL là // 00110011B thì kết quả trong thanh // ghi AL sau phép AND là 00000001B
6.4.4 Nhóm các lệnh dịch chuyển số học hoặc logic (SHIFT ), quay vòng (ROTATE) có hoặc không có số giữ ở ngã vào, sang phải hoặc sang trái. Các lệnh này ựược thực hiện trên một thanh ghi và kết quả lưu giữ trong thanh ghi khác. Số lần dịch chuyển (mỗi lần dịch sang phải hoặc sang trái một bit) thường ựược xác ựịnh trong thanh ghi thứ ba. Hình 6.11 minh hoạ cho các lệnh cơ bản nhất của nhóm này.
SRL (Shift Right Logical - dịch phải logic): Các bit của word ựược dịch chuyển sang phải, bit thấp nhất (bit 0) mất ựi còn trị nhị phân Ộ0Ợ sẽ dịch chuyển vào bit cao nhất SLL (Shift Left Logical - dịch trái logic): Các bit của word ựược dịch chuyển sang trái, trị nhị phân Ộ0Ợ sẽ dịch chuyển vào bit thấp nhất (bit 0) , còn bit cao nhất sẽ mất ựi
SRA (Shift Right Arithmetic - dịch phải số học): Bit cao nhất là bit dấu sẽ ựược giữ lại, các bit còn lại sẽ dịch chuyển sang phải còn bit thấp nhất sẽ mất ựi.
SLA (Shift Left Arithmetic Ờ dịch trái số học): Bắt cao nhất là bit dấu sẽ ựược giữ nguyên, các bit dịch sang trái, bắt kế bit dấu mất ựi, trị nhị phân Ộ0Ợ dịch chuyển vào bit thấp nhất.
6.4.5. Nhóm các lệnh có ựiều kiện và lệnh nhảy (không ựiều kiện)
Lệnh có ựiều kiện có dạng :
Nếu <ựiều kiện> thì <chuỗi lệnh 1> nếu không <chuỗi lệnh 2>
(IF <condition> THEN <instructions1> ELSE <instructions2>)
Lệnh này buộc phải ghi nhớ ựiều kiện và nhảy vòng nếu ựiều kiện ựược thoả.
Ghi nhớ ựiều kiện .
Bộ tắnh toán logic số học ALU cung cấp kết quả ở ngã ra tuỳ theo các ngã vào và phép tắnh cần làm. Nó cũng cho một số thông tin khác về kết quả dưới dạng các bit trạng thái (Hay các bit cờ - flag). Các bit này là những ựại lượng logic đÚNG hoặc SAI
(hình 6.12).
Trong các bit trạng thái ta có:
+ bit dấu S (Sign - đúng nếu kết quả âm),
+ bit trắc nghiệm zero Z (Zero - đúng nếu kết quả bằng không),
+ bit tràn OVF (Overflow) đÚNG nếu phép tắnh số học làm thanh ghi không ựủ khả năng lưu trữ kết quả,
+ bit số giữ C (carry) đÚNG nếu số giữ ở ngã ra là 1 ....
Có hai kỹ thuật cơ bản ựể ghi nhớ các bit trạng thái
Cách thứ nhất, ghi các trạng thái trong một thanh ghi ựa dụng. Vắ dụ lệnh CMP Rk, Ri, Rj
Lệnh trên sẽ làm phép tắnh trừ Ri - Rj mà không ghi kết quả phép trừ, mà lại ghi các bit trạng thái vào thanh ghi Rk. Thanh ghi này ựược dùng cho một lệnh nhảy có ựiều kiện. điểm lợi của kỹ thuật này là giúp lưu trữ nhiều trạng thái sau nhiều phép tắnh ựể dùng về sau. điểm bất lợi là phải dùng một thanh ghi ựa dụng ựể ghi lại trạng thái sau mỗi phép tắnh mà số thanh ghi này lại bị giới hạn ở 32 trong các bộ xử lý hiện ựại.
Cách thứ hai, là ựể các bit trạng thái vào một thanh ghi ựặc biệt gọi là thanh ghi trạng thái. Vấn ựề lưu giữ nội dung thanh ghi này ựược giải quyết bằng nhiều cách. Trong kiến trúc SPARC, chỉ có một số giới hạn lệnh ựược phép thay ựổi thanh ghi trạng thái vắ dụ như lệnh ADDCC, SUBCC (các lệnh này thực hiện các phép tắnh cộng ADD và phép tắnh trừ SUB và còn làm thay ựổi thanh ghi trạng thái). Trong kiến trúc PowerPC, thanh ghi trạng thái ựược
ALU Toán hạng 1 Toán hạng 2 Số mang vào (Carry in) Kết quả Bit S Bit Z Bit OVF Bit C
phân thành 8 trường, mỗi trường 4 bit, vậy là thanh ghi ựã phân thành 8 thanh ghi trạng thái con.
đặc tắnh chung của các lệnh này là thứ tự thực thi chương trình thay ựổi nhờ tác ựộng vào già trị lưu trong thanh ghi ựếm chương trình (Program Counter - PC). Sự thay ựổi trong thanh ghi PC có thể là không có ựiều kiện, vắ dụ như khi chương trình thực hiện ựến một chỗ nào ựó rồi cần phải nhảy ựến một vị trắ khác, khi ựó ta sử dụng lệnh nhảy (Jump instruction). Trường hợp này trong ngôn ngữ cấp cao ta hay gặp ựó là lệnh GOTO, khi ựó gá trị ựược nạp vào trước trong thanh ghi PC sẽ bị xóa ựi và một lệnh mới trong bộ nhớ sẽ ựược nạp vào.
Thanh ghi PC có thể thay ựổi có ựiều kiện, mà những ựiều kiện này chủ yếu dựa vào các cờ như bắt dấu (S), bit Zero (Z), Overflow (O) và bit Carry (C). Những bit cờ này ựược lưu trữ trên một thanh ghi ựặc biệt gọi là thanh ghi mã ựiều kiện (Condition Code register - CC). Giá trị của các bit cờ này thay ựổi dựa vào kết quả thực thi của các lệnh khác nhau.
Chúng ta xem một vắ dụ cụ thể sau:
LOAD #100, R1 Loop: ADD (R2)+ , R0
DECREMENT R1
BEQZ R1, Loop
Câu lệnh thứ 4 là một lệnh có ựiều kiện. Khi kết quả tăng giá trị trong thanh ghi R1 là bằng 0, thì flag Z sẽ chuyển thành 1 và lệnh tiếp theo ựược thực thi sẽ là lệnh ở vị trắ nhãn Loop.
6.5. Cấu trúc lệnh CISC và RISC
Trong máy tắnh mọi thứ ựều ựược ựưa về các con số nhị phân Ộ0Ợ và Ộ1Ợ bởi vì máy tắnh chỉ hiểu các mức ựiện thế tương ứng với 0/1 trên mỗi transistor cụ thể, người sử dụng muốn thực hiện một chương trình nào ựấy, phải nạp các mã lệnh chỉ gồm các con số 0-1 vào bộ nhớ cho máy tắnh. Có 3 cách cơ bản ựể làm việc ấy:
Ớ Viết ngay dạng mã máy với các con số 0, 1 và nạp vào bộ nhớ. Cách này rất khó thực thi bởi vì thứ nhất rất dễ bị nhầm lẫn giữa các con số 0 và 1; thứ hai rất khó nhớ các lệnh ựược mã hóa như thế nào và thứ ba là rất mất thời gian ựể làm việc ựó.
Ớ Viết dạng tên gợi nhớ bằng hợp ngữ (Assembler), sau ựó biên dịch ra mã máy, cấp này cũng rất gần với ngôn ngữ máy và cũng khó thực hiện với các chương trình phức tạp. Tuy nhiên, cấu trúc gọn nhẹ, các lệnh có tên tương ứng dễ nhớ.
Ớ Viết bằng một ngôn ngữ cấp cao như C++, Pascal, Java,Ầ, sau ựó dùng một trình biên dịch (compiler) ựể dịch ra mã máy. Cách này tuy dễ với người viết chương trình nhưng cũng sẽ làm chương trình có dung lượng lớn hơn nếu viết bằng ASM. Và