Chương trình hợp ngữ của 8051.

Một phần của tài liệu Tài liệu Vi điều khiển (Microcontroller) pdf (Trang 43 - 55)

CL RC R bit

2.3.3Chương trình hợp ngữ của 8051.

Giới thiệu.

Theo phân cấp ngôn ngữ lập trình, hợp ngữ nằm giữa ngôn ngữ máy và ngôn ngữ cấp cao. Các ngôn ngữ cấp cao điển hình như ngôn ngữ Pascal, c,... sử dụng các từ hoặc các khai báo dễ hiểu với người sử dụng, mặc dù nó vẫn còn khoảng cách rất xa so với ngôn ngữ tự nhiên. Còn ngôn ngữ máy là ngôn ngữ nhị phân của máy tính. Một chương trình ngôn ngữ máy là một chuỗi các byte nhị phân biểu diễn cho các lệnh mà máy tính có thể thực hiện được.

Hợp ngữ thay thế các mã nhị phân của ngôn ngữ máy, thành các mã gợi nhớ để thuận lợi hơn khi lập trình. Ví dụ lệnh cộng trong ngôn ngữ máy được biểu diễn bằng mã nhị phân ‘’10110011’’, còn trong hợp ngữ là ‘’ADD’’. Việc lập trình được thực hiện bằng hợp ngữ thay vì bằng ngôn ngữ máy.

Các toán hạng của lệnh được biểu diễn bằng các cách định vị địa chỉ khác nhau, trong mã nhị phân của các lệnh ngôn ngữ máy, cũng được thay thế bằng các ký hiệu trong lệnh hợp ngữ.

Một chương trình hợp ngữ (assembly) không thể thực hiện được trên máy tính, mà nó phải được dịch sang mã nhị phân ngôn ngữ máy. Tuỳ thuộc vào mức độ phức tạp của mỗi chương trình, mà quá trình dịch sang chương trình ngôn ngữ máy có thể bao gồm một hoặc nhiều bước. Chương trình dịch tối thiểu được gọi là chương trình hợp dịch, nó dịch các lệnh gợi nhớ thành các lệnh mã máy. Bước đòi hỏi tiếp theo thường là liên kết (linker). Một chương liên kết thực hiện việc kết hợp các phần khác nhau của chương trình trên các tập tin khác nhau, và thiết lập địa chỉ trong bộ nhớ nơi chương trình sẽ thực hiện.

Hoạt động của trình hợp dịch (assembler operation).

Có nhiều trình hợp dịch và các chương trình hỗ trợ khác hiện có để phát triển các ứng dụng vi điều khiển. ASM51 hợp dịch chuẩn nhất so với các chương trình khác. Trong phần này sẽ giới thiệu về cấu trúc lập trình với ASM51. Mặc dù đã được tiêu chuẩn hoá, nhưng một số khai báo trong phần này cũng có thể không sử dụng được với các trình hợp dịch khác. ASM51 là trình hợp dịch mạnh, nó sử dụng cho việc phát triển hệ thống vi điều khiển trên các hệ thống Intel và các máy tính họ IBM PC. Vì các máy tính sử dụng để chạy phần mềm này có CPU khác 8051, nên ASM51 được gọi là trình hợp dịch chéo (cross assembler). Chương trình nguồn 8051 có thể viết trên máy tính, bằng các trình soạn thảo văn bản, sau đó có thể hợp dịch thành file đối tượng (object) và file liệt kê (listing) bằng ASM51. Chú ý rằng, máy tính với một CPU khác nên nó sẽ không hiểu được các lệnh nhị phân của file đối tượng. Vì thế cần một chương trình có khả năng nạp chương trình đối tượng vào hệ thống 8051 để thực hiện.

Để thực hiện việc hợp dịch bằng ASM51, có thể đánh lệnh sau từ dấu nhắc hệ thống: ASM51 source file {assembly controls}

Source file là tên của file nguồn cần hợp dịch, còn assembler controls là các khoá điều khiển tạo ra các tác động khác nhau khi hợp dịch. ASM51 sẽ nhận một file nguồn làm ngõ vào (ví dụ PROGRAM.SCR) và tạo ra 1 file đối tượng (PROGRAM.OBJ) và file listing (PROGRAM.LST)

Vì hầu hết các trình hợp dịch xem xét chương trình nguồn 2 lần trong lúc dịch nó sang ngôn ngữ máy, nên chúng được mô tả qua giai đoạn hợp dịch (two - pass assembler) là:

