




Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
This lecture handout was provided at Quaid-i-Azam University for Microprocessor and Assembly Language Programming course by Prof. Saleem Raza. Its main points are: Flag, Unsigned, Udest, Usrc, Zero, Carry, Sdest, Ssrc, Conditional, Jumps, If, Addressing, sorting
Typology: Study notes
1 / 8
This page cannot be seen from the preview
Don't miss anything!





So if a JA is taken after comparing -2 in the destination with 2 in the source the jump will be taken. If however JG is used after the same comparison the jump will not be taken as it will consider the sign and with the sign -2 is smaller than 2. The key idea is that -2 and 65534 were both stored in memory in the same form. It was the interpretation that treated it as a signed or as an unsigned number. The unsigned comparisons see the numbers as 0 being the smallest and 65535 being the largest with the order that 0 < 1 < 2 … < 65535. The signed comparisons see the number -32768 which has the same memory representation as 32768 as the smallest number and 32767 as the largest with the order -32768 < -32767 < … < -1 < 0 < 1 < 2 < … < 32767. All the negative numbers have the same representation as an unsigned number in the range 32768 … 65535 however the signed interpretation of the signed comparisons makes them be treated as negative numbers smaller than zero. All meaningful situations both for signed and unsigned numbers that occur after a comparison are detailed in the following table.
DEST = SRC ZF = 1 When the source is subtracted from the destination and both are equal the result is zero and therefore the zero flag is set. This works for both signed and unsigned numbers.
UDEST < USRC CF = 1 When an unsigned source is subtracted from an unsigned destination and the destination is smaller, borrow is needed which sets the carry flag.
UDEST USRC ZF = 1 OR CF = 1 If the zero flag is set, it means that the source and destination are equal and if the carry flag is set it means a borrow was needed in the subtraction and therefore the destination is smaller.
UDEST USRC CF = 0^ When^ an^ unsigned^ source^ is subtracted from an unsigned destination no borrow will be needed either when the operands are equal or when the destination is greater than the source.
UDEST > USRC ZF = 0 AND CF = 0 The unsigned source and destination are not equal if the zero flag is not set and the destination is not smaller since no borrow was taken. Therefore the destination is greater than the source.
SDEST < SSRC (^) SF OF When a signed source is subtracted from a signed destination and the answer is negative with no overflow than the destination is smaller than the source. If however there is an overflow meaning that the sign has changed unexpectedly, the meanings are reversed and a
positive number signals that the destination is smaller.
SDEST SSRC ZF = 1 OR SF OF If the^ zero flag is set, it means that the source and destination are equal and if the sign and overflow flags differ it means that the destination is smaller as described above.
SDEST SSRC SF = OF When a signed source is subtracted from a signed destination and the answer is positive with no overflow than the destination is greater than the source. When an overflow is there signaling that sign has changed unexpectedly, we interpret a negative answer as the signal that the destination is greater.
SDEST > SSRC ZF = 0 AND SF = OF If the zero flag is not set, it means that the signed operands are not equal and if the sign and overflow match in addition to this it means that the destination is greater than the source.
For every interesting or meaningful situation of flags, a conditional jump is there. For example JZ and JNZ check the zero flag. If in a comparison both operands are same, the result of subtraction will be zero and the zero flag will be set. Thus JZ and JNZ can be used to test equality. That is why there are renamed versions JE and JNE read as jump if equal or jump if not equal. They seem more logical in writing but mean exactly the same thing with the same opcode. Many jumps are renamed with two or three names for the same jump, so that the appropriate logic can be conveyed in assembly language programs. This renaming is done by Intel and is a standard for iAPX88. JC and JNC test the carry flag. For example we may need to test whether there was an overflow in the last unsigned addition or subtraction. Carry flag will also be set if two unsigned numbers are subtracted and the first is smaller than the second. Therefore the renamed versions JB, JNAE, and JNB, JAE are there standing for jump if below, jump if not above or equal, jump if not below, and jump if above or equal respectively. The operation of all jumps can be seen from the following table.
Jump if carry Jump if below Jump if not above or equal
CF = 1 This jump is taken if the last arithmetic operation generated a carry or required a borrow. After a CMP it is taken if the unsigned destination is smaller than the unsigned source. JNC JNB JAE
Jump if not carry Jump if not below Jump if above or equal
CF = 0 This jump is taken if the last arithmetic operation did not
JO Jump if overflow. OF = 1 This jump is taken if the last arithmetic operation changed the sign unexpectedly. JNO Jump if not overflow OF = 0 This jump is taken if the last arithmetic operation did not change the sign unexpectedly.
JS Jump if sign SF = 1 This jump is taken if the last arithmetic operation produced a negative number in its destination.
JNS Jump if not sign SF = 0 This jump is taken if the last arithmetic operation produced a positive number in its destination.
JP JPE
Jump if parity Jump if even parity
PF = 1 This jump is taken if the last arithmetic operation produced a number in its destination that has even parity. JNP JPO
Jump if not parity Jump if odd parity
PF = 0 This jump is taken if the last arithmetic operation produced a number in its destination that has odd parity. JCXZ Jump if CX is zero CX = 0 This jump is taken if the CX register is zero.
The CMP instruction sets the flags reflecting the relation of the destination to the source. This is important as when we say jump if above, then what is above what. The destination is above the source or the source is above the destination. The JA and JB instructions are related to unsigned numbers. That is our interpretation for the destination and source operands is unsigned. The 16th bit holds data and not the sign. In the JL and JG instructions standing for jump if lower and jump if greater respectively, the interpretation is signed. The 16th bit holds the sign and not the data. The difference between them will be made clear as an elaborate example will be given to explain the difference. One jump is special that it is not dependant on any flag. It is JCXZ, jump if the CX register is zero. This is because of the special treatment of the CX register as a counter. This jump is regardless of the zero flag. There is no counterpart or not form of this instruction. The adding numbers example of the last chapter can be a little simplified using the compare instruction on the BX register and eliminating the need for a separate counter as below.
Example
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017
; a program to add ten numbers without a separate counter [org 0x0100] mov bx, 0 ; initialize array index to zero mov ax, 0 ; initialize sum to zero l1: add ax, [num1+bx] ; add number to ax add bx, 2 ; advance bx to next index cmp bx, 20 ; are we beyond the last index jne l1 ; if not add next number mov [total], ax ; write back sum in memory
mov ax, 0x4c00 ; terminate program int 0x num1: dw 10, 20, 30, 40, 50, 10, 20, 30, 40, 50 total: dw 0
(^006) The format of memory access is still base + offset.
(^008) BX is used as the array index as well as the counter. The offset of
11th number will be 20, so as soon as BX becomes 20 just after the 10th number has been added, the addition is stopped.
(^009) The jump is displayed as JNZ in the debugger even though we have
written JNE in our example. This is because it is a renamed jump with the same opcode as JNZ and the debugger has no way of knowing the mnemonic that we used after looking just at the opcode. Also every code and data reference that we used till now is seen in the opcode as well. However for the jump instruction we see an operand of F2 in the opcode and not 0116. This will be discussed in detail with unconditional jumps. It is actually a short relative jump and the operand is stored in the form of positive or negative offset from this instruction.
With conditional branching in hand, there are just a few small things left in assembly language that fills some gaps. Now there is just imagination and the skill to conceive programs that can make you write any program.
UNCONDITIONAL JUMP
Till now we have been placing data at the end of code. There is no such restriction and we can define data anywhere in the code. Taking the previous example, if we place data at the start of code instead of at the end and we load our program in the debugger. We can see our data placed at the start but the debugger is intending to start execution at our data. The COM file definition said that the first executable instruction is at offset 0100 but we have placed data there instead of code. So the debugger will try to interpret that data as code and showed whatever it could make up out of those opcodes. We introduce a new instruction called JMP. It is the unconditional jump that executes regardless of the state of all flags. So we write an unconditional jump as the very first instruction of our program and jump to the next instruction that follows our data declarations. This time 0100 contains a valid first instruction of our program.
Example
001 002 003 004 005 006
; a program to add ten numbers without a separate counter [org 0x0100] jmp start ; unconditionally jump over data num1: dw 10, 20, 30, 40, 50, 10, 20, 30, 40, 50 total: dw 0
the lower part. A negative number actually is a large number and works this way using the wraparound behavior.
Short Jump
If the offset is stored in a single byte as in 75F2 with the opcode 75 and operand F2, the jump is called a short jump. F2 is added to IP as a signed byte. If the byte is negative the complement is negated from IP otherwise the byte is added. Unconditional jumps can be short, near, and far. The far type is yet to be discussed. Conditional jumps can only be short. A short jump can go +127 bytes ahead in code and -128 bytes backwards and no more. This is the limitation of a byte in singed representation.
Far Jump
Far jump is not position relative but is absolute. Both segment and offset must be given to a far jump. The previous two jumps were used to jump within a segment. Sometimes we may need to go from one code segment to another, and near and short jumps cannot take us there. Far jump must be used and a two byte segment and a two byte offset are given to it. It loads CS with the segment part and IP with the offset part. Execution therefore resumes from that location in physical memory. The three instructions that have a far form are JMP, CALL, and RET, are related to program control. Far capability makes intra segment control possible.
SORTING EXAMPLE
Moving ahead from our example of adding numbers we progress to a program that can sort a list of numbers using the tools that we have accumulated till now. Sorting can be ascending or descending like if the largest number comes at the top, followed by a smaller number and so on till the smallest number the sort will be called descending. The other order starting with the smallest number and ending at the largest is called ascending sort. This is a common problem and many algorithms have been developed to solve it. One simple algorithm is the bubble sort algorithm. In this algorithm we compare consecutive numbers. If they are in required order e.g. if it is a descending sort and the first is larger then the second, then we leave them as it is and if they are not in order, we swap them. Then we do the same process for the next two numbers and so on till the last two are compared and possibly swapped. A complete iteration is called a pass over the array. We need N passes at least in the simplest algorithm if N is the number of elements to be sorted. A finer algorithm is to check if any swap was done in this pass and stop as soon as a pass goes without a swap. The array is now sorted as every pair of elements is in order. For example if our list of numbers is 60, 55, 45, and 58 and we want to sort them in ascending order, the first comparison will be of 60 and 55 and as the order will be reversed to 55 and 60. The next comparison will be of 60 and 45 and again the two will be swapped. The next comparison of 60 and 58 will also cause a swap. At the end of first pass the numbers will be in order of 55, 45, 58, and 60. Observe that the largest number has bubbled down to the bottom. Just like a bubble at bottom of water. In the next pass 55 and 45 will be swapped. 55 and 58 will not be swapped and 58 and 60 will also not be swapped. In the next pass there will be no swap as the elements are in order i.e. 45, 55, 58, and 60. The passes will be stopped as the last pass did not cause any swap. The application of bubble sort on these numbers is further explained with the following illustration.
Example
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028
; sorting a list of ten numbers using bubble sort [org 0x0100] jmp start
data: dw 60, 55, 45, 50, 40, 35, 25, 30, 10, 0 swap: db 0 start: mov bx, 0 ; initialize array index to zero mov byte [swap], 0 ; rest swap flag to no swaps loop1: mov ax, [data+bx] ; load number in ax cmp ax, [data+bx+2] ; compare with next number jbe noswap ; no swap if already in order mov dx, [data+bx+2] ; load second element in dx mov [data+bx+2], ax ; store first number in second mov [data+bx], dx ; store second number in first mov byte [swap], 1 ; flag that a swap has been done noswap: add bx, 2 ; advance bx to next index cmp bx, 18 ; are we at last index jne loop1 ; if not compare next two cmp byte [swap], 1 ; check if a swap has been done je start ; if yes make another pass mov ax, 0x4c00 ; terminate program int 0x
Yes On
Yes On
55 45 60 58 Yes^ On
Off
Yes On
No On
45 55 58 60 No^ On
Off
No Off
No Off
45 55 58 60 No^ Off
Pass 3 Off
Pass 2
Pass 1
No more passes since swap flag is Off
State of Data Swap Done Swap Flag