-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added minimal pit implementation to the kernel test
- Loading branch information
Showing
7 changed files
with
258 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
*/ | ||
|
||
#include "pic.hpp" | ||
#include "..\run.h" | ||
#include "../run.h" | ||
#include <bit> | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
/* | ||
* pit barebones implementation | ||
* | ||
* ergo720 Copyright (c) 2023 | ||
*/ | ||
|
||
#include "pit.hpp" | ||
#include "pic.hpp" | ||
#include "../run.h" | ||
#ifdef __linux__ | ||
#include <sys/time.h> | ||
#elif _WIN64 | ||
#include "Windows.h" | ||
#undef max | ||
#endif | ||
#include <limits> | ||
|
||
|
||
// NOTE: on the xbox, the pit frequency is 6% lower than the default one, see https://xboxdevwiki.net/Porting_an_Operating_System_to_the_Xbox_HOWTO#Timer_Frequency | ||
constexpr uint64_t pit_clock_freq = 1125000; | ||
constexpr uint64_t ticks_per_second = 1000000; | ||
static uint64_t tot_time, last_time; | ||
|
||
#ifdef __linux__ | ||
void | ||
timer_init() | ||
{ | ||
struct timeval tv; | ||
gettimeofday(&tv, NULL); | ||
last_time = static_cast<uint64_t>(tv.tv_sec) * static_cast<uint64_t>(ticks_per_second) + static_cast<uint64_t>(tv.tv_usec); | ||
} | ||
#elif _WIN64 | ||
static uint64_t host_freq; | ||
|
||
void | ||
timer_init() | ||
{ | ||
LARGE_INTEGER freq, now; | ||
QueryPerformanceFrequency(&freq); | ||
host_freq = freq.QuadPart; | ||
QueryPerformanceCounter(&now); | ||
last_time = now.QuadPart; | ||
} | ||
#endif | ||
|
||
uint64_t | ||
get_now() | ||
{ | ||
#ifdef __linux__ | ||
timeval tv; | ||
gettimeofday(&tv, NULL); | ||
uint64_t curr_time = static_cast<uint64_t>(tv.tv_sec) * static_cast<uint64_t>(ticks_per_second) + static_cast<uint64_t>(tv.tv_usec); | ||
return tot_time += (curr_time - last_time); | ||
#elif _WIN64 | ||
LARGE_INTEGER now; | ||
QueryPerformanceCounter(&now); | ||
uint64_t elapsed_us = static_cast<uint64_t>(now.QuadPart) - last_time; | ||
last_time = now.QuadPart; | ||
elapsed_us *= 1000000; | ||
elapsed_us /= host_freq; | ||
tot_time += elapsed_us; | ||
return tot_time; | ||
#else | ||
#error "don't know how to implement the get_now function on this OS" | ||
#endif | ||
} | ||
|
||
static inline uint64_t | ||
pit_counter_to_us() | ||
{ | ||
constexpr double time_scale = static_cast<double>(ticks_per_second) / static_cast<double>(pit_clock_freq); | ||
return (uint64_t)(static_cast<double>(pit.chan[0].counter) * time_scale); | ||
} | ||
|
||
uint64_t | ||
pit_get_next_irq_time(uint64_t now) | ||
{ | ||
if (pit.chan[0].timer_running) { | ||
uint64_t next_time, pit_period = pit_counter_to_us(); | ||
if (now - pit.chan[0].last_irq_time >= pit_period) { | ||
pit.chan[0].last_irq_time = now; | ||
next_time = pit_period; | ||
|
||
pic_lower_irq(0); | ||
pic_raise_irq(0); | ||
} | ||
else { | ||
next_time = pit.chan[0].last_irq_time + pit_period - now; | ||
} | ||
|
||
return next_time; | ||
} | ||
|
||
return std::numeric_limits<uint64_t>::max(); | ||
} | ||
|
||
static void | ||
pit_start_timer(pit_channel_t *chan) | ||
{ | ||
chan->last_irq_time = get_now(); | ||
chan->timer_running = 1; | ||
cpu_set_timeout(cpu, pit_get_next_irq_time(chan->last_irq_time)); | ||
} | ||
|
||
void | ||
pit_write_handler(uint32_t port, const uint8_t value, void *opaque) | ||
{ | ||
uint8_t channel = port & 3; | ||
|
||
switch (channel) | ||
{ | ||
case 3: { | ||
channel = value >> 6; | ||
uint8_t opmode = value >> 1 & 7, bcd = value & 1, access = value >> 4 & 3; | ||
|
||
switch (channel) | ||
{ | ||
case 3: | ||
std::printf("Read back command is not supported\n"); | ||
cpu_exit(cpu); | ||
break; | ||
|
||
case 0: | ||
case 1: | ||
case 2: { | ||
pit_channel_t *chan = &pit.chan[channel]; | ||
if (!access) { | ||
std::printf("Counter latch command is not supported\n"); | ||
cpu_exit(cpu); | ||
} | ||
else { | ||
if (bcd) { | ||
std::printf("BCD mode not supported\n"); | ||
cpu_exit(cpu); | ||
} | ||
|
||
chan->wmode = access; | ||
chan->timer_mode = opmode; | ||
if ((chan->timer_mode == 2) && (channel == 0)) { | ||
pic_raise_irq(0); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
break; | ||
} | ||
break; | ||
|
||
case 0: | ||
case 1: | ||
case 2: { | ||
pit_channel_t *chan = &pit.chan[channel]; | ||
|
||
switch (chan->wmode) | ||
{ | ||
case 0: | ||
case 1: | ||
case 2: | ||
std::printf("Read/Load mode must be LSB first MSB last\n"); | ||
cpu_exit(cpu); | ||
break; | ||
|
||
case 3: | ||
if (chan->lsb_read) { | ||
chan->counter = (static_cast<uint16_t>(value) << 8) | chan->counter; | ||
pit_start_timer(chan); | ||
chan->lsb_read = 0; | ||
} | ||
else { | ||
chan->counter = value; | ||
chan->lsb_read = 1; | ||
} | ||
break; | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
|
||
static void | ||
pit_channel_reset(pit_channel_t *chan) | ||
{ | ||
chan->counter = 0; | ||
chan->timer_mode = 0; | ||
chan->lsb_read = 0; | ||
chan->timer_running = 0; | ||
} | ||
|
||
void | ||
pit_reset() | ||
{ | ||
for (pit_channel_t &chan : pit.chan) { | ||
pit_channel_reset(&chan); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* pit declarations | ||
* | ||
* ergo720 Copyright (c) 2023 | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <stdint.h> | ||
|
||
|
||
struct pit_channel_t { | ||
uint8_t timer_mode, wmode; | ||
uint8_t timer_running, lsb_read; | ||
uint16_t counter; | ||
uint64_t last_irq_time; | ||
}; | ||
|
||
struct pit_t { | ||
pit_channel_t chan[3]; | ||
}; | ||
|
||
inline pit_t pit; | ||
|
||
void timer_init(); | ||
uint64_t get_now(); | ||
uint64_t pit_get_next_irq_time(uint64_t now); | ||
void pit_write_handler(uint32_t port, const uint8_t value, void *opaque); | ||
void pit_reset(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters