Sabtu, 02 Januari 2010

C language program Lecture 2

Another Example:

#include
#include
char st[80] ={"Hello World$"};
char st1[80] ={"Hello Students!$"};
void interrupt (*oldint65)( );

void interrupt newint65( );
void main()
{
oldint65 = getvect(0x65);
setvect(0x65, newint65);

keep(0, 1000);
}
void interrupt newint65( )
{
if (( _AH ) == 0) //corrected
{

_AH = 0x09;
_DX = (unsigned int) st;
geninterrupt (0x21);
}
else
{
if (( _AH ) == 1) //corrected

{
_AH = 0x09;
_DX = (unsigned int) st1;
geninterrupt (0x21);
}

}
}

Various interrupts provide a number of services. The service number is usually placed in the AH register before invoking the interrupt. The ISR should in turn check the value in AH register and then perform the function accordingly. The above example exemplifies just that. In this example int 65 is assigned two services 0 and 1. Service 0 prints the string st and service 1 prints the string st1. These services can be invoked in the following manner.


#include
#include
void main()
{

_AH = 1;
geninterrupt (0x65);
_AH = 0;
geninterrupt (0x65);
}


Interrupt stealing or interrupt hooks
Previously we have discussed how a new interrupt can be written and implemented. Interrupt stealing is a technique by which already implemented services can be altered by the programmer.
This technique makes use of the fact that the vector is stored in the IVT and it can be read and written. The interrupt which is to be hooked its (original routine ) vector is first read from the IVT and then stored in a interrupt pointer type variable, after this the vector is changed to point to one of the interrupt function (new routine) within the program. If the interrupt is invoked now it will force the new routine to be executed provided that its memory resident. Now two things can be done, the original routine might be performing an important task so it also needs to invoked, it can either be invoked in the start of the new routine or at the end of the new routine using its pointer as shown in the following execution charts below

Fig 1 (Normal Execution of an ISR)

Fig 2 (The original ISR being called at he end of new routine)
Fig 3 (The original ISR invoked at the start of new ISR)
Care must be taken while invoking the original interrupt. Generally in case hardware interrupts are intercepted invoking the original interrupt at the start of new routine might cause some problems whereas in case of software interrupts the original interrupt can be invoked anywhere

Sample Program for interrupt Interception

void interrupt newint();
void interrupt (*old)();
void main()
{
old=getvect(0x08);
setvect(0x08,newint);
keep(0,1000);
}
void interrupt newint ()
{


(*old)();
}

The above program gets the address stored at the vector of interrupt 8 and stores it in the pointer oldint. The address of the interrupt function newint is then placed at the vector of int 8 and the program is made memory resident. From this point onwards whenever interrupt 8 occurs the interrupt function newint is invoked. This function after performing its operation calls the original interrupt 8 whose address has been stored in oldint pointer.

Timer Interrupt
In the coming few examples we will intercept interrupt 8. This is the timer interrupt. The timer interrupt has following properties.
  1. Its an Hardware Interrupts
  2. It is Invoked by Means of Hardware
  3. It approximately occurs 18.2 times every second by means of hardware.

BIOS Data Area
BIOS contains trivial I/O routines which have been programmed into a ROM type device and is interfaced with the processor as a part of main memory. However the BIOS routines would require a few variables, these variables are stored in the BIOS data arera at the location 0040:0000H in the main memory.
One such byte stored in the BIOS data area is the keyboard status byte at the location 40:17H. This contains the status of various keys like alt, shift, caps lock etc. This byte can be described by the diagram below

Fig 4 (Keyboard status byte)
Another Example

#include
void interrupt (*old)();

void interrupt new();
char far *scr=(char far* ) 0x00400017;
void main()

{
old=getvect(0x08);
setvect(0x08,new);

keep(0,1000);
}

void interrupt new (){
*scr=64;
(*old)();

}


This fairly simple example intercepts the timer interrupt such that whenever the timer interrupt occurs the function new() is invoked. Remember this is .C program and not a .CPP program. Save the code file with .C extension after writing this code
. On occurrence of interrupt 8 the function new sets the caps lock bit in key board status by placing 64 at this position through its far pointer. So even if the user turns of the caps lock on the next occurrence of int 8 ( almost immediately) the caps lock will be turned on again (turing on the caps lock on like this will not effect its LED in the keyboard only letters will be typed in caps).

Memory Mapped I/O and Isolated I/O

A device may be interfaced with the processor to perform memory mapped or isolated I/O. Main memory and I/O ports both are physically a kind of memory device. In case of Isolated I/O, I/O ports are used to hold data temporary while sending/receiving the data to/from the I/O device. If the similar function is performed using a dedicated part of main memory then the I/O operation is memory mapped.

Fig 5 (Isolated I/O)

Fig 6 (Memory mapped I/O)


Memory Mapped I/O on Monitor
One of the devices in standard PCs that perform memory mapped I/O is the display device (Monitor). The output on the monitor is controller by a controller called video controller within the PC. One of the reason for adopting memory mapped I/O for the monitor is that a large amount of data is needed to be conveyed to the video controller in order to describe the text or that graphics that is to be displayed. Such large amount of data being output through isolated I/O does not form into a feasible idea as the number of port in PCs is limited to 65536.
The memory area starting from the address b800:0000H. Two bytes (a word) are reserved for a single character to be displayed in this area. The low byte contains the ASCII code of the character to be displayed and the high byte contains the attribute of the character to be displayed. The address b800:0000h corresponds to the character displayed at the top left corner of the screen, the next word b800:0002 corresponds to the next character on the same row of the text screen and so on as described In the diagram below.

Fig 7 (Memory mapped I/O on monitor)


The attribute byte (higher byte) describes the forecolor and the backcolor in which the character will be displayed. The DOS screen carries black as the backcolor and white as the fore color by default. The lower 4 bits (lower nibble) represents the forecolor and the higher 4 bits (higher nibble) represents the back color as described by the diagram below
Fig 8 (Attribute Byte)To understand all describe above lets take a look at this example.

unsigned int far *scr=0xb8000000;

void main()
{
(*scr)=0x0756;
(*(scr+1))=0x7055;
}

This example will generate the output VU
The far pointer scr is assigned the value 0xb800H in the high word which is the segment address and value 0x0000H in the low word which is the offset address. The word at this address is loaded with the value 0x0756H and the next word is loaded by the value 0x7055H, 0x07 is the attribute byte meaning black back color and white fore color and the byte 0x70h means white back color and black fore color. ).0x56 and 0x55 are the ASCII value of “V” and “U” respectively.

Tidak ada komentar:

Posting Komentar