Giai đoạn 1 (pass1): file nguồn được xem xét từng đường và bảng ký hiệu được xây dựng. Vị trí bộ đếm chương trình được mặc định là 0, hoặc được thiết lập bằng chỉ thị ORG (origin). Khi file được xem xét, bộ đếm được tăng lên tuỳ theo độ dài của mỗi lệnh. Các chỉ thị định nghĩa dữ liệu (DB hoặc DW) tăng bộ đếm bằng với số byte được định nghĩa. Các chỉ thị nhớ lưu trữ (DS) tăng bộ đếm bằng số byte được dự trữ.

Khi tìm thấy 1 nhãn (bắt đầu một hướng rẽ nhánh), thì nó sẽ được đặt trong bảng ký hiệu theo giá trị hiện hành của bộ đếm. Các ký hiệu được định nghĩa bằng chỉ thị EQU (equal) được đặt trong bảng ký hiệu. Bảng ký hiệu được cất giữ và sau đó dùng trong giai đoạn hợp dịch thứ 2.

Giai đoạn 2 (pass2): tạo ra các file đối tượng và liệt kê. Các lệnh gợi nhớ được dịch thành các opcode và đặt trong file ra. Các toán hạng được định giá trị và đặt phía sau opcode. Khi các toán hạng là các ký hiệu, giá trị của chúng sẽ được lấy lại từ bảng ký hiệu (được tạo ra trong giai đoạn 1), và dùng để tạo thành dữ liệu hoặc địa chỉ đúng cho các lệnh.

Với 2 giai đoạn được thực hiện như trên, nên chương trình nguồn có thể sử dụng các ký hiệu trước khi nó được định nghĩa, ví dụ như các lệnh rẽ nhánh ở đầu chương trình mà các nhãn chuyển tới chưa được định nghĩa.

File đối tượng khi hợp dịch thành công sẽ chỉ chứa các byte nhị phân (00H đến FFH) của chương trình ngôn ngữ máy. File đối tương định vị (object relocatable) sẽ chứa một bảng ký hiệu và thông tin khác cần thiết cho sự liên kết và định vị chương trình. File liệt kê là một file văn bản bao gồm cả các lệnh gợi nhớ và mã máy tương ứng của nó. Khi có lệnh lỗi, file liệt kê cũng chứa cả các thông báo lỗi.

Khuôn dạng một chương trình hợp ngữ 8051.

Các lệnh trong chương trình hợp ngữ bao gồm: các lệnh máy, chỉ thị hợp dịch của trình hợp dịch, lệnh điều khiển trình hợp dịch và các chú thích.

Các lệnh máy tương đương với các lệnh gợi nhớ, chúng được đổi thành các lệnh mã máy khi hợp dịch (ví dụ như ANL). Các chỉ thị hợp dịch của trình hợp dịch, được sử dụng để trình hợp dịch định nghĩa cấu trúc chương trình, các ký hiệu, các dữ liệu, các hằng... (ví dụ ORG). Các lệnh điều khiển sẽ thiết lập các chế độ hợp dịch, và chỉ thị hướng thực hiện của trình hợp ngữ (ví dụ $TITLE). Các chú thích sử dụng giải thích về hoạt động và mục đích của các chuỗi lệnh, giúp người đọc dễ hiểu hơn.

Các dòng lệnh phải được viết theo một nguyên tắc nhất định được qui định bởi trình hợp dịch. Khuôn dạng mỗi hàng lệnh như sau:

(label:) mnemonic [ operand ] [ ; operand ] [... ] [ ; comment ]

Chỉ có phần mã gợi nhớ (mnemonic) là bắt buộc phải có trong hàng lệnh trong tất cả các trình hợp dịch. Một số trình biên dịch yêu cầu phải có nhãn ở cột thứ nhất trong tất cả các dòng lệnh, và các phần sau nó phải được ngăn cách với nhau bằng khoảng trắng (space) hoặc khoảng cách quãng (tab). Với ASM51 nhãn không nhất thiết phải có trên mỗi hàng lệnh, và nhãn cũng không cần phải nằm cùng hàng với lệnh gợi nhớ.

