Kamis, 05 November 2015

Program Kalkulator Menggunakan Bahasa Pemrograman Assembly

Kali ini kita coba ulas kembali tentang bahasa pemrograman yang jarang sekali dipakai oleh para programmer, biasanya kita mempelajari pemrograman java, php, c++ dll, kini kita coba pemrograman dibidang bahasa rakitan, pemrograman bahasa assembly.banyak sekali contoh program bahasa assembly, disini saya akan mencontohkan tentang program sederhana yaitu program kalkulator. program ini berjalan menggunakan emulator emu8086, bagi kalian yang belum punya programnya silahkan download gratis. 


Sebelum kalian mencoba aplikasinya, sebaiknya kalian pelajari juga dasar- dasar dari pemrograman bahasa assembly, agar kalian bisa memahami setiap baris dalam source kode programnya nanti. 
Untuk artikel bahasa assembly bisa kalian download disini
Kode Program Dan Penjelasan Setiap Baris Program
Berikut merupakan kode program kalkulator sederhana menggunakan bahasa assembly:
name "calc2"
org 100h
jmp start

; definisi variabel:

msg0 db "PROGRAM KALKULATOR DEDE RUBIANTO 1003040022 ",0Dh,0Ah
     db " MASUKAN KODE BERIKUT : *,/,+,- TEKAN enter UNTUK MENJALANKAN PROGRAM",0Dh,0Ah,'$'
msg1 db 0Dh,0Ah, 0Dh,0Ah, 'MASUKAN ANGKA: $'
msg2 db "MASUKAN KODE:    +  -  *  /     : $"
msg3 db "MASUKAN ANGKA KEDUA: $"
msg4 db  0dh,0ah , 'HASIL : $'
msg5 db  0dh,0ah ,'TERIMA KASIH MENGGUNAKAN KALKULATOR ,SEMOGA BERMANFAAT BAGI ANDA!', 0Dh,0Ah, '$'
err1 db  "kode yang dimasukan tidak cocok!", 0Dh,0Ah , '$'
smth db  " TIDAK ADA HASIL.... $"

; operator perhitungan dapat berupa: '+','-','*','/' atau 'q' untuk keluar.
opr db '?'

; no pertama dan kedua:
num1 dw ?
num2 dw ?

mulai:
mov dx, offset msg0
mov ah, 9
int 21h
lea dx, msg1
mov ah, 09h    ; keluaran string di ds:dx
int 21h 


call scan_num

; store first number:
mov num1, cx

; baris baru:
putc 0Dh
putc 0Ah

lea dx, msg2
mov ah, 09h     ; keluaran string di ds:dx
int 21h 

; pilih operator perhitungan:
mov ah, 1   ; single char input to AL.
int 21h
mov opr, al

; baris baru:
putc 0Dh
putc 0Ah


cmp opr, 'q'      ; q – untuk keluar.
je exit

cmp opr, '*'
jb wrong_opr
cmp opr, '/'
ja wrong_opr


; keluaran berupa string di ds:dx
lea dx, msg3
mov ah, 09h
int 21h 

call scan_num

; penyimpanan no kedua
mov num2, cx

lea dx, msg4
mov ah, 09h      ; keluaran string di ds:dx
int 21h 

; perhitungan:

cmp opr, '+'
je do_plus

cmp opr, '-'
je do_minus

cmp opr, '*'
je do_mult

cmp opr, '/'
je do_div


; apabila input kosong....
wrong_opr:
lea dx, err1
mov ah, 09h     ; output string at ds:dx
int 21h 

keluar:
; output of a string at ds:dx
lea dx, msg5
mov ah, 09h
int 21h 


; tekan sembarang tombol...
mov ah, 0
int 16h

ret  ; kembali .


do_plus:

mov ax, num1
add ax, num2
call print_num    ; print ax value.

jmp exit

do_minus:


mov ax, num1
sub ax, num2
call print_num    ; print ax value.

jmp exit

do_mult:

mov ax, num1
imul num2 ; (dx ax) = ax * num2.
call print_num    ; print ax value.
; dx is ignored (calc works with tiny numbers only).

jmp exit

do_div:
; dx is ignored (calc works with tiny integer numbers only).
mov dx, 0
mov ax, num1
idiv num2  ; ax = (dx ax) / num2.
cmp dx, 0
jnz approx
call print_num    ; print ax value.
jmp exit
approx:
call print_num    ; print ax value.
lea dx, smth
mov ah, 09h    ; output string at ds:dx
int 21h 
jmp exit



SCAN_NUM        PROC    NEAR
        PUSH    DX
        PUSH    AX
        PUSH    SI
       
        MOV     CX, 0

        ; reset flag:
        MOV     CS:make_minus, 0

next_digit:

        ; get char from keyboard
        ; into AL:
        MOV     AH, 00h
        INT     16h
        ; and print it:
        MOV     AH, 0Eh
        INT     10h

        ; check for MINUS:
        CMP     AL, '-'
        JE      set_minus

        ; check for ENTER key:
        CMP     AL, 0Dh  ; carriage return?
        JNE     not_cr
        JMP     stop_input
not_cr:

        CMP     AL, 8                   ; 'BACKSPACE' pressed?
        JNE     backspace_checked


        MOV     DX, 0                   ; remove last digit by
        MOV     AX, CX                  ; division:
        DIV     CS:ten                  ; AX = DX:AX / 10 (DX-rem).
        MOV     CX, AX
        PUTC    ' '                     ; clear position.
        PUTC    8                       ; backspace again.
        JMP     next_digit
backspace_checked:
        ; allow only digits:
        CMP     AL, '0'
        JAE     ok_AE_0
        JMP     remove_not_digit
