Does a lot of work towards the PIT

Added a math library, with clamp and POW.
added printf support for printing doubles
added a few helper functions in PIT for calcaulting the time in seconds of a clock cycle based on divisor
This commit is contained in:
2025-06-06 22:01:18 -04:00
parent 378f7ef23d
commit f9c2ea2f2b
10 changed files with 215 additions and 0 deletions

View File

@ -1,3 +1,64 @@
#include <math.h>
#include <kernel/x86/pit.h>
#include <kernel/x86/io.h>
struct pit_state pit;
uint32_t normalize_divisor(uint32_t divisor)
{
if (divisor == 0)
return 65536;
return clamp_u32(divisor, 0, 65535);
}
double get_time_from_divisor(uint32_t divisor)
{
uint32_t _divisor = normalize_divisor(divisor);
double clock_rate = 3579545.0 / 3.0; // This is for a bit more precision in the hz rate
return (_divisor / (clock_rate)) * 1000;
}
/**
* Im worried about an overflow
*
*
* What i want to do is
*
* Every time we get the Timer intterupt, i want to increment a variable, just the amount of times its fired
* and then we can use the time rate above to get total time elapsed, which we can use for sleep and stuff
*
* Im worried about overflows, but i can add something that will automatically flip it over? or do uints already roll over? they already rollover!!! WOOOO!!!
* just need to be aware that only a maximum of 52ms * 32int max (64 int max) can be tracked before it rolls over!
*/
uint16_t read_pit_count(uint8_t channel) // Only in lobyte/hibyte mode
{
uint16_t count = 0;
__asm__ volatile ("cli");
outb(PIT_CMD_REG, (channel << 6)); // xx000000 where x is the channel
count = inb(channel);
count |= inb(channel) << 8;
return count; // TODO make sure to enable interrupts after this
}
void set_pit_count(uint8_t channel, uint16_t count) // Only in lobyte/hibyte mode
{
__asm__ volatile ("cli");
outb(channel, count & 0xFF); // low byte
outb(channel, (count & 0xFF00) >> 8); // high byte
// TODO: make sure to set interrupts
}

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include <stdbool.h>
#ifndef ARCH_KEYB_H
#define ARCH_KEYB_H

View File

@ -1,3 +1,5 @@
#include <stdint.h>
#ifndef ARCH_PIT_H
#define ARCH_PIT_H
@ -16,6 +18,27 @@ enum PIT_CHANNEL {
CHANNEL_0 = 0x0,
CHANNEL_1,
CHANNEL_2,
/**
* Isn't supported on 8253 chips, but should be supported on AT and later (except for PS/2).
*
* Layout goes:
* bits:
* 76 - Set for READ_BACK
* 5 - Latch count flag (0 = latch count, 1 = don't latch count)
* 4 - Latch status flag (0 = latch status, 1 = don't latch status) - If this is clear, the next read of the corresponding data port will be a status byte
* 3 - Read back timer channel 2 (1 = yes, 0 = no)
* 2 - Read back timer channel 1 (..)
* 1 - Read back timer channel 0 (..)
* 0 - Reserved - set to 0
*
* Read back status byte:
* bits:
* 7 - Output pin state
* 6 - Null count flags
* 54 - Access mode
* 321 - Operating mode
* 0 BCD/Binary mode
*/
READ_BACK // 8254 only
};
@ -28,6 +51,13 @@ enum PIT_CHANNEL {
* HI AND LOW means that the values will come sequentially through the IO port, lowest followed by highest
*/
enum PIT_ACCESS_MODE {
/*
* To prevent the count from being updated, we can use this command to latch the PIT.
* This must be xx000000 ( where x is the channel ).
* The value for each channel remains latched, until its fully read (or a new CMD has been issued).
* Some older/cheap motherboards have an issue with this command being sent a lot, leading to innaccuracies
* this command shouldn't be sent a lot anyways.
*/
LATCH_COUNT_VAL_CMD = 0x0,
LO_BYTE_ONLY,
HI_BYTE_ONLY,
@ -213,5 +243,16 @@ enum PIT_DIGIT_MODE {
BCD_MODE // four-digit bcd
};
struct pit_state {
uint32_t divisor;
} __attribute__((packed));
void init_pit(uint32_t divisor);
double get_time_from_divisor(uint32_t divisor);
uint16_t read_pit_count(uint8_t channel);
void set_pit_count(uint8_t channel, uint16_t count);
#endif

View File

@ -9,6 +9,7 @@
#include <kernel/x86/io.h>
#include <kernel/x86/keyb.h>
#include <kernel/x86/pit.h>
void kmain(void)
@ -27,6 +28,8 @@ void kmain(void)
init_kb();
printf("%f\n", get_time_from_divisor(10));
printf("Entering loop...\n");
while (1) {