rayzor
diff src/timer.c @ 0:2a5340a6eee4
rayzor first commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 05 Apr 2014 08:46:27 +0300 |
parents | |
children | a826bf0fb169 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/timer.c Sat Apr 05 08:46:27 2014 +0300 1.3 @@ -0,0 +1,131 @@ 1.4 +/* 1.5 +256-color 3D graphics hack for real-mode DOS. 1.6 +Copyright (C) 2011 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 +#include <stdio.h> 1.22 +#include <stdlib.h> 1.23 +#include <conio.h> 1.24 +#include <dos.h> 1.25 +#include <i86.h> 1.26 +#include "pit8254.h" 1.27 + 1.28 +#define PIT_TIMER_INTR 8 1.29 +#define DOS_TIMER_INTR 0x1c 1.30 + 1.31 +/* macro to divide and round to the nearest integer */ 1.32 +#define DIV_ROUND(a, b) \ 1.33 + ((a) / (b) + ((a) % (b)) / ((b) / 2)) 1.34 + 1.35 +static void set_timer_reload(int reload_val); 1.36 +static void cleanup(void); 1.37 +static void __interrupt __far timer_irq(); 1.38 +static void __interrupt __far dos_timer_intr(); 1.39 + 1.40 +static void (__interrupt __far *prev_timer_intr)(); 1.41 + 1.42 +static unsigned long ticks; 1.43 +static unsigned long tick_interval, ticks_per_dos_intr; 1.44 +static int inum; 1.45 + 1.46 +void init_timer(int res_hz) 1.47 +{ 1.48 + _disable(); 1.49 + 1.50 + if(res_hz > 0) { 1.51 + int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz); 1.52 + set_timer_reload(reload_val); 1.53 + 1.54 + tick_interval = DIV_ROUND(1000, res_hz); 1.55 + ticks_per_dos_intr = DIV_ROUND(65535L, reload_val); 1.56 + 1.57 + inum = PIT_TIMER_INTR; 1.58 + prev_timer_intr = _dos_getvect(inum); 1.59 + _dos_setvect(inum, timer_irq); 1.60 + } else { 1.61 + tick_interval = 55; 1.62 + 1.63 + inum = DOS_TIMER_INTR; 1.64 + prev_timer_intr = _dos_getvect(inum); 1.65 + _dos_setvect(inum, dos_timer_intr); 1.66 + } 1.67 + _enable(); 1.68 + 1.69 + atexit(cleanup); 1.70 +} 1.71 + 1.72 +static void cleanup(void) 1.73 +{ 1.74 + if(!prev_timer_intr) { 1.75 + return; /* init hasn't ran, there's nothing to cleanup */ 1.76 + } 1.77 + 1.78 + _disable(); 1.79 + if(inum == PIT_TIMER_INTR) { 1.80 + /* restore the original timer frequency */ 1.81 + set_timer_reload(65535); 1.82 + } 1.83 + 1.84 + /* restore the original interrupt handler */ 1.85 + _dos_setvect(inum, prev_timer_intr); 1.86 + _enable(); 1.87 +} 1.88 + 1.89 +void reset_timer(void) 1.90 +{ 1.91 + ticks = 0; 1.92 +} 1.93 + 1.94 +unsigned long get_msec(void) 1.95 +{ 1.96 + return ticks * tick_interval; 1.97 +} 1.98 + 1.99 +static void set_timer_reload(int reload_val) 1.100 +{ 1.101 + outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE); 1.102 + outp(PORT_DATA0, reload_val & 0xff); 1.103 + outp(PORT_DATA0, (reload_val >> 8) & 0xff); 1.104 +} 1.105 + 1.106 +static void __interrupt __far dos_timer_intr() 1.107 +{ 1.108 + ticks++; 1.109 + _chain_intr(prev_timer_intr); /* DOES NOT RETURN */ 1.110 +} 1.111 + 1.112 +/* first PIC command port */ 1.113 +#define PIC1_CMD 0x20 1.114 +/* end of interrupt control word */ 1.115 +#define OCW2_EOI (1 << 5) 1.116 + 1.117 +static void __interrupt __far timer_irq() 1.118 +{ 1.119 + static unsigned long dos_ticks; 1.120 + 1.121 + ticks++; 1.122 + 1.123 + if(++dos_ticks >= ticks_per_dos_intr) { 1.124 + /* I suppose the dos irq handler does the EOI so I shouldn't 1.125 + * do it if I am to call the previous function 1.126 + */ 1.127 + dos_ticks = 0; 1.128 + _chain_intr(prev_timer_intr); /* XXX DOES NOT RETURN */ 1.129 + return; /* just for clarity */ 1.130 + } 1.131 + 1.132 + /* send EOI to the PIC */ 1.133 + outp(PIC1_CMD, OCW2_EOI); 1.134 +}