Discussion of code handout.
The code in the handout does the upper right-hand corner of the
display in a black line with a blue background. You will have to
change the code so that the background is the same as the rest of
the screen (black).
-------------------- the handout (with extra comments) -------------------
title template.asm
.model small
.stack 100h
.data
x db 20
x1 db 20
y1 db 10
ul db 0dah ; upper left é
ur db 0bfh ; upper right ù
ll db 0c0h ; lower left ë
lr db 0d9h ; lower right û
lhine db 0c4h ; horizontal line ¾
vl db 0b3h ; vertical line ½
.code
main proc
mov ax, @data
mov ds, ax
call sercursorpos ; puts cursor at x=20, y=10
; could instead move into dh and dl coordinates
; for cursor position -- this would probably
; be better design. Shown as it is so you can
; see the complete sequence required to set the
; cursor's position.
call writeline
call setcursorpos
mov al, ul ; upper left
call displchar
; now we have upper left corner and top line.
vertline:
mov cx, 10 ; line will be 10 characters high
inc y1 ; start at next line, otherwise we'd write
; over upper left corner character
l1: call setcursorpos ; will move the cursor to new position
; indicated by x1 (unchanged) and y1: 20, 11
mov al, vl ; set character to display -- vert. line
call displchar ; display the character
inc y1 ; down to next line
loop l1
; here you would add code to reset x1 and y1 to original values
; then set x1 to the righthand side and make another
; vertical line in the right side.
mov ax, 4c00h
int 21h
setcursorpos proc
mov ah, 2
mov dh, y1 ; row 10 'y'
mov dl, x1 ; col 20 'x'
; upper left corner is 0, 0
mov bh, 0 ; video page 0
int 10h ; bios call which is a different kind of a call
; than a dos call. See notes below
ret
setcursorpos endp
displchar proc
push cx
mov ah, 09h
mov bh, 0
mov bl, 10h
mov cx, 1 ; only display the character once!
int 10h
pop cx
ret
displchar endp
writeline proc
mov ah, 9 ; write char and attribute
mov al, 0c4h ; write a line (ascii long dash) ; could've used hline
mov bh, 0 ; video page 0
mov bl, 10h ; blue background, black char
; sets blinking/nonblink, background, foreground
mov cx, 30 ; write 30 long dashes starting where cursor is set
; number in cx causes bios call to loop
int 10h ; call bios
ret
writeline endp
-------------------------------------------------------------------
Works by :
putting cursor in upper left corner
write horizontal line
move back to the starting place
put in corner character
put in vertical line characters
(displays black line in blue background)
Bios calls:
There are 3 levels on which you can do input/output:
- dos calls (slowest, simplest)
- bios calls (faster)
- direct (fastest, most complex) - used for most graphics and
complex video, like Windows.
See page 126
The 10h bios call sets
first byte:
1st bit sets blink/nonblink: 0 indicates nonblink
bits 2-4 indicate background color: 001 means blue
red would be 100
bits 4-8 indicate foreground color
therefore 10h gives you non-blinking blue background (1h=0001b)
with black characters (0h = 0000b)
90h would give you blinking blue background with black characters
You could store the height and width in variables so that
the box could be of a particular size in a particular location.
See the assignment entitled "seventh laboratory assignment" for
additional tasks to add the labels and input lines.
-------------------------------------------------------------------
You could change the background color of the entire screen by calling
0bh (see pages 127 and 577).
-------------------------------------------------------------------
We could have a quiz next week.
The final (which is open book) is December 21st; there will be some
review on December 14th, which is the last day of class.
-------------------------------------------------------------------
Disassemblers will show you the assembler of compiled source
code; you can usually find advertisements for them in the back
pages of Dr. Dobbs, many of which will also put in variable names
and some comments.
It is very hard to disassemble PC code by visually inspecting it
because the instructions are of variable length.
-------------------------------------------------------------------
Page 113: Nested procedure calls
main proc
000A call sub1 ; stack gets copy of return address
000C mov ax...
main endp
sub1 proc
0050 call sub2 ; stack gets copy of return address, already has 000C
; now also has 0052
...
ret
sub1 endp
sub2 proc
0060 call sub3 ; stack is now 000C 0052 0062
...
ret
sub2 endp
sub3 proc
...
ret
sub3 endp
These are referred to as nested procedure calls.
Each time you return, another address is popped off to get you
back. Should the stack reference be messed up by not having the
appropriate # of pushes & pops, you would not go all the way or
enough of the way back to where you came from.
-------------------------------------------------------------------
2 kinds of interrupts:
Machine interrupt -- Takes priority over most other things.
There are 2 kinds of machine interrupts.
Maskable -- you can delay paying attention to it later.
STI -- enable interrupt
CLI -- disable interrupt
Non-maskable (NMI - non-maskable interrupt) -- A special pin
on the CPU creates this
Software interrupt -- Int ### -- not really an interrupt -- it's
a particular kind of subroutine call
When an interrupt occurs, the CPU clears the IF to prevent all other
interrupts from interfering with the ISR. The IF is the Interrupt
Flag (Flags register); the ISR is the Interrupt Service Routine.
Int n -- called a synchronous interrupt, it accesses the Interrupt
Vector Table (IVT). The n Tells CPU which entry to locate
in the IVT.
The Interrupt Handler (a DOS or BIOS function) begins execution
and finishes when the IRET instruction ("interrupt return") is
reached. This causes the program to resume at the next instruction
in the original calling program.
There are a number of Interrupt Service Routines:
INT 10h -- video services
INT 16h -- keyboard services
INT 17h -- printer
INT 1Ch -- timer
INT 21h -- DOS
Make sure to read all this material in the book. Try out some
of the code to see experience the way it works.
-------------------------------------------------------------------
Local labels (this is not in the book!)
Requires LOCALS in your code segment.
For example:
.code
...
LOCALS
@@10: INC AX
CMP AX, 10
JNE @@10 ; goes line of code above that says INC AX
THERE: CMP AX, 20
JNE @@10 ; sends you 2 lines down to line after XOR CX, CX
XOR CX, CX
@@10: ...
Same label in 2 places. Each time you have a new occurrance of the
same label, the previous one loses its definition.
Local labels are distinguished by the two @ followed by up to 255
other characters (special setting for variable length required if
more than 31 characters long.
-------------------------------------------------------------------
Redirecting Input/Output
C:\> prg1 > prn
Invokes prg1.exe, redirecting output to printer.
C:\> prg1 < A:\INFILE
Redirects input to come from a:\infile instead of keyboard.
C:\> prg1 < A:\INFILE > PRN
Redirect both input & output at once.
C:\> prg1 < A:\INFILE > A:\OUTFILE
Read material & code about INT 21h
-------------------------------------------------------------------
Flags are set by instructions such as ADD, SUB, INT, LOOP.
Most commonly, you would set flags by using CMP.
For example
CMP AX, MEM
JNE ; if AX <> MEM then do the jump
CMP has some special register that gets the value of AX-MEM. Does
subtraction without affecting either operand; result is thrown away
and flags are set.
CMP Compare instruction sets the flags as follows:
If destination < Source, CF (Carry Flag) = 1
If destination = source, ZF (Zero flag) = 1
if destination > source, CF (Carry Flag) = 0, ZF (Zero flag) = 0
JZ ; will jump if ZF = 1.
JE ; will jump if CMP dest, source ; if dest, source are equal
JNZ ; zero flag = 0
JNE ;
JA ; if dest > source ; same as JNBE
JNBE ; not below and not equal ; same as JA
Can use these instructions after any instruction that sets the
flag register.
Read all about these in chapter 6.
-------------------------------------------------------------------
Pascal code: sum := 0;
for i := 1 to 10 do
inc(sum,i);
In assembler, this could be done with a LOOP or JMP instruction.
; let i be in register BX
; let sum be in register AX
XOR AX, AX ; sum := 0 (set AX (sum) to 0).
MOV BX, 1 ; set BX (i) to 1.
for: CMP BX, 10 ; check for limit of for loop
JGE outofloop ; jump if BX greater than or equal to 10
; (exit loop if finished)
; BX not >= 10
ADD AX, BX ; Inc(sum, i) (Increment loop counter i)
INC BX
JMP for ; Loop (repeat loop)
outofloop: ...
Pascal loop types C
for for
while..do while
repeat..until do.. while
Pascal code:
while (i < n) do begin
Inc(sum, i);
Inc(i)
end;
in assembler: ; using memory "just for fun"
MOV AX, i
test: CMP AX, n
JL while
JMP out
while: ADD SUM, AX
INC AX
JMP test
out: ...