Printing a triangle with incrementing digits instead of asterisks - loops

I'm experimenting with my program by trying to build different kinds of pyramids and converting the values into different values. I managed to build one with asterisk sign and now I'm trying to find a way on how to change it into running numbers like "0123456789" and the next line is "012345678" and so on. Is there a way to do that without fully/less changes of my code?
.MODEL SMALL
.STACK 100H
.DATA
STAR DB ?
BLANK DB ?
.CODE
MAIN PROC
MOV AX,#DATA
MOV DS,AX
MOV CX,10
MOV BH,10
MOV BL,0
MOV STAR,BH
MOV BLANK,BL
L1:
CMP BLANK,0
JE L2
MOV AH,2
MOV DL,32
INT 21H
DEC BLANK
JMP L1
L2:
MOV AH,2
MOV DL,'*'
INT 21H
DEC STAR
CMP STAR,0
JNE L2
MOV AH,2
MOV DL,0AH
INT 21H
MOV DL,0DH
INT 21H
DEC BH
MOV STAR,BH
INC BL
MOV BLANK,BL
LOOP L1
EXIT:
MOV AH,4CH
INT 21H
MAIN ENDP
END MAIN

I'm trying to find a way on how to change it into running numbers like "0123456789" and the next line is "012345678" and so on. Is there a way to do that without fully/less changes of my code?
While the other answer provides an alternative solution, my solution keeps most of your program intact as per request, only adding the digit sequence:
L2:
mov dl, '0' <--- Setup 1st digit
L3: <--- Extra label
MOV AH,2
INT 21H
inc dl <--- To next digit
DEC STAR
CMP STAR,0 ; Tip: you can remove this instruction
JNE L3 <--- To extra label
Expected output (similar to your asterisks):
0123456789
012345678
01234567
0123456
012345
01234
0123
012
01
0

Consider a simplier algorithm which uses DOS function Int 21h/AH=09h (which displays $-terminated strings). You may shorten the string by overwriting characters at its end with '$' in each loop cycle:
.MODEL SMALL
.STACK 100H
.DATA
EOL DB 13,10,'$' ; End of line string.
TXT DB '0123456789$' ; The initial string.
.CODE
MAIN PROC
MOV AX,#DATA
MOV DS,AX ; Initialize DS to .DATA segment.
MOV AH,9 ; Use DOS function WRITE STRING TO STANDARD OUTPUT.
MOV BX,10 ; Initialize the number of iteration (address index).
L1: MOV DX,OFFSET EOL
INT 21H ; Write EOL first.
MOV [TXT+BX],'$' ; Terminate TXT at index BX.
MOV DX,OFFSET TXT
INT 21H ; Write TXT.
DEC BX ; Let BX index the previous character.
JNZ L1 ; Loop while BX > 0.
EXIT:MOV AH,4CH
INT 21H
MAIN ENDP
END MAIN
Result should be this:
0123456789
012345678
01234567
0123456
012345
01234
0123
012
01
0

Related

Code stuck at an infinite loop when finding the nth fibonacci number

I was trying to find the nth Fibonacci number e.x n=3, output = 1
so my logic was this
a = 0
b = 1
input n
si 0
n>2
loop
temp = b
b = a+b
a = b
loop if si/=cx
print b
This is my pseudo code logic. When I tried to implement this I am stuck in an infinite loop
.MODEL SMALL
.STACK 100h
.DATA
STRING0 DB 'Enter INDEX $'
.CODE
MAIN PROC
MOV AX,#DATA
MOV DS,AX
LEA DX, STRING0
MOV AH,9
INT 21H
MOV AH, 2
MOV DL,0AH ;NEW LINE
INT 21H
MOV DL,0DH
INT 21H
MOV AH,1
INT 21H
SUB CX,CX
MOV CL,AL
MOV SI,0
MOV AX,0
MOV BX,1
LOOP1:
PUSH BX
ADD BX,AX
POP AX
INC SI
LOOP LOOP1
MOV DX,BX
MOV AH,9
INT 21H
MAIN ENDP
END MAIN
I use EMU 4.08. The code us stuck at an infinite loop. I have no idea why
I did SUB cx,cx to move the AL value to CL and use CL as counter otherwise it gives me error that the code failed to send 8bit data to 16bit
I was trying to find the nth Fibonacci number e.x n=3, output = 1
From your example I understand that you consider the Fibonacci sequence to begin with 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
Fibonacci himself started his sequence from 1, 2, 3, 5, 8, ...
See the Wikipedia article https://en.wikipedia.org/wiki/Fibonacci_number
I didn't follow your pseudo code too much as it has flaws of its own!
Why your assembly program fails
You say your "code is stuck at an infinite loop", but that's not really the case. It is just that your loop executes an extra 50 iterations. The reason is that the DOS.GetCharacter function 01h gives you an ASCII code, that you have to convert into the digit that the pressed key represents. eg. If you press 3, DOS gives you AL=51, and you need to subtract 48 to obtain the inputted digit which is 3.
But wait, don't use this number 3 as your loop counter already! Since the 1st and 2nd Fibonacci numbers are known from the start, calculating the 3rd Fibonacci number requires just 1 iteration of the loop. Account for this and subtract 2 beforehand.
Once your program has found the answer you simply move the result from BX to DX, and expect the DOS.PrintString function 09h to output the number. It can't do that. It's a function that outputs a series of characters (so a string beginning at the address in DX), however your result is still a number in a register. You have to convert it into its textual representation. Displaying numbers with DOS has all the fine details about this conversion!
Next code allows the user to input a single-digit from 1 to 9
...
mov ah, 01h ; DOS.GetCharacter
int 21h ; -> AL = ["1","9"]
sub al, 48 ; -> AL = [1,9]
cbw ; -> AH = 0
mov cx, ax ; -> CX = [1,9]
xor ax, ax ; -> AX = 0
dec cx
jz PrintIt ; 1st Fib is 0
inc ax ; -> AX = 1
dec cx
jz PrintIt ; 2nd Fib is 1
cwd ; -> DX = 0
CalcIt: ; 3rd Fib and others
xchg ax, dx
add ax, dx
loop CalcIt
PrintIt: ; AX is at most 21 (because of the limited input)
aam
add ax, 3030h ; Conversion into text
xchg al, ah
cmp al, '0'
mov dh, 02h ; DOS.PrintCharacter
xchg ax, dx
je Ones
int 21h
Ones:
mov dl, dh
int 21h
Because in your program the output is very limited, I used a special code to display at most 2 digits. For the general case of outputting numbers see this Q/A.
I think this should be good:
.MODEL SMALL
.STACK 100h
.DATA
STRING0 DB 'Enter INDEX $'
STRING1 DB 'OUTPUT: $'
.CODE
MAIN PROC
MOV AX,#DATA
MOV DS,AX
LEA DX, STRING0
MOV AH,9
INT 21H
MOV AH, 2
MOV DL,0AH ;NEW LINE
INT 21H
MOV DL,0DH
INT 21H
MOV AH,1
INT 21H
SUB CX,CX
SUB AL,30H ;To convert char into digit value
MOV CL,AL
MOV SI,0
MOV AX,0
MOV BX,1
LOOP1:
PUSH BX
ADD BX,AX
POP AX
INC SI
LOOP LOOP1
MOV AH, 2
MOV DL,0AH ;NEW LINE
INT 21H
MOV DL,0DH
INT 21H
LEA DX, STRING1
MOV AH,9
INT 21H
;Print the result
MOV AX,BX
MOV SI,0
;Push digits from right to left into stack
LOOP2:
MOV DL,10
DIV DL
PUSH AX
MOV AH,0
INC SI
CMP AL,0
JNE LOOP2
;Pop digits from stack and print them
LOOP3:
POP DX
MOV DL,DH
MOV DH,0
ADD DL,30H ;To convert digit to char
MOV AH,2
INT 21H
DEC SI
CMP SI,0
JNE LOOP3
HLT
MAIN ENDP
END MAIN

How to write decimal number by one char to file 8086 YASM

I have a task and I will try to explain it clearly. There is a file with [0; 1000] lines. Each line contains 6 columns.
The first two columns contain string with [1; 20] characters. Characters could be letters, numbers, and whitespaces.
3-5 columns contain integers in the range [-100; 100].
6th column contain real numbers in range [-9.99; 9.99] with only two digits after decimal point.
Each section I separated by a semicolon ';'.
FILE EXAMPLE:
helloA;lB;lC;lD;lE;lF
A11;bas morning;0;0;5;1.15
B12; Hello WoRlD;-100;11;78;1.33
B11;table;10;0;55;-2.44
C1;OakWood;0;8;17;3.77
TASK: count how many lines in the first two sections contain the letters 'B' and 'C'. And print that integer number in the other file.
I did almost all the task, except one thing. I don't know how to print the decimal number in the file. I store this number in memory as hexadecimal. I need to convert that number to decimal and print it into the other file.
I am struggling because there could be 1 good line, but it also could be 1000 good lines. So I need to print 1 character (if the number of good lines is between [0; 9]), but it could be 900 good lines, so then the program has to print 3 characters.
MY CODE
org 100h
%include 'yasmmac.inc'
section .text
startas:
macPutString 'Output file:', crlf, '$'
; Save the writing file's name
mov al, 128
mov dx, writingFile
call procGetStr
macNewLine
; Open reading file
mov dx, readingFile
call procFOpenForReading
jnc .writingFileOpen
macPutString 'Error while opening the writing file!', '$'
exit
; Open the writing file
.writingFileOpen:
mov [readingDescriptor], bx
mov dx, writingFile
call procFCreateOrTruncate
jnc .writingFileSuccessfullyOpened
macPutString 'Error while opening file for writing!', '$'
jmp .writingError
; Sacing writing descriptor
.writingFileSuccessfullyOpened:
mov [writingDescriptor], bx
; Read first line
call procReadLine
; Main loop
.untilEndOfFile:
call procReadLine
; checking the first two columns
;mov al, ';'
; checking first column
.firstColumn:
mov al, [di]
inc di
cmp al, byte 'B'
je .skipALine
cmp al, byte 'b'
je .skipALine
cmp al, byte 'C'
je .skipALine
cmp al, byte 'c'
je .skipALine
cmp al, byte ';'
jne .firstColumn
; checking second column
.secondColumn:
mov al, [di]
inc di
cmp al, byte 'B'
je .skipALine
cmp al, byte 'b'
je .skipALine
cmp al, byte 'C'
je .skipALine
cmp al, byte 'c'
je .skipALine
cmp al, byte ';'
jne .secondColumn
jmp .addNumber ; Adding number because line corresponds to filter.
.addNumber:
call procAddNumber
; If it is not the end of file, jump back to main loop
.skipALine:
cmp [readTheLastLine], byte 0
je .untilEndOfFile
; Writing to file (number, how many good lines)
; **I cant do this part**
mov bx, [writingDescriptor]
mov cx, 2h
mov dx, lineCount
mov ah, 40h
int 21h
; Closing Files
.end:
mov bx, [writingDescriptor]
call procFClose
.writingError:
mov bx, [readingDescriptor]
call procFClose
exit
%include 'yasmlib.asm'
; void procReadLine()
; Read line to buffer 'line'
procReadLine:
push ax
push bx
push cx
push si
mov bx, [readingDescriptor]
mov si, 0
.loop:
call procFGetChar
; End if the end of file or error
cmp ax, 0
je .endOfFile
jc .endOfFile
; Putting symbol to buffer
mov [line+si], cl
inc si
; Check if there is \n?
cmp cl, 0x0A
je .endOfLine
jmp .loop
.endOfFile:
mov [readTheLastLine], byte 1
.endOfLine:
mov [line+si], byte '$'
mov [lineLength], si
pop si
pop cx
pop bx
pop ax
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
procAddNumber:
push si
push ax
push bx
push cx
push dx
;lineCount++
mov ax, [lineCount]
inc ax
mov [lineCount], ax
pop dx
pop cx
pop bx
pop ax
pop si
ret
section .data
readingFile:
db 'input.dat', 00
readingDescriptor:
dw 0000
writingFile:
times 128 db 00
writingDescriptor:
dw 0000
readTheLastLine:
db 00
line:
db 64
times 66 db '$'
lineLength:
dw 0000
lineCount:
dw 0000
GitHub link to macroses:
yasmlib.asm/yasmmac.inc
Any help would be appreciated.
I don't know how to print the decimal number in the file. I store this number in memory as hexadecimal. I need to convert that number to decimal and print it into the other file.
The solution to the problem is already in the yasmlib.asm file! It contains a code procUInt16ToStr that will convert the unsigned number in AX into an ASCIIZ string at the address in DX.
It does not return the length of the string, so you'll have to loop over the string and use procFPutChar to send the individual characters to the file. Alternatively and preferably loop over the string to establish the stringlength and output all at once with DOS function 40h (like you were doing already).
If you're interested in knowing how to convert from integer to string, then you could read my Q/A Displaying numbers with DOS.
.WritingToFile:
mov dx, Buffer
mov ax, [linecount]
call procUInt16ToStr ; produces an ASCIIZ string at DX
mov si, dx
.again:
lodsb
cmp al, 0
jne .again
sub si, dx
lea cx, [si - 1] ; -1 because we don't want to send the zero
mov bx, [writingDescriptor]
mov ah, 40h ; DOS.WriteToFile
int 21h ; -> AX CF
Watch out with these
.untilEndOfFile:
call procReadLine
.firstColumn:
mov al, [di]
This code is using DI without having initialized the register (mov di, line).
.skipALine:
cmp [readTheLastLine], byte 0
je .untilEndOfFile
Inspecting the readTheLastLine variable comes too late! You need this directly following the return from the procReadLine procedure:
.untilEndOfFile:
call procReadLine
cmp byte [readTheLastLine], 0
je .WritingToFile
mov di, line
.firstColumn:
mov al, [di]
...
jmp .untilEndOfFile
.WritingToFile:
You don't need that wasteful procAddNumber procedure to increment the linecount variable.
Simply replace call procAddNumber by inc word [linecount].
While the other answer dealt with your question about writing the textual representation of the number, this answer focusses on a fundamental misunderstanding about what the task is asking.
TASK: count how many lines in the first two sections contain the letters 'B' and 'C'
Your current program is counting the lines that neither contain a 'B' nor a 'C'. The opposite from what was asked. Next will give you the count of lines that either contain a 'B' or a 'C'.
.untilEndOfFile:
call procReadLine
cmp byte [readTheLastLine], 0
je .WritingToFile
...
jne .secondColumn
jmp .untilEndOfFile
.skipALine:
inc word [linecount]
jmp .untilEndOfFile
.WritingToFile:
Note that the above is still not literally "contain the letters 'B' and 'C'", it's more like "contain the letters 'B' or 'C'". But don't worry, a distinction that is very important in programming might not always be considered that important in day to day speech/writing.

How to show a string 10 times using while loop in assembly language?

how to show string 10 times in assembly language?
Here is my code
.model small
.stack 100h
.data
msg db 'rashed $'
.code
main proc
mov ax,#data
mov ds,ax
lea dx,msg
mov ah,9 ;string output
int 21h
mov dx,0 ;dx counts characters
mov ah,9 ;prepare for read
int 21h
while_:
cmp al,0dh ;carriage return?
je end_while ;yes exit
inc dx ;not carrage return,increament count
int 21h ;read character
jmp while_ ;loop back
end_while:
exit:
mov ah,4ch
int 21h
main endp
end main
output is:
i want to show this string 10 times but the string subtracts??
how to show that 10 times??
mov dx,0 ;dx counts characters
To show the same text a number of times, choose a counter register different from the registers that are required to perform the output (In your case AX and DX). I suggest putting the counter in CX.
mov cx, 11
while_:
dec cx ;Change counter
jz end_while ;Exit after 10 iterations
mov ah, 9
int 21h ;Print string
jmp while_ ;Loop back
end_while:
Because a while-loop tests the condition first, I assigned 11
instead of 10.

Assembly programing bug

I'm new at programming assembly. Now I'm trying to write a program that converts number from decimal to binary. But I got stuck with one program while trying to input. After i output msg2 and get into loop, program doesn't turn off. I can input a lot of numbers and program doesn't turn off. I guess problem is in convertnumber: cmp si,cx (si is how many numbers I have to input, cx- how many numbers I have already written), but I am not sure about that. Where have I made a mistake and how could I correct it?
.MODEL small
.Stack 100h
.DATA
msg0 db 'how many numbers will include your input number(example. 123 is 3 numbers)? $'
msg1 db 'Now input number from 0 to 65535: $'
number db 255, ?, 256 dup ('$')
numberinAscii db 255, ?, 256 dup ('$')
enterbutton db 13,10,'$'
.CODE
start:
mov ax, #data
mov ds,ax
mov ah,09h
mov dx, offset msg0 ; first message output
int 21h
xor ah,ah ; function 00h of
int 16h ; int 16h gets a character (ASCII translation in AL)
int 3
mov bl,al
mov dl,al
mov ah,02h ; function 02h - display character
int 21h ; call DOS service
mov ah,09h
mov dx, offset enterbutton
int 21h
mov ah, 09h
mov dx, offset msg1 ; output second message
int 21h
jmp covertHowMany ; converting number that we entered
next:
xor si,si
mov si, ax ; number that we entered now is in si
xor cx,cx
mov cx,0 ;cx=0
enterfirstnumber: ;entering first number (example 123, first number is 1)
xor ah,ah
int 16h ; int 16h gets a one character
int 3
mov bl,al
mov dl,al
mov ah,02h ; function 02h - display character
int 21h ;
jmp convertnumber ; converting this number
input: ;converting number from ascii char to ascii integer
mov ax,bx
mov dx,10
mul dx ; ax:=ax*10
mov bx,ax ; number that I try to convert is in bx now
xor ah,ah
int 16h ; int 16h gets a character (ASCII translation in AL)
int 3
mov bl,al
mov dl,al
mov ah,02h ; function 02h - display character
int 21h
jmp convertnumber
convertHowMany:
sub al,30h ; convert from ascii character to ascii number
jmp next
convertnumber:
sub al,30h
add bx,ax
inc cx
cmp cx, si
jne input
jmp ending
ending:
mov ax,04C00h
int 21h
end start
I see at least two problems with your code:
The first is that when you reach convertHowMany you assume that AL still contains the character that the user typed in. That will not be the case, since both INT 21h/AH=02h and INT 21h/AH=09h modify AL. You'll have to save and restore the value of AL somehow (e.g. by pushing and popping AX).
The second problem is how you initialize SI before the loop. You're moving the value of AX into SI, which means both AL and AH. AH is not zero at that point, because you've just used INT 21h/AH=09h.
You could change the sequence xor si,si / mov si,ax into something like mov si,ax / and si,0FFh.

