.286
.model huge, stdcall ; meomory and calling convation
option casemap :none ; case sensitive
include MyMacro.inc
QUEUE_MAX_BUFFER EQU 4 ; 최대 큐 버퍼 사이즈
init_serial proto near
EnQueue proto :byte
DeQueue proto
;-----------------------------------------------------------
SgIntVact segment at 0
org 30h
V_Com1VactOfs dw ?
V_Com1VactSeg dw ?
SgIntVact ends
;-----------------------------------------------------------
SgBiosData segment at 40h
org 0
V_Com1Port dw ?
V_Com2Port dw ?
SgBiosData ends
;-----------------------------------------------------------
data segment
V_OldComVactOfs dw ?
V_OldComVactSeg dw ?
V_ComDataPort dw ?
V_ComIntEnablePort dw ?
V_ComIntStatPort dw ?
V_ComLineCtrlPort dw ?
V_ComModemCtrlPort dw ?
V_ComLineStatPort dw ?
V_ComModemStatPort dw ?
V_InputChar db ?
Queue db 4 dup(0) ; 실제 큐
QueueSize db 0 ; 큐 사용량
TempPos db 0 ; 가상 인덱스
Position db 0 ; 실제 인덱스
data ends
stackseg segment stack
db 100h dup('stack')
stackseg ends
;-----------------------------------------------------------
code segment
;-----------------------------------------------------------
main proc far
invoke init_serial ;serial port initialize
;set segment
assume cs:code,ds:data
mov ax , data
mov ds , ax
;input loop
mov V_InputChar , 0
.while V_InputChar != '@'
mov ah , 06h
mov dl , 0FFh
int 21h
.if !zero?
mov V_InputChar , al
;send to serial
mov dx , V_ComDataPort
out dx , al
.endif
;큐에서 꺼내 출력하기
.if QueueSize == 4
mov cx, 4
CharLoop:
invoke DeQueue
mov ah, 2
int 21h
loop CharLoop
.endif
.endw
;serial off
cli
in al , 21h ;interupt off
or al , 10h
out 21h , al
;restore interupt vactor
assume es:SgIntVact
mov ax , SgIntVact
mov es , ax
mov ax , V_OldComVactOfs
mov cx , V_OldComVactSeg
mov V_Com1VactOfs , ax
mov V_Com1VactSeg , cx
sti
;serial reset
mov dx , V_ComIntEnablePort
xor ax , ax
out dx , al
mov dx , V_ComModemCtrlPort
out dx , al
;exist
mov ah , 4Ch
int 21h
main endp
;-----------------------------------------------------------
init_serial proc near
;com 1 initialize
;set interupt handler
;set segment
assume cs:code,ds:data,es:SgIntVact
mov ax , data
mov cx , SgIntVact
mov ds , ax
mov es , cx
;backup old interupt vactor
mov ax , V_Com1VactOfs
mov cx , V_Com1VactSeg
mov V_OldComVactOfs , ax
mov V_OldComVactOfs , cx
;set interupt vactor
cli
mov ax , offset Irq_Serial
mov cx , cs
mov V_Com1VactOfs , ax
mov V_Com1VactSeg , cx
;set interupt mask
in al , 21h
and al , 0EFh
out 21h , al
sti
;serial prot initialize
assume es:SgBiosData ;segment set
mov ax , SgBiosData
mov es , ax
;set com port set
mov ax , V_Com1Port
mov bx , offset V_ComDataPort
mov cx , 7
.repeat
mov word ptr ds:[bx] , ax
add bx , 2 ;next register pointer
inc ax ;next port address
.untilcxz
;set boud rate , parrity , data length , stop bit
mov dx , V_ComLineCtrlPort
mov al , 83h ;boud rate setting and none parrity ,
out dx , al ;1 stop bit , 8bit data
mov dx , V_ComDataPort
mov al , 0Ch ;9600 bps
out dx , al
mov dx , V_ComIntEnablePort
xor ax , ax
out dx , al
;set interupt
mov dx , V_ComLineCtrlPort
mov al , 3
out dx , al ;data io mode
mov dx , V_ComIntEnablePort
mov al , 1 ; data receved only
out dx , al
;set modem controler
mov dx , V_ComModemCtrlPort
mov al , 1011b ;enable interupt and RTS,DTR
out dx , al
ret
init_serial endp
;-----------------------------------------------------------
Irq_Serial proc far
;protect register
push ax
push dx
push ds
;set segment
assume ds:data
mov ax , data
mov ds , ax
;when recive do set input charactor
mov dx , V_ComIntStatPort
in al , dx
.if al & 100b ;interupt generate and recive data?
;set data
mov dx , V_ComDataPort
in al , dx
invoke EnQueue, al
.endif
;set EOI
mov al , 20h
out 20h , al
;restore register
pop ds
pop dx
pop ax
iret
Irq_Serial endp
EnQueue PROC MyValue:BYTE
pusha
assume ds:data
mov ax, data ;
mov ds, ax ; 데이터 세그먼트 설정
cmp QueueSize, QUEUE_MAX_BUFFER ; 현재버퍼크기 >= 최대버퍼크기
jge LABEL_BufferFull ; 버퍼가 꽉 찻으므로 종료
cmp Position, QUEUE_MAX_BUFFER ;
jl LABEL_PositionNext ; 데이터인덱스 < 최대버퍼크기
mov Position, 0 ; Postion = 0
LABEL_PositionNext:
mov ah, Position ;----------------------------------
mov al, QueueSize ; TempPos = Position + QueueSize
add ah, al ;
mov TempPos, ah ;----------------------------------
cmp TempPos, QUEUE_MAX_BUFFER ;
jl LABEL_TempPosChange ; TempPos < 최대버퍼크기
sub TempPos, QUEUE_MAX_BUFFER ; TempPos = TempPos - 최대버퍼크기
LABEL_TempPosChange:
mov ah, MyValue ;----------------------------------
xor bx, bx ; 지정된 위치에 데이터 넣기
mov bl, byte ptr TempPos ;
mov Queue[bx], ah ;----------------------------------
inc QueueSize ; 현재버퍼크기 1 증가
LABEL_Exit:
popa
ret
LABEL_BufferFull:
;버퍼가 가득 차면 현재큐내용을 보여주고 초기화
ShowAllQueueDebugString
mov QueueSize, 0
mov TempPos, 0
mov Position, 0
NextLine
;
popa
ret
EnQueue ENDP
;-------------------------------------------------------------------
;
; 큐에서 값 하나를 꺼낸다.
;
; 인자 :
; 리턴 : DL -> 큐에서 꺼낸 값
;
;-------------------------------------------------------------------
DeQueue PROC
push ax ;-----------------------------
push ds ; 레지스터 보호
push bx ; ax, ds, bx, si, cx
push si ;
push cx ;-----------------------------
assume ds:data
mov ax, data ;
mov ds, ax ; 데이터 세그먼트 초기화
cmp QueueSize, 0 ;
jz LABEL_BufferEmpty ; 큐에 내용이 없으면 Buffer UnderFlow
xor bx, bx ;
mov bl, byte ptr Position ; 가져 올 값의 인덱스 구하기 -> BL
mov dl, Queue[bx] ; 구한 인덱스릐 큐 값을 DL에 넣는다. -> DL
mov Queue[bx], 0 ; 값을 빼고 빈자리에 'x'를 넣는다.
inc Position ; 인덱스를 다음 값의 위치로 셋팅
dec QueueSize ; 큐 사이즈를 하나 줄인다.
pop cx ;---------------------------------
pop si ; 레지스터 복원
pop bx ; cx, si, bx, ds, ax
pop ds ;
pop ax ;---------------------------------
ret
LABEL_BufferEmpty:
ShowAllQueueDebugString
mov QueueSize, 0
mov TempPos, 0
mov Position, 0
NextLine
pop cx ;---------------------------------
pop si ; 레지스터 복원
pop bx ; cx, si, bx, ds, ax
pop ds ;
pop ax ;---------------------------------
ret
DeQueue ENDP
;-----------------------------------------------------------
code ends
;-----------------------------------------------------------
end main