home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / modem / async1.arc / ASYNC.DOC < prev   
Text File  |  1985-09-13  |  14KB  |  276 lines

  1.                                    Async.Asm
  2.                                 Operation Notes
  3.                               by Jerry D. Stuckle
  4.                                Userid: 72205,234
  5.  
  6.   Async.Asm is an example assembler program to drive the Asynchronous Adapter
  7. in the IBM-PC.  It accepts the same parameters as the ROM BIOS Interrupt 14
  8. code, with the exception that only one port (COM1:) is available.  The code
  9. can be easily modified to handle two communications ports, but for 1 only
  10. wrote the code for one port to keep things simple.
  11.  
  12.    This routine provides a buffered byte-stream interface to the
  13. communications port.  The following parameters can be used.
  14.  
  15.    AH=0  Open communications port.
  16.    AL has initialization parameters
  17.  
  18.         7       6       5       4       3       2       1       0
  19.         ----Baud Rate----      --Parity--     -Stop-    -Word Len-
  20.             000 -  110          X0 - None     0 - 1     00 - 5 bits
  21.             001 -  150          01 - Odd      1 - 2     01 - 6 bits
  22.             010 -  300          11 - Even               10 - 7 bits
  23.             011 -  600                                  11 - 8 bits
  24.             100 - 1200
  25.             101 - 2400
  26.             110 - 4800
  27.             111 - 9600
  28.  
  29.    On return, conditions set as in call to comm status (AH=3)
  30.  
  31.    AH=1 Send the character in AL to the port.  (AL is preserved).  On exit,
  32. Bit 7 of AH is set if the buffer is full.  If Bit 7 of AH is not set, the
  33. remainder of AH is set as in status request, reflecting the current status of
  34. the line.
  35.  
  36.    AH=2 Receive a character in AL from the port before returning to the
  37. caller. On Exit, if AH is 0FF, the buffer was found to be empty and AL is
  38. indeterminate.  Otherwise, AH has the current line status as set by the status
  39. routine, except the only bits left on are the error bits (7,4,3,2,1).  If AH
  40. has bit 7 on (time out) the remaining bits are unpredictable.  Thus, AH is
  41. non-zero only if errors have occurred.
  42.  
  43.    AH=3 Return the port status in AX.
  44.  
  45.      AH contains the line status
  46.      Bit 7 = Time out
  47.      Bit 6 = Trans buffer empty
  48.      Bit 5 = Trans buffer not full
  49.      Bit 4 = Break detect
  50.      Bit 3 = Framing error
  51.      Bit 2 = Parity error
  52.      Bit 1 = Receive buffer overrun
  53.      Bit 0 = Data ready in receive buffer
  54.  
  55.      AH=FF = Invalid parameter in request.
  56.  
  57.        AL contains the modem status
  58.        Bit 7 = Received line signal detect
  59.        Bit 6 = Ring indicator
  60.        Bit 5 = Data set ready
  61.        Bit 4 = Clear to send
  62.        Bit 3 = Delta receive line signal detect
  63.        Bit 2 = Trailing edge ring indicator
  64.        Bit 1 = Delta data set ready
  65.        Bit 0 = Delta clear to send
  66.  
  67.    AH=4 Close communications port. Resets the communications line and flushes
  68. the buffers.
  69.  
  70.    For all values of AH. DX = parameter indicating which communications port
  71. to use (0 allowed).
  72.  
  73.    Other than AX, all other registers returned unchanged for all calls.
  74.  
  75.    Note: The following changes have been made from the BIOS interrupt 14
  76. driver:
  77.  
  78.    1: This routine is completely interrupt driven, with transmit and receive
  79. buffers so the program does not have to wait for data.
  80.  
  81.    2: Function call 0 (Initialize) will immediately return control to the
  82. program. It is the programmer's responsibility to ensure the port is actually
  83. ready before sending data, although data can be sent.  This allows the program
  84. to open the port with no carrier received.
  85.  
  86.    3: AH=1 will return with Bit 7 of AH set only if the transmit buffer is
  87. full.  Otherwise, the character will be placed in the buffer and transmitted
  88. when the port catches up with the buffer.
  89.  
  90.    4: AH=4 is a new call.  It will disable the interrupts and flush the
  91. transmit and receive buffers.  It should be called before program termination
  92. to disable the port.
  93.  
  94.    5: On all calls, the following bits in AH have changed:
  95.  
  96.        Bit 6 is now Transmit buffer empty.
  97.        Bit 5 is now Transmit buffer not full.
  98.        Bit 1 is now Receive buffer overrun.
  99.        Bit 0 is now Receive buffer not empty.
  100.  
  101.    These bits correspond to equivalent bits in the original code, i.e. Bit 0
  102. was Data ready, and now indicates something in the receive buffer (data
  103. ready).
  104.  
  105.    The receive buffer overrun bit should not occur, if the receive buffer is
  106. large enough and called frequently enough.  If it does occur, the buffer data
  107. is still good, but data will be missing and integrity compromised. The data
  108. will be lost starting X bytes past the current buffer, where X is the buffer
  109. size.
  110.  
  111.    The program was written in a modular form, with mainline code performing
  112. parameter verification checks and routine selection.  All work is done in
  113. procedures.  Some simple macros are included for commonly used functions, and
  114. the transmit and receive buffers are defined using a structure.
  115.  
  116.    Also, I like to use both upper and lower case characters for coding in
  117. assembler.  All registers are in upper case only (AX,BX, etc.) while
  118. everything else is capitalized (Functble, Cinit, etc.).  I feel this makes the
  119. code more readable, but it is up to the programmer writing the code what
  120. format he/she uses.  The only time it will make a difference is in comparing
  121. parameters in a macro call (I.E. using the Ifidn <A>,<a>). This function is
  122. case sensitive, and will fail in the example above.
  123.  
  124.    Since we are working with mostly bytes and port address, this routine uses
  125. .Radix 16.  It could have also been written with the default of .Radix 10, but
  126. then many values would have had to have an 'h' (hexadecimal) notation
  127. following.  As it stands, the only values which need the 'h' appended are
  128. those ending in a 'b' or 'd', which would otherwise signify binary or decimal
  129. representation, respectively.
  130.  
  131.    There are two main procedures in the code.  Int14 is the interrupt 14
  132. handler, and is the user interface to the program.  It replaces the existing
  133. Int14 handler in BIOS and DOS, and for the most part contains the same
  134. functions as the original handler.  (See Async.Doc for specific information).
  135.  
  136.    The other main procedure is Int0C, which is the machine's interface.  It
  137. uses the machine's hardware interrupt 0C from the communications port to drive
  138. it.  When status changes (i.e. character received, modem dropped ready, etc.)
  139. the Int0C code is driven to handle the resultant hardware interrupt.  This
  140. allows the program to update the buffers and/or status indicators when they
  141. occur, and relieves the program of the need to check except when it is ready
  142. to receive the data.
  143.  
  144.    The macros used in the program are defined at the beginning.  These macros
  145. are used in place of coding common code several times in the program, saving
  146. time and the possibility of "finger checks".  They also make reading the code
  147. and debugging easier.  The macros will expand in the listing of the code, so
  148. you can see exactly what is generated for later debugging.
  149.  
  150.    Liberal use of Subttl and Page pseudo-ops have been used to make output
  151. formatting logical and easier to read.  I have found the time saved trying to
  152. find an area of code is much worth the few pages of extra paper used in a
  153. large program.  Also, it starts a procedure at the top of the page instead of
  154. in the middle, making it easier to find later.
  155.  
  156.    Unless absolutely necessary, all jumps should be in a forward direction. If
  157. a jump must be made backwards (occasionally necessary for looping), it should
  158. be as short a distance as possible.  This will minimize the possibility of
  159. loops which cannot be exited, and the resultant reboot which will be
  160. necessary.
  161.  
  162.    One other note: It is possible to program in a structured fashion in MASM,
  163. if procedures are used effectively.  The use of a procedure does not mean it
  164. is called from multiple places in the program.  Rather, it should be a logical
  165. and complete unit or work - that is, a specific function should be desired
  166. upon entry, and that function completed at the end.  This modularity can allow
  167. some common routines to be used in other programs, and definitely makes the
  168. code easier to write and debug.
  169.  
  170.    Operation of the code follows:
  171.  
  172.    Upon entry, the program does a JMP to the initialization code at the end.
  173. This code is placed at the end as it is used once (when invoked from DOS) and
  174. not needed after that.  If placed at the end, its storage can be reused at a
  175. later time by other programs.
  176.  
  177.    At label START, we first initialize the buffers pointers.  This is one
  178. fault with using structures - you can't set an offset from the start of the
  179. program.  Using the pseudo-op '$' (instruction counter) just gives you the
  180. offset from the beginning of the structure. So we have to initialize the
  181. pointers.  After initializing the pointers, we set the interrupt 0C and 14
  182. vectors and terminate.  However, the Int 27 (used for DOS 1.x compatibility)
  183. allows the storage to remain allocated, and the program resident in memory.
  184.  
  185.    Once the program is installed, it is accessed through software through
  186. interrupt 14.  The hardware transfers control to procedure Int14, which
  187. verifies the parameters and calls the correct handling routine.  When control
  188. is returned to this routine, it restores the registers saved on entry and
  189. returns control to the caller through the Iret (Interrupt return) statement.
  190.  
  191.    When control is passed to Int14, it will select a routine to call based on
  192. the value in AH (request code).  It moves the value to BX, multiplies by 2 and
  193. uses this as an offset into a function call table.  The use of a table like
  194. this eliminates the need for checking every possible value of for the request,
  195. and returns control to one common place in the code.  It also makes it easier
  196. to add routines.  All you have to do is add your new routine and a pointer to
  197. it in the table.  The assembler will take care of everything else.
  198.  
  199.    AH = 0.  Copen is called which must be made before any other call.  It will
  200. initialize the system and asynch interrupt regs, flush the buffers of any
  201. residual data, and set the initial status.  Note that the system interrupt
  202. register (port 21) must be enabled BEFORE the asynch board, or you will get a
  203. lockout condition where you never get the interrupt processed.  (This one cost
  204. me four days of debugging!).
  205.  
  206.    AH = 1.  Csend will take the character in AL and place it in the transmit
  207. buffer.  If the buffer is full, it returns with the timeout bit set so the
  208. program can resend at a later time.  If the buffer is not full, it checks to
  209. see if transmit interrupts are enabled.  If they are, it returns with the
  210. status in AH.  If not, it enables the transmit interrupt so the interrupt 0C
  211. routine can send the character.
  212.  
  213.    AH = 2. Crcve will return a character from the buffer in AL and the status
  214. in AH.  If a character is not available, 0FF (-1) will be returned in AH so
  215. the program can check later.
  216.  
  217.    AH = 3. Cstat returns the current status in AH and modem status in AL.
  218.  
  219.    AH = 4. Cclos will disable interrupts from the asynch port and system and
  220. flush the buffers.  It must be the last function called when the program is
  221. through with the port.  Also note that the asynch port must be disabled BEFORE
  222. the system, or an incoming interrupt may cause problems next time the
  223. interrupts are enabled.
  224.  
  225.    The hardware interrupt processing procedure, Int0C, gets control whenever
  226. the communications port interrupts the system.  It runs asynchronously (pardon
  227. the pun) with the rest of the system, and is completely hardware controlled.
  228. The main routine resets the hardware controller at port 20 by putting an x'20'
  229. to it, determines what kind of interrupt is pending, and calls the appropriate
  230. routine.  This loop will continue until all outstanding interrupts are
  231. handled.  This code also uses a branch table and is the only place we have a
  232. backward jump in the code.  The correct routine is called, and the loop
  233. continues until the interrupt id register contains 01 (no interrupts pending).
  234.  
  235.    Procedure Modemst handles interrupt code 00 (modem status change).  This
  236. reads the modem status port and sets it into Mstatus for use by the program.
  237.  
  238.    Procedure Xmithrg handles interrupt code 02 (transmitter holding register
  239. empty).  If a byte is available in the transmit buffer, it is placed in the
  240. transmit register.  If not, the transmit holding reg empty interrupt is
  241. disabled.
  242.  
  243.    Procedure Rdatint handles interrupt code 04 (receive data available).  This
  244. is probably the most important interrupt to handles, as if this is not handled
  245. quickly enough, another character will overlay the one currently in the
  246. register and data will be lost.  If the receive buffer is full, the character
  247. is discarded and the overrun bit set in Lstatus.
  248.  
  249.    Procedure Rcvrlst handles interrupt code 06 (receive line status).  All it
  250. has to do is read the line status register and set it into Lstatus.
  251.  
  252.    This is a quick overview of the major blocks of the program.  This is a
  253. simple program with many changes which can be made.  For example, the routine
  254. could have XON/XOFF functions built in, the modem and line status could be
  255. enhanced, and other changes made.  However, this is a good base to start for
  256. someone who wants to play with the communications port interrupts.  Any simple
  257. routine which will pass characters from the keyboard to the Int 14 handler,
  258. and from the Int 14 handler to the display screen will work nicely to test
  259. this program.  This can be done in 50 lines or so of assembler code, and works
  260. nicely as a test for the program.
  261.  
  262. ===============================================================================
  263. Changes in this upload:
  264.  
  265. 1. The extra CLI at the beginning of the COPEN routine has been removed.
  266.  
  267. 2. Extra code in the CSEND routine has been removed.
  268.  
  269. 3. The line status code has been reworked to operate properly (and more
  270.    efficiently).
  271.  
  272. 4. The only operational change was to set the high order bit (80h) if a
  273.    character was received with a parity error.  As the parity error cannot
  274.    occur if running with 8 data bits, this will have no effect on binary
  275.    transfers of data.
  276.