'Accurate LINE FEED in assembly language

I am writing an asm program, which has to print the contents of 2D array. I succeeded in adding spaces to elements of an array, but I can't add line feeds when the row is over. I tried to add some labels, e.g. @line which adds line feeds and carriage returns, but when i add return statement the loop goes infinitely. What should I do?

Here is my code:

.model small
.stack 100h
.data
message db 0ah,0dh,'Initial array: $',0ah,0dh
array dw 1, 2, 3, 4, 5, 6
      dw 7, 8, 9, 10, 11, 12
      dw 13, 14, 15, 16, 17, 18
      dw 19, 20, 21, 22, 23, 24
      CR_LF db 0dh,0ah, '$'
     x dw ?
    buff dw ? 
.code
main:
mov ax,@data
mov ds,ax
xor ax,ax
printmessage:
mov ah, 09h
lea dx, message
int 21h


mov cx, 24
mov si, 0
@sec_row:
mov ax, array[si]
cmp buff, 24
je @end
jl @main              
@main: 
mov x, ax       
push ax         
cmp ax, 0       
jns @num_count     
mov ah, 02h    
mov dl, '-'     
int 21h        
pop ax         
neg ax          

@num_count:
xor cx, cx      
mov bx, 10      

@dvsn:
xor dx, dx      
div bx          
push dx         
                
inc cx          
test ax, ax     
jnz @dvsn       
mov ah, 02h     

@output:
pop dx          
add dl, 30h     
int 21h        
loop @output
mov dl, ' '
mov ah, 2
int 21h 
inc buff
add si, 2
jmp @sec_row
loop @sec_row    

@end:
mov ax,4c00h 
int 21h
end main


Solution 1:[1]

It will be easier to make the requested addition to the program once the code has been cleaned and works correctly.

Correct the unbalanced stack error

 push ax         <<<
 cmp ax, 0       
 jns @num_count     
 mov ah, 02h    
 mov dl, '-'     
 int 21h        
 pop ax          <<<
 neg ax          
@num_count:

When the number from the array turns out to be negative, you display a minus character, and because you know that this will clobber the AX register, you preserve AX on the stack. Good idea, wrong execution! Currently your code does push ax for any of the numbers while it does pop ax only for the negative numbers. Seeing that your array of numbers exclusively has positive numbers, it is to be expected that the stack will fill up. That will at some point cause problems.

  cmp  ax, 0
  jge  @num_count
  push ax         ; (1)
  mov  ah, 02h
  mov  dl, '-'
  int  21h
  pop  ax         ; (1)
  neg  ax          
@num_count:

Remove the leftovers from previous drafts

 mov cx, 24      <<< 1
 mov si, 0
@sec_row:
 ...
 jl @main        <<< 2
@main:           <<< 2
 mov x, ax       <<< 3
 ...
 add si, 2
 jmp @sec_row
 loop @sec_row   <<< 1

(1) At some time you planned on using the loop instruction for this task but later you changed your mind, perhaps because you saw that you needed CX for the number conversion? You should have removed these lines.
(2) At some time these jl @main and @main would have been not adjacent and making good sense, but here they don't make sense anymore!
(3) At some time this mov x, ax would have preserved the AX register as required for the display of the minus character, but later you changed your mind and started using the stack. You should have removed this line.

Write the loop clearer

Your loop is using the memory-based buff variable to control the number of iterations (24). At the same time your loop is using a register-based variable (SI) that contains the current offset in the array. You don't need both together. Once the SI register gets the value 48 (24 x 2), the end of the array has been reached. Use that info to control the loop:

 xor  si, si           ; Offset in the array
@sec_row:
 mov  ax, array[si]    ; Load current element

 cmp  ax, 0     \  
 jge  @num_count |
 ...             | <PRINTNUMBER>
 mov  dl, ' '    |
 int  21h       /

 add  si, 2            ; Elements are word-sized
 cmp  si, 24 * 2       ; Process 24 elements
 jb   @sec_row

Moving on to displaying the rows of the matrix on separate rows of the screen.

Method 1 introduces a special down-counter that can inform us that the end of the current row has been reached. Since there are 6 elements in a row, this down-counter will be initialized at 6 and once it runs out we display the newline sequence and (very important) we re-initialize the down-counter.

 mov  di, 6            ; DownCount = Number of columns
 xor  si, si           ; Offset in the array

 ...

 <PRINTNUMBER>
 dec  di
 jnz  @not_yet
 lea  dx, CR_LF
 mov  ah, 09h
 int  21h
 mov  di, 6
@not_yet:

Method 2 uses what we call nested loops. Your matrix has 2 dimensions, why not give the loop 2 dimensions? The outer loop runs the vertical direction that has 4 rows, and the inner loop runs the horizontal direction that has 6 columns. Each time the inner loop finishes we display the newline. At the conclusion of the outer loop we will have processed 4 times 6 elements plus their accompanying newline.

 xor  si, si           ; Offset in the array

 mov  di, 4            ; OuterLoopCount = Number of rows
@OuterLoop:

 mov  bp, 6            ; InnerLoopCount = Number of columns
@InnerLoop:

 mov  ax, array[si]    ; Load current element
 <PRINTNUMBER>

 dec  bp
 jnz  @InnerLoop

 lea  dx, CR_LF
 mov  ah, 09h
 int  21h

 dec  di
 jnz  @OuterLoop

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sep Roland