灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2905回复:0

[系统教程]汇编语言---程式设计 (4)

楼主#
更多 发布于:2011-10-07 09:04
第五节    程式写作

    说了不少,才真正到了写作程式的时候,运用指令就相当于写程式。只是,在运用指令前,一定要充份瞭解一应相关的课题。否则,应用指令如同和稀泥一般,堆砌出一团可以运作的成品,我个人不认为那能叫做「写程式」,充其量只是涂鸦罢了。

一、暂存器安排

    因为暂存器不足,必须事先安排妥当,才能有效应用。
    再以前例说明,需要安排的因素有:
  1,字形大小:此项有两个变数需要安排,一是横向之始、终值; 另一是纵向之始、终值。因为在设计之初,我已经      考虑到极限值的问题,将上限定在 256点,恰在一个字元    的范围内。所以我们可以把横向始值放在暂存器BL中,终值放在BH,而纵向始值放在DL,终值放进DH。

  2,笔画粗细:有四个变数值,放在CL中,并使CH为0。( 这点相当重要,为了精简和效率,最好有一个暂存器为0)

  3,字码送入:在始存器SI中。

  4,字形输出:在终存器DI中,根据BX及DX值求得。

二、程式规格

    第二章第四节已介绍过,在此从略。

三、程式及说明

       ------程  式  部  份-----     ----说明部份----
    1: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    2: ;功能:仓颉表格码绘图用。";"后,皆为注解。   ;
    3: ;输入参数:DS:SI=字码(1-2 码),=0为终止。;
    4: ;      BL=X1   BH=X2             ;
    5: ;      DL=Y1   DH=Y2             ;
    6: ;      CX= 笔画粗细值。            ;
    7: ;输出结果:点阵在ES:DI中。            ;
    8: ;破坏暂存器:全部。                ;
    9: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   10: CCODIN:                 ; 字码输入
   11:        LODSB             ; 取一码以作图
   12:        MOV    CL,AL         ; 取粗细值
   13:        INC    AX         ; 调整码值
   14:        AND    AX,001EH     ; 24个有效双数值
   15:        PUSH    BX         ; 保留后用
   16:        PUSH    DX         ; 同上
   17:        MOV    SI,AX         ; AX不能间接定址
   18:        AND    CL,07H         ; 有效值
   19:        CALL    CCODTB[SI]   ; 假设CS=DS
   20:        POP    DX
   21:        POP    BX
   22:        JMP    CCODIN         ; 本程式主流程
   23: CCOD00:                 ; CODe为码
   24:        ADD    SP,6         ; 本程式为子程序
   25:        RET             ; 码为0执行完毕
   26: CCOD06:                 ; 06为 E,F
   27:        SHL    CL,1         ; E,F 粗细值加倍
   28: CLFT02:                 ; LeFT指左横
   29:        ADD    BH,BL         ; 02为输入码 A,B
   30:        SHR    BH,1         ; 左起BH中点值
   31:        JMP    CHOR00         ; HORizon 画横
   32: CCOD08:                 ; 08为G,H
   33:        SHL    CL,1
   34: CLEF04:                 ; 04为C,D
   35:        ADD    DH,DL
   36:        SHR    DH,1         ; 上起DH为中点值
   37:        JMP    CVER00         ; VERtical画直
   38: CCOD0E:
   39:        SHL    CL,1
   40: CRGT0A:                 ; RiGhT 指右横
   41:        ADD    BL,BH         ; 0A为码I,J
   42:        SHR    BL,1         ; BL为中点值
   43:        JMP    CHOR00
   44: CCOD10:
   45:        SHL    CL,1
   46: CCOD0C:
   47:        ADD    DL,DH
   48:        SHR    DL,1         ; DL为中点值
   49:        JMP    CVER00
   50: CCOD16:
   51:        SHL    CL,1
   52: CCOD12:
   53:        JMP    CHOR00
   54: CCOD18:
   55:        SHL    CL,1
   56: CCOD14:
   57:        JMP    CVER00
   58: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   59: ;以下为各码之模组程式,间接定址表    ;
   60: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   61: CCODTB    DW    CCOD00         ; 结束
   62:        DW    CCOD02         ; 码 A,B左横细轻
   63:        DW    CCOD04         ; 码 C,D上直细轻
   64:        DW    CCOD06         ; 码 E,F左横粗重
   65:        DW    CCOD08         ; 码 G,H上直粗重
   66:        DW    CCOD0A         ; 码 I,J右横细轻
   67:        DW    CCOD0C         ; 码 K,L下直细轻
   68:        DW    CCOD0E         ; 码 M,N右横粗重
   69:        DW    CCOD10         ; 码 O,P下直粗重
   70:        DW    CCOD12         ; 码 Q,R长横细轻
   71:        DW    CCOD14         ; 码 S,T长直细轻
   72:        DW    CCOD16         ; 码 U,V长横粗重
   73:        DW    CCOD18         ; 码 W,X长直粗重

    程式到此全部完毕,唯画横及直与本主题无关,在此不做说明。由这段程式,可以看出最初规划输入码不理想之处,以致于需要在各处加粗细值,读者不妨自行研究改良之。
    程式长度为88个字元,共用程式原来已有,在此不计。
    此外,本段程式重复应用了几个指令,有很多方法可以精简,也有待读者动手。
    至于画横及直的子程式CHOR00和CVER00,其位置远近也影响写作方式,在此,且假定在 128B 之内,皆为短跳。否则还要动脑筋,设法简省之。
    还有,读者应该注意到,这段程式中,没有检查错误的手续,那是因为在内码处理时,已经保证无误。一般说来,检查错误是必要的程序。
    改进之方法,姑在此略作导引,设若编码时,将四个连续码视作由细至粗,而把位置分为六组,是则更易记忆,且程式可以减少28个字元之多。由此可见,像这样精简的程式,因资料结构上的缺陷,仍有改进的余地。
    第六节    特殊技巧的运用

    技巧的运用,关系组合语言的效率甚钜,虽然其重要性比不上整体规划,但也可以弥补规划的不足。
    由于「技巧」无法严格定义,兹将几种较常用的技巧介绍如下:

