_MS-DOS ASSEMBLERS COMPARED_

by Michael Schmit

[FIGURE 1]


problem:

            ...
            cmp  ax, 1
            je   near_label
            ... > 128 bytes of code
near_label:
            ...


correction:

            ...
            cmp  ax, 1
            jne  $ + 3
            jmp  near_label
            ... > 128 bytes of code
near_label:
            ...

[FIGURE 2]



Old method (MASM 5.0 and before):


         Public _sample_func
         _sample_func proc near
         push   bp
         mov    bp, sp
         push   bx
         push   cx
         push   dx

         mov    bx, [bp+4]    ; get ptr to var1
         ...

         pop    dx
         pop    cx
         pop    bx
         pop    bp
         ret
         _sample_func endp


New Method:

         .model small, C
         .code

         sample_func proc near USES BX CX DX, var1:PTR

         mov    bx, var1      ; get ptr to var1
         ...

         ret
         sample_func endp



[FIGURE 3]


                test description              MASM     TASM    OPTASM

    test 1 (15 files, 600K total)               85       50       35
    test 2 (6 files, 100K each)                 80       40       26
    test 3 (test 1 with wildcards/make)         85       34       24
    test 4 (test 2 with wildcards/make)         80       32       22


    Notes:
          1) Times are in seconds
          2) All tests on 10 MHz AT clone,
             zero wait states, Seagate
             ST-251 hard disk, no cache

There were 4 test cases run, as described in the article.
Each test consists of just 3 data points, one for each of the assemblers.




[FIGURE 4]


; MASM example

@@:
    inc   ax
    cmp   ax, bx
    je    @f
    loop  @b
@@:
    ret



; TASM example

@@loop:
    inc   ax
    cmp   ax, bx
    je    @@exit
    loop  @@loop
@@exit:
    ret

; OPTASM example

#1:
    inc   ax
    cmp   ax, bx
    je    #2
    loop  #1
#2:
    ret




[FIGURE 5]



title  MASM mode example program   ; comment in title
.model small

stdin   = 0
stdout  = 1
buf_len = 128

dosint MACRO function      ; macro to invoke a DOS interrupt 21h function
  mov ah, function
  int 21h
ENDM

.code

main PROC

   mov   ax, @data           ; load data segment
   mov   ds, ax
   mov   es, ax
   mov   dx, OFFSET inbuf    ; dest for input
   mov   bx, stdin           ; source of input
   mov   cx, buf_len         ; len for input
   dosint 3fh                ; read file
   cmp   ax, 2
   jle   fin
   mov   bx, ax
   mov   inbuf[bx-2], 0      ; null at end (remove CR LF)
   mov   cx, ax              ; len for example
   sub   cx, 2               ; removes CR LF
   call  lower_line
   mov   dx, OFFSET outbuf   ; source of output
   mov   bx, stdout          ; dest for output
   dosint 40h                ; write file
fin:
   dosint 4ch                ; exit to DOS

main ENDP

lower_line PROC near

   push  cx
   mov   si, OFFSET inbuf
   xor   di, di              ; for example no STOS for DI
   cld
loop1:
   lodsb                     ; read a char
   or    al, 20h             ; convert to lower case
   mov   outbuf[di], al      ; store in outbuf
   inc   di
   loop  loop1               ; loop til end of string
   pop   cx
   ret

lower_line ENDP

.data

inbuf  DB buf_len DUP(?)
outbuf DB buf_len DUP(?)

stk SEGMENT STACK            ; reserve space for stack
 db 100 dup(0)               ; using old segment method
stk ENDS

END main                     ; specify starting address

----------------------------------------

IDEAL
%title  "TASM IDEAL mode example program"   ; comment not in title
                             ; all directives affecting listing
                             ; file begin with a percent sign (%)

model small                  ; no periods in IDEAL directives

stdin   = 0
stdout  = 1
buf_len = 128

MACRO dosint function        ; label and MACRO reversed
  mov ah, function
  int 21h
ENDM

codeseg                      ; segmentation directive renamed

PROC main                    ; label and PROC reversed

   mov   ax, @data
   mov   ds, ax
   mov   es, ax
   mov   dx, OFFSET inbuf
   mov   bx, stdin
   mov   cx, buf_len
   dosint 3fh
   cmp   ax, 2
   jle   fin
   mov   bx, ax
   mov   [bx+inbuf-2], 0     ; memory reference must be in []
   mov   cx, ax
   sub   cx, 2
   call  lower_line
   mov   dx, OFFSET outbuf
   mov   bx, stdout
   dosint 40h
fin:
   dosint 4ch

ENDP main                    ; label and ENDP reversed

PROC lower_line near

   push  cx
   mov   si, OFFSET inbuf
   xor   di, di
   cld
@@loop1:
   lodsb
   or    al, 20h
   mov   [di+outbuf], al     ; memory reference in []
   inc   di
   loop  @@loop1             ; local labels available
   pop   cx
   ret

ENDP                         ; matching PROC name optional

dataseg                      ; segmentation directive renamed

inbuf  DB buf_len DUP(?)
outbuf DB buf_len DUP(?)

SEGMENT stk STACK            ; label and SEGMENT reversed
 db 100 dup(0)
ENDS                         ; matching SEG name optional

END main


