运行 DOSBox

  1. mount c: d:\masm
  2. C:
  3. masm test.asm 回车3次
  4. link test.obj 回车4次
  5. debug test.exe
  • -r 运行
  • -t 继续
  • -t 10 运行10条指令
  • -d 内存
  • -u 源码
  • -p 跳过(尤其是库函数)
  • -q 退出

常用指令

  • assume 声明
  • mov 复制内存 mov ax, [bx]
  • inc 加一 inc ax
  • dec 减一
  • jmp 跳转 jmp loop1
  • cmp 比较大小 cmp ax, bx
  • add 增加某数 add ax, 10

其他指令

  • ADC 带进位加法
  • LEA dx, [0000] 相当于MOV字符串

? 比较大小

cmp cx, 0 比较结果执行下面的语句

  • ja > above
  • jb < blow
  • jbe <=
  • jae >=
  • jz == (相减为 zero)
  • jnz !=

库函数

  • INT 21
    • MOV AH 0A 时:接收一个用户输入到 ds[dx]
    • MOV AH 4C 时:退出程序,返回操作系统

寄存器拆开

AX = AH + AL
只有 AX BX CX DX 这四个可以拆开用

常用代码块

声明变量

1
2
assume cs:code, ds:data1
mov ax, data1

变量加一

1
2
3
mov al, [bx] ; 数据段寄存器DS 到 寄存器
inc al ; 增加 1
mov [bx], al ; 寄存器 到 DS

循环

1
for (i = 0; i < 10; i++);
1
2
3
4
5
6
mov cx, 0

loop1:
inc cx
cmp cx, 10
jb loop1

while 循环

1
2
3
4
5
i = 10;
while (i >= 0) {
// P1
i--;
}
1
2
3
4
5
6
7
8
9
10
mov ax, 10

loop1:
cmp ax, 0
jb next
;P1
dec ax
jmp loop1

next:

接收用户输入

1
2
3
4
5
MOV AX, 076A
MOV DS, AX
MOV DX, 0000
MOV AH, 0A
INT 21

清屏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    mov ax,cs
mov ss,ax
mov sp,0x7c00 ;set stack and sp

mov ah,0x06
mov al,0 ; 准备清窗口

mov ch,0 ; 左上角的行号
mov cl,0 ; 左上角的列号
mov dh,25 ; 右下角的行号
mov dl,80 ; 右下角的行号
mov bh,0x07; 属性为蓝底白字
int 0x10 ; 执行清空操作

@1:
jmp @1

times 510-($-$$) db 0
db 0x55,0xaa

画白线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	mov al, 0x13    ; VGA320×200×8bit 显示模式
mov ah, 0x00
int 0x10

mov ax, 0x0a000 ; 往显存中放入点数据
mov ds, ax
mov dl, 30
mov ax, 0

f:
mov bx, ax
mov [ds:bx], dl
inc ax
cmp ax, 50
ja io
jmp f

io:

画线函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
org 0x7c00

mov ax, 80 ; y
mov bx, 50 ; x1
mov cx, 150 ; x2

call drawline ; 运行画线

; y:ax, x1:bx, x2:cx
drawline:
mov dx, 320 ; 屏幕宽是320
mul dx ; dx *= ax 16位中AX为被乘数,8位中AL为被乘数
sub cx, bx ; cx = x2-x1 线的宽度
add bx, ax ; 横偏移量+横纵偏移量 = 偏移位置
mov dl, 1 ; 色号
loop0:
mov [ds:bx], dl ; 填充颜色
inc bx ; 偏移位置+1
dec cx ; 循环次数-1
jnz loop0 ; 受到上面的DEC的ZF标志位
RET

画竖线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
;****************************************
; y1->ax, y2->cx, x->bx
;****************************************
DrawVerticalLine:
mov dx, 320 ; w = 320
mov bp, dx
sub cx, ax ; y1 = y2-y1 循环次数
mul dx ; ax = w * y1 纵偏移量
add bx, ax ; 横纵偏移量
mov dl, 1
x1: mov [ds:bx], dl
add bx, bp
dec cx
jnz x1
ret

设置颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
mov al, 1      ; 颜色号
mov dx, 0x3c8
out dx, al

mov al, 100 ; R / 4 = 25
mov dx, 0x3c9
out dx, al

mov al, 0 ; G
out dx, al

mov al, 0 ; B
out dx, al

数组

1
2
3
4
5
6
7
8
9
;rgb db 100, 0, 0,  0, 100, 0,  0, 0, 100
rgb db 100, 0, 0,
db 0, 100, 0,
db 0, 0, 100

mov ax, 0
mov ds, ax
mov si, rgb
mov [ds:si], ... ; 偏移地址,si为下标

进栈出栈保存变量

1
2
3
push ax
mov ax, 0
pop ax

定时器

每隔18分之一秒运行一次,多个任务的话会被覆盖掉

1
mov word [ds:0x20],int_timer0

打印字符

函数:在 ex:bx 的位置显示一个 ‘A’

1
2
3
4
5
6
7
8
9
10
int_timer0:
mov byte [es:bx],'A'
mov byte [es:bx+1],0x0a
inc bx ; 自增两次到下次打印的字符
inc bx

mov al,0x20
mov dx,0x20
out dx,al ;EOI=0 中断
iret

获取按键输入

1
2
3
4
5
6
7
8
9
10
11
12
int_key:
mov dx, 0x20 ; 下一个键值可以进来了(没有这一段就只能输入一次按键了)
mov al, 0x61
out dx, al

mov dx, 0x60 ; 读取一次按键
in al, dx

cmp al, 0x9e
jz func0

func0:

显示一个数字

1
2