DOS For Embedded Systems: Interrupt Latencies
by Shai Vaingast and Ehud Cohen


Listing One
function y=unwrap(x)
% function y=unwrap(x)
% returns vector y unfolded around 65536

d=diff(x(:));
I=find(d<0);
d(I)=d(I)+65536;
y=cumsum([x(1); d]);

Listing Two
/* INT_LATE.C. Measures interrupt latencies in DOS during disk access.
  The program hooks interrupt 0x8 (CTC channel 0) to generate interrupts at a 
  rate of approximately 66 uSec (80 ticks).  It then measures the time at 
  which interrupts are received (using CTC channel 2 as an accurate timing 
  mechanism) while writing a file to disk.
  Notes:
  1. Must be compiled with 16 bit DOS compiler.
     It was tested on Borland C++ 3.1 and Visual C++ 1.5.
  2. You can NOT compile this program with Test Stack Overflow turned on and 
     get an executable file which will operate correctly. 
  3. The BIOS time is dependent upon interrupt 0x8 and CTC channel 0 values. 
     Therefore system time may be inaccurate after running this program.  
     To maintain an accurate clock, set the correct time after running this 
     program.
*/
#include <stdio.h>
#include <dos.h>

/* interrupt related definitions */
#define CLK_TICK_INT  0x08    /* The clock tick interrupt               */
#define PIC           0x20    /* Programmable Interrupt Controller port */
#define EOI           0x20    /* End Of Interrupts for PIC              */

/* CTC related definitions and macros */
#define MCR           0x43    /* The Counter/Timer Chip register        */
#define PORTB         0x61    /* "Port B" for enabling Channel 2        */
/* a macro for latching the CTC and reading the count in progress       */
#define LATCH_CTC(channel) ((channel)<<6)

/* PROGRAM_CTC macro
   0x34 = 0b00110100 meaning (from MSB to LSB): 
   00 : channel
   11 : access mode=low and high byte,
   010: mode=rate generator
   0  : count in binary
   Refer to 8253/4 documentation for other values
*/
#define PROGRAM_CTC(channel) (((channel)<<6) | 0x34)


#define CTC_PORT(channel) (0x40|(channel))

#define BUF_SIZE   ((int)4096)

/* 'iCount_G' is accessed in the ISR and in main() so it should be volatile */
int volatile iCount_G=0;

/* buffers to store high and low values of CTC channel 2 */
unsigned char auchLoWord_G[BUF_SIZE], auchHiWord_G[BUF_SIZE];

void interrupt handler()
{
  if(iCount_G<BUF_SIZE) 
    {
      /* read channel 2 counter*/
      outp(MCR, LATCH_CTC(2));
      auchLoWord_G[iCount_G] = inp(CTC_PORT(2));
      auchHiWord_G[iCount_G] = inp(CTC_PORT(2));
    }
  iCount_G++;

  outp(PIC,EOI);
  _enable();
}
int main()
{
  FILE *fOutData;
  unsigned char ucIntRate=80;
  int iIndex;
  void (_interrupt *oldhandler)();

  /* save the old interrupt handler our interrupt handler */
  oldhandler = _dos_getvect(CLK_TICK_INT);
  _dos_setvect(CLK_TICK_INT, handler);

  /* program CTC channel 0 to generate interrupts at 'ucIntRate' */
  _disable();

  outp(MCR, PROGRAM_CTC(0));
  outp(CTC_PORT(0), ucIntRate);
  outp(CTC_PORT(0), 0);
  
  /* program CTC channel 2 to count wrap at 65536 */
  outp(MCR, PROGRAM_CTC(2));
  outp(CTC_PORT(2), 0x0);
  outp(CTC_PORT(2), 0x0);

  _enable();

  /* enable CTC channel 2 */
  outp(PORTB, 1);

  /* loop until a quarter of the buffer is full */
  while(iCount_G<(BUF_SIZE>>2));

  /* access disk to measure interrupt latencies by writing a dummy file */
  if(NULL==(fOutData=fopen("INT_LATE.TMP","wb")))
    {
      printf("Can't create file INT_LATE.TMP.\n");
      return 0;
    }
  fwrite(auchLoWord_G, BUF_SIZE, 1, fOutData);
  fclose(fOutData);

  /* loop until buffer is full */
  while(iCount_G<BUF_SIZE);

  /* restore the CTC channel 0 value */
  _disable();
  outp(MCR, PROGRAM_CTC(0));
  outp(CTC_PORT(0), 0);
  outp(CTC_PORT(0), 0);
  _enable();

  /* restore the old interrupt handler */
  _dos_setvect(CLK_TICK_INT, oldhandler);
  
  /* write buffer to file */
  if(NULL==(fOutData=fopen("INT_LATE.DAT","wt")))
    {
      printf("Can't create file INT_LATE.DAT.\n");
      return 0;
    }
  for(iIndex=0; iIndex<BUF_SIZE; iIndex++)
    fprintf(fOutData,"%d\n",(((short)auchHiWord_G[iIndex])<<8) | 
        auchLoWord_G[iIndex]);
  fclose(fOutData);
  printf("Data written to file INT_LATE.DAT\n");
  return 0;
}



3

