Author Topic: A question regarding macros  (Read 3254 times)

0 Members and 1 Guest are viewing this topic.

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
A question regarding macros
« on: March 28, 2007 »
I was wondering if this kind of thing is considered good practice or if its real bad I wanna simulate subroutine calls by using macros to define the inputs but use a proceedure to do all the horse work the advantage being that only a small portion of code is assembled at the point of calling the macro also functionality of macros is improved you can loop in a proceedure but not in macros.
The disadvantage is that it becomes necessary to use the org directive prior to include directives and I am not sure if it works in multiple segment exes. Also proceedures will make their way into code even if the macro which uses that proceedure is not called in the program. Also com files require that a jump be placed before the include directive or else those proceedures will be executed (not good when cpu comes accross a ret instruction)

This example demonstrates the idea what it does is prints a zero terminated string to the screen at the specified co-ordinates then returns the length of the string. both macros share the same proceedure that calculates the length of the string so thats one bonus

Code: [Select]
name "consoleio.inc"
org  100h
jmp  start

$col db 0Fh
;#######################################################
; prints string to screen at the given co-ordinates
; current text colour is used (set colour with col$)
text macro x$,y$,$
    push es       ; preserve es
    pusha         ; preserve registers
    mov  bx,x$    ; get x value
    mov  dx,y$    ; get y value
    lea  si,$     ; get string offset
    call textproc
    popa          ; restore registers
    pop  es       ; restore es
text endm
textproc proc
    ; find length of string
    mov   di,si    ; string address
    call lenproc
    mov   di,si    ; string address
    ; prepare offset for co-ordinates
    push  0B800h   ; screen text buffer
    pop   es
    mov   ax,160   ; screen width in bytes (80 words/chars)
    mul   dx       ; convert to offset
    add   ax,bx    ; x co-ordinate
    add   ax,bx    ; double x (for word)
    mov   di,ax    ; load finished offset
    ; print it to screen
    mov   ah,$col  ; colour attributes
    textloop:
        lodsb      ; load next char
        stosw      ; store char & colour
        loop textloop
    ret
textproc endp

;#######################################################
; returns the length of strint (terminated by zero)
; result is stored in cx
len$ macro $
    push di
    lea  di,$   ; string offset
    call lenproc
    pop  di
len$ endm
lenproc proc
    push es     ; preserve es
    pusha       ; preserve registers
    cld         ; clear flags
    xor   al,al ; compare zero
    mov   cx,-1 ; compare maximum 0FFFFh times
    repnz scasb ; compare until both are zero
    not   cx    ; invert cx
    dec   cx    ; point cx to char before the zero
    mov   es,cx ; conserve value in es
    popa        ; restore registers
    mov  cx,es  ; restore value
    pop  es     ; restore es
    ret
lenproc endp

start:
    mov  ax,03h     ; text mode
    int  10h        ; bios call
    mov  ah,01h     ; cursor attributes
    mov  cx,2B0Bh   ; hide blinking
    int  10h        ; bios call
    text 5,5,string ; prints string to screen
    len$ string     ; length of input is stored to cx
    xor  ah,ah      ; wait for keypress
    int  16h
    ret

    string db "Hello world",00h

Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: A question regarding macros
« Reply #1 on: March 28, 2007 »
There's nothing particularly wrong with the way you're doing that.  The one thing I would advise - which might mean you don't need the macros as much - is to have a 'calling convention'.  That means, decide which registers are and are not corrupted by any subroutine.  So for instance, you might decide that all registers except ax are to be preserved by every subroutine (which is very common).  That means all the pushes and pops are in only one place, the beginning and end of the subroutine, and not every place you call the routine from.  It also means you can call the subroutines with confidence that it won't muck up the registers you are currently using and you have a consistent interface to every function.

You can put the actual subroutines at the end of the program to avoid having the jmp start in there.  If your assembler complains, configure it to make more passes.

Jim
Challenge Trophies Won:

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: A question regarding macros
« Reply #2 on: March 28, 2007 »
Thanks Jim that makes sense in fact to get the len$ macro to work properly I had to put the pusha & popa in the proceedure it messed it all up when they were in the macro. I think I will change the rest of the macros around so that only ax is used to return values its no big problem and now that I think of it I wont be spending time going through the include file to check what register the return is in. Thanks

Challenge Trophies Won: