Why Assembler


API is in (Win32s assembler uses API too!), 16bit/Dos are almost out, but old assembler is still a challenge, a big challenge. It is exciting to manipulate the interrupts, to intercept the keyboard, to dig into the low memory area, to develope all your own code, no API, no overhead, top speed and a last thing is, not many peoples in the universe can do it :-). Believe me only with efforts, you can honestly reach the top of the world (if you are lucky ;-) )

There are a lot of good informations about this subject on the net (see my tips section), some of the best are from MAD Nederland, Adam Blackcat and Dirty Abe Albert (Demo School tutorials). MAD has really a good understand in the stuff and his tutorials are excellent, short but really deep. For rookie try to find "Art of Assembly.pdf" on Google and get a HLA compile (for prof just use tasm, tlink, td (tasm32/tlink32) from Borland 1996, sourcer v6 and maybe softice too). For references (instructions, tickler, interrupts, I/O addresses etc) try to find the informations with the old NG (Norton Guide) format. To understand interrupt (multitasking, i.e more than one tasks at the same time) try to read my own simple multita3.asm or invaders.asm from Paul Raid Canada. Take a look at http://sac-ftp.externet.hu for some other good resources too.

Some of my valuable codes are big_roll.zip (a real scrolling demo with really big font on a nice background. If you want to make a HUGE font or make a scroll so take a look at it.),calc.zip (a calculator for sprite/font-artists and students; good to learn binary/hexadecimal arithmetics visually. I used 32 bit registers and some of my home made (good) algorithms. See the screen dump below).

I wonder there were a lot of you using "lookup table" (just like XXX dw 1234h,5678h etc; lea ax,XXX) for both fonts and images (for other cases just like a sinus table, it is OK). It is quite time consuming/risky to change the huge data if you want to change the image/font and it is quite difficult for you to reuse the code for other projects/demos. Why not just write a reader (e.g read_pcx, read_font etc). It is tough in the beginning (challenge, isn't we want?), but you save a lot lot of time in the future (many file formats can be found at File format, thanks to the internet and that site). I wrote a font package to realise that goal font.zip, it contains a read_font, a fontshow and a nice karaoke. (for those who interest in read-image, get big_roll.zip).

For Van Gogh and palette lover, get a copy of effects.zip (good graphical effects, only about 3300bytes!!). My last valuable code is c828.zip (needed a 8255 I/O IDE/PCI card. You then make your own PLC or your own disco light show!).

Thanks a lot to all of you, who work hard to share/spread (I got this expression from an old wise good Israeler friend) their knowledges to all of us. At the moment I had at least read 150 different tutors/codes from the internet.

If you are interested for other subjects you can download my whole (except the mention codes above) assembly code collections by clicking the link, and please do not send me any Kirch's stocks.

Screen dump from fontshow.exe:

Screen dump from big_roll.exe:

Screen dump from calc.exe:



comment %
API is in; 16 bit and DOS are almost outdated; but assembler is still a challenge!!
Tuan Nguyen Copenhagen 2002  The assembly 32 bit calculator
1002 thanks to the ESP-team BassPasC Hungarian, MAD Nederland, Adam Blackcat AUS and many other on the internet for all the inspirations.

The following operations are used: loop in a loop, 32 bit register, flag, xlat, B800, push/pop, macro, procedure, if/if/if, right-adjustment simulation and of cource some of my top home-made logic/algorithm routines. Some of the code will be difficult/confuse to understand coz I try to catch all the "traps" the user can made :-)

Tips: try to find your capital

Your mission: made a calculator with as much sweat as possible
Your plan: a) find a good debug and a decompile (inverse engine process) b) made many procedures as possible, the downsize is you can not just jump out (for forever) this (sometime you need to) and can not use parameters (use macro instead)  c) divide the prg to 3 parts, for dec, hex and binary  d) offer a directly conversion between all three formats above  e) made a right adjustment simulation  f)  made the user as happy as possible  g) test, test and test  h) mission complete, get a cup of tee.

Test: 4294967*1000=4294967000 ; 418937H(4294967d) *3e8(1000d)=fffffed8  ;1010001111 (655d)*1100100(100d)=1111111111011100 (65500) and among other small integer.

Enjoy. Max 2^32=ffffffff=4294967295. For binary 2^16-1=65535=1111111111111111 (16 ones).

%

.model small
.486
.stack 
.data
video_segment dw 0B800h

frame db "浜様様様様様様様様様様様様融"
      db "                          "
      db "                          "
      db "                          "
      db "                          "
      db "                          "
      db "                          "
      db "藩様様様様様様様様様様様様夕",'$'
    
HELLO DB 'WELCOME TO THE ASM-32S INTEGER ASSEMBLY MACHINE','$'
TEXT5 DB 'E','$'
TEXT6 DB 'TUAN NGUYEN DENMARK 2002 ASSEMBLER CHALLENGE$'
DHB_TEXT DB 'F1 ON 1ST LINE: CONVERT ; F2/F3/F4: CHANGE MODE ; F5: DECI MEM RECALL$'
DHB_TEXT2 DB 'n=AND o=OR x=XOR$'
TRANSLATE_TABLE DB '09876543210','$' ;0 GET 0, 1 GET 9, 2 GET 8 ETC
TRANSLATE_TABLE_HEX DB '876543210','$' ;0 GET 8, 1 GET 7, 2 GET 6 ETC
TRANSLATE_TABLE_DEC DB '876543210','$' ;0 GET 8, 1 GET 7, 2 GET 6 ETC
TRANSLATE_TABLE_BIN DB '0FEDCBA9876543210','$' ;1 GET F ETC
TEMP DB 10 DUP (?)
TEMP_HEX DB 8 DUP (?)
TEMP_DEC DB 8 DUP (?)
TEMP_BIN DB 16 DUP (?)
TEMP_STACK DW ?
NUM1 DD ?
NUM2 DD ?
Z DB ?
TEXT DB 10,13,'PLEASE TOGGLE THE CAPSLOCK OFF$'
;FOR RECALL MEM ROUTINE FOR DECIMAL. STORE 6 NUMBERS FROM EACH LINE (INPUT1, INP2 AND THE RESULT). FLAG_DEC1 (for input line1) or FLAG_DEC2 SET TO 88 IF THE USER USE F5. FLAG_PTR_DEC SET TO 89 IF THE STACK IS FULL. FLAG_LINE1 OG 2 INDICATES WHERE THE USER IS AT THE MOMENT (AT LINE1/INPUT1 OR LINE2/INPUT2), USING FOR ECHO THE RECALL NUMBER ON THE SCREEN. FLAG_MEM_RESULT TELLS PRG ONLY STORE 8 NUMBERS (8 DBs) IN STACK MEM
PTR_DEC DW (0)
STACK_DEC DB 16*6*3  DUP (?);memory 6 number from each line. For F5 mem recall
FLAG_DEC1 DB (0)
FLAG_DEC2 DB (0)
FLAG_PTR_DEC DB (0)
FLAG_LINE DW ?      ;this one pointers either to FLAG_LINE1 or FLAG_LINE2
FLAG_LINE1 EQU 1032
FLAG_LINE2 EQU 1192
FLAG_MEM_RESULT DB(0)
.CODE
    
