delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2001/01/15/05:45:33

From: paul DOT crone AT thomson-csf DOT no
Message-Id: <200101151041.LAA31499@alcatel.no>
To: djgpp AT delorie DOT com
Subject: Problem using timer and irq routines from Allegro
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.5.2650.21)
Date: Mon, 15 Jan 2001 11:35:15 +0100
Reply-To: djgpp AT delorie DOT com

I have a problem that I've been trying to resolve for some time.  This is a 
test harness program to test a timer routine using the Allegro timer.c,
irq.c and irqwrap.S files.  I want to use them in my program.

The program runs and apparently installs the timer and irq's.  My problem is

that I don't get any interrupt 'timerRCU' callbacks and so the printf
statement
never prints.

Please can anyone see the disconnection.

Thanks for your help. 

Paul

(Sorry about all the lines of code.  Should be split into...
 control.c, irq.c, irqwrap.S, timer.c, irq.h, irqwrap.h. timer.h, defines.h)

//**************************************************************************
***
//      DOS timer control test harness. 
//		file: control.c
//
#include "timer.h"
#include "irq.h"

void timerRCU(void);
void timerRCU_end(void);

volatile int periodTimer = 0;
int clockTimer = 0;

int main(int argc, char **argv )
{
  installTimer();

  LOCK_FUNCTION(timerRCU);
  LOCK_VARIABLE(periodTimer);
	
  if (installInt(timerRCU, 1) == -1)
     printf("ERROR: Unable to load timer\n");

  do {
     if (periodTimer >= 10)
     {
        printf("clock %d\r",clockTimer++);
        periodTimer = 0;
     }
  } while (!kbhit());
}

void timerRCU(void)
{
  periodTimer++;
}

void timerRCU_end(void) {}

//**************************************************************************
***
//      DOS irq interrupt routines. 
//		file: irq.c
//
#include <sys/segments.h>
#include <dpmi.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/movedata.h>
#include "irqwrap.h"
#include "irq.h"

#define ASSERT(x)  assert(x)
#define STACK_SIZE  (4 * 1024)  /* 4k stack should be plenty */
#define TRUE 1
#define FALSE 0
#define PADDR_NULL {0, 0}  /* offset32, selector */

__dpmi_paddr OldIRQVectors[16] =
{
  PADDR_NULL, PADDR_NULL, PADDR_NULL, PADDR_NULL,
  PADDR_NULL, PADDR_NULL, PADDR_NULL, PADDR_NULL,
  PADDR_NULL, PADDR_NULL, PADDR_NULL, PADDR_NULL,
  PADDR_NULL, PADDR_NULL, PADDR_NULL, PADDR_NULL
};

void *IRQStacks[IRQ_STACKS];
static int bInitIRQ = FALSE;

//_________
// LockData
int LockData(void *a, long size)
{
  unsigned long baseaddr;
  __dpmi_meminfo region;

  if (__dpmi_get_segment_base_address(_my_ds(), &baseaddr) == -1)
    return (-1);

  region.handle = 0;
  region.size = size;
  region.address = baseaddr + (unsigned long)a;

  if (__dpmi_lock_linear_region(&region) == -1)
    return (-1);
  return (0);
}

//_________
// LockCode
int LockCode(void *a, long size)
{
  unsigned long baseaddr;
  __dpmi_meminfo region;

  if (__dpmi_get_segment_base_address(_my_cs(), &baseaddr) == -1)
    return (-1);

  region.handle = 0;
  region.size = size;
  region.address = baseaddr + (unsigned long)a;

  if (__dpmi_lock_linear_region(&region) == -1)
    return (-1);

  return (0);
}

//___________
// UnlockData
int UnlockData(void *a, long size)
{
  unsigned long baseaddr;
  __dpmi_meminfo region;

  if (__dpmi_get_segment_base_address(_my_ds(), &baseaddr) == -1)
    return (-1);

  region.handle = 0;
  region.size = size;
  region.address = baseaddr + (unsigned long)a;

  if (__dpmi_unlock_linear_region(&region) == -1)
    return (-1);

  return (0);
}

//___________
// UnlockCode
int UnlockCode(void *a, long size)
{
  unsigned long baseaddr;
  __dpmi_meminfo region;

  if (__dpmi_get_segment_base_address(_my_cs(), &baseaddr) == -1)
    return (-1);

  region.handle = 0;
  region.size = size;
  region.address = baseaddr + (unsigned long)a;

  if (__dpmi_unlock_linear_region(&region) == -1)
    return (-1);

  return (0);
}

/* Forward definitions */
static int InitIRQ(void);
static void ShutDownIRQ(void);

//___________
// InstallIRQ
int InstallIRQ(int nIRQ, int (*IRQHandler)(void))
{
  int nIRQVect;
  __dpmi_paddr IRQWrapAddr;

  ASSERT(nIRQ >= 0 && nIRQ < 16);
  ASSERT(OldIRQVectors[nIRQ].selector == 0);
  ASSERT(IRQHandler != NULL);
  ASSERT(IRQHandlers[nIRQ] == NULL);

  if (!bInitIRQ)
    if (!InitIRQ())
	return (FALSE);

  if (nIRQ > 7)
    nIRQVect = 0x70 + (nIRQ - 8);
  else
    nIRQVect = 0x8 + nIRQ;

  IRQWrapAddr.selector = _my_cs();
  IRQWrapAddr.offset32 = (int)IRQWrappers[nIRQ];
  __dpmi_get_protected_mode_interrupt_vector(nIRQVect,
&OldIRQVectors[nIRQ]);
  IRQHandlers[nIRQ] = IRQHandler;  /* IRQWrapper will call IRQHandler */
  __dpmi_set_protected_mode_interrupt_vector(nIRQVect, &IRQWrapAddr);
  return (TRUE);
}

//_____________
// UninstallIRQ
void UninstallIRQ(int nIRQ)
{
  int nIRQVect;
  int i;

  ASSERT(bInitIRQ);
  ASSERT(nIRQ < 16 && nIRQ >= 0);
  ASSERT(IRQHandlers[nIRQ] != NULL);

  if (nIRQ > 7)
    nIRQVect = 0x70 + (nIRQ - 8);
  else
    nIRQVect = 0x8 + nIRQ;

  __dpmi_set_protected_mode_interrupt_vector(nIRQVect,
&OldIRQVectors[nIRQ]);
  IRQHandlers[nIRQ] = NULL;

  /* Check whether all the IRQs are uninstalled and call ShutDownIRQ(). */
  for (i = 0; i < 16; ++i)
    if (IRQHandlers[i] != NULL)
      return;  /* Still remains a handler */
  ShutDownIRQ();
}

extern void IRQWrap(void);
extern void IRQWrap_end(void);

//________
// InitIRQ
static int InitIRQ(void)
{
  int i;

  if (LOCK_VARIABLE(IRQWrappers) == -1)
    return (FALSE);
  if (LOCK_VARIABLE(IRQHandlers) == -1)
    return (FALSE);
  if (LOCK_VARIABLE(OldIRQVectors) == -1)
    return (FALSE);
  if (LOCK_FUNCTION(IRQWrap) == -1)
    return (FALSE);

  for (i = 0; i < IRQ_STACKS; ++i)
  {
    if ((IRQStacks[i] = malloc(STACK_SIZE)) == NULL)
    {
fail:
      for (--i; i >= 0; --i)  /* Free what was allocated */
        free((char *)IRQStacks[i] - (STACK_SIZE - 16));
      return (FALSE);
    }
    if (LockData(IRQStacks[i], STACK_SIZE) == -1)
    {
      free(IRQStacks[i]);  /* Successfully allocated but not locked! */
      goto fail;
    }
    (char *)IRQStacks[i] += (STACK_SIZE - 16);
  }
  bInitIRQ = TRUE;
  return (TRUE);
}

//____________
// ShutDownIRQ
static void ShutDownIRQ(void)
{
  int i;
  char *p;

  ASSERT(bInitIRQ);

  for (i = 0; i	< IRQ_STACKS; ++i)
  {
    ASSERT(IRQStacks[i] != NULL);
    p = (char *)IRQStacks[i] - (STACK_SIZE - 16);
    free(p);
  }
  bInitIRQ = FALSE;
}

//**************************************************************************
***
//      DOS irq wrapper routines. 
//		file: irqwrap.S
//
.data
_IRQWrappers:
	.long	_IRQWrap0,  _IRQWrap1,  _IRQWrap2,  _IRQWrap3
	.long	_IRQWrap4,  _IRQWrap5,  _IRQWrap6,  _IRQWrap7
	.long	_IRQWrap8,  _IRQWrap9,  _IRQWrap10, _IRQWrap11
	.long	_IRQWrap12, _IRQWrap13, _IRQWrap14, _IRQWrap15

_IRQHandlers:
	.long	0, 0, 0, 0  /* 0 - 3 */
	.long	0, 0, 0, 0	/* 4 - 7 */
	.long	0, 0, 0, 0	/* 8 - 11 */
	.long	0, 0, 0, 0	/* 12 - 15 */

	.globl	_IRQWrappers
	.globl	_IRQHandlers
	.globl	_IRQWrap
	.globl	_IRQWrap_end

#define IRQ_STACKS      8

.text
#define IRQWRAP(x)
; \
_IRQWrap##x:
; \
	pushw	%ds						/* save
registers */			; \
	pushw	%es
; \
	pushw	%fs
; \
	pushw	%gs
; \
	pushal
; \
	/* __djgpp_ds_alias is irq sequred selector (see exceptn.h) */	; \
	movw	%cs:___djgpp_ds_alias, %ax
; \
	movw	%ax, %ds				/* set up selectors
*/			; \
	movw	%ax, %es
; \
	movw	%ax, %fs
; \
	movw	%ax, %gs
; \
	

	

	

	
;
	
\
	movl	$(IRQ_STACKS - 1), %ecx	/* look for a free stack */
; \
	/* Search from the last toward the first */
; \
StackSearchLoop##x:
; \
	leal	_IRQStacks(, %ecx, 4), %ebx
; \
	cmpl	$0, (%ebx)
; \
	jnz	FoundStack##x				/* found one! */
; \
	

	

	

	
;
	
\
	decl	%ecx					/* backward */
; \
	jnz	StackSearchLoop##x
; \
	

	

	

	
;
	
\
	jmp	GetOut##x					/* No free
stack! */			; \
	

	

	

	
;
	
\
FoundStack##x:
; \
	movl	%esp, %ecx				/* save old stack in
ecx:dx */	; \
	movw	%ss, %dx
; \
	

	

	

	
;
	
\
	movl	(%ebx), %esp			/* set up our stack */
; \
	movw	%ax, %ss
; \
	

	

	

	
;
	
\
	movl	$0, (%ebx)				/* flag the stack is
in use */	; \
	

	

	

	
;
	
\
	pushl	%edx					/* push old stack
onto new */	; \
	pushl	%ecx
; \
	pushl	%ebx
; \
	

	

	

	
;
	
\
	cld								/*
clear the direction flag */	; \
	

	

	

	
;
	
\
	movl	_IRQHandlers + 4 * x, %eax
; \
	call	*%eax					/* call the C
handler */		; \
	cli
; \
	popl	%ebx					/* restore the old
stack */		; \
	popl	%ecx
; \
	popl	%edx
; \
	movl	%esp, (%ebx)
; \
	movw	%dx, %ss
; \
	movl	%ecx, %esp
; \
	

	

	

	
;
	
\
	orl	%eax, %eax					/* check
return value */		; \
	jz	GetOut##x
; \
	

	

	

	
;
	
\
	popal							/* chain to
old handler */		; \
	popw	%gs
; \
	popw	%fs
; \
	popw	%es
; \
	popw	%ds
; \
									/* 8
=
	
sizeof(__dpmi_padd
									r)
*/	; \
	ljmp	*%cs:_OldIRQVectors + 8 * x
; \
	

	

	

	
;
	
\
GetOut##x:
; \
	popal							/* iret */
; \
	popw	%gs
; \
	popw	%fs
; \
	popw	%es
; \
	popw	%ds
; \
	sti
; \
	iret

_IRQWrap:
	.byte	0

IRQWRAP(0);
IRQWRAP(1);
IRQWRAP(2);
IRQWRAP(3);
IRQWRAP(4);
IRQWRAP(5);
IRQWRAP(6);
IRQWRAP(7);
IRQWRAP(8);
IRQWRAP(9);
IRQWRAP(10);
IRQWRAP(11);
IRQWRAP(12);
IRQWRAP(13);
IRQWRAP(14);
IRQWRAP(15);

_IRQWrap_end:
	.byte	0

//**************************************************************************
***
//      DOS timer interrupt routines. 
//		file: timer.c
//
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <go32.h>
#include <dpmi.h>

#include "timer.h"
#include "irq.h"
#include "defines.h"

#define DISABLE()   asm volatile ("cli")
#define ENABLE()    asm volatile ("sti")

#define MAX_TIMERS					16
#define TIMER_INT					8
#define TIMERS_PER_SECOND			1193181L
#define SECS_TO_TIMER(x)			((long)(x *
TIMERS_PER_SECOND))
#define MSEC_TO_TIMER(x)			((long)(x) *
(TIMERS_PER_SECOND / 1000))	// use whole ms units
only
#define BPS_TO_TIMER(x)				(TIMERS_PER_SECOND /
(long)(x))
#define BPM_TO_TIMER(x)				((60 * TIMERS_PER_SECOND) /
(long)(x))
#define WINDOWS_TIMER_SPEED			BPS_TO_TIMER(200)
#define TIMER_REENTRANT_RECALL_GAP  2500

static int timerInstalled = FALSE;

static int windowsFriendlyTimerMode = FALSE;

static long biosCounter;					// keep BIOS
time up to date
static long timerDelay;						// how long
between interrupts
static int timerSemaphore = FALSE;			// reentrant
interrupt?

static int timerClockingLoss = 0;			// unmeasured time
that gets lost

static struct								//
list of active callbacks
{
	void ((*proc)());
	long speed;
	long counter;
} myIntQueue[MAX_TIMERS];

static struct								//
list of to-be-added callbacks
{
	void ((*proc)());
	long speed;
} waitingList[MAX_TIMERS];

static int waitingListSize = 0;

//_________
// setTimer
static inline void setTimer(long time)
{
printf("setTimer\n");
	outportb(0x43, 0x30);
	outportb(0x40, time & 0xff);
	outportb(0x40, time >> 8);
}

//_____________
// setTimerRate
static inline void setTimerRate(long time)
{
	outportb(0x43, 0x34);
	outportb(0x40, time & 0xff);
	outportb(0x40, time >> 8);
}

//__________
// readTimer
static inline long readTimer()
{
	long x;

	outportb(0x43, 0x00);
	x = inportb(0x40);
	x += inportb(0x40) << 8;
	return (0xFFFF - x + 1) & 0xFFFF;
}

//___________
// myTimerInt
static int myTimerInt()
{
	long newDelay = 0x8000;
	int callback[MAX_TIMERS];
	int bios = FALSE;
	int x;

	// reentrant interrupt?
	if (timerSemaphore)
	{
		if (windowsFriendlyTimerMode)
		{
			timerDelay += WINDOWS_TIMER_SPEED;
		}
		else
		{
			timerDelay +=
TIMER_REENTRANT_RECALL_GAP+readTimer();
	
setTimer(TIMER_REENTRANT_RECALL_GAP-timerClockingLoss/2);
		}
		outportb(0x20, 0x20); 
		return 0;
	}

	timerSemaphore = TRUE;

	if (!windowsFriendlyTimerMode)
	{
		timerDelay += readTimer()+timerClockingLoss;
		setTimer(0);
	}

	// process the user callbacks
	for (x=0; x<MAX_TIMERS; x++)
	{ 
		callback[x] = 0;

		if ((myIntQueue[x].proc) && (myIntQueue[x].speed > 0))
		{
			myIntQueue[x].counter -= timerDelay;

			while (myIntQueue[x].counter <= 0)
			{
				myIntQueue[x].counter +=
myIntQueue[x].speed;
				callback[x]++;
			}

			if (myIntQueue[x].counter < newDelay)
				newDelay = myIntQueue[x].counter;
		}
	}

	// update bios time
	biosCounter -= timerDelay; 

	if (biosCounter <= 0)
	{
		biosCounter += 0x10000;
		bios = TRUE;
	}

	if (biosCounter < newDelay)
		newDelay = biosCounter;

	// fudge factor to prevent interrupts coming too close to each other
	if (newDelay < 1024)
		timerDelay = 1024;
	else
		timerDelay = newDelay;

	// start the timer up again
	if (windowsFriendlyTimerMode)
	{
		timerDelay = WINDOWS_TIMER_SPEED;
	}
	else
	{
		newDelay = readTimer();
		setTimer(timerDelay);
		timerDelay += newDelay;
	}

	if (!bios)
	{
		outportb(0x20, 0x20);			// ack. the
interrupt
		ENABLE();
	}

	// finally call the user timer routines
	for (x=0; x<MAX_TIMERS; x++)
	{
		while (callback[x])
		{
			myIntQueue[x].proc();
			callback[x]--;
		}
	}

	if (!bios)
		DISABLE();

	timerSemaphore = FALSE;
	return bios;
}
END_OF_FUNCTION(myTimerInt);

//________________
// findTimerSlot
static int findTimerSlot(void (*proc)())
{
	int x;

	for (x=0; x<MAX_TIMERS; x++)
	{
		if (myIntQueue[x].proc == proc)
			return x;
	}
	return -1;
}
END_OF_FUNCTION(findTimerSlot);

//______________
// installIntEx
int installIntEx(void (*proc)(), long speed)
{
	int x;

	if (!timerInstalled)
	{
		// we are not alive yet: flag this callback to be started
later
		if (waitingListSize >= MAX_TIMERS)
			return -1;

		waitingList[waitingListSize].proc = proc;
		waitingList[waitingListSize].speed = speed;
		waitingListSize++;
		return 0;
	}

	x = findTimerSlot(proc);				// find the
handler position

	if (x < 0)
// if not there, find free slot
		x = findTimerSlot(NULL);

	if (x < 0)
// are there any free slots?
		return -1;

	if (proc != myIntQueue[x].proc)			// add new entry
	{
		myIntQueue[x].counter = speed;
		myIntQueue[x].proc = proc; 
	}
	else
	{
// alter speed of existing entry
		myIntQueue[x].counter -= myIntQueue[x].speed;
		myIntQueue[x].counter += speed;
	}

	myIntQueue[x].speed = speed;
	return 0;
}
END_OF_FUNCTION(installIntEx);

//___________
// installInt
int installInt(void (*proc)(), long speed)
{
	return installIntEx(proc, MSEC_TO_TIMER(speed));
}
END_OF_FUNCTION(installInt);

//__________
// removeInt
void removeInt(void (*proc)())
{
	int x = findTimerSlot(proc);

	if (x >= 0)
	{
		myIntQueue[x].proc = NULL;
		myIntQueue[x].speed = 0;
		myIntQueue[x].counter = 0;
	}
}
END_OF_FUNCTION(removeInt);

//_____________
// installTimer
int installTimer()
{
	int x, y;

	if (timerInstalled)
		return -1;

	for (x=0; x<MAX_TIMERS; x++)
	{
		myIntQueue[x].proc = NULL;
		myIntQueue[x].speed = 0;
		myIntQueue[x].counter = 0;
	}

	LOCK_VARIABLE(biosCounter);
	LOCK_VARIABLE(timerDelay);
	LOCK_VARIABLE(windowsFriendlyTimerMode);
	LOCK_VARIABLE(myIntQueue);
	LOCK_VARIABLE(timerSemaphore);
	LOCK_VARIABLE(timerClockingLoss);
	LOCK_VARIABLE(restCount);
	LOCK_FUNCTION(restInt);
	LOCK_FUNCTION(myTimerInt);
	LOCK_FUNCTION(findTimerSlot);
	LOCK_FUNCTION(installIntEx);
	LOCK_FUNCTION(installInt);
	LOCK_FUNCTION(removeInt);

	biosCounter = 0x10000;

	if (windowsFriendlyTimerMode)
		timerDelay = WINDOWS_TIMER_SPEED;
	else
		timerDelay = 0x10000;

	if (!InstallIRQ(TIMER_INT, myTimerInt))
		return -1;

	DISABLE();
	if (!windowsFriendlyTimerMode)
	{
		// now work out how much time calls to the 8254 clock chip
take 
		// on this CPU/motherboard combination. It is impossible to
time 
		// a setTimer call so we approximate it by a readTimer call
with 
		// 4/5ths of a readTimer (no maths and no final read wait).
This 
		// gives 9/10ths of 4 readTimers. Do it three times all over
to 
		// get an averaging effect.
		x = readTimer() & 0xFFFF;
		readTimer();
		readTimer();
		readTimer();
		y = readTimer();
		readTimer();
		readTimer();
		readTimer();
		y = readTimer();
		readTimer();
		readTimer();
		readTimer();
		y = readTimer();

		if (y >= x)
			timerClockingLoss = y - x;
		else
			timerClockingLoss = 0x10000 - x + y;

		timerClockingLoss = (9*timerClockingLoss)/30;
	}

	// sometimes it doesn't seem to register if we only do this once...
	for (x=0; x<4; x++)
	{
		if (windowsFriendlyTimerMode)
			setTimerRate(timerDelay);
		else
			setTimer(timerDelay);
	}

	ENABLE();
	timerInstalled = TRUE;

	// activate any waiting callback functions
	for (x=0; x<waitingListSize; x++)
		installIntEx(waitingList[x].proc, waitingList[x].speed);

	waitingListSize = 0;
	return 0;
}

//**************************************************************************
***
//		file: irq.h
//
#ifndef IRQ_H
#define IRQ_H

int LockData(void *a, long size);
int LockCode(void *a, long size);
int UnlockData(void *a, long size);
int UnlockCode(void *a, long size);

#define END_OF_FUNCTION(x)    static void x##_end() { }
#define LOCK_VARIABLE(x)  LockData((void *)&x, sizeof(x))
#define LOCK_FUNCTION(x)  LockCode(x, (long)x##_end - (long)x)

int InstallIRQ(int nIRQ, int (*IRQHandler)(void));
void UninstallIRQ(int nIRQ);
#endif 

//**************************************************************************
***
//		file: irqwrap.h
//
#define IRQ_STACKS      8

extern void *IRQStacks[IRQ_STACKS];
typedef int (*TIRQHandler)(void);
typedef void (*TIRQWrapper)(void);
extern TIRQHandler IRQHandlers[16];
extern TIRQWrapper IRQWrappers[16];

//**************************************************************************
***
//		file: irqwrap.h
//
#ifndef TIMER_H
#define TIMER_H

int installTimer(void);
void removeTimer(void);

int installIntEx(void (*proc)(void), long speed);
int installInt(void (*proc)(void), long speed);
void removeInt(void (*proc)(void));
#endif 

//**************************************************************************
***
//		file: defines.h
//
#ifndef DEFINES_H
#define DEFINES_H

#define TRUE 	1
#define FALSE 	0
#endif

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019