;------------------------------------------------------------------------------ ; This is a simple modem progam that is an unassembly of the program ; JAXTALK by Jack Kilday. See end of this file for his documentation. ; ; Set up to be compiled as an EXE file using MASM v5.1 ; masm jaxtalk2; ; link /cp:1 jaxtalk2; ; ; James R. Webster EMail: jwebste3@bellsouth.net ;------------------------------------------------------------------------------ ;------------------------------------------------- ; 8259 Program Interrupt Controller (PIC) at 21h. ; Status bits (0 = Enabled, 1 = Disabled): ; Bit Use ; --- ------------------------ ; 0 Sytem Timer ; 1 Keyboard Interrupt ; 2 Reserved ; 3 COM2: Interrupt ; 4 COM1: Interrupt ; 5 Fixed Disk Interrupt ; 6 Floppy Disk Interrupt ; 7 Parallel Port Interrupt ;------------------------------------------------- ;---------------------------------------------------------------------- ; 8250 Port Offsets from Base Address. ; Offs COM1 COM2 Name Description ; ---- ---- ---- ----- ------------------------------------------- ; If DLAB bit (bit #7) in LCR = 0. ; 00 03F8 02F8 DATA Received Data Register (if read from). ; Transmit Holding Register (if written to). ; 01 03F9 02F9 IER Interrupt Enable Register. ; If DLAB bit (bit #7) in LCR = 1. ; 00 03F8 02F8 Baud0 BRG Divisor Latch, low byte. ; 01 03F9 02F9 Baud1 BRG Divisor Latch, high byte. ; Remainder is not affected by the setting of the DLAB bit. ; 02 03FA 02FA IID Interrupt Identifier Register. ; 03 03FB 02FB LCR Line Control Register. ; 04 03FC 02FC MCR Modem Control Register. ; 05 03FD 02FD LSR Line Status Register. ; 06 03FE 02FE MSR Modem Status Register. ;---------------------------------------------------------------------- ;----------------------------------------------------------------- ;8250 Interrupt Enable Register (IER) (0 = Disabled, 1 = Enabled): ; Bit(s) Use ; ------ ---------------------------------------------------- ; 0 Enable interrupt on data available. ; If this bit is set to 0, will disable all UART ; interrupts within the 8250! ; 1 Enable interrupt on transmit holding register empty. ; 2 Enable interrupt on receive line status change. ; 3 Enable interrupt on modem status change. ; 4-7 Reserved. ;----------------------------------------------------------------- ;----------------------------------------------------------------- ;8250 Line Control Register (LCR): ; Bit(s) Use ; ------ ---------------------------------------------------- ; 0-1 Data Length. ; 00 = 5 bits 10 = 7 bits ; 01 = 6 bits 11 = 8 bits ; 2 Number of Stop Bits. ; 0 = 1 stop bit ; 1 = 2 stop bits (1.5 if 5 bit DL.) ; 3-5 Parity Checking. ; xx1 = No parity bit. ; 001 = Parity bit is ODD. ; 010 = Parity bit is EVEN. ; 101 = Parity bit is 1. ; 111 = Parity bit is 0. ; 6 0 = Normal UART operation. ; 1 = Send BREAK signal. ; 7 Divisor Latch Access Bit (DLAB). ; 0 = Normal access to ports 3F8/3F9. ; 1 = Use ports 03F8h and 03F9h to specify baud rate. ; 03F8h (MSB) 03F9h (LSB) Baud Rate ; ----------- ----------- ---------- ; 4 17h 110 bps ; 1 90h or 40h? 300 bps ; 0 60h 1,200 bps ; 0 30h 2,400 bps ; 0 18h 4,800 bps ; 0 0Ch 9,600 bps ; 0 06h or 07h 19,200 bps ; 0 03h 38,400 bps ;----------------------------------------------------------------- ;----------------------------------------------------------------- ; 8250 Modem Control Register (MCR) (0 = Disabled, 1 = Enabled): ; Bit(s) Use ; ------ ---------------------------------------------------- ; 0 Sets DTR output to RS232C connector. ; 1 Sets RTS output to RS232C connector. ; 2 Resets Hayes 1200b internal modem. ; 3 Controls 8250 interrupt signals. ; If this bit is set to 0, interrupt signals from the ; UART cannot reach the rest of the PC! ; 4 Turns on UART self-test configuration. ; 5-7 Reserved. ;----------------------------------------------------------------- ;------------------------------------------------------------ ; 8250 Line Status Register (LSR) (0 = No, 1 = Yes): ; Note: This is a read-only register! ; Bit(s) Use ; ------ ----------------------------------------------- ; 0 Received data ready. ; 1 Overrun error (previous read not completed). ; 2 Parity error (if lateral parity is in use). ; 3 Framing error (incoming = 0 at stop-bit time). ; 4 BREAK received. ; 5 Transmit Holding Register empty. ; 6 Transmit Shift Register empty. ; 7 Always 0. ;------------------------------------------------------------ ;---------------------------------------------------------------- ; 8250 Modem Status Register (MSR) (0 = No change, 1 = Changed): ; Bit(s) Use (or voltage level: 0 = Low, 1 = High): ; ------ --------------------------------------------------- ; 0 CTS status. ; 1 DSR status. ; 2 RI status. ; 3 DCD status. ; 4 Clear To Send (CTS) level. ; 5 Data Set Ready (DSR) level. ; 6 Ring Indicator (RI) level. ; 7 Data Carrier Detected (DCD) level. ;---------------------------------------------------------------- .model small jmps macro n ;;Example: jmps next_line jmp short n endm buffer_size equ 32d dosseg .stack .data public on_message, off_message, receive_err, send_error public buff_ovrflo, lsr_status, buf_of_flag, exit_flag public pmr_bx_ptr, mr_bx_ptr, buffer on_message db '- JAXTALK ON -',0dh,0ah,'$' off_message db 0dh,0ah,'- JAXTALK OFF -',0dh,0ah,'$' receive_err db '$' send_error db '$' buff_ovrflo db '$' lsr_status db 0 ;With bits 0, and 5-7 cleared. buf_of_flag db 0 ;FFh = buffer overwrite during modem read. exit_flag db 0 ;FFh = ESC pressed. Quit. pmr_bx_ptr dw offset buffer ;Stored BX ptr for PROCESS_MODEM_RCHAR. mr_bx_ptr dw offset buffer ;Stored BX ptr for MODEM_READ_CHAR. buffer db buffer_size dup (0) .code public main, init_com_port, process_modem_rchar public read_keyboard, modem_read_char public deinit_com_port, read_key, modem_send_char public disp_al_char, display_str, inc_bx_ptr ;------------------------------------------------------------------------------ ; Program start. ; {mov cs:dgrp_seg,ax} ; {dgrp_seg dw ? ;Default DGROUP.} ;------------------------------------------------------------------------------ main proc call init_com_port ;Enable COM1. Display "ON". loop_main: call process_modem_rchar ;Write chars to screen received ; by the modem. call read_keyboard ;Read keyboard and send to modem. cmp exit_flag,-1 ;(FFh) Exit program ? jne loop_main ;If <> FFh, fetch next character. call deinit_com_port ;Disable COM1. Display "OFF". mov ah,4ch int 21h ;Return to DOS. main endp ;------------------------------------------------------------------------------ ; Initials COM1 and displays "ON" msg. ; ; Callers: MAIN. ;------------------------------------------------------------------------------ init_com_port proc mov dx,0 ;DX = COM Port Number. 0 based. mov al,83h ;AL = COM Port Parameter Byte. ; ; 100-00-0-11 ; +------------> ; 1200 baud, no parity, ; | ; 1 stop bit, 8 bits. ;---------------+------------------------------------------------- ;Bit Settings (BBB-PP-S-CC): ; BBB = Baud rate. PP = Parity code. CC = Character size. ; 000 110 baud 00 none 00 unused ; 001 150 baud 01 odd 01 unused ; 010 300 baud 10 none 10 7-bit char size ; 011 600 baud 11 even 11 8-bit char size ; 100 1200 baud S = number of stop-bits code. ; 101 2400 baud 0 1 (one) stop bit ; 110 4800 baud 1 2 (two) stop bits ; 111 9600 baud ;----------------------------------------------------------------- mov ah,00h ;AH = Initial COM Port. int 14h ;Call BIOS. ; Returns: AH = Line Status. ; AL = Modem Status. cli ;Clear Interrupt Flags. lea dx,modem_read_char ;DS:DX = Address of new routine. mov al,0Ch ;AL = Interrupt Vector Number. mov ah,25h ;AH = Set Interrupt Vector. int 21h ;Call DOS. in al,21h ;AL = PIC port status. and al,0EFh ;(1110-1111) Clear bit #4. out 21h,al ;COM1: Interrupt Enabled. mov dx,03FBh ;Base Port COM1 (03F8) + LCR (3). in al,dx ;AL = LCR status. and al,7Fh ;(0111-1111) Clear bit #7. out dx,al ;Initial normal access to ports ; 03F8h and 03F9h. mov dx,03F9h ;Base Port COM1 (03F8) + IER (1). mov al,01h ;Bit #1 only is to be set. out dx,al ;Enable Received Data Ready interr. mov dx,03FCh ;Base Port COM1 (03F8) + MCR (4). mov al,08h ;Bit #3 only is to be set. out dx,al ;Initial 8250 Interrupt Signals. sti ;Set Interrupt Flags. mov ax,dgroup ;AX = Data Segment. mov ds,ax ;Initial DS. nop ;NOP for debugging. lea dx,on_message ;DS:DX = ; "- JAX TALK ON -",0dh,0ah,'$' call display_str ;Display string. ret ;Return. init_com_port endp ;------------------------------------------------------------------------------ ; Retrieves characters from buffer that were received by the modem. ; ; Callers: MAIN ; Uses: DISP_AL_CHAR, DISPLAY_STR ;------------------------------------------------------------------------------ process_modem_rchar proc mov bx,pmr_bx_ptr ;BX = this routines buffer ptr. cmp bx,mr_bx_ptr ;Same as MODEM_READ_CHARs ptr ? jz pmr_check_re ;If so, check for Receive Error. mov al,[bx] ;AL = character from buffer. call inc_bx_ptr ;Inc BX (internal buffer) pointer. mov pmr_bx_ptr,bx ;Store BX pointer. cmp al,0Ah ;LF (Line Feed) ? jz pmr_check_re ;If so, check for Receive Error. call disp_al_char ;Else, write char in AL to screen. cmp al,0Dh ;CR (Carraige Return) ? jnz pmr_check_re ;If not, check for Receive Error. mov al,0Ah ;Else, AL = LF (Line Feed). call disp_al_char ;Write character in AL to screen. pmr_check_re: test lsr_status,-1 ;Receieve error ? jz pmr_check_oe ;If = 0, no. Check Buffer Overflow. lea dx,receive_err ;DS:DX = '$'. call display_str ;Display string. mov lsr_status,00h ;Reset flag to 0, no error. pmr_check_oe: test buf_of_flag,-1 ;Buffer overflow error ? jz exit_process_mr ;If = 0, no. Exit. mov buf_of_flag,00h ;Reset flag to 0, no error. lea dx,buff_ovrflo ;DS:DX = '$'. call display_str ;Display string. exit_process_mr: ret ;Return. process_modem_rchar endp ;------------------------------------------------------------------------------ ; Reads input from the keyboard and sends it to the modem. ; ; Callers: MAIN ; Uses: READ_KEY, MODEM_SEND_CHAR, DISPLAY_STR ; Returns: EXIT_FLAG = -1 if user wishes to quit the program. ;------------------------------------------------------------------------------ read_keyboard proc call read_key ;Read character from keyboard. jz exit_read_kb ;If ZR, no character read. Exit. cmp al,1Bh ;ESC key pressed ? jnz cont_read_kb ;If not, process keypress. mov exit_flag,-1 ;Else, set Exit Program Flag. jmps exit_read_kb ;And exit. cont_read_kb: call modem_send_char ;Send the character in AL to modem. test ah,80h ;(0000-1000) Send Error ? jz exit_read_kb ;If bit #3 not set, no. Exit. lea dx,send_error ;DS:DX = '$'. call display_str ;Display string. exit_read_kb: ret ;Return. read_keyboard endp ;------------------------------------------------------------------------------ ; INT 0Ch hook set by INIT_COM_PORT that reads input received by the modem. ; ; Uses: INC_BX_PTR ;------------------------------------------------------------------------------ modem_read_char proc far sti ;Set Interrupt Flags. push ax ;Push registers. push bx push dx push si push ds mov ax,dgroup ;AX = Data Segment. mov ds,ax ;Initial DS. nop ;NOP for debugging. mov dx,03FDh ;Base Port COM1 (03F8) + LSR (5). in al,dx ;AL = LSR status. and al,1Eh ;(0001-1110) Clear bits 0, & 5-7. jz mrc_no_lsr_error ;If AL = 0, jump. mov lsr_status,al ;Else, store LSR status. mrc_no_lsr_error: mov dx,03F8h ;Base Port COM1 (03F8). in al,dx ;AL = character read by modem. mov bx,mr_bx_ptr ;BX = this routines buffer ptr. mov si,bx ;SI = BX. call far ptr inc_bx_ptr ;Inc BX (internal buffer) pointer. cmp bx,pmr_bx_ptr ;Same as PROCESS_MODEM_RCHARs ptr ? jz mrc_buf_of_err ;If so, Buffer Overflow Error. mov [si],al ;Else, store char read by modem. mov mr_bx_ptr,bx ;Store BX pointer. jmps exit_modem_rchar ;And exit. mrc_buf_of_err: mov buf_of_flag,-1 ;Set flag. Buffer Overflow Error. exit_modem_rchar: cli ;Clear Interrupt Flags. mov al,20h ;AL = process other interrupts. out 20h,al ;Send command to PIC at 20h. pop ds ;Pop registers. pop si pop dx pop bx pop ax iret ;Return far. modem_read_char endp ;------------------------------------------------------------------------------ ; Deinitials COM1 and displays "OFF" msg. ; ; Callers: MAIN ; Uses: DISPLAY_STR ;------------------------------------------------------------------------------ deinit_com_port proc cli ;Clear Interrupt Flags. in al,21h ;AL = PIC port status. or al,10h ;(0001-0000) Set bit #4. out 21h,al ;COM1: Interrupt Disabled. mov dx,03FBh ;Base Port COM1 (03F8) + LCR (3). in al,dx ;AL = LCR status. and al,7Fh ;(0111-1111) Clear bit #7. out dx,al ;Deinitial normal access to ports ; 03F8h and 03F9h. mov dx,03F9h ;Base Port COM1 (03F8) + IER (1). mov al,00h ;All bits are to be cleared. out dx,al ;Disable Received Data Ready inter. mov dx,03FCh ;Base Port COM1 (03F8) + MCR (4). mov al,00h ;All bits are to be cleared. out dx,al ;Deinitial 8250 Interrupt Signals. sti ;Set Interrupt Flags. lea dx,off_message ;DS:DX = 0dh,0ah,'- JAXTALK OFF -', ; 0dh,0ah,'$' call display_str ;Display string. ret ;Return. deinit_com_port endp ;------------------------------------------------------------------------------ ; Reads character from the keyboard buffer using the BIOS. ; ; Callers: READ_KEYBOARD ; Returns: AL = character from keyboard. ; Zero flag set (ZR) = no character read. ;------------------------------------------------------------------------------ read_key proc mov ah,01h ;Read Keyboard Buffer Status. int 16h ;Call BIOS. jz exit_read_key ;If ZR, no character in buffer. pushf ;Push flags. mov ah,00h ;Read Character from Keyboard Buff. ; AL = ASCII character. ; If AL = 0, ; AH = extended ASCII code. int 16h ;Call BIOS. popf ;Pop flags. exit_read_key: ret ;Return. read_key endp ;------------------------------------------------------------------------------ ; Sends character in AL to the modem. ; ; Callers: READ_KEYBOARD ; Returns: AH = LSR status or 80h for Send Error. ;------------------------------------------------------------------------------ modem_send_char proc push bx ;Push registers. push cx push dx mov bl,al ;BL = character in AL. mov dx,03FCh ;Base Port COM1 (03F8) + MCR (4). mov al,0Bh ;(0000-1011) Set bits 0, 1, and 3. out dx,al ;Initial modem to send character. sub cx,cx ;CX = 0. mov dx,03FEh ;Base Port COM1 (03F8) + MSR (6). msc_chk_dsr_dcd: in al,dx ;AL = MSR status. test al,10h ;(1010) Are DSR and DCD bits set ? jnz msc_dsr_dcd_set ;If so, continue. loop msc_chk_dsr_dcd ;Else, loop til CX = 0. (FFFFh) mov ah,80h ;65,536 loops. Modem not ready. ; Set AH for Send Error. jmps exit_modem_schar ;And exit. msc_dsr_dcd_set: mov dx,03FDh ;Base Port COM1 (03F8) + LSR (5). sub cx,cx ;CX = 0. msc_chk_overrun: in al,dx ;AL = LSR status. test al,20h ;(0000-0010) Overrun error ? jnz complete_msc ;If so, continue. ???????? loop msc_chk_overrun ;Else, loop til CX = 0. (FFFFh) mov ah,80h ;65,536 loops. Modem not ready. ; Set AH for Send Error. jmps exit_modem_schar ;And exit. complete_msc: mov ah,al ;AH = LSR status. and ah,7Fh ;(0111-1111) Clear bit #7 in AH. mov al,bl ;AL = original char from keyboard. mov dx,03F8h ;Base Port COM1 (03F8). out dx,al ;Send AL to exit_modem_schar: ; Transmit Holding Register. pop dx ;Pop registers. pop cx pop bx ret ;Return. modem_send_char endp ;------------------------------------------------------------------------------ ; Displays character in AL onto the screen. ; ; Callers: PROCESS_MODEM_RCHAR ;------------------------------------------------------------------------------ disp_al_char proc push ax ;Push registers. push dx mov dl,al ;DL = Character. mov ah,02h ;AH = Character Output to Screen. int 21h ;Call DOS. pop dx ;Pop registers. pop ax ret ;Return. disp_al_char endp ;------------------------------------------------------------------------------ ; Displays string in DS:DX to the screen. ; ; Callers: INIT_COM_PORT, PROCESS_MODEM_RCHAR, READ_KEYBOARD, DEINIT_COM_PORT ;------------------------------------------------------------------------------ display_str proc push ax ;Push register. mov ah,09h ;AH = Display String. ; DS:DX = Address of string. int 21h ;Call DOS. pop ax ;Pop register. ret ;Return. display_str endp ;------------------------------------------------------------------------------ ; Increments BX ptr to internal buffer. Wraps around to prevent overwrite. ; ; Callers: PROCESS_MODEM_RCHAR, MODEM_READ_CHAR ;------------------------------------------------------------------------------ inc_bx_ptr proc inc bx ;BX = BX + 1. cmp bx,offset buffer[+buffer_size] ;End of internal buffer ? jnz exit_inc_bx_ptr ;If <>, exit. lea bx,buffer ;Else, wrap around to buffer start. exit_inc_bx_ptr: ret ;Return. inc_bx_ptr endp end main comment \ J A X T A L K Version 1.01, Sept. 6, 1985 The World's Smallest IBM PC Comm Program (CROSSTALK, eat your heart out!) Note the size of the .COM file. (469 bytes unless rounded up by XMODEM or a library utility. ARC will not round up.) To run: Type JT To quit (to DOS): Press Operation: Use your modem commands to operate. For example, using Hayes-compatible commands -- ATE1 enables modem echo to display what you type before a "connect". ATDT 1-302-764-7522 dials a good BBS. (ATDP if pulse dial system) ATH to hang up. If you see , , or printed to the screen, they are indications of the receive, send, and buffer overflow errors. An internal 32-byte comm buffer seems to do a good job at 1200 bps. Comm parameters are hard coded as COM1:1200,N,8,1. DEBUG may be used to change bps from 1200 to 300 or 2400 by changing the byte at offset 174H from the value 83H (1200 bps) to 43H (300 bps) or A3H (2400 bps). Example: D>debug jt.com -e174 xxxx:0174 83.A3 -w Writing 01D5 bytes -q If you choose to play with JT, I advise originating the call with it. Don't start JT after a "connect" using another comm program, or you'll lose the connection. JT also drops carrier when terminating (pressing ). Jack Kilday Central Ave. Peaks Island, ME 04108 9/6/85 v1.01 - Eliminated test for DSR since older style Hayes 1200's do not return a DSR until carrier detect. Now tests only for CTS. Shaved 13 bytes off program size. \