Sie sind auf Seite 1von 25

A small program that calculates and prints terms of the Fibonacci series

; fibo.asm
; assemble using nasm:
; nasm -o fibo.com -f bin fibo.asm
;
;****************************************************************************
; Alterable Constant
;****************************************************************************
; You can adjust this upward but the upper limit is around 150000 terms.
; the limitation is due to the fact that we can only address 64K of memory
; in a DOS com file, and the program is about 211 bytes long and the
; address space starts at 100h. So that leaves roughly 65000 bytes to
; be shared by the two terms (num1 and num2 at the end of this file). Since
; they're of equal size, that's about 32500 bytes each, and the 150000th
; term of the Fibonacci sequence is 31349 digits long.
;
maxTerms

equ 15000

; number of terms of the series to calculate

;****************************************************************************
; Number digits to use. This is based on a little bit of tricky math.
; One way to calculate F(n) (i.e. the nth term of the Fibonacci seeries)
; is to use the equation int(phi^n/sqrt(5)) where ^ means exponentiation
; and phi = (1 + sqrt(5))/2, the "golden number" which is a constant about
; equal to 1.618. To get the number of decimal digits, we just take the
; base ten log of this number. We can very easily see how to get the
; base phi log of F(n) -- it's just n*lp(phi)+lp(sqrt(5)), where lp means
; a base phi log. To get the base ten log of this we just divide by the
; base ten log of phi. If we work through all that math, we get:
;
; digits = terms * log(phi) + log(sqrt(5))/log(phi)
;

; the constants below are slightly high to assure that we always have
; enough room. As mentioned above the 150000th term has 31349 digits,
; but this formula gives 31351. Not too much waste there, but I'd be
; a little concerned about the stack!
;
digits

equ (maxTerms*209+1673)/1000

; this is just the number of digits for the term counter


cntDigits equ 6

org

100h

; number of digits for counter

; this is a DOS com file

;****************************************************************************
;****************************************************************************
main:
; initializes the two numbers and the counter. Note that this assumes
; that the counter and num1 and num2 areas are contiguous!
;
mov

ax,'00'

; initialize to all ASCII zeroes

mov

di,counter

; including the counter

mov

cx,digits+cntDigits/2

cld

; two bytes at a time

; initialize from low to high memory

rep

stosw

; write the data

inc

ax

; make sure ASCII zero is in al

mov

[num1 + digits - 1],al ; last digit is one

mov

[num2 + digits - 1],al ;

mov

[counter + cntDigits - 1],al

jmp

.bottom

.top
; add num1 to num2
mov

di,num1+digits-1

; done with initialization, so begin

mov

si,num2+digits-1

mov

cx,digits

call

AddNumbers; num2 += num1

mov

bp,num2

call

PrintLine

dec

dword [term]

jz

.done

;
;
; decrement loop counter

; add num2 to num1


mov

di,num2+digits-1

mov

si,num1+digits-1

mov

cx,digits

call

AddNumbers; num1 += num2

.bottom
mov

bp,num1

call

PrintLine

dec

dword [term]

jnz

.top

call

CRLF

; finish off with CRLF

mov

ax,4c00h

; terminate

int

21h

;
; decrement loop counter

.done

;****************************************************************************
;
; PrintLine
; prints a single line of output containing one term of the
; Fibonacci sequence. The first few lines look like this:
;
; Fibonacci(1): 1
; Fibonacci(2): 1

; Fibonacci(3): 2
; Fibonacci(4): 3
;
; INPUT:
; OUTPUT:

ds:bp ==> number string, cx = max string length


CF set on error, AX = error code if carry set

; DESTROYED: ax, bx, cx, dx, di


;
;****************************************************************************
PrintLine:
mov

dx,eol

; print combined CRLF and msg1

mov

cx,msg1len+eollen ;

call

PrintString

mov

di,counter

; print counter

mov

cx,cntDigits ;

call

PrintNumericString

call

IncrementCount

; also increment the counter

mov

dx,msg2

; print msg2

mov

cx,msg2len ;

call

PrintString

mov

di,bp

; recall address of number

mov

cx,digits

; deliberately fall through to PrintNumericString

;****************************************************************************
;
; PrintNumericString
; prints the numeric string at DS:DI, suppressing leading zeroes
; max length is CX

;
; INPUT:

ds:di ==> number string, cx = max string length

; OUTPUT:

CF set on error, AX = error code if carry set