一、变数法:

    我非常反对在程式中采用「常数」的观念,因为常数是固定的,无法灵活应用。例如在 IBM PC 的 Bios 中,萤幕游标上、下、左、右位置固定设为 0,25,0,80 等常数值。每次移动都受到这四个值的限制,故而形成不变的「视区」。若将这些常数改为变数,且容许使用者自行改变,则立即有了可变「视窗」的功能。
    也就是说,萤幕上、下、左、右四个位置,所围起来的区域,就是我们视觉及资料所限制的「视窗」,所有资料显示,在系统程式的控制下,无法超出此区。
    如果此四个位置值是变数,则使用者可以随意设定所需数值,如是则灵活方便,也就是所谓的视窗处理。
    在下文三、虚拟法例中,CKFUN 该段程式即为用变数处理视窗的范例。下面这段程式,亦为变数法的一种应用, MAP87和MAP9A 中,均需调用子程式DYBPJ1,唯一不同者,是在该子程式中,又需分别调用不同的子程式。共用DYBPJ1的方法,是先将不同子程式的位址,放在BP中,再行调用。
    1:MAP87:
    2:        MOV    BP,OFFSET MAPF4
    3:        CALL    MOVS211
    4:        CALL    DYBPJ1
    5:        MOV    DL,AH
    6:        ..

   11:MAP9A:
   12:        MOV    BP,OFFSET MAP46
   13:        CALL    DYBPJ1
   14:        MOV    AH,1
   15:        ..

   20:DYBPJ1:
   21:        PUSH    BX
   22:        PUSH    DX
   23:        MOV    DH,DL
   24:        CALL    BP
   25:        POP    AX
   26:        XCHG    DH,AH
   27:        POP    BX
   28:DYBPJRT:
   29:        RET

