Keep in mind that the default in assembler is decimal, but the
contents of registers are always stored in hexadecimal.
For example, mov ax,20 moves a 20 decimal into ax, where it
is stored as 0014. It is okay to think of ax as containing 20
decimal until you have to perform register arithmetic, for
example, add ah, 1 will make ax contain 114h.
The nature of arithmetic changes remarkably within a computer. For
example, consider real numbers. What is the "next" real number after
1.5? 1.505 comes after 1.5, but there are an infinite number of
numbers between 1.5 and 1.505. There are an infinite more real
numbers than integers. In the computer however, there's always a
next number, since the computer can only store a finite amount of
information.
Review of the test
(1) Assume you have the following data segment:
.data
array_x dw 15h, 25h
array_y dw 20h, 45h
What will ax equal after the following instructions have executed?
mov ax,array_x ; ax = 0015
inc ax ; ax = 0016
mov ax,array_x+2 ; ax = 0025
add ah, 1 ; ax = 0125
sub ax, array_y ; ax = 0105
(2)This is another program to trace. Trace the segment until it
is finished looping. What will ax, bx and cx equal at each
step?
ax bx cx
mov ax, 20 ; 0014
mov bx, 0 ; 0000
mov cx, 3 ; 0003
again: add bx, ax ; 0014
dec ax ; 0013
loop again ; 0002
; add bx, ax ; 0027
; dec ax ; 0012
; loop again ; 0001
; add bx, ax ; 0039
; dec ax ; 0011
; loop again ; 0000
(3) In this question assume you have the following data segment:
.data
array_z dw 250,-100,318,495,9,32,-89,640
(a) Write a program segment to sum all eight numbers in this array
(note that the numbers in array_z might change so your program
must sum whatever numbers are there). When you finish the sum
should be in ax. Your first instruction should be mov ax,0.
mov ax, 0
add ax, array_z ; direct
add ax, array_z+2 ; direct with offset
add ax, array_z+4
add ax, array_z+6
add ax, array_z+8
add ax, array_z+10
add ax, array_z+12
add ax, array_z+14
; or you could've done this:
mov cx, 8
xor ax, ax
mov si, offset array_z
adder: add ax, [si] ; indirect
inc si
inc si ; must add 2 because it's a word
loop adder
(b) Now suppose you want to sum up every other number in the array.
That is, you want to sum the first number, the third number, and the
fifth number, and the seventh number in this array.
Write the program segment you would use to do this. Your first
instruction should be mov ax, 0.
mov ax, 0
add ax, array_z
add ax, array_z+4
add ax, array_z+8
add ax, array_z+12
; or:
mov cx, 4
xor ax, ax
mov si, offset array_z
adder: add ax, [si] ; indirect
add si, 4
loop adder
(4) In this question assume you have the following data segment:
.data
value1 dw 250
value2 dw ?
value3 dw ?
value4 dw ?
Suppose you have a main program which contains the following
instructions.
call copy_it
Subroutine copy_it is to copy value1 into variables value2,
value3, and value4. Write the complete subroutine called copy_it.
(If you use any registers in your subroutine remember to
save them at the beginning and restore them at the end.)
copy_it proc
push ax
mov ax, value1
mov value2, ax
mov value3, ax
mov value4, ax
pop ax
return
end copy_it
(5) In this question you will be using DOS function calls. Write a
program segment which first prints a message to the screen asking the
user to type a single letter (y or n) and then reads in whatever
letter the user has typed. Also declare any variables in the data
segment that you will use.
.data
mess db "type a (Y or N)", 0ah, 0dh, "$"
char db ?
.code
; the usual startup stuff...
mov ah, 9
mov dx, offset mess
int 21h
mov ah, 0Ch ; It is necessary to clear the keyboard buffer first
; or spurious characters may be accepted instead.
mov al, 1
int 21h
mov char, al
-----------------------------------------------------------------------
Extra stuff about question (3)(a)
xor means (a or b) and not (a and b) ("a or b but not both")
a b a or b a and b a or b and not (a and b)
a|b a&b (a|b)&(~(a&b))
0 0 0 0 0
0 1 1 0 1
1 0 1 0 1
1 1 1 1 0
The direct addressing shown probably executes twice as fast.
Here's a bad way of doing it.
add ax,array_z
loc1: add byte ptr loc1-2,2 ; adds 2 to the offset byte of
; previous instruction
Extra stuff about (4)
To make this subroutine more generic, if you called it like
this:
mov si, offset value1
call copy_it
it could read like this:
copy_it proc
push ax
mov ax, [si]
mov [si+2], ax
mov [si+4], ax
mov [si+6], ax
pop ax
return
end copy_it
You call a subroutine by saying
call sub1
where sub1 is the subroutine name.
This gives control to the subroutine, and loads the stack with
the return address -- the instruction immediately following the call.
Call pushes the return address onto stack (push ip); inside the
subroutine, the return instruction will automatically pop this
address off the stack and load it into ip (pop ip).
Therefore, if you fail to do the same number of pops as pushes within
the subroutine, you will not return to the correct location afterwards.
Making a subroutine.
------------------------------------------------------------------------
Review of questions at end of chapter 3.
(1) b - al is 8 bits, var2 is 8 bits
c - unmatched sizes
d - unmatched sizes
h - cannot modify cs
i - cannot modify ip
k - memory to memory
l - can't move immediate value to ds
m - can't move from 1 segment register to another segment
register
(3) Link time
(4) Relocatable. Means your code could be loaded any place in
memory.
(5) BX, BP
(6) a - register, immediate
b - register, direct
c - register, immediate
d - register, indirect
(7) Tell the assembler how big the memory segment is that will put
the value in -- what kind of add to do.
(8) a - no
b - probably not
c - yes
d - yes
e - no
(9) second line: al s/be ax
fourth line: [bl] s/be [bx]
fifth s/be add byte ptr [bx], 2
six needs comma
inc word ptr dx, the word ptr is not necessary
inc [cx] is not allowed