From f9c2ea2f2bb883b8af3c5c56d29632f79396a83b Mon Sep 17 00:00:00 2001 From: Nathan Singer Date: Fri, 6 Jun 2025 22:01:18 -0400 Subject: [PATCH] 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 --- kernel/arch/io/pit.c | 61 ++++++++++++++++++++++++++++++++ kernel/include/kernel/x86/keyb.h | 1 + kernel/include/kernel/x86/pit.h | 41 +++++++++++++++++++++ kernel/kmain.c | 3 ++ libc/include/math.h | 13 +++++++ libc/include/stdlib.h | 2 ++ libc/math/clamp.c | 39 ++++++++++++++++++++ libc/math/pow.c | 9 +++++ libc/stdio/printf.c | 12 +++++++ libc/stdlib/itoa.c | 34 ++++++++++++++++++ 10 files changed, 215 insertions(+) create mode 100644 libc/include/math.h create mode 100644 libc/math/clamp.c create mode 100644 libc/math/pow.c diff --git a/kernel/arch/io/pit.c b/kernel/arch/io/pit.c index 52398c0..67be0f3 100644 --- a/kernel/arch/io/pit.c +++ b/kernel/arch/io/pit.c @@ -1,3 +1,64 @@ +#include + #include +#include + +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 +} diff --git a/kernel/include/kernel/x86/keyb.h b/kernel/include/kernel/x86/keyb.h index 107a085..7759b38 100644 --- a/kernel/include/kernel/x86/keyb.h +++ b/kernel/include/kernel/x86/keyb.h @@ -1,4 +1,5 @@ #include +#include #ifndef ARCH_KEYB_H #define ARCH_KEYB_H diff --git a/kernel/include/kernel/x86/pit.h b/kernel/include/kernel/x86/pit.h index 8bdf063..ed212e9 100644 --- a/kernel/include/kernel/x86/pit.h +++ b/kernel/include/kernel/x86/pit.h @@ -1,3 +1,5 @@ +#include + #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 diff --git a/kernel/kmain.c b/kernel/kmain.c index 45adc3e..5b61bc6 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -9,6 +9,7 @@ #include #include +#include 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) { diff --git a/libc/include/math.h b/libc/include/math.h new file mode 100644 index 0000000..97a7b2a --- /dev/null +++ b/libc/include/math.h @@ -0,0 +1,13 @@ +#include + +#ifndef MATH_H +#define MATH_H + +int pow(int base, int exp); + +uint8_t clamp_u8(uint8_t val, uint8_t min, uint8_t max); +uint16_t clamp_u16(uint16_t val, uint16_t min, uint16_t max); +uint32_t clamp_u32(uint32_t val, uint32_t min, uint32_t max); +uint64_t clamp_u64(uint64_t val, uint64_t min, uint64_t max); + +#endif diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 4de8c7e..2ce508d 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -20,5 +20,7 @@ char* u8toa(uint8_t num, char* buf, int base); char* itoa(int num, char* buf, int base); char* utoa(unsigned int num, char* buf, int base); +char* dtoa(double n, char* buf, int afterpoint); + #endif diff --git a/libc/math/clamp.c b/libc/math/clamp.c new file mode 100644 index 0000000..755c8ab --- /dev/null +++ b/libc/math/clamp.c @@ -0,0 +1,39 @@ +#include +#include + +uint8_t clamp_u8(uint8_t val, uint8_t min, uint8_t max) +{ + if (val > max) + return max; + if (val < min) + return min; + return val; +} + +uint16_t clamp_u16(uint16_t val, uint16_t min, uint16_t max) +{ + if (val > max) + return max; + if (val < min) + return min; + return val; +} + +uint32_t clamp_u32(uint32_t val, uint32_t min, uint32_t max) +{ + if (val > max) + return max; + if (val < min) + return min; + return val; + +} + +uint64_t clamp_u64(uint64_t val, uint64_t min, uint64_t max) +{ + if (val > max) + return max; + if (val < min) + return min; + return val; +} diff --git a/libc/math/pow.c b/libc/math/pow.c new file mode 100644 index 0000000..2fa5f17 --- /dev/null +++ b/libc/math/pow.c @@ -0,0 +1,9 @@ +#include + +int pow(int base, int exp) +{ + int res = base; + for (int i = 0; i < exp; i++) + res *= base; + return res; +} diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index f0ca47a..5a12156 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -77,6 +77,18 @@ int printf(const char* restrict format, ...) { if (!print(buffer, len)) return -1; written += len; + } else if (*format == 'f') { + format++; + double d = (double) va_arg(parameters, double); + dtoa(d, buffer, 5); + size_t len = strlen(buffer); + if (maxrem < len) { + // TODO + return -1; + } + if (!print(buffer, len)) + return -1; + written += len; } else if (*format == 'u') { format++; unsigned int i = (unsigned int) va_arg(parameters, unsigned int); diff --git a/libc/stdlib/itoa.c b/libc/stdlib/itoa.c index 69dbda2..9728612 100644 --- a/libc/stdlib/itoa.c +++ b/libc/stdlib/itoa.c @@ -1,5 +1,7 @@ #include #include +#include +#include static void reverse(char* buf, int len) { @@ -273,3 +275,35 @@ char* utoa(unsigned int num, char* buf, int base) reverse(buf, i); // reverse, since we did it backwards! return buf; } + +static int dbl_to_str(int x, char* buf, int d) +{ + int i = 0; + while (x) { + buf[i++] = (x % 10) + '0'; + x = x / 10; + } + + while (i < d) + buf[i++] = '0'; + + reverse(buf, i); + buf[i] = '\0'; + return i; +} + +char* dtoa(double n, char* buf, int afterpoint) +{ + int whole = (int) n; + + double decimals = n - (double) whole; + + int i = dbl_to_str(whole, buf, 0); + if (afterpoint != 0) { + buf[i] = '.'; // add the decimal + + decimals = decimals * pow(10, afterpoint); + dbl_to_str((int) decimals, buf + i + 1, afterpoint + 1); + } + return buf; +}