; serial port routines for ibm-pc, including atari portfolio ; r. henze 17.07.90 ; last edit 04.01.96 NAME TMIO ;82C50 constants: ser_bas1 equ 402h ;com2 ser_bas0 equ 400h ;com1 rbr equ 0h ;receiver reg thr equ 0h ;transmitter ier equ 1h ;interrupt en iir equ 2h ;interrupt id lcr equ 3h ;line ctrl mcr equ 4h ;modem ctrl lsr equ 5h ;line status msr equ 6h ;modem status ;interrupt controller: int_reg equ 807fh ;adr ser vect reg int_on equ 01h ;enable int int_off equ 00h ;disable int ;control bytes: dtr equ 01h rts equ 02h thre_mask equ 20h ;miscelaneous definitions cr equ 0dh lf equ 0ah ;port_default equ 83h ; 8 bit, 1 stop bit, 1200 baud port_default equ 0e3h ; 8 bit, 1 stop bit, 9600 baud strp_top equ 7fh ;memory allocation blocks: buf_len equ 500h ;input buffer stk_len equ 200h ;stack ;machine identification: pcidsg segment at 0f000h org 0fffeh pcid db (?) pcidsg ends ;------------------------------------ DGROUP GROUP _DATA,_BSS _DATA SEGMENT WORD PUBLIC 'DATA' public _port_stat public _tmdp_cnt tmio_base dw 0 tmio_offc dw 0 tmio_segc dw 0 _port_stat dw 0 port_par dw port_default ;buffer storage tmdp_cbuf db buf_len dup (00) tmdp_head dw offset tmdp_cbuf tmdp_tail dw offset tmdp_cbuf _tmdp_cnt dw 0 ;tmdp_ful dw 0 scratch dw 0 com_port dw 0 int_num dw 000ch ;int number com1 int_ena dw 00efh ;int enable com1 int_dsa dw 0010h ;int disable com1 ctc_flag dw 0 ;control-c flag pf_flag dw 0 ;machine-id flag, 0: normal pc, 1: portfolio _DATA ENDS _BSS SEGMENT WORD PUBLIC 'BSS' _BSS ENDS ;------------------------------------ _TEXT SEGMENT BYTE PUBLIC 'CODE' ASSUME CS: _TEXT, DS: _DATA public _send_com public _exit_com public _tmio_setup public _receive_com public _cout public _put public _hex public _hex8 ;Control-C abfangen: public _nobreak public _get_ctc ;***** aufruf in c: ;extern void nobreak (); ;extern int get_ctc (); ;------------------------------------ ;tmio_setup ;sets up serial port ;parmeters : port parameter-byte ;returns : none ;destroys : none _tmio_setup proc near push bp push ax mov bp,sp mov ax,[bp+6] mov port_par,al mov com_port,ah cmp com_port,0 je co1 mov int_num,0bh ;int number com2 mov int_ena,0f7h ;int enable com2 mov int_dsa,08h ;int disable com2 jmp co2 co1: mov int_num,0ch ;int number com1 mov int_ena,0efh ;int enable com1 mov int_dsa,10h ;int disable com1 co2: push dx cli push bx push es mov al,int_num mov ah,35h int 21h mov tmio_segc,es mov tmio_offc,bx pop es pop bx push ds mov al,int_num mov ah,25h mov dx,offset cs:_tmio_intc mov ds,cs int 21h pop ds sti call _tmio_init call _tmio_inon pop dx pop ax pop bp ret _tmio_setup endp ;----------------------------------- ;receive_com ;get character from buffer ;parmeters : address where character will be installed ;returns : ax : 1 char fetched, 0 no char fetched ;destroys : none _receive_com proc near push bp push dx push di push si mov bp,sp mov ax,[bp+10] ;save parameter cmp _tmdp_cnt,0 ;buffer empty? jle gete0 push ax ;save char pointer mov di,tmdp_tail mov al,[di] ;get char from buffer mov scratch,al ;and save it pop ax ;get char pointer back mov di,ax mov [di],scratch ;store char at input pointer inc tmdp_tail ;and increment pointer mov ax,offset tmdp_cbuf add ax,buf_len cmp ax,tmdp_tail jg get1 mov ax,offset tmdp_cbuf mov tmdp_tail,ax ;turn pointer back to start get1: dec _tmdp_cnt ;decrement buffer count mov ax,1 jmp gete1 gete0: xor ax,ax gete1: pop si pop di pop dx pop bp ret _receive_com endp ;----------------------------------- ; send_com ; sends a char to serial port ; stack : char to send ; returns : ax = 1 ; destroys: none _send_com proc near push bp push dx push di mov bp,sp mov ax,[bp+8] ;uebergabe parameter push ax mov di,tmio_base mov dx,lsr add dx, di char_wthr: in al,dx test al,thre_mask jz char_wthr pop ax mov dx,thr add dx,di out dx,al mov ax,1 pop di pop dx pop bp ret _send_com endp ;----------------------------------- ; tmio_init : init serial port ; 1200 baud, 8 bits, no parity ; dtr high ; parameters : none ; returns: : none ; destroys: :none _tmio_init proc near push ax push si push dx push di ;set machine id (0: normal pc, 1: portfolio) push ax push ds mov ax,pcidsg mov ds,ax cmp pcid,255 je ptf mov al,0 jmp npc ptf: mov al,1 npc: pop ds mov pf_flag,al pop ax ;---end set machine-id cmp com_port,0 je com1 xor ax,ax push ds mov ds,ax mov di,[ser_bas1] pop ds jmp com2 com1: xor ax,ax push ds mov ds,ax mov di,[ser_bas0] pop ds com2: mov tmio_base,di call _tmio_inof mov al,port_par call _tmio_inpt cmp pf_flag,0 je ibm1 ;code for portfolio: mov ax,int_num call _tmio_sint jmp ptf1 ;code for standard ibm-pc: ibm1: in al,21h and al,int_ena out 21h,al ptf1: ;set up modem control reg: mov dx,mcr add dx,di cmp pf_flag,0 je ibm2 ;code for portfolio: mov al,dtr or rts jmp ptf2 ;fuer dcf-77 uhr (pin4=high (+), pin7=low (-) ; mov al,dtr ;code for standard ibm-pc: ibm2: mov al,dtr or rts or 8 ;fuer dcf-77 uhr (pin4=high (+), pin7=low (-) ; mov al,dtr or 8 ptf2: out dx,al call _tmio_inon mov dx,di in al,dx pop di pop dx pop si pop ax ret _tmio_init endp ;------------------------------------ ; tmio_inon ; enables serial interrupts ; parameters : none ; returns : none ; destroys : al, dx _tmio_inon proc near push ax push dx mov dx,ier add dx,tmio_base in al,dx or al,int_on out dx,al pop dx pop ax ret _tmio_inon endp ;------------------------------------- ;tmio_inof ;disable serial interrupts ;parameters : none ;returns : none ;destroys : none _tmio_inof proc near push ax push dx mov dx,ier add dx,tmio_base mov al,int_off out dx,al pop dx pop ax ret _tmio_inof endp ;----------------------------------- ;tmio_intc ;serial read interrupt service ;parameters : none ;returns : none ;destroys : none _tmio_intc proc near push bp push ax push dx push di push ds push es mov ax,_data mov ds,ax mov es,ax ;get our data segment ; mov dx,lsr ; add dx,tmio_base ; in al,dx ;get port status ; mov _port_stat,al ;and save it mov dx,rbr add dx,tmio_base in al,dx ;get character ;*** and al,strp_top mov dl,al ;and save it cmp _tmdp_cnt,buf_len jl intc1 ;jump if buffer not full ; mov al,1 ; mov tmdp_ful,al ;set buffer_ful flag: full jmp icend intc1: ; mov al,0 ; mov tmdp_ful,al ;set buffer_ful flag: not full mov di,tmdp_head mov al,dl mov [di],al ;install char at address inc tmdp_head ;increment buffer pointer mov ax,offset tmdp_cbuf add ax,buf_len cmp ax,tmdp_head jg intc2 mov ax,offset tmdp_cbuf mov tmdp_head,ax ;turn buffer pointer back to start intc2: inc _tmdp_cnt ;increment buffer count icend: cmp pf_flag,1 je ptf3 ;code for standard ibm-pc: mov al,20h out 20h,al ptf3: pop es pop ds pop di pop dx pop ax pop bp iret _tmio_intc endp ;---------------------------------- ;exit_com ;ensures save exit from terminal emulator ;parameters : none ;returns : none ;destroys : none _exit_com proc near push ax push bx push dx call _tmio_inof ;put old interrupt service routine back push ds mov ah,25h mov al,int_num mov dx,tmio_offc mov ds,tmio_segc int 21h pop ds cmp pf_flag,0 je ibm4 ;for portfolio: in al,21h or al,int_dsa out 21h,al mov al,48h call _tmio_sint jmp ptf4 ;code for standard ibm-pc: ibm4: in al,21h or al,int_dsa out 21h,al ptf4: pop dx pop bx pop ax ret _exit_com endp ;------------------------------------ ;tmio_sint ;will replace existing entry if possible ;this routine uses int 61h service 1ch ;to ensure that power down will not ;corrupt serial port vector register ;parmeters : al interrupt number ;returns : none ;destroys : none _tmio_sint proc near push ax push bx push cx push dx ;check for vector already set up push ax mov cl,3 sint_srch: inc cl cmp cl,11 je sint_seti mov ax,1c01h mov bh,cl int 61h ;check if sivr has been set up before cmp dx,int_reg jne sint_srch sint_wral: pop ax mov bl,al mov bh,cl mov dx,int_reg mov ax,1c00h int 61h jmp sint_exit ;find an empty entry table to use sint_seti: mov cl,3 sint_sr00: inc cl cmp cl,11 je sint_bodg mov ax,1c01h mov bh,cl int 61h cmp dx,0 jne sint_sr00 jmp sint_wral sint_bodg: ;no entry table has been found to do ;it the bad way pop ax mov dx,int_reg out dx,al sint_exit: pop dx pop cx pop bx pop ax ret _tmio_sint endp ;------------------------------------- ;tmio_inpt ;initialise 80c50 (based on int 14h serv. 0) ;parameters : al Port parameters ; bits 7,6,5 baud rate ; 00 0 110 ; 00 1 150 ; 01 0 300 ; 01 1 600 ; 10 0 1200 ; 10 1 2400 ; 11 0 4800 ; 11 1 9600 ; bits 4,3 parity ; x0 none ; 01 odd ; 11 even ; bit 2 stop bits ; 0 1 bit ; 1 2 bit ; bits 1,0 word length ; 10 7 bits ; 11 8 bits ; returns : none ; destroys: none _tmio_inpt proc near push ax mov cl,5 shr al,cl jz init_spec mov cl,al mov ch,06h shr cx,cl jmp short init_norm init_spec: mov cx,417h init_norm: mov dx,tmio_base add dx,lcr mov al,80h out dx,al mov dx,tmio_base mov al,cl out dx,al inc dx mov al,ch out dx,al pop ax and al,1fh mov dx,tmio_base add dx,lcr out dx,al ret _tmio_inpt endp ;--------------------------------------------------------------- ;fuer testzwecke: chrout proc near push dx mov dl,al mov ah,2 int 21h pop dx ret chrout endp hexout proc near push cx mov ah,0 push ax mov cl,4 shr ax,cl ;isoliere hs-nibble cmp al,9 jle h1 add al,7 ;bearbeite 0ah...0fh h1: add al,30h ;bearbeite 0...9 call chrout ;ausgabe hs-nibble pop ax and al,0fh ;isoliere ls-nibble cmp al,9 jle h2 add al,7 ;bearbeite 0ah...0fh h2: add al,30h ;bearbeite 0...9 call chrout ;ausgabe hs-nibble pop cx ret hexout endp whxout proc near push ax mov al,ah ;*** cmp al,0 je whx1 ;don't output leading zeros call hexout ;ausgabe hoeherweriges byte whx1: pop ax call hexout ;ausgabe niederweriges byte ret whxout endp ;----------------------------------- _cout proc near push bp push dx mov bp,sp mov dx,[bp+6] ;uebergabe parameter mov ah,2 int 21h pop dx pop bp ret _cout endp ; hex ; puts 16-bit integer hex-coded to console ; stack : 16-bit int ; returns : none ; destroys: none _hex proc near push bp mov bp,sp mov ax,[bp+4] ;uebergabe parameter call whxout pop bp ret _hex endp ;----------------------------------- ; hex8 ; puts 8-bit character hex-coded to console ; stack : 16-bit int ; returns : none ; destroys: none _hex8 proc near push bp mov bp,sp mov ax,[bp+4] ;uebergabe parameter push ax call hexout ;hexcode to screen mov al,20h ;and blank call chrout pop ax pop bp ret _hex8 endp ;----------------------------------- crlf proc near push ax mov al,0dh call chrout mov al,0ah call chrout pop ax ret crlf endp _put proc near ;ausgabe string auf konsole push bp push ax push di mov bp,sp mov ax,[bp+8] ;save parameter (adresse string) mov di,ax putlp: mov al,[di] cmp al,0 je putend cmp al,lf jne put1 mov al,cr call chrout mov al,lf ;lf --> cr,lf put1: call chrout inc di jmp putlp putend: pop di pop ax pop bp ret _put endp ;--------------------------------------------------------------------- ; Control-C abfangen: _nobreak proc near ;-- Interrupt-Handler installieren ---------------- push bp push dx push ax cli push ds mov ax,2523h ;Fkt.nr.: Ctrl-Break-Handler setzen mov dx,offset cs:cbreak ;DS:DX enh„lt jetzt Adresse des H. mov ds,cs int 21h ;DOS-Interrupt aufrufen pop ds sti mov ctc_flag,0 ;clear control-c flag pop ax pop dx pop bp ret _nobreak endp _get_ctc proc near push bp mov ax,ctc_flag ;return control-c flag mov ctc_flag,0 ;clear control-c flag pop bp ret _get_ctc endp ;-- CBREAK: der neue Ctrl-Break-Handler -------------------------------- cbreak proc near ;-- alle, innerhalb dieser Routine ver„nderten Register ------ ;-- (exklusive des Flag-Registers) mssen auf dem Stack ------ ;-- gesichert werden. ------ push bp push ax push dx push di push ds push es mov ax,_data mov ds,ax mov es,ax ;get our data segment mov ctc_flag,2e03h ;-- hier kann z.B. ein Bildschirmfenster ge”ffnet werden, ---- ;-- indem der Benutzer gefragt wird, ob er das Programm ---- ;-- wirklich beenden m”chte. ---- pop es pop ds pop di pop dx pop ax pop bp ; pop ds ;gesicherte Register zurckholen iret ;zurck in's DOS, wo die unterbrochene ;Funktion normal fortgefhrt wird cbreak endp _TEXT ENDS END ;----------- end of file tmio.asm -----------------------------------