ก่อนอื่นต้องขอสวัดดีและทักทายก่อนนะครับ กระทู้นี้เปนกระทู้แรกของผมเลยจะเป็นการแนะนำการเขียนโปรแกรมโดยใช้ภาษา assembly นะครับ เปนพื้นฐานสำหรับคนที่ยังไม่เคยเขียนหรือเคยเขียนแล้วแต่ยังไม่ค่อยเข้าใจ
ส่วนการเขียนในระดับขั้นสูง จะนำเสนอต่อๆไปครับ
เอาล่ะมาว่ากันเลยดีกว่า ภาษา แอสเซ็มบลีนี้จัดเป็นภาษาระดับต่ำครับ ถ้าเทียบกับภาษาระดับสูงเช่น c++,java อะไรพวกนี้ ภาษา assembly จะใช้เวลาในการทำงานของเครื่องน้อยกว่านะครับ เน้นว่าเวลาในการทำงานของเครื่อง
ไม่ใช่เวลาในการเขียนโคตของคนนะจ๊ะ เรามาดูตัวอย่างโปรแกรมเทียบกันเลยดีกว่าเพื่อความเข้าใจมากขี้น
hello world ใน c++ เขียนได้ดังนี้
#include <iostream>
using name space std;
void main()
{
cout<<"hello world";
}
แค่เนี้ยเองครับ สำหรับภาษาระดับสูง
ต่อไปเรามาดู assembly ของเรากานดีกว่า อิอิอิ
.model small
.stack 100h
.data
msg db 'hello world $'
.code
main proc
mov ax,@data
mov ds,ax
lea dx,msg
mov ah,9
int 21h
mov ah,4ch
int 21h
endp
end main
ครับนี่แหละครับ สำหรับ hello world ใน assembly ท่านจะเห็นว่าเห้ย แล้วในเมื่อมันยาวกว่าภาษาระดับสูง แล้วเอ็งจะเขียนไปทำ...ไรล่ะครับ อืมนั่นน่ะสินะ ฮืม โดยตัวภาษาแล้วนะครับ assembly จะเอาไว้เขียนติดต่อ
กับพวก hardware โดยตรงน่ะครับ สำหรับใครที่เรียนสาย hardware ก็น่าจะศึกษาไว้นะจ๊ะ รู้ไ้ว้ดีกว่าไม่รู้นี่ครับ ยิ้ม
เอาล่ะ ถ้าท่านพร้อมแล้วนะครับ เชิญมาศึกษาต่อไปเลยครับ ผมจะว่ายาวละนะ รูดซิบปากอิอิ
ว่าด้วย ทฤษฎี ที่อิงคนเขียนเปนใหญ่ไม่อิงวิชาการ
อย่างแรกเลยผมอยากให้รู้จักกับ register ครับ register ก็เปนเหมือนหน่วยความจำอะครับ ให้ท่านเข้าใจว่ามันคือ register ไปก่อนละกัน register โดยการเขียนพื้นฐานเราจะใช้ ระดับ 8 บิต กับ 16 บิตครับ
[hide=5]register ขนาด 8 bit มีดังนี้ ah,al,bh,bl,ch,cl,dh,dl hแทน hight l แทน low นะครับ
register ขนาด 16 bit ก็มีดังนี้ ax,bx,cx,dx,bp,si,di ถึงตรงนี้ท่านอาจจะสังเกตเอ๊ะ ax มันเกี่ยวกะ ah กับ al รึเปล่า โป๊ะเช๊ะครับท่านมาถูกทางแล้ว อย่างที่ผมบอกไว้ h แทนบิตสูง l แทนบิตต่ำ
ในเมื่อ ax มี 16 บิต ดังนั้น ax จึงประกอบไปด้วย ah 8 bit และ al 8 bit ที่มาก็มาด้วยประการฉะนี้แล ตกใจ อึ้งไปเลยล่ะสิ รูดซิบปาก
ลืมบอกไปนะครับไอ้ 8 บิต 16 บิตเนี่ย เราใช้เลขฐานสองแทนนะครับ คือมันจะประกอบไปด้วย 0 กะ 1 นะจ๊ะ
ตัวอย่างเพื่อช่วยให้ความเข้าใจเพิ่มมากขี้นครับ แลบลิ้น
สมมุต ผมมีค่าใน bh=00100010 bl=00111100 ค่าใน bx ผมก็จะเปน 0010001000111100
โฮะๆ คงจะเข้าใจกันแล้วนะครับ
ต่อไปเราจะว่าด้วยคำสั่งที่ใช้ในการดำเนินการครับ มันเรียกว่า opcode ภ้าเรียกให้ดูดีหน่อยก็เปน operation code แลบลิ้น opcode ตัวแรกที่ท่านควรจะรู้จักคือ mov ครับ
ว่าด้วยคำสั่ง mov
สมมุต ตอนแรก ใน bx ผมเก็บข้อมูล 4c00h ไว้ เพิ่มเติมนะครับ 4c00h คือเลขฐานสิบหก ไอ้ตัว h ที่อยู่หลังสุดอะมันย่อมาจาก hex decimal แปลเป็นไทยก็คือ เลข ฐานสิบหกนั่นเอง ขอรับ ซึ่งสามารถแปลงเป็นเลขฐานสองได้คือ 0100 1100 0000 0000 คือวิธีง่ายๆในการเปลี่ยนเลขฐานสิบหกเป็นเลขฐานสอง ก็ให้ท่าน ดูข้อมูลฐานสิบหกทีละตัวครับแล้วแต่ละตัวของฐานสิบหกจับมันแยกเปนฐานสอง 4 ตัวเช่น 4=0100 c=1100 เหนไหมครับ
เอาละนอกเรื่องไปไกลมา mov กานดีกว่านะ ให้ bx ผมเก็บ 4c00h นะครับ
mov bx,4c00h ; เนี่ยแหละครับเป็นการย้าย 4c00h ไปเก็บใน bx คือมันจะย้ายจากด้านขวาไปทางด้านซ้ายอะครับ ส่วนไอ้เจ้าเครื่องหมาย ; ก็เปนเครื่องหมาย comment อะครับ คล้าย // ใน c++
mov ax,32 ; เก็บค่า 32 ใน ax ครับซึ่งมันจะแปลงเปนเลขฐานสิบหกเกบไว้ถ้าทั่นใช้โปรแกรมตรวจสอบดูจะเหนว่า ax มันเกบ 20 h อะครับ
mov bx,ax ;เอาข้อมูลจาก ax มาเกบใน bx ครับ และข้อมูลในax ก็ยังคงเดิมไม่เปลี่ยนแปลงใดใดทั้ง สิ้น คล้ายๆกับการ copy เลยครับ
พอจบโปรแกรม แล้ว bxจะเกบค่า ที่axเก็บครับนั่นก็คือ 32 ฐานสิบหรือ 20h ส่วน ax ก็จะเก็บค่า 32 เหมือนเดิมครับ เพราะมันก๊อบตัวเองไปให้ bx แต่ตัวมันเองก็ไม่เปลี่ยนแปลงใดใดทั้งสิ้น
*********ลักษณะของภาษา assembly*****
------ เป็นภาษาที่จะทำงานทีละบรรทัดจนจบโปรแกรม มันจะไล่ไปเรื่อยๆเลยครับ
------ เป็นภาษาที่ไม่แยกแยะตัวใหญ่ตัวเล็กครับ เช่น MOV AX,BX ให้ผลลัพเหมือนกับ mov ax,bx ทุกประการ
------ เครื่องหมาย ; มีไว้เพื่อ commentข้อความ
------- ถ้าท่านศึกษาไปเรื่อยๆจะเจอ interrupt มันก็เปนพวก int 10h int 21 h อะไรประมาณนี้ พวกอินเทอรัพจะเป็นคำสั่งที่ใช้ในการดำเนินการข้อมูลให้เห็นผลลัพครับ เช่น เราต้องการแสดงตัวเองษรบนจอภาพเราก็ต้อง
เรียก int 21h ตอนนี้อาจจะงงอยู่ แต่ถ้าดูไปเรื่อยๆก็จะกระจ่างขี้นเรื่อยๆครับ
------ เขียน assembly เยอะๆจะทำให้การพิมของทั่นเร็วขี้นเพราะกว่าจะเขียนให้มันออกมาได้ทีละอย่างเหนื่อยครับ แลบลิ้น
assembly เนี่ยมันจะประกอบไปด้วย segment ถ้าจะให้แปลเปนไทยก็น่าจะเปนส่วนของโปรแกรมมั้งครับ ซึ่งประกอบไปด้วย segment หลักๆ 4 ส่วนด้วยกันดังนี้
1. stack segment (SS) 2.data segment (DS) 3.extra segment (ES) 4.code segment (CS)
เรามาดูโครงสร้างแบบเต็มของ assembly กันครับ มันมีโครงสร้างแบบย่อด้วยนะ อิอิ ยิ้ม ยิ้ม
เราไม่สามารถใช้คำสั่ง mov ระหว่าง segment ได้นะครับ เช่น mov ds,cs อันนี้ใช้ไม่ได้ครับ
; skeleton
stsm segment ; ส่้วนนี้เป็นการประกาศ stack segment ครับ เราประกาศมันไว้เพื่อใช้ opcode push,pop น่ะครับ ทั่นจะเห็นว่าผมเขียน stsm ซึ่งท่านสามารถแปลงเป็นชื่ออื่นก็ได้นะครับตามความเข้าใจ
; เช่น stackseg segment จำไว้ว่าประกาศ segment รูปแบบเปนดัง นี้ namesegment segment แล้วมันจะปิดด้วย ends ซึ่งก็คือจบเซ็กเมนนั่นเองขอรับ
ends
dtsm segment
msg db 'hello world $ ' ;data segment ส่วนเนี้ยจะเอาไว้ประกาศตัวแปลอะครับ msg คือชื่อตัวแปล db= difine byte คือให้มันเก็บได้ 1 byte แล้วก็ตามด้วยข้อความที่เราต้องการ
ends ; โดยข้อความต้อง ใช้เครื่องหมาย $ ปิดเสมอ เพื่อจะเอามันไปใช้แสดงผลได้
cdsm segment ; ส่วนของโคตเซ็กเม็นท์ครับ ฃื่อก็บอกแล้วมันเป็นที่ๆเราเอาไว้ใช้ในการเขียนโคตนั่นเอง
assume cs:cdsm,ss:stsm,ds:dtsm ; assume เ้ป็นคำสั่งที่ใช้บอกว่า เออ ไอ้เจ้า cdsm เนี่ยมันคือ cs นะ cs ก็คือ โคตเซ็กเม็นท์ไงครับ dtsm ก็คือ data segment นั่นเอง เพราะโปรแกรมไม่รู้หรอกครับ
main proc ;ว่าไอ้ที่เราประกาศ segment อะมันคือsegment อะไร ดังนั้นเราจึงต้องจำเป็นต้อง assume ค่าให้มันนั่นเอง ; main proc คือฟังชันเมน ครับ
mov ax,dtsm ;การที่เราจะดึงเอาข้อมูลจาก data segment มาใช้เราต้องย้ายผ่าน register ครับ ในที่นี้เราไม่สามารถใช้คำสั่ง mov ds,dtsm ได้โดยตรง เราจึงใช้ ax มาเป็นตัวช่วย
mov ds,ax ; ท่านอาจจะถามว่าแล้วจะย้ายทำไม เราย้ายเพื่่อจะดึงเอาข้อมูล หรือ ตัวแปล จาก data segment มาใช้น่ะครับ
lea dx,msg ; lea เป็น opcode ตัวนึง มาจาก load effective address เป็นการโหลด ค่า msg ไปเก็บใน dx น่ะครับ ใช้ร่วมกับ ฟังชัน 09 เพื่อ แสดงผล สตริง
mov ah,09 ; ให้ค่า ah เป็น 9 เพื่อใช้งานคำสั่งในการ print string
int 21h ; เรียก interrupt 21 h เพื่อทำการ print string ออกมาทางจอภาพ
mov ah,4ch ; เรียกคำสั่งในการออกจากดอส
int 21h ; ดำเนินคำสั่งออกจากดอส
endp ; จบฟังชัน
ends ; จบ code segment
end main ; จบโปรแกรม
ก็จบไปแล้วนะครับสำหรับการเขียนแบบเต็ม บางคนอาจจะบอกว่าเห้ยยุ่งยากจัง งั้นเรามาดู hello world แบบย่อกันดีกว่า
โครงสร้างมันก็เปนแบบนี้ครับ
.model small ;เป็นขนาดของหน่วยความจำอะครับ เราสามารถกำหนดให้ เป็น tiny small medium compact large ไม่ต้องไปซีเรียสกะส่วนนี้มากเอา small ไปแหละ
.stack 100h ;ประกาศ stack segment ให้มีที่ว่าง 100 byte เอาไว้ใช้ พวก push,pop อะครับ
.data ;ส่วนนี้ก็เปน data segment เอาไว้ประกาศตัวแปรครับ
.code ; code segment ครับ
.model small
.stack 100h
.data
msg db 'hello world $'
.code
main proc
mov ax,@data
mov ds,ax
lea dx,msg
mov ah,9
int 21h
mov ah,4ch
int 21h
endp
end main
จะเห็นว่าการเขียนแบบย่อดูง่ายกว่านะครับ ก็แล้วแต่ใครชอบแบบไหนครับ ส่วนผมชอบแบบย่อ ยิ้ม ยิ้ม
บางท่านอาจจะงงอ่าวเห้ยแล้วข้าเขียนแอสเซ็มบลีไปแล้วข้าจะรู้ได้ยังไง ว่ามันถูกหรือเปล่ามีโปรแกรมไว้คอมไพล์ไหม ฮืม โฮะๆๆทุกอย่างอยู่ในกระทู้นี้แ้ล้วครับ เราจะใช้ตัว tasm เปนตัวช่วยในการ compile + run แ้ละจะใช้
ืng หรือ เรียกเท่ๆว่า norton guide ในการเปนไกด์ช่วยทั่นให้เขียนโปรแกรมง่ายขี้นครับ ไม่พูดพร่ำทำเพลงละ เรามาดูวิธีการใช้กันเลยดีกว่านะ
ลิงค์สำหรับdownload อุปกรณ์ครับ http://www.winnershare.com/up/download.php...764assembly.rar
step 1-------ให้ทั่นโหลดโปรแกรมที่ผมฝากไว้เอาไปไว้ในเครื่องของทั่นเลยครับ โดยในตัวอย่างนี้ผมจะลงไว้ในไดรฟ์ d: นะครับ หลังจากนั้นแตกไฟล์ออกมาจะเหนโฟลเดอร์ที่ชื่อว่า assembly จุมพิตนั่นหละครับทั่นมาถูกทางระ ให้ทั่นเข้าไปใน
โฟลเดอร์ assembly ข้างในมันจะมีโฟลเดอร์ ng กับ tasm อยู่ครับ
Click!!
step 2-------ให้ทั่นเขียนโปรแกรมบนเท็กไฟล์ชื่ออะไรก็ได้โดยผมจะเขียนชื่อว่า xxx.txt เมื่อเขีัยนเสร็จแล้วให้นำมันไปวางไว้ใน folder tasm\bin ใส่ไปใน bin น่ะครับ แล้วเปลี่ยนนามสกุลมันให้เป็น xxx.asm ซะ
Click!!
step 3-------เข้า run-->cmd-->พิม d: เพื่อไปยังไดรฟ์ d แล้วพิม cd assembly\tasm\bin ถ้ามาถูกจะเปนตามรูปนี้ครับ
Click!!
step 4-------พิม tasm ชื่อไฟล์.asm ในที่นี้คือ tasm xxx.asm
step 5-------พิม tlink ชื่อไฟล์.obj ในที่นี้คือ tlink xxx.obj
step 6-------พิม ชื่อไฟล์.exe ทั่นก็จะได้เหนว่าโปรแกรมที่ทำมามันเปนยังไง ยิ้ม ยิ้ม
Click!!
ก็มีเท่านี้ล่ะครับเสต็ปในการ compile and run โดยใช้ tasm
ต่อไปเป็นการdebug โปรแกรมด้วย td เรียกเขาหล่อๆว่า turbo debugger
ทำเหมือนเดิมครับ step1-3
step 4------ พิม tasm /zi ชื่อไฟล์.asm
step 5------ พิม tlink /v ชื่อไฟล์.obj
step 6------ พิม td ชื่อไฟล์.exe
Click!!
หน้าตามันก็จะเป็นแบบนี้ครับ td
Click!!
วิธีการใช้ก็ให้ทั่นกด f7 ไปเรื่อยๆมันจะรันค่าให้ดูแล้วเช็คว่า register แต่ละตัวค่าเปนยังไง อันนี้ต้องอาศัยประสบการในการใช้ครับ ใช้ไปบ่อยๆเด๋วก็เปนเอง
บางคนอาจบอกว่าขี้เกรียจพิมอะ tasm tlink อะไรตั้งเยอะแยะ วันนี้ผมก็มี ทางลัดมานำสเนอครับเพื่อความสะดวกสบายของทุกๆท่าน ยิงฟันยิ้ม
โดยเราจะมาสร้าง script batch file กัน เพราะมันเปนการทำงานซ้ำไปซ้ำมานิ
ให้ท่านนำโคต๊นี้ไปใส่ลงในเท็กไฟล์เลยครับ แล้วใส่แล้วเซฟแปลงให้นามสกุลเปน .bat ซะ
@echo off
tasm %1.asm
tlink %1.obj
%1.exe
พอได้แบทไฟล์เรียบรอ้ยให้ทั่นเอาไปไว้ในโฟลเดอร์ที่อยู่ของ tasm\bin อะครับ ที่ๆทั่นเก็บโดต๊ไว้ ในที่นี้ผมเซฟไว้ในชื่อ gg.bat
พอจะใช้ก็แค่ พิม gg.bat ชื่อไฟล์ที่เขียนโคตassemblyไว้แ้ล้ว ในที่นี้คือ gg.bat xxx
Click!!
เรียบร้อยครับ รวดเร็ว ทันใจ ปลอดภัย ใช้ได้จริง ตกใจ
ช่วงนี้ไกล้สอบครับเด๋วอ่านนังสือสอบก่อน ยิ้ม สอบเสร็จแล้วจะมาต่อให้อีกนะครับ ตกใจ
บทเรียนที่1 มารุจัก interrupt สำหรับมือไหม่กันดีกว่า
1.int dos ใช้ int 21h
2.int video bios ใช้ int 10h
3.int key board ใช้ int 16h
4.int mouse ใช้ int 33h
1 >>>>>>>>>> ฟังชันสำคัญใน int 21h <<<<<<<<<<
****รับค่าตัวอักษร 1 ตัวจากคีบรอด (input) วิธีการใช้งาน mov ah,1 ;ให้ ah เป็น 1 ครับเพื่อเรียกฟังชัน 1 สำหรับการรับค่าจากคีบรอด
int 21h ; เรียก อินเทอรัพ เพื่อใช้ฟังชันนี้
ค่าที่ได้จากการทำฟังชันนี้ (output) ก็คือ al ซึ่งมันจะเก็บรหัส แอสกี้ของตัวอักษร เช่น ท่านป้อนเลข 1 เข้าไป มันจะเก็บค่า 31h ไว้ใน al
****print 1 ตัวอักษร วิธีใช้ mov ah,2 ; เรียกฟังชัน 2 เพื่อแสดงค่าตัวอักษร ที่เก็บใน dl ครับ
mov dl,'A' ; dl ของเราก็จะเก็บตัวอักขระ A ไว้ซึ่งมันเก็บในรูปรหัส แอสกี้
int 21h ; เรียกอินเทอรัพ เพื่อใช้ฟังชันนี้
****รับ 1 ตัวอักษรโดยไม่แสดงตัวอักษรนั้น ใช้ mov ah,8 ครับ แล้ว เรียก int 21h วิธีใช้เหมือนฟังชัน 1 ทุกประการ
****print string หรือ print ข้อความนั่นเอง mov ah,9 ; ฟังชัน 9 ไว้สำหรับ print string
lea dx,msg ; โหลดค่าแอดเดรส หน่วยความจำที่ชื่อว่า msg ที่เราใช้เก็บค่าสตริง มายัง dx ครับ
int 21h ; หลังจากเรียก int 21 h สตริงก็จะถูกปริ๊นออกมา
ฟังชันหลักๆที่นิยมใช้ใน 21h สำหรับเริ่มต้นก็มีประมาณนี้ครับ ใครอยากศึกษาเพิ่มเติมก็เปิด ng เอานะ
บทเรียนที่ 2 ว่าด้วยเงื่อนไข การกระโดด การใช้ loop
1.คำสั่ง cmp ทั่นอาจจะอ่านมันได้ว่าคอมแพ ครับ นำไปใช้ดังนี้ cmp ax,bx มันจะทำการลบค่า ax ด้วย bx ครับ แต่จริงๆแล้วมันไม่ได้ลบ มันคิดแต่มันไม่ได้ทำ พอมันคิดว่าเออนี่ ลบกันได้ 0 ไหม หรือลบแล้ว bx มากกว่า ax หรือนอ้ยกว่า ax จำไว้้นะครับมันไม่ได้ลบค่าออกจริงๆ มันเป็นเหมือนการเปรียบเทียบค่า
คำสั่ง cmp จะนำไปใช้กับคำสั่งกระโดดครับ ซึ่งจะว่าในหัวข้อต่อไป
2.คำสั่งกระโดดทั้งหลายแหล่มีเยอะมากครับแต่ที่นิยมใช้ ก็มีประมาณนี้
**** jmp (จัมพ์) กระโดดแบบไม่มีเงื่อนไข คือจะกระโดดไปส่วนใดของโปรแกรมก็ได้
mov ah,1 ;ฟังชัน 1 ใช้เพื่อรับค่าตัวอักษร 1ตัว
int 21h
jmp gogo
mov ah,2 ; ใช้เพื่อแสดงตัวอักษร 1 ตัว
mov dl,'@'
int 21h
gogo: mov ah,4ch ;ออกจากโปรแกรม
int 21h
สำหรับโปรแกรมนี้จะรับค่าตัวอักษร 1 ตัวแล้วกระโดดออกจากโปรแกรมเลย มันจะไม่แสดงเครื่องหมาย @ ครับเพราะมันกระโดดข้ามไปแล้ว
***** je กระโดดถ้าค่าที่ที่นำมาเปรียบเทียบมีค่าเท่ากัน เช่น
mov ax,5
mov bx ,5
cmp ax,bx
je escape
mov ah,2 ; ฟังชันแสดง 1 ตัวอักษร
mov dl,'?'
int 21h
escape: mov ah,4ch
int 21h
สำหรับโปรแกรมนี้ จะเป็นการเปรียบเทียบค่า ax กับ bx ทั่นจะเห็นว่ามันเท่ากัน ดังนั้น มันจึงกระโดดไปยัง escape เลยครับ โดยมันจะไม่ทำการปริ๊นเครื่องหมาย ? ออกมาให้ยลโฉมเลย ขอให้ดูรูปแบบการใช้แล้วลองเขียนดู ไม่ยากครับถ้าตั้งใจ
***** ต่อไปก็เป็นคำสั่งอีก 4 คำสั่งที่เราใช้กันบ่อยๆครับ
jb (jump if below) กระโดดถ้าตัวหน้ามีค่าน้อยกว่าตัวหลัง ต้อง cmp ก่อนครับ เช่น cmp cx,dx ถ้าค่า cx น้อยกว่า dx มันก็จะกระโดดไปยังส่วนที่เราต้องการ
jbe (jump if below or equal) การโดดถ้าตัวหน้ามีค่าน้อยกว่าหรือเท่ากับตัวหลัง ก็อธิบายเหมือนกับข้างบนครับเพีัยงแต่เพิ่มความสามารถในการเท่ากันมา
ja (jump if above) กระโดดถ้าตัวหน้ามีค่ามากกว่าตัวหลัง เฃ่น cmp ax,cx ถ้าค่า ax มากกว่า cx ก็จะกระโดดไปยังส่วนที่เราต้องการ
jae (jump if above or equal) กระโดดถ้าตัวหน้ามีค่ามากกว่าหรือเท่ากับตัวหลัง
***** การใช้คำสั่ง loop
การใช้คำสั่ง loop จะต้องกำหนดค่า cx ให้เป็นตัวนับ เช่น mov cx,9 ก็จะเป็นการกำหนดให้ลูปวนเป็นจำนวน 9 ครั้ง
mov cx,9 ;กำหนดว่าจะให้ลูปวนกี่รอบ
gg: mov ah,2
mov dl,'*' ;ทำการปริ๊นตัว *
int 21h
loop gg ; เป็นการบอกให้โปรแกรมทำ gg ซ้ำครับ
โปรแกรมนี้ก็จะเป็นการปริ๊นตัว * ออกมาเป็นจำนวน 9ตัวครับ
ก็ขอจบส่วนที่ 2 แต่เพียงเท่านี้
โจทย์ สำหรับบทเรียนที่ 1-2
จงเขียนโปรแกรมรับค่าตัวเลขจากคีบรอดถ้า รับเลข 1 มาจะแสดง ชื่อของผู้เขียนโปรแกรม แต่ถ้ารับเลข 2 จะแสดง นามสกุลของผู้เขียน
.model small
.stack 100h
.data
firstname db 'White_Hat $' ;ประกาศตัวแปร firstname ในดาต้าเซ็กเม็นท์ อย่าลืมนะครับว่าถ้าเราจะประกาศสตริงเราจำเป็นต้องปิดด้วยเครื่องหมาย $
lastname db '@IT-DARK $' ;ประกาศตัวแปร lastname ในดาต้าเซ็กเม็นท์ อย่าลืมนะครับว่าถ้าเราจะประกาศสตริงเราจำเป็นต้องปิดด้วยเครื่องหมาย $
.code
main proc far
mov ax,@data ;จำไว้เลยนะครับว่าก่อนจะทำอะไรเกี่ยวกับดาต้าเซ็กเม็นท์ต้อง mov ax,@data แล้วก็ mov ds,ax นะครับ
mov ds,ax
mov cx,10 ; วนลูป 10 รอบ
gg:
mov ah,1 ; เรียกฟังชันรับตัวอักษร ซึ่งรับมาแล้วจะเก็บไว้ใน al เก็บค่าในรูปรหัสแอสกี้
int 21h
cmp al,31h ;ดูว่าตัวอักษรที่รับมาเนี่ยมันมีค่าเท่ากับ 1 ไหม ซึ่งรหัสแอสกี้ของ 1 ก็คือ 31 hนั่นเองครับ
je fname ; ถ้าเท่ากัน กระโดดไปยัง fname
cmp al,32h ; ดูว่าอักษรที่รับมามีค่าเท่ากับ 2 ไหม
je lname ; ภ้าใช่กระโดดไป lastname
loop gg ;ถ้ารับค่ามาไม่ใช่ทั้ง 1 และ 2 โปรแกรมจะทำการวนลูปเพื่อเริ่มรับค่าจากคีบรอดไหม่อีกที
fname: lea dx,firstname ; ชี้ dx ไปยัง ตัวแปร firstname จำเป็นต้องใช้คำสั่ง lea dx,ตัวแปร ทุกครั้งถ้าเราจะใช้ฟังชัน 9 ในการแสดงผลสตริง
mov ah,9 ;เรียกฟังชันแสดงผลสตริง ซึ่งในที่นี้จะแสดงชื่อ
int 21h ;เรียกอินเทอรัพเพื่อดำเนินการซะ
jmp ex ;เสร็จกิจแล้วก็กระโดดไป ex เลย
lname: lea dx,lastname
mov ah,9 ;เรียกฟังชัน 9 เพื่อแสดงผลนามสกุล
int 21h
jmp ex
ex: mov ah,4ch ;ออกจากโค๊ดมายังดอส
int 21h
main endp ;จบ โปรซีเยอร์
end main ;จบโปรแกรม
ก็เรียบรอ้ยไปแล้วครับสำหรับโปรแกรมนี้
บทเรียนที่ 3 ว่าด้วยคำสั่ง + - * / บวก ลบ คูณ หาร รูดซิบปาก
วันนี้เรามาเรียนคณิตศาสตร์กันดีกว่าครับ อิอิ
1.add หรือคำสั่ง + วิธีใช้
mov dh,2
mov bl,3
add dh,bl ; เอา dh กับ bl มา + กัน ผลบวกจะเก็บไว้ใน dh ซึ่งเป็นตัวหน้าครับผม
ผลลัพที่ได้ dh จะเก็บค่า 5 ส่วน bl จะเก็บค่า 3 ครับ
2.sub หรือคำสั่ง - วิธีใช้
mov ax,20
mov bx,15
sub ax,bx ; เอา ax กับ bx มา - กัน ผลลบที่ได้จะเก็บไว้ใน ax ซึ่งเป็นตัวหน้าครับ
ผลลัพที่ได้ ax จะมีค่าเป็น 5 ส่วน bx จะมีค่าเป็น 15 ดังเดิม
3.mul คำสั่งคูณ
3.1 การคูณ byte กับ byte 8bit vs 8bit
กรณีนี้ตัวตั้งจะเป็น al ส่วนตัวคูณจะเป็น register ขนาด 1 byte เ่ช่น ah,bl,bh,ch,cl,dh,dl หรือจะเป็นตัวแปรก็ได้
ค่าที่ได้จากการคูณจะเก็บไว้ที่ ax ครับ
mov al,9 ;กำหนดตัวตั้ง al ให้เป็น 9
mov dh,3 ;กำหนดตัวคูณ ให้เป็น 3
mul dh ; ใช้คำสั่ง mul เพื่อทำการคูณ al กับ dh โดยผลลัพที่ได้ 27 จะเก็บไว้ใน ax ครับผม
3.2 การคูณ word กับ word 16bit vs 16bit
กรณีีนี้ ax จะเ้ป็นตัวตั้ง ตัวคูณเป็น register ขนาด 1 word เช่น bx,cx,dx หรือตัวแปรก็ได้ ผลลัพที่ได้ เวิดสูงจะเก็บใส่ dx เวิดต่ำจะเก็บใส่ ax
mov ax,0163h ;กำหนดตัวตั้ง
mov bx,01F4h ;กำหนดตัวที่จะเอามาคูณ
mul bx ; ใช้คำสั่ง mul กับตัวที่จะเอามาคูณ
ผลลัพที่ได้ ax จะมีค่าเป็น 0B55Ch dx จะมีค่าเป็น 0002h สำหรับการคูณนี้ผมใช้ turbo debugger ในการตรวจสอบนะครับ
4.div คำสั่ง หาร
4.1 การหาร byte กับ byte 8bit vs 8bit
กรณีนี้ตัวตั้งจะเป็น al ส่วนตัวหารเป็นรีจิสเตอร์ 8 bit ผลลัพที่ได้ al จะเก็บค่าจากการหาร ah จะเก็บเศษ เพราะฉะนั้นก่อนคำสั่งหารควรทำการเคลียค่าให้ ah
mov al,9 ;กำหนดตัวตั้ง
mov ah,0 ;เคลียค่า ah ให้เป็น 0
mov dl,5 ;กำหนดตัวหาร
div dl ; ทำการหาร ผลลัพจะเก็บใน al เศษจะเก็บใน ah
ในกรณีนี้ alจะมีค่าเป็น 1 ส่วน ah จะมีค่าเป็น 4 ครับ
4.2 การหาร word กับ word 16bit vs 16bit
กรณีีนี้ ax จะเ้ป็นตัวตั้ง พอหารเสร็จ ax จะเก็บผลลัพ dx จะเก็บเศษ เพราะฉะนั้นควรเคลียค่า dx ให้เป็น 0 ก่อนการหาร
mov ax,9 ; เซ็ทตัวตั้ง
mov cx,5 ; เซ็ทตัวหาร
mov dx,0 ; เคลียค่า dx ก่อนหารเพื่อเศษจะได้ไม่ผิดพลาด
div cx ; ใช้คำสั่ง div กับตัวหาร
ผลลัพ ax จะเก็บ ค่า 1 ส่วน dx จะเก็บค่า 4
ก็ขอจบส่วน + - * / แต่เพียงเท่านี้ครับ
บทเรียนที่ 4 การใช้ push pop การใช้ pointer การเรียกฟังชัน และ การรับสตริงจากคีบรอด
1.การใช้คำสั่ง push pop หลายทั่นคงงง เราจะประกาศ .stack 100 hไว้ทำไม เราประกาศไว้ก็เพื่อจะได้ใช้ คำสั่ง push pop นี่แหละครับ
บางทั่นอาจถามว่า stack คืออะไร ให้ทั่นนึกถึงเลย์ สแตก ครับ ที่เป็นมันฝรั่งอะ เราจะกินมันฝรั่งเราก็จะหยิบส่วนบนสุดของกระป๋องก่อน ชิมิ
แผ่นแรกที่เรายัดเข้าไปในกระป๋องจะเป็นแผ่นสุดท้ายที่เรากิน แต่แผ่นสุดท้ายที่ยัดเข้าไปเราจะหยิบมากินก่อน นี่ล่ะครับที่เขาเรียกว่า lifo (last in first out )
การใช้ push ก็คือ จับมันฝรั่งยัดเข้าไปในกระป๋อง
การใช้ pop ก็เอามันฝรั่งออกมารับประทาน ตกใจ
คำสั่งนี้ใช้สำหรับ register ขนาด 16 bit นะครับ เช่น
mov ax,55
push ax ; เอามันใส่ลงกระป๋องซะ
mov ax,88
pop ax ; เอามันออกมากินซะ
ทั่นคิดว่าจบโปรแกรมตัวนี้แล้ว ax จะมีค่าเป็นอะไร ฮืม
ขยิบตา ถูกต้องนะครับ ax จะมีค่าเป็น 55 เพราะ ax ตัวสุดท้ายมันเกิดจากการ pop มันก็จะแทนที่ค่า 88 ครับผม
2.การใช้งาน pointer register pointer ที่นิยมใช้กันก็จะมี si,di,bx ครับ ผม โดยมันจะทำหน้าที่เก็บค่าตำแหน่งของตัวที่มันชี้ไปนะครับ
mov di,0 ; ให้ พอยเตอร์ชี้ไปที่ตำแหน่ง 0 ครับ ค่า di มันก็จะเก็บ 0 ไว้
mov al,[di] ; ให้เครื่องหมาย [] ที่ล้อมลอบ di นั้นหมายความว่าเอาค่าที่ตำแหน่งที่ di ชี้ น่ะครับ ย้ายมันมาไว้ใน al ซะ สมมุตว่าถ้า
; ตำแหน่ง 0 เก็บค่า 5 ไว้ [di] ก็จะมีค่าเป็น 5 ครับ
3.การเรียกฟังชัน
การเรียกฟังชันย่อยจะทำให้โค๊ดเราดูสวยงาม แล้ว มันยังบำรุงแก้ไขได้ง่ายด้วยครับ การเรียกฟังชันใช้ คำสั่ง call ครับ
.model small
.stack 100h
.data
.code
main proc far
call prints ;เรียกฟังชัน prints
call endf ;เรียกฟังชัน endf
main endp ; จบ โปรซีเยอร์ main
prints proc near ;การประกาศฟังชันก็ธรรมดาครับทั่นลองดูรูปแบบเอา
mov ah,2
mov dl,'s' ;ฟังชันนี้จะเป็นฟังชันใช้สำหรับ แสดงตัวอักษร s 1 ตัวออกทางหน้าจอครับ
int 21h
ret ;จำไว้นะครับ ว่าก่อนจบฟังชันเราต้องใช้คำสั่ง ret ทุกครั้ง มันจะทำการ return ค่าที่ได้จากฟังชันไปยังฟังชันที่เรา call มันครับ
prints endp ; จบฟังชัน prints
endf proc near
mov ah,4ch ;ฟังชัน endf ไว้สำหรับออกจากโคตมายังดอสครับ
int 21h
ret ; อย่าลืม คำสั่ง ret เป็นอันขาด
endf endp ; จบฟังชัน endf
end main ; จบโปรแกรม
เห็นไหมครับว่าฟังชันไม่ยากเลย แถมยังดูเรียบรอ้ยเป็นระเบียบด้วย
4.การรับอินพุทสตริง
ในกรณีนี้เราจะใช้ฟังชัน 0ah ในการรับอินพุทแบบข้อความครับ
รูปแบบ mov ah,0ah
lea dx,ตัวแปรในดาต้าเซ็กเม็นท์
int 21h
เราจะเป็นต้องมีตัวแปร buffer เป็นจำนวน 3 ส่วนเพื่อใช้ฟังชันนี้ เช่น
buffer db 8,?,8 dup(?)
ส่วนแรก 8 หมายความว่า ใช้เก็บตัวอักษรสูงสุดที่รับเข้ามาในที่นี้รับได้สูงสุด 8 ตัว
ส่วนสอง ? หมายความว่า เอาไว้เก็บจำนวนไบต์ครับ
ส่วนที่ีสาม 8 dup (?) หมายถึง เอาไว้เก็บตัวอักษรที่ป้อนเข้ามาซึ่งจะสิ้นสุดด้วยการกด enter อักขระ enter ในรหัสแอสกี้ก็คือ 0ch ครับ
คือส่วนที่เราจะเก็บ input ได้แค่ 7 ตัวเท่านั้น ตัว ที่ 8 เอาไว้ เก็บอักขระ 0dh ซึ่งเป็นอักระสำหรับการกด enter oั่นเองครับ
.model small
.stack 100h
.data
buffer db 8,?,8 dup(?) ;การประกาศแบบ 8 dup(?) หมายความว่าจอง ? ไว้จำนวน 8 ไบต์ครับผม
.code
main proc far
mov ax,@data ; อย่าลืมครับทำอะไรเกี่ยวกับ data segment ต้อง mov ax,@data ตามด้วย mov ds,ax ตลอด
mov ds,ax
lea dx,buffer ;ชี้ dx ไปยัง ตัวแปร buffer
mov ah,0ah ;เรียกฟังชัน 0ah เพื่อรับอินพุทสตริง
int 21h
call crlf ;เรียกฟังชัน crlf
mov ah,4ch ; ออกจากโค๊ดมายังดอส
int 21h
main endp
crlf proc near ; ฟังชันนี้มีไว้สำหรับเว้นบรรทัดครับ
mov ah,2
mov dl,0ah
int 21h
mov dl,0dh
int 21h
ret
crlf endp
end main
โปรแกรมนี้เป็นโปรแกรมรับค่า input 7 ตัวมาเก็บไว้ใน buffer ครับ
ขอจบบทเรียนที่ 4 แต่เพียงเท่านี้
โจทย์ สำหรับบทเรียนที่ 1-4
จงเขียนโปรแกรมรับค่าชื่อของท่านจากคีบรอดเป็นจำนวน 30 ตัวอักษรหรือน้อยกว่าก็ได้ แล้วให้แสดงมันออกมาที่หน้าจอด้วย
สมมุตผมป้อน white_hat@it-dark
ผลลัพก็จะออกมาเป็น white_hat@it-dark ประมาณนี้น่ะครับ
.model small
.stack 100h
.data
org 20 ; กำหนดตำแหน่งเริ่มต้นของ data segment เป็น 20
buffer db 30,?,30 dup(?)
.code
main proc far
mov ax,@data
mov ds,ax
lea dx,buffer
mov ah,0ah
int 21h
call crlf ; เรียกฟังชันเว้นบรรทัด
mov cx,30 ;กำหนด cx 30 เพื่อวนลูป 30 รอบ
mov di,22
gg: call prints ;เรียกฟังชัน print
loop gg
ex: mov ah,4ch
int 21h
main endp
prints proc near
mov ah,2 ;เรียกฟังชัน print 1 ตัวอักษร
mov dl,[di] ; ให้ dl เก็บค่า ที่ di ชี้
int 21h
inc di ; เลื่อนตำแหน่ง di ไปอีก 1 หรือ+ค่าตำแหน่ง ไปอีก 1 นั่นเอง
cmp [di],0dh ;ดูค่าว่ามันเป็นอักขระ enter หรือยังถ้าเป็นแล้วให้กระโดดไปยัง ex เลย
je ex
ret
prints endp
crlf proc near
mov ah,2
mov dl,0ah
int 21h
mov dl,0dh
int 21h
ret
crlf endp
end main
สำหรับแนวคิดของโจทย์นี้เราจะให้ di ชี้ไปค่าที่เก็บในบัฟเฟอร์แต่ละตัว แล้ววนลูป print มันออกมาซะ แค่นี้เองครับแนวคิด
วันนี้ก็สอบเสร็จไป 1 ตัวละครับ ว่างๆเลยจะทำหัวข้อโจทย์แอสเซ็มบลีนะครับ
โจทย์ assembly โจทย์
จุดประสงค์
เพื่อให้ทั่นได้พัฒนา การเขียน assembly โดย coding ด้วยตัวเอง เชื่อผมครับ การดูcode อย่างเดียว แล้วไม่พยายามเขียนด้วยตัวเอง มันจะไม่ทำให้เราเกิดสกิลครับ หรืออาจจะเกิดแต่ช้า
การที่คนเรา ได้ลงมือปติบัติเองแล้ว สำเร็จในสิ่งนั้น ความภาคภูมิใจจะตามมา แล้วก็จะอยากค้นคว้าต่อไปครับ ทั่นคงคิดในใจเอ๊ะ ไอ้นี่บ่นยาวจิง รูดซิบปาก ครับไม่รบกวนละ มาเริ่มกันเลยดีกว่า
ปล . ขอให้ทั่นได้พยายามเขียน code ด้วยตัวเองก่อนนะครับ พยายาม ถ้าไม่ได้จริงๆค่อยเอา code ที่ผมวางไว้ไปศึกษาครับ แต่ขอให้พยายามก่อนนะ ขยิบตา
ระดับความยาก ปานกลาง-ยาก สำหรับมือไหม่นะครับ แต่สำหรับทั่นที่เขียนเปนแล้วอาจบอกว่าง่ายว่ะ ไม่ว่ากันครับ เศร้า
1.ข้อนี้เปนข้อสอบที่ทำวันนี้เลยครับ - - * เอาละโจทย์เขาว่ามาว่า ให้ทั่นเขียนโปรแกรมติดต่อกับหน้าจอคอมพิวเตอร์ โดยใช้ direct video ห้ามใช้ interrupt นะครับ เน้น ห้ามใช้ interrupt
โดยโปรแกรมจะให้ทั่น พิม ตัวอักษรA สีแดงบนพื้นสีขาว ครึ่งหน้าจอครับ คือหน้าจอทางด้านซ้ายจะมี ตัว Aอยู่แถวละ 40 ตัวเปนจำนวน 24 แถว แล้วก็พิมตัว F สีขาวบนพื้นแดง อยู่ทางด้านขวาของจอภาพ
เปนจำนวน 40 ตัว เช่นเดียวกัน (ระดับความยาก 3)
hint : ทั่นต้อง debug ด้วย td ก่อนนะครับ ถึงจะเหนผลลัพ
ข้าคิดไม่ออกเว้ย เฉลยให้หน่อย รูดซิบปาก ด้านล่างเลยครับ
.model small
.stack 100h
.data
.code
main proc
mov ax,0b800h
mov ds,ax
mov di,0
mov cx,25
aa: push cx
jmp left
yy: jmp right
zz: mov cx,0
pop cx
loop aa
jmp ex
left: mov cx,40
gg: mov [di],0f441h
add di,2
loop gg
jmp yy
right: mov cx,40
tt: mov [di],4f46h
add di,2
loop tt
jmp zz
ex:
mov ah,4ch
int 21h
endp
end main
2.ให้ทั่นเขียนโปรแกรมโดยวาดสี่เหลี่ยมจตุรัส ขนาดใดก็ได้บนลงจอภาพโดยใช้ เมาส์นะครับ คือ กดคลิกซ้ายทีนึงสี่เหลื่ยมก็จะขี้นมาบนหน้าจอ ถ้ากด ซ้ำตำแหน่งเดิมมันก็จะทับ อันเก่าครับ คือคลิกซ็ายแล้ว สี่เหลี่ยม
มันเกิดมาเรื่อยๆอะนะ ตกใจ ข้อนี้ยากพอสมควรเลยครับ ถ้าทำได้ทั่นก็เริ่มมีความแน่นอนใน ภาษา assembly แล้วครับ (ระดับความยาก 5)
อันนี้เฉลยครับ สำหรับคนที่คิดไม่ออก แต่ต้องพยายามก่อนนะจ๊ะ
.model small
.stack 100h
.data
dix db 8
q db '***** $'
.code
main proc far
mov ax,@data
mov ds,ax
mov ax,0
int 33h
mov ax,1
int 33h
call clrscr
gg: mov ax,3
int 33h
mov ax,dx
div dix
mov dh,al
mov ax,cx
div dix
mov dl,al
cmp bx,1
je ggg
cmp bx,2
je ex
loop gg
ggg: push dx
call setcur
call printq
pop dx
inc dh
push dx
call setcur
call printq
pop dx
inc dh
push dx
call setcur
call printq
pop dx
inc dh
push dx
call setcur
call printq
pop dx
inc dh
call setcur
call printq
jmp gg
ex:
mov ah,4ch
int 21h
main endp
printq proc near
mov ah,9
lea dx,q
int 21h
ret
printq endp
printa proc near
mov ah,02
mov dl,'A'
int 21h
ret
printa endp
clrscr proc near
mov ah,6
mov al,0
mov bh,14
mov cx,0000
mov dh,24
mov dl,79
int 10h
ret
clrscr endp
setcur proc near
mov ah,2
mov bh,0
int 10h
ret
setcur endp
end main
3.จงเขียนโปรแกรมเลื่อนตัว A ไปทั่วจอภาพโดยใช้คีบรอดครับ คือ กกลูกศรขี้นตัว มันก็จะเลื่อนขี้น กดลงก็ลง กดซ็ายก็ไปซ็าย กดขวาก็ไปขวา ข้อยกเ้ว้นคือห้ามให้ตัว A หลุดจากจอภาพเปนอันขาดดดด
ระดับความยาก (3.5)
นี่ครับ เฉลย ไม่มีอะไรได้มาง่ายถ้าปราศจากความพยายามครับ
.model small
.stack 100h
.data
.code
main proc far
call setmode
call clrscr
mov dx,0000h
start: call setcur
push dx
call printa
call key
cmp ah,48h
je up
cmp ah,50h
je down
cmp ah,4bh
je left
cmp ah,4dh
je right
cmp al,0dh
je ex
jmp start
up: pop dx
cmp dh,0
je start
push dx
call clrscr
pop dx
dec dh
push dx
jmp start
down:
pop dx
cmp dh,24
je start
push dx
call clrscr
pop dx
inc dh
push dx
jmp start
right:
pop dx
cmp dl,78
je start
push dx
call clrscr
pop dx
inc dl
push dx
jmp start
left:
pop dx
cmp dl,0
je start
push dx
call clrscr
pop dx
dec dl
push dx
jmp start
ex:
mov ah,4ch
int 21h
endp
setmode proc near
mov ah,0
mov al,3
int 10h
ret
setmode endp
setcur proc near
mov ah,2
mov bh,0
int 10h
ret
setcur endp
clrscr proc near
mov ah,6
mov al,0
mov cx,0000
mov dx,184fh
mov bh,14h
int 10h
ret
clrscr endp
getch proc near
mov ah,10h
int 16h
ret
getch endp
key proc near
mov ah,0
int 16h
ret
key endp
printa proc near
mov ah,02
mov dl,'A'
int 21h