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