;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Hw7 Parallel IO ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .model small .586 .stack 100h ;Set maximum stack size to 256 bytes .data ;; all port definitions for COM1 rbr equ 03f8h thr equ 03f8h ier equ 03f9h iir equ 03fAh fcr equ 03fAh lcr equ 03fBh mcr equ 03fCh lsr equ 03fDh msr equ 03feh scr equ 03ffh dl_lsb equ 03f8h dl_msb equ 03f9h .data bufsize equ 256 ;; define buffer size buffer db bufsize dup(?) ;; buffer data area head dw 0 tail dw 0 ;; assume this routine is called on a 16550D interrupt ;; will stick a character in the circular buffer .code serint proc push dx push ax ; first check if this is a receive interrupt mov dx, iir in al, dx cmp al, 04h ;; from table 10.7, this value indicates byte is ready jne other_interrupt ;; need to stick data in serial buffer. First, save all other registers that we will ;; use push ds push bx push cx ;; set data segment to correct value mov ax, @data mov ds, ax rd_loop: call in1char_nowait ;; read character from 16550D if it is available jc serinit_exit ;; ignore character if error jz serinit_exit ;; if zero flag set, then no character, exit mov cl, al ;; save character in cl ;; now, we need to increment the head pointer. We will not check ;; for full conditions, data will simply be lost. mov ax, [head] call inc_ptr ;; call subroutine to increment pointer mov [head],ax ;; save new head pointer mov bx, offset bufsize ;; get starting address of buffer add bx, ax ;; compute address of where to put data ;; bx now points to where to store data mov [bx],al ;; store character in buffer jmp rd_loop ;; need to keep reading characters until fifo empty serinit_exit: pop cx ;; restore registers and return. pop bx pop ds pop ax pop dx iret other_interrupt: ;; would need code here to check and clear other interrupts ;; just return for now pop ax pop dx iret serint endp inc_ptr proc ;; procedure to increment either head or tail pointer passed in ax inc ax cmp ax, bufsize ;; see if we are at end of buffer jb inc_ptr_exit ;; if below bufsize, not at end yet mov ax, 0 ;; set pointer back to zero inc_ptr_exit: ret inc_ptr endp ; will return character in al if one is available. If no character ; available, the Z=1, else Z=0. ; if error occurs, set C=1. in1char_nowait proc ;; check if RBR has data, check DR bit in line status register mov dx,lsr ;; point dx at lsr in al,dx ;; read lsr test al, 00000001b ;; check if DS bit set jz noerror ;; no data, Z=1 ;; RBR now has data, read it. mov dx, rbr ;; point dx at RBR in al, dx ;; now check for errors mov bl,al ;; save al in bl mov dx, lsr ;; point dx at line status register in al, dx ;; read lsr test al, 00001110b ;; check for Framing error, parity error, overrun jnz inerror mov al,bl ;; no error, put character back in al or dl, 1 ;; clear zero flag noerror: clc ;; clear carry ret inerror: stc ;; error, set carry, return. AL has error status ret in1char_nowait endp ;; wait for data to be place in circular buffer, and read it get_data_wait proc push ds mov ax, @data mov dx, ax ;; point data segment at data get_lp1: mov ax,[tail] cmp ax,[head] ;; compare head to tail jz get_lp1 ;; loop until not empty call inc_ptr ;; increment the pointer mov [tail],ax ;; save new tail value mov bx, offset bufsize ;; get starting address of buffer add bx, ax ;; compute address of where to put data ;; bx now points to where to store data mov al,[bx] ;; read character from buffer pop ds ret get_data_wait endp end in1char_nowait