Assembly2010. 1. 5. 02:02

벌써 세월이 이렇게나 지나서 이렇게 다시 보니 감회가 새롭네요. 우연히 찾은거라 백업용으로 남겨둡니다.
Posted by houdinist
Assembly2010. 1. 5. 01:53

.286
.model large, stdcall
option casemap:none


;------------------------------------------------------------------------------------
; procedure declare
;------------------------------------------------------------------------------------
;------------------------------------------------------------------------------------
; DrawBitmap
;
; wBitmapSegment:word   =>  Bitmap Data segment
; wBitmapOffset:word    =>  Bitmap Data offset
; wX:word               =>  x coordination
; wY:word               =>  y coordination
; wWidth:word           =>  width
; wHeight:word          =>  height
; wColorKey             =>  Color Key
;
; 반환값                =>  cx : x 좌표
;                           dx : y 좌표
DrawBitmap proto far :word, :word, :word, :word, :word, :word, :word

;------------------------------------------------------------------------------------
; ClearBitmap
;
; wBitmapSegment:word   =>  Bitmap Data segment
; wBitmapOffset:word    =>  Bitmap Data offset
; wX:word               =>  x coordination
; wY:word               =>  y coordination
; wWidth:word           =>  width
; wHeight:word          =>  height
ClearBitmap proto far :word, :word, :word, :word, :word, :word

;------------------------------------------------------------------------------------
; data segment
;------------------------------------------------------------------------------------
seg_data segment
        v_image byte    054h,054h,054h,023h,023h,023h,023h,054h,054h,054h,
                        054h,054h,023h,023h,023h,023h,023h,023h,054h,054h,
                        054h,023h,023h,023h,023h,023h,023h,023h,023h,054h,
                        023h,023h,023h,023h,023h,023h,023h,023h,023h,023h
        v_backupimage   byte    100     dup     (18h)
        v_x             word    0
        v_y             word    0
seg_data ends

;------------------------------------------------------------------------------------
; stack segment
;------------------------------------------------------------------------------------
seg_stack segment stack
                        byte    100h    dup     ('stack')
seg_stack ends

;------------------------------------------------------------------------------------
; code segment
;------------------------------------------------------------------------------------
seg_code segment
main proc far
        xor     ax, ax
        push    ds
        push    ax

        assume  cs:seg_code, ds:seg_data, ss:seg_stack
        mov     ax, seg_data
        mov     ds, ax

        ; 13h graphic mode
        mov     ah, 0
        mov     al, 13h
        int     10h

        mov     ax, 0A000h
        mov     es, ax

        ; Clear Screen
        mov     cx, 320*200
        mov     di, 0
        mov     al, 018h
        cld
        rep     stosb

L_TEXTLOOP:
        mov     ax, 3
        int     33h
        or      bx, bx
        jnz     L_EXIT

        shr   cx , 1

        .if (v_x != cx)||(v_y != dx)
                push    cx
                push    dx
                invoke  ClearBitmap, seg v_backupimage, offset v_backupimage, v_x, v_y, 10, 4
                pop     dx
                pop     cx

                mov     v_x, cx
                mov     v_y, dx
                invoke  DrawBitmap,  seg v_image,  offset v_image,  cx,  dx,  10,  4, 54h
        .endif

        jmp     L_TEXTLOOP
L_EXIT:
        ; 3 text mode
        mov     ah, 0
        mov     al, 3
        int     10h

        ret
main endp

