home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.tar / ftp.whtech.com / club100 / pg / pggene / ml-pgm.tip < prev    next >
Text File  |  2006-10-19  |  5KB  |  134 lines

  1.           ML-PGM.TIP  by Paul Globman
  2.               Copyright (c) 1990
  3.           ---------------------------
  4.  
  5. I believe that over time, most assembly language programmers develop their own
  6. handy little routines, to do one thing or another.  I would like to share a
  7. couple of tips that I often use, which will save a few bytes in your program,
  8. and make your program run faster, and safer.
  9.  
  10. TIP #1
  11. ------
  12. Assembly language programs must leave no stones unturned, and the programmer is
  13. responsible for considering every possibility that the program might encounter.
  14. This includes errors, subroutine re-direction, and stack manipulation.
  15.  
  16. The Model 100 ROM operating system is very capable of managing free RAM,
  17. allocating file buffers for BASIC programs, and maintaining the computers
  18. "stack area".  Most assembly language programs assume that the stack is
  19. properly positioned and make no attempt to alter or relocate the stack.
  20.  
  21. This is common and not incorrect in the Model 100 environment, but depending
  22. upon the program, the stack could become larger than expected, and run into an
  23. area of memory that should not be used.  Here's an example of how this could
  24. happen... consider this program...
  25.  
  26. begin:    call display
  27.     call get_input
  28.     call function
  29.     jmp begin
  30.  
  31. Now suppose you are in the middle of the "function" routine, and you discover
  32. the input is not valid. You wish to send the user a BEEP, and start over again.
  33. Since you got to the "function" routine via a CALL, the stack is holding the
  34. return address of the call.  So a simple BEEP and return will not restart the
  35. program, and a BEEP with a JMP BEGIN will leave the stack with the previous
  36. CALL's return address still on the stack.
  37.  
  38. You could have an error routine and JMP ERROR.  The error routine could pop the
  39. unwanted address off the stack, BEEP and JMP BEGIN, for example...
  40.  
  41. error:    pop h
  42.     call beep
  43.     jmp begin
  44.  
  45. This type of error trap is okay, but the POP H instruction requires that ERROR
  46. should only be jumped to when only one CALL instruction has been executed.
  47. Very often programmers write all their routines as subroutines.  So routine #1
  48. will call routine #2, which calls routine #3, which encounters an error.  Now
  49. the above ERROR routine will not solve the problem of keeping the stack
  50. balanced ("balanced" means a RETURN for every CALL and a POP for every PUSH).
  51. If this happens frequently in a program, the stack pointer can quickly run down
  52. into an area of memory containing data or programs, and cause program
  53. malfunction, destroyed files and programs, or even cold starts.
  54.  
  55. Here's how to ensure stack balancing, regardless of how many nested CALLS, or
  56. unmatched PUSHes you have executed.  You can break out to an error routine
  57. without concern of stack pointer housekeeping.
  58.  
  59. start:    lxi h,0
  60.     dad sp
  61.     shld begin+1
  62. ;
  63. begin:    lxi sp,0
  64.     call display
  65.     call get_input
  66.     call function
  67.     jmp begin
  68. ;
  69. error:    call beep
  70.     jmp begin
  71.  
  72. By executing the three instructions before BEGIN, you ensure that every time
  73. you JMP BEGIN the stack pointer is reset.  This is done by making the first
  74. instruction of BEGIN restore the stack pointer to its original value.  You can
  75. JMP ERROR (or JMP BEGIN) at any time without concern about CALLs, PUSHes, or
  76. stack balancing.
  77.  
  78. I would also point out that this technique can be used more than once within
  79. a single program, thus restoring the SP register to what it should be at
  80. different parts of the program.  This will allow the program to freely abort
  81. subroutines when necessary, and spare the programmer the need to write special
  82. "housekeeping" code for each aborted subroutine.
  83.  
  84.  
  85. TIP #2
  86. ------
  87. Very often the assembly language programmer will use DB and DW statements to
  88. Define Bytes or Define Words (word = 2 bytes).  This is a common way for one
  89. part of a program to pass a value to a subroutine, for example...
  90.  
  91. main:    sta value1
  92.     shld value2
  93.     call sub1
  94.      .
  95.      .
  96.  
  97. sub1:    lda value1
  98.     lhld value2
  99.      .
  100.      .
  101.     ret
  102.  
  103. value1:    db 0
  104. value2:    dw 00
  105.  
  106. In the above listing, the main program stores A and HL in the data storage
  107. areas, value1 and value2.  Then a subroutine that needs those values will get
  108. them from the storage area, and use them as needed.
  109.  
  110. Now consider this alternative...
  111.  
  112. main:    sta sub1+1
  113.     shld v2+1
  114.     call sub1
  115.      .
  116.      .
  117.  
  118. sub1:    mvi a,0
  119. v2:    lxi h,0
  120.      .
  121.      .
  122.     ret
  123.  
  124. Note that the main program stores the A and HL values directly into the operand
  125. address of the instruction designed to retrieve those values.  This eliminates
  126. the need to allocate space for the variables, and "immediate" instruction (MVI
  127. and LXI) executes much faster than its "reference" counterpart (LDA and LHLD).
  128. You save bytes and have a faster running program!
  129.  
  130. I've been using these programming techniques for some time now, and I'm sure
  131. they will be useful to the experienced (as well as the novice) assembly
  132. language programmer.
  133.  
  134.