实验4 [bx]和loop的使用

assume cs: codesg
codesg segment
     
    mov ax, 20h  ;   20:0 到 20:3f
    mov ds, ax
 
    mov bx, 0
    mov cx, 64   ;    循环64次
 
s:  mov [bx], bl  ;  ((ds)*16+ bx) = (bl) = ( 0 到 63)
    inc bl
    loop s
 
    mov ax, 4c00H
    int 21H
 
codesg ends
 
end 

实验5 编写、调试具有多个段的程序

(5)

assume cs: code
 
a segment
    db 1,2,3,4,5,6,7,8
a ends
 
b segment
    db 1,2,3,4,5,6,7,8
b ends
 
c segment
    db 0,0,0,0,0,0,0,0
c ends
 
code segment
    start:
    mov ax, c
    mov ds, ax
 
    mov ax, b
    mov es, ax
 
    mov bx, 0
    mov cx, 4
;;;;;;;;;;;;;;;;;;;;c = b
    s:
    mov ax, es:[bx]
    mov [bx], ax
    add bx, 2
    loop s
 
    mov ax, a
    mov es, ax
    mov bx, 0
    mov cx, 4
;;;;;;;;;;;;;;;;;;;;c = c + a
    s1:
    mov ax, es:[bx]
    add [bx], ax
    add bx, 2
    loop s1
 
    mov ax,4c00H
    int 21H
code ends
 
end start 

(6)

assume cs: code
 
a segment
    dw 1,2,3,4,5,6,7,8
a ends
 
b segment
    dw 0,0,0,0,0,0,0,0
b ends
 
code segment
    start:
    mov ax, a
    mov ds, ax
 
    mov ax, b
    mov ss, ax
    mov sp, 10H
     
    mov cx, 8
    s:
    push  [bx]
    add bx, 2
    loop s
 
    mov ax,4c00H
    int 21H
code ends
 
end start 

实验6 实践课程中的程序

(2)

assume cs:code, ds:data
stack segment
    dw 0,0,0,0,0,0,0,0
stack ends
data segment
    ;;;'0123456789abcdef'
    db '1. display      '
    db '2. brows        '
    db '3. replace      '
    db '4. modify       '
data ends
 
code segment
    start: 
        ;初始 ss sp and ds
        mov ax, stack
        mov ss, ax
        mov sp,10H
        mov ax, data
        mov ds, ax 
 
        ;下一行:bx+=16,
        ;下一个:cx-- 
        mov bx, 0
        mov cx, 4
    s:  
         
        push cx  ;备份cx
        mov si, 0
        mov cx, 4
        s1:
            mov al, [bx+si+3]
            and al, 11011111b
            mov [bx+si+3], al
            inc si
        loop s1   
        add bx, 16
         
        pop cx   ;恢复cx
    loop s
    mov ax, 4c00h
    int 21h
code ends
 
end start 

实验7 寻址方式在结构化数据访问中的应用

assume cs:code
data segment
    ; 以下是表示21年的21个字符串    
    db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
    db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
    db '1993', '1994', '1995'
    ; 以下是表示21年公司总收入的21个DWORD型数据
    dd 16, 22, 382, 1356, 2390, 8000, 16000, 2446, 50065, 97479, 140417, 197514 
    dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000 
    ; 以下是表示21年公司雇员人数的21个word型数据  
    dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226 
    dw 11542, 14430, 15257, 17800 
data ends
 
table segment
    ;;;;;;;;;;;'0123456789ABCDEF'
    db 21 dup ('year summ ne ?? ')
table ends
 
code segment
    start:
        mov ax, table
        mov ds, ax
 
        mov ax, data
        mov es, ax
 
        mov si, 0
        mov di, 0
        mov bx, 0
        mov cx, 21
        s:
            ;table.年份 = [bx].0h
            ;4字节
            mov ax, es:0[si]
            mov [bx].0h, ax
            mov ax, es:2[si]
            mov [bx].2h, ax
 
            ;table.收入 = [bx].5h
            ;4字节
            mov ax, es:84[si]
            mov [bx].5h, ax
            mov ax, es:86[si]
            mov [bx].7h, ax
 
            ;table.雇员数 = [bx].0ah
            ;2字节
            mov ax, es:168[di]
            mov [bx].0ah, ax
 
            ;table.人均收入 = table.收入 / table.雇员数
            ;2字节
            mov ax, [bx].5h
            mov dx, [bx].7h
            div word ptr [bx].0ah
            mov [bx].0dh, ax
             
            add si, 4
            add di, 2
            add bx, 10h
        loop s
    mov ax, 4c00h
    int 21h
code ends
end start 

实验9 根据材料编程

assume cs:code, ss:stack, ds:data
 
stack segment
    dw 8 dup(0)
stack ends
 
data segment
    db 'Welcome to masm!'
    ;绿色,绿底红色,白底蓝色
    db 02h,24h,71h
     
data ends
 
code segment
start:
    mov ax, stack
    mov ss, ax
    mov sp, 10h
 
    mov ax, data
    mov es, ax
 
    mov ax, 0B878h ;12行段地址
    mov di, 10h ;第一个颜色偏移地址
    mov cx, 3
