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) Content-Type: text/plain; charset="iso-8859-1" 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 #include #include #include #include #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(®ion) == -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(®ion) == -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(®ion) == -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(®ion) == -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 #include #include #include #include #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 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) 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= 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