Graphics by Lord Azathoth

Handling the interrupts
For writing a game is necessary to handling particulary interrupts, expecially the timer and the keyboard interrupts. In this section I'll explain how to handling this interrupts with the DJGPP in protected mode.
Handling the timer
A great vantage of the new computers is the speed of computing, but for the games this is a trouble. Have you ever played an old game on a new Pentium 133Mhz? Surely the speed of the game was too up to play...
For resolving the problem of syncronization we can use the timer interrupt. This interrupt (INT 08h) is issued by the hardware about 18.2 times/sec, but we can program the speed of issuing. For handling an interrupt we must first save the address of the old handler, install the new handler and last, before the exit of the program, reinstall the old handler. So we can build two functions like these:

    void init_handler(void)
    {
       new_handler.pm_offset = (int)new_handler;
       new_handler.pm_selector = _go32_my_cs();
       _go32_dpmi_get_protected_mode_interrupt_vector(0x08, &old_handler);
       _go32_dpmi_allocate_iret_wrapper(&new_handler);
       _go32_dpmi_set_protected_mode_interrupt_vector(0x08, &new_handler);
    }

    void done_handler(void)
    {
       _go32_dpmi_set_protected_mode_interrupt_vector(0x08, &old_handler);
       _go32_dpmi_free_iret_wrapper(&new_handler);
    }

The structure of an interrupt handler is very simple: saving the registers, handling and restore the registers:

    void new_handler(void)
    {
       asm("cli; pusha");      // Saving the register and disabiliting the interrupts

       // Place here the code
       outportb(0x20, 0x20);   // EOI if is a hardware interrupt

       asm("popa; sti");       // Restoring the registers and abiliting the interrupts
    }

Well, for syncrinozing we must count the number of issuing of the timer in a variable (eg. `timer_tick`) and control in the game if the variable is true before advance in the elaboration of the game data:

    while(!quit)
       while(!timer_tick);
       timer_tick=0;
       .
       .
       // Code of the game
    }

Setting up the speed of the timer
The hardware have a timer chip (8253 or 8254) with tree channels:

1. Channel 0: the system timer (or int 08h). We use this channels for programming.
2. Channel 1: RAM refresh. Don't touch.....
3. Channel 2: controls the frequency generation of the PC speaker. Try it for good sounds!

This chip have a frequency input of 1.19318 Mhz and we can program the channels to divide this frequency for generating the speed that we want. The 8253 have four ports: from 40h to 43h. With the ports 40h..42h we program the frequency divisor of the channels, but first we must use the port 43h for prepare the chip in this mode:

- bits 7 - 6: channel selector:
  - 00: channel 0
  - 01: channel 1 (don't use!)
  - 02: channel 2
- bits 5 - 4: operation selector:
  - 00: save the counter (or divisor) for reading
  - 01: enable the writing of the high byte of the counter
  - 10: enable the writing of the low byte of the counter
  - 11: enable the writing of the low byte and next of the high byte
- bits 3 - 1: function mode selector (from 000 to 101)
- bit 0: counter mode:
  - 0: binary
  - 1: BCD

Well, for programming the timer at a speed tree times up the default we must write the value 05555h in the counter:

       asm("cli");
       outportb(0x43, 0x36);
       outportb(0x40, 0x55);
       outportb(0x40, 0x55);
       asm("sti");

And for restore the default speed we must write the value 0000h:

       asm("cli");
       outportb(0x43, 0x36);
       outportb(0x40, 0);
       outportb(0x40, 0);
       asm("sti");

Handling the keyboard
For each key pressed or released an interrupt (INT 09h) is issued by the keyboard controller. When the interrupt is issued we can read the value of the key pressed/released from the port 60h: if the 7th bit is set the key is released, else is pressed. So we can register multiple keys pressions and the sequence of the last n key pressed in this way:

    void keyboard_handler(void)
    {
       BYTE al, ah;
       asm("cli; pusha");

       // Read the key from the keyboard controller
       last_key=inportb(0x60);

       // Check if the key is pressed (bit 7 = 0) or released (bit 7 = 1)
       if(last_key<128) {
          key_status[last_key]=TRUE;          // Update the status

          // Insert in the key sequence
          for(al=SEQUENCE_LENGTH-1;al>0;al--)
             key_sequence[al]=key_sequence[al-1];
          key_sequence[0]=last_key;
       } else key_status[last_key-128]=FALSE; // Update the status

       // Tell to the controller that the key code is readed
       al=inportb(0x61);
       al|=0x82;
       outportb(0x61,al);
       al&=0x7F;
       outportb(0x61,al);

       key_delay_count=0;      // Recounting
       outportb(0x20, 0x20);   // EOI
       asm("popa; sti");
    }

For the right detection of the key sequence we must add some lines of code in the timer handler, where every n issues insert a NULL key in the sequence:

    if(++key_delay_count>key_delay) {
       for(i=SEQUENCE_LENGTH-1;i>0;i--)
          key_sequence[i]=key_sequence[i-1];
       key_sequence[0]=0x00;
       key_delay_count=0;
    }

Press here to download the source of the demo program.

[main] [prec] [next] [email]
Site Made and Maintained by The Dark Angel <DarkAngel@tin.it>
My ICQ Number is 2063026
You Visited This Page
times
This page hosted by Get your own Free Home Page