;------------------------------------------------------------------------------------
; Bitmap Draw
DrawBitmap proc far wBitmapSegment:word, wBitmapOffset:word, wX:word, wY:word, wWidth:word, wHeight:word, wColorKey:word
        ; 지역변수 선언
        local   wXCount:word
        local   wYCount:word

        mov     wXCount, 0
        mov     wYCount, 0

        ; 레지스터 보호
        push    ds
        push    es

        ; 클리핑 처리
        .if     wX >= 309
                mov     wX, 309
        .elseif wY >= 195
                mov     wY, 195
        .elseif wX <= 0
                mov     wX, 0
        .elseif wY <= 0
                mov     wY, 0
        .endif

        ; 비트맵 세그먼트 설정
        mov     ax, wBitmapSegment
        mov     ds, ax

        ; 비트맵 옵셋 설정
        mov     si, wBitmapOffset

        ; 비디오 세그먼트 설정
        mov     ax, 0A000h
        mov     es, ax

        ; 시작 주소 계산
        mov     ax, wY
        mov     cx, 320
        mul     cx
        add     ax, wX
        mov     di, ax  ; di => 최종 비디오 메모리 주소

        push    di
        ; 배경 저장
        mov     ax, wHeight
        lea     bx, ds:v_backupimage
        .while wYCount < ax
                mov     ax, wWidth
                .while  wXCount < ax
                        mov     al, es:[di]
                        mov     ds:[bx], al
                        inc     di
                        inc     bx
                        inc     wXCount
                        mov     ax, wWidth
                .endw

                mov     ax, 320
                sub     ax, wWidth
                add     di, ax

                mov     wXCount, 0
                inc     wYCount
                mov     ax, wHeight
        .endw
        pop     di

        mov     wXCount, 0
        mov     wYCount, 0
        ; 실제 그리기
        mov     ax, wHeight
        .while wYCount < ax
                mov     ax, wWidth
                .while wXCount < ax
                        mov     al, byte ptr ds:[si]
                        .if     al != byte ptr wColorKey
                                mov     es:[di], al
                                inc     di
                                inc     si
                                inc     wXCount
                                mov     ax, wWidth
                        .else
                                inc     di
                                inc     si
                                inc     wXCount
                                mov     ax, wWidth
                        .endif
                .endw

                mov     ax, 320
                sub     ax, wWidth
                add     di, ax

                mov     wXCount, 0
                inc     wYCount
                mov     ax, wHeight
        .endw

L_EXIT:
        ; 위치 저장
        mov     cx, wX
        mov     dx, wY

        pop     es
        pop     ds
        ret
DrawBitmap      endp

;------------------------------------------------------------------------------------
; Bitmap Clear
ClearBitmap proc far wBitmapSegment:word, wBitmapOffset:word, wX:word, wY:word, wWidth:word, wHeight:word
        ; 지역변수 선언
        local   wXCount:word
        local   wYCount:word
        mov     wXCount, 0
        mov     wYCount, 0

        ; 레지스터 보호
        push    es

        .if     wX >= 309
                mov     wX, 309
        .elseif wY >= 195
                mov     wY, 195
        .elseif wX <= 0
                mov     wX, 0
        .elseif wY <= 0
                mov     wY, 0
        .endif

        ; 비트맵 세그먼트 설정
        mov     ax, wBitmapSegment
        mov     ds, ax

        ; 비트맵 옵셋 설정
        mov     si, wBitmapOffset

        ; 비디오 세그먼트 설정
        mov     ax, 0A000h
        mov     es, ax

        ; 시작 주소 계산
        mov     ax, wY
        mov     cx, 320
        mul     cx
        add     ax, wX
        mov     di, ax          ; di => 최종 비디오 메모리 주소

        ; 배경 이미지 복원
        mov     ax, wHeight
        .while wYCount < ax
                mov     ax, wWidth
                .while  wXCount < ax
                        mov     al, byte ptr ds:[si]
                        mov     es:[di], al
                        inc     di
                        inc     si
                        inc     wXCount
                        mov     ax, wWidth
                .endw

                mov     ax, 320
                sub     ax, wWidth
                add     di, ax

                mov     wXCount, 0
                inc     wYCount
                mov     ax, wHeight
        .endw

L_EXIT:
        pop     es
        ret
ClearBitmap     endp
seg_code ends

        end     main




Posted by houdinist
Assembly2010. 1. 5. 01:46




.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

Posted by houdinist
Assembly2010. 1. 5. 01:44



.MODEL LARGE, STDCALL

.386

;----------------------------------------------------------------------------------------
;    인클루드 선언
;----------------------------------------------------------------------------------------
INCLUDE MyMacro.inc



;----------------------------------------------------------------------------------------
;    프로시져 선언
;----------------------------------------------------------------------------------------
PROC_EnQueue PROTO  :BYTE
PROC_DeQueue PROTO



;----------------------------------------------------------------------------------------
;    퍼블릭 선언
;----------------------------------------------------------------------------------------
PUBLIC Queue                ; 외부에서 큐 내용을 참조할 수 있도록 공개



;----------------------------------------------------------------------------------------
;    상수 선언
;----------------------------------------------------------------------------------------
QUEUE_MAX_BUFFER    EQU    4    ; 최대 큐 버퍼 사이즈
Debug            EQU    1    ; 1 -> 디버깅 내용 출력, 0 -> 디버깅 내용 출력 안함



;----------------------------------------------------------------------------------------
;    데이터 세그먼트
;----------------------------------------------------------------------------------------
QUEUE_DATASEG SEGMENT
    Queue            db    4 dup('x')    ; 실제 큐
    QueueSize        db    0        ; 큐 사용량
    TempPos            db    0        ; 가상 인덱스
    Position        db    0        ; 실제 인덱스
    StrBufferOverFlow    db    'Buffer Overflow', 0Ah, 0Dh
    BufferUnderFlow        db    'Buffer Underflow', 0Ah, 0Dh
    strDeQueueText        db    'DeQueue Value = '
QUEUE_DATASEG ENDS



;----------------------------------------------------------------------------------------
;    스택 세그먼트
;----------------------------------------------------------------------------------------
QUEUE_STACK SEGMENT STACK
    DB    100h    DUP('stack')
QUEUE_STACK ENDS



;----------------------------------------------------------------------------------------
;    코드 세그먼트
;----------------------------------------------------------------------------------------
QUEUE_CODE SEGMENT PARA 'CODE'

    ;-------------------------------------------------------------------
    ;
    ;    큐에 값 하나를 넣는다.
    ;   
    ;    인자 : MyValue:BYTE
    ;    리턴 :
    ;
    ;-------------------------------------------------------------------
    ASSUME CS:QUEUE_CODE, DS:QUEUE_DATASEG, SS:QUEUE_STACK
START:
    PROC_EnQueue PROC MyValue:BYTE
        pusha
       
        mov ax, QUEUE_DATASEG        ;
        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:
   
        ;----------------------------------------------------------------------
        ; Debugging Text -> 큐 전체 내용을 찍는다.
        IF Debug
            ShowAllQueueDebugString
        ENDIF       
        ; Debugging Text End
        ;----------------------------------------------------------------------

        popa
        ret

    LABEL_BufferFull:
       
       
        mov ax , QUEUE_DATASEG
        mov ds , ax
        mov dx , OFFSET StrBufferOverFlow
        mov cx , SIZEOF StrBufferOverFlow
        xor bx , bx   ;consol handle = 0
        mov ah , 40h
        int 21h

        NextLine
            ;
       
        popa
        ret
    PROC_EnQueue ENDP

    ;-------------------------------------------------------------------
    ;
    ;    큐에서 값 하나를 꺼낸다.
    ;   
    ;    인자 :
    ;    리턴 : DL -> 큐에서 꺼낸 값
    ;
    ;-------------------------------------------------------------------
    PROC_DeQueue PROC
        push ax                ;-----------------------------
        push ds                ; 레지스터 보호
        push bx                ; ax, ds, bx, si, cx
        push si                ;
        push cx                ;-----------------------------
       
               
        mov ax, QUEUE_DATASEG        ;
        mov ds, ax            ; 데이터 세그먼트 초기화
       
        cmp QueueSize, 0        ;
        jz  LABEL_BufferEmpty        ; 큐에 내용이 없으면 Buffer UnderFlow

        xor bx, bx            ;
        mov bl, byte ptr Position    ; 가져 올 값의 인덱스 구하기 -> BL
               

        ;----------------------------------------------------------------
        ; Debugging Text -> 꺼낸 값 하나를 찍는다.
        ;       
        IF Debug
            DeQueueValueDebugString QUEUE_DATASEG, strDeQueueText
        ENDIF
        ; Debugging Text End
        ;-----------------------------------------------------------------
       
        mov dl, Queue[bx]        ; 구한 인덱스릐 큐 값을 DL에 넣는다. -> DL
        mov Queue[bx], 'x'        ; 값을 빼고 빈자리에 'x'를 넣는다.

        inc Position            ; 인덱스를 다음 값의 위치로 셋팅
        dec QueueSize            ; 큐 사이즈를 하나 줄인다.


        ;-----------------------------------------------------------------
        ; Debugging Text -> 큐 전체 내용을 찍는다.
        IF Debug
            ShowAllQueueDebugString
        ENDIF
        ; Debugging Text End   
        ;-----------------------------------------------------------------

        pop cx                ;---------------------------------
        pop si                ; 레지스터 복원
        pop bx                ; cx, si, bx, ds, ax
        pop ds                ;
        pop ax                ;---------------------------------
               
        ret

    LABEL_BufferEmpty:
       
        mov ax , QUEUE_DATASEG
        mov ds , ax
        mov dx , OFFSET BufferUnderFlow
        mov cx , SIZEOF BufferUnderFlow
        xor bx , bx   ;consol handle = 0
        mov ah , 40h
        int 21h

        NextLine



        pop cx                ;---------------------------------
        pop si                ; 레지스터 복원
        pop bx                ; cx, si, bx, ds, ax
        pop ds                ;
        pop ax                ;---------------------------------
               

        ret
    PROC_DeQueue ENDP   

   
