Showing posts with label Assembly Language. Show all posts
Showing posts with label Assembly Language. Show all posts

Add Single Digit Numbers With Filtering

This problem is easily solved if we are to use High level programming language, but for assembly language, we need to remember that each entry from the keyboard are accepted as hexadecimal equivalent of characters, even if the entry is a digit, as long as it is from the keyboard. To manipulate these data, we need to be able to work with the registers and the memory allocation since that is the only thing we can work with during processing when.

So here's how we did it:
Since we are just entering a single digit number, we just use the 

MOV ah, 01h 
INT 21h

to enter a character which will then be stored inside AL
for the first number, we transfered it to CL to not loose the data since we are to use AL again for the second input. We then decrement the inputed characters by 30H to get its equivalent numerical value in hexadecimal.

To determine if the input is valid or not, right after we enter the data, we test it first if the value is between 30h to 39h, since the characters '0' to '9' is only within that range, we use the compare then jump algorithm. JL for Jump if Lesser. JG for Jump if Greater. JE for Jump if Equal.

CMP AL, 30H
JL

The code above compares the AL to 30H, and if it is lesser than the value(which is lesser than the valid range for numerical characters), we let it jump to the label where we want it to go to.

CMP AL, 39H
JG

The code above compares the AL to 39H, and if it is greater than the value(which is higher than the valid range for numerical characters), we let it jump to the label where we want it to go to.

At the second input, we leave the second number to AL since later, we are to use AAA(ASCII Adjust for Addition) in case our result of the addition will exceed 09h. During the AAA, if it exceeds to 09h, the AL will be added by 06H to get the appropriate value then zero out the most significant nibble, then add AH by 1, that is also why we zeroed out first the AH in order for our highest significant digit to start at 0.

After adjustment, we add the two values with 30H to bring it back to its ASCII equivalent(ADD AX, 3030H). We then PUSH the data (which is stored inside AX momentarily) to the stack to be stored in the MM to prevent data loss(PUSH AX). 

Then later, when we are ready to print the result, we just simply POP out the result (POP CX) then store it to CX and one by one display the characters starting from the highest significant number.

There is another filtering during the displaying of the result, that is if the most significant number of the result is equal to zero, which means that the result of the addition did not exceed 09h.

CMP AH, 30H
JE

The code above is to let the program skip a printing the the Highest Significant Number if the it is equal to 30H or simply '0' to the specified label for the printing of the Lowest Significant Number.


For the output: I provided 3 situations
1st situation is when we add values where the result is greater than 9.
2nd situation is when we add values within 0 - 9.
3rd situation is when there is an invalid input.

Pyramid of Letters


With this code, based on the number cx, loops would generate a pyramid of letters.
The soluttion is to have multiple loops. Now the problem with this is that the CX is the only register used to count how many loops. Since we have two loops, we need to store first the CX to another register then store it back again to the CX when doing the outer loop since when doing the inner loop we need to be able to have a new value for CX without loosing the old value of CX.

The data segment:
msg1 db 0ah, 0dh, '$'
ctr1 dw 1
ctr2 dw ?
tem db ?
let db 'A'

The code segment:
mov cx, 5 ; assign the first value of CX to
; a specific number to determine
; the level of the pyramid in this
; situation, we give the pyramid
; with level 5

a: mov ctr2, cx ; store cx to a memory
; alocation
mov cx, ctr1 ; give a new value for cx
; for the inner loop

mov bh, let ; assign the letter to be
; displayed starting from 'A'
mov tem, bh

b: mov ah, 02h
int 21h ; print the character inside tem
inc tem ; increment tem to proceed
; to the next letter
loop b

mov ah, 09h
lea dx, msg1 ; print the new line stored at msg1
int 21h

inc ctr1 ; increment the ctr1 to increase
; the next level
mov cx, ctr2 ; give cx its old value to proceed
; with the outer loop.

loop a ; repeat the process with the old counter

Stack - Reversing a String


The concept for reversing a string using a stack is to remember that the last item to be inserted will always be the first item to be removed (LIFO). We would just simply, push each character of the string into the stack starting from the beginning to the very last of the string then popping it out of the stack starting from the last item inserted then displaying the item.

Here is the sample code:

For the Data Segment:
STR1 DB 30, 31 DUP('$')
STR2 DB 0AH, 0DH, '$'

The pushing of the elements to the stack:
LEA DX, STR1
MOV CL, STR1[1]
MOV SI, DX
ADD SI, 02H
A: MOV DL, [SI]
PUSH DX
INC SI
LOOP A

The popping and displaying of each element from the stack:
MOV CL, STR1[1]

B: MOV AH, 02H
POP DX
INT 21H
LOOP B

Converting an All Upper Case String to an All Lower Case String



The concept of the code is to read each character from the memory allocation and converting one by one into it equivalent lower case character. Since the difference between a Lower Case and an Upper Case letter is equivalent to 20H, and since the Upper Case has a lower value that the Lower Case, to convert to lower case, we add the value of the Upper Case Letter to 20H. To traverse through the string, we start at index 2 up to the last. the CL holds the length of the string so that it is possible to determine how many times the process will repeat. We also use the Stack Index to hold the index of the character we are looking for, so everytime we repeat the loop, we increment the SI to proceed with the next index.

Why didn't we use the CX? It is because, the Counter Register counts backwards. Meaning, if CX=09H, it counts from 09H to 01H.

Here is the code.

Data Segment
   STR1 DB 11, 12 DUP('$')
  STR2 DB 0AH, 0DH, '$'

Code Segment
MOV AX, dseg 
MOV DS, AX

LEA DX, STR1 
MOV AH, 0AH
INT 21H
 
LEA DX, STR2
MOV AH, 09H
INT 21H
LEA DX, STR1
MOV SI, DX ; asign the si with DX since it already holds the address of str1
ADD SI, 02H ; increment 2H to start at the third element
MOV CL, STR1[1] ; assign CL with the length of the string

A: MOV AH, 02H
MOV DL, [SI] ; get each character based on SI
ADD DL, 20H ; convert each character
INT 21H
INC SI ; increment the index
LOOP A ; repeat the process

MOV AH, 4CH   
INT 21H

Reading An Input from the keyboard and displaying

To read input from the keyboard using assembly language, we need to understand first how memory is alocated for a string. Basically, each character of the string is stored in one memory location, the string is basically ordered the way you have entered it. But the begining of that alocation is not the beginning of the string. In actuality, the first two alocation in the memory for your string is actually reserved. The second alocation, specifically index 1 (the first alocation starts with index 0), is stored with the length of the string you have entered. The first character of your string would therefore be the third memory alocation, therefore index 2. So here is the sample code.

For example, we have an identifier able to accept 10 characters.

STR1 DB 11, 12 DUP('$')
STR2 DB 0AH, 0DH, '$'

So here is the sample code.

MOV AX, dseg ;initialize the dseg (data segment) to DS register
MOV DS, AX

LEA DX, STR1 ;load the effective address of str to dx to be ready for reading
MOV AH, 0AH ;prepare the function for reading an input(string)
INT 21H ;trigger the function

LEA DX, STR2 ;print str2 for new line
MOV AH, 09H
INT 21H

LEA DX, STR1[2] ;load the effective address of str but starting at the index 2
MOV AH, 09H ;prepare the fun
ction for printing a string
INT 21H ;trigger the function

MOV AH, 4CH ;exit
INT 21H

Sample output: