High Speed IRQ Timer/Clock in C

A

Andrew Wan

I found this excellent High Speed Timer (in Pascal). I compiled it
(using Turbo Pascal 7 and it runs fine):

http://www.sorucevap.com/bilisimteknolojisi/programcilik/pascal/ders.asp?207995
and same High Speed Timer here too:
http://groups.google.com/group/comp...1C)+inline($9C)&rnum=1&hl=en#e67ff3cf587648ef

I converted it to C (using p2c), compiled it using Borland C++ 4.5 and
it runs. But it crashes when it gets to setvect(...) in TimerOn.

Does anyone know how IRQ programming works in C? If you know IRQ timer/
clock please contact me. I need urgent help in understanding why it's
not working.
 
A

Andrew Wan

And so we have a translated C code here:
#include "p2c.h"
#include "extra.h"

#define TIMER_G
#include "timer.h"



#define MaxRate 1193180L


void interrupt(__far *OldInt08)();//Static _PROCEDURE OldInt08,
OldInt1C;
void interrupt(__far *OldInt1C)();
Static unsigned short IntCount08, Trigger;
Static boolean TimerAlreadySet;
Static unsigned short Frequency;

void GetIntVec(int a, void interrupt(__far *b)())
{
b = getvect(a);
}

void SetIntVec(int a, void interrupt(__far *b)())
{
setvect(a, b);
}


Static Void IrqOn()
{
/* p2c: timer1.pas, line 37:
* Note: Inline assembly language encountered [254] */
asm{sti;}//asm(" inline $FB");
}


Static Void IrqOff()
{
/* p2c: timer1.pas, line 40:
* Note: Inline assembly language encountered [254] */
asm{cli;}//asm(" inline $FA");
}
/* p2c: timer1.pas, line 43: Note: Ignoring INTERRUPT keyword [258] */


/*$F+*/
void interrupt NewInt1C()//Static Void NewInt1C()
{printf("\nNewInt1C()");
ClockTicks++;
}
/* p2c: timer1.pas, line 50: Note: Ignoring INTERRUPT keyword [258] */


/*$F-*/

/*$F+*/
void interrupt NewInt08()//Static Void NewInt08()
{printf("\nNewInt08()");
IrqOff();
/* p2c: timer1.pas, line 53:
* Note: Inline assembly language encountered [254] */
asm{int 1Ch;}//asm(" inline $CD");
//asm(" inline $1C"); /*Generate INT 1Ch instruction to call
interrupt 1Ch*/
if (IntCount08 == Trigger) {
IntCount08 = 0;
/* p2c: timer1.pas, line 57:
* Note: Inline assembly language encountered [254] */
asm{pushf;}//asm(" inline $9C");
OldInt08();/*if (OldInt08.link != NULL)
(*(Void(*) PP((Anyptr _link)))OldInt08.proc)(OldInt08.link);
else
(*(Void(*) PV())OldInt08.proc)();*/
} else
IntCount08++;
outportb( 0x20, 0x20 );//PORT(0x20) = 0x20; /*Sends non-specific
EOI to the PIC*/
/* p2c: timer1.pas, line 64: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 64: Warning: Invalid assignment [168] */
IrqOn();
}


/*$F-*/

Void TimerOn(Freq)
long Freq;
{
LONGINT Temp = MaxRate;
unsigned short Count;
_PROCEDURE TEMP1;
printf("\nTimerOn()");
if (TimerAlreadySet)
return;
ClockTicks = 0;
IntCount08 = 0;
Frequency = Freq;
Trigger = (long)(Freq / 18.2);
Temp = (long)((double)Temp / Freq);
Count = Temp;
GetIntVec(0x8, OldInt08);
TEMP1.proc = (Anyptr)NewInt08;
TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 83:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x8, NewInt08);//SetIntVec(0x8, TEMP1);
/* p2c: timer1.pas, line 84:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
GetIntVec(0x1c, OldInt1C);
TEMP1.proc = (Anyptr)NewInt1C;
TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 85:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x1c, NewInt1C);//SetIntVec(0x1c, TEMP1);
/* p2c: timer1.pas, line 86:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
outportb( 0x43, 0xb6);
/* p2c: timer1.pas, line 87: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 87: Warning: Invalid assignment [168] */
outportb( 0x40, Count & 255);
/* p2c: timer1.pas, line 88: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 88: Warning: Invalid assignment [168] */
outportb( 0x40, Count >> 8);
/* p2c: timer1.pas, line 89: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 89: Warning: Invalid assignment [168] */
TimerAlreadySet = true;
}


Void TimerOff()
{printf("\nTimerOff()");
if (!TimerAlreadySet)
return;
outportb( 0x43, 0xb6);
/* p2c: timer1.pas, line 98: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 98: Warning: Invalid assignment [168] */
outportb( 0x40, 0xff);
/* p2c: timer1.pas, line 99: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 99: Warning: Invalid assignment [168] */
outportb( 0x40, 0xff);
/* p2c: timer1.pas, line 100: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 100: Warning: Invalid assignment [168] */
SetIntVec(0x8, OldInt08);
/* p2c: timer1.pas, line 101:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
SetIntVec(0x1c, OldInt1C);
/* p2c: timer1.pas, line 102:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
TimerAlreadySet = false;
}


Void ResetTimer()
{
ClockTicks = 0;
}


double TimeElapsed()
{
return ((double)ClockTicks / Frequency);
}


void _Timer_init()
{
static int _was_initialized = 0;
if (_was_initialized++)
return;
TimerAlreadySet = false;
}
/* p2c: Note: Remember to call _Timer_init() in main program [215] */



/* End. */

void main()
{
int i;
_Timer_init();

TimerOn(546);
for(i=0; i<100000; i++) {
if (i%10000==0)
printf("\n... %d", i);
}
TimerOff();

}
 
R

Rod Pemberton

Dropped comp.lang.c++, openwatcom.users.c_cpp NG's. Francis Glassborow
posted to
comp.lang.learn.c-c++,alt.lang.asm,alt.msdos.programmer,comp.os.msdos.progra
mmer NG's, so you may get some responses on those too.

The code is very close to compiling for OpenWatcom. Mostly some incorrect
keywords, wrong location for keywords, and differently named environment
specific functions... You should replace the "Static", "boolean", "Void"
etc. with the correct text instead of using the #define's like I did below.
Many of the functions have K&R style void arg's, e.g., the () in "Static
Void IrqOn()". These should be reworked to "Static Void IrqOn(void)". You
should replace the C++ comments // with C comments /* */ or #if 0 #endif.
Once you get it compile, if it doesn't work as you expect, you can post to
openwatcom.users.c_cpp, alt.os.development, comp.os.msdos.programmer, etc.
for IRQ programming.


Rod Pemberton
And so we have a translated C code here:
#include "p2c.h"
#include "extra.h"

//#include "p2c.h"
//#include "extra.h"
#define TIMER_G
#include "timer.h"

//#include "timer.h"
#define MaxRate 1193180L

#if 1
#define Static static
#define boolean int
#define Void void
#define LONGINT long int
#define getvect _dos_getvect
#define setvect _dos_setvect
#if 0
#define asm _asm
#endif
#define outportb outp
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#define true 1
#define false 0
unsigned long ClockTicks;
#endif

void interrupt(__far *OldInt08)();//Static _PROCEDURE OldInt08,
OldInt1C;

//void interrupt(__far *OldInt08)();//Static _PROCEDURE OldInt08, OldInt1C;
void (__interrupt __far *OldInt08)();
void interrupt(__far *OldInt1C)();

//void interrupt(__far *OldInt1C)();
void (__interrupt __far *OldInt1C)();
Static unsigned short IntCount08, Trigger;
Static boolean TimerAlreadySet;
Static unsigned short Frequency;

void GetIntVec(int a, void interrupt(__far *b)())

//void GetIntVec(int a, void interrupt(__far *b)())
void GetIntVec(int a, void (__interrupt __far *b)())
{
b = getvect(a);
}

void SetIntVec(int a, void interrupt(__far *b)())

//void SetIntVec(int a, void interrupt(__far *b)())
void SetIntVec(int a, void (__interrupt __far *b)())
{
setvect(a, b);
}


Static Void IrqOn()
{
/* p2c: timer1.pas, line 37:
* Note: Inline assembly language encountered [254] */
asm{sti;}//asm(" inline $FB");

//asm{sti;}//asm(" inline $FB");
_asm{sti}
}


Static Void IrqOff()
{
/* p2c: timer1.pas, line 40:
* Note: Inline assembly language encountered [254] */
asm{cli;}//asm(" inline $FA");

//asm{cli;}//asm(" inline $FA");
_asm{cli}
}
/* p2c: timer1.pas, line 43: Note: Ignoring INTERRUPT keyword [258] */


/*$F+*/
void interrupt NewInt1C()//Static Void NewInt1C()
{printf("\nNewInt1C()");
ClockTicks++;
}
/* p2c: timer1.pas, line 50: Note: Ignoring INTERRUPT keyword [258] */


/*$F-*/

/*$F+*/
void interrupt NewInt08()//Static Void NewInt08()
{printf("\nNewInt08()");
IrqOff();
/* p2c: timer1.pas, line 53:
* Note: Inline assembly language encountered [254] */
asm{int 1Ch;}//asm(" inline $CD");

//asm{int 1Ch;}//asm(" inline $CD");
_asm{int 1Ch}
//asm(" inline $1C"); /*Generate INT 1Ch instruction to call
interrupt 1Ch*/
if (IntCount08 == Trigger) {
IntCount08 = 0;
/* p2c: timer1.pas, line 57:
* Note: Inline assembly language encountered [254] */
asm{pushf;}//asm(" inline $9C");

//asm{pushf;}//asm(" inline $9C");
_asm{pushf}
OldInt08();/*if (OldInt08.link != NULL)
(*(Void(*) PP((Anyptr _link)))OldInt08.proc)(OldInt08.link);
else
(*(Void(*) PV())OldInt08.proc)();*/
} else
IntCount08++;
outportb( 0x20, 0x20 );//PORT(0x20) = 0x20; /*Sends non-specific
EOI to the PIC*/
/* p2c: timer1.pas, line 64: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 64: Warning: Invalid assignment [168] */
IrqOn();
}


/*$F-*/

Void TimerOn(Freq)
long Freq;
{
LONGINT Temp = MaxRate;
unsigned short Count;
_PROCEDURE TEMP1;

// _PROCEDURE TEMP1;
printf("\nTimerOn()");
if (TimerAlreadySet)
return;
ClockTicks = 0;
IntCount08 = 0;
Frequency = Freq;
Trigger = (long)(Freq / 18.2);
Temp = (long)((double)Temp / Freq);
Count = Temp;
GetIntVec(0x8, OldInt08);
TEMP1.proc = (Anyptr)NewInt08;
TEMP1.link = (Anyptr)NULL;

//TEMP1.proc = (Anyptr)NewInt08;
//TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 83:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x8, NewInt08);//SetIntVec(0x8, TEMP1);
/* p2c: timer1.pas, line 84:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
GetIntVec(0x1c, OldInt1C);
TEMP1.proc = (Anyptr)NewInt1C;
TEMP1.link = (Anyptr)NULL;

//TEMP1.proc = (Anyptr)NewInt1C;
//TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 85:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x1c, NewInt1C);//SetIntVec(0x1c, TEMP1);
/* p2c: timer1.pas, line 86:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
outportb( 0x43, 0xb6);
/* p2c: timer1.pas, line 87: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 87: Warning: Invalid assignment [168] */
outportb( 0x40, Count & 255);
/* p2c: timer1.pas, line 88: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 88: Warning: Invalid assignment [168] */
outportb( 0x40, Count >> 8);
/* p2c: timer1.pas, line 89: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 89: Warning: Invalid assignment [168] */
TimerAlreadySet = true;
}


Void TimerOff()
{printf("\nTimerOff()");
if (!TimerAlreadySet)
return;
outportb( 0x43, 0xb6);
/* p2c: timer1.pas, line 98: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 98: Warning: Invalid assignment [168] */
outportb( 0x40, 0xff);
/* p2c: timer1.pas, line 99: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 99: Warning: Invalid assignment [168] */
outportb( 0x40, 0xff);
/* p2c: timer1.pas, line 100: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 100: Warning: Invalid assignment [168] */
SetIntVec(0x8, OldInt08);
/* p2c: timer1.pas, line 101:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
SetIntVec(0x1c, OldInt1C);
/* p2c: timer1.pas, line 102:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
TimerAlreadySet = false;
}


Void ResetTimer()
{
ClockTicks = 0;
}


double TimeElapsed()
{
return ((double)ClockTicks / Frequency);
}


void _Timer_init()
{
static int _was_initialized = 0;
if (_was_initialized++)
return;
TimerAlreadySet = false;
}
/* p2c: Note: Remember to call _Timer_init() in main program [215] */



/* End. */

void main()

int main(void)
 
C

CBFalconer

Andrew said:
And so we have a translated C code here:
#include "p2c.h"
#include "extra.h"

#define TIMER_G
#include "timer.h"
.... snip ...

And what does this have to do with the C language?
 
M

Marco van de Voort

... snip ...

And what does this have to do with the C language?

1. Dunno, but neither does it with Pascal language.
2. The OP didn't suffix "-language". That's yours.
 
A

Andrew Wan

1. Dunno, but neither does it with Pascal language.
2. The OP didn't suffix "-language". That's yours.

Rod, thanks for converting the code for OpenWatcom. It compiles fine
under Borland C++ 4.5 and Turbo C 3.0. I posted it to both Pascal & C
newsgroups for help in understanding both low level Pascal & C
language.

I found the closest Turbo C DOS timer source code written by David
Oshinsky at:

http://www.bookcase.com/library/software/msdos.devel.apps.turbo- c.html (TIMERTST)

To get my own timer (original Pascal port) I had to comment out
asm{ int 1Ch;} & asm{pushf;} in NewInt08() function. Also I had to
omit all debugging printfs in the interrupt functions. Afterwards my
program doesn't crash anymore.

What am wondering is:

1. In Pascal version it uses inline($CD / $1C); & inline($9C); before
the OldInt08() call. I though I could call the equivalent asm{ int
1Ch;} & asm{pushf;} but I guess this was wrong since it crashed my
program. Is there an inline assembly call in C?

2. David's initializing the timer code uses
Code:
/* Set up 8259 PIC chip to allow INT0 interrupt. */
outportb(0x21, inportb(0x21) & 0xfe);

/* issue command to 8253:  counter 0, binary counter, rate generator
*/
/* (mode 2), load least significant byte of counter followed by
*/
/* most significant byte                         */
outportb(0x43, 0x34);

/* Timer is set for 0x4cd * 813.8 ns = 1 ms (LSB followed by MSB). */
outportb(0x40, 0xcd); /* least significant byte of timer count */
outportb(0x40, 0x04); /* most significant byte of timer count  */
But mine uses
Code:
outportb( 0x43, 0xb6);
outportb( 0x40, Count & 255);
outportb( 0x40, Count >> 8);
What is the difference? Even though both works.

3. Same goes for the clean up code:
His is:
Code:
/* restore 8253 to original state set during PC boot  */
/* NOTE:  this program leaves 8259 mask register with */
/* least significant bit clear (i.e., INT0 enabled).  */
outportb(0x43, 0x34);
outportb(0x40, 0);
outportb(0x40, 0);
Mine is:
Code:
outportb( 0x43, 0xb6);
outportb( 0x40, 0xff);
outportb( 0x40, 0xff);
Again both works but I don't understand why different?
 
M

Marco van de Voort

What am wondering is:

1. In Pascal version it uses inline($CD / $1C); & inline($9C); before
the OldInt08() call. I though I could call the equivalent asm{ int
1Ch;} & asm{pushf;} but I guess this was wrong since it crashed my
program. Is there an inline assembly call in C?

TP has support for interrupt routines, that end with "Retf" instead of
"Ret". It could be that the C compiler did it differently, or somehow reacts
more badly to the stack modification.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top