s:
    ;备份ax和cx
    push ax
    push cx
 
    mov ds, ax
    mov bx, 0
    mov si, 0
    mov cx, 10h
 
    s1:
        mov al, es:[bx]
        mov [si].32h, al ;ascii
        mov al, es:[di]
        mov [si].33h, al ;color
        inc bx
        add si, 2
        loop s1
 
    inc di ;下一个颜色
    ;恢复ax和cx
    pop cx 
    pop ax
    
    add ax, 0ah  ;下一行
    loop s
 
    mov ax, 4c00h
    int 21h
code ends
end start 

实验10 编写子程序

  1. 显示字符串
assume cs:code
 
data segment
        db 'Welcome to masm!', 0
data ends
 
code segment
start: 
       mov dh, 8
       mov dl, 3
       mov cl, 2
       mov ax, data
       mov ds, ax
       mov si, 0
     
       call show_str
       mov ax, 4c00h
       int 21h
 
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;     (cl)=颜色,ds:si指向字符串的首地址
;返回:无
show_str: push si        ;保存寄存器
          push cx
 
          mov al, 0ah
          mul dh
          add ax, 0b800h
          mov es, ax      ;得到行
 
          mov al, 2
          mul dl
          mov di, ax      ;得到列
 
          mov ch, 0       ;
          mov ah, cl      ;(ah) = 颜色
 
        show_char: 
          mov al, [si]    ;(al)= 字符
          mov cl, al      ;保存字符到cl
          jcxz ok         ;遇到结束符(0),跳出
          mov es:[di], ax ;显示一个带颜色的字符
          inc si          ;data segment下一个字符
          add di, 2       ;显示缓冲区下一个位置(占2字符)
          jmp short show_char
 
    ok: pop cx            ;恢复寄存器
        pop si
        ret
code ends
 
end start 
  1. 解决除法溢出的问题
assume cs:code
code segment
    start:
    mov ax, 4240h
    mov dx, 000fh
    mov cx, 0ah
     
    call divdw
    mov ax, 4c00h
    int 21h
;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型
;参数:(ax)= dword型数据的低16位
;      (dx)= dword型数据的高16位
;      (cx)= 除数
;返回:(dx)= 结果的高16位,(ax)= 结果的低16位
;      (cx)= 余数
divdw:
    ;(dx)/(cx)
    push ax
    mov ax, dx 
    mov dx, 0
    div cx    
    mov bx, ax ;高16商
 
    ;(ax)/(cx)
    pop ax     ;dx中已经保存了余数,即:(dx)%(cx)
    div cx
    mov cx, dx ;返回余数cx
    add dx, bx ;
    ret
 
code ends
end start  
  1. 数值显示
assume cs:code
data segment
    db 10 dup(0)
data ends
code segment
start:
    mov ax, 12666
    mov bx, data
    mov ds, bx
    mov si, 0
     
    call dtoc
 
    mov dh, 8
    mov dl, 3
    mov cl, 2
    call show_str
 
    mov ax, 4c00h
    int 21h
;功能:将word型数据转变为表示十进制数的字符串,字符串以0为结束符。
;参数:(ax)= word型数据
;      ds:si指向字符串的首地址
;返回:无
dtoc: add si, 8           ;word型最大只有65535=0xffff
      dtoc_s: mov cx, ax
              jcxz ok
              mov dx, 0   ;(dx) = 0
              mov bx, 10  
              div bx      ;(dx)*10000h+(ax)/(bx) = (ax)/(bx)
              add dl, 30h ;word -> ascii
              mov [si], dl;类似压入堆栈一个字节
              dec si
      jmp short dtoc_s  
      ok: inc si
          ret
 
;功能:在指定的位置用指定的颜色显示一个用0结束的字符串。
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;     (cl)=颜色,ds:si指向字符串的首地址
;返回:无
show_str: push si        ;保存寄存器
          push cx
 
          mov al, 0ah
          mul dh
          add ax, 0b800h
          mov es, ax      ;得到行
 
          mov al, 2
          mul dl
          mov di, ax      ;得到列
 
          mov ch, 0       ;
          mov ah, cl      ;(ah) = 颜色
 
        show_char: 
          mov al, [si]    ;(al)= 字符
          mov cl, al      ;保存字符到cl
          jcxz okk         ;遇到结束符(0),跳出
          mov es:[di], ax ;显示一个带颜色的字符
          inc si          ;data segment下一个字符
          add di, 2       ;显示缓冲区下一个位置(占2字符)
          jmp short show_char
 
    okk: pop cx            ;恢复寄存器
        pop si
        ret 
 
code ends
end start 

课程设计 1

assume cs:code
data segment
    db 16 dup(0)
data ends
 
poweridea segment
    ; 以下是表示21年的21个字符串
    db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
    db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
    db '1993', '1994', '1995'
    ; 以下是表示21年公司总收入的21个DWORD型数据
    dd 16, 22, 382, 1356, 2390, 8000, 16000, 2446, 50065, 97479, 140417, 197514
    dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
    ; 以下是表示21年公司雇员人数的21个word型数据
    dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
    dw 11542, 14430, 15257, 17800
