programmers resources  (c)2019
Search :  
Lingua Italiana    English Language   
just an empty assembly space
just an arrow Intel Platform
just an arrow Article & Guides
just an arrow Download Software

23/01/2009 Featured Article: How to remove Buzus Virus (permalink)

Bottone Scambio Directory
Home Page | Articles & Guides | Download | Intel Platform | Contacts


Bookmark and Share
Tell a friend

Make sound from the speaker using assembly

8253, 8255, 8284 program example in asm

(by william cravener)

A well commented document that showes a practical example of how to program the Timer 8253 (which uses the 8284 oscillator) and the 8255 PPI programmable peripheral interface. The code will generate sound from the speaker and the code is a very good lesson on using IN and OUT instructions.
This article is online from 3378 days and has been seen 37434 times

!          The - INs ORs ANDs OUTs - of creating sound on the IBM PC         !
!                                                                            !
!        by  William Cravener  520 N. Stateline Rd.  Sharon, Pa. 16146       !
!                                                                            !
!         -Swift-Ware->      Copyright 1991-93       CIS: 72230,1306        

        There are two important electronic chips involved in creating sound 
on the IBM PC - the 8253 timer chip (channel 2 of this chip is connected to 
the speaker),  and the 8255 peripheral interface chip  (it appears regardless
of what peripheral interface chip is used in any particular machine, the same
port address and bit assignments are used).  The pulse rate of each chip can
be altered,  and by combining the actions of the two chips it is possible to
produce special sound effects.

        To make sounds on the IBM PC you must actually turn ON and OFF an
electronic "gate" (which is a kind of toggle switch).  Each time we toggle the 
"gate" ON and OFF again, we create a pulse: a brief period when current flows 
in a circuit (look at the example below).  These pulses are amplified and sent 
to the speaker, where they make a sound.  This "gate" is turned ON and OFF 
with the assembly OUT instruction.

       |     |
 +     +-----+     +-----+     +-----+
       !     !     !     !     !     !
 0 ----+     +-----+     +-----+     +----  <-- Wave form sent to the Speaker
       |     |
       |   "gate"
       |    is turned OFF here
      is turned ON here

        The faster we send the pulses, the higher the pitch of the sound. We 
can control how fast we send the pulses by putting a delay loop into our
program.  We then turn the "gate" ON, delay, turn the "gate" OFF, delay, and 
so on and so on. The assembly LOOP instruction is used to cause the delay that
we will need for our example sound program.

        But, before we go on to the example program lets talk a little about 
addressing the PORTs (I/O Ports).  Ports are something like registers, in
that you can send 8-bit or 16-bit data to them. This is always accomplished
using the AL or AX register, you can also read the port contents back into 
the AL or AX register. The big difference between ports and registers is that
ports can be connected to devices either inside or outside of your computer.

        How then, do you access these I/O Ports???    Well, its not that 
difficult once you acquire a little understanding about how to send information 
to these ports using a few very simple assembly language instructions.

        The two most important instructions you will be using are the assembly
IN and OUT instructions. The IN instruction places a byte of information into
the AL or AX register, the OUT instruction copies a byte or word of information
from the AL or AX register. 

The instruction that turns our "gate" ON and OFF is:

OUT     61H, AL    

This instruction copies the contents of the AL register to the port 61H.

        This port addresses the 8255 or equivalent programmable peripheral
interface chip or PPI.  The PPI is used to control the keyboard, the speaker
and the computer configuration settings.

        OUT is very much like the assembly MOV instruction, but instead of
moving information to a register we copy it from a register to a port address
as in the above example (port address 61H).

        Now in the case of creating sound we need to be concerned with two of
the 8-bits we send to port address 61H.  These are the bits numbered 0 and 1.
               8-bit number -->  11111111
