Search code examples
functionassemblyx86tasm

Creating a function in assembly language (TASM)


I wanted to print the first 20 numbers using loop.

Printing the first nine numbers is absolutely fine as the hexadecimal and decimal codes are the same, but from the 10th number I had to convert each number into its appropriate code and then convert it and store it to string and eventually display it

That is,

If (NUMBER > 9)
ADD 6D
;10d = 0ah --(+6)--> 16d = 10h
IF NUMBER IS > 19
ADD 12D
;20d = 14h --(+12)--> 32d = 20h

Then rotating and shifting each number to get the desired output number, that is,

DAA          # let al = 74h = 0111.0100

XOR AH,AH    # ah = 0 (Just in case it wasn't)
             # ax = 0000.0000.0111.0100

ROR AX,4     # ax = 0100.0000.0000.0111 = 4007h
SHR AH,4     # ax = 0000.0100.0000.0111 = 0407h
ADD AX,3030h # ax = 0011.0100.0011.0111 = 3437h = ASCII "74" (Reversed due to little endian)

And then storing the result in to the string and displaying it, that is,

MOV BX,OFFSET Result    ;Let Result is an empty string
MOV byte ptr[BX],5      ;Size of the string
MOV byte ptr[BX+4],'$'  ;String terminator
MOV byte ptr[BX+3],AH   ;storing number
MOV byte ptr[BX+2],AL

MOV DX,BX
ADD DX,02  ;Displaying the result
MOV AH,09H ;Interrupt 21 service to display string
INT 21H

And here is the complete code with proper commenting,

MOV CX,20  ;Number of iterations
MOV DX,0   ;First value of the sequence

L1:

    PUSH DX
    ADD DX,30H  ; 30H is equal to 0 in hexadecimal , 31H = 1 and so on
    MOV AH,02H  ; INTERRUPT Service to print the DX content
    INT 21H
    POP DX
    ADD DX,1
    CMP DX,09   ; if number is > 9 i.e 0A then go to L2
    JA L2
LOOP L1


L2:
    PUSH DX
    MOV AX,DX
    CMP AX,14H   ;If number is equal to 14H(20) then Jump to L3
    JE L3
    ADD AX,6D    ;If less than 20 then add 6D
    XOR AH,AH    ;Clear the content of AH

    ROR AX,4     ;Rotating and Shifting for to properly store
    SHR AH,4

    ADC AX,3030h
    MOV BX,OFFSET Result
    MOV byte ptr[BX],5
    MOV byte ptr[BX+4],'$'
    MOV byte ptr[BX+3],AH
    MOV byte ptr[BX+2],AL

    MOV DX,BX
    ADD DX,02
    MOV AH,09H
    INT 21H
    POP DX
    ADD DX,1
LOOP L2

;If the number is equal to 20 come here, ->
; Every step is repeated here just to change 6D to 12D

L3:
    ADD AX,12D
    XOR AH,AH

    ROR AX,1
    ROR AX,1
    ROR AX,1
    ROR AX,1

    SHR AH,1
    SHR AH,1
    SHR AH,1
    SHR AH,1

    ADC AX,3030h
    MOV BX,OFFSET Result
    MOV byte ptr[BX],5
    MOV byte ptr[BX+4],'$'
    MOV byte ptr[BX+3],AH
    MOV byte ptr[BX+2],AL

    MOV DX,BX
    ADD DX,02
    MOV AH,09H
    INT 21H

Is there any proper way to do it, creating a function and using if/else (jumps) to get the desired output rather than repeating the code again and again?

PSEUDO CODE:

VAR = 6
IF Number is > 9
ADD AX,VAR
Else IF Number is > 19
ADD AX,(VAR*2)
ELSE IF NUMBER is > 29
ADD AX,(VAR*3)

Solution

  • So you just want to print 0 ... 20 as ASCII characters? It looks like you understand that the numerals are identified as 0x30 ... 0x39 for '0' to '9', so you could use integer division to generate the character for the tens digit:

    I usually work with C but conversion to assembler shouldn't be too complicated since these are all fundamental operations and there are no function calls.

    int i_value = 29;
    int i_tens = i_value/10; //Integer division! 29/10 = 2, save for later use
    char c_tens = '0' + i_tens;
    char c_ones = '0' + i_value-(10*i_tens); // Subtract N*10 from value
    

    The output will be c_tens = 0x32, c_ones = 0x39. You should be able to wrap this inside of a loop pretty easily using a pair of registers.

    Pseudocode

    regA <- num_iterations //For example, 20
    regB <- 0 //Initialize counter register
    
    LOOP:
        //Do conversion for the current iteration.
        //Manipulate bytes for output as necessary.
        regB <- regB +1
        branch not equal regA, regB LOOP