Verified Commit e3950bd3 authored by Allie Sargente's avatar Allie Sargente 😑

Added timekeeping and PIT implementation

Tests pass
parent c6c34aa7
No preview for this file type
No preview for this file type
......@@ -15,7 +15,7 @@ Release 0.1.0
- [ ] Floppy Disk Controller
- [ ] Basic I/O Support
- [ ] PS/2 Keyboard
- [ ] Serial I/O
- [X] Serial I/O
- [ ] Parallel Port
- [ ] Some Standard Library Implemented
- [ ] All of String.h
......
......@@ -61,6 +61,13 @@ void disable_interrupts()
__asm__ volatile("cli");
}
int get_interrupt_state()
{
uint32_t flags;
__asm__ volatile ( "pushf \n\t" "pop %0" : "=g"(flags) );
return flags & (1 << 9); // Return the interrupt enabled flag
}
void set_interrupt_state(int enable)
{
if(enable) {
......
/*
* (c) 2018 Apollo Project Developers
* pit.c - Initialize the programmable interrupt timer
* Driver for the 8253/8254
*/
#include <arch/x86/ports.h>
#include <arch/x86/pit.h>
#include <sys/hal.h>
#include <sys/timekeeping.h>
#include <stdio.h>
// 36.157 KHz, 99 ticks per correction, 2 tick correction.
// 27 Microseconds per tick, 3 ticks per correction, 2 uS correction.
static const uint32_t PIT_config[] = { 36157, 99, 2, 27, 3, 2 };
static int timekeeping(struct regs *regs, void *p)
{
uint64_t ts = get_timestamp();
timekeeping_state_t *state = (timekeeping_state_t*)p;
state->ticks += 1;
state->correction_count += 1;
// PIT is definately gonna be set to less than 1 uS
ts += state->us_per_tick; // Add microseconds the clock.
state->us_correction_count++;
if(state->us_correction_count >= state->us_correction_rate) {
ts += state->us_correction_factor;
}
if (state->correction_count >= state->correction_rate) {
state->ticks = state->ticks + state->correction_factor;
state->correction_count = 0;
}
set_timestamp(ts);
return 0;
}
static int PIT_init()
{
uint32_t divisor;
uint8_t low, high, init_byte;
timekeeping_state_t state;
int interrupt_state;
state.frequency = PIT_config[0];
state.correction_rate = PIT_config[1];
state.correction_factor = PIT_config[2];
state.us_per_tick = PIT_config[3];
state.us_correction_factor = PIT_config[4];
state.us_correction_rate = PIT_config[5];
state.tick_per_us = 0;
state.ticks = 0;
state.correction_count = 0;
state.us_correction_count = 0;
set_timestamp(0);
init_byte = PIT_CHANNEL_0 | PIT_LHBYTE | PIT_MODE_2 | PIT_BIN_MODE;
divisor = PIT_BASE_FREQ / PIT_config[0];
low = (uint8_t)(divisor & 0xFF);
high = (uint8_t)((divisor >> 8) & 0xFF);
interrupt_state = get_interrupt_state();
disable_interrupts();
write_register(PIT_DATA_PORT, PIT_CMD, init_byte);
write_register(PIT_DATA_PORT, PIT_DATA_0, low);
write_register(PIT_DATA_PORT, PIT_DATA_0, high);
// PIC is on IRQ 0, which is int 32.
register_interrupt_handler(32, &timekeeping, (void*)&state);
set_interrupt_state(interrupt_state);
return 0;
}
static prereq_t prereqs[] = {{"interrupts", NULL}, {NULL, NULL}};
MODULE = {
.name = "PIT",
.required = prereqs,
.load_after = NULL,
.init = &PIT_init,
.fini = NULL,
};
......@@ -217,7 +217,7 @@ static int register_serial()
return 0;
}
static prereq_t prereqs[] = { {"console",NULL}, {NULL,NULL} };
static prereq_t prereqs[] = {{"console",NULL}, {"interrupts",NULL}, {NULL,NULL}};
MODULE = {
.name = "x86/serial",
......
......@@ -56,6 +56,7 @@ int main(int argc, char **argv)
set_log_level(0);
init_module(test_module);
} else {
enable_interrupts();
for(;;) {
char a = 0;
read_console(&a, 1);
......
/*
* (C) 2018 Apollo Project Developers
* pic.h - Definitions for controlling the PIT microcontrollers
* pic.h - Definitions for controlling the PIC microcontrollers
*/
#ifndef __ARCH_X86_PIC_H
......
/*
* (C) 2018 Apollo Project Developers
* pit.h - Definitions for controlling the PIT microcontrollers
*/
#ifndef __ARCH_X86_PIT_H
#define __ARCH_X86_PIT_H
#include <stdint.h>
#define PIT_BASE_FREQ 1193182 /* 1.193181666666666 MHz */
#define PIT_DATA_PORT 0x40
#define PIT_DATA_0 0
#define PIT_DATA_1 1
#define PIT_DATA_2 2
#define PIT_CMD 3
#define PIT_BIN_MODE 0x00 /* 16 Bit Binary Counting Mode */
#define PIT_BCD_MODE 0x01 /* Four Digit Binary Coded Decimal Counting */
#define PIT_MODE_0 0x00 /* Interrupt on Terminal Count */
#define PIT_MODE_1 0x02 /* Hardware re-triggerable One-Shot */
#define PIT_MODE_2 0x04 /* Rate Generator */
#define PIT_MODE_3 0x06 /* Square Wave Generator */
#define PIT_MODE_4 0x08 /* Software Triggered Strobe */
#define PIT_MODE_5 0x0A /* Hardware Triggered Strobe */
#define PIT_LATCH 0x00 /* Latch Count Value Command */
#define PIT_LOBYTE 0x10 /* Access Low Byte Only */
#define PIT_HIBYTE 0x20 /* Access High Byte Only */
#define PIT_LHBYTE 0x30 /* Access Both Bytes */
#define PIT_CHANNEL_0 0x00 /* Select Channel 0 */
#define PIT_CHANNEL_1 0x40 /* Select Channel 1 */
#define PIT_CHANNEL_2 0x80 /* Select Channel 2 */
#define PIT_READBACK 0xC0 /* 8254 Readback Command */
#endif
/*
* (c) 2019 Apollo Developers
* timekeeping.h - Functionality for time
*/
typedef struct timekeeping_state
{
uint32_t frequency; // Frequency of clock
int32_t ticks; // Simple number of ticks
uint32_t rollover; // Rollover for ticks
uint32_t tick_per_us; // Set to 0 if tick > 1 microsecond
uint32_t us_per_tick; // Set to 0 if tick < 1 microsecond
uint32_t us_correction_factor; // How much to correct
uint32_t us_correction_rate; // How often to apply correction
uint32_t us_correction_count; // Count for correction
uint32_t correction_rate; // How often to apply correction
uint32_t correction_factor; // How much to correct
uint32_t correction_count; // Count for correction
} timekeeping_state_t;
#include <sys/hal.h>
#include <sys/testing.h>
TEST_GROUP(pit_test);
static volatile uint32_t testVar;
static int callback(struct regs *r, void *p)
{
testVar++;
return 0;
}
TEST_SETUP(pit_test)
{
testVar = 0;
register_interrupt_handler(32, &callback, (void*)0xDEADBEEF);
}
TEST_TEAR_DOWN(pit_test)
{
unregister_interrupt_handler(32, &callback, (void*)0xDEADBEEF);
}
TEST(pit_test, didTimePass)
{
while(testVar < 200);
TEST_ASSERT(testVar != 0); // Make sure time has passed
}
TEST(pit_test, updatedTimestamp)
{
uint64_t ts = get_timestamp();
while(testVar < 200);
TEST_ASSERT(get_timestamp() > ts);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment