Assembly, printing ascii number
Asked Answered
K

4

2

I have a problem with my assembly code. I want to print number stored in register cx, but when i tried to print it, it printed ascii character instead of ascii number, so I decided to write a procedure to convert ascii char to ascii value. Problem is, that when I try to call that procedure, the program freezes and I have to restart dosbox. Does anyone know whats wrong with this code? Thanks.

P4      PROC                
            MOV AX,CX           ;CX = VALUE THAT I WANT TO CONVERT
            MOV BX,10           
    ASC2:
            DIV BX              ;DIV AX/10
            ADD DX,48           ;ADD 48 TO REMAINDER TO GET ASCII CHARACTER OF NUMBER 
            PUSH AX             ;SAVE AX
            MOV AH,2            ;PRINT REMAINDER STORED IN DX
            INT 21H             ;INTERRUP
            POP AX              ;POP AX BACK
            CMP AX,0            
            JZ EXTT             ;IF AX=0, END OF THE PROCEDURE
            JMP ASC2            ;ELSE REPEAT
    EXTT:
            RET
    P4      ENDP
Kessinger answered 25/3, 2013 at 17:39 Comment(2)
You need to clear DX before dividing. DIV BX divides DX:AX by BX.Telmatelo
Apart from what @Telmatelo said, you also have the problem that you'll end up printing the digits in reverse order. E.g. 123 will be printed as 321 with your code.Server
S
5

Something like this would work better for printing a decimal value (the new code is in lowercase):

        mov byte [buffer+9],'$'
        lea si,[buffer+9]

        MOV AX,CX           ;CX = VALUE THAT I WANT TO CONVERT
        MOV BX,10         
ASC2:
        mov dx,0            ; clear dx prior to dividing dx:ax by bx
        DIV BX              ;DIV AX/10
        ADD DX,48           ;ADD 48 TO REMAINDER TO GET ASCII CHARACTER OF NUMBER 
        dec si              ; store characters in reverse order
        mov [si],dl
        CMP AX,0            
        JZ EXTT             ;IF AX=0, END OF THE PROCEDURE
        JMP ASC2            ;ELSE REPEAT
EXTT:
        mov ah,9            ; print string
        mov dx,si
        int 21h
        RET

buffer: resb 10

Instead of printing each character directly it adds the characters to a buffer in reverse order. For the value 123 it would add '3' at buffer[8], '2' at buffer[7] and '1' at buffer[6] - so if you then print the string starting at buffer+6 you get "123".
I'm using NASM syntax but hopefully it should be clear enough.

Server answered 25/3, 2013 at 18:2 Comment(1)
Hey! can I get some help on this one? I tried to add this piece into my code but it throws me the error undefined var: byte [buffer+9] makes sense but cant figure it out since its my first day of learning assembly and I'm already stuck at "how to convert decimal to string and print it on the screen"Dramatization
E
1

As Michael has written in his code, you need to clear DX , ie make it 0 before you divide.

But if you ask me, if you only need to display a number in the ASCII form (not get a smiley face when you want a number to be displayed). Converting the value to ASCII internally can be quite inconvenient.

Why don't you just use an array defined in the start of the program that has all the ASCII values of the numbers and pick the one that is corresponds to.

for eg. DB arr '0123456789' and compare each number with the particular position and print that one. It's been a really long time since I've coded in 8086 but I remember using this logic for a program which required me to print an ASCII value of a hex number. So i used an array which had 0123456789ABCDEF and it worked perfectly.

Just my two cents. Since you only wanted the result. doesn't really matter how you compute it.

Embolden answered 1/4, 2013 at 18:1 Comment(0)
M
0

Thought I should post an update to this. This post really helped me out looking for a way to get key input for PHP CLI scripts. I couldn't find a Windows/DOS solution anywhere so I opted for an external program.

I'm using a really old version of a86 assembler so the code is pretty basic.

( and how do I turn off "Run Code Snippet"? )

;Key input for scripts that can use some "shell" function.
;Waits for a keypress then returns a string "key:scan"
;if "key" is 0 then you can check "scan" for arrow keys
;or other non-ASCII keys this way.

  mov ah,0
  int 16h

  push ax
  mov ah,0
  mov cx,ax
  call ASC

  mov dx,':'
  call COUT
  pop ax
  shr ax,8
  mov ah,0
  mov cx,ax
  call ASC
  jp EXIT

