.286
.model small
.code
org 100h

; UART Registers

SER_RBF			EQU	0	; Буфер чтения
SER_THR			EQU 0	; буфер записи
SER_IER			EQU	1	; регистр разрешения прерываний
SER_IIR			EQU 2	; рег. идентификации прерываний
SER_LCR			EQU 3	; рег. управл. данных и разрешен. загрузки делителя
SER_MCR			EQU 4	; рег. управл. модемом
SER_LSR			EQU 5	; рег. состояния линии
SER_MSR			EQU 6	; рег. сост. модема
SER_DLL			EQU 0	; рег. младш. байт делителя
SER_DLH			EQU 1	; рег. старш. байт делителя 

; Registers Bit masks

SER_BAUD_1200	EQU 96	; делители для различных скоростей
SER_BAUD_2400	EQU 48
SER_BAUD_9600	EQU 12
SER_BAUD_19200	EQU 6
SER_BAUD_38400	EQU	3
SER_BAUD_57600	EQU 2

SER_GP02		EQU 8	; разрешение прерываний

COM1			EQU	3f8h	; Начальные порты комов
COM2			EQU 2f8h    ;

SER_STOP_1		EQU 0	; стоп-бит на символ
SER_STOP_2		EQU 4	

SER_BITS_5		EQU 0	; х зачащих бит на символ
SER_BITS_6		EQU 1
SER_BITS_7		EQU 2
SER_BITS_8		EQU 3

SER_PARITY_NONE	EQU 0 	; контроль четности
SER_PARITY_ODD	EQU 8
SER_PARITY_EVEN	EQU 24

SER_DIV_LATCH_ON	EQU 128	; исп при загрузке делителя

PIC_IMR			EQU 21h		; маска для регистра прерываний
PIC_ICR			EQU 20h		; маска для контроллера прерываний

INT_SER_PORT_0	EQU 0Ch		; для управления прерыван. COM1 & COM3
INT_SER_PORT_1	EQU 0Bh		; для управления прерыван. COM2 & COM4

; Current setting(for COM1), change them 
;-------------------------------
PORT 			EQU 3f8h
INT_SER_PORT	EQU 0Ch
INT_MASK		EQU 0EFh	; (0F7h - for COM2-4)
CONFIG			EQU 3	 	; (PARITY_NONE|SER_BITS_8|SER_STOP_1)
SER_BAUD		EQU 3		; 38400
BUF_LEN			EQU 1024
;-------------------------------
start:
;		Open sereal port
;----------------------------
									;  Set port speed
		mov dx, PORT+SER_LCR		;-------
		mov al, SER_DIV_LATCH_ON	; разрешаем загрузку делителя
		out dx, al					;-------

		mov dx, PORT+SER_DLL		;-------
		mov al, SER_BAUD			; посылаем младш байт делителя
		out dx, al					;-------

		mov dx, PORT+SER_DLH		;-------
		mov al, 0       			; посылаем старш байт делителя
		out dx, al					;-------

		mov dx, PORT+SER_LCR		;-------
		mov al, CONFIG  			; уст конфигурацию порта
		out dx, al					;-------

		mov dx, PORT+SER_MCR		;-------
		mov al, SER_GP02			;
		out dx, al					; Разрешаем
		mov dx, PORT+SER_IER		;       прерывания
		mov al, 1					;
		out dx, al					;-------

		mov ah,	35h					;-----------
		mov al, INT_SER_PORT		; Get Old 
		int 21h						;		Vector
		mov old_vec_seg,	es		;			PORT COM1
		mov old_vec_offs,	bx		;-----------

		mov ah,	25h					;-----------
		mov al, INT_SER_PORT		; Set NEW 
		mov dx, offset Serial_ISR	;		Vector
		int 21h						;-----------

		in 	al, PIC_IMR				; Старые биты контроллера прерываний
		mov old_int_mask, al		; 
		and al, INT_MASK

		out PIC_IMR, al				; разрешаем прерывание COM1
;-----------------------------------------------------------------
		mov ah, 08h
		int 21h

;------------------------------------
; Close port
;		
		mov dx, PORT+SER_MCR		;-------
		mov al, 0					;
		out dx, al					; Запрещаем
		mov dx, PORT+SER_IER		;       прерывания
		mov al, 0					;
		out dx, al					;-------
		
		mov al, old_int_mask		;
		out PIC_IMR, al				; Уст старые настройки контроллера прерыван

		mov ah,	25h					;-----------
		mov al, INT_SER_PORT		; Set OLD
		mov dx, old_vec_offs		;		Vector
		mov ds, old_vec_seg			;		Vector
		int 21h						;-----------
		int 20h

; Interrupt vector
Serial_ISR:
	pusha
		mov ser_lock, 1
		mov dx, PORT+SER_RBF 
		in al, dx    
		inc pos_wrt
		cmp pos_wrt, BUF_LEN-1
		jna OK
		mov pos_wrt, 0
OK:		mov di, pos_wrt
		mov buffer[di], al
		inc char_ready
		mov al, 20h
		cli
		out PIC_ICR, al
		mov ser_lock, 0
	popa
iret

Ser_Write	proc	near	; Ser_Write(ch: char)
push bp
mov bp, sp
	CHAR	EQU byte ptr [bp+4]
	pusha
		mov dx, PORT+SER_LSR 
WT:		in al, dx
		and al, 20h
		jz WT
		mov dx, PORT+SER_THR
		mov al, CHAR
		cli
		out dx, al
		sti		
	popa
	pop bp
	ret 2
endp

old_vec_offs	dw 0
old_vec_seg		dw 0
old_int_mask	db 0
ser_lock		db 0
pos_wrt			dw -1
pos_rd			dw -1
char_ready		db 0
buffer			db BUF_LEN dup (?)
end start