Nhãn (label field): Một nhãn tượng trưng cho địa chỉ của lệnh (hoặc dữ liệu) nằm sau nó. Khi rẽ nhánh đến lệnh này, nhãn này được dùng trong toán hạng của lệnh rẽ nhánh hoặc lệnh nhảy (ví dụ SJMP SKIP).

Khác với “nhãn” luôn chỉ thị một địa chỉ, ký hiệu (symbol) có ứng dụng tổng quát hơn. Nhãn chỉ là một trong các loại của ký hiệu và nó được phân biệt bằng dấu hai chấm (:) phía sau. Ký hiệu để gán các giá trị hoặc thuộc tính sử dụng trong các chỉ thị hợp dịch của hợp ngữ như: EQU, SEGMENT, bit, DATA... Các ký hiệu có thể là địa chỉ, hằng số, tên các đoạn (segment), hoặc các cấu trúc khác được hiểu bởi người lập trình. Sau đây là 1 ví dụ để phân biệt nhãn và ký hiệu:

PAR EQU 500 ; PAR là ký hiệu biểu diễn thay cho giá trị 500. START: MOV A,#0FFH; start là nhãn tượng trưng địa chỉ lệnh MOV.

Một ký hiệu hoặc nhãn phải bắt đầu bằng một chữ cái, dấu ’?’ hoặc dấu ‘_’, và có thể chứa tới 31 ký tự. Các ký hiệu có thể là chữ hoa hoặc chữ thường đều được hiểu giống nhau, nhưng chúng không được trùng với các lệnh gợi nhớ, các ký hiệu đã được định nghĩa trước và các chỉ thị hợp dịch.

Lệnh gợi nhớ (mnemonic): Các lệnh gợi nhớ hoặc các chỉ thị hợp dịch được viết tại phần mnemonic của dòng lệnh sau nhãn hoặc ký hiệu. Ví dụ các lệnh gợi nhớ như: ADD, MOV, DIV, INC...; Ví dụ các chỉ thị hợp dịch như: ORG, EQU hoặc DB.

Toán hạng (operand): Phần toán hạng được viết sau phần mã gợi nhớ trong hàng lệnh. Vùng này chứa địa chỉ hoặc dữ liệu sử dụng trong lệnh. Một nhãn có thể được dùng để biểu diễn cho địa chỉ của dữ liệu, hoặc một ký hiệu có thể được dùng để biểu diễn cho hằng dữ liệu. Có nhiều cách biểu diễn các toán hạng tuỳ thuộc vào các lệnh cụ thể. Một số lệnh không có toán hạng (như RET, NOP), còn một số lệnh lại có nhiều toán hạng được phân ra bằng các dấu phẩy.

Chú thích (comment): Các chú thích làm dễ hiểu chương trình, chúng đặt ở cuối mỗi dòng lệnh, và trước nó phải có dấu chấm phẩy (;). Cũng có thể thực hiện cả một dòng chú thích bằng cách bắt đầu bằng dấu ‘;’. Một chương trình con hoặc một đoạn lệnh dài có thể bắt đầu bằng một khối chú thích (gồm nhiều dòng liên tiếp) để giải thích tính chất chung của phần chương trình bên dưới.

Các ký hiệu hợp dịch đặc biệt (special assembler symbol): Các ký hiệu hợp dịch đặc biệt được dùng trong các chế độ định vị thanh ghi cụ thể. Chúng bao gồm thanh ghi A, R0 – R7, DPTR, PC, C, và AB. Cũng như ký hiệu $ được dùng để biểu diễn giá trị hiện hành của bộ đếm chương trình.

Ví dụ lệnh JNB TI,$ tương đương với dòng lệnh sau:

HERE : JNB TI,HERE (adsbygoogle = window.adsbygoogle || []).push({});

Địa chỉ gián tiếp (indirect address): một số lệnh có toán hạng là một thanh ghi chứa địa chỉ của dữ liệu. Ký hiệu @ cho biết địa chỉ gián tiếp và chỉ có thể dùng với R0, R1, DPTR. Ví dụ lệnh MOV A,@R0 nạp dữ liệu từ RAM nội tại địa chỉ trong R0 vào thanh chứa A. Lệnh MOVC A,@A+PC nạp dữ liệu từ bộ nhớ mã ngoài tại địa chỉ là tổng nội dung thanh ghi A với bộ đếm chương trình vào thanh chứa A.