二、对称法:

    本法实际上就是利用间接定址的指令,将原系对称处理,或可以调整成为对称型的程式,灵活调用。
    下面这段程式,表面看来似乎毫不相干,但经过整理后,就有了眉目,然后再以暂存器间接定址,合并为一。像这种程式,规模越大,所节省的空间就越多。
    1:ABCD:
    2:        CMP    DX,BUFA
    3:        JB    ABCD1
    4:        CMP    CL,BUFD
    5:        JB    ABCD1
    6:        MOV    BUFC,CL
    7:        INC    BUFE
    8:        MOV    BUFB,DX
    9:        DEC    BUFF
   10: ABCD1:
   11:        ..
   12:        ..
      与另一段程式:
   20:EFGH:
   21:        CMP    BX,BUFG
   22:        JB    EFGH1
   23:        CMP    CH,BUFH
   24:        JB    EFGH1
   25:        INC    BUFK
   26:        DEC    BUFL
   27:        MOV    BUFI,BX
   28:        MOV    BUFJ,CH
   29:EFGH1:
   30:        ..
   31:        ..
    看来分别很大,先经过整理,得到左右两组程式:
    EFGH:              ABCD:
    CMP    BX,BUFG       CMP        DX,BUFA
    JB    EFGH1          JB        ABCD1
    CMP    CH,BUFH       CMP        CL,BUFD
    JB    EFGH1          JB        ABCD1
    INC    BUFK          INC        BUFE
    DEC    BUFL          DEC        BUFF
    MOV    BUFI,BX       MOV        BUFB,DX
    MOV    BUFJ,CH       MOV        BUFC,CL
    EFGH1:              ABCD1:
    ..              ..
    ..              ..
    对照之下可以看出,其所不同的,只是暂存器及缓冲器的分别而已。这种程式的出现,是由于事先规划不当,未能通盘考虑,头痛医头,脚痛医脚。原可以把暂存器及缓冲器统一运用,现在木已成舟,想要变更很可能影响大局。
    其次是写作的风格及习惯没有养成,在用指令时,信手拈来,以致两段程式,两种写法!
    现在唯一的补救方法,是利用间接定址法,先将两组不同的缓冲器,照相对次序排列妥当,再改写程式。
    1:ABCD:
    2:        MOV    SI,OFFSET BUFA
    3:        MOV    DI,OFFSET BUFB
    4:        MOV    BX,DX
    5:        MOV    CH,CL
    6:        JMP    SHORT EFGH1
    7:EFGH:
    8:        MOV    SI,OFFSET BUFG
    9:        MOV    DI,OFFSET BUFI
   10:EFGH1:
   11:        CMP    BX,[SI]
   12:        JB    EFGH2
   13:        CMP    CH,[SI+2]
   14:        JB    EFGH2
   15:        MOV    [DI],BX
   16:        MOV    [DI+2],CH
   17:        INC    BYTE PTR[DI+3]
   18:        DEC    BYTE PTR[DI+4]
   19:EFGH2:
   20:        ..
    其缓冲器的相对顺序,如下所示:
   35:BUFA    DW    0
   36:BUFD    DB    0
   37:BUFB    DW    0
   38:BUFC    DB    0
   39:BUFE    DB    0
   40:BUFF    DB    0
   41:..
   65:BUFG    DW    0
   66:BUFH    DB    0
   67:BUFI    DW    0
   68:BUFJ    DB    0
   69:BUFK    DB    0
   70:BUFL    DB    0
    凡对称形式或结构相同的程式,都可以采用这种技巧。

