home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / MODEMS / NOISECHK.ZIP / NOISE.ASM < prev    next >
Encoding:
Assembly Source File  |  1989-01-29  |  33.2 KB  |  1,197 lines

  1. ;
  2. ;
  3. TITLE * NOISE.ASM 
  4. ;
  5. ;
  6. COMMENT *
  7.     Purpose:    Checks the transmission quality of phone lines.
  8.  
  9.     Created:    28-NOV-1988    V1.00    Richard B. Johnson
  10.  
  11.     Modified:    14-DEC-1988    V1.01    Richard B. Johnson
  12.     Added TESTING assembly conditional.
  13.     Removed some redundant code.
  14.     Added routine for stack-overflow test.
  15.  
  16.     16-DEC-1988    V1.02    Richard B. Johnson
  17.     Changed code in TX_WAIT to use HLT rather than a software-loop.
  18.     Should make the code more machine-independent.
  19.  
  20.     18-DEC-1988    V1.03    Richard B. Johnson
  21.     Added subroutine CLEAR to help get the UART restarted after missed
  22.     interrupts. Speeds up synchronization after a bad or incomplete block
  23.     has been received.
  24.  
  25.     19-DEC-1988    V1.04    Richard B. Johnson
  26.     Changed many routines to use in-line code to speed execution.
  27.     The UART hardware interrupt was completely rewritten. Also
  28.     the print-string routines were changed to 'write-file/device'
  29.     MACROS.
  30.  
  31.     20-DEC-1988    V1.05    Richard B. Johnson
  32.     Added routines to set the UART baud rate. Not usually used, but
  33.     it makes the code more complete. The table for baud-rate divisors
  34.     is placed in the interrupt-buffer to save space during execution.
  35.  
  36.     29-JAN-1988    V1.06    Richard B. Johnson
  37.     Fixed bug in communications-adapter port table, label, 'TABLE'
  38.     where COM3 was entered twice rather than COM3 then COM4.
  39. *
  40. FALSE    EQU    0
  41. TRUE    EQU    NOT FALSE
  42. TESTING    EQU    FALSE            ; "TRUE" disables carrier-det.
  43. CR    EQU    0DH            ; ASCII
  44. LF    EQU    0AH
  45. MS_DOS    EQU    21H            ; Dos function calls
  46. KBD    EQU    16H            ; Keyboard BIOS
  47. MAX    EQU    256            ; Max bytes per block
  48. ONE_SEC    EQU    18            ; Clock-ticks/second (about)
  49. ;
  50. ;    ASCII structures
  51. ;
  52. VERS    STRUC
  53.     DB    'V1.06'
  54. @VERS    DB    ' '
  55. VERS    ENDS
  56. HEAD1    STRUC
  57.     DB    ' C O M M U N I C A T I O N S'
  58. @HEAD1    DB    ' '
  59. HEAD1    ENDS
  60. ;
  61. HEAD2    STRUC
  62.     DB    ' Line Transmission Quality Monitor'
  63. @HEAD2    DB    ' '
  64. HEAD2    ENDS
  65. ;
  66. HEAD3    STRUC
  67.     DB    ' Version'
  68. @HEAD3    DB    ' '
  69. HEAD3    ENDS
  70. ;
  71. HEAD4    STRUC
  72.     DB    ' Created 2-DEC-1988   Richard B. Johnson'
  73. @HEAD4    DB    ' '
  74. HEAD4    ENDS
  75. ;
  76. HEAD5    STRUC
  77.     DB    ' - Use [ESC], [CTRL]-C, or [CTRL]-Break to end -'
  78. @HEAD5    DB    ' '
  79. HEAD5    ENDS
  80. ;
  81. NRM    STRUC
  82.     DB    27,'[0m'
  83. NRM    ENDS
  84. ;
  85. REV    STRUC
  86.     DB    27,'[7m'
  87. REV    ENDS
  88. ;
  89. SPACES    STRUC
  90.     DB    15 DUP (' ')
  91. SPACES    ENDS
  92. ;
  93. ;    Interrupt control equates.
  94. ;
  95. INT_CTL    EQU    21H            ; Interrupt controller address
  96. INT_NOS    EQU    20H            ; Non-specific end-of-interrupt
  97. INT_RES    EQU    20H            ; Interrupt controller reset addr.
  98. INT_1    EQU    0CH            ; For COM1
  99. INT_2    EQU    0BH            ; For COM2
  100. IRQ4    EQU    11101111B        ; For COM1
  101. IRQ3    EQU    11110111B        ; For COM2
  102. ;
  103. ;    8250 UART equates.
  104. ;
  105. MOD_STA    EQU    6            ; Offset to modem-status register
  106. LIN_STA    EQU    5            ; Offset to line-status register
  107. MOD_CTL    EQU    4            ; Offset to modem-control register
  108. LIN_CTL    EQU    3            ; Offset to line-control register
  109. INT_IDR    EQU    2            ; Interrupt identification register
  110. INT_ENA    EQU    1            ; Offset to interrupt-enable reg
  111. INT_RC    EQU    00000001B        ; Interrupt on received chars
  112. INT_TX    EQU    00000010B        ; Interrupt on TX empty
  113. INT_MS    EQU    00001000B        ; Interrupt on modem status change
  114. DR    EQU    00000001B        ; Data ready
  115. DTR    EQU    00000001B        ; Data terminal ready
  116. RTS    EQU    00000010B        ; Request to send
  117. NORM    EQU    00000011B        ; 8-bits, no parity, 1-stop bit
  118. TRI    EQU    00001100B        ; Tri-state enable
  119. THRE    EQU    00100000B        ; Transmitter holding register ready.
  120. RLSD    EQU    10000000B        ; Received line signal detect
  121. DLAB    EQU    10000000B        ; Divisor-latch access bit
  122. ;
  123. ;    Structures for communications adapters.
  124. ;
  125. COM1    STRUC
  126. BPRT    DW    03F8H            ; Base port
  127. INTN    DB    INT_1            ; Interrupt number
  128. IMSK    DB    IRQ4            ; Controller mask
  129. COM1    ENDS
  130. ;
  131. COM2    STRUC
  132. COM2PRT    DW    02F8H            ; Base port
  133. COM2INT    DB    INT_2            ; Interrupt number
  134. COM2MSK    DB    IRQ3            ; Controller mask
  135. COM2    ENDS
  136. ;
  137. COM3    STRUC
  138. COM3PRT    DW    03E8H            ; Base port
  139. COM3INT    DB    INT_1            ; Interrupt number
  140. COM3MSK    DB    IRQ4            ; Controller mask
  141. COM3    ENDS
  142. ;
  143. COM4    STRUC
  144. COM4PRT    DW    02E8H            ; Base port
  145. COM4INT    DB    INT_2            ; Interrupt number
  146. COM4MSK    DB    IRQ3            ; Controller mask
  147. COM4    ENDS
  148. ;
  149. ;         - MACROS -
  150. ;    Save interrupt vector(s) address
  151. ;
  152.     SAVE    MACRO ADDR,VECT
  153.     PUSH    ES            ; Save segment
  154.     MOV    AH,35H            ; Get vector function
  155.     IFNB    <VECT>
  156.     MOV    AL,VECT            ; Interrupt number
  157.     ENDIF
  158.     INT    MS_DOS            ; Get the vector, returns in ES:BX
  159.     MOV    WORD PTR [ADDR],BX    ; Save the offset
  160.     MOV    WORD PTR [ADDR+2],ES    ; Save the segment
  161.     POP    ES            ; Restore the segment
  162.     ENDM
  163. ;
  164. ;    Set an interrupt vector address
  165. ;
  166.     SET    MACRO ADDR,VECT
  167.     MOV    AH,25H            ; Set vector function
  168.     IFNB    <VECT>
  169.     MOV    AL,VECT            ; Interrupt number
  170.     ENDIF
  171.     MOV    DX,OFFSET ADDR        ; Point to address
  172.     INT    MS_DOS            ; Set the vector, returns in ES:BX
  173.     ENDM
  174. ;
  175. ;    Restore previously-saved interrupt vectors.
  176. ;
  177.     RESTORE    MACRO ADDR,VECT
  178.     MOV    AH,25H            ; Set vector function
  179.     IFNB    <VECT>
  180.     MOV    AL,VECT            ; Interrupt number
  181.     ENDIF
  182.     PUSH    DS            ; Save data segment
  183.     LDS    DX,ADDR            ; Get old address
  184.     INT    MS_DOS            ; Set the vector
  185.     POP    DS
  186.     ENDM
  187. ;
  188. ;    Index into the table of communications port parameters
  189. ;
  190.     INDEX    MACRO PARAM,REG
  191.     MOV    BX,WORD PTR [COM]    ; Get port number index
  192.     SHL    BX,1            ; Times 2
  193.     SHL    BX,1            ; Times 4
  194.     ADD    BX,OFFSET TABLE+PARAM    ; Offset into the table
  195.     MOV    REG,[BX]
  196.     ENDM
  197. ;
  198. ;    Reset interrupt controller.
  199. ;
  200.     RESET    MACRO
  201.     MOV    AL,INT_NOS        ; Non-specific end-of-interrupt
  202.     OUT    INT_RES,AL        ; Reset the controller
  203.     STI                ; Allow interrupts
  204.     ENDM
  205. ;
  206. ;    Print string addressed by DS:DX. Byte count is in CX.
  207. ;
  208.     PROMPT    MACRO STRING,LENGTH
  209.     MOV    DX,STRING        ; Point to string
  210.     MOV    CX,LENGTH        ; Get string length
  211.     MOV    BX,1            ; Console 'handle'
  212.     MOV    AX,4000H        ; Write to file/device
  213.     INT    MS_DOS
  214.     ENDM
  215. ;
  216. ;    Program code segment.
  217. ;
  218. PSEG    SEGMENT    PARA PUBLIC 'CODE'
  219. START    EQU    $            ; Equate for stack offset
  220.     ASSUME CS:PSEG, DS:PSEG, ES:PSEG, SS:NOTHING
  221.     ORG    100H            ; Entry point
  222. MAIN    PROC    NEAR
  223.     MOV    SP,OFFSET STKTOP    ; Keep in a safe place
  224.     MOV    WORD PTR [IBP],OFFSET BUFFER    ; Set RX buffer pointer
  225.     MOV    WORD PTR [TBP],OFFSET DBUFF    ; Set TX buffer pointer
  226.     MOV    WORD PTR [COMP],0    ; TX 'complete' address.
  227.     STI                ; Make sure a TSR didn't disable.
  228.     CLD                ; Forwards.
  229.     CALL    CHK_CMD            ; Check command line
  230.     JNC    CMD_OK            ; Command line was okay
  231.     MOV    AX,4C01H        ; Exit with error
  232.     INT    MS_DOS            ;  to DOS
  233. CMD_OK:    CALL    CHK_COM            ; Check for communications port
  234.     CALL    SET_INT            ; Set up interrupts
  235.     CALL    SET_PRT            ; Set up communications port
  236.     CMP    BYTE PTR [MODE],0    ; Check for mode
  237.     JZ    MAIN0            ; Normal user-test mode
  238.     PROMPT    <OFFSET PRP0>, STOP    ; Print PRP0 to screen
  239.     PROMPT    <OFFSET PRP6>, INF_LEN    ; Print PRP6 to screen
  240.     MOV    SI,OFFSET PRP6        ; Source string
  241.     MOV    DI,OFFSET DBUFF        ; Where to put the string
  242.     MOV    CX,INF_LEN        ; Length of string
  243.     REP    MOVSB            ; Put into the buffer
  244.     MOV    CX,INF_LEN        ; Length of string
  245.     CALL    SEND            ; Send prompt string to remote
  246.     CALL    MIRROR            ; Remote mirror mode
  247.     MOV    SI,OFFSET PRP7        ; Point to 'reloading BBS' prompt
  248.     MOV    DI,OFFSET DBUFF        ; Where to put the string
  249.     MOV    CX,REL_LEN        ; Length of the string
  250.     PUSH    CX            ; Save string length
  251.     REP    MOVSB            ; Put into the buffer
  252.     POP    CX            ; Length of the string
  253.     CALL    SEND            ; Send to remote
  254.     JMP    SHORT MAIN1        ; Exit
  255. MAIN0:    CALL    TST_LIN            ; Test the line
  256. MAIN1:    CALL    TX_WAIT            ; Wait for TX buffer to clear
  257.     CALL    RES_PRT            ; Restore port parameters
  258.     CALL    RES_INT            ; Restore interrupts
  259.     JMP    FINIS            ; Exit the program
  260. MAIN    ENDP
  261. ;
  262. ;    Get the modem status of the UART and save it.
  263. ;
  264. CHK_COM    PROC    NEAR
  265.     INDEX    BPRT, DX        ; Get base port
  266.     MOV    WORD PTR [BASE],DX    ; Set it up
  267.     ADD    DX,MOD_STA        ; Offset to modem status
  268.     IN    AL,DX            ; Get modem status
  269.     MOV    BYTE PTR [STATUS],AL    ; Save present status
  270.     RET
  271. CHK_COM    ENDP
  272. ;
  273. ;    Set the communications port up for interrupt control.
  274. ;
  275. SET_PRT    PROC    NEAR
  276.     MOV    DX,WORD PTR [BASE]    ; Get base port
  277.     MOV    BX,DX            ; Save port
  278.     ADD    DX,INT_ENA        ; Pick up interrupt enable register
  279.     IN    AL,DX            ; Get the enable mask
  280.     MOV    BYTE PTR [OLD_UAR],AL    ; Save old mask
  281.     MOV    AL,(INT_RC OR INT_MS OR INT_TX)    ; Mask for UART interrupts
  282.     OUT    DX,AL            ; Set interrupt enable mask
  283.     MOV    DX,BX            ; Get base port again
  284.     ADD    DX,MOD_CTL        ; To modem-control register
  285.     MOV    AL,(RTS OR DTR OR TRI)    ; Turn on output lines
  286.     OUT    DX,AL            ; Set modem control
  287.     MOV    DX,BX            ; Get base port again
  288.     ADD    DX,LIN_CTL        ; Line control register
  289.     CMP    WORD PTR [DIVIS],0    ; see if we have a divisor
  290.     JZ    NO_DIV            ; None, leave alone
  291.     MOV    AL,DLAB            ; Raise divisor-latch access bit
  292.     OUT    DX,AL
  293.     MOV    DX,BX            ; Get base port again
  294.     MOV    AX,WORD PTR [DIVIS]    ; Get divisor
  295.     OUT    DX,AL            ; Set LSB
  296.     INC    DX            ; Next port
  297.     MOV    AL,AH            ; Get MSB
  298.     OUT    DX,AL            ; Set MSB
  299.     MOV    DX,BX            ; Get base port again
  300.     ADD    DX,LIN_CTL        ; Line control register
  301. NO_DIV:    MOV    AL,NORM            ; 8 bits, 1 stop, no parity
  302.     OUT    DX,AL            ; Set parameters
  303.     JMP    CLEAR            ; Implied return
  304. SET_PRT    ENDP
  305. ;
  306. ;    Read all registers in the UART and clear any interrupts that may
  307. ;    occur.
  308. ;
  309. CLEAR    PROC    NEAR
  310.     STI                ; Make sure a TSR didn't disable.
  311.     MOV    DX,WORD PTR [BASE]    ; Get base port
  312.     MOV    CX,6            ; Six registers to read
  313. RD_EM:    IN    AL,DX            ; Get byte/ throw away
  314.     RESET                ; Could interrupt, reset controller
  315.     INC    DX            ; Ready next port
  316.     LOOP    RD_EM            ; Continue for all ports
  317.     RET
  318. CLEAR    ENDP
  319. ;
  320. ;    Restore communications port parameters.
  321. ;
  322. RES_PRT    PROC    NEAR
  323.     MOV    DX,WORD PTR [BASE]    ; Get base port
  324.     ADD    DX,INT_ENA        ; Pick up interrupt eable register
  325.     MOV    AL,BYTE PTR [OLD_UAR]    ; Get old UART mask
  326.     OUT    DX,AL            ; Restore the mask
  327.     JMP    CLEAR            ; Implied return
  328. RES_PRT    ENDP
  329. ;
  330. ;    Check the command line to determine if we are master/slave.
  331. ;
  332. CHK_CMD    PROC    NEAR
  333.     CMP    BYTE PTR DS:[80H],0    ; See is anything typed
  334.     JNZ    CONT0            ; Yes
  335.     RET                ; No, use defaults
  336. CONT0:    MOV    SI,80H            ; Point to command line
  337.     LODSB                ; Get bytes typed
  338.     CBW
  339.     MOV    CX,AX            ; Use as a count
  340.     PUSH    CX            ; Save count
  341.     MOV    DI,OFFSET DBUFF        ; Where to put the string
  342.     CALL    MAP            ; Map to upper case
  343.     POP    CX            ; Restore count
  344.     PUSH    CX            ; Save again
  345.     MOV    SI,OFFSET DBUFF        ; Where the string is
  346.     MOV    DX,OFFSET AS_COM    ; Point to the string to look for
  347.     MOV    BX,AS_LEN        ; Get search length
  348.     CALL    SEARCH            ; Search the string
  349.     JNZ    CONT1            ; Not fount
  350.     LODSB                ; Get found byte
  351.     SUB    AL,'0'            ; Remove ASCII bias
  352.     JBE    CONT1            ; Out of range
  353.     DEC    AL            ; Change to an offset
  354.     JZ    CONT1            ; Out of range
  355.     CMP    AL,3            ; Check high range
  356.     JG    CONT1            ; Out of range
  357.     CBW
  358.     MOV    WORD PTR [COM],AX    ; New com-port offset
  359. CONT1:    POP    CX            ; Restore string length
  360.     PUSH    CX            ; Save string length
  361.     MOV    SI,OFFSET DBUFF        ; Where the string is
  362.     MOV    DX,OFFSET AS_MOD    ; Point to the string to look for
  363.     MOV    BX,AS_LEN        ; Get search length
  364.     CALL    SEARCH            ; Search the string
  365.     JNZ    CONT2            ; Not found
  366.     LODSB                ; Get found byte
  367.     CMP    AL,'M'            ; Want to mirror?
  368.     JNZ    CONT2            ; No
  369.     MOV    BYTE PTR [MODE],0FFH    ; Set mirror flag
  370. CONT2:    POP    CX            ; Restore string length
  371.     MOV    SI,OFFSET DBUFF        ; Where the string is
  372.     MOV    DX,OFFSET AS_RAT    ; String to find
  373.     MOV    BX,RAT_LEN        ; Length of the substring
  374.     CALL    SEARCH            ; Try to find it
  375.     JNZ    CONT4            ; Not found
  376.     MOV    DX,SI            ; Point to byte after '='
  377.     MOV    SI,OFFSET SPEEDS    ; Point to table of values
  378.     MOV    CX,TAB_LEN        ; Length of the table
  379.     MOV    BX,3            ; Length of the numbers
  380.     CALL    SEARCH            ; Try to find a value that matches
  381.     JZ    CONT3            ; Divisor found
  382.     PROMPT    <OFFSET PRP9>, LEN_P9    ; Print 'not found'
  383.     STC                ; Show error
  384.     RET                ; Exit
  385. CONT3:    LODSW                ; Get the divisor
  386.     MOV    WORD PTR [DIVIS],AX    ; Save the divisor.
  387. CONT4:    CLC                ; Show no error    
  388.     RET
  389. CHK_CMD    ENDP
  390. ;
  391. ;    Set up the interrupt vectors.
  392. ;
  393. SET_INT    PROC    NEAR
  394.     SAVE    OLD_CLK, 08H        ; Save old clock vector
  395.     SAVE    OLD_BRK, 1BH        ; Save old break vector
  396.     SAVE    OLD_CTC, 23H        ; Save old ^C vector
  397.     SAVE    OLD_KBD, 16H        ; Save keyboard vector
  398.     INDEX    INTN, AL        ; Get interrupt number
  399.     SAVE    OLD_PRT            ; Save old interrupt contents
  400. ;
  401.     SET    NEW_CLK, 08H        ; Set new clock vector
  402.     SET    NEW_BRK, 1BH        ; Set new break vector
  403.     SET    NEW_CTC, 23H        ; Set new ^C vector
  404.     INDEX    INTN, AL        ; Get interrupt number
  405.     SET    NEW_PRT            ; Set new interrupt vector.
  406. ;
  407.     IN    AL,INT_CTL        ; Get present interrupt mask
  408.     MOV    BYTE PTR [OLD_MSK],AL    ; Save old interrupt mask
  409.     INDEX    IMSK, AH        ; Get interrupt mask
  410.     AND    AL,AH            ; Reset the bit
  411.     OUT    INT_CTL,AL        ; Un-mask the controller
  412.     STI                ; Make sure a TSR didn't disable.
  413.     RET
  414. SET_INT    ENDP
  415. ;
  416. ;    Restore interrupt vectors to their like-new condition.
  417. ;
  418. RES_INT    PROC    NEAR
  419.     MOV    AL,BYTE PTR [OLD_MSK]    ; Get old interrupt mask
  420.     OUT    INT_CTL,AL        ; Restore old mask
  421.     RESTORE    OLD_CLK, 08H        ; Restore old clock vector
  422.     RESTORE OLD_BRK, 1BH        ; Restore old break vector
  423.     RESTORE    OLD_CTC, 23H        ; Restore old ^C vector
  424.     INDEX    INTN, AL        ; Get interrupt number
  425.     RESTORE OLD_PRT            ; Restore old interrupt contents
  426.     RET
  427. RES_INT    ENDP
  428. ;
  429. ;    Clear the interrupt buffer.
  430. ;
  431. CLR_BUF    PROC    NEAR
  432.     MOV    WORD PTR [IBP],OFFSET BUFFER    ; Reset buffer pointer
  433.     RET
  434. CLR_BUF    ENDP
  435. ;
  436. ;    Test the line. If we are the slave, simply loop to send everything
  437. ;    received. Abort when a control-C is received.
  438. ;
  439. TST_LIN    PROC    NEAR
  440.     PROMPT    <OFFSET PRP0>, LEN_P0    ; Print PRP0 to the screen
  441. TSTLN0:    CALL    CLEAR            ; Reset the UART
  442.     MOV    CX,MAX            ; Bytes to send
  443.     MOV    DI,OFFSET DBUFF        ; Where to build the string
  444.     XOR    AL,AL            ; Start at zero
  445. TEST0:    CMP    AL,'C'-64        ; Don't send ^C
  446.     JNZ    OKAY            ; Was okay
  447.     INC    AL            ; Next character
  448. OKAY:    STOSB                ; Put character in the buffer
  449.     INC    AL            ; Ready next character
  450.     LOOP    TEST0            ; Continue for whole string
  451. ;
  452. TEST1:    CMP    BYTE PTR [ABORT],0    ; Check for an abort
  453.     JZ    TEST2            ; Abort
  454. QUIT:    MOV    CX,10            ; Bytes to send
  455.     MOV    DI,OFFSET DBUFF        ; Where to build string
  456.     MOV    AL,'C'-64        ; Control-C
  457.     REP    STOSB            ; Put in buffer
  458.     MOV    CX,10            ; Bytes to send
  459.     CALL    SEND            ; Send them
  460.     RET
  461. ;
  462. TEST2:    CALL    CLR_BUF            ; Clear receive buffer
  463.     MOV    CX,MAX            ; Bytes to send
  464.     CALL    SEND            ; Send them
  465. ;
  466. ;    Check to see if a key has been hit on the keyboard. Check for an
  467. ;    escape of a control-C. Since we wish to keep the interrupts enabled
  468. ;    we will CALL this interrupt by pushing the flags first, then making
  469. ;    a long CALL. The routine ends with an IRET so it is necessary to
  470. ;    push the flags onto the stack before the call.
  471. ;
  472.     MOV    AH,1            ; Check for character at from KBD
  473.     PUSHF                ; Dummy "interrupt"
  474.     CALL    DWORD PTR [OLD_KBD]    ; Returns with an IRET
  475.     JZ    TEST3            ; Nothing ready
  476.     MOV    AH,0            ; Go get the character
  477.     PUSHF                ; Dummy "interrupt"
  478.     CALL    DWORD PTR [OLD_KBD]    ; Returns with an IRET
  479.     CMP    AL,'C'-64        ; Check for control-C
  480.     JZ    QUIT            ; Going to exit
  481.     CMP    AL,27            ; Check for escape
  482.     JZ    QUIT            ; Exit
  483. ;
  484. TEST3:    PROMPT    <WORD PTR [GD_BD]>, LEN_P1    ; Print string variable
  485.     PROMPT    <OFFSET PRP3>, LEN_P3    ; Print stats to the screen
  486.     MOV    DI,OFFSET ERRAV        ; Point to average error-rate str
  487.     XOR    AL,AL            ; Flag for <average> RATE
  488.     CALL    RATE            ; Convert
  489.     MOV    DX,WORD PTR [TOTTX_H]    ; Get bytes transmitted H
  490.     MOV    AX,WORD PTR [TOTTX_L]    ; Get bytes transmitted L
  491.     SUB    AX,WORD PTR [TOTRX_L]    ; Subtract low bytes received
  492.     SBB    DX,WORD PTR [TOTRX_H]    ; Take care of borrow
  493.     MOV    DI,OFFSET BBYTE        ; Where to build the string
  494.     CALL    ASCII            ; Convert to ASCII
  495.     INC    WORD PTR [BLKN]        ; Bump count
  496.     ADD    WORD PTR [TOTTX_L],MAX    ; Update count
  497.     ADC    WORD PTR [TOTTX_H],0    ; Update high word
  498.     MOV    DI,OFFSET BLKS        ; Where to build the string
  499.     XOR    DX,DX            ; Zero high word
  500.     MOV    AX,WORD PTR [BLKN]    ; Get the block number
  501.     CALL    ASCII            ; Build the strin
  502.     MOV    DI,OFFSET BTX        ; Where to build the string
  503.     MOV    DX,WORD PTR [TOTTX_H]    ; Get high word
  504.     MOV    AX,WORD PTR [TOTTX_L]    ; Get low word
  505.     CALL    ASCII            ; Convert
  506. ;
  507.     IF (NOT TESTING)
  508.     TEST    BYTE PTR [STATUS],RLSD    ; Get modem status
  509.     JNZ    CAR_OK            ; Carrier okay
  510.     PROMPT    <OFFSET PRP5>, LEN_P5    ; Print 'carrier fail' string
  511.     RET                ; Exit
  512.     ENDIF
  513. ;
  514. CAR_OK:    CALL    CHK_STK            ; Check for stack overflow
  515.     JZ    STK_OK            ; Its okay
  516.     PROMPT    <OFFSET PRP8>, LEN_P8    ; Print 'stack overflow'
  517.     JMP    QUIT            ; Cleanup and exit
  518. ;
  519. STK_OK:    MOV    CX,MAX            ; Bytes to receive
  520.     CALL    RECV            ; Receive the bytes
  521.     PUSH    AX            ; Save for now
  522.     ADD    WORD PTR [TOTRX_L],AX    ; Update count
  523.     ADC    WORD PTR [TOTRX_H],0    ; Update high word
  524.     MOV    DI,OFFSET BRX        ; Where to build the string
  525.     MOV    DX,WORD PTR [TOTRX_H]    ; Get high word
  526.     MOV    AX,WORD PTR [TOTRX_L]    ; Get low word
  527.     CALL    ASCII            ; Convert
  528.     POP    AX            ; Restore received byte count
  529.     CMP    AX,MAX            ; Get them all?
  530.     JNZ    BAD            ; No
  531.     CALL    CHK_BUF            ; Check buffer bytes
  532.     JNZ    BAD            ; Bad data
  533.     MOV    WORD PTR [GD_BD],OFFSET PRP1
  534.     JMP    TEST1            ; Continue
  535. ;
  536. BAD:    MOV    WORD PTR [GD_BD],OFFSET PRP2
  537.     MOV    DI,OFFSET LBRX        ; String for received bytes
  538.     CALL    BINARY            ; Convert AL to binary-ASCII
  539.     MOV    DI,OFFSET LBTX        ; String for transmitted bytes
  540.     MOV    AL,AH            ; Get what bytes should be
  541.     CALL    BINARY
  542.     MOV    DI,OFFSET ERRAT        ; Point to peak error-rate string
  543.     OR    AL,0FFH            ; Flag for <peak> RATE
  544.     CALL    RATE            ; Calculate
  545.     JMP    TSTLN0            ; Continue
  546. TST_LIN    ENDP
  547. ;
  548. ;    Check the bytes in the buffer to see if they are the same as
  549. ;    transmitted. Subtract bytes after the first mis-compare from the
  550. ;    total received bytes.
  551. ;
  552. CHK_BUF    PROC    NEAR
  553.     MOV    AH,0            ; Start with a NULL
  554.     MOV    SI,OFFSET DBUFF        ; Point to data buffer
  555.     MOV    CX,MAX            ; Bytes to check
  556. CHK_B0:    LODSB                ; Get buffered byte
  557.     CMP    AH,'C'-64        ; Compare with ^C
  558.     JNZ    CHK_B1            ; No
  559.     INC    AH            ; Bypass ^C
  560. CHK_B1:    CMP    AH,AL            ; Check for a match
  561.     JNZ    NOGOOD            ; No match
  562.     INC    AH            ; Ready next check byte
  563.     LOOP    CHK_B0            ; Continue
  564.     XOR    AH,AH            ; Set flags for okay
  565. NOGOOD:    PUSHF                ; Save flage
  566.     SUB    WORD PTR [TOTRX_L],CX    ; Update count
  567.     SBB    WORD PTR [TOTRX_H],0    ; Update high word
  568.     POPF                ; Restore flags
  569.     RET
  570. CHK_BUF    ENDP
  571. ;
  572. ;    Calculate the error rate.
  573. ;
  574. RATE    PROC    NEAR
  575.     PUSH    AX            ; Save flag
  576.     MOV    AX,WORD PTR [TOTTX_L]    ; Total bytes transmitted
  577.     MOV    DX,WORD PTR [TOTTX_H]    ; Total bytes transmitted
  578.     MOV    BX,WORD PTR [TOTRX_L]    ; Total bytes received
  579.     MOV    CX,WORD PTR [TOTRX_H]    ; Total bytes received
  580. ;
  581. RATE0:    CMP    DX,0            ; Check for register clear
  582.     JNZ    HIGH0            ; Not clear
  583.     CMP    CX,0            ; Check for register clear
  584.     JZ    RATE3            ; Its clear
  585. HIGH0:    CLC
  586.     RCR    DX,1            ; Shift the high bits over
  587.     RCR    AX,1            ; Shift the low bits over
  588. RATE1:    CLC
  589.     RCR    CX,1            ; Move over high bits
  590.     RCR    BX,1            ; Move low bits over
  591. RATE2:    JMP    SHORT RATE0        ; Continue
  592. RATE3:    CMP    AX,0            ; Check for div by zero
  593.     JNZ    RATE4            ; Not zero, continue
  594.     POP    AX            ; Level the stack
  595.     RET                ; Zero, exit
  596. ;
  597. RATE4:    PUSH    AX            ; Save bytes transmitted
  598.     SUB    AX,BX            ; AX = bad bytes
  599.     MUL    WORD PTR [_10000]    ; Scale the bad bytes
  600.     POP    BX            ; Restore bytes transmitted
  601.     DIV    BX
  602.     POP    BX            ; Flag (was AX when pushed)
  603.     CMP    BL,0            ; Check for ave/peak
  604.     JZ    AVE            ; Calc the percentage
  605.     CMP    AX,WORD PTR [OLD_PK]    ; See if greater than old
  606.     JNC    PEAK            ; Its greater
  607.     RET                ; Less or equal, ignore
  608. ;
  609. PEAK:    MOV    WORD PTR [OLD_PK],AX    ; Update the peak count
  610. AVE:    CALL    PERCENT            ; Conv
  611.     MOV    AX,DX            ; Convert overflow
  612. ;    XOR    DX,DX            ; Ready for multiply
  613. ;    MUL    WORD PTR [_10000]    ; (REM * 10000) / 65536
  614. ;    MOV    CX,10
  615. ;    MUL    CX
  616. ;    MOV    AX,DX            ; Is /65536
  617.     CALL    PRECIS            ; Finish numerical precision
  618.     RET
  619. RATE    ENDP
  620. ;
  621. ;    Local clock vector (hardware interrupt).
  622. ;
  623. NEW_CLK    PROC    FAR
  624.     PUSH    AX            ; Save register
  625.     RESET                ; Reset the controller
  626.     POP    AX
  627.     SUB    BYTE PTR CS:[CLOCK],1    ; Bump the clock
  628.     ADC    BYTE PTR CS:[CLOCK],0    ; If we went below zero
  629.     JMP    DWORD PTR CS:[OLD_CLK]    ; Continue to old address
  630. NEW_CLK    ENDP
  631. ;
  632. ;    Local control-C vector (software interrupt)
  633. ;
  634. NEW_CTC    PROC    FAR
  635.     MOV    BYTE PTR CS:[ABORT],0FFH    ; Set flag
  636.     IRET
  637. NEW_CTC    ENDP
  638. ;
  639. ;    Local control-BRK vector (software interrupt)
  640. ;
  641. NEW_BRK    PROC    FAR
  642.     MOV    BYTE PTR CS:[ABORT],0FFH    ; Set flag
  643.     IRET
  644. NEW_BRK    ENDP
  645. ;
  646. ;    Local modem port interrupt vector (hardware interrupt). The code
  647. ;    is as 'in-line' as I could make it to speed execution.
  648. ;
  649. NEW_PRT    PROC    FAR
  650.     PUSH    AX            ; Save registers used
  651.     PUSH    DX
  652.     PUSH    DS
  653. ;
  654.     PUSH    CS
  655.     POP    DS            ; DS=CS
  656.     MOV    DX,WORD PTR [BASE]    ; Get base port
  657.     ADD    DX,INT_IDR        ; Offset to Interrupt ident
  658.     IN    AL,DX            ; Get status byte
  659.     SUB    DX,INT_IDR        ; Back to the base port
  660.     TEST    AL,00000100B        ; Got a byte?
  661.     JNZ    GET_DAT            ; Yes
  662.     TEST    AL,00000010B        ; TX holding register empty?
  663.     JNZ    PUT_DAT            ; Yes
  664. ;
  665. GET_STA:
  666.     ADD    DX,MOD_STA        ; Offset to modem status
  667.     IN    AL,DX            ; Get modem status
  668.     MOV    BYTE PTR [STATUS],AL    ; Save modem status
  669.     RESET                ; Reset the controller
  670.     POP    DS            ; Restore registers used
  671.     POP    DX
  672.     POP    AX
  673.     IRET
  674. ;
  675. GET_DAT:
  676.     PUSH    BX            ; Save index
  677.     IN    AL,DX            ; Get the byte
  678.     MOV    BX,WORD PTR [IBP]    ; Get buffer pointer
  679.     MOV    BYTE PTR [BX],AL    ; Put byte in the buffer
  680.     RESET                ; Reset the controller
  681.     ADD    WORD PTR [IBP],1    ; Ready next
  682.     SBB    WORD PTR [IBP],0    ; Don't wrap around segment!
  683.     MOV    BYTE PTR [CLOCK],ONE_SEC    ; Reset the clock
  684.     POP    BX            ; Restore index
  685.     POP    DS            ; Restore registers used
  686.     POP    DX
  687.     POP    AX
  688.     IRET
  689. ;
  690. PUT_DAT:
  691.     PUSH    SI            ; Save index
  692.     MOV    SI,WORD PTR [TBP]    ; Get TX buffer pointer
  693.     CMP    SI,WORD PTR [COMP]    ; Check limits
  694.     JNC    NO_SND            ; Don't output the byte
  695.     LODSB                ; Get buffer byte
  696.     OUT    DX,AL            ; Send it out
  697.     MOV    WORD PTR [TBP],SI    ; Ready next
  698. NO_SND:    RESET                ; Reset the controller
  699.     POP    SI            ; Restore index
  700.     POP    DS            ; Restore registers used
  701.     POP    DX
  702.     POP    AX
  703.     IRET
  704. NEW_PRT    ENDP
  705. ;
  706. ;    Check receive status. Return DX=byte count. ZF = no bytes
  707. ;
  708. CHK_STA    PROC    NEAR
  709.     MOV    DX,WORD PTR [IBP]    ; Get the interrupt buffer pointer
  710.     SUB    DX,OFFSET BUFFER    ; Starting address
  711.     RET
  712. CHK_STA    ENDP
  713. ;
  714. ;    Get CX bytes from interrupt buffer and put at address DBUFF.
  715. ;    Upon return, AX shows actual bytes transferred. Return in 
  716. ;    1 second after the last byte if not all bytes received.
  717. ;
  718. RECV    PROC    NEAR
  719.     MOV    SI,OFFSET BUFFER    ; Where the bytes should be
  720.     MOV    DI,OFFSET DBUFF        ; Where to put the bytes
  721.     XOR    DX,DX            ; Zero byte count
  722.     MOV    BYTE PTR [CLOCK],ONE_SEC    ; Set the clock
  723. AGAIN:    CMP    BYTE PTR [CLOCK],0    ; Have we timed out?
  724.     JZ    SOMEB            ; Yes
  725.     CALL    CHK_STA            ; Check for bytes available
  726.     CMP    DX,CX            ; Same as requested?
  727.     JC    AGAIN            ; No wait
  728. ;
  729. SOMEB:    MOV    CX,DX            ; Get real byte count
  730.     JCXZ    NONE            ; No bytes
  731.     REP    MOVSB            ; Transfer the bytes
  732. ;
  733. NONE:    MOV    AX,DI            ; Get ending address
  734.     SUB    AX,OFFSET DBUFF        ; Subtract starting address
  735.     RET
  736. RECV    ENDP
  737. ;
  738. ;    Send CX bytes, from buffer DBUFF. Set the transmitter-buffer-pointer
  739. ;    [TBP] to the second byte in the buffer. Calculate the completion-
  740. ;    address [COMP] by adding in the byte-count. Send the first byte to
  741. ;    start TX interrupt.
  742. ;
  743. SEND    PROC    NEAR
  744.     CALL    TX_WAIT            ; Wait for previous TX to complete
  745.     MOV    WORD PTR [TBP],OFFSET DBUFF + 1    ; Set TX buffer pointer
  746.     MOV    BX,OFFSET DBUFF        ; Point to the buffer
  747.     ADD    BX,CX            ; Calc last address
  748.     MOV    WORD PTR [COMP],BX    ; Set ending address
  749.     MOV    DX,WORD PTR [BASE]    ; Pick up UART base address
  750.     MOV    AL,BYTE PTR [DBUFF]    ; Get first buffer byte
  751.     OUT    DX,AL            ; TX the first byte
  752.     RET
  753. SEND    ENDP
  754. ;
  755. ;    Wait for TX to complete sending the string. If [TBP] and [COMP]
  756. ;    are the same, transmission is complete. It may never complete so
  757. ;    don't hang the system by waiting forever.
  758. ;
  759. TX_WAIT    PROC    NEAR
  760.     STI                ; Make sure a TSR didn't disable.
  761. WAIT0:    MOV    BX,WORD PTR [TBP]    ; Get the transmitter buffer pointer
  762. WAIT1:    CMP    BX,WORD PTR [COMP]    ; Check completion pointer
  763.     JNC    WAIT2            ; TX is complete
  764.     HLT                ; Wait for any interrupt (maybe clock)
  765.     HLT                ; Wait for any interrupt (maybe UART)
  766.     CMP    BX,WORD PTR [TBP]    ; See if pointer changed
  767.     JNZ    WAIT0            ; Yes, continue wait
  768. WAIT2:    RET
  769. TX_WAIT    ENDP
  770. ;
  771. ;    Terminate the program. Put the cursor at the bottom os the screen.
  772. ;
  773. FINIS    PROC    NEAR
  774.     PROMPT    <OFFSET PRP4>, LEN_P4    ; Print restore cursor.
  775.     MOV    AX,4C00H        ; Normal exit
  776.     INT    MS_DOS
  777. FINIS    ENDP
  778. ;
  779. ;    Convert binary in AL to ASCII-binary addressed by [DI]. DI and
  780. ;    CX is destroyed. All others saved.
  781. ;
  782. BINARY    PROC    NEAR
  783.     PUSH    AX
  784.     MOV    CX,8            ; Number of bits to display.
  785.     MOV    AH,AL            ; Save the number
  786. BIN0:    MOV    AL,'0'            ; Assume a '0'
  787.     RCR    AH,1            ; Into the carry
  788.     ADC    AL,0            ; Becomes '1' if a carry
  789.     STOSB                ; Save in the string
  790.     LOOP    BIN0            ; Do all bits
  791.     POP    AX
  792.     RET
  793. BINARY    ENDP
  794. ;
  795. ;    Create a 'percent' string from binary in AX. String is addressed
  796. ;    by DI.
  797. ;
  798. PRECIS    PROC    NEAR
  799.     MOV    CX,10000
  800.     CALL    PSUB            ; Subtract 10 thousands
  801.     MOV    CX,1000            ; Subtract 1 thousands
  802.     CALL    PSUB
  803.     MOV    CX,100            ; Subtract hundreds
  804.     CALL    PSUB
  805.     MOV    CX,10            ; Subtract tens
  806.     CALL    PSUB
  807.     ADD    AL,'0'            ; Add ASCII bias to remainder
  808.     STOSB                ; Save in string
  809.     RET
  810. ;
  811. PERCENT    PROC    NEAR
  812.     MOV    CX,10000
  813.     CALL    PSUB            ; Subtract 10 thousands
  814.     MOV    BYTE PTR [DI],'.'    ; Put in a decimal point
  815.     INC    DI            ; Ready next destination
  816.     MOV    CX,1000            ; Subtract 1 thousands
  817.     CALL    PSUB
  818.     MOV    CX,100            ; Subtract hundreds
  819.     CALL    PSUB
  820.     MOV    CX,10            ; Subtract tens
  821.     CALL    PSUB
  822.     ADD    AL,'0'            ; Add ASCII bias to remainder
  823.     STOSB                ; Save in string
  824.     RET
  825. ;
  826. PSUB    PROC    NEAR
  827.     MOV    BL,'0'-1        ; ASCII bias - 1
  828. PSUB0:    INC    BL            ; Powers of 10 counter
  829.     SUB    AX,CX            ; Subtract powers of 10
  830.     JNC    PSUB0            ; Continue until too much
  831.     ADD    AX,CX            ; Too much, add back
  832.     MOV    BYTE PTR [DI],BL    ; Put ASCII byte in memory
  833.     INC    DI            ; Ready next
  834.     RET
  835. PSUB    ENDP
  836. PERCENT    ENDP
  837. PRECIS    ENDP
  838. ;
  839. ;    Send any incoming bytes out the modem port until a ^C
  840. ;
  841. MIRROR    PROC    NEAR
  842.     CALL    CLR_BUF            ; Clear interrupt buffer
  843.     MOV    SI,OFFSET BUFFER    ; Interrupt buffer
  844.     MOV    DI,OFFSET DBUFF        ; Where to put new bytes when ready
  845. MIR1:    TEST    BYTE PTR [STATUS],RLSD    ; Get modem status
  846.     JNZ    MIR2            ; Carrier okay
  847.     IF (NOT TESTING)
  848.     PROMPT    <OFFSET PRP5>, LEN_P5    ; Print 'carrier failed'
  849.     RET                ; Dead, exit
  850.     ENDIF
  851. ;
  852. MIR2:    CMP    BYTE PTR [ABORT],0    ; Do we want to abort
  853.     JZ    MIR3            ; No
  854. ;
  855. BYE:    MOV    DI,OFFSET DBUFF        ; Data buffer
  856.     MOV    AL,'C'-64        ; Control-C
  857.     MOV    CX,10            ; Bytes to send
  858.     REP    STOSB            ; Put in the buffer
  859.     MOV    CX,10            ; 10 Bytes to send
  860.     CALL    SEND            ; Send the bytes
  861.     RET
  862. ;
  863. MIR3:    CALL    CHK_STA            ; Check for bytes ready
  864.     JZ    MIR1            ; Nothing there
  865.     MOV    CX,DX            ; Ask for all bytes available
  866.     CLI                ; No new bytes (please!!)
  867.     REP    MOVSB            ; Transfer the bytes
  868.     CALL    CLR_BUF            ; Ready for next group
  869.     STI                ; Allow new bytes
  870.     MOV    CX,DX            ; Bytes received
  871.     PUSH    CX            ; Save byte-count
  872.     MOV    AL,'C'-64        ; Check for an abort
  873.     MOV    DI,OFFSET DBUFF        ; Where the bytes
  874.     REPNZ    SCASB            ; Check for ^C
  875.     POP    CX            ; Restore count
  876.     JNZ    MIR4            ; Was no ^C (s)
  877.     RET                ; ^C received, exit
  878. MIR4:    CALL    SEND            ; Send string
  879.     JMP    SHORT MIRROR        ; Continue
  880. MIRROR    ENDP
  881. ;
  882. ; Print double precision number in DX:AX. The string is addressed by DI
  883. ; All registers including BP are destroyed by this call.
  884. ;
  885. ASCII    PROC    NEAR
  886.     MOV    BP,0000            ; Leading zero flag
  887.     MOV    CX,3B9AH        ; Get billions
  888.     MOV    BX,0CA00H
  889.     CALL    SUBTR            ; Subtract them out
  890.     CALL    COMMA            ; Put in a comma
  891.     MOV    CX,05F5H        ; Get hundred-millions
  892.     MOV    BX,0E100H
  893.     CALL    SUBTR            ; Subtract them out
  894.     MOV    CX,0098H        ; Get ten-millions
  895.     MOV    BX,9680H
  896.     CALL    SUBTR            ; Subtract them out
  897.     MOV    CX,000FH        ; Get millions
  898.     MOV    BX,4240H
  899.     CALL    SUBTR            ; Subtract them out
  900.     CALL    COMMA            ; Put in a comma
  901.     MOV    CX,0001H        ; Get hundred-thousands
  902.     MOV    BX,86A0H
  903.     CALL    SUBTR            ; Subtract them out
  904.     MOV    CX,0000H        ; Get ten-thousands
  905.     MOV    BX,2710H
  906.     CALL    SUBTR            ; Subtract them out
  907.     MOV    CX,0000H        ; Get thousands
  908.     MOV    BX,03E8H
  909.     CALL    SUBTR            ; Subtract them out
  910.     CALL    COMMA            ; Put in a comma
  911.     MOV    CX,0000H        ; Get hundreds
  912.     MOV    BX,0064H
  913.     CALL    SUBTR            ; Subtract them out
  914.     MOV    CX,0000H        ; Get tens
  915.     MOV    BX,000AH
  916.     CALL    SUBTR            ; Subtract them out
  917.     ADD    AL,'0'            ; Add bias to residual
  918.     STOSB                ; Put in the string
  919.     RET
  920. ;
  921. SUBTR:     MOV     SI,'0'-1        ; We are out of registers!
  922. SUBTR1:     INC     SI            ; Counter
  923.      SUB     AX,BX            ; Dword subtraction
  924.      SBB     DX,CX
  925.      JNB     SUBTR1            ; Continue until a carry
  926.      ADD     AX,BX            ; One too many, add back
  927.      ADC     DX,CX            ;   and the remainder
  928.      CMP     BP,0            ; See if we printed anything yet
  929.      JNZ     SUBTR2            ; No, can't be a leading zero
  930.      CMP     SI,'0'            ; See if its a zero
  931.      JZ     SUBTR3            ; Yes, don't print them
  932. ;
  933. SUBTR2:     INC    BP            ; We are now 'printing' a character
  934.      PUSH    AX            ; Save accumulator
  935.      MOV    AX,SI            ; Get index
  936.      STOSB                ; Put in string
  937.      POP    AX            ; Restore accumulator
  938. SUBTR3:     RET
  939. ;
  940. COMMA:    CMP    BP,0            ; Any bytes printed?
  941.     JZ    PASS            ; No, then no commas
  942.     PUSH    AX            ; Yes, save
  943.     MOV    AL,','            ; Get a comma
  944.     STOSB                ; Into string
  945.     POP    AX            ; Restore
  946. PASS:    RET
  947. ASCII    ENDP
  948. ;
  949. ;    Search string addressed by SI for a substring addressed by DX.
  950. ;    String length = CX, Substring length = BX. Return ZR if string
  951. ;    is found.
  952. ;
  953. SEARCH    PROC    NEAR
  954.     PUSH    CX            ; Save string length
  955.     MOV    DI,DX            ; Get location of substring
  956.     MOV    CX,BX            ; Get substring length
  957.     REPZ    CMPSB            ; Check for match
  958.     POP    CX            ; Restore string length
  959.     JZ    FOUND
  960.     LOOP    SEARCH            ; Continue for whole string
  961.     INC    CX            ; Set non-zero
  962. FOUND:    RET
  963. SEARCH    ENDP
  964. ;
  965. ;    Map string addressed by SI to upper case. Put in address defined
  966. ;    by DI. CX = byte count.
  967. ;
  968. MAP    PROC    NEAR
  969.     LODSB                ; Get byte
  970.     CMP    AL,'z'            ; Check high range
  971.     JG    NOMAP            ; Not a lower-case letter
  972.     CMP    AL,'a'            ; Check low range
  973.     JL    NOMAP            ; Not a lower-case letter
  974.     AND    AL,95            ; Reset lower-case bits
  975. NOMAP:    STOSB
  976.     LOOP    MAP            ; Do all bytes
  977.     RET
  978. MAP    ENDP
  979. ;
  980. ;    Check for stack overflow. The user may have TRSs that are using
  981. ;    interrupts which could cause an overflow. We want to abort before
  982. ;    anything bad happens.
  983. ;
  984. CHK_STK    PROC    NEAR
  985.     MOV    SI,OFFSET LEVEL        ; Point to end of stack area
  986.     MOV    DI,OFFSET LEVEL + 8    ; Point to end + 8
  987.     MOV    CX,8            ; Check 8 bytes
  988.     REPZ    CMPSB            ; Should be the same.
  989.     RET
  990. CHK_STK    ENDP
  991. ;
  992. ;        - Data area follows -
  993. ;
  994. PRP0    DB    CR,LF,'You need to install your ANSI.SYS driver!'
  995.     DB    27,'[2J'
  996.     DB    (80 - @HEAD1)/2 DUP (' ')
  997.     HEAD1    <>
  998.     DB    CR,LF
  999.     DB    (80 - @HEAD2)/2 DUP (' ')
  1000.     HEAD2    <>
  1001.     DB    CR,LF
  1002.     DB    (80 - (@HEAD3+@VERS))/2 DUP (' ')
  1003.     HEAD3    <>
  1004.     VERS    <>
  1005.     DB    CR,LF
  1006.     DB    (80 - @HEAD4)/2 DUP (' ')
  1007.     HEAD4    <>
  1008.     DB    CR,LF
  1009.     DB    (80 - @HEAD5)/2 DUP (' ')
  1010.     HEAD5    <>
  1011.     DB    CR,LF
  1012.     DB     CR,LF
  1013. STOP    EQU    $ - PRP0
  1014.     REV    <>
  1015.     DB    ' Block number '
  1016.     NRM    <>
  1017.     DB    '     '
  1018.     REV    <>
  1019.     DB    ' Bytes transmitted '
  1020.     NRM    <>
  1021.     DB    '     '
  1022.     REV    <>
  1023.     DB    ' Bytes received '
  1024.     NRM    <>
  1025.     DB    '     '
  1026.     REV    <>
  1027.     DB    ' Bad bytes '
  1028.     NRM    <>
  1029.     DB    CR,LF,LF
  1030. LEN_P0    EQU    $ - PRP0
  1031. PRP3    DB    ' '
  1032. BLKS    DB    '              '
  1033. BTX    DB    '                        '
  1034. BRX    DB    '                     '
  1035. BBYTE    DB    '         '
  1036.     DB    CR,LF,LF
  1037.     REV    <>
  1038.     DB    '  Last Bad byte '
  1039.     NRM    <>
  1040.     DB    CR,LF
  1041.     REV    <>
  1042.     DB    '   Transmitted :'
  1043.     NRM    <>
  1044.     DB    ' '
  1045. LBTX    DB    '- NONE -'
  1046.     DB    CR,LF
  1047.     REV    <>
  1048.     DB    '      Received :'
  1049.     NRM    <>
  1050.     DB    ' '
  1051. LBRX    DB    '- NONE -'
  1052.     DB    CR,LF
  1053.     REV    <>
  1054.     DB    ' Pk Error Rate :'
  1055.     NRM    <>
  1056.     DB    ' '
  1057. ERRAT    DB    '0.000000000'
  1058.     DB    CR,LF
  1059.     REV    <>
  1060.     DB    ' Av Error Rate :'
  1061.     NRM    <>
  1062.     DB    ' '
  1063. ERRAV    DB    '0.000000000'
  1064.     DB    27,'[9;1H'            ; Restore cursor position
  1065. LEN_P3    EQU    $ - PRP3
  1066. PRP1    DB    CR,' Good'
  1067. LEN_P1    EQU    $ - PRP1
  1068. PRP2    DB    CR,' Bad '
  1069. LEN_P2    EQU    $ - PRP2
  1070. PRP4    DB    27,'[23;1H'
  1071. LEN_P4    EQU    $ - PRP4
  1072. STP0    DB    '     '
  1073. PRP5    DB    27,'[23;1H'
  1074.     DB    '- ABORTED -   Modem Carrier failed!'
  1075.     DB    CR,LF
  1076. LEN_P5    EQU    $ - PRP5
  1077. PRP6    DB    CR,LF
  1078.     SPACES    <>
  1079.     DB    'At this time,  the  system is set up like a'
  1080.     DB    CR,LF
  1081.     SPACES    <>
  1082.     DB    'mirror.  Everything sent will be  reflected'
  1083.     DB    CR,LF
  1084.     SPACES    <>
  1085.     DB    'back.'
  1086.     DB    CR,LF
  1087.     DB    CR,LF
  1088.     SPACES    <>
  1089.     DB    'Execute your local  NOISE.COM  program now.'
  1090.     DB    CR,LF
  1091.     SPACES    <>
  1092.     DB    'If you don''t have this program, abort with'
  1093.     DB    CR,LF
  1094.     SPACES    <>
  1095.     DB    '^C and download it first!'
  1096.     DB    CR,LF,LF
  1097. INF_LEN    EQU    $ - PRP6
  1098. PRP7    DB    CR,LF
  1099.     SPACES    <>
  1100.     DB    'Reloading BBS system, please standby......'
  1101. REL_LEN    EQU    $ - PRP7
  1102. ;
  1103. PRP8    DB    27,'[23;1H'
  1104.     DB    '- ABORTED -   Stack overflow!'
  1105.     DB    CR,LF
  1106. LEN_P8    EQU    $ - PRP8
  1107. ;
  1108. PRP9    DB    CR,LF,'Requested baud-rate not supported.'
  1109. LEN_P9    EQU    $ - PRP9
  1110. ;
  1111. ;    Table of communications adapter parameters.
  1112. ;
  1113. TABLE    LABEL    BYTE
  1114.     COM1    <>
  1115.     COM2    <>
  1116.     COM3    <>
  1117.     COM4    <>
  1118. EVEN                    ; Align all the WORDS
  1119. ;
  1120. ;    Saved interrupt vector addresses.
  1121. ;
  1122. OLD_PRT    LABEL    DWORD            ; Old UART interrupt vector
  1123.     DQ    ?
  1124. OLD_CTC    LABEL    DWORD            ; Old control-C vector
  1125.     DQ    ?
  1126. OLD_BRK    LABEL    DWORD            ; Old control-break vector
  1127.     DQ    ?
  1128. OLD_CLK    LABEL    DWORD            ; Old timer-tick vector
  1129.     DQ    ?
  1130. OLD_KBD    LABEL    DWORD            ; Old keyboard interrupt
  1131.     DQ    ?
  1132. ;
  1133. _10000    DW    10000            ; For error-rate multiply
  1134. BASE    DW    03F8H            ; Communications adapter base port
  1135. BLKN    DW    0            ; Block number
  1136. COM    DW    0            ; Com port offset
  1137. COMP    DW    ?            ; TX completion address
  1138. GD_BD    DW    STP0            ; Where to start.
  1139. IBP    DW    ?            ; Interrupt buffer pointer
  1140. TBP    DW    ?            ; Transmitter buffer pointer
  1141. TOTTX_H    DW    ?            ; Total bytes transmitted
  1142. TOTTX_L    DW    ?            ; Total bytes transmitted
  1143. TOTRX_H    DW    ?            ; Total bytes received
  1144. TOTRX_L    DW    ?            ; Total bytes received
  1145. OLD_PK    DW    0            ; Previous peak error rate
  1146. DIVIS    DW    ?            ; UART Divisor
  1147. CLOCK    DB    ?            ; Local clock
  1148. ABORT    DB    0            ; Program abort flag
  1149. OLD_MSK    DB    ?            ; Old controller mask
  1150. OLD_UAR    DB    ?            ; Old UART interrupt mask
  1151. MODE    DB    0            ; Normal/mirror mode
  1152. STATUS    DB    0FFH            ; Modem status
  1153. AS_COM    DB    'PORT='            ; Command-line search-string
  1154. AS_LEN    EQU    $ - AS_COM        ; Its length
  1155. AS_MOD    DB    'MODE='            ; Command-line search string
  1156. AS_RAT    DB    'SPEED='        ; Command-line search string
  1157. RAT_LEN    EQU    $ - AS_RAT        ; Length of the search-string
  1158. ;
  1159. ;    Put Stack on a paragraph boundary. Looks better in DEBUG.
  1160. ;
  1161.     ORG    (($ - START) + 16 ) AND 0FFF0H
  1162. LEVEL    DB    32 DUP ('STACK   ')
  1163. STKTOP    LABEL    WORD            ; Stack-pointer
  1164. DBUFF    DB    MAX DUP (?)        ; Data buffer
  1165. BUFFER    LABEL    BYTE            ; Interrupt buffer
  1166. SPEEDS    DB    '150'            ; 150 baud rate
  1167.     DW    768
  1168.     DB    '300'            ; 300 baud
  1169.     DW    384
  1170.     DB    '600'            ; 600 baud
  1171.     DW    192
  1172.     DB    '120'            ; 1200 baud
  1173.     DW    96
  1174.     DB    '180'            ; 1800 baud
  1175.     DW    64
  1176.     DB    '200'            ; 2000 baud
  1177.     DW    58
  1178.     DB    '240'            ; 2400 baud
  1179.     DW    48
  1180.     DB    '360'            ; 3600 baud
  1181.     DW    32
  1182.     DB    '480'            ; 4800 baud
  1183.     DW    24
  1184.     DB    '720'            ; 7200 baud
  1185.     DW    16
  1186.     DB    '960'            ; 9600 baud
  1187.     DW    12
  1188.     DB    '192'            ; 19200 baud
  1189.     DW    6
  1190.     DB    '384'            ; 38400 baud
  1191.     DW    3
  1192.     DB    '560'            ; 56000 baud
  1193.     DW    2
  1194. TAB_LEN    EQU    $ - SPEEDS
  1195. PSEG    ENDS
  1196.     END    MAIN
  1197.