Pietro Contadini
Pietro Contadini

Reputation: 61

Printing a triangle of characters in assembly

I am developing this exercise:

write the assembler program that, given a character as input, outputs a triangle of size 5 x 5 of the character itself.

I have a problem because when I go to input a character, the characters do not form a triangle, but other characters are printed.

My input:

f

My output:

Desired output:

f
ff
fff
ffff
fffff

My code:

Title PROVA
;programma per la prova dell’ambiente Turbo Assembler 

DOSSEG
.MODEL SMALL
.STACK 100 
.DATA 
; se ci sono qui vanno dichiarate le vriabili

.CODE
  MOV AX, @data  ;(obbligatorie) inizializzano il DS      
  MOV DS, AX 
  
  MOV AX, 00
  MOV BX, 00
  MOV CX, 00
  MOV DX, 00

  mov ah,01h ;input va a mettere l'input in AL ;n
  int 21h
  MOV BL, AL ;n
  MOV CL, BL ;n
  
  MOV CH, 0H
  
  ciclo:
  CMP CH, 5H
  JE fine

  inc CH

  MOV DL, BL
  mov ah, 02h  ;stampa il contenuto di dl
  int 21h

  mov DL, 10D
  int 21h
  mov DL, 13D
  int 21h
  
  ;BL
  ADD BL, CL 
  
  JMP ciclo

  fine:
  MOV AL, 00H  ;(obbligatorie) ritornano il controllo al sistema operativo      
  MOV AH, 4CH 
  INT 21H 
 
END  

Upvotes: 1

Views: 1480

Answers (3)

Sep Roland
Sep Roland

Reputation: 39191

ADD BL, CL 
JMP ciclo

You seem to expect that this addition will double the number of characters. That is not the case! With BL and CL both holding your inputted "f" character, this instruction will just double the ASCII code for that particular character. And the DOS.PrintCharacter function 02h will only ever print a single character, so you need to repeat that operation in a loop.

MOV AX, @data  ;(obbligatorie) inizializzano il DS      
MOV DS, AX

If your program does not use items from the .DATA sections then setting up the DS segment register can be safely omitted.

MOV AX, 00
MOV BX, 00
MOV CX, 00
MOV DX, 00

This code is correct, but it is almost never needed to zero all your registers at program start. This program being a perfect example...

MOV AL, 00H  ;(obbligatorie) ritornano il controllo al sistema operativo      
MOV AH, 4CH 
INT 21H

Again, this code is correct, but it is definitely not better to load AL and AH separately, when you can write mov ax, 4C00h.

This is your improved program:

Title PROVA
;programma per la prova dell’ambiente Turbo Assembler 

DOSSEG
.MODEL SMALL
.STACK 100 
.DATA 
; se ci sono qui vanno dichiarate le vriabili

.CODE
  mov  ah, 01h          ; DOS.GetKeyboardCharacter
  int  21h              ; -> AL
  mov  bl, al
  mov  ah, 02h          ; DOS.PrintCharacter
  mov  bp, 1            ; BP is number of characters on current line
OuterLoop:
  mov  cx, bp           ; Setup count in CX for the inner loop that follows
  mov  dl, bl           ; BL is the inputted character
InnerLoop:
  int  21h              ; -> AL == DL (BL)
  loop InnerLoop
  mov  dl, 13           ; Carriage return
  int  21h              ; -> AL == DL (13)
  mov  dl, 10           ; Linefeed
  int  21h              ; -> AL == DL (10)
  inc  bp
  cmp  bp, 6
  jb   OuterLoop

  mov  ax, 4C00h        ; DOS.TerminateWithReturncode
  int  21h
END

Below is my version that builds the entire output in a buffer memory and then prints it all at once with a single invokation of the DOS.PrintString function 09h.
It is perhaps not the most obvious way to solve this particular, extremely simple task, but at least:

  • it justifies setting up DS
  • it runs much faster due to a single API call to output
Title PROVA
;programma per la prova dell’ambiente Turbo Assembler 

DOSSEG
.MODEL SMALL
.STACK 100 
.DATA
Buffer db 100 dup (0)

.CODE
  mov  ax, @data
  mov  ds, ax

  mov  ah, 01h          ; DOS.GetKeyboardCharacter
  int  21h              ; -> AL
  mov  dx, OFFSET Buffer
  mov  di, dx
  xor  cx, cx           ; CX is number of characters on current line
OuterLoop:
  inc  cx               ; -> CX=[1,5]
  mov  bx, cx
  mov  word ptr [di+bx], 0A0Dh ; Carriage return and linefeed together
InnerLoop:
  dec  bx               ; (*)
  mov  [di+bx], al      ; AL is the inputted character
  jnz  InnerLoop        ; (*) Acts on the flags defined by `DEC BX`
  add  di, cx
  add  di, 2
  cmp  cx, 5
  jb   OuterLoop
  mov  byte ptr [di], "$"
  mov  ah, 09h          ; DOS.PrintString
  int  21h              ; -> AL == "$"

  mov  ax, 4C00h        ; DOS.TerminateWithReturncode
  int  21h
END

Upvotes: 1

Tanvir Islam Streame
Tanvir Islam Streame

Reputation: 460

I solved in this way

org 100h
MOV AH, 2 
MOV BX, 0 

row:   
 INC BX
 MOV CX,BX 
    
    col:
    MOV DL, 102  

    int 21h
    loop col
    
MOV DL ,010 
INT 21h 
MOV DL, 13

INT 21h

CMP BL, 5
JE break

JMP row   
   
break:
 ret

ret

Upvotes: 0

W. Chang
W. Chang

Reputation: 502

As vitsoft pointed out, the char changed because you add CL to BL. To make a triangle you need to use another loop, as Michael said. Below is the part to change:

  MOV   AH, 01h  ; input va a mettere l'input in AL ;n
  INT   21H
  MOV   BL, AL   ; n
  
  MOV   CH, 0H
ciclo:
  CMP   CH, 5H
  JE    fine
  INC   CH
  
  MOV   DL, 10D
  INT   21H
  MOV   DL, 13D
  INT   21H
  
  MOV   CL, CH
  MOV   AH, 02H  ; stampa il contenuto di dl
  MOV   DL, BL
innerLoop:
  INT   21H
  DEC   CL
  JNE   innerLoop

  JMP ciclo

fine:

Upvotes: 1

Related Questions