三、虚拟法:

    对来处不同的资料,只要性质相同,都可以采用虚拟的技巧,将各种参数事先设妥,利用参数统一处理。
    兹有一程式,系供萤幕画图之用,所有功能皆用游标完成之,特以此段处理游标的程式为例说明如后。
    先虚拟各种功能及缓冲器:
    区段位移:         BBBLKMOV     DB  ?     ;?= 位移值
    十字游标:         BBCROCSR     DB  ?     ;?= 位移值
    视框移动:         BBFRMMOV     DB  ?     ;?= 位移值
    画笔作图:         BBDRW     DB  ?     ;?= 画笔宽
    橡皮擦:         BBDEL     DB  ?     ;?= 橡皮宽
    闪动游标:         BBCSR     DB  ?     ;?= 游标宽
    文字显示:         BBCHRDSP     DB  ?     ;?= 字框值
    游标移动值:     BWMOV     DW  ?     ;依当前功能先                           ;设定
    视框上限:         BWTOP     DW  ?     ;?= 设定值
    视框下限:         BWBTM     DW  ?     ;?= 设定值
    视框左限:         BWLFT     DW  ?     ;?= 设定值
    视框右限:         BWRGT     DW  ?     ;?= 设定值
    右界边际值:     BWADDX     DW  ?     ;?= 字或图宽
    ..
    程式入口:         CHKKEY     DW  CK47; 向左上移
                 DW  CK48; 向上移
                 DW  CK49; 向右上移
                 DW  CRET; 无效
                 DW  CK4B; 向左移
                 DW  CRET; 无效
                 DW  CK4D; 向右移
                 DW  CRET; 无效
                 DW  CK4F; 向左下移
                 DW  CK50; 向下移
                 DW  CK51; 向右下移
    AX =  输入游标键扫瞄码
    BP =  萤幕X向移动值
    DX =  萤幕Y向移动值
    ES:DI=萤幕记忆区位址

    主流程: ( 已知 AL=0 AH=Scan-Code )
    1:KEYIN:
    2:        SUB    AH,47H        ; =HOME
    3:        JB    KEYRET        ; 无效
    4:        CMP    AH,11        ; >扫瞄码范围
    5:        JA    KEYRET
    6:        MOV    BL,AH
    7:        SUB    BH,BH
    8:        SHL    BX,1
    9:        MOV    AX,BWMOV    ; 移动值
   10:        JMP    CHKKEY[BX]  ; 进入各处理程式
   ..
   40:CK47:
   41:        SUB    DX,AX        ; Y 向
   42:CK4B:
   43:        NEG    AX        ; 向左为负
   44:CK49:
   45:        ADD    BP,AX        ; X 向
   46:        JMP    SHORT CKFUN
   47:CK4D:
   48:        SUB    DX,AX
   49:        JMP    CK49
   50:CK51:
   51:        ADD    DX,AX
   52:        JMP    CK49
   53:CK48:
   54:        NEG    AX        ; 向上为负
   55:CK50:
   56:        ADD    DX,AX
   57:CKFUN:             ; 用变数观念检查「视窗」
   58:        CMP    DX,BWTOP    ; 超出上限?
   59:        JNS    CKFUN1
   60:        MOV    DX,BWTOP    ; 上限值
   61:CKFUN1:
   62:        CMP    DX,BWBTM    ; 超出下限?
   63:        JBE    CKFUN2
   64:        MOV    DX,BWBTM    ; 下限值
   65:CKFUN2:
   66:        CMP    BP,BWLFT    ; 超出左限?
   67:        JNS    CKFUN3
   68:        MOV    BP,BWLFT    ; 左限值
   69:CKFUN3:
   70:        PUSH    BP
   71:        ADD    BP,BWADDX   ; 右限+边际值再比
   72:        CMP    BP,BWRGT    ; 超出右限?
   73:        POP    BP
   74:        JBE    CKFUN4
   75:        MOV    BP,BWRGT    ; 右限值
   76:CKFUN4:
   77:        ..
    CKFUN4以下为功能处理,由前面的功能参数决定。
    用这种方法,多种功能可以共用一个入口,程式精简且速度快。(灯火互联网)


喜欢0 评分0
游客

返回顶部