poweridea ends
 
table segment
    ;;;;;;;;;;;'0123456789ABCDEF'
    db 21 dup ('year summ ne ?? ')
table ends
 
code segment
start:
    call poweridea2table
 
    mov bx, 0h
    mov cx, 21
    mov dh, 0
bwf:
    push cx
    mov dl, 8
    mov cl, 2
 
    call showyear
    mov dl, 18
    call showsum
    mov dl, 28
    call shownum
    mov dl, 38
    call showaverage
 
    add bx, 10h
    inc dh
    pop cx
    loop bwf
 
    mov ax, 4c00h
    int 21h
;功能:将dword型数据转变为表示十进制数的字符串,字符串以0为结束符。
;参数:(ax)= dword型数据的低16位
;      (dx)= dword型数据的高16位
;返回: ds:si指向字符串的首地址
dwtoc: add si, 14           ;word型最大只有4294967295=0xffffffff
        push cx
        push ax
        push dx
      dwtoc_s: mov cx, ax
              add cx, dx
              jcxz ok
              mov cx, 10
              call divdw
              add cl, 30h ;word -> ascii
              mov [si], cl;类似压入堆栈一个字节
              dec si
      jmp short dwtoc_s
      ok: inc si
            pop dx
            pop ax
            pop cx
          ret
 
;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型
;参数:(ax)= dword型数据的低16位
;      (dx)= dword型数据的高16位
;      (cx)= 除数
;返回:(dx)= 结果的高16位,(ax)= 结果的低16位
;      (cx)= 余数
divdw:
    ;(dx)/(cx)
    push bx
    push ax
    mov ax, dx
    mov dx, 0
    div cx
    mov bx, ax ;高16商
 
    ;(ax)/(cx)
    pop ax     ;dx中已经保存了余数,即:(dx)%(cx)
    div cx
    mov cx, dx ;返回余数cx
    mov dx, bx ;
    pop bx
    ret
 
;功能:在指定的位置用指定的颜色显示一个用0结束的字符串。
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;     (cl)=颜色,ds:si指向字符串的首地址
;返回:无
show_str: push si        ;保存寄存器
          push cx
 
          mov al, 0ah
          mul dh
          add ax, 0b800h
          mov es, ax      ;得到行
 
          mov al, 2
          mul dl
          mov di, ax      ;得到列
 
          mov ch, 0       ;
          mov ah, cl      ;(ah) = 颜色
 
        show_char:
          mov al, [si]    ;(al)= 字符
          mov cl, al      ;保存字符到cl
          jcxz okk         ;遇到结束符(0),跳出
          mov es:[di], ax ;显示一个带颜色的字符
          inc si          ;data segment下一个字符
          add di, 2       ;显示缓冲区下一个位置(占2字符)
          jmp short show_char
 
    okk: pop cx            ;恢复寄存器
        pop si
        ret
 
;功能:把poweridea公司的数据转换为table格式
;参数:无
;返回:无
poweridea2table:
        mov ax, table
        mov ds, ax
 
        mov ax, poweridea
        mov es, ax
 
        mov si, 0
        mov di, 0
        mov bx, 0
        mov cx, 21
        s:
            ;table.年份 = [bx].0h
            ;4字节
            mov ax, es:0[si]
            mov [bx].0h, ax
            mov ax, es:2[si]
            mov [bx].2h, ax
 
            ;table.收入 = [bx].5h
            ;4字节
            mov ax, es:84[si]
            mov [bx].5h, ax
            mov ax, es:86[si]
            mov [bx].7h, ax
 
            ;table.雇员数 = [bx].0ah
            ;2字节
            mov ax, es:168[di]
            mov [bx].0ah, ax
 
            ;table.人均收入 = table.收入 / table.雇员数
            ;2字节
            mov ax, [bx].5h
            mov dx, [bx].7h
            div word ptr [bx].0ah
            mov [bx].0dh, ax
 
            add si, 4
            add di, 2
            add bx, 10h
        loop s
 
ret
 
;在指定的位置用指定的颜色显示年份。
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;      (cl)=颜色,bx指向第几条记录
;返回:无
showyear:
    mov ax, data
    mov ds, ax
    mov ax, table
    mov es, ax
 
    mov ax, es:[bx].0
    mov ds:0, ax
    mov ax, es:[bx].2
    mov ds:2, ax
    mov si,0
    call show_str
ret
 
;在指定的位置用指定的颜色显示公司总收入。
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;      (cl)=颜色,bx指向第几条记录
;返回:无
showsum:
    push dx
    mov ax, table
    mov es, ax
    mov ax, data
    mov ds, ax
    mov ax, es:[bx].5
    mov dx, es:[bx].7
    mov si, 0
    call dwtoc
    pop dx
    call show_str
ret
 