Dữ liệu tức thời (Immediate data): Các lệnh sử dụng định vị tức thời, cung cấp dữ liệu toán hạng trong một phần của lệnh. Các dữ liệu tức thời phải bắt đầu bằng dấu ‘#’. Ví dụ

CONSTANT EQU 100 MOV A,#0FFH

ORL 40H,#CONSTANT

Tất cả các toán hạng tức thời (trừ trong lệnh MOV DPTR,#DATA) đều là 8 bit. Nếu dữ liệu được viết thành 16 bit thì byte thấp sẽ được sử dụng. Tất cả các bit trong byte cao phải giống nhau (00H hoặc FFH). Nếu không sẽ có thông báo lỗi ‘value not fit in a byte’ (giá trị không nằm trong một byte).

Ví dụ các lệnh sau đúng cú pháp: MOV A,#0FF00H MOV A,#00FFH

Hai lệnh sau đây sinh ra thông báo lỗi: MOV A,#0FE00H MOV A,#01FFH

Các hằng số thập phân từ -256 đến +256 cũng có thể sử dụng được cho toán hạng tức thời. Ví dụ 2 lệnh sau đúng cú pháp và tương đương với nhau:

MOV A,# -256 MOV A,#0FF01H

Địa chỉ trực tiếp (DATA address): Nhiều lệnh truy xuất các vùng nhớ sử dụng định vị trực tiếp và cần 1 toán hạng địa chỉ RAM nội (00H đến FFH). Các ký hiệu đã được định nghĩa có thể được dùng cho các địa chỉ SFR.

Ví dụ: MOV A,45H

hay MOV A,SBUF tương đương với lệnh MOV A,99H.

Địa chỉ bit (bit address): Một trong các điểm mạnh của các bộ vi điều khiển là khả năng truy xuất các bit riêng lẻ. Các lệnh truy xuất các bit phải cung cấp 1 địa chỉ bit trong RAM nội (vùng 00H đến 7FH), hoặc địa chỉ bit trong các SFR (vùng 80H đến FFH).

Có 3 cách để chỉ thị địa chỉ bit trong một lệnh: dùng địa chỉ bit trực tiếp, dùng chỉ số chỉ thị vị trí của bit trong một byte dữ liệu, dùng ký hiệu hợp dịch đã được định nghĩa trước.

Ví dụ: SETB 0E7H ; Dùng địa chỉ bit trực tiếp SETB ACC.7 ; Dùng chỉ số chỉ thị vị trí bit.

JNB TI, $ ; Dùng ký hiệu được định nghĩa ‘’TI’’.

Địa chỉ mã (code address): Địa chỉ mã được dùng cho toán hạng của các lệnh nhảy bao gồm: nhảy tương đối (như SJMP và nhảy có điều kiện), nhảy và gọi tuyệt đối (ACALL, AJMP), nhảy và gọi dài (LJMP, LCAL). Địa chỉ mã thường được cho ở dạng nhãn. Ví dụ:

HERE: _ _ _

SJMP HERE

ASM51 sẽ xác định mã địa chỉ đúng để đưa vào lệnh: hoặc là địa chỉ độ dời 8 bit có dấu, hoặc địa chỉ trang 11 bit hoặc địa chỉ dài 16 bit tuỳ theo từng lệnh.

Các lệnh nhảy và gọi sử dụng chung (generic jumps and calls): ASM51 cho phép người lập trình dùng các lệnh gợi nhớ sử dụng chung JMP hoặc CALL. Lệnh ‘’JMP’’ có thể được dùng để thay cho SJMP, AJMP hoặc LJMP, và ‘’CALL’’ có thể được dùng để thay cho ACALL hoặc LCALL. Trình hợp dịch biến đổi lệnh gợi nhớ chung thành một lệnh “thực tế” sau vài quy luật đơn giản. Lệnh gợi nhớ chung được biến đổi thành dạng ngắn (chỉ sử dụng cho JMP) nếu nơi nhảy đến không theo hướng tới và trong vùng -128, hoặc thành dạng tuyệt đối nếu đích chuyển đến không theo hướng tới vượt quá giới hạn ngắn, nhưng nằm trong vùng 2K. Nếu các dạng ngắn và tuyệt đối không sử dụng được thì lệnh chung sẽ được chuyển thành dạng dài.

Ví dụ : ORG 1234H

Start: INC A

JMP Start ;Hợp dịch như lệnh SJMP ORG Start + 200

JMP Start ; Hợp dịch như lệnh AJMP JMP Finish ; Hợp dịch như lệnh LJMP Finish:INC A

END

Sự hợp dịch này không thực hiện việc lựa chọn tốt nhất cho chương trình. Ví dụ nếu nhảy theo hướng tới (JMP Finish) chỉ cách khoảng vài byte nhưng lệnh chung JMP vẫn được đổi thành lệnh nhảy dài (LJMP 3 byte), mà không đổi thành lệnh nhảy ngắn (SJMP chỉ có 1 byte).

Biểu thức tính toán tức thời khi hợp dịch (assemble - time expression evaluation).

Các giá trị và hằng số trong một toán hạng có thể biểu diễn theo ba cách: biểu diễn bằng giá trị tức thời (ví dụ 0EFH), biểu diễn bằng ký hiệu đã được định nghĩa trước (ví dụ Acc) hoặc bằng một biểu thức (ví dụ 2 + 3).

Việc sử dụng biểu thức cung cấp một kỹ thuật mạnh cho việc thực hiện các chương trình hợp ngữ có khả năng dễ đọc và mềm dẻo hơn. Khi hợp dịch các biểu thức trong lệnh gợi nhớ sẽ được tính toán thành giá trị cụ thể để đưa vào lệnh. (adsbygoogle = window.adsbygoogle || []).push({});

Tất cả các biểu thức đều được tính toán bằng các phép tính số học 16 bit, tuy nhiên các số 8 bit cũng có thể sử dụng khi cần thiết. Ví dụ hai lệnh sau là hoàn toàn tương đương:

MOV DTPR,#04FFH + 3 MOV DPTR,#0502H

Tổng quát về các nguyên tắc cho các biểu thức tính toán trong chương trình hợp ngữ bao gồm các phần như sau:

Các số (Number bases): Các con số trong các biểu thức thường sử dụng giống như trong các vi xử lý của Intel. Các hằng số cần phải theo sau bởi các ký tự qui định: “B” cho số nhị phân, “O” hoặc “Q” cho các số trong hệ 8, “D” hoặc không có gì cho số hệ 10 và “H” cho số hệ 16. Ví dụ:

MOV A,#15 ; thập phân

MOV A,#1111B ; nhị phân

MOV A,#0FH ; hex

MOV A,#15D ; thập phân

MOV A,#17Q ; Octal.

Chú ý rằng các số trong hệ 16 phải luôn bắt đầu bằng các con số (ví dụ 0AH).

Các chuỗi ký tự (character strings): các chuỗi 1 hoặc 2 ký tự có thể được dùng như các toán hạng trong các biểu thức. Các mã ASCII của ký tự sẽ được biến đổi thành mã nhị phân tương ứng của nó khi hợp dịch. Các hằng ký tự phải nằm trong dấu ngoặc kép (‘a’). Ví dụ:

CJNE A,#’Q’,AGAIN.

Các phép toán số học (Arithmetic operations): Các phép toán số học thực hiện được trong biểu thức là:

+ : cộng - : trừ

. : nhân

/ : chia

MOD : phép lấy dư sau khi chia.

Ví dụ lệnh MOV A,#10+10H và lệnh MOV A,#1AH là tương đương, 2 lệnh MOV A,#25 MOD 7 và MOV A,#4 cũng giống nhau.

Các phép toán logic (logical operations): Các phép toán logic cho phép trong biểu thức gồm: OR, AND, XOR, NOT. Các phép toán logic được thức hiện trên các bit tương ứng trong mỗi toán hạng. Các phép toán phải được phân cách với nhau bằng ký tự khoảng trắng (space) hoặc cách quãng (tab). Ví dụ 3 lệnh MOV sau đây giống nhau:

THERE EQU 3

MINUS_THREE EQU_3

MOV A,# (NOT THREE) +1

MOV A,#MINUS_THREE MOV A,#11111101B

Các phép xử lý đặc biệt (special operations): Các phép xử lý đặc biệt là: SHR (dịch phải), SHL (dịch trái), HIGH (byte cao), LOW (byte thấp)

Ví dụ 2 lệnh: MOV A,#8 SHL 1 và MOV A,#10H thực hiện cùng một việc giống nhau, và hai lệnh MOV A,#HIGH 1234H và lệnh MOV A,12H cũng tương đương.

Một phần của tài liệu Tài liệu Vi điều khiển (Microcontroller) pdf (Trang 43 - 55)