Giáo trình Lập trình hợp ngữ

pdf 78 trang vanle 2650
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Lập trình hợp ngữ", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfgiao_trinh_lap_trinh_hop_ngu.pdf

Nội dung text: Giáo trình Lập trình hợp ngữ

  1. KHOA CÔNG NGHỆ THÔNG TIN Bộ môn Công nghệ điều khiển tự động ĐỖ VĂN TOÀN DƯƠNG CHÍNH CƯƠNG Giáo trình LẬP TRÌNH HỢP NGỮ THÁI NGUYÊN, 2007
  2. Chương 1. NGÔN NGỮ ASM VÀ CÁCH LẬP TRÌNH (25 tiết) 1.1. Mở đầu Giới thiệu Ngôn ngữ Asembler là ngôn ngữ bậc thấp. ¾ Ưu điểm : Vì ngôn ngữ Assembler rất gần gũi với ngôn ngữ máy nên chương trình + Chạy nhanh. + Tiết kiệm bộ nhớ. + Có thể lập trình truy cập qua các giao diện vào ra nhưng hiện nay các ngôn ngữ bậc cao cũng có thể làm được. ¾ Nhược điểm + Khó viết bởi vì yêu cầu người lập trình rất am hiểu về phần cứng. + Khó tìm sai: bao gồm sai về cú pháp (syntax) và sai về thuật toán (Algorithm). Chương trình dịch sẽ thông báo sai ta sẽ dùng debug của DOS để kiểm tra. + Không chuyển chương trình Assembler cho các máy tính có cấu trúc khác nhau. ¾ Ứng dụng + Viết lõi của hệ điều hành. + Các chương trình trò chơi (ngày trước). + Tạo virus. + Các chương trình đo và điều khiển sử dụng trong công nghiệp, ngày nay các vi điều khiển được sử dụng một cách rộng rãi. 1.2. Cài đặt chương trình dịch TASM Hiện nay có hai chương trình dịch rất phổ biến là MASM (của hãng Microsoft) và TASM (của hãng Borland) về cơ bản là hai chương dịch này rất giống nhau nhưng khác nhau ở chỗ: khi viết lệnh push Nếu viết : push ax push bx push cx 2
  3. thì cả hai chương trình đều biên dịch được. (cách viết này theo MASM). Còn trong TASM thì cho phép viết push ax bx cx Cài đặt chương trình dịch TASM: ¾ Cách 1 : Mua đĩa bản quyền nếu là đĩa mềm thì có 5 đĩa hoặc là 1 đĩa CD Run → cmd A:\ install ¾ Cách 2: + Tạo thư mụC: C:\TASM + Copy 4 tệp lõi từ máy khác đã cài đặt theo cách 1 về thư mục đã tạo trước 1.3. Các bước thực hiện một chương trình Assember trên máy PC: (soạn thảo chương trình, dịch chương trình, liên kết, chạy thử và cách tìm sai bằng DEBUG của DOS và TD (Turbo Debug) của Borland) Bao gồm 4 bướC: + Bước l: Dùng chương trình soạn thảo bất kì (Edit, NC, TC, ) để soạn thảo chương trình. Sau khi soạn thảo xong phải cất tệp có đuôi là .ASM. + Bước 2: Dịch chương trình gốc có đuôi .ASM thành tệp có đuôi là .OBJ Cú pháp: C:\BT> tasm ren tệp[.ASM] ↵ → ten tep.OBJ Chú ý: khi chương trình dịch có lỗi thì không sinh ra tệp có đuôi là .OBJ Cách khai báo sai * * Error len tệp.asm[ 10] lllegal Instruction 3
  4. dòng thứ bao nhiêu   lỗi gì + Bước 3: Liên kết để chuyển tên tệp có đuôi .OBJ sang tệp .EXE hay .COM Cú pháp: C:\BT> trinh ren tệp[.OBJ] ↵ →ten tep.EXE hay ten tep.COM + Bước 4: Chạy thử chương trình Khi chạy nếu có lỗi thì dùng debug để kiểm tra. 1.4. Sự hỗ trợ của hệ thống cho việc lập trình Assember 1.4.1 Cấu trúc các thanh ghi a) Thanh ghi là gì? Thanh ghi là một vùng nhớ đặc biệt dạng RAM nằm ở CPU, việc thâm nhập các thanh ghi được thực hiện bằng tên huý (tên thanh ghi). + Người lập trình ASM hay dùng thanh ghi làm toán hạng thay cho biến nhớ vì vậy làm cho chương trình chạy nhanh hơn. + Giải thích: vì các thanh ghi nằm ở CPU nên dữ liệu lấy ra nhanh hơn. + Vùng nhớ cache là vùng nhớ nằm trong CPU. b) Phân loại thanh ghi + Máy tính 16 bit có 14 thanh ghi. + Máy tính 32 bit có 16 thanh ghi. ¾ Cấu trúc thanh ghi của máy tính 16 bít + Nhóm 1. Thanh ghi cờ Người lập trình ASM hay dùng trạng thái các bit cờ làm điều kiện cho các lệnh nhảy có điều kiện. x x x x O D I T S Z x A x P x C + x: không được định nghĩa. 6 bit cờ trạng thái thể hiện các trạng thái khác nhau của kết quả sau một thao tác nào đó, trong đó 5 bit cờ đầu thuộc byte thấp của thanh cờ là các cờ giống như của bộ vi xử lý 8 bit 8085 của Intel. + C hoặc CT (Carry flag): cờ nhớ. CF = 1 khi có nhớ hoặc mượn từ MSB. + P hoặc PF (Parity flag): cờ parity. PF phản ánh tính chẵn lẻ (parity) của tổng số bịt có trong kết quả. PF = 1 khi tổng số bịt 1 trong kết quả là chẵn. + A hoặc AF (Auxiliary carry flag): cờ nhớ phụ, rất có ý nghĩa khi ta làm việc 4
  5. với các số BCD AF = 1 khi có nhớ hoặc mượn từ một số BCD thấp (4 bit thấp) sang một số BCD cao (4 bịt cao). + Z hoặc ZF ( Zero flag): cờ rỗng, ZF = 1 khi kết quả bằng 0. + S hoặc SF (Sum flag): cờ dấu, SF = 1 khi kết quả âm. + O hoặc OF (Overnow flag): cờ tràn, OF = 1 khi kết quả là một số bù hai vượt ra ngoài giới hạn biểu diễn dành cho nó. Ngoài ra bộ vi xử lí 8088 còn có các cờ điều khiển sau đây: + T hoặc TF thấp nao): cờ bẫy, TF = 1 thì CPU làm việc ở chế độ chạy từng lệnh (chế độ này cần dùng khi cần tìm lỗi trong một chương trình). + I hoặc IF (Interrupt enable flag): cờ cho phép ngắt, IF = 1 thì CPU cho phép các yêu cầu ngắt được tác động. + D hoặc DF (Direction flag): cờ hướng, DF = 1 khi CPU làm việc với chuỗi kí tự theo thứ tự từ trái sang phải (hay còn gọi D là cờ lùi). + Nhóm 2. Thanh ghi đa năng: gồm 8 thanh ghi 16 bits. + Trong đó H(high) thể hiện các bit cao, L(low) thể hiện các bit thấp. + Trong 4 thanh ghi AX, BX, CX và DX có 3 cách truy cập: truy cập theo 8 bit cao hoặc theo 8 bit thấp hoặc theo cả 16 bit. Các thanh ghi còn lại chỉ có một cách truy cập. + AX (Accumulator, Acc): thanh chứa. Các kết quả của các thao tác thường được chứa ở đây (kết quả của phép nhân, chia). Nếu kết quả là 8 bit thì thanh ghi AL được coi là Acc. + BX (Base): thanh ghi cơ sở, thường chứa địa chỉ có sở của một bảng dùng trong lệnh XLAT. + CX (Count): bộ đếm, CX thường được dùng để chứa số lần lặp trong trường hợp các lệnh LOOP, còn CL thường chứa số lần dịch hoặc quay trong các lệnh dịch hay quay thanh ghi. + DX (Data): thanh ghi dữ liệu, DX cùng AX tham gia vào các thao tác của phép nhân hoặc chia các số 16 bit. DX còn dùng để chứa địa chỉ của các cổng trong 5
  6. các lệnh vào ra trực tiệp (IN/OUT). + SI (Source index): chỉ số gốc ấy nguồn, SI chỉ vào dữ liệu trong đoạn dữ liệu DS mà địa chỉ cụ thể đầy đủ tương ứng với DS : SI. + DI (Destination index): chỉ số đích, DI chỉ vào dữ liệu trong đoạn dữ liệu DS mà địa chỉ cụ thể đầy đủ tương ứng với DS : DI. + BP (Base pointer) : con trỏ cơ sở, BP luôn trỏ vào một dữ liệu nằm trong đoạn ngăn xếp SS. Địa chỉ đầy đủ của một phần tử trong đoạn ngăn xếp ứng với SS : BP. + SP (Stack pointer): con trỏ ngăn xếp, SP luôn trỏ vào đỉnh hiện thời của ngăn xếp SS. Địa chỉ đầy đủ của đỉnh ngăn xếp ứng với SS:SP. Người lập trình chỉ dùng 7 thanh ghi sau: AX, BX, CX, DX, SI, DI, BP. + Nhóm 3: Thanh ghi con trỏ lệnh IP (Instruction pointer) hay PC(Program pointer) IP (Instruction Pointer) 15 0 Nội dung trong thanh ghi IP cho biết địa chỉ offset của vùng nhớ chứa mã lệnh. + Nhóm 4: Thanh ghi Segmnet (phân đoạn): 4 thanh ghi 16 bits. 15 CS 0 DS ES SS Các thanh ghi segment cho biết địa chỉ segment. + CS (Code segment): mã máy. + DS, ES: dữ liệu. + SS: ngăn xếp ¾ Cấu trúc thanh ghi của máy tính 32 bit + Nhóm l + nhóm 2 + nhóm 3 là các thanh ghi 32 bit và với chữ E ở đầu (ví dụ: EAX hay EBX) EAX 31 15 AX 0 6
  7. 1.4.2 Cách thể hiện địa chỉ ô nhớ (ROM hoặc RAM): dạng 1ôgíc và dạng vật lý Một thanh ghi 16 bit thì trỏ được 64k nhưng vùng nhớ của máy tính hiện nay rất lớn do vậy phải dùng 2thanh ghi để thể hiện địa chỉ của một ô nhớ. Và vùng nhớ được chia thành nhiều phần, mỗi phần 64k. a) Dạng Logic Địa chỉ 1 ô nhớ = segment : offset + Thanh ghi thứ nhất cho biết ô nhớ đó nằm ở 64k thứ mấy (địa chỉ segment). + Thanh ghi thứ hai cho biết khoảng cách từ đầu segment đến vị trí ô nhớ đó (địa chỉ offset). Ví dụ: 2 : 100 tức là địa chỉ của ô nhớ nằm ở vị trí 100 tính từ trên đỉnh của segment thứ hai. b) Dạng vật lý Địa chỉ ô nhớ = seg * 16 + offset + Cách đánh địa chỉ này hay được dùng. 1.4.3 Các ngắt hay dùng hỗ trợ cho lập trình Assembler + Hàm l: Chờ 1 kí tự Mov ah,1 ; gán ah = 1 ai chứa mã ASCII ; al = 0 khi kí tự gõ vào là các phím chức năng. Int 21h + Hàm 2: Hiện 1 ký tự lên màn hình từ vị trí con trỏ đang đứng. Cách 1 : Mov al, mã ASCII Mov ah,0eh Int 10h Cách 2: Mov dl, mã ASCII ; dl = mã ASCII của kí tự cần hiển thị Mov ah,2 Int 21h + Hàm 3: Hiện xâu kí tự kết thúc '$' lên màn hình. lea dx, tên biến xâu 7
  8. ; mov dx,offset tên biến xâu Mov ah,9 Int 21h + Hàm 4: Trở về DOS Mov ah,4ch Int 21h 1.5. Hệ lệnh Assembler + Tập lệnh MNEMONIC sinh mã máy để chạy chương trình. + Các DIRECTIVE điều khiển khi dịch chương trình. 1.5.1. Cú pháp của một dòng lệnh ASM + Mỗi một dòng chỉ được viết một lệnh. + [Label] [Directive/Mnemonic] [Operands] [;Commnet] [Nhãn] [Loại lệnh] [Toán hạng] [Ghi chú] Từ ; cho đến hết dòng là ghi chú và nó có hiệu lực chỉ trên 1 dòng. 1.5.2. Tập lệnh Mnemonic - Tập lệnh Mnẹmonic là gì? Đó là lệnh của ASM được thể hiện bằng viết tắt của tiếng Anh cho dễ hiểu. Tiếng Anh Lệnh dang Mnemonic Move mov Addition add Multiplication mul - Các quy ước vê toán hạng + SRC: Toán hạng nguồn. + DST: Toán hạng đích. + REG(reg8/reg 16 : Toán hạng là thanh ghi + Data: Toán hạng là hằng số. 8
  9. + Mem: Toán hạng là biến nhớ. + Segreg: Toán hạng là thanh ghi segment. - Tập lệnh MNEMONIC gồm có 6 nhóm + Nhóm 1 : Các lệnh di chuyển dữ liệu + Nhóm 2: Các lệnh số học. + Nhóm 3: Các lệnh thao tác bit + Nhóm 4: Các lệnh thao tác xâu ký tự. + Nhóm 5: Các lệnh rẽ nhánh + Nhóm 6 : Các hệ thống cờ a) Nhóm 1: Các lệnh di chuyển dữ liệu Tất cả lệnh trong nhóm này khi thực hiện không làm thay đổi trạng thái của các bit cờ. - Lệnh mov Chức năng: Đưa nội dung từ SRC đến DST Cú pháp: mov DST. SRC Reg1 Reg2 → mov ax, bx Reg Data → mov cx, 100 Reg Mem → mov dx, value Mem Reg → mov value, dx Mem Data → mov value, 100 Regreg Reg16 → mov ds, ax Reg16 Segreg → mov bx,cs Regreg Mem16 → mov cs, value Mem16 Regreg → mov value, cs Chú ý: + Không được di chuyển giữa hai biến nhớ (mov mem 1 ,mem2) . Thực hiện gián tiếp: mov reg,mem2 mov mem 1,regs + Không đưa trực tiếp dữ liệu vào thanh ghi segment (mov seg,data). Thực hiện gián tiếp: 9
  10. mov reg 16,data mov segreg,reg 16 + Sự khác nhau khi sử dụng các chế độ địa chỉ ( mov ax,bx khác với mov ax,[bx]; đưa nội dung mà bx trỏ đến vào ax) mov ax,[bx] tương đương với mov ax, ds:[bx] (SI,DI hay BP) - Lệnh push Chức năng: Cất 2 byte của SRC vào đỉnh ngăn xếp(stack). Cú pháp: PUSH SRC reg16 mem16 Ví dụ: push ax Toán hạng gốc có thể tìm được theo các chế độ địa chỉ khác nhau: có thể là thanh ghi đa năng, thanh ghi đoạn hay là ô nhớ. Lệnh này thường được dùng với lệnh POP như là một cặp đối ngẫu để xử lý các dữ liệu và trạng thái của chương trình chính(CTC) khi vào ra chương trình con(ctc). - Lệnh POP Chức năng: lấy 2 byte ( 1 từ) ở đỉnh ngăn xếp (stack) vào toán hạn đích. Cú pháp: POP DST Reg16 mem16 Ví dụ: push ax push bx push cx Đoạn Chương trình pop cx pop bx pop ax 10
  11. Chú ý: - Cơ chế PUSH/POP là Lipo(last infirst out) - Cách viết trên chỉ được sử dụng trong MASM còn trong TASM được viết như sau: push ax bx cx - Lệnh PUSHF Chức năng; cất giá trị thanh ghi cờ vào đỉnh ngăn xếp Cú pháp: PUSHF Dữ liệu tại ngăn xếp không thay đổi, SS không thay đổi. - Lệnh POPF Chức năng: Lấy 2 byte từ đỉnh ngăn xếp rồi đưa vào thanh ghi cờ. Cú pháp: POPF Sau lệnh này dữ liệu tại ngăn xếp không thay đổi, SS không thay đổi. - Lệnh XCHG (Exchange 2 Operands) Tráo nội dung 2 toán hạng Chức năng: Tráo nội dung 2 toán hạng DST ⇔ SRC Cú pháp XCHG DST SRC reg1 reg2 reg mem Trong toán hạng đích có thể tìm theo chế độ đị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à 2 ô nhớ và cũng không được là thanh ghi đoạn. Sau lệnh XCHG toán hạng chứa nội dung cũ của toán hạng kia và ngược lại. Lệnh này không tác động đến cờ. - Lệnh IN Chức năng: đọc dữ liệu từ cổng vào thanh ghi AL/AX Cú pháp: IN AL/AX, địa chỉ cổng Chú ý: + Nếu địa chỉ cổng <256 thì số địa chỉ đứng trực tiếp trong lệnh IN Ví dụ: địa chỉ cổng là 1 từ IN AL, 1 từ; nội dung cổng 1fh đưa vào AL. + Nếu địa chỉ cổng ≥ 256 thì phải nhờ đến thanh ghi DX 11
  12. Ví dụ: địa chỉ COM1 = 378h mov dx,378h in al,dx Lệnh OUT Chức năng: đưa dữ liệu từ thanh ghi AL/AX ra cổng Cú pháp: OUT địa chỉ cổng, AL/AX Chú ý: + Nếu địa chỉ cổng <256 thì số địa chỉ đứng trực tiếp trong lệnh OUT Ví dụ: địa chỉ cổng là 1fh OUT 1fh,AL; nội dung cổng 1fh đưa vào AL. + Nếu địa chỉ cổng ≥ 256 thì phải nhờ đến thanh ghi DX Ví dụ: địa chỉ COMI = 378h mov dx,378h out dx,al Lệnh này không tác động đến cờ. - Lệnh LEA (loạn Efective address) Chức năng: lấy phần địa chỉ offset của biến đưa vào thanh ghi 16 bit Cú pháp: lea reg16, mem Ví dụ: lea bx, Value hay mov bx, OFFSET Value Đích thường là các thanh ghi: BX, CX, DX, BP, SI, DI. Nguồn là tên biến trong đoạn DS được chỉ rõ trong lệnh hay ô nhớ cụ thể. Ví dụ: lea dx, msg; Nạp địa chỉ offset của bản tin msl vào dx - Lệnh LES (Load register and ES with words from memory) Chức năng: chuyển giá trị của 1 từ từ một vùng nhớ vào thanh ghi đích và giá trị của từ tiếp theo sau của vùng nhớ vào thanh ghi ES. Cú pháp: les reg, mem Trong đó: Đích là một trong các thanh ghi AX, BX,CX, DX, SP, BP, SI, DI. Gốc là ô nhớ trong đoạn DS được chỉ rõ trong lệnh 12
  13. - Lệnh LDS (Load resgister and DS with words from memory) Chức năng: Nạp một từ từ bộ nhớ vào thanh ghi cho trong lệnh và 1 từ tiếp theo vào DS. Cú pháp: lds reg, mem b) Nhóm 2: Các lệnh số học b1) Số có dấu và số không dấu - Số không dấu: Nếu nhìn vào toán hạng (độ lớn các toán hạng là 1 byte hay là là 2 byte) với số không dấu thì bit cao nhất mang giá trị tại vị trí đó. Ví dụ: 1 1 1 1 1 1 1 1 255 - Số có dấu: Nếu nhìn vào toán hạng của số có dấu thì bit cao nhất sẽ mang ý nghĩa về dấu: 1 toán hạng là số âm, 0 toán hạng là số dương. b2) Cách thể hiện một số âm của máy tính Máy tính thể hiện số âm bằng cách bù 2 giá trị tuyệt đối của số đó. Ví dụ: mov ax, - 1 L = 0000 0000 0000 0001 bù l: 1111 1111 1111 1110 + 1 bù 2: 1111 1111 1111 1111 mov ax, - 100 100 = 0000 0000 0110 0100 1111 1111 1001 1011 13
  14. + 1 bù2: 1111 1111 1001 1100 Hầu hết các lệnh trong nhóm này khi thực hiện có thể làm thay đổi các kí tự. - Lệnh ADD (addition) Chức năng: DST ← DST + SRC Cộng hai toán hạng: lấy toán hạng đích cộng với toán hạng nguồn rồi đưa vào toán hạng đích. Cú pháp:TR11 add DST, SRC reg 1 reg2 → add ax, bx reg data → add cx, 100 reg mem → add dx,value mem reg → add value,dx mem data → add value, 100 Tác động đến cờ: C, P, A, Z, S, O. - Lệnh ADC(Add with carry) Chức năng: cộng có nhớ, DST ← DST + SRC + CF Cú pháp: adc DST, SRC Tác động đến cờ: C, P, A, Z, S, O. Ví dụ: adc ax, bx - Lệnh INC(Increment Destination Register or Memory) Chức năng: Tăng toán hạng đích thêm 1. DST ← DST + 1 Cú pháp: inc DST 14
  15. Tác động đến cờ: C, P, Z, S, O. Ví dụ: reg → inc ax mem → inc value - Lệnh SUB (Substraction) Chức năng: Trừ hai toán hạng, DST ← DST - SRC Cú pháp: sub DST, SRC Ví dụ: sub ax, bx Tác động đến cờ: C, P, A, Z, S, O. Chú ý: chế độ địa chỉ không được đồng thời là 2 ô nhớ hay là thanh ghi đoạn. Lệnh SBB (substraction with borrow) Chức năng: Trừ có mượn, DST ← DST - SRC - CF Cú pháp: sbb DST, SRC Ví dụ: sbb ax, bx Tác động đến cờ: C, P, A, Z, S, O. - Lệnh MUL/ IMUL (Multiply Unsigned Byte or Word/ Integer Multiplieation) Chức năng: Nhân 2 toán hạng với số không dấu (MUL), số có dấu (IMUL) Cú pháp: MUL(IMUL) SRC reg mem Có hai trường hợp tổ chức phép nhân + 8 bits * 8 bits Số bị nhân phải là số 8 bit để trong AL Sau khi nhân: al*SRC → AX + 16 bits * 16 bits Sô bị nhân phải là số 16 bit để trong AX 15
  16. Sau khi nhân: ax*SRC → dx:ax Tác động đến cờ: C, O. Chú ý: Al = 1111 1111 bl = 0000 0010 mul bl → ax = al*bl (255*2 - 510) imul bl → ax = al*bl (- 1 *2 = -2 ) Trong phép chia thì ax, bx, dx (ai,bl,dx) là ẩn - Lệnh DIV/IDIV(Unsigned Divide/integer Division) Chức năng: Chia hai toán hạng với số không dấu/ số có dấu Cú pháp: DIV (IDIV) SRC reg mem Hai trường hợp tổ chức phép chia + Nếu số 16 bits chia cho số 8 bits + Nếu số 32 bits chia cho số 16 bits Trong phép chia thì ax, bx, dx (al,bl,dx) là ẩn Ví dụ: - Lệnh DEC (Decrement Destination Register or Memory) Chức năng: Giảm toán hạng đích đi 1, DST ← DST - 1 Cú pháp: dec DST 16
  17. Reg → dec ax mem → dec value Tác động đến cờ: C, P, Z, S, O. - Lệnh NEG (Negate a Operand) Chức năng: lấy bù hai của một toán hạng, đảo dấu của một toán hạng DST ← - DST Cú pháp: neg DST Reg → neg ax mem → neg value Tác động đến cờ: C, P, A, Z, S, O. - Lệnh CMP (Compare Byte or Word) Chức năng: So sánh nội dung của hai toán hạng và dựng cờ. Sau khi thực hiện lệnh này nội dung của hai toán hạng không thay đổi. Cú pháp: cmp DST, SRC Tác ứng đến cờ: C, P, Z, S, O. Cách dựng cờ: cmp DST, SRC + NẾU DST < SRC thì CF = 1 . + NẾU DST ≥ SRC thì CF = 0. + NẾU DST = SRC thì ZF = 1 . + Nếu DST ≠ SRC thì ZF = 0. c) Nhóm 3: Các lệnh thao tác bit Chú ý: tất cả các lệnh trong nhóm này khi thực hiện có thể làm thay đổi trạng thái các bit cờ. - Lệnh AND Chức năng: Thực hiện phép "và logic", bit của kết quả bằng 1 khi 2 bit tương ứng đều bằng 1. DST ← DST ∧ SRC Ví dụ: al = 1010 1010 bl = 1100 1100 and al,bl = 1000 1000 17
  18. Cú pháp: and DST, SRC Cách hay dùng: + Tách bit: al = xxxx xxxx 0001 0000 and al, 10h = 000x 0000 Khi dùng phép AND để che đi/ giữ lại một vài bit nào đó của một toán hạng thì bằng cách nhân logic toán hạng đó với toán hạng tức thì có các bit0/1 ở các chỗ cần che/ giữ nguyên tương ứng. + Dựng cờ and DST,DST Ví dụ: and ax, ax Nếu ax < 0 thì SF = 1. Nếu ax ≥ 0 thì SF = 0. Nếu ax = 0 thì ZF = 1 . Nếu ax ≠ 0 thì ZF = 0. - Lệnh OR Chức năng: thực hiện phép hoặc logic, Bit của kết quả = 1 khi 1 trong 2 bit là 1. DST ← DST ∨ SRC Ví dụ: al = 1010 1010 bl = 1100 1100 or al,bl = 1110 1110 Cú pháp: or DST, SRC Tác động đến cờ: C = O = 0, P, Z, S. - Lệnh XOR Chức năng: Thực hiện phép "hoặc loại trừ" 2 toán hạng, bit của kết quả bằng 1 khi 2 bit tương ứng khác nhau. Ví dụ: al = 1010 1010 bl = 1100 1100 xor al,bl = 0110 0110 18
  19. Cú pháp: xor DST, SRC Cách hay dùng: + Tách bit: al = xxxx xxxx 0001 0000 and al, 10h = 000x 0000 Tác động đến cờ: C = O = 0, P, Z, S. Ví dụ: Thực hiện ax = 0 1. mov ax,0 3 byte 2. and ax,0 3. sub ax,ax 2 byte 4. xor ax,ax - Lệnh SHL (Shift Left) Chức năng: dịch trái các bit của toán hạng đích đi một số lần nào đó (số lần dịch được cất trong thanh ghi CL). Cú pháp: SHL DST, CL (reg, mem) Tác động đến cờ: C, P, Z, S, O. Mỗi một lần dịch MSB sẽ đưa qua cờ CF và đưa 0 vào LSB. CL chứa số lần dịch mong muốn. Nếu dịch một lần thì ta có thể viết trực tiếp. VD: shl ax,l Nếu số lần dịch ≥ 2 thì phải nhờ đến CL/CX shl ax 4 ≡ mov cl/cx, 4 shl ax, cl/cx Ý nghĩa: Dịch trái 1 lần là nhân 2 với số nguyên dương. - Lệnh SHR (shift Right) Chức năng: dịch phải logic các bit của toán hạng đích đi một số lần nào đó (số lần dịch được cất trong thanh ghi CL). 19
  20. Cú pháp: SHR DST, CL (reg, mem) Tác động đến cờ: C, P, Z, S, O. Mỗi một lần dịch LSB sẽ đưa qua cờ CF và đưa 0 vào MSB. CL chứa số lần dịch mong muốn. Nếu dịch một lần thì ta có thể viết trực tiếp. VD: sai ax,1 Nếu số lần dịch ≥ 2thì phải nhờ đến CL/CX Shr ax,4 ≡ mov cl/cx, 4 shr ax, cl/cx Ý nghĩa: Dịch phải 1 lần là chia đôi và làm tròn dưới với số nguyên dương - Lệnh SAR ( Shift Arithmetically Right). Chức năng: dịch phải số học các bit của toán hạng đích đi một số lần nào đó (số lần dịch được cất trong thanh ghi CL). Cú pháp: SAR DST, CL (reg, mem) Tác động đến cờ: C, P, Z, S, O. Mỗi một lần MSB được giữ lại (nếu ta hiểu đây là bit dấu của một số nào đó thì dấu luôn không đổi sau phép dịch phải số học) còn LSB được đưa vào cờ CF. CL chứa sẵn số lần dịch mong muốn. Nếu dịch một lần thì ta có thể viết trực tiếp. VD:sar ax,1 Nếu số lần dịch ≥ 2thì phải nhờ đến CL/CX Sar ax,4 ≡ mov cl/cx, 4 sar ax, cl/cx Ý nghĩa: Dịch phải 1 lần là chia đôi và làm tròn dưới với số có dấu. 20
  21. - Lệnh ROL (Rotate All Bits to the Left) Chức năng: quay vòng sang trái các bit của toán hạng đích đi một số lần nào đó (số lần dịch được cất trong thanh ghi CL). Trong mỗi lần quay giá trị bit cao nhất vừa chuyển vào thanh ghi cờ CF đồng thời chuyển vào bit thấp nhất Cú pháp: ROL DST, CL (reo,mem) Tác động đến cờ: C, O. Nếu dịch một lần thì ta có thể viết trực tiếp. VD: rol ax,1 - Lệnh ROR Chức năng: quay vòng sang phải các bit của toán hạng đích đi một số lần nào đó (số lần dịch được cất trong thanh ghi CL). Trong mỗi lần quay giá trị bit thấp LSB nhất vừa chuyển vào thanh ghi cờ CF đồng thời chuyển vào bit cao nhất MSB. Cú pháp: ROR DST, CL Tác động đến cờ: C, O. Nếu dịch một lần thì ta có thể viết trực tiếp. VD: rol ax,1 d) Nhóm 4: Các lệnh làm việc với xâu Chú ý: Chỉ có 2 lệnh trong nhóm này khi thực hiện làm thay đổi các bit cờ. - Lệnh MOVSB/MOVSW (Move String Byte or String Word) Chức năng: Chuyển một xâu ký tự theo từng byte(MOVSB) hay theo từng từ (MOVSW) từ vùng nhớ trỏ bởi DS:SI sang vùng nhớ trỏ bởi ES:DI. Sau mỗi lần dịch chuyển thì giá trị của SI, DI tự động tăng lên 1 hoặc 2 khi cờ hướng DF = 0 hoặc giảm đi 1 hoặc 2 khi DF = 1 . Phần tử của Chuỗi đích ← phần tử của Chuỗi gốc Cú pháp: MOVSB hoặc MOVSW 21
  22. Chuẩn bị trước ds:si con trỏ đến đầu xâu SRC, es:di con trỏ đến đầu xâu DST Lệnh này không tác động đến cờ. - Lệnh LODSB/LODSW (Load String Byte or Word into AL/AX) Chức năng: Chuyển các kí tự theo từng byte (LODSB) hay theo từng từ (LODSW) từ vùng nhớ trỏ bởi DS:SI vào AL/AX. Cú pháp: LODSB hoặc LODSW Chuẩn bị trước ds : si con trỏ ở đầu xâu, df = 0 hay df = 1. Lệnh này không tác động đến cờ. - Lệnh STOSB/STOSW (Store AL/AX in String Bytel/Word) Chức năng: Chuyển các kí tự nằm ở AL(STOSB)/AX (STOSW) vào vùng nhớ trỏ bởi ES:DI. Cú pháp: STOSB hoặc STOSW hoặc STOS Chuỗi đích. Xác lập trước ES:DI trỏ đến đầu vùng nhớ, df= 0 hay df= 1. Lệnh này không tác động đến cờ. Nhận xét: 1. movsb = lodsb + stosb 2. movsw = lodsw + stosw - Lệnh CMPSB/CMPSW Chức năng: So sánh hai xâu kí tự theo từng byte (CMPSB) / theo từng từ (CMPSW) giữa hai vùng nhớ trỏ bởi DS:SI và ES:DI. Lệnh này chỉ tạo cờ, không lưu lại kết quả so sánh, sau khi so sánh các toán hạng không bị thay đổi. Cú pháp: CMPSB hoặc CMPSW hoặc STOS Chuỗi đích. Xác lập trước DS:SI trỏ đến đầu xâu 1, ES:DI trỏ đến đầu xâu 2, df = 0 hay df = 1 Tác động đến cờ: ZF = 1 khi hai xâu bằng nhau, ZF = 0 khi hai xâu khác nhau. - Tiền tố REP (Repeat String Instruction until CX = O). 22
  23. Chức năng: Lặp đi lặp lại lệnh làm việc với xâu kí tự đằng sau nó cho đến khi cx = 0. Sau mỗi lần thực hiện cx tự động giảm đi 1 Cú pháp: mov cx, số lần reg lệnh làm việc với xâu ; reg movsb Thuật toán 1. DS:SI 2. ES:DI 3. D = 0 4. CX = 5 5. reg movsb; sau mỗi lần cx = cx - 1 cho đến khi cx = 0. e) Nhóm 5: Các lệnh rẽ nhánh - Lệnh Call Chức năng: Gọi chương trình con Cú pháp Call Addr (seg:offset) Label Tên chương trình con reg mem - Lệnh RET Chức năng: quay về chương trình đã gọi chương trình con Cú pháp: RET (nằm ở cuối chương trình con) - Lệnh INT Chức năng: Kích hoạt một ngắt (chuyển sang chạy chương trình con phục vụ ngắt) (Ngắt mềm). 23
  24. Cú pháp: im n (số ngắt viết theo số hexa) Ví du : im 21h = im 33 - Lệnh IRET Chức năng: quay về chương trình đã kích hoạt nó từ chương trình con phục ngắt. Cú pháp: IRET - Lệnh JMP (go to) Chức năng: nhảy không điều kiện Cú pháp: jmp Addr (seg:offset) Label Tên chương trình con reg mem Chú ý: Bước nhảy của lệnh jump SRC js Nhãn Khi SF=l Địa chỉ SRC Địa chỉ Địa chỉ Jae/jnh Nhãn Khi DST Jge/jnl Nhãn Khi DST ≥ SRC jns Nhãn Khi Địa chỉ trên/=SRC Địa chỉ Địa chỉ SF=0 Chú ý: Bước nhảy các lệnh nhảy có điều kiện phải nhỏ hơn hoặc bằng 128byte - Lệnh LOOP (for của ASM) Chức năng: lặp đi lặp lại khối lệnh ASM nằm giữa nhãn và loop cho đến khi cx 24
  25. = 0 Mỗi khi thực hiện một vòng lặp giá trị của CX giảm đi 1. Cú pháp: Mov cx, số lần lặp; số lần lặp ≥ 1 Nhan: Khối lệnh ASM Loop Nhan f) Nhóm 6: Các lệnh thao tác với cờ - Lệnh CLC (Clear CF) Chức năng: Xoá giá trị cờ CF về 0, CF = 0 Cú pháp: CLC Cờ C = 0 - Lệnh STC Chức năng: Đưa giá trị cờ CF lên 1 , CF = 1 Cú pháp: STC Cờ C = 1 - Lệnh CMC Chức năng: Đảo giá trị hiện thời của cờ CF. Cú pháp: CMC Tác động đền cờ C . - Lệnh CLI Chức năng: Xoá giá trị của cờ IF về O(IF = O). Cấm toàn bộ các ngắt cứng trừ ngắt MNI. Cú pháp: CLI Cờ IF = 0. - Lệnh STI Chức năng: Đưa giá trị của cờ IF lên 1 (IF = l). Cho phép ngắt cứng. Cú pháp: STI Cờ IF = 1 . - Lệnh CLD Chức năng: Xoá giá trị của cờ DF về 0 (DF = 0). 25
  26. Cú pháp: CLD Cờ DF = 0, dựng cờ. - Lệnh STD Chức năng: Đưa giá trị của cờ DF lên1 (DF = l). Cú pháp: STD Cờ DF = 1 . - Lệnh HLT Chức năng: dừng máy Cú pháp: HLT - Lệnh NOP Chức năng: lệnh này không thực hiện gì cả Cú pháp: NOP (4 μ s) Ý nghĩa: Tạo trễ (delay) Tạo vòng chờ vô tận để chờ ngắt. L1: nop Jmp L1 1.5.3 Các lệnh điều khiển khi dịch chương trình (directive) 1.5.3.1. Các directive điều khiển segment: dạng đơn giản ( MODEL, .STACK, .DATA, .CODE, ) a) Directive .MODEL Chức năng: cho phép người lập trình xác lập vùng nhớ RAM thích hợp cho chương trình. Cú pháp . Model Kiểu Tiny Code + data ≤ 64k Small Code ≤ 64k; data ≤ 64k 26
  27. Compact Code ≤ 64k; data ≥ 64k Medium Code ≥ 64k; data ≤ 64k Large Code ≥ 64k; data ≥ 64k 1 array ≤ 64k Huge Code ≥ 64k; data ≥ 64k 1 array ≥ 64k b) Directive .STACK Chức năng: báo cho chương trình dịch của ASM biết xác lập 1 vùng nhớ RAM cho Stack. Với lệnh điều khiển này thì DOS sẽ xác lập địa chỉ đầu của ngăn xếp và giá trị đó được đưa vào thanh ghi segment SS. Cú pháp: .stack độ dài (tính theo byte) Ví dụ: .stack 100h Nếu không có khai báo .stack thì lấy độ dài mặc định default. c) Directive .DATA Chức năng: báo cho chương trình dịch của ASM biết để xác lập 1 vùng nhớ RAM cho dữ liệu chương trình. Cú pháp: .DATA Khai báo biến Biến trong ASM có ba loại: biến số, biến xâu kí tự và biến trường số - Khai báo biến số .DATA Tên biến Kiểu Giá trị ban đầu/? db ( 1 byte) dw ( 2 byte) dd ( 4 byte) dp ( 6 byte) dq ( 8 byte) dt ( 10 byte) trong đó 2 biến db và dw hay dùng. Ví dự 27
  28. .DATA Value dw ? Value db 10 - Khai báo biến xâu kí tự .DATA Tên biến db Các kí tự cách nhau bởi dấu phẩy , độ lớn dup ( 1 kí tự/ ?) Ví dụ: .DATA xau1 db 'H','e','l','l','l,'o' xau2 db 100h dup('A') xau2 db 100 dup(?) - Khai báo biến trường số .DATA Tên trường số kiểu của thành phần (Các số cách nhau bởi dấu,) Độ lớn dup( 1 số/?) Ví dụ: .DATA array 1 db 1 00,2,21 ,31 array2 dw 100h dup(- 100) array3 dd 100 dup(?) Chú ý: Nếu chương trình có khai báo biến (tức là có .DATA) thì người lập trình ASM phải đưa phần địa chỉ segment của vùng nhớ dữ liệu vào trong DS nhờ 2 lệnh sau: mov reg 16, @data mov ds ,reg 16 Ví dụ: mov ax, @data mov ds,ax d) Directive .CODE Chức năng: Báo cho chương trình dịch ASM biết để xác lập 1 vùng nhớ RAM 28
  29. cho phần tử mã máy của chương trình. Cú pháp: .CODE e) Dạng thường thấy 1 chương trình ASM đơn giản (Khai báo theo directive điều khiển segment dạng đơn giản) .MODEL .STACK .DATA Khai báo biến .CODE Nhãn chương trình: mov ax, @ldata mov ds,ax Thân chương trình mov ah, 4ch int 21h END Nhãn chương trình Ví dụ 1 : Hiện 1 xâu lên màn hình Cách 1: Dùng chức năng hiện 1 xâu '$' lên màn hình lea dx, tên biến xâu mov ah,9 int 21h C:\BT>edit vd1.asm .MODEL small .STACK 100h .DATA 29
  30. M db 'Hello, World?$' .CODE Mov ax, @data mov ds,ax lea dx, M mov ah,9 int 21h mov ah, 1 int 21h mov ah,4ch int 21h END PS Cách 2: Dùng lệnh LODSB và xâu khai báo theo dạng ngôn ngữ C .MODEL small .STACK looh .DATA M db 'Hello, World!',0 .CODE Mov ax, @data mov ds,ax lea si, M cld L1: Lodsb And al,al Jz KT mov ah,0eh int 10h jmp Ll KT 30
  31. mov ah, 1 int 21h mov ah,4ch int 21h END PS Cách 3: Không dùng lệnh làm việc với xâu .MODEL small .STACK looh .DATA M db 'Hello, World!',O .CODE PS: mov ax, @data mov ds,ax lea si, M cld Ll: mov al,[si]; mov al, ds:[si] and al,al jz KT mov ah,0eh int 10h inc si jmp Ll KT: mov ah, 1 int 21h mov ah,4ch int 21h END PS 31
  32. Ví dụ 2: Hiện nội dung AX lên màn hình dạng binary AX= -1 suy ra ct 1111 1111 1111 1111 AX = 100 → 0000 0000 0110 0100 AX = 255 → 0000 0000 1111 1111 C:\BT>edit vd2.asm .MODEL small .STACK 100h .CODE mov ax, số thứ -1 hoặc 100 hoặc 255 mov bx,ax mov cx, 16 Ll: xor al, al shl bx, 1 adc al,0 add al,30h; hiện mã ASCII mov ah,0eh int 10h loop L1 mov ah, 1 int 21h mov ah,4ch int 21h END PS ví dụ 3: Tính 5! Cách l: không dùng biến .MODEL small .STACK 100h .CODE mov ax, 1 32
  33. mov cx, 5 Ll: mul cx loop L1 mov ah, 1 int 21h mov ah,4ch int 21h END PS Cách 2: dùng biến .MODEL small .STACK 100h .DATA FV dw ? FAC dw ? .CODE PS: mov ax, @data mov ds,ax mov FV, 1 mov FAC, 2 mov cx, 4 L1: mov ax, FV mul FAC mov FV, ax inc FAC loop L 1 mov ah,4ch int 21h 33
  34. END PS Giải thích: cx = 4 ax = FV = 1 dx:ax = ax*FAC = ax=l.2 ax = 1.2 ax = 1.2.3 ax = 1.2.3.4 FV = ax = 1.2 ax = 1.2.3 ax = 1.2.3.4 ax = 1.2.3.4.5 FAC = 3 FV=l.2.3 FV=l.2.3.4 FV=l.2.3.4.5 cx 3?0 FAC = 4 FAC = 5 FAC = 6 Cx = 2?0 Cx = l?0 CX = 0?0 f) Công cụ DEBUG Chức năng: gỡ rối chương trình ASM quy ước : - Mỗi lệnh là 1 ký tự: D, T, G, P, Q, N, L, O - Giá trị làm việc với DEBUG là hệ hexa Khởi động công cụ DEBUG Cách 1 : . . . . .\>debug tentep.exe (.com) ↵ Cách 2 : . . . .\> debug ↵ - N tentep.exe (.com)↵ - L ↵ Các lệnh hay dùng - Lệnh D (Dump = Display) Chức năng: hiện vùng nhớ lên máy tính Cú pháp: - D địa chỉ ô đầu ; ↵ (seg:offset) - D ↵ hiện tiếp 128 byte - Lệnh E (Enter) Chức năng: hiện và sửa nội dung ô nhớ . 34
  35. Cú pháp: - E địa chỉ offset ; ↵ (seg:offset) - Lệnh R(Rigister) Chức năng: Hiện và sửa nội dung một thanh ghi Cú pháp: -R Tên thanh ghi ↵; Tên huý của thanh ghi Tên thanh ghi - Lệnh G (Go) Chức năng: chạy từ nơi chương trình đang đứng (IP đang trỏ) đến hết chương trình. Cú pháp: - G ↵ Giải thích: lệnh 1 lệnh 2 - Lệnh T/P Chức năng: cho phép chạy 1 bước. Cú pháp: - T/P↵ Hiện nội dung các thanh ghi AX BX CX DX SI DI BP DS ES CS SS IP SP lệnh sắp thực hiện tiếp theo. 35
  36. Sự khác nhau giữa T và P 1.Call Call tên chương trình con - T ↵ 1 nhảy vào chương trình con - P ↵ chạy hết chương trình con, coi chương trình con là 1 lệnh 2. INT (ngắt mềm) im n - T ↵ nhảy vào thân chương trình con phục vụ ngắt - P ↵ chạy hết chương trình con phục vụ ngắt 3. Loop Nhãn Nhan: Loop Nhan - T ↵ chạy từng vòng một; cx = cx - 1?0 - P ↵ chạy toàn bộ các vòng cx → 0 - Lệnh Q (Quit) Chức năng: trở về DOS. Cú pháp: - Q ↵ - Lệnh U (UnAssembly) Chức năng: dịch ngược từ dạng .exe hay .com sang dạng .asm Cú pháp: - U địa chỉ ô nhớ đầu ↵ ; seg: offset địa chỉ mã máy lệnh mnemonic xx:yy eg jmp Chú ý vấn đề khai báo biến 1. Khai báo biến tức là xin cấp phát ô nhớ. 2. Biến nào được khai báo trước sẽ chiếm ô nhớ trước. 3. Biến khai báo đầu tiên sẽ có địa chỉ offset = 0000h 36
  37. Giải thích .DATA FV dw ? FAC dw ? mov FV, 1 → mov word PTR[0000];1 mov FAC,1 → mov word PTR[0002];2 1.5.3.2. Các directive điều khiển segment: dạng chuẩn (SEGMENT, GROUP và ASSUME) a) Directive SEGMENT Chức năng: báo cho chương trình dịch ASM xác lập các segment cho chương trình. Cú pháp : - Tên Segment: bất kỳ một định danh nào. - Align Chức năng: xác lập khoảng trống giữa segment đang khai báo với segment trước nó. Cú pháp: ALIGN BYTE WORD PARA (16 BYTE) (Default) PAGE (128 BYTE) Giải thích: 37
  38. - Combine Chức năng 1: cho phép đặt segment khai báo 1 vùng nhớ RAM theo yêu cầu. Cú pháp: tên segment SEGMENT at địa chỉ Tên segment ENDS Chức năng 1: phục vụ chương trình đa tệp thuần tuý ASM, cách gộp các segment có cùng tên nằm ở các tệp khác nhau khi liên kết. Cú pháp: COMMON Overlay đè lên nhau PUBLIC Continue, ∑ PRIVATE (Default) Không biết nhau Ví dụ: tepl.asm tep2.asm Xl Segment common Xl Segment common - USE : chỉ máy tính 32 bit trở lên use16 → ASM 16 bit (default) use32 → ASM 32 bit - ‘CLASS’ Chức năng: cho phép gộp các segment có cùng lớp lại gần nhau khi liên kết 38
  39. Cách khai báo 3 segment của chương trình Dạng chuẩnDạng đơn giản stack segment db 100h dup (?) ← .stack 100h Data segment .DATA Khai báo biến Khai báo biến Chú ý: mov ax, data chú ý: mov ax, @data code segment .CODE Nhan CT: Nhan CT: Code ends ENDS Nhan CT ENDS Nhan CT b) Directive GROUP Chức năng: gộp các segment cùng loại cho dễ dàng qui chiếu. Cú pháp: tên nhóm GROUP tên các segment Khai báo các segment Giải thích: Data1 segment Ml db ? 39
  40. Data1 ends Data2 segment M2 dw ? Data2 ends Code segment PS: mov ax, data1 mov ds,ax mov cl, Ml mov ax, data2 mov ds,ax mov cl, M2 Ta làm group như sau: Nhom_DL GROUP datal,data2 Data1 segment M1 db ? Data1 ends Data2 segment M2 dw ? Data2 ends Code segment PS: mov ax, nhom_DL mov cl, M 1 mov dx,M2 c) Dircctive ASSUME Chức năng: cho biết segment khai báo thuộc loại segment nào Cú pháp: 40
  41. assume tên thanh ghi segment : tên segment Giải thích assume cs:x3, ds:x2,ss:xl Chú ý: assume thường là dòng đầu của code segment Dạng chương trình ASM đơn giản (dạng chuẩn) Stack segment db 100h dup (?) Stack ends Data segment Khai báo biến Data ends Code segment Assume cs:code, ds:data, ss:_stack Nhan CT: mov ax, data2 mov ds,ax mov ah, 4ch int 21h code ends END Nhan CT Bài tập: Hiện xâu kí tự '$" 41
  42. Stack segment db 100h dup (?) Stack ends Data segment M db 'Hello, World!$' Data ends Code segment Assume cs:code, ds:data, ss:_stack PS: mov ax, data mov ds,ax lea dx, M mov ah, 9 int 21h mov ah, 1 int 21h mov ah, 4ch int 21h code ends END PS 1.5.3.3. Các directive hay dùng khác (PTR, EQU, LABEL, SEG, OFFSET, DUP, FAR, NEAR, ARG, COMMENT, ) a) Directive OFFSET Chức năng: báo cho chương trình dịch của ASM lấy phần địa chỉ offset của biến nhớ Cú pháp: OFFSET mem ; phần địa chỉ offset Ví dụ: .DATA Value dw ? 42
  43. mov bx, OFFSET Value yy ≡ lea bx, value b) Directive SEG Chức năng: báo cho chương trình dịch của ASM lấy phần địa chỉ segment của biến nhớ. Cú pháp: SEG mem Ví dụ: mov ax, SEG value xx c) Directive PTR Chức năng: con trỏ đến các thành phần của biến nhớ (cho phép lấy từng byte). Cú pháp: Kiểu PTR [thanh ghi] Ví dụ: .DATA Value dw ? .CODE 1.6. Chương trình con 1.6.1. Ý nghĩa của chương trình con - Làm cho chương trình có cấu trúc. - Tiết kiệm vùng nhớ. 43
  44. 1.6.2. Cơ chế khi một chương trình con bị gọi Cơ chế có 5 bướC: - Bước 1 : Tham số thực đưa vào stack - Bước 2: Địa chỉ lệnh tiếp theo đưa vào stack - Bước 3 : Hệ điều hành biết được địa chỉ đầu của chương trình con. Do vậy hệ điều hành đưa địa chỉ đầu của chương trình con vào CS:IP → rẽ nhánh vào chương trình con. - Bước 4 : Thực hiện chương trình con cho đến khi gặp re tum thì vào stack lấy địa chỉ lệnh tiếp theo (đã cất ở bước 2 để đưa vào CS:IP) và quay về chương trình đã gọi nó. - Bước 5 : tiếp tục chương trình đang thực hiện dở. 1.6.3. Cú pháp một chương trình con ASM Tên chương trình con PROC [near/far] Bảo vệ các thanh ghi mà thân chương trình con phá vỡ. Các lệnh ASM của thân chương trình con. Hồi phục các thanh ghi mà thân chương trình con đã phá vỡ. RET Tên chương trình con ENDP Nhận xét 1. Chương trình con thuần tuý ASM không có đối. 2.Vấn đề near/ far - Chương trình con là nêm khi mã máy của chương trình con và mã máy của chương trình chính là cùng nằm trong 1 segment, địa chỉ của chương trình con và chương trình chỉ khác nhau phần địa chỉ offset. Cho nên địa chỉ lệnh tiếp theo cất vào stack (Bước 2, mục l.6.2) chỉ cần 2 byte offset. - Chương trình con là far khi mã máy của chương trình con và mã máy của chương trình chính nằm trên các segment khác nhau, địa chỉ của chương trình con và chương trình chính khác nhau cả về phần địa chỉ segment. Cho nên địa chỉ lệnh tiếp 44
  45. theo cất vào stack (Bước 2, mục l.6.2) phải cần 4 byte offset (2 byte segment và 2 byte offset). Default: - Với chương trình được khai báo directive dạng đơn giản thì directive MODEL sẽ cho biết chương trình con là near hay far Nếu .MODEL tiny/small/compact thì chương trình con là NEAR(mã máy 64k) - Với chương trình con được viết theo directive dạng chuẩn thì mặc định là near. Còn muốn chương trình con là far thì phải viết far khi viết chương trình con. 3. Vấn đề cần bảo vệ thanh ghi và phục hồi các thanh ghi trong thân chương trình con. Ví dụ: Chương trình chính Chương trình con ⎯→ push ax Mov ax, 10 call chương trình con mov cx,ax . xor ax, ax ←⎯ pop ax RET Bảo vệ và hồi phục các thanh ghi và thân chương trình con phá vỡ tốt nhất bằng cơ chế PUSH và POP. Ví dụ 1: Hãy viết chương trình con ASM cho phép nhận một.số nguyên (- 32768 ~ l2767) từ bàn phím kết thúc nhận một số nguyên bằng phím Enter (13 = 0dh). Kết quả nằm trong thanh ghi ax. Chú ý không cho phép đánh sai và sửa. a) Nhận số nguyên dương Dùng hàm nhận kí tự mov an, 1 int 21h Suy ra al chứa mã ASCII của kí tự. al - 30h: thành mã ASCII chuyển thành số - Số vừa đưa vào sẽ cộng phần số đã cất vào trước *10 45
  46. b) Nhận một số nguyên âm Có 1 biến cờ dấu: 0 là số dương, 1 là sô âm. Nếu phát hiện kí tự đầu là dấu âm thì biến cờ dấu sẽ bằng 1 . Nhận một số nguyên dương sau đó hỏi biến cờ dấu. Nếu cờ dấu = 1 thì chuyển sang số bù 2 để đổi dấu. VAO_SO_N PROC push bx cx dx, si mov bx, 10 xor cx, cx; cx = 0 cx = phần số đã vào trước mov si, cx; SI = biến cờ dấu VSN1 : mov ah, 1 int 21h cmp al, 13; Enter? je VSN3 cmp al, ‘_‘ jne VSN2 inc si jmp VSN1 VSN2 : sub al, 30h xor ah, ah exchg ax, cx; Đổi chỗ số vừa vào và số đã vào trước mul bx add cx, ax jmp VSN 1 VSN3: and si,si jz VSN4 neg cx VSN4: 46
  47. Mov ax, cx pop SI dx cx bx VAO_SO_N ENDP Ví dụ 2: Viết chương trình con hiện nội dung có trong AX ra ngoài màn hình dạng cơ số 10 Thuật toán: a) AX chứa số nguyên dương vòng loop X: pop ax Mov an, 0ch int 10h loop X b) AX chứa số âm Kiểm tra hiện AX ≤ 0 - Nếu AX ≤ 0 hiện dấu ra màn hình sau đó đổi dấu AX rồi hiện như một số nguyên dương sau dấu trừ. - chương trình HIEN_SO_N PROC push ax bx cx dx mov bx, 10 xor cx, cx and ax, ax 47
  48. jns HSNI push ax mov al, ‘_’ mov ah, 0eh int 21h pop ax neg ax HSN1: xor dx, dx div bx add dx 30h push dx inc cx and ax, ax jnz HSNI HSN2: pop ax mov ah,0eh int 10h loop HSN2 pop dx cx bx ax ret HIEN_SO_N END 1.7. MACRO 1.7.1. Ý nghĩa Cho phép người lập trình ASM tạo lập 1 lệnh ASM mới, trên cơ sở tập lệnh chuẩn của ASM. 1.7.2. Khai báo (xác lập) MACRO Cú pháp: Tên Macro Macro [đối] Bảo vệ các thanh ghi mà thân Macro phá vỡ 48
  49. Các lệnh ASM trong thân Macro Hồi phục các thanh ghi mà thân Macro đã phá vỡ ENDM Ví dụ: Hãy khai báo 1 Macro tạo 1 lệnh mới cho phép xoá toàn bộ màn hình Cơ chế màn hình ở chế độ text, mỗi lần đặt mode cho màn hình thì màn hình sẽ bị xoá và con trỏ đứng ở góc trên bên trái. Set mode: mov al, số mode mov ah,0 int 10h Get mode mov ah, 0fh int 10h Clrscr MACRO push ax mov an, 0fh; get mode int 10h mov ah,0 iin 10h; set mode pop ax ENDM Ví dụ 2: Khai báo 1 Macro cho phép hiện 1 xâu lên màn hình Hienstring MACRO push ax dx lea dx, xau mov ah,9 int 21h pop dx ax ENDM 49
  50. 1.7.3 Cách dùng MACRO đã được xác lập Sau khi 1 Macro đã được khai báo thì tên Macro được tạo thành 1 lệnh mới của ASM. Sử dụng bằng cách viết tên Macro và thay tham số thực cho đối. Chú ý: Cơ chế của chương trình dịch khi gặp lệnh mới ⏐ Clrscr ⏐ Hienstring M1 - Điều gì xẩy ra nếu có lệnh nhảy trong Macro? Phải dùng Directive LOCAL Ví dụ: 1.8. Directive INCLUDE 1.8.1. Ý nghĩa - Cho phép chèn khối lệnh nằm ở 1 tệp ngoài chương trình đang viết 1.8.2 Cú pháp chèn include ổ đĩa:\đường dẫn\ tên tệp.đuôi 1.8.3. Cơ chế khi chương trình dịch TASMGẶP directive INCLUDE ⏐ include ổ đĩa:\đường dẫn\ tên tệp.đuôi ⏐ Các bước thực hiện B1: tìm tệp đứng sau directive INCLUDE 50
  51. B2: Mở tệp đó. B3 : Chèn khối lệnh vào directive INCLUDE B4: Dịch khối lệnh đó B5: Đóng tệp Chú ý: Nếu dùng directive INCLUDE với 1 tệp 2 lần trở lên thì không cho phép dùng lệnh nhảy trong đó. Dạng thường thấy 1 chương trình ASM phức tạp (Khai báo MACRO, STRUC, UNION ) Các Directive điều khiển segment Dạng đơn giản Dạng chuẩn .MODEL small stack segment .STACK 100h db 100h .DATA ; Khai báo biến Stack ends .CODE Data segment Nhãn CT: Khai báo biến [mov ax, @data Data ends mov ds, ax] Code segment ⏐ Assume cs:code, ds:data, ss:stack Thân CT chính Nhãn CT: ⏐ [mov ax, data mov ah, 4ch mov ds, ax] int 21h ⏐ [Các CT con] Thân CT chính END Nhãn CT ⏐ mov ah, 4ch int 21h [ Các CT con] code ends END Nhãn CT Giả thiết: lib1.asm Clrscr hiện string lib2.asm 51
  52. VAO_SO_N PROC RET VAO_SO_N END HIEN_SO_N PROC RET HIEN_SO_N ENDP BÀI TẬP Bài l: So sánh 2 số nguyên và hiện số có giá trị bé lên màn hình. Khi chạy chương trình yêu cầu có dang: - Xoá màn hình. Hay vao so thu nhat: -152↵ Hay vao so thu hai : 31↵ So be la: -152↵ Hướng dẫn: Tạo file C:\BT>edit sosanh.asm Include libl.asm .MODEL small .STACK 100h .DATA M1 db 13, 10, 'Hay vao so thu nhat : $ ' M2 db 13, 10, 'Hay vao so thu hai : $ ' M3 db 13,10, ' So be la: $' M4 db 13,10, 'Co tiep tuc CT (C/K): $' .CODE PS: mov ax, @data mov ds, ax clrscr Hienstring M1 call VAO_SO_N 52
  53. mov bx, ax Hienstring M2 call VAO_SO_N Hienstring M3 cmp ax, bx jl Ll xchg ax, bx Ll: call Hien_so_N Hienstring M4 mov ah, 1 int 21h cmp al , ‘c’ jne exit jmp PS Exit: mov ah,4ch int 21h Inculde lib2.asm END PS Bài 2: Tính n! (0 - 7) Chi chương trình chạy yêu cầu: - Xoá màn hình Hay vao so n: 7↵. Giai thua cua 7 la: 5040↵ Co tiep tuc CT (C/K)? C:\BT>edit gth.asm↵ Include lib1.asm Stack segment 53
  54. db 100h dup(?) Stack ends Data segment Ml db 13,10, 'Hay vao so n: $' M2 db 13,10, 'Giai thua cua 9 $' M3 db 13,10, ' 9 la: $' M4 db 13,10, 'Co tiep tuc CT (C/K): $' FV dw ? FAC dw ? Data ends Code segment Assume cs:code, ds:data, ss:stack PS: mov ax, data mov ds, ax clrscr Hienstring Ml call VAO_SO_N Hienstring M2 call VAO_SO_N Hienstring M3 mov FV, 1 mov FAC, 2 mov cx, ax cmp cx, 2 jb Ll dec cx Ll: mov ax, FV mul FAC 54
  55. mov FV, ax inc FAC loop L2 L2: mov ax, FV call HIEN_SO_N Hienstring M4 mov ah, 1 int 21h jmp al, 'c' jne Exit jmp PS Exit: mov ah,4ch int 21h Include lib2.asm Code ends END PS Bài 3: an (a là số nguyên, n là số nguyên dương) Khi chương trình chạy yêu cầu có dạng - Xoá màn hình Hay vao a: - 4 ↵ Hay vao n: 3 ↵ -4 luy thua 3 là: -64 C:\BT>edit lt.asm. Include libl.asm .MODEL small .STACK 100h .DATA Ml db 13,10, 'Hay vao a: $' 55
  56. M2 db 13,10,' Hay vao n: $' . Crlf db 13, 10, '$' M3 db ' 9 luy thua 9 : $ ' M4 db ' 9 la : $' M5 db 13, 10, ' Co tiep tuc CT (C/K): $ . CODE PS: mov ax, @data mov ds, ax clrscr Hienstring M 1 call VAO_SO_N mov cx, ax; cx = n Hienstring Crlf mov ax, bx call HIEN_SO_N Hienstring M3 mov ax, bx call HIEN_SO_N Hienstring M4 mov ax, 1 and cx, ax jz Ll Ll: mul ax; ax*bx để vào ax loop L2 L2: call HIEN_SO_N Hienstring M5 mov ah, 1 int 21h 56
  57. cmp al, 'c' jne Exit jmp PS Exit: mov ah,4ch int 21h Include lib2.asm END PS Bài 4: trung bình cộng các số nguyên Khi chương trình chạy yêu cầu có dạng: Hay vao so thu nhat: - 12↵ Hay vao so thu hai: - 15↵ TBC hai so la: - 13,5↵ C:\BT>edit tbc.asm Include lib1. asm _Stack segment db 100h dup(?) _Stack ends Data segment Ml db 13, 10, 'Hay vao so thu that: $' M2 db 13, 10 , 'H ay vao so thu hai: $ ' M3 db 13, 10, ' TBC hai so la: $' M4 db ' 9 $' M5 db ' .5 $' M6 db 13, 10, 'Co tiep tuc CT (C/K): $' Data ends Code segment Assume cs:code, ds:data, ss:stack PS: Mov ax, data mov ds, ax 57
  58. clrscr Hienstring Ml call VAO_SO_N mov bx, ax Hienstring M2 call VAO_SO_N Hienstring M3 add ax, bx and ax, ax jns Ll Hienstring M4 neg ax; đổi dấu = lấy bù 2 Ll: shr ax, 1; dịch phải 1 lần pushf call HIEN_SO_N popf jnc L2 Hienstring M5 L2 : Hienstring M6 mov ah, 1 int 21h cmp al,'c' jne Exit jmp PS Exit: mov ah,4ch int 21h Include lib2.asm 58
  59. Code ends END PS Bài 5: Tính tổng 1 dãy số nguyên. Yêu cầu: - Nhập số lượng thành phần. - Nhận các số đưa vào mảng - Hiện các số vừa vào ra màn hình - Tính tổng. - Hiện kết quả Yêu cầu khi chơng trình chạy có dạng: Hay vao s1tp : 4 ↵ A[0] = 1 ↵ A[l] = 2 ↵ A[2] = 3 ↵ A [3] = 4 ↵ Day so vua vao la: 1 2 3 4 Co tiep tuc ct (C/K)? C:\BT>edit tong.asm INCLUDE lib1.asm .MODEL small .STACK looh .DATA M1 db 13, 10, ' Hay vao so luong thanh phan : $ ' M2 db 13,10, 'a [ $' M3 db ' 9 ] $' M4 db 13,10, ' Day so vua vao la : $' M5 db ' 99 $' M6 db 13, 10, ' Tong day la : $ ' M7 db 13, 10, ' Co tiep tuc CT (C/K): $ S1tp dw 59
  60. i dw a dw 100h dup(?); khai báo mảng .CODE PS: mov ax, @data mov ds, ax clrscr Hienstring M 1 call VAO_SO_N mov sltp,ax mov cx, ax lea bx, a; lấy phần địa chỉ offset a[0] đưa vào bx mov i, 0 L1: ; Nhập các số đưa vào mảng Hienstring M2 mov ax, i call HIEN_SO_N Hienstring M3 call VAO_SO_N mov [bx], ax inc i add bx, 2 ; tăng 2 lần bx tức + 2 vào bx loop L1 Hienstring M4 mov cx, s1tp lea bx, a ; bx trỏ vào a[0] L2 : ; lấy các số hiện lên màn hình mov ax, [bx] call HIEN_SO_N Hienstring M5 60
  61. add bx, 2 loop L2 Hienstring M6 Mov cx, s1tp lea bx, a xor ax, ax L3: add ax, [bx] add bx,2 loop L3 call HIEN_SO_N Hienstring M7 mov ah, 1 int 21h cmp al, 'c' jne Exit jmp PS Exit: mov ah,4ch int 21h Include lib2.asm END PS Bổ xung: Tính tổng dương, tổng âm L3: mov dx, [bx] and dx, dx js L4 ; jns add ax, dx L4: 61
  62. add bx, 2 loop L3 Tính tổng chẵn, tổng lẻ L3: mov dx, [bx] shr dx, 1 jc L4 ; inc add ax, [bx] L4 : add bx, 2 loop L3 Bài 6: Số nguyên tố C:\BT>edit snt.asm INCLUDE lib1.asm .MODEL small .STACK 100h .DATA M1 db 13, 10, ' Hay vao so gioi han : $ ' M2 db 13, 10, ' Cac so nguyen to vào tu 2 den 9 $ ' M3 db ' 9 la: $' M4 db ' 99 $' M5 db 13, 10, ‘ Co tiep tuc CT (C/K) : $’ so dw .CODE PS: mov ax, @data mov ds, ax clrscr Hienstring Ml call VAO_SO_N 62
  63. mov bx,ax ;bx = so gioi han Hienstring M2 call HIEN_SO_N Hienstring M3 mov i, 0 Ll: inc so mov ax, so cmp ax, bx ja KT ; so sánh đưa ra kết thúc mov cx,ax shr ax, 1 ;cx = so/2 L2: cmp cx, 2 jb HIEN xor dx, dx div cx and dx, dx jz Ll mov ax, so loop L2 HIEN Call HIEN_SO_N Hienstring M4 jmp Ll KT: Hienstring M5 Mov ah, 1 im 21h cmp al, 'c' 63
  64. jne Exit jmp PS Exit: mov ah,4ch im 21h Include lib2.asm END PS 1.9. Chương trình đa tệp 1.9.1. Ý nghĩa Cho phép nhiều người cùng tham gia viết 1 chương trình lớn. Làm sao các nhãn dùng chung(tên biến nhớ, tên chương trình con) phải hiểu nhau. Để giải quyết vấn đề này chương trình dịch ASM có trang bị hai directive đó là PUBLIC (cho phép) và EXTRN(xin phép) 1.9.2. Directive PUBLIC Chức năng: báo cho chương trình dịch ASM biết module(tệp) này cho phép các tệp khác được dùng những nhãn nào mà không cần xác lập lại. Cú pháp: PUBLIC Tên nhãn Xác lập nhãn - Nhãn là tên biến .DATA PUBLIC Tên biến Khai báo biến Ví dụ: .DATA PUBLIC x,y x db ? y dw ? - Nhãn là tên chương trình con .CODE PUBLIC Tên chương trình con 64
  65. Tên chương trình con PROC RET Tên chương trình con ENDP 1.9.3. Directive EXTRN Chức năng: báo cho chương trình dịch ASM biết tệp này xin phép dùng các nhãn mà các modul khác đã xác lập và cho phép. Cú pháp : EXTRN Tên nhãn: Kiểu - Với nhãn là biến nhớ .DATA EXTRN Tên biến: Kiểu PUBLIC BYTE db WORD dw DWORD dd Vi dụ: .DATA EXTRN X:BYTE, Y:WORD - Nhãn là tên chương trình con .CODE EXTRN Tên chương trình con:PROC Ví dụ: n! Anh A (gt1 .asm) n, FV, GT - Nhận n . PUBLIC, EXTRN, EXTRN - Gọi chương trình con tính n! (do B viết) - Hiện kểt quả Anh B (gt2.asm): Viết chương trình con tính n! n, FV, GT EXTRN, PUBLIC, PUBLIC . Viết CT C:\BT>edit gt1.asm Include lib1.asm 65
  66. .MODEL small .STACK 100h .DATA Ml db 13,10, ' Hay vao so n: $' M2 db 13, 10, ' Giai thua cua 9 $ ' M3 db , ' 9 la: $' M4 db 13,10, ' Co tiep tuc CT (C/K): $' PUBLIC n n dw ? EXTRN FV:Word .CODE EXTRN Factorial:PROC PS: mov ax, @data mov ds, ax clrscr Hienstring M1 call VAO_SO_N mov n, ax Hienstring M2 call HIEN_SO_N Hienstring M3 call Factorial mov ax, FV call Hien_so_N Hienstring M4 mov ah,l int 21h cmp al,'c' jne xit jmp PS 66
  67. Exit: mov ah,4ch int 21h Inculde lib2.asm END PS C:\BT>edit gt2.asm .MODEL small .DATA EXTRN n : Word PUBLIC FV dw ? FAC dw ? .CODE PUBLIC Factorial Factorial PROC mov FV, 1 mov FV,2 mov cx,n cmp cx, 2 jb L2 dec cx L1: mov ax, FV mul FAC mov FV, ax inc FAC loop L1 L2: ret Factorial ENDP 67
  68. END 1.9.4. Cách dịch và liên kết Bước 1: Dịch từng tệp .asm sang .obj VD : C :\B T>tasm gt1.asm ↵→ gt1.obj C:\BT>tasm gt2.asm ↵→ gt2.obj Bước 2: Gộp các tệp .obj thành 1 tệp .exe Cú pháp: tlink tep1 + tep2 + + tepn ↵→ tep1.exe VD: C:\BT>tlink gtl.asm + gt2.asm ↵→ gt1.exe Chú ý: Khi khai báo directive điều khiển segment dạng chuẩn cho chương trình đa tệp. Tepl.asm Tep2.asm Data segment PUBLIC Data segment PUBLIC PUBLIC n EXTRN n:Wod n dw ? Data ends Data ends 1.10. Biến hỗn hợp : Directive STRUC, RECORD và UNION 1.10.1. Cấu trúc STRUC Ý nghĩa: xác lập 1 kiểu khai báo trong đó các thành phần có thể khác kiểu nhau. Cú pháp - Xác lập kiểu khai báo mới Tên cấu trúc STRUC Các thành phần Tên cấu trúc ENDS Ví dụ: Person STRUC Name db 60 dup(?) Age db ? Income dw ? Person ENDS 68
  69. Khai báo biến vừa xác lập . Sau khi 1 cấu trúc được xác lập thì tên của cấu trúc trở thành 1 kiểu khai báo biến. .DATA US_president person x dw ? 1.10.2 Directive UNION Ý nghĩa: Xác lập 1 kiểu khai báo biến dùng chung vùng nhớ RAM. Giải thích .DATA x do ? y dw ? Sử dụng 1 phần hard dish để lưu lại giá trị của biến. 1.11. Xây dựng chương trình Assembly để được tệp thực hiện dạng .COM 1.11.1. Sự khác nhau chương trình dạng COM và EXE - Chương trình dạng .COM Tất cả code, data, stack đều nằm trong 1 segment - Chương trình dạng .EXE Code, data, stack nằm trên các segment khác nhau. 1.11.2. Làm thế nào để có được chương trình dạng .COM - TỪ DOS Ver5.O trở về trướC: Có 1 chương trình EXE2BIN.EXE dùng để chuyển 1 tệp EXE sang >COM - Từ DOS Ver6.0đến các phiên bản sau này: không có tệp EXE2BIN.EXE nên phải viết chương trình ASM có dạng đặc biệt để sau khi dịch, liên kết để chuyển sang .COM 1.11.3. Các vấn đề cần lưu ý - Directive ORG 100h IP Code segment 69
  70. - Khai báo biến Với chương trình dạng .COM chỉ có 1 segment và đó là code segment. Vậy khai báo biến ở đâu? Khai báo biến ở code segment và được tiến hành như sau: .CODE Nhãn Chương trình [jmp Nhãn khác Khai báo biến Nhãn khác] - Trở về DOS ( EXE + .COM) (.COM) mov ah, 4ch int 20h int 21h 1.11.4. Dạng thường thấy 1 chương trình ASM để được dạng COM (Khai báo Macro, Struc, Union) Các Directive điều khiển segment Dạng đơn giản Dạng chuẩn .MODEL tiny code segment .CODE ORG 100h ORG 100h Assume cs:code, ds:code, ss:code Nhãn CT: Nhãn CT: [jmp Nhãn khác [jmp Nhãn khác Khai báo biến Khai báo biến Nhãn, khác] Nhãn khác] ⏐ ⏐ Thân CT chính Thân CT chính ⏐ ⏐ Int 20h Int 20h [ Các CT con] [ Các CT con END Nhãn CT code ends END Nhãn CT Chú ý : khi dịch ta dùng lệnh tlink/t để dịch sang dạng .COM Bài tập Bài 1: Chia 2 số nguyên trong đó số bị chia là số nguyên, số chia là nguyên dương. 70
  71. vao so bi chia:↵ Vao so chia:↵ Thuong là:↵ Co tiep tuc CT (C/K)? C:\BT>edit chia.asm INCLUDE lib1.asm .MODEL small .STACK l00h .DATA Ml db 13,10, ' Hay vao so bị chia: $' M2 db 13,10, ' Hay vao so chia: $ ' M3 db 13,10, ' Thuong la : $ ' M4 db ‘ 9 : $’ M5 db ' $' M6 db 13,10, ' Co tiep tuc CT (C/K): $' .CODE PS: mov ax, @data mov ds, ax clrscr Hienstring Ml mov bx,ax ;bx = so gioi han Hienstring M2 call VAO_SO_N xchg ax, bx Hienstring M3 and ax, ax ; kiểm tra có phải là số ân hay ko? jns Ll Hienstring M4 Neg dx Ll: 71
  72. xor dx, ax div bx call HIEN_SO_N and dx, dx jz KT Hienstring M5 mov cx, 2 mov si, 10 mov ax, dx L2: mov ax, dx div dx call HIEN_SO_N and dx, dx jz KT loop L2 KT: Hienstring M5 mov ah, 1 int 21h cmp a1,'c' jne Exit jmp PS Exit: mov ah,4ch int 21h Inculde lib2.asm END PS Dạng .COM C:\BT>edit chiacom.asm 72
  73. Include lib1.asm .MODEL tiny .Code org 100h PS: Jmp Start M1 db 13,10, ' Hay vao so bị chia: $ ' M2 db 13,10, ' Hay vao so chia: $' M3 db 13,10, ' Thuong la : $ ' M4 db ' 9 : $' M5 db ' $ ' M6 db 13,10, ' Co tiep tuc CT (C/K): $' Start: Clrscr Hienstrtng M1 mov bx,ax ;bx = so gioi han Hienstring M2 Call VA O_SO_N Xchg ax, bx Hienstring M3 and ax, ax ; kiểm tra cóphải là số ân hay ko? jnsL1 Hienstring M4 Neg dx L1: xor dx, ax div bx call HIEN_SO_N and dx, dx jz KT 73
  74. Hienstring M5 mov cx, 2 mov si, 10 L2: mov ax, dx div dx call HIEN_SO_N and dx, dx jz KT loop L2 KT: Hienstring M5 mov ah,1 int 21h cmp al, 'c ' jne exit jmp PS Exit: int 20h Include lib2.asm END PS n n Bài 2: Tính tổng ∑∑− i = i i==11i Khi chạy chương trình yêu cầu: Nhap so n: 5 ↵ Tong so tu -l đen -5 la: ↵ Co tiep tuc chuong trinh (C /K)? C:\BT>edit sum.asm Dạng .EXE INCLUDE libl.asm 74
  75. Stack segment Db 100h dup(?) Stack ends Data segment Ml db 13,10, ' Nhap so n: $' M2 db 13,10, ' Tong tu - 1 den - : $ ' M3 db ‘ 9 la : $' M4 db 13,10, ' Co tiep tuc CT (C/K): $' Data ends Code segment Assume cs:code, ds: data, ss: stack PS: mov ax, data mov ds, ax clrscr Hienstring Ml call VAO_SO_N Hienstring M2 call HIEN_SO_N Hienstring M3 mov cx,ax dec cx L1: add ax, cx loop L1 reg ax call HIEN_SO_N Hienstring M4 mov ah, 1 int 21h 75
  76. cmp al, 'c' jne Exit jmp PS Exit: mov ah,4ch int 21h Inculde lib2.asm Code end END PS Dạng >COM C:\BT>edit sumcom.asm Inclụde libl.asm .MODEL tiny .Code segment org 100h assume cs:code, ds: data, ss: stack PS: Jmp Start Ml db 13,10, ' Nhap so n: $' M2 db 13,10, ' Tong tu - 1 den - : $ ' M3 db ‘ 9 la : $’ M4 db 13,10, ' Co tiep tuc CT (C/K): $' Start: clrscr Hienstring Ml call VAO_SO_N Hienstring M2 can HIEN_SO_N Hienstring M3 mov cx,ax 76
  77. dec cx L1: add ax, cx loop L1 reg ax call HIEN_SO_N Hienstring M4 mov ah, 1 int 21h cmp a1, 'c' jne Exit jmp PS Exit: int 20h Include lib2.asm Code ends END PS Chú ý: dùng tlink/t Một số lưu ý khi sử dụng thanh ghi thay cho biến nhớ - Nguyên tắc chung: cố gắng sử dụng thanh ghi thay cho biến nhớ trong trường hợp có thể, chương trình sẽ chạy nhanh hơn. - Các loại biến: biến xâu và biến trường sồ (không được dùng thanh ghi), biến số (dd, dw) dùng thanh ghi được (dd, dp, dt: không dùng). - Các thanh ghi có thể dùng thay miến nhớ AX(ah, al), CX, BX, SI, DI, BP. - Các thanh ghi không được phép thay biến nhớ: CS, DS, SS, IP, SP, FLAG - Thanh ghi AX: có thể đứng làm toán hạng cho hầu hết các lệnh ASM. Ngoại lệ làm toán hạng ẩn trong các lệnh MUL/IMUL và DIV/IDIV. Ví dụ: mul bx ; ax*bx → dx: ax Trong các lệnh IN/OUT chỉ có al có thể thực hiện hai lệnh này, không có thanh ghi nào thay thế được. 77
  78. IN al, địa chỉ cổng OUT địa chỉ cổng, al/ax - Thanh ghi BX giống như AX ngoại trừ Người lập trình có thể dùng bx làm con trỏ offset (SI/DI) Ví dụ: lea bx,a - Thanh ghi CX : chỉ số của lệnh loop, trong các lệnh dịch, quay với số lần lớn hơn hoặc bằng 2. sar ax,4 ≡ mov cl/cx, 4 sar ax, cl/cx - Thanh ghi DX Ngoại lệ: Toán hạng ẩn mul/imul và div/idiv, địa chỉ cổng khi ≥ 256 Ví dụ: địa chỉ cổng COM1 là 378h I N AL 378h ≡ mov dx,378h in all/ax - Thanh ghi SI,DI Ngoại lệ: Là con trỏ offset trong các lệnh làm việc với xâu. Người lập trình ASM có thể dùng SI, DI làm địa chỉ offset của biến nhớ - Thanh ghi BP Ngoại lệ: làm con trỏ offset của stack khi liên kết ngôn ngữ bậc cao với ASM khi hàm có đối. 78