;在指定的位置用指定的颜色显示公司雇员人数。
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;      (cl)=颜色,bx指向第几条记录
;返回:无
shownum:
    push dx
    mov ax, table
    mov es, ax
    mov ax, data
    mov ds, ax
    mov ax, es:[bx].0ah
    mov dx, 0
    mov si, 0
    call dwtoc
    pop dx
    call show_str
ret
 
;在指定的位置用指定的颜色显示公司雇员人均收入。
;参数:(dh)=行号(取值范围0~24),(dl)=列号(取值范围0~79),
;      (cl)=颜色,bx指向第几条记录
;返回:无
showaverage:
    push dx
    mov ax, table
    mov es, ax
    mov ax, data
    mov ds, ax
    mov ax, es:[bx].0dh
    mov dx, 0
    mov si, 0
    call dwtoc
    pop dx
    call show_str
ret
code ends
end start

实验11 编写子程序

assume cs:code
data segment
    db "{Beginner's All-purpose Symbolic Instruction Code.}", 0
data ends
code segment
    start:  mov ax, data
            mov ds, ax
            mov si, 0
            call letterc
            mov ax, 4c00h
            int 21h
 
;名称:letterc
;功能:将以0结尾的字符串的小写字母转变成大写字母
;参数:ds:si指向字符串首地址
;返回:无
letterc: cmp byte ptr [si], 0
         je ok
         cmp byte ptr [si], 61h
         jb s0
         cmp byte ptr [si], 7ah
         ja s0
         and byte ptr [si], 11011111b
     s0: inc si
         jmp short letterc
     ok: ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
code ends   
end start 

实验12 编写0号中断的处理程序

assume cs:code
code segment
start: 
;;;;;;;;do0安装程序;;;;;;;;;;;;;;;;;;;;;;;
        mov ax, cs
        mov ds, ax
        mov si, offset do0                  ;设置ds:si指向源地址
        mov ax, 0
        mov es, ax
        mov di, 200h                        ;设置es:di指向目的地址
 
        mov cx, offset do0end - offset do0  ;设置cx传输长度
        cld
        rep movsb
;;;;;;;;设置中断向量表;;;;;;;;;;;;;;;;;;;;;
        mov ax, 0
        mov es, ax
        mov word ptr es:[0*4], 200h
        mov word ptr es:[0*4+2], 0
         
        mov ax, 4c00h
        int 21h
;;;;;;;;显示overflow;;;;;;;;;;;;;;;;;;;;;;;
do0:        jmp short do0start
            db "Divide error!"
do0start:   mov ax, cs
            mov ds, ax
            mov si, 202h                     ;设置ds:si指向字符串
 
            mov ax, 0b800h
            mov es, ax
            mov di, 12 * 160 + 27 * 2        ;设置es:di指向显存空间的中间位置
            mov cx, offset do0start - offset do0 - 2
             
s:          mov al, [si]
            mov es:[di], al
            mov al, 11111100b           
            mov es:[di+1], al
            inc si
            add di, 2
            loop s
            mov ax, 4c00h
            int 21h
do0end: nop
 
code ends
end start
 
测试代码3.asm
assume cs:code
code segment
start: 
        mov bl, 0
        div bl
 
        mov ax, 4c00h
        int 21h
code ends
end start 

实验13 编写、应用中断例程

(1)

assume cs:code
code segment
start:  mov ax, cs
        mov ds, ax
        mov si, offset lp
        mov ax, 0
        mov es, ax
        mov di, 200h
        mov cx, offset lpend - offset lp
        cld
        rep movsb
         
        mov word ptr es:[7ch*4], 200h
        mov word ptr es:[7ch*4+2], 0
        mov ax, 4c00h
        int 21h   
 
;功能:显示一个用0结束的字符串
;参数:(dh) = 行号,(dl) = 列号,(cl) = 颜色,ds:si指向字符串首地址
lp:     push ax
        push di
        push si
 
        mov ax, 0b800h
        mov es, ax
 
        mov al, 160
        mul dh
        mov di, ax
        mov al, 2
        mul dl
        add di, ax
 
        mov al, cl    ;保存颜色
lp0:    mov cx, [si]
        jcxz ok
        mov es:[di], cl
        mov es:[di+1], al
        inc si
        add di, 2
        jmp short lp0
 
ok:     pop si
        pop di
        pop ax
        iret
lpend:  nop
 
code ends
end start 

(2)

assume cs:code
code segment
start:  mov ax, cs
        mov ds, ax
        mov si, offset lp
        mov ax, 0
        mov es, ax
        mov di, 200h
        mov cx, offset lpend - offset lp
        cld
        rep movsb
         
        mov ax, 0
        mov es, ax
        mov word ptr es:[7ch*4], 200h
        mov word ptr es:[7ch*4+2], 0h
         
        mov ax, 4c00h
        int 21h
lp:     push bp
        mov bp, sp
        dec cx
        jcxz ok
        add [bp+2], bx
ok:     pop bp
        iret
lpend: nop
code ends
end start 

(3)

