home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / modem / asm_term.arc / TERM.ASM next >
Assembly Source File  |  1988-04-18  |  14KB  |  382 lines

  1. ;                   /-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\
  2. ;                   |                                     |
  3. ;                   |  Terminal in assembler, A86 format  |
  4. ;                   |     Interrupt driven reception      |
  5. ;                   |   -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-   |
  6. ;                   |        Weefus on GEnie or           |
  7. ;                   |    Keith Rolland    1:321/112.5     |
  8. ;                   |        (!) Copywrong 1988           |
  9. ;                   |                                     |
  10. ;                   \-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-/
  11. ;
  12. ;
  13. jmp BEGIN_PRG       ;jump over our data area to the real beginning
  14.  
  15. MESSAGE1 db 07h,0dh,0ah,0ah,0ah,"Press <alt>-q to quit.......",0dh,0ah,0ah,"$"
  16. MESSAGE2 db "          Arrgg, I spent HOW much time on this?!?         $"
  17.  
  18. BUFFER_BOT equ $
  19. BUFFER db 0ffh DUP 00h        ;the actual incoming buffer, 255 bytes
  20. BUFFER_TOP equ $
  21.  
  22. BUFFER_TAIL dw 0000h          ;used to control where characters are put
  23. BUFFER_HEAD dw 0000h          ;into and taken from the buffer
  24.  
  25. LINE_CTL_REG = 03fbh          ;various memory locations for rs232 registers
  26. MODEM_CTL_REG = 03fch
  27. LINE_STAT_REG = 03fdh
  28. MODEM_STAT_REG = 03feh
  29. CHAR_HOLDING_REG = 03f8h
  30.  
  31. BOX_TLCOR = 0c9h                   ;Ascii graphic characters used for
  32. BOX_TRCOR = 0bbh                   ;making the box.
  33. BOX_BLCOR = 0c8H                   ;TLCOR = TopLeftCORner and so on....
  34. BOX_BRCOR = 0bch
  35. BOX_VERT  = 0bah
  36. BOX_HORZ  = 0cdh
  37. SPACE     = 020h
  38.  
  39. SCROLL_COUNT db 00h
  40. ;============================================================================
  41. BEGIN_PRG:
  42. mov w[BUFFER_TAIL], offset BUFFER       ;set up buffer pointer variables
  43. mov w[BUFFER_HEAD], offset BUFFER       ;for our circular buffer
  44.  
  45. call CLEAR_SCREEN   ;routine that will....... (guess :)
  46.  
  47. call BOX_MAKE       ;make our superneato ascii box and message
  48.  
  49. call SETUP          ;set up rs232 and new interrupt routines
  50.  
  51. ;*****************************************************************************
  52. MAIN_LOOP:
  53. call CHECK_INCOMING ;check the buffer, and print any waiting characters
  54. call CHECK_OUTGOING ;see if any keystrokes are waiting in the keyboard queue
  55. jnc MAIN_LOOP       ;if carry flag not set, jump to main loop
  56. ;*****************************************************************************
  57. cli                 ;the carry flag is set, indicating an exit request
  58. in al,021h          ;reset the com1 interrupt bit in the IMR
  59. or al,010h          ;so that no more com1 ints are performed
  60. out 021h,al         ;put it back
  61. mov dx,LINE_CTL_REG ;line control reg
  62. in al,dx            ;get byte
  63. and al,07fh         ;clear bit 7, com1 interrupt enable bit
  64. out dx,al           ;put it back
  65. mov al,00h          ;tell the modem we no longer will be operating.....
  66. mov dx,MODEM_CTL_REG ;clear modem control reg
  67. out dx,al           ;do it
  68. sti                 ;re-enable interrupts
  69. int 20h             ;standard end program interrupt
  70. ;-----------------------
  71. SETUP:              ;direct set-up of registers, no bios or dos calls
  72.             ;my mom said it was ok............:)
  73. mov dx,LINE_CTL_REG ;point to the line control register, it controls a lot.
  74. mov al,080h         ;turn on bit 7
  75. out dx,al           ;send byte
  76. dec dx              ;point to msb of baud rate divisor
  77. dec dx
  78. mov al,00h          ;msb for any rate > 1200 baud is 00h
  79. out dx,al           ;send byte
  80. dec dx              ;point to lsb of baud rate divisor
  81. mov al,060h         ;lsb for 1200 bps is 60h, use 30h for 2400 bps
  82. out dx,al           ;send byte
  83. mov dx,LINE_CTL_REG ;line control register
  84. mov al,0ah          ;7/E/1 settings=0ah /use 03h for 8/n/1
  85. out dx,al           ;send byte
  86.  
  87. mov dx,offset NEW_INT ;point com1 interrupt to our new routine, NEW_INT
  88. mov al,0ch          ;interrupt to replace = COM1
  89. mov ah,025h         ;dos function number for change-a-vector
  90. int 21h             ;call dos to change vector
  91.  
  92. in al,021h          ;this will enable interrupts by setting the
  93. and al,0efh         ;com1 interrupt bit in the IMR (don't ask! :)
  94. out 021h,al         ;IMR is the Interrupt Mask Register
  95. cli                 ;we don't want to be disturbed during this...
  96. mov dx,LINE_CTL_REG ;point to line control register, rs232
  97. in al,dx            ;get byte
  98. and al,07fh         ;set high bit
  99. out dx,al           ;and put it back
  100. dec dx
  101. dec dx              ;move to the rs232 interrupt enable register
  102. mov al,01h          ;set it to interrupt when data recieved
  103. out dx,al           ;put it back
  104. inc dx
  105. inc dx              ;move to modem control register |could have done ....|
  106. inc dx              ;set it for using interrupts    |mov dx,MODEM_CTL_REG|
  107. mov al,08h          ;bit #3 high
  108. out dx,al           ;put it back
  109. sti                 ;re-enable normal interrupts
  110. mov dx,offset MESSAGE1 ;print how-to-exit message
  111. mov ah,09h             ;via dos
  112. int 21h
  113. ret                    ;end of set-up
  114. ;-----------------------
  115. CHECK_INCOMING:
  116. mov bx,w[BUFFER_TAIL]  ;check to see if anything
  117. cmp bx,w[BUFFER_HEAD]  ;is in the buffer....
  118. je ret                 ;jump if nothing ready
  119. mov al,b[bx]           ;character is ready, get it in al
  120. inc bx
  121. cmp bx,BUFFER_TOP      ;if buffer_head is at the top of the
  122. jne >L17               ;buffer, we must point it to the other end
  123. mov bx,BUFFER_BOT
  124. L17:
  125. mov w[BUFFER_TAIL],bx  ;place new buffer tail in storage
  126. cmp al,1bh          ;is char an <escape>?
  127. jne >L13            ;no, so jump, otherwise.....
  128. mov al,0dbh         ;change it to a graphic char. No vt100/ansi stuff allowed!
  129. L13:                ;      this is a *real* simple program! :)
  130. mov dl,al           ;dos wants the char in dl to print it
  131. mov ah,02h          ;dos print function
  132. int 21h             ;call dos
  133. ret                 ;end check_incoming
  134. ;-----------------------
  135. CHECK_OUTGOING:
  136. call CK_FOR_KEY     ;subroutine checks for keypress via bios interrupt
  137. je ret              ;no key pressed, return to main_loop
  138. jnc >L4             ;no exit request pending so jump ahead
  139. ret                 ;carry set, so just return and main_loop will act on it
  140. L4:
  141. push bx             ;push these on stack
  142. push dx             ;as they will be used
  143. push cx             ;here internally
  144. mov bl,al           ;put keypress in bl temporarily
  145. mov dx,MODEM_CTL_REG ;point to modem control register
  146. mov al,0bh          ;tell modem we want to send
  147. out dx,al           ;put byte in the register
  148. mov dx,MODEM_STAT_REG ;point to modem status register
  149. WAIT_FOR_CLR:
  150. in al,dx            ;get modem status
  151. test al,010h        ;test for modems 'clear-to-send' line (bit #4)
  152. jne >L5             ;no problems so jump
  153. loop WAIT_FOR_CLR   ;wait for ok (modem is presently busy)
  154. L5:
  155. mov dx,LINE_STAT_REG ;point to line status register
  156. OK_STATUS:
  157. in al,dx            ;get status byte
  158. test al,020h        ;test bit #5, 'transmit register empty'
  159. jne >L6             ;it's empty,so it's ready for another character
  160. loop OK_STATUS      ;it is full, so loop until it is empty
  161. L6:
  162. mov al,bl           ;put keypress in al
  163. mov dx,CHAR_HOLDING_REG ;point to transmitter holding register
  164. out dx,al           ;put keypress in transmit register, where it
  165. pop cx              ;automagicly will be sent upon it's way
  166. pop dx              ;restore these from stack
  167. pop bx
  168. ret                 ;end check_outgoing
  169. ;-----------------------
  170. NEW_INT:            ;Our New Interrupt Handler
  171. cli                 ;this interrupt routine is called by the hardware
  172. push ax             ;every time a character is recieved via rs232
  173. push bx
  174. push dx             ;save registers on stack
  175. push si
  176. push ds
  177. mov ax,cs           ;make sure data seg is code seg
  178. mov ds,ax
  179. mov dx,CHAR_HOLDING_REG ;recieve register, the incoming char is held here
  180. in al,dx              ;get byte, the incoming character, from register
  181. mov bx,w[BUFFER_HEAD] ;get present buffer head position in bx
  182. mov si,bx             ;and then increase bx to point to where
  183. inc bx                ;the next character will be placed
  184. cmp bx,BUFFER_TOP   ;if BUFFER_HEAD=BUFFER_TOP, we make it BUFFER_BOT
  185. jne >L10            ;next char goes somewhere in the middle of the buffer
  186. mov bx,BUFFER_BOT   ;here we reset BUFFER_HEAD to BUFFER_BOT
  187. L10:
  188. cmp bx,w[BUFFER_TAIL]  ;if BUFFER_HEAD=BUFFER_TAIL, we have no more room
  189. je >L9                 ;in the buffer, ie a buffer overrun has occured!
  190.                ;in this case, we don't store the incoming char.
  191.                ;ideally, at this point we should call an error
  192.                ;handling routine, but you can write that. :)
  193. mov b[si],al           ;put byte in buffer if everything is ok
  194. mov w[BUFFER_HEAD],bx  ;point buffer_head to new head-of-buffer
  195. L9:
  196. mov al,020h         ;tell the hardware we are through with this interrupt
  197. out 020h,al         ;by doing this. Only with hardware related ints.
  198. pop ds
  199. pop si
  200. pop dx
  201. pop bx
  202. pop ax
  203. sti
  204. iret                ;end new_int
  205. ;-----------------------
  206. CK_FOR_KEY:
  207. mov ah,01h          ;use int 16h function #01 to test for
  208. int 16h             ;keypress available
  209. je ret              ;none ready yet so return
  210. pushf
  211. mov ah,00h          ;use function #0 to get the keypress
  212. int 16h
  213. popf
  214. clc                 ;clear it before testing
  215. cmp al,00h          ;is the keypress an extended code?
  216. jne ret             ;no, so return to check_outgoing
  217. cmp ah,010h         ;we have an extended code now- is it <alt>-q?
  218. jne ret             ;no, so we will let the odd code go through for now
  219. stc                 ;yes, it is <alt>-q, so we set the carry flag and return
  220. ret                 ;end ck_for_key
  221. ;-----------------------
  222. CLEAR_SCREEN:      ;the hard way!
  223. mov ah,02h         ;use bios video to
  224. mov bh,00h         ;set cursor position to top left
  225. mov dx,00h         ;of screen
  226. int 10h            ;bios function 02h
  227. ;
  228. mov ah,09h         ;now using function 09h
  229. mov cx,0800h       ;print a space char 0800h times, ~2000d...
  230. mov al,20h         ;20h = space char
  231. mov bl,07h         ;attribute of character
  232. int 10h            ;clear it!
  233. ;
  234. mov ah,02h         ;now let's put the
  235. mov bh,00h         ;cursor back up in
  236. mov dx,00h         ;the upper left corner
  237. int 10h            ;bios video function
  238. ret                ;end clear_screen
  239. ;-------------------------------------------------
  240.             ;*******************************
  241.             ;* Following are used to make  *
  242.             ;* the ascii box. Is it worth  *
  243.             ;* all of the programming?     *
  244.             ;*******************************
  245. PRINT_MANY:
  246. mov ah,02h          ;load dl with character to be printed
  247. PRINT_MORE:
  248. int 21h             ;and cx with the number of times it
  249. dec cx
  250. jcxz ret            ;should be printed
  251. jmp PRINT_MORE
  252. ;-----------------------
  253. PRINT_ONE:
  254. mov ah,02h          ;load dl with character
  255. int 21h
  256. ret
  257. ;-----------------------
  258. POSITION:
  259. MOV dl,SPACE
  260. mov cx,0ah
  261. call PRINT_MANY
  262. ret
  263. ;-----------------------
  264. CR_LF:
  265. mov ah,02h
  266. mov dl,0dh
  267. int 21h
  268. mov dl,0ah
  269. int 21h
  270. ret
  271. ;-----------------------
  272. SIDES:                        ;symbols make for good reading!
  273. call POSITION
  274. mov dl,BOX_VERT
  275. call PRINT_ONE
  276. mov dl,SPACE
  277. mov cx,03ah
  278. call PRINT_MANY
  279. mov dl,BOX_VERT
  280. call PRINT_ONE
  281. call CR_LF
  282. ret
  283. ;-----------------------
  284. BOX_TOP:
  285. call POSITION
  286. mov dl,BOX_TLCOR
  287. call PRINT_ONE
  288. mov dl,BOX_HORZ
  289. mov cx,03ah
  290. call PRINT_MANY
  291. mov dl,BOX_TRCOR
  292. call PRINT_ONE
  293. call CR_LF
  294. ret
  295. ;-----------------------
  296. BOX_BOT:
  297. call POSITION
  298. mov dl,BOX_BLCOR
  299. call PRINT_ONE
  300. mov dl,BOX_HORZ
  301. mov cx,03ah
  302. call PRINT_MANY
  303. mov dl,BOX_BRCOR
  304. call PRINT_ONE
  305. ret
  306. ;-----------------------
  307. BOX_MAKE:
  308. call CR_LF
  309. call CR_LF
  310. call BOX_TOP
  311. call SIDES
  312. call POSITION
  313. mov dl,BOX_VERT
  314. call PRINT_ONE
  315. lea dx,MESSAGE2     ;set up for dos' print-string routine
  316. mov ah,09h          ;dos function number for same
  317. int 21h             ;do it
  318. mov dl,BOX_VERT
  319. call PRINT_ONE
  320. call CR_LF
  321. call SIDES
  322. call BOX_BOT
  323. call CR_LF
  324. call SCROLL_DOWN
  325. call SCROLL_UP
  326. ret                 ;end box_make. Not exactly elegant, huh? :)
  327. ;-----------------------
  328. SCROLL_UP:
  329. mov SCROLL_COUNT,0fh ;number of lines to scroll
  330. DO_SCROLL:
  331. mov ah,00h          ;get time of day
  332. int 01ah            ;tod interrupt
  333. add dx,01h          ;delay value
  334. mov bx,dx           ;store ending value in bx
  335. push ax
  336. push bx
  337. mov ah,06h          ;scroll up using bios function 6
  338. mov al,01h          ;number of rows to scroll up
  339. mov cx,00h          ;cl=top left row cl=top left col
  340. mov dh,018h         ;b r row
  341. mov dl,050h         ;b r col
  342. mov bh,07h          ;attribute of cleared line
  343. int 10h             ;do it
  344. pop bx
  345. pop ax
  346. WAIT_HERE:
  347. int 01ah            ;check tod to see if delay is over
  348. cmp dx,bx
  349. jne WAIT_HERE
  350. dec SCROLL_COUNT
  351. mov al,SCROLL_COUNT
  352. jnz DO_SCROLL
  353. ret
  354. ;-----------------------
  355. SCROLL_DOWN:
  356. mov SCROLL_COUNT,0fh ;number of lines to scroll
  357. DO_SCROLL2:
  358. mov ah,00h          ;get time of day
  359. int 01ah            ;tod interrupt
  360. add dx,01h          ;delay value
  361. mov bx,dx           ;store ending value in bx
  362. push ax
  363. push bx
  364. mov ah,07h          ;scroll down using bios function 7
  365. mov al,01h          ;number of rows to scroll down
  366. mov cx,00h          ;cl=top left row cl=top left col
  367. mov dh,018h         ;b r row
  368. mov dl,050h         ;b r col
  369. mov bh,07h          ;attribute of cleared line
  370. int 10h             ;do it
  371. pop bx
  372. pop ax
  373. WAIT_HERE2:
  374. int 01ah            ;check tod to see if delay is over
  375. cmp dx,bx
  376. jne WAIT_HERE2
  377. dec SCROLL_COUNT
  378. mov al,SCROLL_COUNT
  379. jnz DO_SCROLL2
  380. ret
  381. ;-----------------------
  382.