The two we are interested in ->  111111XX
(marked as X's)                        ||___ bit number 0
                                       |____ bit number 1

        In order to change bits 0 and 1 (without changing the other 6 bits),
we need to find out how all the bits are initially set.  This is easily done 
by using the assembly IN instruction to retreive this value. Once we know how
all 8-bits are initially set, we can change the first two (0 and 1) then copy
the value back to the port address 61H.

IN      AL, 61H    

This instruction copies the current 8-bit value of port 61H to the AL register.

        Once we have this 8-bit value we need to change bits 0 and 1 so we
can send the changed ON or OFF value back OUT to our port address.  This is a
two part procedure, first we wish to turn the speaker ON so we OR the 8-bit
value with a value of our own that will not change the upper 6-bits, the 
assembly OR instruction accomplishes this:

OR      AL, 00000011B    ;<- More often then not programmers show 
                    |    ;   this OR or AND value as a binary number.
                    |____ The letter "B" simply tells the assembler
                          that this group of numbers is a binary value.

The unknown value we get from port 61H ---> 101010 00 <- ( IN  AL, 61H )
Then we first OR it with this value ------> 000000 11 <-Our ORing ON value
                                                        this value will enable
                                                        the speaker.

Leaves all bits except 0 and 1 unchanged -> 101010 11 <-The resulting valu
e -
                                                   ||   bits 0 and 1 have both
                                            bit 1__||   been forced to values
                                            bit 0___|   of - 1  (ON)

        Now we want to return this altered number back OUT to port 61H to 
turn ON the speaker. This is easily accomplished by using the above explained
assembly OUT instruction in the following manner.

OUT     61H, AL    ;<-- copy the value in the AL register to Port 61H

        At this point the computers speaker will sound until a new binary 
value is sent back OUT to port 61H to turn the speaker OFF.

Here is the complete code to turn ON the speaker:

IN      AL, 61H          ;Get current value of port 61H.
OR      AL, 00000011B    ;OR AL to this value, forcing first two bits high.
OUT     61H, AL          ;Copy it to port 61H of the PPI chip.

        Here is where our next assembly instruction needs to enter the picture
to turn the speaker OFF. That instruction is the AND instruction, kind of like
the opposite of the OR instruction. As with turning ON the speaker we must use
a similar procedure to turn the speaker OFF.

First get unknown value from port 61H ----> 101010 11 <- ( IN  AL, 61H )
Then we first AND it with this value -----> 111111 00 <-Our ANDing OFF val
ue -
(This 8-bit number is the exact opposite                this value will disable
of our OR value above).                                 the speaker.

Leaves all bits except 0 and 1 unchanged -> 101010 00 <-The resulting valu
e -
                                                   ||   bits 0 and 1 have both
                                            bit 1__||   been forced to values
                                            bit 0___|   of - 0  (OFF)

Here is the complete code to turn OFF the speaker:

IN      AL,61H          ;Get current value of port 61H.
AND     AL,11111100B    ;AND AL to this value, forcing first two bits low.
OUT     61H,AL          ;Copy it to port 61H of the PPI chip.

Ok, now if you think about it if we were to turn the speaker ON with:

IN      AL, 61H
OR      AL, 00000011B
OUT     61H, AL

And then, directly turn the speaker back OFF with:

IN      AL, 61H
AND     AL, 11111100B
OUT     61H, AL

        You wouldn't hear a thing (except maybe a click), it all happens to
fast.  We need to cause some kind of delay between the two procedures. We do
this by setting up a LOOP instruction between our two procedures.  This is
done by putting a value in the CX register and executing the assembly LOOP 

Here is an example of its use:

MOV     CX, 100          ;Repeat the loop 100 times
DELAY_LOOP:              ;We loop back to here
LOOP    DELAY_LOOP       ;Jump repeatedly to DELAY_LOOP until CX = 0

This will sound the speaker for a Duration of 100 repeated Loops.

Here is the Whole Noisy Routine:

IN      AL,61H          ;Get current value of port 61H.
OR      AL,00000011B    ;OR AL to this value, forcing first two bits high.
OUT     61H,AL          ;Copy it to port 61H of the PPI chip.

MOV     CX,100          ;Repeat the loop 100 times
DELAY_LOOP:             ;We loop back to here
LOOP    DELAY_LOOP      ;Jump repeatedly to DELAY_LOOP until CX = 0

IN      AL,61H          ;Get current value of port 61H.
AND     AL,11111100B    ;AND AL to this value, forcing first two bits low.
OUT     61H,AL          ;Copy it to port 61H of the PPI chip.

        This is a very good method of creating beeps and boops, but we what 
to get a little more involved then this and create more interesting sound
effects. We could create many different sounds if we were to include help
from the computers timer chip. This is the 8253 programmable timer and has
the ability to enable a certain action at a certain point in time. It senses 
timing from oscillations it recieves from the PC's 8284 oscillator chip, which
generates 1,193,180 pulses per second.  The 8253 chip can then be instructed 
how many of these pulses it should wait for before triggering a certain action.
In the case of tone generation, this action consists of sending a pulse to the
speaker.  Before executing this action, the 8253 chip must be programmed for a
particular frequency it should generate.

        There are actually three different timers built into the computer.
Timer 0 is used in DMA data transfer (Direct Memory Access), Timer 1 is used
as a system clock oscillator (18.2 times per second), and the one we are
interested in Timer 2 which is connected to the computers speaker.

        Using the Timer to generate sound is a little more complicated than 
simply sending pulses to the speaker. There are three steps envolved in using
this method of sound creation. 
    Step 1.  Copy a certain number to Timer 2 to initialize it.
    Step 2.  Copy a 16 bit number to Timer 2 to establish the frequency 
             of the tone to be generated.
    Step 3.  Turn on the speaker to enable the frequency adjusted sound
             to be heard.

        You access Timer 2 thru two port addresses,  the first is used to 
initialize (make it ready to receive data) thru port 43H, you then send a 
16-bit value in two 8-bit steps.  First, the Least Significant Byte (LSB)
is copied to port address 42H, second, the Most Significant Byte (MSB) is
copied to port address 42H. A 16-bit value is called a WORD, a WORD value
is made up of two BYTES, LSB and MSB.

                         _______________ ____ (WORD)
                        |               |
16-bit binary value ->  00000000 00000001
                        |      | |______|____ (BYTE) LSB
                        |      |         
                        |______|_____________ (BYTE) MSB

Here is how all this is accomplished:

MOV     BX, 1            ; Frequency Value.
                         ; Formula = 1,193,180 \ frequency value
                         ; Will put it in BX for now. 
                         ; The lower the value the higher
                         ; the sound / the higher the value
                         ; the lower the sound.

MOV     AL, 10110110B    ; The Magic Number (use this binary number only!)
OUT     43H, AL          ; Send it to the initializing port 43H Timer 2.

MOV     AX, BX           ; Move our Frequency Value into AX.

OUT     42H, AL          ; Send LSB to port 42H.
MOV     AL, AH           ; Move MSB into AL
OUT     42H, AL          ; Send MSB to port 42H.

IN      AL, 61H          ; Get current value of port 61H.
OR      AL, 00000011B    ; OR AL to this value, forcing first two bits high.
OUT     61H, AL          ; Copy it to port 61H of the PPI Chip
                         ; to turn ON the speaker.

MOV     CX, 100          ; Repeat the loop 100 times.
DELAY_LOOP:              ; We loop back to here.
LOOP    DELAY_LOOP       ; Jump repeatedly to DELAY_LOOP until CX = 0

IN      AL, 61H          ; Get current value of port 61H.
AND     AL, 11111100B    ; AND AL to this value, forcing first two bits low.
OUT     61H, AL          ; Copy it to port 61H of the PPI Chip
                         ; to turn OFF the speaker.

        Next we need to make our sound maker more interesting. To do this 
we will simply use a method of repeating the whole thing a specified number
of times and also increment the frequency value to create a sound that drops
in frequency. To accomplish this we will use the assembly JMP instruction 
and also at the same time, increment our frequency value.
Here is a complete example:

MOV     DX,2000          ; Number of times to repeat whole routine.

MOV     BX,1             ; Frequency value.

MOV     AL, 10110110B    ; The Magic Number (use this binary number only)
OUT     43H, AL          ; Send it to the initializing port 43H Timer 2.

NEXT_FREQUENCY:          ; This is were we will jump back to 2000 times.

MOV     AX, BX           ; Move our Frequency value into AX.

OUT     42H, AL          ; Send LSB to port 42H.
MOV     AL, AH           ; Move MSB into AL  
OUT     42H, AL          ; Send MSB to port 42H.

IN      AL, 61H          ; Get current value of port 61H.
OR      AL, 00000011B    ; OR AL to this value, forcing first two bits high.
OUT     61H, AL          ; Copy it to port 61H of the PPI Chip
                         ; to turn ON the speaker.

MOV     CX, 100          ; Repeat loop 100 times
DELAY_LOOP:              ; Here is where we loop back too.
LOOP    DELAY_LOOP       ; Jump repeatedly to DELAY_LOOP until CX = 0

INC     BX               ; Incrementing the value of BX lowers 
                         ; the frequency each time we repeat the
                         ; whole routine

DEC     DX               ; Decrement repeat routine count

CMP     DX, 0            ; Is DX (repeat count) = to 0
                         ; and do whole routine again.

                         ; Else DX = 0 time to turn speaker OFF

IN      AL,61H           ; Get current value of port 61H.
AND     AL,11111100B     ; AND AL to this value, forcing first two bits low.
OUT     61H,AL           ; Copy it to port 61H of the PPI Chip
                         ; to turn OFF the speaker.

In conclusion, with the included examples and a little imagination, there is no
limit to the sound effects that are possible to create.

Have Fun !! 


Tell a friend
Bookmark and Share

Similar Articles

8237A Programmable DMA Controller
Intel Chipset 8237A Datasheet
(by Intel)

8254 Programmable Interval Timer
Intel Chipset 8254 Datasheet
(by Intel)

8255 Programmable Peripheral Interface
Intel Chipset 8255 Datasheet
(by Intel)

8259A Programmable Interrupt Controller
Intel Chipset 8259 Datasheet
(by Intel)

82C54 Programmable Interval Timer
Intel 82C54 Technical Manual
(by Intel)

82C55A Programmable Peripheral Interface
Intel 82C55A Techical Manual
(by Intel)

An asm source code for Linux. Hello World
A 59 byte
(by Brian Raiter)

CPUID3 an Intel CPU detection program
Interesting src code for detecting different Cpus
(by Intel Corporation)

Fastclock source code C / Asm
Coding on 8259 timer for high precision clock
(by unknown)

How to program the DMA 8237 chip
Basic info and examples of C and Asm programming
(by Night Stalker)

Il Chip 8259: IRQ Controller (NEW)
Un'introduzione sull'8259
(by JES)

Intel 8272 Floppy Disk Controller Chip
Tecnical manual, commands and controls
(by Intel)

Intel 82801AA (ICH), 82801AB (ICH0) I/O Controller
Hub AC '97 Programmer's Reference Manual
(by Intel)

Intel i8255 PIO Programming Tutorial: Extracts
A practical use of the 8255 with basic programming
(by Richard Steven Walz)

Leggi e Scrivi in Console
Esempio di codice per leggere e scrivere in consol
(by JES)

Programming the Intel 8253
Short howto program Programmable Interval Timer
(by Mark Feldman)

Programming the PC Speaker
A short practical intro on programming 8254
(by Mark Feldman)

Simple Horizontal Scroller
Asm code for scrolling text in vga
(by Carlos Hasan)

Sorgente ASM true.asm
An asm source code for Linux
(by Brian Raiter

TIMING CODE MODULE (80x86 specific code)
Setting pc timer 8259 - Commented source code
(by Ethan Rohrer)

Timing on the PC family (rel.3)
Over 290 pages on programming 8253/8254
(by Kris Heidenstrom)

Uso rapido del CPUID
Esempio di codice per l'istruzione MMX CPUID
(by JES)

x86 chksum.asm source code
8 bit Checksum (CRC) Calculation Utility/Sample
(by Erdogan Tan)

 Tags: 8254, 8255, easy source, chipset

webmaster jes
writers rguru, tech-g, aiguru, drAx

site optimized for IE/Firefox/Chrome with 1024x768 resolution

Valid HTML 4.01 Transitional


hosting&web -

find rguru on
... send an email ...
Your name

Destination email


captcha! Code