UMBC CMSC 211 |
Our focus will be the common bus. As you might imagine, we must ensure that every byte sent reaches the correct device and any received must be correctly labeled as to where it came from.
One way to do this is to reserve a set of memory locations for this purpose. Then a set of memory addresses represent the data byte, others represent the control registers in the device. This is a simple approach but in today's multi-processing systems, there is a lack of control that is not acceptable.
Another approach is to use ports. On the PC, there are 65,536 ports, each one separately addressable. Input/output operations are then performed by the instructions IN and OUT, which read and write directly to the ports. They have two operands, the accumulator and a port specified.
It is possible to use an accumulator of any size, AL, AX, EAX, and
a port address in the range of 0 to 65535 (0FFFFh). However,
yoou can not specify a port of greater than 255 as an immediate
operand. To exceed that, you must use a register:
mov dx, 3D8h ; store port number in DX
out al, dx ; send byte contained in AL to port 3D8h;
Many of the ports are already reserved for IBM-Compatible PCs.
Port Address | Device Connected |
---|---|
020h - 023h | Programmable interrupt controller 8259 |
030h - 03Fh | Interrupt controller 1 (AT and PS/2) |
040h - 043h | Timer |
060h - 06Fh | PPI on PC and XT, keyboard on AT and PS/2 |
1F0h - 1F8h | Fixed disk controller (AT) |
278h - 27Bh | Parallel printer (LPT2) |
2E8h - 2EFh | Serial Port 4 |
2F8h - 2FFh | Serial Port 2 |
378h - 37Bh | Parallel printer (LPT1) |
3B0h - 3BBh | MDA or VGA video adapter |
3BCh - 3BFh | Parallel printer (LPT3) |
3C0h - 3Cfh | EGA/VGA video adapter |
3D0h - 3DFh | CGA/VGA video adapter |
3E8h - 3EFh | Serial port 3 |
3F0h - 3F7h | Floppy disk control |
3F8h - 3FFh | Serial port 1 |
Peripheral interface | Intel 8255 |
Interrupt controller | Intel 8259 |
Timer | Intel 8253 |
Serial Port | UART 8250 |
It must be noted that not all systems use the same chips and some of the chips have been upgraded. Sometimes it is helpful to have your program determine which system you have:
; ; Program DetPC ; Copyright 1993, Vitaly Maljugin, Jacov Izrailevich, Semyon Lavon ; Aleksandr Sopin ; .model large HiBios segment at 0F000h org 0FFFEh PcType db ? ; Computer idenifier HiBios ends .code ASSUME es:HiBios ; ES wil be used for accessing ROM BIOS area Begin: mov ax,@data ; load segment address of DATA segement mov ds,ax ; DS points to DATA segment mov ax,HiBios ; load segment address or ROM BIOS data mov es,ax ; ES points to ROM BIOS segment mov cx,Ltable ; Load length of table to be searched mov dl,PcType ; Extract the type from BIOS area Search: mov bx,cx ; Address of current table element cmp dl,TypeTbl[bx-1] ;Compare type and element of table je EndSear ; If found, stop searching loop Search ; Test next element of table EndSear:mov al,cl ; number element found passed as return code mov ah,4Ch ; DOS service 4H - terminate process int 21h ; DOS service call .data ; ; Table of microprocessors' types db 0 ; 0 - Uknown type TypeTbl db 0F8h ; 1 - IBM PS/2 model 80 db 0F9h ; 2 - IBM PC Convertible db 0FAh ; 3 - IBM PS/2 Model 30 db 0FBh ; 4 - PC XT Ext keyboard, 3.5" drives db 0FCh ; 5 - PC-AT or PS/2 Models 50,60 db 0FDh ; 6 - IBM PC-JR db 0FEh ; 7 - PC-XT db 0FFh ; 8 - IBM PC db 09Ah ; 9 - Compaq XT / Compaq Plus db 030h ; 10 - Sperry PC db 02Dh ; 11 - Compaq PC / Compaq Deskpro Ltable equ $-TypeTbl end begin
If it is polling, the computer must continual, even constantly, check to see if there is any event. If the program is constantly checking, it can do nothing else. This makes the program very easy to debug, but it prevents any other useful work from being perform, which lowers the overall speed and program efficiency.
The other approach is to use hardware interrupts. The interrupt handle is activated when there is a key pressed on the keyboard. The handler preserves the state of the CPU, gets the input and deals with it.
; ; Program ScanCodD ; Copyright 1993, Vitaly Maljugin, Jacov Izrailevich, Semyon Lavon ; Aleksandr Sopin ; .model small .stack .data CR equ 00Dh ; Carriage return code LF equ 00Ah ; Line feed code EscScan equ 001h ; Scan code for ESC key KbdPort equ 060h ; PPI 9225 port A EndMsg equ 024h ; Dollar sign - end of message for DOS service NewHand dd NewInt9 ; Reference to the new handler for int 09 ScanCod db 0 BegMsg db CR,LF,LF db ' SCAN CODES BROWSER 3.0 ', CR,CR,LF db 'Interrupt 09h handler totally replaced',CR,LF db EndMsg Kbd83 db CR,LF,'You have a standard 83-key keyboard',CR,LF,EndMsg Kbd101 db CR,LF,'You have an enhanced 101/102 keyboard',CR,LF,EndMsg InsMsg db CR,LF,'Press ESC to exit else',CR,LF db 'Press and relese any other key',CR,LF,LF,EndMsg FinMsg db CR,LF,' Job terminated',CR,LF db ' Standard value of interrupt vector 09h ' db 'has been restored.', CR,LF, EndMsg .code OutB PROC NEAR USES AX cmp al,0Ah ; Is it decimal digit ( 0 - 9)? jb NoCorr ; No correction - first 10 hex digit are dec cmp al,10h ; Is it hexadecimal digit ( A - F )? jb HexCyph ; If so correct for character representation mov al,' ' ; If not, replace it with blank jmp OutScr ; and output HexCyph:add al,07h ; This transform hex digits A - F NoCorr: add al,30h ; Convert integer to character OutScr: mov ah,0Eh ; Function 0Eh - write character int 10h ; BIOS video service inc NumL cmp NumL,60 jl NoNewL mov al,CR int 10h mov al,LF int 10h mov NumL,0 NoNewL: ret NumL dw 0 OutB ENDP PrtByte PROC near uses AX DX mov ah,0 ; Clear high part of AX mov dx,0010h ; Divider into BX div dl ; AL - result, AH - remainder mov dx,ax ; Save results call OutB mov al,dh call OutB mov al,' ' ; Character to be printed is a blank call OutB ret ; Return to the caller PrtByte ENDP EndInt PROC NEAR in al,61h ; read Port B or al,80h ; set bit 7 to 1 out 61h,al ; output to port B jmp $+2 ; delay (needed for fast PC) and al, not 80h ; clear bit 7 out 61h,al ; output to port B mov al,20h ; EOI code into AL out 20h,al ; signal EOI ret EndInt ENDP NewInt9 PROC near mov SaveAX,ax ContKey:pushf ; save original flags in al,60h ; read scan code cmp al,EscScan ; ESC pressed? je Fin ; if so, return call PrtByte ; output scan code Call EndInt sti ; allow interrupts popf ; restore original flags iret Fin: Call EndInt mov ax,SaveAX popf Jmp9 db 0EAh ; opcode for JMP FAR OldInt9 dw ?,? ; Address of old handler for interrupt 09h SaveAX dw ? NewInt9 ENDP .startup lea dx,BegMsg ; Addres of start message into DX mov ah,09 ; Function 09h - output text string int 21h ; Dos service call mov ax,40h ; 40h - segment address for BIOS data area mov es,ax ; Place this address into ES test byte ptr es:[96h],10h ; Bit 4 - 101-key keyboard indicator jnz Pres101 lea dx,Kbd83 ; Addres of start message into DX mov ah,09 ; Function 09h - output text string int 21h ; Dos service call jmp PrtInstr Pres101: lea dx,Kbd101 ; Addres of start message into DX mov ah,09 ; Function 09h - output text string int 21h ; Dos service call PrtInstr: lea dx,InsMsg ; Addres of start message into DX mov ah,09 ; Function 09h - output text string int 21h ; Dos service call mov ah,35h ; Function 35h - Get interrupt vector mov al,09h ; Interrupt number is 09h int 21h ; DOS service call mov OldInt9[0],bx ; Save offset addres of old handler mov OldInt9[2],es ; Save segment address of old handler push ds ; DS will contain the segment of new handler lds dx,NewHand ; Full addres of new handler into DS:DX mov ah,25h ; Function 25h - set interrupt vector int 21h ; DOS service call pop ds ; Restore the data segment register NextKey:mov ah,0Ch ; Function 0Ch - clear the keyboard buffer int 21h ; Dos service call mov ah,0 ; Function 00h - read character from keyboard int 16h ; BIOS keyboard service cmp ah,EscScan ; Is the ESC key pressed? jne NextKey ; If not - process the next key Finis: lea dx,FinMsg ; Addres of start message into DX mov ah,09 ; Function 09h - output text string int 21h ; Dos service call mov dx,OldInt9[0] ; Offset address for old handler into DX mov ds,OldInt9[2] ; Segment address for old handler into DS mov ax,2509h ; Set interrupt vector for INT 9 int 21h ; DOS service call mov ax,4C00h ; Function 4Ch - terminate process int 21h ; DOS service call END
The three parallel port registers are:
Bit | Meaning if set |
---|---|
0 | Timeout |
1-2 | Not used |
3 | I/O error |
4 | Printer is On-Line |
5 | Out of Paper |
6 | Acknowledge (if zero, normal setting) |
7 | Printer is not busy |
Bit | Meaning if set |
---|---|
0 | sending byte |
1 | CR treated as CR + LF |
2 | normal setting (reset printer when 0) |
3 | select printer |
4 | enable printe IRQ (IRQ 7 for LPT1) |
5 - 7 | not used |
Logical level | MS-DOS service available through functions of interrupt 21h |
Basic level | BIOS service available through interrupt 17h |
Low level | Controlling the printer ports directly |
The basic level allows you to programmically check on the status of things and to provide a different type of control, instead of relying on the standard DOS functions.
The low level is the most powerful and most difficult. In the case of the printer, there is not too much different in low level and the basic level, except that there can be a slight improvement in speed.
Programs which support the mouse must be capable of receiving and interpreting the signals generated by the mouse. There are different types of mice, and each requires a unique driver.
All signals generated by a mouse could be processed in a user program, however very few applicaitons actually do this. Normally, the program uses the servcies of the mouse driver.
Make sure that if you are programming with a mouse, that you don't call the null address!
An application program that uses a mouse gets information about its state and location and performs a relevant action. One of the most common uses of the mouse in applications is for selecting an item in a menu. This process involves the following steps:
The mouse cursor is generated by the mouse driver that changes its location as you move the mouse. "When it is moved, the mouse generates short impulses called mickeys (christened by Bill Gates). The number of mickeys per inches is dependent on how the mouse was built and typically ranges from 200 to 400 mickeys per inch. Usually, the drivers moves the cursor by 1 pixel per mickey horizontally and 2 pixes per mickey vertically.
;*********************************************************************** ; Program PMouse2 ( Chapter 10 ) ; ; The demo program for mouse (the menu selection, Text Mode) ; ; Author: A.I.Sopin, Voronezh University. 1993 ; ; The interrupt 33h (mouse service) is used ; ; Mouse driver must be installed ; ;*********************************************************************** NAME PMOUSE2 .DOSSEG .MODEL SMALL .STACK 100h ;---------------------------------------------------------- .DATA BELL EQU 07 ; sound signal LF EQU 10 ; Line Feed CR EQU 13 ; Carriage Return TEXT0 DB " The MOUSE demo program (INT 33h). " DB " Press any key to continue...", BELL, CR, LF, "$" TEXT1 DB " The mouse driver is not installed !!!." DB " Press any key...", BELL, CR, LF, "$" TEXT2 DB " An active mouse driver found." DB " Press any key...", BELL, CR, LF, "$" TEXT3 DB 'The menu command selection using the mouse (text mode).' Ltxt3 EQU $-TEXT3 TEXT8 DB "Select Command and press Left Button:" Ltxt8 EQU $-TEXT8 TEXT10 DB "1 - Command one " Ltxt10 EQU $-TEXT10 TEXT11 DB "2 - Command two " Ltxt11 EQU $-TEXT11 TEXT12 DB "3 - Command three" Ltxt12 EQU $-TEXT12 TEXT13 DB "4 - Command four " Ltxt13 EQU $-TEXT13 TEXT14 DB "5 - Command five " Ltxt14 EQU $-TEXT14 TEXT15 DB "6 - Exit " Ltxt15 EQU $-TEXT15 TXT3L DB "Left button pressed. Command " NumSel DB 20h DB " selected." DB BELL, "$" VMODE DB 0 ; video mode saved ATTR DB 0 ; ROW0 DB 0 COL0 DB 0 CX0 DW 0 DX0 DW 0 ;---------------------------------------------------------- .CODE OutMsg MACRO Txt ;======= output text message lea dx,Txt ; adders of message mov ah,09h ; function 09h - output text string int 21h ; DOS service call ENDM WaitKey MACRO ;======= Wait for a key pressed xor ah,ah ; function 0 - wait for key pressed int 16h ; BIOS keyboard service ENDM SetCurs MACRO Row,Column ;======= Move the cursor mov ah,2 ; function 02h - set cursor position xor bh,bh ; video page 0 is used mov dh,&Row ; cursor row mov dl,&Column ; cursor column int 10h ; BIOS vide service call ENDM PutStr MACRO Row,Column,Text,Leng,Attrib Local M0 push si mov cx,Leng ; string length lea si,Text ; DS:SI - address of text string mov dl,Column ; initial position (column) cld ; process strings from left to right ; Outputting one character M0: SetCurs Row,dl ; lodsb ; AL - character to be output mov bl,Attrib ; BL - attribute mov ah,9 ; function 09 - output char+attr xor bh,bh ; video page 0 is used push cx ; save cycle counter mov cx,1 ; number of characters output int 10h ; BIOS video service call pop cx ; restore cycle counter inc dl ; next position for output loop M0 ; next cycle step pop si ; ENDM ;------------------------------------------------------------------- .STARTUP mov ah,0Fh ; function 0Fh - get video mode int 10h ; BIOS video service call mov VMODE,al ; save current video mode mov ah,0 ; function 0 - set video mode mov al,3 ; 80x25 Text int 10h ; BIOS video service call ; Output initial message OutMsg TEXT0 ; output initial message WaitKey ; check for mouse driver present mov ax, 03533h ; function 35h - get interrupt vector int 21h ; DOS service call mov ax,es ; segment address of handler or ax,bx ; AX - segment .OR. offset of int 33 jz Nomouse ; if full adders is 0 - no mouse mov bl,es:[bx] ; get first instruction of handler cmp bl,0CFh ; is this IRET instruction? jne Begin ; if not - driver installed Nomouse: OutMsg TEXT1 ; output message "driver not found" WaitKey ; wait for key pressed jmp Exit ; Exit program ;------------------------------------------------------------------- Begin: OutMsg TEXT2 ; output message "driver installed" WaitKey ; wait for key pressed ;------------------------------------------------------------------- ; Initialize mouse and report status (function 0 of INT 33h) Func0: xor ax,ax ; Initialize mouse int 33h ; mouse service call cmp ax,0 ; is mouse installed? jnz Clear25 ; if so, pass to function 10 jmp Exit ; if not, exit program ; Fill the screen (yellow character on blue background) Clear25:SetCurs 0,0 ; cursor to left upper corner mov ah,9 ; function 09h - output char+attr xor bh,bh ; video page 0 is used mov al,20h ; character to be output mov bl,1Eh ; attribute - yellow on blue mov cx,2000 ; number of characters to be output int 10h ; BIOS video service call ;------------------------------------------------------------------- ; Output the header and the menu text onto the screen PutStr 2,16,TEXT3, Ltxt3, 1Eh PutStr 8,20,TEXT8, Ltxt8, 1Eh PutStr 10,20,TEXT10,Ltxt10,1Fh PutStr 11,20,TEXT11,Ltxt11,1Fh PutStr 12,20,TEXT12,Ltxt12,1Fh PutStr 13,20,TEXT13,Ltxt13,1Fh PutStr 14,20,TEXT14,Ltxt14,1Fh PutStr 15,20,TEXT15,Ltxt15,1Fh SetCurs 25,80 ; move cursor out of screen ;------------------------------------------------------------------- ; Function 10 - define text cursor Func10: mov ax,10 ; define text cursor xor bx,bx ; software cursor is used mov cx,0FFFFh ; screen Mask mov dx,4700h ; cursor Mask int 33h ; mouse service call ;------------------------------------------------------------------- ; Function 1 - show the mouse cursor Func1: mov ax,1 ; function 01 - show mouse cursor int 33h ; mouse service call ;------------------------------------------------------------------- ; Determining mouse keys pressed Func3: mov ah,1 ; function 01h - check keyboard buffer int 16h ; BIOS keyboard service jz ContF3 ; if no key pressed, continue jmp Exit ; exit if key pressed ContF3: mov ax,3 ; func. 03 - button status and location int 33h ; mouse service call mov CX0,cx ; save X coordinate (column) mov DX0,dx ; save Y coordinate (row) test bx,1 ; left button pressed? jnz X_Range ; OK ! jmp short Func3 ; no button pressed - check again ; Check horizontal cursor location X_Range:mov ax,CX0 ; X coordinate (Column) mov cl,3 ; number bits to shift shr ax,cl ; shift by 3 - divide by 8 cmp ax,20 ; cursor on the left ? jb Func3 ; not - continue check cmp ax,36 ; cursor on the right? ja Func3 ; not - continue check ; Check vertical cursor location Y_Range:mov ax,DX0 ; X coordinate (Column) mov cl,3 ; number bits to shift shr ax,cl ; shift by 3 - divide by 8 cmp ax,10 ; cursor on the top ? jb Func3 ; not - continue check cmp ax,15 ; cursor on the bottom? ja Func3 ; not - continue check ; report the number of the command selected mov ax,DX0 ; Y coordinate (Row) mov cl,3 ; number bits to shift shr ax,cl ; shift by 3 - divide by 8 cmp ax,15 ; line 15 (Exit) ? je Exit ; if so - finish sub ax,9 ; number of command selected or al,30h ; convert to ASCII character mov NumSel,al ; put number to output message SetCurs 17,20 ; move cursor OutMsg TXT3L ; output message "command selected" jmp short Func3 ; check again ;------------------------------------------------------------------- ; Terminate program and exit to DOS Exit: mov al,VMODE ; remember video mode on entry mov ah,0 ; function 0 - set video mode int 10h ; BIOS video service Call CLRKEY ; clear keyboard buffer mov ax,4C00h ; function 4Ch - terminate process int 21h ; DOS service call ;------------------------------------------------------------------- ; ; This procedure clears the keyboard buffer ; ;------------------------------------------------------------------- CLRKEY PROC NEAR uses ax es mov ax,40h ; address of BIOS data segment mov ES,ax ; ES points to BIOS data cli ; no interrupts - system data modified mov ax,ES:[1Ah] ; buffer head printer mov ES:[1Ch],ax ; clear buffer (head ptr = tail ptr) sti ; buffer cleared - allow interrupts ret CLRKEY ENDP END
Sending or receiving one byte of data through the serial channel actuall involves transferring the following sequence of bits:
A special chip, the Intel UART8250 (Universal Asynchronous Receiver Transmitter) was designed to support serial data transfers. Access to this chip is thorough the I/O ports.
MS-DOS support two basic communications ports - COM1 and COM2. Their base addresses are stored in the BIOS data area at 0040:0000h (COM1) and 0040:0002h (COM2). The ports used by COM1 and COM2 are not fixed, but 3F8h and 2F8h are common, but so is the reverse. Alway get the port numbers from the BIOS data area. Many different devices can be connected via the serial ports.
The 8250 chip is programmed by 10 one-byte registers, available through the corresponding I/O ports. Some registers are write-only, some are read only and the remainder can be both.
Port | Mode value | DLAB | Meaning |
---|---|---|---|
3F8h | OUT | 0 | Transmitter holding register |
3F8h | IN | 0 | Receiver holding register |
3F8h | OUT | 1 | Divisor latch (low byte) |
3F9h | OUT | 1 | Divisor latch (high byte) |
3F9h | OUT | 0 | Interrupt enable register |
3FAh | IN | Interrupt identification register | |
3FBh | OUT | Line control register | |
3FCh | OUT | Modem control register | |
3FDh | IN | Line status register | |
3FEh | IN | Modem status register |
This range covers only 7 addresses, you can increase the number of registers actually available to 10 by setting the 7th bit of the line control register (3FBh). This bit is called DLAB - Divisor Latch Access Bit).
You can use the BIOS service through interrupt 14h. These functions allow you to initialize the port, set parameters for transferring data such as number of stop bits, the type of parity control and the speed of transfer. however, it will only allow you to set the speed to 9600 baud.
Low-level programming lets you use all the UART 8250 chip facilities, including working with the transfer speed to 115K and over, but requires that the hardware interrupt related to communications ports be processed by your program.
The 8255A chip is controlled by the ports that are attached to it.
Denotation | Address | Type | Purpose |
---|---|---|---|
Port A | 60h | R/W | Keyboard input |
Port B | 61h | R/W | Configuratin info, speaker and keyboard control |
Port C | 62h | R | Get system information |
63h | R | Mode control for ports A-C | |
h4h | R | Keyboard status (AT or PS/2) |
Bit | Meaning |
---|---|
0 | Timer 2 gate (speaker) |
1 | Timer 2 data |
2 | Must be 0 |
3 | 1 = read high switches; 0 = read low swithces |
4 | 0 = enable RAM parity checking; 1 = disable |
5 | 0 = enable I/O channel check |
6 | 0 = hold keyboard clock low |
7 | 0 = enable keyboard; 1 = disable keyboard |
Bit | Contents |
---|---|
0 | 0 - no floppy drives |
1 | Not used |
2-3 | The number of memory banks on the system board |
4-5 | Display mode 11 = monochrome 10 - color 80x25 01 - color 40x25 |
6-7 | PC: The number of floppy disk drives |
Bit | Meaning |
---|---|
0 | Values of DIP switches as in Equipment List |
1 | " |
2 | " |
3 | " |
4 | Must be 0 |
5 | If set - Time channel 2 out |
6 | if set - I/O channel check |
7 | if set RAM parity check error occurred |
In order to handle multiple interrupts occurring at the same time, there are 8 or 16 interrupt levels (using one or two 8259's). We know them as IRQ0 - IRQ7 and IRQ8 - IRQ15. The smaller the number, the higher the priority is for that interrupt. The highest priority IRQ0 is for the system timer. IRQ1 is for the keyboard. There is an interrupt vector in the BIOS for each IRQ. You can disable some or all of the interrupts. You disable all of them with the CLI (Clear Interrupt) and enable all of them with STI (Set Interrupt). NOTE: IRQ2 (I/O channel) can not can not be disabled and is called a non-maskable interrupt.
There is an Interrupt Mask Register (IMR) that allows you to disable only certain interrupts. The least significant bit is IRQ0 and if it is set to 1, the interrupt is disabled. The first 8 interrupts are controlled through port 21h and the second 8 are controlled through port 0A1h.
Level | Vector | Enable Mask | Disable Mask | Meaning |
---|---|---|---|---|
IRQ0 | 08h | XXXX XXX0 | XXXX XXX1 | Timer |
IRQ1 | 09h | XXXX XX0X | XXXX XX1X | Keyboard |
IRQ2 | 0Ah | XXXX X0XX | XXXX X1XX | I/O channel |
IRQ3 | 0Bh | XXXX 0XXX | XXXX 1XXX | COM2 (AT), COM1 (XT) |
IRQ4 | 0Ch | XXX0 XXXX | XXX1 XXXX | COM1 (AT), COM2 (XT) |
IRQ5 | 0Dh | XX0X XXXX | XX1X XXXX | HDD (LPT2 for AT) |
IRQ6 | 0Eh | X0XX XXXX | X1XX XXXX | FDD controller |
IRQ7 | 0fh | 0XXX XXXX | 1XXX XXXX | LPT1 |
IRQ8 | 70h | XXXX XXX0 | XXXX XXX1 | Real-time Clock |
IRQ9 | 71h | XXXX XX0X | XXXX XX1X | Translated into IRQ2 |
IRQ10 | 72h | XXXX X0XX | XXXX X1XX | Reserved |
IRQ11 | 73h | XXXX 0XXX | XXXX 1XXX | Reserved |
IRQ12 | 74h | XXX0 XXXX | XXX1 XXXX | Reserved |
IRQ13 | 75h | XX0X XXXX | XX1X XXXX | Math co-processor |
IRQ14 | 76h | X0XX XXXX | X1XX XXXX | HDD controller |
IRQ15 | 77h | 0XXX XXXX | 1XXX XXXX | reserved |
Bit | Meaning | |
---|---|---|
0 | 0 - binary data, 1 - BCD | |
1-3 | Number of mode used (000-101) | |
4-5 | Operation Type 00 - send the value of counter 01 - read/write high byte 10 - read/write low/byte 11 - read/write both high and low bytes | |
6-7 | Number of channel to be programmed |
Channel 0 is used by teh system clock to calculate the time of day. It is programmed for 18.2 pulses per second (called ticks) and stored in the BIOS data area at 0040h:006Ch. Every pulse initiates a timer interrupt 8h (IRQ0). Don't mess with this one!
Channel 1 is responsible for refreshing RAM and counts the pulses during disk operations, so that it can reset the timer counter upon completion of an operation. This is also not a good one to mess with.
Channel 2 (port 42h) is connected to the computer's speaker and issues square wave pulses used to make sounds. You can change the sound frequency with this channel.The 8255 chip, (PPI) is also involved in generating sound and that bits 0 and 1 of port 61h also control the speaker.
;*************************************************************** ; Program Sound ( Chapter 10 ) ; ; The program for outputting a sound of prescribed tone ; ; Author: A.I.Sopin Voronezh, Russia 1990 --- 1992 ; ------ ; ; Call from Assembler programs: ; ; Call SOUND ; ; Parameters passed through the registers: ; ; Frequency - DI register (from 21 to 65535 hertz) ; ; Duration -BX register (in hundredth of second) ; ; Registers AX, CX, DX, DS, ES, SI are retained by the program ; ; ; ;*************************************************************** PUBLIC SOUND CODE SEGMENT ASSUME CS:CODE SOUND PROC FAR push ax push cx push dx push ds push es push si ;----------------------------------------------------------- in al,61h ; Read current port mode B (8255) mov cl,al ; Save current mode or al,3 ; Switch on speaker and timer out 61h,al ; mov al,0B6h ; set for channel 2 (8253) out 43h,al ; command register 8253 mov dx,14h ; mov ax,4F38h ; divisor of frequency div di ; out 42h,al ; lower byte of frequency mov al,ah ; out 42h,al ; higher byte of frequency ; Generation of sound delay mov ax,91 ; multiplier - AX register ! mul bx ; AX =BX*91 (result in DX:AX) mov bx,500 ; divisor, dividend in DX:AX div bx ; result in AX, remainder in DX mov bx,ax ; save result mov ah,0 ; read time int 1Ah ; add dx,bx ; mov bx,dx ; Cycle: int 1Ah ; cmp dx,bx ; Has time gone ? jne Cycle ; in al,61h ; Read mode of port B (8255) mov al,cl ; Previous mode and al,0FCh ; out 61h,al ; Restore mode ;----------------------------------------------------------- ; Restoring registers and exit Exit: pop si ; pop es ; pop ds ; pop dx ; pop cx ; pop ax ; RETF ; exit from subroutine SOUND ENDP CODE ENDS END