CODE: [Copy to clipboard]
001 #include <stdio.h>
002 #include <dos.h>
003 #include <string.h>
004 #include <dpmi.h>
005 #include <pc.h>
006 void pm_new8h(void);
007 void lock_pm_new8h(void);
008 void pm_new70h(void);
009 void lock_pm_new70h(void);
010 char *get_cmostime(void);
011 #define IRQ0 0x8 // 8254 time interrupt
012 #define IRQ8 0x70 // Real time interrupt
013 #define PIT0 0x40 // 8254 timer0
014 #define PITMODE 0x43 // 8254 control word
/* 8254 controll word
bit 7:6 timer number 00--timer0 01--timer1 10--timer2
bit 5:4 latch,read format;
00--latch current count;
01--write low byte(no latching);
10--write high byte(no latching);
11--write low,then high byte
bit 3:1 mode number;
000--interrupt on terminal count;
001--programmable one-shot;
010--rate generator
011--sequare wave generator;
100--software triggered strobe;
101--hardware triggered strobe
bit 0 count byte; 0--binary 1--bcd
*/
015 #define IMR0 0x21 // IMR of 8259-0
016 #define IMR1 0xa1 // IMR of 8259-1
017 #define RTC_ADDR 0x70
018 #define RTC_DATA 0x71
019 #define PITCONST 1193180L // Frequence of 8254
020 #define PIT0DEF 18.2067597 // ticks per sec of previous int
021 #define RT_MS_PER_TICK 0.9765625
022 #define NEW8H 1 // flag. new int 8h valiable.
023 static float tick_per_ms = 0.0182068; // ticks per ms
024 static float ms_per_tick = 54.9246551; // interval between two ticks
025 static float freq8h = 18.2067597; // frequency of system timer
026 static unsigned char flag8h = 0;
027 static _go32_dpmi_seginfo old_handler_8h, new_handler_8h;
028 static _go32_dpmi_seginfo old_handler_70h, new_handler_70h;
029 static _go32_dpmi_registers r;
030 unsigned long int ticks_8h = 0;
031 unsigned long int ticks_70h = 0;
/***********************************************
* New int 8h initialization
* It chains int routine of protected mode and
* real mode
***********************************************/
032 void pctimer_init(unsigned int Hz) {
033 unsigned int pit0_set, pit0_value;
034 if (flag8h != NEW8H) { // Current int 8h is old.
035 disable(); // Disable interrupts
036 lock_pm_new8h(); // Lock int routine in protected mode
037 lock_pm_new70h(); // Lock int routine in protected mode
// Lock some var that will be used in int routine
038 _go32_dpmi_lock_data(&ticks_8h, sizeof(ticks_8h));
039 _go32_dpmi_lock_data(&ticks_70h, sizeof(ticks_70h));
040 _go32_dpmi_lock_data(&r, sizeof(r));
// Get the previous int routine in protected mode
// and chain a new routine
041 _go32_dpmi_get_protected_mode_interrupt_vector(IRQ0, &old_handler_8h);
042 new_handler_8h.pm_offset = (int)pm_new8h;
043 new_handler_8h.pm_selector = _go32_my_cs();
044 _go32_dpmi_chain_protected_mode_interrupt_vector(IRQ0, &new_handler_8h);
045 _go32_dpmi_get_protected_mode_interrupt_vector(IRQ8, &old_handler_70h);
046 new_handler_70h.pm_offset = (int)pm_new70h;
047 new_handler_70h.pm_selector = _go32_my_cs();
048 _go32_dpmi_allocate_iret_wrapper(&new_handler_70h);
049 _go32_dpmi_set_protected_mode_interrupt_vector(IRQ8, &new_handler_70h);
// initial RTC
050 outportb(RTC_ADDR, 0x0b);
051 outportb(RTC_DATA, 0x42);
// initial 8259-2
052 outportb(IMR1, 0x0c);
// initial Timer0 of 8254
053 outportb(PITMODE, 0x36); // 8254 command register
// 00110110b.timer0,write low and high
// sequare wave generator,binary
054 pit0_value = PITCONST / Hz;
055 pit0_set = (pit0_value & 0x00ff);
056 outportb (PIT0, pit0_set);
057 pit0_set = (pit0_value >> 8);
058 outportb (PIT0, pit0_set);
059 // initial vars for int
060 ticks_8h = 0;
061 flag8h = NEW8H; // new int 8h
062 freq8h = Hz; // frequence of new int
063 tick_per_ms = freq8h / 1000; // ticks per ms
064 ms_per_tick = 1000 / freq8h; // ms of per tick
065 enable(); // enable interrupts
066 }
067 }
068 void pctimer_exit(void) {
069 unsigned int pit0_set, pit0_value;
070 unsigned long tick;
071 char *cmostime;
072 if (flag8h == NEW8H) {
073 disable();
074 outportb(PITMODE, 0x36);
075 outportb(PIT0, 0x00);
076 outportb(PIT0, 0x00);
077 outportb(RTC_ADDR, 0x0b);
078 outportb(RTC_DATA, 0x02);
079 outportb(IMR1, 0x0d);
080 _go32_dpmi_set_protected_mode_interrupt_vector(IRQ0, &old_handler_8h);
081 _go32_dpmi_free_iret_wrapper(&new_handler_70h);
082 _go32_dpmi_set_protected_mode_interrupt_vector(IRQ8, &old_handler_70h);
083 enable();
084 cmostime = get_cmostime();
085 tick = PIT0DEF *
(
(((float) *cmostime) * 3600) +
(((float) *(cmostime + 1)) * 60) +
(((float) *(cmostime + 2)))
);
086 biostime(1, tick);
087 flag8h = 0;
088 freq8h = PIT0DEF;
089 tick_per_ms = freq8h / 1000;
090 ms_per_tick = 1000 / freq8h;
091 }
092 }
/****************************************
* New int 8h routine in protected mode
****************************************/
093 void pm_new8h(void) {
094 ticks_8h++;
095 }
/************************************************
* Lock the memory of new int 8h routine region
* in protected mode
************************************************/
096 void lock_pm_new8h(void) {
097 _go32_dpmi_lock_code(pm_new8h, (unsigned long)(lock_pm_new8h - pm_new8h));
098 }
/****************************************
* New int 70h routine in protected mode
****************************************/
099 void pm_new70h(void) {
100 disable();
101 ticks_70h++;
102 outportb(RTC_ADDR, 0x0c);
103 inportb(RTC_DATA);
104 outportb(0xa0, 0x20);
105 outportb(0x20, 0x20);
106 enable();
107 }
/************************************************
* Lock the memory of new int 70h routine region
* in protected mode
************************************************/
108 void lock_pm_new70h(void) {
109 _go32_dpmi_lock_code(pm_new70h, (unsigned long)(lock_pm_new70h - pm_new70h));
110 }
/*****************************************
* Sleep delayms ms
*****************************************/
111 void pctimer_sleep(unsigned int delayms) {
112 unsigned long int delaytick;
113 delaytick = delayms * tick_per_ms + ticks_8h;
114 do {
115 } while (ticks_8h <= delaytick);
116 }
117 char *get_cmostime(void) {
118 char *buff;
119 static char buffer[6];
120 char ch;
121 buff = buffer;
122 memset(&r, 0, sizeof (r));
123 r.h.ah = 0x02;
124 _go32_dpmi_simulate_int(0x1a, &r);
125 ch = r.h.ch;
126 buffer[0] = (char)((int)(ch & 0x0f) + (int)((ch >> 4) & 0x0f) * 10);
127 ch = r.h.cl;
128 buffer[1] = (char)((int)(ch & 0x0f) + (int)((ch >> 4) & 0x0f) * 10);
129 ch = r.h.dh;
130 buffer[2] = (char)((int)(ch & 0x0f) + (int)((ch >> 4) & 0x0f) * 10);
131 buffer[3] = r.h.dl;
132 buffer[4] = (char)(r.x.flags & 0x0001);
133 buffer[5] = 0x00;
134 return(buff);
135 }
// Main program
136 int main(void) {
137 int i;
138 unsigned long int start, finish;
139 int elapsedtime[20];
140 float average_error, sum = 0;
141 printf("Press any key to begin the test. ");
142 printf("(It lasts for 20 seconds.)\n\n");
143 getch();
144 printf("Test in progress. Please wait...\n");
145 pctimer_init(1000); // 1000Hz, 1000 ticks per sec
146 for (i = 0; i < 10; i++) {
147 start = ticks_70h;
148 pctimer_sleep(1000);
149 finish = ticks_70h;
150 elapsedtime[i] = (int)(finish - start);
151 }
152 pctimer_exit();
153 printf("Test finished.\n");
154 printf("Press any key to display the result...\n");
155 getch();
156 for (i = 0; i < 10; i++) {
157 sum += (float)((elapsedtime[i] - 1024) * RT_MS_PER_TICK);
158 printf("iteration:%2d expected:1024 observed:%d difference:%d\n",
i + 1, elapsedtime[i], elapsedtime[i] - 1024);
159 }
160 average_error = (float)sum / 10;
161 printf("\ntotal error:%.2f ms average error:%.2f ms\n",
sum, average_error);
162 return 0;
163 }
为了说明方便,源程序中加了行号,所有的注释语句没有行号。