START:
    
    mov ax, @data
    mov ds,ax
    mov ah,2 ;keyboard status
    int 16h
    and al,01000000b ;looking for capslock, is it on?
    cmp al,64
    je warning
    jmp goon
WARNING:
    lea dx,text
    mov ah,9
    int 21h
    mov ah,7
    int 21h
    jmp start
GOON:
    mov dx,offset hello
; MOV AH, 00H ; SET VIDEO MODE
; MOV AL, 012H ; MODE 12H VGA
; INT 10H
    mov es,[video_segment]
    call cls
    call cls
;-----------------------------------------------------------------------
    cursor_pos macro param,param2 ;use for position the cursor
    mov ah,2
    mov dh,param2 ;row
    mov dl,param ;column
    xor bh,bh ;put the cursor on page 0
    int 10h ;call video_io
ENDM CURSOR_POS
;-----------------------------------------------------------------------
    call init_temp ;init the buffer temp
;-----------------------------------------------------------------------
;THE D H B CHARACTERS
FORMAT MACRO PARA1,PARA2,PARA3
    cursor_pos 22,5
    mov ah,9
    mov al, 'd'
    mov bl,para1 ;color
    mov cx,1
    int 10h
    cursor_pos 24,5
    mov ah,9
    mov al, 'h'
    mov bl,para2
    int 10h
    cursor_pos 26,5
    mov ah,9
    mov al, 'b'
    mov bl,para3
    int 10h
ENDM FORMAT
    
    format 10,8,8
    comment %
    add cx,dx
    add cx,bx
;MOV CX,217 ;TEST
    cmp cx,217 ;(22*8 +5*8 +1) one is for the left button
    je m_d
    cmp cx,233
    je m_h
    cmp cx,249
    je m_b
    jmp go_on
    m_d: format 10,8,8
    jmp go_on
    m_h: format 8,10,8
    jmp go_on
    m_b: format 8,8,10
GO_ON:
    %
;-----------------------------------------------------------------------
;DECI PART
;1. NUMBER
    cursor_pos 43,6
    mov bx,0 ;maximum 8 numbers the user can enter
    mov ax,flag_line1  ;indicate that we are at line1 on the calculator
    mov flag_line,ax