ok_AE_0:       
        CMP     AL, '9'
        JBE     ok_digit
remove_not_digit:      
        PUTC    8       ; backspace.
        PUTC    ' '     ; clear last entered not digit.
        PUTC    8       ; backspace again.       
        JMP     next_digit ; wait for next input.      
ok_digit:
        ; multiply CX by 10 (first time the result is zero)
        PUSH    AX
        MOV     AX, CX
        MUL     CS:ten                  ; DX:AX = AX*10
        MOV     CX, AX
        POP     AX

        ; mengecek input yang terlalu besar
        ; (result should be 16 bits)
        CMP     DX, 0
        JNE     too_big


        ; convert from ASCII code:
        SUB     AL, 30h

        ; add AL to CX:
        MOV     AH, 0
        MOV     DX, CX      ; backup, in case the result will be too big.
        ADD     CX, AX
        JC      too_big2    ; jump if the number is too big.

        JMP     next_digit

set_minus:
        MOV     CS:make_minus, 1
        JMP     next_digit

too_big2:
        MOV     CX, DX      ; restore the backuped value before add.
        MOV     DX, 0       ; DX was zero before backup!
too_big:
        MOV     AX, CX
        DIV     CS:ten  ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
        MOV     CX, AX
        PUTC    8       ; backspace.
        PUTC    ' '     ; clear last entered digit.
        PUTC    8       ; backspace again.       
        JMP     next_digit ; wait for Enter/Backspace.
       
stop_input:
        ; check flag:
        CMP     CS:make_minus, 0
        JE      not_minus
        NEG     CX


not_minus:

        POP     SI
        POP     AX
        POP     DX
        RET
make_minus      DB      ?       ; used as a flag.
SCAN_NUM        ENDP

; this procedure prints number in AX,
; used with PRINT_NUM_UNS to print signed numbers:
PRINT_NUM       PROC    NEAR
        PUSH    DX
        PUSH    AX

        CMP     AX, 0
        JNZ     not_zero

        PUTC    '0'
        JMP     printed

not_zero:
        ; the check SIGN of AX,
        ; make absolute if it's negative:
        CMP     AX, 0
        JNS     positive
        NEG     AX

        PUTC    '-'
positive:
        CALL    PRINT_NUM_UNS



printed:
        POP     AX
        POP     DX
        RET
PRINT_NUM       ENDP

; number in AX (not just a single digit)
; allowed values are from 0 to 65535 (FFFF)
PRINT_NUM_UNS   PROC    NEAR
        PUSH    AX
        PUSH    BX
        PUSH    CX
        PUSH    DX

        ; flag to prevent printing zeros before number:
        MOV     CX, 1

        ; (result of "/ 10000" is always less or equal to 9).
        MOV     BX, 10000       ; 2710h - divider.

        ; AX is zero?
        CMP     AX, 0
        JZ      print_zero

begin_print:

        ; check divider (if zero go to end_print):
        CMP     BX,0
        JZ      end_print

        ; avoid printing zeros before number:
        CMP     CX, 0
        JE      calc

        ; if AX<BX then result of DIV will be zero:
        CMP     AX, BX
        JB      skip
calc:
        MOV     CX, 0   ; set flag.

        MOV     DX, 0
        DIV     BX      ; AX = DX:AX / BX   (DX=remainder).

        ; print last digit
        ; AH is always ZERO, so it's ignored
        ADD     AL, 30h    ; convert to ASCII code.
        PUTC    AL
        MOV     AX, DX  ; get remainder from last div.

skip:
        ; calculate BX=BX/10
        PUSH    AX
        MOV     DX, 0
        MOV     AX, BX
        DIV     CS:ten  ; AX = DX:AX / 10   (DX=remainder).
        MOV     BX, AX
        POP     AX

        JMP     begin_print
       
print_zero:
        PUTC    '0'
       
end_print:

        POP     DX
        POP     CX

        POP     BX
        POP     AX
        RET
PRINT_NUM_UNS   ENDP

ten             DW      10      ; used as multiplier/divider by SCAN_NUM & PRINT_NUM_UNS.

GET_STRING      PROC    NEAR
PUSH    AX
PUSH    CX
PUSH    DI
PUSH    DX

MOV     CX, 0                   ; char counter.

CMP     DX, 1                   ; buffer too small?
JBE     empty_buffer            ;

DEC     DX                      ; reserve space for last zero.

;============================
; Eternal loop to get
; and processes key presses:

wait_for_key:

MOV     AH, 0                   ; get pressed key.
INT     16h

CMP     AL, 0Dh                  ; 'RETURN' pressed?
JZ      exit_GET_STRING


CMP     AL, 8                   ; 'BACKSPACE' pressed?
JNE     add_to_buffer
JCXZ    wait_for_key            ; nothing to remove!
DEC     CX
DEC     DI
PUTC    8                       ; backspace.
PUTC    ' '                     ; clear position.
PUTC    8                       ; backspace again.
JMP     wait_for_key

add_to_buffer:

        CMP     CX, DX          ; buffer is full?
        JAE     wait_for_key    ; if so wait for 'BACKSPACE' or 'RETURN'...

        MOV     [DI], AL
        INC     DI
        INC     CX
       
        ; print the key:
        MOV     AH, 0Eh
        INT     10h

JMP     wait_for_key
;============================

exit_GET_STRING:


; terminate by null:
MOV     [DI], 0

empty_buffer:

POP     DX
POP     DI
POP     CX
POP     AX
RET
GET_STRING      ENDP

Untuk output dari source kode diatas seperti dibawah ini :

Semoga artikel ini bisa bermanfaat gays, bila ada kesalahan atau kurang jelas silahkan coret - coret dikolom koment . Salam Wong Tani. . . . .


Tidak ada komentar: