| UMBC CMSC 211 |
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 interrupproach 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.plicaitons 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 ; 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 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, ; 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 ; 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 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 | 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 signifirrupts. 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 ad/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) -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 ;
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