QUEUE_CODE ENDS

END START
       

Posted by houdinist
Assembly2010. 1. 5. 01:41


main.asm
-------------------------------------------------------------------
.model large
.386

extern ReadBitCountProc:proc

SegData segment
    v_numbers    word    1345h,0F4h,1123h,1212h,12h
    v_bitCount    byte    5 dup (0)    ; 숫자의 1에 대한 각각의 카운트 저장
    v_sortingNumber word    1345h,0F4h,1123h,1212h,12h    ; 소팅된 자료 입력
    v_key        word    5
SegData ends

SegStack segment stack
    byte 100h dup (?)
SegStack ends

SegCode segment   
    mainProc proc
    assume cs:SegCode, ds:SegData, ss:SegStack
    xor  ax, ax
    push ds
    push ax

    mov  ax, SegData
    mov  ds, ax

    xor  si, si    ; word길이씩 증가하는 배열의 인덱스 초기화
    xor  di, di    ; byte길이씩 증가하는 배열의 인덱스 초기화
L_start:
    mov  dx, v_numbers[si]    ; dx에 데이터 입력
    call ReadBitCountProc   
    mov  v_bitCount[di], dl ; 리턴값을 v_bitCount에 저장

    cmp  si, 8    ; 배열의 끝인가 ?
            ; 인덱스가 0 2 4 6 8일때의 값이므로 마지막 인덱스가 8임..
    jz   L_end
    add  si, 2    ; word 배열 인덱스 증가
    inc  di        ; byte 배열 인덱스 증가
    jmp  L_start   

L_end:
    ;--------------------------------------------------------------------------   
    ;    데이터 버블소팅하기
    ;--------------------------------------------------------------------------
    mov  bx, offset v_sortingNumber
    mov  di, v_key
    dec  di
L_01:
    mov  cx, di
    xor  si, si
L_02:
    mov  ax, [bx][si]
    cmp  ax, [bx][si+2]
    jl   L_end2
    mov  dx, [bx][si+2]
    mov  [bx][si], dx
    mov  [bx][si+2], ax
L_end2:
    add  si, 2
    loop L_02

    dec  di
    cmp  di, 0
    jg   L_01

    ret
    mainProc endp
SegCode ends

    end mainProc





sub.asm
-------------------------------------------------------------------
.model large
.386

SegCode segment   
; dx에 입력된 데이터의 1의 숫자를 세어서 dx에 갯수를 출력하는 프로시져
;
; 입력 dx:카운트 하려는 데이터
; 출력 dx:카운트 값
ReadBitCountProc proc
    push cx
    push ax

    xor  cx, cx   
    xor  ax, ax

    mov  cx, 16    ; word길이를 로테이트 하기위해 16번 카운트 설정