COUT:
  mov ah,2
  int 21h
  ret

STROUT:			
  mov ah,9 					
  mov dx,si
  int 21h
  ret

ASC:
  mov byte [buffer+9],'$'
  lea si,[buffer+9]
  mov ax,cx
  mov bx,10 

ASC_LOOP:
  mov dx,0
  div bx
  add dx,48
  dec si
  mov [si],dl
  cmp ax,0            
  jz STROUT
  jmp ASC_LOOP

EXIT:
  mov ah,4ch
  int 21h
  ret

buffer: db "          " ; 10 spaces.  no "resb" in my assembler.

A sample PHP script to test it in:

<?php

function getKey() {
	return shell_exec("getkey.com");
}

print "Press [ESC] to exit.\n\n";

$key = "";
while (ord($key) != 27) {
	$getch = explode(":",getKey());
	$key = chr($getch[0]);
	$scan = $getch[1];
	if (ord($key) != 0) {
		print $key;
	} else {
		print "SCAN:$scan\n";
	}
}

?>

Admittedly after all was said and done I realized I could have done the same thing in C++. But I learned a lot more about ASM this time around.

So thanks again folks!

Misinterpret answered 17/11, 2014 at 3:6 Comment(0)
M
0

Here's the well tested code for printing number

.186
.model SMALL
.STACK 100h
.data
    HelloMessage db 'Hello World', 13, 10, '$'
    SuperNumber dw 13565
.code

; Writes word number from AX to output
; Usage
; .186
; ....
; mov ax, 13444
; call PRINT_NUMBER

PRINT_NUMBER PROC NEAR  ; Outputs integer word number stored in AX registry. Requires CPU
    ; Save state of registers.
    PUSHA       ; Save all general purpose registers
    PUSH BP     ; We're going to change that.

    ; we need variables

    ; word number;      2 bytes
    ; byte digitsCount; 1 byte

    ; reserving space for variables on stack (3 bytes)
    mov bp, sp; ; bp := address of the top of a stack
    sub sp, 3*8 ; allocate 3 bytes on stack. Addresses of variables will be
            ; number:   WORD PTR [rbp - 2*8]
            ; digitsCount:  BYTE PTR [rbp - 3*8]

    ; Getting digits
    ; number = ax;
    ; digitsCount = 0;
    ; do
    ; {
    ;   push number%10;
    ;   digitsCount++;
    ;   number = number / 10;
    ; }
    ; while (number > 0)
    mov WORD PTR [bp - 2*8], ax ; number = ax;
    mov BYTE PTR [bp - 3*8], 0  ; digitsCount = 0;

    getDigits:          ; do
        mov ax, WORD PTR [bp - 2*8]; number/10: ax = number / 10, dx: number % 10
        ;cwd
        mov dx, 0
        mov bx, 10
        div bx

        push dx         ; push number%10
        mov WORD PTR[bp - 2*8], ax; number = number/10;
        inc byte PTR[bp - 3*8]  ; digitsCount++;

        cmp WORD PTR[bp - 2*8], 0; compare number and 0
        je getDigitsEnd     ; if number == 0 goto getDigitsEnd
        jmp getDigits       ; goto getDigits;
    getDigitsEnd:

    mov ah, 9
    mov dx, offset HelloMessage
    int 21h


    ;while (digitsCount > 0)
    ;{
    ;   pop digit into ax
    ;   print digit
    ;   digitsCount--;
    ;}
    printDigits:
        cmp BYTE PTR[bp - 3*8], 0; compare digits count and 0
        je printDigitsEnd   ; if digitsCount == 0 goto printDigitsEnd

        pop ax          ; pop digit into al
        add al, 30h     ; get character from digit into al

        mov ah, 0eh     ; wanna print digit!
        int 10h         ; BIOS, do it!

        dec BYTE PTR[bp - 3*8]  ; digitsCount--

        jmp printDigits     ; goto printDigits
    printDigitsEnd:

    ; Deallocate local variables back.
    mov sp, bp

    ; Restore state of registers in reverse order.
    POP BP
    POPA

    ; Exit from procedure.
    RET

PRINT_NUMBER ENDP

start:
    mov ax, @data
    mov ds, ax

    mov ah, 9
    mov dx, offset HelloMessage
    int 21h

    mov ax, 64454   
    call Print_Number

    mov ah, 4ch
    int 21h
end start
Middlemost answered 6/3, 2015 at 18:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.