OBJECTIVE: This assignment involves the 8259 Interrupt controller which resides in the PC. You are to interface a debounced SPDT switch so that the inputs to the 8259's IRQ3 and/or IRQ4 interrupt request lines can be switched. (Note: IRQ3 and IRQ4 are included on the signal connections provided by the lab breadboard system.) You will write service routines to handle interrupt requests from IRQ3 and IRQ4. These service routines will involve displaying a 3 (for IRQ3) and a 4 (IRQ4) on the computer screen for a period of 10 (or less depending) seconds. First, you will investigate what happens when a single request is made from either IRQ3 and IRQ4. Then you will observe the priority interrupt handling capability of the 8259 by activating simultaneous requests to both IRQ3 and IRQ4.
EQUIPMENT NECESSARY:
| Breadboard |
| SPDT switch |
| DIP Switches |
| Basic logic gates |
PRE-LAB:
1. Look over the debounced SPDT switch as shown here.
This switch configuration will permit signal level changes generated by
the SPDT switch to be presented through the DIP switches, to either IRQ3
and/or IRQ4 via the breadboard connections. The 8259 had already
been initialized by the OS to be in the "edge triggered" mode. Therefore,
the signal that you generate using the SPDT switch should look like:
____________________________ ________________________________
|___|
2. Write the software to adjust the initialization of the 8259
and to handle the interrupts requested via IRQ3 and IRQ4. Since the
8259 in the PC is initialized by the OS, you should avoid disturbing its
parameters as much as possible. This is because there are other system
resources that depend on its functionality. The only thing that you
should change are two bits in the mask register: your program should
unmask the 8259's IRQ3 and IRQ4 request lines, without disturbing the mask
bits for the other six request lines (see HINTS
section below). Each of the 2 interrupt service routines should do
the following: display the corresponding interrupt line number on the screen
(for 10 seconds), then clear it from the screen. For example, if
an IRQ3 interrupt occurs, the character 3 should be displayed for 10 seconds,
and if an interrupt from IRQ4 occurs then the character 4 should be displayed
for 10 seconds. In order to control the screen directly, you can
use the following code fragment to display the characters:
-------------------------------
// To display a 3
pokeb(0xB800, 0x860, 0x33);
pokeb(0xB800, 0x861, 0x1F);
// To clear a 3
pokeb(0xB800, 0x860, 0x20);
pokeb(0xB800, 0x861, 0x1F);
// To display a 4
pokeb(0xB800, 0x910, 0x34);
pokeb(0xB800, 0x910, 0x1F);
// To clear a 4
pokeb(0xB800, 0x910, 0x20);
pokeb(0xB800, 0x910, 0x1F);
-------------------------------
The first two parameters in each pokeb command above specify a position on the screen. There are actually two address for each position on the screen: an even value that is specified along with the ASCII code for the character to be displayed (e.g. 0x33 = 3, 0x34 = 4, 0x20 = <space>), and the next highest odd value that is grouped with a control code that specifies how the character is to be displayed (e.g. 0x1F = <white character on a blue background>). The space character is used for blanking a previously displayed digit after 10 seconds. Note: The 3 will be displayed at a different position in the screen than the 4.
Each service routine should should re-enable interrupts using "enable()" so is can be interrupted by IRQ3 and IRQ4.
At the end of each service routine, a non-specific end-of-interrupt (EOI) should be sent to the 8259 (using OCW2).
Your background program, which runs when there are no interrupts being serviced, should display a 4 digit HEX counter on the screen. Your counter should stop when a key is pressed on the PCs keyboard.
Please refer to the "skeleton" program below. You may use it as a framework upon which to develop your software.
Note: at the beginning of your program, you should read the current values of the interrupt vectors associated with IRQ3 and IRQ4 and save them. This will allow you to restore them after your program terminates due to a key being pressed on the keyboard.
DURING
LAB:
1. Set up the circuit with the switches, as shown in the in the
diagram.
2. Run your program. Verify and show your TA that your system
can handle the following:
SKELETON
PROGRAM:
-----------------------------------------------------------
#include <stdio.h>
#include <dos.h>
#define MASK_PORT 0x21
/* 8259 Mask Register Port */
#define MASK_BYTE ??
/* Byte used to unmask interrupts */
#define IVT_INDEX3 ??
/* IBM PC interrupt number for IRQ3 */
#define IVT_INDEX4 ??
/* IBM PC interrupt number for IRQ3 */
/* Storage for old IVT entries */
void (interrupt *old_isr3) (void);
void (interrupt *old_isr4) (void);
void interrupt new_isr3(void)
{
/* Your interrupt
service routine goes here */
/* Remember
no DOS calls are allowed in this region */
outportb(0x20,
0x20);
/* send a non-specific EOI (end of interrupt) */
}
void interrupt new_isr3(void)
{
/* Your interrupt
service routine goes here */
/* Remember
no DOS calls are allowed in this region */
outportb(0x20,
0x20);
/* send a non-specific EOI (end of interrupt) */
}
void main(void)
{
/* Declare variables */
/* Disable interrupts and save old
IVTs */
disable();
old_isr3=getvect(IVT_INDEX3);
old_isr4=getvect(IVT_INDEX4);
/* Place new vectors into table
*/
setvect(IVT_INDEX3,
new_isr3);
setvect(IVT_INDEX4,
new_isr4);
/* Get the mask register */
mask=inportb(MASK_PORT);
/* Set correct bits to INTS=0,
rest=1 */
outportb(MASK_PORT,
?? );
/* Re-enable interrupts */
enable();
........
/* Your background code will go
here */
........
/* Restore old interrupts */
disable();
setvect(IVT_INDEX3,
old_isr3);
setvect(IVT_INDEX4,
old_isr4);
outportb(MASK_PORT,
mask);
enable();
}
---------------------------------------------------------
HINTS:
To set certain bits in a particular byte, just remember that you can
do bit-wise operations. For example, if you want to set bit 4 and 7 to
1 without disturbing the other bits then you could do this in a generic
example:
(pseudo-code)
byte = get_byte();
MASK = 0b10010000
newbyte = byte | MASK
So what you would have is:
| value | operator | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | |
| byte | x | x | x | x | x | x | x | x | ||
| MASK | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | ||
| bit-wise OR | ||||||||||
| newbyte | 1 | x | x | 1 | x | x | x | x |
What this would do is force bits 7 and 4 to be 1 and leave the other
bits the way they were before.