Author Topic: Printing out decimal values: Help  (Read 1980 times)

Ben

  • Guest
Printing out decimal values: Help
« on: March 29, 2009, 11:20:09 AM »
I am now trying to create a program that will output decimal numbers 1 to 10 in order on screen then start a new line. this is an extension of a program i wrote to do the same with the letters a-z
I get no compile errors but nothing prints to screen when i run.
I assume this is something to do with converting between binary and hex or something similar?
am using NASM

Thanks for any help,
Ben


BITS 16                      ;SET CODE TO 16 BIT MODE
ORG 0X0100                   ;SET CODE START ADDRESS TO 0100H

SECTION .text                ;MAIN CODE SECTION

MAIN:                        ;LABEL START OF MAIN CODE


    MOV DX,1               ;MOVE HEX VALUE 'Z' TO DX

WHILE:
    CMP DX,10               ;COMPARE A TO VALUE IN DX
    JLE NEXT                  ;JUMP < 0 TO NEXT
    MOV AH,02H               ;CALL PRINT FUNCTION INTERRUPT
    INT 21H
    ADD DX,01H               ;SUB HEX VALUE 1 FROM DX
    JMP WHILE                ;JUMP TO WHILE

NEXT:

MOV DX,CR                ;OUTPUT NEW LINE
    MOV DX,LF
    MOV AX, 04C00H           ;THIS FUNCTION EXITS THE PROGRAM
    INT 21H


SECTION .data                ;DATA SECTION FOR INITIALISED DATA & CONSTANTS
CR  EQU  0DH                 ;CARRIAGE RETURN
LF  EQU  0AH                 ;LINE FEED

SECTION .bss                 ;DATA SECTION FOR UNINITIALISED DATA

NUM1 RESB 2

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2379
  • Country: us
Re: Printing out decimal values: Help
« Reply #1 on: March 30, 2009, 10:00:06 AM »
Ah, there we go! SourceForge wasn't letting me reply for a while there...

So why isn't your program printing anything?

> BITS 16                      ;SET CODE TO 16 BIT MODE
> ORG 0X0100                   ;SET CODE START ADDRESS TO 0100H
>
> SECTION .text                ;MAIN CODE SECTION
>
> MAIN:                        ;LABEL START OF MAIN CODE
>
>
>     MOV DX,1               ;MOVE HEX VALUE 'Z' TO DX
>
> WHILE:
>     CMP DX,10               ;COMPARE A TO VALUE IN DX
>     JLE NEXT                  ;JUMP < 0 TO NEXT

Since DX is less than 10...

>     MOV AH,02H               ;CALL PRINT FUNCTION INTERRUPT
>     INT 21H
>     ADD DX,01H               ;SUB HEX VALUE 1 FROM DX
>     JMP WHILE                ;JUMP TO WHILE
>
> NEXT:

... you jump here... and quit...

>     MOV DX,CR                ;OUTPUT NEW LINE
>     MOV DX,LF
>     MOV AX, 04C00H           ;THIS FUNCTION EXITS THE PROGRAM
>     INT 21H
>
>
> SECTION .data                ;DATA SECTION FOR INITIALISED DATA & CONSTANTS
> CR  EQU  0DH                 ;CARRIAGE RETURN
> LF  EQU  0AH                 ;LINE FEED
>
> SECTION .bss                 ;DATA SECTION FOR UNINITIALISED DATA
>
> NUM1 RESB 2

How 'bout something simpler, '0' to '9'...

BITS 16                      ;SET CODE TO 16 BIT MODE
ORG 0X0100                   ;SET CODE START ADDRESS TO 0100H

SECTION .text                ;MAIN CODE SECTION

MAIN:                        ;LABEL START OF MAIN CODE


    MOV DX, '0'               ;MOVE '0' TO DX

WHILE:
    CMP DX, '9'               ;COMPARE A TO VALUE IN DX
    JLE NEXT                  ;JUMP < 0 TO NEXT
    MOV AH,02H               ;CALL PRINT FUNCTION INTERRUPT
    INT 21H
    ADD DX,01H               ;SUB HEX VALUE 1 FROM DX
    JMP WHILE                ;JUMP TO WHILE

NEXT:

MOV DX,CR                ;OUTPUT NEW LINE
    MOV DX,LF
    MOV AX, 04C00H           ;THIS FUNCTION EXITS THE PROGRAM
    INT 21H


SECTION .data                ;DATA SECTION FOR INITIALISED DATA & CONSTANTS
CR  EQU  0DH                 ;CARRIAGE RETURN
LF  EQU  0AH                 ;LINE FEED

SECTION .bss                 ;DATA SECTION FOR UNINITIALISED DATA

NUM1 RESB 2


Untested, but it looks okay to me. That'll take care of '0' to '9'. There is no character '10', of course, we're gonna have to print '1' and then '0'. That's where the fun starts! Dividing 10 by 10 would give a quotient of 1 and a remainder of 0. That's a start, but we'll still have to add '0' (30h or 48 decimal) to the numbers before we can print 'em - the number 1 is different from the character '1'! (try printing 7 - "beep" - you know what 10 and 13 do... 9 is TAB, 8 is backspace...)

Moving on to something more ambitious, s'pose we want to print 123. Divide by 10 gives 12, with a remainder of 3. Dividing again by 10 gives 1, with a remainder of 2. Dividing by 10 again gives 0, with a remainder of 1. The remainders are the numbers we want to print (after converting 'em to characters by adding '0'), but we get 'em in the wrong order - we'll print "321" if we aren't careful!

There are a number of ways to fix that. We can put the characters in a buffer and then run "string_reverse" on it, or store the characters starting at the "end" of the buffer and work forward. A recursive function can be used - calls itself after each "div", and prints the character after it "ret"s. The easiest to understand(?) is probably to push 'em on the stack, and pop 'em off - they'll be in the right order. We'll want to either count characters, or use a "guard" value on the stack so we'll know when to stop popping!

There's a "gotcha" with "div" (besides it's slow) - it has "built in" operands. "div bl" would divide ax (not just al) by bl, and put the quotient in al, remainder in ah. "div bx" divides dx:ax (dx * 64k + ax, that is) by bx (not just ax!), puts the quotient in ax, remainder in dx. We don't "care" about dx - we want it to be zero - but "div" uses it... and makes it non-zero... so we need to make it zero before the "div" - every time (notice it's inside the loop).

...
mov ax, 123 ; number in ax
...

mov bx, 10 ; we'll divide by ten
mov cx, 0 ; count characters
top:
mov dx, 0 ; "xor dx, dx" is shorter...
div bx
add dl, '0'
push dx
inc cx
cmp ax, 0
jnz top

mov ah, 2
poptop:
pop dx
int 21h
loop poptop
...

That's untested, but probably close enough so you can make it work. You should learn to use DEBUG anyway. :)

Best,
Frank