Why Assembler
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