; DESTROYED: ax, bx, cx, dx, di


;
;****************************************************************************
PrintNumericString:
; first scan for the first non-zero byte
mov

al,'0'

cld

; look for ASCII zero


; scan from MSD to LSD

repe

scasb

mov

dx,di

; points to one byte after

dec

dx

; back up one character

inc

cx

; deliberately fall through to PrintString

;****************************************************************************
;
; PrintString
; prints the string at DS:DX with length CX to stdout
;
; INPUT:

ds:dx ==> string, cx = string length

; OUTPUT:

CF set on error, AX = error code if carry set

; DESTROYED: ax, bx
;
;****************************************************************************
PrintString:
mov
mov
int
ret

bx, 1

; write to stdout

ah, 040h
21h

; write to file handle


; ignore return value
;

;****************************************************************************
;
; AddNumbers
; add number 2 at ds:si to number 1 at es:di of width cx
;
;
; INPUT:

es:di ==> number1, ds:si ==> number2, cx= max width

; OUTPUT:

CF set on overflow

; DESTROYED: ax, si, di


;
;****************************************************************************
AddNumbers:
std

; go from LSB to MSB

clc

pushf

; save carry flag

.top
mov

ax,0f0fh

; convert from ASCII BCD to BCD

and

al,[si]

; get next digit of number2 in al

and

ah,[di]

; get next digit of number1 in ah

popf
adc

; recall carry flag


al,ah

; add these digits

aaa

; convert to BCD

pushf

add

al,'0'

stosb

; convert back to ASCII BCD digit


; save it and increment both counters

dec

si

loop

.top

; keep going until we've got them all

popf

; recall carry flag

ret

;****************************************************************************
;

; IncrementCount
; increments a multidigit term counter by one
;
; INPUT:

none

; OUTPUT:

CF set on overflow

; DESTROYED: ax, cx, di


;
;****************************************************************************
IncrementCount:
mov

cx,cntDigits ;

mov

di,counter+cntDigits-1

std

; go from LSB to MSB

stc

; this is our increment

pushf

; save carry flag

.top
mov

ax,000fh

; convert from ASCII BCD to BCD

and

al,[di]

; get next digit of counter in al

popf
adc

; recall carry flag


al,ah

; add these digits

aaa

; convert to BCD

pushf

add

al,'0'

stosb
loop

; convert back to ASCII BCD digit


; save and increment counter

.top

popf

; recall carry flag

ret

;****************************************************************************
;
; CRLF
; prints carriage return, line feed pair to stdout
;

; INPUT:

none

; OUTPUT:

CF set on error, AX = error code if carry set

; DESTROYED: ax, bx, cx, dx


;
;****************************************************************************
CRLF: mov

dx,eol

mov

cx,eollen

jmp

PrintString

;****************************************************************************
; static data
;****************************************************************************
eol

db 13,10

; DOS-style end of line

eollen equ $ - eol

msg1 db 'Fibonacci('
msg1len

equ $ - msg1

msg2 db '): '


msg2len

equ $ - msg2

;****************************************************************************
; initialized data
;****************************************************************************
term dd maxTerms

;****************************************************************************
; unallocated data
;
; A better way to do this would be to actually ask for a memory
; allocation and use that memory space, but this is a DOS COM file
; and so we are given the entire 64K of space. Technically, this
; could fail since we *might* be running on a machine which doesn't
; have 64K free. If you're running on such a memory poor machine,

; my advice would be to not run this program.


;
;****************************************************************************
; static data
counter:

num1 equ counter+cntDigits

num2 equ num1+digits

Alarm

cseg segment para public 'code'


org

100h

alarm proc far

; Memory-resident program to intercept the timer interrupt and display the


; system time in the upper right-hand corner of the display.
; This program is run as 'ALARM hh:mm x', where hh:mm is the alarm time and
; x is '-' to turn the display off. Any other value of x or no value will
; turn the clock on

intaddr equ 1ch*4

; interrupt address

segaddr equ 62h*4

; segment address of first copy

mfactor equ 17478

; minute conversion factor * 16

whozat

equ 1234h

color equ 14h

; signature
; color attribute

assume cs:cseg,ds:cseg,ss:nothing,es:nothing
jmp p150

; start-up code

jumpval dd 0

; address of prior interrupt

signature dw whozat

; program signature

state db 0

; '-' = off, all else = on

wait

dw 18

; wait time - 1 second or 18 ticks

hour dw 0

; hour of the day

atime dw 0ffffh

; minutes past midnite for alarm

acount

dw 0

atone db 5

; alarm beep counter - number of seconds (5)


; alarm tone - may be from 1 to 255 - the
; higher the number, the lower the frequency

aleng dw 8080h

dhours

dw 0

; alarm length (loop count) may be from 1-FFFF

; display hours

db ':'
dmins dw 0

; display minutes

db ':'
dsecs dw 0

; display seconds

db '-'
ampmdb 0

; 'A' or 'P' for am or pm

db 'm'

tstack db 16 dup('stack ') ; temporary stack


estack

db 0

; end of stack

holdsp

dw 0

; original sp

holdssdw 0

; original ss

p000:

; interrupt code
push ax

; save registers

push ds
pushf

push cs
pop ds
mov ax,wait
dec ax
jz p010

; make ds=cs
; check wait time
; zero?
; yes - 1 second has elapsed

mov wait,ax

; not this time

jmp p080

; return

p010: cli
mov ax,ss

; disable interrupts
; save stack

mov holdss,ax
mov holdsp,sp
mov ax,ds
mov ss,ax

; point to internal stack

mov sp,offset estack


sti

; allow interrupts

push bx

; save other registers

push cx
push dx
push es
push si
push di
push bp

mov ax,18

; reset wait time

mov wait,ax

mov al,state

; are we disabled?

cmp al,'-'
jnz p015

; no

jmp p070

p015: mov ah,0

; read time

int 1ah

; get time of day

mov ax,dx

; low part

mov dx,cx

; high part

mov cl,4
shl dx,cl

; multiply by 16

mov bx,ax
mov cl,12
shr bx,cl

; isolate top 4 bits of ax

add dx,bx

; now in upper

mov cl,4
shl ax,cl

; multiply by 16

mov bx,mfactor
div bx

; compute minutes
; minutes in ax, remainder in dx

cmp ax,atime

; time to sound the alarm?

jnz p020

; no

call p100

; yes - beep the speaker twice

push ax
mov ax,acount

; get beep count

dec ax

; down by 1

mov acount,ax

; save beep count

cmp ax,0

; is it zero?

jnz p018

; no - keep alarm on

mov ax,0ffffh

; turn off alarm

mov atime,ax
p018: pop ax

p020: mov dsecs,dx

; save remainder

mov bx,60

; compute hours

xor dx,dx

; zero it

div bx

; hours in ax, minutes in dx

mov dmins,dx

; save minutes

cmp ax,0

; midnight?

jnz p030

; no

mov ax,12

; yes

jmp p040a

p030: cmp ax,12

; set am

; before noon?

jb p040a

; yes - set am

jz p040p

; noon - set pm

sub ax,12

; convert the rest

p040p:

mov bl,'p'

jmp p040x

p040a:

mov bl,'a'

p040x:

mov ampm,bl

aam

; fix up hour

cmp ax,hour

; top of the hour?

jz p060

; no

mov hour,ax
call p120

p060: add ax,3030h

; beep the speaker once

; convert hours to ascii

xchg ah,al
mov dhours,ax

mov ax,dmins

; get minutes

aam
add ax,3030h

; convert to ascii

xchg ah,al
mov dmins,ax

mov ax,dsecs
xor dx,dx
mov bx,60

; get seconds (remainder)

mul bx
mov bx,mfactor
div bx

; seconds in ax

aam
add ax,3030h
xchg ah,al
mov dsecs,ax

xor ax,ax

; check monitor type

mov es,ax
mov ax,es:[410h]

; get config byte

and al,30h

; isolate monitor type

cmp al,30h

; color?

mov ax,0b000h
jz p061

; assume mono
; its mono

mov ax,0b800h

; color screen address

p061: mov dx,es:[463h] ; point to 6845 base port


add dx,6

; point to status port

mov es,ax

; point to monitor

mov bh,color

; color in bh

mov si,offset dhours

; point to time

mov di,138

; row 1, col 69

cld
mov cx,11

; loop count

p062: mov bl,[si]

; get next character

p063: in al,dx

; get crt status

test al,1

; is it low?

jnz p063

; no - wait

cli

; no interrupts

p064: in al,dx

; get crt status

test al,1

; is it high?

jz p064

; no - wait

mov ax,bx

; move color & character

stosw

; move color & character again

sti

; interrupts back on

inc si

; point to next character

loop p062

; done?

p070: pop bp

; restore registers