L_rotateNumber:
    rcl  dx, 1    ; 캐리를 포함해서 왼쪽으로 1번 쉬프트
    jc   L_addCount ; 캐리가 발생하면 L_addCount로 이동
    loop L_rotateNumber  ; 캐리가 발생하지 않았으면 L_rotateNumber로 이동
    jmp  L_next     ; cx 카운트가 끝났으면 루프 종료
L_addCount:
    inc  ax         ; 리턴값으로 사용할 임시변수에 1 증가
    loop L_rotateNumber

L_next:   
    mov  dx, ax     ; 최종 카운트 갯수 dx에 저장

    pop  ax
    pop  cx
    ret
ReadBitCountProc endp
SegCode ends

    end

'Assembly' 카테고리의 다른 글

[DOS] Serial 통신  (0) 2010.01.05
[DOS] Queue  (0) 2010.01.05
[DOS] 문자열을 입력받아 끝에 $ 추가해서 출력하기  (0) 2010.01.05
[DOS] 10진수를 출력하는 예제  (0) 2010.01.05
[DOS] 어셈블리에서 클래스 구현  (0) 2010.01.05
Posted by houdinist
Assembly2010. 1. 5. 01:37



.model large
.386

DATSEG  SEGMENT
    INPUT DB  30
DATSEG  ENDS

STACKSEG SEGMENT stack
    db 100h dup (?)
STACKSEG ENDS

CODSEG  SEGMENT
        ASSUME  CS:CODSEG,DS:DATSEG,SS:CODSEG
START: 
    MOV AX,DATSEG
        MOV DS,AX
    MOV DX,OFFSET INPUT
    MOV AH,0AH   
    INT 21H      

    xor bx, bx
    mov bl, INPUT+1
    add bx, 2
    mov INPUT[bx], '$'

    MOV DL,0AH
    MOV AH,02H                      
    INT 21H

    MOV DX,OFFSET INPUT+2    
    MOV AH,09H                      
    INT 21H                         
   
    mov ah, 4ch
    int 21h
CODSEG  ENDS
            
         END START


Posted by houdinist
Assembly2010. 1. 5. 01:36



.model large
.386
.stack 100h
.data
    num  word 0f3f2h
.code
L_start:
    mov ax, @data
    mov ds, ax
   
    mov dx, num
    call printDecimal
   
    mov ah, 4ch
    int 21h

;---------------------------------
; 헥스값을 10진수로 변환
; 입력값 dx : 16-bit unsigned
;
; F3F2라는 숫자를 10진수로 출력하려면 F3F2라는 숫자를 10으로 나누어
; 나머지를 스택에 차례로 저장했다가 복원하면서 하나씩 아스키문자로
; 변환해서 출력해 주면 됩니다.
; F3F2 / 10 = 1865....0
; 1865 / 10 = 270.....5
; 270 / 10  = 3E......4
; 3E / 10   = 6.......2
; 6 / 10    = 0.......6
; 각 자리를 푸쉬하는 이유는 각 연산의 결과 05426이 됩니다. 그렇기
; 때문에 자리를 뒤집어서 찍어줘야 합니다. 이런 경우 스택을 사용하면
; 간단히 해결할 수 있습니다. 스택의 구조는 후입선출로서 나중에 들어
; 간 것이 먼저 나오므로 각 연산의 결과를 스택에 푸쉬해 두고 차례로
; 팝하면서 찍어주면 62450이 정상적으로 찍히게 됩니다.
;
; 각 자리를 10으로 나누기 때문에 9이상의 숫자가 나머지로 나올 수
; 없습니다. 10이 나온다면 10으로 나누어 떨어져 결국 나머지는 0이기
; 때문입니다.
; 0~9는 10진수와 16진수가 공통으로 가지고 있는 부분이기
; 때문에 다른 변환없이 바로 사용할 수 있습니다. 때문에 16진수를
; 출력하는 프로시져로 출력해도 정상적인 10 진수를 출력할 수 있습니다.
printDecimal proc
        pusha                  ; 레지스터 보호
        mov ax, dx             ; 피젯수를 ax에 저장
        mov si, 10             ; 젯수를 si에 저장
        xor cx, cx             ; cx를 0으로 초기화
