93 lines
2.0 KiB
C++
93 lines
2.0 KiB
C++
#include <go32.h>
|
|
|
|
#include "Timer.h"
|
|
|
|
#include "Pic.h"
|
|
#include "../util/Asm.h"
|
|
|
|
#define PIT_FREQ 1193181
|
|
#define PIT_MODE_CH0 0x00
|
|
#define PIT_MODE_CH1 0x40
|
|
#define PIT_MODE_CH2 0x80
|
|
#define PIT_MODE_ACCESS_LO 0x10
|
|
#define PIT_MODE_ACCESS_HI 0x20
|
|
#define PIT_MODE_ACCESS_LOHI 0x30
|
|
#define PIT_MODE_M0 0x00
|
|
#define PIT_MODE_M1 0x02
|
|
#define PIT_MODE_M2 0x04
|
|
#define PIT_MODE_M3 0x06
|
|
#define PIT_MODE_M4 0x08
|
|
#define PIT_MODE_M5 0x0a
|
|
#define PIT_MODE_BIN 0x00
|
|
#define PIT_MODE_BCD 0x01
|
|
|
|
#define PIT_REG_CH0 0x40
|
|
#define PIT_REG_CH1 0x41
|
|
#define PIT_REG_CH2 0x42
|
|
#define PIT_REG_MODE 0x43
|
|
|
|
Timer timer;
|
|
|
|
void timerISR() {
|
|
timer.update();
|
|
}
|
|
|
|
Timer::Timer() {
|
|
_go32_dpmi_get_protected_mode_interrupt_vector(8, &_oldIsr);
|
|
|
|
_newIsr.pm_offset = reinterpret_cast<int>(timerISR);
|
|
_newIsr.pm_selector = _go32_my_cs();
|
|
_go32_dpmi_allocate_iret_wrapper(&_newIsr);
|
|
_go32_dpmi_set_protected_mode_interrupt_vector(8, &_newIsr);
|
|
}
|
|
|
|
Timer::~Timer() {
|
|
setDivider(65535);
|
|
_go32_dpmi_set_protected_mode_interrupt_vector(8, &_oldIsr);
|
|
_go32_dpmi_free_iret_wrapper(&_newIsr);
|
|
}
|
|
|
|
void Timer::update() {
|
|
_ticks++;
|
|
|
|
if (_callback) _callback();
|
|
|
|
_elapsed += _div;
|
|
if (_elapsed >= 65535) {
|
|
_elapsed -= 65535;
|
|
// TODO call old isr
|
|
// Documentation is kind of nonexistant so we will not call the handler for now
|
|
Pic::clearInterrupt();
|
|
} else {
|
|
Pic::clearInterrupt();
|
|
}
|
|
}
|
|
|
|
uint32_t Timer::getTicks() const {
|
|
return _ticks;
|
|
}
|
|
|
|
void Timer::setFrequency(uint16_t freq) {
|
|
setDivider(PIT_FREQ / freq);
|
|
}
|
|
|
|
void Timer::setDivider(uint16_t div) {
|
|
auto wasEnabled = interruptsEnabled();
|
|
disableInterrupts();
|
|
|
|
_div = div;
|
|
|
|
// Update PIT frequency
|
|
outb(PIT_REG_MODE, PIT_MODE_CH0|PIT_MODE_ACCESS_LOHI|PIT_MODE_M2|PIT_MODE_BIN);
|
|
outb(PIT_REG_CH0, _div & 0xff);
|
|
outb(PIT_REG_CH0, (_div >> 8) & 0xff);
|
|
|
|
if (1) enableInterrupts();
|
|
}
|
|
|
|
Timer::Callback Timer::setCallback(Timer::Callback callback) {
|
|
auto oldCallback = _callback;
|
|
_callback = callback;
|
|
return oldCallback;
|
|
}
|