timer/scheduler working

This commit is contained in:
Eggert Jung
2025-07-08 01:11:22 +02:00
parent 689c77f19e
commit bc0a94b705
6 changed files with 143 additions and 38 deletions

View File

@@ -68,7 +68,10 @@ enum Vector {
// Interrupts
KEYBOARD=32,
PANIC=33
PANIC=33,
TIMER = 251,
ASSASSIN = 252,
};
constexpr size_t VECTORS = 256;

View File

@@ -1,5 +1,9 @@
#include "lapic.h"
#include "lapic_registers.h"
#include "core.h"
#include "pit.h"
#include "../debug/output.h"
namespace LAPIC {
namespace Timer {
@@ -56,36 +60,118 @@ static const Register div_masks[] = {
* \param div Divider, must be power of two: 1, 2, 4, 8, 16, 32, 64, 128
* \return Bit mask for LAPIC::setTimer() or `0xff` if `div` is invalid.
*/
Register getClockDiv(uint8_t div) {
(void)div;
return 0;
static Register getClockDiv(uint8_t div) {
switch (div) {
case 1: return div_masks[0];
case 2: return div_masks[1];
case 4: return div_masks[2];
case 8: return div_masks[3];
case 16: return div_masks[4];
case 32: return div_masks[5];
case 64: return div_masks[6];
case 128: return div_masks[7];
default : return 0xff;
}
}
/*! \brief Calculate the LAPIC-timer divider for the bit mask.
* \param div_mask The bit mask, must be one of: 0xb, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa
* \return LAPIC-timer divider or `0xff` if `div_mask` is invalid.
*/
static uint8_t fromClockDiv(Register div_mask) {
if (div_mask == div_masks[0]) return 1;
if (div_mask == div_masks[1]) return 2;
if (div_mask == div_masks[2]) return 4;
if (div_mask == div_masks[3]) return 8;
if (div_mask == div_masks[4]) return 16;
if (div_mask == div_masks[5]) return 32;
if (div_mask == div_masks[6]) return 64;
if (div_mask == div_masks[7]) return 128;
return 0xff;
}
uint32_t ticks(void) {
uint32_t ticks = 0; // ticks per millisecond
// Calculation (Assignment 5)
static uint32_t ticks = 0; // ticks per millisecond
if (ticks != 0) return ticks;
// Prepare Counter
LAPIC::Timer::set(0, 1, 0, false, true);
// Set timer for 10ms
PIT::set(10 * 1000);
// Start LAPIC-Timer
LAPIC::write(TIMER_INITIAL_COUNTER, UINT32_MAX);
PIT::waitForTimeout();
// Get final Count
uint32_t counter = LAPIC::read(TIMER_CURRENT_COUNTER);
// Disable LAPIC-Timer
LAPIC::write(TIMER_INITIAL_COUNTER, 0);
// Calculate tick count.
ticks = (UINT32_MAX - counter) / 10;
DBG << "LAPIC-Timer calibration using PIT" << endl;
return ticks;
}
void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
bool masked) {
(void)counter;
(void)divide;
(void)vector;
(void)periodic;
(void)masked;
if (divide == 0 || (divide & (divide - 1)) != 0) {
// Not a power of 2
return;
}
ControlRegister tcr;
tcr.vector = Core::Interrupt::Vector::TIMER;
tcr.timer_mode = periodic ? PERIODIC : ONE_SHOT;
tcr.masked = masked ? MASKED : NOT_MASKED;
LAPIC::write(TIMER_CONTROL, tcr.value);
LAPIC::write(TIMER_DIVIDE_CONFIGURATION, getClockDiv(divide));
LAPIC::write(TIMER_INITIAL_COUNTER, counter);
}
bool setup(uint32_t us) {
(void)us;
return false;
uint64_t timer_ticks = (static_cast<uint64_t>(ticks()) * us) / 1000ULL;
uint8_t divisor = 1;
while (timer_ticks > UINT32_MAX) {
// While timer_ticks is to large to fit in 32bits.
timer_ticks >>= 1;
divisor <<= 1;
}
if (divisor > 128)
return false; // Timer interval is to large.
// Setup Masked interrupts to effectively disable the timer.
set(static_cast<uint32_t>(timer_ticks), divisor, Core::Interrupt::TIMER, true, true);
return true;
}
uint32_t interval() { return 0; }
uint32_t interval() {
uint32_t timer_ticks = LAPIC::read(TIMER_INITIAL_COUNTER);
uint32_t divisor = fromClockDiv(LAPIC::read(TIMER_DIVIDE_CONFIGURATION));
void activate() {}
uint64_t us = (static_cast<uint64_t>(timer_ticks) * divisor * 1000ULL) / static_cast<uint64_t>(ticks());
return static_cast<uint32_t>(us);
}
void setMasked(bool masked) { (void)masked; }
void activate() {
uint32_t timer_ticks = LAPIC::read(TIMER_INITIAL_COUNTER);
// Disable Counter to avoid spouriose interrupts.
LAPIC::write(TIMER_INITIAL_COUNTER, 0);
// Activate Timer interrupts.
setMasked(false);
// enable counter with correct value.
LAPIC::write(TIMER_INITIAL_COUNTER, timer_ticks);
}
void setMasked(bool masked) {
ControlRegister tcr;
tcr.value = LAPIC::read(TIMER_CONTROL);
tcr.masked = masked ? MASKED : NOT_MASKED;
LAPIC::write(TIMER_CONTROL, tcr.value);
}
} // namespace Timer
} // namespace LAPIC