Reputation: 47
I am trying to build a program in emu8086 which would be given as input 1 8 bit binary number then display in the output the hexadecimal form of it.
My code is this:
data segment
ends
stack segment
dw 128 dup(0)
ends
code segment
start:
mov ax,data
mov ds,ax
mov cx,0
mov bl,8
input:
mov ah,07h
int 21h
cmp al,46
sub al,30h
cmp al,0
je valid
cmp al,1
je valid
jmp input
valid:
cmp bl,0
je exit
sub bl,1
shl cl,1
add cl,al
jmp input
exit:
mov bl,15
and bl,cl
cmp bl,0
je printzero
cmp bl,1
je printone
cmp bl,2
je printtwo
cmp bl,3
je printthree
cmp bl,4
je printfour
cmp bl,5
je printfive
cmp bl,6
je printsix
cmp bl,7
je printseven
cmp bl,8
je printeight
cmp bl,9
je printnine
cmp bl,10
je printa
cmp bl,11
je printb
cmp bl,12
je printc
cmp bl,13
je printd
cmp bl,14
je printe
cmp bl,15
je printf
printzero:
mov dl,'0'
mov ah,02h
int 21h
jmp exit2
printone:
mov dl,'1'
mov ah,02h
int 21h
jmp exit2
printtwo:
mov dl,'2'
mov ah,02h
int 21h
jmp exit2
printthree:
mov dl,'3'
mov ah,02h
int 21h
jmp exit2
printfour:
mov dl,'4'
mov ah,02h
int 21h
jmp exit2
printfive:
mov dl,'5'
mov ah,02h
int 21h
jmp exit2
printsix:
mov dl,'6'
mov ah,02h
int 21h
jmp exit2
printseven:
mov dl,'7'
mov ah,02h
int 21h
jmp exit2
printeight:
mov dl,'8'
mov ah,02h
int 21h
jmp exit2
printnine:
mov dl,'9'
mov ah,02h
int 21h
jmp exit2
printa:
mov dl,'A'
mov ah,02h
int 21h
jmp exit2
printb:
mov dl,'B'
mov ah,02h
int 21h
jmp exit2
printc:
mov dl,'C'
mov ah,02h
int 21h
jmp exit2
printd:
mov dl,'D'
mov ah,02h
int 21h
jmp exit2
printe:
mov dl,'E'
mov ah,02h
int 21h
jmp exit2
printf:
mov dl,'F'
mov ah,02h
int 21h
jmp exit2
exit2:
mov bl,240
and bl,cl
cmp bl,0
je printzero2
cmp bl,1
je printone2
cmp bl,2
je printtwo2
cmp bl,3
je printthree2
cmp bl,4
je printfour2
cmp bl,5
je printfive2
cmp bl,6
je printsix2
cmp bl,7
je printseven2
cmp bl,8
je printeight2
cmp bl,9
je printnine2
cmp bl,10
je printa2
cmp bl,11
je printb2
cmp bl,12
je printc2
cmp bl,13
je printd2
cmp bl,14
je printe2
cmp bl,15
je printf2
printzero2:
mov dl,'0'
mov ah,02h
int 21h
jmp exit3
printone2:
mov dl,'1'
mov ah,02h
int 21h
jmp exit3
printtwo2:
mov dl,'2'
mov ah,02h
int 21h
jmp exit3
printthree2:
mov dl,'3'
mov ah,02h
int 21h
jmp exit3
printfour2:
mov dl,'4'
mov ah,02h
int 21h
jmp exit3
printfive2:
mov dl,'5'
mov ah,02h
int 21h
jmp exit3
printsix2:
mov dl,'6'
mov ah,02h
int 21h
jmp exit3
printseven2:
mov dl,'7'
mov ah,02h
int 21h
jmp exit3
printeight2:
mov dl,'8'
mov ah,02h
int 21h
jmp exit3
printnine2:
mov dl,'9'
mov ah,02h
int 21h
jmp exit3
printa2:
mov dl,'A'
mov ah,02h
int 21h
jmp exit3
printb2:
mov dl,'B'
mov ah,02h
int 21h
jmp exit3
printc2:
mov dl,'C'
mov ah,02h
int 21h
jmp exit3
printd2:
mov dl,'D'
mov ah,02h
int 21h
jmp exit3
printe2:
mov dl,'E'
mov ah,02h
int 21h
jmp exit3
printf2:
mov dl,'F'
mov ah,02h
int 21h
jmp exit3
exit3:
mov ax, 4c00h
int 21h
ends
end start
I quickly realised that you dont need to store every input in a array , you can shift left by 1 the value of the register which would store the number then add the input (1 or 0).Well I expected my code to work but I came into a issue:
The register which stores the value of my number is CL
.And it does correctly if I type 11110000
in this order the value of CL
becomes F0
which is what I want.I put it through a AND mask of Fh
to extract the 4 LSB and then through a AND mask of F0h
to extract the 4 MSB however in the output I get 00
.I honestly dont know where I am wrong.The value of BL
register becomes the same with the value of the CL
register but it still doesnt work.
Upvotes: 1
Views: 64
Reputation: 39721
mov bl,8 input: mov ah,07h int 21h cmp al,46 sub al,30h cmp al,0 je valid cmp al,1 je valid jmp input valid: cmp bl,0 je exit sub bl,1 shl cl,1 add cl,al jmp input exit:
cmp al,46
instruction serves no purpose. It is a left-over from some previous edit: just remove it.You can simplify the checking, as well as the looping:
mov bl, 8
input:
mov ah, 07h ; DOS.DirectSTDINInput
int 21h ; -> AL
sub al, 30h ; Convert from character to number [0,9]
cmp al, 1 ; Everything other than [0,1] is ABOVE 1 ...
ja input ; and so `JA input` will go repeat the input
shl cl, 1 ; Make room in CL
add cl, al ; Add the new digit
dec bl ; `DEC` already sets the flags
jnz input ; Repeating 8 times means we jump back 7 times
exit:
exit: mov bl,15 and bl,cl cmp bl,0 je printzero cmp bl,1 je printone ... exit2: mov bl,240 and bl,cl cmp bl,0 je printzero2 cmp bl,1 je printone2 ...
and
with 240 does is remove the Low Nibble from the BL register, but the High Nibble still remains where it was. This means that the value in BL is in {0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240}.The quick fix then is to replace the series of cmp bl,?
instructions:
exit:
mov bl, 240
and bl, cl
cmp bl, 0
je printzero2
cmp bl, 16
je printone2
cmp bl, 32
je printtwo2
...
exit2:
mov bl, 15
and bl, cl
cmp bl, 0
je printzero
cmp bl, 1
je printone
cmp bl, 2
je printtwo
...
Currently your program contains a lot of repeated instructions. Better solutions exist and I'm sure that the links provided by @PeterCordes will reveal these.
Nonetheless, short of doing the whole task myself, I suggest you study the below code and that you find out for yourself that this already simplifies the program a lot, and that it demonstrates how to write readable code. Mind you, I don't present this as the optimal solution:
mov bl, 8
input:
mov ah, 07h ; DOS.DirectSTDINInput
int 21h ; -> AL
sub al, '0' ; Convert from character to number [0,9]
cmp al, 1 ; Everything other than [0,1] is ABOVE 1 ...
ja input ; and so `JA input` will go repeat the input
shl cl, 1 ; Make room in CL
add cl, al ; Add the new digit
dec bl ; `DEC` already sets the flags
jnz input ; Repeating 8 times means we jump back 7 times
; ---------------
mov bl, 0F0h ; High Nibble mask
and bl, cl ; BL = {0, 16, 32, 48, ... , 208, 224, 240}
mov dl, '0'
cmp bl, 0
je printHigh
mov dl, '1'
cmp bl, 16
je printHigh
...
mov dl, 'E'
cmp bl, 224
je printHigh
mov dl, 'F' ; No need for `CMP BL, 240`. It's 240 for sure
printHigh:
mov ah, 02h
int 21h
; ---------------
mov bl, 0Fh ; Low Nibble mask
and bl, cl ; BL = {0, 1, 2, 3, ... , 13, 14, 15}
mov dl, '0'
cmp bl, 0
je printLow
mov dl, '1'
cmp bl, 1
je printLow
...
mov dl, 'E'
cmp bl, 14
je printLow
mov dl, 'F' ; No need for `CMP BL, 15`. It's 15 for sure
printLow:
mov ah, 02h
int 21h
; ---------------
mov ax, 4C00h
int 21h
Because your program encompasses eight counts of character input from the keyboard as well as two counts of character output to the screen, an optimized version would focus on code-size rather than execution time. The time spent in those ten DOS functions represents almost 100% of the execution time!
Due to all the repeated instructions, your program currently contains 471 bytes. My 'first steps' solution already lowered this number to 255 bytes, but surely we can do (much) better?
Let's look at what the program does. You input eight binary digits, combine these into a single byte-sized value, and then immediately after, you decompose the byte into its two nibbles.
Very often a (considerable) speed gain or size reduction comes from radically changing the methodology we use. What I propose is to not have to decompose a byte into its two nibbles. The below snippets repeat twice, the input of only four binary digits that are converted into one hex character.
ORG 256
call @f ; -> DH (AX BX)
mov dl, dh
call @f ; -> DH (AX BX)
mov ah, 02h ; DOS.DisplayOutput
int 21h ; -> (AL)
mov dl, dh
int 21h ; -> (AL)
ret ; Terminate in .COM program
@@: mov bx, 0010h ; Initialize BX with a sentinel-bit set at index 4
mov ah, 07h ; DOS.DirectSTDINInput
@@: int 21h ; -> AL
sub al, '0' ; Convert from ["0","1"] to [0,1]
shr al, 1 ; Bring digit [0,1] into the carry flag
jnz @b ; Every invalid key repeats the loop
rcl bl, 1 ; Bring new digit into BL
jnc @b ; Repeat while sentinel-bit was not shifted out
mov dh, [list + bx] ; Fetch a hex character
ret
lst: db '0123456789ABCDEF'
ORG 256
call @f ; -> AL (AX BX)
xchg dx, ax ; Shorter code than `mov dl, al`
call @f ; -> AL (AX BX)
push ax
mov ah, 02h ; DOS.DisplayOutput
int 21h ; -> (AL)
pop dx
int 21h ; -> (AL)
ret ; Terminate in .COM program
@@: mov bl, 00010000b ; Initialize BL with a sentinel-bit set at index 4
mov ah, 07h ; DOS.DirectSTDINInput
@@: int 21h ; -> AL
sub al, '0' ; Convert from ["0","1"] to [0,1]
shr al, 1 ; Bring digit [0,1] into the carry flag
jnz @b ; Every invalid key repeats the loop
rcl bl, 1 ; Bring new digit into BL
jnc @b ; Repeat while sentinel-bit was not shifted out
xchg ax, bx ; Shorter code than `mov al, bl`
cmp al, 10 ; \.
sbb al, 69h ; |. From [0,15] to {["0","9"],["A","F"]}
das ; /.
ret ; AL now has a hex character
These optimized snippets were assembled using FASM.
Upvotes: 1