LOOP1:
    xor ax,ax ;read keyboard sub routine 0 for int 16h
    int 16h
    cmp ah,1 ;exit
    je bye2
    call not_allow_empty ;avoid machine crack, the user might not enter with empty buffer
    cmp ah,99 ;flag trick :-)) my own favorit
    je loop1
    call not_allow_function_yet; user must not enter one of the 4 operations yet (+-/*)
    cmp ah,99 ;flag trick :-)) my own favorit
    je loop1
    cmp ah,61 ;f3
    je start_hex
    cmp ah,62 ;f4
    je start_bina
    cmp ah,63  ;f5
    je wh2jmp1
    jmp oracle
WH2JMP1:
    mov flag_dec1,88   ;indicate how to jump if the user uses "recall"  memory F5. I do not want to run the convert2real PROC again (I got it already)
    jmp recall   ;recall from stack memory
ORACLE:
    call not_allow_f1_yet ;f1 can only use when there is/are number at line 1
    cmp ah,100 ;f1 for hexi
    je hexi
    
    cmp al,'+'
    je save_operation
    cmp al,'-'
    je save_operation
    cmp al,'*'
    je save_operation
    cmp al,'/'
    je save_operation
    cmp al,'n' ;and
    je save_operation
    cmp al,'o' ;or
    je save_operation
    cmp al,'x' ;xor
    je save_operation
    
    cmp al,'0' ;smart!! jump to if4 if al<'0' and al>'9'; a trick i learned from
;ESP-TEAM BASSPASC COMPILER HUNGARIAN, THANKS
    jb loop1
    cmp al,'9'
    ja loop1
    mov di,1032 ; for procedure wrtnum see next line
    call wrtnum ;echo on the screen with "right adjustment!"
    push ax   ;save the entered number. i pop them back in CONVERT2REAL proc
    inc bx
    call check ;check if the entered number contains 5 chars
    cmp ah,99 ;made a forced enter , my favorit flag again
    je operation
    jmp loop1
    jmp operation   ;jmp above the reacll label if no F5 is used
;-----------------------------------------------------------------------
    
RECALL:   ;this one is used for both line1/input1 AND input2
    mov bx,ptr_dec    ;indicate the position in the stack memory buffer
RESTORE:
    cmp flag_ptr_dec,89   ;was set by memory PROC if the mem stack is filled
    je loop_fr_top
    jmp check_mem_empty
LOOP_FR_TOP:
    cmp bx,0
    je loop_fr_top2
    jmp contin
CHECK_MEM_EMPTY:
    cmp bx,0
    je loop1   ;mem stack is empty the first time the user uses the calc
    jmp contin
LOOP_FR_TOP2:
    mov bx,288   ;go to top of the stack mem
CONTIN:    
    sub bx,16    ;get the last information
    mov si,bx
    mov edx,dword ptr stack_dec[si]
    cmp flag_dec1,88    ;write to num1 IF you are atthe first line
    je wrt_num1
    jmp monro
WRT_NUM1:
    mov num1,edx
MONRO:
    add si,8
    
    xor di,di
RESTORE_HUMAN:     ;always fill 8 bytes (right adjustment)
    mov al,stack_dec[si]
    mov byte ptr temp[di],al  ;the "human" value with right-adjustment
    inc si
    inc di
    cmp di,8
    jne restore_human
    
    ;display buffer temp
    mov di,flag_line  ;write position
    lea   si,temp
    mov   cx,8
    mov   ah,31; color

PRINT_LOOP10:        
      lodsb          ; pointer ds:si
      stosw          ; store al into es:di, must be word, one position has 2 bytes!
    loop  print_loop10
    cmp bx,0
    je reinit
    cmp flag_dec1,88     ;where to jump
    je loop4     ;just below
    cmp flag_dec2,88
    je recall_line2     ;loop input for line 2
REINIT:
    cmp flag_ptr_dec,89   ;was set by memory PROC
    je stibo
    jmp roland
STIBO:  ;do nothing
    cmp flag_dec1,88     ;where to jump
    je loop4     ;just below
    cmp flag_dec2,88
    je recall_line2     ;loop input for line 2
ROLAND:   ;readjust the pointer of the mem stack
    mov bx,ptr_dec   ;loop to ptr_dec in the case the memo stack is not filled up
    cmp flag_dec1,88     ;where to jump
    je loop4     ;just below
;   cmp flag_dec2,88
;   je recall_line2
RECALL_LINE2:
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,1 ;exit
    je bye2
    cmp al,0dh ;the enter ascii code
    je finish_mem
    cmp ah,63  ;f5
    jne recall_line2
    jmp restore
    
;-----------------------------------------------------------------------
OPERATION:
;NOW CHOOSE ONE OF THE 4 OPERATIONS (IF THE USER DID NOT DO IT BEFORE)
LOOP4:
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,1 ;exit
    je bye2
    cmp ah,59 ;f1 for hexi
    je hexi
    cmp ah,61 ;f3
    je start_hex
    cmp ah,62 ;f4
    je start_bina
    cmp ah,63  ;f5
    je restore
    cmp al,'n' ;and
    je save_operation
    cmp al,'o' ;or
    je save_operation
    cmp al,'x' ;xor
    je save_operation
    
    cmp al,'*'
    jb loop4
    cmp al,'/'
    ja loop4
    cmp al,'.'
    je loop4
    cmp al,';'
    je loop4
    mov [z],al ;save the choosen operation
    call echo
    cmp flag_dec1,88    ;set just in the beginning of the recall label
    je second_nr_fr_recall
    jmp second_nr
;-----------------------------------------------------------------------
SAVE_OPERATION:
    mov [z],al ;save the choosen operation
    call echo
;-----------------------------------------------------------------------
SECOND_NR:
    call convert2real ;convert the first number to "real" number, see the proc
    mov num1,edx
    call memory   ;save in stack memory    
;NOW GET THE SECOND NUMBER
SECOND_NR_FR_RECALL:
    mov flag_dec1,0  ;reset flag for the next computation
    cursor_pos 43,7
    mov ax,flag_line2  ;indicate that we are at line1 on the calculator
    mov flag_line,ax
    call init_temp
    mov bx,0
LOOP2:
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,1 ;exit
    je bye2
    call not_allow_empty ;avoid machine crack, the buffer must not be empty!!
    cmp ah,99
    je loop2
    cmp al,0dh ;the enter ascii code
    je finish
    cmp ah,61 ;f3
    je start_hex
    cmp ah,62 ;f4
    je start_bina
    cmp ah,63  ;f5
    je wh2jmp2
    jmp sony
WH2JMP2:
    mov flag_dec2,88  ;use to find out where the prg should jump in the recall label
    jmp recall   ;recall from stack memory
SONY:
    cmp al,'0' ;accepted only between 0-9
    jb loop2
    cmp al,'9'
    ja loop2
    mov di,1192
    call wrtnum ;echo on the screen
    push ax ;save the number
    inc bx
    call check
    cmp ah,99 ;made a forced enter
    je finish
    jmp loop2
    
FINISH:
    call convert2real ;convert the second number to real number
    mov ecx,edx ;not a good idea to use dx for a multiplication!
    call memory   ;save in stack memory       
FINISH_MEM:
    mov flag_dec2,0; reset for the next computation    
    mov ecx,edx ;not a good idea to use dx for a multiplication!
    mov flag_mem_result,88  ;indicates that now we are at the 3. line. Use in memory proc
;-----------------------------------------------------------------------
;THE OPERATION
    mov al,[z] ;what was the operation the user choose?
    cmp al,'+'
    je plus
    cmp al,'-'
    je minus
    cmp al,'*'
    je mult
    cmp al,'/'
    je divi
    cmp al,'n'
    je and_dec
    cmp al,'o'
    je or_dec
    cmp al,'x'
    je xor_dec
    
PLUS:
    mov eax,num1 ;now the 1. number is in eax
    add eax,ecx
    jc toobig ;jump carry
    call print_result
    jmp bye
    
MINUS:
    mov eax,num1 ;now the 1. number is in eax
    sub eax,ecx
    jc toobig
    call print_result
    jmp bye
    
MULT:
    mov eax,num1 ;now the 1. number is in eax
    mul ecx
    jc toobig
    call print_result
    jmp bye
    
DIVI:
    mov edx,0 ;otherwise get "division overflow" error from dos!!
    mov eax,num1 ;now the 1. number is in eax
    div ecx
    jc toobig
    call print_result
    jmp bye
    
AND_DEC:
    mov eax,num1 ;now the 1. number is in eax
    and eax,ecx
    jc toobig
    call print_result
    jmp bye
    
OR_DEC:
    mov eax,num1 ;now the 1. number is in eax
    or eax,ecx
    jc toobig
    call print_result
    jmp bye
    
XOR_DEC:
    mov eax,num1 ;now the 1. number is in eax
    xor eax,ecx
    jc toobig
    call print_result
    jmp bye
    
    toobig: ;print an e (for error) for number >2^32
    lea si,text5
    mov di,1366
    mov ah,32
;MOVSB ;NO ATTRIBUTE (COLOUR) WHEN USING THIS ONE
    lodsb ; pointer ds:si
    stosw ; pointer es:di
    
BYE:
    call memory ;save the result in mem stack, ONLY 16 bytes (8 numbers)
    mov flag_mem_result,0  ;reset ready for a new computation
    xor ax,ax
    int 16h
    cmp ah,01 ;escape key
    jne start
    cursor_pos 0,13
    mov ax, 04c00h
    int 21h
    
BYE2:
    cursor_pos 0,13
    mov ax, 04c00h
    int 21h
;-----------------------------------------------------------------------
    
CLS PROC
;CLEAR THE SCREEN
    mov di,0 ;the same with xor di,di (faster). i do not want to use it because clarity
    mov al,0 ;character
    mov ah,52 ;color of text+backgrd= foregrd+backgrd*16 ;cyan backgrd, red foregr
    mov cx,2000 ;80*25
    rep stosw
    
    mov di,186 ;position must be even!! each line uses 80*1*2=160bytes
    lea si,hello
    mov cx,47 ;47 characters from text hello
    mov ah,31; 158 ;yellow text
PRINT_LOOP:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop
    
;BUILD THE FRAME
    
    mov di,520 ;position must be even!! each line uses 80*1*2=160bytes
    lea si,frame
    mov ah,31
    xor bx,bx
    out_loop: ;draw down
    mov cx,28 ;28 characters from frame
    print_loop2: ;draw across
    lodsb ; load ds:si into al , do it 28 times in a row!!
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop2
    inc bx
    add di,104 ;next row position
    cmp bx,8
    jne out_loop
    
    cursor_pos 2,2
    mov dx, offset dhb_text
    mov ah,9
    int 21h
    cursor_pos 25,12
    mov dx, offset dhb_text2
    mov ah,9
    int 21h
    ret
CLS ENDP
;-----------------------------------------------------------------------
INIT_TEMP PROC
;MOV TEMP,0000000000H
    mov bx,0
INIT3:
    mov [temp+bx],0
    inc bx
    cmp bx,10
    jne init3
    
    mov bx,0
INIT4:
    mov [temp_hex+bx],0
    inc bx
    cmp bx,8
    jne init4
    
    mov bx,0
INIT5:
    mov [temp_bin+bx],0
    inc bx
    cmp bx,16
    jne init5
    
    mov bx,0
INIT6:
    mov [temp_dec+bx],0
    inc bx
    cmp bx,8
    jne init6
    
    ret
INIT_TEMP ENDP
;-----------------------------------------------------------------------
NOT_ALLOW_EMPTY PROC ;THE BUFFER MUST NOT BE EMPTY
    cmp bx,0
    je @a
    ret
@A:
    cmp al,0dh
    je @b
    ret
@B:
    mov ah,99 ;use as a flag
    ret
NOT_ALLOW_EMPTY ENDP
    
;-----------------------------------------------------------------------
NOT_ALLOW_FUNCTION_YET PROC ;THE BUFFER MUST NOT BE EMPTY
    cmp bx,0
    je @a1
    ret
@A1:
    cmp al,'+'
    je @b1
    cmp al,'-'
    je @b1
    cmp al,'*'
    je @b1
    cmp al,'/'
    je @b1
    cmp al,'n'
    je @b1
    cmp al,'o'
    je @b1
    cmp al,'x'
    je @b1
    ret
@B1:
    mov ah,99 ;use as a flag
    ret
NOT_ALLOW_FUNCTION_YET ENDP
;-----------------------------------------------------------------------
    
NOT_ALLOW_F1_YET PROC ;THE BUFFER MUST NOT BE EMPTY
    cmp bx,0 ;not any number yet
    ja @c
    ret
@C:
    cmp ah,59 ;f1
    je @c1
    ret
@C1:
    mov ah,100 ;use as a flag
    ret
NOT_ALLOW_F1_YET ENDP
;-----------------------------------------------------------------------
WRTNUM PROC ; SIMULATE "RIGHT ADJUSTMENT" USER THE temp_decORARY BUFFER "temp_dec"
    push bx ;save the previous bx because i need to use bx for index register
;MOV CX,7 ;FOR REPETITION DO NOT USE IT!!! IT DESTROYS/MOVES THE BUFFERS AROUND??
    mov bx,1 ;castle value in buffer temp_dec, 0 is the leftmost:1->0, 2->1, 3->2 and 4->3 ;(simulere the number, movement like a calculator)
CASTLE_LOOP:
    mov dl,temp[bx]
    mov temp[bx-1],dl
    inc bx
;LOOP CASTLE_LOOP ;DO NOT USE IT!!! IT DESTROYS/MOVES THE BUFFERS AROUND??
    cmp bx,8
    jne castle_loop
    mov [temp+7],al ;the last position in the buffer
    
;DISPLAY BUFFER temp
;MOV DI,XXX ;IT IS SET JUST BEFORE CALLING THIS PROCEDURE
    lea si,temp
    mov cx,8
    mov ah,31; color
PRINT_LOOP3:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop3
    pop bx
    ret
WRTNUM ENDP
;-----------------------------------------------------------------------
ECHO PROC ;ECHO AL ON THE SCREEN, NOR BUFFER MANIPULATION
    cursor_pos 24,7
    mov dl,al
    mov ah,2 ;write ascii code directly on the screen
    int 21h
    ret ;return to the first call
ECHO ENDP
;-----------------------------------------------------------------------
CHECK PROC ;ONLY ALLOWED 8 NUMBERS
    cmp bx,8
    je hop
    ret
HOP:
    mov ah,99 ;use as a flag
    ret
CHECK ENDP
;-----------------------------------------------------------------------    
CONVERT2REAL PROC
    pop cx ;trick: cos at the time you have ALL the numbers the user entered in the stack, therefore you need to save the return address and put it back when this proc is finished. (see pop ax just below)
    mov temp_stack,cx
;EX: IF THE NUMBER FOR 126D IN THE STACK IS: 31 32 36 (31H = 1D), IT SHOULD
;CONVERT TO 126D (BY 1*100+2*10+6*1). IT IS THE REAL VALUE
    mov cx,bx ;use for loop, thanks to the value bx
    xor edx,edx
    mov ebx,1 ;starting with multiplication by 1
STACK2BUFFER:
    xor eax,eax ;just to be sure
    pop ax  ;those values I had put during the "entered"-routine 
    and ax,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
;USE MY CALCULATE TO CHECK IT, TRUE?? :-)
    push edx ;oh i really need one more register :-)no matter anyway, we have stack :-)
    mul ebx
    pop edx
    add edx,eax ;dx is the "real" value
    mov eax,10 ;increase bx with *10 for next loop
    push edx
    mul ebx
    pop edx
    mov ebx,eax
    loop stack2buffer
    mov cx,temp_stack ;pop the return addr back
    push cx
    ret
CONVERT2REAL ENDP
    
;-----------------------------------------------------------------------
;MADE STACK MEMORY
MEMORY PROC
    cmp edx,99999999  ;do not save numbers bigger than 99999999 (NB: the 3.lin can have 10 numbers!)
    ja cont
    mov cx,ptr_dec    ;indicate the position in the stack memory buffer
    mov si,cx
    ;clear the next 16 bytes
    xor bx,bx
ERASE:
    mov byte ptr stack_dec[si+bx],0
    inc bx
    cmp bx,16
    jne erase
    
    ;copy the hexa number, the one the OS (operative system) uses
    mov dword ptr stack_dec[si],edx
    add si,8   ; next part
    xor di,di    
    cmp flag_mem_result,88   ;special case for the 3.line, take only 8 numbers from temp
    je atlantis
    jmp copy_human
ATLANTIS:
    mov al,byte ptr temp[di+2]    ;take only the last 8 numbers from the result. TEMP has 10 DBs
    mov stack_dec[si],al
    inc si
    inc di
    cmp di,8
    jne atlantis
    jmp miss
COPY_HUMAN:     ;always fill 8 bytes (right adjustment)
    mov al,byte ptr temp[di]  ;the "human" value with right-adjustment
    mov stack_dec[si],al
    inc si
    inc di
    cmp di,8
    jne copy_human
MISS:
    add ptr_dec,16  ;ready for the next position
    cmp ptr_dec,288
    je reset_ptr    
    jmp cont
RESET_PTR:    
    mov ptr_dec,0
    mov flag_ptr_dec,89   ;use to indicate that the memory stack is filled FIFO. recall label uses this information
CONT:
   ret
MEMORY ENDP

;-----------------------------------------------------------------------
PRINT_RESULT PROC ; SHOW DEC ON SCREEN
    push eax ; save ax, it is the result
    push eax ;using for mem stack function F5
    call init_temp ;init buffer temp
    cursor_pos 43,8
    pop eax
    xor cx,cx
    mov ebx,10 ;divide by 10
DECLOOP:
    xor edx,edx ;high 16 bits zero.
    div ebx ;remainder in dx, quotient in ax
    inc cx
    push dx ;save remainder
    cmp ax,0 ;is quotient zero?
    jnz decloop
    
;USING TRANSLATE FOR EASY "RIGHT ADJUSTMENT". IMAGINE A REAL CALCULATOR
    
    xor ax,ax
    lea bx, translate_table ;pointer to table translate_table
    mov al, cl ;digit to be translated to al
    xlat translate_table ;translate the value in al
    
;DEBUG TRANSLATE TABEL
;PUSH AX CX DX
;CURSOR_POS 1,1
;MOV AH,2
;MOV DL,AL
;INT 21H
;MOV AH,2
;ADD CL,030H
;MOV DL,CL
;INT 21H
;POP DX CX AX
    
    and al,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
        
    mov di,ax ; transfer al to di
;
    mov bx,0 ;buffer pos 0
    poploop: ;pop out the result and store it in the buffer temp
    pop dx ;get the remainder
    add dl,030h ;30h='0' get the hex code
    mov temp[di+bx],dl ;start at save in the position di (al from translate table above)
    inc bx
    dec cx
    jnz poploop
    
;DISPLAY BUFFER TEMP
    mov di,1348 ;pos at the third line
    lea si,temp
    mov cx,10
    mov ah,142; color
PRINT_LOOP4:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop4
    pop edx  ;using for mem stack F5
    ret
PRINT_RESULT ENDP
    
;-----------------------------------------------------------------------
HEXI: ;to show hex value for convert routine
    cmp ax,999 ;this one is from deci: flag. Do not do convert2real again
    je hollywood
    cmp flag_dec1,88 ;aha the user uses F5 memory recall
    je fr_mem
    jmp bolero
FR_MEM:
    mov eax,edx
    push eax ;pop up by bina
    jmp tokyo
BOLERO:
    call convert2real ;convert the first number to "real" number, see the proc
    mov eax,edx
    push eax ;pop up by bina
    jmp tokyo
;THE NEXT 2 LINES ARE FOR "RERUN", MEANING THE USER KEEP PRESSING F1
HOLLYWOOD:
    pop eax ;pop back from deci
    push eax ;pop up by bina
TOKYO:
    mov flag_dec1,0   ;reset flag
    push eax
    format 8,10,8
    call init_temp ;init buffer temp
    cursor_pos 43,6
    pop eax
    xor cx,cx
    mov ebx,16 ;divide by 16 for hex
DECLOOP2:
    xor edx,edx ;high 16 bits zero.
    div ebx ;remainder in dx, quotient in ax
    inc cx
    push dx ;save remainder
    cmp ax,0 ;is quotient zero?
    jnz decloop2
    
;USING TRANSLATE FOR EASY "RIGHT ADJUSTMENT".
    
    xor ax,ax
    lea bx, translate_table_hex ;pointer to table translate_table
    mov al, cl ;digit to be translated to al
    xlat translate_table_hex ;translate the value in al
    and al,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
    mov di,ax ; transfer al to di
;
    mov bx,0 ;buffer pos 0
    poploop2: ;pop out the result and store it in the buffer temp
    pop dx ;get the remainder
;ADD DL,030H ;30H='0' GET THE HEX CODE
;MOV TEMP[DI+BX],DL ;START AT SAVE IN THE POSITION DI (AL FROM TRANSLATE TABLE
    cmp dl,9
    ja not_number
    add dl,030h ;30h='0' get the hex code
    jmp paris
NOT_NUMBER:
    add dl,037h ;41h='a' get the hex code
PARIS:
    mov temp_hex[di+bx],dl
    inc bx
    dec cx
    jnz poploop2
    
;DISPLAY BUFFER TEMP
    mov di,1032
    lea si,temp_hex
    mov cx,8
    mov ah,142; color
PRINT_LOOP5:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop5
    
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,59 ;f1 for bina
    je tng
    jmp start_hex
TNG:
    mov ax,999
    jmp bina
    
    
;-----------------------------------------------------------------------
    bina: ;to show binary value
    
    cmp ax,999 ;this one is from hexi: flag
    je jakarta
CALL CONVERT2REAL_HEX ;CONVERT THE FIRST NUMBER TO "REAL" NUMBER, SEE THE PROC
    mov eax,edx
    push eax ;save for deci
    jmp haifa
;THE NEXT 3 LINES ARE FOR "RERUN", MEANING WHEN THE USER KEEP PRESSING F1
    
JAKARTA:
POP EAX ;POP BACK FROM THE PREVIOUS HEXI:
PUSH EAX ;SAVE FOR DECI THE NEXT LABEL:
;
HAIFA:
    
PUSH EAX ;SAVE BEFORE CALLING INIT_TEMP PROC
    format 8,8,10
    call init_temp ;init buffer temp
    cursor_pos 43,6
    pop eax
    xor cx,cx
    mov ebx,2 ;divide by 2 for binary
DECLOOP3:
    xor edx,edx ;high 16 bits zero.
    div ebx ;remainder in dx, quotient in ax
    inc cx
    push dx ;save remainder
    cmp ax,0 ;is quotient zero?
    jnz decloop3
    
;USING TRANSLATE FOR EASY "RIGHT ADJUSTMENT"
    
    xor ax,ax
    lea bx, translate_table_bin ;pointer to table translate_table
    mov al, cl ;digit to be translated to al
    xlat translate_table_bin ;translate the value in al
    
    comment %
;DEBUG TRANSLATE TABEL
    push ax cx dx
    cursor_pos 1,1
    mov ah,2
    mov dl,al
    int 21h
    mov ah,2
    add cl,030h
    mov dl,cl
    int 21h
    pop dx cx ax
    %
    
    cmp al,'9'
    ja not_number4 ;for abcdef
    and al,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
    jmp saigon
NOT_NUMBER4:
    and al,0fh ;to get decimal number (30h and fh get 0 (corresponding to 0 decimal))
    add al,9 ;a is 10
    
SAIGON:
    
    mov di,ax
    mov bx,0 ;buffer pos 0
    poploop3: ;pop out the result and store it in the buffer temp
    pop dx ;get the remainder
    add dl,030h ;30h='0'
    mov temp_bin[di+bx],dl
    inc bx
    dec cx
    jnz poploop3
    
;DISPLAY BUFFER TEMP
    mov di,1016
    lea si,temp_bin
    mov cx,16
    mov ah,142; color
PRINT_LOOP6:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop6
    
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,59 ;f1 for deci
    je hanoi
    jmp start_bina
    jmp start ;erase !!
HANOI:
    mov ax,999
    jmp deci
    
;-----------------------------------------------------------------------
DECI:
    
    cmp ax,999 ;this one is from bina above, using as a flag
    je odense
    call convert2real_bin ;convert the first number to "real" number, see the proc
    mov eax,edx
    push eax ;save for deci
    jmp capetown
;THE NEXT 3 LINES ARE FOR "RERUN", MEANING WHEN THE USER KEEP PRESSING F1
    
ODENSE:
    pop eax ;pop back from the previous bina:
    push eax ;save for hexi the next label:
;
CAPETOWN:
    
    push eax ;save before calling init_temp proc
    format 10,8,8
    call init_temp ;init buffer temp
    cursor_pos 43,6
    pop eax
    xor cx,cx
    mov ebx,10 ;divide by 10
DECLOOP4:
    xor edx,edx ;high 16 bits zero.
    div ebx ;remainder in dx, quotient in ax
    inc cx
    push dx ;save remainder
    cmp ax,0 ;is quotient zero?
    jnz decloop4
    
;USING TRANSLATE FOR EASY "RIGHT ADJUSTMENT".
    
    xor ax,ax
    lea bx, translate_table_dec ;pointer to table translate_table
    mov al, cl ;digit to be translated to al
    xlat translate_table_dec ;translate the value in al
    
    and al,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
    mov di,ax ; transfer al to di
;
    mov bx,0 ;buffer pos 0
    poploop4: ;pop out the result and store it in the buffer temp
    pop dx ;get the remainder
    add dl,030h ;30h='0' get the hex code
    mov temp_dec[di+bx],dl ;start at save in the position di (al from translate table above)
    inc bx
    dec cx
    jnz poploop4
    
;DISPLAY BUFFER TEMP
;CLEAR FIRST THE DATA FROM BINARY (16 AGAINT 8 FELTS)
    mov di,1016
    mov al,0 ;character
    mov ah,31 ;color of text+backgrd= foregrd+backgrd*16 ;cyan backgrd, red foregr
    mov cx,16 ;8*2
    rep stosw
    
    mov di,1032
    lea si,temp_dec
    mov cx,8
    mov ah,142; color
PRINT_LOOP7:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop7
    
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,59 ;f1 for hexi
    je copenhagen
    jmp start
COPENHAGEN:
    mov ax,999
    jmp hexi
    
    
;-----------------------------------------------------------------------
;HEX PART
    
START_HEX:
    call cls
    call init_temp
    format 8,10,8
;1. NUMBER
    cursor_pos 43,6
    mov bx,0 ;maximum 8 numbers the user can enter
LOOP1_HEX:
    xor ax,ax ;read keyboard sub routine 0 for int 16h
    int 16h
    cmp ah,1 ;exit
    je bye2
    call not_allow_empty ;avoid machine crack, the user might not enter with empty buffer
    cmp ah,99 ;flag trick :-)) my own favorit
    je loop1_hex
    call not_allow_function_yet; user must not enter one of the 4 operations yet (+-/*)
    cmp ah,99 ;flag trick :-)) my own favorit
    je loop1_hex
    
    cmp al,'a'
    je london
    cmp al,'b'
    je london
    cmp al,'c'
    je london
    cmp al,'d'
    je london
    cmp al,'e'
    je london
    cmp al,'f'
    je london
    
    cmp al,'+'
    je save_operation2
    cmp al,'-'
    je save_operation2
    cmp al,'*'
    je save_operation2
    cmp al,'/'
    je save_operation2
    cmp al,'n' ;and
    je save_operation2
    cmp al,'o' ;or
    je save_operation2
    cmp al,'x' ;xor
    je save_operation2
    
    call not_allow_f1_yet ;f1 can only use when there is/are number at line 1
    cmp ah,100 ;f1 for bina
    je bina
    cmp ah,60 ;f2
    je start ;deci
    cmp ah,62 ;f4
    je start_bina
    
    cmp al,'0' ;smart!! jump to if4 if al<'0' and al>'9'; a trick i learned from
    
    jb loop1_hex
    cmp al,'9'
    ja loop1_hex
LONDON:
    mov di,1032 ; for procedure wrtnum see next line
    call wrtnum ;echo on the screen with "right adjustment!"
;USE PUSH POP TO SAVE THE ENTERED NUMBER. I POP THEM BACK IN ABOUT 10 LINES
    push ax
    inc bx
    call check ;check if the entered number contains 8 chars
    cmp ah,99 ;made a forced enter , my favorit flag again
    je operation2
    jmp loop1_hex
;-----------------------------------------------------------------------
OPERATION2:
;NOW CHOOSE ONE OF THE 4 OPERATIONS (IF THE USER DID NOT DO IT BEFORE)
LOOP4_HEX:
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,59 ;f1 for bina
    je bina
    cmp ah,60 ;f2
    je start ;deci
    cmp ah,62 ;f4
    je start_bina
    
    cmp al,'n' ;and
    je save_operation2
    cmp al,'o' ;or
    je save_operation2
    cmp al,'x' ;xor
    je save_operation2
    
    cmp al,'*'
    jb loop4_hex
    cmp al,'/'
    ja loop4_hex
    cmp al,'.'
    je loop4_hex
    cmp al,';'
    je loop4_hex
    mov [z],al ;save the choosen operation
    call echo
    jmp second_nr_hex
;-----------------------------------------------------------------------
SAVE_OPERATION2:
    mov [z],al ;save the choosen operation
    call echo
;-----------------------------------------------------------------------
SECOND_NR_HEX:
CALL CONVERT2REAL_HEX ;CONVERT THE FIRST NUMBER TO "REAL" NUMBER, SEE THE PROC
    mov num1,edx
    
;NOW GET THE SECOND NUMBER
    cursor_pos 43,7
    call init_temp
    mov bx,0
LOOP_HEX:
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,1 ;exit
    je bye2
    call not_allow_empty ;avoid machine crack, the buffer must not be empty!!
    cmp ah,99
    je loop_hex
    
    cmp al,'a'
    je cairo
    cmp al,'b'
    je cairo
    cmp al,'c'
    je cairo
    cmp al,'d'
    je cairo
    cmp al,'e'
    je cairo
    cmp al,'f'
    je cairo
    
    cmp al,0dh ;the enter ascii code
    je finish2
    
    cmp ah,60 ;f2
    je start ;deci
    cmp ah,62 ;f4
    je start_bina
    
    cmp al,'0' ;accepted only between 0-9
    jb loop_hex
    cmp al,'9'
    ja loop_hex
CAIRO:
    mov di,1192
    call wrtnum ;echo on the screen
    push ax ;save the number
    inc bx
    call check
    cmp ah,99 ;made a forced enter
    je finish
    jmp loop_hex
    
FINISH2:
    call convert2real_hex ;convert the second number to real number
    mov ecx,edx ;not a good idea to use dx for a multiplication! (destroy)
;-----------------------------------------------------------------------
;THE OPERAION
    mov al,[z] ;what was the operation the user choose?
    cmp al,'+'
    je plus2
    cmp al,'-'
    je minus2
    cmp al,'*'
    je mult2
    cmp al,'/'
    je divi2
    cmp al,'n'
    je and_dec2
    cmp al,'o'
    je or_dec2
    cmp al,'x'
    je xor_dec2
    
    plus2: ;02bh
    mov eax,num1 ;now the 1. number is in eax
    add eax,ecx
    jc toobig2 ;jump carry
    call print_result_hex
    jmp bye_hex
    
MINUS2:
    mov eax,num1 ;now the 1. number is in eax
    sub eax,ecx
    jc toobig2
    call print_result_hex
    jmp bye_hex
    
MULT2:
    mov eax,num1 ;now the 1. number is in eax
    mul ecx
    jc toobig2
    call print_result_hex
    jmp bye_hex
    
DIVI2:
    mov edx,0 ;otherwise get "division overflow" error from dos!!
    mov eax,num1 ;now the 1. number is in eax
    div ecx
    jc toobig2
    call print_result_hex
    jmp bye_hex
    
AND_DEC2:
    mov eax,num1 ;now the 1. number is in eax
    and eax,ecx
    jc toobig2
    call print_result_hex
    jmp bye_hex
    
OR_DEC2:
    mov eax,num1 ;now the 1. number is in eax
    or eax,ecx
    jc toobig2
    call print_result_hex
    jmp bye_hex
    
XOR_DEC2:
    mov eax,num1 ;now the 1. number is in eax
    xor eax,ecx
    jc toobig2
    call print_result_hex
    jmp bye_hex
    
    toobig2: ;print an e (for error) for number >2^32
    lea si,text5
    mov di,1366
    mov ah,32
    lodsb ; pointer ds:si
    stosw ; pointer es:di
    
BYE_HEX:
    xor ax,ax
    int 16h
    cmp ah,01 ;escape key
    jne start_hex
    cursor_pos 0,13
    mov ax, 04c00h
    int 21h
;-----------------------------------------------------------------------
CONVERT2REAL_HEX PROC
    pop cx ;trick: save the return address and put it back in stack at the end of the proc
    mov temp_stack,cx
;EX: IF THE NUMBER FOR 1ACH IN THE STACK IS: 31 34 35 (31H = 1D), IT SHOULD
;CONVERT TO 428D (BY 1*256+10*16+12*1). IT IS THE REAL VALUE
    mov cx,bx ;use for loop, thanks to the value bx
    xor edx,edx
    mov ebx,1 ;starting with multiplication by 1
STACK2BUFFER_HEX:
    xor eax,eax ;just to be sure
    pop ax
    
;TRAP FOR A TO F
    cmp al,060h ;61h='a'
    ja chicago2 ;of course at the time all the other "invalid" chars has been filter out
; FOR 0-9
    and ax,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
    jmp sydney2
    chicago2: ;for a-f
    and ax,0fh ;to get decimal number (61h and fh get 1 (corresponding to 1 decimal))
    add ax,9 ;add 9 to get a=10 ; b=11 etc
SYDNEY2:
    push edx ;oh i really need one more register :-)no matter anyway, we have stack :-)
    mul ebx
    pop edx
    add edx,eax ;dx is the "real" value
    mov eax,16 ;increase bx with *16 for next loop
    push edx
    mul ebx ;eax=eax*ebx
    pop edx
    mov ebx,eax ;the next multi part
    loop stack2buffer_hex
    mov cx,temp_stack ;pop the return addr back
    %
    push cx
    ret
CONVERT2REAL_HEX ENDP
    
;-----------------------------------------------------------------------
PRINT_RESULT_HEX PROC ; SHOW HEX ON SCREEN
    push eax ; save ax, it is the result
    call init_temp ;init buffer temp
    cursor_pos 43,8
    pop eax
    xor cx,cx
    mov ebx,16 ;divide by 16
DECLOOP5:
    xor edx,edx ;high 16 bits zero.
    div ebx ;remainder in dx, quotient in ax
    inc cx
    push dx ;save remainder
    cmp ax,0 ;is quotient zero?
    jnz decloop5
    
;USING TRANSLATE FOR EASY "RIGHT ADJUSTMENT".
    
    xor ax,ax
    lea bx, translate_table_hex ;pointer to table translate_table
    mov al, cl ;digit to be translated to al
    xlat translate_table_hex ;translate the value in al
    and al,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
    mov di,ax ; transfer al to di
;
    mov bx,0 ;buffer pos 0
    
    poploop_hex: ;pop out the result and store it in the buffer temp
    pop dx ;get the remainder
;ADD DL,030H ;30H='0' GET THE HEX CODE
;MOV TEMP[DI+BX],DL ;START AT SAVE IN THE POSITION DI (AL FROM TRANSLATE TABLE
    cmp dl,9
    ja not_number2
    add dl,030h ;30h='0' get the hex code
    jmp paris2
NOT_NUMBER2:
    add dl,037h ;41h='a' get the hex code
PARIS2:
    mov temp_hex[di+bx],dl
    inc bx
    dec cx
    jnz poploop_hex
    
    
;DISPLAY BUFFER TEMP
    mov di,1352 ;pos at the third line
    lea si,temp_hex
    mov cx,8
    mov ah,142; color
PRINT_LOOP9:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop9
    ret
PRINT_RESULT_HEX ENDP
    
;-----------------------------------------------------------------------
    
;BINA PART
    
START_BINA:
    call cls
    call init_temp
    format 8,8,10
;1. NUMBER
    cursor_pos 43,6
    mov bx,0 ;maximum 16 numbers the user can enter
LOOP1_BIN:
    xor ax,ax ;read keyboard sub routine 0 for int 16h
    int 16h
    cmp ah,1 ;exit
    je bye3
    call not_allow_empty ;avoid machine crack, the user might not enter with empty buffer
    cmp ah,99 ;flag trick :-)) my own favorit
    je loop1_bin
    call not_allow_function_yet; user must not enter one of the 7 opers yet (+-/* nox)
    cmp ah,99 ;flag trick :-)) my own favorit
    je loop1_bin
    
    call not_allow_f1_yet ;f1 can only use when there is/are number at line 1
    cmp ah,100 ;f1 for deci
    je deci
    
    cmp al,'+'
    je save_operation3
    cmp al,'-'
    je save_operation3
    cmp al,'*'
    je save_operation3
    cmp al,'/'
    je save_operation3
    cmp al,'n' ;and
    je save_operation3
    cmp al,'o' ;or
    je save_operation3
    cmp al,'x' ;xor
    je save_operation3
    
    cmp ah,60 ;f2
    je start ;deci
    cmp ah,61 ;f3
    je start_hex
    
    cmp al,'0' ; allowed al='0' and al='1'
    jb loop1_bin
    cmp al,'1'
    ja loop1_bin
HOLLAND:
    mov di,1016 ; for procedure wrtnum see next line
    call wrtnum_bin ;echo on the screen with "right adjustment!"
;USE PUSH POP TO SAVE THE ENTERED NUMBER. I POP THEM BACK IN ABOUT 10 LINES
    push ax
    inc bx
    call check_bin ;check if the entered number contains 8 chars
    cmp ah,99 ;made a forced enter , my favorit flag again
    je operation3
    jmp loop1_bin
;-----------------------------------------------------------------------
OPERATION3:
;NOW CHOOSE ONE OF THE 4 OPERATIONS (IF THE USER DID NOT DO IT BEFORE)
LOOP4_BIN:
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,59 ;f1 for deci
    je deci
    cmp ah,60 ;f2
    je start ;deci
    cmp ah,61 ;f3
    je start_hex
    cmp al,'n' ;and
    je save_operation3
    cmp al,'o' ;or
    je save_operation3
    cmp al,'x' ;xor
    je save_operation3
    
    cmp al,'*'
    jb loop4_bin
    cmp al,'/'
    ja loop4_bin
    cmp al,'.'
    je loop4_bin
    cmp al,';'
    je loop4_bin
    mov [z],al ;save the choosen operation
    call echo
    jmp second_nr_bin
;-----------------------------------------------------------------------
SAVE_OPERATION3:
    mov [z],al ;save the choosen operation
    call echo
;-----------------------------------------------------------------------
SECOND_NR_BIN:
CALL CONVERT2REAL_BIN ;CONVERT THE FIRST NUMBER TO "REAL" NUMBER, SEE THE PROC
    mov num1,edx
    
;NOW GET THE SECOND NUMBER
    cursor_pos 43,7
    call init_temp
    mov bx,0
LOOP_BIN:
    xor ax,ax ;read keyboard
    int 16h
    cmp ah,1 ;exit
    je bye3
    call not_allow_empty ;avoid machine crack, the buffer must not be empty!!
    cmp ah,99
    je loop_bin
    
    cmp al,0dh ;the enter ascii code
    je finish3
    cmp ah,60 ;f2
    je start ;deci
    cmp ah,61 ;f3
    je start_hex
    
    cmp al,'0' ; allowed al='0' and al='1'
    jb loop_bin
    cmp al,'1'
    ja loop_bin
    
SIDNEY:
    mov di,1176
    call wrtnum_bin ;echo on the screen
    push ax ;save the number
    inc bx
    call check_bin
    cmp ah,99 ;made a forced enter
    je finish3
    jmp loop_bin
    
FINISH3:
    call convert2real_bin ;convert the second number to real number
    mov ecx,edx ;not a good idea to use dx for a multiplication! (destroy)
;-----------------------------------------------------------------------
;THE OPERAION
    mov al,[z] ;what was the operation the user choose?
    cmp al,'+' ;02bh
    je plus3
    cmp al,'-'
    je minus3
    cmp al,'*'
    je mult3
    cmp al,'/'
    je divi3
    cmp al,'n'
    je and_dec3
    cmp al,'o'
    je or_dec3
    cmp al,'x'
    je xor_dec3
    
    plus3: ;02bh
    mov eax,num1 ;now the 1. number is in eax
    add eax,ecx
    jc toobig3 ;jump carry
    call print_result_bin
    jmp bye_bin
    
MINUS3:
    mov eax,num1 ;now the 1. number is in eax
    sub eax,ecx
    jc toobig3
    call print_result_bin
    jmp bye_bin
    
MULT3:
    mov eax,num1 ;now the 1. number is in eax
    mul ecx
    jc toobig3
    call print_result_bin
    jmp bye_bin
    
DIVI3:
    mov edx,0 ;otherwise get "division overflow" error from dos!!
    mov eax,num1 ;now the 1. number is in eax
    div ecx
    jc toobig3
    call print_result_bin
    jmp bye_bin
    
AND_DEC3:
    mov eax,num1 ;now the 1. number is in eax
    and eax,ecx
    jc toobig3
    call print_result_bin
    jmp bye_bin
    
OR_DEC3:
    mov eax,num1 ;now the 1. number is in eax
    or eax,ecx
    jc toobig3
    call print_result_bin
    jmp bye_bin
    
XOR_DEC3:
    mov eax,num1 ;now the 1. number is in eax
    xor eax,ecx
    jc toobig3
    call print_result_bin
    jmp bye_bin
    
    toobig3: ;print an e (for error) for number >2^32
    lea si,text5
    mov di,1366
    mov ah,32
    lodsb ; pointer ds:si
    stosw ; pointer es:di
    
BYE_BIN:
    xor ax,ax
    int 16h
    cmp ah,01 ;escape key
    jne start_bina
    cursor_pos 0,13
    mov ax, 04c00h
    int 21h
    
BYE3:
    cursor_pos 0,13
    mov ax, 04c00h
    int 21h
;-----------------------------------------------------------------------
CHECK_BIN PROC ;ONLY ALLOWED 8 NUMBERS
    cmp bx,16
    je hop1
    ret
HOP1:
    mov ah,99 ;use as a flag
    ret
CHECK_BIN ENDP
    
;-----------------------------------------------------------------------
WRTNUM_BIN PROC ; SIMULATE "RIGHT ADJUSTMENT" USER THE TEMPORARY BUFFER "TEMP"
    push bx ;save the previous bx because i need to use bx for index register
;MOV CX,15 ;FOR REPETITION
    mov bx,1 ;castle value in buffer temp, 0 is the leftmost:1->0, 2->1, 3->2 and 4->3 ;(simulere the number, movement like a calculator)
CASTLE_LOOP2:
    mov dl,temp_bin[bx]
    mov temp_bin[bx-1],dl
    inc bx
;LOOP CASTLE_LOOP2 ;CX CONTROLS THE LOOP
    cmp bx,16
    jne castle_loop2
    mov [temp_bin+15],al ;the last position in the buffer
    
;DISPLAY BUFFER TEMP
;MOV DI,XXX ;IT IS SET JUST BEFORE CALLING THIS PROCEDURE
    lea si,temp_bin
    mov cx,16
    mov ah,31; color
PRINT_LOOP_WRT_BIN:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop_wrt_bin
    pop bx
    ret
WRTNUM_BIN ENDP
;-----------------------------------------------------------------------
CONVERT2REAL_BIN PROC
POP CX ;TRICK: SAVE THE RETURN ADDRESS AND PUT IT BACK IN STACK AT THE END OF THE PROC
    mov temp_stack,cx
;EX: IF THE NUMBER FOR 101B IN THE STACK IS: 31 30 31 (31H = 1D), IT SHOULD
;CONVERT TO 5D (BY 1*4+0*2+1*1). IT IS THE REAL VALUE
    mov cx,bx ;use for loop, thanks to the value bx
    xor edx,edx
    mov ebx,1 ;starting with multiplication by 1
STACK2BUFFER_BIN:
    xor eax,eax ;just to be sure
    pop ax
    and ax,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
    push edx ;oh i really need one more register :-)no matter anyway, we have stack :-)
    mul ebx
    pop edx
    add edx,eax ;dx is the "real" value
    mov eax,2 ;increase bx with *2 for next loop
    push edx
    mul ebx
    pop edx
    mov ebx,eax
    loop stack2buffer_bin
    mov cx,temp_stack ;pop the return addr back
    push cx
    ret
CONVERT2REAL_BIN ENDP
    
;-----------------------------------------------------------------------
PRINT_RESULT_BIN PROC ; SHOW BIN ON SCREEN
    push eax ; save ax, it is the result
    call init_temp ;init buffer temp
    cursor_pos 43,8
    pop eax
    xor cx,cx
    mov ebx,2 ;divide by 2
DECLOOP_BIN:
    xor edx,edx
    div ebx ;remainder in dx, quotient in ax
    inc cx
    push dx ;save remainder
    cmp ax,0 ;is quotient zero?
    jnz decloop_bin
    
;USING TRANSLATE FOR EASY "RIGHT ADJUSTMENT". THE TRANSLATE TAKE CARE FOR THAT IT
    
    xor ax,ax
    lea bx, translate_table_bin ;pointer to table translate_table
    mov al, cl ;digit to be translated to al
    xlat translate_table_bin ;translate the value in al
    
    comment %
;DEBUG TRANSLATE TABEL
    push ax cx dx
    cursor_pos 1,1
    mov ah,2
    mov dl,al
    int 21h
    mov ah,2
    add cl,030h
    mov dl,cl
    int 21h
    pop dx cx ax
    %
    
    cmp al,'9'
    ja not_number3 ;for abcdef
    and al,0fh ;to get decimal number (39h and fh get 9 (corresponding to 9 decimal))
    jmp budapest
NOT_NUMBER3:
    and al,0fh ;to get decimal number (30h and fh get 0 (corresponding to 0 decimal))
    add al,9 ;a is 10
    
BUDAPEST:
    mov di,ax ; transfer al to di
    mov bx,0 ;buffer pos 0
    poploop_bin: ;pop out the result and store it in the buffer temp
    pop dx ;get the remainder
    add dl,030h
    mov temp_bin[di+bx],dl ;start at save in the position di (al from translate table above)
    inc bx
    dec cx
    jnz poploop_bin
    
;DISPLAY BUFFER TEMP
    mov di,1336 ;pos at the third line
    lea si,temp_bin
    mov cx,16
    mov ah,142; color
PRINT_LOOP8:
    lodsb ; pointer ds:si
    stosw ; store al into es:di, must be word, one position has 2 bytes!
    loop print_loop8
    ret
PRINT_RESULT_BIN ENDP
    
;-----------------------------------------------------------------------
    end start