assume cs:code
code segment
s1: db 'Good, better, best,' , '$'
s2: db 'Never let it rest,'  , '$'
s3: db 'Till good is better,', '$'
s4: db 'And better, best.'   , '$'
s:  dw offset s1, offset s2, offset s3, offset s4
row:db 2, 4, 6, 8
start:  mov ax, cs
        mov ds, ax
        mov bx, offset s
        mov si, offset row
        mov cx, 4
ok:     mov bh, 0    ;页
        mov dh, [si] ;行
        mov dl, 0    ;列
        mov ah, 2    ;置光标
        int 10h      ;bios中断例程
 
        mov dx, [bx] ;字符串位置 ds:dx
        mov ah, 9    ;光标位置显示字符串
        int 21h      ;dos中断例程
        inc si
        add bx, 2
        loop ok
 
        mov ax, 4c00h
        int 21h        
code ends
end start 

检测点14.2

assume cs:code
code segment
start:  mov ax, 2
 
        mov bx, ax
        shl ax, 1  ;(ax)*2
        mov cl, 3
        shl bx, cl ;(ax)*8
        add ax, bx ;(ax)*2 + (ax)*8
 
        mov ax, 4c00h
        int 21h        
code ends
end start 

实验14 访问CMOS RAM

assume cs:code
data segment
    db 9, '/', 8, '/', 7, ' ', 4, ':', 2, ':', 0
data ends
code segment
start:  mov ax, data
        mov ds, ax
        mov si, 0
        mov ax, 0b800h
        mov es, ax
         
        mov cx, 11
        mov di, 0
s:      push cx
        cmp byte ptr [si], 9
        mov al, [si]
        ja s0
        mov al, [si]
        out 70h, al
        in al, 71h
        mov ah, al
        mov cl, 4
        shr ah, cl
        and al, 00001111b
        add ax, 3030h                            ;转换为ascii
        mov byte ptr es:[160*12+40*2+di], ah     ;十位
        add di, 2
s0:     mov byte ptr es:[160*12+40*2+di], al     ;个位 或分隔符
        add si, 1
        add di, 2
        pop cx
        loop s
 
        mov ax, 4c00h
        int 21h        
code ends
end start 

实验15 安装新的int 9 中断例程

assume cs:code
stack segment
    db 128 dup(0)
stack ends
code segment
start:  mov ax, stack
        mov ss, ax
        mov sp, 128
     
        push cs
        pop ds
 
        mov ax, 0
        mov es, ax
         
        mov si, offset int9
        mov di, 204h
        mov cx, offset int9end - offset int9
        cld
        rep movsb
         
        push es:[9*4]
        pop es:[200h]
        push es:[9*4+2]
        pop es:[202h]
         
        cli
        mov word ptr es:[9*4], 204h
        mov word ptr es:[9*4+2], 0
        sti
        mov ax, 4c00h
        int 21h
int9:   push ax
        push bx
        push cx
        push es
         
        in al, 60h
         
        pushf
        call dword ptr cs:[200h]
         
        cmp al, 9eh ;A的断码
        jne int9ret
 
        mov ax, 0b800h
        mov es, ax
        mov bx, 0
        mov cx, 2000
s:      mov byte ptr es:[bx], 'A'
        add bx, 2
        loop s
int9ret:    pop es
            pop cx
            pop bx
            pop ax
            iret
int9end:    nop
code ends
end start 

实验16 编写包含多个功能子程序的中断例程

assume cs:code
stack segment
    db 128 dup(0)
stack ends
code segment
start:  mov ax, stack
        mov ss, ax
        mov sp, 128 
 
        mov ax, cs
        mov ds, ax
        mov si, offset setscreen
        mov ax, 0
        mov es, ax
        mov di, 200h
        mov cx, offset setscreenend - offset setscreen
        cld
        rep movsb
 
        mov ax, 0
        mov es, ax
        mov word ptr es:[7ch*4], 0h
        mov word ptr es:[7ch*4+2], 20h 
 
        mov ax, 4c00h
        int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;屏幕设置
setscreen:  jmp short set           ;安装后这条语句地址是0020:0000,下一条0020:0002
table:     dw offset sub1 - offset setscreen, offset sub2 - offset setscreen, offset sub3 - offset setscreen, offset sub4 - offset setscreen
set:        push bx
            cmp ah, 3
            ja sret
            mov bl, ah
            mov bh, 0
            add bx, bx                  ;bx是偏移地址
            call word ptr cs:2h[bx]     ;即0020:(0002+bx)
sret:       pop bx
            iret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;清屏
sub1:   push bx
        push cx
        push es
        mov bx, 0b800h
        mov es, bx
        mov bx, 0
        mov cx, 2000
sub1s:  mov byte ptr es:[bx], ' '
        add bx, 2
        loop sub1s
        pop es
        pop cx
        pop bx
        ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;设置前景色
sub2:   push bx
        push cx
        push es
        mov bx, 0b800h
        mov es, bx
        mov bx, 1
        mov cx, 2000
sub2s:  and byte ptr es:[bx], 11111000b
        or es:[bx], al
        add bx, 2
        loop sub2s
        pop es
        pop cx
        pop bx
        ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;设置背景色
sub3:   push bx
        push cx
        push es
        mov cl, 4
        shl al, cl
        mov bx, 0b800h
        mov es, bx
        mov bx, 1
        mov cx, 2000
sub3s:  and byte ptr es:[bx], 10001111b
        or es:[bx], al
        add bx, 2
        loop sub3s
        pop es
        pop cx
        pop bx
        ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;向上滚动一行
sub4:   push cx
        push si
        push di
        push es
        push ds
 
        mov si, 0b800h
        mov es, si
        mov ds, si
        mov si, 160
        mov di, 0
        cld
        mov cx, 24
sub4s:  push cx
        mov cx, 160
        rep movsb
        pop cx
        loop sub4s
        mov cx, 80
        mov si, 0
sub4s1: mov byte ptr [160*24+si], ' '
        add si, 2
        loop sub4s1
        pop ds
        pop es
        pop di
        pop si
        pop cx
        ret
setscreenend: nop
code ends
end start 

附上测试代码:

assume cs:code
code segment
start:  mov ah, 1
        mov al, 010b
        int 7ch         ;调用1号子程序,设置前景色为绿色
        call delay
 
        mov ah, 2
        mov al, 001b    ;调用2号子程序,设置背景色为蓝色
        int 7ch
        call delay
 
        mov ah, 3
        int 7ch         ;调用3号子程序,上滚一行
        call delay
         
        mov ah, 3
        int 7ch         ;调用3号子程序,上滚一行
        call delay
 
        mov ax, 4c00h
        int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;
;暂停
delay:  push ax
        push dx
        mov dx, 4000h
        mov ax, 0
s1:     sub ax, 1
        sbb dx, 0
        cmp ax, 0
        jne s1
        cmp dx, 0
        jne s1
        pop dx
        pop ax
        ret
code ends
end start

字符串的输入

assume cs:code ds:data
data segment
    dd 128 dup(0)
data ends
code segment
start:  mov ax, data
        mov ds, ax
        mov dx, 0   ;0行0列
        call getstr 
        mov ax, 4c00h
        int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
getstr: push ax
getstrs:    mov ah, 0
            int 16h
            cmp al, 20h 
            jb nochar       ;ascii小于20h(sp),说明不是字符
            mov ah, 0
            call charstack  ;字符入栈
            mov ah, 2
            call charstack  ;显示栈中的字符
            jmp getstrs
;控制符(退格和回车)
nochar: cmp ah, 0eh         ;退格键的扫描码
        je  backspace
        cmp ah, 1ch         ;回车键的扫描码
        je  enter
        jmp getstrs
;退格
backspace:  mov ah, 1
            call charstack  ;字符出栈
            mov ah, 2
            call charstack  ;显示栈中的字符
            jmp getstrs
;回车
enter:  mov al, 0
        mov ah, 0
        call charstack      ;0入栈
        mov ah, 2
        call charstack      ;显示栈中的字符
        pop ax
        ret 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;功能:  字符栈的入栈,出栈和显示
;参数:  (ah)=功能号,0表示入栈,1表示出栈,2表示显示;
;       ds:si指向字符栈空间;
;       对于0号功能:(al)=入栈字符;
;       对于1号功能:(al)=返回字符;
;       对于2号功能:(dh),(dl)=字符串在屏幕上显示的行,列位置。
charstack:  jmp short charstart
    table   dw charpush, charpop, charshow
    top     dw 0            ;栈顶
charstart:  push bx
            push dx
            push di
            push es
 
            cmp ah, 2
            ja  sret
            mov bl, ah
            mov bh, 0
            add bx, bx
            jmp word ptr table[bx]
;入栈
charpush:   mov bx, top
            mov [si][bx], al
            inc top
            jmp sret
;出栈
charpop:    cmp top, 0
            je sret
            dec top
            mov bx, top
            mov al, [si][bx]
            jmp sret
;显示
charshow:   mov bx, 0b800h
            mov es, bx
            mov al, 160
            mov ah, 0
            mul dh
            mov di, ax
            add dl, dl
            mov dh, 0
            add di, dx  ; (dh)*160 + (dl)+(dl)
 
            mov bx, 0
 
charshows:  cmp bx, top
            jne noempty
            mov byte ptr es:[di], ' '
            jmp sret
 
noempty:    mov al, [si][bx]
            mov es:[di], al
            mov byte ptr es:[di+2], ' '
            inc bx
            add di, 2
            jmp charshows
 
sret:       pop es
            pop di
            pop dx
            pop bx
            ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
code ends
end start 

debug读取软盘0面0道1扇区到文件

(测试环境BOCHS + MS-DOS7.1)

书299页代码编译连接生成4.exe

下面用debug把0扇区写到文件4.txt

C:\ASMSTUDY>4.exe 运行后0扇区写入到了0:200开始的512b内存中
C:\ASMSTUDY>debug
-rcx
cx 0000
:1ff 此处是大小0到1ff就是200h即512b
-rcs
cs 0A7F
:10 段地址cs=10,ip=100,即从20:0开始
-n4.txt n为新建,4.txt为文件名
-w w即写入
Writing 001FF bytes
-_
完毕

实验17 编写包含多个功能子程序的中断例程

assume cs:code
data segment
    db 512 dup(0)
data ends
code segment
start:  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;安装int 7ch号中断例程
        mov ax, cs
        mov ds, ax
        mov si, offset rwfloppy
 
        mov ax, 0
        mov es, ax
        mov di, 200h
        mov cx, offset rwfloppyend - offset rwfloppy
        cld
        rep movsb
 
        mov word ptr es:[7ch*4], 200h
        mov word ptr es:[7ch*4+2], 0
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;测试
        mov ax, data
        mov es, ax
        mov si, 0h
         
        mov di, 0
        mov cx, 2880    ;2880个扇区
s:
        mov ah, 0       ;读
        mov al, 1       ;读入扇区数
        mov dl, 0       ;软驱A
        mov bx, di      ;逻辑扇区号
        int 7ch
 
        mov ah, 1       ;写
        mov al, 1       ;写入扇区数
        mov dl, 1       ;软驱B
        mov bx, di      ;逻辑扇区号
        int 7ch
        inc di
        loop s
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
        mov ax, 4c00h
        int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;功能:使用逻辑扇区号读写软盘
;参数:(ah) = 0 表示读,1 表示写
;      (al) = 要读写的扇区数
;      (dl) = 驱动器号,0:软盘A,1:软盘B
;      (bx) = 要读写的逻辑扇区号
;      es:si 指向存储读出数据或写入数据的内存区
rwfloppy:   cmp ah, 1
            ja ok               ;大于1跳出
            push bx             ;保护bx
            push cx             ;保护cx
            push dx             ;保护dx
            add ah, 2           ;读或写:0+2 or 1+2
            push ax             ;保存写入的扇区数和功能号(al)和(ah)
            push dx             ;保存驱动器号(dl)
            mov ax, bx
            mov dx, 0       
            mov bx, 1440        
            div bx 
            mov bx, dx          ;(bx) = (bx)%1440
            pop dx              ;恢复驱动器号(dl)
            mov dh, al          ;面: (dh) = (bx)/1440 
            mov ax, bx
            mov bl, 18
            div bl
            mov ch, al          ;磁道号:(ch) = ((bx)%1440)/18
            mov cl, ah
            inc cl              ;扇区号:(cl) = ((bx)%1440)%18+1
            mov bx, si
            pop ax              
            int 13h             ;调用bios中断
            sub ah, 2           ;恢复ax
            pop dx              ;恢复dx
            pop cx              ;恢复cx
            pop bx              ;恢复bx
ok:         iret
         
rwfloppyend:    nop
code ends
end start 

课程设计2

;课程设计2 ( 0.1版)
;功能:此为安装程序,使得电脑可以从软盘A启动,启动后有以下功能
;      功能界面,F1键改变显示颜色
;      1键重启
;      2键从c盘启动
;      3显示时间,按ESC键返回
assume cs:code
data segment
    db 510 dup(0)
    dw 0aa55h
data ends
code segment
start:  call int7ch
        call copytoa0
        call copytoa1
        mov ax, 4c00h
        int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;安装int 7ch号中断例程
int7ch:     mov ax, cs
            mov ds, ax
            mov si, offset rwfloppy
 
            mov ax, 0
            mov es, ax
            mov di, 200h
            mov cx, offset rwfloppyend - offset rwfloppy
            cld
            rep movsb
 
            mov word ptr es:[7ch*4], 200h
            mov word ptr es:[7ch*4+2], 0
            ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;功能:使用逻辑扇区号读写软盘
;参数:(ah) = 0 表示读,1 表示写
;      (al) = 要读写的扇区数
;      (dl) = 驱动器号,0:软盘A,1:软盘B
;      (bx) = 要读写的逻辑扇区号
;      es:si 指向存储读出数据或写入数据的内存区
rwfloppy:   push bx             ;保护bx
            push cx             ;保护cx
            push dx             ;保护dx
            add ah, 2           ;读或写:0+2 or 1+2
            push ax             ;保存写入的扇区数和功能号(al)和(ah)
            push dx             ;保存驱动器号(dl)
            mov ax, bx
            mov dx, 0       
            mov bx, 1440        
            div bx 
            mov bx, dx          ;(bx) = (bx)%1440
            pop dx              ;恢复驱动器号(dl)
            mov dh, al          ;面: (dh) = (bx)/1440 
            mov ax, bx
            mov bl, 18
            div bl
            mov ch, al          ;磁道号:(ch) = ((bx)%1440)/18
            mov cl, ah
            inc cl              ;扇区号:(cl) = ((bx)%1440)%18+1
            mov bx, si
            pop ax              
            int 13h             ;调用bios中断
            ;call debug
            sub ah, 2           ;恢复ax
            pop dx              ;恢复dx
            pop cx              ;恢复cx
            pop bx              ;恢复bx
            iret
rwfloppyend:    nop
 
copytoa0:
        mov ax, cs
        mov ds, ax
        mov si, offset asmedusystem
 
        mov ax, data
        mov es, ax
        mov di, 0
        mov cx, offset asmedusystemend - offset asmedusystem
        cld
        rep movsb        
 
        mov ax, data
        mov es, ax
        mov si, 0        
         
        mov ah, 1      ;写
        mov al, 1      ;写入扇区数
        mov dl, 0      ;软驱A
        mov bx, 0      ;逻辑扇区号
        int 7ch
 
        ret
;C盘引导区备份到软盘A的1号扇区
copytoa1:         
        mov ax, data 
        mov es, ax
        mov bx, 0   
        mov ah, 2       ;读磁盘
        mov al, 1       ;读取扇区数
        mov ch, 0       ;磁道号
        mov cl, 1       ;扇区号(逻辑0号)
        mov dh, 0       ;磁头号
        mov dl, 80h     ;驱动器号
        int 13h
 
 
        mov ax, data
        mov es, ax
        mov si, 0              
        mov ah, 1      ;写
        mov al, 1      ;写入扇区数
        mov dl, 0      ;软驱A
        mov bx, 1      ;逻辑扇区号
        int 7ch
 
        ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
org 7c00h
asmedusystem:
          call  init
       
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;显示系统界面
init: jmp initstart
    table db '[1] reset pc',             0
          db '[2] start system',         0
          db '[3] clock',                0
          db '[4] set clock',            0
          
initstart:   call clear
             mov bh, 2   ;绿色
show:        mov bl, 4   ;6行字符
             call puts
             jmp short show
             ret
;;;;;;;;;;;;;;;;;;;;;;;;;;
;显示时间
showtime:
        call clear
showtime_:        call clock
        in al, 60h
        cmp al, 1   ;按键esc
        je  init  ;重启
        jmp showtime_
        ret  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;显示以0结束的字符串
puts:   push ax
        mov ax, 0b800h 
        mov ds, ax
        mov si, 0
        mov di, 0
        mov ch, 0
puts_:  cmp bl, 0
        je short putsok
        mov cl, table[di]
        jcxz putsnext
        mov [si+50+160*10], cl
        push ax
 
        in al, 60h
        cmp al, 2   ;按键1
        je  resetpc  ;重启
        cmp al, 3   ;按键2
        je startdiskc ;c盘启动
        cmp al, 4   ;按键3
        je  showtime ;显示时间
        cmp al, 3bh ;按键F1
        jne nof1    ;改变颜色        
         
        inc bh
nof1:   mov [si+50+160*10+1], bh
        pop ax
        add si, 2
        inc di
        jmp short puts_
putsnext:  
           add ax, 0ah
           mov ds, ax
           dec bl
           inc di
           mov si, 0
           
           jmp short puts_
putsok: pop ax
        ret
       
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;重新启动计算机
resetpc:  
    db 0eah, 0, 0, 0ffh, 0ffh ;jmp ffff:0000
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;引导现有的操作系统(引导C盘)
startdiskc:
       mov ax, cs
       mov ds, ax
       mov si, offset startdiskc_
 
       mov ax, 0
       mov es, ax
       mov di, 200h
       mov cx, offset startdiskcend_ - offset startdiskc_
       cld
       rep movsb
       db 0eah, 0, 2, 0, 0 ;jmp 0000:0200
 
startdiskc_:   mov ax, 0 
                mov es, ax
                mov bx, 7c00h   
                mov ah, 2       ;读磁盘
                mov al, 1       ;读取扇区数
                mov ch, 0       ;磁道号
                mov cl, 2       ;扇区号(1号逻辑)
                mov dh, 0       ;磁头号
                mov dl, 0       ;驱动器号
                int 13h
                db 0eah, 0, 7ch, 0, 0
startdiskcend_:        ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;
;清屏
clear:  push bx
        push cx
        push es
        mov bx, 0b800h
        mov es, bx
        mov bx, 0
        mov cx, 2000
clear_:  mov byte ptr es:[bx], ' '
        mov byte ptr es:[bx+1], 111b
        add bx, 2
        loop clear_
        pop es
        pop cx
        pop bx         
        ret
 
;;;;;;;;;;;;;;;;;;;;;
;clock
clock:  jmp clock_
    time db 9, '/', 8, '/', 7, ' ', 4, ':', 2, ':', 0 
clock_: mov si, 0
        mov ax, 0b800h
        mov es, ax
        mov cx, 11
        mov di, 0
s:      push cx
        cmp byte ptr time[si], 9
        mov al, time[si]
        ja s0
        mov al, time[si]
        out 70h, al
        in al, 71h
        mov ah, al
        mov cl, 4
        shr ah, cl
        and al, 00001111b
        add ax, 3030h                            ;转换为ascii
        mov byte ptr es:[160*12+30*2+di], ah     ;十位
        add di, 2
s0:     mov byte ptr es:[160*12+30*2+di], al     ;个位 或分隔符
        inc si
        add di, 2
        pop cx
        loop s 
         
        ret
 
asmedusystemend: nop
 
code ends
end start