How to loop in assembly language

How would I calculate the first 12 values in the Fibonacci number sequence and be able to place it in EAX reg. and display calling DumpRegs? Using Indirect addressing I know I need a for loop here but I'm not sure how to even go about this. Any help or tips are appreciated.
INCLUDE Irvine32.inc
; (insert symbol definitions here)
.data
; (insert variables here)
Fibonacci BYTE 1, 1, 10 DUP (?)
.code
main PROC
; (insert executable instructions here)
; (This below will show hexa contents of string.)
mov esi, OFFSET Fibonacci ; offset the variables
mov ebx,1 ; byte format
mov ecx, SIZEOF Fibonacci ; counter
call dumpMem
exit ; exit to operating system
main ENDP
; (insert additional procedures here)
END main
You can make a loop like this:
mov ecx,12
your_label:
; your code
loop your_label
The loop instruction decrements ecx and jumps to the specified label unless ecx is equal to zero. You could also construct the same loop like this:
mov ecx,12
your_label:
; your code
dec ecx
jnz your_label
You determined that you need a for loop to achieve your goal, so maybe the C implementation of the for loop, in assembly, will help you:
Code Generation for For Loop
for (i=0; i < 100; i++)
{
. . .
}
* Data Register D2 is used to implement i.
* Set D2 to zero (i=0)
CLR.L D2
L1
. . .
* Increment i for (i++)
ADDQ.L #1, D2
* Check for the for loop exit condition ( i < 100)
CMPI.L #100, D2
* Branch to the beginning of for loop if less than flag is set
BLT.S L1
SOURCE: eventhelix.com
.model small
.stack 100h
.data
msg db 'Enter height of the square form 1-9: $'
hash db '#$'
height db 1
length db 0
ctr dw 0
msgagain db 13,10,'Do you want to repeat the program? $'
msgend db 13,10,'Program Terminated! Press any key to exit..$'
.code
mov ax, #data
mov ds, ax
REPEAT:
mov ax, 03
int 10h
mov ah, 09
lea dx, msg
int 21h
mov ah, 01
int 21h
cmp al, '1'
jl REPEAT
cmp al, '9'
jg REPEAT
sub al, 48
mov length, al
mov bl, 1
mul bl
mov height, 1
mov di, 1
mov ctr, ax
mov cx, ax
nextline:
dec length
mov ah, 02
mov bh, 00
mov dl, length
mov dh, height
int 10h
mov cx, di
hashtags:
mov ah, 09
lea dx, hash
int 21h
loop hashtags
inc di
inc height
mov cx, ctr
dec ctr
loop nextline
mov ah, 09
lea dx, msgagain
int 21h
mov ah, 01
int 21h
cmp al, 'Y'
je REPEAT
cmp al, 'y'
je REPEAT
mov ah, 09
lea dx, msgend
int 21h
mov ah, 01
int 21h
mov ah, 4ch
int 21h
END

Resources