NONE_ZERO:
        xor dx, dx             ; dx를 0으로 초기화
        div si                 ; ax의 내용을 si의 값으로 나눔
        push dx                ; 나머지 dx를 스택에 저장
        inc cx                 ; cx 증가시킴
        or ax, ax              ; ax 가 0인가 ?
        jne NONE_ZERO          ; 0이 아니면 NONE_ZERO로 이동
WRITE_DIGIT_LOOP:
        pop dx                 ; 푸쉬한 수만큼 스택에서 꺼내면서 출력하기
        call printHex             ; 16진수 출력 루틴
        loop WRITE_DIGIT_LOOP
END_DECIMAL:
        popa                   ; 레지스터 보호 해제

        ret                    ; 프로시져 리턴
printDecimal endp

;--------------------------------
; 헥스값이나 10진수 값을 화면에 출력
; 입력값 dl : 8-bit 의 출력하고자하는 니블의 값
printHex proc
        push dx         ; 레지스터 보호
        push ax        

        cmp dl, 10              ; dl을 10과 비교  
        jae HEX_LETTER    ; 10보다 크거나 같으면 16진수 A~F에 해당하는 아스키 출력
        add dl, '0'              ; 10보다 작으면 '0'의 아스키코드 30h를 더해 실제 아스키코드 만듦
                        ; 가령 dl이 9이면 30+9=39 39는 아스키코드 '9'임                                      
                   
        jmp short WRITE_DIGIT   ; 아스키코드 출력 루틴으로 이동
HEX_LETTER:
        add dl, 'A'-10         ; 10이상인 경우 10~15까지의 숫자가 A~F로 할당된다. dl이 11이라면
                    ; 'A'에 해당하는 아스키코드 41h + 0Bh = 4Ch가 되어 'L'에 해당하는
                    ; 아스키코드가 되어 버린다. 여기서 변환하는 목적은 실제 수를 변환
                    ; 하거나 연산하는 것이 아니고, 단순히 그 숫자에 해당하는 아스키
                    ; 코드를 찍어주는 것이다. 그러므로 10~15의 숫자중 1의 자리에 해당
                    ; 하는 0~5만 있으면 A~F의 아스키코드에 짝지울 수 있다.
                    ; 그래서 아스키코드'A'에서 10을 빼주는 것이다. dl이 11이면 10을
                    ; 빼서 1로 만들고 거기에 아스키코드'A'를 더해주면 아스키코드'B'
                    ; 가 나와서 정확한 수치표현을 할 수 있다. 여기서 sub dl, 0Ah를
                    ; 하고 add dl, 'A'를 하지 않는 이유는 불필요한 코드를 줄이기 위해서
                    ; 이다. 'A'-10은 컴파일시에 자동으로 41h-0Ah=37h 하여 37h값으로
                    ; 대치하여 컴파일 해준다. 어째됐건 우리의 목표인 10을 빼는데 문제
                    ; 가 없으므로 필요없는 2줄의 코드를 한줄로 줄여주는 효과가 있다.
WRITE_DIGIT:
        mov ah, 2         ; 도스기능 호출 2번으로 dl에 저장된 하나의 문자를 출력
        int 21h
                
        pop ax             ; 레지스터 복원
        pop dx

        ret
printHex endp

          end L_start   

Posted by houdinist
Assembly2010. 1. 5. 00:47
1. 클래스의 등장 배경
        
1) 초기에는 순차적으로 쭉 코드를 써내려갔습니다.
        
2) 하지만 같은 코드가 계속 반복되어 비효율적입니다. 그래서 같은 코드는 한번만 코딩해 주고 필요할때 불러서 쓰는 서브루틴 개념이 생겼습니다. call 과 ret 개념이 생긴거지요.        
        
3) 역시나 서브루틴은 너무 하나의 프로그램에 종속적이기 때문에 다른 프로그램에서 재사용하기 힘듭니다. 그래서 생겨난 것이 함수입니다. 각종 인자를 넘기고 리턴값을 받을 수 있습니다. 이로서 프로그램간에 코드를 공유하기 쉬워졌습니다.
        
