Skip to content

Commit

Permalink
Added minimal pit implementation to the kernel test
Browse files Browse the repository at this point in the history
  • Loading branch information
ergo720 committed Oct 4, 2023
1 parent d197025 commit 00f0909
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 3 deletions.
2 changes: 2 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ set(TEST_RUN86_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR})
file (GLOB HEADERS
"${TEST_RUN86_ROOT_DIR}/run.h"
"${TEST_RUN86_ROOT_DIR}/nboxkrnl/pic.hpp"
"${TEST_RUN86_ROOT_DIR}/nboxkrnl/pit.hpp"
)

file (GLOB SOURCES
"${TEST_RUN86_ROOT_DIR}/debug.cpp"
"${TEST_RUN86_ROOT_DIR}/hook.cpp"
"${TEST_RUN86_ROOT_DIR}/nboxkrnl/kernel.cpp"
"${TEST_RUN86_ROOT_DIR}/nboxkrnl/pic.cpp"
"${TEST_RUN86_ROOT_DIR}/nboxkrnl/pit.cpp"
"${TEST_RUN86_ROOT_DIR}/run.cpp"
"${TEST_RUN86_ROOT_DIR}/test386.cpp"
"${TEST_RUN86_ROOT_DIR}/test80186.cpp"
Expand Down
22 changes: 21 additions & 1 deletion test/nboxkrnl/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

#include <fstream>
#include "pic.hpp"
#include "..\run.h"
#include "pit.hpp"
#include "../run.h"

#define CONTIGUOUS_MEMORY_BASE 0x80000000

Expand Down Expand Up @@ -253,7 +254,12 @@ gen_nboxkrnl_test(const std::string &executable)
return false;
}

if (!LC86_SUCCESS(mem_init_region_io(cpu, 0x40, 4, true, io_handlers_t{ .fnw8 = pit_write_handler }, nullptr))) {
return false;
}

pic_reset();
pit_reset();

// Load kernel exe into ram
uint8_t *ram = get_ram_ptr(cpu);
Expand Down Expand Up @@ -311,3 +317,17 @@ gen_nboxkrnl_test(const std::string &executable)

return true;
}

lc86_status
run_nboxkrnl_test()
{
timer_init();
cpu_sync_state(cpu);

while (true) {
lc86_status ret = cpu_run_until(cpu, pit_get_next_irq_time(get_now()));
if (ret != lc86_status::timeout) [[unlikely]] {
return ret;
}
}
}
2 changes: 1 addition & 1 deletion test/nboxkrnl/pic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

#include "pic.hpp"
#include "..\run.h"
#include "../run.h"
#include <bit>


Expand Down
196 changes: 196 additions & 0 deletions test/nboxkrnl/pit.cpp
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);
}
}
29 changes: 29 additions & 0 deletions test/nboxkrnl/pit.hpp
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();
9 changes: 8 additions & 1 deletion test/run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,14 @@ main(int argc, char **argv)

cpu_set_flags(cpu, syntax | (use_dbg ? CPU_DBG_PRESENT : 0) | CPU_ABORT_ON_HLT);

lc86_status code = cpu_run(cpu);
lc86_status code;
if (test_num == 3) {
code = run_nboxkrnl_test();
}
else {
code = cpu_run(cpu);
}

std::printf("Emulation terminated with status %d. The error was \"%s\"\n", static_cast<int32_t>(code), get_last_error().c_str());
cpu_free(cpu);

Expand Down
1 change: 1 addition & 0 deletions test/run.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ bool gen_hook_test();
bool gen_dbg_test();
bool gen_nboxkrnl_test(const std::string &executable);
void gen_test80186_test(const std::string &path, int syntax, int use_dbg);
lc86_status run_nboxkrnl_test();

0 comments on commit 00f0909

Please sign in to comment.