pop di
pop si
pop es
pop dx
pop cx
pop bx
cli

; no interrupts

mov ax,holdss
mov ss,ax
mov sp,holdsp
sti

; allow interrupts

p080: popf
pop ds
pop ax
jmp cs:[jumpval]

p100 proc near

; beep the speaker twice

call p120
push cx
mov cx,20000
p105: loop p105

; wait around

pop cx
call p120
push cx
mov cx,20000
p106: loop p106

; wait around

pop cx
call p120
ret
p100 endp

p120 proc near

; beep the speaker once

push ax
push cx
mov al,182
out 43h,al

; setup for sound

mov al,0
out 42h,al
mov al,atone
out 42h,al

; low part
; get alarm tone
; high part

in al,61h
push ax

; save port value

or al,3
out 61h,al
mov cx,aleng
p125: loop p125
pop ax
out 61h,al
pop cx

; turn speaker on
; get loop count
; wait around
; restore original port value
; turn speaker off

pop ax
ret
p120 endp

p150:

; start of transient code


mov dx,offset copyr
call p220

; print copyright

mov ax,0
mov es,ax

; segment 0

mov di,segaddr+2 ; this program's prior location


mov ax,es:[di]
mov es,ax

; get prior code segment


; point to prior program segment

mov di,offset signature


mov cx,es:[di]

; is it this program?

cmp cx,whozat
jnz p160

; no - install it

call p200

; set state & alarm

int 20h

; terminate

p160: mov di,segaddr+2 ; point to int 62h


mov ax,0
mov es,ax

; segment 0

mov ax,ds

; get current ds

mov es:[di],ax

; set int 62h

mov si,offset jumpval


mov di,intaddr

; point to timer interrupt

mov bx,es:[di]

; get timer ip

mov ax,es:[di+2]

; and cs

mov [si],bx

; save prior ip

mov [si+2],ax
mov bx,offset p000
mov ax,ds

; and cs

cli

; clear interrupts

mov es:[di],bx

; set new timer interrupt

mov es:[di+2],ax
sti

; set interrupts

push ds
pop es
call p200

; set state & alarm

mov dx,offset p150; last byte of resident portion


inc dx
int 27h

p200 proc near


mov si,80h

; terminate

; set state & alarm


; point to command line

mov ax,0
mov di,0ffffh

; init hours

mov bh,0
mov ch,0
mov dh,0

; : counter

mov es:[state],bh ; turn clock on


mov cl,[si]

; get length

jcxz p210

; it's zero

p203: inc si
mov bl,[si]
cmp bl,'-'

; point to next char


; get it
; is it a minus?

jnz p204

; no

mov es:[state],bl

; turn clock off

push dx
mov dx,offset msg3
call p220
pop dx
jmp p206

; print msg

p204: cmp dh,2


jz p206

; seen 2nd colon?


; yes - ignore seconds

cmp bl,':'

; colon?

jnz p205

; no

inc dh
cmp dh,2

; second colon?

jz p206

; yes - ignore seconds

push cx
push dx
mov cx,60
mul cx

; multiply current ax by 60

pop dx
pop cx
mov di,ax

; save hours

mov ax,0
jmp p206
p205: cmp bl,'0'
jb p206

; too low

cmp bl,'9'
ja p206
sub bl,'0'

; too high - can be a problem


; convert it to binary

push cx
push dx
mov cx,10
mul cx
add ax,bx

; multiply current value by 10


; and add latest digit

pop dx
pop cx
p206: loop p203

; done yet?

cmp di,0ffffh

; any time to set?

jz p210

; no

add ax,di

; add hours

cmp ax,24*60
jb p209

; ok

mov dx,offset msg1

; print error message

call p220
jmp p210

p209: mov es:[atime],ax ; save minutes past midnight


mov ax,5
mov es:[acount],ax ; set alarm count
mov dx,offset msg2

; print set msg

call p220
p210: ret
p200 endp

p220 proc near

; print message

push ax
mov ah,9
int 21h
pop ax
ret
p220 endp

copyr db 'Alarm - Clock',10,13,'$'


msg1 db 'Invalid time - must be from 00:00 to 23:59',10,13,'$'
msg2 db 'Resetting alarm time',10,13,'$'
msg3 db 'Turning clock display off',10,13,'$'

alarm endp
cseg ends
end

alarm

8086 microprocessor assembly language programs


Write a Program For Read a Character From The Keyboard
MOV
INT

ah,

1h

//keyboard
//

21h

//
MOV c, al

character
is
//copy character from alto c

input
character

subprogram
input

in

al

stored

Write a Program For Reading and Displaying a Character


MOV

ah,

1h

//

INT
MOV

21h
dl,

MOV
INT 21h

ah,
2h
// display character in dl

keyboard

//read
//copy

al

input

character
character

//character

subprogram
into
to

output

al
dl

subprogram

Write a Program Using General Purpose Registers


ORG

100h

MOV
LEA

AL, VAR1
BX,
VAR1

MOV
MOV

BYTE
PTR
AL, VAR1

//

check

value
//get

of

[BX],
44h
//
//check value

RET
VAR1

VAR1
address

modify
of VAR1

by

moving it
of
VAR1

the
contents
by moving it

to

the
in

AL.
BX.

of
VAR1.
to the AL.

DB

22h

END
Write a Program For Displaying The String Using Library Functions
include
ORG

emu8086.inc

//Macro

PRINT
GOTOXY
PUTC
PUTC
RET
END

declaration
100h

Hello
10,
65

//

65

//return
//directive to stop the compiler.

World!
5
is
to

an

ASCII
the

code

operating

for

A
B

system.

Arithmetic and Logic Instructions


The 8086 processes of arithmetic and logic unit has separated into three groups such as
addition, division, and increment operation. Most Arithmetic and Logic Instructions affect the
processor status register.
The assembly language programming 8086 mnemonics are in the form of op-code, such as
MOV, MUL, JMP, and so on, which are used to perform the operations. Assembly language
programming 8086 examples

Addition
ORG0000h
MOV DX, #07H

// move the value 7 to the register AX//

MOV AX, #09H


Add AX, 00H

// move the value 9 to accumulator AX//


// add CX value with R0 value and stores the result in AX//

END
Multiplication
ORG0000h
MOV DX, #04H

// move the value 4 to the register DX//

MOV AX, #08H


MUL AX, 06H

// move the value 8 to accumulator AX//


// Multiplied result is stored in the Accumulator AX //

END
Subtraction
ORG 0000h
MOV DX, #02H

// move the value 2 to register DX//

MOV AX, #08H


SUBB AX, 09H

// move the value 8 to accumulator AX//


// Result value is stored in the Accumulator A X//

END
Division
ORG 0000h
MOV DX, #08H

// move the value 3 to register DX//

MOV AX, #19H // move the value 5 to accumulator AX//


DIV AX, 08H // final value is stored in the Accumulator AX //
END

Example programs

Character transmission using a time delay

A program shown below takes the character in 'A' register, transmits it, delays for transmission time, and returns to the calling
program. Timer-1 is used to set the baud rate, which is 1200 baud in this program
The delay for one character transmission (in Mode 1 i.e.10 bits) is

10/2400
Or, 8.33 milliseconds

0.00833

Hence
software
delay
of
10ms
Timer-1 generates a baud rate close to 1200. Using a 12MHz crystal, the reload value is

Or, 230 i.e. E6H

seconds

is

used.

This
gives
rise
SMOD is programmed to be 0.

to

an

actual

baud

rate

of

1202.

Assembly language Program is as follows

; Code to wait for the transmission to complete


The subroutine TRMITTIME generates a delay of about 10ms. With a clock of 12MHz, one instruction cycle time is

The loop "MILSEC" generates a delay of about 1 x 10-3 sec. This gets executed 10 times for a total delay of 10 x 10-3 sec or 10ms

Interrupt driven character transmission

In 8051, when a character is transmitted, SBUF register becomes empty and this generates a serial port interrupt (TI). TI and RI
both point to the vector location 0023H in the program memory. An interrupt service routine can be written at 0023H to send the nex

character.

A program is written here to transmit a character say 'A' continuously based on interrupt. The microcontroller uses a clock of 12MHz
with a baud rate of 1202. The program is executed following a hardware reset.

Assembly language program is as follows.

Interrupt driven data reception

When a character is received, if receive mode is enabled, RI flag is set. This leads to the interruption of the main program and the
processor goes to the interrupt vector location, i.e. 0023H for serial port. The interrupt service routine at 0023H gets executed to
read the character so that the next character can be received. The following program receives a character on interrupt basis and
outputs the character to port-1, possibly for a display.
The crystal frequency is12MHz and baud rate is set at 1202 baud.

Assembly language program is as follows

Das könnte Ihnen auch gefallen