南郊居士 发表于 2015-6-9 23:26:09

实验16——为了节约内存,拼了。。。

在正式开始做实验16之前,我不知道0:200到0:2ff的空间够不够放得下四个子程序。

在看16.4的时候,我发现子程序2和子程序3的功能基本相同,一个是改前景色,一个是改背景色,代码也基本相同。我想,既然不能确定内存空间够不够,干脆就采用最节约的方式吧,把程序2和程序3做成一个程序

当然了,我遇到了大家初次做实验16应该都会遇到的问题,就是假如采用16.4的思路,直接定址表中的内存地址在安装之后是错的。笨人当然有笨人的策略,于是我就这样做了:
assume cs:code

stack segment stack
      dw 32 dup(0)
stack ends

code segment
start:mov ax, cs
      mov ds, ax
      mov si, offset int7ch
      
      xor ax, ax
      mov es, ax
      mov di, 200h
      
      mov cx, offset int7chend - offset int7ch
      cld
      rep movsb
      
      cli
      mov word ptr es:, 200h
      mov word ptr es:, 0h
      sti
      
      mov ax, 4c00h
      int 21h
      
int7ch: jmp short screenstart
      dw sub1 - int7ch + 200h, sub23 - int7ch + 200h, sub23 - int7ch + 200h, sub4 - int7ch + 200h
      
screenstart:
      push bx
      cmp ah, 3
      ja quit
      
      mov bl, ah
      xor bh, bh
      add bx, bx
      
      call word ptr cs:
      
quit:   pop bx
      iret
      
sub1:   push cx
      push ds
      push si
      
      mov si, 0b800h
      mov ds, si
      mov si, 0
      
      mov cx, 4000h
sub1s:mov byte ptr , 0
      add si, 2
      loop sub1s
      
      pop si
      pop ds
      pop cx
      ret
      
      ; 子程序2和3的功能类似,合并为一了
sub23:push bx
      push cx
      push ds
      push si
      
      jmp sub23switch
      submask db 11111000b, 10001111b ; 色彩掩码
      bits db 0, 4 ; 移动位数
sub23switch:
      mov bx, 0b800h
      mov ds, bx
      mov si, 1
      
      mov bl, ah
      xor bh, bh
      shr bx, 1 ; 这里是将1和2对应为0和1
      
      ; 假如修改背景色,al是要左移4位的
      mov cl, cs:
      shl al, cl
      mov bl, cs:
      
      mov cx, 2000h
sub23s: and , bl
      or , al
      add si, 2
      loop sub23s
      
      pop si
      pop ds
      pop cx
      pop bx
      ret
      
sub4:   push cx
      push ds
      push es
      push si
      push di
      
      mov si, 0b800h
      mov ds, si
      mov es, si
      mov si, 80 * 2
      mov di, 0
      
      cld
      mov cx, 24
sub4s:push cx
      mov cx, 160
      rep movsb
      pop cx
      loop sub4s
      
      mov cx, 80
sub4s1: mov byte ptr , 0
      add si, 2
      loop sub4s1
      
      pop di
      pop si
      pop es
      pop ds
      pop cx
      ret
      
int7chend:
      nop
      
code ends
end start

大约可以节省15字节的空间

定址方法并不算好,只是权宜之计。假如中断程序安装的位置发生了变化,本程序需要修改的地方还是比较多的。

下面总结两种个人认为很有价值的方案:
1、将需要安装的中断程序放在主程序前面。这样的好处在于不论在安装程序中还是在安装后的中断程序中,直接定址表中保存的偏移地址是一致的,不需要像我的程序需要大量换算。此时,中断向量表中的cs和ip就不能是0和200h了,而应该是20h和0,个中妙处实在难以言喻。
2、采用ORG伪指令。依旧是主程序在前中断程序在后,但在中断程序前加ORG 200h指令,规定下面的代码从200h开始,这样一来,直接定址表就会按照200h为基准计算偏移。
以上两种方案的优势均在于思路直观,便于修改

ps:如果采用宏,我的程序也并不是很难改的,只是我还不会 :P
页: [1]
查看完整版本: 实验16——为了节约内存,拼了。。。