4) 하지만 여러 프로그램에서 같이 쓰기 위해서는 너무 많은 인자를 넘겨줘야 하는 경우가 생겼습니다. 그래서 생각한것이 필요한 인자를 구조체로 만들어서 구조체주소를 넘겨 주는거지요.
        
5) 그러나, 문제가 있었습니다. 이 구조체란게 너무 함수에 밀접하게 관계가 있어서 다른 곳에서는 쓰이지 않습니다. 게다가 이 함수를 쓰기 해서는 어떤 구조체를 쓰는지도 알아야 합니다. 반대로 이 구조체가 쓰는 함수를 알아내는 것도 쉽지 않습니다.
        
6) 그래서, 클래스가 등장하게 된것입니다. 위에서 본 것과 같이 클래스란 단순히 함수가 쓰는 구조체와 함수를 함께 묶어주는 역활을 하는것입니다. 이로써 구조체와 관련함수가 하나로 묶여서 코드의 재사용성이 증가합니다.

2. 클래스의 구조        
        
1) 그럼 클래스의 구조를 보도록 하죠.        
        
class CTest        
{       
private:                
WORD        wFirst;        
public:                
WORD        Add(WORD wValue);        
};
        
위와 같이 클래스가 있다고 합시다. 여기서 주의해야할 점이 있습니다.        
private: public: 같은 키워드에 의해 데이터가 보호되는 것은 단지 컴파일러에서 지원해 주는 기능일 뿐이지 바이너리코드 상의 차이점은 아니라는 점입니다. private: 이나 public:은 바이너리 코드상에서는 모두 같다는 겁니다. 다시 한번 말씀드리지만, 이 키워드들은 단지 컴파일 과정에서 컴파일러가 에러를 내주는 것이라는 겁니다.
        
이제 이 클래스를 어셈블리로 변환해 보죠..
        
CTest struct                
wFirst                word        ?                
AddTest             dword      AddFunc        
CTest ends
        
이게 전부입니다. 간단하지요 ?  단지 함수선언은 함수포인터로 대치되는게 차이점이라면 차이점입니다. 이 함수 포인터가 바로 계승에 절대적인 도움을 주는 점입니다.
        
이 클래스를 계승한 자식클래스를 만든다면 다음과 같이 하면 됩니다.
        
CTestChild struct                
CTest { ?,AddNewFunc }        
CTestChild ends
        
단순히 자식클래스 상단에 부모구조체를 써주면 됩니다. 그리고 이 예제에서는 메서드를 자식함수로 오버라이드하고 있습니다. 자식클래스에 프로퍼티와 메소드를 추가한다면 다음과 같겠지요.
        
CTestChild struct                
CTest { ?,AddNewFunc }                
wSecond      word         ?                
Multiply        dword        MultiplyFunc        
CTestChild ends
        
이로써 자식클래스만의 프로퍼티와 메소드를 정의하였습니다. 간단하지요 ?
        
하지만 주의해야 할 점이 있습니다. 부모구조체가 항상 자식구조체 시작위치에 있어야 한다는 점입니다. 이렇게 하야만 계승된 필드가 같은 옵셋에 치해 있다는것을 보장할 수 있습니다.

Posted by houdinist
Assembly2010. 1. 5. 00:37
1. 세그먼트 정의
    세그먼트이름 segment 옵션
    세그먼트이름 ends

    옵션 :
    1) alignment type
       BYTE, WORD, DWORD, PARA, PAGE으로 1,2,4,16,256의 배수에 시작
       지정하지 않으면 디폴트로 PARA
  
    2) combine type
       다른 세그먼트와 결합시키는 방식으로, PUBLIC, COMMON, STACK,
       PRIVATE, AT

    3) class type
       ''사이에 넣으며 세그먼트를 하나로 합치는게 아니라 독립적으로 존재
       하며, 단지 기억장소가 인접해 있음.

2. 프로시져 정의
    프로시져이름 proc 옵션
    프로시져이름 endp

    옵션 :
    1) NEAR : 옵션주소만 저장한다.
    2) FAR  : 세그먼트와 옵셋주소를 저장한다.

3. 지역변수와 매개변수의 사용

.model huge, stdcall
option casemap:none
.286

dseg segment
     char db "1234567890",'$'
dseg ends

sseg segment stack
     byte 100h dup('stack')
sseg ends

cseg segment
main proc near
     assume cs:cseg, ds:dseg, ss:sseg
     mov ax, dseg
     mov ds, ax

     mov ax, offset char
     push ax ; 매개변수로 주소를 넘김 (2바이트)
     call TTT

     mov ah, 4Ch
     int 21h
     main endp

TTT proc near

     push bp     ; bp를 저장
     mov bp, sp  ; 스택포인터를 저장
     sub sp, 2   ; 지역변수를 위해 2바이트 확보

     mov ah, 9
     mov dx, [bp+4] ; near 방식이므로 주소값과 bp크기만큼 더해 4
                          ; far 방식일때는 세그먼트까지 [bp+6]이 된다.
     int 21h

     mov byte ptr [bp], 'A' ; 확보한 첫바이트에 'A' 저장
     mov ah,2
     mov dl, [bp]
     int 21h

     mov byte ptr [bp+1], 'B' ; 확보한 두번째 바이트에 'B' 저장
     mov ah,2
     mov dl, [bp+1]
     int 21h

     add sp, 2 ; 지역변수를 해제, 즉 할당한 만큼스택크기를 줄인다
     pop bp     ; bp 복구
     ret
TTT endp
cseg ends

     end main

invoke 사용시는 local 변수이름:크기 를 사용해서 지역변수를 사용할 수 있
습니다. 하지만 결국은 위과 같은 방식으로 바뀌므로 기본적인 방법에 익숙해 지는 것이 좋겠지요.

4. 매크로의 정의
   매크로이름 macro 인자
   endm

   1) 매크로를 지정하면 매크로이름을 쓴곳에 정의한 부분으로 치환하여
      컴파일해 줍니다.

   2) 인자 역시 매크로 안에서 해당값으로 치환되어 들어갑니다.

   3) 인자:req 로 지정하면 항상 인자값을 넣어주어야 합니다. 반드시
      필요한 인자인데 넣지 않는 버그를 없애기 위해 컴파일 에러를 내줍
      니다.

   4) 소스에 내용이 치환되는 관계로 라벨이름이 중복되어 사용될 수 있습
      니다. 그래서 LOCAL 라벨이름을 이용하여 컴파일러가 중복되지 않는
      라벨을 자동으로 생성하게 합니다.
      여기서 중요한게 프로시져 내부에서도 local 을 사용하는데, 프로시져에
      서 local은 지역변수 선언을 의미하며, 스택에 지정한만큼 메모리를 잡아
      줍니다. 매크로의 local과 프로시져의 local을 구별해 두세요.


5. EXTERN, PUBLIC의 사용
   1) PUBLIC : 다른 파일에서 변수나 프로시져를 사용할 수 있게 이름을 외부
                로 노출시킵니다. 프로시져에서 PROTO를 사용할 경우 따로
                PUBLIC을 선언할 필요는 없습니다.

   2) EXTERN : 다른 파일에서 변수나 프로시져를 참조할때 사용합니다.


6. proto, invoke의 사용
    invoke문을 사용하기 위해서는 프로그램 선두에 사용할 프로시져의 인자
    를 미리 선언해야 합니다.

    프로시져이름 proto :byte, :byte  <- 바이트 2개를 받는 프로시져 선언

    invoke 프로시져이름 인자이름:byte, 인자이름:byte
    인자이름을 바로 사용해서 인자를 참조할 수 있습니다. invoke문은
    push 인자
    call 프로시져
    를 단순화한 명령이라고 할 수 있습니다. 결국은 위에서 설명한 방식으로
    매개변수와 지역변수를 사용합니다. 이 방식이 좋은 이유는 간단하면서
    인자를 크기에 맞게 자동캐스팅해줍니다. 그밖에 여러가지 잇점이 있습니
    다.
Posted by houdinist